您的位置:首页 > 其它

S3C2410驱动分析之ADC通用驱动

2012-09-13 14:21 363 查看
内核版本:2.6.36

源码路径:arch/arm/plat-samsung/adc.c


在Linux-2.6.36中,提供了一个S3C2410的ADC通用驱动模块,定义在arch/arm/plat-samsung/adc.c文件中。用户要使用ADC,可以使用该通用驱动模块提供的接口进行注册和读取。

首先我们来看初始化函数adc_init:

[cpp]viewplaincopyprint?477staticint__initadc_init(void)
478{
479intret;
480
481ret=platform_driver_register(&s3c_adc_driver);
482if(ret)
483printk(KERN_ERR"%s:failedtoaddadcdriver\n",__func__);
484
485returnret;
486}
481行,注册了platform_drivers3c_adc_driver,其定义如下:
465staticstructplatform_drivers3c_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};
[code]477staticint__initadc_init(void)
478{
479intret;
480
481ret=platform_driver_register(&s3c_adc_driver);
482if(ret)
483printk(KERN_ERR"%s:failedtoaddadcdriver\n",__func__);
484
485returnret;
486}
481行,注册了platform_drivers3c_adc_driver,其定义如下:
465staticstructplatform_drivers3c_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就会执行,其代码如下:[/code]
[cpp]viewplaincopyprint?322staticints3c_adc_probe(structplatform_device*pdev)
323{
324structdevice*dev=&pdev->dev;
325structadc_device*adc;
326structresource*regs;
327intret;
328unsignedtmp;
329
330adc=kzalloc(sizeof(structadc_device),GFP_KERNEL);
331if(adc==NULL){
332dev_err(dev,"failedtoallocateadc_device\n");
333return-ENOMEM;
334}
335
336spin_lock_init(&adc->lock);
337
338adc->pdev=pdev;
339adc->prescale=S3C2410_ADCCON_PRSCVL(49);
340
341adc->irq=platform_get_irq(pdev,1);
342if(adc->irq<=0){
343dev_err(dev,"failedtogetadcirq\n");
344ret=-ENOENT;
345gotoerr_alloc;
346}
347
348ret=request_irq(adc->irq,s3c_adc_irq,0,dev_name(dev),adc);
349if(ret<0){
350dev_err(dev,"failedtoattachadcirq\n");
351gotoerr_alloc;
352}
353
354adc->clk=clk_get(dev,"adc");
355if(IS_ERR(adc->clk)){
356dev_err(dev,"failedtogetadcclock\n");
357ret=PTR_ERR(adc->clk);
358gotoerr_irq;
359}
360
361regs=platform_get_resource(pdev,IORESOURCE_MEM,0);
362if(!regs){
363dev_err(dev,"failedtofindregisters\n");
364ret=-ENXIO;
365gotoerr_clk;
366}
367
368adc->regs=ioremap(regs->start,resource_size(regs));
369if(!adc->regs){
370dev_err(dev,"failedtomapregisters\n");
371ret=-ENXIO;
372gotoerr_clk;
373}
374
375clk_enable(adc->clk);
376
377tmp=adc->prescale|S3C2410_ADCCON_PRSCEN;
378if(platform_get_device_id(pdev)->driver_data==TYPE_S3C64XX){
379/*Enable12-bitADCresolution*/
380tmp|=S3C64XX_ADCCON_RESSEL;
381}
382writel(tmp,adc->regs+S3C2410_ADCCON);
383
384dev_info(dev,"attachedadcdriver\n");
385
386platform_set_drvdata(pdev,adc);
387adc_dev=adc;
388
389return0;
390
391err_clk:
392clk_put(adc->clk);
393
394err_irq:
395free_irq(adc->irq,adc);
396
397err_alloc:
398kfree(adc);
399returnret;
400}
[code]322staticints3c_adc_probe(structplatform_device*pdev)
323{
324structdevice*dev=&pdev->dev;
325structadc_device*adc;
326structresource*regs;
327intret;
328unsignedtmp;
329
330adc=kzalloc(sizeof(structadc_device),GFP_KERNEL);
331if(adc==NULL){
332dev_err(dev,"failedtoallocateadc_device\n");
333return-ENOMEM;
334}
335
336spin_lock_init(&adc->lock);
337
338adc->pdev=pdev;
339adc->prescale=S3C2410_ADCCON_PRSCVL(49);
340
341adc->irq=platform_get_irq(pdev,1);
342if(adc->irq<=0){
343dev_err(dev,"failedtogetadcirq\n");
344ret=-ENOENT;
345gotoerr_alloc;
346}
347
348ret=request_irq(adc->irq,s3c_adc_irq,0,dev_name(dev),adc);
349if(ret<0){
350dev_err(dev,"failedtoattachadcirq\n");
351gotoerr_alloc;
352}
353
354adc->clk=clk_get(dev,"adc");
355if(IS_ERR(adc->clk)){
356dev_err(dev,"failedtogetadcclock\n");
357ret=PTR_ERR(adc->clk);
358gotoerr_irq;
359}
360
361regs=platform_get_resource(pdev,IORESOURCE_MEM,0);
362if(!regs){
363dev_err(dev,"failedtofindregisters\n");
364ret=-ENXIO;
365gotoerr_clk;
366}
367
368adc->regs=ioremap(regs->start,resource_size(regs));
369if(!adc->regs){
370dev_err(dev,"failedtomapregisters\n");
371ret=-ENXIO;
372gotoerr_clk;
373}
374
375clk_enable(adc->clk);
376
377tmp=adc->prescale|S3C2410_ADCCON_PRSCEN;
378if(platform_get_device_id(pdev)->driver_data==TYPE_S3C64XX){
379/*Enable12-bitADCresolution*/
380tmp|=S3C64XX_ADCCON_RESSEL;
381}
382writel(tmp,adc->regs+S3C2410_ADCCON);
383
384dev_info(dev,"attachedadcdriver\n");
385
386platform_set_drvdata(pdev,adc);
387adc_dev=adc;
388
389return0;
390
391err_clk:
392clk_put(adc->clk);
393
394err_irq:
395free_irq(adc->irq,adc);
396
397err_alloc:
398kfree(adc);
399returnret;
400}

