Chinaunix首页 | 论坛 | 博客
  • 博客访问: 473740
  • 博文数量: 223
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2145
  • 用 户 组: 普通用户
  • 注册时间: 2014-03-01 10:23
个人简介

该坚持的时候坚持,该妥协的时候妥协,该放弃的时候放弃

文章分类

全部博文(223)

文章存档

2017年(56)

2016年(118)

2015年(3)

2014年(46)

我的朋友

分类: 嵌入式

2016-12-15 23:01:25

一、SPI子系统模型


三个组成部分:
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. }

阅读(632) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~