Linux spi驱动分析(一)----总线驱动

转载 2015年11月17日 18:08:58

一、SPI总线驱动介绍

        SPI总线总共需要四根线,包括MOSI、MISO、CLK和CS。本文首先从SPI设备注册开始来讲述SPI总线驱动。

二、设备注册

        在系统启动的时候,会按照顺序执行一些初始化程序,比如device_initcall和module_init等宏。这些宏是按照顺序执行的,
比如device_initcall的优先级高于module_init,现在我们看下在系统启动的时候注册的spi设备信息。

        程序如下:

点击(此处)折叠或打开

  1. /* SPI controller */
  2. #if defined(CONFIG_GSC3280_SPI)

  3. #ifdef CONFIG_SPI1
  4. static struct resource spi1_resources[] = {
  5.         [0] = {
  6.                 .start    = GSC3280_SPI1_BASEADDR & 0x1fffffff,
  7.                 .end    = (GSC3280_SPI1_BASEADDR & 0x1fffffff)+ 0x54 - 1 ,
  8.                 .flags    = IORESOURCE_MEM,
  9.         },
  10.         [1] = {
  11.                 .start    = EXT_GSC3280_SPI1_IRQ,
  12.                 .end    = EXT_GSC3280_SPI1_IRQ,
  13.                 .flags    = IORESOURCE_IRQ,
  14.         },
  15. };
  16. static struct platform_device gsc3280_spi1_device = {
  17.         .name            = "gsc3280-spi",
  18.         .id                = 1,

  19. #ifdef CONFIG_GSC3280_SPI_DMA
  20.         .dev            = {
  21.         .dma_mask            = NULL,
  22.         .coherent_dma_mask    = DMA_BIT_MASK(32),
  23.         .platform_data        = NULL,
  24.         },
  25. #endif
  26.         .resource        = spi1_resources,
  27.         .num_resources    = ARRAY_SIZE(spi1_resources),
  28. };
  29. #endif
  30. /* SPI devices */
  31. #if defined(CONFIG_SPI_FLASH_W25Q)
  32.  static struct gsc3280_spi_info w25q_spi1_dev_platdata = {
  33.     .pin_cs            = 87,
  34.     .num_cs            = 1,
  35.     .cs_value            = 0,
  36.     .lsb_flg            = 0,
  37.     .bits_per_word    = 8,
  38. };
  39. #endif
  40. static struct spi_board_info gsc3280_spi_devices[] = {
  41. #if defined(CONFIG_SPI_FLASH_W25Q)
  42.     {
  43.         .modalias        = "spi-w25q",
  44.         .bus_num        = 1,
  45.         .chip_select        = 3,
  46.         .mode            = SPI_MODE_3,
  47.         .max_speed_hz    = 5 * 1000 * 1000,
  48.         .controller_data    = &w25q_spi1_dev_platdata,
  49.     },
  50. #endif

  51. };
  52. static int __init gsc3280_spi_devices_init(void)
  53. {
  54.     spi_register_board_info(gsc3280_spi_devices, ARRAY_SIZE(gsc3280_spi_devices));
  55.     return 0;
  56. }
  57. device_initcall(gsc3280_spi_devices_init);
  58. #endif    //end #if defined(CONFIG_GSC3280_SPI)
        注意到此处共定义两个设备,使用spi_register_board_info()函数对spi设备进行注册,程序如下:

点击(此处)折叠或打开

  1. int __init
  2. spi_register_board_info(struct spi_board_info const *info, unsigned n)
  3. {
  4.     struct boardinfo *bi;
  5.     int i;

  6.     bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
  7.     if (!bi)
  8.         return -ENOMEM;

  9.     for (i = 0; i < n; i++, bi++, info++) {
  10.         struct spi_master *master;

  11.         memcpy(&bi->board_info, info, sizeof(*info));
  12.         mutex_lock(&board_lock);
  13.         list_add_tail(&bi->list, &board_list);
  14.         list_for_each_entry(master, &spi_master_list, list)
  15.             spi_match_master_to_boardinfo(master, &bi->board_info);
  16.         mutex_unlock(&board_lock);
  17.     }

  18.     return 0;
  19. }

        对于此处,n为1,在程序中首先创建相应的内存,在for循环中,将信息保存到内存中,然后插入board_list链表,接着遍历
spi_master_list链表,注意此处,由于device_initcall
的优先级高于module_init,所以此时spi_master_list链表为空,那么还
不能调用spi_match_master_to_boardinfo函数创建spi设备,具体的创建设备将在spi总线驱动的探测函数中,使用spi_register_master()
函数创建设备。

三、总线驱动探测、退出和电源管理函数

3.1、探测函数gsc3280_spi_probe

    程序如下:

