Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1710632
  • 博文数量: 143
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 1462
  • 用 户 组: 普通用户
  • 注册时间: 2016-08-23 11:14
文章分类

全部博文(143)

文章存档

2022年(3)

2021年(13)

2020年(21)

2019年(8)

2018年(28)

2017年(7)

2016年(63)

我的朋友

分类: 嵌入式

2016-08-27 15:52:46

背景介绍:本文参考:http://blog.csdn.net/qq345260600/article/details/7851620 和 http://blog.chinaunix.net/uid-27717694-id-3774328.html 对ICETEK OMAPL138开发板自带的Linux内核SPI子系统的代码走读了一遍。我根据自身对SPI子系统的认识,对SPI代码划分为以下几个部分。
1 第一阶段 初始化
static struct spi_board_info da850_spi_board_info[] = {
       [0] = {
               .modalias = "m25p80",
               .platform_data = &spi_flash_data,
               .mode = SPI_MODE_0,
               .max_speed_hz = 30000000,       /* max sample rate at 3V */
               .bus_num = 1,
               .chip_select = 0,
       },
};
static __init void da850_evm_init(void)
{
...
       ret = da8xx_pinmux_setup(da850_spi1_pins);
       if (ret)
               pr_warning("da850_evm_init: spi1 mux setup failed: %d\n",
                               ret);

       da850_init_spi1(BIT(0), da850_spi_board_info,
                       ARRAY_SIZE(da850_spi_board_info));
...
}
很明显,是先配置spi pinmux;再配置spi1。而pinmux的配置请参考我另一篇文章,这里我们研究da850_init_spi1:
static struct davinci_spi_platform_data da850_spi1_pdata = {
       .version        = SPI_VERSION_2,
       .num_chipselect = 1,
       .wdelay         = 0,
       .odd_parity     = 0,
       .parity_enable  = 0,
       .wait_enable    = 0,
       .timer_disable  = 0,
       .clk_internal   = 1,
       .cs_hold        = 1,
       .intr_level     = 1,
       .poll_mode      = 1,
       .use_dma        = 1,
       .c2tdelay       = 8,
       .t2cdelay       = 8,
};
static struct resource da850_spi1_resources[] = {
       [0] = {
               .start = 0x01F0E000,
               .end = 0x01F0E000 + 0xfff,
               .flags = IORESOURCE_MEM,
       },
       [1] = {
               .start = IRQ_DA8XX_SPINT1,
               .end = IRQ_DA8XX_SPINT1,
               .flags = IORESOURCE_IRQ,
       },
       [2] = {
               .start = EDMA_CTLR_CHAN(0, 18),
               .end = EDMA_CTLR_CHAN(0, 18),
               .flags = IORESOURCE_DMA,
       },
       [3] = {
               .start = EDMA_CTLR_CHAN(0, 19),
               .end = EDMA_CTLR_CHAN(0, 19),
               .flags = IORESOURCE_DMA,
       },
       [4] = {
               .start = 1,
               .end = 1,
               .flags = IORESOURCE_DMA,
       },
};
static struct platform_device da850_spi1_device = {
       .name = "spi_davinci",
       .id = 1,
       .resource = da850_spi1_resources,
       .num_resources = ARRAY_SIZE(da850_spi1_resources),
       .dev = {
               .platform_data = &da850_spi1_pdata,
       },
};
void __init da850_init_spi1(unsigned chipselect_mask,
               struct spi_board_info *info, unsigned len)
{
       //注册spi device的信息到board_list链表中,待spi master注册好后扫描board_list链表,再正真注册spi device
       spi_register_board_info(info, len);

