summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-kernel/linux/linux-aspeed/0086-ADC-linux-driver-for-AST2600.patch
blob: 63b6838265ac8a72f9b78ac9285ce963b114d166 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
From 14a4e77c801be8adbfc0726667a8051957e7a7dd Mon Sep 17 00:00:00 2001
From: Chen Yugang <yugang.chen@linux.intel.com>
Date: Tue, 3 Dec 2019 13:41:37 +0800
Subject: [PATCH] ADC linux driver for AST2600

Tested:
it's tested with DC input.

Signed-off-by: Chen Yugang <yugang.chen@linux.intel.com>
---
 arch/arm/boot/dts/aspeed-g6.dtsi | 14 +++++-
 drivers/iio/adc/aspeed_adc.c     | 99 +++++++++++++++++++++++++++++++++++-----
 2 files changed, 99 insertions(+), 14 deletions(-)

diff --git a/arch/arm/boot/dts/aspeed-g6.dtsi b/arch/arm/boot/dts/aspeed-g6.dtsi
index 34281b1..4e8d25f 100644
--- a/arch/arm/boot/dts/aspeed-g6.dtsi
+++ b/arch/arm/boot/dts/aspeed-g6.dtsi
@@ -320,12 +320,22 @@
 				interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
 			};
 
-			adc: adc@1e6e9000 {
-				compatible = "aspeed,ast2500-adc";
+			adc0: adc@1e6e9000 {
+				compatible = "aspeed,ast2600-adc";
 				reg = <0x1e6e9000 0x100>;
 				clocks = <&syscon ASPEED_CLK_APB2>;
+				resets = <&syscon ASPEED_RESET_ADC>;
 				interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
+				#io-channel-cells = <1>;
+				status = "disabled";
+			};
+
+			adc1: adc@1e6e9100 {
+				compatible = "aspeed,ast2600-adc";
+				reg = <0x1e6e9100 0x100>;
+				clocks = <&syscon ASPEED_CLK_APB2>;
 				resets = <&syscon ASPEED_RESET_ADC>;
+				interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
 				#io-channel-cells = <1>;
 				status = "disabled";
 			};
diff --git a/drivers/iio/adc/aspeed_adc.c b/drivers/iio/adc/aspeed_adc.c
index d3fc39d..1dd5a97 100644
--- a/drivers/iio/adc/aspeed_adc.c
+++ b/drivers/iio/adc/aspeed_adc.c
@@ -1,8 +1,12 @@
-// SPDX-License-Identifier: GPL-2.0-only
 /*
- * Aspeed AST2400/2500 ADC
+ * Aspeed AST2400/2500/2600 ADC
  *
  * Copyright (C) 2017 Google, Inc.
+ * Copyright (C) ASPEED Technology Inc.
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
  */
 
 #include <linux/clk.h>
@@ -30,6 +34,14 @@
 #define ASPEED_REG_CLOCK_CONTROL	0x0C
 #define ASPEED_REG_MAX			0xC0
 
+/* ast2600 */
+#define REF_VLOTAGE_2500mV 		0
+#define REF_VLOTAGE_1200mV 		GENMASK(6, 6)
+#define REF_VLOTAGE_1550mV 		GENMASK(7, 7)
+#define REF_VLOTAGE_900mV 		GENMASK(7, 6)
+
+#define ASPEED_AUTOPENSATING		BIT(5)
+
 #define ASPEED_OPERATION_MODE_POWER_DOWN	(0x0 << 1)
 #define ASPEED_OPERATION_MODE_STANDBY		(0x1 << 1)
 #define ASPEED_OPERATION_MODE_NORMAL		(0x7 << 1)
@@ -45,8 +57,10 @@ 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
+	u32 vref_voltage;	// mV
 	bool wait_init_sequence;
+	struct iio_chan_spec const	*channels;
+	int num_channels;
 };
 
 struct aspeed_adc_data {
@@ -56,6 +70,7 @@ struct aspeed_adc_data {
 	struct clk_hw		*clk_prescaler;
 	struct clk_hw		*clk_scaler;
 	struct reset_control	*rst;
+	int 				cv;
 };
 
 #define ASPEED_CHAN(_idx, _data_reg_addr) {			\
@@ -87,6 +102,17 @@ static const struct iio_chan_spec aspeed_adc_iio_channels[] = {
 	ASPEED_CHAN(15, 0x2E),
 };
 
+static const struct iio_chan_spec ast2600_adc_iio_channels[] = {
+	ASPEED_CHAN(0, 0x10),
+	ASPEED_CHAN(1, 0x12),
+	ASPEED_CHAN(2, 0x14),
+	ASPEED_CHAN(3, 0x16),
+	ASPEED_CHAN(4, 0x18),
+	ASPEED_CHAN(5, 0x1A),
+	ASPEED_CHAN(6, 0x1C),
+	ASPEED_CHAN(7, 0x1E),
+};
+
 static int aspeed_adc_read_raw(struct iio_dev *indio_dev,
 			       struct iio_chan_spec const *chan,
 			       int *val, int *val2, long mask)
@@ -175,7 +201,10 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	const struct aspeed_adc_model_data *model_data;
 	struct resource *res;
 	const char *clk_parent_name;
+	char prescaler_clk_name[32];
+	char scaler_clk_name[32];
 	int ret;
+	u32 eng_ctrl = 0;
 	u32 adc_engine_control_reg_val;
 
 	indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*data));
@@ -194,19 +223,21 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	spin_lock_init(&data->clk_lock);
 	clk_parent_name = of_clk_get_parent_name(pdev->dev.of_node, 0);
 
+	snprintf(prescaler_clk_name, sizeof(prescaler_clk_name), "prescaler-%s", pdev->name);
 	data->clk_prescaler = clk_hw_register_divider(
-				&pdev->dev, "prescaler", clk_parent_name, 0,
+				&pdev->dev, prescaler_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(scaler_clk_name, sizeof(scaler_clk_name), "scaler-%s", pdev->name);
 	/*
 	 * Register ADC clock scaler downstream from the prescaler. Allow rate
 	 * setting to adjust the prescaler as well.
 	 */
 	data->clk_scaler = clk_hw_register_divider(
-				&pdev->dev, "scaler", "prescaler",
+				&pdev->dev, scaler_clk_name, prescaler_clk_name,
 				CLK_SET_RATE_PARENT,
 				data->base + ASPEED_REG_CLOCK_CONTROL,
 				0, 10, 0, &data->clk_lock);
@@ -215,7 +246,7 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 		goto scaler_error;
 	}
 
-	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");
@@ -225,11 +256,26 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	reset_control_deassert(data->rst);
 
 	model_data = of_device_get_match_data(&pdev->dev);
+	if (!of_property_read_u32(pdev->dev.of_node, "ref_voltage", (u32 *)&model_data->vref_voltage)) {
+		if (model_data->vref_voltage == 2500)
+			eng_ctrl = REF_VLOTAGE_2500mV;
+		else if (model_data->vref_voltage == 1200)
+			eng_ctrl = REF_VLOTAGE_1200mV;
+		else if ((model_data->vref_voltage >= 1550) && (model_data->vref_voltage <= 2700))
+			eng_ctrl = REF_VLOTAGE_1550mV;
+		else if ((model_data->vref_voltage >= 900) && (model_data->vref_voltage <= 1650))
+			eng_ctrl = REF_VLOTAGE_900mV;
+		else {
+			printk("error ref voltage %d \n", model_data->vref_voltage);
+			eng_ctrl = 0;
+		}
+	} else
+		eng_ctrl = 0;
 
 	if (model_data->wait_init_sequence) {
 		/* Enable engine in normal mode. */
-		writel(ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE,
-		       data->base + ASPEED_REG_ENGINE_CONTROL);
+		eng_ctrl |= ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE;
+		writel(eng_ctrl, data->base + ASPEED_REG_ENGINE_CONTROL);
 
 		/* Wait for initial sequence complete. */
 		ret = readl_poll_timeout(data->base + ASPEED_REG_ENGINE_CONTROL,
@@ -242,12 +288,26 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 			goto poll_timeout_error;
 	}
 
+	/* do compensating calculation use ch 0 */
+	writel(eng_ctrl | ASPEED_OPERATION_MODE_NORMAL |
+			ASPEED_ENGINE_ENABLE | ASPEED_AUTOPENSATING, data->base + ASPEED_REG_ENGINE_CONTROL);
+
+	writel(eng_ctrl | ASPEED_OPERATION_MODE_NORMAL | BIT(16) |
+			ASPEED_ENGINE_ENABLE | ASPEED_AUTOPENSATING, data->base + ASPEED_REG_ENGINE_CONTROL);
+	mdelay(1);
+
+	data->cv = 0x200 - (readl(data->base + 0x10) & GENMASK(9, 0));
+
+	writel(eng_ctrl | ASPEED_OPERATION_MODE_NORMAL |
+			ASPEED_ENGINE_ENABLE | ASPEED_AUTOPENSATING, data->base + ASPEED_REG_ENGINE_CONTROL);
+	printk(KERN_INFO "aspeed_adc: cv %d \n", data->cv);
+
 	/* Start all channels in normal mode. */
 	ret = clk_prepare_enable(data->clk_scaler->clk);
 	if (ret)
 		goto clk_enable_error;
 
-	adc_engine_control_reg_val = GENMASK(31, 16) |
+	adc_engine_control_reg_val = eng_ctrl | GENMASK(31, 16) |
 		ASPEED_OPERATION_MODE_NORMAL | ASPEED_ENGINE_ENABLE;
 	writel(adc_engine_control_reg_val,
 		data->base + ASPEED_REG_ENGINE_CONTROL);
@@ -257,8 +317,8 @@ static int aspeed_adc_probe(struct platform_device *pdev)
 	indio_dev->dev.parent = &pdev->dev;
 	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->channels = model_data->channels;
+	indio_dev->num_channels = model_data->num_channels;
 
 	ret = iio_device_register(indio_dev);
 	if (ret)
@@ -301,6 +361,8 @@ static const struct aspeed_adc_model_data ast2400_model_data = {
 	.vref_voltage = 2500, // mV
 	.min_sampling_rate = 10000,
 	.max_sampling_rate = 500000,
+	.channels = aspeed_adc_iio_channels,
+	.num_channels = 16,
 };
 
 static const struct aspeed_adc_model_data ast2500_model_data = {
@@ -309,11 +371,24 @@ static const struct aspeed_adc_model_data ast2500_model_data = {
 	.min_sampling_rate = 1,
 	.max_sampling_rate = 1000000,
 	.wait_init_sequence = true,
+	.channels = aspeed_adc_iio_channels,
+	.num_channels = 16,
+};
+
+static const struct aspeed_adc_model_data ast2600_model_data = {
+	.model_name = "ast2500-adc",
+	.vref_voltage = 1800, /* mV --> can be 1.2v or 2.5 or ext 1.55~2.7v, 0.9v ~1.65v */
+	.min_sampling_rate = 1,
+	.max_sampling_rate = 1000000,
+	.wait_init_sequence = true,
+	.channels = ast2600_adc_iio_channels,
+	.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-adc", .data = &ast2600_model_data },
 	{},
 };
 MODULE_DEVICE_TABLE(of, aspeed_adc_matches);
@@ -330,5 +405,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.7.4