linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 1/3] dt-bindings: iio/adc: Add a compatible string for JZ4770 SoC ADC
@ 2019-07-27 19:59 Artur Rojek
  2019-07-27 19:59 ` [PATCH v2 2/3] dt-bindings: iio/adc: Add AUX2 channel idx " Artur Rojek
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Artur Rojek @ 2019-07-27 19:59 UTC (permalink / raw)
  To: Jonathan Cameron, Rob Herring, Mark Rutland, Paul Cercueil
  Cc: linux-iio, devicetree, linux-kernel, Artur Rojek, Rob Herring

Add a compatible string for the ADC controller present on
Ingenic JZ4770 SoC.

Signed-off-by: Artur Rojek <contact@artur-rojek.eu>
Reviewed-by: Rob Herring <robh@kernel.org>
---

Changes:

v2: no change

 Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt b/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt
index f01159f20d87..cd9048cf9dcf 100644
--- a/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt
+++ b/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt
@@ -5,6 +5,7 @@ Required properties:
 - compatible: Should be one of:
   * ingenic,jz4725b-adc
   * ingenic,jz4740-adc
+  * ingenic,jz4770-adc
 - reg: ADC controller registers location and length.
 - clocks: phandle to the SoC's ADC clock.
 - clock-names: Must be set to "adc".
-- 
2.22.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 2/3] dt-bindings: iio/adc: Add AUX2 channel idx for JZ4770 SoC ADC
  2019-07-27 19:59 [PATCH v2 1/3] dt-bindings: iio/adc: Add a compatible string for JZ4770 SoC ADC Artur Rojek
@ 2019-07-27 19:59 ` Artur Rojek
  2019-09-08 12:24   ` Jonathan Cameron
  2019-07-27 19:59 ` [PATCH v2 3/3] IIO: Ingenic JZ47xx: Add support " Artur Rojek
  2019-07-28  8:45 ` [PATCH v2 1/3] dt-bindings: iio/adc: Add a compatible string " Jonathan Cameron
  2 siblings, 1 reply; 8+ messages in thread
From: Artur Rojek @ 2019-07-27 19:59 UTC (permalink / raw)
  To: Jonathan Cameron, Rob Herring, Mark Rutland, Paul Cercueil
  Cc: linux-iio, devicetree, linux-kernel, Artur Rojek, Rob Herring

Introduce support for AUX2 channel found in ADC hardware present on
Ingenic JZ4770 SoC.

Signed-off-by: Artur Rojek <contact@artur-rojek.eu>
Reviewed-by: Rob Herring <robh@kernel.org>
---

Changes:

v2: no change

 include/dt-bindings/iio/adc/ingenic,adc.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/dt-bindings/iio/adc/ingenic,adc.h b/include/dt-bindings/iio/adc/ingenic,adc.h
index 82706b2706ac..42f871ab3272 100644
--- a/include/dt-bindings/iio/adc/ingenic,adc.h
+++ b/include/dt-bindings/iio/adc/ingenic,adc.h
@@ -6,5 +6,6 @@
 /* ADC channel idx. */
 #define INGENIC_ADC_AUX		0
 #define INGENIC_ADC_BATTERY	1
+#define INGENIC_ADC_AUX2	2
 
 #endif
-- 
2.22.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH v2 3/3] IIO: Ingenic JZ47xx: Add support for JZ4770 SoC ADC.
  2019-07-27 19:59 [PATCH v2 1/3] dt-bindings: iio/adc: Add a compatible string for JZ4770 SoC ADC Artur Rojek
  2019-07-27 19:59 ` [PATCH v2 2/3] dt-bindings: iio/adc: Add AUX2 channel idx " Artur Rojek
