SPI驱动分析
zynq SPI控制器理解记录
如下:spi一般都由一下两个不通的模式组合成四个模式:
自动/手到发送数据:
自动:当TxFIFO有数据就进行发送;无数据则停止发送。
手动:通过使能发送位进行数据的发送。
自动/手动控制CS使能信号:
自动:当TXFIFO有数据的时候就自动使能,Txfifo数据传输完成之后就不使能
手动:通过使能位来软件控制片选信号的使能
SPI总线
一个SOC有多个spi控制器,这些控制器都是连接在SPI总线上,linux采用SPI总线来管理这些设备。
其中driver/spi/spi.c中实现了对spi总线的注册,同时为上层设备提供了统一的接口,以下是spi.c中初始化代码
static int __init spi_init(void)
{
int status;
buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
if (!buf) {
status = -ENOMEM;
goto err0;
}
status = bus_register(&spi_bus_type);
if (status < 0)
goto err1;
status = class_register(&spi_master_class);
if (status < 0)
goto err2;
return 0;
err2:
bus_unregister(&spi_bus_type);
err1:
kfree(buf);
buf = NULL;
err0:
return status;
}
/* board_info is normally registered in arch_initcall(),
* but even essential drivers wait till later
*
* REVISIT only boardinfo really needs static linking. the rest (device and
* driver registration) _could_ be dynamically linked (modular) ... costs
* include needing to have boardinfo data structures be much more public.
*/
postcore_initcall(spi_init);
其中postcore_initcall(*)是一个宏,内核起来的时候会执行宏里面定义的函数。
status = bus_register(&spi_bus_type);实现对SPI总线的注册
SPI Master控制器驱动
SPI Master控制器是SOC内部的控制器,一般一个SOC有多个控制器,使用同一个控制器驱动,对应的代码在drivers/spi/spi-xxx.c。每一个文件对应着不通的spi控制器驱动,本文以spi-candance.c为例
/**
* cdns_spi_probe - Probe method for the SPI driver
* @pdev: Pointer to the platform_device structure
*
* This function initializes the driver data structures and the hardware.
*
* Return: 0 on success and error value on error
*/
static int cdns_spi_probe(struct platform_device *pdev)
{
int ret = 0, irq;
struct spi_master *master;
struct cdns_spi *xspi;
struct resource *res;
u32 num_cs;
//pr_info("cdns_spi_probe....\r\n");
//pr_info("sizeof(*xspi)=%d\n", sizeof(*xspi));
master = spi_alloc_master(&pdev->dev, sizeof(*xspi));
if (master == NULL)
return -ENOMEM;
xspi = spi_master_get_devdata(master);
master->dev.of_node = pdev->dev.of_node;
platform_set_drvdata(pdev, master);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
//pr_info("addr:0x%x\n", res->start);
xspi->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(xspi->regs)) {
ret = PTR_ERR(xspi->reg