点击(此处)折叠或打开

  1. static int __init gsc3280_spi_probe(struct platform_device *pdev)
  2. {
  3.     int ret = 0;
  4.     struct gsc3280_spi *gscs;
  5.     struct spi_master *master;
  6.     struct resource *mem, *ioarea;

  7.     DBG("############\n");
  8.     DBG("gsc3280 spi probe start\n");
  9.     master = spi_alloc_master(&pdev->dev, sizeof(struct gsc3280_spi));
  10.     if (!master) {
  11.         ret = -ENOMEM;
  12.         DBG("!!!!spi_alloc_master error\n");
  13.         goto exit;
  14.     }
  15.     gscs = spi_master_get_devdata(master);
  16.     memset(gscs, 0, sizeof(struct gsc3280_spi));
  17.     gscs->master = spi_master_get(master);
  18.     mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  19.     if (!mem) {
  20.         DBG("!!!!no mem resource!\n");
  21.         ret = -EINVAL;
  22.         goto err_kfree;
  23.     }
  24.     ioarea = request_mem_region(mem->start, resource_size(mem), pdev->name);
  25.     if (!ioarea) {
  26.         DBG("!!!!SPI region already claimed!\n");
  27.         ret = -EBUSY;
  28.         goto err_kfree;
  29.     }
  30.     gscs->regs = ioremap_nocache(mem->start, resource_size(mem));
  31.     if (!gscs->regs) {
  32.         DBG("!!!!SPI ioremap error!\n");
  33.         ret = -ENOMEM;
  34.         goto err_release_reg;
  35.     }
  36.     DBG("gscs->regs = 0x%p\n", gscs->regs);
  37.     gscs->irq = platform_get_irq(pdev, 0);
  38.     if (gscs->irq < 0) {
  39.         DBG("!!!!no irq resource!\n");
  40.         ret = gscs->irq;
  41.         goto err_unmap;
  42.     }
  43.     ret = request_irq(gscs->irq, gsc3280_spi_irq, IRQF_DISABLED, dev_name(&pdev->dev), gscs);
  44.     if (ret < 0) {
  45.         DBG("!!!!can not get IRQ!\n");
  46.         goto err_irq;
  47.     }
  48.     gscs->clk = clk_get(NULL, "spi1");
  49.     if (IS_ERR(gscs->clk)) {
  50.         DBG("!!!!failed to find spi1 clock source!\n");
  51.         ret = PTR_ERR(gscs->clk);
  52.         goto err_irq;
  53.     }
  54.     gscs->max_freq = clk_get_rate(gscs->clk);
  55.     DBG("rate is %d\n", gscs->max_freq);
  56.     clk_enable(gscs->clk);
  57.     gscs->bus_num = pdev->id;
  58.     gscs->num_cs = 4;
  59.     gscs->prev_chip = NULL;
  60.     INIT_LIST_HEAD(&gscs->queue);
  61.     spin_lock_init(&gscs->slock);
  62.     
  63. #ifdef CONFIG_GSC3280_SPI_DMA
  64.     gscs->dma_priv = pdev->dev.platform_data = &spi_platform_data;
  65.     if (!gscs->dma_priv)
  66.         goto err_clk;    //return -ENOMEM;
  67.     gscs->dma_ops = &gscs_dma_ops;
  68.     gscs->dma_inited = 0;
  69.     gscs->dma_addr = (dma_addr_t)(gscs->regs + 0x24) & 0x1fffffff;
  70. #endif

  71.     platform_set_drvdata(pdev, master);
  72.     master->mode_bits = SPI_CPOL | SPI_CPHA;
  73.     master->bus_num = gscs->bus_num;
  74.     master->num_chipselect = gscs->num_cs;
  75.     master->cleanup = gsc3280_spi_cleanup;
  76.     master->setup = gsc3280_spi_setup;
  77.     master->transfer = gsc3280_spi_transfer;
  78.     gsc3280_spi_hw_init(gscs);

  79. #ifdef CONFIG_SPI_GSC3280_DMA
  80.     if (gscs->dma_ops && gscs->dma_ops->dma_init) {
  81.         ret = gscs->dma_ops->dma_init(gscs);
  82.         if (ret) {
  83.             dev_warn(&master->dev, "DMA init failed\n");
  84.             gscs->dma_inited = 0;
  85.         }
  86.     }
  87. #endif

  88.     ret = gsc3280_init_queue(gscs);
  89.     if (ret != 0) {
  90.         DBG("!!!!problem initializing queue!\n");
  91.         goto err_diable_hw;
  92.     }
  93.     ret = gsc3280_start_queue(gscs);
  94.     if (ret != 0) {
  95.         DBG("!!!!problem starting queue!\n");
  96.         goto err_queue_alloc;
  97.     }
  98.     ret = spi_register_master(master);
  99.     if (ret != 0) {
  100.         DBG("!!!!register spi master error!\n");
  101.         goto err_queue_alloc;
  102.     }
  103.     DBG("gsc3280 spi probe success\n");
  104.     DBG("############\n");
  105.     return 0;

  106. //err_free_master:
  107.     //spi_master_put(master);
  108. err_queue_alloc:
  109.     gsc3280_spi_destroy_queue(gscs);
  110. #ifdef CONFIG_SPI_GSC3280_DMA
  111.     if (gscs->dma_ops && gscs->dma_ops->dma_exit)
  112.         gscs->dma_ops->dma_exit(gscs);
  113. #endif
  114. err_diable_hw:
  115.     gsc3280_enable_spi(gscs, GSC_SPI_DISABLE);
  116. //err_clk:
  117.     clk_disable(gscs->clk);
  118.     clk_put(gscs->clk);
  119. err_irq:
  120.     free_irq(gscs->irq, gscs);
  121. err_unmap:
  122.     iounmap(gscs->regs);
  123. err_release_reg:
  124.     release_mem_region(mem->start, resource_size(mem));
  125. err_kfree:
  126.     kfree(gscs);
  127.     kfree(master);
  128. exit:
  129.     printk(KERN_ERR "!!!!!!gsc3280 probe error!!!!!!\n");
  130.     return ret;
  131. }
        说明:

        1) 首先是总线资源的注册,包括申请IO空间和中断。

        2) 接下来注册了中断函数。

        3) 然后注册了spi_master所需要的函数,包括清除、设置和传输等函数,在四中会讲述。

        4) gsc3280_spi_hw_init函数初始化了SPI总线寄存器,接下来讲述。

        5) 总线驱动采用queue机制实现多设备SPI读写,接下来初始化和启动了queue,接下来讲述。

        6) 使用spi_register_master函数注册master,此函数即实现创建了SPI设备结构体,接下来讲述。

        SPI总线寄存器初始化函数gsc3280_spi_hw_init:

点击(此处)折叠或打开

  1. /* Restart the controller, disable all interrupts, clean fifo */
  2. static void gsc3280_spi_hw_init(struct gsc3280_spi *gscs)
  3. {
  4.     gsc3280_enable_spi(gscs, GSC_SPI_DISABLE);
  5.     gsc3280_spi_mask_intr(gscs, GSC_SPI_SR_MASK);
  6.     if (!gscs->fifo_len) {
  7.         gscs->fifo_len = 0x10;
  8.         __raw_writew(0x00, gscs->regs + GSC_SPI_TXFTLR);
  9.         __raw_writew(0x00, gscs->regs + GSC_SPI_RXFTLR);
  10.     }
  11.     gsc3280_enable_spi(gscs, GSC_SPI_ENABLE);
  12. }

        由程序可以看出,此函数首先禁止SPI,屏蔽中断,然后设置fifo深度,最后使能SPI。

        初始化queue函数gsc3280_init_queue:

点击(此处)折叠或打开

  1. static int __devinit gsc3280_init_queue(struct gsc3280_spi *gscs)
  2. {
  3.     gscs->queue_state = GSC_SPI_QUEUE_STOP;
  4.     gscs->busy = 0;
  5.     tasklet_init(&gscs->pump_transfers, gsc3280_spi_pump_transfers, (unsigned long)gscs);
  6.     INIT_WORK(&gscs->pump_messages, gsc3280_spi_pump_messages);
  7.     gscs->workqueue = create_singlethread_workqueue(dev_name(gscs->master->dev.parent));
  8.     if (gscs->workqueue == NULL) {
  9.         DBG("!!!!create_singlethread_workqueue error!\n");
  10.         return -EBUSY;
  11.     }
  12.     else
  13.         return 0;
  14. }
        由程序看出,此函数主要完成初始化队列的作用,包括对queue函数的初始化,最后创建了queue。
        开始queue函数gsc3280_start_queue

