本文基于 linux4.6.69 + ti am335x 分析
1、linux 下 spi driver 的代码文件
下面两个文件是 TI 平台 spi 控制器驱动 , 主要和SOC的相关的寄存器配置有关,和具体的外设 SPI设备进行物理上的通信。
drivers/spi/spi-omap2-mcspi.c (master)
drivers/spi/spi-omap2-mcspi-slave.c (slave)
下面的 spi.c 主要是注册spi bus , 一个SOC的 spi 控制器对应一个 spi bus , 对应一个 spi_master
drivers/spi/spi.c
下面的 spidev.c 属于 protocol drivers, 属于一种通用的spi 驱动,可选的,如果你要使用其他driver,比如 spi-flash , FRAM ,或者bitbang,也是可以的, 如果你在设备树中添加的spi 设备的 compatible=“spidev” 的话,匹配成功之后,就会产生 /dev/spidevX.Y 设备节点,通过这个节点可以和应用层进行交互
drivers/spi/spidev.c
spidev_read
(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
spidev_write
(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
spidev_ioctl
(struct file *filp, unsigned int cmd, unsigned long arg)
static struct spi_driver spidev_spi_driver = {
.driver = {
.name = "spidev",
.of_match_table = of_match_ptr(spidev_dt_ids),
.acpi_match_table = ACPI_PTR(spidev_acpi_ids),
},
.probe = spidev_probe,
.remove = spidev_remove,
};
下面的 spi-gpio.c spi-bitbang.c 属于 protocol drivers ,是用gpio来模拟spi 的一种驱动,这种情况是当SOC的spi 控制器被占用或者不够使用时,才会用到这个驱动,需要3-4个gpio 。
如果你在设备树中添加的spi 设备的 compatible=“spi-gpio” 的话, 才会使用这个驱动,这个后续再讲解此驱动的实现方式。
drivers/spi/spi-bitbang.c 模拟 控制器驱动
drivers/spi/spi-gpio.c protocol drivers,类似于spidev.c
比如我们有用到一个 128K 的SPI接口的FRAM,就可以自己写一个driver ,不用上面的spidev bitbang等驱动 ,记住一个 spi_device 对应 一个 spi_driver 就可以了, 为了简单使用,使用了sysfs,
fm25_bin_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
spi_read()
}
fm25_bin_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t off, size_t count)
{
spi_write()
}
static int fm25_probe(struct spi_device *spi)
{
sysfs_bin_attr_init(&fm25->bin);
fm25->bin.read = fm25_bin_read;
fm25->bin.write = fm25_bin_write;
sysfs_create_bin_file(&spi->dev.kobj, &fm25->bin);
}
static const struct of_device_id fm25_of_match[] = {
{ .compatible = "cypress,fm25", },
{ }
};
MODULE_DEVICE_TABLE(of, fm25_of_match);
static struct spi_driver fm25_driver = {
.driver = {
.name = "fm25",
.of_match_table = fm25_of_match,
},
.probe = fm25_probe,
.remove = fm25_remove,
};
其中 spi_read spi_write 在 spi.h 中
驱动层读写 spi 从设备的接口,可以被 spidev 或者 自己写的其他驱动比如FRAM的驱动调用,并不会与应用层交互。
spi_write(struct spi_device *spi, const void *buf, size_t len)
spi_read(struct spi_device *spi, void *buf, size_t len)
//spi.c
int spi_write_then_read
(struct spi_device *spi,
const void *txbuf, unsigned n_tx,
void *rxbuf, unsigned n_rx)
其实这三个接口,都是通过下面的接口实现的
spi_message_init(&m);
spi_message_add_tail(&t, &m);
spidev_sync(spidev, &m);
2、spi 框架
下面是使用SOC spi 控制器驱动框架
下面是 用gpio模拟spi ,bit-bang 框架