@ 2019-07-27 19:59 ` Artur Rojek
  2019-09-08 12:25   ` Jonathan Cameron
  2019-07-28  8:45 ` [PATCH v2 1/3] dt-bindings: iio/adc: Add a compatible string " Jonathan Cameron
  2 siblings, 1 reply; 8+ messages in thread
From: Artur Rojek @ 2019-07-27 19:59 UTC (permalink / raw)
  To: Jonathan Cameron, Rob Herring, Mark Rutland, Paul Cercueil
  Cc: linux-iio, devicetree, linux-kernel, Artur Rojek

Add support for the ADC hardware present on Ingenic JZ4770 SoC.

Signed-off-by: Artur Rojek <contact@artur-rojek.eu>
Tested-by: Paul Cercueil <paul@crapouillou.net>
---

Changes:

v2: - move the IIO_CHAN_INFO_RAW block into a utility function,
    - unconditionally lock aux_lock for reduced complexity

 drivers/iio/adc/ingenic-adc.c | 149 +++++++++++++++++++++++++++++-----
 1 file changed, 127 insertions(+), 22 deletions(-)

diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c
index e234970b7150..7a53c2f8d438 100644
--- a/drivers/iio/adc/ingenic-adc.c
+++ b/drivers/iio/adc/ingenic-adc.c
@@ -25,9 +25,13 @@
 #define JZ_ADC_REG_ADSDAT		0x20
 #define JZ_ADC_REG_ADCLK		0x28
 
+#define JZ_ADC_REG_ENABLE_PD		BIT(7)
+#define JZ_ADC_REG_CFG_AUX_MD		(BIT(0) | BIT(1))
 #define JZ_ADC_REG_CFG_BAT_MD		BIT(4)
 #define JZ_ADC_REG_ADCLK_CLKDIV_LSB	0
-#define JZ_ADC_REG_ADCLK_CLKDIV10US_LSB	16
+#define JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB	16
+#define JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB	8
+#define JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB	16
 
 #define JZ_ADC_AUX_VREF				3300
 #define JZ_ADC_AUX_VREF_BITS			12
@@ -37,6 +41,8 @@
 #define JZ4725B_ADC_BATTERY_HIGH_VREF_BITS	10
 #define JZ4740_ADC_BATTERY_HIGH_VREF		(7500 * 0.986)
 #define JZ4740_ADC_BATTERY_HIGH_VREF_BITS	12
+#define JZ4770_ADC_BATTERY_VREF			6600
+#define JZ4770_ADC_BATTERY_VREF_BITS		12
 
 struct ingenic_adc;
 
@@ -47,6 +53,8 @@ struct ingenic_adc_soc_data {
 	size_t battery_raw_avail_size;
 	const int *battery_scale_avail;
 	size_t battery_scale_avail_size;
+	unsigned int battery_vref_mode: 1;
+	unsigned int has_aux2: 1;
 	int (*init_clk_div)(struct device *dev, struct ingenic_adc *adc);
 };
 
@@ -54,6 +62,7 @@ struct ingenic_adc {
 	void __iomem *base;
 	struct clk *clk;
 	struct mutex lock;
+	struct mutex aux_lock;
 	const struct ingenic_adc_soc_data *soc_data;
 	bool low_vref_mode;
 };
@@ -120,6 +129,8 @@ static int ingenic_adc_write_raw(struct iio_dev *iio_dev,
 	case IIO_CHAN_INFO_SCALE:
 		switch (chan->channel) {
 		case INGENIC_ADC_BATTERY:
+			if (!adc->soc_data->battery_vref_mode)
+				return -EINVAL;
 			if (val > JZ_ADC_BATTERY_LOW_VREF) {
 				ingenic_adc_set_config(adc,
 						       JZ_ADC_REG_CFG_BAT_MD,
@@ -158,6 +169,14 @@ static const int jz4740_adc_battery_scale_avail[] = {
 	JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
 };
 
+static const int jz4770_adc_battery_raw_avail[] = {
+	0, 1, (1 << JZ4770_ADC_BATTERY_VREF_BITS) - 1,
+};
+
+static const int jz4770_adc_battery_scale_avail[] = {
+	JZ4770_ADC_BATTERY_VREF, JZ4770_ADC_BATTERY_VREF_BITS,
+};
+
 static int jz4725b_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc)
 {
 	struct clk *parent_clk;
@@ -187,7 +206,45 @@ static int jz4725b_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc)
 	/* We also need a divider that produces a 10us clock. */
 	div_10us = DIV_ROUND_UP(rate, 100000);
 
-	writel(((div_10us - 1) << JZ_ADC_REG_ADCLK_CLKDIV10US_LSB) |
+	writel(((div_10us - 1) << JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB) |
+	       (div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB,
+	       adc->base + JZ_ADC_REG_ADCLK);
+
+	return 0;
+}
+
+static int jz4770_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc)
+{
+	struct clk *parent_clk;
+	unsigned long parent_rate, rate;
+	unsigned int div_main, div_ms, div_10us;
+
+	parent_clk = clk_get_parent(adc->clk);
+	if (!parent_clk) {
+		dev_err(dev, "ADC clock has no parent\n");
+		return -ENODEV;
+	}
+	parent_rate = clk_get_rate(parent_clk);
+
+	/*
+	 * The JZ4770 ADC works at 20 kHz to 200 kHz.
+	 * We pick the highest rate possible.
+	 */
+	div_main = DIV_ROUND_UP(parent_rate, 200000);
+	div_main = clamp(div_main, 1u, 256u);
+	rate = parent_rate / div_main;
+	if (rate < 20000 || rate > 200000) {
+		dev_err(dev, "No valid divider for ADC main clock\n");
+		return -EINVAL;
+	}
+
+	/* We also need a divider that produces a 10us clock. */
+	div_10us = DIV_ROUND_UP(rate, 10000);
+	/* And another, which produces a 1ms clock. */
+	div_ms = DIV_ROUND_UP(rate, 1000);
+
+	writel(((div_ms - 1) << JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB) |
+	       ((div_10us - 1) << JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB) |
 	       (div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB,
 	       adc->base + JZ_ADC_REG_ADCLK);
 
@@ -201,6 +258,8 @@ static const struct ingenic_adc_soc_data jz4725b_adc_soc_data = {
 	.battery_raw_avail_size = ARRAY_SIZE(jz4725b_adc_battery_raw_avail),
 	.battery_scale_avail = jz4725b_adc_battery_scale_avail,
 	.battery_scale_avail_size = ARRAY_SIZE(jz4725b_adc_battery_scale_avail),
+	.battery_vref_mode = true,
+	.has_aux2 = false,
 	.init_clk_div = jz4725b_adc_init_clk_div,
 };
 
@@ -211,9 +270,23 @@ static const struct ingenic_adc_soc_data jz4740_adc_soc_data = {
 	.battery_raw_avail_size = ARRAY_SIZE(jz4740_adc_battery_raw_avail),
 	.battery_scale_avail = jz4740_adc_battery_scale_avail,
 	.battery_scale_avail_size = ARRAY_SIZE(jz4740_adc_battery_scale_avail),
+	.battery_vref_mode = true,
+	.has_aux2 = false,
 	.init_clk_div = NULL, /* no ADCLK register on JZ4740 */
 };
 
+static const struct ingenic_adc_soc_data jz4770_adc_soc_data = {
+	.battery_high_vref = JZ4770_ADC_BATTERY_VREF,
+	.battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS,
+	.battery_raw_avail = jz4770_adc_battery_raw_avail,
+	.battery_raw_avail_size = ARRAY_SIZE(jz4770_adc_battery_raw_avail),
+	.battery_scale_avail = jz4770_adc_battery_scale_avail,
+	.battery_scale_avail_size = ARRAY_SIZE(jz4770_adc_battery_scale_avail),
+	.battery_vref_mode = false,
+	.has_aux2 = true,
+	.init_clk_div = jz4770_adc_init_clk_div,
+};
+
 static int ingenic_adc_read_avail(struct iio_dev *iio_dev,
 				  struct iio_chan_spec const *chan,
 				  const int **vals,
@@ -239,6 +312,42 @@ static int ingenic_adc_read_avail(struct iio_dev *iio_dev,
 	};
 }
 
+static int ingenic_adc_read_chan_info_raw(struct ingenic_adc *adc,
+					  struct iio_chan_spec const *chan,
+					  int *val)
+{
+	int bit, ret, engine = (chan->channel == INGENIC_ADC_BATTERY);
+
+	/* We cannot sample AUX/AUX2 in parallel. */
+	mutex_lock(&adc->aux_lock);
+	if (adc->soc_data->has_aux2 && engine == 0) {
+		bit = BIT(chan->channel == INGENIC_ADC_AUX2);
+		ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, bit);
+	}
+
+	clk_enable(adc->clk);
+	ret = ingenic_adc_capture(adc, engine);
+	if (ret)
+		goto out;
+
+	switch (chan->channel) {
+	case INGENIC_ADC_AUX:
+	case INGENIC_ADC_AUX2:
+		*val = readw(adc->base + JZ_ADC_REG_ADSDAT);
+		break;
+	case INGENIC_ADC_BATTERY:
+		*val = readw(adc->base + JZ_ADC_REG_ADBDAT);
+		break;
+	}
+
+	ret = IIO_VAL_INT;
+out:
+	clk_disable(adc->clk);
+	mutex_unlock(&adc->aux_lock);
+
+	return ret;
+}
+
 static int ingenic_adc_read_raw(struct iio_dev *iio_dev,
 				struct iio_chan_spec const *chan,
 				int *val,
@@ -246,32 +355,14 @@ static int ingenic_adc_read_raw(struct iio_dev *iio_dev,
 				long m)
 {
 	struct ingenic_adc *adc = iio_priv(iio_dev);
-	int ret;
 
 	switch (m) {
 	case IIO_CHAN_INFO_RAW:
-		clk_enable(adc->clk);
-		ret = ingenic_adc_capture(adc, chan->channel);
-		if (ret) {
-			clk_disable(adc->clk);
-			return ret;
-		}
-
-		switch (chan->channel) {
-		case INGENIC_ADC_AUX:
-			*val = readw(adc->base + JZ_ADC_REG_ADSDAT);
-			break;
-		case INGENIC_ADC_BATTERY:
-			*val = readw(adc->base + JZ_ADC_REG_ADBDAT);
-			break;
-		}
-
-		clk_disable(adc->clk);
-
-		return IIO_VAL_INT;
+		return ingenic_adc_read_chan_info_raw(adc, chan, val);
 	case IIO_CHAN_INFO_SCALE:
 		switch (chan->channel) {
 		case INGENIC_ADC_AUX:
+		case INGENIC_ADC_AUX2:
 			*val = JZ_ADC_AUX_VREF;
 			*val2 = JZ_ADC_AUX_VREF_BITS;
 			break;
@@ -322,6 +413,14 @@ static const struct iio_chan_spec ingenic_channels[] = {
 		.indexed = 1,
 		.channel = INGENIC_ADC_BATTERY,
 	},
+	{ /* Must always be last in the array. */
+		.extend_name = "aux2",
+		.type = IIO_VOLTAGE,
+		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+				      BIT(IIO_CHAN_INFO_SCALE),
+		.indexed = 1,
+		.channel = INGENIC_ADC_AUX2,
+	},
 };
 
 static int ingenic_adc_probe(struct platform_device *pdev)
@@ -343,6 +442,7 @@ static int ingenic_adc_probe(struct platform_device *pdev)
 
 	adc = iio_priv(iio_dev);
 	mutex_init(&adc->lock);
+	mutex_init(&adc->aux_lock);
 	adc->soc_data = soc_data;
 
 	mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -374,6 +474,7 @@ static int ingenic_adc_probe(struct platform_device *pdev)
 	/* Put hardware in a known passive state. */
 	writeb(0x00, adc->base + JZ_ADC_REG_ENABLE);
 	writeb(0xff, adc->base + JZ_ADC_REG_CTRL);
+	usleep_range(2000, 3000); /* Must wait at least 2ms. */
 	clk_disable(adc->clk);
 
 	ret = devm_add_action_or_reset(dev, ingenic_adc_clk_cleanup, adc->clk);
@@ -387,6 +488,9 @@ static int ingenic_adc_probe(struct platform_device *pdev)
 	iio_dev->modes = INDIO_DIRECT_MODE;
 	iio_dev->channels = ingenic_channels;
 	iio_dev->num_channels = ARRAY_SIZE(ingenic_channels);
+	/* Remove AUX2 from the list of supported channels. */
+	if (!adc->soc_data->has_aux2)
+		iio_dev->num_channels -= 1;
 	iio_dev->info = &ingenic_adc_info;
 
 	ret = devm_iio_device_register(dev, iio_dev);
@@ -400,6 +504,7 @@ static int ingenic_adc_probe(struct platform_device *pdev)
 static const struct of_device_id ingenic_adc_of_match[] = {
 	{ .compatible = "ingenic,jz4725b-adc", .data = &jz4725b_adc_soc_data, },
 	{ .compatible = "ingenic,jz4740-adc", .data = &jz4740_adc_soc_data, },
+	{ .compatible = "ingenic,jz4770-adc", .data = &jz4770_adc_soc_data, },
 	{ },
 };
 MODULE_DEVICE_TABLE(of, ingenic_adc_of_match);
-- 
2.22.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/3] dt-bindings: iio/adc: Add a compatible string for JZ4770 SoC ADC
  2019-07-27 19:59 [PATCH v2 1/3] dt-bindings: iio/adc: Add a compatible string for JZ4770 SoC ADC Artur Rojek
  2019-07-27 19:59 ` [PATCH v2 2/3] dt-bindings: iio/adc: Add AUX2 channel idx " Artur Rojek
  2019-07-27 19:59 ` [PATCH v2 3/3] IIO: Ingenic JZ47xx: Add support " Artur Rojek
@ 2019-07-28  8:45 ` Jonathan Cameron
  2019-09-03 19:09   ` Artur Rojek
  2 siblings, 1 reply; 8+ messages in thread
From: Jonathan Cameron @ 2019-07-28  8:45 UTC (permalink / raw)
  To: Artur Rojek
  Cc: Rob Herring, Mark Rutland, Paul Cercueil, linux-iio, devicetree,
	linux-kernel, Rob Herring

On Sat, 27 Jul 2019 21:59:38 +0200
Artur Rojek <contact@artur-rojek.eu> wrote:

> Add a compatible string for the ADC controller present on
> Ingenic JZ4770 SoC.
> 
> Signed-off-by: Artur Rojek <contact@artur-rojek.eu>
> Reviewed-by: Rob Herring <robh@kernel.org>

Hi Artur,

I'll have to hold this series for a few weeks as the fix for the
clock rate divider isn't in my upstream for the togreg branch yet
(as I haven't sent a pull request since the merge window).

Give me a poke if I seem to have forgotten these in a few weeks
time.

Thanks,

Jonathan

> ---
> 
> Changes:
> 
> v2: no change
> 
>  Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt b/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt
> index f01159f20d87..cd9048cf9dcf 100644
> --- a/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt
> +++ b/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt
> @@ -5,6 +5,7 @@ Required properties:
>  - compatible: Should be one of:
>    * ingenic,jz4725b-adc
>    * ingenic,jz4740-adc
> +  * ingenic,jz4770-adc
>  - reg: ADC controller registers location and length.
>  - clocks: phandle to the SoC's ADC clock.
>  - clock-names: Must be set to "adc".


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/3] dt-bindings: iio/adc: Add a compatible string for JZ4770 SoC ADC
  2019-07-28  8:45 ` [PATCH v2 1/3] dt-bindings: iio/adc: Add a compatible string " Jonathan Cameron