       //注册spi1的platform_device
       platform_device_register(&da850_spi1_device);
}
接下来,我们分开看spi_register_board_info()和platform_device_register()
1.1 第一.一阶段 注册spi device到board_list 重点关注spi_register_board_info()
/**
* spi_register_board_info - register SPI devices for a given board
* @info: array of chip descriptors
* @n: how many descriptors are provided
* Context: can sleep
*
* Board-specific early init code calls this (probably during arch_initcall)
* with segments of the SPI device table.  Any device nodes are created later,
* after the relevant parent SPI controller (bus_num) is defined.  We keep
* this table of devices forever, so that reloading a controller driver will
* not make Linux forget about these hard-wired devices.
*
* Other code can also call this, e.g. a particular add-on board might provide
* SPI devices through its expansion connector, so code initializing that board
* would naturally declare its SPI devices.
*
* The board info passed can safely be __initdata ... but be careful of
* any embedded pointers (platform_data, etc), they're copied as-is.
*/
int __init
spi_register_board_info(struct spi_board_info const *info, unsigned n)
{
       struct boardinfo        *bi;

       printk(KERN_INFO "spi_board_info is %d\n", n);
       bi = kmalloc(sizeof(*bi) + n * sizeof *info, GFP_KERNEL);
       if (!bi)
               return -ENOMEM;
       bi->n_board_info = n;
       memcpy(bi->board_info, info, n * sizeof *info);

       mutex_lock(&board_lock);
       list_add_tail(&bi->list, &board_list);//【重点函数 1】挂载到全局链表board_list中,待spi控制器注册后,将会扫描board_list链表进行匹配,才正真注册spi device
       mutex_unlock(&board_lock);
       return 0;
}
1.2 第一.二阶段 注册platform_device 重点关注platform_device_register()
/**
* platform_device_register - add a platform-level device
* @pdev: platform device we're adding
*/
int platform_device_register(struct platform_device *pdev)
{
       device_initialize(&pdev->dev);
       return platform_device_add(pdev);
}
EXPORT_SYMBOL_GPL(platform_device_register);
如下仅将2个被调用函数列出,并不继续研究。
/**
* device_initialize - init device structure.
* @dev: device.
*
* This prepares the device for use by other layers by initializing
* its fields.
* It is the first half of device_register(), if called by
* that function, though it can also be called separately, so one
* may use @dev's fields. In particular, get_device()/put_device()
* may be used for reference counting of @dev after calling this
* function.
*
* NOTE: Use put_device() to give up your reference instead of freeing
* @dev directly once you have called this function.
*/
void device_initialize(struct device *dev)
{
       dev->kobj.kset = devices_kset;
       kobject_init(&dev->kobj, &device_ktype);
       INIT_LIST_HEAD(&dev->dma_pools);
       init_MUTEX(&dev->sem);
       spin_lock_init(&dev->devres_lock);
       INIT_LIST_HEAD(&dev->devres_head);
       device_init_wakeup(dev, 0);
       device_pm_init(dev);
       set_dev_node(dev, -1);
}
EXPORT_SYMBOL_GPL(device_initialize);
/**
* platform_device_add - add a platform device to device hierarchy
* @pdev: platform device we're adding
*
* This is part 2 of platform_device_register(), though may be called
* separately _iff_ pdev was allocated by platform_device_alloc().
*/
int platform_device_add(struct platform_device *pdev)
{
       int i, ret = 0;

       if (!pdev)
               return -EINVAL;

       if (!pdev->dev.parent)
               pdev->dev.parent = &platform_bus;

       pdev->dev.bus = &platform_bus_type;

       if (pdev->id != -1)
               dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
       else
               dev_set_name(&pdev->dev, "%s", pdev->name);

       for (i = 0; i < pdev->num_resources; i++) {
               struct resource *p, *r = &pdev->resource[i];

               if (r->name == NULL)
                       r->name = dev_name(&pdev->dev);

               p = r->parent;
               if (!p) {
                       if (resource_type(r) == IORESOURCE_MEM)
                               p = &iomem_resource;
                       else if (resource_type(r) == IORESOURCE_IO)
                               p = &ioport_resource;
               }

               if (p && insert_resource(p, r)) {
                       printk(KERN_ERR
                              "%s: failed to claim resource %d\n",
                              dev_name(&pdev->dev), i);
                       ret = -EBUSY;
                       goto failed;
               }
       }

       pr_debug("Registering platform device '%s'. Parent at %s\n",
                dev_name(&pdev->dev), dev_name(pdev->dev.parent));

       ret = device_add(&pdev->dev);
       if (ret == 0)
               return ret;

failed:
       while (--i >= 0) {
               struct resource *r = &pdev->resource[i];
               unsigned long type = resource_type(r);

               if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
                       release_resource(r);
       }

       return ret;
}
EXPORT_SYMBOL_GPL(platform_device_add);

