技术文摘

Linux spi驱动分析(一)——GSC3280总线驱动












一、SPI总线驱动介绍

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

二、设备注册

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

对于此处,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.   

8.      DBG("############\n");

9.      DBG("gsc3280 spi probe start\n");

10.    master = spi_alloc_master(&pdev->dev, sizeof(struct gsc3280_spi));

11.    if (!master) {

12.        ret = -ENOMEM;

13.        DBG("!!!!spi_alloc_master error\n");

14.        goto exit;

15.    }

16.    gscs = spi_master_get_devdata(master);

17.    memset(gscs, 0, sizeof(struct gsc3280_spi));

18.    gscs->master = spi_master_get(master);

19.    mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 

20.    if (!mem) {

21.        DBG("!!!!no mem resource!\n");

22.        ret = -EINVAL;

23.        goto err_kfree;

24.    }

25.    ioarea = request_mem_region(mem->start, resource_size(mem), pdev->name); 

26.    if (!ioarea) {

27.        DBG("!!!!SPI region already claimed!\n");

28.        ret = -EBUSY;

29.        goto err_kfree;

30.    }

31.    gscs->regs = ioremap_nocache(mem->start, resource_size(mem)); 

32.    if (!gscs->regs) {

33.        DBG("!!!!SPI ioremap error!\n");

34.        ret = -ENOMEM;

35.        goto err_release_reg;

36.    }

37.    DBG("gscs->regs = 0x%p\n", gscs->regs);

38.    gscs->irq = platform_get_irq(pdev, 0); 

39.    if (gscs->irq < 0) {

40.        DBG("!!!!no irq resource!\n");

41.        ret = gscs->irq;

42.        goto err_unmap;

43.    }

44.    ret = request_irq(gscs->irq, gsc3280_spi_irq, IRQF_DISABLED, dev_name(&pdev->dev), gscs);

45.    if (ret < 0) {

46.        DBG("!!!!can not get IRQ!\n");

47.        goto err_irq;

48.    }

49.    gscs->clk = clk_get(NULL, "spi1");

50.    if (IS_ERR(gscs->clk)) {

51.        DBG("!!!!failed to find spi1 clock source!\n");

52.        ret = PTR_ERR(gscs->clk);

53.        goto err_irq;

54.    }

55.    gscs->max_freq = clk_get_rate(gscs->clk);

56.    DBG("rate is %d\n", gscs->max_freq);

57.    clk_enable(gscs->clk);

58.    gscs->bus_num = pdev->id;

59.    gscs->num_cs = 4;

60.    gscs->prev_chip = NULL;

61.    INIT_LIST_HEAD(&gscs->queue);

62.    spin_lock_init(&gscs->slock);

63.    

64.#ifdef CONFIG_GSC3280_SPI_DMA

65.    gscs->dma_priv = pdev->dev.platform_data = &spi_platform_data;

66.    if (!gscs->dma_priv)

67.        goto err_clk;    //return -ENOMEM;

68.    gscs->dma_ops = &gscs_dma_ops;

69.    gscs->dma_inited = 0;

70.    gscs->dma_addr = (dma_addr_t)(gscs->regs + 0x24) & 0x1fffffff;

71.#endif

72. 

73.    platform_set_drvdata(pdev, master);

74.    master->mode_bits = SPI_CPOL | SPI_CPHA;

75.    master->bus_num = gscs->bus_num;

76.    master->num_chipselect = gscs->num_cs;

77.    master->cleanup = gsc3280_spi_cleanup;

78.    master->setup = gsc3280_spi_setup;

79.    master->transfer = gsc3280_spi_transfer;

80.    gsc3280_spi_hw_init(gscs);

81. 

82.#ifdef CONFIG_SPI_GSC3280_DMA

83.    if (gscs->dma_ops && gscs->dma_ops->dma_init) {

84.        ret = gscs->dma_ops->dma_init(gscs);

85.        if (ret) {

86.            dev_warn(&master->dev, "DMA init failed\n");

87.            gscs->dma_inited = 0;

88.        }

89.    }

90.#endif

91. 

92.    ret = gsc3280_init_queue(gscs);

