在linux-3.6.6中,系统已经有了关于s3c2440的ADC通用驱动程序文件——arch/arm/plat-samsung/adc.c,但还没有应用层文件,如果要想使ADC工作,并利用系统已有的驱动文件,那么就必须自己动手写一个应用层文件。
本文先介绍adc.c,然后给出一个通用的ADC应用层文件,并移植到开发板上。
先看adc.c文件中的初始化函数adc_init:
static int __init adc_init(void)
{
int ret;
//注册ADC驱动
ret = platform_driver_register(&s3c_adc_driver);
if (ret)
printk(KERN_ERR "%s:failed to add adc driver\n", __func__);
return ret;
}
s3c_adc_driver的定义为:
static struct platform_driver s3c_adc_driver = {
.id_table = s3c_adc_driver_ids,
.driver = {
.name = "s3c-adc",
.owner = THIS_MODULE,
.pm = &adc_pm_ops,
},
.probe = s3c_adc_probe,
.remove = __devexit_p(s3c_adc_remove),
};
s3c_adc_driver_ids的定义为:
static struct platform_device_id s3c_adc_driver_ids[] = {
{
.name = "s3c24xx-adc",
.driver_data = TYPE_ADCV1,
}, {
.name = "s3c2443-adc",
.driver_data = TYPE_ADCV11,
}, {
.name = "s3c2416-adc",
.driver_data = TYPE_ADCV12,
}, {
.name = "s3c64xx-adc",
.driver_data = TYPE_ADCV2,
}, {
.name = "samsung-adc-v3",
.driver_data = TYPE_ADCV3,
},
{ }
};
下面重点介绍probe函数s3c_adc_probe
static int s3c_adc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct adc_device *adc;
struct resource *regs;
enum s3c_cpu_typecpu = platform_get_device_id(pdev)->driver_data;
int ret;
unsigned tmp;
//在内存中开辟一段空间给ADC设备——adc_device
adc = kzalloc(sizeof(struct adc_device), GFP_KERNEL);
if (adc == NULL) {
dev_err(dev, "failed toallocate adc_device\n");
return -ENOMEM;
}
spin_lock_init(&adc->lock);
adc->pdev = pdev;
//为ADC设置预分频
adc->prescale = S3C2410_ADCCON_PRSCVL(49);
//得到ADC的调整器
adc->vdd = regulator_get(dev, "vdd");
if (IS_ERR(adc->vdd)) {
dev_err(dev, "operatingwithout regulator \"vdd\" .\n");
ret = PTR_ERR(adc->vdd);
goto err_alloc;
}
//得到ADC的中断号
adc->irq = platform_get_irq(pdev, 1);
if (adc->irq <= 0) {
dev_err(dev, "failed toget adc irq\n");
ret = -ENOENT;
goto err_reg;
}
//申请中断,中断处理函数为s3c_adc_irq
ret = request_irq(adc->irq, s3c_adc_irq, 0, dev_name(dev), adc);
if (ret < 0) {
dev_err(dev, "failed toattach adc irq\n");
goto err_reg;
}
//得到ADC时钟
adc->clk = clk_get(dev, "adc");
if (IS_ERR(adc->clk)) {
dev_err(dev, "failed toget adc clock\n");
ret = PTR_ERR(adc->clk);
goto err_irq;
}
//得到ADC的IO内存资源
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
dev_err(dev, "failed tofind registers\n");
ret = -ENXIO;
goto err_clk;
}
//得到虚拟地址