Commit | Line | Data |
---|---|---|
1a78daea AR |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * ADC driver for the Ingenic JZ47xx SoCs | |
4 | * Copyright (c) 2019 Artur Rojek <contact@artur-rojek.eu> | |
5 | * | |
6 | * based on drivers/mfd/jz4740-adc.c | |
7 | */ | |
8 | ||
9 | #include <dt-bindings/iio/adc/ingenic,adc.h> | |
10 | #include <linux/clk.h> | |
b96952f4 | 11 | #include <linux/iio/buffer.h> |
1a78daea | 12 | #include <linux/iio/iio.h> |
b96952f4 | 13 | #include <linux/interrupt.h> |
1a78daea AR |
14 | #include <linux/io.h> |
15 | #include <linux/iopoll.h> | |
5a304e1a | 16 | #include <linux/kernel.h> |
1a78daea | 17 | #include <linux/module.h> |
a07a4fe5 | 18 | #include <linux/mod_devicetable.h> |
1a78daea | 19 | #include <linux/mutex.h> |
4738b57a | 20 | #include <linux/of.h> |
1a78daea | 21 | #include <linux/platform_device.h> |
4738b57a | 22 | #include <linux/property.h> |
1a78daea AR |
23 | |
24 | #define JZ_ADC_REG_ENABLE 0x00 | |
25 | #define JZ_ADC_REG_CFG 0x04 | |
26 | #define JZ_ADC_REG_CTRL 0x08 | |
27 | #define JZ_ADC_REG_STATUS 0x0c | |
b96952f4 AR |
28 | #define JZ_ADC_REG_ADSAME 0x10 |
29 | #define JZ_ADC_REG_ADWAIT 0x14 | |
1a78daea AR |
30 | #define JZ_ADC_REG_ADTCH 0x18 |
31 | #define JZ_ADC_REG_ADBDAT 0x1c | |
32 | #define JZ_ADC_REG_ADSDAT 0x20 | |
b96952f4 | 33 | #define JZ_ADC_REG_ADCMD 0x24 |
5a304e1a | 34 | #define JZ_ADC_REG_ADCLK 0x28 |
1a78daea | 35 | |
a515d648 AR |
36 | #define JZ_ADC_REG_ENABLE_PD BIT(7) |
37 | #define JZ_ADC_REG_CFG_AUX_MD (BIT(0) | BIT(1)) | |
1a78daea | 38 | #define JZ_ADC_REG_CFG_BAT_MD BIT(4) |
b96952f4 AR |
39 | #define JZ_ADC_REG_CFG_SAMPLE_NUM(n) ((n) << 10) |
40 | #define JZ_ADC_REG_CFG_PULL_UP(n) ((n) << 16) | |
41 | #define JZ_ADC_REG_CFG_CMD_SEL BIT(22) | |
bf1b2418 | 42 | #define JZ_ADC_REG_CFG_VBAT_SEL BIT(30) |
b96952f4 | 43 | #define JZ_ADC_REG_CFG_TOUCH_OPS_MASK (BIT(31) | GENMASK(23, 10)) |
5a304e1a | 44 | #define JZ_ADC_REG_ADCLK_CLKDIV_LSB 0 |
a515d648 AR |
45 | #define JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB 16 |
46 | #define JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB 8 | |
47 | #define JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB 16 | |
1a78daea | 48 | |
b96952f4 AR |
49 | #define JZ_ADC_REG_ADCMD_YNADC BIT(7) |
50 | #define JZ_ADC_REG_ADCMD_YPADC BIT(8) | |
51 | #define JZ_ADC_REG_ADCMD_XNADC BIT(9) | |
52 | #define JZ_ADC_REG_ADCMD_XPADC BIT(10) | |
53 | #define JZ_ADC_REG_ADCMD_VREFPYP BIT(11) | |
54 | #define JZ_ADC_REG_ADCMD_VREFPXP BIT(12) | |
55 | #define JZ_ADC_REG_ADCMD_VREFPXN BIT(13) | |
56 | #define JZ_ADC_REG_ADCMD_VREFPAUX BIT(14) | |
57 | #define JZ_ADC_REG_ADCMD_VREFPVDD33 BIT(15) | |
58 | #define JZ_ADC_REG_ADCMD_VREFNYN BIT(16) | |
59 | #define JZ_ADC_REG_ADCMD_VREFNXP BIT(17) | |
60 | #define JZ_ADC_REG_ADCMD_VREFNXN BIT(18) | |
61 | #define JZ_ADC_REG_ADCMD_VREFAUX BIT(19) | |
62 | #define JZ_ADC_REG_ADCMD_YNGRU BIT(20) | |
63 | #define JZ_ADC_REG_ADCMD_XNGRU BIT(21) | |
64 | #define JZ_ADC_REG_ADCMD_XPGRU BIT(22) | |
65 | #define JZ_ADC_REG_ADCMD_YPSUP BIT(23) | |
66 | #define JZ_ADC_REG_ADCMD_XNSUP BIT(24) | |
67 | #define JZ_ADC_REG_ADCMD_XPSUP BIT(25) | |
68 | ||
1a78daea AR |
69 | #define JZ_ADC_AUX_VREF 3300 |
70 | #define JZ_ADC_AUX_VREF_BITS 12 | |
71 | #define JZ_ADC_BATTERY_LOW_VREF 2500 | |
72 | #define JZ_ADC_BATTERY_LOW_VREF_BITS 12 | |
73 | #define JZ4725B_ADC_BATTERY_HIGH_VREF 7500 | |
74 | #define JZ4725B_ADC_BATTERY_HIGH_VREF_BITS 10 | |
75 | #define JZ4740_ADC_BATTERY_HIGH_VREF (7500 * 0.986) | |
76 | #define JZ4740_ADC_BATTERY_HIGH_VREF_BITS 12 | |
b9e9bdd4 | 77 | #define JZ4760_ADC_BATTERY_VREF 2500 |
c91ebcc5 | 78 | #define JZ4770_ADC_BATTERY_VREF 1200 |
a515d648 | 79 | #define JZ4770_ADC_BATTERY_VREF_BITS 12 |
1a78daea | 80 | |
b96952f4 AR |
81 | #define JZ_ADC_IRQ_AUX BIT(0) |
82 | #define JZ_ADC_IRQ_BATTERY BIT(1) | |
83 | #define JZ_ADC_IRQ_TOUCH BIT(2) | |
84 | #define JZ_ADC_IRQ_PEN_DOWN BIT(3) | |
85 | #define JZ_ADC_IRQ_PEN_UP BIT(4) | |
86 | #define JZ_ADC_IRQ_PEN_DOWN_SLEEP BIT(5) | |
87 | #define JZ_ADC_IRQ_SLEEP BIT(7) | |
88 | ||
5a304e1a MH |
89 | struct ingenic_adc; |
90 | ||
1a78daea AR |
91 | struct ingenic_adc_soc_data { |
92 | unsigned int battery_high_vref; | |
93 | unsigned int battery_high_vref_bits; | |
94 | const int *battery_raw_avail; | |
95 | size_t battery_raw_avail_size; | |
96 | const int *battery_scale_avail; | |
97 | size_t battery_scale_avail_size; | |
a515d648 | 98 | unsigned int battery_vref_mode: 1; |
9c5eb724 | 99 | unsigned int has_aux_md: 1; |
6a294b41 PC |
100 | const struct iio_chan_spec *channels; |
101 | unsigned int num_channels; | |
5a304e1a | 102 | int (*init_clk_div)(struct device *dev, struct ingenic_adc *adc); |
1a78daea AR |
103 | }; |
104 | ||
105 | struct ingenic_adc { | |
106 | void __iomem *base; | |
107 | struct clk *clk; | |
108 | struct mutex lock; | |
a515d648 | 109 | struct mutex aux_lock; |
1a78daea AR |
110 | const struct ingenic_adc_soc_data *soc_data; |
111 | bool low_vref_mode; | |
112 | }; | |
113 | ||
b96952f4 AR |
114 | static void ingenic_adc_set_adcmd(struct iio_dev *iio_dev, unsigned long mask) |
115 | { | |
116 | struct ingenic_adc *adc = iio_priv(iio_dev); | |
117 | ||
118 | mutex_lock(&adc->lock); | |
119 | ||
120 | /* Init ADCMD */ | |
121 | readl(adc->base + JZ_ADC_REG_ADCMD); | |
122 | ||
123 | if (mask & 0x3) { | |
124 | /* Second channel (INGENIC_ADC_TOUCH_YP): sample YP vs. GND */ | |
125 | writel(JZ_ADC_REG_ADCMD_XNGRU | |
126 | | JZ_ADC_REG_ADCMD_VREFNXN | JZ_ADC_REG_ADCMD_VREFPVDD33 | |
127 | | JZ_ADC_REG_ADCMD_YPADC, | |
128 | adc->base + JZ_ADC_REG_ADCMD); | |
129 | ||
130 | /* First channel (INGENIC_ADC_TOUCH_XP): sample XP vs. GND */ | |
131 | writel(JZ_ADC_REG_ADCMD_YNGRU | |
132 | | JZ_ADC_REG_ADCMD_VREFNYN | JZ_ADC_REG_ADCMD_VREFPVDD33 | |
133 | | JZ_ADC_REG_ADCMD_XPADC, | |
134 | adc->base + JZ_ADC_REG_ADCMD); | |
135 | } | |
136 | ||
137 | if (mask & 0xc) { | |
138 | /* Fourth channel (INGENIC_ADC_TOUCH_YN): sample YN vs. GND */ | |
139 | writel(JZ_ADC_REG_ADCMD_XNGRU | |
140 | | JZ_ADC_REG_ADCMD_VREFNXN | JZ_ADC_REG_ADCMD_VREFPVDD33 | |
141 | | JZ_ADC_REG_ADCMD_YNADC, | |
142 | adc->base + JZ_ADC_REG_ADCMD); | |
143 | ||
144 | /* Third channel (INGENIC_ADC_TOUCH_XN): sample XN vs. GND */ | |
145 | writel(JZ_ADC_REG_ADCMD_YNGRU | |
146 | | JZ_ADC_REG_ADCMD_VREFNYN | JZ_ADC_REG_ADCMD_VREFPVDD33 | |
147 | | JZ_ADC_REG_ADCMD_XNADC, | |
148 | adc->base + JZ_ADC_REG_ADCMD); | |
149 | } | |
150 | ||
151 | if (mask & 0x30) { | |
152 | /* Sixth channel (INGENIC_ADC_TOUCH_YD): sample YP vs. YN */ | |
153 | writel(JZ_ADC_REG_ADCMD_VREFNYN | JZ_ADC_REG_ADCMD_VREFPVDD33 | |
154 | | JZ_ADC_REG_ADCMD_YPADC, | |
155 | adc->base + JZ_ADC_REG_ADCMD); | |
156 | ||
157 | /* Fifth channel (INGENIC_ADC_TOUCH_XD): sample XP vs. XN */ | |
158 | writel(JZ_ADC_REG_ADCMD_VREFNXN | JZ_ADC_REG_ADCMD_VREFPVDD33 | |
159 | | JZ_ADC_REG_ADCMD_XPADC, | |
160 | adc->base + JZ_ADC_REG_ADCMD); | |
161 | } | |
162 | ||
163 | /* We're done */ | |
164 | writel(0, adc->base + JZ_ADC_REG_ADCMD); | |
165 | ||
166 | mutex_unlock(&adc->lock); | |
167 | } | |
168 | ||
1a78daea AR |
169 | static void ingenic_adc_set_config(struct ingenic_adc *adc, |
170 | uint32_t mask, | |
171 | uint32_t val) | |
172 | { | |
173 | uint32_t cfg; | |
174 | ||
1a78daea AR |
175 | mutex_lock(&adc->lock); |
176 | ||
177 | cfg = readl(adc->base + JZ_ADC_REG_CFG) & ~mask; | |
178 | cfg |= val; | |
179 | writel(cfg, adc->base + JZ_ADC_REG_CFG); | |
180 | ||
181 | mutex_unlock(&adc->lock); | |
1a78daea AR |
182 | } |
183 | ||
6d6aa290 PC |
184 | static void ingenic_adc_enable_unlocked(struct ingenic_adc *adc, |
185 | int engine, | |
186 | bool enabled) | |
1a78daea AR |
187 | { |
188 | u8 val; | |
189 | ||
1a78daea AR |
190 | val = readb(adc->base + JZ_ADC_REG_ENABLE); |
191 | ||
192 | if (enabled) | |
193 | val |= BIT(engine); | |
194 | else | |
195 | val &= ~BIT(engine); | |
196 | ||
197 | writeb(val, adc->base + JZ_ADC_REG_ENABLE); | |
6d6aa290 PC |
198 | } |
199 | ||
200 | static void ingenic_adc_enable(struct ingenic_adc *adc, | |
201 | int engine, | |
202 | bool enabled) | |
203 | { | |
204 | mutex_lock(&adc->lock); | |
205 | ingenic_adc_enable_unlocked(adc, engine, enabled); | |
1a78daea AR |
206 | mutex_unlock(&adc->lock); |
207 | } | |
208 | ||
209 | static int ingenic_adc_capture(struct ingenic_adc *adc, | |
210 | int engine) | |
211 | { | |
6d6aa290 | 212 | u32 cfg; |
1a78daea AR |
213 | u8 val; |
214 | int ret; | |
215 | ||
6d6aa290 PC |
216 | /* |
217 | * Disable CMD_SEL temporarily, because it causes wrong VBAT readings, | |
218 | * probably due to the switch of VREF. We must keep the lock here to | |
219 | * avoid races with the buffer enable/disable functions. | |
220 | */ | |
221 | mutex_lock(&adc->lock); | |
222 | cfg = readl(adc->base + JZ_ADC_REG_CFG); | |
223 | writel(cfg & ~JZ_ADC_REG_CFG_CMD_SEL, adc->base + JZ_ADC_REG_CFG); | |
224 | ||
225 | ingenic_adc_enable_unlocked(adc, engine, true); | |
1a78daea AR |
226 | ret = readb_poll_timeout(adc->base + JZ_ADC_REG_ENABLE, val, |
227 | !(val & BIT(engine)), 250, 1000); | |
228 | if (ret) | |
6d6aa290 PC |
229 | ingenic_adc_enable_unlocked(adc, engine, false); |
230 | ||
231 | writel(cfg, adc->base + JZ_ADC_REG_CFG); | |
232 | mutex_unlock(&adc->lock); | |
1a78daea AR |
233 | |
234 | return ret; | |
235 | } | |
236 | ||
237 | static int ingenic_adc_write_raw(struct iio_dev *iio_dev, | |
238 | struct iio_chan_spec const *chan, | |
239 | int val, | |
240 | int val2, | |
241 | long m) | |
242 | { | |
243 | struct ingenic_adc *adc = iio_priv(iio_dev); | |
1a99dc46 AR |
244 | struct device *dev = iio_dev->dev.parent; |
245 | int ret; | |
1a78daea AR |
246 | |
247 | switch (m) { | |
248 | case IIO_CHAN_INFO_SCALE: | |
249 | switch (chan->channel) { | |
250 | case INGENIC_ADC_BATTERY: | |
a515d648 AR |
251 | if (!adc->soc_data->battery_vref_mode) |
252 | return -EINVAL; | |
1a99dc46 AR |
253 | |
254 | ret = clk_enable(adc->clk); | |
255 | if (ret) { | |
256 | dev_err(dev, "Failed to enable clock: %d\n", | |
257 | ret); | |
258 | return ret; | |
259 | } | |
260 | ||
1a78daea AR |
261 | if (val > JZ_ADC_BATTERY_LOW_VREF) { |
262 | ingenic_adc_set_config(adc, | |
263 | JZ_ADC_REG_CFG_BAT_MD, | |
264 | 0); | |
265 | adc->low_vref_mode = false; | |
266 | } else { | |
267 | ingenic_adc_set_config(adc, | |
268 | JZ_ADC_REG_CFG_BAT_MD, | |
269 | JZ_ADC_REG_CFG_BAT_MD); | |
270 | adc->low_vref_mode = true; | |
271 | } | |
1a99dc46 AR |
272 | |
273 | clk_disable(adc->clk); | |
274 | ||
1a78daea AR |
275 | return 0; |
276 | default: | |
277 | return -EINVAL; | |
278 | } | |
279 | default: | |
280 | return -EINVAL; | |
281 | } | |
282 | } | |
283 | ||
284 | static const int jz4725b_adc_battery_raw_avail[] = { | |
285 | 0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1, | |
286 | }; | |
287 | ||
288 | static const int jz4725b_adc_battery_scale_avail[] = { | |
289 | JZ4725B_ADC_BATTERY_HIGH_VREF, JZ4725B_ADC_BATTERY_HIGH_VREF_BITS, | |
290 | JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS, | |
291 | }; | |
292 | ||
293 | static const int jz4740_adc_battery_raw_avail[] = { | |
294 | 0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1, | |
295 | }; | |
296 | ||
297 | static const int jz4740_adc_battery_scale_avail[] = { | |
298 | JZ4740_ADC_BATTERY_HIGH_VREF, JZ4740_ADC_BATTERY_HIGH_VREF_BITS, | |
299 | JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS, | |
300 | }; | |
301 | ||
b9e9bdd4 CB |
302 | static const int jz4760_adc_battery_scale_avail[] = { |
303 | JZ4760_ADC_BATTERY_VREF, JZ4770_ADC_BATTERY_VREF_BITS, | |
304 | }; | |
305 | ||
a515d648 AR |
306 | static const int jz4770_adc_battery_raw_avail[] = { |
307 | 0, 1, (1 << JZ4770_ADC_BATTERY_VREF_BITS) - 1, | |
308 | }; | |
309 | ||
310 | static const int jz4770_adc_battery_scale_avail[] = { | |
311 | JZ4770_ADC_BATTERY_VREF, JZ4770_ADC_BATTERY_VREF_BITS, | |
312 | }; | |
313 | ||
5a304e1a MH |
314 | static int jz4725b_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc) |
315 | { | |
316 | struct clk *parent_clk; | |
317 | unsigned long parent_rate, rate; | |
318 | unsigned int div_main, div_10us; | |
319 | ||
320 | parent_clk = clk_get_parent(adc->clk); | |
321 | if (!parent_clk) { | |
322 | dev_err(dev, "ADC clock has no parent\n"); | |
323 | return -ENODEV; | |
324 | } | |
325 | parent_rate = clk_get_rate(parent_clk); | |
326 | ||
327 | /* | |
328 | * The JZ4725B ADC works at 500 kHz to 8 MHz. | |
329 | * We pick the highest rate possible. | |
330 | * In practice we typically get 6 MHz, half of the 12 MHz EXT clock. | |
331 | */ | |
332 | div_main = DIV_ROUND_UP(parent_rate, 8000000); | |
333 | div_main = clamp(div_main, 1u, 64u); | |
334 | rate = parent_rate / div_main; | |
335 | if (rate < 500000 || rate > 8000000) { | |
336 | dev_err(dev, "No valid divider for ADC main clock\n"); | |
337 | return -EINVAL; | |
338 | } | |
339 | ||
340 | /* We also need a divider that produces a 10us clock. */ | |
341 | div_10us = DIV_ROUND_UP(rate, 100000); | |
342 | ||
a515d648 AR |
343 | writel(((div_10us - 1) << JZ4725B_ADC_REG_ADCLK_CLKDIV10US_LSB) | |
344 | (div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB, | |
345 | adc->base + JZ_ADC_REG_ADCLK); | |
346 | ||
347 | return 0; | |
348 | } | |
349 | ||
350 | static int jz4770_adc_init_clk_div(struct device *dev, struct ingenic_adc *adc) | |
351 | { | |
352 | struct clk *parent_clk; | |
353 | unsigned long parent_rate, rate; | |
354 | unsigned int div_main, div_ms, div_10us; | |
355 | ||
356 | parent_clk = clk_get_parent(adc->clk); | |
357 | if (!parent_clk) { | |
358 | dev_err(dev, "ADC clock has no parent\n"); | |
359 | return -ENODEV; | |
360 | } | |
361 | parent_rate = clk_get_rate(parent_clk); | |
362 | ||
363 | /* | |
364 | * The JZ4770 ADC works at 20 kHz to 200 kHz. | |
365 | * We pick the highest rate possible. | |
366 | */ | |
367 | div_main = DIV_ROUND_UP(parent_rate, 200000); | |
368 | div_main = clamp(div_main, 1u, 256u); | |
369 | rate = parent_rate / div_main; | |
370 | if (rate < 20000 || rate > 200000) { | |
371 | dev_err(dev, "No valid divider for ADC main clock\n"); | |
372 | return -EINVAL; | |
373 | } | |
374 | ||
375 | /* We also need a divider that produces a 10us clock. */ | |
376 | div_10us = DIV_ROUND_UP(rate, 10000); | |
377 | /* And another, which produces a 1ms clock. */ | |
378 | div_ms = DIV_ROUND_UP(rate, 1000); | |
379 | ||
380 | writel(((div_ms - 1) << JZ4770_ADC_REG_ADCLK_CLKDIVMS_LSB) | | |
381 | ((div_10us - 1) << JZ4770_ADC_REG_ADCLK_CLKDIV10US_LSB) | | |
5a304e1a MH |
382 | (div_main - 1) << JZ_ADC_REG_ADCLK_CLKDIV_LSB, |
383 | adc->base + JZ_ADC_REG_ADCLK); | |
384 | ||
385 | return 0; | |
386 | } | |
387 | ||
6a294b41 PC |
388 | static const struct iio_chan_spec jz4740_channels[] = { |
389 | { | |
390 | .extend_name = "aux", | |
391 | .type = IIO_VOLTAGE, | |
392 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | |
393 | BIT(IIO_CHAN_INFO_SCALE), | |
394 | .indexed = 1, | |
395 | .channel = INGENIC_ADC_AUX, | |
396 | .scan_index = -1, | |
397 | }, | |
398 | { | |
399 | .extend_name = "battery", | |
400 | .type = IIO_VOLTAGE, | |
401 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | |
402 | BIT(IIO_CHAN_INFO_SCALE), | |
403 | .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW) | | |
404 | BIT(IIO_CHAN_INFO_SCALE), | |
405 | .indexed = 1, | |
406 | .channel = INGENIC_ADC_BATTERY, | |
407 | .scan_index = -1, | |
408 | }, | |
409 | }; | |
410 | ||
b9e9bdd4 CB |
411 | static const struct iio_chan_spec jz4760_channels[] = { |
412 | { | |
413 | .extend_name = "aux", | |
414 | .type = IIO_VOLTAGE, | |
415 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | |
416 | BIT(IIO_CHAN_INFO_SCALE), | |
417 | .indexed = 1, | |
418 | .channel = INGENIC_ADC_AUX0, | |
419 | .scan_index = -1, | |
420 | }, | |
421 | { | |
422 | .extend_name = "aux1", | |
423 | .type = IIO_VOLTAGE, | |
424 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | |
425 | BIT(IIO_CHAN_INFO_SCALE), | |
426 | .indexed = 1, | |
427 | .channel = INGENIC_ADC_AUX, | |
428 | .scan_index = -1, | |
429 | }, | |
430 | { | |
431 | .extend_name = "aux2", | |
432 | .type = IIO_VOLTAGE, | |
433 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | |
434 | BIT(IIO_CHAN_INFO_SCALE), | |
435 | .indexed = 1, | |
436 | .channel = INGENIC_ADC_AUX2, | |
437 | .scan_index = -1, | |
438 | }, | |
439 | { | |
440 | .extend_name = "battery", | |
441 | .type = IIO_VOLTAGE, | |
442 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | |
443 | BIT(IIO_CHAN_INFO_SCALE), | |
444 | .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW) | | |
445 | BIT(IIO_CHAN_INFO_SCALE), | |
446 | .indexed = 1, | |
447 | .channel = INGENIC_ADC_BATTERY, | |
448 | .scan_index = -1, | |
449 | }, | |
450 | }; | |
451 | ||
6a294b41 | 452 | static const struct iio_chan_spec jz4770_channels[] = { |
b96952f4 AR |
453 | { |
454 | .type = IIO_VOLTAGE, | |
455 | .indexed = 1, | |
456 | .channel = INGENIC_ADC_TOUCH_XP, | |
457 | .scan_index = 0, | |
458 | .scan_type = { | |
459 | .sign = 'u', | |
460 | .realbits = 12, | |
461 | .storagebits = 16, | |
462 | }, | |
463 | }, | |
464 | { | |
465 | .type = IIO_VOLTAGE, | |
466 | .indexed = 1, | |
467 | .channel = INGENIC_ADC_TOUCH_YP, | |
468 | .scan_index = 1, | |
469 | .scan_type = { | |
470 | .sign = 'u', | |
471 | .realbits = 12, | |
472 | .storagebits = 16, | |
473 | }, | |
474 | }, | |
475 | { | |
476 | .type = IIO_VOLTAGE, | |
477 | .indexed = 1, | |
478 | .channel = INGENIC_ADC_TOUCH_XN, | |
479 | .scan_index = 2, | |
480 | .scan_type = { | |
481 | .sign = 'u', | |
482 | .realbits = 12, | |
483 | .storagebits = 16, | |
484 | }, | |
485 | }, | |
486 | { | |
487 | .type = IIO_VOLTAGE, | |
488 | .indexed = 1, | |
489 | .channel = INGENIC_ADC_TOUCH_YN, | |
490 | .scan_index = 3, | |
491 | .scan_type = { | |
492 | .sign = 'u', | |
493 | .realbits = 12, | |
494 | .storagebits = 16, | |
495 | }, | |
496 | }, | |
497 | { | |
498 | .type = IIO_VOLTAGE, | |
499 | .indexed = 1, | |
500 | .channel = INGENIC_ADC_TOUCH_XD, | |
501 | .scan_index = 4, | |
502 | .scan_type = { | |
503 | .sign = 'u', | |
504 | .realbits = 12, | |
505 | .storagebits = 16, | |
506 | }, | |
507 | }, | |
508 | { | |
509 | .type = IIO_VOLTAGE, | |
510 | .indexed = 1, | |
511 | .channel = INGENIC_ADC_TOUCH_YD, | |
512 | .scan_index = 5, | |
513 | .scan_type = { | |
514 | .sign = 'u', | |
515 | .realbits = 12, | |
516 | .storagebits = 16, | |
517 | }, | |
518 | }, | |
6a294b41 PC |
519 | { |
520 | .extend_name = "aux", | |
521 | .type = IIO_VOLTAGE, | |
522 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | |
523 | BIT(IIO_CHAN_INFO_SCALE), | |
524 | .indexed = 1, | |
525 | .channel = INGENIC_ADC_AUX, | |
526 | .scan_index = -1, | |
527 | }, | |
528 | { | |
529 | .extend_name = "battery", | |
530 | .type = IIO_VOLTAGE, | |
531 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | |
532 | BIT(IIO_CHAN_INFO_SCALE), | |
533 | .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW) | | |
534 | BIT(IIO_CHAN_INFO_SCALE), | |
535 | .indexed = 1, | |
536 | .channel = INGENIC_ADC_BATTERY, | |
537 | .scan_index = -1, | |
538 | }, | |
539 | { | |
540 | .extend_name = "aux2", | |
541 | .type = IIO_VOLTAGE, | |
542 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | | |
543 | BIT(IIO_CHAN_INFO_SCALE), | |
544 | .indexed = 1, | |
545 | .channel = INGENIC_ADC_AUX2, | |
546 | .scan_index = -1, | |
547 | }, | |
548 | }; | |
549 | ||
1a78daea AR |
550 | static const struct ingenic_adc_soc_data jz4725b_adc_soc_data = { |
551 | .battery_high_vref = JZ4725B_ADC_BATTERY_HIGH_VREF, | |
552 | .battery_high_vref_bits = JZ4725B_ADC_BATTERY_HIGH_VREF_BITS, | |
553 | .battery_raw_avail = jz4725b_adc_battery_raw_avail, | |
554 | .battery_raw_avail_size = ARRAY_SIZE(jz4725b_adc_battery_raw_avail), | |
555 | .battery_scale_avail = jz4725b_adc_battery_scale_avail, | |
556 | .battery_scale_avail_size = ARRAY_SIZE(jz4725b_adc_battery_scale_avail), | |
a515d648 | 557 | .battery_vref_mode = true, |
9c5eb724 | 558 | .has_aux_md = false, |
6a294b41 PC |
559 | .channels = jz4740_channels, |
560 | .num_channels = ARRAY_SIZE(jz4740_channels), | |
5a304e1a | 561 | .init_clk_div = jz4725b_adc_init_clk_div, |
1a78daea AR |
562 | }; |
563 | ||
564 | static const struct ingenic_adc_soc_data jz4740_adc_soc_data = { | |
565 | .battery_high_vref = JZ4740_ADC_BATTERY_HIGH_VREF, | |
566 | .battery_high_vref_bits = JZ4740_ADC_BATTERY_HIGH_VREF_BITS, | |
567 | .battery_raw_avail = jz4740_adc_battery_raw_avail, | |
568 | .battery_raw_avail_size = ARRAY_SIZE(jz4740_adc_battery_raw_avail), | |
569 | .battery_scale_avail = jz4740_adc_battery_scale_avail, | |
570 | .battery_scale_avail_size = ARRAY_SIZE(jz4740_adc_battery_scale_avail), | |
a515d648 | 571 | .battery_vref_mode = true, |
9c5eb724 | 572 | .has_aux_md = false, |
6a294b41 PC |
573 | .channels = jz4740_channels, |
574 | .num_channels = ARRAY_SIZE(jz4740_channels), | |
5a304e1a | 575 | .init_clk_div = NULL, /* no ADCLK register on JZ4740 */ |
1a78daea AR |
576 | }; |
577 | ||
b9e9bdd4 CB |
578 | static const struct ingenic_adc_soc_data jz4760_adc_soc_data = { |
579 | .battery_high_vref = JZ4760_ADC_BATTERY_VREF, | |
580 | .battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS, | |
581 | .battery_raw_avail = jz4770_adc_battery_raw_avail, | |
582 | .battery_raw_avail_size = ARRAY_SIZE(jz4770_adc_battery_raw_avail), | |
583 | .battery_scale_avail = jz4760_adc_battery_scale_avail, | |
584 | .battery_scale_avail_size = ARRAY_SIZE(jz4760_adc_battery_scale_avail), | |
585 | .battery_vref_mode = false, | |
586 | .has_aux_md = true, | |
587 | .channels = jz4760_channels, | |
588 | .num_channels = ARRAY_SIZE(jz4760_channels), | |
589 | .init_clk_div = jz4770_adc_init_clk_div, | |
590 | }; | |
591 | ||
a515d648 AR |
592 | static const struct ingenic_adc_soc_data jz4770_adc_soc_data = { |
593 | .battery_high_vref = JZ4770_ADC_BATTERY_VREF, | |
594 | .battery_high_vref_bits = JZ4770_ADC_BATTERY_VREF_BITS, | |
595 | .battery_raw_avail = jz4770_adc_battery_raw_avail, | |
596 | .battery_raw_avail_size = ARRAY_SIZE(jz4770_adc_battery_raw_avail), | |
597 | .battery_scale_avail = jz4770_adc_battery_scale_avail, | |
598 | .battery_scale_avail_size = ARRAY_SIZE(jz4770_adc_battery_scale_avail), | |
599 | .battery_vref_mode = false, | |
9c5eb724 | 600 | .has_aux_md = true, |
6a294b41 PC |
601 | .channels = jz4770_channels, |
602 | .num_channels = ARRAY_SIZE(jz4770_channels), | |
a515d648 AR |
603 | .init_clk_div = jz4770_adc_init_clk_div, |
604 | }; | |
605 | ||
1a78daea AR |
606 | static int ingenic_adc_read_avail(struct iio_dev *iio_dev, |
607 | struct iio_chan_spec const *chan, | |
608 | const int **vals, | |
609 | int *type, | |
610 | int *length, | |
611 | long m) | |
612 | { | |
613 | struct ingenic_adc *adc = iio_priv(iio_dev); | |
614 | ||
615 | switch (m) { | |
616 | case IIO_CHAN_INFO_RAW: | |
617 | *type = IIO_VAL_INT; | |
618 | *length = adc->soc_data->battery_raw_avail_size; | |
619 | *vals = adc->soc_data->battery_raw_avail; | |
620 | return IIO_AVAIL_RANGE; | |
621 | case IIO_CHAN_INFO_SCALE: | |
622 | *type = IIO_VAL_FRACTIONAL_LOG2; | |
623 | *length = adc->soc_data->battery_scale_avail_size; | |
624 | *vals = adc->soc_data->battery_scale_avail; | |
625 | return IIO_AVAIL_LIST; | |
626 | default: | |
627 | return -EINVAL; | |
4a6261c3 | 628 | } |
1a78daea AR |
629 | } |
630 | ||
1a99dc46 | 631 | static int ingenic_adc_read_chan_info_raw(struct iio_dev *iio_dev, |
a515d648 AR |
632 | struct iio_chan_spec const *chan, |
633 | int *val) | |
634 | { | |
b9e9bdd4 | 635 | int cmd, ret, engine = (chan->channel == INGENIC_ADC_BATTERY); |
1a99dc46 AR |
636 | struct ingenic_adc *adc = iio_priv(iio_dev); |
637 | ||
638 | ret = clk_enable(adc->clk); | |
639 | if (ret) { | |
640 | dev_err(iio_dev->dev.parent, "Failed to enable clock: %d\n", | |
641 | ret); | |
642 | return ret; | |
643 | } | |
a515d648 | 644 | |
b9e9bdd4 | 645 | /* We cannot sample the aux channels in parallel. */ |
a515d648 | 646 | mutex_lock(&adc->aux_lock); |
9c5eb724 | 647 | if (adc->soc_data->has_aux_md && engine == 0) { |
b9e9bdd4 CB |
648 | switch (chan->channel) { |
649 | case INGENIC_ADC_AUX0: | |
650 | cmd = 0; | |
651 | break; | |
652 | case INGENIC_ADC_AUX: | |
653 | cmd = 1; | |
654 | break; | |
655 | case INGENIC_ADC_AUX2: | |
656 | cmd = 2; | |
657 | break; | |
658 | } | |
659 | ||
660 | ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_AUX_MD, cmd); | |
a515d648 AR |
661 | } |
662 | ||
a515d648 AR |
663 | ret = ingenic_adc_capture(adc, engine); |
664 | if (ret) | |
665 | goto out; | |
666 | ||
667 | switch (chan->channel) { | |
b9e9bdd4 | 668 | case INGENIC_ADC_AUX0: |
a515d648 AR |
669 | case INGENIC_ADC_AUX: |
670 | case INGENIC_ADC_AUX2: | |
671 | *val = readw(adc->base + JZ_ADC_REG_ADSDAT); | |
672 | break; | |
673 | case INGENIC_ADC_BATTERY: | |
674 | *val = readw(adc->base + JZ_ADC_REG_ADBDAT); | |
675 | break; | |
676 | } | |
677 | ||
678 | ret = IIO_VAL_INT; | |
679 | out: | |
a515d648 | 680 | mutex_unlock(&adc->aux_lock); |
1a99dc46 | 681 | clk_disable(adc->clk); |
a515d648 AR |
682 | |
683 | return ret; | |
684 | } | |
685 | ||
1a78daea AR |
686 | static int ingenic_adc_read_raw(struct iio_dev *iio_dev, |
687 | struct iio_chan_spec const *chan, | |
688 | int *val, | |
689 | int *val2, | |
690 | long m) | |
691 | { | |
692 | struct ingenic_adc *adc = iio_priv(iio_dev); | |
1a78daea AR |
693 | |
694 | switch (m) { | |
695 | case IIO_CHAN_INFO_RAW: | |
1a99dc46 | 696 | return ingenic_adc_read_chan_info_raw(iio_dev, chan, val); |
1a78daea AR |
697 | case IIO_CHAN_INFO_SCALE: |
698 | switch (chan->channel) { | |
b9e9bdd4 | 699 | case INGENIC_ADC_AUX0: |
1a78daea | 700 | case INGENIC_ADC_AUX: |
a515d648 | 701 | case INGENIC_ADC_AUX2: |
1a78daea AR |
702 | *val = JZ_ADC_AUX_VREF; |
703 | *val2 = JZ_ADC_AUX_VREF_BITS; | |
704 | break; | |
705 | case INGENIC_ADC_BATTERY: | |
706 | if (adc->low_vref_mode) { | |
707 | *val = JZ_ADC_BATTERY_LOW_VREF; | |
708 | *val2 = JZ_ADC_BATTERY_LOW_VREF_BITS; | |
709 | } else { | |
710 | *val = adc->soc_data->battery_high_vref; | |
711 | *val2 = adc->soc_data->battery_high_vref_bits; | |
712 | } | |
713 | break; | |
714 | } | |
715 | ||
716 | return IIO_VAL_FRACTIONAL_LOG2; | |
717 | default: | |
718 | return -EINVAL; | |
719 | } | |
720 | } | |
721 | ||
9ac07597 NS |
722 | static int ingenic_adc_fwnode_xlate(struct iio_dev *iio_dev, |
723 | const struct fwnode_reference_args *iiospec) | |
155e41ef AR |
724 | { |
725 | int i; | |
726 | ||
9ac07597 | 727 | if (!iiospec->nargs) |
155e41ef AR |
728 | return -EINVAL; |
729 | ||
730 | for (i = 0; i < iio_dev->num_channels; ++i) | |
731 | if (iio_dev->channels[i].channel == iiospec->args[0]) | |
732 | return i; | |
733 | ||
734 | return -EINVAL; | |
735 | } | |
736 | ||
1a78daea AR |
737 | static const struct iio_info ingenic_adc_info = { |
738 | .write_raw = ingenic_adc_write_raw, | |
739 | .read_raw = ingenic_adc_read_raw, | |
740 | .read_avail = ingenic_adc_read_avail, | |
9ac07597 | 741 | .fwnode_xlate = ingenic_adc_fwnode_xlate, |
1a78daea AR |
742 | }; |
743 | ||
b96952f4 AR |
744 | static int ingenic_adc_buffer_enable(struct iio_dev *iio_dev) |
745 | { | |
746 | struct ingenic_adc *adc = iio_priv(iio_dev); | |
747 | int ret; | |
748 | ||
749 | ret = clk_enable(adc->clk); | |
750 | if (ret) { | |
751 | dev_err(iio_dev->dev.parent, "Failed to enable clock: %d\n", | |
752 | ret); | |
753 | return ret; | |
754 | } | |
755 | ||
756 | /* It takes significant time for the touchscreen hw to stabilize. */ | |
757 | msleep(50); | |
758 | ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_TOUCH_OPS_MASK, | |
759 | JZ_ADC_REG_CFG_SAMPLE_NUM(4) | | |
760 | JZ_ADC_REG_CFG_PULL_UP(4)); | |
761 | ||
762 | writew(80, adc->base + JZ_ADC_REG_ADWAIT); | |
763 | writew(2, adc->base + JZ_ADC_REG_ADSAME); | |
764 | writeb((u8)~JZ_ADC_IRQ_TOUCH, adc->base + JZ_ADC_REG_CTRL); | |
765 | writel(0, adc->base + JZ_ADC_REG_ADTCH); | |
766 | ||
767 | ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_CMD_SEL, | |
768 | JZ_ADC_REG_CFG_CMD_SEL); | |
769 | ingenic_adc_set_adcmd(iio_dev, iio_dev->active_scan_mask[0]); | |
770 | ||
771 | ingenic_adc_enable(adc, 2, true); | |
772 | ||
773 | return 0; | |
774 | } | |
775 | ||
776 | static int ingenic_adc_buffer_disable(struct iio_dev *iio_dev) | |
777 | { | |
778 | struct ingenic_adc *adc = iio_priv(iio_dev); | |
779 | ||
780 | ingenic_adc_enable(adc, 2, false); | |
781 | ||
782 | ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_CMD_SEL, 0); | |
783 | ||
784 | writeb(0xff, adc->base + JZ_ADC_REG_CTRL); | |
785 | writeb(0xff, adc->base + JZ_ADC_REG_STATUS); | |
786 | ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_TOUCH_OPS_MASK, 0); | |
787 | writew(0, adc->base + JZ_ADC_REG_ADSAME); | |
788 | writew(0, adc->base + JZ_ADC_REG_ADWAIT); | |
789 | clk_disable(adc->clk); | |
790 | ||
791 | return 0; | |
792 | } | |
793 | ||
794 | static const struct iio_buffer_setup_ops ingenic_buffer_setup_ops = { | |
795 | .postenable = &ingenic_adc_buffer_enable, | |
796 | .predisable = &ingenic_adc_buffer_disable | |
1a78daea AR |
797 | }; |
798 | ||
b96952f4 AR |
799 | static irqreturn_t ingenic_adc_irq(int irq, void *data) |
800 | { | |
801 | struct iio_dev *iio_dev = data; | |
802 | struct ingenic_adc *adc = iio_priv(iio_dev); | |
803 | unsigned long mask = iio_dev->active_scan_mask[0]; | |
804 | unsigned int i; | |
805 | u32 tdat[3]; | |
806 | ||
807 | for (i = 0; i < ARRAY_SIZE(tdat); mask >>= 2, i++) { | |
808 | if (mask & 0x3) | |
809 | tdat[i] = readl(adc->base + JZ_ADC_REG_ADTCH); | |
810 | else | |
811 | tdat[i] = 0; | |
812 | } | |
813 | ||
814 | iio_push_to_buffers(iio_dev, tdat); | |
815 | writeb(JZ_ADC_IRQ_TOUCH, adc->base + JZ_ADC_REG_STATUS); | |
816 | ||
817 | return IRQ_HANDLED; | |
818 | } | |
819 | ||
1a78daea AR |
820 | static int ingenic_adc_probe(struct platform_device *pdev) |
821 | { | |
822 | struct device *dev = &pdev->dev; | |
823 | struct iio_dev *iio_dev; | |
824 | struct ingenic_adc *adc; | |
1a78daea | 825 | const struct ingenic_adc_soc_data *soc_data; |
b96952f4 | 826 | int irq, ret; |
1a78daea AR |
827 | |
828 | soc_data = device_get_match_data(dev); | |
829 | if (!soc_data) | |
830 | return -EINVAL; | |
831 | ||
832 | iio_dev = devm_iio_device_alloc(dev, sizeof(*adc)); | |
833 | if (!iio_dev) | |
834 | return -ENOMEM; | |
835 | ||
836 | adc = iio_priv(iio_dev); | |
837 | mutex_init(&adc->lock); | |
a515d648 | 838 | mutex_init(&adc->aux_lock); |
1a78daea AR |
839 | adc->soc_data = soc_data; |
840 | ||
b96952f4 AR |
841 | irq = platform_get_irq(pdev, 0); |
842 | if (irq < 0) | |
843 | return irq; | |
844 | ||
845 | ret = devm_request_irq(dev, irq, ingenic_adc_irq, 0, | |
846 | dev_name(dev), iio_dev); | |
847 | if (ret < 0) { | |
848 | dev_err(dev, "Failed to request irq: %d\n", ret); | |
849 | return ret; | |
850 | } | |
851 | ||
f449aa3e | 852 | adc->base = devm_platform_ioremap_resource(pdev, 0); |
76838a8f | 853 | if (IS_ERR(adc->base)) |
1a78daea | 854 | return PTR_ERR(adc->base); |
1a78daea | 855 | |
51f2f910 | 856 | adc->clk = devm_clk_get_prepared(dev, "adc"); |
1a78daea AR |
857 | if (IS_ERR(adc->clk)) { |
858 | dev_err(dev, "Unable to get clock\n"); | |
859 | return PTR_ERR(adc->clk); | |
860 | } | |
861 | ||
51f2f910 | 862 | ret = clk_enable(adc->clk); |
1a78daea AR |
863 | if (ret) { |
864 | dev_err(dev, "Failed to enable clock\n"); | |
865 | return ret; | |
866 | } | |
867 | ||
5a304e1a MH |
868 | /* Set clock dividers. */ |
869 | if (soc_data->init_clk_div) { | |
870 | ret = soc_data->init_clk_div(dev, adc); | |
871 | if (ret) { | |
872 | clk_disable_unprepare(adc->clk); | |
873 | return ret; | |
874 | } | |
875 | } | |
876 | ||
1a78daea AR |
877 | /* Put hardware in a known passive state. */ |
878 | writeb(0x00, adc->base + JZ_ADC_REG_ENABLE); | |
879 | writeb(0xff, adc->base + JZ_ADC_REG_CTRL); | |
bf1b2418 CB |
880 | |
881 | /* JZ4760B specific */ | |
882 | if (device_property_present(dev, "ingenic,use-internal-divider")) | |
883 | ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_VBAT_SEL, | |
884 | JZ_ADC_REG_CFG_VBAT_SEL); | |
885 | else | |
886 | ingenic_adc_set_config(adc, JZ_ADC_REG_CFG_VBAT_SEL, 0); | |
887 | ||
a515d648 | 888 | usleep_range(2000, 3000); /* Must wait at least 2ms. */ |
1a78daea AR |
889 | clk_disable(adc->clk); |
890 | ||
1a78daea | 891 | iio_dev->name = "jz-adc"; |
b96952f4 AR |
892 | iio_dev->modes = INDIO_DIRECT_MODE | INDIO_BUFFER_SOFTWARE; |
893 | iio_dev->setup_ops = &ingenic_buffer_setup_ops; | |
6a294b41 PC |
894 | iio_dev->channels = soc_data->channels; |
895 | iio_dev->num_channels = soc_data->num_channels; | |
1a78daea AR |
896 | iio_dev->info = &ingenic_adc_info; |
897 | ||
898 | ret = devm_iio_device_register(dev, iio_dev); | |
899 | if (ret) | |
900 | dev_err(dev, "Unable to register IIO device\n"); | |
901 | ||
902 | return ret; | |
903 | } | |
904 | ||
1a78daea AR |
905 | static const struct of_device_id ingenic_adc_of_match[] = { |
906 | { .compatible = "ingenic,jz4725b-adc", .data = &jz4725b_adc_soc_data, }, | |
907 | { .compatible = "ingenic,jz4740-adc", .data = &jz4740_adc_soc_data, }, | |
b9e9bdd4 | 908 | { .compatible = "ingenic,jz4760-adc", .data = &jz4760_adc_soc_data, }, |
bf1b2418 | 909 | { .compatible = "ingenic,jz4760b-adc", .data = &jz4760_adc_soc_data, }, |
a515d648 | 910 | { .compatible = "ingenic,jz4770-adc", .data = &jz4770_adc_soc_data, }, |
1a78daea AR |
911 | { }, |
912 | }; | |
913 | MODULE_DEVICE_TABLE(of, ingenic_adc_of_match); | |
1a78daea AR |
914 | |
915 | static struct platform_driver ingenic_adc_driver = { | |
916 | .driver = { | |
917 | .name = "ingenic-adc", | |
a07a4fe5 | 918 | .of_match_table = ingenic_adc_of_match, |
1a78daea AR |
919 | }, |
920 | .probe = ingenic_adc_probe, | |
921 | }; | |
922 | module_platform_driver(ingenic_adc_driver); | |
923 | MODULE_LICENSE("GPL v2"); |