330行,创建了adc_device结构体变量adc,adc_device结构体代表一个ADC设备,其定义如下:[/code]
[cpp]viewplaincopyprint?62structadc_device{
63structplatform_device*pdev;
64structplatform_device*owner;
65structclk*clk;
66structs3c_adc_client*cur;
67structs3c_adc_client*ts_pend;
68void__iomem*regs;
69spinlock_tlock;
70
71unsignedintprescale;
72
73intirq;
74};
[code]62structadc_device{
63structplatform_device*pdev;
64structplatform_device*owner;
65structclk*clk;
66structs3c_adc_client*cur;
67structs3c_adc_client*ts_pend;
68void__iomem*regs;
69spinlock_tlock;
70
71unsignedintprescale;
72
73intirq;
74};

65行,clk代表ADC时钟。[/code]
66行,cur代表当前正在处理的客户。

67行,ts_pend代表触摸屏,这里ADC把客户分为触摸屏和非触摸屏两大类,专门用ts_pend代表触摸屏。

68行,regs是ADC的I/O内存。

71行,prescale是ADC的预分频系数。

73行,irq是触摸屏中断号。

adc_device中用到了s3c_adc_client结构,其定义如下:

[cpp]viewplaincopyprint?46structs3c_adc_client{
47structplatform_device*pdev;
48structlist_headpend;
49wait_queue_head_t*wait;
50
51unsignedintnr_samples;
52intresult;
53unsignedcharis_ts;
54unsignedcharchannel;
55
56void(*select_cb)(structs3c_adc_client*c,unsignedselected);
57void(*convert_cb)(structs3c_adc_client*c,
58unsignedval1,unsignedval2,
59unsigned*samples_left);
60};
[code]46structs3c_adc_client{
47structplatform_device*pdev;
48structlist_headpend;
49wait_queue_head_t*wait;
50
51unsignedintnr_samples;
52intresult;
53unsignedcharis_ts;
54unsignedcharchannel;
55
56void(*select_cb)(structs3c_adc_client*c,unsignedselected);
57void(*convert_cb)(structs3c_adc_client*c,
58unsignedval1,unsignedval2,
59unsigned*samples_left);
60};

s3c_adc_client代表了一个请求ADC服务的客户(client)。[/code]
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转换结果进行相应处理。

回到s3c_adc_probe函数:

339行,设置预分频系统为49。

341行,取得ADC中断号。

348行,申请中断,注册ADC中断处理函数为s3c_adc_irq。

354行,取得ADC时钟。

361行,取得ADCI/O内存。

368行,使用ioremap得到I/O内存对应的虚拟地址。