2 第二阶段 注册platform_driver 重点关注platform_driver_register()
static struct platform_driver davinci_spi_driver = {
       .driver.name = "spi_davinci",
       .remove = __exit_p(davinci_spi_remove),
       .suspend = davinci_spi_suspend,
       .resume = davinci_spi_resume,
};
static int __init davinci_spi_init(void)
{
       return platform_driver_probe(&davinci_spi_driver, davinci_spi_probe);
}
module_init(davinci_spi_init);
那么就调用到“核心层”的函数接口,在/driver/base/platform.c中:
/**
* platform_driver_probe - register driver for non-hotpluggable device
* @drv: platform driver structure
* @probe: the driver probe routine, probably from an __init section
*
* Use this instead of platform_driver_register() when you know the device
* is not hotpluggable and has already been registered, and you want to
* remove its run-once probe() infrastructure from memory after the driver
* has bound to the device.
*
* One typical use for this would be with drivers for controllers integrated
* into system-on-chip processors, where the controller devices have been
* configured as part of board setup.
*
* Returns zero if the driver registered and bound to a device, else returns
* a negative error code and with the driver not registered.
*/
int __init_or_module platform_driver_probe(struct platform_driver *drv,
               int (*probe)(struct platform_device *))
{
       int retval, code;

       /* make sure driver won't have bind/unbind attributes */
       drv->driver.suppress_bind_attrs = true;

       /* temporary section violation during probe() */
       drv->probe = probe;
       retval = code = platform_driver_register(drv);//其实看得出参数davinci_spi_probe仅仅是被注册到davinci_spi_driver->probe下,而真正要调用的是platform_driver_register(davinci_spi_driver),所以有些版本的内核中无davinci_spi_probe(),而是直接调用platform_driver_register()。

       /*
        * Fixup that section violation, being paranoid about code scanning
        * the list of drivers in order to probe new devices.  Check to see
        * if the probe was successful, and make sure any forced probes of
        * new devices fail.
        */
       spin_lock(&platform_bus_type.p->klist_drivers.k_lock);
       drv->probe = NULL;
       if (code == 0 && list_empty(&drv->driver.p->klist_devices.k_list))
               retval = -ENODEV;
       drv->driver.probe = platform_drv_probe_fail;
       spin_unlock(&platform_bus_type.p->klist_drivers.k_lock);

       if (code != retval)
               platform_driver_unregister(drv);
       return retval;
}
EXPORT_SYMBOL_GPL(platform_driver_probe);

