imx6 spi分析

/**************************************************************************
 *本文主要跟踪imx6 spi设备和驱动的注册过程。
 *
 *                                    Tony Liu, 2016-4-13, Shenzhen
 *************************************************************************/                                                                                

kernel/arch/arm/mach-mx6/board-mx6q_sabresd.c                                   

MACHINE_START(MX6Q_SABRESD, "Freescale i.MX 6Quad/DualLite/Solo Sabre-SD Board")
    /* Maintainer: Freescale Semiconductor, Inc. */
    .boot_params = MX6_PHYS_OFFSET + 0x100,
    .fixup = fixup_mxc_board,
    .map_io = mx6_map_io,
    .init_irq = mx6_init_irq,
    .init_machine = mx6_sabresd_board_init,
    .timer = &mx6_sabresd_timer,         |
    .reserve = mx6q_sabresd_reserve,     |
MACHINE_END                              |
                                         V
static void __init mx6_sabresd_board_init(void)
{
    ... ...
    imx6q_add_ecspi(0, &mx6q_sabresd_spi_data);
    imx6q_add_ecspi(1, &mx6q_sabresd_spi2_data);
    spi_device_init();        --------------------------------------------+
    ... ...                               |                               |
}                                         |                               |
                                          V                               |
static const struct spi_imx_master mx6q_sabresd_spi_data __initconst = {  |
    .chipselect     = mx6q_sabresd_spi_cs,        --------+               |
    .num_chipselect = ARRAY_SIZE(mx6q_sabresd_spi_cs),    |               |
};                                                        |               |
                                                          |               |
static int mx6q_sabresd_spi_cs[] = {             <--------+               |
    SABRESD_ECSPI1_CS1,                                                   |
};                                                                        |
#define SABRESD_ECSPI1_CS1     IMX_GPIO_NR(3, 19)                         |
                                                                          |
//注册平台设备                                                            |
#define imx6q_add_ecspi(id, pdata)    \                                   |
    imx_add_spi_imx(&imx6q_ecspi_data[id], pdata)  ----+                  |
                                                       |                  |
struct platform_device *__init imx_add_spi_imx(    <---+                  |
        const struct imx_spi_imx_data *data,                              |
        const struct spi_imx_master *pdata)                               |
{                                                                         |
    struct resource res[] = {                                             |
        {                                                                 |
            .start = data->iobase,                                        |
            .end = data->iobase + data->iosize - 1,                       |
            .flags = IORESOURCE_MEM,                                      |
        }, {                                                              |
            .start = data->irq,                                           |
            .end = data->irq,                                             |
            .flags = IORESOURCE_IRQ,                                      |
        },                                                                |
    };                                                                    |
    return imx_add_platform_device(data->devid, data->id,                 |
            res, ARRAY_SIZE(res), pdata, sizeof(*pdata));                 |
}                                                                         |
                                                                          |
static void spi_device_init(void)                <------------------------+
{
    spi_register_board_info(imx6_sabresd_spi_nor_device,     -------------+
                ARRAY_SIZE(imx6_sabresd_spi_nor_device));                 |
}                                            |                            |
                                             V                            |
static struct spi_board_info imx6_sabresd_spi_nor_device[] __initdata = { |
#if 0                                                                     |
#if defined(CONFIG_MTD_M25P80)                                            |
    {                                                                     |
        .modalias = "m25p80",                                             |
        .max_speed_hz = 20000000, /* max spi clock (SCK) speed in HZ */   |
        .bus_num = 0,                                                     |
        .chip_select = 0,                                                 |
        .platform_data = &imx6_sabresd__spi_flash_data,                   |
    },                                                                    |
#endif                                                                    |
#endif                                                                    |
    {                                                                     |
        .modalias = "ar1020-spi",                                         |
        .max_speed_hz = 50000, /* max spi clock (SCK) speed in HZ */      |
        .bus_num = 1,                                                     |
        .chip_select = 0,                                                 |
        .mode = SPI_MODE_1,                                               |
        .irq = gpio_to_irq(SABRESD_AR1020_INT),                           |
                                                                          |
        //.platform_data = &imx6_sabresd__spi_flash_data,                 |
    },                                                                    |
                                                                          |
};                                                                        |
                                                                          |
