aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/iio/adc/exynos_adc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/iio/adc/exynos_adc.c')
-rw-r--r--drivers/iio/adc/exynos_adc.c138
1 files changed, 127 insertions, 11 deletions
diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c
index fc9dfc23ecb7..43620fd4c66a 100644
--- a/drivers/iio/adc/exynos_adc.c
+++ b/drivers/iio/adc/exynos_adc.c
@@ -40,13 +40,16 @@
40#include <linux/iio/machine.h> 40#include <linux/iio/machine.h>
41#include <linux/iio/driver.h> 41#include <linux/iio/driver.h>
42 42
43/* EXYNOS4412/5250 ADC_V1 registers definitions */ 43/* S3C/EXYNOS4412/5250 ADC_V1 registers definitions */
44#define ADC_V1_CON(x) ((x) + 0x00) 44#define ADC_V1_CON(x) ((x) + 0x00)
45#define ADC_V1_DLY(x) ((x) + 0x08) 45#define ADC_V1_DLY(x) ((x) + 0x08)
46#define ADC_V1_DATX(x) ((x) + 0x0C) 46#define ADC_V1_DATX(x) ((x) + 0x0C)
47#define ADC_V1_INTCLR(x) ((x) + 0x18) 47#define ADC_V1_INTCLR(x) ((x) + 0x18)
48#define ADC_V1_MUX(x) ((x) + 0x1c) 48#define ADC_V1_MUX(x) ((x) + 0x1c)
49 49
50/* S3C2410 ADC registers definitions */
51#define ADC_S3C2410_MUX(x) ((x) + 0x18)
52
50/* Future ADC_V2 registers definitions */ 53/* Future ADC_V2 registers definitions */
51#define ADC_V2_CON1(x) ((x) + 0x00) 54#define ADC_V2_CON1(x) ((x) + 0x00)
52#define ADC_V2_CON2(x) ((x) + 0x04) 55#define ADC_V2_CON2(x) ((x) + 0x04)
@@ -61,6 +64,11 @@
61#define ADC_V1_CON_PRSCLV(x) (((x) & 0xFF) << 6) 64#define ADC_V1_CON_PRSCLV(x) (((x) & 0xFF) << 6)
62#define ADC_V1_CON_STANDBY (1u << 2) 65#define ADC_V1_CON_STANDBY (1u << 2)
63 66
67/* Bit definitions for S3C2410 ADC */
68#define ADC_S3C2410_CON_SELMUX(x) (((x) & 7) << 3)
69#define ADC_S3C2410_DATX_MASK 0x3FF
70#define ADC_S3C2416_CON_RES_SEL (1u << 3)
71
64/* Bit definitions for ADC_V2 */ 72/* Bit definitions for ADC_V2 */
65#define ADC_V2_CON1_SOFT_RESET (1u << 2) 73#define ADC_V2_CON1_SOFT_RESET (1u << 2)
66 74
@@ -77,6 +85,7 @@
77 85
78/* Bit definitions common for ADC_V1 and ADC_V2 */ 86/* Bit definitions common for ADC_V1 and ADC_V2 */
79#define ADC_CON_EN_START (1u << 0) 87#define ADC_CON_EN_START (1u << 0)
88#define ADC_CON_EN_START_MASK (0x3 << 0)
80#define ADC_DATX_MASK 0xFFF 89#define ADC_DATX_MASK 0xFFF
81 90
82#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100)) 91#define EXYNOS_ADC_TIMEOUT (msecs_to_jiffies(100))
@@ -100,6 +109,8 @@ struct exynos_adc {
100struct exynos_adc_data { 109struct exynos_adc_data {
101 int num_channels; 110 int num_channels;
102 bool needs_sclk; 111 bool needs_sclk;
112 bool needs_adc_phy;
113 u32 mask;
103 114
104 void (*init_hw)(struct exynos_adc *info); 115 void (*init_hw)(struct exynos_adc *info);
105 void (*exit_hw)(struct exynos_adc *info); 116 void (*exit_hw)(struct exynos_adc *info);
@@ -171,7 +182,8 @@ static void exynos_adc_v1_init_hw(struct exynos_adc *info)
171{ 182{
172 u32 con1; 183 u32 con1;
173 184
174 writel(1, info->enable_reg); 185 if (info->data->needs_adc_phy)
186 writel(1, info->enable_reg);
175 187
176 /* set default prescaler values and Enable prescaler */ 188 /* set default prescaler values and Enable prescaler */
177 con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN; 189 con1 = ADC_V1_CON_PRSCLV(49) | ADC_V1_CON_PRSCEN;
@@ -185,7 +197,8 @@ static void exynos_adc_v1_exit_hw(struct exynos_adc *info)
185{ 197{
186 u32 con; 198 u32 con;
187 199
188 writel(0, info->enable_reg); 200 if (info->data->needs_adc_phy)
201 writel(0, info->enable_reg);
189 202
190 con = readl(ADC_V1_CON(info->regs)); 203 con = readl(ADC_V1_CON(info->regs));
191 con |= ADC_V1_CON_STANDBY; 204 con |= ADC_V1_CON_STANDBY;
@@ -210,6 +223,8 @@ static void exynos_adc_v1_start_conv(struct exynos_adc *info,
210 223
211static const struct exynos_adc_data exynos_adc_v1_data = { 224static const struct exynos_adc_data exynos_adc_v1_data = {
212 .num_channels = MAX_ADC_V1_CHANNELS, 225 .num_channels = MAX_ADC_V1_CHANNELS,
226 .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
227 .needs_adc_phy = true,
213 228
214 .init_hw = exynos_adc_v1_init_hw, 229 .init_hw = exynos_adc_v1_init_hw,
215 .exit_hw = exynos_adc_v1_exit_hw, 230 .exit_hw = exynos_adc_v1_exit_hw,
@@ -217,11 +232,89 @@ static const struct exynos_adc_data exynos_adc_v1_data = {
217 .start_conv = exynos_adc_v1_start_conv, 232 .start_conv = exynos_adc_v1_start_conv,
218}; 233};
219 234
235static void exynos_adc_s3c2416_start_conv(struct exynos_adc *info,
236 unsigned long addr)
237{
238 u32 con1;
239
240 /* Enable 12 bit ADC resolution */
241 con1 = readl(ADC_V1_CON(info->regs));
242 con1 |= ADC_S3C2416_CON_RES_SEL;
243 writel(con1, ADC_V1_CON(info->regs));
244
245 /* Select channel for S3C2416 */
246 writel(addr, ADC_S3C2410_MUX(info->regs));
247
248 con1 = readl(ADC_V1_CON(info->regs));
249 writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
250}
251
252static struct exynos_adc_data const exynos_adc_s3c2416_data = {
253 .num_channels = MAX_ADC_V1_CHANNELS,
254 .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
255
256 .init_hw = exynos_adc_v1_init_hw,
257 .exit_hw = exynos_adc_v1_exit_hw,
258 .start_conv = exynos_adc_s3c2416_start_conv,
259};
260
261static void exynos_adc_s3c2443_start_conv(struct exynos_adc *info,
262 unsigned long addr)
263{
264 u32 con1;
265
266 /* Select channel for S3C2433 */
267 writel(addr, ADC_S3C2410_MUX(info->regs));
268
269 con1 = readl(ADC_V1_CON(info->regs));
270 writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
271}
272
273static struct exynos_adc_data const exynos_adc_s3c2443_data = {
274 .num_channels = MAX_ADC_V1_CHANNELS,
275 .mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */
276
277 .init_hw = exynos_adc_v1_init_hw,
278 .exit_hw = exynos_adc_v1_exit_hw,
279 .start_conv = exynos_adc_s3c2443_start_conv,
280};
281
282static void exynos_adc_s3c64xx_start_conv(struct exynos_adc *info,
283 unsigned long addr)
284{
285 u32 con1;
286
287 con1 = readl(ADC_V1_CON(info->regs));
288 con1 &= ~ADC_S3C2410_CON_SELMUX(0x7);
289 con1 |= ADC_S3C2410_CON_SELMUX(addr);
290 writel(con1 | ADC_CON_EN_START, ADC_V1_CON(info->regs));
291}
292
293static struct exynos_adc_data const exynos_adc_s3c24xx_data = {
294 .num_channels = MAX_ADC_V1_CHANNELS,
295 .mask = ADC_S3C2410_DATX_MASK, /* 10 bit ADC resolution */
296
297 .init_hw = exynos_adc_v1_init_hw,
298 .exit_hw = exynos_adc_v1_exit_hw,
299 .start_conv = exynos_adc_s3c64xx_start_conv,
300};
301
302static struct exynos_adc_data const exynos_adc_s3c64xx_data = {
303 .num_channels = MAX_ADC_V1_CHANNELS,
304 .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
305
306 .init_hw = exynos_adc_v1_init_hw,
307 .exit_hw = exynos_adc_v1_exit_hw,
308 .clear_irq = exynos_adc_v1_clear_irq,
309 .start_conv = exynos_adc_s3c64xx_start_conv,
310};
311
220static void exynos_adc_v2_init_hw(struct exynos_adc *info) 312static void exynos_adc_v2_init_hw(struct exynos_adc *info)
221{ 313{
222 u32 con1, con2; 314 u32 con1, con2;
223 315
224 writel(1, info->enable_reg); 316 if (info->data->needs_adc_phy)
317 writel(1, info->enable_reg);
225 318
226 con1 = ADC_V2_CON1_SOFT_RESET; 319 con1 = ADC_V2_CON1_SOFT_RESET;
227 writel(con1, ADC_V2_CON1(info->regs)); 320 writel(con1, ADC_V2_CON1(info->regs));
@@ -238,7 +331,8 @@ static void exynos_adc_v2_exit_hw(struct exynos_adc *info)
238{ 331{
239 u32 con; 332 u32 con;
240 333
241 writel(0, info->enable_reg); 334 if (info->data->needs_adc_phy)
335 writel(0, info->enable_reg);
242 336
243 con = readl(ADC_V2_CON1(info->regs)); 337 con = readl(ADC_V2_CON1(info->regs));
244 con &= ~ADC_CON_EN_START; 338 con &= ~ADC_CON_EN_START;
@@ -266,6 +360,8 @@ static void exynos_adc_v2_start_conv(struct exynos_adc *info,
266 360
267static const struct exynos_adc_data exynos_adc_v2_data = { 361static const struct exynos_adc_data exynos_adc_v2_data = {
268 .num_channels = MAX_ADC_V2_CHANNELS, 362 .num_channels = MAX_ADC_V2_CHANNELS,
363 .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
364 .needs_adc_phy = true,
269 365
270 .init_hw = exynos_adc_v2_init_hw, 366 .init_hw = exynos_adc_v2_init_hw,
271 .exit_hw = exynos_adc_v2_exit_hw, 367 .exit_hw = exynos_adc_v2_exit_hw,
@@ -275,7 +371,9 @@ static const struct exynos_adc_data exynos_adc_v2_data = {
275 371
276static const struct exynos_adc_data exynos3250_adc_data = { 372static const struct exynos_adc_data exynos3250_adc_data = {
277 .num_channels = MAX_EXYNOS3250_ADC_CHANNELS, 373 .num_channels = MAX_EXYNOS3250_ADC_CHANNELS,
374 .mask = ADC_DATX_MASK, /* 12 bit ADC resolution */
278 .needs_sclk = true, 375 .needs_sclk = true,
376 .needs_adc_phy = true,
279 377
280 .init_hw = exynos_adc_v2_init_hw, 378 .init_hw = exynos_adc_v2_init_hw,
281 .exit_hw = exynos_adc_v2_exit_hw, 379 .exit_hw = exynos_adc_v2_exit_hw,
@@ -285,6 +383,21 @@ static const struct exynos_adc_data exynos3250_adc_data = {
285 383
286static const struct of_device_id exynos_adc_match[] = { 384static const struct of_device_id exynos_adc_match[] = {
287 { 385 {
386 .compatible = "samsung,s3c2410-adc",
387 .data = &exynos_adc_s3c24xx_data,
388 }, {
389 .compatible = "samsung,s3c2416-adc",
390 .data = &exynos_adc_s3c2416_data,
391 }, {
392 .compatible = "samsung,s3c2440-adc",
393 .data = &exynos_adc_s3c24xx_data,
394 }, {
395 .compatible = "samsung,s3c2443-adc",
396 .data = &exynos_adc_s3c2443_data,
397 }, {
398 .compatible = "samsung,s3c6410-adc",
399 .data = &exynos_adc_s3c64xx_data,
400 }, {
288 .compatible = "samsung,exynos-adc-v1", 401 .compatible = "samsung,exynos-adc-v1",
289 .data = &exynos_adc_v1_data, 402 .data = &exynos_adc_v1_data,
290 }, { 403 }, {
@@ -347,9 +460,10 @@ static int exynos_read_raw(struct iio_dev *indio_dev,
347static irqreturn_t exynos_adc_isr(int irq, void *dev_id) 460static irqreturn_t exynos_adc_isr(int irq, void *dev_id)
348{ 461{
349 struct exynos_adc *info = (struct exynos_adc *)dev_id; 462 struct exynos_adc *info = (struct exynos_adc *)dev_id;
463 u32 mask = info->data->mask;
350 464
351 /* Read value */ 465 /* Read value */
352 info->value = readl(ADC_V1_DATX(info->regs)) & ADC_DATX_MASK; 466 info->value = readl(ADC_V1_DATX(info->regs)) & mask;
353 467
354 /* clear irq */ 468 /* clear irq */
355 if (info->data->clear_irq) 469 if (info->data->clear_irq)
@@ -442,10 +556,13 @@ static int exynos_adc_probe(struct platform_device *pdev)
442 if (IS_ERR(info->regs)) 556 if (IS_ERR(info->regs))
443 return PTR_ERR(info->regs); 557 return PTR_ERR(info->regs);
444 558
445 mem = platform_get_resource(pdev, IORESOURCE_MEM, 1); 559
446 info->enable_reg = devm_ioremap_resource(&pdev->dev, mem); 560 if (info->data->needs_adc_phy) {
447 if (IS_ERR(info->enable_reg)) 561 mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
448 return PTR_ERR(info->enable_reg); 562 info->enable_reg = devm_ioremap_resource(&pdev->dev, mem);
563 if (IS_ERR(info->enable_reg))
564 return PTR_ERR(info->enable_reg);
565 }
449 566
450 irq = platform_get_irq(pdev, 0); 567 irq = platform_get_irq(pdev, 0);
451 if (irq < 0) { 568 if (irq < 0) {
@@ -606,7 +723,6 @@ static struct platform_driver exynos_adc_driver = {
606 .remove = exynos_adc_remove, 723 .remove = exynos_adc_remove,
607 .driver = { 724 .driver = {
608 .name = "exynos-adc", 725 .name = "exynos-adc",
609 .owner = THIS_MODULE,
610 .of_match_table = exynos_adc_match, 726 .of_match_table = exynos_adc_match,
611 .pm = &exynos_adc_pm_ops, 727 .pm = &exynos_adc_pm_ops,
612 }, 728 },