3.X的内核,对于platform_device的注册和platform data,全都放在dts文件中指定,对于spi nor来说,它的整个驱动
包括了master driver,master device,spi nor driver 和spi nor device.
对于spi master的驱动是在driver/spi/下有相关的文件来完成,而spi master device是在dts中来指定,
对于zynq板子来说,我们在driver/spi/可以找到相关的spi master的驱动文件,在这里它就是一个platfrom driver.
对于device 是在dts文件中一指定的:
ps7_qspi_0: ps7-qspi@e000d000 {
clock-names = "ref_clk", "aper_clk";
clocks = <&clkc 10>, <&clkc 43>;
compatible = "xlnx,zynq-qspi-1.0";
interrupt-parent = <&ps7_scugic_0>;
interrupts = <0 19 4>;
is-dual = <0>;
num-chip-select = <1>;
reg = <0xe000d000 0x1000>;
xlnx,fb-clk = <0x1>;
xlnx,qspi-mode = <0x0>;
#address-cells = <1>;
#size-cells = <0>;
flash@0 {
compatible = "s25fl256s1";
reg = <0x0>;
spi-max-frequency = <50000000>;
#address-cells = <1>;
#size-cells = <1>;
partition@qspi-fsbl-uboot {
label = "qspi-fsbl-uboot";
reg = <0x0 0x100000>;
};
partition@qspi-linux {
label = "qspi-linux";
reg = <0x100000 0x500000>;
};
partition@qspi-device-tree {
label = "qspi-device-tree";
reg = <0x600000 0x20000>;
};
partition@qspi-rootfs {
label = "qspi-rootfs";
reg = <0x620000 0x5E0000>;
};
partition@qspi-bitstream {
label = "qspi-bitstream";
reg = <0xC00000 0x400000>;
};
};
} ;
在linux启动后,会解析这个dts文件,当进行spi master driver注册时,会进行match,之后就调用spi master driver下的probe函数,
probe函数中会调用spi_register_master函数.我们知道有spi master只是有总线的驱动了,那一定还有spi相关的device,没错,
spi device就是在spi_register_master中来完成的,我们也可以通过上面的spi master 的dts代码看到,在这个spi bus 下只挂了一个spi nor flash.在spi_register_master中会对master下所挂的spi nor device进行add:
int spi_register_master(struct spi_master *master)
{
static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1);
struct device *dev = master->dev.parent;
struct boardinfo *bi;
int status = -ENODEV;
int dynamic = 0;
if (!dev)
return -ENODEV;
status = of_spi_register_master(master);
if (status)
return status;
/* even if it's just one always-selected device, there must
* be at least one chipselect
*/
if (master->num_chipselect == 0)
return -EINVAL;
if ((master->bus_num < 0) && master->dev.of_node)
master->bus_num = of_alias_get_id(master->dev.of_node, "spi");
/* convention: dynamically assigned bus IDs count down from the max */
if (master->bus_num < 0) {
/* FIXME switch to an IDR based scheme, something like
* I2C now uses, so we can't run out of "dynamic" IDs
*/
master->bus_num = atomic_dec_return(&dyn_bus_id);
dynamic = 1;
}
spin_lock_init(&master->bus_lock_spinlock);
mutex_init(&master->bus_lock_mutex);
master->bus_lock_flag = 0;
init_completion(&master->xfer_completion);
if (!master->max_dma_len)
master->max_dma_len = INT_MAX;
/* register the device, then userspace will see it.
* registration fails if the bus ID is in use.
*/
dev_set_name(&master->dev, "spi%u", master->bus_num);
status = device_add(&master->dev);
if (status < 0)
goto done;
dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
dynamic ? " (dynamic)" : "");
/* If we're using a queued driver, start the queue */
if (master->transfer)
dev_info(dev, "master is unqueued, this is deprecated\n");
else {
status = spi_master_initialize_queue(master);
if (status) {
device_del(&master->dev);
goto done;
}
}
mutex_lock(&board_lock);
list_add_tail(&master->list, &spi_master_list);
list_for_each_entry(bi, &board_list, list)
spi_match_master_to_boardinfo(master, &bi->board_info);
mutex_unlock(&board_lock);
/* Register devices from the device tree and ACPI */
of_register_spi_devices(master); //注册这个master下所挂载的spi device.
acpi_register_spi_devices(master);
done:
return status;
}
static void of_register_spi_devices(struct spi_master *master)
{
struct spi_device *spi;
struct device_node *nc;
int rc;
u32 value;
if (!master->dev.of_node)
return;
for_each_available_child_of_node(master->dev.of_node, nc) {
/* Alloc an spi_device */
spi = spi_alloc_device(master);
if (!spi) {
dev_err(&master->dev, "spi_device alloc error for %s\n",
nc->full_name);
spi_dev_put(spi);
continue;
}
/* Select device driver */
if (of_modalias_node(nc, spi->modalias,
sizeof(spi->modalias)) < 0) {
dev_err(&master->dev, "cannot find modalias for %s\n",
nc->full_name);
spi_dev_put(spi);
continue;
}
/* Device address */
rc = of_property_read_u32(nc, "reg", &value);
if (rc) {
dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n",
nc->full_name, rc);
spi_dev_put(spi);
continue;
}
spi->chip_select = value;
/* Mode (clock phase/polarity/etc.) */
if (of_find_property(nc, "spi-cpha", NULL))
spi->mode |= SPI_CPHA;
if (of_find_property(nc, "spi-cpol", NULL))
spi->mode |= SPI_CPOL;
if (of_find_property(nc, "spi-cs-high", NULL))
spi->mode |= SPI_CS_HIGH;
if (of_find_property(nc, "spi-3wire", NULL))
spi->mode |= SPI_3WIRE;
if (of_find_property(nc, "spi-lsb-first", NULL))
spi->mode |= SPI_LSB_FIRST;
/* Device DUAL/QUAD mode */
if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) { //从dts中获取相关的写模式,
switch (value) {
case 1:
break;
case 2:
spi->mode |= SPI_TX_DUAL;
break;
case 4:
spi->mode |= SPI_TX_QUAD;
break;
default:
dev_warn(&master->dev,
"spi-tx-bus-width %d not supported\n",
value);
break;
}
}
if (!of_property_read_u32(nc, "spi-rx-bus-width", &value)) { //获取read的mode
switch (value) {
case 1:
break;
case 2:
spi->mode |= SPI_RX_DUAL;
break;
case 4:
spi->mode |= SPI_RX_QUAD;
break;
default:
dev_warn(&master->dev,
"spi-rx-bus-width %d not supported\n",
value);
break;
}
}
/* Device speed */
rc = of_property_read_u32(nc, "spi-max-frequency", &value);
if (rc) {
dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)\n",
nc->full_name, rc);
spi_dev_put(spi);
continue;
}
spi->max_speed_hz = value;
/* IRQ */
spi->irq = irq_of_parse_and_map(nc, 0);
/* Store a pointer to the node in the device structure */
of_node_get(nc);
spi->dev.of_node = nc;
/* Register the new device */
request_module("%s%s", SPI_MODULE_PREFIX, spi->modalias); //加载设备对应的驱动文件
rc = spi_add_device(spi); //增加这个spi device
if (rc) {
dev_err(&master->dev, "spi_device register error %s\n",
nc->full_name);
spi_dev_put(spi);
}
}
}
我们可以看到在这个函数中完成了相关spi device的增加和相关属性的指定.
但在这些代码中我们没有找到相关partition的指定,因为partition在spi nor driver的probe中会从spi device中的platfrom_data中直接获取.????如下,也有可能是在解析dts时就已经对device中的platform_data作了指定.可以看最后面的备注.
static int m25p_probe(struct spi_device *spi)
{
struct mtd_part_parser_data ppdata;
struct flash_platform_data *data;
struct m25p *flash;
struct spi_nor *nor;
enum read_mode mode = SPI_NOR_NORMAL;
int ret;
flash = devm_kzalloc(&spi->dev, sizeof(*flash), GFP_KERNEL);
if (!flash)
return -ENOMEM;
nor = &flash->spi_nor;
/* install the hooks */
nor->read = m25p80_read;
nor->write = m25p80_write;
nor->erase = m25p80_erase;
nor->write_reg = m25p80_write_reg;
nor->read_reg = m25p80_read_reg;
nor->dev = &spi->dev;
nor->mtd = &flash->mtd;
nor->priv = flash;
spi_set_drvdata(spi, flash);
flash->mtd.priv = nor;
flash->spi = spi;
if (spi->mode & SPI_RX_QUAD)
mode = SPI_NOR_QUAD;
else if (spi->mode & SPI_RX_DUAL)
mode = SPI_NOR_DUAL;
ret = spi_nor_scan(nor, spi_get_device_id(spi), mode);
if (ret)
return ret;
data = dev_get_platdata(&spi->dev); //获取device platform_data
ppdata.of_node = spi->dev.of_node;
return mtd_device_parse_register(&flash->mtd, NULL, &ppdata,
data ? data->parts : NULL,
data ? data->nr_parts : 0);
}
注:
系统平台上挂载了很多总线,如i2c、spi、uart等等,每一个总线分别被描述为一个节点。Linux在启动后,到C入口时,会执行以下操作,加载系统平台上的总线和设备:
start_kernel() --> setup_arch() --> unflatten_device_tree() .
在执行完unflatten_device_tree()后,DTS节点信息被解析出来,保存到of_allnodes链表中,of_allnodes会在后面被用到。
随后,当系统启动到board文件时,会调用.init_machine,高通zynq平台对应的是zynq_init_machine()。接着调用of_platform_populate(....)接口,加载平台总线和平台设备。至此,系统平台上的所有已配置的总线和设备将被注册到系统中。
在of_platform_populate会调用of_platform_bus_create函数,在这里面会地我上面所提到platform_data进行指定:of_platform_device_create_pdata.