1、前言
- 学习参考书籍以及本文涉及的示例程序:李山文的《Linux驱动开发进阶》
- 本文属于个人学习后的总结,不太具备教学功能。
2、SPI总线注册
驱动源码文件:drivers/spi/spi.c,负责注册spi总线和spi设备以及spi控制器设备:
上面的spi_init是整个总线注册的入口,但是没有spi_exit出口函数。这一点很多驱动的总线也是这样,只有注册,没有注销,这是因为总线会一直存在,只有当系统关闭时,总线才不需要了。相关的spi总线结构体如下:
除了注册bus,还注册了class:
相关class结构体为:
注册类后,会在/sys/class目录下生成spi_master文件夹,而dev_groups会在/sys/class/spi_master目录下生成相关的属性文件分组目录。
3、SPI设备注册
在注册SPI控制器驱动时,此时会扫描设备树中的spi控制器节点,找到匹配的,则会注册成设备,并且会将控制器设备树节点下的子节点全部注册为spi设备。如下代码所示,spi注册控制器时,在最后会调用of_register_spi_devices函数来解析设备树,然后将其注册为spi设备。
int spi_register_controller(struct spi_controller *ctlr)
{
...
/* Register devices from the device tree and ACPI */
of_register_spi_devices(ctlr); // 将spi子设备注册进spi总线
acpi_register_spi_devices(ctlr);
return status;
...
}
4、SPI驱动注册
SPI驱动分为控制器驱动和设备驱动,其中控制器驱动又称为BSP驱动程序,该驱动程序一般由芯片原厂的驱动工程师来编写,而设备驱动程序指对芯片的外部设备来编写驱动。
先看SPI控制器驱动的注册,该驱动注册由platform总线注册,这是因为在SPI控制器驱动注册前,SPI的设备驱动无法注册,原因就是SPI子设备驱动的注册依赖于SPI控制器驱动,只有当SPI控制器驱动注册完毕后,module_spi_driver宏才能使用(实际上是spi_register_driver和spi_unregister_driver函数)。所以SPI控制器驱动注册只能依靠platform平台总线注册,因为platform平台总线驱动编译到内核中的,一定会注册, 即module_platform_driver宏一定是可以使用的。
5、SPI BSP驱动
spi bsp驱动其实就是编写spi的控制器驱动。linux中spi控制器被抽象为spi_master或者spi_controller,在bsp中,我们常用spi_master,结构体如下:
struct spi_controller {
struct device dev;
struct list_head list;
s16 bus_num;
u16 num_chipselect;
u16 dma_alignment;
u32 mode_bits;
u32 buswidth_override_bits;
u32 bits_per_word_mask;
#define SPI_BPW_MASK(bits) BIT((bits) - 1)
#define SPI_BPW_RANGE_MASK(min, max) GENMASK((max) - 1, (min) - 1)
u32 min_speed_hz;
u32 max_speed_hz;
u16 flags;
#define SPI_CONTROLLER_HALF_DUPLEX BIT(0) /* can't do full duplex */
#define SPI_CONTROLLER_NO_RX BIT(1) /* can't do buffer read */
#define SPI_CONTROLLER_NO_TX BIT(2) /* can't do buffer write */
#define SPI_CONTROLLER_MUST_RX BIT(3) /* requires rx */
#define SPI_CONTROLLER_MUST_TX BIT(4) /* requires tx */
#define SPI_MASTER_GPIO_SS BIT(5) /* GPIO CS must select slave */
bool slave;
size_t (*max_transfer_size)(struct spi_device *spi);
size_t (*max_message_size)(struct spi_device *spi);
struct mutex io_mutex;
spinlock_t bus_lock_spinlock;
struct mutex bus_lock_mutex;
bool bus_lock_flag;
int (*setup)(struct spi_device *spi);
int (*set_cs_timing)(struct spi_device *spi, struct spi_delay *setup,
struct spi_delay *hold, struct spi_delay *inactive);
int (*transfer)(struct spi_device *spi,
struct spi_message *mesg);
void (*cleanup)(struct spi_device *spi);
bool (*can_dma)(struct spi_controller *ctlr,
struct spi_device *spi,
struct spi_transfer *xfer);
bool queued;
struct kthread_worker *kworker;
struct kthread_work pump_messages;
spinlock_t queue_lock;
struct list_head queue;
struct spi_message *cur_msg;
bool idling;
bool busy;
bool running;
bool rt;
bool auto_runtime_pm;
bool cur_msg_prepared;
bool cur_msg_mapped;
bool last_cs_enable;
bool last_cs_mode_high;
bool fallback;
struct completion xfer_completion;
size_t max_dma_len;
int (*prepare_transfer_hardware)(struct spi_controller *ctlr);
int (*transfer_one_message)(struct spi_controller *ctlr,
struct spi_message *mesg);
int (*unprepare_transfer_hardware)(struct spi_controller *ctlr);
int (*prepare_message)(struct spi_controller *ctlr,
struct spi_message *message);
int (*unprepare_message)(struct spi_controller *ctlr,
struct spi_message *message);
int (*slave_abort)(struct spi_controller *ctlr);
void (*set_cs)(struct spi_device *spi, bool enable);
int (*transfer_one)(struct spi_controller *ctlr, struct spi_device *spi,
struct spi_transfer *transfer);
void (*handle_err)(struct spi_controller *ctlr,
struct spi_message *message);
const struct spi_controller_mem_ops *mem_ops;
struct spi_delay cs_setup;
struct spi_delay cs_hold;
struct spi_delay cs_inactive;
int *cs_gpios;
struct gpio_desc **cs_gpiods;
bool use_gpio_descriptors;
#ifdef __GENKSYMS__
u8 unused_native_cs;
u8 max_native_cs;
#else
s8 unused_native_cs;
s8 max_native_cs;
#endif
struct spi_statistics statistics;
struct dma_chan *dma_tx;
struct dma_chan *dma_rx;
void *dummy_rx;
void *dummy_tx;
int (*fw_translate_cs)(struct spi_controller *ctlr, unsigned cs);
bool ptp_sts_supported;
unsigned long irq_flags;
ANDROID_KABI_RESERVE(1);
ANDROID_KABI_RESERVE(2);
};
以下列出几个比较重要字段的解释,后面会重点看看transfer_one_message字段,该字段实现真实数据的传输:
linux提供了一个函数来分配一个spi控制器:
static inline struct spi_controller *spi_alloc_master(struct device *host,
unsigned int size)
{
return __spi_alloc_controller(host, size, false);
}
然后使用如下函数注册:
int devm_spi_register_controller(struct device *dev,
struct spi_controller *ctlr)
对于bsp而言,在使用前必须开启spi时钟。如下所示,设备树中spi时钟属性,用来指定时钟源:
spi bsp示例程序可以参考:李山文的《Linux驱动开发进阶》spi子系统示例程序。
下面贴出dummy-spimaster.c
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/spi/spi.h>
#include <linux/sysfs.h>
#include <linux/slab.h>
static int dummy_spimaster_setup(struct spi_device *spi)
{
int ret = 0;
if(spi->chip_select >= spi->master->num_chipselect)
{
printk(KERN_INFO " invalid chip_select\n");
return -1;
}
return ret;
}
static void dummy_spimaster_set_cs(struct spi_device *spi, bool enable)
{
if (enable) {
//set IO(spi->chip_select) high level
printk(KERN_INFO "spi cs[%d]: high\n", spi->chip_select);
}
else {
//set IO(spi->chip_select) low level
printk(KERN_INFO "spi cs[%d]: low\n", spi->chip_select);
}
}
static int dummy_spimaster_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *tfr)
{
int bytes;
unsigned char *rx_buff = tfr->rx_buf;
const unsigned char *tx_buff = tfr->tx_buf;
bytes = tfr->len;
while(bytes) {
if(tx_buff) {
printk(KERN_INFO "TX: %c \n", *tx_buff);
tx_buff ++ ;
}
if(rx_buff) {
*rx_buff = 'a';//读取时每次获取'a'
rx_buff ++ ;
}
bytes -- ;
}
return 0;
}
static int dummy_spimaster_probe(struct platform_device *pdev)
{
int ret;
struct spi_master *master;
master = spi_alloc_master(&pdev->dev, 0);
if (!master)
{
printk(KERN_ERR "unable to alloc SPI master\n");
return -EINVAL;
}
master->dev.of_node = pdev->dev.of_node;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
master->bus_num = -1;
master->auto_runtime_pm = false;//不支持PM,如果需要支持,则需要实现platform_driver中.driver.pm
master->num_chipselect = 4;
master->transfer_one = dummy_spimaster_transfer_one;
master->setup = dummy_spimaster_setup;
master->max_speed_hz = 100 * 1000 * 1000; //100MHz
master->min_speed_hz = 3 * 1000; //3kHz
master->set_cs = dummy_spimaster_set_cs;
ret = devm_spi_register_master(&pdev->dev, master);
if (ret) {
dev_err(&pdev->dev, "spi register master failed!\n");
spi_master_put(master);
return ret;
}
platform_set_drvdata(pdev, master);
return 0;
}
static int dummy_spimaster_remove(struct platform_device *pdev)
{
struct spi_master *master = platform_get_drvdata(pdev);
spi_unregister_master(master);
printk("%s:%d\n", __FUNCTION__, __LINE__);
return 0;
}
static const struct of_device_id dummy_spimaster_match[] = {
{ .compatible = "dummy-spi-master", },
{}
};
MODULE_DEVICE_TABLE(of, dummy_spimaster_match);
static struct platform_driver dummy_spimaster_driver = {
.driver = {
.name = "dummy_spimaster_driver",
.owner = THIS_MODULE,
.of_match_table = dummy_spimaster_match,
},
.probe = dummy_spimaster_probe,
.remove = dummy_spimaster_remove,
//.driver.pm =
};
module_platform_driver(dummy_spimaster_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("1477153217@qq.com");
MODULE_VERSION("0.1");
MODULE_DESCRIPTION("dummy spi controller driver test");
static int dummy_spimaster_transfer_one(struct spi_master *master, struct spi_device *spi, struct spi_transfer *tfr)
{
int bytes;
unsigned char *rx_buff = tfr->rx_buf;
const unsigned char *tx_buff = tfr->tx_buf;
bytes = tfr->len;
while(bytes) {
if(tx_buff) {
printk(KERN_INFO "TX: %c \n", *tx_buff);
tx_buff ++ ;
}
if(rx_buff) {
*rx_buff = 'a';//读取时每次获取'a'
rx_buff ++ ;
}
bytes -- ;
}
return 0;
}
接下来再看spi设备驱动程序: