三个组成部分:
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
");
-
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
");
-
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
", &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
");
-
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
");
-
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
");
-
err = -ENXIO;
-
goto err_no_iomap;
-
}
-
-
hw->irq = platform_get_irq(pdev, 0); //获取中断号
-
if (hw->irq < 0) {
-
dev_err(&pdev->dev, "No IRQ specified
");
-
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
");
-
goto err_no_irq;
-
}
-
-
hw->clk = clk_get(&pdev->dev, "spi");
-
if (IS_ERR(hw->clk)) {
-
dev_err(&pdev->dev, "No clock for device
");
-
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
");
-
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
");
-
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
");
-
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;
- }
-
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);
-
}
- }
-
static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
-
{
-
struct s3c24xx_spi *hw = dev;
-
unsigned int spsta = readb(hw->regs + S3C2410_SPSTA);
-
unsigned int count = hw->count;
-
-
if (spsta & S3C2410_SPSTA_DCOL) {
-
dev_dbg(hw->dev, "data-collision
");
-
complete(&hw->done);
-
goto irq_done;
-
}
-
-
if (!(spsta & S3C2410_SPSTA_READY)) {
-
dev_dbg(hw->dev, "spi not ready for tx?
");
-
complete(&hw->done);
-
goto irq_done;
-
}
-
-
hw->count++;
-
-
if (hw->rx)
-
hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);
-
-
count++;
-
-
if (count < hw->len) //判断长度来收发?
-
writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);
-
else
-
complete(&hw->done);
-
-
irq_done:
-
return IRQ_HANDLED;
- }