375行,使能ADC时钟。

377-382行,设置使用预分频及预分频系统。

至此,ADC模块的初始化就完成了。

下面我们看客户注册ADC服务的接口函数s3c_adc_register,代码如下:

[cpp]viewplaincopyprint?207structs3c_adc_client*s3c_adc_register(structplatform_device*pdev,
208void(*select)(structs3c_adc_client*client,
209unsignedintselected),
210void(*conv)(structs3c_adc_client*client,
211unsignedd0,unsignedd1,
212unsigned*samples_left),
213unsignedintis_ts)
214{
215structs3c_adc_client*client;
216
217WARN_ON(!pdev);
218
219if(!select)
220select=s3c_adc_default_select;
221
222if(!pdev)
223returnERR_PTR(-EINVAL);
224
225client=kzalloc(sizeof(structs3c_adc_client),GFP_KERNEL);
226if(!client){
227dev_err(&pdev->dev,"nomemoryforadcclient\n");
228returnERR_PTR(-ENOMEM);
229}
230
231client->pdev=pdev;
232client->is_ts=is_ts;
233client->select_cb=select;
234client->convert_cb=conv;
235
236returnclient;
237}
[code]207structs3c_adc_client*s3c_adc_register(structplatform_device*pdev,
208void(*select)(structs3c_adc_client*client,
209unsignedintselected),
210void(*conv)(structs3c_adc_client*client,
211unsignedd0,unsignedd1,
212unsigned*samples_left),
213unsignedintis_ts)
214{
215structs3c_adc_client*client;
216
217WARN_ON(!pdev);
218
219if(!select)
220select=s3c_adc_default_select;
221
222if(!pdev)
223returnERR_PTR(-EINVAL);
224
225client=kzalloc(sizeof(structs3c_adc_client),GFP_KERNEL);
226if(!client){
227dev_err(&pdev->dev,"nomemoryforadcclient\n");
228returnERR_PTR(-ENOMEM);
229}
230
231client->pdev=pdev;
232client->is_ts=is_ts;
233client->select_cb=select;
234client->convert_cb=conv;
235
236returnclient;
237}

219-220行,如果没有指定select回调函数,则使用默认的回调函数s3c_adc_default_select,这个函数的实现没有做任何事情,是个空函数。由这句话可以看出,select回调函数是必须定义的,自己不定义也要使用默认的。而convert回调函数则不是必须定义的。[/code]
225-234行,为client分配空间,并初始化相关成员。

236行,返回client。

当客户要读取AD转换结果时,可调用s3c_adc_read函数,其定义如下:

[cpp]viewplaincopyprint?175ints3c_adc_read(structs3c_adc_client*client,unsignedintch)
176{
177DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake);
178intret;
179
180client->convert_cb=s3c_convert_done;
181client->wait=&wake;
182client->result=-1;
183
184ret=s3c_adc_start(client,ch,1);
185if(ret<0)
186gotoerr;
187
188ret=wait_event_timeout(wake,client->result>=0,HZ/2);
189if(client->result<0){
190ret=-ETIMEDOUT;
191gotoerr;
192}
193
194client->convert_cb=NULL;
195returnclient->result;
196
197err:
198returnret;
199}
[code]175ints3c_adc_read(structs3c_adc_client*client,unsignedintch)
176{
177DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wake);
178intret;
179
180client->convert_cb=s3c_convert_done;
181client->wait=&wake;
182client->result=-1;
183
184ret=s3c_adc_start(client,ch,1);
185if(ret<0)
186gotoerr;
187
188ret=wait_event_timeout(wake,client->result>=0,HZ/2);
189if(client->result<0){
190ret=-ETIMEDOUT;
191gotoerr;
192}
193
194client->convert_cb=NULL;
195returnclient->result;
196
197err:
198returnret;
199}

175行,第二个参数ch代表要读ADC控制器的哪个通道。[/code]
177行,定义等待队列头。

180行,指定convert回调函数是s3c_convert_done,该函数我们在后面分析。

184行,调用s3c_adc_start函数,该函数我们在后面分析,第二个参数代表使用的ADC通道,第三个参数指定采样次数,这里可以看出,使用s3c_adc_read,采样次数均为1。

188行,调用wait_event_timeout在等待队列wake上休眠,休眠条件是client->result>=0,最长休眠时间为HZ/2。

client的convert回调函数s3c_convert_done定义如下:

[cpp]viewplaincopyprint?168staticvoids3c_convert_done(structs3c_adc_client*client,
169unsignedv,unsignedu,unsigned*left)
170{
171client->result=v;
172wake_up(client->wait);
173}
[code]168staticvoids3c_convert_done(structs3c_adc_client*client,
169unsignedv,unsignedu,unsigned*left)
170{
171client->result=v;
172wake_up(client->wait);
173}

171行,将第二个参数(data0)赋值给client->result。[/code]
172行,唤醒等待队列中的休眠进程。

s3c_adc_start函数定义如下:

[cpp]viewplaincopyprint?135ints3c_adc_start(structs3c_adc_client*client,
136unsignedintchannel,unsignedintnr_samples)
137{
138structadc_device*adc=adc_dev;
139unsignedlongflags;
140
141if(!adc){
142printk(KERN_ERR"%s:failedtofindadc\n",__func__);
143return-EINVAL;
144}
145
146if(client->is_ts&&adc->ts_pend)
147return-EAGAIN;
148
149spin_lock_irqsave(&adc->lock,flags);
150
151client->channel=channel;
152client->nr_samples=nr_samples;
153
154if(client->is_ts)
155adc->ts_pend=client;
156else
157list_add_tail(&client->pend,&adc_pending);
158
159if(!adc->cur)
160s3c_adc_try(adc);
161
162spin_unlock_irqrestore(&adc->lock,flags);
163
164return0;
165}
[code]135ints3c_adc_start(structs3c_adc_client*client,
136unsignedintchannel,unsignedintnr_samples)
137{
138structadc_device*adc=adc_dev;
139unsignedlongflags;
140
141if(!adc){
142printk(KERN_ERR"%s:failedtofindadc\n",__func__);
143return-EINVAL;
144}
145
146if(client->is_ts&&adc->ts_pend)
147return-EAGAIN;
148
149spin_lock_irqsave(&adc->lock,flags);
150
151client->channel=channel;
152client->nr_samples=nr_samples;
153
154if(client->is_ts)
155adc->ts_pend=client;
156else
157list_add_tail(&client->pend,&adc_pending);
158
159if(!adc->cur)
160s3c_adc_try(adc);
161
162spin_unlock_irqrestore(&adc->lock,flags);
163
164return0;
165}

151行,设置ADC通道。[/code]
152行,设置采样次数。

155行,如果是触摸屏,则将client保存在adc->ts_pend中。

157行,如果不是触摸屏,则将client插入adc_pending链表中。

159-160行,如果没有正在处理其他客户请求,则调用s3c_adc_try函数处理当前客户请求。

下面看s3c_adc_try函数的定义:

[cpp]viewplaincopyprint?115staticvoids3c_adc_try(structadc_device*adc)
116{
117structs3c_adc_client*next=adc->ts_pend;
118
119if(!next&&!list_empty(&adc_pending)){
120next=list_first_entry(&adc_pending,
121structs3c_adc_client,pend);
122list_del(&next->pend);
123}else
124adc->ts_pend=NULL;
125
126if(next){
127adc_dbg(adc,"newclientis%p\n",next);
128adc->cur=next;
129s3c_adc_select(adc,next);
130s3c_adc_convert(adc);
131s3c_adc_dbgshow(adc);
132}
133}
[code]115staticvoids3c_adc_try(structadc_device*adc)
116{
117structs3c_adc_client*next=adc->ts_pend;
118
119if(!next&&!list_empty(&adc_pending)){
120next=list_first_entry(&adc_pending,
121structs3c_adc_client,pend);
122list_del(&next->pend);
123}else
124adc->ts_pend=NULL;
125
126if(next){
127adc_dbg(adc,"newclientis%p\n",next);
128adc->cur=next;
129s3c_adc_select(adc,next);
130s3c_adc_convert(adc);
131s3c_adc_dbgshow(adc);
132}
133}

117-124行,看是否有客户(client)在等待AD转换,首先检查adc->ts_pend,即有没有触摸屏客户在等待,然后再检查adc_pending链表,即检查有没有非触摸屏客户在等待。[/code]
126-132行,如果没有等待的客户,则ADC处理结束。如果有等待的客户(client),则对客户AD转换请求进行处理。其中用到了s3c_adc_select,s3c_adc_convert,s3c_adc_dbgshow函数。下面依次进行分析。

首先看s3c_adc_select函数:

[cpp]viewplaincopyprint?90staticinlinevoids3c_adc_select(structadc_device*adc,
91structs3c_adc_client*client)
92{
93unsignedcon=readl(adc->regs+S3C2410_ADCCON);
94
95client->select_cb(client,1);
96
97con&=~S3C2410_ADCCON_MUXMASK;
98con&=~S3C2410_ADCCON_STDBM;
99con&=~S3C2410_ADCCON_STARTMASK;
100
101if(!client->is_ts)
102con|=S3C2410_ADCCON_SELMUX(client->channel);
103
104writel(con,adc->regs+S3C2410_ADCCON);
105}
[code]90staticinlinevoids3c_adc_select(structadc_device*adc,
91structs3c_adc_client*client)
92{
93unsignedcon=readl(adc->regs+S3C2410_ADCCON);
94
95client->select_cb(client,1);
96
97con&=~S3C2410_ADCCON_MUXMASK;
98con&=~S3C2410_ADCCON_STDBM;
99con&=~S3C2410_ADCCON_STARTMASK;
100
101if(!client->is_ts)
102con|=S3C2410_ADCCON_SELMUX(client->channel);
103
104writel(con,adc->regs+S3C2410_ADCCON);
105}

95行,执行客户定义的select回调函数。[/code]
97-104行,初始化ADC控制器。

下面我们看s3c_adc_convert函数的定义:

[cpp]viewplaincopyprint?82staticinlinevoids3c_adc_convert(structadc_device*adc)
83{
84unsignedcon=readl(adc->regs+S3C2410_ADCCON);
85
86con|=S3C2410_ADCCON_ENABLE_START;
87writel(con,adc->regs+S3C2410_ADCCON);
88}
[code]82staticinlinevoids3c_adc_convert(structadc_device*adc)
83{
84unsignedcon=readl(adc->regs+S3C2410_ADCCON);
85
86con|=S3C2410_ADCCON_ENABLE_START;
87writel(con,adc->regs+S3C2410_ADCCON);
88}

在arch/arm/plat-samsung/include/plat/regs-adc.h文件中有如下定义:[/code]
#defineS3C2410_ADCCON_ENABLE_START(1<<0)

所以s3c_adc_convert的作用是启动AD转换。

下面是s3c_adc_dbgshow函数的定义:

[cpp]viewplaincopyprint?107staticvoids3c_adc_dbgshow(structadc_device*adc)
108{
109adc_dbg(adc,"CON=%08x,TSC=%08x,DLY=%08x\n",
110readl(adc->regs+S3C2410_ADCCON),
111readl(adc->regs+S3C2410_ADCTSC),
112readl(adc->regs+S3C2410_ADCDLY));
113}
[code]107staticvoids3c_adc_dbgshow(structadc_device*adc)
108{
109adc_dbg(adc,"CON=%08x,TSC=%08x,DLY=%08x\n",
110readl(adc->regs+S3C2410_ADCCON),
111readl(adc->regs+S3C2410_ADCTSC),
112readl(adc->regs+S3C2410_ADCDLY));
113}

打印ADCCON,ADCTSC,ADCDLY三个寄存器的值。[/code]
s3c_adc_convert函数启动AD转换,转换结束后,会触发ADC中断,下面看ADC中断处理函数s3c_adc_irq,其代码如下:

[cpp]viewplaincopyprint?270staticirqreturn_ts3c_adc_irq(intirq,void*pw)
271{
272structadc_device*adc=pw;
273structs3c_adc_client*client=adc->cur;
274enums3c_cpu_typecpu=platform_get_device_id(adc->pdev)->driver_data;
275unsigneddata0,data1;
276
277if(!client){
278dev_warn(&adc->pdev->dev,"%s:noadcpending\n",__func__);
279gotoexit;
280}
281
282data0=readl(adc->regs+S3C2410_ADCDAT0);
283data1=readl(adc->regs+S3C2410_ADCDAT1);
284adc_dbg(adc,"read%d:0x%04x,0x%04x\n",client->nr_samples,data0,data1);
285
286client->nr_samples--;
287
288if(cpu==TYPE_S3C64XX){
289/*S3C64XXADCresolutionis12-bit*/
290data0&=0xfff;
291data1&=0xfff;
292}else{
293data0&=0x3ff;
294data1&=0x3ff;
295}
296
297if(client->convert_cb)
298(client->convert_cb)(client,data0,data1,&client->nr_samples);
299
300if(client->nr_samples>0){
301/*fireanotherconversionforthis*/
302
303client->select_cb(client,1);
304s3c_adc_convert(adc);
305}else{
306spin_lock(&adc->lock);
307(client->select_cb)(client,0);
308adc->cur=NULL;
309
310s3c_adc_try(adc);
311spin_unlock(&adc->lock);
312}
313
314exit:
315if(cpu==TYPE_S3C64XX){
316/*ClearADCinterrupt*/
317writel(0,adc->regs+S3C64XX_ADCCLRINT);
318}
319returnIRQ_HANDLED;
320}
[code]270staticirqreturn_ts3c_adc_irq(intirq,void*pw)
271{
272structadc_device*adc=pw;
273structs3c_adc_client*client=adc->cur;
274enums3c_cpu_typecpu=platform_get_device_id(adc->pdev)->driver_data;
275unsigneddata0,data1;
276
277if(!client){
278dev_warn(&adc->pdev->dev,"%s:noadcpending\n",__func__);
279gotoexit;
280}
281
282data0=readl(adc->regs+S3C2410_ADCDAT0);
283data1=readl(adc->regs+S3C2410_ADCDAT1);
284adc_dbg(adc,"read%d:0x%04x,0x%04x\n",client->nr_samples,data0,data1);
285
286client->nr_samples--;
287
288if(cpu==TYPE_S3C64XX){
289/*S3C64XXADCresolutionis12-bit*/
290data0&=0xfff;
291data1&=0xfff;
292}else{
293data0&=0x3ff;
294data1&=0x3ff;
295}
296
297if(client->convert_cb)
298(client->convert_cb)(client,data0,data1,&client->nr_samples);
299
300if(client->nr_samples>0){
301/*fireanotherconversionforthis*/
302
303client->select_cb(client,1);
304s3c_adc_convert(adc);
305}else{
306spin_lock(&adc->lock);
307(client->select_cb)(client,0);
308adc->cur=NULL;
309
310s3c_adc_try(adc);
311spin_unlock(&adc->lock);
312}
313
314exit:
315if(cpu==TYPE_S3C64XX){
316/*ClearADCinterrupt*/
317writel(0,adc->regs+S3C64XX_ADCCLRINT);
318}
319returnIRQ_HANDLED;
320}

273行,获得当前正在请求ADC服务的客户(client),即adc->cur。[/code]
282行,读ADCDAT0,保存在data0中。

283行,读ADCDAT1,保存在data1中。

293-294行,取data0和data1的低10位,分别对应x坐标值和y坐标值。

297-298行,如果客户(client)定义了convert_cb,则调用之。这个回调函数的例子,可以看S3C2410触摸屏驱动的相应回调函数s3c24xx_ts_conversion,定义在drivers/input/touchscreen/s3c2410_ts.c文件中。这个回调函数的作用是根据驱动程序的具体要求,对转换结果进行相应处理。对于S3C2410触摸屏驱动的相应回调函数,就是把每次转换后的X坐标值求和,Y坐标值求和,同时记录转换次数,以便在以后取多次转换结果的平均值。

300行,如果client->nr_samples>0,说明还要进行一次采样。

303行,client->select_cb(client,1),这个回调函数的例子,可以看S3C2410触摸屏驱动的相应回调函数s3c24xx_ts_select。第二个参数为1,表示选择客户client,让客户初始化好,准备处理AD转换结果;第二个参数为0,表示取消对客户client的选择。

304行,调用s3c_adc_convert函数,因为300判断了还要再进行采样,所以这里调用s3c_adc_convert再次进行AD转换。

307行,如果不需要再进行一次采样,调用(client->select_cb)(client,0),取消对客户client的选择,同时客户会对AD转换结果进行处理。

308行,将adc->cur设置为NULL。

310行,调用s3c_adc_try(adc)函数,其作用是检查是否还有客户在等待ADC服务,如果有,则将其设置为当前客户,并启动AD转换。

至此,整个ADC通用驱动我们就分析完了。

下面整理一下用户要执行ADC操作时函数调用流程:

1.用户调用s3c_adc_register注册client。

2.用户调用s3c_adc_read读取ADC控制器->s3c_adc_start->s3c_adc_try->s3c_adc_select(选择客户)、s3c_adc_convert(启动AD转换)->转换结束后发出中断,执行中断处理函数s3c_adc_irq。

3.用户也可以不通过调用s3c_adc_read函数,直接调用s3c_adc_start函数执行ADC操作。S3C2410触摸屏驱动就是这样做的。


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: