Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1834949
  • 博文数量: 134
  • 博客积分: 2488
  • 博客等级: 大尉
  • 技术积分: 7554
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-26 21:19
个人简介

1.每日自省; 2.享受人生; 3.尽力而为; 4.坚持不懈; 5.切莫急躁; 6.慎言敏行; 7.动心忍性; 8.上善若水。

文章分类

全部博文(134)

文章存档

2014年(38)

2013年(42)

2012年(15)

2011年(39)

分类: LINUX

2013-11-26 10:41:11

一、芯片和驱动架构总体介绍

1.1、芯片介绍

        本文使用的芯片为GSC3280,根据芯片手册的介绍,ADC 与触摸屏控制器通过 SPI 接口挂在GSC3280的SPI0总
线上,支持4线电阻式触摸
屏或当ADC输入使用。GSC3280片上集成的ADC与触摸屏控制器主要有以下特性:

        1、通过标准SPI接口传输命令和数据;

        2、最大分辨率为12位;

        3、输入最大的SPI 时钟是6MHz,对应最大采样率为120Ksps;

        4、支持4线电阻式触摸屏;

        5、可以当4路ADC输入;

        6、支持触摸屏触笔中断;

        7、支持低功耗模式;

1.2、驱动架构介绍

        本文所设计的ADC子系统架构关系图如下:


        由于AD转换使用的是SPI0,所以此处在Linux内核源码目录的/driver/spi目录下建立一个adc目录,根据上图,
建立了adc-core
.cadc-dev.cadc-sysfs.cadc-proc.cadc.h gsc3280_adc.c等文件。现在先简单说下
各个文件的功能:

        gsc3280_adc.c:是最底层的直接和硬件打交道的驱动文件,将在(二)中讲述。
        adc-core.cgsc3280_adc.c的上面一层提供了ADC子系统的一些公共函数,让各个ADC驱动注册集成到
linux内核中,
向驱动程序提供了注册/注销接口。将在第二篇文章中讲述。
        adc-dev.c:adc-core.c再往上就到了adc-dev.cadc-dev.c最终生成了/dev/adc设备节点,上层的应用程
序就是通过操作此文件来进行相关的读取
AD转换值
等操作的。
定义了基本的设备文件操作函数,
用户程序与ADC驱
动的接口函数,这里定义了每个ioctl命令需要调用的函数
,还有open,read等。将在第二篇文章中讲述。

        adc-proc.c:与proc文件系统有关,提供通过proc文件系统操作ADC将在第二篇文章中讲述。
        adc-sysfs.c:与sysfs有关,提供通过sys文件系统操作ADC将在第二篇文章中讲述。

        adc.h、adc-core.h:定义了与ADC有关的数据结构,变量和函数声明等。在使用时讲述。

二、驱动程序gsc3280_adc.c  

2.1、模块初始化

        本部分讲述gsc3280_adc.c文件中的程序,此即为上图中的最下部分--驱动程序,首先从模块初始化开始,程
序如下:

点击(此处)折叠或打开

  1. static struct platform_driver gsc3280adc_driver = {
  2.     .driver    = {
  3.         .name    = "adc-core",
  4.         .owner    = THIS_MODULE,
  5.     },
  6.     .probe    = gsc3280_adc_probe,
  7.     .remove    = __devexit_p(gsc3280_adc_remove),
  8.     .suspend    = gsc3280_adc_suspend,
  9.     .resume    = gsc3280_adc_resume,
  10. };

  11. static int __init gsc3280_adc_init(void)
  12. {
  13.     int ret = 0;
  14.     
  15.     ret = platform_driver_register(&gsc3280adc_driver);
  16.     if (ret != 0)
  17.         DBG("!!!!!!gsc adc core register error!!!!!!\n");
  18.     return ret;
  19. }
  20. static void __exit gsc3280_adc_exit(void)
  21. {
  22.     platform_driver_unregister(&gsc3280adc_driver);
  23. }
  24. module_init(gsc3280_adc_init);
  25. module_exit(gsc3280_adc_exit);

  26. MODULE_AUTHOR("Davied");
  27. MODULE_DESCRIPTION("gsc3280 spi0 adc Driver");
  28. MODULE_LICENSE("GPL");
  29. MODULE_ALIAS("platform:gsc3280-spi0 adc");

        在这里将设备定义为平台设备,驱动注册函数即为平台驱动的注册。

2.2、探测函数

        接下来看下平台驱动的探测函数,程序如下:

点击(此处)折叠或打开

  1. static int __devinit gsc3280_adc_probe(struct platform_device *pdev)
  2. {
  3.     int ret = 0, size = 0;
  4.     unsigned long rate = 0;
  5.     struct gsc_adc_dev *adc;
  6.     struct resource *mem, *ioarea;

  7.     DBG("############\n");
  8.     printk(KERN_INFO "GSC3280 spi0 adc probe start\n");
  9.     adc = kzalloc(sizeof(struct gsc_adc_dev), GFP_KERNEL);
  10.     if (adc == NULL) {
  11.         DBG("failed to allocate adc_core_dev\n");
  12.         return -ENOMEM;
  13.     }
  14.     mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  15.     if (!mem) {
  16.         DBG("no mem resource.\n");
  17.         ret = -EINVAL;
  18.         goto err_alloc;
  19.     }
  20.     size = resource_size(mem);
  21.     ioarea = request_mem_region(mem->start, size, pdev->name);
  22.     if (!ioarea) {
  23.         DBG("SPI region already claimed.\n");
  24.         ret = -EBUSY;
  25.         goto err_alloc;
  26.     }
  27.     adc->regs = ioremap_nocache(mem->start, resource_size(mem));
  28.     if (!adc->regs) {
  29.         DBG("SPI region already mapped.\n");
  30.         ret = -ENOMEM;
  31.         goto err_mem;
  32.     }
  33.     DBG("probe: mapped spi0 base=%p.\n", adc->regs);

  34.     adc->clk = clk_get(NULL, "spi0");
  35.     if (IS_ERR(adc->clk)) {
  36.         DBG("failed to find watchdog clock source.\n");
  37.         ret = PTR_ERR(adc->clk);
  38.         goto err_map;
  39.     }
  40.     rate = clk_get_rate(adc->clk);
  41.     DBG("rate is %ld.\n", rate);
  42.     clk_enable(adc->clk);
  43.     ret = adc_sysctl(adc);
  44.     if (ret != 0)
  45.         goto err_map;
  46.     
  47.     spin_lock_init(&adc->lock);
  48.     INIT_LIST_HEAD(&adc->device_entry);
  49.     strlcpy(adc->name, GSC3280_ADC_NAME, sizeof(adc->name));

  50.     mutex_lock(&gsc3280_adc_list_lock);
  51.     list_add(&adc->device_entry, &gsc3280_adc_list);
  52.     mutex_unlock(&gsc3280_adc_list_lock);

  53.     adc->adc_dev = adc_device_register(adc->name, &pdev->dev, &gsc3280_adc_ops, THIS_MODULE);
  54.     if (IS_ERR(adc->adc_dev)) {
  55.         ret = PTR_ERR(adc->adc_dev);
  56.         DBG("unable to register the class device\n");
  57.         goto err_clk;
  58.     }

  59.     platform_set_drvdata(pdev, adc);
  60.     printk(KERN_INFO "GSC3280 adc probe SUCCESS.\n");
  61.     DBG("############\n");
  62.     return 0;

  63.  err_clk:
  64.     clk_disable(adc->clk);
  65.     clk_put(adc->clk);
  66.  err_map:
  67.     iounmap(adc->regs);
  68.  err_mem:
  69.     release_mem_region(mem->start, size);
  70.     mem = NULL;
  71.  err_alloc:
  72.     kfree(adc);
  73.     printk(KERN_INFO "!!!!!!GSC3280 adc probe error!!!!!!\n");
  74.     return ret;
  75. }

        说明:

        1、首先申请驱动结构体内存。

        2、对资源的申请和映射,包括IO内存等。

        3、使能spi0时钟。

        4、配置系统控制寄存器--ret = adc_sysctl(adc)

        5、驱动结构体成员初始化。

        6、adc子系统注册,此处尤为重要,将在(三)中讲述。

        7、通过gsc3280_adc_list_lock和gsc3280_adc_list,使得在其他函数中也能找到1中定义的驱动结构体内存。

        8、在红色部分程序中,注册了文件操作函数集gsc3280_adc_ops,在第二篇文章中会多次使用此函数,具体定
义如下:

点击(此处)折叠或打开

  1. static const struct adc_class_ops gsc3280_adc_ops = {
  2.     .convert = gsc3280AdcCon,
  3. };

        这里只定义一个转换函数gsc3280AdcCon,就是底层驱动程序提供的对spi0操作的函数,上层调用的AD转换动
作,最终都是由此程序来完成的。具体程序如下:

点击(此处)折叠或打开

  1. //return 0:date valid, other:date error
  2. static int gsc3280AdcCon(unsigned short cmd)
  3. {
  4.     struct gsc_adc_dev *adc;
  5.     int ret = 0, status = 0/*, cnt = 0*/;

  6.     //DBG("gscAdcCon\n");
  7.     mutex_lock(&gsc3280_adc_list_lock);
  8.     list_for_each_entry(adc, &gsc3280_adc_list, device_entry) {
  9.         if(strcmp(adc->name, GSC3280_ADC_NAME) == 0) {
  10.             status = 0;
  11.             break;
  12.         }
  13.     }
  14.     mutex_unlock(&gsc3280_adc_list_lock);
  15.     if (status != 0) {
  16.         DBG("get gsc3280 adc struct error\n");
  17.         return -5;
  18.     }

  19.     adc->cmd = cmd;
  20.     ret = writeSpiDate(adc);    //send test cmd
  21.     if (ret < 0) {
  22.         //DBG("cmd = %x\n", adc->cmd);
  23.         return ret;
  24.     }
  25.     ret = readSpiDate(adc);
  26.     if (ret < 0) {
  27.         //DBG("result = %x\n", adc->result);
  28.         return ret;
  29.     }
  30.     if (adc->result != ((adc->cmd >> 12) | 0x8000)) {
  31.         DBG("cmd error\n");
  32.         return CMD_ERR;
  33.     }
  34. again:
  35.     adc->cmd = CMD_GSC_ADC_NOP;
  36.     ret = writeSpiDate(adc);    //send nop cmd
  37.     if (ret < 0) {
  38.         DBG("send nop cmd error\n");
  39.         return ret;
  40.     }
  41.     ret = readSpiDate(adc);
  42.     if (ret < 0) {
  43.         DBG("in read result = %x\n", adc->result);
  44.         return ret;
  45.     }
  46.     if ((adc->result & 0xf000) == 0xf000)
  47.         goto again;
  48.     if ((adc->result & 0xf000) == 0) {
  49.         adc->result &= 0x0fff;
  50.         DBG("get result success, result = %d\n", adc->result);
  51.         return adc->result;
  52.     } else {
  53.         DBG("get adc result error, result = %d\n", adc->result);
  54.         return RESULT_ERR;
  55.     }
  56. }

        使用spi读写数据函数如下:

点击(此处)折叠或打开

  1. //ret: 1:busy, 0:free
  2. static int getSpiState(struct gsc_adc_dev *adc)
  3. {
  4.     unsigned int time_cnt = 0;

  5.     while (readl(adc->regs + GSC_SPI_SR) & GSC_SPI_SR_BUSY) {
  6.         if (time_cnt++ > MAX_WAIT_CNT) {
  7.             DBG("spi busy, stat = %x\n", readl(adc->regs + GSC_SPI_SR));
  8.             return SPI_BUSY;
  9.         }
  10.     }
  11.     return 0;
  12. }

  13. static int writeSpiDate(struct gsc_adc_dev *adc)
  14. {
  15.     int cnt = 0, stat = 0;
  16.     
  17.     stat = getSpiState(adc);
  18.     if (stat != 0) {
  19.         DBG("in write spi date,spi is busy\n");
  20.         return stat;
  21.     }
  22.     //spi0 fifo can write, transmit fifo empty
  23.     while (!(readl(adc->regs + GSC_SPI_SR) & GSC_SPI_SR_TX_NO_FULL)) {
  24.         if (cnt++ > MAX_WAIT_CNT) {
  25.             DBG("write spi date error, stat = %x\n", readl(adc->regs + GSC_SPI_SR));
  26.             return WRITE_DATE_ERR;
  27.         }
  28.     }
  29.     writel(adc->cmd, adc->regs + GSC_SPI_DA_S);
  30.     return 0;
  31. }

  32. /* prepare to read data from adc */
  33. static int readSpiDate(struct gsc_adc_dev *adc)
  34. {
  35.     int cnt= 0, stat = 0;
  36.     
  37.     stat = getSpiState(adc);
  38.     if (stat < 0) {
  39.         DBG("in read spi date,spi is busy\n");
  40.         return stat;
  41.     }
  42.     //spi0 fifo receive not empty
  43.     while (!(readl(adc->regs + GSC_SPI_SR) & GSC_SPI_SR_RX_N_EMPTY)) {
  44.         if (cnt++ > MAX_WAIT_CNT) {
  45.             DBG("read spi date error, spi stat = %x\n", readl(adc->regs + GSC_SPI_SR));
  46.             return READ_DATE_ERR;
  47.         }
  48.     }
  49.     adc->result = (unsigned short)readl(adc->regs + GSC_SPI_DA_S);
  50.     return 0;
  51. }

2.3、移除函数--gsc3280_adc_remove

        移除函数就是探测函数的相反过程,程序如下:

点击(此处)折叠或打开

  1. static int __devexit gsc3280_adc_remove(struct platform_device *pdev)
  2. {
  3.     struct gsc_adc_dev *adc = platform_get_drvdata(pdev);

  4.     iounmap(adc->regs);
  5.     clk_disable(adc->clk);
  6.     clk_put(adc->clk);
  7.     adc_device_unregister(adc->adc_dev);
  8.     kfree(adc);
  9.     return 0;
  10. }

三、ADC子系统核心(adc-core.c)

        adc-core.c是gsc3280_adc.c的上面一层提供了ADC子系统的一些公共函数,让各个ADC驱动注册集成到

linux内核中,向驱动程序提供了注册/注销接口。首先还是先看下模块初始化和退出函数。

3.1、模块初始化和退出函数

点击(此处)折叠或打开

  1. static int __init gsc_adc_init(void)
  2. {
  3.     adc_class = class_create(THIS_MODULE, "adc");
  4.     if (IS_ERR(adc_class)) {
  5.         printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
  6.         return PTR_ERR(adc_class);
  7.     }
  8.     //adc_class->suspend = adcSuspend;
  9.     //adc_class->resume = adcResume;
  10.     adc_dev_init();
  11.     adc_sysfs_init(adc_class);
  12.     writel(0x01, (volatile unsigned int *)0xbc04a0ac);    //enable ts and adc
  13.     return 0;
  14. }
  15. static void __exit gsc_adc_exit(void)
  16. {
  17.     adc_dev_exit();
  18.     class_destroy(adc_class);
  19.     idr_destroy(&adc_idr);
  20. }
  21. subsys_initcall(gsc_adc_init);
  22. module_exit(gsc_adc_exit);

        说明:

        1、首先建立了一个设备类,在《GSC3280的ADC子系统驱动模型(三)----class的使用》中介绍。

        2、对ADC子系统中的dev进行初始化,第二篇文章讲述。

        3、对ADC子系统中的sysfs进行初始化,第二篇文章讲述。

        4、注意:此处的初始化宏使用的是subsys_initcall,优先级高于module_init(),即subsys_initcall先于module_init()执行。

        5、退出函数就是初始化函数的相反过程。

3.2、ADC子系统注册和注销函数

        现在就来看下2.2中涉及到的ADC子系统注册函数。程序如下:

点击(此处)折叠或打开

  1. struct class *adc_class;
  2. static DEFINE_IDR(adc_idr);
  3. static DEFINE_MUTEX(adc_idr_lock);

  4. static void adc_device_release(struct device *dev)
  5. {
  6.     struct adc_core_dev *adc = to_adc_device(dev);
  7.     
  8.     mutex_lock(&adc_idr_lock);
  9.     idr_remove(&adc_idr, adc->id);
  10.     mutex_unlock(&adc_idr_lock);
  11.     kfree(adc);
  12. }

  13. /**
  14.  * adc_device_register - register w/ ADC class
  15.  * @dev: the device to register
  16.  *
  17.  * adc_device_unregister() must be called when the class device is no
  18.  * longer needed.
  19.  *
  20.  * Returns the pointer to the new struct class device.
  21.  */
  22. struct adc_core_dev *adc_device_register(const char *name, struct device *dev,
  23.                                         const struct adc_class_ops *ops,
  24.                                         struct module *owner)
  25. {
  26.     struct adc_core_dev *adc;
  27.     int id, err;

  28.     if (idr_pre_get(&adc_idr, GFP_KERNEL) == 0) {
  29.         err = -ENOMEM;
  30.         goto exit;
  31.     }
  32.     mutex_lock(&adc_idr_lock);
  33.     err = idr_get_new(&adc_idr, NULL, &id);
  34.     mutex_unlock(&adc_idr_lock);
  35.     if (err < 0)
  36.         goto exit;
  37.     id = id & MAX_ID_MASK;

  38.     adc= kzalloc(sizeof(struct adc_core_dev), GFP_KERNEL);
  39.     if (adc == NULL) {
  40.         err = -ENOMEM;
  41.         goto exit_idr;
  42.     }

  43.     adc->id = id;
  44.     adc->ops = ops;
  45.     adc->owner = owner;
  46.     adc->dev.parent = dev;
  47.     adc->dev.class = adc_class;
  48.     adc->dev.release = adc_device_release;

  49.     mutex_init(&adc->ops_lock);
  50.     strlcpy(adc->name, name, ADC_CORE_NAME_SIZE);
  51.     dev_set_name(&adc->dev, "adc%d", id);

  52.     adc_dev_prepare(adc);

  53.     err = device_register(&adc->dev);
  54.     if (err) {
  55.         put_device(&adc->dev);
  56.         goto exit_kfree;
  57.     }

  58. #ifdef CONFIG_TOUCHSCREEN_GSC3280
  59.     err = adc_ts_add_dev(adc);
  60.     if (err < 0)
  61.         DBG("adc ts add dev error\n");
  62. #endif

  63.     adc_dev_add_device(adc);
  64.     adc_sysfs_add_device(adc);
  65.     adc_proc_add_device(adc);

  66.     dev_info(dev, "adc core: registered %s as %s\n", adc->name, dev_name(&adc->dev));
  67.     return adc;

  68. exit_kfree:
  69.     kfree(adc);
  70. exit_idr:
  71.     mutex_lock(&adc_idr_lock);
  72.     idr_remove(&adc_idr, id);
  73.     mutex_unlock(&adc_idr_lock);
  74. exit:
  75.     dev_err(dev, "adc core: unable to register %s, err = %d\n", name, err);
  76.     return ERR_PTR(err);
  77. }
  78. EXPORT_SYMBOL_GPL(adc_device_register);

  79. /**
  80.  * adc_device_unregister - removes the previously registered ADC class device
  81.  *
  82.  * @adc: the ADC class device to destroy
  83.  */
  84. void adc_device_unregister(struct adc_core_dev *adc)
  85. {
  86.     if (get_device(&adc->dev) != NULL) {
  87.         mutex_lock(&adc->ops_lock);
  88.         adc_sysfs_del_device(adc);
  89.         adc_dev_del_device(adc);
  90.         adc_proc_del_device(adc);
  91.         device_unregister(&adc->dev);
  92.         adc->ops = NULL;
  93.         mutex_unlock(&adc->ops_lock);
  94.         put_device(&adc->dev);
  95.     }
  96. }
  97. EXPORT_SYMBOL_GPL(adc_device_unregister);

        说明:

        1、首先使用idr机制获取id。

        2、申请结构体内存,初始化成员变量。

        3、注册device,在《GSC3280的ADC子系统驱动模型(三)----class的使用》中介绍。

        4、增加dev、proc和sysfs设备,第二篇文章中讲述

        5、注销函数是注册函数的相反过程。

        6、释放函数就是移除idr,释放结构体内存。

四、Kconfig和Makefile编写

        首先我们在Linux内核源码目录下的/driver/spi/adc目录下创建Kconfig和Makefile文件。

4.1、Kconfig

        Kconfig程序如下:

点击(此处)折叠或打开

  1. #
  2. # Sensor device configuration
  3. # add by hdw,in order to use adc
  4. #

  5. menuconfig SPI0_ADC
  6.     bool "Adc Hardware support"
  7.     help
  8.      GSC3280 Adc Hardware support.


  9. if SPI0_ADC

  10. config GSC_SPI0_ADC_CORE
  11.     tristate "support adc core"
  12.     default SPI0_ADC
  13.     help
  14.      If you say yes to this option, support will be included gsc3280
  15.      adc core.

  16. config GSC_ADC_CORE_DEBUG
  17.     bool "adc core debugging messages"
  18.     depends on GSC_SPI0_ADC_CORE
  19.     help
  20.      Say Y here if you want the GSC3280 to produce a bunch of debug
  21.      messages to the system log. Select this if you are having a
  22.      problem with GSC3280 and want to see more of what is going on.

  23. comment "ADC interfaces"

  24. config ADC_INTF_SYSFS
  25.     boolean "/sys/class/adc/adcN (sysfs)"
  26.     depends on SYSFS
  27.     default SPI0_ADC
  28.     help
  29.      Say yes here if you want to use your ADCs using sysfs interfaces,
  30.      /sys/class/adc/adc0 through /sys/.../adcN.

  31.      If unsure, say Y.

  32. config ADC_SYS_DEBUG
  33.     bool "adc sys debugging messages"
  34.     depends on ADC_INTF_SYSFS
  35.     help
  36.      Say Y here if you want the adc sysfs dev to produce a bunch of debug
  37.      messages to the system log. Select this if you are having a
  38.      problem with adc core and want to see more of what is going on.

  39. config ADC_INTF_PROC
  40.     boolean "/proc/driver/adc (procfs for adc0)"
  41.     depends on PROC_FS
  42.     default SPI0_ADC
  43.     help
  44.      Say yes here if you want to use your first ADC through the proc
  45.      interface, /proc/driver/adc. Other ADCs will not be available
  46.      through that API.

  47.      If unsure, say Y.

  48. config ADC_PROC_DEBUG
  49.     bool "adc proc debugging messages"
  50.     depends on ADC_INTF_PROC
  51.     help
  52.      Say Y here if you want the adc proc dev to produce a bunch of debug
  53.      messages to the system log. Select this if you are having a
  54.      problem with adc core and want to see more of what is going on.

  55. config ADC_INTF_DEV
  56.     boolean "/dev/adcN (character devices)"
  57.     default SPI0_ADC
  58.     help
  59.      Say yes here if you want to use your ADCs using the /dev
  60.      interfaces, which "udev" sets up as /dev/adc0 through
  61.      /dev/adcN.

  62.      You may want to set up a symbolic link so one of these
  63.      can be accessed as /dev/adc, which is a name
  64.      expected by "hwclock" and some other programs. Recent
  65.      versions of "udev" are known to set up the symlink for you.

  66.      If unsure, say Y.

  67. config ADC_DEV_DEBUG
  68.     bool "adc dev debugging messages"
  69.     depends on ADC_INTF_DEV
  70.     help
  71.      Say Y here if you want the adc dev to produce a bunch of debug
  72.      messages to the system log. Select this if you are having a
  73.      problem with adc core and want to see more of what is going on.


  74. comment "ADC devices"

  75. config GSC3280_ADC
  76.     tristate "support gsc3280 adc"
  77.     depends on GSC_SPI0_ADC_CORE
  78.     default SPI0_ADC
  79.     help
  80.      If you say yes to this option, support will be included gsc3280
  81.      adc convert and touchscreen.

  82. config GSC3280_ADC_DEBUG
  83.     bool "GSC3280 adc debugging messages"
  84.     depends on GSC3280_ADC
  85.     help
  86.      Say Y here if you want the GSC3280 adc to produce a bunch of debug
  87.      messages to the system log. Select this if you are having a
  88.      problem with GSC3280 and want to see more of what is going on.
  89.     

  90. endif

        在上一层的Kconfig,也就是Linux内核源码目录下的/driver/spi下的Kconfig增加如下内容:

点击(此处)折叠或打开

  1. # add by hdw
  2. comment "gsc3280 spi0 adc"
  3. source drivers/spi/adc/Kconfig

        这样在配置选项中,就可以配置ADC子系统的内容了。

4.2、Makefile

        类似Kconfig,在Linux内核源码目录/driver/spi/adc目录下创建Makefile文件,具体内容如下:

点击(此处)折叠或打开

  1. #
  2. # Makefile for the i2c bus drivers.
  3. #

  4. obj-$(CONFIG_GSC_SPI0_ADC_CORE)        += adc-core.o
  5. obj-$(CONFIG_ADC_INTF_DEV)            += adc-dev.o
  6. obj-$(CONFIG_ADC_INTF_PROC)            += adc-proc.o
  7. obj-$(CONFIG_ADC_INTF_SYSFS)            += adc-sysfs.o

  8. obj-$(CONFIG_GSC3280_ADC)            += gsc3280_adc.o

  9. ccflags-$(CONFIG_GSC_ADC_DEV_DEBUG) += -DGSC3280_ADC_DEV_DEBUG
        在上一层的Makefile,也就是Linux内核源码目录下的/driver/spi下的Makefile增加如下内容:

点击(此处)折叠或打开

  1. #add by hdw
  2. obj-y                += adc/
阅读(5087) | 评论(1) | 转发(3) |
给主人留下些什么吧!~~

CU博客助理2013-12-11 11:11:28

嘉宾点评:
驱动模型一与驱动模型二应该属于同一篇,楼主详细的描述了使用ADC子系统的例子,过程以及原理分析,还有模型介绍,很全面。
(感谢您参与“原创博文评选”获奖结果即将公布)