93.    if (ret != 0) {

94.        DBG("!!!!problem initializing queue!\n");

95.        goto err_diable_hw;

96.    }

97.    ret = gsc3280_start_queue(gscs);

98.    if (ret != 0) {

99.        DBG("!!!!problem starting queue!\n");

100.                 goto err_queue_alloc;

101.             }

102.             ret = spi_register_master(master);

103.             if (ret != 0) {

104.                 DBG("!!!!register spi master error!\n");

105.                 goto err_queue_alloc;

106.             }

107.             DBG("gsc3280 spi probe success\n");

108.             DBG("############\n");

109.             return 0;

110.          

111.         //err_free_master:

112.             //spi_master_put(master);

113.         err_queue_alloc:

114.             gsc3280_spi_destroy_queue(gscs);

115.         #ifdef CONFIG_SPI_GSC3280_DMA

116.             if (gscs->dma_ops && gscs->dma_ops->dma_exit)

117.                 gscs->dma_ops->dma_exit(gscs);

118.         #endif

119.         err_diable_hw:

120.             gsc3280_enable_spi(gscs, GSC_SPI_DISABLE);

121.         //err_clk:

122.             clk_disable(gscs->clk);

123.             clk_put(gscs->clk);

124.         err_irq:

125.             free_irq(gscs->irq, gscs);

126.         err_unmap:

127.             iounmap(gscs->regs);

128.         err_release_reg:

129.             release_mem_region(mem->start, resource_size(mem));

130.         err_kfree:

131.             kfree(gscs);

132.             kfree(master);

133.         exit:

134.             printk(KERN_ERR "!!!!!!gsc3280 probe error!!!!!!\n");

135.             return ret;

136.         }


说明:

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.   

5.      spin_lock_irqsave(&gscs->lock, flags);

6.      if ((gscs->run == GSC_SPI_QUEUE_RUN) || gscs->busy) {

7.          spin_unlock_irqrestore(&gscs->lock, flags);

8.          return -EBUSY;

9.      }

10.    gscs->run = GSC_SPI_QUEUE_RUN;

11.    gscs->cur_msg = NULL;

12.    gscs->cur_transfer = NULL;

13.    gscs->cur_chip = NULL;

14.    gscs->prev_chip = NULL;

15.    spin_unlock_irqrestore(&gscs->lock, flags);

16.    queue_work(gscs->workqueue, &gscs->pump_messages);

17.    return 0;

18.}

此函数首先对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.   

9.      if (!dev)

10.        return -ENODEV;

11. 

12.    /* even if it's just one always-selected device, there must

13.     * be at least one chipselect

14.     */

15.    if (master->num_chipselect == 0)

16.        return -EINVAL;

17. 

18.    /* convention: dynamically assigned bus IDs count down from the max */

19.    if (master->bus_num < 0) {

20.        /* FIXME switch to an IDR based scheme, something like

21.         * I2C now uses, so we can't run out of "dynamic" IDs

22.         */

23.        master->bus_num = atomic_dec_return(&dyn_bus_id);

24.        dynamic = 1;

25.    }

26. 

27.    spin_lock_init(&master->bus_lock_spinlock);

28.    mutex_init(&master->bus_lock_mutex);

29.    master->bus_lock_flag = 0;

30. 

31.    /* register the device, then userspace will see it.

32.     * registration fails if the bus ID is in use.

33.     */

34.    dev_set_name(&master->dev, "spi%u", master->bus_num);

35.    status = device_add(&master->dev);

36.    if (status < 0)

37.        goto done;

38.    dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),

39.            dynamic ? " (dynamic)" : "");

40. 

41.    mutex_lock(&board_lock);

42.    list_add_tail(&master->list, &spi_master_list);

43.    list_for_each_entry(bi, &board_list, list)

44.        spi_match_master_to_boardinfo(master, &bi->board_info);

45.    mutex_unlock(&board_lock);

46. 

47.    status = 0;

48. 

49.    /* Register devices from the device tree */

50.    of_register_spi_devices(master);

51.done:

52.    return status;

53.}

54.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.   

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

7.          return;

8.   

9.      dev = spi_new_device(master, bi);

10.    if (!dev)