3 第三阶段 注册一个用于描述spi控制器的结构体spi_master和正真注册spi device 重点关注spi_register_master()
关于platform我们就不再深入研究了,我们只需要知道:当platform_device(即da850_spi1_device)和platform_drvier(即davinci_spi_driver)匹配成功后,会执行驱动中的×××_probe(即davinci_spi_probe)。那么,接着看davinci_spi_probe:
/*
* davinci_spi_probe - probe function for SPI Master Controller
* pdev: platform_device structure which contains plateform specific data
*/
static int davinci_spi_probe(struct platform_device *pdev)
{
       struct spi_master *master;
       struct davinci_spi *davinci_spi;
       struct davinci_spi_platform_data *pdata;
       struct resource *r, *mem;
       resource_size_t dma_rx_chan = SPI_NO_RESOURCE;
       resource_size_t dma_tx_chan = SPI_NO_RESOURCE;
       resource_size_t dma_eventq = SPI_NO_RESOURCE;
       int i = 0, ret = 0;

       pdata = pdev->dev.platform_data;
       if (pdata == NULL) {
               ret = -ENODEV;
               goto err;
       }

       //分配一个spi控制器的spi_master结构,分配struct spi_master + struct davinci_spi大小的数据,把davinci_spi设为spi_master的私有数据
       master = spi_alloc_master(&pdev->dev, sizeof(struct davinci_spi));
       if (master == NULL) {
               ret = -ENOMEM;
               goto err;
       }

       //把spi_master设置为platform_device结构中dev的私有数据
       dev_set_drvdata(&pdev->dev, master);

       //从master中获得私有数据davinci_spi
       davinci_spi = spi_master_get_devdata(master);
       if (davinci_spi == NULL) {
               ret = -ENOENT;
               goto free_master;
       }

       //从platform device的私有数据中获得spi控制器的寄存器物理地址资源
       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
       if (r == NULL) {
               ret = -ENOENT;
               goto free_master;
       }

       davinci_spi->pbase = r->start;//spi寄存器起始物理地址
       davinci_spi->region_size = resource_size(r);
       davinci_spi->pdata = pdata;

       //为spi控制器的物理地址申请内存空间
       mem = request_mem_region(r->start, davinci_spi->region_size,
                                       pdev->name);
       if (mem == NULL) {
               ret = -EBUSY;
               goto free_master;
       }

       //将spi控制器的寄存器物理地址映射到内核空间
       davinci_spi->base = (struct davinci_spi_reg __iomem *)
                       ioremap(r->start, davinci_spi->region_size);
       if (davinci_spi->base == NULL) {
               ret = -ENOMEM;
               goto release_region;
       }

       //从platform device的私有数据中获得spi控制器的中断号
       davinci_spi->irq = platform_get_irq(pdev, 0);
       if (davinci_spi->irq <= 0) {
               ret = -EINVAL;
               goto unmap_io;
       }

       //申请中断号
       ret = request_irq(davinci_spi->irq, davinci_spi_irq, IRQF_DISABLED,
                         dev_name(&pdev->dev), davinci_spi);
       if (ret)
               goto unmap_io;

       /* Allocate tmp_buf for tx_buf */
       davinci_spi->tmp_buf = kzalloc(SPI_BUFSIZ, GFP_KERNEL);
       if (davinci_spi->tmp_buf == NULL) {
               ret = -ENOMEM;
               goto irq_free;
       }

       //spi master计数加1
       davinci_spi->bitbang.master = spi_master_get(master);
       if (davinci_spi->bitbang.master == NULL) {
               ret = -ENODEV;
               goto free_tmp_buf;
       }

       //获得spi时钟
       davinci_spi->clk = clk_get(&pdev->dev, NULL);
       if (IS_ERR(davinci_spi->clk)) {
               ret = -ENODEV;
               goto put_master;
       }
       clk_enable(davinci_spi->clk);


       master->bus_num = pdev->id;//spi控制器所在的spi总线号
       master->num_chipselect = pdata->num_chipselect;//spi控制器的片选数量
       master->setup = davinci_spi_setup;//spi控制器的setup函数
       master->cleanup = davinci_spi_cleanup;

       //spi_bitbang专门负责数据的传输
       davinci_spi->bitbang.chipselect = davinci_spi_chipselect;//片选选择函数
       davinci_spi->bitbang.setup_transfer = davinci_spi_setup_transfer;//建立传输的函数

       davinci_spi->version = pdata->version;//版本号SPI_VERSION_2
       use_dma = pdata->use_dma;

       //设置一些标志位
       davinci_spi->bitbang.flags = SPI_NO_CS | SPI_LSB_FIRST | SPI_LOOP;
       if (davinci_spi->version == SPI_VERSION_2)
               davinci_spi->bitbang.flags |= SPI_READY;

       //DMA操作的一些设置
       if (use_dma) {
                       r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
                       if (r)
                               dma_rx_chan = r->start;
                       r = platform_get_resource(pdev, IORESOURCE_DMA, 1);
                       if (r)
                               dma_tx_chan = r->start;
                       r = platform_get_resource(pdev, IORESOURCE_DMA, 2);
                       if (r)
                               dma_eventq = r->start;
       }

       if (!use_dma ||
           dma_rx_chan == SPI_NO_RESOURCE ||
           dma_tx_chan == SPI_NO_RESOURCE ||
           dma_eventq  == SPI_NO_RESOURCE) {
               davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_pio;
               use_dma = 0;
       } else {
               davinci_spi->bitbang.txrx_bufs = davinci_spi_bufs_dma;
               davinci_spi->dma_channels = kzalloc(master->num_chipselect
                               * sizeof(struct davinci_spi_dma), GFP_KERNEL);
               if (davinci_spi->dma_channels == NULL) {
                       ret = -ENOMEM;
                       goto free_clk;
               }

               for (i = 0; i < master->num_chipselect; i++) {
                       davinci_spi->dma_channels[i].dma_rx_channel = -1;
                       davinci_spi->dma_channels[i].dma_rx_sync_dev =
                               dma_rx_chan;
                       davinci_spi->dma_channels[i].dma_tx_channel = -1;
                       davinci_spi->dma_channels[i].dma_tx_sync_dev =
                               dma_tx_chan;
                       davinci_spi->dma_channels[i].eventq = dma_eventq;
               }
               dev_info(&pdev->dev, "DaVinci SPI driver in EDMA mode\n"
                               "Using RX channel = %d , TX channel = %d and "
                               "event queue = %d", dma_rx_chan, dma_tx_chan,
                               dma_eventq);
       }

       //设置spi的读写函数
       davinci_spi->get_rx = davinci_spi_rx_buf_u8;
       davinci_spi->get_tx = davinci_spi_tx_buf_u8;

       init_completion(&davinci_spi->done);
       ret = davinci_spi_cpufreq_register(davinci_spi);
       if (ret) {
               pr_info("davinci SPI contorller driver failed to register "
                                                       "cpufreq\n");
               goto free_dma;
       }

       /* Reset In/OUT SPI module */
       iowrite32(0, davinci_spi->base + SPIGCR0);
       udelay(100);
       iowrite32(1, davinci_spi->base + SPIGCR0);

       /* Clock internal */
       if (davinci_spi->pdata->clk_internal)
               set_io_bits(davinci_spi->base + SPIGCR1,
                               SPIGCR1_CLKMOD_MASK);
       else
               clear_io_bits(davinci_spi->base + SPIGCR1,
                               SPIGCR1_CLKMOD_MASK);

       /* master mode default */
       set_io_bits(davinci_spi->base + SPIGCR1, SPIGCR1_MASTER_MASK);

       if (davinci_spi->pdata->intr_level)
               iowrite32(SPI_INTLVL_1, davinci_spi->base + SPILVL);
       else
               iowrite32(SPI_INTLVL_0, davinci_spi->base + SPILVL);

       //设置bitbang传输
       ret = spi_bitbang_start(&davinci_spi->bitbang);
       if (ret)
               goto unregister_cpufreq;

       dev_info(&pdev->dev, "Controller at 0x%p \n", davinci_spi->base);

       if (!pdata->poll_mode)
               dev_info(&pdev->dev, "Operating in interrupt mode"
                       " using IRQ %d\n", davinci_spi->irq);

       return ret;

unregister_cpufreq:
       davinci_spi_cpufreq_deregister(davinci_spi);
free_dma:
       kfree(davinci_spi->dma_channels);
free_clk:
       clk_disable(davinci_spi->clk);
       clk_put(davinci_spi->clk);
put_master:
       spi_master_put(master);
free_tmp_buf:
       kfree(davinci_spi->tmp_buf);
irq_free:
       free_irq(davinci_spi->irq, davinci_spi);
unmap_io:
       iounmap(davinci_spi->base);
release_region:
       release_mem_region(davinci_spi->pbase, davinci_spi->region_size);
free_master:
       kfree(master);
err:
       return ret;
}
此probe函数中数据结构和代码的设计都是按照驱动框架的要求来实现的,主要包括spi controller memory的映射,IRQ的注册,controller的reset和对register进行初始化赋值。以及,调用spi_alloc_master分配一个用于描述spi controller的spi_master,并对spi_master进行赋值等。最后,它将调用spi_bitbang_start()来创建一个work queue,由此SPI设备驱动可以向这个工作队列注册transfer方法。
这里,我们接着看spi_bitbang_start:
/**
* spi_bitbang_start - start up a polled/bitbanging SPI master driver
* @bitbang: driver handle
*
* Caller should have zero-initialized all parts of the structure, and then
* provided callbacks for chip selection and I/O loops.  If the master has
* a transfer method, its final step should call spi_bitbang_transfer; or,
* that's the default if the transfer routine is not initialized.  It should
* also set up the bus number and number of chipselects.
*
* For i/o loops, provide callbacks either per-word (for bitbanging, or for
* hardware that basically exposes a shift register) or per-spi_transfer
* (which takes better advantage of hardware like fifos or DMA engines).
*
* Drivers using per-word I/O loops should use (or call) spi_bitbang_setup,
* spi_bitbang_cleanup and spi_bitbang_setup_transfer to handle those spi
* master methods.  Those methods are the defaults if the bitbang->txrx_bufs
* routine isn't initialized.
*
* This routine registers the spi_master, which will process requests in a
* dedicated task, keeping IRQs unblocked most of the time.  To stop
* processing those requests, call spi_bitbang_stop().
*/
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;

       /* 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
        */
       //注册spi控制器
       status = spi_register_master(bitbang->master);
       if (status < 0)
               goto err2;

       return status;

