linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RESEND v4 00/15] Add support for ast2600 ADC
@ 2021-08-24  9:12 Billy Tsai
  2021-08-24  9:12 ` [RESEND v4 01/15] dt-bindings: iio: adc: Add ast2600-adc bindings Billy Tsai
                   ` (21 more replies)
  0 siblings, 22 replies; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

This patch serials make aspeed_adc.c can support ast2600 and backward
compatible.

RESEND due to miss some patches when sent patch v4.
Change since v3:
dt-bindings:
  - Fix properties:aspeed,int_vref_mv type error.

Change since v2:
dt-bindings:
  - Create a new dt-bindings for ast2600 adc
aspeed_adc.c:
  - Splits the patch for more details
  - Remove version enum and use the flags in model data to distinguish
  hardware feature
  - Support trimming data get and set.
  - Use devm_add_action_or_reset to simplify probe error handling.

Changes since v1:
dt-bindings:
  - Fix the aspeed,adc.yaml check error.
  - Add battery-sensing property.
aspeed_adc.c:
  - Change the init flow:
    Clock and reference voltage setting should be completed before adc
    engine enable.
  - Change the default sampling rate to meet most user case.
  - Add patch #8 to suppoert battery sensing mode.

Billy Tsai (15):
  dt-bindings: iio: adc: Add ast2600-adc bindings
  iio: adc: aspeed: completes the bitfield declare.
  iio: adc: aspeed: set driver data when adc probe.
  iio: adc: aspeed: Keep model data to driver data.
  iio: adc: aspeed: Refactory model data structure
  iio: adc: aspeed: Add vref config function
  iio: adc: aspeed: Set num_channels with model data
  iio: adc: aspeed: Use model_data to set clk scaler.
  iio: adc: aspeed: Use devm_add_action_or_reset.
  iio: adc: aspeed: Support ast2600 adc.
  iio: adc: aspeed: Fix the calculate error of clock.
  iio: adc: aspeed: Add func to set sampling rate.
  iio: adc: aspeed: Add compensation phase.
  iio: adc: aspeed: Support battery sensing.
  iio: adc: aspeed: Get and set trimming data.

 .../bindings/iio/adc/aspeed,ast2600-adc.yaml  |  97 +++
 drivers/iio/adc/aspeed_adc.c                  | 562 +++++++++++++++---
 2 files changed, 569 insertions(+), 90 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml

-- 
2.25.1


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

* [RESEND v4 01/15] dt-bindings: iio: adc: Add ast2600-adc bindings
  2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
@ 2021-08-24  9:12 ` Billy Tsai
  2021-08-24  9:12 ` [RESEND v4 02/15] iio: adc: aspeed: completes the bitfield declare Billy Tsai
                   ` (20 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

Add device tree bindings document for the aspeed ast2600 adc device
driver.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
 .../bindings/iio/adc/aspeed,ast2600-adc.yaml  | 97 +++++++++++++++++++
 1 file changed, 97 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml

diff --git a/Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml b/Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml
new file mode 100644
index 000000000000..248cda7d91e9
--- /dev/null
+++ b/Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml
@@ -0,0 +1,97 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/iio/adc/aspeed,ast2600-adc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ADC that forms part of an ASPEED server management processor.
+
+maintainers:
+  - Billy Tsai <billy_tsai@aspeedtech.com>
+
+description: |
+  • 10-bits resolution for 16 voltage channels.
+  • The device split into two individual engine and each contains 8 voltage
+  channels.
+  • Channel scanning can be non-continuous.
+  • Programmable ADC clock frequency.
+  • Programmable upper and lower threshold for each channels.
+  • Interrupt when larger or less than threshold for each channels.
+  • Support hysteresis for each channels.
+  • Built-in a compensating method.
+  • Built-in a register to trim internal reference voltage.
+  • Internal or External reference voltage.
+  • Support 2 Internal reference voltage 1.2v or 2.5v.
+  • Integrate dividing circuit for battery sensing.
+
+properties:
+  compatible:
+    enum:
+      - aspeed,ast2600-adc0
+      - aspeed,ast2600-adc1
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    description:
+      Input clock used to derive the sample clock. Expected to be the
+      SoC's APB clock.
+
+  resets:
+    maxItems: 1
+
+  "#io-channel-cells":
+    const: 1
+
+  vref-supply:
+    description:
+      The external regulator supply ADC reference voltage.
+
+  aspeed,int_vref_mv:
+    $ref: /schemas/types.yaml#/definitions/uint32
+    enum: [1200, 2500]
+    description:
+      ADC internal reference voltage in millivolts.
+
+  aspeed,battery-sensing:
+    type: boolean
+    description:
+      Inform the driver that last channel will be used to sensor battery.
+
+  aspeed,trim-data-valid:
+    type: boolean
+    description: |
+      The ADC reference voltage can be calibrated to obtain the trimming
+      data which will be stored in otp. This property informs the driver that
+      the data store in the otp is valid.
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - resets
+  - "#io-channel-cells"
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/ast2600-clock.h>
+    adc0: adc@1e6e9000 {
+        compatible = "aspeed,ast2600-adc0";
+        reg = <0x1e6e9000 0x100>;
+        clocks = <&syscon ASPEED_CLK_APB2>;
+        resets = <&syscon ASPEED_RESET_ADC>;
+        #io-channel-cells = <1>;
+        aspeed,int_vref_mv = <2500>;
+    };
+    adc1: adc@1e6e9100 {
+        compatible = "aspeed,ast2600-adc1";
+        reg = <0x1e6e9100 0x100>;
+        clocks = <&syscon ASPEED_CLK_APB2>;
+        resets = <&syscon ASPEED_RESET_ADC>;
+        #io-channel-cells = <1>;
+        aspeed,int_vref_mv = <2500>;
+    };
+...
-- 
2.25.1


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

* [RESEND v4 02/15] iio: adc: aspeed: completes the bitfield declare.
  2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
  2021-08-24  9:12 ` [RESEND v4 01/15] dt-bindings: iio: adc: Add ast2600-adc bindings Billy Tsai
@ 2021-08-24  9:12 ` Billy Tsai
  2021-08-29 15:07   ` Jonathan Cameron
  2021-08-24  9:12 ` [RESEND v4 03/15] iio: adc: aspeed: set driver data when adc probe Billy Tsai
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

This patch completes the declare of adc register bitfields and uses the
same prefix ASPEED_ADC_* for these bitfields.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
 drivers/iio/adc/aspeed_adc.c | 56 +++++++++++++++++++++++++-----------
 1 file changed, 39 insertions(+), 17 deletions(-)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 19efaa41bc34..7010d56ac3b9 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -3,6 +3,7 @@
  * Aspeed AST2400/2500 ADC
  *
  * Copyright (C) 2017 Google, Inc.
+ * Copyright (C) 2021 Aspeed Technology Inc.
  */
 
 #include <linux/clk.h>
@@ -16,6 +17,7 @@
 #include <linux/reset.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
+#include <linux/bitfield.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/driver.h>
@@ -28,15 +30,31 @@
 #define ASPEED_REG_INTERRUPT_CONTROL	0x04
 #define ASPEED_REG_VGA_DETECT_CONTROL	0x08
 #define ASPEED_REG_CLOCK_CONTROL	0x0C
-#define ASPEED_REG_MAX			0xC0
-
-#define ASPEED_OPERATION_MODE_POWER_DOWN	(0x0 << 1)
-#define ASPEED_OPERATION_MODE_STANDBY		(0x1 << 1)
-#define ASPEED_OPERATION_MODE_NORMAL		(0x7 << 1)
-
-#define ASPEED_ENGINE_ENABLE		BIT(0)
-
-#define ASPEED_ADC_CTRL_INIT_RDY	BIT(8)
+#define ASPEED_REG_COMPENSATION_TRIM	0xC4
+#define ASPEED_REG_MAX			0xCC
+
+#define ASPEED_ADC_ENGINE_ENABLE		BIT(0)
+#define ASPEED_ADC_OP_MODE			GENMASK(3, 1)
+#define ASPEED_ADC_OP_MODE_PWR_DOWN		0
+#define ASPEED_ADC_OP_MODE_STANDBY		1
+#define ASPEED_ADC_OP_MODE_NORMAL		7
+#define ASPEED_ADC_CTRL_COMPENSATION		BIT(4)
+#define ASPEED_ADC_AUTO_COMPENSATION		BIT(5)
+#define ASPEED_ADC_REF_VOLTAGE			GENMASK(7, 6)
+#define ASPEED_ADC_REF_VOLTAGE_2500mV		0
+#define ASPEED_ADC_REF_VOLTAGE_1200mV		1
+#define ASPEED_ADC_REF_VOLTAGE_EXT_HIGH		2
+#define ASPEED_ADC_REF_VOLTAGE_EXT_LOW		3
+#define ASPEED_ADC_BAT_SENSING_DIV		BIT(6)
+#define ASPEED_ADC_BAT_SENSING_DIV_2_3		0
+#define ASPEED_ADC_BAT_SENSING_DIV_1_3		1
+#define ASPEED_ADC_CTRL_INIT_RDY		BIT(8)
+#define ASPEED_ADC_CH7_MODE			BIT(12)
+#define ASPEED_ADC_CH7_NORMAL			0
+#define ASPEED_ADC_CH7_BAT			1
+#define ASPEED_ADC_BAT_SENSING_ENABLE		BIT(13)
+#define ASPEED_ADC_CTRL_CHANNEL			GENMASK(31, 16)
+#define ASPEED_ADC_CTRL_CHANNEL_ENABLE(ch)	FIELD_PREP(ASPEED_ADC_CTRL_CHANNEL, BIT(ch))
 
 #define ASPEED_ADC_INIT_POLLING_TIME	500
 #define ASPEED_ADC_INIT_TIMEOUT		500000
@@ -226,7 +244,9 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 
 	if (model_data->wait_init_sequence) {
 		/* Enable engine in normal mode. */
-		writel(ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE,
+		writel(FIELD_PREP(ASPEED_ADC_OP_MODE,
+				  ASPEED_ADC_OP_MODE_NORMAL) |
+			       ASPEED_ADC_ENGINE_ENABLE,
 		       data->base + ASPEED_REG_ENGINE_CONTROL);
 
 		/* Wait for initial sequence complete. */
@@ -245,10 +265,12 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	if (ret)
 		goto clk_enable_error;
 
-	adc_engine_control_reg_val = GENMASK(31, 16) |
-		ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE;
+	adc_engine_control_reg_val =
+		ASPEED_ADC_CTRL_CHANNEL |
+		FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_NORMAL) |
+		ASPEED_ADC_ENGINE_ENABLE;
 	writel(adc_engine_control_reg_val,
-		data->base + ASPEED_REG_ENGINE_CONTROL);
+	       data->base + ASPEED_REG_ENGINE_CONTROL);
 
 	model_data = of_device_get_match_data(&pdev->dev);
 	indio_dev->name = model_data->model_name;
@@ -264,8 +286,8 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	return 0;
 
 iio_register_error:
-	writel(ASPEED_OPERATION_MODE_POWER_DOWN,
-		data->base + ASPEED_REG_ENGINE_CONTROL);
+	writel(FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_PWR_DOWN),
+	       data->base + ASPEED_REG_ENGINE_CONTROL);
 	clk_disable_unprepare(data->clk_scaler->clk);
 clk_enable_error:
 poll_timeout_error:
@@ -283,8 +305,8 @@ static int aspeed_adc_remove(struct platform_device *pdev)
 	struct aspeed_adc_data *data = iio_priv(indio_dev);
 
 	iio_device_unregister(indio_dev);
-	writel(ASPEED_OPERATION_MODE_POWER_DOWN,
-		data->base + ASPEED_REG_ENGINE_CONTROL);
+	writel(FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_PWR_DOWN),
+	       data->base + ASPEED_REG_ENGINE_CONTROL);
 	clk_disable_unprepare(data->clk_scaler->clk);
 	reset_control_assert(data->rst);
 	clk_hw_unregister_divider(data->clk_scaler);
-- 
2.25.1


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

* [RESEND v4 03/15] iio: adc: aspeed: set driver data when adc probe.
  2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
  2021-08-24  9:12 ` [RESEND v4 01/15] dt-bindings: iio: adc: Add ast2600-adc bindings Billy Tsai
  2021-08-24  9:12 ` [RESEND v4 02/15] iio: adc: aspeed: completes the bitfield declare Billy Tsai
@ 2021-08-24  9:12 ` Billy Tsai
  2021-08-29 15:08   ` Jonathan Cameron
  2021-08-24  9:12 ` [RESEND v4 04/15] iio: adc: aspeed: Keep model data to driver data Billy Tsai
                   ` (18 subsequent siblings)
  21 siblings, 1 reply; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

Fix the issue when adc remove will get the null driver data.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
 drivers/iio/adc/aspeed_adc.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 7010d56ac3b9..20462cf659e4 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -201,6 +201,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 
 	data = iio_priv(indio_dev);
 	data->dev = &pdev->dev;
+	platform_set_drvdata(pdev, indio_dev);
 
 	data->base = devm_platform_ioremap_resource(pdev, 0);
 	if (IS_ERR(data->base))
-- 
2.25.1


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

* [RESEND v4 04/15] iio: adc: aspeed: Keep model data to driver data.
  2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
                   ` (2 preceding siblings ...)
  2021-08-24  9:12 ` [RESEND v4 03/15] iio: adc: aspeed: set driver data when adc probe Billy Tsai
@ 2021-08-24  9:12 ` Billy Tsai
  2021-08-24  9:12 ` [RESEND v4 05/15] iio: adc: aspeed: Refactory model data structure Billy Tsai
                   ` (17 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

Keep the model data pointer to driver data for reducing the usage of
of_device_get_match_data().

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
 drivers/iio/adc/aspeed_adc.c | 20 +++++++-------------
 1 file changed, 7 insertions(+), 13 deletions(-)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 20462cf659e4..d85aa31ee3b1 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -69,6 +69,7 @@ struct aspeed_adc_model_data {
 
 struct aspeed_adc_data {
 	struct device		*dev;
+	const struct aspeed_adc_model_data *model_data;
 	void __iomem		*base;
 	spinlock_t		clk_lock;
 	struct clk_hw		*clk_prescaler;
@@ -110,8 +111,6 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
 			       int *val, int *val2, long mask)
 {
 	struct aspeed_adc_data *data = iio_priv(indio_dev);
-	const struct aspeed_adc_model_data *model_data =
-			of_device_get_match_data(data->dev);
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
@@ -119,7 +118,7 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
 		return IIO_VAL_INT;
 
 	case IIO_CHAN_INFO_SCALE:
-		*val = model_data->vref_voltage;
+		*val = data->model_data->vref_voltage;
 		*val2 = ASPEED_RESOLUTION_BITS;
 		return IIO_VAL_FRACTIONAL_LOG2;
 
@@ -138,13 +137,11 @@ static int aspeed_adc_write_raw(struct iio_dev *indio_dev,
 				int val, int val2, long mask)
 {
 	struct aspeed_adc_data *data = iio_priv(indio_dev);
-	const struct aspeed_adc_model_data *model_data =
-			of_device_get_match_data(data->dev);
 
 	switch (mask) {
 	case IIO_CHAN_INFO_SAMP_FREQ:
-		if (val < model_data->min_sampling_rate ||
-			val > model_data->max_sampling_rate)
+		if (val < data->model_data->min_sampling_rate ||
+			val > data->model_data->max_sampling_rate)
 			return -EINVAL;
 
 		clk_set_rate(data->clk_scaler->clk,
@@ -190,7 +187,6 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 {
 	struct iio_dev *indio_dev;
 	struct aspeed_adc_data *data;
-	const struct aspeed_adc_model_data *model_data;
 	const char *clk_parent_name;
 	int ret;
 	u32 adc_engine_control_reg_val;
@@ -201,6 +197,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 
 	data = iio_priv(indio_dev);
 	data->dev = &pdev->dev;
+	data->model_data = of_device_get_match_data(&pdev->dev);
 	platform_set_drvdata(pdev, indio_dev);
 
 	data->base = devm_platform_ioremap_resource(pdev, 0);
@@ -241,9 +238,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	}
 	reset_control_deassert(data->rst);
 
-	model_data = of_device_get_match_data(&pdev->dev);
-
-	if (model_data->wait_init_sequence) {
+	if (data->model_data->wait_init_sequence) {
 		/* Enable engine in normal mode. */
 		writel(FIELD_PREP(ASPEED_ADC_OP_MODE,
 				  ASPEED_ADC_OP_MODE_NORMAL) |
@@ -273,8 +268,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	writel(adc_engine_control_reg_val,
 	       data->base + ASPEED_REG_ENGINE_CONTROL);
 
-	model_data = of_device_get_match_data(&pdev->dev);
-	indio_dev->name = model_data->model_name;
+	indio_dev->name = data->model_data->model_name;
 	indio_dev->info = &aspeed_adc_iio_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = aspeed_adc_iio_channels;
-- 
2.25.1


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

* [RESEND v4 05/15] iio: adc: aspeed: Refactory model data structure
  2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
                   ` (3 preceding siblings ...)
  2021-08-24  9:12 ` [RESEND v4 04/15] iio: adc: aspeed: Keep model data to driver data Billy Tsai
@ 2021-08-24  9:12 ` Billy Tsai
  2021-08-29 15:13   ` Jonathan Cameron
  2021-08-24  9:12 ` [RESEND v4 06/15] iio: adc: aspeed: Add vref config function Billy Tsai
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

This patch refactory the model data structure to distinguish the
function form differnet version of aspeed adc.
- Rename the vref_voltag to vref_fixed and add vref driver data
When driver probe will check vref_fixed value and store it
to vref which isn't const value.
- Add num_channels
Make num_channles of iio device can be changed by differnet model_data
- Add need_prescaler flag and scaler_bit_width
The need_prescaler flag used to tell the driver the clock divider needs
another prescaler and the scaler_bit_width to set the clock divider
bitfiled width.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
 drivers/iio/adc/aspeed_adc.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index d85aa31ee3b1..f03c7921d534 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -63,8 +63,11 @@ struct aspeed_adc_model_data {
 	const char *model_name;
 	unsigned int min_sampling_rate;	// Hz
 	unsigned int max_sampling_rate;	// Hz
-	unsigned int vref_voltage;	// mV
+	unsigned int vref_fixed;	// mV
 	bool wait_init_sequence;
+	bool need_prescaler;
+	u8 scaler_bit_width;
+	unsigned int num_channels;
 };
 
 struct aspeed_adc_data {
@@ -75,6 +78,7 @@ struct aspeed_adc_data {
 	struct clk_hw		*clk_prescaler;
 	struct clk_hw		*clk_scaler;
 	struct reset_control	*rst;
+	int			vref;
 };
 
 #define ASPEED_CHAN(_idx, _data_reg_addr) {			\
@@ -118,7 +122,7 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
 		return IIO_VAL_INT;
 
 	case IIO_CHAN_INFO_SCALE:
-		*val = data->model_data->vref_voltage;
+		*val = data->model_data->vref_fixed;
 		*val2 = ASPEED_RESOLUTION_BITS;
 		return IIO_VAL_FRACTIONAL_LOG2;
 
@@ -312,17 +316,23 @@ static int aspeed_adc_remove(struct platform_device *pdev)
 
 static const struct aspeed_adc_model_data ast2400_model_data = {
 	.model_name = "ast2400-adc",
-	.vref_voltage = 2500, // mV
+	.vref_fixed = 2500, // mV
 	.min_sampling_rate = 10000,
 	.max_sampling_rate = 500000,
+	.need_prescaler = true,
+	.scaler_bit_width = 10,
+	.num_channels = 16,
 };
 
 static const struct aspeed_adc_model_data ast2500_model_data = {
 	.model_name = "ast2500-adc",
-	.vref_voltage = 1800, // mV
+	.vref_fixed = 1800, // mV
 	.min_sampling_rate = 1,
 	.max_sampling_rate = 1000000,
 	.wait_init_sequence = true,
+	.need_prescaler = true,
+	.scaler_bit_width = 10,
+	.num_channels = 16,
 };
 
 static const struct of_device_id aspeed_adc_matches[] = {
-- 
2.25.1


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

* [RESEND v4 06/15] iio: adc: aspeed: Add vref config function
  2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
                   ` (4 preceding siblings ...)
  2021-08-24  9:12 ` [RESEND v4 05/15] iio: adc: aspeed: Refactory model data structure Billy Tsai
@ 2021-08-24  9:12 ` Billy Tsai
  2021-08-24  9:12 ` [RESEND v4 07/15] iio: adc: aspeed: Set num_channels with model data Billy Tsai
                   ` (15 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

Add the function to check the vref_fixed and set the value to driver
data.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
 drivers/iio/adc/aspeed_adc.c | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index f03c7921d534..f260e40ab9b2 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -122,7 +122,7 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
 		return IIO_VAL_INT;
 
 	case IIO_CHAN_INFO_SCALE:
-		*val = data->model_data->vref_fixed;
+		*val = data->vref;
 		*val2 = ASPEED_RESOLUTION_BITS;
 		return IIO_VAL_FRACTIONAL_LOG2;
 
@@ -187,6 +187,17 @@ static const struct iio_info aspeed_adc_iio_info = {
 	.debugfs_reg_access = aspeed_adc_reg_access,
 };
 
+static int aspeed_adc_vref_config(struct iio_dev *indio_dev)
+{
+	struct aspeed_adc_data *data = iio_priv(indio_dev);
+
+	if (data->model_data->vref_fixed) {
+		data->vref = data->model_data->vref_fixed;
+		return 0;
+	}
+	return 0;
+}
+
 static int aspeed_adc_probe(struct platform_device *pdev)
 {
 	struct iio_dev *indio_dev;
@@ -242,6 +253,10 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	}
 	reset_control_deassert(data->rst);
 
+	ret = aspeed_adc_vref_config(indio_dev);
+	if (ret)
+		goto vref_config_error;
+
 	if (data->model_data->wait_init_sequence) {
 		/* Enable engine in normal mode. */
 		writel(FIELD_PREP(ASPEED_ADC_OP_MODE,
@@ -290,6 +305,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	clk_disable_unprepare(data->clk_scaler->clk);
 clk_enable_error:
 poll_timeout_error:
+vref_config_error:
 	reset_control_assert(data->rst);
 reset_error:
 	clk_hw_unregister_divider(data->clk_scaler);
-- 
2.25.1


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

* [RESEND v4 07/15] iio: adc: aspeed: Set num_channels with model data
  2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
                   ` (5 preceding siblings ...)
  2021-08-24  9:12 ` [RESEND v4 06/15] iio: adc: aspeed: Add vref config function Billy Tsai
@ 2021-08-24  9:12 ` Billy Tsai
  2021-08-24  9:12 ` [RESEND v4 08/15] iio: adc: aspeed: Use model_data to set clk scaler Billy Tsai
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

Use the model_data member num_channels to set the num_channels of iio
device.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
 drivers/iio/adc/aspeed_adc.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index f260e40ab9b2..2d6215a91f99 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -291,7 +291,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	indio_dev->info = &aspeed_adc_iio_info;
 	indio_dev->modes = INDIO_DIRECT_MODE;
 	indio_dev->channels = aspeed_adc_iio_channels;
-	indio_dev->num_channels = ARRAY_SIZE(aspeed_adc_iio_channels);
+	indio_dev->num_channels = data->model_data->num_channels;
 
 	ret = iio_device_register(indio_dev);
 	if (ret)
-- 
2.25.1


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

* [RESEND v4 08/15] iio: adc: aspeed: Use model_data to set clk scaler.
  2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
                   ` (6 preceding siblings ...)
  2021-08-24  9:12 ` [RESEND v4 07/15] iio: adc: aspeed: Set num_channels with model data Billy Tsai
@ 2021-08-24  9:12 ` Billy Tsai
  2021-08-24  9:12 ` [RESEND v4 09/15] iio: adc: aspeed: Use devm_add_action_or_reset Billy Tsai
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

This patch use need_prescaler and scaler_bit_width to set the adc clock
scaler.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
 drivers/iio/adc/aspeed_adc.c | 39 +++++++++++++++++++++---------------
 1 file changed, 23 insertions(+), 16 deletions(-)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 2d6215a91f99..52db38be9699 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -202,9 +202,10 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 {
 	struct iio_dev *indio_dev;
 	struct aspeed_adc_data *data;
-	const char *clk_parent_name;
 	int ret;
 	u32 adc_engine_control_reg_val;
+	unsigned long scaler_flags = 0;
+	char clk_name[32], clk_parent_name[32];
 
 	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data));
 	if (!indio_dev)
@@ -221,24 +222,28 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 
 	/* Register ADC clock prescaler with source specified by device tree. */
 	spin_lock_init(&data->clk_lock);
-	clk_parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
-
-	data->clk_prescaler = clk_hw_register_divider(
-				&pdev->dev, "prescaler", clk_parent_name, 0,
-				data->base + ASPEED_REG_CLOCK_CONTROL,
-				17, 15, 0, &data->clk_lock);
-	if (IS_ERR(data->clk_prescaler))
-		return PTR_ERR(data->clk_prescaler);
-
+	snprintf(clk_parent_name, 32, of_clk_get_parent_name(pdev->dev.of_node, 0));
+	if (data->model_data->need_prescaler) {
+		snprintf(clk_name, 32, "%s-prescaler",
+			 data->model_data->model_name);
+		data->clk_prescaler = clk_hw_register_divider(
+			&pdev->dev, clk_name, clk_parent_name, 0,
+			data->base + ASPEED_REG_CLOCK_CONTROL, 17, 15, 0,
+			&data->clk_lock);
+		if (IS_ERR(data->clk_prescaler))
+			return PTR_ERR(data->clk_prescaler);
+		snprintf(clk_parent_name, 32, clk_name);
+		scaler_flags = CLK_SET_RATE_PARENT;
+	}
 	/*
 	 * Register ADC clock scaler downstream from the prescaler. Allow rate
 	 * setting to adjust the prescaler as well.
 	 */
+	snprintf(clk_name, 32, "%s-scaler", data->model_data->model_name);
 	data->clk_scaler = clk_hw_register_divider(
-				&pdev->dev, "scaler", "prescaler",
-				CLK_SET_RATE_PARENT,
-				data->base + ASPEED_REG_CLOCK_CONTROL,
-				0, 10, 0, &data->clk_lock);
+		&pdev->dev, clk_name, clk_parent_name, scaler_flags,
+		data->base + ASPEED_REG_CLOCK_CONTROL, 0,
+		data->model_data->scaler_bit_width, 0, &data->clk_lock);
 	if (IS_ERR(data->clk_scaler)) {
 		ret = PTR_ERR(data->clk_scaler);
 		goto scaler_error;
@@ -310,7 +315,8 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 reset_error:
 	clk_hw_unregister_divider(data->clk_scaler);
 scaler_error:
-	clk_hw_unregister_divider(data->clk_prescaler);
+	if (data->model_data->need_prescaler)
+		clk_hw_unregister_divider(data->clk_prescaler);
 	return ret;
 }
 
@@ -325,7 +331,8 @@ static int aspeed_adc_remove(struct platform_device *pdev)
 	clk_disable_unprepare(data->clk_scaler->clk);
 	reset_control_assert(data->rst);
 	clk_hw_unregister_divider(data->clk_scaler);
-	clk_hw_unregister_divider(data->clk_prescaler);
+	if (data->model_data->need_prescaler)
+		clk_hw_unregister_divider(data->clk_prescaler);
 
 	return 0;
 }
-- 
2.25.1


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

* [RESEND v4 09/15] iio: adc: aspeed: Use devm_add_action_or_reset.
  2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
                   ` (7 preceding siblings ...)
  2021-08-24  9:12 ` [RESEND v4 08/15] iio: adc: aspeed: Use model_data to set clk scaler Billy Tsai
@ 2021-08-24  9:12 ` Billy Tsai
  2021-08-24  9:12 ` Billy Tsai
                   ` (12 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

This patch use devm_add_action_or_reset to handle the error in probe
phase.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
 drivers/iio/adc/aspeed_adc.c | 92 +++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 37 deletions(-)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 52db38be9699..1c87e12a0cab 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -187,6 +187,27 @@ static const struct iio_info aspeed_adc_iio_info = {
 	.debugfs_reg_access = aspeed_adc_reg_access,
 };
 
+static void aspeed_adc_unregister_divider(void *data)
+{
+	struct clk_hw *clk = data;
+
+	clk_hw_unregister_divider(clk);
+}
+
+static void aspeed_adc_reset_assert(void *data)
+{
+	struct reset_control *rst = data;
+
+	reset_control_assert(rst);
+}
+
+static void aspeed_adc_clk_disable_unprepare(void *data)
+{
+	struct clk *clk = data;
+
+	clk_disable_unprepare(clk);
+}
+
 static int aspeed_adc_vref_config(struct iio_dev *indio_dev)
 {
 	struct aspeed_adc_data *data = iio_priv(indio_dev);
@@ -232,6 +253,12 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 			&data->clk_lock);
 		if (IS_ERR(data->clk_prescaler))
 			return PTR_ERR(data->clk_prescaler);
+
+		ret = devm_add_action_or_reset(data->dev,
+					       aspeed_adc_unregister_divider,
+					       data->clk_prescaler);
+		if (ret)
+			return ret;
 		snprintf(clk_parent_name, 32, clk_name);
 		scaler_flags = CLK_SET_RATE_PARENT;
 	}
@@ -244,23 +271,30 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 		&pdev->dev, clk_name, clk_parent_name, scaler_flags,
 		data->base + ASPEED_REG_CLOCK_CONTROL, 0,
 		data->model_data->scaler_bit_width, 0, &data->clk_lock);
-	if (IS_ERR(data->clk_scaler)) {
-		ret = PTR_ERR(data->clk_scaler);
-		goto scaler_error;
-	}
+	if (IS_ERR(data->clk_scaler))
+		return PTR_ERR(data->clk_scaler);
+
+	ret = devm_add_action_or_reset(data->dev, aspeed_adc_unregister_divider,
+				       data->clk_scaler);
+	if (ret)
+		return ret;
 
 	data->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
 	if (IS_ERR(data->rst)) {
 		dev_err(&pdev->dev,
 			"invalid or missing reset controller device tree entry");
-		ret = PTR_ERR(data->rst);
-		goto reset_error;
+		return PTR_ERR(data->rst);
 	}
 	reset_control_deassert(data->rst);
 
+	ret = devm_add_action_or_reset(data->dev, aspeed_adc_reset_assert,
+				       data->rst);
+	if (ret)
+		return ret;
+
 	ret = aspeed_adc_vref_config(indio_dev);
 	if (ret)
-		goto vref_config_error;
+		return ret;
 
 	if (data->model_data->wait_init_sequence) {
 		/* Enable engine in normal mode. */
@@ -277,13 +311,19 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 					 ASPEED_ADC_INIT_POLLING_TIME,
 					 ASPEED_ADC_INIT_TIMEOUT);
 		if (ret)
-			goto poll_timeout_error;
+			return ret;
 	}
 
 	/* Start all channels in normal mode. */
 	ret = clk_prepare_enable(data->clk_scaler->clk);
 	if (ret)
-		goto clk_enable_error;
+		return ret;
+
+	ret = devm_add_action_or_reset(data->dev,
+				       aspeed_adc_clk_disable_unprepare,
+				       data->clk_scaler->clk);
+	if (ret)
+		return ret;
 
 	adc_engine_control_reg_val =
 		ASPEED_ADC_CTRL_CHANNEL |
@@ -299,41 +339,19 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	indio_dev->num_channels = data->model_data->num_channels;
 
 	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto iio_register_error;
-
+	if (ret) {
+		writel(FIELD_PREP(ASPEED_ADC_OP_MODE,
+				  ASPEED_ADC_OP_MODE_PWR_DOWN),
+		       data->base + ASPEED_REG_ENGINE_CONTROL);
+		return ret;
+	}
 	return 0;
-
-iio_register_error:
-	writel(FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_PWR_DOWN),
-	       data->base + ASPEED_REG_ENGINE_CONTROL);
-	clk_disable_unprepare(data->clk_scaler->clk);
-clk_enable_error:
-poll_timeout_error:
-vref_config_error:
-	reset_control_assert(data->rst);
-reset_error:
-	clk_hw_unregister_divider(data->clk_scaler);
-scaler_error:
-	if (data->model_data->need_prescaler)
-		clk_hw_unregister_divider(data->clk_prescaler);
-	return ret;
 }
 
 static int aspeed_adc_remove(struct platform_device *pdev)
 {
 	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
-	struct aspeed_adc_data *data = iio_priv(indio_dev);
-
 	iio_device_unregister(indio_dev);
-	writel(FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_PWR_DOWN),
-	       data->base + ASPEED_REG_ENGINE_CONTROL);
-	clk_disable_unprepare(data->clk_scaler->clk);
-	reset_control_assert(data->rst);
-	clk_hw_unregister_divider(data->clk_scaler);
-	if (data->model_data->need_prescaler)
-		clk_hw_unregister_divider(data->clk_prescaler);
-
 	return 0;
 }
 
-- 
2.25.1


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

* [RESEND v4 09/15] iio: adc: aspeed: Use devm_add_action_or_reset.
  2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
                   ` (8 preceding siblings ...)
  2021-08-24  9:12 ` [RESEND v4 09/15] iio: adc: aspeed: Use devm_add_action_or_reset Billy Tsai
@ 2021-08-24  9:12 ` Billy Tsai
  2021-08-24  9:12 ` [RESEND v4 10/15] iio: adc: aspeed: Support ast2600 adc Billy Tsai
                   ` (11 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

This patch use devm_add_action_or_reset to handle the error in probe
phase.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
 drivers/iio/adc/aspeed_adc.c | 92 +++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 37 deletions(-)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 52db38be9699..1c87e12a0cab 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -187,6 +187,27 @@ static const struct iio_info aspeed_adc_iio_info = {
 	.debugfs_reg_access = aspeed_adc_reg_access,
 };
 
+static void aspeed_adc_unregister_divider(void *data)
+{
+	struct clk_hw *clk = data;
+
+	clk_hw_unregister_divider(clk);
+}
+
+static void aspeed_adc_reset_assert(void *data)
+{
+	struct reset_control *rst = data;
+
+	reset_control_assert(rst);
+}
+
+static void aspeed_adc_clk_disable_unprepare(void *data)
+{
+	struct clk *clk = data;
+
+	clk_disable_unprepare(clk);
+}
+
 static int aspeed_adc_vref_config(struct iio_dev *indio_dev)
 {
 	struct aspeed_adc_data *data = iio_priv(indio_dev);
@@ -232,6 +253,12 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 			&data->clk_lock);
 		if (IS_ERR(data->clk_prescaler))
 			return PTR_ERR(data->clk_prescaler);
+
+		ret = devm_add_action_or_reset(data->dev,
+					       aspeed_adc_unregister_divider,
+					       data->clk_prescaler);
+		if (ret)
+			return ret;
 		snprintf(clk_parent_name, 32, clk_name);
 		scaler_flags = CLK_SET_RATE_PARENT;
 	}
@@ -244,23 +271,30 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 		&pdev->dev, clk_name, clk_parent_name, scaler_flags,
 		data->base + ASPEED_REG_CLOCK_CONTROL, 0,
 		data->model_data->scaler_bit_width, 0, &data->clk_lock);
-	if (IS_ERR(data->clk_scaler)) {
-		ret = PTR_ERR(data->clk_scaler);
-		goto scaler_error;
-	}
+	if (IS_ERR(data->clk_scaler))
+		return PTR_ERR(data->clk_scaler);
+
+	ret = devm_add_action_or_reset(data->dev, aspeed_adc_unregister_divider,
+				       data->clk_scaler);
+	if (ret)
+		return ret;
 
 	data->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
 	if (IS_ERR(data->rst)) {
 		dev_err(&pdev->dev,
 			"invalid or missing reset controller device tree entry");
-		ret = PTR_ERR(data->rst);
-		goto reset_error;
+		return PTR_ERR(data->rst);
 	}
 	reset_control_deassert(data->rst);
 
+	ret = devm_add_action_or_reset(data->dev, aspeed_adc_reset_assert,
+				       data->rst);
+	if (ret)
+		return ret;
+
 	ret = aspeed_adc_vref_config(indio_dev);
 	if (ret)
-		goto vref_config_error;
+		return ret;
 
 	if (data->model_data->wait_init_sequence) {
 		/* Enable engine in normal mode. */
@@ -277,13 +311,19 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 					 ASPEED_ADC_INIT_POLLING_TIME,
 					 ASPEED_ADC_INIT_TIMEOUT);
 		if (ret)
-			goto poll_timeout_error;
+			return ret;
 	}
 
 	/* Start all channels in normal mode. */
 	ret = clk_prepare_enable(data->clk_scaler->clk);
 	if (ret)
-		goto clk_enable_error;
+		return ret;
+
+	ret = devm_add_action_or_reset(data->dev,
+				       aspeed_adc_clk_disable_unprepare,
+				       data->clk_scaler->clk);
+	if (ret)
+		return ret;
 
 	adc_engine_control_reg_val =
 		ASPEED_ADC_CTRL_CHANNEL |
@@ -299,41 +339,19 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	indio_dev->num_channels = data->model_data->num_channels;
 
 	ret = iio_device_register(indio_dev);
-	if (ret)
-		goto iio_register_error;
-
+	if (ret) {
+		writel(FIELD_PREP(ASPEED_ADC_OP_MODE,
+				  ASPEED_ADC_OP_MODE_PWR_DOWN),
+		       data->base + ASPEED_REG_ENGINE_CONTROL);
+		return ret;
+	}
 	return 0;
-
-iio_register_error:
-	writel(FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_PWR_DOWN),
-	       data->base + ASPEED_REG_ENGINE_CONTROL);
-	clk_disable_unprepare(data->clk_scaler->clk);
-clk_enable_error:
-poll_timeout_error:
-vref_config_error:
-	reset_control_assert(data->rst);
-reset_error:
-	clk_hw_unregister_divider(data->clk_scaler);
-scaler_error:
-	if (data->model_data->need_prescaler)
-		clk_hw_unregister_divider(data->clk_prescaler);
-	return ret;
 }
 
 static int aspeed_adc_remove(struct platform_device *pdev)
 {
 	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
-	struct aspeed_adc_data *data = iio_priv(indio_dev);
-
 	iio_device_unregister(indio_dev);
-	writel(FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_PWR_DOWN),
-	       data->base + ASPEED_REG_ENGINE_CONTROL);
-	clk_disable_unprepare(data->clk_scaler->clk);
-	reset_control_assert(data->rst);
-	clk_hw_unregister_divider(data->clk_scaler);
-	if (data->model_data->need_prescaler)
-		clk_hw_unregister_divider(data->clk_prescaler);
-
 	return 0;
 }
 
-- 
2.25.1


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

* [RESEND v4 10/15] iio: adc: aspeed: Support ast2600 adc.
  2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
                   ` (9 preceding siblings ...)
  2021-08-24  9:12 ` Billy Tsai
@ 2021-08-24  9:12 ` Billy Tsai
  2021-08-29 15:31   ` Jonathan Cameron
  2021-08-24  9:12 ` [RESEND v4 11/15] iio: adc: aspeed: Fix the calculate error of clock Billy Tsai
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

Make driver to support ast2600 adc device.
- Use shared reset controller
- Complete the vref configure function
- Add the model data for ast2600 adc

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
 drivers/iio/adc/aspeed_adc.c | 106 +++++++++++++++++++++++++++++++++--
 1 file changed, 100 insertions(+), 6 deletions(-)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 1c87e12a0cab..ea3e9a52fcc9 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Aspeed AST2400/2500 ADC
+ * Aspeed AST2400/2500/2600 ADC
  *
  * Copyright (C) 2017 Google, Inc.
  * Copyright (C) 2021 Aspeed Technology Inc.
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
 #include <linux/reset.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
@@ -73,6 +74,7 @@ struct aspeed_adc_model_data {
 struct aspeed_adc_data {
 	struct device		*dev;
 	const struct aspeed_adc_model_data *model_data;
+	struct regulator	*regulator;
 	void __iomem		*base;
 	spinlock_t		clk_lock;
 	struct clk_hw		*clk_prescaler;
@@ -208,14 +210,80 @@ static void aspeed_adc_clk_disable_unprepare(void *data)
 	clk_disable_unprepare(clk);
 }
 
+static void aspeed_adc_reg_disable(void *data)
+{
+	struct regulator *reg = data;
+
+	regulator_disable(reg);
+}
+
 static int aspeed_adc_vref_config(struct iio_dev *indio_dev)
 {
 	struct aspeed_adc_data *data = iio_priv(indio_dev);
+	int ret;
+	u32 adc_engine_control_reg_val =
+		readl(data->base + ASPEED_REG_ENGINE_CONTROL);
 
 	if (data->model_data->vref_fixed) {
 		data->vref = data->model_data->vref_fixed;
 		return 0;
 	}
+
+	data->regulator = devm_regulator_get_optional(data->dev, "vref");
+	if (!IS_ERR(data->regulator)) {
+		ret = regulator_enable(data->regulator);
+		if (ret)
+			return ret;
+		ret = devm_add_action_or_reset(
+			data->dev, aspeed_adc_reg_disable, data->regulator);
+		if (ret)
+			return ret;
+		data->vref = regulator_get_voltage(data->regulator);
+		/* Conversion from uV to mV */
+		data->vref /= 1000;
+		if ((data->vref >= 1550) && (data->vref <= 2700))
+			writel(adc_engine_control_reg_val |
+				       FIELD_PREP(
+					       ASPEED_ADC_REF_VOLTAGE,
+					       ASPEED_ADC_REF_VOLTAGE_EXT_HIGH),
+			       data->base + ASPEED_REG_ENGINE_CONTROL);
+		else if ((data->vref >= 900) && (data->vref <= 1650))
+			writel(adc_engine_control_reg_val |
+				       FIELD_PREP(
+					       ASPEED_ADC_REF_VOLTAGE,
+					       ASPEED_ADC_REF_VOLTAGE_EXT_LOW),
+			       data->base + ASPEED_REG_ENGINE_CONTROL);
+		else {
+			dev_err(data->dev, "Regulator voltage %d not support",
+				data->vref);
+			return -EOPNOTSUPP;
+		}
+	} else {
+		if (PTR_ERR(data->regulator) != -ENODEV)
+			return PTR_ERR(data->regulator);
+		ret = of_property_read_u32(data->dev->of_node,
+					   "aspeed,int_vref_mv", &data->vref);
+		if (ret < 0) {
+			dev_warn(data->dev,
+				 "Using default vref: internal 2500 mv");
+			data->vref = 2500;
+		}
+		if (data->vref == 2500)
+			writel(adc_engine_control_reg_val |
+				       FIELD_PREP(ASPEED_ADC_REF_VOLTAGE,
+						  ASPEED_ADC_REF_VOLTAGE_2500mV),
+			       data->base + ASPEED_REG_ENGINE_CONTROL);
+		else if (data->vref == 1200)
+			writel(adc_engine_control_reg_val |
+				       FIELD_PREP(ASPEED_ADC_REF_VOLTAGE,
+						  ASPEED_ADC_REF_VOLTAGE_1200mV),
+			       data->base + ASPEED_REG_ENGINE_CONTROL);
+		else {
+			dev_err(data->dev, "Voltage %d not support", data->vref);
+			return -EOPNOTSUPP;
+		}
+	}
+
 	return 0;
 }
 
@@ -279,7 +347,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	data->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
+	data->rst = devm_reset_control_get_shared(&pdev->dev, NULL);
 	if (IS_ERR(data->rst)) {
 		dev_err(&pdev->dev,
 			"invalid or missing reset controller device tree entry");
@@ -297,10 +365,14 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 		return ret;
 
 	if (data->model_data->wait_init_sequence) {
+		adc_engine_control_reg_val =
+			readl(data->base + ASPEED_REG_ENGINE_CONTROL);
+		adc_engine_control_reg_val |=
+			FIELD_PREP(ASPEED_ADC_OP_MODE,
+				   ASPEED_ADC_OP_MODE_NORMAL) |
+			ASPEED_ADC_ENGINE_ENABLE;
 		/* Enable engine in normal mode. */
-		writel(FIELD_PREP(ASPEED_ADC_OP_MODE,
-				  ASPEED_ADC_OP_MODE_NORMAL) |
-			       ASPEED_ADC_ENGINE_ENABLE,
+		writel(adc_engine_control_reg_val,
 		       data->base + ASPEED_REG_ENGINE_CONTROL);
 
 		/* Wait for initial sequence complete. */
@@ -326,6 +398,8 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 		return ret;
 
 	adc_engine_control_reg_val =
+		readl(data->base + ASPEED_REG_ENGINE_CONTROL);
+	adc_engine_control_reg_val |=
 		ASPEED_ADC_CTRL_CHANNEL |
 		FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_NORMAL) |
 		ASPEED_ADC_ENGINE_ENABLE;
@@ -376,9 +450,29 @@ static const struct aspeed_adc_model_data ast2500_model_data = {
 	.num_channels = 16,
 };
 
+static const struct aspeed_adc_model_data ast2600_adc0_model_data = {
+	.model_name = "ast2600-adc0",
+	.min_sampling_rate = 10000,
+	.max_sampling_rate = 500000,
+	.wait_init_sequence = true,
+	.scaler_bit_width = 16,
+	.num_channels = 8,
+};
+
+static const struct aspeed_adc_model_data ast2600_adc1_model_data = {
+	.model_name = "ast2600-adc1",
+	.min_sampling_rate = 10000,
+	.max_sampling_rate = 500000,
+	.wait_init_sequence = true,
+	.scaler_bit_width = 16,
+	.num_channels = 8,
+};
+
 static const struct of_device_id aspeed_adc_matches[] = {
 	{ .compatible = "aspeed,ast2400-adc", .data = &ast2400_model_data },
 	{ .compatible = "aspeed,ast2500-adc", .data = &ast2500_model_data },
+	{ .compatible = "aspeed,ast2600-adc0", .data = &ast2600_adc0_model_data },
+	{ .compatible = "aspeed,ast2600-adc1", .data = &ast2600_adc1_model_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, aspeed_adc_matches);
@@ -395,5 +489,5 @@ static struct platform_driver aspeed_adc_driver = {
 module_platform_driver(aspeed_adc_driver);
 
 MODULE_AUTHOR("Rick Altherr <raltherr@google.com>");
-MODULE_DESCRIPTION("Aspeed AST2400/2500 ADC Driver");
+MODULE_DESCRIPTION("Aspeed AST2400/2500/2600 ADC Driver");
 MODULE_LICENSE("GPL");
-- 
2.25.1


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

* [RESEND v4 11/15] iio: adc: aspeed: Fix the calculate error of clock.
  2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
                   ` (10 preceding siblings ...)
  2021-08-24  9:12 ` [RESEND v4 10/15] iio: adc: aspeed: Support ast2600 adc Billy Tsai
@ 2021-08-24  9:12 ` Billy Tsai
  2021-08-29 15:33   ` Jonathan Cameron
  2021-08-24  9:12 ` [RESEND v4 12/15] iio: adc: aspeed: Add func to set sampling rate Billy Tsai
                   ` (9 subsequent siblings)
  21 siblings, 1 reply; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

The adc clcok formula is
ast2400/2500:
ADC clock period = PCLK * 2 * (ADC0C[31:17] + 1) * (ADC0C[9:0] + 1)
ast2600:
ADC clock period = PCLK * 2 * (ADC0C[15:0] + 1)
They all have one fixed divided 2 and the legacy driver didn't handle it.
This patch register the fixed factory clock device as the parent of adc
clock scaler to fix this issue.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
 drivers/iio/adc/aspeed_adc.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index ea3e9a52fcc9..8fe7da1a651f 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -4,6 +4,12 @@
  *
  * Copyright (C) 2017 Google, Inc.
  * Copyright (C) 2021 Aspeed Technology Inc.
+ *
+ * ADC clock formula:
+ * Ast2400/Ast2500:
+ * clock period = period of PCLK * 2 * (ADC0C[31:17] + 1) * (ADC0C[9:0] + 1)
+ * Ast2600:
+ * clock period = period of PCLK * 2 * (ADC0C[15:0] + 1)
  */
 
 #include <linux/clk.h>
@@ -77,6 +83,7 @@ struct aspeed_adc_data {
 	struct regulator	*regulator;
 	void __iomem		*base;
 	spinlock_t		clk_lock;
+	struct clk_hw		*fixed_div_clk;
 	struct clk_hw		*clk_prescaler;
 	struct clk_hw		*clk_scaler;
 	struct reset_control	*rst;
@@ -196,6 +203,13 @@ static void aspeed_adc_unregister_divider(void *data)
 	clk_hw_unregister_divider(clk);
 }
 
+static void aspeed_adc_unregister_fixed_divider(void *data)
+{
+	struct clk_hw *clk = data;
+
+	clk_hw_unregister_fixed_factor(clk);
+}
+
 static void aspeed_adc_reset_assert(void *data)
 {
 	struct reset_control *rst = data;
@@ -312,6 +326,18 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	/* Register ADC clock prescaler with source specified by device tree. */
 	spin_lock_init(&data->clk_lock);
 	snprintf(clk_parent_name, 32, of_clk_get_parent_name(pdev->dev.of_node, 0));
+	snprintf(clk_name, 32, "%s-fixed-div", data->model_data->model_name);
+	data->fixed_div_clk = clk_hw_register_fixed_factor(
+		&pdev->dev, clk_name, clk_parent_name, 0, 1, 2);
+	if (IS_ERR(data->fixed_div_clk))
+		return PTR_ERR(data->fixed_div_clk);
+
+	ret = devm_add_action_or_reset(data->dev,
+				       aspeed_adc_unregister_fixed_divider,
+				       data->clk_prescaler);
+	if (ret)
+		return ret;
+	snprintf(clk_parent_name, 32, clk_name);
 	if (data->model_data->need_prescaler) {
 		snprintf(clk_name, 32, "%s-prescaler",
 			 data->model_data->model_name);
-- 
2.25.1


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

* [RESEND v4 12/15] iio: adc: aspeed: Add func to set sampling rate.
  2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
                   ` (11 preceding siblings ...)
  2021-08-24  9:12 ` [RESEND v4 11/15] iio: adc: aspeed: Fix the calculate error of clock Billy Tsai
@ 2021-08-24  9:12 ` Billy Tsai
  2021-08-24  9:12 ` [RESEND v4 13/15] iio: adc: aspeed: Add compensation phase Billy Tsai
                   ` (8 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

Add the function to set the sampling rate and keep the sampling period
for a driver used to wait the lastest value.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
 drivers/iio/adc/aspeed_adc.c | 58 +++++++++++++++++++++++++-----------
 1 file changed, 40 insertions(+), 18 deletions(-)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 8fe7da1a651f..4d979dd7fe88 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -65,6 +65,12 @@
 
 #define ASPEED_ADC_INIT_POLLING_TIME	500
 #define ASPEED_ADC_INIT_TIMEOUT		500000
+/*
+ * When the sampling rate is too high, the ADC may not have enough charging
+ * time, resulting in a low voltage value. Thus, default use slow sampling
+ * rate for most user case.
+ */
+#define ASPEED_ADC_DEF_SAMPLING_RATE	65000
 
 struct aspeed_adc_model_data {
 	const char *model_name;
@@ -88,6 +94,7 @@ struct aspeed_adc_data {
 	struct clk_hw		*clk_scaler;
 	struct reset_control	*rst;
 	int			vref;
+	u32			sample_period_ns;
 };
 
 #define ASPEED_CHAN(_idx, _data_reg_addr) {			\
@@ -119,6 +126,24 @@ static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
 	ASPEED_CHAN(15, 0x2E),
 };
 
+static int aspeed_adc_set_sampling_rate(struct iio_dev *indio_dev, u32 rate)
+{
+	struct aspeed_adc_data *data = iio_priv(indio_dev);
+
+	if (rate < data->model_data->min_sampling_rate ||
+	    rate > data->model_data->max_sampling_rate)
+		return -EINVAL;
+	/* Each sampling needs 12 clocks to covert.*/
+	clk_set_rate(data->clk_scaler->clk, rate * ASPEED_CLOCKS_PER_SAMPLE);
+	rate = clk_get_rate(data->clk_scaler->clk);
+	data->sample_period_ns = DIV_ROUND_UP_ULL(
+		(u64)NSEC_PER_SEC * ASPEED_CLOCKS_PER_SAMPLE, rate);
+	dev_dbg(data->dev, "Adc clock = %d sample period = %d ns", rate,
+		data->sample_period_ns);
+
+	return 0;
+}
+
 static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
 			       struct iio_chan_spec const *chan,
 			       int *val, int *val2, long mask)
@@ -149,17 +174,10 @@ static int aspeed_adc_write_raw(struct iio_dev *indio_dev,
 				struct iio_chan_spec const *chan,
 				int val, int val2, long mask)
 {
-	struct aspeed_adc_data *data = iio_priv(indio_dev);
 
 	switch (mask) {
 	case IIO_CHAN_INFO_SAMP_FREQ:
-		if (val < data->model_data->min_sampling_rate ||
-			val > data->model_data->max_sampling_rate)
-			return -EINVAL;
-
-		clk_set_rate(data->clk_scaler->clk,
-				val * ASPEED_CLOCKS_PER_SAMPLE);
-		return 0;
+		return aspeed_adc_set_sampling_rate(indio_dev, val);
 
 	case IIO_CHAN_INFO_SCALE:
 	case IIO_CHAN_INFO_RAW:
@@ -386,6 +404,20 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	ret = clk_prepare_enable(data->clk_scaler->clk);
+	if (ret)
+		return ret;
+
+	ret = devm_add_action_or_reset(data->dev,
+				       aspeed_adc_clk_disable_unprepare,
+				       data->clk_scaler->clk);
+	if (ret)
+		return ret;
+
+	ret = aspeed_adc_set_sampling_rate(indio_dev, ASPEED_ADC_DEF_SAMPLING_RATE);
+	if (ret)
+		return ret;
+
 	ret = aspeed_adc_vref_config(indio_dev);
 	if (ret)
 		return ret;
@@ -413,16 +445,6 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	}
 
 	/* Start all channels in normal mode. */
-	ret = clk_prepare_enable(data->clk_scaler->clk);
-	if (ret)
-		return ret;
-
-	ret = devm_add_action_or_reset(data->dev,
-				       aspeed_adc_clk_disable_unprepare,
-				       data->clk_scaler->clk);
-	if (ret)
-		return ret;
-
 	adc_engine_control_reg_val =
 		readl(data->base + ASPEED_REG_ENGINE_CONTROL);
 	adc_engine_control_reg_val |=
-- 
2.25.1


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

* [RESEND v4 13/15] iio: adc: aspeed: Add compensation phase.
  2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
                   ` (12 preceding siblings ...)
  2021-08-24  9:12 ` [RESEND v4 12/15] iio: adc: aspeed: Add func to set sampling rate Billy Tsai
@ 2021-08-24  9:12 ` Billy Tsai
  2021-08-24  9:12 ` [RESEND v4 14/15] iio: adc: aspeed: Support battery sensing Billy Tsai
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

This patch adds a compensation phase to improve the accurate of ADC
measurement. This is the built-in function though input half of the
reference voltage to get the ADC offset.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
 drivers/iio/adc/aspeed_adc.c | 54 +++++++++++++++++++++++++++++++++++-
 1 file changed, 53 insertions(+), 1 deletion(-)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 4d979dd7fe88..20caf28dff18 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -95,6 +95,7 @@ struct aspeed_adc_data {
 	struct reset_control	*rst;
 	int			vref;
 	u32			sample_period_ns;
+	int			cv;
 };
 
 #define ASPEED_CHAN(_idx, _data_reg_addr) {			\
@@ -104,7 +105,8 @@ struct aspeed_adc_data {
 	.address = (_data_reg_addr),				\
 	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
 	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\
-				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
+				BIT(IIO_CHAN_INFO_SAMP_FREQ) |	\
+				BIT(IIO_CHAN_INFO_OFFSET),	\
 }
 
 static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
@@ -126,6 +128,51 @@ static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
 	ASPEED_CHAN(15, 0x2E),
 };
 
+static int aspeed_adc_compensation(struct iio_dev *indio_dev)
+{
+	struct aspeed_adc_data *data = iio_priv(indio_dev);
+	u32 index, adc_raw = 0;
+	u32 adc_engine_control_reg_val;
+
+	adc_engine_control_reg_val =
+		readl(data->base + ASPEED_REG_ENGINE_CONTROL);
+	adc_engine_control_reg_val &= ~ASPEED_ADC_OP_MODE;
+	adc_engine_control_reg_val |=
+		(FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_NORMAL) |
+		 ASPEED_ADC_ENGINE_ENABLE);
+	/*
+	 * Enable compensating sensing:
+	 * After that, the input voltage of ADC will force to half of the reference
+	 * voltage. So the expected reading raw data will become half of the max
+	 * value. We can get compensating value = 0x200 - ADC read raw value.
+	 * It is recommended to average at least 10 samples to get a final CV.
+	 */
+	writel(adc_engine_control_reg_val | ASPEED_ADC_CTRL_COMPENSATION |
+		       ASPEED_ADC_CTRL_CHANNEL_ENABLE(0),
+	       data->base + ASPEED_REG_ENGINE_CONTROL);
+	/*
+	 * After enable compensating sensing mode need to wait some time for ADC stable
+	 * Experiment result is 1ms.
+	 */
+	mdelay(1);
+
+	for (index = 0; index < 16; index++) {
+		/*
+		 * Waiting for the sampling period ensures that the value acquired
+		 * is fresh each time.
+		 */
+		ndelay(data->sample_period_ns);
+		adc_raw += readw(data->base + aspeed_adc_iio_channels[0].address);
+	}
+	adc_raw >>= 4;
+	data->cv = BIT(ASPEED_RESOLUTION_BITS - 1) - adc_raw;
+	writel(adc_engine_control_reg_val,
+	       data->base + ASPEED_REG_ENGINE_CONTROL);
+	dev_dbg(data->dev, "Compensating value = %d\n", data->cv);
+
+	return 0;
+}
+
 static int aspeed_adc_set_sampling_rate(struct iio_dev *indio_dev, u32 rate)
 {
 	struct aspeed_adc_data *data = iio_priv(indio_dev);
@@ -155,6 +202,10 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
 		*val = readw(data->base + chan->address);
 		return IIO_VAL_INT;
 
+	case IIO_CHAN_INFO_OFFSET:
+		*val = data->cv;
+		return IIO_VAL_INT;
+
 	case IIO_CHAN_INFO_SCALE:
 		*val = data->vref;
 		*val2 = ASPEED_RESOLUTION_BITS;
@@ -444,6 +495,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 			return ret;
 	}
 
+	aspeed_adc_compensation(indio_dev);
 	/* Start all channels in normal mode. */
 	adc_engine_control_reg_val =
 		readl(data->base + ASPEED_REG_ENGINE_CONTROL);
-- 
2.25.1


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

* [RESEND v4 14/15] iio: adc: aspeed: Support battery sensing.
  2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
                   ` (13 preceding siblings ...)
  2021-08-24  9:12 ` [RESEND v4 13/15] iio: adc: aspeed: Add compensation phase Billy Tsai
@ 2021-08-24  9:12 ` Billy Tsai
  2021-08-24  9:12 ` [RESEND v4 15/15] iio: adc: aspeed: Get and set trimming data Billy Tsai
                   ` (6 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

In ast2600, ADC integrate dividing circuit at last input channel for
battery sensing. This patch use the dts property "battery-sensing" to
enable this feature makes the last channel of each adc can tolerance
higher voltage than reference voltage.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
 drivers/iio/adc/aspeed_adc.c | 62 +++++++++++++++++++++++++++++++++---
 1 file changed, 57 insertions(+), 5 deletions(-)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 20caf28dff18..0c5d84e82561 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -79,10 +79,16 @@ struct aspeed_adc_model_data {
 	unsigned int vref_fixed;	// mV
 	bool wait_init_sequence;
 	bool need_prescaler;
+	bool bat_sense_sup;
 	u8 scaler_bit_width;
 	unsigned int num_channels;
 };
 
+struct adc_gain {
+	u8 mult;
+	u8 div;
+};
+
 struct aspeed_adc_data {
 	struct device		*dev;
 	const struct aspeed_adc_model_data *model_data;
@@ -96,6 +102,8 @@ struct aspeed_adc_data {
 	int			vref;
 	u32			sample_period_ns;
 	int			cv;
+	bool			battery_sensing;
+	struct adc_gain		battery_mode_gain;
 };
 
 #define ASPEED_CHAN(_idx, _data_reg_addr) {			\
@@ -103,10 +111,10 @@ struct aspeed_adc_data {
 	.indexed = 1,						\
 	.channel = (_idx),					\
 	.address = (_data_reg_addr),				\
-	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
-	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\
-				BIT(IIO_CHAN_INFO_SAMP_FREQ) |	\
+	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
 				BIT(IIO_CHAN_INFO_OFFSET),	\
+	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\
+				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
 }
 
 static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
@@ -196,14 +204,39 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
 			       int *val, int *val2, long mask)
 {
 	struct aspeed_adc_data *data = iio_priv(indio_dev);
+	u32 adc_engine_control_reg_val;
 
 	switch (mask) {
 	case IIO_CHAN_INFO_RAW:
-		*val = readw(data->base + chan->address);
+		if (data->battery_sensing && chan->channel == 7) {
+			adc_engine_control_reg_val =
+				readl(data->base + ASPEED_REG_ENGINE_CONTROL);
+			writel(adc_engine_control_reg_val |
+				       FIELD_PREP(ASPEED_ADC_CH7_MODE,
+						  ASPEED_ADC_CH7_BAT) |
+				       ASPEED_ADC_BAT_SENSING_ENABLE,
+			       data->base + ASPEED_REG_ENGINE_CONTROL);
+			/*
+			 * After enable battery sensing mode need to wait some time for adc stable
+			 * Experiment result is 1ms.
+			 */
+			mdelay(1);
+			*val = readw(data->base + chan->address);
+			*val = (*val * data->battery_mode_gain.mult) /
+			       data->battery_mode_gain.div;
+			/* Restore control register value */
+			writel(adc_engine_control_reg_val,
+			       data->base + ASPEED_REG_ENGINE_CONTROL);
+		} else
+			*val = readw(data->base + chan->address);
 		return IIO_VAL_INT;
 
 	case IIO_CHAN_INFO_OFFSET:
-		*val = data->cv;
+		if (data->battery_sensing && chan->channel == 7)
+			*val = (data->cv * data->battery_mode_gain.mult) /
+			       data->battery_mode_gain.div;
+		else
+			*val = data->cv;
 		return IIO_VAL_INT;
 
 	case IIO_CHAN_INFO_SCALE:
@@ -473,6 +506,23 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	if (of_find_property(data->dev->of_node, "aspeed,battery-sensing",
+			     NULL)) {
+		if (data->model_data->bat_sense_sup) {
+			data->battery_sensing = 1;
+			if (readl(data->base + ASPEED_REG_ENGINE_CONTROL) &
+			ASPEED_ADC_BAT_SENSING_DIV) {
+				data->battery_mode_gain.mult = 3;
+				data->battery_mode_gain.div = 1;
+			} else {
+				data->battery_mode_gain.mult = 3;
+				data->battery_mode_gain.div = 2;
+			}
+		} else
+			dev_warn(&pdev->dev,
+				"Failed to enable battey-sensing mode\n");
+	}
+
 	if (data->model_data->wait_init_sequence) {
 		adc_engine_control_reg_val =
 			readl(data->base + ASPEED_REG_ENGINE_CONTROL);
@@ -555,6 +605,7 @@ static const struct aspeed_adc_model_data ast2600_adc0_model_data = {
 	.min_sampling_rate = 10000,
 	.max_sampling_rate = 500000,
 	.wait_init_sequence = true,
+	.bat_sense_sup = true,
 	.scaler_bit_width = 16,
 	.num_channels = 8,
 };
@@ -564,6 +615,7 @@ static const struct aspeed_adc_model_data ast2600_adc1_model_data = {
 	.min_sampling_rate = 10000,
 	.max_sampling_rate = 500000,
 	.wait_init_sequence = true,
+	.bat_sense_sup = true,
 	.scaler_bit_width = 16,
 	.num_channels = 8,
 };
-- 
2.25.1


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

* [RESEND v4 15/15] iio: adc: aspeed: Get and set trimming data.
  2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
                   ` (14 preceding siblings ...)
  2021-08-24  9:12 ` [RESEND v4 14/15] iio: adc: aspeed: Support battery sensing Billy Tsai
@ 2021-08-24  9:12 ` Billy Tsai
       [not found] ` <202108250006.17P06IgG097015@twspam01.aspeedtech.com>
                   ` (5 subsequent siblings)
  21 siblings, 0 replies; 30+ messages in thread
From: Billy Tsai @ 2021-08-24  9:12 UTC (permalink / raw)
  To: jic23, lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood,
	broonie, linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel
  Cc: BMC-SW

The adc controller have trimming register for fine-tune the reference
voltage. The trimming value come from the otp register which will be
written before chip product. This patch will read this otp value and
configure it to the adc register when adc controller probe and using dts
property "aspeed,trim-data-valid" to determine whether to execute this
flow.

Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
---
 drivers/iio/adc/aspeed_adc.c | 68 ++++++++++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index 0c5d84e82561..bd7fb23f3510 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -25,6 +25,8 @@
 #include <linux/spinlock.h>
 #include <linux/types.h>
 #include <linux/bitfield.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
 
 #include <linux/iio/iio.h>
 #include <linux/iio/driver.h>
@@ -72,6 +74,11 @@
  */
 #define ASPEED_ADC_DEF_SAMPLING_RATE	65000
 
+struct aspeed_adc_trim_locate {
+	const unsigned int offset;
+	const unsigned int field;
+};
+
 struct aspeed_adc_model_data {
 	const char *model_name;
 	unsigned int min_sampling_rate;	// Hz
@@ -82,6 +89,7 @@ struct aspeed_adc_model_data {
 	bool bat_sense_sup;
 	u8 scaler_bit_width;
 	unsigned int num_channels;
+	const struct aspeed_adc_trim_locate *trim_locate;
 };
 
 struct adc_gain {
@@ -136,6 +144,44 @@ static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
 	ASPEED_CHAN(15, 0x2E),
 };
 
+static int aspeed_adc_set_trim_data(struct iio_dev *indio_dev)
+{
+	struct device_node *syscon;
+	struct regmap *scu;
+	u32 scu_otp, trimming_val;
+	struct aspeed_adc_data *data = iio_priv(indio_dev);
+
+	syscon = of_find_node_by_name(NULL, "syscon");
+	if (syscon == NULL) {
+		dev_warn(data->dev, "Couldn't find syscon node\n");
+		return -EOPNOTSUPP;
+	}
+	scu = syscon_node_to_regmap(syscon);
+	if (IS_ERR(scu)) {
+		dev_warn(data->dev, "Failed to get syscon regmap\n");
+		return -EOPNOTSUPP;
+	}
+	if (data->model_data->trim_locate) {
+		if (regmap_read(scu, data->model_data->trim_locate->offset,
+				&scu_otp)) {
+			dev_warn(data->dev,
+				 "Failed to get adc trimming data\n");
+			trimming_val = 0x8;
+		} else {
+			trimming_val =
+				((scu_otp) &
+				 (data->model_data->trim_locate->field)) >>
+				__ffs(data->model_data->trim_locate->field);
+		}
+		dev_dbg(data->dev,
+			"trimming val = %d, offset = %08x, fields = %08x\n",
+			trimming_val, data->model_data->trim_locate->offset,
+			data->model_data->trim_locate->field);
+		writel(trimming_val, data->base + ASPEED_REG_COMPENSATION_TRIM);
+	}
+	return 0;
+}
+
 static int aspeed_adc_compensation(struct iio_dev *indio_dev)
 {
 	struct aspeed_adc_data *data = iio_priv(indio_dev);
@@ -506,6 +552,10 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	if (of_find_property(data->dev->of_node, "aspeed,trim-data-valid",
+			     NULL))
+		aspeed_adc_set_trim_data(indio_dev);
+
 	if (of_find_property(data->dev->of_node, "aspeed,battery-sensing",
 			     NULL)) {
 		if (data->model_data->bat_sense_sup) {
@@ -579,6 +629,21 @@ static int aspeed_adc_remove(struct platform_device *pdev)
 	return 0;
 }
 
+static const struct aspeed_adc_trim_locate ast2500_adc_trim = {
+	.offset = 0x154,
+	.field = GENMASK(31, 28),
+};
+
+static const struct aspeed_adc_trim_locate ast2600_adc0_trim = {
+	.offset = 0x5d0,
+	.field = GENMASK(3, 0),
+};
+
+static const struct aspeed_adc_trim_locate ast2600_adc1_trim = {
+	.offset = 0x5d0,
+	.field = GENMASK(7, 4),
+};
+
 static const struct aspeed_adc_model_data ast2400_model_data = {
 	.model_name = "ast2400-adc",
 	.vref_fixed = 2500, // mV
@@ -598,6 +663,7 @@ static const struct aspeed_adc_model_data ast2500_model_data = {
 	.need_prescaler = true,
 	.scaler_bit_width = 10,
 	.num_channels = 16,
+	.trim_locate = &ast2500_adc_trim,
 };
 
 static const struct aspeed_adc_model_data ast2600_adc0_model_data = {
@@ -608,6 +674,7 @@ static const struct aspeed_adc_model_data ast2600_adc0_model_data = {
 	.bat_sense_sup = true,
 	.scaler_bit_width = 16,
 	.num_channels = 8,
+	.trim_locate = &ast2600_adc0_trim,
 };
 
 static const struct aspeed_adc_model_data ast2600_adc1_model_data = {
@@ -618,6 +685,7 @@ static const struct aspeed_adc_model_data ast2600_adc1_model_data = {
 	.bat_sense_sup = true,
 	.scaler_bit_width = 16,
 	.num_channels = 8,
+	.trim_locate = &ast2600_adc1_trim,
 };
 
 static const struct of_device_id aspeed_adc_matches[] = {
-- 
2.25.1


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

* Re: [RESEND v4 02/15] iio: adc: aspeed: completes the bitfield declare.
  2021-08-24  9:12 ` [RESEND v4 02/15] iio: adc: aspeed: completes the bitfield declare Billy Tsai
@ 2021-08-29 15:07   ` Jonathan Cameron
  0 siblings, 0 replies; 30+ messages in thread
From: Jonathan Cameron @ 2021-08-29 15:07 UTC (permalink / raw)
  To: Billy Tsai
  Cc: lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood, broonie,
	linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel, BMC-SW

On Tue, 24 Aug 2021 17:12:30 +0800
Billy Tsai <billy_tsai@aspeedtech.com> wrote:

> This patch completes the declare of adc register bitfields and uses the
> same prefix ASPEED_ADC_* for these bitfields.
> 
> Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
> ---
>  drivers/iio/adc/aspeed_adc.c | 56 +++++++++++++++++++++++++-----------
>  1 file changed, 39 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
> index 19efaa41bc34..7010d56ac3b9 100644
> --- a/drivers/iio/adc/aspeed_adc.c
> +++ b/drivers/iio/adc/aspeed_adc.c
> @@ -3,6 +3,7 @@
>   * Aspeed AST2400/2500 ADC
>   *
>   * Copyright (C) 2017 Google, Inc.
> + * Copyright (C) 2021 Aspeed Technology Inc.
>   */
>  
>  #include <linux/clk.h>
> @@ -16,6 +17,7 @@
>  #include <linux/reset.h>
>  #include <linux/spinlock.h>
>  #include <linux/types.h>
> +#include <linux/bitfield.h>
>  
>  #include <linux/iio/iio.h>
>  #include <linux/iio/driver.h>
> @@ -28,15 +30,31 @@
>  #define ASPEED_REG_INTERRUPT_CONTROL	0x04
>  #define ASPEED_REG_VGA_DETECT_CONTROL	0x08
>  #define ASPEED_REG_CLOCK_CONTROL	0x0C
> -#define ASPEED_REG_MAX			0xC0
> -
> -#define ASPEED_OPERATION_MODE_POWER_DOWN	(0x0 << 1)
> -#define ASPEED_OPERATION_MODE_STANDBY		(0x1 << 1)
> -#define ASPEED_OPERATION_MODE_NORMAL		(0x7 << 1)
> -
> -#define ASPEED_ENGINE_ENABLE		BIT(0)
> -
> -#define ASPEED_ADC_CTRL_INIT_RDY	BIT(8)
> +#define ASPEED_REG_COMPENSATION_TRIM	0xC4
> +#define ASPEED_REG_MAX			0xCC

This REG_MAX value is used as a sanity check for debugfs based access.
As this raises the limit for all devices supported by the driver, not just the
new ast2600, are we fine to read these non existent registers on the other
parts?  If so, perhaps a comment to say that here somewhere?

> +
> +#define ASPEED_ADC_ENGINE_ENABLE		BIT(0)

Are all the following in the same register?  Bit usual to have
overlapping fields, so if they are, perhaps a few comments to
explain what is going on would be good.

> +#define ASPEED_ADC_OP_MODE			GENMASK(3, 1)
> +#define ASPEED_ADC_OP_MODE_PWR_DOWN		0
> +#define ASPEED_ADC_OP_MODE_STANDBY		1
> +#define ASPEED_ADC_OP_MODE_NORMAL		7
> +#define ASPEED_ADC_CTRL_COMPENSATION		BIT(4)
> +#define ASPEED_ADC_AUTO_COMPENSATION		BIT(5)
> +#define ASPEED_ADC_REF_VOLTAGE			GENMASK(7, 6)
> +#define ASPEED_ADC_REF_VOLTAGE_2500mV		0
> +#define ASPEED_ADC_REF_VOLTAGE_1200mV		1
> +#define ASPEED_ADC_REF_VOLTAGE_EXT_HIGH		2
> +#define ASPEED_ADC_REF_VOLTAGE_EXT_LOW		3
> +#define ASPEED_ADC_BAT_SENSING_DIV		BIT(6)
> +#define ASPEED_ADC_BAT_SENSING_DIV_2_3		0
> +#define ASPEED_ADC_BAT_SENSING_DIV_1_3		1
> +#define ASPEED_ADC_CTRL_INIT_RDY		BIT(8)
> +#define ASPEED_ADC_CH7_MODE			BIT(12)
> +#define ASPEED_ADC_CH7_NORMAL			0
> +#define ASPEED_ADC_CH7_BAT			1
> +#define ASPEED_ADC_BAT_SENSING_ENABLE		BIT(13)
> +#define ASPEED_ADC_CTRL_CHANNEL			GENMASK(31, 16)
> +#define ASPEED_ADC_CTRL_CHANNEL_ENABLE(ch)	FIELD_PREP(ASPEED_ADC_CTRL_CHANNEL, BIT(ch))
>  
>  #define ASPEED_ADC_INIT_POLLING_TIME	500
>  #define ASPEED_ADC_INIT_TIMEOUT		500000
> @@ -226,7 +244,9 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  
>  	if (model_data->wait_init_sequence) {
>  		/* Enable engine in normal mode. */
> -		writel(ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE,
> +		writel(FIELD_PREP(ASPEED_ADC_OP_MODE,
> +				  ASPEED_ADC_OP_MODE_NORMAL) |
> +			       ASPEED_ADC_ENGINE_ENABLE,
>  		       data->base + ASPEED_REG_ENGINE_CONTROL);
>  
>  		/* Wait for initial sequence complete. */
> @@ -245,10 +265,12 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  	if (ret)
>  		goto clk_enable_error;
>  
> -	adc_engine_control_reg_val = GENMASK(31, 16) |
> -		ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE;
> +	adc_engine_control_reg_val =
> +		ASPEED_ADC_CTRL_CHANNEL |
> +		FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_NORMAL) |
> +		ASPEED_ADC_ENGINE_ENABLE;
>  	writel(adc_engine_control_reg_val,
> -		data->base + ASPEED_REG_ENGINE_CONTROL);
> +	       data->base + ASPEED_REG_ENGINE_CONTROL);
>  
>  	model_data = of_device_get_match_data(&pdev->dev);
>  	indio_dev->name = model_data->model_name;
> @@ -264,8 +286,8 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  	return 0;
>  
>  iio_register_error:
> -	writel(ASPEED_OPERATION_MODE_POWER_DOWN,
> -		data->base + ASPEED_REG_ENGINE_CONTROL);
> +	writel(FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_PWR_DOWN),
> +	       data->base + ASPEED_REG_ENGINE_CONTROL);
>  	clk_disable_unprepare(data->clk_scaler->clk);
>  clk_enable_error:
>  poll_timeout_error:
> @@ -283,8 +305,8 @@ static int aspeed_adc_remove(struct platform_device *pdev)
>  	struct aspeed_adc_data *data = iio_priv(indio_dev);
>  
>  	iio_device_unregister(indio_dev);
> -	writel(ASPEED_OPERATION_MODE_POWER_DOWN,
> -		data->base + ASPEED_REG_ENGINE_CONTROL);
> +	writel(FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_PWR_DOWN),
> +	       data->base + ASPEED_REG_ENGINE_CONTROL);

Ideally these white space changes would be in a precursor patch.
At the very least mention them in the patch description.  They are good
thing to tidy up, but they do add noise to this patch.

>  	clk_disable_unprepare(data->clk_scaler->clk);
>  	reset_control_assert(data->rst);
>  	clk_hw_unregister_divider(data->clk_scaler);


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

* Re: [RESEND v4 03/15] iio: adc: aspeed: set driver data when adc probe.
  2021-08-24  9:12 ` [RESEND v4 03/15] iio: adc: aspeed: set driver data when adc probe Billy Tsai
@ 2021-08-29 15:08   ` Jonathan Cameron
  0 siblings, 0 replies; 30+ messages in thread
From: Jonathan Cameron @ 2021-08-29 15:08 UTC (permalink / raw)
  To: Billy Tsai
  Cc: lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood, broonie,
	linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel, BMC-SW

On Tue, 24 Aug 2021 17:12:31 +0800
Billy Tsai <billy_tsai@aspeedtech.com> wrote:

> Fix the issue when adc remove will get the null driver data.
> 
> Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>

This is a fix that we should probably backport.  Please add a fixes tag and move
it to the start of the series so I can pick it during this kernel
cycle rather than waiting for the next one.

Thanks,

Jonathan

> ---
>  drivers/iio/adc/aspeed_adc.c | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
> index 7010d56ac3b9..20462cf659e4 100644
> --- a/drivers/iio/adc/aspeed_adc.c
> +++ b/drivers/iio/adc/aspeed_adc.c
> @@ -201,6 +201,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  
>  	data = iio_priv(indio_dev);
>  	data->dev = &pdev->dev;
> +	platform_set_drvdata(pdev, indio_dev);
>  
>  	data->base = devm_platform_ioremap_resource(pdev, 0);
>  	if (IS_ERR(data->base))


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

* Re: [RESEND v4 05/15] iio: adc: aspeed: Refactory model data structure
  2021-08-24  9:12 ` [RESEND v4 05/15] iio: adc: aspeed: Refactory model data structure Billy Tsai
@ 2021-08-29 15:13   ` Jonathan Cameron
  0 siblings, 0 replies; 30+ messages in thread
From: Jonathan Cameron @ 2021-08-29 15:13 UTC (permalink / raw)
  To: Billy Tsai
  Cc: lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood, broonie,
	linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel, BMC-SW

On Tue, 24 Aug 2021 17:12:33 +0800
Billy Tsai <billy_tsai@aspeedtech.com> wrote:

> This patch refactory the model data structure to distinguish the
> function form differnet version of aspeed adc.

from different versions 

> - Rename the vref_voltag to vref_fixed and add vref driver data

vref_voltage

> When driver probe will check vref_fixed value and store it
> to vref which isn't const value.
> - Add num_channels
> Make num_channles of iio device can be changed by differnet model_data

different

> - Add need_prescaler flag and scaler_bit_width
> The need_prescaler flag used to tell the driver the clock divider needs
> another prescaler and the scaler_bit_width to set the clock divider
> bitfiled width.

bitfield?

> 
> Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
> ---
>  drivers/iio/adc/aspeed_adc.c | 18 ++++++++++++++----
>  1 file changed, 14 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
> index d85aa31ee3b1..f03c7921d534 100644
> --- a/drivers/iio/adc/aspeed_adc.c
> +++ b/drivers/iio/adc/aspeed_adc.c
> @@ -63,8 +63,11 @@ struct aspeed_adc_model_data {
>  	const char *model_name;
>  	unsigned int min_sampling_rate;	// Hz
>  	unsigned int max_sampling_rate;	// Hz
> -	unsigned int vref_voltage;	// mV
> +	unsigned int vref_fixed;	// mV

Whilst here, you could make the name carry the information of the units.
e.g. vref_fixed_mv;  That way we always know what the units are without having
to spot this comment.

>  	bool wait_init_sequence;
> +	bool need_prescaler;
> +	u8 scaler_bit_width;
> +	unsigned int num_channels;
>  };
>  
>  struct aspeed_adc_data {
> @@ -75,6 +78,7 @@ struct aspeed_adc_data {
>  	struct clk_hw		*clk_prescaler;
>  	struct clk_hw		*clk_scaler;
>  	struct reset_control	*rst;
> +	int			vref;
vref_mv as above perhaps?
>  };
>  
>  #define ASPEED_CHAN(_idx, _data_reg_addr) {			\
> @@ -118,7 +122,7 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
>  		return IIO_VAL_INT;
>  
>  	case IIO_CHAN_INFO_SCALE:
> -		*val = data->model_data->vref_voltage;
> +		*val = data->model_data->vref_fixed;
>  		*val2 = ASPEED_RESOLUTION_BITS;
>  		return IIO_VAL_FRACTIONAL_LOG2;
>  
> @@ -312,17 +316,23 @@ static int aspeed_adc_remove(struct platform_device *pdev)
>  
>  static const struct aspeed_adc_model_data ast2400_model_data = {
>  	.model_name = "ast2400-adc",
> -	.vref_voltage = 2500, // mV
> +	.vref_fixed = 2500, // mV
>  	.min_sampling_rate = 10000,
>  	.max_sampling_rate = 500000,
> +	.need_prescaler = true,
> +	.scaler_bit_width = 10,
> +	.num_channels = 16,
>  };
>  
>  static const struct aspeed_adc_model_data ast2500_model_data = {
>  	.model_name = "ast2500-adc",
> -	.vref_voltage = 1800, // mV
> +	.vref_fixed = 1800, // mV
>  	.min_sampling_rate = 1,
>  	.max_sampling_rate = 1000000,
>  	.wait_init_sequence = true,
> +	.need_prescaler = true,
> +	.scaler_bit_width = 10,
> +	.num_channels = 16,
>  };
>  
>  static const struct of_device_id aspeed_adc_matches[] = {


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

* Re: [RESEND v4 08/15] iio: adc: aspeed: Use model_data to set clk scaler.
       [not found] ` <202108250006.17P06IgG097015@twspam01.aspeedtech.com>
@ 2021-08-29 15:20   ` Jonathan Cameron
  0 siblings, 0 replies; 30+ messages in thread
From: Jonathan Cameron @ 2021-08-29 15:20 UTC (permalink / raw)
  To: Billy Tsai
  Cc: lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood, broonie,
	linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel, BMC-SW

On Tue, 24 Aug 2021 17:12:36 +0800
Billy Tsai <billy_tsai@aspeedtech.com> wrote:

> This patch use need_prescaler and scaler_bit_width to set the adc clock
> scaler.
> 
> Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
Hi Billy,

One minor comment inline.

Thanks,

Jonathan

> ---
>  drivers/iio/adc/aspeed_adc.c | 39 +++++++++++++++++++++---------------
>  1 file changed, 23 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
> index 2d6215a91f99..52db38be9699 100644
> --- a/drivers/iio/adc/aspeed_adc.c
> +++ b/drivers/iio/adc/aspeed_adc.c
> @@ -202,9 +202,10 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  {
>  	struct iio_dev *indio_dev;
>  	struct aspeed_adc_data *data;
> -	const char *clk_parent_name;
>  	int ret;
>  	u32 adc_engine_control_reg_val;
> +	unsigned long scaler_flags = 0;
> +	char clk_name[32], clk_parent_name[32];
>  
>  	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data));
>  	if (!indio_dev)
> @@ -221,24 +222,28 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  
>  	/* Register ADC clock prescaler with source specified by device tree. */
>  	spin_lock_init(&data->clk_lock);
> -	clk_parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
> -
> -	data->clk_prescaler = clk_hw_register_divider(
> -				&pdev->dev, "prescaler", clk_parent_name, 0,
> -				data->base + ASPEED_REG_CLOCK_CONTROL,
> -				17, 15, 0, &data->clk_lock);
> -	if (IS_ERR(data->clk_prescaler))
> -		return PTR_ERR(data->clk_prescaler);
> -
> +	snprintf(clk_parent_name, 32, of_clk_get_parent_name(pdev->dev.of_node, 0));

ARRAY_SIZE(clk_parent_name) instead of 32.
Same for other places this pattern occurs.


> +	if (data->model_data->need_prescaler) {
> +		snprintf(clk_name, 32, "%s-prescaler",
> +			 data->model_data->model_name);
> +		data->clk_prescaler = clk_hw_register_divider(
> +			&pdev->dev, clk_name, clk_parent_name, 0,
> +			data->base + ASPEED_REG_CLOCK_CONTROL, 17, 15, 0,
> +			&data->clk_lock);
> +		if (IS_ERR(data->clk_prescaler))
> +			return PTR_ERR(data->clk_prescaler);
> +		snprintf(clk_parent_name, 32, clk_name);
> +		scaler_flags = CLK_SET_RATE_PARENT;
> +	}
>  	/*
>  	 * Register ADC clock scaler downstream from the prescaler. Allow rate
>  	 * setting to adjust the prescaler as well.
>  	 */
> +	snprintf(clk_name, 32, "%s-scaler", data->model_data->model_name);
>  	data->clk_scaler = clk_hw_register_divider(
> -				&pdev->dev, "scaler", "prescaler",
> -				CLK_SET_RATE_PARENT,
> -				data->base + ASPEED_REG_CLOCK_CONTROL,
> -				0, 10, 0, &data->clk_lock);
> +		&pdev->dev, clk_name, clk_parent_name, scaler_flags,
> +		data->base + ASPEED_REG_CLOCK_CONTROL, 0,
> +		data->model_data->scaler_bit_width, 0, &data->clk_lock);
>  	if (IS_ERR(data->clk_scaler)) {
>  		ret = PTR_ERR(data->clk_scaler);
>  		goto scaler_error;
> @@ -310,7 +315,8 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  reset_error:
>  	clk_hw_unregister_divider(data->clk_scaler);
>  scaler_error:
> -	clk_hw_unregister_divider(data->clk_prescaler);
> +	if (data->model_data->need_prescaler)
> +		clk_hw_unregister_divider(data->clk_prescaler);
>  	return ret;
>  }
>  
> @@ -325,7 +331,8 @@ static int aspeed_adc_remove(struct platform_device *pdev)
>  	clk_disable_unprepare(data->clk_scaler->clk);
>  	reset_control_assert(data->rst);
>  	clk_hw_unregister_divider(data->clk_scaler);
> -	clk_hw_unregister_divider(data->clk_prescaler);
> +	if (data->model_data->need_prescaler)
> +		clk_hw_unregister_divider(data->clk_prescaler);
>  
>  	return 0;
>  }


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

* Re: [RESEND v4 09/15] iio: adc: aspeed: Use devm_add_action_or_reset.
       [not found] ` <202108250004.17P04FdD094082@twspam01.aspeedtech.com>
@ 2021-08-29 15:25   ` Jonathan Cameron
  0 siblings, 0 replies; 30+ messages in thread
From: Jonathan Cameron @ 2021-08-29 15:25 UTC (permalink / raw)
  To: Billy Tsai
  Cc: lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood, broonie,
	linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel, BMC-SW

On Tue, 24 Aug 2021 17:12:37 +0800
Billy Tsai <billy_tsai@aspeedtech.com> wrote:

> This patch use devm_add_action_or_reset to handle the error in probe
> phase.
> 
> Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
> ---
>  drivers/iio/adc/aspeed_adc.c | 92 +++++++++++++++++++++---------------
>  1 file changed, 55 insertions(+), 37 deletions(-)
> 
> diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
> index 52db38be9699..1c87e12a0cab 100644
> --- a/drivers/iio/adc/aspeed_adc.c
> +++ b/drivers/iio/adc/aspeed_adc.c
> @@ -187,6 +187,27 @@ static const struct iio_info aspeed_adc_iio_info = {
>  	.debugfs_reg_access = aspeed_adc_reg_access,
>  };
>  
> +static void aspeed_adc_unregister_divider(void *data)
> +{
> +	struct clk_hw *clk = data;
> +
> +	clk_hw_unregister_divider(clk);
> +}
> +
> +static void aspeed_adc_reset_assert(void *data)
> +{
> +	struct reset_control *rst = data;
> +
> +	reset_control_assert(rst);
> +}
> +
> +static void aspeed_adc_clk_disable_unprepare(void *data)
> +{
> +	struct clk *clk = data;
> +
> +	clk_disable_unprepare(clk);
> +}
> +
>  static int aspeed_adc_vref_config(struct iio_dev *indio_dev)
>  {
>  	struct aspeed_adc_data *data = iio_priv(indio_dev);
> @@ -232,6 +253,12 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  			&data->clk_lock);
>  		if (IS_ERR(data->clk_prescaler))
>  			return PTR_ERR(data->clk_prescaler);
> +
> +		ret = devm_add_action_or_reset(data->dev,
> +					       aspeed_adc_unregister_divider,
> +					       data->clk_prescaler);
> +		if (ret)
> +			return ret;
>  		snprintf(clk_parent_name, 32, clk_name);
>  		scaler_flags = CLK_SET_RATE_PARENT;
>  	}
> @@ -244,23 +271,30 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  		&pdev->dev, clk_name, clk_parent_name, scaler_flags,
>  		data->base + ASPEED_REG_CLOCK_CONTROL, 0,
>  		data->model_data->scaler_bit_width, 0, &data->clk_lock);
> -	if (IS_ERR(data->clk_scaler)) {
> -		ret = PTR_ERR(data->clk_scaler);
> -		goto scaler_error;
> -	}
> +	if (IS_ERR(data->clk_scaler))
> +		return PTR_ERR(data->clk_scaler);
> +
> +	ret = devm_add_action_or_reset(data->dev, aspeed_adc_unregister_divider,
> +				       data->clk_scaler);
> +	if (ret)
> +		return ret;
>  
>  	data->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
>  	if (IS_ERR(data->rst)) {
>  		dev_err(&pdev->dev,
>  			"invalid or missing reset controller device tree entry");
> -		ret = PTR_ERR(data->rst);
> -		goto reset_error;
> +		return PTR_ERR(data->rst);
>  	}
>  	reset_control_deassert(data->rst);
>  
> +	ret = devm_add_action_or_reset(data->dev, aspeed_adc_reset_assert,
> +				       data->rst);
> +	if (ret)
> +		return ret;
> +
>  	ret = aspeed_adc_vref_config(indio_dev);
>  	if (ret)
> -		goto vref_config_error;
> +		return ret;
>  
>  	if (data->model_data->wait_init_sequence) {
>  		/* Enable engine in normal mode. */
> @@ -277,13 +311,19 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  					 ASPEED_ADC_INIT_POLLING_TIME,
>  					 ASPEED_ADC_INIT_TIMEOUT);
>  		if (ret)
> -			goto poll_timeout_error;
> +			return ret;
>  	}
>  
>  	/* Start all channels in normal mode. */
>  	ret = clk_prepare_enable(data->clk_scaler->clk);
>  	if (ret)
> -		goto clk_enable_error;
> +		return ret;
> +
> +	ret = devm_add_action_or_reset(data->dev,
> +				       aspeed_adc_clk_disable_unprepare,
> +				       data->clk_scaler->clk);
> +	if (ret)
> +		return ret;
>  
>  	adc_engine_control_reg_val =
>  		ASPEED_ADC_CTRL_CHANNEL |
> @@ -299,41 +339,19 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  	indio_dev->num_channels = data->model_data->num_channels;
>  
>  	ret = iio_device_register(indio_dev);
> -	if (ret)
> -		goto iio_register_error;
> -
> +	if (ret) {
> +		writel(FIELD_PREP(ASPEED_ADC_OP_MODE,
> +				  ASPEED_ADC_OP_MODE_PWR_DOWN),
> +		       data->base + ASPEED_REG_ENGINE_CONTROL);
> +		return ret;
> +	}
>  	return 0;
> -
> -iio_register_error:
> -	writel(FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_PWR_DOWN),
> -	       data->base + ASPEED_REG_ENGINE_CONTROL);
> -	clk_disable_unprepare(data->clk_scaler->clk);
> -clk_enable_error:
> -poll_timeout_error:
> -vref_config_error:
> -	reset_control_assert(data->rst);
> -reset_error:
> -	clk_hw_unregister_divider(data->clk_scaler);
> -scaler_error:
> -	if (data->model_data->need_prescaler)
> -		clk_hw_unregister_divider(data->clk_prescaler);
> -	return ret;
>  }
>  
>  static int aspeed_adc_remove(struct platform_device *pdev)
>  {
>  	struct iio_dev *indio_dev = platform_get_drvdata(pdev);
> -	struct aspeed_adc_data *data = iio_priv(indio_dev);
> -
>  	iio_device_unregister(indio_dev);

Given there is no longer anything here, you should be safe to call
devm_iio_device_unregister() and get rid of this function entirely.


> -	writel(FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_PWR_DOWN),
> -	       data->base + ASPEED_REG_ENGINE_CONTROL);

Unless I'm missing something this is not handled via any of the
devm_add_action_or_reset() callbacks. You handle it in the error paths manually
but if you move this to managed as well you can drop that handling and still
have it automatically called on remove.


> -	clk_disable_unprepare(data->clk_scaler->clk);
> -	reset_control_assert(data->rst);
> -	clk_hw_unregister_divider(data->clk_scaler);
> -	if (data->model_data->need_prescaler)
> -		clk_hw_unregister_divider(data->clk_prescaler);
> -
>  	return 0;
>  }
>  


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

* Re: [RESEND v4 10/15] iio: adc: aspeed: Support ast2600 adc.
  2021-08-24  9:12 ` [RESEND v4 10/15] iio: adc: aspeed: Support ast2600 adc Billy Tsai
@ 2021-08-29 15:31   ` Jonathan Cameron
  0 siblings, 0 replies; 30+ messages in thread
From: Jonathan Cameron @ 2021-08-29 15:31 UTC (permalink / raw)
  To: Billy Tsai
  Cc: lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood, broonie,
	linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel, BMC-SW

On Tue, 24 Aug 2021 17:12:38 +0800
Billy Tsai <billy_tsai@aspeedtech.com> wrote:

> Make driver to support ast2600 adc device.
> - Use shared reset controller
> - Complete the vref configure function
> - Add the model data for ast2600 adc
> 
> Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
Hi Billy,

A few minor things inline,

Jonathan

> ---
>  drivers/iio/adc/aspeed_adc.c | 106 +++++++++++++++++++++++++++++++++--
>  1 file changed, 100 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
> index 1c87e12a0cab..ea3e9a52fcc9 100644
> --- a/drivers/iio/adc/aspeed_adc.c
> +++ b/drivers/iio/adc/aspeed_adc.c
> @@ -1,6 +1,6 @@
>  // SPDX-License-Identifier: GPL-2.0-only
>  /*
> - * Aspeed AST2400/2500 ADC
> + * Aspeed AST2400/2500/2600 ADC
>   *
>   * Copyright (C) 2017 Google, Inc.
>   * Copyright (C) 2021 Aspeed Technology Inc.
> @@ -14,6 +14,7 @@
>  #include <linux/module.h>
>  #include <linux/of_platform.h>
>  #include <linux/platform_device.h>
> +#include <linux/regulator/consumer.h>
>  #include <linux/reset.h>
>  #include <linux/spinlock.h>
>  #include <linux/types.h>
> @@ -73,6 +74,7 @@ struct aspeed_adc_model_data {
>  struct aspeed_adc_data {
>  	struct device		*dev;
>  	const struct aspeed_adc_model_data *model_data;
> +	struct regulator	*regulator;
>  	void __iomem		*base;
>  	spinlock_t		clk_lock;
>  	struct clk_hw		*clk_prescaler;
> @@ -208,14 +210,80 @@ static void aspeed_adc_clk_disable_unprepare(void *data)
>  	clk_disable_unprepare(clk);
>  }
>  
> +static void aspeed_adc_reg_disable(void *data)
> +{
> +	struct regulator *reg = data;
> +
> +	regulator_disable(reg);
> +}
> +
>  static int aspeed_adc_vref_config(struct iio_dev *indio_dev)
>  {
>  	struct aspeed_adc_data *data = iio_priv(indio_dev);
> +	int ret;
> +	u32 adc_engine_control_reg_val =
> +		readl(data->base + ASPEED_REG_ENGINE_CONTROL);

Given you aren't going to use this if vref_fixed is set, move the read
until after that.

>  
>  	if (data->model_data->vref_fixed) {
>  		data->vref = data->model_data->vref_fixed;
>  		return 0;
>  	}
> +
> +	data->regulator = devm_regulator_get_optional(data->dev, "vref");
> +	if (!IS_ERR(data->regulator)) {
> +		ret = regulator_enable(data->regulator);
> +		if (ret)
> +			return ret;
> +		ret = devm_add_action_or_reset(
> +			data->dev, aspeed_adc_reg_disable, data->regulator);
> +		if (ret)
> +			return ret;
> +		data->vref = regulator_get_voltage(data->regulator);
> +		/* Conversion from uV to mV */
> +		data->vref /= 1000;
> +		if ((data->vref >= 1550) && (data->vref <= 2700))
> +			writel(adc_engine_control_reg_val |
> +				       FIELD_PREP(
> +					       ASPEED_ADC_REF_VOLTAGE,
> +					       ASPEED_ADC_REF_VOLTAGE_EXT_HIGH),
> +			       data->base + ASPEED_REG_ENGINE_CONTROL);
> +		else if ((data->vref >= 900) && (data->vref <= 1650))
> +			writel(adc_engine_control_reg_val |
> +				       FIELD_PREP(
> +					       ASPEED_ADC_REF_VOLTAGE,
> +					       ASPEED_ADC_REF_VOLTAGE_EXT_LOW),
> +			       data->base + ASPEED_REG_ENGINE_CONTROL);
> +		else {
> +			dev_err(data->dev, "Regulator voltage %d not support",
> +				data->vref);
> +			return -EOPNOTSUPP;
> +		}
> +	} else {
> +		if (PTR_ERR(data->regulator) != -ENODEV)
> +			return PTR_ERR(data->regulator);
> +		ret = of_property_read_u32(data->dev->of_node,
> +					   "aspeed,int_vref_mv", &data->vref);
> +		if (ret < 0) {
> +			dev_warn(data->dev,
> +				 "Using default vref: internal 2500 mv");

Perhaps document that as default in the dt-binding, then you can remove this warning and
handle this as:

		data->vref = 2500;
		of_property_read_u32(data->dev->of_node,
				     "aspeed,int-vref-mvolts", &data->vref);
etc

> +			data->vref = 2500;
> +		}
> +		if (data->vref == 2500)
> +			writel(adc_engine_control_reg_val |
> +				       FIELD_PREP(ASPEED_ADC_REF_VOLTAGE,
> +						  ASPEED_ADC	writel(adc_engine_control_reg_val,
		data->base + ASPEED_REG_ENGINE_CONTROL);_REF_VOLTAGE_2500mV),
> +			       data->base + ASPEED_REG_ENGINE_CONTROL);
> +		else if (data->vref == 1200)
> +			writel(adc_engine_control_reg_val |
> +				       FIELD_PREP(ASPEED_ADC_REF_VOLTAGE,
> +						  ASPEED_ADC_REF_VOLTAGE_1200mV),
> +			       data->base + ASPEED_REG_ENGINE_CONTROL);
> +		else {
> +			dev_err(data->dev, "Voltage %d not support", data->vref);
> +			return -EOPNOTSUPP;
> +		}
> +	}
> +
>  	return 0;
>  }
>  
> @@ -279,7 +347,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  	if (ret)
>  		return ret;
>  
> -	data->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
> +	data->rst = devm_reset_control_get_shared(&pdev->dev, NULL);
>  	if (IS_ERR(data->rst)) {
>  		dev_err(&pdev->dev,
>  			"invalid or missing reset controller device tree entry");
> @@ -297,10 +365,14 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  		return ret;
>  
>  	if (data->model_data->wait_init_sequence) {
> +		adc_engine_control_reg_val =
> +			readl(data->base + ASPEED_REG_ENGINE_CONTROL);
> +		adc_engine_control_reg_val |=
> +			FIELD_PREP(ASPEED_ADC_OP_MODE,
> +				   ASPEED_ADC_OP_MODE_NORMAL) |
> +			ASPEED_ADC_ENGINE_ENABLE;
>  		/* Enable engine in normal mode. */
> -		writel(FIELD_PREP(ASPEED_ADC_OP_MODE,
> -				  ASPEED_ADC_OP_MODE_NORMAL) |
> -			       ASPEED_ADC_ENGINE_ENABLE,
> +		writel(adc_engine_control_reg_val,
>  		       data->base + ASPEED_REG_ENGINE_CONTROL);
>  
>  		/* Wait for initial sequence complete. */
> @@ -326,6 +398,8 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  		return ret;
>  
>  	adc_engine_control_reg_val =
> +		readl(data->base + ASPEED_REG_ENGINE_CONTROL);
> +	adc_engine_control_reg_val |=
>  		ASPEED_ADC_CTRL_CHANNEL |
>  		FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_NORMAL) |
>  		ASPEED_ADC_ENGINE_ENABLE;
> @@ -376,9 +450,29 @@ static const struct aspeed_adc_model_data ast2500_model_data = {
>  	.num_channels = 16,
>  };
>  
> +static const struct aspeed_adc_model_data ast2600_adc0_model_data = {
> +	.model_name = "ast2600-adc0",
> +	.min_sampling_rate = 10000,
> +	.max_sampling_rate = 500000,
> +	.wait_init_sequence = true,
> +	.scaler_bit_width = 16,
> +	.num_channels = 8,
> +};
> +
> +static const struct aspeed_adc_model_data ast2600_adc1_model_data = {
> +	.model_name = "ast2600-adc1",
> +	.min_sampling_rate = 10000,
> +	.max_sampling_rate = 500000,
> +	.wait_init_sequence = true,
> +	.scaler_bit_width = 16,
> +	.num_channels = 8,
> +};
> +
>  static const struct of_device_id aspeed_adc_matches[] = {
>  	{ .compatible = "aspeed,ast2400-adc", .data = &ast2400_model_data },
>  	{ .compatible = "aspeed,ast2500-adc", .data = &ast2500_model_data },
> +	{ .compatible = "aspeed,ast2600-adc0", .data = &ast2600_adc0_model_data },
> +	{ .compatible = "aspeed,ast2600-adc1", .data = &ast2600_adc1_model_data },
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, aspeed_adc_matches);
> @@ -395,5 +489,5 @@ static struct platform_driver aspeed_adc_driver = {
>  module_platform_driver(aspeed_adc_driver);
>  
>  MODULE_AUTHOR("Rick Altherr <raltherr@google.com>");
> -MODULE_DESCRIPTION("Aspeed AST2400/2500 ADC Driver");
> +MODULE_DESCRIPTION("Aspeed AST2400/2500/2600 ADC Driver");
>  MODULE_LICENSE("GPL");


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

* Re: [RESEND v4 11/15] iio: adc: aspeed: Fix the calculate error of clock.
  2021-08-24  9:12 ` [RESEND v4 11/15] iio: adc: aspeed: Fix the calculate error of clock Billy Tsai
@ 2021-08-29 15:33   ` Jonathan Cameron
  0 siblings, 0 replies; 30+ messages in thread
From: Jonathan Cameron @ 2021-08-29 15:33 UTC (permalink / raw)
  To: Billy Tsai
  Cc: lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood, broonie,
	linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel, BMC-SW

On Tue, 24 Aug 2021 17:12:39 +0800
Billy Tsai <billy_tsai@aspeedtech.com> wrote:

> The adc clcok formula is

clock

> ast2400/2500:
> ADC clock period = PCLK * 2 * (ADC0C[31:17] + 1) * (ADC0C[9:0] + 1)
> ast2600:
> ADC clock period = PCLK * 2 * (ADC0C[15:0] + 1)
> They all have one fixed divided 2 and the legacy driver didn't handle it.
> This patch register the fixed factory clock device as the parent of adc
> clock scaler to fix this issue.

What are the impacts of this being wrong before?  Is this something we
should look to backport?

Comment inline.
> 
> Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
> ---
>  drivers/iio/adc/aspeed_adc.c | 26 ++++++++++++++++++++++++++
>  1 file changed, 26 insertions(+)
> 
> diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
> index ea3e9a52fcc9..8fe7da1a651f 100644
> --- a/drivers/iio/adc/aspeed_adc.c
> +++ b/drivers/iio/adc/aspeed_adc.c
> @@ -4,6 +4,12 @@
>   *
>   * Copyright (C) 2017 Google, Inc.
>   * Copyright (C) 2021 Aspeed Technology Inc.
> + *
> + * ADC clock formula:
> + * Ast2400/Ast2500:
> + * clock period = period of PCLK * 2 * (ADC0C[31:17] + 1) * (ADC0C[9:0] + 1)
> + * Ast2600:
> + * clock period = period of PCLK * 2 * (ADC0C[15:0] + 1)
>   */
>  
>  #include <linux/clk.h>
> @@ -77,6 +83,7 @@ struct aspeed_adc_data {
>  	struct regulator	*regulator;
>  	void __iomem		*base;
>  	spinlock_t		clk_lock;
> +	struct clk_hw		*fixed_div_clk;
>  	struct clk_hw		*clk_prescaler;
>  	struct clk_hw		*clk_scaler;
>  	struct reset_control	*rst;
> @@ -196,6 +203,13 @@ static void aspeed_adc_unregister_divider(void *data)
>  	clk_hw_unregister_divider(clk);
>  }
>  
> +static void aspeed_adc_unregister_fixed_divider(void *data)
> +{
> +	struct clk_hw *clk = data;
> +
> +	clk_hw_unregister_fixed_factor(clk);
> +}
> +
>  static void aspeed_adc_reset_assert(void *data)
>  {
>  	struct reset_control *rst = data;
> @@ -312,6 +326,18 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  	/* Register ADC clock prescaler with source specified by device tree. */
>  	spin_lock_init(&data->clk_lock);
>  	snprintf(clk_parent_name, 32, of_clk_get_parent_name(pdev->dev.of_node, 0));
> +	snprintf(clk_name, 32, "%s-fixed-div", data->model_data->model_name);

ARRAY_SIZE

> +	data->fixed_div_clk = clk_hw_register_fixed_factor(
> +		&pdev->dev, clk_name, clk_parent_name, 0, 1, 2);
> +	if (IS_ERR(data->fixed_div_clk))
> +		return PTR_ERR(data->fixed_div_clk);
> +
> +	ret = devm_add_action_or_reset(data->dev,
> +				       aspeed_adc_unregister_fixed_divider,
> +				       data->clk_prescaler);
> +	if (ret)
> +		return ret;
> +	snprintf(clk_parent_name, 32, clk_name);
>  	if (data->model_data->need_prescaler) {
>  		snprintf(clk_name, 32, "%s-prescaler",
>  			 data->model_data->model_name);


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

* Re: [RESEND v4 12/15] iio: adc: aspeed: Add func to set sampling rate.
       [not found] ` <202108250003.17P03KRU092474@twspam01.aspeedtech.com>
@ 2021-08-29 15:36   ` Jonathan Cameron
  2021-08-30  8:35     ` Billy Tsai
  0 siblings, 1 reply; 30+ messages in thread
From: Jonathan Cameron @ 2021-08-29 15:36 UTC (permalink / raw)
  To: Billy Tsai
  Cc: lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood, broonie,
	linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel, BMC-SW

On Tue, 24 Aug 2021 17:12:40 +0800
Billy Tsai <billy_tsai@aspeedtech.com> wrote:

> Add the function to set the sampling rate and keep the sampling period
> for a driver used to wait the lastest value.
> 
> Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>

Why move the code as well as factoring out the setter function?
I doubt it does any harm, but I'd like to understand why you did it.

Jonathan


> ---
>  drivers/iio/adc/aspeed_adc.c | 58 +++++++++++++++++++++++++-----------
>  1 file changed, 40 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
> index 8fe7da1a651f..4d979dd7fe88 100644
> --- a/drivers/iio/adc/aspeed_adc.c
> +++ b/drivers/iio/adc/aspeed_adc.c
> @@ -65,6 +65,12 @@
>  
>  #define ASPEED_ADC_INIT_POLLING_TIME	500
>  #define ASPEED_ADC_INIT_TIMEOUT		500000
> +/*
> + * When the sampling rate is too high, the ADC may not have enough charging
> + * time, resulting in a low voltage value. Thus, default use slow sampling
> + * rate for most user case.
> + */
> +#define ASPEED_ADC_DEF_SAMPLING_RATE	65000
>  
>  struct aspeed_adc_model_data {
>  	const char *model_name;
> @@ -88,6 +94,7 @@ struct aspeed_adc_data {
>  	struct clk_hw		*clk_scaler;
>  	struct reset_control	*rst;
>  	int			vref;
> +	u32			sample_period_ns;
>  };
>  
>  #define ASPEED_CHAN(_idx, _data_reg_addr) {			\
> @@ -119,6 +126,24 @@ static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
>  	ASPEED_CHAN(15, 0x2E),
>  };
>  
> +static int aspeed_adc_set_sampling_rate(struct iio_dev *indio_dev, u32 rate)
> +{
> +	struct aspeed_adc_data *data = iio_priv(indio_dev);
> +
> +	if (rate < data->model_data->min_sampling_rate ||
> +	    rate > data->model_data->max_sampling_rate)
> +		return -EINVAL;
> +	/* Each sampling needs 12 clocks to covert.*/

convert.  Please run a spell checker over these patches.

> +	clk_set_rate(data->clk_scaler->clk, rate * ASPEED_CLOCKS_PER_SAMPLE);
> +	rate = clk_get_rate(data->clk_scaler->clk);
> +	data->sample_period_ns = DIV_ROUND_UP_ULL(
> +		(u64)NSEC_PER_SEC * ASPEED_CLOCKS_PER_SAMPLE, rate);
> +	dev_dbg(data->dev, "Adc clock = %d sample period = %d ns", rate,
> +		data->sample_period_ns);
> +
> +	return 0;
> +}
> +
>  static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
>  			       struct iio_chan_spec const *chan,
>  			       int *val, int *val2, long mask)
> @@ -149,17 +174,10 @@ static int aspeed_adc_write_raw(struct iio_dev *indio_dev,
>  				struct iio_chan_spec const *chan,
>  				int val, int val2, long mask)
>  {
> -	struct aspeed_adc_data *data = iio_priv(indio_dev);
>  
>  	switch (mask) {
>  	case IIO_CHAN_INFO_SAMP_FREQ:
> -		if (val < data->model_data->min_sampling_rate ||
> -			val > data->model_data->max_sampling_rate)
> -			return -EINVAL;
> -
> -		clk_set_rate(data->clk_scaler->clk,
> -				val * ASPEED_CLOCKS_PER_SAMPLE);
> -		return 0;
> +		return aspeed_adc_set_sampling_rate(indio_dev, val);
>  
>  	case IIO_CHAN_INFO_SCALE:
>  	case IIO_CHAN_INFO_RAW:
> @@ -386,6 +404,20 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  	if (ret)
>  		return ret;
>  
> +	ret = clk_prepare_enable(data->clk_scaler->clk);
> +	if (ret)
> +		return ret;
> +
> +	ret = devm_add_action_or_reset(data->dev,
> +				       aspeed_adc_clk_disable_unprepare,
> +				       data->clk_scaler->clk);
> +	if (ret)
> +		return ret;
> +
> +	ret = aspeed_adc_set_sampling_rate(indio_dev, ASPEED_ADC_DEF_SAMPLING_RATE);
> +	if (ret)
> +		return ret;
> +
>  	ret = aspeed_adc_vref_config(indio_dev);
>  	if (ret)
>  		return ret;
> @@ -413,16 +445,6 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  	}
>  
>  	/* Start all channels in normal mode. */

Why move this code up?

> -	ret = clk_prepare_enable(data->clk_scaler->clk);
> -	if (ret)
> -		return ret;
> -
> -	ret = devm_add_action_or_reset(data->dev,
> -				       aspeed_adc_clk_disable_unprepare,
> -				       data->clk_scaler->clk);
> -	if (ret)
> -		return ret;
> -
>  	adc_engine_control_reg_val =
>  		readl(data->base + ASPEED_REG_ENGINE_CONTROL);
>  	adc_engine_control_reg_val |=


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

* Re: [RESEND v4 13/15] iio: adc: aspeed: Add compensation phase.
       [not found] ` <202108250006.17P066YP096721@twspam01.aspeedtech.com>
@ 2021-08-29 15:39   ` Jonathan Cameron
  0 siblings, 0 replies; 30+ messages in thread
From: Jonathan Cameron @ 2021-08-29 15:39 UTC (permalink / raw)
  To: Billy Tsai
  Cc: lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood, broonie,
	linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel, BMC-SW

On Tue, 24 Aug 2021 17:12:41 +0800
Billy Tsai <billy_tsai@aspeedtech.com> wrote:

> This patch adds a compensation phase to improve the accurate of ADC

accuracy of the ADC measurement.

> measurement. This is the built-in function though input half of the
> reference voltage to get the ADC offset.
> 
> Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
This looks like fairly standard calibration which is good to have.

Thanks,

Jonathan

> ---
>  drivers/iio/adc/aspeed_adc.c | 54 +++++++++++++++++++++++++++++++++++-
>  1 file changed, 53 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
> index 4d979dd7fe88..20caf28dff18 100644
> --- a/drivers/iio/adc/aspeed_adc.c
> +++ b/drivers/iio/adc/aspeed_adc.c
> @@ -95,6 +95,7 @@ struct aspeed_adc_data {
>  	struct reset_control	*rst;
>  	int			vref;
>  	u32			sample_period_ns;
> +	int			cv;
>  };
>  
>  #define ASPEED_CHAN(_idx, _data_reg_addr) {			\
> @@ -104,7 +105,8 @@ struct aspeed_adc_data {
>  	.address = (_data_reg_addr),				\
>  	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
>  	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\
> -				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
> +				BIT(IIO_CHAN_INFO_SAMP_FREQ) |	\
> +				BIT(IIO_CHAN_INFO_OFFSET),	\
>  }
>  
>  static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
> @@ -126,6 +128,51 @@ static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
>  	ASPEED_CHAN(15, 0x2E),
>  };
>  
> +static int aspeed_adc_compensation(struct iio_dev *indio_dev)
> +{
> +	struct aspeed_adc_data *data = iio_priv(indio_dev);
> +	u32 index, adc_raw = 0;
> +	u32 adc_engine_control_reg_val;
> +
> +	adc_engine_control_reg_val =
> +		readl(data->base + ASPEED_REG_ENGINE_CONTROL);
> +	adc_engine_control_reg_val &= ~ASPEED_ADC_OP_MODE;
> +	adc_engine_control_reg_val |=
> +		(FIELD_PREP(ASPEED_ADC_OP_MODE, ASPEED_ADC_OP_MODE_NORMAL) |
> +		 ASPEED_ADC_ENGINE_ENABLE);
> +	/*
> +	 * Enable compensating sensing:
> +	 * After that, the input voltage of ADC will force to half of the reference
> +	 * voltage. So the expected reading raw data will become half of the max
> +	 * value. We can get compensating value = 0x200 - ADC read raw value.
> +	 * It is recommended to average at least 10 samples to get a final CV.
> +	 */
> +	writel(adc_engine_control_reg_val | ASPEED_ADC_CTRL_COMPENSATION |
> +		       ASPEED_ADC_CTRL_CHANNEL_ENABLE(0),
> +	       data->base + ASPEED_REG_ENGINE_CONTROL);
> +	/*
> +	 * After enable compensating sensing mode need to wait some time for ADC stable
> +	 * Experiment result is 1ms.
> +	 */
> +	mdelay(1);
> +
> +	for (index = 0; index < 16; index++) {
> +		/*
> +		 * Waiting for the sampling period ensures that the value acquired
> +		 * is fresh each time.
> +		 */
> +		ndelay(data->sample_period_ns);
> +		adc_raw += readw(data->base + aspeed_adc_iio_channels[0].address);
> +	}
> +	adc_raw >>= 4;
> +	data->cv = BIT(ASPEED_RESOLUTION_BITS - 1) - adc_raw;
> +	writel(adc_engine_control_reg_val,
> +	       data->base + ASPEED_REG_ENGINE_CONTROL);
> +	dev_dbg(data->dev, "Compensating value = %d\n", data->cv);
> +
> +	return 0;
> +}
> +
>  static int aspeed_adc_set_sampling_rate(struct iio_dev *indio_dev, u32 rate)
>  {
>  	struct aspeed_adc_data *data = iio_priv(indio_dev);
> @@ -155,6 +202,10 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
>  		*val = readw(data->base + chan->address);
>  		return IIO_VAL_INT;
>  
> +	case IIO_CHAN_INFO_OFFSET:
> +		*val = data->cv;
> +		return IIO_VAL_INT;
> +
>  	case IIO_CHAN_INFO_SCALE:
>  		*val = data->vref;
>  		*val2 = ASPEED_RESOLUTION_BITS;
> @@ -444,6 +495,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  			return ret;
>  	}
>  
> +	aspeed_adc_compensation(indio_dev);
>  	/* Start all channels in normal mode. */
>  	adc_engine_control_reg_val =
>  		readl(data->base + ASPEED_REG_ENGINE_CONTROL);


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

* Re: [RESEND v4 14/15] iio: adc: aspeed: Support battery sensing.
       [not found] ` <202108250005.17P05agj096445@twspam01.aspeedtech.com>
@ 2021-08-29 15:43   ` Jonathan Cameron
  0 siblings, 0 replies; 30+ messages in thread
From: Jonathan Cameron @ 2021-08-29 15:43 UTC (permalink / raw)
  To: Billy Tsai
  Cc: lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood, broonie,
	linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel, BMC-SW

On Tue, 24 Aug 2021 17:12:42 +0800
Billy Tsai <billy_tsai@aspeedtech.com> wrote:

> In ast2600, ADC integrate dividing circuit at last input channel for
> battery sensing. This patch use the dts property "battery-sensing" to
> enable this feature makes the last channel of each adc can tolerance
> higher voltage than reference voltage.
> 
> Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>

The slight issue here is this  changes the userspace
ABI for the older parts.   Whilst a per channel offset is perfectly valid
it's still an ABI change and someone might be relying on a dodgy script
that uses it.

So, whilst it's a pain you should have two different chan_spec arrays and pick
between them dependent on model of device.  That way you can leave the
old ABI untouched and add this control for the ast2600 only.

> ---
>  drivers/iio/adc/aspeed_adc.c | 62 +++++++++++++++++++++++++++++++++---
>  1 file changed, 57 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
> index 20caf28dff18..0c5d84e82561 100644
> --- a/drivers/iio/adc/aspeed_adc.c
> +++ b/drivers/iio/adc/aspeed_adc.c
> @@ -79,10 +79,16 @@ struct aspeed_adc_model_data {
>  	unsigned int vref_fixed;	// mV
>  	bool wait_init_sequence;
>  	bool need_prescaler;
> +	bool bat_sense_sup;
>  	u8 scaler_bit_width;
>  	unsigned int num_channels;
>  };
>  
> +struct adc_gain {
> +	u8 mult;
> +	u8 div;
> +};
> +
>  struct aspeed_adc_data {
>  	struct device		*dev;
>  	const struct aspeed_adc_model_data *model_data;
> @@ -96,6 +102,8 @@ struct aspeed_adc_data {
>  	int			vref;
>  	u32			sample_period_ns;
>  	int			cv;
> +	bool			battery_sensing;
> +	struct adc_gain		battery_mode_gain;
>  };
>  
>  #define ASPEED_CHAN(_idx, _data_reg_addr) {			\
> @@ -103,10 +111,10 @@ struct aspeed_adc_data {
>  	.indexed = 1,						\
>  	.channel = (_idx),					\
>  	.address = (_data_reg_addr),				\
> -	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),		\
> -	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\
> -				BIT(IIO_CHAN_INFO_SAMP_FREQ) |	\
> +	.info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |		\
>  				BIT(IIO_CHAN_INFO_OFFSET),	\
> +	.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |	\
> +				BIT(IIO_CHAN_INFO_SAMP_FREQ),	\
>  }
>  
>  static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
> @@ -196,14 +204,39 @@ static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
>  			       int *val, int *val2, long mask)
>  {
>  	struct aspeed_adc_data *data = iio_priv(indio_dev);
> +	u32 adc_engine_control_reg_val;
>  
>  	switch (mask) {
>  	case IIO_CHAN_INFO_RAW:
> -		*val = readw(data->base + chan->address);
> +		if (data->battery_sensing && chan->channel == 7) {
> +			adc_engine_control_reg_val =
> +				readl(data->base + ASPEED_REG_ENGINE_CONTROL);
> +			writel(adc_engine_control_reg_val |
> +				       FIELD_PREP(ASPEED_ADC_CH7_MODE,
> +						  ASPEED_ADC_CH7_BAT) |
> +				       ASPEED_ADC_BAT_SENSING_ENABLE,
> +			       data->base + ASPEED_REG_ENGINE_CONTROL);
> +			/*
> +			 * After enable battery sensing mode need to wait some time for adc stable
> +			 * Experiment result is 1ms.
> +			 */
> +			mdelay(1);
> +			*val = readw(data->base + chan->address);
> +			*val = (*val * data->battery_mode_gain.mult) /
> +			       data->battery_mode_gain.div;
> +			/* Restore control register value */
> +			writel(adc_engine_control_reg_val,
> +			       data->base + ASPEED_REG_ENGINE_CONTROL);
> +		} else
> +			*val = readw(data->base + chan->address);
>  		return IIO_VAL_INT;
>  
>  	case IIO_CHAN_INFO_OFFSET:
> -		*val = data->cv;
> +		if (data->battery_sensing && chan->channel == 7)
> +			*val = (data->cv * data->battery_mode_gain.mult) /
> +			       data->battery_mode_gain.div;
> +		else
> +			*val = data->cv;
>  		return IIO_VAL_INT;
>  
>  	case IIO_CHAN_INFO_SCALE:
> @@ -473,6 +506,23 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  	if (ret)
>  		return ret;
>  
> +	if (of_find_property(data->dev->of_node, "aspeed,battery-sensing",
> +			     NULL)) {
> +		if (data->model_data->bat_sense_sup) {
> +			data->battery_sensing = 1;
> +			if (readl(data->base + ASPEED_REG_ENGINE_CONTROL) &
> +			ASPEED_ADC_BAT_SENSING_DIV) {
> +				data->battery_mode_gain.mult = 3;
> +				data->battery_mode_gain.div = 1;
> +			} else {
> +				data->battery_mode_gain.mult = 3;
> +				data->battery_mode_gain.div = 2;
> +			}
> +		} else
> +			dev_warn(&pdev->dev,
> +				"Failed to enable battey-sensing mode\n");
> +	}
> +
>  	if (data->model_data->wait_init_sequence) {
>  		adc_engine_control_reg_val =
>  			readl(data->base + ASPEED_REG_ENGINE_CONTROL);
> @@ -555,6 +605,7 @@ static const struct aspeed_adc_model_data ast2600_adc0_model_data = {
>  	.min_sampling_rate = 10000,
>  	.max_sampling_rate = 500000,
>  	.wait_init_sequence = true,
> +	.bat_sense_sup = true,
>  	.scaler_bit_width = 16,
>  	.num_channels = 8,
>  };
> @@ -564,6 +615,7 @@ static const struct aspeed_adc_model_data ast2600_adc1_model_data = {
>  	.min_sampling_rate = 10000,
>  	.max_sampling_rate = 500000,
>  	.wait_init_sequence = true,
> +	.bat_sense_sup = true,
>  	.scaler_bit_width = 16,
>  	.num_channels = 8,
>  };


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

* Re: [RESEND v4 15/15] iio: adc: aspeed: Get and set trimming data.
       [not found] ` <202108250007.17P07NFj097422@twspam01.aspeedtech.com>
@ 2021-08-29 15:45   ` Jonathan Cameron
  0 siblings, 0 replies; 30+ messages in thread
From: Jonathan Cameron @ 2021-08-29 15:45 UTC (permalink / raw)
  To: Billy Tsai
  Cc: lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood, broonie,
	linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel, BMC-SW

On Tue, 24 Aug 2021 17:12:43 +0800
Billy Tsai <billy_tsai@aspeedtech.com> wrote:

> The adc controller have trimming register for fine-tune the reference

Nice to have ADC instead of adc (though not that important as meaning is clear).

> voltage. The trimming value come from the otp register which will be
> written before chip product. This patch will read this otp value and

written during chip production? (perhaps that's what is intended?)

> configure it to the adc register when adc controller probe and using dts
> property "aspeed,trim-data-valid" to determine whether to execute this
> flow.
> 
> Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>
> ---
>  drivers/iio/adc/aspeed_adc.c | 68 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 68 insertions(+)
> 
> diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
> index 0c5d84e82561..bd7fb23f3510 100644
> --- a/drivers/iio/adc/aspeed_adc.c
> +++ b/drivers/iio/adc/aspeed_adc.c
> @@ -25,6 +25,8 @@
>  #include <linux/spinlock.h>
>  #include <linux/types.h>
>  #include <linux/bitfield.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
>  
>  #include <linux/iio/iio.h>
>  #include <linux/iio/driver.h>
> @@ -72,6 +74,11 @@
>   */
>  #define ASPEED_ADC_DEF_SAMPLING_RATE	65000
>  
> +struct aspeed_adc_trim_locate {
> +	const unsigned int offset;
> +	const unsigned int field;
> +};
> +
>  struct aspeed_adc_model_data {
>  	const char *model_name;
>  	unsigned int min_sampling_rate;	// Hz
> @@ -82,6 +89,7 @@ struct aspeed_adc_model_data {
>  	bool bat_sense_sup;
>  	u8 scaler_bit_width;
>  	unsigned int num_channels;
> +	const struct aspeed_adc_trim_locate *trim_locate;
>  };
>  
>  struct adc_gain {
> @@ -136,6 +144,44 @@ static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
>  	ASPEED_CHAN(15, 0x2E),
>  };
>  
> +static int aspeed_adc_set_trim_data(struct iio_dev *indio_dev)
> +{
> +	struct device_node *syscon;
> +	struct regmap *scu;
> +	u32 scu_otp, trimming_val;
> +	struct aspeed_adc_data *data = iio_priv(indio_dev);
> +
> +	syscon = of_find_node_by_name(NULL, "syscon");
> +	if (syscon == NULL) {
> +		dev_warn(data->dev, "Couldn't find syscon node\n");
> +		return -EOPNOTSUPP;
> +	}
> +	scu = syscon_node_to_regmap(syscon);
> +	if (IS_ERR(scu)) {
> +		dev_warn(data->dev, "Failed to get syscon regmap\n");
> +		return -EOPNOTSUPP;
> +	}
> +	if (data->model_data->trim_locate) {
> +		if (regmap_read(scu, data->model_data->trim_locate->offset,
> +				&scu_otp)) {
> +			dev_warn(data->dev,
> +				 "Failed to get adc trimming data\n");
> +			trimming_val = 0x8;
> +		} else {
> +			trimming_val =
> +				((scu_otp) &
> +				 (data->model_data->trim_locate->field)) >>
> +				__ffs(data->model_data->trim_locate->field);
> +		}
> +		dev_dbg(data->dev,
> +			"trimming val = %d, offset = %08x, fields = %08x\n",
> +			trimming_val, data->model_data->trim_locate->offset,
> +			data->model_data->trim_locate->field);
> +		writel(trimming_val, data->base + ASPEED_REG_COMPENSATION_TRIM);
> +	}
> +	return 0;
> +}
> +
>  static int aspeed_adc_compensation(struct iio_dev *indio_dev)
>  {
>  	struct aspeed_adc_data *data = iio_priv(indio_dev);
> @@ -506,6 +552,10 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>  	if (ret)
>  		return ret;
>  
> +	if (of_find_property(data->dev->of_node, "aspeed,trim-data-valid",
> +			     NULL))
> +		aspeed_adc_set_trim_data(indio_dev);
> +
>  	if (of_find_property(data->dev->of_node, "aspeed,battery-sensing",
>  			     NULL)) {
>  		if (data->model_data->bat_sense_sup) {
> @@ -579,6 +629,21 @@ static int aspeed_adc_remove(struct platform_device *pdev)
>  	return 0;
>  }
>  
> +static const struct aspeed_adc_trim_locate ast2500_adc_trim = {
> +	.offset = 0x154,
> +	.field = GENMASK(31, 28),
> +};
> +
> +static const struct aspeed_adc_trim_locate ast2600_adc0_trim = {
> +	.offset = 0x5d0,
> +	.field = GENMASK(3, 0),
> +};
> +
> +static const struct aspeed_adc_trim_locate ast2600_adc1_trim = {
> +	.offset = 0x5d0,
> +	.field = GENMASK(7, 4),
> +};
> +
>  static const struct aspeed_adc_model_data ast2400_model_data = {
>  	.model_name = "ast2400-adc",
>  	.vref_fixed = 2500, // mV
> @@ -598,6 +663,7 @@ static const struct aspeed_adc_model_data ast2500_model_data = {
>  	.need_prescaler = true,
>  	.scaler_bit_width = 10,
>  	.num_channels = 16,
> +	.trim_locate = &ast2500_adc_trim,
>  };
>  
>  static const struct aspeed_adc_model_data ast2600_adc0_model_data = {
> @@ -608,6 +674,7 @@ static const struct aspeed_adc_model_data ast2600_adc0_model_data = {
>  	.bat_sense_sup = true,
>  	.scaler_bit_width = 16,
>  	.num_channels = 8,
> +	.trim_locate = &ast2600_adc0_trim,
>  };
>  
>  static const struct aspeed_adc_model_data ast2600_adc1_model_data = {
> @@ -618,6 +685,7 @@ static const struct aspeed_adc_model_data ast2600_adc1_model_data = {
>  	.bat_sense_sup = true,
>  	.scaler_bit_width = 16,
>  	.num_channels = 8,
> +	.trim_locate = &ast2600_adc1_trim,
>  };
>  
>  static const struct of_device_id aspeed_adc_matches[] = {


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

* Re: [RESEND v4 12/15] iio: adc: aspeed: Add func to set sampling rate.
  2021-08-29 15:36   ` [RESEND v4 12/15] iio: adc: aspeed: Add func to set sampling rate Jonathan Cameron
@ 2021-08-30  8:35     ` Billy Tsai
  2021-08-30  9:52       ` Jonathan Cameron
  0 siblings, 1 reply; 30+ messages in thread
From: Billy Tsai @ 2021-08-30  8:35 UTC (permalink / raw)
  To: Jonathan Cameron
  Cc: lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood, broonie,
	linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel, BMC-SW

Hi Jonathan,

On 2021/8/29, 11:33 PM, "Jonathan Cameron" <jic23@kernel.org> wrote:

    On Tue, 24 Aug 2021 17:12:40 +0800
    Billy Tsai <billy_tsai@aspeedtech.com> wrote:

    >> Add the function to set the sampling rate and keep the sampling period
    >> for a driver used to wait the lastest value.
    >> 
    >> Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>

    > Why move the code as well as factoring out the setter function?
    > I doubt it does any harm, but I'd like to understand why you did it.

    > Jonathan

    >> +	ret = clk_prepare_enable(data->clk_scaler->clk);
    >> +	if (ret)
    >> +		return ret;
    >> +
    >> +	ret = devm_add_action_or_reset(data->dev,
    >> +				       aspeed_adc_clk_disable_unprepare,
    >> +				       data->clk_scaler->clk);
    >> +	if (ret)
    >> +		return ret;
    >> +
    >> +	ret = aspeed_adc_set_sampling_rate(indio_dev, ASPEED_ADC_DEF_SAMPLING_RATE);
    >> +	if (ret)
    >> +		return ret;
    >> +
    >>  	ret = aspeed_adc_vref_config(indio_dev);
    >>  	if (ret)
    >>  		return ret;
    >> @@ -413,16 +445,6 @@ static int aspeed_adc_probe(struct platform_device *pdev)
    >>  	}
    >>  
    >>  	/* Start all channels in normal mode. */

    > Why move this code up?

Because the ADC clock is required when initializing the ADC device.
In our system, the clock is always on. Thus, the legacy driver won't encounter any issues.
I move the clk_prepare_enable ahead of initializing phase for making the driver probe logically closer to the hardware. 

    >> -	ret = clk_prepare_enable(data->clk_scaler->clk);
    >> -	if (ret)
    >> -		return ret;
    >> -
    >> -	ret = devm_add_action_or_reset(data->dev,
    >> -				       aspeed_adc_clk_disable_unprepare,
    >> -				       data->clk_scaler->clk);
    >> -	if (ret)
    >> -		return ret;
    >> -
    >>  	adc_engine_control_reg_val =
    >>  		readl(data->base + ASPEED_REG_ENGINE_CONTROL);
    >>  	adc_engine_control_reg_val |=


Best Regards,
Billy Tsai


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

* Re: [RESEND v4 12/15] iio: adc: aspeed: Add func to set sampling rate.
  2021-08-30  8:35     ` Billy Tsai
@ 2021-08-30  9:52       ` Jonathan Cameron
  0 siblings, 0 replies; 30+ messages in thread
From: Jonathan Cameron @ 2021-08-30  9:52 UTC (permalink / raw)
  To: Billy Tsai
  Cc: lars, pmeerw, robh+dt, joel, andrew, p.zabel, lgirdwood, broonie,
	linux-iio, devicetree, linux-arm-kernel, linux-aspeed,
	linux-kernel, BMC-SW

On Mon, 30 Aug 2021 08:35:53 +0000
Billy Tsai <billy_tsai@aspeedtech.com> wrote:

> Hi Jonathan,
> 
> On 2021/8/29, 11:33 PM, "Jonathan Cameron" <jic23@kernel.org> wrote:
> 
>     On Tue, 24 Aug 2021 17:12:40 +0800
>     Billy Tsai <billy_tsai@aspeedtech.com> wrote:
> 
>     >> Add the function to set the sampling rate and keep the sampling period
>     >> for a driver used to wait the lastest value.
>     >> 
>     >> Signed-off-by: Billy Tsai <billy_tsai@aspeedtech.com>  
> 
>     > Why move the code as well as factoring out the setter function?
>     > I doubt it does any harm, but I'd like to understand why you did it.  
> 
>     > Jonathan  
> 
>     >> +	ret = clk_prepare_enable(data->clk_scaler->clk);
>     >> +	if (ret)
>     >> +		return ret;
>     >> +
>     >> +	ret = devm_add_action_or_reset(data->dev,
>     >> +				       aspeed_adc_clk_disable_unprepare,
>     >> +				       data->clk_scaler->clk);
>     >> +	if (ret)
>     >> +		return ret;
>     >> +
>     >> +	ret = aspeed_adc_set_sampling_rate(indio_dev, ASPEED_ADC_DEF_SAMPLING_RATE);
>     >> +	if (ret)
>     >> +		return ret;
>     >> +
>     >>  	ret = aspeed_adc_vref_config(indio_dev);
>     >>  	if (ret)
>     >>  		return ret;
>     >> @@ -413,16 +445,6 @@ static int aspeed_adc_probe(struct platform_device *pdev)
>     >>  	}
>     >>  
>     >>  	/* Start all channels in normal mode. */  
> 
>     > Why move this code up?  
> 
> Because the ADC clock is required when initializing the ADC device.
> In our system, the clock is always on. Thus, the legacy driver won't encounter any issues.
> I move the clk_prepare_enable ahead of initializing phase for making the driver probe logically closer to the hardware. 

Thanks. Please add something to the patch description to say this.

Jonathan

> 
>     >> -	ret = clk_prepare_enable(data->clk_scaler->clk);
>     >> -	if (ret)
>     >> -		return ret;
>     >> -
>     >> -	ret = devm_add_action_or_reset(data->dev,
>     >> -				       aspeed_adc_clk_disable_unprepare,
>     >> -				       data->clk_scaler->clk);
>     >> -	if (ret)
>     >> -		return ret;
>     >> -
>     >>  	adc_engine_control_reg_val =
>     >>  		readl(data->base + ASPEED_REG_ENGINE_CONTROL);
>     >>  	adc_engine_control_reg_val |=  
> 
> 
> Best Regards,
> Billy Tsai
> 


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

end of thread, other threads:[~2021-08-30  9:49 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-08-24  9:12 [RESEND v4 00/15] Add support for ast2600 ADC Billy Tsai
2021-08-24  9:12 ` [RESEND v4 01/15] dt-bindings: iio: adc: Add ast2600-adc bindings Billy Tsai
2021-08-24  9:12 ` [RESEND v4 02/15] iio: adc: aspeed: completes the bitfield declare Billy Tsai
2021-08-29 15:07   ` Jonathan Cameron
2021-08-24  9:12 ` [RESEND v4 03/15] iio: adc: aspeed: set driver data when adc probe Billy Tsai
2021-08-29 15:08   ` Jonathan Cameron
2021-08-24  9:12 ` [RESEND v4 04/15] iio: adc: aspeed: Keep model data to driver data Billy Tsai
2021-08-24  9:12 ` [RESEND v4 05/15] iio: adc: aspeed: Refactory model data structure Billy Tsai
2021-08-29 15:13   ` Jonathan Cameron
2021-08-24  9:12 ` [RESEND v4 06/15] iio: adc: aspeed: Add vref config function Billy Tsai
2021-08-24  9:12 ` [RESEND v4 07/15] iio: adc: aspeed: Set num_channels with model data Billy Tsai
2021-08-24  9:12 ` [RESEND v4 08/15] iio: adc: aspeed: Use model_data to set clk scaler Billy Tsai
2021-08-24  9:12 ` [RESEND v4 09/15] iio: adc: aspeed: Use devm_add_action_or_reset Billy Tsai
2021-08-24  9:12 ` Billy Tsai
2021-08-24  9:12 ` [RESEND v4 10/15] iio: adc: aspeed: Support ast2600 adc Billy Tsai
2021-08-29 15:31   ` Jonathan Cameron
2021-08-24  9:12 ` [RESEND v4 11/15] iio: adc: aspeed: Fix the calculate error of clock Billy Tsai
2021-08-29 15:33   ` Jonathan Cameron
2021-08-24  9:12 ` [RESEND v4 12/15] iio: adc: aspeed: Add func to set sampling rate Billy Tsai
2021-08-24  9:12 ` [RESEND v4 13/15] iio: adc: aspeed: Add compensation phase Billy Tsai
2021-08-24  9:12 ` [RESEND v4 14/15] iio: adc: aspeed: Support battery sensing Billy Tsai
2021-08-24  9:12 ` [RESEND v4 15/15] iio: adc: aspeed: Get and set trimming data Billy Tsai
     [not found] ` <202108250006.17P06IgG097015@twspam01.aspeedtech.com>
2021-08-29 15:20   ` [RESEND v4 08/15] iio: adc: aspeed: Use model_data to set clk scaler Jonathan Cameron
     [not found] ` <202108250004.17P04FdD094082@twspam01.aspeedtech.com>
2021-08-29 15:25   ` [RESEND v4 09/15] iio: adc: aspeed: Use devm_add_action_or_reset Jonathan Cameron
     [not found] ` <202108250003.17P03KRU092474@twspam01.aspeedtech.com>
2021-08-29 15:36   ` [RESEND v4 12/15] iio: adc: aspeed: Add func to set sampling rate Jonathan Cameron
2021-08-30  8:35     ` Billy Tsai
2021-08-30  9:52       ` Jonathan Cameron
     [not found] ` <202108250006.17P066YP096721@twspam01.aspeedtech.com>
2021-08-29 15:39   ` [RESEND v4 13/15] iio: adc: aspeed: Add compensation phase Jonathan Cameron
     [not found] ` <202108250005.17P05agj096445@twspam01.aspeedtech.com>
2021-08-29 15:43   ` [RESEND v4 14/15] iio: adc: aspeed: Support battery sensing Jonathan Cameron
     [not found] ` <202108250007.17P07NFj097422@twspam01.aspeedtech.com>
2021-08-29 15:45   ` [RESEND v4 15/15] iio: adc: aspeed: Get and set trimming data 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).