11.        dev_err(master->dev.parent, "can't create new device for %s\n",

12.            bi->modalias);

13.}


说明:

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.   

7.      /* NOTE: caller did any chip->bus_num checks necessary.

8.       *

9.       * Also, unless we change the return value convention to use

10.     * error-or-pointer (not NULL-or-pointer), troubleshootability

11.     * suggests syslogged diagnostics are best here (ugh).

12.     */

13. 

14.    proxy = spi_alloc_device(master);

15.    if (!proxy)

16.        return NULL;

17. 

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

19. 

20.    proxy->chip_select = chip->chip_select;

21.    proxy->max_speed_hz = chip->max_speed_hz;

22.    proxy->mode = chip->mode;

23.    proxy->irq = chip->irq;

24.    strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));

25.    proxy->dev.platform_data = (void *) chip->platform_data;

26.    proxy->controller_data = chip->controller_data;

27.    proxy->controller_state = NULL;

28. 

29.    status = spi_add_device(proxy);

30.    if (status < 0) {

31.        spi_dev_put(proxy);

32.        return NULL;

33.    }

34. 

35.    return proxy;

36.}

37.EXPORT_SYMBOL_GPL(spi_new_device);

38. 

39.struct spi_device *spi_alloc_device(struct spi_master *master)

40.{

41.    struct spi_device    *spi;

42.    struct device        *dev = master->dev.parent;

43. 

44.    if (!spi_master_get(master))

45.        return NULL;

46. 

47.    spi = kzalloc(sizeof *spi, GFP_KERNEL);

48.    if (!spi) {

49.        dev_err(dev, "cannot alloc spi_device\n");

50.        spi_master_put(master);

51.        return NULL;

52.    }

53. 

54.    spi->master = master;

55.    spi->dev.parent = dev;

56.    spi->dev.bus = &spi_bus_type;

57.    spi->dev.release = spidev_release;

58.    device_initialize(&spi->dev);

59.    return spi;

60.}

61.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.   

7.      if (!gscs)

8.          return;

9.      status = gsc3280_spi_destroy_queue(gscs);

10.    if (status != 0)

11.        dev_err(&gscs->master->dev, "gsc3280_spi_remove: workqueue will not "

12.            "complete, message memory not freed\n");

13. 

14.#ifdef CONFIG_SPI_GSC3280_DMA

15.    if (gscs->dma_ops && gscs->dma_ops->dma_exit)

16.        gscs->dma_ops->dma_exit(gscs);

17.#endif

18. 

19.    gsc3280_enable_spi(gscs, GSC_SPI_DISABLE);

20.    free_irq(gscs->irq, gscs);

21.    iounmap(gscs->regs);

22.    spi_unregister_master(gscs->master);

23.}


说明:

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.   

7.      ret = gsc3280_spi_stop_queue(gscs);

8.      if (ret)

9.          return ret;

10.    gsc3280_enable_spi(gscs, GSC_SPI_DISABLE);

11.    return ret;

12.}


程序中首先停止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.   

7.      gsc3280_spi_hw_init(gscs);

8.      ret = gsc3280_start_queue(gscs);

9.      if (ret)

10.        dev_err(&gscs->master->dev, "fail to start queue (%d)\n", ret);

11.    return ret;

12.}

程序主要初始化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.   

8.      DBG("######gsc3280 spi bus setup start######\n");

9.      chip = spi_get_ctldata(spi);        /* Only alloc on first setup */

10.    if (!chip) {

11.        chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);

12.        if (!chip) {

13.            DBG("!!!!kzalloc error!\n");

14.            ret = -ENOMEM;

15.            goto exit;

16.        }

17.    }

18.    chip_info = spi->controller_data;

19.    /* chip_info doesn't always exist */

20.    if (chip_info) {

21.#ifdef CONFIG_GSC3280_SPI_DMA

22.        chip->poll_mode = chip_info->poll_mode;

23.        chip->enable_dma = chip_info->enable_dma;

24.#endif

25.        chip->pin_cs = chip_info->pin_cs;

26.        chip->cs_value = chip_info->cs_value;

27.        chip->bits_per_word = chip_info->bits_per_word;

28.        chip->lsb_flg = chip_info->lsb_flg;

29.        gpio_request(chip->pin_cs, spi->modalias);

30.        if (chip->cs_value == 0)

31.            gpio_direction_output(chip->pin_cs, 1);

32.        else

33.            gpio_direction_output(chip->pin_cs, 0);

34.    }

