1、概览
spi子系统中分为spi控制器驱动和spi设备驱动。前面已经讲述了spi控制器驱动。下面讲述一下spi设备驱动。所谓的spi设备驱动,就是挂在spi总线上形形色色的芯片驱动。它可能是一个Flash芯片,一个声音编解码芯片,也可能是一个网卡芯片。这些芯片如果要正常工作,那就必须为之编写对应的驱动,这个驱动就是spi设备驱动。下面将讲解如何实现一个spi设备驱动
2、向内核注册spi设备
如果希望一个spi设备可以在linux系统下很好的工作,除了写驱动,还要向内核申明和注册这个spi设备。目前有两种方法向内核注册一个spi设备。在稍微老点版本的内核(2.6.xx)中通过向内核注册struct spi_board_info对象,来申明一个spi设备。在比较新的内核中(3.xx)使用device tree的方式向内核申明并注册一个spi设备的。无论使用哪种方式,其实最终的目的就是为了建立一个struct spi_deivce对象,并注册到spi子系统中。下面就结合代码来看看是如何注册一
个spi设备到内核中的。
spi_board_info的方式
783 struct spi_board_info {
784 /* the device name and module name are coupled, like platform_bus;
785 * "modalias" is normally the driver name.
786 *
787 * platform_data goes to spi_device.dev.platform_data,
788 * controller_data goes to spi_device.controller_data,
789 * irq is copied too
790 */
791 char modalias[SPI_NAME_SIZE];
792 const void *platform_data;
793 void *controller_data;
794 int irq;
795
796 /* slower signaling on noisy or low voltage boards */
797 u32 max_speed_hz;
798
799
800 /* bus_num is board specific and matches the bus_num of some
801 * spi_master that will probably be registered later.
802 *
803 * chip_select reflects how this chip is wired to that master;
804 * it's less than num_chipselect.
805 */
806 u16 bus_num;
807 u16 chip_select;
808
809 /* mode becomes spi_device.mode, and is essential for chips
810 * where the default of SPI_CS_HIGH = 0 is wrong.
811 */
812 u8 mode;
813
814 /* ... may need additional spi_device chip config data here.
815 * avoid stuff protocol drivers can set; but include stuff
816 * needed to behave without being bound to a driver:
817 * - quirks like clock rate mattering when not selected
818 */
819 };
下面就结合imx51的一个板级代码讲解struct spi_board_info各个字段的含义,以及如何在板级代码中注册struct spi_board_info。在代码kernel/arch/arm/mach-imx51-3ds.c的121行左右:
121 static struct spi_board_info mx51_3ds_spi_nor_device[] = {
122 {
123 .modalias = "m25p80",
124 .max_speed_hz = 25000000, /* max spi clock (SCK) speed in HZ */
125 .bus_num = 1,
126 .chip_select = 1,
127 .mode = SPI_MODE_0,
128 .platform_data = NULL,},
129 };
一个struct spi_board_info对象对应一个spi设备。上面代码中:
.modalias = “m25p80”,
spi设备名字,设备驱动探测时会用到该项;
.max_speed_hz = 25000000,
记录了这个spi设备支持的最大速度;
.bus_num = 1,
记录了该spi设备是连接在哪个spi总线上的,所在总线的编号;
.chip_select = 1,
该spi设备的片选编号;
.mode = SPI_MODE_0,
和这个spi设备支持spi总线的工作模式。
注册spi_dev
46 spi_register_board_info(mx51_3ds_spi_nor_device,
147 ARRAY_SIZE(mx51_3ds_spi_nor_device));
在kernel/drivers/spi/spi.c中的515行左右,就是将struct boardinfo对象添加到board_list:
501 int spi_register_board_info(struct spi_board_info const *info, unsigned n)
502 {
503 struct boardinfo *bi;
504 int i;
505
506 bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
507 if (!bi)
508 return -ENOMEM;
509
510 for (i = 0; i < n; i++, bi++, info++) {
511 struct spi_master *master;
512
513 memcpy(&bi->board_info, info, sizeof(*info));
514 mutex_lock(&board_lock);
515 list_add_tail(&bi->list, &board_list);
516 list_for_each_entry(master, &spi_master_list, list)
517 spi_match_master_to_boardinfo(master, &bi->board_info);
518 mutex_unlock(&board_lock);
519 }
520
521 return 0;
522 }
遍历spi_master_list上的所有struct spi_master对象,并将上面一步spi_board_info.bus_num和spi_master.bus_num做比较,相等则创建struct spi_device对象并注册。
spi_master_list记录系统中所有的spi控制器。spi_master.bus_num和spi_board_info.bus_num相等,则说明该spi_board_info所对应的spi设备连接在该spi控制器上。我们的最终目的是创建并注册struct spi_device。在前面的文章说到,struct spi_device`在内核中才真正代表一个spi设备。
下面看看spi_master和spi_board_info是如何匹配的,在kernel/drivers/spi/spi.c:
468 static void spi_match_master_to_boardinfo(struct spi_master *master,
469 struct spi_board_info *bi)
470 {
471 struct spi_device *dev;
472
473 if (master->bus_num != bi->bus_num)
474 return;
475
476 dev = spi_new_device(master, bi);
477 if (!dev)
478 dev_err(master->dev.parent, "can't create new device for %s\n",
479 bi->modalias);
480 }
通过代码我们可以看到,其实就是spi_master.bus_num和spi_board_info.bus_num的简单比较。匹配的话就调用spi_new_device()创建struct spi_device对象并注册,在kernel/drivers/spi/spi.c中:
430 struct spi_device *spi_new_device(struct spi_master *master,
431 struct spi_board_info *chip)
432 {
433 struct spi_device *proxy;
434 int status;
435
436 /* NOTE: caller did any chip->bus_num checks necessary.
437 *
438 * Also, unless we change the return value convention to use
439 * error-or-pointer (not NULL-or-pointer), troubleshootability
440 * suggests syslogged diagnostics are best here (ugh).
441 */
442
443 proxy = spi_alloc_device(master);
444 if (!proxy)
445 return NULL;
446
447 WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
448
449 proxy->chip_select = chip->chip_select;
450 proxy->max_speed_hz = chip->max_speed_hz;
451 proxy->mode = chip->mode;
452 proxy->irq = chip->irq;
453 strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
454 proxy->dev.platform_data = (void *) chip->platform_data;
455 proxy->controller_data = chip->controller_data;
456 proxy->controller_state = NULL;
457
458 status = spi_add_device(proxy);
459 if (status < 0) {
460 spi_dev_put(proxy);
461 return NULL;
462 }
463
464 return proxy;
465 }
466 EXPORT_SYMBOL_GPL(spi_new_device);
使用DEVICE TREE
下面以am33xx的一个平台,讲解如何使用device tree来向内核中添加一个spi设备,首先看下面的device tree代码片段kernel/arch/arm/boot/dts/am335x-evm.dts:
&spi0 {
status = "okay";
spi-flash@0 {
compatible = "spansion,s25fl064k", "m25p80";
spi-max-frequency = <24000000>;
reg = <0>;
};
};
这个device tree最外面的节点spi0描述的就是一个spi控制器,这个我们已经在上篇博文中说过了,这里面就是上篇博文提到的spi0。这里我们主要关注子节点。
在spi控制器的每一个子节点,都会被内核解析成一个spi设备,最后生成一个struct spi_device,并注册到内核中,我们这个节点也不例外。这里的spi-flash节点就会被解析成一个struct spi_device对象。那么在什么时候这些子节点被解析成呢?这些子节点是在它的父节点对应的控制器被注册时解析的,也就是说是在调用spi_register_master()向内核注册一个spi控制器时,在这个函数中被解析。这个函数的的最后调用了of_register_spi_devices(master),这个函数的主要目的就是遍历struct spi_master对象所对应的device tree节点的所有子节点,并使用子节点中的属性信息创建对应的struct spi_device,然后注册至内核中。
spi设备驱动
上面的两种方法注册spi设备,讲的都是m25p80这个spi flash设备,spi设备的驱动,我们也讲解m25p80的驱动。代码在kernel/drivers/mtd/devices/m25p80.c。
/* 定义个一个struct spi_driver*/
static struct spi_driver m25p80_driver = {
.driver = {
.name = "m25p80",
.owner = THIS_MODULE,
},
.id_table = m25p_ids,
.probe = m25p_probe,
.remove = m25p_remove,
/* REVISIT: many of these chips have deep power-down modes, which
* should clearly be entered on suspend() to minimize power use.
* And also when they're otherwise idle...
*/
};
/* 注册struct spi_driver对象至内核 */
module_spi_driver(m25p80_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Mike Lavender");
MODULE_DESCRIPTION("MTD SPI driver for ST M25Pxx flash chips");
static int m25p_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct flash_platform_data *data;
struct m25p *flash;
struct flash_info *info;
unsigned i;
struct mtd_part_parser_data ppdata;
struct device_node __maybe_unused *np = spi->dev.of_node;
#ifdef CONFIG_MTD_OF_PARTS
if (!of_device_is_available(np)) /* 解析device tree中配置的partition */
return -ENODEV;
#endif
/* {......} */
info = (void *)id->driver_data; /* 获取spi_device_id中的driver_data*/
/* {......} */
/* 创建flash设备 */
flash = kzalloc(sizeof *flash, GFP_KERNEL);
if (!flash)
return -ENOMEM;
flash->command = kmalloc(MAX_CMD_SIZE + (flash->fast_read ? 1 : 0),
GFP_KERNEL);
if (!flash->command) {
kfree(flash);
return -ENOMEM;
}
flash->spi = spi;
mutex_init(&flash->lock);
dev_set_drvdata(&spi->dev, flash);
/* {......} */
/* 设置mtd设备的信息和接口*/
if (data && data->name)
flash->mtd.name = data->name;
else
flash->mtd.name = dev_name(&spi->dev);
flash->mtd.type = MTD_NORFLASH; /*类型为norflash*/
flash->mtd.writesize = 1; /*写的大小*/
flash->mtd.flags = MTD_CAP_NORFLASH;
flash->mtd.size = info->sector_size * info->n_sectors; /* mtd总大小*/
flash->mtd._erase = m25p80_erase; /* mtd 擦接口*/
flash->mtd._read = m25p80_read; /* mtd 读接口*/
/* 下面设置写接口,和一次擦除的大小 */
/* sst flash chips use AAI word program */
if (JEDEC_MFR(info->jedec_id) == CFI_MFR_SST)
flash->mtd._write = sst_write;
else
flash->mtd._write = m25p80_write;
/* prefer "small sector" erase if possible */
if (info->flags & SECT_4K) {
flash->erase_opcode = OPCODE_BE_4K;
flash->mtd.erasesize = 4096;
} else {
flash->erase_opcode = OPCODE_SE;
flash->mtd.erasesize = info->sector_size;
}
/* {......} */
/* partitions should match sector boundaries; and it may be good to
* use readonly partitions for writeprotected sectors (BP2..BP0).
*/
/* 注册mtd设备至内核 */
return mtd_device_parse_register(&flash->mtd, NULL, &ppdata,
data ? data->parts : NULL,
data ? data->nr_parts : 0);
}
匹配成功 spi_driver侧拿到spi_device中的spi_master,然后使用控制器的spi_transfer进行设备的读写