diff options
author | Heiko Stübner <heiko@sntech.de> | 2014-07-23 17:24:00 -0400 |
---|---|---|
committer | Jonathan Cameron <jic23@kernel.org> | 2014-08-07 10:13:02 -0400 |
commit | 44d6f2ef94f9825e6eb9072f1611e0ea4cd81fa1 (patch) | |
tree | c0ad7617550b142a62c747d81e112f797b6014f9 /drivers/iio | |
parent | af097e86312f2a2ec83d9d2497425f5d61592953 (diff) |
iio: adc: add driver for Rockchip saradc
The ADC is a 3-channel signal-ended 10-bit Successive Approximation
Register (SAR) A/D Converter. It uses the supply and ground as its reference
and converts the analog input signal into 10-bit binary digital codes.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Reviewed-by: Hartmut Knaack <knaack.h@gmx.de>
Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio')
-rw-r--r-- | drivers/iio/adc/Kconfig | 10 | ||||
-rw-r--r-- | drivers/iio/adc/Makefile | 1 | ||||
-rw-r--r-- | drivers/iio/adc/rockchip_saradc.c | 317 |
3 files changed, 328 insertions, 0 deletions
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 3ea56a39b9d2..6655fd41acd9 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig | |||
@@ -206,6 +206,16 @@ config NAU7802 | |||
206 | To compile this driver as a module, choose M here: the | 206 | To compile this driver as a module, choose M here: the |
207 | module will be called nau7802. | 207 | module will be called nau7802. |
208 | 208 | ||
209 | config ROCKCHIP_SARADC | ||
210 | tristate "Rockchip SARADC driver" | ||
211 | depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST) | ||
212 | help | ||
213 | Say yes here to build support for the SARADC found in SoCs from | ||
214 | Rockchip. | ||
215 | |||
216 | To compile this driver as a module, choose M here: the | ||
217 | module will be called rockchip_saradc. | ||
218 | |||
209 | config TI_ADC081C | 219 | config TI_ADC081C |
210 | tristate "Texas Instruments ADC081C021/027" | 220 | tristate "Texas Instruments ADC081C021/027" |
211 | depends on I2C | 221 | depends on I2C |
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 9cc37f66f9d0..cb88a6a23b8f 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile | |||
@@ -22,6 +22,7 @@ obj-$(CONFIG_MCP320X) += mcp320x.o | |||
22 | obj-$(CONFIG_MCP3422) += mcp3422.o | 22 | obj-$(CONFIG_MCP3422) += mcp3422.o |
23 | obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o | 23 | obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o |
24 | obj-$(CONFIG_NAU7802) += nau7802.o | 24 | obj-$(CONFIG_NAU7802) += nau7802.o |
25 | obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o | ||
25 | obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o | 26 | obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o |
26 | obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o | 27 | obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o |
27 | obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o | 28 | obj-$(CONFIG_TI_AM335X_ADC) += ti_am335x_adc.o |
diff --git a/drivers/iio/adc/rockchip_saradc.c b/drivers/iio/adc/rockchip_saradc.c new file mode 100644 index 000000000000..1fad9647cef4 --- /dev/null +++ b/drivers/iio/adc/rockchip_saradc.c | |||
@@ -0,0 +1,317 @@ | |||
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> | ||
21 | #include <linux/clk.h> | ||
22 | #include <linux/completion.h> | ||
23 | #include <linux/regulator/consumer.h> | ||
24 | #include <linux/iio/iio.h> | ||
25 | |||
26 | #define SARADC_DATA 0x00 | ||
27 | #define SARADC_DATA_MASK 0x3ff | ||
28 | |||
29 | #define SARADC_STAS 0x04 | ||
30 | #define SARADC_STAS_BUSY BIT(0) | ||
31 | |||
32 | #define SARADC_CTRL 0x08 | ||
33 | #define SARADC_CTRL_IRQ_STATUS BIT(6) | ||
34 | #define SARADC_CTRL_IRQ_ENABLE BIT(5) | ||
35 | #define SARADC_CTRL_POWER_CTRL BIT(3) | ||
36 | #define SARADC_CTRL_CHN_MASK 0x7 | ||
37 | |||
38 | #define SARADC_DLY_PU_SOC 0x0c | ||
39 | #define SARADC_DLY_PU_SOC_MASK 0x3f | ||
40 | |||
41 | #define SARADC_BITS 10 | ||
42 | #define SARADC_TIMEOUT msecs_to_jiffies(100) | ||
43 | |||
44 | struct rockchip_saradc { | ||
45 | void __iomem *regs; | ||
46 | struct clk *pclk; | ||
47 | struct clk *clk; | ||
48 | struct completion completion; | ||
49 | struct regulator *vref; | ||
50 | u16 last_val; | ||
51 | }; | ||
52 | |||
53 | static int rockchip_saradc_read_raw(struct iio_dev *indio_dev, | ||
54 | struct iio_chan_spec const *chan, | ||
55 | int *val, int *val2, long mask) | ||
56 | { | ||
57 | struct rockchip_saradc *info = iio_priv(indio_dev); | ||
58 | int ret; | ||
59 | |||
60 | switch (mask) { | ||
61 | case IIO_CHAN_INFO_RAW: | ||
62 | mutex_lock(&indio_dev->mlock); | ||
63 | |||
64 | reinit_completion(&info->completion); | ||
65 | |||
66 | /* 8 clock periods as delay between power up and start cmd */ | ||
67 | writel_relaxed(8, info->regs + SARADC_DLY_PU_SOC); | ||
68 | |||
69 | /* Select the channel to be used and trigger conversion */ | ||
70 | writel(SARADC_CTRL_POWER_CTRL | ||
71 | | (chan->channel & SARADC_CTRL_CHN_MASK) | ||
72 | | SARADC_CTRL_IRQ_ENABLE, | ||
73 | info->regs + SARADC_CTRL); | ||
74 | |||
75 | if (!wait_for_completion_timeout(&info->completion, | ||
76 | SARADC_TIMEOUT)) { | ||
77 | writel_relaxed(0, info->regs + SARADC_CTRL); | ||
78 | mutex_unlock(&indio_dev->mlock); | ||
79 | return -ETIMEDOUT; | ||
80 | } | ||
81 | |||
82 | *val = info->last_val; | ||
83 | mutex_unlock(&indio_dev->mlock); | ||
84 | return IIO_VAL_INT; | ||
85 | case IIO_CHAN_INFO_SCALE: | ||
86 | ret = regulator_get_voltage(info->vref); | ||
87 | if (ret < 0) { | ||
88 | dev_err(&indio_dev->dev, "failed to get voltage\n"); | ||
89 | return ret; | ||
90 | } | ||
91 | |||
92 | *val = ret / 1000; | ||
93 | *val2 = SARADC_BITS; | ||
94 | return IIO_VAL_FRACTIONAL_LOG2; | ||
95 | default: | ||
96 | return -EINVAL; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | static irqreturn_t rockchip_saradc_isr(int irq, void *dev_id) | ||
101 | { | ||
102 | struct rockchip_saradc *info = (struct rockchip_saradc *)dev_id; | ||
103 | |||
104 | /* Read value */ | ||
105 | info->last_val = readl_relaxed(info->regs + SARADC_DATA); | ||
106 | info->last_val &= SARADC_DATA_MASK; | ||
107 | |||
108 | /* Clear irq & power down adc */ | ||
109 | writel_relaxed(0, info->regs + SARADC_CTRL); | ||
110 | |||
111 | complete(&info->completion); | ||
112 | |||
113 | return IRQ_HANDLED; | ||
114 | } | ||
115 | |||
116 | static const struct iio_info rockchip_saradc_iio_info = { | ||
117 | .read_raw = rockchip_saradc_read_raw, | ||
118 | .driver_module = THIS_MODULE, | ||
119 | }; | ||
120 | |||
121 | #define ADC_CHANNEL(_index, _id) { \ | ||
122 | .type = IIO_VOLTAGE, \ | ||
123 | .indexed = 1, \ | ||
124 | .channel = _index, \ | ||
125 | .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \ | ||
126 | .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \ | ||
127 | .datasheet_name = _id, \ | ||
128 | } | ||
129 | |||
130 | static const struct iio_chan_spec rockchip_saradc_iio_channels[] = { | ||
131 | ADC_CHANNEL(0, "adc0"), | ||
132 | ADC_CHANNEL(1, "adc1"), | ||
133 | ADC_CHANNEL(2, "adc2"), | ||
134 | }; | ||
135 | |||
136 | static int rockchip_saradc_probe(struct platform_device *pdev) | ||
137 | { | ||
138 | struct rockchip_saradc *info = NULL; | ||
139 | struct device_node *np = pdev->dev.of_node; | ||
140 | struct iio_dev *indio_dev = NULL; | ||
141 | struct resource *mem; | ||
142 | int ret; | ||
143 | int irq; | ||
144 | u32 rate; | ||
145 | |||
146 | if (!np) | ||
147 | return -ENODEV; | ||
148 | |||
149 | indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info)); | ||
150 | if (!indio_dev) { | ||
151 | dev_err(&pdev->dev, "failed allocating iio device\n"); | ||
152 | return -ENOMEM; | ||
153 | } | ||
154 | info = iio_priv(indio_dev); | ||
155 | |||
156 | mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
157 | info->regs = devm_ioremap_resource(&pdev->dev, mem); | ||
158 | if (IS_ERR(info->regs)) | ||
159 | return PTR_ERR(info->regs); | ||
160 | |||
161 | init_completion(&info->completion); | ||
162 | |||
163 | irq = platform_get_irq(pdev, 0); | ||
164 | if (irq < 0) { | ||
165 | dev_err(&pdev->dev, "no irq resource?\n"); | ||
166 | return irq; | ||
167 | } | ||
168 | |||
169 | ret = devm_request_irq(&pdev->dev, irq, rockchip_saradc_isr, | ||
170 | 0, dev_name(&pdev->dev), info); | ||
171 | if (ret < 0) { | ||
172 | dev_err(&pdev->dev, "failed requesting irq %d\n", irq); | ||
173 | return ret; | ||
174 | } | ||
175 | |||
176 | info->pclk = devm_clk_get(&pdev->dev, "apb_pclk"); | ||
177 | if (IS_ERR(info->pclk)) { | ||
178 | dev_err(&pdev->dev, "failed to get pclk\n"); | ||
179 | return PTR_ERR(info->pclk); | ||
180 | } | ||
181 | |||
182 | info->clk = devm_clk_get(&pdev->dev, "saradc"); | ||
183 | if (IS_ERR(info->clk)) { | ||
184 | dev_err(&pdev->dev, "failed to get adc clock\n"); | ||
185 | return PTR_ERR(info->clk); | ||
186 | } | ||
187 | |||
188 | info->vref = devm_regulator_get(&pdev->dev, "vref"); | ||
189 | if (IS_ERR(info->vref)) { | ||
190 | dev_err(&pdev->dev, "failed to get regulator, %ld\n", | ||
191 | PTR_ERR(info->vref)); | ||
192 | return PTR_ERR(info->vref); | ||
193 | } | ||
194 | |||
195 | /* | ||
196 | * Use a default of 1MHz for the converter clock. | ||
197 | * This may become user-configurable in the future. | ||
198 | */ | ||
199 | ret = clk_set_rate(info->clk, 1000000); | ||
200 | if (ret < 0) { | ||
201 | dev_err(&pdev->dev, "failed to set adc clk rate, %d\n", ret); | ||
202 | return ret; | ||
203 | } | ||
204 | |||
205 | ret = regulator_enable(info->vref); | ||
206 | if (ret < 0) { | ||
207 | dev_err(&pdev->dev, "failed to enable vref regulator\n"); | ||
208 | return ret; | ||
209 | } | ||
210 | |||
211 | ret = clk_prepare_enable(info->pclk); | ||
212 | if (ret < 0) { | ||
213 | dev_err(&pdev->dev, "failed to enable pclk\n"); | ||
214 | goto err_reg_voltage; | ||
215 | } | ||
216 | |||
217 | ret = clk_prepare_enable(info->clk); | ||
218 | if (ret < 0) { | ||
219 | dev_err(&pdev->dev, "failed to enable converter clock\n"); | ||
220 | goto err_pclk; | ||
221 | } | ||
222 | |||
223 | platform_set_drvdata(pdev, indio_dev); | ||
224 | |||
225 | indio_dev->name = dev_name(&pdev->dev); | ||
226 | indio_dev->dev.parent = &pdev->dev; | ||
227 | indio_dev->dev.of_node = pdev->dev.of_node; | ||
228 | indio_dev->info = &rockchip_saradc_iio_info; | ||
229 | indio_dev->modes = INDIO_DIRECT_MODE; | ||
230 | |||
231 | indio_dev->channels = rockchip_saradc_iio_channels; | ||
232 | indio_dev->num_channels = ARRAY_SIZE(rockchip_saradc_iio_channels); | ||
233 | |||
234 | ret = iio_device_register(indio_dev); | ||
235 | if (ret) | ||
236 | goto err_clk; | ||
237 | |||
238 | return 0; | ||
239 | |||
240 | err_clk: | ||
241 | clk_disable_unprepare(info->clk); | ||
242 | err_pclk: | ||
243 | clk_disable_unprepare(info->pclk); | ||
244 | err_reg_voltage: | ||
245 | regulator_disable(info->vref); | ||
246 | return ret; | ||
247 | } | ||
248 | |||
249 | static int rockchip_saradc_remove(struct platform_device *pdev) | ||
250 | { | ||
251 | struct iio_dev *indio_dev = platform_get_drvdata(pdev); | ||
252 | struct rockchip_saradc *info = iio_priv(indio_dev); | ||
253 | |||
254 | iio_device_unregister(indio_dev); | ||
255 | clk_disable_unprepare(info->clk); | ||
256 | clk_disable_unprepare(info->pclk); | ||
257 | regulator_disable(info->vref); | ||
258 | |||
259 | return 0; | ||
260 | } | ||
261 | |||
262 | #ifdef CONFIG_PM_SLEEP | ||
263 | static int rockchip_saradc_suspend(struct device *dev) | ||
264 | { | ||
265 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
266 | struct rockchip_saradc *info = iio_priv(indio_dev); | ||
267 | |||
268 | clk_disable_unprepare(info->clk); | ||
269 | clk_disable_unprepare(info->pclk); | ||
270 | regulator_disable(info->vref); | ||
271 | |||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static int rockchip_saradc_resume(struct device *dev) | ||
276 | { | ||
277 | struct iio_dev *indio_dev = dev_get_drvdata(dev); | ||
278 | struct rockchip_saradc *info = iio_priv(indio_dev); | ||
279 | int ret; | ||
280 | |||
281 | ret = regulator_enable(info->vref); | ||
282 | if (ret) | ||
283 | return ret; | ||
284 | |||
285 | ret = clk_prepare_enable(info->pclk); | ||
286 | if (ret) | ||
287 | return ret; | ||
288 | |||
289 | ret = clk_prepare_enable(info->clk); | ||
290 | if (ret) | ||
291 | return ret; | ||
292 | |||
293 | return ret; | ||
294 | } | ||
295 | #endif | ||
296 | |||
297 | static SIMPLE_DEV_PM_OPS(rockchip_saradc_pm_ops, | ||
298 | rockchip_saradc_suspend, rockchip_saradc_resume); | ||
299 | |||
300 | static const struct of_device_id rockchip_saradc_match[] = { | ||
301 | { .compatible = "rockchip,saradc" }, | ||
302 | {}, | ||
303 | }; | ||
304 | MODULE_DEVICE_TABLE(of, rockchip_saradc_match); | ||
305 | |||
306 | static struct platform_driver rockchip_saradc_driver = { | ||
307 | .probe = rockchip_saradc_probe, | ||
308 | .remove = rockchip_saradc_remove, | ||
309 | .driver = { | ||
310 | .name = "rockchip-saradc", | ||
311 | .owner = THIS_MODULE, | ||
312 | .of_match_table = rockchip_saradc_match, | ||
313 | .pm = &rockchip_saradc_pm_ops, | ||
314 | }, | ||
315 | }; | ||
316 | |||
317 | module_platform_driver(rockchip_saradc_driver); | ||