35.    if (spi->bits_per_word == 8) {

36.        chip->n_bytes = 1;

37.#ifdef CONFIG_GSC3280_SPI_DMA

38.        chip->dma_width = 1;

39.#endif

40.    } else if (spi->bits_per_word == 16) {

41.        chip->n_bytes = 2;

42.#ifdef CONFIG_GSC3280_SPI_DMA

43.        chip->dma_width = 2;

44.#endif

45.    } else {

46.        DBG("!!!!spi->bits_per_word = %d error!\n", spi->bits_per_word);

47.        ret = -EINVAL;

48.        goto exit;

49.    }

50.    if (!spi->max_speed_hz) {

51.        DBG("!!!!spi->max_speed_hz = %d, error!\n", spi->max_speed_hz);

52.        ret = -EINVAL;

53.        goto exit;

54.    }

55.    chip->speed_hz = spi->max_speed_hz;

56.    chip->cr = (chip->lsb_flg << GSC_SPI_CTL_BITS_NUM) | (spi->mode << GSC_SPI_CTL_MOD)

57.                | ((chip->bits_per_word - 1) << GSC_SPI_CTL_DSS);

58.    spi_set_ctldata(spi, chip);

59. 

60.exit:

61.    if (ret != 0)

62.        DBG("!!!!gsc3280 spi bus setup error!\n");

63.    else

64.        DBG("######gsc3280 spi bus setup success######\n");

65.    return ret;

66.}


说明:

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.   

7.      DBG("####gsc3280 spi transfer start####\n");

8.      if (gscs->queue_state == GSC_SPI_QUEUE_STOP) {

9.          DBG("!!!!queue is stop!\n");

10.        return -ESHUTDOWN;

11.    }

12.    msg->actual_length = 0;

13.    msg->status = -EINPROGRESS;

14.    msg->state = START_STATE;

15.    spin_lock_irqsave(&gscs->slock, flags);

16.    list_add_tail(&msg->queue, &gscs->queue);

17.    spin_unlock_irqrestore(&gscs->slock, flags);

18.    //writel(0x3f, (volatile unsigned int *)(0xbc04a000 + 0x38));    //max divid freq

19.    if (gscs->cur_transfer || gscs->cur_msg) {

20.        //DBG("gsc3280_spi_transfer: cur transfer or msg not empty\n");

21.    } else {

22.        //DBG("gsc3280_spi_transfer: no cur transfer and msg\n");

23.        queue_work(gscs->workqueue, &gscs->pump_messages);

24.    }

25.    DBG("####gsc3280 spi transfer success####\n");

26.    return 0;

27.}

 
说明:

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. 

11.    DBG("####gsc3280_spi_pump_messages####\n");

12.    if (list_empty(&gscs->queue) || (gscs->queue_state == GSC_SPI_QUEUE_STOP)) {

13.        if (gscs->queue_state == GSC_SPI_QUEUE_STOP)

14.            DBG("!!!!queue is stop!\n");

15.        else

16.            DBG("msg is finished!\n");

17.        gscs->busy = 0;

18.        return;

19.    }

20.    

21.    spin_lock_irqsave(&gscs->slock, flags);

22.    gscs->cur_msg = list_entry(gscs->queue.next, struct spi_message, queue);

23.    if (!gscs->cur_msg) {

24.        spin_unlock_irqrestore(&gscs->slock, flags);

25.        DBG("!!!!gsc3280_spi_pump_messages: current no msg!\n");

26.        return;

27.    }

28.    list_del_init(&gscs->cur_msg->queue);

29.    gscs->cur_msg->state = RUNNING_STATE;

30.    gscs->cur_chip = spi_get_ctldata(gscs->cur_msg->spi);

31.    gscs->n_bytes = gscs->cur_chip->n_bytes;

32.    gscs->busy = 1;