@ 2019-09-03 19:09   ` Artur Rojek
  2019-09-08 12:23     ` Jonathan Cameron
  0 siblings, 1 reply; 8+ messages in thread
From: Artur Rojek @ 2019-09-03 19:09 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: Rob Herring, Mark Rutland, Paul Cercueil, linux-iio, devicetree,
	linux-kernel, Rob Herring

Hi Jonathan,

Just reminding you of this patch set.

Artur

On 2019-07-28 10:45, Jonathan Cameron wrote:
> On Sat, 27 Jul 2019 21:59:38 +0200
> Artur Rojek <contact@artur-rojek.eu> wrote:
> 
>> Add a compatible string for the ADC controller present on
>> Ingenic JZ4770 SoC.
>> 
>> Signed-off-by: Artur Rojek <contact@artur-rojek.eu>
>> Reviewed-by: Rob Herring <robh@kernel.org>
> 
> Hi Artur,
> 
> I'll have to hold this series for a few weeks as the fix for the
> clock rate divider isn't in my upstream for the togreg branch yet
> (as I haven't sent a pull request since the merge window).
> 
> Give me a poke if I seem to have forgotten these in a few weeks
> time.
> 
> Thanks,
> 
> Jonathan
> 
>> ---
>> 
>> Changes:
>> 
>> v2: no change
>> 
>>  Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt | 1 +
>>  1 file changed, 1 insertion(+)
>> 
>> diff --git a/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt 
>> b/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt
>> index f01159f20d87..cd9048cf9dcf 100644
>> --- a/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt
>> +++ b/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt
>> @@ -5,6 +5,7 @@ Required properties:
>>  - compatible: Should be one of:
>>    * ingenic,jz4725b-adc
>>    * ingenic,jz4740-adc
>> +  * ingenic,jz4770-adc
>>  - reg: ADC controller registers location and length.
>>  - clocks: phandle to the SoC's ADC clock.
>>  - clock-names: Must be set to "adc".

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 1/3] dt-bindings: iio/adc: Add a compatible string for JZ4770 SoC ADC
  2019-09-03 19:09   ` Artur Rojek
@ 2019-09-08 12:23     ` Jonathan Cameron
  0 siblings, 0 replies; 8+ messages in thread
From: Jonathan Cameron @ 2019-09-08 12:23 UTC (permalink / raw)
  To: Artur Rojek
  Cc: Rob Herring, Mark Rutland, Paul Cercueil, linux-iio, devicetree,
	linux-kernel, Rob Herring

On Tue, 03 Sep 2019 21:09:24 +0200
Artur Rojek <contact@artur-rojek.eu> wrote:

> Hi Jonathan,
> 
> Just reminding you of this patch set.
> 
> Artur

Hi Artur,

Thanks for the reminder.  As you'd no doubt concluded, I'd
dropped it down the back of the sofa.

Unfortunately it's now just missed my last pull for 5.4 (probably)
so I've queued it up for the 5.5 cycle.

Applied to the togreg branch of iio.git and pushed out as testing
for the autobuilders to play with it.

Thanks,

Jonathan

> 
> On 2019-07-28 10:45, Jonathan Cameron wrote:
> > On Sat, 27 Jul 2019 21:59:38 +0200
> > Artur Rojek <contact@artur-rojek.eu> wrote:
> >   
> >> Add a compatible string for the ADC controller present on
> >> Ingenic JZ4770 SoC.
> >> 
> >> Signed-off-by: Artur Rojek <contact@artur-rojek.eu>
> >> Reviewed-by: Rob Herring <robh@kernel.org>  
> > 
> > Hi Artur,
> > 
> > I'll have to hold this series for a few weeks as the fix for the
> > clock rate divider isn't in my upstream for the togreg branch yet
> > (as I haven't sent a pull request since the merge window).
> > 
> > Give me a poke if I seem to have forgotten these in a few weeks
> > time.
> > 
> > Thanks,
> > 
> > Jonathan
> >   
> >> ---
> >> 
> >> Changes:
> >> 
> >> v2: no change
> >> 
> >>  Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt | 1 +
> >>  1 file changed, 1 insertion(+)
> >> 
> >> diff --git a/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt 
> >> b/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt
> >> index f01159f20d87..cd9048cf9dcf 100644
> >> --- a/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt
> >> +++ b/Documentation/devicetree/bindings/iio/adc/ingenic,adc.txt
> >> @@ -5,6 +5,7 @@ Required properties:
> >>  - compatible: Should be one of:
> >>    * ingenic,jz4725b-adc
> >>    * ingenic,jz4740-adc
> >> +  * ingenic,jz4770-adc
> >>  - reg: ADC controller registers location and length.
> >>  - clocks: phandle to the SoC's ADC clock.
> >>  - clock-names: Must be set to "adc".  


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 2/3] dt-bindings: iio/adc: Add AUX2 channel idx for JZ4770 SoC ADC
  2019-07-27 19:59 ` [PATCH v2 2/3] dt-bindings: iio/adc: Add AUX2 channel idx " Artur Rojek
@ 2019-09-08 12:24   ` Jonathan Cameron
  0 siblings, 0 replies; 8+ messages in thread
From: Jonathan Cameron @ 2019-09-08 12:24 UTC (permalink / raw)
  To: Artur Rojek
  Cc: Rob Herring, Mark Rutland, Paul Cercueil, linux-iio, devicetree,
	linux-kernel, Rob Herring

On Sat, 27 Jul 2019 21:59:39 +0200
Artur Rojek <contact@artur-rojek.eu> wrote:

> Introduce support for AUX2 channel found in ADC hardware present on
> Ingenic JZ4770 SoC.
> 
> Signed-off-by: Artur Rojek <contact@artur-rojek.eu>
> Reviewed-by: Rob Herring <robh@kernel.org>
Applied to the togreg branch of iio.git and pushed out as testing for
the autobuilders to mostly ignore it.

Thanks,

Jonathan

> ---
> 
> Changes:
> 
> v2: no change
> 
>  include/dt-bindings/iio/adc/ingenic,adc.h | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/include/dt-bindings/iio/adc/ingenic,adc.h b/include/dt-bindings/iio/adc/ingenic,adc.h
> index 82706b2706ac..42f871ab3272 100644
> --- a/include/dt-bindings/iio/adc/ingenic,adc.h
> +++ b/include/dt-bindings/iio/adc/ingenic,adc.h
> @@ -6,5 +6,6 @@
>  /* ADC channel idx. */
>  #define INGENIC_ADC_AUX		0
>  #define INGENIC_ADC_BATTERY	1
> +#define INGENIC_ADC_AUX2	2
>  
>  #endif


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH v2 3/3] IIO: Ingenic JZ47xx: Add support for JZ4770 SoC ADC.
  2019-07-27 19:59 ` [PATCH v2 3/3] IIO: Ingenic JZ47xx: Add support " Artur Rojek
@ 2019-09-08 12:25   ` Jonathan Cameron
  0 siblings, 0 replies; 8+ messages in thread
From: Jonathan Cameron @ 2019-09-08 12:25 UTC (permalink / raw)
  To: Artur Rojek
  Cc: Rob Herring, Mark Rutland, Paul Cercueil, linux-iio, devicetree,
	linux-kernel

On Sat, 27 Jul 2019 21:59:40 +0200
Artur Rojek <contact@artur-rojek.eu> wrote:

> Add support for the ADC hardware present on Ingenic JZ4770 SoC.
> 
> Signed-off-by: Artur Rojek <contact@artur-rojek.eu>
> Tested-by: Paul Cercueil <paul@crapouillou.net>

Applied to the togreg branch of iio.git and pushed out as testing for
the autobuilders to play with it.

Thanks,

Jonathan

> ---
> 
> Changes:
> 
> v2: - move the IIO_CHAN_INFO_RAW block into a utility function,
>     - unconditionally lock aux_lock for reduced complexity
> 
>  drivers/iio/adc/ingenic-adc.c | 149 +++++++++++++++++++++++++++++-----
>  1 file changed, 127 insertions(+), 22 deletions(-)
> 
> diff --git a/drivers/iio/adc/ingenic-adc.c b/drivers/iio/adc/ingenic-adc.c
> index e234970b7150..7a53c2f8d438 100644
> --- a/drivers/iio/adc/ingenic-adc.c
> +++ b/drivers/iio/adc/ingenic-adc.c
> @@ -25,9 +25,13 @@
>  #define JZ_ADC_REG_ADSDAT		0x20
>  #define JZ_ADC_REG_ADCLK		0x28
>  
> +#define JZ_ADC_REG_ENABLE_PD		BIT(7)
> +#define JZ_ADC_REG_CFG_AUX_MD		(BIT(0) | BIT(1))
>  #define JZ_ADC_REG_CFG_BAT_MD		BIT(4)
>  #define JZ_ADC_REG_ADCLK_CLKDIV_LSB	0
> -#define JZ_ADC_REG_ADCLK_CLKDIV10US_LSB	16
> +#define JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB	16
> +#define JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB	8
> +#define JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB	16
>  
>  #define JZ_ADC_AUX_VREF				3300
>  #define JZ_ADC_AUX_VREF_BITS			12
> @@ -37,6 +41,8 @@
>  #define JZ4725B_ADC_BATTERY_HIGH_VREF_BITS	10
>  #define JZ4740_ADC_BATTERY_HIGH_VREF		(7500 * 0.986)
>  #define JZ4740_ADC_BATTERY_HIGH_VREF_BITS	12
> +#define JZ4770_ADC_BATTERY_VREF			6600
> +#define JZ4770_ADC_BATTERY_VREF_BITS		12
>  
>  struct ingenic_adc;
>  
> @@ -47,6 +53,8 @@ struct ingenic_adc_soc_data {
>  	size_t battery_raw_avail_size;
>  	const int *battery_scale_avail;
>  	size_t battery_scale_avail_size;
> +	unsigned int battery_vref_mode: 1;
> +	unsigned int has_aux2: 1;
>  	int (*init_clk_div)(struct device *dev, struct ingenic_adc *adc);
>  };
>  
> @@ -54,6 +62,7 @@ struct ingenic_adc {
>  	void __iomem *base;
>  	struct clk *clk;
>  	struct mutex lock;
> +	struct mutex aux_lock;
>  	const struct ingenic_adc_soc_data *soc_data;
>  	bool low_vref_mode;
>  };
> @@ -120,6 +129,8 @@ static int ingenic_adc_write_raw(struct iio_dev *iio_dev,
>  	case IIO_CHAN_INFO_SCALE:
>  		switch (chan->channel) {
>  		case INGENIC_ADC_BATTERY:
> +			if (!adc->soc_data->battery_vref_mode)
> +				return -EINVAL;
>  			if (val > JZ_ADC_BATTERY_LOW_VREF) {
>  				ingenic_adc_set_config(adc,
>  						       JZ_ADC_REG_CFG_BAT_MD,
> @@ -158,6 +169,14 @@ static const int jz4740_adc_battery_scale_avail[] = {
>  	JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
>  };
>  
> +static const int jz4770_adc_battery_raw_avail[] = {
> +	0, 1, (1 << JZ4770_ADC_BATTERY_VREF_BITS) - 1,
> +};
> +
> +static const int jz4770_adc_battery_scale_avail[] = {
> +	JZ4770_ADC_BATTERY_VREF, JZ4770_ADC_BATTERY_VREF_BITS,
> +};
> +
>  static int jz4725b_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc)
>  {
>  	struct clk *parent_clk;
> @@ -187,7 +206,45 @@ static int jz4725b_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc)
>  	/* We also need a divider that produces a 10us clock. */
>  	div_10us = DIV_ROUND_UP(rate, 100000);
>  
> -	writel(((div_10us - 1) << JZ_ADC_REG_ADCLK_CLKDIV10US_LSB) |
> +	writel(((div_10us - 1) << JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB) |
> +	       (div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB,
> +	       adc->base + JZ_ADC_REG_ADCLK);
> +
> +	return 0;
> +}
> +
> +static int jz4770_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc)
> +{
> +	struct clk *parent_clk;
> +	unsigned long parent_rate, rate;
> +	unsigned int div_main, div_ms, div_10us;
> +
> +	parent_clk = clk_get_parent(adc->clk);
> +	if (!parent_clk) {
> +		dev_err(dev, "ADC clock has no parent\n");
> +		return -ENODEV;
> +	}
> +	parent_rate = clk_get_rate(parent_clk);
> +
> +	/*
> +	 * The JZ4770 ADC works at 20 kHz to 200 kHz.
> +	 * We pick the highest rate possible.
> +	 */
> +	div_main = DIV_ROUND_UP(parent_rate, 200000);
> +	div_main = clamp(div_main, 1u, 256u);
> +	rate = parent_rate / div_main;
> +	if (rate < 20000 || rate > 200000) {
> +		dev_err(dev, "No valid divider for ADC main clock\n");
> +		return -EINVAL;
> +	}
> +
> +	/* We also need a divider that produces a 10us clock. */
> +	div_10us = DIV_ROUND_UP(rate, 10000);
> +	/* And another, which produces a 1ms clock. */
> +	div_ms = DIV_ROUND_UP(rate, 1000);
> +
> +	writel(((div_ms - 1) << JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB) |
> +	       ((div_10us - 1) << JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB) |
>  	       (div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB,
>  	       adc->base + JZ_ADC_REG_ADCLK);
>  
> @@ -201,6 +258,8 @@ static const struct ingenic_adc_soc_data jz4725b_adc_soc_data = {
>  	.battery_raw_avail_size = ARRAY_SIZE(jz4725b_adc_battery_raw_avail),
>  	.battery_scale_avail = jz4725b_adc_battery_scale_avail,
>  	.battery_scale_avail_size = ARRAY_SIZE(jz4725b_adc_battery_scale_avail),
> +	.battery_vref_mode = true,
> +	.has_aux2 = false,
>  	.init_clk_div = jz4725b_adc_init_clk_div,
>  };
>  
> @@ -211,9 +270,23 @@ static const struct ingenic_adc_soc_data jz4740_adc_soc_data = {
>  	.battery_raw_avail_size = ARRAY_SIZE(jz4740_adc_battery_raw_avail),
>  	.battery_scale_avail = jz4740_adc_battery_scale_avail,
>  	.battery_scale_avail_size = ARRAY_SIZE(jz4740_adc_battery_scale_avail),
> +	.battery_vref_mode = true,
> +	.has_aux2 = false,
>  	.init_clk_div = NULL, /* no ADCLK register on JZ4740 */
>  };
>  
> +static const struct ingenic_adc_soc_data jz4770_adc_soc_data = {
> +	.battery_high_vref = JZ4770_ADC_BATTERY_VREF,
> +	.battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS,
> +	.battery_raw_avail = jz4770_adc_battery_raw_avail,
> +	.battery_raw_avail_size = ARRAY_SIZE(jz4770_adc_battery_raw_avail),
> +	.battery_scale_avail = jz4770_adc_battery_scale_avail,
> +	.battery_scale_avail_size = ARRAY_SIZE(jz4770_adc_battery_scale_avail),
> +	.battery_vref_mode = false,
> +	.has_aux2 = true,
> +	.init_clk_div = jz4770_adc_init_clk_div,
> +};
> +
>  static int ingenic_adc_read_avail(struct iio_dev *iio_dev,
>  				  struct iio_chan_spec const *chan,
>  				  const int **vals,
> @@ -239,6 +312,42 @@ static int ingenic_adc_read_avail(struct iio_dev *iio_dev,
>  	};
>  }
>  
> +static int ingenic_adc_read_chan_info_raw(struct ingenic_adc *adc,
> +					  struct iio_chan_spec const *chan,
> +					  int *val)
> +{
> +	int bit, ret, engine = (chan->channel == INGENIC_ADC_BATTERY);
> +
> +	/* We cannot sample AUX/AUX2 in parallel. */
> +	mutex_lock(&adc->aux_lock);
> +	if (adc->soc_data->has_aux2 && engine == 0) {
> +		bit = BIT(chan->channel == INGENIC_ADC_AUX2);
> +		ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, bit);
> +	}
> +
> +	clk_enable(adc->clk);
> +	ret = ingenic_adc_capture(adc, engine);
> +	if (ret)
> +		goto out;
> +
> +	switch (chan->channel) {
> +	case INGENIC_ADC_AUX:
> +	case INGENIC_ADC_AUX2:
> +		*val = readw(adc->base + JZ_ADC_REG_ADSDAT);
> +		break;
> +	case INGENIC_ADC_BATTERY:
> +		*val = readw(adc->base + JZ_ADC_REG_ADBDAT);
> +		break;
> +	}
> +
> +	ret = IIO_VAL_INT;
> +out:
> +	clk_disable(adc->clk);
> +	mutex_unlock(&adc->aux_lock);
> +
> +	return ret;
> +}
> +
>  static int ingenic_adc_read_raw(struct iio_dev *iio_dev,
>  				struct iio_chan_spec const *chan,
>  				int *val,
> @@ -246,32 +355,14 @@ static int ingenic_adc_read_raw(struct iio_dev *iio_dev,
>  				long m)
>  {
>  	struct ingenic_adc *adc = iio_priv(iio_dev);
> -	int ret;
>  
>  	switch (m) {
>  	case IIO_CHAN_INFO_RAW:
> -		clk_enable(adc->clk);
> -		ret = ingenic_adc_capture(adc, chan->channel);
> -		if (ret) {
> -			clk_disable(adc->clk);
> -			return ret;
> -		}
> -
> -		switch (chan->channel) {
> -		case INGENIC_ADC_AUX:
> -			*val = readw(adc->base + JZ_ADC_REG_ADSDAT);
> -			break;
> -		case INGENIC_ADC_BATTERY:
> -			*val = readw(adc->base + JZ_ADC_REG_ADBDAT);
> -			break;
> -		}
> -
> -		clk_disable(adc->clk);
> -
> -		return IIO_VAL_INT;
> +		return ingenic_adc_read_chan_info_raw(adc, chan, val);
>  	case IIO_CHAN_INFO_SCALE:
>  		switch (chan->channel) {
>  		case INGENIC_ADC_AUX:
> +		case INGENIC_ADC_AUX2:
>  			*val = JZ_ADC_AUX_VREF;
>  			*val2 = JZ_ADC_AUX_VREF_BITS;
>  			break;
> @@ -322,6 +413,14 @@ static const struct iio_chan_spec ingenic_channels[] = {
>  		.indexed = 1,
>  		.channel = INGENIC_ADC_BATTERY,
>  	},
> +	{ /* Must always be last in the array. */
> +		.extend_name = "aux2",
> +		.type = IIO_VOLTAGE,
> +		.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
> +				      BIT(IIO_CHAN_INFO_SCALE),
> +		.indexed = 1,
> +		.channel = INGENIC_ADC_AUX2,
> +	},
>  };
>  
>  static int ingenic_adc_probe(struct platform_device *pdev)
> @@ -343,6 +442,7 @@ static int ingenic_adc_probe(struct platform_device *pdev)
>  
>  	adc = iio_priv(iio_dev);
>  	mutex_init(&adc->lock);
> +	mutex_init(&adc->aux_lock);
>  	adc->soc_data = soc_data;
>  
>  	mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> @@ -374,6 +474,7 @@ static int ingenic_adc_probe(struct platform_device *pdev)
>  	/* Put hardware in a known passive state. */
>  	writeb(0x00, adc->base + JZ_ADC_REG_ENABLE);
>  	writeb(0xff, adc->base + JZ_ADC_REG_CTRL);
> +	usleep_range(2000, 3000); /* Must wait at least 2ms. */
>  	clk_disable(adc->clk);
>  
>  	ret = devm_add_action_or_reset(dev, ingenic_adc_clk_cleanup, adc->clk);
> @@ -387,6 +488,9 @@ static int ingenic_adc_probe(struct platform_device *pdev)
>  	iio_dev->modes = INDIO_DIRECT_MODE;
>  	iio_dev->channels = ingenic_channels;
>  	iio_dev->num_channels = ARRAY_SIZE(ingenic_channels);
> +	/* Remove AUX2 from the list of supported channels. */
> +	if (!adc->soc_data->has_aux2)
> +		iio_dev->num_channels -= 1;
>  	iio_dev->info = &ingenic_adc_info;
>  
>  	ret = devm_iio_device_register(dev, iio_dev);
> @@ -400,6 +504,7 @@ static int ingenic_adc_probe(struct platform_device *pdev)
>  static const struct of_device_id ingenic_adc_of_match[] = {
>  	{ .compatible = "ingenic,jz4725b-adc", .data = &jz4725b_adc_soc_data, },
>  	{ .compatible = "ingenic,jz4740-adc", .data = &jz4740_adc_soc_data, },
> +	{ .compatible = "ingenic,jz4770-adc", .data = &jz4770_adc_soc_data, },
>  	{ },
>  };
>  MODULE_DEVICE_TABLE(of, ingenic_adc_of_match);


^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2019-09-08 12:25 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-07-27 19:59 [PATCH v2 1/3] dt-bindings: iio/adc: Add a compatible string for JZ4770 SoC ADC Artur Rojek
2019-07-27 19:59 ` [PATCH v2 2/3] dt-bindings: iio/adc: Add AUX2 channel idx " Artur Rojek
2019-09-08 12:24   ` Jonathan Cameron
2019-07-27 19:59 ` [PATCH v2 3/3] IIO: Ingenic JZ47xx: Add support " Artur Rojek
2019-09-08 12:25   ` Jonathan Cameron
2019-07-28  8:45 ` [PATCH v2 1/3] dt-bindings: iio/adc: Add a compatible string " Jonathan Cameron
2019-09-03 19:09   ` Artur Rojek
2019-09-08 12:23     ` Jonathan Cameron

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).