Commit | Line | Data |
---|---|---|
44d6f2ef HS |
1 | /* |
2 | * Rockchip Successive Approximation Register (SAR) A/D Converter | |
3 | * Copyright (C) 2014 ROCKCHIP, Inc. | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * This program is distributed in the hope that it will be useful, | |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 | * GNU General Public License for more details. | |
14 | */ | |
15 | ||
16 | #include <linux/module.h> | |
17 | #include <linux/platform_device.h> | |
18 | #include <linux/interrupt.h> | |
19 | #include <linux/io.h> | |
20 | #include <linux/of.h> | |
4c21bbb4 | 21 | #include <linux/of_device.h> |
44d6f2ef HS |
22 | #include <linux/clk.h> |
23 | #include <linux/completion.h> | |
543852af CW |
24 | #include <linux/delay.h> |
25 | #include <linux/reset.h> | |
44d6f2ef HS |
26 | #include <linux/regulator/consumer.h> |
27 | #include <linux/iio/iio.h> | |
28 | ||
29 | #define SARADC_DATA 0x00 | |
44d6f2ef HS |
30 | |
31 | #define SARADC_STAS 0x04 | |
32 | #define SARADC_STAS_BUSY BIT(0) | |
33 | ||
34 | #define SARADC_CTRL 0x08 | |
35 | #define SARADC_CTRL_IRQ_STATUS BIT(6) | |
36 | #define SARADC_CTRL_IRQ_ENABLE BIT(5) | |
37 | #define SARADC_CTRL_POWER_CTRL BIT(3) | |
38 | #define SARADC_CTRL_CHN_MASK 0x7 | |
39 | ||
40 | #define SARADC_DLY_PU_SOC 0x0c | |
41 | #define SARADC_DLY_PU_SOC_MASK 0x3f | |
42 | ||
44d6f2ef HS |
43 | #define SARADC_TIMEOUT msecs_to_jiffies(100) |
44 | ||
4c21bbb4 HS |
45 | struct rockchip_saradc_data { |
46 | int num_bits; | |
47 | const struct iio_chan_spec *channels; | |
48 | int num_channels; | |
49 | unsigned long clk_rate; | |
50 | }; | |
51 | ||
44d6f2ef HS |
52 | struct rockchip_saradc { |
53 | void __iomem *regs; | |
54 | struct clk *pclk; | |
55 | struct clk *clk; | |
56 | struct completion completion; | |
57 | struct regulator *vref; | |
543852af | 58 | struct reset_control *reset; |
4c21bbb4 | 59 | const struct rockchip_saradc_data *data; |
44d6f2ef HS |
60 | u16 last_val; |
61 | }; | |
62 | ||
63 | static int rockchip_saradc_read_raw(struct iio_dev *indio_dev, | |
64 | struct iio_chan_spec const *chan, | |
65 | int *val, int *val2, long mask) | |
66 | { | |
67 | struct rockchip_saradc *info = iio_priv(indio_dev); | |
68 | int ret; | |
69 | ||
70 | switch (mask) { | |
71 | case IIO_CHAN_INFO_RAW: | |
72 | mutex_lock(&indio_dev->mlock); | |
73 | ||
74 | reinit_completion(&info->completion); | |
75 | ||
76 | /* 8 clock periods as delay between power up and start cmd */ | |
77 | writel_relaxed(8, info->regs + SARADC_DLY_PU_SOC); | |
78 | ||
79 | /* Select the channel to be used and trigger conversion */ | |
80 | writel(SARADC_CTRL_POWER_CTRL | |
81 | | (chan->channel & SARADC_CTRL_CHN_MASK) | |
82 | | SARADC_CTRL_IRQ_ENABLE, | |
83 | info->regs + SARADC_CTRL); | |
84 | ||
85 | if (!wait_for_completion_timeout(&info->completion, | |
86 | SARADC_TIMEOUT)) { | |
87 | writel_relaxed(0, info->regs + SARADC_CTRL); | |
88 | mutex_unlock(&indio_dev->mlock); | |
89 | return -ETIMEDOUT; | |
90 | } | |
91 | ||
92 | *val = info->last_val; | |
93 | mutex_unlock(&indio_dev->mlock); | |
94 | return IIO_VAL_INT; | |
95 | case IIO_CHAN_INFO_SCALE: | |
96 | ret = regulator_get_voltage(info->vref); | |
97 | if (ret < 0) { | |
98 | dev_err(&indio_dev->dev, "failed to get voltage\n"); | |
99 | return ret; | |
100 | } | |
101 | ||
102 | *val = ret / 1000; | |
4c21bbb4 | 103 | *val2 = info->data->num_bits; |
44d6f2ef HS |
104 | return IIO_VAL_FRACTIONAL_LOG2; |
105 | default: | |
106 | return -EINVAL; | |
107 | } | |
108 | } | |
109 | ||
110 | static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id) | |
111 | { | |
112 | struct rockchip_saradc *info = (struct rockchip_saradc *)dev_id; | |
113 | ||
114 | /* Read value */ | |
115 | info->last_val = readl_relaxed(info->regs + SARADC_DATA); | |
4c21bbb4 | 116 | info->last_val &= GENMASK(info->data->num_bits - 1, 0); |
44d6f2ef HS |
117 | |
118 | /* Clear irq & power down adc */ | |
119 | writel_relaxed(0, info->regs + SARADC_CTRL); | |
120 | ||
121 | complete(&info->completion); | |
122 | ||
123 | return IRQ_HANDLED; | |
124 | } | |
125 | ||
126 | static const struct iio_info rockchip_saradc_iio_info = { | |
127 | .read_raw = rockchip_saradc_read_raw, | |
128 | .driver_module = THIS_MODULE, | |
129 | }; | |
130 | ||
131 | #define ADC_CHANNEL(_index, _id) { \ | |
132 | .type = IIO_VOLTAGE, \ | |
133 | .indexed = 1, \ | |
134 | .channel = _index, \ | |
135 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | |
136 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ | |
137 | .datasheet_name = _id, \ | |
138 | } | |
139 | ||
140 | static const struct iio_chan_spec rockchip_saradc_iio_channels[] = { | |
141 | ADC_CHANNEL(0, "adc0"), | |
142 | ADC_CHANNEL(1, "adc1"), | |
143 | ADC_CHANNEL(2, "adc2"), | |
144 | }; | |
145 | ||
4c21bbb4 HS |
146 | static const struct rockchip_saradc_data saradc_data = { |
147 | .num_bits = 10, | |
148 | .channels = rockchip_saradc_iio_channels, | |
149 | .num_channels = ARRAY_SIZE(rockchip_saradc_iio_channels), | |
150 | .clk_rate = 1000000, | |
151 | }; | |
152 | ||
153 | static const struct iio_chan_spec rockchip_rk3066_tsadc_iio_channels[] = { | |
154 | ADC_CHANNEL(0, "adc0"), | |
155 | ADC_CHANNEL(1, "adc1"), | |
156 | }; | |
157 | ||
158 | static const struct rockchip_saradc_data rk3066_tsadc_data = { | |
159 | .num_bits = 12, | |
160 | .channels = rockchip_rk3066_tsadc_iio_channels, | |
161 | .num_channels = ARRAY_SIZE(rockchip_rk3066_tsadc_iio_channels), | |
162 | .clk_rate = 50000, | |
163 | }; | |
164 | ||
ae549a72 DW |
165 | static const struct iio_chan_spec rockchip_rk3399_saradc_iio_channels[] = { |
166 | ADC_CHANNEL(0, "adc0"), | |
167 | ADC_CHANNEL(1, "adc1"), | |
168 | ADC_CHANNEL(2, "adc2"), | |
169 | ADC_CHANNEL(3, "adc3"), | |
170 | ADC_CHANNEL(4, "adc4"), | |
171 | ADC_CHANNEL(5, "adc5"), | |
172 | }; | |
173 | ||
174 | static const struct rockchip_saradc_data rk3399_saradc_data = { | |
175 | .num_bits = 10, | |
176 | .channels = rockchip_rk3399_saradc_iio_channels, | |
177 | .num_channels = ARRAY_SIZE(rockchip_rk3399_saradc_iio_channels), | |
178 | .clk_rate = 1000000, | |
179 | }; | |
180 | ||
4c21bbb4 HS |
181 | static const struct of_device_id rockchip_saradc_match[] = { |
182 | { | |
183 | .compatible = "rockchip,saradc", | |
184 | .data = &saradc_data, | |
185 | }, { | |
186 | .compatible = "rockchip,rk3066-tsadc", | |
187 | .data = &rk3066_tsadc_data, | |
ae549a72 DW |
188 | }, { |
189 | .compatible = "rockchip,rk3399-saradc", | |
190 | .data = &rk3399_saradc_data, | |
4c21bbb4 HS |
191 | }, |
192 | {}, | |
193 | }; | |
194 | MODULE_DEVICE_TABLE(of, rockchip_saradc_match); | |
195 | ||
543852af CW |
196 | /** |
197 | * Reset SARADC Controller. | |
198 | */ | |
199 | static void rockchip_saradc_reset_controller(struct reset_control *reset) | |
200 | { | |
201 | reset_control_assert(reset); | |
202 | usleep_range(10, 20); | |
203 | reset_control_deassert(reset); | |
204 | } | |
205 | ||
44d6f2ef HS |
206 | static int rockchip_saradc_probe(struct platform_device *pdev) |
207 | { | |
208 | struct rockchip_saradc *info = NULL; | |
209 | struct device_node *np = pdev->dev.of_node; | |
210 | struct iio_dev *indio_dev = NULL; | |
211 | struct resource *mem; | |
4c21bbb4 | 212 | const struct of_device_id *match; |
44d6f2ef HS |
213 | int ret; |
214 | int irq; | |
44d6f2ef HS |
215 | |
216 | if (!np) | |
217 | return -ENODEV; | |
218 | ||
219 | indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info)); | |
220 | if (!indio_dev) { | |
221 | dev_err(&pdev->dev, "failed allocating iio device\n"); | |
222 | return -ENOMEM; | |
223 | } | |
224 | info = iio_priv(indio_dev); | |
225 | ||
4c21bbb4 HS |
226 | match = of_match_device(rockchip_saradc_match, &pdev->dev); |
227 | info->data = match->data; | |
228 | ||
44d6f2ef HS |
229 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
230 | info->regs = devm_ioremap_resource(&pdev->dev, mem); | |
231 | if (IS_ERR(info->regs)) | |
232 | return PTR_ERR(info->regs); | |
233 | ||
543852af CW |
234 | /* |
235 | * The reset should be an optional property, as it should work | |
236 | * with old devicetrees as well | |
237 | */ | |
238 | info->reset = devm_reset_control_get(&pdev->dev, "saradc-apb"); | |
239 | if (IS_ERR(info->reset)) { | |
240 | ret = PTR_ERR(info->reset); | |
241 | if (ret != -ENOENT) | |
242 | return ret; | |
243 | ||
244 | dev_dbg(&pdev->dev, "no reset control found\n"); | |
245 | info->reset = NULL; | |
246 | } | |
247 | ||
44d6f2ef HS |
248 | init_completion(&info->completion); |
249 | ||
250 | irq = platform_get_irq(pdev, 0); | |
251 | if (irq < 0) { | |
252 | dev_err(&pdev->dev, "no irq resource?\n"); | |
253 | return irq; | |
254 | } | |
255 | ||
256 | ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr, | |
257 | 0, dev_name(&pdev->dev), info); | |
258 | if (ret < 0) { | |
259 | dev_err(&pdev->dev, "failed requesting irq %d\n", irq); | |
260 | return ret; | |
261 | } | |
262 | ||
263 | info->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); | |
264 | if (IS_ERR(info->pclk)) { | |
265 | dev_err(&pdev->dev, "failed to get pclk\n"); | |
266 | return PTR_ERR(info->pclk); | |
267 | } | |
268 | ||
269 | info->clk = devm_clk_get(&pdev->dev, "saradc"); | |
270 | if (IS_ERR(info->clk)) { | |
271 | dev_err(&pdev->dev, "failed to get adc clock\n"); | |
272 | return PTR_ERR(info->clk); | |
273 | } | |
274 | ||
275 | info->vref = devm_regulator_get(&pdev->dev, "vref"); | |
276 | if (IS_ERR(info->vref)) { | |
277 | dev_err(&pdev->dev, "failed to get regulator, %ld\n", | |
278 | PTR_ERR(info->vref)); | |
279 | return PTR_ERR(info->vref); | |
280 | } | |
281 | ||
543852af CW |
282 | if (info->reset) |
283 | rockchip_saradc_reset_controller(info->reset); | |
284 | ||
44d6f2ef | 285 | /* |
4c21bbb4 | 286 | * Use a default value for the converter clock. |
44d6f2ef HS |
287 | * This may become user-configurable in the future. |
288 | */ | |
4c21bbb4 | 289 | ret = clk_set_rate(info->clk, info->data->clk_rate); |
44d6f2ef HS |
290 | if (ret < 0) { |
291 | dev_err(&pdev->dev, "failed to set adc clk rate, %d\n", ret); | |
292 | return ret; | |
293 | } | |
294 | ||
295 | ret = regulator_enable(info->vref); | |
296 | if (ret < 0) { | |
297 | dev_err(&pdev->dev, "failed to enable vref regulator\n"); | |
298 | return ret; | |
299 | } | |
300 | ||
301 | ret = clk_prepare_enable(info->pclk); | |
302 | if (ret < 0) { | |
303 | dev_err(&pdev->dev, "failed to enable pclk\n"); | |
304 | goto err_reg_voltage; | |
305 | } | |
306 | ||
307 | ret = clk_prepare_enable(info->clk); | |
308 | if (ret < 0) { | |
309 | dev_err(&pdev->dev, "failed to enable converter clock\n"); | |
310 | goto err_pclk; | |
311 | } | |
312 | ||
313 | platform_set_drvdata(pdev, indio_dev); | |
314 | ||
315 | indio_dev->name = dev_name(&pdev->dev); | |
316 | indio_dev->dev.parent = &pdev->dev; | |
317 | indio_dev->dev.of_node = pdev->dev.of_node; | |
318 | indio_dev->info = &rockchip_saradc_iio_info; | |
319 | indio_dev->modes = INDIO_DIRECT_MODE; | |
320 | ||
4c21bbb4 HS |
321 | indio_dev->channels = info->data->channels; |
322 | indio_dev->num_channels = info->data->num_channels; | |
44d6f2ef HS |
323 | |
324 | ret = iio_device_register(indio_dev); | |
325 | if (ret) | |
326 | goto err_clk; | |
327 | ||
328 | return 0; | |
329 | ||
330 | err_clk: | |
331 | clk_disable_unprepare(info->clk); | |
332 | err_pclk: | |
333 | clk_disable_unprepare(info->pclk); | |
334 | err_reg_voltage: | |
335 | regulator_disable(info->vref); | |
336 | return ret; | |
337 | } | |
338 | ||
339 | static int rockchip_saradc_remove(struct platform_device *pdev) | |
340 | { | |
341 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); | |
342 | struct rockchip_saradc *info = iio_priv(indio_dev); | |
343 | ||
344 | iio_device_unregister(indio_dev); | |
345 | clk_disable_unprepare(info->clk); | |
346 | clk_disable_unprepare(info->pclk); | |
347 | regulator_disable(info->vref); | |
348 | ||
349 | return 0; | |
350 | } | |
351 | ||
352 | #ifdef CONFIG_PM_SLEEP | |
353 | static int rockchip_saradc_suspend(struct device *dev) | |
354 | { | |
355 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
356 | struct rockchip_saradc *info = iio_priv(indio_dev); | |
357 | ||
358 | clk_disable_unprepare(info->clk); | |
359 | clk_disable_unprepare(info->pclk); | |
360 | regulator_disable(info->vref); | |
361 | ||
362 | return 0; | |
363 | } | |
364 | ||
365 | static int rockchip_saradc_resume(struct device *dev) | |
366 | { | |
367 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | |
368 | struct rockchip_saradc *info = iio_priv(indio_dev); | |
369 | int ret; | |
370 | ||
371 | ret = regulator_enable(info->vref); | |
372 | if (ret) | |
373 | return ret; | |
374 | ||
375 | ret = clk_prepare_enable(info->pclk); | |
376 | if (ret) | |
377 | return ret; | |
378 | ||
379 | ret = clk_prepare_enable(info->clk); | |
380 | if (ret) | |
381 | return ret; | |
382 | ||
383 | return ret; | |
384 | } | |
385 | #endif | |
386 | ||
387 | static SIMPLE_DEV_PM_OPS(rockchip_saradc_pm_ops, | |
388 | rockchip_saradc_suspend, rockchip_saradc_resume); | |
389 | ||
44d6f2ef HS |
390 | static struct platform_driver rockchip_saradc_driver = { |
391 | .probe = rockchip_saradc_probe, | |
392 | .remove = rockchip_saradc_remove, | |
393 | .driver = { | |
394 | .name = "rockchip-saradc", | |
44d6f2ef HS |
395 | .of_match_table = rockchip_saradc_match, |
396 | .pm = &rockchip_saradc_pm_ops, | |
397 | }, | |
398 | }; | |
399 | ||
400 | module_platform_driver(rockchip_saradc_driver); | |
dc7b8d98 HS |
401 | |
402 | MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); | |
403 | MODULE_DESCRIPTION("Rockchip SARADC driver"); | |
404 | MODULE_LICENSE("GPL v2"); |