33.    spin_unlock_irqrestore(&gscs->slock, flags);

34. 

35.    DBG("cs select enable\n");

36.    if (gscs->cur_chip->cs_value == 0) {

37.        gpio_set_value(gscs->cur_chip->pin_cs, 0);

38.    }

39.    else

40.        gpio_set_value(gscs->cur_chip->pin_cs, 1);

41.    /* get first transfer */

42.    gscs->cur_transfer = list_entry(gscs->cur_msg->transfers.next, struct spi_transfer, transfer_list);

43.    if (!gscs->cur_transfer) {

44.        DBG("!!!!gsc3280_spi_pump_transfers: current no transfer!\n");

45.        return;

46.    }

47.    tasklet_schedule(&gscs->pump_transfers);

48.    return;

49.}


说明:

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.   

10.    //DBG("gsc3280_spi_pump_transfers\n");

11.    if (gscs->cur_msg->state == ERROR_STATE) {

12.        DBG("!!!!pump_transfers:cur msg state error!\n");

13.        gscs->cur_msg->status = -EIO;

14.        goto early_exit;

15.    }

16.    /* Handle end of message */

17.    if (gscs->cur_msg->state == DONE_STATE) {

18.        gscs->cur_msg->status = 0;

19.        goto early_exit;

20.    }

21.    /* Delay if requested at end of transfer*/

22.    if (gscs->cur_msg->state == RUNNING_STATE) {

23.        previous = list_entry(gscs->cur_transfer->transfer_list.prev, struct spi_transfer, transfer_list);

24.        if (previous->delay_usecs)

25.            udelay(previous->delay_usecs);

26.    }

27. 

28.#ifdef CONFIG_SPI_GSC3280_DMA

29.    gscs->dma_width = gscs->cur_chip->dma_width;

30.    gscs->rx_dma = gscs->cur_transfer->rx_dma;

31.    gscs->tx_dma = gscs->cur_transfer->tx_dma;

32.#endif

33. 

34.    /* Handle per transfer options for bpw and speed */

35.    if (gscs->cur_transfer->speed_hz) {

36.        if (gscs->cur_transfer->speed_hz != gscs->cur_chip->speed_hz) {

37.            if (gscs->cur_transfer->speed_hz > gscs->max_freq) {

38.                printk(KERN_ERR "SPI1: unsupported freq: %dHz\n", gscs->cur_transfer->speed_hz);

39.                gscs->cur_msg->status = -EIO;

40.                return;

41.            } else

42.                gscs->cur_chip->speed_hz = gscs->cur_transfer->speed_hz;

43.        }

44.    }

45.    if (gscs->cur_transfer->bits_per_word) {

46.        switch (gscs->cur_transfer->bits_per_word) {

47.        case 8:

48.        case 16:

49.            gscs->n_bytes = gscs->cur_transfer->bits_per_word >> 3;

50.#ifdef CONFIG_SPI_GSC3280_DMA

51.            gscs->dma_width = gscs->n_bytes;

52.#endif

53.            break;

54.        default:

55.            printk(KERN_ERR "SPI1: unsupported bits:" "%db\n", gscs->cur_transfer->bits_per_word);

56.            gscs->cur_msg->status = -EIO;

57.            return;

58.        }

59.    }

60. 

61.    clk_div = gscs->max_freq / gscs->cur_transfer->speed_hz;

62.    clk_div = clk_div / 2 - 1;

63.    if (clk_div < 0)

64.        clk_div = 0;

65.    gscs->cur_chip->clk_div = (u16)clk_div;

66. 

67.    cr = gscs->cur_chip->cr | GSC_SPI_CTL_EN;

68.    writel(cr, gscs->regs + GSC_SPI_CTRL);    /* enable spi */

69.    writel(gscs->cur_chip->clk_div, gscs->regs + GSC_SPI_SEABAUR);

70.    

71.    spin_lock_irqsave(&gscs->slock, flags);

72.    //gscs->n_bytes = gscs->cur_chip->n_bytes;

73.    gscs->tx = (void *)gscs->cur_transfer->tx_buf;

74.    gscs->tx_end = gscs->tx + gscs->cur_transfer->len;

