歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> S3C2410驅動分析之ADC通用驅動

S3C2410驅動分析之ADC通用驅動

日期:2017/3/1 10:24:33   编辑:Linux編程

內核版本:2.6.36

源碼路徑:arch/arm/plat-samsung/adc.c

在Linux-2.6.36中,提供了一個S3C2410的ADC通用驅動模塊,定義在arch/arm/plat-samsung/adc.c文件中。用戶要使用ADC,可以使用該通用驅動模塊提供的接口進行注冊和讀取。
首先我們來看初始化函數adc_init:
  1. 477static int __init adc_init(void)
  2. 478{
  3. 479 int ret;
  4. 480
  5. 481 ret = platform_driver_register(&s3c_adc_driver);
  6. 482 if (ret)
  7. 483 printk(KERN_ERR "%s: failed to add adc driver\n", __func__);
  8. 484
  9. 485 return ret;
  10. 486}
  11. 481行,注冊了platform_driver s3c_adc_driver,其定義如下:
  12. 465static struct platform_driver s3c_adc_driver = {
  13. 466 .id_table = s3c_adc_driver_ids,
  14. 467 .driver = {
  15. 468 .name = "s3c-adc",
  16. 469 .owner = THIS_MODULE,
  17. 470 },
  18. 471 .probe = s3c_adc_probe,
  19. 472 .remove = __devexit_p(s3c_adc_remove),
  20. 473 .suspend = s3c_adc_suspend,
  21. 474 .resume = s3c_adc_resume,
  22. 475};

注冊驅動程序時,probe函數s3c_adc_probe就會執行,其代碼如下:
 
  1. 322static int s3c_adc_probe(struct platform_device *pdev)
  2. 323{
  3. 324 struct device *dev = &pdev->dev;
  4. 325 struct adc_device *adc;
  5. 326 struct resource *regs;
  6. 327 int ret;
  7. 328 unsigned tmp;
  8. 329
  9. 330 adc = kzalloc(sizeof(struct adc_device), GFP_KERNEL);
  10. 331 if (adc == NULL) {
  11. 332 dev_err(dev, "failed to allocate adc_device\n");
  12. 333 return -ENOMEM;
  13. 334 }
  14. 335
  15. 336 spin_lock_init(&adc->lock);
  16. 337
  17. 338 adc->pdev = pdev;
  18. 339 adc->prescale = S3C2410_ADCCON_PRSCVL(49);
  19. 340
  20. 341 adc->irq = platform_get_irq(pdev, 1);
  21. 342 if (adc->irq <= 0) {
  22. 343 dev_err(dev, "failed to get adc irq\n");
  23. 344 ret = -ENOENT;
  24. 345 goto err_alloc;
  25. 346 }
  26. 347
  27. 348 ret = request_irq(adc->irq, s3c_adc_irq, 0, dev_name(dev), adc);
  28. 349 if (ret < 0) {
  29. 350 dev_err(dev, "failed to attach adc irq\n");
  30. 351 goto err_alloc;
  31. 352 }
  32. 353
  33. 354 adc->clk = clk_get(dev, "adc");
  34. 355 if (IS_ERR(adc->clk)) {
  35. 356 dev_err(dev, "failed to get adc clock\n");
  36. 357 ret = PTR_ERR(adc->clk);
  37. 358 goto err_irq;
  38. 359 }
  39. 360
  40. 361 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  41. 362 if (!regs) {
  42. 363 dev_err(dev, "failed to find registers\n");
  43. 364 ret = -ENXIO;
  44. 365 goto err_clk;
  45. 366 }
  46. 367
  47. 368 adc->regs = ioremap(regs->start, resource_size(regs));
  48. 369 if (!adc->regs) {
  49. 370 dev_err(dev, "failed to map registers\n");
  50. 371 ret = -ENXIO;
  51. 372 goto err_clk;
  52. 373 }
  53. 374
  54. 375 clk_enable(adc->clk);
  55. 376
  56. 377 tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
  57. 378 if (platform_get_device_id(pdev)->driver_data == TYPE_S3C64XX) {
  58. 379 /* Enable 12-bit ADC resolution */
  59. 380 tmp |= S3C64XX_ADCCON_RESSEL;
  60. 381 }
  61. 382 writel(tmp, adc->regs + S3C2410_ADCCON);
  62. 383
  63. 384 dev_info(dev, "attached adc driver\n");
  64. 385
  65. 386 platform_set_drvdata(pdev, adc);
  66. 387 adc_dev = adc;
  67. 388
  68. 389 return 0;
  69. 390
  70. 391 err_clk:
  71. 392 clk_put(adc->clk);
  72. 393
  73. 394 err_irq:
  74. 395 free_irq(adc->irq, adc);
  75. 396
  76. 397 err_alloc:
  77. 398 kfree(adc);
  78. 399 return ret;
  79. 400}

330行,創建了adc_device結構體變量adc,adc_device結構體代表一個ADC設備,其定義如下:
  1. 62struct adc_device {
  2. 63 struct platform_device *pdev;
  3. 64 struct platform_device *owner;
  4. 65 struct clk *clk;
  5. 66 struct s3c_adc_client *cur;
  6. 67 struct s3c_adc_client *ts_pend;
  7. 68 void __iomem *regs;
  8. 69 spinlock_t lock;
  9. 70
  10. 71 unsigned int prescale;
  11. 72
  12. 73 int irq;
  13. 74};

65行,clk代表ADC時鐘。
66行,cur代表當前正在處理的客戶。
67行,ts_pend代表觸摸屏,這裡ADC把客戶分為觸摸屏和非觸摸屏兩大類,專門用ts_pend代表觸摸屏。
68行,regs是ADC的I/O內存。
71行,prescale是ADC的預分頻系數。
73行,irq是觸摸屏中斷號。
adc_device中用到了s3c_adc_client結構,其定義如下:
  1. 46struct s3c_adc_client {
  2. 47 struct platform_device *pdev;
  3. 48 struct list_head pend;
  4. 49 wait_queue_head_t *wait;
  5. 50
  6. 51 unsigned int nr_samples;
  7. 52 int result;
  8. 53 unsigned char is_ts;
  9. 54 unsigned char channel;
  10. 55
  11. 56 void (*select_cb)(struct s3c_adc_client *c, unsigned selected);
  12. 57 void (*convert_cb)(struct s3c_adc_client *c,
  13. 58 unsigned val1, unsigned val2,
  14. 59 unsigned *samples_left);
  15. 60};

s3c_adc_client代表了一個請求ADC服務的客戶(client)。
48行,是一個鏈表項,用來將client插入等待鏈表adc_pending。
49行,wait是client的等待隊列頭,如果必須等待,client進程會在wait上休眠。
51行,nr_samples記錄客戶指定的采樣次數。
52行,result記錄采樣結果。
53行,is_ts表明是不是觸摸屏。
54行,channel表明客戶要使用的ADC通道。
56行,select回調函數,用於選擇客戶(初始化客戶)和取消選擇客戶。
57行,convert回調函數,用於對AD轉換結果進行相應處理。
Copyright © Linux教程網 All Rights Reserved