err2:
       destroy_workqueue(bitbang->workqueue);
err1:
       return status;
}
EXPORT_SYMBOL_GPL(spi_bitbang_start);
我们下面看spi_register_master:
/**
* spi_register_master - register SPI master controller
* @master: initialized master, originally from spi_alloc_master()
* Context: can sleep
*
* SPI master controllers connect to their drivers using some non-SPI bus,
* such as the platform bus.  The final stage of probe() in that code
* includes calling spi_register_master() to hook up to this SPI bus glue.
*
* SPI controllers use board specific (often SOC specific) bus numbers,
* and board-specific addressing for SPI devices combines those numbers
* with chip select numbers.  Since SPI does not directly support dynamic
* device identification, boards need configuration tables telling which
* chip is at which address.
*
* This must be called from context that can sleep.  It returns zero on
* success, else a negative error code (dropping the master's refcount).
* After a successful return, the caller is responsible for calling
* spi_unregister_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;
       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;
       }

       /* register the device, then userspace will see it.
        * registration fails if the bus ID is in use.
        */
       //设置spi控制器的名称,即在sysfs文件系统中显示的名称
       dev_set_name(&master->dev, "spi%u", master->bus_num);
       //设备添加到内核,会在sysfs文件系统下创建属性文件,这也是sys/class/spi_master下产生spi0,spi1的原因
       status = device_add(&master->dev);
       if (status < 0)
               goto done;
       dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
                       dynamic ? " (dynamic)" : "");

       /* populate children from any spi device tables */
       //搜寻总线上的spi device并注册到内核
       scan_boardinfo(master);
       status = 0;