75.    gscs->rx = gscs->cur_transfer->rx_buf;

76.    gscs->rx_end = gscs->rx + gscs->cur_transfer->len;

77.    gscs->cs_change = gscs->cur_transfer->cs_change;

78.    gscs->len = gscs->cur_transfer->len;

79.    spin_unlock_irqrestore(&gscs->slock, flags);

80.    

81.    imask |= SPI_INT_TX_H_OVER | SPI_INT_RX_L_OVER | SPI_INT_RX_H_OVER | SPI_INT_RX_FULL;

82.    if (gscs->tx != NULL) {

83.        imask |= SPI_INT_TX_EMPTY;

84.    }

85.    gsc3280_spi_umask_intr(gscs, imask);

86. 

87.#ifdef CONFIG_GSC3280_SPI_DMA

88.    /* Check if current transfer is a DMA transaction */

89.    gscs->dma_mapped = map_dma_buffers(gscs);

90.    /* Interrupt mode we only need set the TXEI IRQ, as TX/RX always happen syncronizely */

91.    if (!gscs->dma_mapped && !gscs->cur_chip->poll_mode) {

92.        //int templen = gscs->len / gscs->n_bytes;

93.        //txint_level = gscs->fifo_len / 2;

94.        //txint_level = (templen > txint_level) ? txint_level : templen;

95.    }

96.    if (gscs->dma_mapped)

97.        gscs->dma_ops->dma_transfer(gscs, cs_change);

98.    if (gscs->cur_chip->poll_mode)

99.        gsc3280_spi_poll_transfer(gscs);

100.         #endif

101.             

102.             return;

103.             

104.         early_exit:

105.             gsc3280_spi_giveback(gscs);

106.             return;

107.         }


说明:

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. 

14.    if (!irq_status ) {

15.        DBG("!!!!gsc3280_spi_irq: no irq!\n");

16.        return IRQ_NONE;

17.    }

18.    if (!gscs->cur_msg) {

19.        DBG("!!!!gsc3280_spi_irq: no msg!\n");

20.        gsc3280_spi_mask_intr(gscs, SPI_INT_TX_EMPTY | SPI_INT_RX_FULL);

21.        return IRQ_HANDLED;

22.    }

23.    if (irq_status & (SPI_INT_TX_H_OVER | SPI_INT_RX_L_OVER | SPI_INT_RX_H_OVER)) {

24.        DBG("!!!!gsc3280_spi_irq: fifo overrun/underrun!\n");

25.        __raw_writew(0x0e, gscs->regs + GSC_SPI_ISR);

26.        gscs->cur_msg->state = ERROR_STATE;

27.        gscs->cur_msg->status = -EIO;

28.        queue_work(gscs->workqueue, &gscs->pump_messages);

29.        return IRQ_HANDLED;

30.    }

31.    if (irq_status & SPI_INT_RX_FULL) {

32.        spi_gsc_read(gscs);

33.        return IRQ_HANDLED;

34.    }

35.    if (irq_status & SPI_INT_TX_EMPTY) {

36.        spi_gsc_write(gscs);

37.    }

38.    return IRQ_HANDLED;

39.}

 
说明:

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

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

3) 判断是否是错误中断,包括溢出等,如果是,屏蔽中断,退出中断。

4) 如果是接收满中断,则首先接收数据。然后退出中断。

5) 如果是发送空中断,则发送数据,发送完成后,退出中断。

现在看下发送数据函数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.   

7.      //DBG("max = %d, gscs->n_bytes = 0x%x", max, gscs->n_bytes);

8.      spin_lock_irqsave(&gscs->slock, flags);

9.      while (max--) {

10.        if (gscs->n_bytes == 1)

11.            txw = *(u8 *)(gscs->tx);

12.        else

13.            txw = *(u16 *)(gscs->tx);

14.        DBG("txw = 0x%x\n", txw);

15.        writel(txw, gscs->regs + GSC_SPI_DA_S);

16.        gscs->tx += gscs->n_bytes;

17.    }

18.    spin_unlock_irqrestore(&gscs->slock, flags);

19.}

20.static void spi_gsc_write(struct gsc3280_spi *gscs)

