SPI子系统

一、SPI子系统模型


三个组成部分:
SPI核心:连通了SPI客户驱动、SPI主控制器驱动
SPI控制器驱动:驱动芯片中的SPI控制器
SPI的FLASH(客户驱动)

二、SPI控制器驱动分析
static int __init s3c24xx_spi_probe(struct platform_device *pdev)
{
    struct s3c2410_spi_info *pdata;
    struct s3c24xx_spi *hw;
    struct spi_master *master;
    struct resource *res;
    int err = 0;

    master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
    if (master == NULL) {
        dev_err(&pdev->dev, "No memory for spi_master\n");
        err = -ENOMEM;
        goto err_nomem;
    }

    hw = spi_master_get_devdata(master);
    memset(hw, 0, sizeof(struct s3c24xx_spi));

    hw->master = spi_master_get(master);
    hw->pdata = pdata = pdev->dev.platform_data;
    hw->dev = &pdev->dev;

    if (pdata == NULL) {
        dev_err(&pdev->dev, "No platform data supplied\n");
        err = -ENOENT;
        goto err_no_pdata;
    }

    platform_set_drvdata(pdev, hw);
    init_completion(&hw->done);

    /* setup the master state. */

    master->num_chipselect = hw->pdata->num_cs;
    master->bus_num = pdata->bus_num;

    /* setup the state for the bitbang driver */

    hw->bitbang.master = hw->master;
    hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;
    hw->bitbang.chipselect = s3c24xx_spi_chipsel;
    hw->bitbang.txrx_bufs = s3c24xx_spi_txrx;
    hw->bitbang.master->setup = s3c24xx_spi_setup;

    dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);

    /* find and map our resources */

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (res == NULL) {
        dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
        err = -ENOENT;
        goto err_no_iores;
    }

    hw->ioarea = request_mem_region(res->start, (res->end - res->start)+1,
                    pdev->name);                                                                    //设置硬件资源

    if (hw->ioarea == NULL) {
        dev_err(&pdev->dev, "Cannot reserve region\n");
        err = -ENXIO;
        goto err_no_iores;
    }

    hw->regs = ioremap(res->start, (res->end - res->start)+1);                                      //获取映射地址
    if (hw->regs == NULL) {
        dev_err(&pdev->dev, "Cannot map IO\n");
        err = -ENXIO;
        goto err_no_iomap;
    }

    hw->irq = platform_get_irq(pdev, 0);                                                            //获取中断号
    if (hw->irq < 0) {
        dev_err(&pdev->dev, "No IRQ specified\n");
        err = -ENOENT;
        goto err_no_irq;
    }

    err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw);                                 //注册中断
    if (err) {
        dev_err(&pdev->dev, "Cannot claim IRQ\n");
        goto err_no_irq;
    }

    hw->clk = clk_get(&pdev->dev, "spi");
    if (IS_ERR(hw->clk)) {
        dev_err(&pdev->dev, "No clock for device\n");
        err = PTR_ERR(hw->clk);
        goto err_no_clk;
    }

    /* setup any gpio we can */

    if (!pdata->set_cs) {
        if (pdata->pin_cs < 0) {
            dev_err(&pdev->dev, "No chipselect pin\n");
            goto err_register;
        }

        err = gpio_request(pdata->pin_cs, dev_name(&pdev->dev));
        if (err) {
            dev_err(&pdev->dev, "Failed to get gpio for cs\n");
            goto err_register;
        }

        hw->set_cs = s3c24xx_spi_gpiocs;
        gpio_direction_output(pdata->pin_cs, 1);
    } else
        hw->set_cs = pdata->set_cs;

    s3c24xx_spi_initialsetup(hw);                                                                    //初始化部分

    /* register our spi controller */

    err = spi_bitbang_start(&hw->bitbang);                                                           //完成注册
    if (err) {
        dev_err(&pdev->dev, "Failed to register SPI master\n");
        goto err_register;
    }

    return 0;

 err_register:
    if (hw->set_cs == s3c24xx_spi_gpiocs)
        gpio_free(pdata->pin_cs);

    clk_disable(hw->clk);
    clk_put(hw->clk);

 err_no_clk:
    free_irq(hw->irq, hw);

 err_no_irq:
    iounmap(hw->regs);

 err_no_iomap:
    release_resource(hw->ioarea);
    kfree(hw->ioarea);

 err_no_iores:
 err_no_pdata:
    spi_master_put(hw->master);;

 err_nomem:
    return err;
}
s3c24xx_spi_initialsetup:
static void s3c24xx_spi_initialsetup(struct s3c24xx_spi *hw)
{
    /* for the moment, permanently enable the clock */

    clk_enable(hw->clk);

    /* program defaults into the registers */

    writeb(0xff, hw->regs + S3C2410_SPPRE);
    writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN);
    writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON);                                       //设置成中断触发方式

    if (hw->pdata) {
        if (hw->set_cs == s3c24xx_spi_gpiocs)
            gpio_direction_output(hw->pdata->pin_cs, 1);

        if (hw->pdata->gpio_setup)
            hw->pdata->gpio_setup(hw->pdata, 1);
    }
}
中断函数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. }

转载于:https://www.cnblogs.com/ch122633/p/7363291.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值