Merge tag 'for-5.2/block-20190507' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / drivers / iio / adc / ingenic-adc.c
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>
11 #include <linux/iio/iio.h>
12 #include <linux/io.h>
13 #include <linux/iopoll.h>
14 #include <linux/module.h>
15 #include <linux/mutex.h>
16 #include <linux/platform_device.h>
17
18 #define JZ_ADC_REG_ENABLE               0x00
19 #define JZ_ADC_REG_CFG                  0x04
20 #define JZ_ADC_REG_CTRL                 0x08
21 #define JZ_ADC_REG_STATUS               0x0c
22 #define JZ_ADC_REG_ADTCH                0x18
23 #define JZ_ADC_REG_ADBDAT               0x1c
24 #define JZ_ADC_REG_ADSDAT               0x20
25
26 #define JZ_ADC_REG_CFG_BAT_MD           BIT(4)
27
28 #define JZ_ADC_AUX_VREF                         3300
29 #define JZ_ADC_AUX_VREF_BITS                    12
30 #define JZ_ADC_BATTERY_LOW_VREF                 2500
31 #define JZ_ADC_BATTERY_LOW_VREF_BITS            12
32 #define JZ4725B_ADC_BATTERY_HIGH_VREF           7500
33 #define JZ4725B_ADC_BATTERY_HIGH_VREF_BITS      10
34 #define JZ4740_ADC_BATTERY_HIGH_VREF            (7500 * 0.986)
35 #define JZ4740_ADC_BATTERY_HIGH_VREF_BITS       12
36
37 struct ingenic_adc_soc_data {
38         unsigned int battery_high_vref;
39         unsigned int battery_high_vref_bits;
40         const int *battery_raw_avail;
41         size_t battery_raw_avail_size;
42         const int *battery_scale_avail;
43         size_t battery_scale_avail_size;
44 };
45
46 struct ingenic_adc {
47         void __iomem *base;
48         struct clk *clk;
49         struct mutex lock;
50         const struct ingenic_adc_soc_data *soc_data;
51         bool low_vref_mode;
52 };
53
54 static void ingenic_adc_set_config(struct ingenic_adc *adc,
55                                    uint32_t mask,
56                                    uint32_t val)
57 {
58         uint32_t cfg;
59
60         clk_enable(adc->clk);
61         mutex_lock(&adc->lock);
62
63         cfg = readl(adc->base + JZ_ADC_REG_CFG) & ~mask;
64         cfg |= val;
65         writel(cfg, adc->base + JZ_ADC_REG_CFG);
66
67         mutex_unlock(&adc->lock);
68         clk_disable(adc->clk);
69 }
70
71 static void ingenic_adc_enable(struct ingenic_adc *adc,
72                                int engine,
73                                bool enabled)
74 {
75         u8 val;
76
77         mutex_lock(&adc->lock);
78         val = readb(adc->base + JZ_ADC_REG_ENABLE);
79
80         if (enabled)
81                 val |= BIT(engine);
82         else
83                 val &= ~BIT(engine);
84
85         writeb(val, adc->base + JZ_ADC_REG_ENABLE);
86         mutex_unlock(&adc->lock);
87 }
88
89 static int ingenic_adc_capture(struct ingenic_adc *adc,
90                                int engine)
91 {
92         u8 val;
93         int ret;
94
95         ingenic_adc_enable(adc, engine, true);
96         ret = readb_poll_timeout(adc->base + JZ_ADC_REG_ENABLE, val,
97                                  !(val & BIT(engine)), 250, 1000);
98         if (ret)
99                 ingenic_adc_enable(adc, engine, false);
100
101         return ret;
102 }
103
104 static int ingenic_adc_write_raw(struct iio_dev *iio_dev,
105                                  struct iio_chan_spec const *chan,
106                                  int val,
107                                  int val2,
108                                  long m)
109 {
110         struct ingenic_adc *adc = iio_priv(iio_dev);
111
112         switch (m) {
113         case IIO_CHAN_INFO_SCALE:
114                 switch (chan->channel) {
115                 case INGENIC_ADC_BATTERY:
116                         if (val > JZ_ADC_BATTERY_LOW_VREF) {
117                                 ingenic_adc_set_config(adc,
118                                                        JZ_ADC_REG_CFG_BAT_MD,
119                                                        0);
120                                 adc->low_vref_mode = false;
121                         } else {
122                                 ingenic_adc_set_config(adc,
123                                                        JZ_ADC_REG_CFG_BAT_MD,
124                                                        JZ_ADC_REG_CFG_BAT_MD);
125                                 adc->low_vref_mode = true;
126                         }
127                         return 0;
128                 default:
129                         return -EINVAL;
130                 }
131         default:
132                 return -EINVAL;
133         }
134 }
135
136 static const int jz4725b_adc_battery_raw_avail[] = {
137         0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1,
138 };
139
140 static const int jz4725b_adc_battery_scale_avail[] = {
141         JZ4725B_ADC_BATTERY_HIGH_VREF, JZ4725B_ADC_BATTERY_HIGH_VREF_BITS,
142         JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
143 };
144
145 static const int jz4740_adc_battery_raw_avail[] = {
146         0, 1, (1 << JZ_ADC_BATTERY_LOW_VREF_BITS) - 1,
147 };
148
149 static const int jz4740_adc_battery_scale_avail[] = {
150         JZ4740_ADC_BATTERY_HIGH_VREF, JZ4740_ADC_BATTERY_HIGH_VREF_BITS,
151         JZ_ADC_BATTERY_LOW_VREF, JZ_ADC_BATTERY_LOW_VREF_BITS,
152 };
153
154 static const struct ingenic_adc_soc_data jz4725b_adc_soc_data = {
155         .battery_high_vref = JZ4725B_ADC_BATTERY_HIGH_VREF,
156         .battery_high_vref_bits = JZ4725B_ADC_BATTERY_HIGH_VREF_BITS,
157         .battery_raw_avail = jz4725b_adc_battery_raw_avail,
158         .battery_raw_avail_size = ARRAY_SIZE(jz4725b_adc_battery_raw_avail),
159         .battery_scale_avail = jz4725b_adc_battery_scale_avail,
160         .battery_scale_avail_size = ARRAY_SIZE(jz4725b_adc_battery_scale_avail),
161 };
162
163 static const struct ingenic_adc_soc_data jz4740_adc_soc_data = {
164         .battery_high_vref = JZ4740_ADC_BATTERY_HIGH_VREF,
165         .battery_high_vref_bits = JZ4740_ADC_BATTERY_HIGH_VREF_BITS,
166         .battery_raw_avail = jz4740_adc_battery_raw_avail,
167         .battery_raw_avail_size = ARRAY_SIZE(jz4740_adc_battery_raw_avail),
168         .battery_scale_avail = jz4740_adc_battery_scale_avail,
169         .battery_scale_avail_size = ARRAY_SIZE(jz4740_adc_battery_scale_avail),
170 };
171
172 static int ingenic_adc_read_avail(struct iio_dev *iio_dev,
173                                   struct iio_chan_spec const *chan,
174                                   const int **vals,
175                                   int *type,
176                                   int *length,
177                                   long m)
178 {
179         struct ingenic_adc *adc = iio_priv(iio_dev);
180
181         switch (m) {
182         case IIO_CHAN_INFO_RAW:
183                 *type = IIO_VAL_INT;
184                 *length = adc->soc_data->battery_raw_avail_size;
185                 *vals = adc->soc_data->battery_raw_avail;
186                 return IIO_AVAIL_RANGE;
187         case IIO_CHAN_INFO_SCALE:
188                 *type = IIO_VAL_FRACTIONAL_LOG2;
189                 *length = adc->soc_data->battery_scale_avail_size;
190                 *vals = adc->soc_data->battery_scale_avail;
191                 return IIO_AVAIL_LIST;
192         default:
193                 return -EINVAL;
194         };
195 }
196
197 static int ingenic_adc_read_raw(struct iio_dev *iio_dev,
198                                 struct iio_chan_spec const *chan,
199                                 int *val,
200                                 int *val2,
201                                 long m)
202 {
203         struct ingenic_adc *adc = iio_priv(iio_dev);
204         int ret;
205
206         switch (m) {
207         case IIO_CHAN_INFO_RAW:
208                 clk_enable(adc->clk);
209                 ret = ingenic_adc_capture(adc, chan->channel);
210                 if (ret) {
211                         clk_disable(adc->clk);
212                         return ret;
213                 }
214
215                 switch (chan->channel) {
216                 case INGENIC_ADC_AUX:
217                         *val = readw(adc->base + JZ_ADC_REG_ADSDAT);
218                         break;
219                 case INGENIC_ADC_BATTERY:
220                         *val = readw(adc->base + JZ_ADC_REG_ADBDAT);
221                         break;
222                 }
223
224                 clk_disable(adc->clk);
225
226                 return IIO_VAL_INT;
227         case IIO_CHAN_INFO_SCALE:
228                 switch (chan->channel) {
229                 case INGENIC_ADC_AUX:
230                         *val = JZ_ADC_AUX_VREF;
231                         *val2 = JZ_ADC_AUX_VREF_BITS;
232                         break;
233                 case INGENIC_ADC_BATTERY:
234                         if (adc->low_vref_mode) {
235                                 *val = JZ_ADC_BATTERY_LOW_VREF;
236                                 *val2 = JZ_ADC_BATTERY_LOW_VREF_BITS;
237                         } else {
238                                 *val = adc->soc_data->battery_high_vref;
239                                 *val2 = adc->soc_data->battery_high_vref_bits;
240                         }
241                         break;
242                 }
243
244                 return IIO_VAL_FRACTIONAL_LOG2;
245         default:
246                 return -EINVAL;
247         }
248 }
249
250 static void ingenic_adc_clk_cleanup(void *data)
251 {
252         clk_unprepare(data);
253 }
254
255 static const struct iio_info ingenic_adc_info = {
256         .write_raw = ingenic_adc_write_raw,
257         .read_raw = ingenic_adc_read_raw,
258         .read_avail = ingenic_adc_read_avail,
259 };
260
261 static const struct iio_chan_spec ingenic_channels[] = {
262         {
263                 .extend_name = "aux",
264                 .type = IIO_VOLTAGE,
265                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
266                                       BIT(IIO_CHAN_INFO_SCALE),
267                 .indexed = 1,
268                 .channel = INGENIC_ADC_AUX,
269         },
270         {
271                 .extend_name = "battery",
272                 .type = IIO_VOLTAGE,
273                 .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
274                                       BIT(IIO_CHAN_INFO_SCALE),
275                 .info_mask_separate_available = BIT(IIO_CHAN_INFO_RAW) |
276                                                 BIT(IIO_CHAN_INFO_SCALE),
277                 .indexed = 1,
278                 .channel = INGENIC_ADC_BATTERY,
279         },
280 };
281
282 static int ingenic_adc_probe(struct platform_device *pdev)
283 {
284         struct device *dev = &pdev->dev;
285         struct iio_dev *iio_dev;
286         struct ingenic_adc *adc;
287         struct resource *mem_base;
288         const struct ingenic_adc_soc_data *soc_data;
289         int ret;
290
291         soc_data = device_get_match_data(dev);
292         if (!soc_data)
293                 return -EINVAL;
294
295         iio_dev = devm_iio_device_alloc(dev, sizeof(*adc));
296         if (!iio_dev)
297                 return -ENOMEM;
298
299         adc = iio_priv(iio_dev);
300         mutex_init(&adc->lock);
301         adc->soc_data = soc_data;
302
303         mem_base = platform_get_resource(pdev, IORESOURCE_MEM, 0);
304         adc->base = devm_ioremap_resource(dev, mem_base);
305         if (IS_ERR(adc->base))
306                 return PTR_ERR(adc->base);
307
308         adc->clk = devm_clk_get(dev, "adc");
309         if (IS_ERR(adc->clk)) {
310                 dev_err(dev, "Unable to get clock\n");
311                 return PTR_ERR(adc->clk);
312         }
313
314         ret = clk_prepare_enable(adc->clk);
315         if (ret) {
316                 dev_err(dev, "Failed to enable clock\n");
317                 return ret;
318         }
319
320         /* Put hardware in a known passive state. */
321         writeb(0x00, adc->base + JZ_ADC_REG_ENABLE);
322         writeb(0xff, adc->base + JZ_ADC_REG_CTRL);
323         clk_disable(adc->clk);
324
325         ret = devm_add_action_or_reset(dev, ingenic_adc_clk_cleanup, adc->clk);
326         if (ret) {
327                 dev_err(dev, "Unable to add action\n");
328                 return ret;
329         }
330
331         iio_dev->dev.parent = dev;
332         iio_dev->name = "jz-adc";
333         iio_dev->modes = INDIO_DIRECT_MODE;
334         iio_dev->channels = ingenic_channels;
335         iio_dev->num_channels = ARRAY_SIZE(ingenic_channels);
336         iio_dev->info = &ingenic_adc_info;
337
338         ret = devm_iio_device_register(dev, iio_dev);
339         if (ret)
340                 dev_err(dev, "Unable to register IIO device\n");
341
342         return ret;
343 }
344
345 #ifdef CONFIG_OF
346 static const struct of_device_id ingenic_adc_of_match[] = {
347         { .compatible = "ingenic,jz4725b-adc", .data = &jz4725b_adc_soc_data, },
348         { .compatible = "ingenic,jz4740-adc", .data = &jz4740_adc_soc_data, },
349         { },
350 };
351 MODULE_DEVICE_TABLE(of, ingenic_adc_of_match);
352 #endif
353
354 static struct platform_driver ingenic_adc_driver = {
355         .driver = {
356                 .name = "ingenic-adc",
357                 .of_match_table = of_match_ptr(ingenic_adc_of_match),
358         },
359         .probe = ingenic_adc_probe,
360 };
361 module_platform_driver(ingenic_adc_driver);
362 MODULE_LICENSE("GPL v2");