21.{

22.    //DBG("spi_gsc_write\n");

23.    gsc3280_spi_mask_intr(gscs, GSC_SPI_SR_MASK);

24.    gsc3280_writer(gscs);

25.    if (gscs->tx_end == gscs->tx) {

26.        gsc3280_spi_xfer_done(gscs);

27.    }

28.    else {

29.        gsc3280_spi_umask_intr(gscs, GSC_SPI_SR_MASK);

30.    }

31.}


说明:

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.   

6.      if (trans->transfer_list.next != &msg->transfers) {

7.          gscs->cur_transfer = list_entry(trans->transfer_list.next, struct spi_transfer, transfer_list);

8.          return RUNNING_STATE;

9.      } else

10.        return DONE_STATE;

11.}

12.static void gsc3280_spi_xfer_done(struct gsc3280_spi *gscs)

13.{

14.    //DBG("gsc3280_spi_xfer_done\n");

15.    //DBG("irq_status = 0x%x\n", __raw_readw(gscs->regs + GSC_SPI_ISR));

16.    //DBG("imsr = 0x%x\n", __raw_readl(gscs->regs + GSC_SPI_IMSR));

17.    /* Update total byte transferred return count actual bytes read */

18.    gscs->cur_msg->actual_length += gscs->len;

19.    /* Move to next transfer */

20.    gscs->cur_msg->state = gsc3280_spi_next_transfer(gscs);

21.    if (gscs->cur_msg->state == DONE_STATE) {

22.        /* Handle end of message */

23.        gscs->cur_msg->status = 0;

24.        gsc3280_spi_giveback(gscs);

25.    } else {

26.        tasklet_schedule(&gscs->pump_transfers);

27.    }

28.}       


说明:

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.   

6.      DBG("gsc3280_spi_giveback\n");

7.      //DBG("irq_status = 0x%x\n", readl(gscs->regs + GSC_SPI_ISR));

8.      gsc3280_spi_mask_intr(gscs, GSC_SPI_SR_MASK);

9.      DBG("cs select disable\n");

10.    if (gscs->cur_chip->cs_value == 0) {

11.        gpio_set_value(gscs->cur_chip->pin_cs, 1);

12.    }

13.    else

14.        gpio_set_value(gscs->cur_chip->pin_cs, 0);

15.    gscs->cur_msg->state = NULL;

16.    if (gscs->cur_msg->complete)

17.        gscs->cur_msg->complete(gscs->cur_msg->context);

18.    

19.    spin_lock_irqsave(&gscs->slock, flags);

20.    gscs->cur_msg = NULL;

21.    gscs->cur_transfer = NULL;

22.    gscs->prev_chip = gscs->cur_chip;

23.    gscs->cur_chip = NULL;

24.    gscs->busy = 0;

25.#ifdef CONFIG_SPI_GSC3280_DMA

26.    gscs->dma_mapped = 0;

27.#endif

28.    spin_unlock_irqrestore(&gscs->slock, flags);

29.    queue_work(gscs->workqueue, &gscs->pump_messages);

30.}


说明:

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.   

7.      //DBG("max = %d, gscs->n_bytes = 0x%x", max, gscs->n_bytes);

8.      spin_lock_irqsave(&gscs->slock, flags);

9.      while (max--) {

10.        rxw = readl(gscs->regs + GSC_SPI_DA_S);

11.        DBG("rxw = 0x%x\n", rxw);

12.        if (gscs->n_bytes == 1)

13.            *(u8 *)(gscs->rx) = (u8)rxw;

14.        else

15.            *(u16 *)(gscs->rx) = rxw;

16.        gscs->rx += gscs->n_bytes;

17.    }

18.    spin_unlock_irqrestore(&gscs->slock, flags);

19.}

20.static void spi_gsc_read(struct gsc3280_spi *gscs)

21.{

22.    //DBG("spi_gsc_read\n");

23.    gsc3280_reader(gscs);

24.    if (gscs->rx_end == gscs->rx) {

25.        gsc3280_spi_xfer_done(gscs);

26.    }

27.}


说明:

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

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







原文参见:http://blog.chinaunix.net/uid-25445243-id-3987576.html