aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio
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:58:26 -0400
commitadb4e3f4cf9ed50c28cc8fb02e3f04e962ff184d (patch)
treee9e8d80b061e89e109644dce84b04644b3a5232d /drivers/iio
parente49d99e0ecc88191c2e51a6535b1d0df635f1f3b (diff)
iio: adc: exynos_adc: Control special clock of ADC to support Exynos3250 ADC
This patch control special clock for ADC in Exynos series's FSYS block. If special clock of ADC is registerd on clock list of common clk framework, Exynos ADC drvier have to control this clock. Exynos3250/Exynos4/Exynos5 has 'adc' clock as following: - 'adc' clock: bus clock for ADC Exynos3250 has additional 'sclk_adc' clock as following: - 'sclk_adc' clock: special clock for ADC which provide clock to internal ADC Exynos 4210/4212/4412 and Exynos5250/5420 has not included 'sclk_adc' clock in FSYS_BLK. But, Exynos3250 based on Cortex-A7 has only included 'sclk_adc' clock in FSYS_BLK. Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com> Acked-by: Kyungmin Park <kyungmin.park@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')
-rw-r--r--drivers/iio/adc/exynos_adc.c111
1 files changed, 103 insertions, 8 deletions
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index 66d27c638d83..fc9dfc23ecb7 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -24,6 +24,7 @@
24#include <linux/platform_device.h> 24#include <linux/platform_device.h>
25#include <linux/interrupt.h> 25#include <linux/interrupt.h>
26#include <linux/delay.h> 26#include <linux/delay.h>
27#include <linux/errno.h>
27#include <linux/kernel.h> 28#include <linux/kernel.h>
28#include <linux/slab.h> 29#include <linux/slab.h>
29#include <linux/io.h> 30#include <linux/io.h>
@@ -70,8 +71,9 @@
70#define ADC_V2_CON2_ACH_SEL(x) (((x) & 0xF) << 0) 71#define ADC_V2_CON2_ACH_SEL(x) (((x) & 0xF) << 0)
71#define ADC_V2_CON2_ACH_MASK 0xF 72#define ADC_V2_CON2_ACH_MASK 0xF
72 73
73#define MAX_ADC_V2_CHANNELS 10 74#define MAX_ADC_V2_CHANNELS 10
74#define MAX_ADC_V1_CHANNELS 8 75#define MAX_ADC_V1_CHANNELS 8
76#define MAX_EXYNOS3250_ADC_CHANNELS 2
75 77
76/* Bit definitions common for ADC_V1 and ADC_V2 */ 78/* Bit definitions common for ADC_V1 and ADC_V2 */
77#define ADC_CON_EN_START (1u << 0) 79#define ADC_CON_EN_START (1u << 0)
@@ -81,9 +83,11 @@
81 83
82struct exynos_adc { 84struct exynos_adc {
83 struct exynos_adc_data *data; 85 struct exynos_adc_data *data;
86 struct device *dev;
84 void __iomem *regs; 87 void __iomem *regs;
85 void __iomem *enable_reg; 88 void __iomem *enable_reg;
86 struct clk *clk; 89 struct clk *clk;
90 struct clk *sclk;
87 unsigned int irq; 91 unsigned int irq;
88 struct regulator *vdd; 92 struct regulator *vdd;
89 93
@@ -95,6 +99,7 @@ struct exynos_adc {
95 99
96struct exynos_adc_data { 100struct exynos_adc_data {
97 int num_channels; 101 int num_channels;
102 bool needs_sclk;
98 103
99 void (*init_hw)(struct exynos_adc *info); 104 void (*init_hw)(struct exynos_adc *info);
100 void (*exit_hw)(struct exynos_adc *info); 105 void (*exit_hw)(struct exynos_adc *info);
@@ -102,6 +107,66 @@ struct exynos_adc_data {
102 void (*start_conv)(struct exynos_adc *info, unsigned long addr); 107 void (*start_conv)(struct exynos_adc *info, unsigned long addr);
103}; 108};
104 109
110static void exynos_adc_unprepare_clk(struct exynos_adc *info)
111{
112 if (info->data->needs_sclk)
113 clk_unprepare(info->sclk);
114 clk_unprepare(info->clk);
115}
116
117static int exynos_adc_prepare_clk(struct exynos_adc *info)
118{
119 int ret;
120
121 ret = clk_prepare(info->clk);
122 if (ret) {
123 dev_err(info->dev, "failed preparing adc clock: %d\n", ret);
124 return ret;
125 }
126
127 if (info->data->needs_sclk) {
128 ret = clk_prepare(info->sclk);
129 if (ret) {
130 clk_unprepare(info->clk);
131 dev_err(info->dev,
132 "failed preparing sclk_adc clock: %d\n", ret);
133 return ret;
134 }
135 }
136
137 return 0;
138}
139
140static void exynos_adc_disable_clk(struct exynos_adc *info)
141{
142 if (info->data->needs_sclk)
143 clk_disable(info->sclk);
144 clk_disable(info->clk);
145}
146
147static int exynos_adc_enable_clk(struct exynos_adc *info)
148{
149 int ret;
150
151 ret = clk_enable(info->clk);
152 if (ret) {
153 dev_err(info->dev, "failed enabling adc clock: %d\n", ret);
154 return ret;
155 }
156
157 if (info->data->needs_sclk) {
158 ret = clk_enable(info->sclk);
159 if (ret) {
160 clk_disable(info->clk);
161 dev_err(info->dev,
162 "failed enabling sclk_adc clock: %d\n", ret);
163 return ret;
164 }
165 }
166
167 return 0;
168}
169
105static void exynos_adc_v1_init_hw(struct exynos_adc *info) 170static void exynos_adc_v1_init_hw(struct exynos_adc *info)
106{ 171{
107 u32 con1; 172 u32 con1;
@@ -208,6 +273,16 @@ static const struct exynos_adc_data exynos_adc_v2_data = {
208 .start_conv = exynos_adc_v2_start_conv, 273 .start_conv = exynos_adc_v2_start_conv,
209}; 274};
210 275
276static const struct exynos_adc_data exynos3250_adc_data = {
277 .num_channels = MAX_EXYNOS3250_ADC_CHANNELS,
278 .needs_sclk = true,
279
280 .init_hw = exynos_adc_v2_init_hw,
281 .exit_hw = exynos_adc_v2_exit_hw,
282 .clear_irq = exynos_adc_v2_clear_irq,
283 .start_conv = exynos_adc_v2_start_conv,
284};
285
211static const struct of_device_id exynos_adc_match[] = { 286static const struct of_device_id exynos_adc_match[] = {
212 { 287 {
213 .compatible = "samsung,exynos-adc-v1", 288 .compatible = "samsung,exynos-adc-v1",
@@ -215,6 +290,9 @@ static const struct of_device_id exynos_adc_match[] = {
215 }, { 290 }, {
216 .compatible = "samsung,exynos-adc-v2", 291 .compatible = "samsung,exynos-adc-v2",
217 .data = &exynos_adc_v2_data, 292 .data = &exynos_adc_v2_data,
293 }, {
294 .compatible = "samsung,exynos3250-adc",
295 .data = &exynos3250_adc_data,
218 }, 296 },
219 {}, 297 {},
220}; 298};
@@ -376,6 +454,7 @@ static int exynos_adc_probe(struct platform_device *pdev)
376 } 454 }
377 455
378 info->irq = irq; 456 info->irq = irq;
457 info->dev = &pdev->dev;
379 458
380 init_completion(&info->completion); 459 init_completion(&info->completion);
381 460
@@ -386,6 +465,16 @@ static int exynos_adc_probe(struct platform_device *pdev)
386 return PTR_ERR(info->clk); 465 return PTR_ERR(info->clk);
387 } 466 }
388 467
468 if (info->data->needs_sclk) {
469 info->sclk = devm_clk_get(&pdev->dev, "sclk");
470 if (IS_ERR(info->sclk)) {
471 dev_err(&pdev->dev,
472 "failed getting sclk clock, err = %ld\n",
473 PTR_ERR(info->sclk));
474 return PTR_ERR(info->sclk);
475 }
476 }
477
389 info->vdd = devm_regulator_get(&pdev->dev, "vdd"); 478 info->vdd = devm_regulator_get(&pdev->dev, "vdd");
390 if (IS_ERR(info->vdd)) { 479 if (IS_ERR(info->vdd)) {
391 dev_err(&pdev->dev, "failed getting regulator, err = %ld\n", 480 dev_err(&pdev->dev, "failed getting regulator, err = %ld\n",
@@ -397,10 +486,14 @@ static int exynos_adc_probe(struct platform_device *pdev)
397 if (ret) 486 if (ret)
398 return ret; 487 return ret;
399 488
400 ret = clk_prepare_enable(info->clk); 489 ret = exynos_adc_prepare_clk(info);
401 if (ret) 490 if (ret)
402 goto err_disable_reg; 491 goto err_disable_reg;
403 492
493 ret = exynos_adc_enable_clk(info);
494 if (ret)
495 goto err_unprepare_clk;
496
404 platform_set_drvdata(pdev, indio_dev); 497 platform_set_drvdata(pdev, indio_dev);
405 498
406 indio_dev->name = dev_name(&pdev->dev); 499 indio_dev->name = dev_name(&pdev->dev);
@@ -443,7 +536,9 @@ err_irq:
443err_disable_clk: 536err_disable_clk:
444 if (info->data->exit_hw) 537 if (info->data->exit_hw)
445 info->data->exit_hw(info); 538 info->data->exit_hw(info);
446 clk_disable_unprepare(info->clk); 539 exynos_adc_disable_clk(info);
540err_unprepare_clk:
541 exynos_adc_unprepare_clk(info);
447err_disable_reg: 542err_disable_reg:
448 regulator_disable(info->vdd); 543 regulator_disable(info->vdd);
449 return ret; 544 return ret;
@@ -460,7 +555,8 @@ static int exynos_adc_remove(struct platform_device *pdev)
460 free_irq(info->irq, info); 555 free_irq(info->irq, info);
461 if (info->data->exit_hw) 556 if (info->data->exit_hw)
462 info->data->exit_hw(info); 557 info->data->exit_hw(info);
463 clk_disable_unprepare(info->clk); 558 exynos_adc_disable_clk(info);
559 exynos_adc_unprepare_clk(info);
464 regulator_disable(info->vdd); 560 regulator_disable(info->vdd);
465 561
466 return 0; 562 return 0;
@@ -474,8 +570,7 @@ static int exynos_adc_suspend(struct device *dev)
474 570
475 if (info->data->exit_hw) 571 if (info->data->exit_hw)
476 info->data->exit_hw(info); 572 info->data->exit_hw(info);
477 573 exynos_adc_disable_clk(info);
478 clk_disable_unprepare(info->clk);
479 regulator_disable(info->vdd); 574 regulator_disable(info->vdd);
480 575
481 return 0; 576 return 0;
@@ -491,7 +586,7 @@ static int exynos_adc_resume(struct device *dev)
491 if (ret) 586 if (ret)
492 return ret; 587 return ret;
493 588
494 ret = clk_prepare_enable(info->clk); 589 ret = exynos_adc_enable_clk(info);
495 if (ret) 590 if (ret)
496 return ret; 591 return ret;
497 592