点击(此处)折叠或打开

  1. static int gsc3280_start_queue(struct gsc3280_spi *gscs)
  2. {
  3.     unsigned long flags;

  4.     spin_lock_irqsave(&gscs->lock, flags);
  5.     if ((gscs->run == GSC_SPI_QUEUE_RUN) || gscs->busy) {
  6.         spin_unlock_irqrestore(&gscs->lock, flags);
  7.         return -EBUSY;
  8.     }
  9.     gscs->run = GSC_SPI_QUEUE_RUN;
  10.     gscs->cur_msg = NULL;
  11.     gscs->cur_transfer = NULL;
  12.     gscs->cur_chip = NULL;
  13.     gscs->prev_chip = NULL;
  14.     spin_unlock_irqrestore(&gscs->lock, flags);
  15.     queue_work(gscs->workqueue, &gscs->pump_messages);
  16.     return 0;
  17. }

        此函数首先对queue的状态进行判断,然后初始化相关成员变量,最后调度queue。

        最后看下master注册函数spi_register_master:

点击(此处)折叠或打开

  1. int spi_register_master(struct spi_master *master)
  2. {
  3.     static atomic_t        dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
  4.     struct device        *dev = master->dev.parent;
  5.     struct boardinfo    *bi;
  6.     int            status = -ENODEV;
  7.     int            dynamic = 0;

  8.     if (!dev)
  9.         return -ENODEV;

  10.     /* even if it's just one always-selected device, there must
  11.      * be at least one chipselect
  12.      */
  13.     if (master->num_chipselect == 0)
  14.         return -EINVAL;

  15.     /* convention: dynamically assigned bus IDs count down from the max */
  16.     if (master->bus_num < 0) {
  17.         /* FIXME switch to an IDR based scheme, something like
  18.          * I2C now uses, so we can't run out of "dynamic" IDs
  19.          */
  20.         master->bus_num = atomic_dec_return(&dyn_bus_id);
  21.         dynamic = 1;
  22.     }

  23.     spin_lock_init(&master->bus_lock_spinlock);
  24.     mutex_init(&master->bus_lock_mutex);
  25.     master->bus_lock_flag = 0;

  26.     /* register the device, then userspace will see it.
  27.      * registration fails if the bus ID is in use.
  28.      */
  29.     dev_set_name(&master->dev, "spi%u", master->bus_num);
  30.     status = device_add(&master->dev);
  31.     if (status < 0)
  32.         goto done;
  33.     dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
  34.             dynamic ? " (dynamic)" : "");

  35.     mutex_lock(&board_lock);
  36.     list_add_tail(&master->list, &spi_master_list);
  37.     list_for_each_entry(bi, &board_list, list)
  38.         spi_match_master_to_boardinfo(master, &bi->board_info);
  39.     mutex_unlock(&board_lock);

  40.     status = 0;

  41.     /* Register devices from the device tree */
  42.     of_register_spi_devices(master);
  43. done:
  44.     return status;
  45. }
  46. EXPORT_SYMBOL_GPL(spi_register_master);

        说明:

        1) 首先对master成员变量进行检查。

        2) 初始化成员变量。

        3) 将master->list插入到spi_master_list链表中。

        4) 语句list_for_each_entry(bi, &board_list, list)实现遍历board_list链表,在二设备注册中已经讲述了将设备插入到
board_list链表中。此时的board_list链表不为空,已经有相应设备结构体信息了。

        5) 语句spi_match_master_to_boardinfo(master, &bi->board_info);实现设备的创建,函数程序如下:

点击(此处)折叠或打开

  1. static void spi_match_master_to_boardinfo(struct spi_master *master,
  2.                 struct spi_board_info *bi)
  3. {
  4.     struct spi_device *dev;

  5.     if (master->bus_num != bi->bus_num)
  6.         return;

  7.     dev = spi_new_device(master, bi);
  8.     if (!dev)
  9.         dev_err(master->dev.parent, "can't create new device for %s\n",
  10.             bi->modalias);
  11. }

        说明:

        1) 函数首先判断master的总线号和设备的总线号是否相等,如果不等直接返回。

        2) 函数spi_new_device(master, bi);实现设备创建,如下:

点击(此处)折叠或打开

  1. struct spi_device *spi_new_device(struct spi_master *master,
  2.                  struct spi_board_info *chip)
  3. {
  4.     struct spi_device    *proxy;
  5.     int            status;

  6.     /* NOTE: caller did any chip->bus_num checks necessary.
  7.      *
  8.      * Also, unless we change the return value convention to use
  9.      * error-or-pointer (not NULL-or-pointer), troubleshootability
  10.      * suggests syslogged diagnostics are best here (ugh).
  11.      */

  12.     proxy = spi_alloc_device(master);
  13.     if (!proxy)
  14.         return NULL;

  15.     WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));

  16.     proxy->chip_select = chip->chip_select;
  17.     proxy->max_speed_hz = chip->max_speed_hz;
  18.     proxy->mode = chip->mode;
  19.     proxy->irq = chip->irq;
  20.     strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
  21.     proxy->dev.platform_data = (void *) chip->platform_data;
  22.     proxy->controller_data = chip->controller_data;
  23.     proxy->controller_state = NULL;

  24.     status = spi_add_device(proxy);
  25.     if (status < 0) {
  26.         spi_dev_put(proxy);
  27.         return NULL;
  28.     }

  29.     return proxy;
  30. }
  31. EXPORT_SYMBOL_GPL(spi_new_device);

  32. struct spi_device *spi_alloc_device(struct spi_master *master)
  33. {
  34.     struct spi_device    *spi;
  35.     struct device        *dev = master->dev.parent;

  36.     if (!spi_master_get(master))
  37.         return NULL;

  38.     spi = kzalloc(sizeof *spi, GFP_KERNEL);
  39.     if (!spi) {
  40.         dev_err(dev, "cannot alloc spi_device\n");
  41.         spi_master_put(master);
  42.         return NULL;
  43.     }

  44.     spi->master = master;
  45.     spi->dev.parent = dev;
  46.     spi->dev.bus = &spi_bus_type;
  47.     spi->dev.release = spidev_release;
  48.     device_initialize(&spi->dev);
  49.     return spi;
  50. }
  51. EXPORT_SYMBOL_GPL(spi_alloc_device);

        说明:

        1) 首先调用spi_alloc_device函数创建设备内存,从spi_alloc_device函数中可以看到,首先申请内存,然后对设备程序进行赋值。

        2) 接下来将芯片的信息赋值给设备结构体,包括片选、最大速率、模式、中断和名称等。此处名称尤为重要,在spi设备的注册函数
