Commit | Line | Data |
---|---|---|
70f19379 AT |
1 | /* |
2 | * Marvell Berlin2 ADC driver | |
3 | * | |
4 | * Copyright (C) 2015 Marvell Technology Group Ltd. | |
5 | * | |
6 | * Antoine Tenart <antoine.tenart@free-electrons.com> | |
7 | * | |
8 | * This file is licensed under the terms of the GNU General Public | |
9 | * License version 2. This program is licensed "as is" without any | |
10 | * warranty of any kind, whether express or implied. | |
11 | */ | |
12 | ||
13 | #include <linux/iio/iio.h> | |
14 | #include <linux/iio/driver.h> | |
15 | #include <linux/iio/machine.h> | |
16 | #include <linux/interrupt.h> | |
17 | #include <linux/kernel.h> | |
18 | #include <linux/module.h> | |
19 | #include <linux/platform_device.h> | |
20 | #include <linux/slab.h> | |
21 | #include <linux/mfd/syscon.h> | |
22 | #include <linux/regmap.h> | |
23 | #include <linux/sched.h> | |
24 | #include <linux/wait.h> | |
25 | ||
26 | #define BERLIN2_SM_CTRL 0x14 | |
27 | #define BERLIN2_SM_CTRL_SM_SOC_INT BIT(1) | |
28 | #define BERLIN2_SM_CTRL_SOC_SM_INT BIT(2) | |
57cb0676 | 29 | #define BERLIN2_SM_CTRL_ADC_SEL(x) ((x) << 5) /* 0-15 */ |
4b308e8c | 30 | #define BERLIN2_SM_CTRL_ADC_SEL_MASK GENMASK(8, 5) |
70f19379 AT |
31 | #define BERLIN2_SM_CTRL_ADC_POWER BIT(9) |
32 | #define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV2 (0x0 << 10) | |
33 | #define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV3 (0x1 << 10) | |
34 | #define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV4 (0x2 << 10) | |
35 | #define BERLIN2_SM_CTRL_ADC_CLKSEL_DIV8 (0x3 << 10) | |
4b308e8c | 36 | #define BERLIN2_SM_CTRL_ADC_CLKSEL_MASK GENMASK(11, 10) |
70f19379 AT |
37 | #define BERLIN2_SM_CTRL_ADC_START BIT(12) |
38 | #define BERLIN2_SM_CTRL_ADC_RESET BIT(13) | |
39 | #define BERLIN2_SM_CTRL_ADC_BANDGAP_RDY BIT(14) | |
40 | #define BERLIN2_SM_CTRL_ADC_CONT_SINGLE (0x0 << 15) | |
41 | #define BERLIN2_SM_CTRL_ADC_CONT_CONTINUOUS (0x1 << 15) | |
42 | #define BERLIN2_SM_CTRL_ADC_BUFFER_EN BIT(16) | |
43 | #define BERLIN2_SM_CTRL_ADC_VREF_EXT (0x0 << 17) | |
44 | #define BERLIN2_SM_CTRL_ADC_VREF_INT (0x1 << 17) | |
45 | #define BERLIN2_SM_CTRL_ADC_ROTATE BIT(19) | |
46 | #define BERLIN2_SM_CTRL_TSEN_EN BIT(20) | |
47 | #define BERLIN2_SM_CTRL_TSEN_CLK_SEL_125 (0x0 << 21) /* 1.25 MHz */ | |
48 | #define BERLIN2_SM_CTRL_TSEN_CLK_SEL_250 (0x1 << 21) /* 2.5 MHz */ | |
49 | #define BERLIN2_SM_CTRL_TSEN_MODE_0_125 (0x0 << 22) /* 0-125 C */ | |
50 | #define BERLIN2_SM_CTRL_TSEN_MODE_10_50 (0x1 << 22) /* 10-50 C */ | |
51 | #define BERLIN2_SM_CTRL_TSEN_RESET BIT(29) | |
52 | #define BERLIN2_SM_ADC_DATA 0x20 | |
4b308e8c | 53 | #define BERLIN2_SM_ADC_MASK GENMASK(9, 0) |
70f19379 AT |
54 | #define BERLIN2_SM_ADC_STATUS 0x1c |
55 | #define BERLIN2_SM_ADC_STATUS_DATA_RDY(x) BIT(x) /* 0-15 */ | |
57cb0676 | 56 | #define BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK GENMASK(15, 0) |
70f19379 | 57 | #define BERLIN2_SM_ADC_STATUS_INT_EN(x) (BIT(x) << 16) /* 0-15 */ |
57cb0676 | 58 | #define BERLIN2_SM_ADC_STATUS_INT_EN_MASK GENMASK(31, 16) |
70f19379 AT |
59 | #define BERLIN2_SM_TSEN_STATUS 0x24 |
60 | #define BERLIN2_SM_TSEN_STATUS_DATA_RDY BIT(0) | |
61 | #define BERLIN2_SM_TSEN_STATUS_INT_EN BIT(1) | |
62 | #define BERLIN2_SM_TSEN_DATA 0x28 | |
57cb0676 | 63 | #define BERLIN2_SM_TSEN_MASK GENMASK(9, 0) |
70f19379 AT |
64 | #define BERLIN2_SM_TSEN_CTRL 0x74 |
65 | #define BERLIN2_SM_TSEN_CTRL_START BIT(8) | |
66 | #define BERLIN2_SM_TSEN_CTRL_SETTLING_4 (0x0 << 21) /* 4 us */ | |
67 | #define BERLIN2_SM_TSEN_CTRL_SETTLING_12 (0x1 << 21) /* 12 us */ | |
4b308e8c | 68 | #define BERLIN2_SM_TSEN_CTRL_SETTLING_MASK BIT(21) |
70f19379 | 69 | #define BERLIN2_SM_TSEN_CTRL_TRIM(x) ((x) << 22) |
4b308e8c | 70 | #define BERLIN2_SM_TSEN_CTRL_TRIM_MASK GENMASK(25, 22) |
70f19379 AT |
71 | |
72 | struct berlin2_adc_priv { | |
73 | struct regmap *regmap; | |
74 | struct mutex lock; | |
75 | wait_queue_head_t wq; | |
76 | bool data_available; | |
77 | int data; | |
78 | }; | |
79 | ||
80 | #define BERLIN2_ADC_CHANNEL(n, t) \ | |
b465fc54 HK |
81 | { \ |
82 | .channel = n, \ | |
83 | .datasheet_name = "channel"#n, \ | |
84 | .type = t, \ | |
85 | .indexed = 1, \ | |
86 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | |
87 | } | |
70f19379 | 88 | |
688febbd | 89 | static const struct iio_chan_spec berlin2_adc_channels[] = { |
70f19379 AT |
90 | BERLIN2_ADC_CHANNEL(0, IIO_VOLTAGE), /* external input */ |
91 | BERLIN2_ADC_CHANNEL(1, IIO_VOLTAGE), /* external input */ | |
92 | BERLIN2_ADC_CHANNEL(2, IIO_VOLTAGE), /* external input */ | |
93 | BERLIN2_ADC_CHANNEL(3, IIO_VOLTAGE), /* external input */ | |
94 | BERLIN2_ADC_CHANNEL(4, IIO_VOLTAGE), /* reserved */ | |
95 | BERLIN2_ADC_CHANNEL(5, IIO_VOLTAGE), /* reserved */ | |
96 | { /* temperature sensor */ | |
97 | .channel = 6, | |
98 | .datasheet_name = "channel6", | |
99 | .type = IIO_TEMP, | |
100 | .indexed = 0, | |
101 | .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), | |
102 | }, | |
103 | BERLIN2_ADC_CHANNEL(7, IIO_VOLTAGE), /* reserved */ | |
104 | IIO_CHAN_SOFT_TIMESTAMP(8), /* timestamp */ | |
105 | }; | |
70f19379 AT |
106 | |
107 | static int berlin2_adc_read(struct iio_dev *indio_dev, int channel) | |
108 | { | |
109 | struct berlin2_adc_priv *priv = iio_priv(indio_dev); | |
110 | int data, ret; | |
111 | ||
112 | mutex_lock(&priv->lock); | |
113 | ||
3ac06522 HK |
114 | /* Enable the interrupts */ |
115 | regmap_write(priv->regmap, BERLIN2_SM_ADC_STATUS, | |
116 | BERLIN2_SM_ADC_STATUS_INT_EN(channel)); | |
117 | ||
70f19379 AT |
118 | /* Configure the ADC */ |
119 | regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, | |
b465fc54 HK |
120 | BERLIN2_SM_CTRL_ADC_RESET | |
121 | BERLIN2_SM_CTRL_ADC_SEL_MASK | | |
122 | BERLIN2_SM_CTRL_ADC_START, | |
123 | BERLIN2_SM_CTRL_ADC_SEL(channel) | | |
124 | BERLIN2_SM_CTRL_ADC_START); | |
70f19379 AT |
125 | |
126 | ret = wait_event_interruptible_timeout(priv->wq, priv->data_available, | |
b465fc54 | 127 | msecs_to_jiffies(1000)); |
70f19379 AT |
128 | |
129 | /* Disable the interrupts */ | |
130 | regmap_update_bits(priv->regmap, BERLIN2_SM_ADC_STATUS, | |
b465fc54 | 131 | BERLIN2_SM_ADC_STATUS_INT_EN(channel), 0); |
70f19379 AT |
132 | |
133 | if (ret == 0) | |
134 | ret = -ETIMEDOUT; | |
135 | if (ret < 0) { | |
136 | mutex_unlock(&priv->lock); | |
137 | return ret; | |
138 | } | |
139 | ||
140 | regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, | |
b465fc54 | 141 | BERLIN2_SM_CTRL_ADC_START, 0); |
70f19379 AT |
142 | |
143 | data = priv->data; | |
144 | priv->data_available = false; | |
145 | ||
146 | mutex_unlock(&priv->lock); | |
147 | ||
148 | return data; | |
149 | } | |
150 | ||
151 | static int berlin2_adc_tsen_read(struct iio_dev *indio_dev) | |
152 | { | |
153 | struct berlin2_adc_priv *priv = iio_priv(indio_dev); | |
154 | int data, ret; | |
155 | ||
156 | mutex_lock(&priv->lock); | |
157 | ||
3ac06522 HK |
158 | /* Enable interrupts */ |
159 | regmap_write(priv->regmap, BERLIN2_SM_TSEN_STATUS, | |
160 | BERLIN2_SM_TSEN_STATUS_INT_EN); | |
161 | ||
70f19379 AT |
162 | /* Configure the ADC */ |
163 | regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, | |
b465fc54 HK |
164 | BERLIN2_SM_CTRL_TSEN_RESET | |
165 | BERLIN2_SM_CTRL_ADC_ROTATE, | |
166 | BERLIN2_SM_CTRL_ADC_ROTATE); | |
70f19379 AT |
167 | |
168 | /* Configure the temperature sensor */ | |
169 | regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL, | |
b465fc54 HK |
170 | BERLIN2_SM_TSEN_CTRL_TRIM_MASK | |
171 | BERLIN2_SM_TSEN_CTRL_SETTLING_MASK | | |
172 | BERLIN2_SM_TSEN_CTRL_START, | |
173 | BERLIN2_SM_TSEN_CTRL_TRIM(3) | | |
174 | BERLIN2_SM_TSEN_CTRL_SETTLING_12 | | |
175 | BERLIN2_SM_TSEN_CTRL_START); | |
70f19379 AT |
176 | |
177 | ret = wait_event_interruptible_timeout(priv->wq, priv->data_available, | |
b465fc54 | 178 | msecs_to_jiffies(1000)); |
70f19379 AT |
179 | |
180 | /* Disable interrupts */ | |
181 | regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_STATUS, | |
b465fc54 | 182 | BERLIN2_SM_TSEN_STATUS_INT_EN, 0); |
70f19379 AT |
183 | |
184 | if (ret == 0) | |
185 | ret = -ETIMEDOUT; | |
186 | if (ret < 0) { | |
187 | mutex_unlock(&priv->lock); | |
188 | return ret; | |
189 | } | |
190 | ||
191 | regmap_update_bits(priv->regmap, BERLIN2_SM_TSEN_CTRL, | |
b465fc54 | 192 | BERLIN2_SM_TSEN_CTRL_START, 0); |
70f19379 AT |
193 | |
194 | data = priv->data; | |
195 | priv->data_available = false; | |
196 | ||
197 | mutex_unlock(&priv->lock); | |
198 | ||
199 | return data; | |
200 | } | |
201 | ||
202 | static int berlin2_adc_read_raw(struct iio_dev *indio_dev, | |
b465fc54 HK |
203 | struct iio_chan_spec const *chan, int *val, |
204 | int *val2, long mask) | |
70f19379 | 205 | { |
70f19379 AT |
206 | int temp; |
207 | ||
208 | switch (mask) { | |
209 | case IIO_CHAN_INFO_RAW: | |
210 | if (chan->type != IIO_VOLTAGE) | |
211 | return -EINVAL; | |
212 | ||
70f19379 AT |
213 | *val = berlin2_adc_read(indio_dev, chan->channel); |
214 | if (*val < 0) | |
215 | return *val; | |
216 | ||
217 | return IIO_VAL_INT; | |
218 | case IIO_CHAN_INFO_PROCESSED: | |
219 | if (chan->type != IIO_TEMP) | |
220 | return -EINVAL; | |
221 | ||
70f19379 AT |
222 | temp = berlin2_adc_tsen_read(indio_dev); |
223 | if (temp < 0) | |
224 | return temp; | |
225 | ||
226 | if (temp > 2047) | |
609e9d88 | 227 | temp -= 4096; |
70f19379 AT |
228 | |
229 | /* Convert to milli Celsius */ | |
230 | *val = ((temp * 100000) / 264 - 270000); | |
231 | return IIO_VAL_INT; | |
232 | default: | |
233 | break; | |
234 | } | |
235 | ||
236 | return -EINVAL; | |
237 | } | |
238 | ||
239 | static irqreturn_t berlin2_adc_irq(int irq, void *private) | |
240 | { | |
241 | struct berlin2_adc_priv *priv = iio_priv(private); | |
242 | unsigned val; | |
243 | ||
244 | regmap_read(priv->regmap, BERLIN2_SM_ADC_STATUS, &val); | |
245 | if (val & BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK) { | |
246 | regmap_read(priv->regmap, BERLIN2_SM_ADC_DATA, &priv->data); | |
247 | priv->data &= BERLIN2_SM_ADC_MASK; | |
248 | ||
249 | val &= ~BERLIN2_SM_ADC_STATUS_DATA_RDY_MASK; | |
250 | regmap_write(priv->regmap, BERLIN2_SM_ADC_STATUS, val); | |
251 | ||
252 | priv->data_available = true; | |
253 | wake_up_interruptible(&priv->wq); | |
254 | } | |
255 | ||
256 | return IRQ_HANDLED; | |
257 | } | |
258 | ||
259 | static irqreturn_t berlin2_adc_tsen_irq(int irq, void *private) | |
260 | { | |
261 | struct berlin2_adc_priv *priv = iio_priv(private); | |
262 | unsigned val; | |
263 | ||
264 | regmap_read(priv->regmap, BERLIN2_SM_TSEN_STATUS, &val); | |
265 | if (val & BERLIN2_SM_TSEN_STATUS_DATA_RDY) { | |
266 | regmap_read(priv->regmap, BERLIN2_SM_TSEN_DATA, &priv->data); | |
267 | priv->data &= BERLIN2_SM_TSEN_MASK; | |
268 | ||
269 | val &= ~BERLIN2_SM_TSEN_STATUS_DATA_RDY; | |
270 | regmap_write(priv->regmap, BERLIN2_SM_TSEN_STATUS, val); | |
271 | ||
272 | priv->data_available = true; | |
273 | wake_up_interruptible(&priv->wq); | |
274 | } | |
275 | ||
276 | return IRQ_HANDLED; | |
277 | } | |
278 | ||
279 | static const struct iio_info berlin2_adc_info = { | |
280 | .driver_module = THIS_MODULE, | |
281 | .read_raw = berlin2_adc_read_raw, | |
282 | }; | |
283 | ||
284 | static int berlin2_adc_probe(struct platform_device *pdev) | |
285 | { | |
286 | struct iio_dev *indio_dev; | |
287 | struct berlin2_adc_priv *priv; | |
288 | struct device_node *parent_np = of_get_parent(pdev->dev.of_node); | |
289 | int irq, tsen_irq; | |
290 | int ret; | |
291 | ||
609e9d88 | 292 | indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*priv)); |
70f19379 AT |
293 | if (!indio_dev) |
294 | return -ENOMEM; | |
295 | ||
296 | priv = iio_priv(indio_dev); | |
297 | platform_set_drvdata(pdev, indio_dev); | |
298 | ||
299 | priv->regmap = syscon_node_to_regmap(parent_np); | |
300 | of_node_put(parent_np); | |
301 | if (IS_ERR(priv->regmap)) | |
302 | return PTR_ERR(priv->regmap); | |
303 | ||
304 | irq = platform_get_irq_byname(pdev, "adc"); | |
305 | if (irq < 0) | |
19d56642 | 306 | return irq; |
70f19379 AT |
307 | |
308 | tsen_irq = platform_get_irq_byname(pdev, "tsen"); | |
309 | if (tsen_irq < 0) | |
19d56642 | 310 | return tsen_irq; |
70f19379 AT |
311 | |
312 | ret = devm_request_irq(&pdev->dev, irq, berlin2_adc_irq, 0, | |
b465fc54 | 313 | pdev->dev.driver->name, indio_dev); |
70f19379 AT |
314 | if (ret) |
315 | return ret; | |
316 | ||
317 | ret = devm_request_irq(&pdev->dev, tsen_irq, berlin2_adc_tsen_irq, | |
b465fc54 | 318 | 0, pdev->dev.driver->name, indio_dev); |
70f19379 AT |
319 | if (ret) |
320 | return ret; | |
321 | ||
322 | init_waitqueue_head(&priv->wq); | |
323 | mutex_init(&priv->lock); | |
324 | ||
325 | indio_dev->dev.parent = &pdev->dev; | |
326 | indio_dev->name = dev_name(&pdev->dev); | |
327 | indio_dev->modes = INDIO_DIRECT_MODE; | |
328 | indio_dev->info = &berlin2_adc_info; | |
329 | ||
70f19379 | 330 | indio_dev->channels = berlin2_adc_channels; |
546384c9 | 331 | indio_dev->num_channels = ARRAY_SIZE(berlin2_adc_channels); |
70f19379 AT |
332 | |
333 | /* Power up the ADC */ | |
334 | regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, | |
b465fc54 HK |
335 | BERLIN2_SM_CTRL_ADC_POWER, |
336 | BERLIN2_SM_CTRL_ADC_POWER); | |
70f19379 AT |
337 | |
338 | ret = iio_device_register(indio_dev); | |
339 | if (ret) { | |
340 | /* Power down the ADC */ | |
341 | regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, | |
b465fc54 | 342 | BERLIN2_SM_CTRL_ADC_POWER, 0); |
70f19379 AT |
343 | return ret; |
344 | } | |
345 | ||
346 | return 0; | |
347 | } | |
348 | ||
349 | static int berlin2_adc_remove(struct platform_device *pdev) | |
350 | { | |
351 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); | |
352 | struct berlin2_adc_priv *priv = iio_priv(indio_dev); | |
353 | ||
354 | iio_device_unregister(indio_dev); | |
355 | ||
356 | /* Power down the ADC */ | |
357 | regmap_update_bits(priv->regmap, BERLIN2_SM_CTRL, | |
b465fc54 | 358 | BERLIN2_SM_CTRL_ADC_POWER, 0); |
70f19379 AT |
359 | |
360 | return 0; | |
361 | } | |
362 | ||
363 | static const struct of_device_id berlin2_adc_match[] = { | |
364 | { .compatible = "marvell,berlin2-adc", }, | |
365 | { }, | |
366 | }; | |
367 | MODULE_DEVICE_TABLE(of, berlin2_adc_match); | |
368 | ||
369 | static struct platform_driver berlin2_adc_driver = { | |
370 | .driver = { | |
371 | .name = "berlin2-adc", | |
372 | .of_match_table = berlin2_adc_match, | |
373 | }, | |
374 | .probe = berlin2_adc_probe, | |
375 | .remove = berlin2_adc_remove, | |
376 | }; | |
377 | module_platform_driver(berlin2_adc_driver); | |
378 | ||
379 | MODULE_AUTHOR("Antoine Tenart <antoine.tenart@free-electrons.com>"); | |
380 | MODULE_DESCRIPTION("Marvell Berlin2 ADC driver"); | |
381 | MODULE_LICENSE("GPL v2"); |