一、SPI子系统模型

SPI子系统-LMLPHP



三个组成部分:

SPI核心:连通了SPI客户驱动、SPI主控制器驱动

SPI控制器驱动:驱动芯片中的SPI控制器

SPI的FLASH(客户驱动)



二、SPI控制器驱动分析

  1. static int __init s3c24xx_spi_probe(struct platform_device *pdev)
  2. {
  3. struct s3c2410_spi_info *pdata;
  4. struct s3c24xx_spi *hw;
  5. struct spi_master *master;
  6. struct resource *res;
  7. int err = 0;
  8. master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
  9. if (master == NULL) {
  10. dev_err(&pdev->dev, "No memory for spi_master\n");
  11. err = -ENOMEM;
  12. goto err_nomem;
  13. }
  14. hw = spi_master_get_devdata(master);
  15. memset(hw, 0, sizeof(struct s3c24xx_spi));
  16. hw->master = spi_master_get(master);
  17. hw->pdata = pdata = pdev->dev.platform_data;
  18. hw->dev = &pdev->dev;
  19. if (pdata == NULL) {
  20. dev_err(&pdev->dev, "No platform data supplied\n");
  21. err = -ENOENT;
  22. goto err_no_pdata;
  23. }
  24. platform_set_drvdata(pdev, hw);
  25. init_completion(&hw->done);
  26. /* setup the master state. */
  27. master->num_chipselect = hw->pdata->num_cs;
  28. master->bus_num = pdata->bus_num;
  29. /* setup the state for the bitbang driver */
  30. hw->bitbang.master = hw->master;
  31. hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;
  32. hw->bitbang.chipselect = s3c24xx_spi_chipsel;
  33. hw->bitbang.txrx_bufs = s3c24xx_spi_txrx;
  34. hw->bitbang.master->setup = s3c24xx_spi_setup;
  35. dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);
  36. /* find and map our resources */
  37. res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
  38. if (res == NULL) {
  39. dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
  40. err = -ENOENT;
  41. goto err_no_iores;
  42. }
  43. hw->ioarea = request_mem_region(res->start, (res->end - res->start)+1,
  44. pdev->name);                                                                    //设置硬件资源
  45. if (hw->ioarea == NULL) {
  46. dev_err(&pdev->dev, "Cannot reserve region\n");
  47. err = -ENXIO;
  48. goto err_no_iores;
  49. }
  50. hw->regs = ioremap(res->start, (res->end - res->start)+1);                                      //获取映射地址
  51. if (hw->regs == NULL) {
  52. dev_err(&pdev->dev, "Cannot map IO\n");
  53. err = -ENXIO;
  54. goto err_no_iomap;
  55. }
  56. hw->irq = platform_get_irq(pdev, 0);                                                            //获取中断号
  57. if (hw->irq < 0) {
  58. dev_err(&pdev->dev, "No IRQ specified\n");
  59. err = -ENOENT;
  60. goto err_no_irq;
  61. }
  62. err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw);                                 //注册中断
  63. if (err) {
  64. dev_err(&pdev->dev, "Cannot claim IRQ\n");
  65. goto err_no_irq;
  66. }
  67. hw->clk = clk_get(&pdev->dev, "spi");
  68. if (IS_ERR(hw->clk)) {
  69. dev_err(&pdev->dev, "No clock for device\n");
  70. err = PTR_ERR(hw->clk);
  71. goto err_no_clk;
  72. }
  73. /* setup any gpio we can */
  74. if (!pdata->set_cs) {
  75. if (pdata->pin_cs < 0) {
  76. dev_err(&pdev->dev, "No chipselect pin\n");
  77. goto err_register;
  78. }
  79. err = gpio_request(pdata->pin_cs, dev_name(&pdev->dev));
  80. if (err) {
  81. dev_err(&pdev->dev, "Failed to get gpio for cs\n");
  82. goto err_register;
  83. }
  84. hw->set_cs = s3c24xx_spi_gpiocs;
  85. gpio_direction_output(pdata->pin_cs, 1);
  86. } else
  87. hw->set_cs = pdata->set_cs;
  88. s3c24xx_spi_initialsetup(hw);                                                                    //初始化部分
  89. /* register our spi controller */
  90. err = spi_bitbang_start(&hw->bitbang);                                                           //完成注册
  91. if (err) {
  92. dev_err(&pdev->dev, "Failed to register SPI master\n");
  93. goto err_register;
  94. }
  95. return 0;
  96. err_register:
  97. if (hw->set_cs == s3c24xx_spi_gpiocs)
  98. gpio_free(pdata->pin_cs);
  99. clk_disable(hw->clk);
  100. clk_put(hw->clk);
  101. err_no_clk:
  102. free_irq(hw->irq, hw);
  103. err_no_irq:
  104. iounmap(hw->regs);
  105. err_no_iomap:
  106. release_resource(hw->ioarea);
  107. kfree(hw->ioarea);
  108. err_no_iores:
  109. err_no_pdata:
  110. spi_master_put(hw->master);;
  111. err_nomem:
  112. return err;
  113. }

s3c24xx_spi_initialsetup:

  1. static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw)
  2. {
  3. /* for the moment, permanently enable the clock */
  4. clk_enable(hw->clk);
  5. /* program defaults into the registers */
  6. writeb(0xff, hw->regs + S3C2410_SPPRE);
  7. writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN);
  8. writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON);                                       //设置成中断触发方式
  9. if (hw->pdata) {
  10. if (hw->set_cs == s3c24xx_spi_gpiocs)
  11. gpio_direction_output(hw->pdata->pin_cs, 1);
  12. if (hw->pdata->gpio_setup)
  13. hw->pdata->gpio_setup(hw->pdata, 1);
  14. }
  15. }

中断函数s3c24xx_spi_irq:

  1. static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
  2. {
  3. struct s3c24xx_spi *hw = dev;
  4. unsigned int spsta = readb(hw->regs + S3C2410_SPSTA);
  5. unsigned int count = hw->count;
  6. if (spsta & S3C2410_SPSTA_DCOL) {
  7. dev_dbg(hw->dev, "data-collision\n");
  8. complete(&hw->done);
  9. goto irq_done;
  10. }
  11. if (!(spsta & S3C2410_SPSTA_READY)) {
  12. dev_dbg(hw->dev, "spi not ready for tx?\n");
  13. complete(&hw->done);
  14. goto irq_done;
  15. }
  16. hw->count++;
  17. if (hw->rx)
  18. hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);
  19. count++;
  20. if (count < hw->len)                                                                            //判断长度来收发?
  21. writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);
  22. else
  23. complete(&hw->done);
  24. irq_done:
  25. return IRQ_HANDLED;
  26. }
05-11 22:03