done:
       return status;
}
EXPORT_SYMBOL_GPL(spi_register_master);
此函数主要是注册spi master和搜寻spi device并注册,接着我们看scan_boardinfo:
/* FIXME someone should add support for a __setup("spi", ...) that
* creates board info from kernel command lines
*/
static void scan_boardinfo(struct spi_master *master)
{
       struct boardinfo        *bi;

       mutex_lock(&board_lock);
       //【重点函数 2】遍历board_list中的spi_board_info,如果设备的总线号与控制器的总线好相等,则创建新spi device
       //此board_list就是上面list_add_tail(&bi->list, &board_list);中生成的board_list。
       list_for_each_entry(bi, &board_list, list) {
               struct spi_board_info   *chip = bi->board_info;
               unsigned                n;

               for (n = bi->n_board_info; n > 0; n--, chip++) {
                       //检查在同一个spi总线上
                       if (chip->bus_num != master->bus_num)
                               continue;
                       /* NOTE: this relies on spi_new_device to
                        * issue diagnostics when given bogus inputs
                        */
                       //将spi master和spi device联系起来
                       (void) spi_new_device(master, chip);
               }
       }
       mutex_unlock(&board_lock);
}
这里根据board_list搜寻spi device,我们接着看将spi控制器和spi外设联系起来的实现,spi_new_device:
/**
* spi_new_device - instantiate one new SPI device
* @master: Controller to which device is connected
* @chip: Describes the SPI device
* Context: can sleep
*
* On typical mainboards, this is purely internal; and it's not needed
* after board init creates the hard-wired devices.  Some development
* platforms may not be able to use spi_register_board_info though, and
* this is exported so that for example a USB or parport based adapter
* driver could add devices (which it would learn about out-of-band).
*
* Returns the new device, or NULL.
*/
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).
        */

       //申请1个spi device,并将master赋值给spi device,这样可以通过spi device访问到master
       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;

       //添加spi device
       status = spi_add_device(proxy);
       if (status < 0) {
               spi_dev_put(proxy);
               return NULL;
       }

       return proxy;
}
EXPORT_SYMBOL_GPL(spi_new_device);
接着看添加spi外设,spi_add_device:
/**
* spi_add_device - Add spi_device allocated with spi_alloc_device
* @spi: spi_device to register
*
* Companion function to spi_alloc_device.  Devices allocated with
* spi_alloc_device can be added onto the spi bus with this function.
*
* Returns 0 on success; negative errno on failure
*/
int spi_add_device(struct spi_device *spi)
{
       static DEFINE_MUTEX(spi_add_lock);
       struct device *dev = spi->master->dev.parent;
       int status;

       //检查spi device的片选号不能超过spi控制器的片选数量
       /* Chipselects are numbered 0..max; validate. */
       if (spi->chip_select >= spi->master->num_chipselect) {
               dev_err(dev, "cs%d >= max %d\n",
                       spi->chip_select,
                       spi->master->num_chipselect);
               return -EINVAL;
       }

       //设置spi device在Linux设备驱动模型中的name,如spi0.0
       /* Set the bus ID string */
       dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),
                       spi->chip_select);


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

       //检查总线上没有重名的spi device
       if (bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev))
                       != NULL) {
               dev_err(dev, "chipselect %d already in use\n",
                               spi->chip_select);
               status = -EBUSY;
               goto done;
       }

       //设置spi控制器
       /* 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 %s %s, status %d\n",
                               "setup", dev_name(&spi->dev), status);
               goto done;
       }

       //把spi device添加到内核,在sysfs文件系统下创建相应的属性文件(设备文件dev文件不会在这里创建,下边注册spi driver时会创建dev文件)
       /* Device may be bound to an active driver when this returns */
       status = device_add(&spi->dev);
       if (status < 0)
               dev_err(dev, "can't %s %s, status %d\n",
                               "add", 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);
我们接着看spi_setup:
/**
* spi_setup - setup SPI mode and clock rate
* @spi: the device whose settings are being modified
* Context: can sleep, and no requests are queued to the device
*
* SPI protocol drivers may need to update the transfer mode if the
* device doesn't work with its default.  They may likewise need
* to update clock rates or word sizes from initial values.  This function
* changes those settings, and must be called from a context that can sleep.
* Except for SPI_CS_HIGH, which takes effect immediately, the changes take
* effect the next time the device is selected and data is transferred to
* or from it.  When this function returns, the spi device is deselected.
*
* Note that this call will fail if the protocol driver specifies an option
* that the underlying controller or its driver does not support.  For
* example, not all hardware supports wire transfers using nine bit words,
* LSB-first wire encoding, or active-high chipselects.
*/
int spi_setup(struct spi_device *spi)
{
       unsigned        bad_bits;
       int             status;

       /* help drivers fail *cleanly* when they need options
        * that aren't supported with their current master
        */
       bad_bits = spi->mode & ~spi->master->mode_bits;
       if (bad_bits) {
               dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
                       bad_bits);
               return -EINVAL;
       }

       if (!spi->bits_per_word)
               spi->bits_per_word = 8;

       status = spi->master->setup(spi);

       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);
spi->master->setup()是个钩子函数,其在上面的davinci_spi_probe()中被赋值,那么真正调用的是davinci_spi_setup():
/*
* davinci_spi_setup - This functions will set default transfer method
* @spi: spi device on which data transfer to be done
*
* This functions sets the default transfer method.
*/