spi_register_driver中,就是通过名称找到相应的设备信息结构体的。

        3) 程序status = spi_add_device(proxy);实现添加spi设备信息。此函数在--Linux spi驱动分析(二)----spi内核中讲述。

3.2、移除函数gsc3280_spi_remove

        程序如下:

点击(此处)折叠或打开

  1. void __exit gsc3280_spi_remove(struct platform_device *pdev)
  2. {
  3.     int status = 0;
  4.     struct spi_master *master = platform_get_drvdata(pdev);
  5.     struct gsc3280_spi *gscs = spi_master_get_devdata(master);

  6.     if (!gscs)
  7.         return;
  8.     status = gsc3280_spi_destroy_queue(gscs);
  9.     if (status != 0)
  10.         dev_err(&gscs->master->dev, "gsc3280_spi_remove: workqueue will not "
  11.             "complete, message memory not freed\n");

  12. #ifdef CONFIG_SPI_GSC3280_DMA
  13.     if (gscs->dma_ops && gscs->dma_ops->dma_exit)
  14.         gscs->dma_ops->dma_exit(gscs);
  15. #endif

  16.     gsc3280_enable_spi(gscs, GSC_SPI_DISABLE);
  17.     free_irq(gscs->irq, gscs);
  18.     iounmap(gscs->regs);
  19.     spi_unregister_master(gscs->master);
  20. }

        说明:

        1) 首先获得总线结构体

        2) 然后删除queue

        3) 最后禁止SPI,释放中断和IO,最后注销master。

3.3、挂起函数gsc3280_spi_suspend

        程序如下:

点击(此处)折叠或打开

  1. static int gsc3280_spi_suspend(struct platform_device *pdev, pm_message_t mesg)
  2. {
  3.     int ret = 0;
  4.     struct spi_master *master = platform_get_drvdata(pdev);
  5.     struct gsc3280_spi *gscs = spi_master_get_devdata(master);

  6.     ret = gsc3280_spi_stop_queue(gscs);
  7.     if (ret)
  8.         return ret;
  9.     gsc3280_enable_spi(gscs, GSC_SPI_DISABLE);
  10.     return ret;
  11. }

        程序中首先停止queue,然后禁止SPI。

        停止queue函数内容如下:

点击(此处)折叠或打开

  1. static int gsc3280_spi_stop_queue(struct gsc3280_spi *gscs)
  2. {
  3.     int status = 0;
  4.     unsigned long flags;
  5.     unsigned limit = 50;
  6.     
  7.     spin_lock_irqsave(&gscs->lock, flags);
  8.     while ((!list_empty(&gscs->queue) || gscs->busy) && limit--) {
  9.         spin_unlock_irqrestore(&gscs->lock, flags);
  10.         msleep(10);
  11.         spin_lock_irqsave(&gscs->lock, flags);
  12.     }
  13.     if (!list_empty(&gscs->queue) || gscs->busy)
  14.         status = -EBUSY;
  15.     else
  16.         gscs->queue_state = GSC_SPI_QUEUE_STOP;
  17.     spin_unlock_irqrestore(&gscs->lock, flags);
  18.     return status;
  19. }

        程序首先遍历queue链表,查看是否还有queue没有执行,总共尝试50次,如果还有queue没有执行或者设备忙,则错误返回,否
则置正确queue状态。

3.4、恢复函数gsc3280_spi_resume

        程序如下:

点击(此处)折叠或打开

  1. static int gsc3280_spi_resume(struct platform_device *pdev)
  2. {
  3.     int ret = 0;
  4.     struct spi_master *master = platform_get_drvdata(pdev);
  5.     struct gsc3280_spi *gscs = spi_master_get_devdata(master);

  6.     gsc3280_spi_hw_init(gscs);
  7.     ret = gsc3280_start_queue(gscs);
  8.     if (ret)
  9.         dev_err(&gscs->master->dev, "fail to start queue (%d)\n", ret);
  10.     return ret;
  11. }

        程序主要初始化SPI寄存器,然后开始运行queue。

四、spi master支持函数

4.1、清除函数gsc3280_spi_cleanup

点击(此处)折叠或打开

  1. static void gsc3280_spi_cleanup(struct spi_device *spi)
  2. {
  3.     struct chip_data *chip = spi_get_ctldata(spi);
  4.     kfree(chip);
  5. }

        程序首先获取设备指针,然后释放内存。

4.2、设置函数gsc3280_spi_setup

        此函数是一个回调函数,spi核心中的spi_setup()函数会调用此函数,程序如下:

点击(此处)折叠或打开

  1. /* This may be called twice for each spi dev */
  2. static int gsc3280_spi_setup(struct spi_device *spi)
  3. {
  4.     int ret = 0;
  5.     struct chip_data *chip = NULL;
  6.     struct gsc3280_spi_info *chip_info = NULL;

  7.     DBG("######gsc3280 spi bus setup start######\n");
  8.     chip = spi_get_ctldata(spi);        /* Only alloc on first setup */
  9.     if (!chip) {
  10.         chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
  11.         if (!chip) {
  12.             DBG("!!!!kzalloc error!\n");
  13.             ret = -ENOMEM;
  14.             goto exit;
  15.         }
  16.     }
  17.     chip_info = spi->controller_data;
  18.     /* chip_info doesn't always exist */
  19.     if (chip_info) {
  20. #ifdef CONFIG_GSC3280_SPI_DMA
  21.         chip->poll_mode = chip_info->poll_mode;
  22.         chip->enable_dma = chip_info->enable_dma;
  23. #endif
  24.         chip->pin_cs = chip_info->pin_cs;
  25.         chip->cs_value = chip_info->cs_value;
  26.         chip->bits_per_word = chip_info->bits_per_word;
  27.         chip->lsb_flg = chip_info->lsb_flg;
  28.         gpio_request(chip->pin_cs, spi->modalias);
  29.         if (chip->cs_value == 0)
  30.             gpio_direction_output(chip->pin_cs, 1);
  31.         else
  32.             gpio_direction_output(chip->pin_cs, 0);
  33.     }
  34.     if (spi->bits_per_word == 8) {
  35.         chip->n_bytes = 1;
  36. #ifdef CONFIG_GSC3280_SPI_DMA
  37.         chip->dma_width = 1;
  38. #endif
  39.     } else if (spi->bits_per_word == 16) {
  40.         chip->n_bytes = 2;
  41. #ifdef CONFIG_GSC3280_SPI_DMA
  42.         chip->dma_width = 2;
  43. #endif
  44.     } else {
  45.         DBG("!!!!spi->bits_per_word = %d error!\n", spi->bits_per_word);
  46.         ret = -EINVAL;
  47.         goto exit;
  48.     }
  49.     if (!spi->max_speed_hz) {
  50.         DBG("!!!!spi->max_speed_hz = %d, error!\n", spi->max_speed_hz);
  51.         ret = -EINVAL;
  52.         goto exit;
  53.     }
  54.     chip->speed_hz = spi->max_speed_hz;
  55.     chip->cr = (chip->lsb_flg << GSC_SPI_CTL_BITS_NUM) | (spi->mode << GSC_SPI_CTL_MOD)
  56.                 | ((chip->bits_per_word - 1) << GSC_SPI_CTL_DSS);
  57.     spi_set_ctldata(spi, chip);

  58. exit:
  59.     if (ret != 0)
  60.         DBG("!!!!gsc3280 spi bus setup error!\n");
  61.     else
  62.         DBG("######gsc3280 spi bus setup success######\n");
  63.     return ret;
  64. }
        说明:

        1) 首先判断参数,如果参数错误,直接返回。

        2) 获取spi控制数据,如果没有,则申请内存创建设备。

        3) 接下来根据实际情况对设备结构体赋值。

4.3、传输函数gsc3280_spi_transfer

        此函数尤为重要,SPI设备传输数据时,就是调用此函数实现数据传输的,此函数主要完成结构体成员变量的
初始化,具体的传输在中断中进行。

点击(此处)折叠或打开

  1. /* spi driver call this function transfer data */
  2. static int gsc3280_spi_transfer(struct spi_device *spi, struct spi_message *msg)
  3. {
  4.     unsigned long flags = 0;
  5.     struct gsc3280_spi *gscs = spi_master_get_devdata(spi->master);

  6.     DBG("####gsc3280 spi transfer start####\n");
  7.     if (gscs->queue_state == GSC_SPI_QUEUE_STOP) {
  8.         DBG("!!!!queue is stop!\n");
  9.         return -ESHUTDOWN;
  10.     }
  11.     msg->actual_length = 0;
  12.     msg->status = -EINPROGRESS;
  13.     msg->state = START_STATE;
  14.     spin_lock_irqsave(&gscs->slock, flags);
  15.     list_add_tail(&msg->queue, &gscs->queue);
  16.     spin_unlock_irqrestore(&gscs->slock, flags);
  17.     //writel(0x3f, (volatile unsigned int *)(0xbc04a000 + 0x38));    //max divid freq
  18.     if (gscs->cur_transfer || gscs->cur_msg) {
  19.         //DBG("gsc3280_spi_transfer: cur transfer or msg not empty\n");
  20.     } else {
  21.         //DBG("gsc3280_spi_transfer: no cur transfer and msg\n");
  22.         queue_work(gscs->workqueue, &gscs->pump_messages);
  23.     }
  24.     DBG("####gsc3280 spi transfer success####\n");
  25.     return 0;
  26. }

        说明:

        1) 首先判断queue状态,如果是停止状态,则退出。

        2) 对传送结构体成员变量赋值。

        3) 判断当前是否有数据在收发,如果有,就先直接返回。

        4) 如果没有,则调用queue_work()函数,调度函数gsc3280_spi_pump_messages()。程序如下:

点击(此处)折叠或打开

  1. /*
  2.   * when call this function, no msg transfering
  3.   * deal one msg when call this funciton once.
  4.   *
  5.   */
  6. static void gsc3280_spi_pump_messages(struct work_struct *work)
  7. {
  8.     unsigned long flags = 0;
  9.     struct gsc3280_spi *gscs = container_of(work, struct gsc3280_spi, pump_messages);

  10.     DBG("####gsc3280_spi_pump_messages####\n");
  11.     if (list_empty(&gscs->queue) || (gscs->queue_state == GSC_SPI_QUEUE_STOP)) {
  12.         if (gscs->queue_state == GSC_SPI_QUEUE_STOP)
  13.             DBG("!!!!queue is stop!\n");
  14.         else
  15.             DBG("msg is finished!\n");
  16.         gscs->busy = 0;
  17.         return;
  18.     }
  19.     
  20.     spin_lock_irqsave(&gscs->slock, flags);
  21.     gscs->cur_msg = list_entry(gscs->queue.next, struct spi_message, queue);
  22.     if (!gscs->cur_msg) {
  23.         spin_unlock_irqrestore(&gscs->slock, flags);
  24.         DBG("!!!!gsc3280_spi_pump_messages: current no msg!\n");
  25.         return;
  26.     }
  27.     list_del_init(&gscs->cur_msg->queue);
  28.     gscs->cur_msg->state = RUNNING_STATE;
  29.     gscs->cur_chip = spi_get_ctldata(gscs->cur_msg->spi);
  30.     gscs->n_bytes = gscs->cur_chip->n_bytes;
  31.     gscs->busy = 1;
  32.     spin_unlock_irqrestore(&gscs->slock, flags);

  33.     DBG("cs select enable\n");
  34.     if (gscs->cur_chip->cs_value == 0) {
  35.         gpio_set_value(gscs->cur_chip->pin_cs, 0);
  36.     }
  37.     else
  38.         gpio_set_value(gscs->cur_chip->pin_cs, 1);
  39.     /* get first transfer */
  40.     gscs->cur_transfer = list_entry(gscs->cur_msg->transfers.next, struct spi_transfer, transfer_list);
  41.     if (!gscs->cur_transfer) {
  42.         DBG("!!!!gsc3280_spi_pump_transfers: current no transfer!\n");
  43.         return;
  44.     }
  45.     tasklet_schedule(&gscs->pump_transfers);
  46.     return;
  47. }
        说明:

        1) 此函数在两种情况下会被调用:

            a) 当第一次开始SPI传输时,会调用此函数,设置message结构体变量。

            b) 当传输完一个message后,如果判断还有message没有被传输,则调用此函数获取新的message。

        2) 程序首先对变量进行检查,有两种退出情况,第一种是队列已经处于停止状态,第二种是传输msg链表为空。

        3) 上锁,获取新的传输message,如果获取失败,直接解锁退出。

        4) 如果获取msg成功,先删除获取成功msg的链表,然后对SPI总线驱动结构体变量赋初值。
        5) 解锁,使能片选信号CS。
        6) 获取传输的第一个transfer。

        7) 调度gsc3280_spi_pump_transfers函数,函数如下:

点击(此处)折叠或打开

  1. /* when call this function,the cur_msg is the new msg */
  2. static void gsc3280_spi_pump_transfers(unsigned long data)
  3. {
  4.     int clk_div = 0;
  5.     u32 imask = 0, cr = 0;
  6.     unsigned long flags = 0;
  7.     struct spi_transfer *previous = NULL;
  8.     struct gsc3280_spi *gscs = (struct gsc3280_spi *)data;

  9.     //DBG("gsc3280_spi_pump_transfers\n");
  10.     if (gscs->cur_msg->state == ERROR_STATE) {
  11.         DBG("!!!!pump_transfers:cur msg state error!\n");
  12.         gscs->cur_msg->status = -EIO;
  13.         goto early_exit;
  14.     }
  15.     /* Handle end of message */
  16.     if (gscs->cur_msg->state == DONE_STATE) {
  17.         gscs->cur_msg->status = 0;
  18.         goto early_exit;
  19.     }
  20.     /* Delay if requested at end of transfer*/
  21.     if (gscs->cur_msg->state == RUNNING_STATE) {
  22.         previous = list_entry(gscs->cur_transfer->transfer_list.prev, struct spi_transfer, transfer_list);
  23.         if (previous->delay_usecs)
  24.             udelay(previous->delay_usecs);
  25.     }

  26. #ifdef CONFIG_SPI_GSC3280_DMA
  27.     gscs->dma_width = gscs->cur_chip->dma_width;
  28.     gscs->rx_dma = gscs->cur_transfer->rx_dma;
  29.     gscs->tx_dma = gscs->cur_transfer->tx_dma;
  30. #endif

  31.     /* Handle per transfer options for bpw and speed */
  32.     if (gscs->cur_transfer->speed_hz) {
  33.         if (gscs->cur_transfer->speed_hz != gscs->cur_chip->speed_hz) {
  34.             if (gscs->cur_transfer->speed_hz > gscs->max_freq) {
  35.                 printk(KERN_ERR "SPI1: unsupported freq: %dHz\n", gscs->cur_transfer->speed_hz);
  36.                 gscs->cur_msg->status = -EIO;
  37.                 return;
  38.             } else
  39.                 gscs->cur_chip->speed_hz = gscs->cur_transfer->speed_hz;
  40.         }
  41.     }
  42.     if (gscs->cur_transfer->bits_per_word) {
  43.         switch (gscs->cur_transfer->bits_per_word) {
  44.         case 8:
  45.         case 16:
  46.             gscs->n_bytes = gscs->cur_transfer->bits_per_word >> 3;
  47. #ifdef CONFIG_SPI_GSC3280_DMA
  48.             gscs->dma_width = gscs->n_bytes;
  49. #endif
  50.             break;
  51.         default:
  52.             printk(KERN_ERR "SPI1: unsupported bits:" "%db\n", gscs->cur_transfer->bits_per_word);
  53.             gscs->cur_msg->status = -EIO;
  54.             return;
  55.         }
  56.     }

  57.     clk_div = gscs->max_freq / gscs->cur_transfer->speed_hz;
  58.     clk_div = clk_div / 2 - 1;
  59.     if (clk_div < 0)
  60.         clk_div = 0;
  61.     gscs->cur_chip->clk_div = (u16)clk_div;

  62.     cr = gscs->cur_chip->cr | GSC_SPI_CTL_EN;
  63.     writel(cr, gscs->regs + GSC_SPI_CTRL);    /* enable spi */
  64.     writel(gscs->cur_chip->clk_div, gscs->regs + GSC_SPI_SEABAUR);
  65.     
  66.     spin_lock_irqsave(&gscs->slock, flags);
  67.     //gscs->n_bytes = gscs->cur_chip->n_bytes;
  68.     gscs->tx = (void *)gscs->cur_transfer->tx_buf;
  69.     gscs->tx_end = gscs->tx + gscs->cur_transfer->len;
  70.     gscs->rx = gscs->cur_transfer->rx_buf;
  71.     gscs->rx_end = gscs->rx + gscs->cur_transfer->len;
  72.     gscs->cs_change = gscs->cur_transfer->cs_change;
  73.     gscs->len = gscs->cur_transfer->len;
  74.     spin_unlock_irqrestore(&gscs->slock, flags);
  75.     
  76.     imask |= SPI_INT_TX_H_OVER | SPI_INT_RX_L_OVER | SPI_INT_RX_H_OVER | SPI_INT_RX_FULL;
  77.     if (gscs->tx != NULL) {
  78.         imask |= SPI_INT_TX_EMPTY;
  79.     }
  80.     gsc3280_spi_umask_intr(gscs, imask);

  81. #ifdef CONFIG_GSC3280_SPI_DMA
  82.     /* Check if current transfer is a DMA transaction */
  83.     gscs->dma_mapped = map_dma_buffers(gscs);
  84.     /* Interrupt mode we only need set the TXEI IRQ, as TX/RX always happen syncronizely */
  85.     if (!gscs->dma_mapped && !gscs->cur_chip->poll_mode) {
  86.         //int templen = gscs->len / gscs->n_bytes;
  87.         //txint_level = gscs->fifo_len / 2;
  88.         //txint_level = (templen > txint_level) ? txint_level : templen;
  89.     }
  90.     if (gscs->dma_mapped)
  91.         gscs->dma_ops->dma_transfer(gscs, cs_change);
  92.     if (gscs->cur_chip->poll_mode)
  93.         gsc3280_spi_poll_transfer(gscs);
  94. #endif
  95.     
  96.     return;
  97.     
  98. early_exit:
  99.     gsc3280_spi_giveback(gscs);
  100.     return;
  101. }
        说明:

        1) 首先对msg变量进行检测。

        2) 如果变量正确,获取此次传输的分频系数和每次传输几个字节。
        3) 设置SPI控制寄存器和分频
寄存器,
        4) 设置SPI总线驱动结构体中的传输或者接收数据指针,打开中断,开始数据传输。

        5) 每传输一个transfer,都会调用此函数一次。

        实际的传输数据在中断中进行,程序如下:

