aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/plat-samsung/adc.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/plat-samsung/adc.c')
-rw-r--r--arch/arm/plat-samsung/adc.c84
1 files changed, 64 insertions, 20 deletions
diff --git a/arch/arm/plat-samsung/adc.c b/arch/arm/plat-samsung/adc.c
index e8f2be2d67f..ee8deef1948 100644
--- a/arch/arm/plat-samsung/adc.c
+++ b/arch/arm/plat-samsung/adc.c
@@ -21,6 +21,7 @@
21#include <linux/clk.h> 21#include <linux/clk.h>
22#include <linux/interrupt.h> 22#include <linux/interrupt.h>
23#include <linux/io.h> 23#include <linux/io.h>
24#include <linux/regulator/consumer.h>
24 25
25#include <plat/regs-adc.h> 26#include <plat/regs-adc.h>
26#include <plat/adc.h> 27#include <plat/adc.h>
@@ -39,8 +40,9 @@
39 */ 40 */
40 41
41enum s3c_cpu_type { 42enum s3c_cpu_type {
42 TYPE_S3C24XX, 43 TYPE_ADCV1, /* S3C24XX */
43 TYPE_S3C64XX 44 TYPE_ADCV2, /* S3C64XX, S5P64X0, S5PC100 */
45 TYPE_ADCV3, /* S5PV210, S5PC110, EXYNOS4210 */
44}; 46};
45 47
46struct s3c_adc_client { 48struct s3c_adc_client {
@@ -71,6 +73,7 @@ struct adc_device {
71 unsigned int prescale; 73 unsigned int prescale;
72 74
73 int irq; 75 int irq;
76 struct regulator *vdd;
74}; 77};
75 78
76static struct adc_device *adc_dev; 79static struct adc_device *adc_dev;
@@ -91,6 +94,7 @@ static inline void s3c_adc_select(struct adc_device *adc,
91 struct s3c_adc_client *client) 94 struct s3c_adc_client *client)
92{ 95{
93 unsigned con = readl(adc->regs + S3C2410_ADCCON); 96 unsigned con = readl(adc->regs + S3C2410_ADCCON);
97 enum s3c_cpu_type cpu = platform_get_device_id(adc->pdev)->driver_data;
94 98
95 client->select_cb(client, 1); 99 client->select_cb(client, 1);
96 100
@@ -98,8 +102,12 @@ static inline void s3c_adc_select(struct adc_device *adc,
98 con &= ~S3C2410_ADCCON_STDBM; 102 con &= ~S3C2410_ADCCON_STDBM;
99 con &= ~S3C2410_ADCCON_STARTMASK; 103 con &= ~S3C2410_ADCCON_STARTMASK;
100 104
101 if (!client->is_ts) 105 if (!client->is_ts) {
102 con |= S3C2410_ADCCON_SELMUX(client->channel); 106 if (cpu == TYPE_ADCV3)
107 writel(client->channel & 0xf, adc->regs + S5P_ADCMUX);
108 else
109 con |= S3C2410_ADCCON_SELMUX(client->channel);
110 }
103 111
104 writel(con, adc->regs + S3C2410_ADCCON); 112 writel(con, adc->regs + S3C2410_ADCCON);
105} 113}
@@ -285,8 +293,8 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw)
285 293
286 client->nr_samples--; 294 client->nr_samples--;
287 295
288 if (cpu == TYPE_S3C64XX) { 296 if (cpu != TYPE_ADCV1) {
289 /* S3C64XX ADC resolution is 12-bit */ 297 /* S3C64XX/S5P ADC resolution is 12-bit */
290 data0 &= 0xfff; 298 data0 &= 0xfff;
291 data1 &= 0xfff; 299 data1 &= 0xfff;
292 } else { 300 } else {
@@ -312,7 +320,7 @@ static irqreturn_t s3c_adc_irq(int irq, void *pw)
312 } 320 }
313 321
314exit: 322exit:
315 if (cpu == TYPE_S3C64XX) { 323 if (cpu != TYPE_ADCV1) {
316 /* Clear ADC interrupt */ 324 /* Clear ADC interrupt */
317 writel(0, adc->regs + S3C64XX_ADCCLRINT); 325 writel(0, adc->regs + S3C64XX_ADCCLRINT);
318 } 326 }
@@ -338,17 +346,24 @@ static int s3c_adc_probe(struct platform_device *pdev)
338 adc->pdev = pdev; 346 adc->pdev = pdev;
339 adc->prescale = S3C2410_ADCCON_PRSCVL(49); 347 adc->prescale = S3C2410_ADCCON_PRSCVL(49);
340 348
349 adc->vdd = regulator_get(dev, "vdd");
350 if (IS_ERR(adc->vdd)) {
351 dev_err(dev, "operating without regulator \"vdd\" .\n");
352 ret = PTR_ERR(adc->vdd);
353 goto err_alloc;
354 }
355
341 adc->irq = platform_get_irq(pdev, 1); 356 adc->irq = platform_get_irq(pdev, 1);
342 if (adc->irq <= 0) { 357 if (adc->irq <= 0) {
343 dev_err(dev, "failed to get adc irq\n"); 358 dev_err(dev, "failed to get adc irq\n");
344 ret = -ENOENT; 359 ret = -ENOENT;
345 goto err_alloc; 360 goto err_reg;
346 } 361 }
347 362
348 ret = request_irq(adc->irq, s3c_adc_irq, 0, dev_name(dev), adc); 363 ret = request_irq(adc->irq, s3c_adc_irq, 0, dev_name(dev), adc);
349 if (ret < 0) { 364 if (ret < 0) {
350 dev_err(dev, "failed to attach adc irq\n"); 365 dev_err(dev, "failed to attach adc irq\n");
351 goto err_alloc; 366 goto err_reg;
352 } 367 }
353 368
354 adc->clk = clk_get(dev, "adc"); 369 adc->clk = clk_get(dev, "adc");
@@ -372,10 +387,14 @@ static int s3c_adc_probe(struct platform_device *pdev)
372 goto err_clk; 387 goto err_clk;
373 } 388 }
374 389
390 ret = regulator_enable(adc->vdd);
391 if (ret)
392 goto err_ioremap;
393
375 clk_enable(adc->clk); 394 clk_enable(adc->clk);
376 395
377 tmp = adc->prescale | S3C2410_ADCCON_PRSCEN; 396 tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
378 if (platform_get_device_id(pdev)->driver_data == TYPE_S3C64XX) { 397 if (platform_get_device_id(pdev)->driver_data != TYPE_ADCV1) {
379 /* Enable 12-bit ADC resolution */ 398 /* Enable 12-bit ADC resolution */
380 tmp |= S3C64XX_ADCCON_RESSEL; 399 tmp |= S3C64XX_ADCCON_RESSEL;
381 } 400 }
@@ -388,12 +407,15 @@ static int s3c_adc_probe(struct platform_device *pdev)
388 407
389 return 0; 408 return 0;
390 409
410 err_ioremap:
411 iounmap(adc->regs);
391 err_clk: 412 err_clk:
392 clk_put(adc->clk); 413 clk_put(adc->clk);
393 414
394 err_irq: 415 err_irq:
395 free_irq(adc->irq, adc); 416 free_irq(adc->irq, adc);
396 417 err_reg:
418 regulator_put(adc->vdd);
397 err_alloc: 419 err_alloc:
398 kfree(adc); 420 kfree(adc);
399 return ret; 421 return ret;
@@ -406,6 +428,8 @@ static int __devexit s3c_adc_remove(struct platform_device *pdev)
406 iounmap(adc->regs); 428 iounmap(adc->regs);
407 free_irq(adc->irq, adc); 429 free_irq(adc->irq, adc);
408 clk_disable(adc->clk); 430 clk_disable(adc->clk);
431 regulator_disable(adc->vdd);
432 regulator_put(adc->vdd);
409 clk_put(adc->clk); 433 clk_put(adc->clk);
410 kfree(adc); 434 kfree(adc);
411 435
@@ -413,8 +437,10 @@ static int __devexit s3c_adc_remove(struct platform_device *pdev)
413} 437}
414 438
415#ifdef CONFIG_PM 439#ifdef CONFIG_PM
416static int s3c_adc_suspend(struct platform_device *pdev, pm_message_t state) 440static int s3c_adc_suspend(struct device *dev)
417{ 441{
442 struct platform_device *pdev = container_of(dev,
443 struct platform_device, dev);
418 struct adc_device *adc = platform_get_drvdata(pdev); 444 struct adc_device *adc = platform_get_drvdata(pdev);
419 unsigned long flags; 445 unsigned long flags;
420 u32 con; 446 u32 con;
@@ -428,19 +454,30 @@ static int s3c_adc_suspend(struct platform_device *pdev, pm_message_t state)
428 disable_irq(adc->irq); 454 disable_irq(adc->irq);
429 spin_unlock_irqrestore(&adc->lock, flags); 455 spin_unlock_irqrestore(&adc->lock, flags);
430 clk_disable(adc->clk); 456 clk_disable(adc->clk);
457 regulator_disable(adc->vdd);
431 458
432 return 0; 459 return 0;
433} 460}
434 461
435static int s3c_adc_resume(struct platform_device *pdev) 462static int s3c_adc_resume(struct device *dev)
436{ 463{
464 struct platform_device *pdev = container_of(dev,
465 struct platform_device, dev);
437 struct adc_device *adc = platform_get_drvdata(pdev); 466 struct adc_device *adc = platform_get_drvdata(pdev);
467 int ret;
468 unsigned long tmp;
438 469
470 ret = regulator_enable(adc->vdd);
471 if (ret)
472 return ret;
439 clk_enable(adc->clk); 473 clk_enable(adc->clk);
440 enable_irq(adc->irq); 474 enable_irq(adc->irq);
441 475
442 writel(adc->prescale | S3C2410_ADCCON_PRSCEN, 476 tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
443 adc->regs + S3C2410_ADCCON); 477 /* Enable 12-bit ADC resolution */
478 if (platform_get_device_id(pdev)->driver_data != TYPE_ADCV1)
479 tmp |= S3C64XX_ADCCON_RESSEL;
480 writel(tmp, adc->regs + S3C2410_ADCCON);
444 481
445 return 0; 482 return 0;
446} 483}
@@ -453,25 +490,32 @@ static int s3c_adc_resume(struct platform_device *pdev)
453static struct platform_device_id s3c_adc_driver_ids[] = { 490static struct platform_device_id s3c_adc_driver_ids[] = {
454 { 491 {
455 .name = "s3c24xx-adc", 492 .name = "s3c24xx-adc",
456 .driver_data = TYPE_S3C24XX, 493 .driver_data = TYPE_ADCV1,
457 }, { 494 }, {
458 .name = "s3c64xx-adc", 495 .name = "s3c64xx-adc",
459 .driver_data = TYPE_S3C64XX, 496 .driver_data = TYPE_ADCV2,
497 }, {
498 .name = "samsung-adc-v3",
499 .driver_data = TYPE_ADCV3,
460 }, 500 },
461 { } 501 { }
462}; 502};
463MODULE_DEVICE_TABLE(platform, s3c_adc_driver_ids); 503MODULE_DEVICE_TABLE(platform, s3c_adc_driver_ids);
464 504
505static const struct dev_pm_ops adc_pm_ops = {
506 .suspend = s3c_adc_suspend,
507 .resume = s3c_adc_resume,
508};
509
465static struct platform_driver s3c_adc_driver = { 510static struct platform_driver s3c_adc_driver = {
466 .id_table = s3c_adc_driver_ids, 511 .id_table = s3c_adc_driver_ids,
467 .driver = { 512 .driver = {
468 .name = "s3c-adc", 513 .name = "s3c-adc",
469 .owner = THIS_MODULE, 514 .owner = THIS_MODULE,
515 .pm = &adc_pm_ops,
470 }, 516 },
471 .probe = s3c_adc_probe, 517 .probe = s3c_adc_probe,
472 .remove = __devexit_p(s3c_adc_remove), 518 .remove = __devexit_p(s3c_adc_remove),
473 .suspend = s3c_adc_suspend,
474 .resume = s3c_adc_resume,
475}; 519};
476 520
477static int __init adc_init(void) 521static int __init adc_init(void)
@@ -485,4 +529,4 @@ static int __init adc_init(void)
485 return ret; 529 return ret;
486} 530}
487 531
488arch_initcall(adc_init); 532module_init(adc_init);