static int davinci_spi_setup(struct spi_device *spi)
{
       int retval;
       struct davinci_spi *davinci_spi;
       struct davinci_spi_dma *davinci_spi_dma;
       struct device *sdev;

       //从spi master的私有数据中取出davinci_spi
       davinci_spi = spi_master_get_devdata(spi->master);
       sdev = davinci_spi->bitbang.master->dev.parent;

       //设置spi发送速度
       /* if bits per word length is zero then set it default 8 */
       if (!spi->bits_per_word)
               spi->bits_per_word = 8;

       davinci_spi->slave[spi->chip_select].cmd_to_write = 0;

       //设置spi dma
       if (use_dma && davinci_spi->dma_channels) {
               davinci_spi_dma = &davinci_spi->dma_channels[spi->chip_select];

               if ((davinci_spi_dma->dma_rx_channel == -1)
                               || (davinci_spi_dma->dma_tx_channel == -1)) {
                       retval = davinci_spi_request_dma(spi);
                       if (retval < 0)
                       {
                               return retval;
                       }
               }
       }

       /*
        * SPI in DaVinci and DA8xx operate between
        * 600 KHz and 50 MHz
        */
       if (spi->max_speed_hz < 600000 || spi->max_speed_hz > 50000000) {
               dev_dbg(sdev, "Operating frequency is not in acceptable "
                               "range\n");
               return -EINVAL;
       }

       //设置spi FMT寄存器
       /*
        * Set up SPIFMTn register, unique to this chipselect.
        *
        * NOTE: we could do all of these with one write.  Also, some
        * of the "version 2" features are found in chips that don't
        * support all of them...
        */
       if (spi->mode & SPI_LSB_FIRST)
               set_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK,
                               spi->chip_select);
       else
               clear_fmt_bits(davinci_spi->base, SPIFMT_SHIFTDIR_MASK,
                               spi->chip_select);

       if (spi->mode & SPI_CPOL)
               set_fmt_bits(davinci_spi->base, SPIFMT_POLARITY_MASK,
                               spi->chip_select);
       else
               clear_fmt_bits(davinci_spi->base, SPIFMT_POLARITY_MASK,
                               spi->chip_select);

       if (!(spi->mode & SPI_CPHA))
               set_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK,
                               spi->chip_select);
       else
               clear_fmt_bits(davinci_spi->base, SPIFMT_PHASE_MASK,
                               spi->chip_select);

       //设置spi控制器和片选拐角
       /*
        * Version 1 hardware supports two basic SPI modes:
        *  - Standard SPI mode uses 4 pins, with chipselect
        *  - 3 pin SPI is a 4 pin variant without CS (SPI_NO_CS)
        *      (distinct from SPI_3WIRE, with just one data wire;
        *      or similar variants without MOSI or without MISO)
        *
        * Version 2 hardware supports an optional handshaking signal,
        * so it can support two more modes:
        *  - 5 pin SPI variant is standard SPI plus SPI_READY
        *  - 4 pin with enable is (SPI_READY | SPI_NO_CS)
        */

       if (davinci_spi->version == SPI_VERSION_2) {
               clear_fmt_bits(davinci_spi->base, SPIFMT_WDELAY_MASK,
                               spi->chip_select);
               set_fmt_bits(davinci_spi->base,
                               (davinci_spi->pdata->wdelay
                                               << SPIFMT_WDELAY_SHIFT)
                                       & SPIFMT_WDELAY_MASK,
                               spi->chip_select);

               if (davinci_spi->pdata->odd_parity)
                       set_fmt_bits(davinci_spi->base,
                                       SPIFMT_ODD_PARITY_MASK,
                                       spi->chip_select);
               else
                       clear_fmt_bits(davinci_spi->base,
                                       SPIFMT_ODD_PARITY_MASK,
                                       spi->chip_select);

               if (davinci_spi->pdata->parity_enable)
                       set_fmt_bits(davinci_spi->base,
                                       SPIFMT_PARITYENA_MASK,
                                       spi->chip_select);
               else
                       clear_fmt_bits(davinci_spi->base,
                                       SPIFMT_PARITYENA_MASK,
                                       spi->chip_select);

               if (davinci_spi->pdata->wait_enable)
                       set_fmt_bits(davinci_spi->base,
                                       SPIFMT_WAITENA_MASK,
                                       spi->chip_select);
               else
                       clear_fmt_bits(davinci_spi->base,
                                       SPIFMT_WAITENA_MASK,
                                       spi->chip_select);

               if (davinci_spi->pdata->timer_disable)
                       set_fmt_bits(davinci_spi->base,
                                       SPIFMT_DISTIMER_MASK,
                                       spi->chip_select);
               else
                       clear_fmt_bits(davinci_spi->base,
                                       SPIFMT_DISTIMER_MASK,
                                       spi->chip_select);
       }

       //设置spi传输模式
       retval = davinci_spi_setup_transfer(spi, NULL);

       return retval;
}
这里就是配置spi控制器的寄存器了,可以对照到omapl138的芯片手册中spi register配置章节。

4 第四阶段 注册spi driver 重点关注spi_register_driver()
这里我们以spidev驱动为例继续分析spi driver。/driver/spi/spidev.c是linux内核提供的一个spi通用驱动。
static struct spi_driver spidev_spi_driver = {
       .driver = {
               .name =         "spidev",
               .owner =        THIS_MODULE,
       },
       .probe =        spidev_probe,
       .remove =       __devexit_p(spidev_remove),

       /* NOTE:  suspend/resume methods are not necessary here.
        * We don't do anything except pass the requests to/from
        * the underlying controller.  The refrigerator handles
        * most issues; the controller driver handles the rest.
        */
};
static int __init spidev_init(void)
{
       int status;

       /* Claim our 256 reserved device numbers.  Then register a class
        * that will key udev/mdev to add/remove /dev nodes.  Last, register
        * the driver which manages those device numbers.
        */
       BUILD_BUG_ON(N_SPI_MINORS > 256);
       //注册spi字符设备的操作方法
       status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
       if (status < 0)
               return status;

       spidev_class = class_create(THIS_MODULE, "spidev");
       if (IS_ERR(spidev_class)) {
               unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
               return PTR_ERR(spidev_class);
       }

       //注册spi driver
       status = spi_register_driver(&spidev_spi_driver);
       if (status < 0) {
               class_destroy(spidev_class);
               unregister_chrdev(SPIDEV_MAJOR, spidev_spi_driver.driver.name);
       }
       return status;
}
module_init(spidev_init);
接着我们看spi_register_driver:
/**
* spi_register_driver - register a SPI driver
* @sdrv: the driver to register
* Context: can sleep
*/
int spi_register_driver(struct spi_driver *sdrv)
{
       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);
到这里,我不再向下深入研究spi外设驱动在内核的调用流程,但需要知道当spi device和spi driver匹配成功后,会调用spidev_probe(),此函数会注册spi外设的字符设备。如下,仅列出spidev_probe():

/*-------------------------------------------------------------------------*/

 

/* The main reason to have this class is to make mdev/udev create the

 * /dev/spidevB.C character device nodes exposing our userspace API.

 * It also simplifies memory management.

 */

 

static struct class *spidev_class;

 

/*-------------------------------------------------------------------------*/

 

static int __devinit spidev_probe(struct spi_device *spi)

{

         struct spidev_data  *spidev;

         int                      status;

         unsigned long          minor;

 

         /* Allocate driver data */

         spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);

         if (!spidev)

                  return -ENOMEM;

 

         /* Initialize the driver data */

         spidev->spi = spi;

         spin_lock_init(&spidev->spi_lock);

         mutex_init(&spidev->buf_lock);

 

         INIT_LIST_HEAD(&spidev->device_entry);

 

         /* If we can allocate a minor number, hook up this device.

          * Reusing minors is fine so long as udev or mdev is working.

          */

         mutex_lock(&device_list_lock);

         minor = find_first_zero_bit(minors, N_SPI_MINORS);

         if (minor < N_SPI_MINORS) {

                  struct device *dev;

 

                  spidev->devt = MKDEV(SPIDEV_MAJOR, minor);

                  dev = device_create(spidev_class, &spi->dev, spidev->devt,

                                       spidev, "spidev%d.%d",

                                       spi->master->bus_num, spi->chip_select);

                  status = IS_ERR(dev) ? PTR_ERR(dev) : 0;

         } else {

                  dev_dbg(&spi->dev, "no minor number available!\n");

                  status = -ENODEV;

         }

         if (status == 0) {

                  set_bit(minor, minors);

                  list_add(&spidev->device_entry, &device_list);

         }

         mutex_unlock(&device_list_lock);

 

         if (status == 0)

                  spi_set_drvdata(spi, spidev);

         else

                  kfree(spidev);

 

         return status;

}

另外,spidev_init()函数中注册了标准的read/write/ioctl/open/release函数接口,以便在用户空间的应用程序对spi外设进行“读”“写”“设置”(设置是通过调用ioctl(),调到spi_setup(),实现重新设置spi device的默认传输方式)操作:

static const struct file_operations spidev_fops = {

         .owner = THIS_MODULE,

         /* REVISIT switch to aio primitives, so that userspace

          * gets more complete API coverage.  It'll simplify things

          * too, except for the locking.

          */

         .write =    spidev_write,

         .read =              spidev_read,

         .unlocked_ioctl = spidev_ioctl,

         .open =             spidev_open,

         .release =         spidev_release,

};

以上操作函数的具体实现不一一列出,但需要知道spidev.c中,设备的半双工模式和全双工模式都实现了。spi应用程序的编码,请看我后面的文章。


备注:涉及到的相关目录如下
/arch/arm/mach-davici/
/driver/spi/spi.c    /driver/spi/davinci_spi.c    /driver/spi/spi_bitbang.c
/driver/base/platform.c    /driver/base/core.c
阅读(3737) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~