mtk_spi 总线架构

3 篇文章 0 订阅
3 篇文章 0 订阅
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 = <GIC_SPI 118 IRQ_TYPE_LEVEL_LOW>;
        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 = <GIC_SPI 122 IRQ_TYPE_LEVEL_LOW>;
        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 = <GIC_SPI 128 IRQ_TYPE_LEVEL_LOW>;
        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 = <GIC_SPI 118 IRQ_TYPE_LEVEL_LOW>;
            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=========================

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值