內核版本:2.6.36
源碼路徑:arch/arm/plat-samsung/adc.c
在Linux-2.6.36中,提供了一個S3C2410的ADC通用驅動模塊,定義在arch/arm/plat-samsung/adc.c文件中。用戶要使用ADC,可以使用該通用驅動模塊提供的接口進行注冊和讀取。
首先我們來看初始化函數adc_init:
- 477static int __init adc_init(void)
- 478{
- 479 int ret;
- 480
- 481 ret = platform_driver_register(&s3c_adc_driver);
- 482 if (ret)
- 483 printk(KERN_ERR "%s: failed to add adc driver\n", __func__);
- 484
- 485 return ret;
- 486}
- 481行,注冊了platform_driver s3c_adc_driver,其定義如下:
- 465static struct platform_driver s3c_adc_driver = {
- 466 .id_table = s3c_adc_driver_ids,
- 467 .driver = {
- 468 .name = "s3c-adc",
- 469 .owner = THIS_MODULE,
- 470 },
- 471 .probe = s3c_adc_probe,
- 472 .remove = __devexit_p(s3c_adc_remove),
- 473 .suspend = s3c_adc_suspend,
- 474 .resume = s3c_adc_resume,
- 475};
注冊驅動程序時,probe函數s3c_adc_probe就會執行,其代碼如下:
- 322static int s3c_adc_probe(struct platform_device *pdev)
- 323{
- 324 struct device *dev = &pdev->dev;
- 325 struct adc_device *adc;
- 326 struct resource *regs;
- 327 int ret;
- 328 unsigned tmp;
- 329
- 330 adc = kzalloc(sizeof(struct adc_device), GFP_KERNEL);
- 331 if (adc == NULL) {
- 332 dev_err(dev, "failed to allocate adc_device\n");
- 333 return -ENOMEM;
- 334 }
- 335
- 336 spin_lock_init(&adc->lock);
- 337
- 338 adc->pdev = pdev;
- 339 adc->prescale = S3C2410_ADCCON_PRSCVL(49);
- 340
- 341 adc->irq = platform_get_irq(pdev, 1);
- 342 if (adc->irq <= 0) {
- 343 dev_err(dev, "failed to get adc irq\n");
- 344 ret = -ENOENT;
- 345 goto err_alloc;
- 346 }
- 347
- 348 ret = request_irq(adc->irq, s3c_adc_irq, 0, dev_name(dev), adc);
- 349 if (ret < 0) {
- 350 dev_err(dev, "failed to attach adc irq\n");
- 351 goto err_alloc;
- 352 }
- 353
- 354 adc->clk = clk_get(dev, "adc");
- 355 if (IS_ERR(adc->clk)) {
- 356 dev_err(dev, "failed to get adc clock\n");
- 357 ret = PTR_ERR(adc->clk);
- 358 goto err_irq;
- 359 }
- 360
- 361 regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- 362 if (!regs) {
- 363 dev_err(dev, "failed to find registers\n");
- 364 ret = -ENXIO;
- 365 goto err_clk;
- 366 }
- 367
- 368 adc->regs = ioremap(regs->start, resource_size(regs));
- 369 if (!adc->regs) {
- 370 dev_err(dev, "failed to map registers\n");
- 371 ret = -ENXIO;
- 372 goto err_clk;
- 373 }
- 374
- 375 clk_enable(adc->clk);
- 376
- 377 tmp = adc->prescale | S3C2410_ADCCON_PRSCEN;
- 378 if (platform_get_device_id(pdev)->driver_data == TYPE_S3C64XX) {
- 379 /* Enable 12-bit ADC resolution */
- 380 tmp |= S3C64XX_ADCCON_RESSEL;
- 381 }
- 382 writel(tmp, adc->regs + S3C2410_ADCCON);
- 383
- 384 dev_info(dev, "attached adc driver\n");
- 385
- 386 platform_set_drvdata(pdev, adc);
- 387 adc_dev = adc;
- 388
- 389 return 0;
- 390
- 391 err_clk:
- 392 clk_put(adc->clk);
- 393
- 394 err_irq:
- 395 free_irq(adc->irq, adc);
- 396
- 397 err_alloc:
- 398 kfree(adc);
- 399 return ret;
- 400}
330行,創建了adc_device結構體變量adc,adc_device結構體代表一個ADC設備,其定義如下:
- 62struct adc_device {
- 63 struct platform_device *pdev;
- 64 struct platform_device *owner;
- 65 struct clk *clk;
- 66 struct s3c_adc_client *cur;
- 67 struct s3c_adc_client *ts_pend;
- 68 void __iomem *regs;
- 69 spinlock_t lock;
- 70
- 71 unsigned int prescale;
- 72
- 73 int irq;
- 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結構,其定義如下:
- 46struct s3c_adc_client {
- 47 struct platform_device *pdev;
- 48 struct list_head pend;
- 49 wait_queue_head_t *wait;
- 50
- 51 unsigned int nr_samples;
- 52 int result;
- 53 unsigned char is_ts;
- 54 unsigned char channel;
- 55
- 56 void (*select_cb)(struct s3c_adc_client *c, unsigned selected);
- 57 void (*convert_cb)(struct s3c_adc_client *c,
- 58 unsigned val1, unsigned val2,
- 59 unsigned *samples_left);
- 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轉換結果進行相應處理。