int __init                                                                |
spi_register_board_info(struct spi_board_info const *info, unsigned n) <--+
{
    struct boardinfo *bi;
    int i;                                                                      

    bi = kzalloc(n * sizeof(*bi), GFP_KERNEL);
    if (!bi)
        return -ENOMEM;                                                         

    for (i = 0; i < n; i++, bi++, info++) {
        struct spi_master *master;                                              

        memcpy(&bi->board_info, info, sizeof(*info));
        mutex_lock(&board_lock);
        //将所有的spi设备添加到链表中
        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);
        mutex_unlock(&board_lock);
    }                                                                           

    return 0;
}                                                                               

kernel/drivers/spi/spi_imx.c
static int __init spi_imx_init(void)
{
    return platform_driver_register(&spi_imx_driver);
}                                     |
                                      V
static struct platform_driver spi_imx_driver = {
    .driver = {
           .name = DRIVER_NAME,            // "spi_imx"
           .owner = THIS_MODULE,
           },
    .id_table = spi_imx_devtype,
    .probe = spi_imx_probe,                 -------+
    .remove = __devexit_p(spi_imx_remove),         |
};                                                 |
                                                   V
static int __devinit spi_imx_probe(struct platform_device *pdev)
{
    struct spi_imx_master *mxc_platform_info;
    struct spi_master *master;
    struct spi_imx_data *spi_imx;
    struct resource *res;
    int i, ret;                                                                 

    mxc_platform_info = dev_get_platdata(&pdev->dev);
    if (!mxc_platform_info) {
        dev_err(&pdev->dev, "can‘t get the platform data\n");
        return -EINVAL;
    }                                                                           

    master = spi_alloc_master(&pdev->dev, sizeof(struct spi_imx_data));
    if (!master)
        return -ENOMEM;                                                         

    platform_set_drvdata(pdev, master);                                         

    master->bus_num = pdev->id;
    master->num_chipselect = mxc_platform_info->num_chipselect;                 

    spi_imx = spi_master_get_devdata(master);
    spi_imx->bitbang.master = spi_master_get(master);     ---------------------+
    spi_imx->chipselect = mxc_platform_info->chipselect;                       |
    //控制spi的chipselect引脚                                                    |
    for (i = 0; i < master->num_chipselect; i++) {                             |
        if (spi_imx->chipselect[i] < 0)                                        |
            continue;                                                          |
        ret = gpio_request(spi_imx->chipselect[i], DRIVER_NAME);               |
        if (ret) {                                                             |
            while (i > 0) {                                                    |
                i--;                                                           |
                if (spi_imx->chipselect[i] >= 0)                               |
                    gpio_free(spi_imx->chipselect[i]);                         |
            }                                                                  |
            dev_err(&pdev->dev, "can‘t get cs gpios\n");                       |
            goto out_master_put;                                               |
        }                                                                      |
    }                                                                          |
    // spi 对应的操作函数                                                      |
    spi_imx->bitbang.chipselect = spi_imx_chipselect;                          |
    spi_imx->bitbang.setup_transfer = spi_imx_setupxfer;                       |
    spi_imx->bitbang.txrx_bufs = spi_imx_transfer;                             |
    spi_imx->bitbang.master->setup = spi_imx_setup;                            |
    spi_imx->bitbang.master->cleanup = spi_imx_cleanup;                        |
    spi_imx->bitbang.master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;    |
                                                                               |
    init_completion(&spi_imx->xfer_done);                                      |
                                                                               |
    spi_imx->devtype_data =                                                    |
        spi_imx_devtype_data[pdev->id_entry->driver_data];                     |
                                                                               |
    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);                      |
    if (!res) {                                                                |
        dev_err(&pdev->dev, "can‘t get platform resource\n");                  |
        ret = -ENOMEM;                                                         |
        goto out_gpio_free;                                                    |
    }                                                                          |
                                                                               |
    if (!request_mem_region(res->start, resource_size(res), pdev->name)) {     |
        dev_err(&pdev->dev, "request_mem_region failed\n");                    |
        ret = -EBUSY;                                                          |
        goto out_gpio_free;                                                    |
    }                                                                          |
                                                                               |
    spi_imx->base = ioremap(res->start, resource_size(res));                   |
    if (!spi_imx->base) {                                                      |
        ret = -EINVAL;                                                         |
        goto out_release_mem;                                                  |
    }                                                                          |
                                                                               |
    spi_imx->irq = platform_get_irq(pdev, 0);                                  |
    if (spi_imx->irq < 0) {                                                    |
        ret = -EINVAL;                                                         |
        goto out_iounmap;                                                      |
    }                                                                          |
                                                                               |
    ret = request_irq(spi_imx->irq, spi_imx_isr, 0, DRIVER_NAME, spi_imx);     |
    if (ret) {                                                                 |
        dev_err(&pdev->dev, "can‘t get irq%d: %d\n", spi_imx->irq, ret);       |
        goto out_iounmap;                                                      |
    }                                                                          |
                                                                               |
    spi_imx->clk = clk_get(&pdev->dev, NULL);                                  |
    if (IS_ERR(spi_imx->clk)) {                                                |
        dev_err(&pdev->dev, "unable to get clock\n");                          |
        ret = PTR_ERR(spi_imx->clk);                                           |
        goto out_free_irq;                                                     |
    }                                                                          |
                                                                               |
    clk_enable(spi_imx->clk);                                                  |
    spi_imx->spi_clk = clk_get_rate(spi_imx->clk);                             |
                                                                               |
    spi_imx->devtype_data.reset(spi_imx);                                      |
                                                                               |
    spi_imx->devtype_data.intctrl(spi_imx, 0);                                 |
    ret = spi_bitbang_start(&spi_imx->bitbang);                                |
    if (ret) {                                                                 |
        dev_err(&pdev->dev, "bitbang start failed with %d\n", ret);            |
        goto out_clk_put;                                                      |
    }                                                                          |
    clk_disable(spi_imx->clk);                                                 |
                                                                               |
    dev_info(&pdev->dev, "probed\n");                                          |
                                                                               |
    return ret;                                                                |
                                                                               |
out_clk_put:                                                                   |
    clk_disable(spi_imx->clk);                                                 |
    clk_put(spi_imx->clk);                                                     |
out_free_irq:                                                                  |
    free_irq(spi_imx->irq, spi_imx);                                           |
out_iounmap:                                                                   |
    iounmap(spi_imx->base);                                                    |
out_release_mem:                                                               |
    release_mem_region(res->start, resource_size(res));                        |
out_gpio_free:                                                                 |
    for (i = 0; i < master->num_chipselect; i++)                               |
        if (spi_imx->chipselect[i] >= 0)                                       |
            gpio_free(spi_imx->chipselect[i]);                                 |
out_master_put:                                                                |
    spi_master_put(master);                                                    |
    kfree(master);                                                             |
    platform_set_drvdata(pdev, NULL);                                          |
    return ret;                                                                |
}                                                                              |
                                                                               |
int spi_bitbang_start(struct spi_bitbang *bitbang)           <-----------------+
{
    int    status;                                                              

    if (!bitbang->master || !bitbang->chipselect)
        return -EINVAL;                                                         

    INIT_WORK(&bitbang->work, bitbang_work);
    spin_lock_init(&bitbang->lock);
    INIT_LIST_HEAD(&bitbang->queue);                                            

    if (!bitbang->master->mode_bits)
        bitbang->master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;      

    if (!bitbang->master->transfer)
        bitbang->master->transfer = spi_bitbang_transfer;
    if (!bitbang->txrx_bufs) {
        bitbang->use_dma = 0;
        bitbang->txrx_bufs = spi_bitbang_bufs;
        if (!bitbang->master->setup) {
            if (!bitbang->setup_transfer)
                bitbang->setup_transfer =
                     spi_bitbang_setup_transfer;
            bitbang->master->setup = spi_bitbang_setup;
            bitbang->master->cleanup = spi_bitbang_cleanup;
        }
    } else if (!bitbang->master->setup)
        return -EINVAL;
    if (bitbang->master->transfer == spi_bitbang_transfer &&
            !bitbang->setup_transfer)
        return -EINVAL;                                                         

    /* this task is the only thing to touch the SPI bits */
    bitbang->busy = 0;
    bitbang->workqueue = create_singlethread_workqueue(
            dev_name(bitbang->master->dev.parent));
    if (bitbang->workqueue == NULL) {
        status = -EBUSY;
        goto err1;
    }                                                                           

    /* driver may get busy before register() returns, especially
     * if someone registered boardinfo for devices
     */
    status = spi_register_master(bitbang->master);  -----+
    if (status < 0)                                      |
        goto err2;                                       |
                                                         |
    return status;                                       |
                                                         |
err2:                                                    |
    destroy_workqueue(bitbang->workqueue);               |
err1:                                                    |
    return status;                                       |
}                                                        |
                                                         |
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;                                                         

    /* even if it‘s just one always-selected device, there must
     * be at least one chipselect
     */
    if (master->num_chipselect == 0)
        return -EINVAL;                                                         

    /* 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;                                                  

    /* register the device, then userspace will see it.
     * registration fails if the bus ID is in use.
     */
    //设置设备节点的设备名 /dev/spi0, /dev/spi1
    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)" : "");                                       

    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);                                                  

    status = 0;                                                                 

    /* Register devices from the device tree */
    of_register_spi_devices(master);