点击(此处)折叠或打开

  1. /* this is transfer message function */
  2. static irqreturn_t gsc3280_spi_irq(int irq, void *dev_id)
  3. {
  4.     struct gsc3280_spi *gscs = dev_id;
  5.     u32 irq_status = __raw_readw(gscs->regs + GSC_SPI_ISR);
  6.     
  7.     //DBG("gsc3280_spi_irq\n");
  8.     //DBG("sys_ctl0 = 0x%x\n", readl((volatile unsigned int *)(0xbc04a000 + 0x08)));
  9.     //DBG("clddiv_spi1 = 0x%x\n", readl((volatile unsigned int *)(0xbc04a000 + 0x38)));
  10.     //DBG("imux_cfg0 = 0x%x\n", readl((volatile unsigned int *)(0xbc04a000 + 0xb0)));
  11.     DBG("cr = 0x%x\n", __raw_readw(gscs->regs + GSC_SPI_CTRL));
  12.     DBG("imsr = 0x%x, irq_status = 0x%x\n", __raw_readl(gscs->regs + GSC_SPI_IMSR), irq_status);

  13.     if (!irq_status ) {
  14.         DBG("!!!!gsc3280_spi_irq: no irq!\n");
  15.         return IRQ_NONE;
  16.     }
  17.     if (!gscs->cur_msg) {
  18.         DBG("!!!!gsc3280_spi_irq: no msg!\n");
  19.         gsc3280_spi_mask_intr(gscs, SPI_INT_TX_EMPTY | SPI_INT_RX_FULL);
  20.         return IRQ_HANDLED;
  21.     }
  22.     if (irq_status & (SPI_INT_TX_H_OVER | SPI_INT_RX_L_OVER | SPI_INT_RX_H_OVER)) {
  23.         DBG("!!!!gsc3280_spi_irq: fifo overrun/underrun!\n");
  24.         __raw_writew(0x0e, gscs->regs + GSC_SPI_ISR);
  25.         gscs->cur_msg->state = ERROR_STATE;
  26.         gscs->cur_msg->status = -EIO;
  27.         queue_work(gscs->workqueue, &gscs->pump_messages);
  28.         return IRQ_HANDLED;
  29.     }
  30.     if (irq_status & SPI_INT_RX_FULL) {
  31.         spi_gsc_read(gscs);
  32.         return IRQ_HANDLED;
  33.     }
  34.     if (irq_status & SPI_INT_TX_EMPTY) {
  35.         spi_gsc_write(gscs);
  36.     }
  37.     return IRQ_HANDLED;
  38. }
        说明:

        1) 首先读取中断状态,如果是空中断,退出中断。

        2) 判断当前是否有msg在传输,如果没有,退出中断

        3) 判断是否是错误中断,包括溢出等,如果是,屏蔽中断,退出中断
        4) 如果是接收满中断,则首先接收数据。然后退出中断

        4) 如果是发送空中断,则发送数据,发送完成后,退出中断。
        现在看下发送数据函数spi_gsc_write():

点击(此处)折叠或打开

  1. static void gsc3280_writer(struct gsc3280_spi *gscs)
  2. {
  3.     u16 txw = 0;
  4.     unsigned long flags = 0;
  5.     u32 max = gsc3280_spi_tx_max(gscs);

  6.     //DBG("max = %d, gscs->n_bytes = 0x%x", max, gscs->n_bytes);
  7.     spin_lock_irqsave(&gscs->slock, flags);
  8.     while (max--) {
  9.         if (gscs->n_bytes == 1)
  10.             txw = *(u8 *)(gscs->tx);
  11.         else
  12.             txw = *(u16 *)(gscs->tx);
  13.         DBG("txw = 0x%x\n", txw);
  14.         writel(txw, gscs->regs + GSC_SPI_DA_S);
  15.         gscs->tx += gscs->n_bytes;
  16.     }
  17.     spin_unlock_irqrestore(&gscs->slock, flags);
  18. }
  19. static void spi_gsc_write(struct gsc3280_spi *gscs)
  20. {
  21.     //DBG("spi_gsc_write\n");
  22.     gsc3280_spi_mask_intr(gscs, GSC_SPI_SR_MASK);
  23.     gsc3280_writer(gscs);
  24.     if (gscs->tx_end == gscs->tx) {
  25.         gsc3280_spi_xfer_done(gscs);
  26.     }
  27.     else {
  28.         gsc3280_spi_umask_intr(gscs, GSC_SPI_SR_MASK);
  29.     }
  30. }

        说明:

        1) 首先屏蔽中断。

        2) 发送数据。

        3) 如果发送完成,执行gsc3280_spi_xfer_done(gscs)函数。

        4) 如果没有完成,打开中断,继续发数据。

        对于gsc3280_spi_xfer_done()函数,如下:

点击(此处)折叠或打开

  1. static void *gsc3280_spi_next_transfer(struct gsc3280_spi *gscs)
  2. {
  3.     struct spi_message *msg = gscs->cur_msg;
  4.     struct spi_transfer *trans = gscs->cur_transfer;

  5.     if (trans->transfer_list.next != &msg->transfers) {
  6.         gscs->cur_transfer = list_entry(trans->transfer_list.next, struct spi_transfer, transfer_list);
  7.         return RUNNING_STATE;
  8.     } else
  9.         return DONE_STATE;
  10. }
  11. static void gsc3280_spi_xfer_done(struct gsc3280_spi *gscs)
  12. {
  13.     //DBG("gsc3280_spi_xfer_done\n");
  14.     //DBG("irq_status = 0x%x\n", __raw_readw(gscs->regs + GSC_SPI_ISR));
  15.     //DBG("imsr = 0x%x\n", __raw_readl(gscs->regs + GSC_SPI_IMSR));
  16.     /* Update total byte transferred return count actual bytes read */
  17.     gscs->cur_msg->actual_length += gscs->len;
  18.     /* Move to next transfer */
  19.     gscs->cur_msg->state = gsc3280_spi_next_transfer(gscs);
  20.     if (gscs->cur_msg->state == DONE_STATE) {
  21.         /* Handle end of message */
  22.         gscs->cur_msg->status = 0;
  23.         gsc3280_spi_giveback(gscs);
  24.     } else {
  25.         tasklet_schedule(&gscs->pump_transfers);
  26.     }
  27. }        说明:

        1) 获取下一个transfer,如果还有,则调度gsc3280_spi_pump_transfers()函数准备开始传输。

        2) 如果没有transfer需要传输,调用函数gsc3280_spi_giveback(gscs)说明此时已经处理完成了一个msg。

        gsc3280_spi_giveback(gscs)函数如下:

点击(此处)折叠或打开

  1. /* Caller already set message->status; dma and pio irqs are blocked */
  2. static void gsc3280_spi_giveback(struct gsc3280_spi *gscs)
  3. {
  4.     unsigned long flags = 0;

  5.     DBG("gsc3280_spi_giveback\n");
  6.     //DBG("irq_status = 0x%x\n", readl(gscs->regs + GSC_SPI_ISR));
  7.     gsc3280_spi_mask_intr(gscs, GSC_SPI_SR_MASK);
  8.     DBG("cs select disable\n");
  9.     if (gscs->cur_chip->cs_value == 0) {
  10.         gpio_set_value(gscs->cur_chip->pin_cs, 1);
  11.     }
  12.     else
  13.         gpio_set_value(gscs->cur_chip->pin_cs, 0);
  14.     gscs->cur_msg->state = NULL;
  15.     if (gscs->cur_msg->complete)
  16.         gscs->cur_msg->complete(gscs->cur_msg->context);
  17.     
  18.     spin_lock_irqsave(&gscs->slock, flags);
  19.     gscs->cur_msg = NULL;
  20.     gscs->cur_transfer = NULL;
  21.     gscs->prev_chip = gscs->cur_chip;
  22.     gscs->cur_chip = NULL;
  23.     gscs->busy = 0;
  24. #ifdef CONFIG_SPI_GSC3280_DMA
  25.     gscs->dma_mapped = 0;
  26. #endif
  27.     spin_unlock_irqrestore(&gscs->slock, flags);
  28.     queue_work(gscs->workqueue, &gscs->pump_messages);
  29. }

        说明:

        1) 首先屏蔽中断。

        2) 禁止片选。

        3) 设置完成msg。

        4) 上锁,初始化SPI总线结构体变量。

        5) 调用gsc3280_spi_pump_messages()函数,处理下一个msg。

        中断接收数据函数spi_gsc_read(gscs)如下:

点击(此处)折叠或打开

  1. static void gsc3280_reader(struct gsc3280_spi *gscs)
  2. {
  3.     u16 rxw = 0;
  4.     unsigned long flags = 0;
  5.     u32 max = gsc3280_spi_rx_max(gscs);

  6.     //DBG("max = %d, gscs->n_bytes = 0x%x", max, gscs->n_bytes);
  7.     spin_lock_irqsave(&gscs->slock, flags);
  8.     while (max--) {
  9.         rxw = readl(gscs->regs + GSC_SPI_DA_S);
  10.         DBG("rxw = 0x%x\n", rxw);
  11.         if (gscs->n_bytes == 1)
  12.             *(u8 *)(gscs->rx) = (u8)rxw;
  13.         else
  14.             *(u16 *)(gscs->rx) = rxw;
  15.         gscs->rx += gscs->n_bytes;
  16.     }
  17.     spin_unlock_irqrestore(&gscs->slock, flags);
  18. }
  19. static void spi_gsc_read(struct gsc3280_spi *gscs)
  20. {
  21.     //DBG("spi_gsc_read\n");
  22.     gsc3280_reader(gscs);
  23.     if (gscs->rx_end == gscs->rx) {
  24.         gsc3280_spi_xfer_done(gscs);
  25.     }
  26. }

        说明:

        1) 首先接收数据,如果接收成功,调用gsc3280_spi_xfer_done(gscs);

        到此,SPI总线驱动就全部讲述完成了,在总线驱动中,使用了queue和tasklet两种机制,queue实现了不同
msg的传输,tasklet实现了msg中不同transfer的传输。


from:http://blog.chinaunix.net/uid-25445243-id-3987576.html

linux内核SPI总线驱动分析

http://www.embedu.org/Column/Column367.htm 下面有两个大的模块: 一个是SPI总线驱动的分析            (研究了具体实现的过程) 另一个...

linux内核SPI总线驱动分析

下面有两个大的模块: 一个是SPI总线驱动的分析            (研究了具体实现的过程) 另一个是SPI总线驱动的编写(不用研究具体的实现过程) SPI总线驱动分析 1 SPI概...

linux内核SPI总线驱动分析(一)

下面有两个大的模块: 一个是SPI总线驱动的分析            (研究了具体实现的过程) 另一个是SPI总线驱动的编写(不用研究具体的实现过程) SPI总线驱动分析  ...

linux内核SPI总线驱动分析

1、SPI概述 SPI是英语Serial Peripheral interface的缩写,顾名思义就是串行外围设备接口,SPI是一种高速的,全双工, 同步的通信总线,并且在芯片的管脚上只占用四根线。通...
  • lrl2ye
  • lrl2ye
  • 2017年05月04日 08:41
  • 145

linux内核SPI总线驱动分析(一)

转载自: http://www.cnblogs.com/liugf05/archive/2012/12/03/2800457.html 下面有两个大的模块: 一个是SPI总线驱动的分析     ...

linux内核SPI总线驱动分析(一)

下面有两个大的模块: 一个是SPI总线驱动的分析            (研究了具体实现的过程) 另一个是SPI总线驱动的编写(不用研究具体的实现过程) SPI总线驱动分析   1 SPI概述   ...

Linux下SPI总线驱动分析

Linux下SPI总线驱动有通用接口,一般的SPI设备驱动使用这个驱动接口实现设备驱动。分析驱动最好是先了解核心代码,然后从具体设备分析入手,然后从下至上,了解整个框架,再从上到下分析,理解透彻。 ...

linux内核SPI总线驱动分析(一)

下面有两个大的模块: 一个是SPI总线驱动的分析            (研究了具体实现的过程) 另一个是SPI总线驱动的编写(不用研究具体的实现过程) SPI总线驱动分析  ...

Linux spi驱动分析(一)----总线驱动

一、SPI总线驱动介绍         SPI总线总共需要四根线,包括MOSI、MISO、CLK和CS。本文首先从SPI设备注册开始来讲述SPI总线驱动。 二、设备注册       ...
  • yuzeze
  • yuzeze
  • 2016年08月25日 11:04
  • 277

Linux spi驱动分析(一)----总线驱动

本文讲述了一款芯片的SPI总线驱动,在驱动中,使用了queue和taslet机制来实现多message和多transfer的传输。 本文作为SPI的第一篇文章,后面会继续讲述spi核心,spidev和...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Linux spi驱动分析(一)----总线驱动
举报原因:
原因补充:

(最多只允许输入30个字)