aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/adc
diff options
context:
space:
mode:
authorChanwoo Choi <cw00.choi@samsung.com>2014-07-21 22:04:00 -0400
committerJonathan Cameron <jic23@kernel.org>2014-07-23 16:55:47 -0400
commite49d99e0ecc88191c2e51a6535b1d0df635f1f3b (patch)
treeb0c0e52ffa946189f39a0a266022d04244d94305 /drivers/iio/adc
parentd3f1621960223799b19bca9b503c333a3833d7f7 (diff)
iio: adc: exynos_adc: Add exynos_adc_data structure to improve readability
This patchset add 'exynos_adc_data' structure which includes some functions to control ADC operation and specific data according to ADC version (v1 or v2). Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Acked-by: Kyungmin Park <kyungmin.park@samsung.com> Reviewed-by: Naveen Krishna Chatradhi <ch.naveen@samsung.com> Reviewed-by: Tomasz Figa <t.figa@samsung.com> Acked-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Jonathan Cameron <jic23@kernel.org>
Diffstat (limited to 'drivers/iio/adc')
-rw-r--r--drivers/iio/adc/exynos_adc.c226
1 files changed, 147 insertions, 79 deletions
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 010578f1d762..66d27c638d83 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -39,11 +39,6 @@
39#include <linux/iio/machine.h> 39#include <linux/iio/machine.h>
40#include <linux/iio/driver.h> 40#include <linux/iio/driver.h>
41 41
42enum adc_version {
43 ADC_V1,
44 ADC_V2
45};
46
47/* EXYNOS4412/5250 ADC_V1 registers definitions */ 42/* EXYNOS4412/5250 ADC_V1 registers definitions */
48#define ADC_V1_CON(x) ((x) + 0x00) 43#define ADC_V1_CON(x) ((x) + 0x00)
49#define ADC_V1_DLY(x) ((x) + 0x08) 44#define ADC_V1_DLY(x) ((x) + 0x08)
@@ -85,6 +80,7 @@ enum adc_version {
85#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100)) 80#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100))
86 81
87struct exynos_adc { 82struct exynos_adc {
83 struct exynos_adc_data *data;
88 void __iomem *regs; 84 void __iomem *regs;
89 void __iomem *enable_reg; 85 void __iomem *enable_reg;
90 struct clk *clk; 86 struct clk *clk;
@@ -97,43 +93,139 @@ struct exynos_adc {
97 unsigned int version; 93 unsigned int version;
98}; 94};
99 95
100static const struct of_device_id exynos_adc_match[] = { 96struct exynos_adc_data {
101 { .compatible = "samsung,exynos-adc-v1", .data = (void *)ADC_V1 }, 97 int num_channels;
102 { .compatible = "samsung,exynos-adc-v2", .data = (void *)ADC_V2 }, 98
103 {}, 99 void (*init_hw)(struct exynos_adc *info);
100 void (*exit_hw)(struct exynos_adc *info);
101 void (*clear_irq)(struct exynos_adc *info);
102 void (*start_conv)(struct exynos_adc *info, unsigned long addr);
104}; 103};
105MODULE_DEVICE_TABLE(of, exynos_adc_match);
106 104
107static inline unsigned int exynos_adc_get_version(struct platform_device *pdev) 105static void exynos_adc_v1_init_hw(struct exynos_adc *info)
108{ 106{
109 const struct of_device_id *match; 107 u32 con1;
110 108
111 match = of_match_node(exynos_adc_match, pdev->dev.of_node); 109 writel(1, info->enable_reg);
112 return (unsigned int)match->data; 110
111 /* set default prescaler values and Enable prescaler */
112 con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
113
114 /* Enable 12-bit ADC resolution */
115 con1 |= ADC_V1_CON_RES;
116 writel(con1, ADC_V1_CON(info->regs));
117}
118
119static void exynos_adc_v1_exit_hw(struct exynos_adc *info)
120{
121 u32 con;
122
123 writel(0, info->enable_reg);
124
125 con = readl(ADC_V1_CON(info->regs));
126 con |= ADC_V1_CON_STANDBY;
127 writel(con, ADC_V1_CON(info->regs));
128}
129
130static void exynos_adc_v1_clear_irq(struct exynos_adc *info)
131{
132 writel(1, ADC_V1_INTCLR(info->regs));
113} 133}
114 134
115static void exynos_adc_hw_init(struct exynos_adc *info) 135static void exynos_adc_v1_start_conv(struct exynos_adc *info,
136 unsigned long addr)
137{
138 u32 con1;
139
140 writel(addr, ADC_V1_MUX(info->regs));
141
142 con1 = readl(ADC_V1_CON(info->regs));
143 writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
144}
145
146static const struct exynos_adc_data exynos_adc_v1_data = {
147 .num_channels = MAX_ADC_V1_CHANNELS,
148
149 .init_hw = exynos_adc_v1_init_hw,
150 .exit_hw = exynos_adc_v1_exit_hw,
151 .clear_irq = exynos_adc_v1_clear_irq,
152 .start_conv = exynos_adc_v1_start_conv,
153};
154
155static void exynos_adc_v2_init_hw(struct exynos_adc *info)
116{ 156{
117 u32 con1, con2; 157 u32 con1, con2;
118 158
119 if (info->version == ADC_V2) { 159 writel(1, info->enable_reg);
120 con1 = ADC_V2_CON1_SOFT_RESET;
121 writel(con1, ADC_V2_CON1(info->regs));
122 160
123 con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL | 161 con1 = ADC_V2_CON1_SOFT_RESET;
124 ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0); 162 writel(con1, ADC_V2_CON1(info->regs));
125 writel(con2, ADC_V2_CON2(info->regs));
126 163
127 /* Enable interrupts */ 164 con2 = ADC_V2_CON2_OSEL | ADC_V2_CON2_ESEL |
128 writel(1, ADC_V2_INT_EN(info->regs)); 165 ADC_V2_CON2_HIGHF | ADC_V2_CON2_C_TIME(0);
129 } else { 166 writel(con2, ADC_V2_CON2(info->regs));
130 /* set default prescaler values and Enable prescaler */
131 con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
132 167
133 /* Enable 12-bit ADC resolution */ 168 /* Enable interrupts */
134 con1 |= ADC_V1_CON_RES; 169 writel(1, ADC_V2_INT_EN(info->regs));
135 writel(con1, ADC_V1_CON(info->regs)); 170}
136 } 171
172static void exynos_adc_v2_exit_hw(struct exynos_adc *info)
173{
174 u32 con;
175
176 writel(0, info->enable_reg);
177
178 con = readl(ADC_V2_CON1(info->regs));
179 con &= ~ADC_CON_EN_START;
180 writel(con, ADC_V2_CON1(info->regs));
181}
182
183static void exynos_adc_v2_clear_irq(struct exynos_adc *info)
184{
185 writel(1, ADC_V2_INT_ST(info->regs));
186}
187
188static void exynos_adc_v2_start_conv(struct exynos_adc *info,
189 unsigned long addr)
190{
191 u32 con1, con2;
192
193 con2 = readl(ADC_V2_CON2(info->regs));
194 con2 &= ~ADC_V2_CON2_ACH_MASK;
195 con2 |= ADC_V2_CON2_ACH_SEL(addr);
196 writel(con2, ADC_V2_CON2(info->regs));
197
198 con1 = readl(ADC_V2_CON1(info->regs));
199 writel(con1 | ADC_CON_EN_START, ADC_V2_CON1(info->regs));
200}
201
202static const struct exynos_adc_data exynos_adc_v2_data = {
203 .num_channels = MAX_ADC_V2_CHANNELS,
204
205 .init_hw = exynos_adc_v2_init_hw,
206 .exit_hw = exynos_adc_v2_exit_hw,
207 .clear_irq = exynos_adc_v2_clear_irq,
208 .start_conv = exynos_adc_v2_start_conv,
209};
210
211static const struct of_device_id exynos_adc_match[] = {
212 {
213 .compatible = "samsung,exynos-adc-v1",
214 .data = &exynos_adc_v1_data,
215 }, {
216 .compatible = "samsung,exynos-adc-v2",
217 .data = &exynos_adc_v2_data,
218 },
219 {},
220};
221MODULE_DEVICE_TABLE(of, exynos_adc_match);
222
223static struct exynos_adc_data *exynos_adc_get_data(struct platform_device *pdev)
224{
225 const struct of_device_id *match;
226
227 match = of_match_node(exynos_adc_match, pdev->dev.of_node);
228 return (struct exynos_adc_data *)match->data;
137} 229}
138 230
139static int exynos_read_raw(struct iio_dev *indio_dev, 231static int exynos_read_raw(struct iio_dev *indio_dev,
@@ -144,7 +236,6 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
144{ 236{
145 struct exynos_adc *info = iio_priv(indio_dev); 237 struct exynos_adc *info = iio_priv(indio_dev);
146 unsigned long timeout; 238 unsigned long timeout;
147 u32 con1, con2;
148 int ret; 239 int ret;
149 240
150 if (mask != IIO_CHAN_INFO_RAW) 241 if (mask != IIO_CHAN_INFO_RAW)
@@ -154,28 +245,15 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
154 reinit_completion(&info->completion); 245 reinit_completion(&info->completion);
155 246
156 /* Select the channel to be used and Trigger conversion */ 247 /* Select the channel to be used and Trigger conversion */
157 if (info->version == ADC_V2) { 248 if (info->data->start_conv)
158 con2 = readl(ADC_V2_CON2(info->regs)); 249 info->data->start_conv(info, chan->address);
159 con2 &= ~ADC_V2_CON2_ACH_MASK;
160 con2 |= ADC_V2_CON2_ACH_SEL(chan->address);
161 writel(con2, ADC_V2_CON2(info->regs));
162
163 con1 = readl(ADC_V2_CON1(info->regs));
164 writel(con1 | ADC_CON_EN_START,
165 ADC_V2_CON1(info->regs));
166 } else {
167 writel(chan->address, ADC_V1_MUX(info->regs));
168
169 con1 = readl(ADC_V1_CON(info->regs));
170 writel(con1 | ADC_CON_EN_START,
171 ADC_V1_CON(info->regs));
172 }
173 250
174 timeout = wait_for_completion_timeout 251 timeout = wait_for_completion_timeout
175 (&info->completion, EXYNOS_ADC_TIMEOUT); 252 (&info->completion, EXYNOS_ADC_TIMEOUT);
176 if (timeout == 0) { 253 if (timeout == 0) {
177 dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n"); 254 dev_warn(&indio_dev->dev, "Conversion timed out! Resetting\n");
178 exynos_adc_hw_init(info); 255 if (info->data->init_hw)
256 info->data->init_hw(info);
179 ret = -ETIMEDOUT; 257 ret = -ETIMEDOUT;
180 } else { 258 } else {
181 *val = info->value; 259 *val = info->value;
@@ -193,13 +271,11 @@ static irqreturn_t exynos_adc_isr(int irq, void *dev_id)
193 struct exynos_adc *info = (struct exynos_adc *)dev_id; 271 struct exynos_adc *info = (struct exynos_adc *)dev_id;
194 272
195 /* Read value */ 273 /* Read value */
196 info->value = readl(ADC_V1_DATX(info->regs)) & 274 info->value = readl(ADC_V1_DATX(info->regs)) & ADC_DATX_MASK;
197 ADC_DATX_MASK; 275
198 /* clear irq */ 276 /* clear irq */
199 if (info->version == ADC_V2) 277 if (info->data->clear_irq)
200 writel(1, ADC_V2_INT_ST(info->regs)); 278 info->data->clear_irq(info);
201 else
202 writel(1, ADC_V1_INTCLR(info->regs));
203 279
204 complete(&info->completion); 280 complete(&info->completion);
205 281
@@ -277,6 +353,12 @@ static int exynos_adc_probe(struct platform_device *pdev)
277 353
278 info = iio_priv(indio_dev); 354 info = iio_priv(indio_dev);
279 355
356 info->data = exynos_adc_get_data(pdev);
357 if (!info->data) {
358 dev_err(&pdev->dev, "failed getting exynos_adc_data\n");
359 return -EINVAL;
360 }
361
280 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 362 mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
281 info->regs = devm_ioremap_resource(&pdev->dev, mem); 363 info->regs = devm_ioremap_resource(&pdev->dev, mem);
282 if (IS_ERR(info->regs)) 364 if (IS_ERR(info->regs))
@@ -319,10 +401,6 @@ static int exynos_adc_probe(struct platform_device *pdev)
319 if (ret) 401 if (ret)
320 goto err_disable_reg; 402 goto err_disable_reg;
321 403
322 writel(1, info->enable_reg);
323
324 info->version = exynos_adc_get_version(pdev);
325
326 platform_set_drvdata(pdev, indio_dev); 404 platform_set_drvdata(pdev, indio_dev);
327 405
328 indio_dev->name = dev_name(&pdev->dev); 406 indio_dev->name = dev_name(&pdev->dev);
@@ -331,11 +409,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
331 indio_dev->info = &exynos_adc_iio_info; 409 indio_dev->info = &exynos_adc_iio_info;
332 indio_dev->modes = INDIO_DIRECT_MODE; 410 indio_dev->modes = INDIO_DIRECT_MODE;
333 indio_dev->channels = exynos_adc_iio_channels; 411 indio_dev->channels = exynos_adc_iio_channels;
334 412 indio_dev->num_channels = info->data->num_channels;
335 if (info->version == ADC_V1)
336 indio_dev->num_channels = MAX_ADC_V1_CHANNELS;
337 else
338 indio_dev->num_channels = MAX_ADC_V2_CHANNELS;
339 413
340 ret = request_irq(info->irq, exynos_adc_isr, 414 ret = request_irq(info->irq, exynos_adc_isr,
341 0, dev_name(&pdev->dev), info); 415 0, dev_name(&pdev->dev), info);
@@ -349,7 +423,8 @@ static int exynos_adc_probe(struct platform_device *pdev)
349 if (ret) 423 if (ret)
350 goto err_irq; 424 goto err_irq;
351 425
352 exynos_adc_hw_init(info); 426 if (info->data->init_hw)
427 info->data->init_hw(info);
353 428
354 ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev); 429 ret = of_platform_populate(np, exynos_adc_match, NULL, &indio_dev->dev);
355 if (ret < 0) { 430 if (ret < 0) {
@@ -366,7 +441,8 @@ err_of_populate:
366err_irq: 441err_irq:
367 free_irq(info->irq, info); 442 free_irq(info->irq, info);
368err_disable_clk: 443err_disable_clk:
369 writel(0, info->enable_reg); 444 if (info->data->exit_hw)
445 info->data->exit_hw(info);
370 clk_disable_unprepare(info->clk); 446 clk_disable_unprepare(info->clk);
371err_disable_reg: 447err_disable_reg:
372 regulator_disable(info->vdd); 448 regulator_disable(info->vdd);
@@ -382,7 +458,8 @@ static int exynos_adc_remove(struct platform_device *pdev)
382 exynos_adc_remove_devices); 458 exynos_adc_remove_devices);
383 iio_device_unregister(indio_dev); 459 iio_device_unregister(indio_dev);
384 free_irq(info->irq, info); 460 free_irq(info->irq, info);
385 writel(0, info->enable_reg); 461 if (info->data->exit_hw)
462 info->data->exit_hw(info);
386 clk_disable_unprepare(info->clk); 463 clk_disable_unprepare(info->clk);
387 regulator_disable(info->vdd); 464 regulator_disable(info->vdd);
388 465
@@ -394,19 +471,10 @@ static int exynos_adc_suspend(struct device *dev)
394{ 471{
395 struct iio_dev *indio_dev = dev_get_drvdata(dev); 472 struct iio_dev *indio_dev = dev_get_drvdata(dev);
396 struct exynos_adc *info = iio_priv(indio_dev); 473 struct exynos_adc *info = iio_priv(indio_dev);
397 u32 con;
398 474
399 if (info->version == ADC_V2) { 475 if (info->data->exit_hw)
400 con = readl(ADC_V2_CON1(info->regs)); 476 info->data->exit_hw(info);
401 con &= ~ADC_CON_EN_START;
402 writel(con, ADC_V2_CON1(info->regs));
403 } else {
404 con = readl(ADC_V1_CON(info->regs));
405 con |= ADC_V1_CON_STANDBY;
406 writel(con, ADC_V1_CON(info->regs));
407 }
408 477
409 writel(0, info->enable_reg);
410 clk_disable_unprepare(info->clk); 478 clk_disable_unprepare(info->clk);
411 regulator_disable(info->vdd); 479 regulator_disable(info->vdd);
412 480
@@ -427,8 +495,8 @@ static int exynos_adc_resume(struct device *dev)
427 if (ret) 495 if (ret)
428 return ret; 496 return ret;
429 497
430 writel(1, info->enable_reg); 498 if (info->data->init_hw)
431 exynos_adc_hw_init(info); 499 info->data->init_hw(info);
432 500
433 return 0; 501 return 0;
434} 502}