done:
    return status;
}                                                                               
时间: 2024-10-05 01:37:25

imx6 spi分析的相关文章

Imx6 spi时钟

阅读手册知,imx6 的 spi 时钟是针对某一个 spi 通道进行配置的.imx6下共有5个 spi通道,spi1 ~ spi5 以下为手册相关内容说明: CCGR1 寄存器相关内容

imx6 i2c分析

本文主要分析: 1. i2c设备注册 2. i2c驱动注册 3. 上层调用过程参考: http://www.cnblogs.com/helloworldtoyou/p/5126618.html 1. i2c设备注册 kernel/arch/arm/mach-mx6/board-mx6q_sabresd.c static void __init mx6_sabresd_board_init(void) { mxc_iomux_v3_setup_multiple_pads(mx6q_sabresd_

imx6 spi slave 数据接收时移位寄存器的工作机理

如上图, 移位寄存器(shift register)及 接收FIFO (RXDATA)对程序来说是透明的. 唯一可访问的 Receive Data Register (ECSPIx_RXDATA) 只能访问 接收FIFO的 top 字.如下: 当把 spi2 配置成为 slave 模式时,外部的主spi 端将数据发送到 spi 的 MOSI 线上,mosi线上的数据是按bit 传输的. 在 bpw 配置为 32时,移位寄存器中 每满 32bit 才可以向 接收FIFO 打一个字. 如果,mosi

linux3.2 spi框架分析

刘术河 2017.04.12 写oled的驱动时,核心板用的是am335x,spi用的是ti自带的spi驱动框架,为了弄清楚spi底层工作流程,特意分析了spi驱动框架 g:\嵌入式\linux-3.2.0\arch\arm\mach-omap2\Board-am335xevm.c 该文件是am335x的板级配置文件 1.配置spi的管脚复用功能 static struct pinmux_config spi1_pin_mux[] = { {"mcasp0_aclkx.spi1_sclk&quo

关于 printk() 对 spi slave 内核驱动程序的性能影响

调试 imx6 的 spi slave 内核驱动,前期调试总免不了得要追一下寄存器的设置,过程函数的调用. 采用了 printk() 打印语句. 1.采用的硬件方法是: 分析 imx6 spi slave 的各路引脚主要是 clk, cs, mosi, miso, gnd, vcc,连接至spi 主端(CC1110f32 MCU) 的各路对应引脚.对应如下:  imx6 spi 从机 cc1110f32 spi 主机 vcc vcc gnd gnd clk clk cs cs mosi mosi

Linux SPI初始化及接口函数代码细究

2012-01-08 22:11:38 目的:我需要掌握spi驱动相关数据结构关系,及在哪部分函数中把这些数值进行底层寄存器赋值的.结合应用层函数完成spi驱动的代码测试.已达到灵活修改的目的. 按顺序看probe函数中 if (!pdata->set_cs) 则              hw->set_cs = s3c24xx_spi_gpiocs; gpio_direction_output(pdata->pin_cs, 1); 由于我的platform_device.platfo

spi协议及工作原理分析

转自----http://blog.csdn.net/skyflying2012/article/details/11710801 一.概述. SPI, Serial Perripheral Interface, 串行外围设备接口, 是 Motorola 公司推出的一种同步串行接口技术. SPI 总线在物理上是通过接在外围设备微控制器(PICmicro) 上面的微处理控制单元 (MCU) 上叫作同步串行端口(Synchronous Serial Port) 的模块(Module)来实现的, 它允

Solr4.8.0源码分析(7)之Solr SPI

Solr4.8.0源码分析(7)之Solr SPI 查看Solr源码时候会发现,每一个package都会由对应的resources. 如下图所示: 一时对这玩意好奇了,看了文档以后才发现,这个services就是java SPI机制.首先介绍下java SPI机制,然后再结合Solr谈一下SPI. 1. JAVA SPI 当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件.该文件里就是实现该服务接口的具体实现类.而

Motan的SPI机制实现分析

Motan使用SPI机制来实现模块间的访问,基于接口和name来获取实现类,降低了模块间的耦合. 首先来看一下使用方式: 有两个注解 @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) public @interface Spi { Scope scope() default Scope.PROTOTYPE; } @Documented @Retention(RetentionPolicy.RUN