mt6739-kernel4.4
0. file_list
2. alps/kernel-4.4/include/linux/spi/spi.h
struct spi_device, struct spi_driver, struct spi_board_info, struct spi_transfer, struct spi_master,
struct spi_message, struct spi_statistics,
spi_master_get_devdata();
3. alps/kernel-4.4/drivers/spi/spi.c
struct bus_type spi_bus_type, static struct class spi_master_class
spi_new_device(); spi_add_device(); __spi_register_driver(); spi_dev_set_name();
spi_register_master(); devm_spi_register_master(); spi_setup(); __spi_sync(); spi_sync();
spi_match_device(); spi_uevent(); __spi_register_driver(); spi_alloc_master();
spi_match_master_to_boardinfo();
5. alps/kernel-4.4/drivers/spi/spi-adi-v3.c //亚德诺半导体
6. alps/kernel-4.4/drivers/spi/spi-mt65xx.c //spi控制器驱动, spi_master
struct mtk_spi;
module_platform_driver(); mtk_spi_setup();
7. alps/kernel-4.4/include/linux/list.h
list_add_tail(); list_for_each_entry();
8. alps/kernel-4.4/drivers/base/bus.c
bus_for_each_dev(); bus_register();
9. kernel-4.4/drivers/base/core.c
device_add();
10. alps/kernel-4.4/include/linux/device.h
dev_get_drvdata();
11. alps/kernel-4.4/include/linux/of_device.h //dts
of_driver_match_device();
12. alps/kernel-4.4/drivers/base/base.h
driver_match_device();
13. alps/kernel-4.4/drivers/base/driver.c
driver_register();
-----mt6735/37-kernel3.18
20. alps/kernel-3.18/drivers/spi/mediatek/mt6735/spi.c
mt_spi_probe(){ pdev->id }
==master=start====================================================
/*总线添加master(spi控制器)*/
m1 ------ dts ------------------------------------------------
/{
... ...
spi0: spi@1100a000 {
compatible = "mediatek,mt6739-spi";
mediatek,pad-select = <0>;
reg = <0 0x1100a000 0 0x1000>;
interrupts = ;
clocks = <&topckgen CLK_TOP_SYSPLL3_D2>,
<&topckgen CLK_TOP_SPI_SEL>,
<&infracfg_ao CLK_INFRA_SPI0>;
clock-names = "parent-clk", "sel-clk", "spi-clk";
};
spi1: spi@11010000 {
compatible = "mediatek,mt6739-spi";
mediatek,pad-select = <0>;
reg = <0 0x11010000 0 0x1000>;
interrupts = ;
clocks = <&topckgen CLK_TOP_SYSPLL3_D2>,
<&topckgen CLK_TOP_SPI_SEL>,
<&infracfg_ao CLK_INFRA_SPI1>;
clock-names = "parent-clk", "sel-clk", "spi-clk";
};
spi2: spi@11012000 {
compatible = "mediatek,mt6739-spi";
mediatek,pad-select = <0>;
reg = <0 0x11012000 0 0x1000>;
interrupts = ;
clocks = <&topckgen CLK_TOP_SYSPLL3_D2>,
<&topckgen CLK_TOP_SPI_SEL>,
<&infracfg_ao CLK_INFRA_SPI2>;
clock-names = "parent-clk", "sel-clk", "spi-clk";
};
... ...
}
// ipt_slave
&spi0 {
#address-cells = <1>;
#size-cells = <0>;
finger@0 {
compatible = "mediatek,finger-spi";
reg = <0>;
spi-max-frequency = <60000000>;
status = "okay";
};
};
m2. alps/kernel-4.4/drivers/spi/spi-mt65xx.c
static const struct of_device_id mtk_spi_of_match[] = {
... ...
{ .compatible = "mediatek,mt6739-spi", //ipt
.data = (void *)&mt6739_compat,
},
{ .compatible = "mediatek,mt8135-spi",
.data = (void *)&mtk_common_compat,
},
... ...
{}
};
MODULE_DEVICE_TABLE(of, mtk_spi_of_match);
static struct platform_driver mtk_spi_driver = {
.driver = {
.name = "mtk-spi",
.pm = &mtk_spi_pm,
.of_match_table = mtk_spi_of_match, //ipt
},
.probe = mtk_spi_probe,
.remove = mtk_spi_remove,
};
module_platform_driver(mtk_spi_driver); //ipt
/* -- 调用流程 --- */
module_platform_driver(mtk_spi_driver);
int mtk_spi_probe(struct platform_device *pdev);
|master->setup = mtk_spi_setup;
|master = spi_alloc_master(&pdev->dev, sizeof(*mdata));
|ret = devm_spi_register_master(&pdev->dev, master);
ret = spi_register_master(master);
for(;spi_master_list;) { //list_for_each_entry
spi_match_master_to_boardinfo(master, &bi->board_info);
dev = spi_new_device(master, bi);
|proxy = spi_alloc_device(master);
|status = spi_add_device(proxy);
|spi_dev_set_name(spi);
|status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
|status = spi_setup(spi);
|status = spi->master->setup(spi); //mtk_spi_setup
mtk_spi_setup();
|struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
|gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
|spi_set_cs(spi, false);
|status = device_add(&spi->dev);
}//for
of_register_spi_devices(master); //spi_register_master' invoke
/* ------- 细节 0 start------spi_bus_type-----------------*/
/*
ps: slave 在注册driver(spi_driver)的时候都要指定spi_bus_type
=>
驱动&设备会在/sys/spi的drivers&devices文件下生成相关设备
*/
@ alps/kernel-4.4/drivers/spi/spi.c
struct bus_type spi_bus_type = {
.name = "spi",
.dev_groups = spi_dev_groups,
.match = spi_match_device,
.uevent = spi_uevent,
};
EXPORT_SYMBOL_GPL(spi_bus_type);
static int __init spi_init(void)
{
status = bus_register(&spi_bus_type);
return 0;
}
postcore_initcall(spi_init);
/*
生成/sys/bus/文件目录
驱动.bus配置了spi_bus_type, 生成的驱动会在/sys/bus/目录生成相关文件(drivers&devices)
*/
-----------------------------------------------
@ alps/driver/xxx/modexxx.c
static struct spi_driver modexxx_driver = {
.driver = {
.name = SPI_DRV_NAME,
.bus = &spi_bus_type, //ipt
.owner = THIS_MODULE,
.pm = &modexxx_pm,
#ifdef CONFIG_OF //ipt not user
.of_match_table = of_match_ptr(modexxx_of_match),
#endif
},
.id_table = modexxx_id,
.probe = modexxx_probe,
.remove = modexxx_remove,
};
static int modexxx_spi_init(void)
{
... ...
ret=spi_register_driver(&modexxx_driver);
... ...
return 1;
}
late_initcall_sync(modexxx_spi_init);
/* ------- 细节 0 ends------spi_bus_type-----------------*/
/* ------- 细节 1 start------bus_num-----------------*/
dts: mtk_spi_driver驱动根据"mediatek,mt6739-spi"匹配到设备之后, 注册master
bus_num: spi_alloc_master() => master->bus_num=-1;
spi_register_master(struct spi_master *master)
static atomic_t dyn_bus_id = ATOMIC_INIT((1<<15) - 1); //32768-1=32667
master->bus_num = of_alias_get_id(master->dev.of_node, "spi"); //bus_num=4294967277
master->bus_num = atomic_dec_return(&dyn_bus_id); //bus_num=32766=32767-1, ps: 后面的逐步-1, 32765, 32764
==>
master->bus_num=32766;
/* ------- 细节 1 ends-------bus_num----------------*/
/* ------- 细节 2 start----------master在总线上的id及名称------------*/
spi_register_master(struct spi_master *master)
dev_set_name(&master->dev, "spi%u", master->bus_num); //dev_name="spi32766"
for(;spi_master_list;) { //list_for_each_entry
spi_match_master_to_boardinfo(master, &bi->board_info);
dev = spi_new_device(master, bi);
status = spi_add_device(proxy);
spi_dev_set_name(spi);
dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev), spi->chip_select); //dev_name="spi32766.0" spi(总线名称, .0 is cs)
/* ------- 细节 2 ends----------master在总线上的id及名称------------*/
/* ------- 细节 3 start------加载master下的从设备-----------------*/
// 关键字: ipt_slave, 由上面dts配置可以知道, master配置spi0: spi@1100a000下存在finger@0 {... }
spi_register_master(struct spi_master *master)
of_register_spi_devices(master);
for_each_available_child_of_node(master->dev.of_node, nc) { //遍历master下的子设备
spi = of_register_spi_device(master, nc);
|spi = spi_alloc_device(master);
//对以上finger@0 {}的配置解析(reg, spi-max-frequency等)
|rc = of_property_read_u32(nc, "reg", &value);
|rc = of_property_read_u32(nc, "spi-max-frequency", &value);
} //for
/* ------- 细节 3 ends------加载master下的从设备-----------------*/
/* ------- 细节 4 start------如果未使用dts, 匹配spi master和spi slave-----------------*/
/* 关键字: not_dts,
以设备modexxx为例, 如果没有dts配置,
需要自己使用spi_register_board_info添加设备dev(供spi_register_driver匹配);
根据bus_num和master的bus_num配置绑定(dts不需要,具体关注”细节 3“) */
static struct spi_driver modexxx_driver = {
.driver = {
.name = SPI_DRV_NAME,
.bus = &spi_bus_type, //ipt
.owner = THIS_MODULE,
.pm = &modexxx_pm,
#ifdef CONFIG_OF //ipt not user
.of_match_table = of_match_ptr(modexxx_of_match),
#endif
},
.id_table = modexxx_id,
.probe = modexxx_probe,
.remove = modexxx_remove,
};
// ipt
#ifndef CONFIG_OF
static struct spi_board_info spi_board_modexxx[] __initdata = {
[0] = {
.modalias = "mode_name",
.bus_num = 0, // ipt not_dts
.chip_select = 0,
.mode = SPI_MODE_0,
.max_speed_hz = 6000000,
},
};
#endif
static int modexxx_spi_init(void)
{
int ret;
#ifndef CONFIG_OF // ipt not_dts
ret=spi_register_board_info(spi_board_modexxx, ARRAY_SIZE(spi_board_modexxx));
#endif
printk("modexxx_spi_init\r\n");
ret=spi_register_driver(&modexxx_driver);
if(ret<0)
{
printk("modexxx_spi_init fail\r\n");
}
return 1;
}
late_initcall_sync(modexxx_spi_init);
ps:
spi_register_board_info(struct spi_board_info const *info, unsigned n);
list_add_tail(&bi->list, &board_list);
list_for_each_entry(master, &spi_master_list, list)
spi_match_master_to_boardinfo(master, &bi->board_info);
/* ------- 细节 4 ends------如果未使用dts, 匹配spi master和spi slave-----------------*/
==master=ends====================================================
==================================================
/*通用接口层*/
postcore_initcall(spi_init);
buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
status = bus_register(&spi_bus_type);
status = class_register(&spi_master_class);
==================================================
/* 数据发送 */
spi_sync(struct spi_device *spi, struct spi_message *message);
__spi_sync(struct spi_device *spi, struct spi_message *message, int bus_locked);
#if
trace_spi_message_submit(message);
status = __spi_queued_transfer(spi, message, false);
#else
status = spi_async_locked(spi, message);
ret = __spi_async(spi, message);
|trace_spi_message_submit(message);
|master->transfer(spi, message);
#endif
spi_async(struct spi_device *spi, struct spi_message *message)
static int __spi_async(struct spi_device *spi, struct spi_message *message)
|trace_spi_message_submit(message);
|master->transfer(spi, message);
==================================================
ret=spi_register_driver(&cdfinger_driver);
__spi_register_driver(struct module *owner, struct spi_driver *sdrv)
driver_register(&sdrv->driver);
ps:
#define spi_register_driver(driver) \
__spi_register_driver(THIS_MODULE, driver)
==================================================
mt6737/35-kernel3.18
/*
mt6737(kernel3.18)&mt6739(kernel4.4)注册spimaster的机制不同
*/
0. xxx.dts/dtsi
spi0:spi@1100a000 {
compatible = "mediatek,mt6735-spi";
cell-index = <0>; //ipt
spi-padmacro = <0>;
reg = <0x1100a000 0x1000>;
interrupts = ;
clocks = <&perisys PERI_SPI0>;
clock-names = "spi-main";
clock-frequency = <109000000>;
clock-div = <1>;
};
1. alps/kernel-3.18/drivers/spi/mediatek/mt6735/spi.c
static int __init mt_spi_probe(struct platform_device *pdev)
{
struct spi_master *master;
master = spi_alloc_master(&pdev->dev, sizeof(struct mt_spi_t));
ms = spi_master_get_devdata(master);
... ...
if (of_property_read_u32(pdev->dev.of_node, "cell-index", &pdev->id)) { //ipt
dev_err(&pdev->dev, "SPI get cell-index failed\n");
return -ENODEV;
}
... ...
master->num_chipselect = 2;
master->mode_bits = (SPI_CPOL | SPI_CPHA);
master->bus_num = pdev->id; //ipt
master->setup = mt_spi_setup;
master->transfer = mt_spi_transfer;
master->cleanup = mt_spi_cleanup;
platform_set_drvdata(pdev, master);
... ...
spi_master_set_devdata(master, ms);
... ...
ret = spi_register_master(master); //ipt
... ...
}
=================================================
3. alps/kernel-4.4/drivers/spi/spi.c
struct bus_type spi_bus_type = {
.name = "spi",
.dev_groups = spi_dev_groups,
.match = spi_match_device,
.uevent = spi_uevent,
};
EXPORT_SYMBOL_GPL(spi_bus_type);
static struct class spi_master_class = {
.name = "spi_master",
.owner = THIS_MODULE,
.dev_release = spi_master_release,
.dev_groups = spi_master_groups,
};
static int __init spi_init(void)
{
status = bus_register(&spi_bus_type);
status = class_register(&spi_master_class);
}
postcore_initcall(spi_init);
2. alps/kernel-4.4/include/linux/spi/spi.h
struct spi_device {
struct device dev;
struct spi_master *master;
u32 max_speed_hz;
u8 chip_select;
u8 bits_per_word;
u16 mode;
#define SPI_CPHA 0x01 /* clock phase */
... ...
#define SPI_RX_QUAD 0x800 /* receive with 4 wires */
int irq;
void *controller_state;
void *controller_data;
char modalias[SPI_NAME_SIZE];
int cs_gpio; /* chip select gpio */
/* the statistics */
struct spi_statistics statistics;
};
struct spi_board_info {
char modalias[SPI_NAME_SIZE];
const void *platform_data;
void *controller_data;
int irq;
u32 max_speed_hz;
u16 bus_num;
u16 chip_select;
u16 mode;
};
#define spi_register_driver(driver) \
__spi_register_driver(THIS_MODULE, driver)
3. alps/kernel-4.4/drivers/spi/spi.c
int devm_spi_register_master(struct device *dev, struct spi_master *master)
{
struct spi_master **ptr;
int ret;
ptr = devres_alloc(devm_spi_unregister, sizeof(*ptr), GFP_KERNEL);
if (!ptr)
return -ENOMEM;
ret = spi_register_master(master);
if (!ret) {
*ptr = master;
devres_add(dev, ptr);
} else {
devres_free(ptr);
}
return ret;
}
EXPORT_SYMBOL_GPL(devm_spi_register_master);
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;
printk("jun before operation bus_num=%u", master->bus_num); //bus_num=4294867295
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;
}
INIT_LIST_HEAD(&master->queue);
spin_lock_init(&master->queue_lock);
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); //bus_num=32766
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;
}
}
/* add statistics */
spin_lock_init(&master->statistics.lock);
printk("jun after operation bus_num=%u", master->bus_num); //bus_num=32766
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);
acpi_register_spi_devices(master);
printk("jun end operation bus_num=%u", master->bus_num); //bus_num=32766
dump_stack();
done:
return status;
}
EXPORT_SYMBOL_GPL(spi_register_master);
6. alps/kernel-4.4/drivers/spi/spi-mt65xx.c //spi控制器驱动, spi_master
module_platform_driver(mtk_spi_driver);
int mtk_spi_probe(struct platform_device *pdev);
| master->setup = mtk_spi_setup;
|master = spi_alloc_master(&pdev->dev, sizeof(*mdata));
|ret = devm_spi_register_master(&pdev->dev, master);
ret = spi_register_master(master);
|dev_set_name(&master->dev, "spi%u", master->bus_num);
|for(;;) { //list_for_each_entry(bi, &board_list, list)
spi_match_master_to_boardinfo(master, &bi->board_info);
dev = spi_new_device(master, bi);
|proxy = spi_alloc_device(master);
|status = spi_add_device(proxy);
|spi_dev_set_name(spi);
|status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
|status = spi_setup(spi);
|status = spi->master->setup(spi); //mtk_spi_setup
mtk_spi_setup();
|struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
|gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
|spi_set_cs(spi, false);
|status = device_add(&spi->dev);
}
static void spi_match_master_to_boardinfo(struct spi_master *master,
struct spi_board_info *bi)
{
struct spi_device *dev;
if (master->bus_num != bi->bus_num)
return;
dev = spi_new_device(master, bi);
if (!dev)
dev_err(master->dev.parent, "can't create new device for %s\n",
bi->modalias);
}
struct spi_device *spi_new_device(struct spi_master *master,
struct spi_board_info *chip)
{
struct spi_device *proxy;
int status;
/* NOTE: caller did any chip->bus_num checks necessary.
*
* Also, unless we change the return value convention to use
* error-or-pointer (not NULL-or-pointer), troubleshootability
* suggests syslogged diagnostics are best here (ugh).
*/
proxy = spi_alloc_device(master);
if (!proxy)
return NULL;
WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
proxy->chip_select = chip->chip_select;
proxy->max_speed_hz = chip->max_speed_hz;
proxy->mode = chip->mode;
proxy->irq = chip->irq;
strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
proxy->dev.platform_data = (void *) chip->platform_data;
proxy->controller_data = chip->controller_data;
proxy->controller_state = NULL;
status = spi_add_device(proxy);
if (status < 0) {
spi_dev_put(proxy);
return NULL;
}
return proxy;
}
EXPORT_SYMBOL_GPL(spi_new_device);
struct spi_device *spi_alloc_device(struct spi_master *master)
{
struct spi_device *spi;
if (!spi_master_get(master))
return NULL;
spi = kzalloc(sizeof(*spi), GFP_KERNEL);
if (!spi) {
spi_master_put(master);
return NULL;
}
spi->master = master;
spi->dev.parent = &master->dev;
spi->dev.bus = &spi_bus_type;
spi->dev.release = spidev_release;
spi->cs_gpio = -ENOENT;
spin_lock_init(&spi->statistics.lock);
device_initialize(&spi->dev);
return spi;
}
EXPORT_SYMBOL_GPL(spi_alloc_device);
int spi_add_device(struct spi_device *spi)
{
static DEFINE_MUTEX(spi_add_lock);
struct spi_master *master = spi->master;
struct device *dev = master->dev.parent;
int status;
/* Chipselects are numbered 0..max; validate. */
if (spi->chip_select >= master->num_chipselect) {
dev_err(dev, "cs%d >= max %d\n",
spi->chip_select,
master->num_chipselect);
return -EINVAL;
}
/* Set the bus ID string */
spi_dev_set_name(spi);
/* We need to make sure there's no other device with this
* chipselect **BEFORE** we call setup(), else we'll trash
* its configuration. Lock against concurrent add() calls.
*/
mutex_lock(&spi_add_lock);
status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
if (status) {
dev_err(dev, "chipselect %d already in use\n",
spi->chip_select);
goto done;
}
if (master->cs_gpios)
spi->cs_gpio = master->cs_gpios[spi->chip_select];
/* Drivers may modify this initial i/o setup, but will
* normally rely on the device being setup. Devices
* using SPI_CS_HIGH can't coexist well otherwise...
*/
status = spi_setup(spi);
if (status < 0) {
dev_err(dev, "can't setup %s, status %d\n",
dev_name(&spi->dev), status);
goto done;
}
/* Device may be bound to an active driver when this returns */
status = device_add(&spi->dev);
if (status < 0)
dev_err(dev, "can't add %s, status %d\n",
dev_name(&spi->dev), status);
else
dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));
done:
mutex_unlock(&spi_add_lock);
return status;
}
EXPORT_SYMBOL_GPL(spi_add_device);
//set name spi327666.0
static void spi_dev_set_name(struct spi_device *spi)
{
struct acpi_device *adev = ACPI_COMPANION(&spi->dev);
if (adev) {
dev_set_name(&spi->dev, "spi-%s", acpi_dev_name(adev));
return;
}
dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),
spi->chip_select);
}
int bus_for_each_dev(struct bus_type *bus, struct device *start,
void *data, int (*fn)(struct device *, void *))
{
struct klist_iter i;
struct device *dev;
int error = 0;
if (!bus || !bus->p)
return -EINVAL;
klist_iter_init_node(&bus->p->klist_devices, &i,
(start ? &start->p->knode_bus : NULL));
while ((dev = next_device(&i)) && !error)
error = fn(dev, data);
klist_iter_exit(&i);
return error;
}
EXPORT_SYMBOL_GPL(bus_for_each_dev);
int spi_setup(struct spi_device *spi)
{
unsigned bad_bits, ugly_bits;
int status;
/* check mode to prevent that DUAL and QUAD set at the same time
*/
if (((spi->mode & SPI_TX_DUAL) && (spi->mode & SPI_TX_QUAD)) ||
((spi->mode & SPI_RX_DUAL) && (spi->mode & SPI_RX_QUAD))) {
dev_err(&spi->dev,
"setup: can not select dual and quad at the same time\n");
return -EINVAL;
}
/* if it is SPI_3WIRE mode, DUAL and QUAD should be forbidden
*/
if ((spi->mode & SPI_3WIRE) && (spi->mode &
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD)))
return -EINVAL;
/* help drivers fail *cleanly* when they need options
* that aren't supported with their current master
*/
bad_bits = spi->mode & ~spi->master->mode_bits;
ugly_bits = bad_bits &
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD);
if (ugly_bits) {
dev_warn(&spi->dev,
"setup: ignoring unsupported mode bits %x\n",
ugly_bits);
spi->mode &= ~ugly_bits;
bad_bits &= ~ugly_bits;
}
if (bad_bits) {
dev_err(&spi->dev, "setup: unsupported mode bits %x\n",
bad_bits);
return -EINVAL;
}
if (!spi->bits_per_word)
spi->bits_per_word = 8;
status = __spi_validate_bits_per_word(spi->master, spi->bits_per_word);
if (status)
return status;
if (!spi->max_speed_hz)
spi->max_speed_hz = spi->master->max_speed_hz;
if (spi->master->setup)
status = spi->master->setup(spi);
spi_set_cs(spi, false);
dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%u bits/w, %u Hz max --> %d\n",
(int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
(spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
(spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
(spi->mode & SPI_3WIRE) ? "3wire, " : "",
(spi->mode & SPI_LOOP) ? "loopback, " : "",
spi->bits_per_word, spi->max_speed_hz,
status);
return status;
}
EXPORT_SYMBOL_GPL(spi_setup);
static void spi_set_cs(struct spi_device *spi, bool enable)
{
if (spi->mode & SPI_CS_HIGH)
enable = !enable;
if (gpio_is_valid(spi->cs_gpio))
gpio_set_value(spi->cs_gpio, !enable);
else if (spi->master->set_cs)
spi->master->set_cs(spi, !enable);
}
static int mtk_spi_setup(struct spi_device *spi)
{
struct mtk_spi *mdata = spi_master_get_devdata(spi->master);
if (!spi->controller_data)
spi->controller_data = (void *)&mtk_default_chip_info;
if (mdata->dev_comp->need_pad_sel && gpio_is_valid(spi->cs_gpio))
gpio_direction_output(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
return 0;
}
static inline void *spi_master_get_devdata(struct spi_master *master)
{
return dev_get_drvdata(&master->dev);
}
static inline void *dev_get_drvdata(const struct device *dev)
{
return dev->driver_data;
}
int spi_sync(struct spi_device *spi, struct spi_message *message)
{
return __spi_sync(spi, message, 0);
}
EXPORT_SYMBOL_GPL(spi_sync);
static int spi_match_device(struct device *dev, struct device_driver *drv)
{
const struct spi_device *spi = to_spi_device(dev);
const struct spi_driver *sdrv = to_spi_driver(drv);
/* Attempt an OF style match */
if (of_driver_match_device(dev, drv))
return 1;
/* Then try ACPI */
if (acpi_driver_match_device(dev, drv))
return 1;
if (sdrv->id_table)
return !!spi_match_id(sdrv->id_table, spi);
return strcmp(spi->modalias, drv->name) == 0;
}
static int spi_uevent(struct device *dev, struct kobj_uevent_env *env)
{
const struct spi_device *spi = to_spi_device(dev);
int rc;
rc = acpi_device_uevent_modalias(dev, env);
if (rc != -ENODEV)
return rc;
add_uevent_var(env, "MODALIAS=%s%s", SPI_MODULE_PREFIX, spi->modalias);
return 0;
}
struct bus_type spi_bus_type = {
.name = "spi",
.dev_groups = spi_dev_groups,
.match = spi_match_device,
.uevent = spi_uevent,
};
EXPORT_SYMBOL_GPL(spi_bus_type);
static inline int driver_match_device(struct device_driver *drv,
struct device *dev)
{
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
}
=========dts start===============================
static inline int of_driver_match_device(struct device *dev,
const struct device_driver *drv)
{
return of_match_device(drv->of_match_table, dev) != NULL;
}
#define of_match_device(matches, dev) \
__of_match_device(of_match_ptr(matches), (dev))
=========dts end===============================
int __spi_register_driver(struct module *owner, struct spi_driver *sdrv)
{
sdrv->driver.owner = owner;
sdrv->driver.bus = &spi_bus_type;
if (sdrv->probe)
sdrv->driver.probe = spi_drv_probe;
if (sdrv->remove)
sdrv->driver.remove = spi_drv_remove;
if (sdrv->shutdown)
sdrv->driver.shutdown = spi_drv_shutdown;
return driver_register(&sdrv->driver);
}
EXPORT_SYMBOL_GPL(__spi_register_driver);
int driver_register(struct device_driver *drv)
{
int ret;
struct device_driver *other;
BUG_ON(!drv->bus->p);
if ((drv->bus->probe && drv->probe) ||
(drv->bus->remove && drv->remove) ||
(drv->bus->shutdown && drv->shutdown))
printk(KERN_WARNING "Driver '%s' needs updating - please use "
"bus_type methods\n", drv->name);
other = driver_find(drv->name, drv->bus);
if (other) {
printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name);
return -EBUSY;
}
ret = bus_add_driver(drv);
if (ret)
return ret;
ret = driver_add_groups(drv, drv->groups);
if (ret) {
bus_remove_driver(drv);
return ret;
}
kobject_uevent(&drv->p->kobj, KOBJ_ADD);
return ret;
}
EXPORT_SYMBOL_GPL(driver_register);
struct mtk_spi {
void __iomem *base;
void __iomem *peri_regs;
u32 state;
int pad_num;
u32 *pad_sel;
struct clk *parent_clk, *sel_clk, *spi_clk;
struct spi_transfer *cur_transfer;
u32 xfer_len;
struct scatterlist *tx_sgl, *rx_sgl;
u32 tx_sgl_len, rx_sgl_len;
const struct mtk_spi_compatible *dev_comp;
u32 dram_8gb_offset;
};
=========================================
OTHER:
=========================================
========1================================
static LIST_HEAD(spi_master_list);
LIST_HEAD: 双向链表结构体的指针的数据结构
========2==start========================
#define module_platform_driver(__platform_driver) \
module_driver(__platform_driver, platform_driver_register, \
platform_driver_unregister)
==>
#define module_driver(__driver, __register, __unregister, ...) \
static int __init __driver##_init(void) \
{ \
return __register(&(__driver) , ##__VA_ARGS__); \
} \
module_init(__driver##_init); \
static void __exit __driver##_exit(void) \
{ \
__unregister(&(__driver) , ##__VA_ARGS__); \
} \
module_exit(__driver##_exit);
==>
module_platform_driver(xxx);
最终展开后就是如下形式:
static int __init xxx_init(void)
{
return platform_driver_register(&xxx);
}
module_init(xxx_init);
static void __exit xxx_init(void)
{
return platform_driver_unregister(&xxx);
}
module_exit(xxx_exit);
========2==end=========================
========3==start=========================
将new所代表的list_head插入head所索引的队列的尾部
static inline void list_add_tail(struct list_head *new, struct list_head *head)
{
__list_add(new, head->prev, head);
}
static inline void __list_add(struct list_head *new,
struct list_head *prev,
struct list_head *next)
{
next->prev = new; //(1)
new->next = next; //(2)
new->prev = prev; //(3)
prev->next = new; //(4)
}
----------------------------------------------------------------------------------
#define list_for_each_entry(pos, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member); \
&pos->member != (head); \
pos = list_next_entry(pos, member))
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)
#define list_entry(ptr, type, member) \
container_of(ptr, type, member
container_of: 根据member的地址计算出contain(list)的首地址
#define list_next_entry(pos, member) \
list_entry((pos)->member.next, typeof(*(pos)), member)
list_next_entry: 如果next为空 => 计算不出首地址 => 退出循环
========3==end=========================