Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1138078
  • 博文数量: 241
  • 博客积分: 10
  • 博客等级: 民兵
  • 技术积分: 2279
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-27 19:53
个人简介

JustForFun

文章分类

全部博文(241)

文章存档

2023年(8)

2022年(2)

2021年(3)

2020年(30)

2019年(11)

2018年(27)

2017年(54)

2016年(83)

2015年(23)

我的朋友

分类: LINUX

2018-12-16 21:55:54

 spi.c是spi子系统初始化的核心代码,由内核负责初始化
spidev.c是spi用户接口初始化的代码,编译的时候需要选择该模块
spi_sam.c是平台驱动的初始化代码,编译时需要选择spi s3c64xx模块

drivers/spi/spi_test.c 这个文件可以细看,是详细分析spi驱动的好文件。
//////////////////////////////////////////////////////////////////////////////////////////////////////

obj-$(CONFIG_HS_SPI_S3C6410)            += spi_sam.o
obj-$(CONFIG_SPI_MASTER)                += spi.o
obj-$(CONFIG_SPI_SPIDEV)        += spidev.o


//////////////////////////////////////////////////////////////////////////////////////////////////////
<.config>
CONFIG_SPI=y
CONFIG_SPI_DEBUG=y
CONFIG_SPI_MASTER=y
CONFIG_HS_SPI_S3C6410=y
CONFIG_SPI_SPIDEV=y
//////////////////////////////////////////////////////////////////////////////////////////////////////

module_init(sam_spi_init);
static int __init sam_spi_init(void)
{
    dbg_printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
//
在match函数匹配成功的情况下, 系统将调用相应的probe函数,此处是直接在模块初始化时直接调用probe?
    return platform_driver_probe(&sam_spi_driver, samspi_probe);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////

//见
//
struct platform_device s3c_device_spi0 = { .name          = "sam-spi",
 

static struct platform_driver sam_spi_driver = {
    .driver = {

 
        .name    = "sam-spi",

        .owner = THIS_MODULE,
        .bus    = &platform_bus_type,
    },
};
struct bus_type platform_bus_type = {
    .name        = "platform",
    .dev_attrs    = platform_dev_attrs,
    .match        = platform_match,
    .uevent        = platform_uevent,
    .pm        = PLATFORM_PM_OPS_PTR,
};
//////////////////////////////////////////////////////////////////////////////////////////////////////

       .name    = "sam-spi",的设备和驱动匹配到的时候会调用samspi_probe函数
 
static int __init samspi_probe(struct platform_device *pdev)
{
    struct spi_master *master;
    struct samspi_bus *sspi;
    int ret = -ENODEV;

    dbg_printk("%s:%s:%d ID=%d\n", __FILE__, __func__, __LINE__, pdev->id);
//分配 SPI控制器struct spi_master    *master;空间

//实际申请的内存大小为一个struct master + struct samspi_bus,并用master->dev->driver_data 指向这个多出来的 struct samspi_bus 空间,用来存放 master 的中断 、寄存器等东西。
//分配struct spi_master+struct samspi_bus大小的数据,把samspi_bus设为spi_master的私有数据
 
    master = spi_alloc_master(&pdev->dev, sizeof(struct samspi_bus)); /* Allocate contiguous SPI controller */
    if (master == NULL)
        return ret;
//
/*从master中获得samspi_bus*/  
 
    sspi = spi_master_get_devdata(master);
    sspi->pdev = pdev;
    sspi->master = master;
 /* 将 Master 放入 pdev->dev->driver_data 里*/ 
/*设置平台的私有数据为master
 
 
    platform_set_drvdata(pdev, master);

//初始化工作队列并将其与处理函数绑定
    INIT_WORK(&sspi->work, samspi_work);
    spin_lock_init(&sspi->lock);
    INIT_LIST_HEAD(&sspi->queue);
//初始化 完成量
    init_completion(&sspi->xfer_completion);

    sspi->clk = clk_get(&pdev->dev, "spi");
    if (IS_ERR(sspi->clk)) {
        sspi->clk = NULL;
        dev_err(&pdev->dev, "cannot acquire clock \n");
        ret = -EBUSY;
        goto lb1;
    }
    ret = clk_enable(sspi->clk);
    if (ret) {
        clk_put(sspi->clk);
        sspi->clk = NULL;
        dev_err(&pdev->dev, "cannot enable clock \n");
        ret = -EBUSY;
        goto lb2;
    }

    sspi->cur_mode = SPI_SLAVE; /* Start in Slave mode */
    sspi->cur_bpw = 8;
    sspi->max_speed = clk_get_rate(sspi->clk) / 2 / (0x0 + 1);
    sspi->min_speed = clk_get_rate(sspi->clk) / 2 / (0xff + 1);

    /* Get and Map Resources */
    sspi->iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    if (sspi->iores == NULL) {
        dev_err(&pdev->dev, "cannot find IO resource\n");
        ret = -ENOENT;
        goto lb3;
    }

    sspi->ioarea = request_mem_region(sspi->iores->start, sspi->iores->end - sspi->iores->start + 1, pdev->name);
    if (sspi->ioarea == NULL) {
        dev_err(&pdev->dev, "cannot request IO\n");
        ret = -ENXIO;
        goto lb4;
    }

    sspi->regs = ioremap(sspi->iores->start, sspi->iores->end - sspi->iores->start + 1);
    if (sspi->regs == NULL) {
        dev_err(&pdev->dev, "cannot map IO\n");
        ret = -ENXIO;
        goto lb5;
    }

    sspi->tx_dma_cpu = dma_alloc_coherent(&pdev->dev, SAMSPI_DMABUF_LEN, &sspi->tx_dma_phys, GFP_KERNEL | GFP_DMA);
    if(sspi->tx_dma_cpu == NULL){
        dev_err(&pdev->dev, "Unable to allocate TX DMA buffers\n");
        ret = -ENOMEM;
        goto lb6;
    }

    sspi->rx_dma_cpu = dma_alloc_coherent(&pdev->dev, SAMSPI_DMABUF_LEN, &sspi->rx_dma_phys, GFP_KERNEL | GFP_DMA);
    if(sspi->rx_dma_cpu == NULL){
        dev_err(&pdev->dev, "Unable to allocate RX DMA buffers\n");
        ret = -ENOMEM;
        goto lb7;
    }

    sspi->irqres = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
    if(sspi->irqres == NULL){
        dev_err(&pdev->dev, "cannot find IRQ\n");
        ret = -ENOENT;
        goto lb8;
    }

    ret = request_irq(sspi->irqres->start, samspi_interrupt, IRQF_DISABLED,
            pdev->name, sspi);
    if(ret){
        dev_err(&pdev->dev, "cannot acquire IRQ\n");
        ret = -EBUSY;
        goto lb9;
    }

//用于创建workqueue,只创建一个内核线程( 不管几个核)
 
    sspi->workqueue = create_singlethread_workqueue(master->dev.parent->bus_id);
    if(!sspi->workqueue){
        dev_err(&pdev->dev, "cannot create workqueue\n");
        ret = -EBUSY;
        goto lb10;
    }

    master->bus_num = pdev->id;
    master->setup = samspi_setup;
    master->transfer = samspi_transfer;
    master->cleanup = samspi_cleanup;
    master->num_chipselect = 1; /* Only 1 Slave connected on SMDK */

//register SPI master controller  
//
spi_register_master调用了 device_add(&master->dev);将master注册到内核中去
 
//
spi_register_master调用了 scan_boardinfo(master)扫描spi设备信息,创建设备
//创建了一个
设备名字是     .modalias     = "spidev", /* Test Interface */的设备device
//会和
static struct spi_driver spidev_spi这个driver驱动匹配。
 
//

//
static struct spi_board_info __initdata sam_spi_devs[] = {
//.modalias     = "spidev", /* Test Interface */

 
    if(spi_register_master(master)){
        dev_err(&pdev->dev, "cannot register SPI master\n");
        ret = -EBUSY;
        goto lb11;
    }

    /* Configure GPIOs */
    if(pdev->id == 0)
        SETUP_SPI(sspi, 0);
    else if(pdev->id == 1)
        SETUP_SPI(sspi, 1);

    if(s3c2410_dma_request(sspi->rx_dmach, &samspi_dma_client, NULL)){
        dev_err(&pdev->dev, "cannot get RxDMA\n");
        ret = -EBUSY;
        goto lb12;
    }
    s3c2410_dma_set_buffdone_fn(sspi->rx_dmach, samspi_dma_rxcb);
    s3c2410_dma_devconfig(sspi->rx_dmach, S3C2410_DMASRC_HW, 0, sspi->sfr_phyaddr + SAMSPI_SPI_RX_DATA);
    s3c2410_dma_config(sspi->rx_dmach, sspi->cur_bpw/8, 0);
    s3c2410_dma_setflags(sspi->rx_dmach, S3C2410_DMAF_AUTOSTART);

    if(s3c2410_dma_request(sspi->tx_dmach, &samspi_dma_client, NULL)){
        dev_err(&pdev->dev, "cannot get TxDMA\n");
        ret = -EBUSY;
        goto lb13;
    }
    s3c2410_dma_set_buffdone_fn(sspi->tx_dmach, samspi_dma_txcb);
    s3c2410_dma_devconfig(sspi->tx_dmach, S3C2410_DMASRC_MEM, 0, sspi->sfr_phyaddr + SAMSPI_SPI_TX_DATA);
    s3c2410_dma_config(sspi->tx_dmach, sspi->cur_bpw/8, 0);
    s3c2410_dma_setflags(sspi->tx_dmach, S3C2410_DMAF_AUTOSTART);

    /* Setup Deufult Mode */
    samspi_hwinit(sspi, pdev->id);

    printk("Samsung SoC SPI Driver loaded for SPI-%d\n", pdev->id);
    printk("\tMax,Min-Speed [%d, %d]Hz\n", sspi->max_speed, sspi->min_speed);
    printk("\tIrq=%d\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
            sspi->irqres->start,
            sspi->iores->end, sspi->iores->start,
            sspi->rx_dmach, sspi->tx_dmach);
    return 0;

lb13:
    s3c2410_dma_free(sspi->rx_dmach, &samspi_dma_client);
lb12:
    spi_unregister_master(master);
lb11:
    destroy_workqueue(sspi->workqueue);
lb10:
    free_irq(sspi->irqres->start, sspi);
lb9:
lb8:
    dma_free_coherent(&pdev->dev, SAMSPI_DMABUF_LEN, sspi->rx_dma_cpu, sspi->rx_dma_phys);
lb7:
    dma_free_coherent(&pdev->dev, SAMSPI_DMABUF_LEN, sspi->tx_dma_cpu, sspi->tx_dma_phys);
lb6:
    iounmap((void *) sspi->regs);
lb5:
    release_mem_region(sspi->iores->start, sspi->iores->end - sspi->iores->start + 1);
lb4:
lb3:
    clk_disable(sspi->clk);
lb2:
    clk_put(sspi->clk);
lb1:
    platform_set_drvdata(pdev, NULL);
    spi_master_put(master);

    return ret;
}

//////////////////////////////////////////////////////////////////////////////////////////////////////


//static int __init samspi_probe(struct platform_device *pdev)函数中调用
 
//初始化工作队列并将其与处理函数绑定
 //   INIT_WORK(&sspi->work, samspi_work);

static void samspi_work(struct work_struct *work)
{
//通过链表节点拿到包含这个链表节点的解构体的头地址
    struct samspi_bus *sspi = container_of(work, struct samspi_bus, work);
    unsigned long flags;

    spin_lock_irqsave(&sspi->lock, flags);
    while (!list_empty(&sspi->queue)) {
        struct spi_message *msg;

        msg = container_of(sspi->queue.next, struct spi_message, queue);
        list_del_init(&msg->queue);
        spin_unlock_irqrestore(&sspi->lock, flags);

        handle_msg(sspi, msg);

        spin_lock_irqsave(&sspi->lock, flags);
    }
    spin_unlock_irqrestore(&sspi->lock, flags);
}
///////////////////////////////////////////////////////////////////////////////////////////////

static void handle_msg(struct samspi_bus *sspi, struct spi_message *msg)
{
    u8 bpw;
    u32 speed, val;
    int status = 0;
    struct spi_transfer *xfer;
    struct spi_device *spi = msg->spi;

    config_sspi(sspi);

    dump_regs(sspi);
    list_for_each_entry (xfer, &msg->transfers, transfer_list) {

        if(!msg->is_dma_mapped && samspi_map_xfer(sspi, xfer)){
           dev_err(&spi->dev, "Xfer: Unable to allocate DMA buffer!\n");
           status = -ENOMEM;
           goto out;
        }

        INIT_COMPLETION(sspi->xfer_completion);

        /* Only BPW and Speed may change across transfers */
        bpw = xfer->bits_per_word ? : spi->bits_per_word;
        speed = xfer->speed_hz ? : spi->max_speed_hz;

        if(sspi->cur_bpw != bpw || sspi->cur_speed != speed){
            sspi->cur_bpw = bpw;
            sspi->cur_speed = speed;
            config_sspi(sspi);
        }

        /* Pending only which is to be done */
        sspi->rx_done = PASS;
        sspi->tx_done = PASS;
        sspi->state = RUNNING;

        /* Enable Interrupts */
        enable_spiintr(sspi, xfer);

        /* Enqueue data on DMA */
        enable_spienqueue(sspi, xfer);

        /* Enable DMA */
        enable_spidma(sspi, xfer);

        /* Enable TX/RX */
        enable_spichan(sspi, xfer);

        /* Slave Select */
        enable_spics(sspi, xfer);

        dump_regs(sspi);
        status = wait_for_xfer(sspi, xfer);

        /**************
         * Block Here *
         **************/

        if(status == -ETIMEDOUT){
           dev_err(&spi->dev, "Xfer: Timeout!\n");
           dump_regs(sspi);
           sspi->state = STOPPED;
           /* DMA Disable*/
           val = readl(sspi->regs + SAMSPI_MODE_CFG);
           val &= ~(SPI_MODE_TXDMA_ON | SPI_MODE_RXDMA_ON);
           writel(val, sspi->regs + SAMSPI_MODE_CFG);
           flush_dma(sspi, xfer);
           flush_spi(sspi);
           if(!msg->is_dma_mapped)
              samspi_unmap_xfer(sspi, xfer);
           goto out;
        }
        if(status == -EINTR){
           dev_err(&spi->dev, "Xfer: Interrupted!\n");
           dump_regs(sspi);
           sspi->state = STOPPED;
           /* DMA Disable*/
           val = readl(sspi->regs + SAMSPI_MODE_CFG);
           val &= ~(SPI_MODE_TXDMA_ON | SPI_MODE_RXDMA_ON);
           writel(val, sspi->regs + SAMSPI_MODE_CFG);
           flush_dma(sspi, xfer);
           flush_spi(sspi);
           if(!msg->is_dma_mapped)
              samspi_unmap_xfer(sspi, xfer);
           goto out;
        }
        if(status == -EIO){ /* Some Xfer failed */
           dev_err(&spi->dev, "Xfer: Failed!\n");
           dump_regs(sspi);
           sspi->state = STOPPED;
           /* DMA Disable*/
           val = readl(sspi->regs + SAMSPI_MODE_CFG);
           val &= ~(SPI_MODE_TXDMA_ON | SPI_MODE_RXDMA_ON);
           writel(val, sspi->regs + SAMSPI_MODE_CFG);
           flush_dma(sspi, xfer);
           flush_spi(sspi);
           if(!msg->is_dma_mapped)
              samspi_unmap_xfer(sspi, xfer);
           goto out;
        }

        if(xfer->delay_usecs){
           udelay(xfer->delay_usecs);
           dbg_printk("xfer-delay=%u\n", xfer->delay_usecs);
        }
        if(xfer->cs_change && !(sspi->cur_mode & SPI_SLAVE)){
           writel(readl(sspi->regs + SAMSPI_SLAVE_SEL) | SPI_SLAVE_SIG_INACT,
                 sspi->regs + SAMSPI_SLAVE_SEL);
           dbg_printk("xfer-cs_chng=%u\n", xfer->cs_change);
        }

        msg->actual_length += xfer->len;

        if(!msg->is_dma_mapped)
           samspi_unmap_xfer(sspi, xfer);
    }

out:
    /* Slave Deselect */
    val = readl(sspi->regs + SAMSPI_SLAVE_SEL);
    val &= ~SPI_SLAVE_AUTO;
    val |= SPI_SLAVE_SIG_INACT;
    writel(val, sspi->regs + SAMSPI_SLAVE_SEL);

    /* Disable Interrupts */
    writel(0, sspi->regs + SAMSPI_SPI_INT_EN);

    /* Tx/Rx Disable */
    val = readl(sspi->regs + SAMSPI_CH_CFG);
    val &= ~(SPI_CH_RXCH_ON | SPI_CH_TXCH_ON);
    writel(val, sspi->regs + SAMSPI_CH_CFG);

    /* DMA Disable*/
    val = readl(sspi->regs + SAMSPI_MODE_CFG);
    val &= ~(SPI_MODE_TXDMA_ON | SPI_MODE_RXDMA_ON);
    writel(val, sspi->regs + SAMSPI_MODE_CFG);

    msg->status = status;
//
//spidev_sync(struct spidev_data *spidev, struct spi_message *message)函数
//有一行    message->complete = spidev_complete;
//所以此处调用的是spidev_complete函数,其实spidev_complete(arg)也就是直接调用complete(arg);
//唤醒 spidev_sync函数的       wait_for_completion(&done);这行往下执行
    if(msg->complete)
       msg->complete(msg->context);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
spidev_write函数调用----->spidev_sync_write(spidev, count);------->spidev_sync(spidev, &m);
                 ---------->spi_async(spidev->spi, message);
  -------------->
static inline int
spi_async(struct spi_device *spi, struct spi_message *message)
{
    message->spi = spi;

//看看.name =        "spidev"的这对设备和驱动
//在这里与.name    = "sam-spi",的一对平台设备和驱动联系起来
//
module_init(spidev_init);与
//
module_init(sam_spi_init);这两个模块的连接点在这行程序里体现
//
struct spi_device里的master成员是什么时候赋值过去的?
//samspi_probe(struct platform_device *pdev)
------>spi_register_master(master);
//---------->scan_boardinfo(master);------->spi_new_device(master, chip);--------->proxy = spi_alloc_device(master);
///在spi_alloc_device函数里有一行spi->master = master;,返回值 return spi;
/////////这个便是调用samspi_transfer函数了。数据的发送传输
    return spi->master->transfer(spi, message);
}
//////////

static int samspi_transfer(struct spi_device *spi, struct spi_message *msg)
{
    struct spi_master *master = spi->master;
    struct samspi_bus *sspi = spi_master_get_devdata(master);
    unsigned long flags;

    spin_lock_irqsave(&sspi->lock, flags);
    msg->actual_length = 0;
//将struct spi_message *msg通过queue链表节点成员加入sspi->queue这个链表头
    list_add_tail(&msg->queue, &sspi->queue);

//调度执行一个指定workqueue中的任务。输入参数:
//@ workqueue_struct
:指定的workqueue指针
//@work_struct
:具体任务对象指针
//static int __init samspi_probe(struct platform_device *pdev)函数中调用
//    sspi->workqueue = create_singlethread_workqueue(master->dev.parent->bus_id);
 
//初始化工作队列并将其与处理函数绑定
 //INIT_WORK(&sspi->work, samspi_work);



//将
sspi->work加入sspi->workqueue中调度运行

    queue_work(sspi->workqueue, &sspi->work);
    spin_unlock_irqrestore(&sspi->lock, flags);

    return 0;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * 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.
     */
//此处有device_add 后面scan_boardinfo ----》spi_new_device------》spi_add_device
    status = device_add(&master->dev);
    if (status < 0)
        goto done;

    /* populate children from any spi device tables */
    scan_boardinfo(master);
    status = 0;
done:
    return status;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/* 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);
//遍历所有挂在board_list上的struct boardinfo 实例
    list_for_each_entry(bi, &board_list, list) {
        struct spi_board_info    *chip = bi->board_info;
        unsigned        n;
//遍历每个 boardinfo 管理的spi_board_info类型子成员,如果设备的总线号与控制器的总线号相等,则创建新设备
        for (n = bi->n_board_info; n > 0; n--, chip++) {
            if (chip->bus_num != master->bus_num)
                continue;
            /* NOTE: this relies on spi_new_device to
             * issue diagnostics when given bogus inputs
             */
            (void) spi_new_device(master, chip);
        }
    }
    mutex_unlock(&board_lock);
}
//////////////////////////////////////////////////////////////////////////////////////////////////

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

    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;
//这里获得了spi_device的名字,这个modalias也是在我们移植时
//在
mach-smdk6410.c中的static struct spi_board_info __initdata sam_spi_devs[]中设定的
    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;
}
//////////////////////////////////////////////////////////////////////////////////////////////////


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

    /* Chipselects are numbered 0..max; validate. */
//spi_device的片选号不能大于spi控制器的片选数
    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,
//而在/dev/下设备节点的名字是proxy->modalias中的名字

    /* Set the bus ID string */
    snprintf(spi->dev.bus_id, sizeof spi->dev.bus_id,
            "%s.%u", spi->master->dev.bus_id,
            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);
//如果总线上挂的设备已经有这个名字,则设置状态忙碌,退出
    if (bus_find_device_by_name(&spi_bus_type, NULL, spi->dev.bus_id)
            != NULL) {
        dev_err(dev, "chipselect %d already in use\n",
                spi->chip_select);
        status = -EBUSY;
        goto done;
    }

    /* 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->master->setup(spi);
    if (status < 0) {
        dev_err(dev, "can't %s %s, status %d\n",
                "setup", spi->dev.bus_id, 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 %s %s, status %d\n",
                "add", spi->dev.bus_id, status);
    else
        dev_dbg(dev, "registered child %s\n", spi->dev.bus_id);

done:
    mutex_unlock(&spi_add_lock);
    return status;
}
//////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * spi_alloc_device - Allocate a new SPI device
 * @master: Controller to which device is connected
 * Context: can sleep
 *
 * Allows a driver to allocate and initialize a spi_device without
 * registering it immediately.  This allows a driver to directly
 * fill the spi_device with device parameters before calling
 * spi_add_device() on it.
 *
 * Caller is responsible to call spi_add_device() on the returned
 * spi_device structure to add it to the SPI master.  If the caller
 * needs to discard the spi_device without adding it, then it should
 * call spi_dev_put() on it.
 *
 * Returns a pointer to the new device, or NULL.
 */
struct spi_device *spi_alloc_device(struct spi_master *master)
{
    struct spi_device    *spi;
    struct device        *dev = master->dev.parent;

    if (!spi_master_get(master))
        return NULL;

    spi = kzalloc(sizeof *spi, GFP_KERNEL);
    if (!spi) {
        dev_err(dev, "cannot alloc spi_device\n");
        spi_master_put(master);
        return NULL;
    }

    spi->master = master;
//spi_device与spi_master是同一个父设备,这是在spi_new_device()-->spi_alloc_device函数中设定的,
//一般这个设备是一个物理设备

    spi->dev.parent = dev;
//总线设置成spi_bus_type
    spi->dev.bus = &spi_bus_type;
    spi->dev.release = spidev_release;
    device_initialize(&spi->dev);
    return spi;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


/**
 * struct spi_master - interface to SPI master controller
 * @dev: device interface to this driver
 * @bus_num: board-specific (and often SOC-specific) identifier for a
 *    given SPI controller.
 * @num_chipselect: chipselects are used to distinguish individual
 *    SPI slaves, and are numbered from zero to num_chipselects.
 *    each slave has a chipselect signal, but it's common that not
 *    every chipselect is connected to a slave.
 * @setup: updates the device mode and clocking records used by a
 *    device's SPI controller; protocol code may call this.  This
 *    must fail if an unrecognized or unsupported mode is requested.
 *    It's always safe to call this unless transfers are pending on
 *    the device whose settings are being modified.
 * @transfer: adds a message to the controller's transfer queue.
 * @cleanup: frees controller-specific state
 *
 * Each SPI master controller can communicate with one or more @spi_device
 * children.  These make a small bus, sharing MOSI, MISO and SCK signals
 * but not chip select signals.  Each device may be configured to use a
 * different clock rate, since those shared signals are ignored unless
 * the chip is selected.
 *
 * The driver for an SPI controller manages access to those devices through
 * a queue of spi_message transactions, copying data between CPU memory and
 * an SPI slave device.  For each such message it queues, it calls the
 * message's completion function when the transaction completes.
 */
//SPI主控制器
struct spi_master {
////驱动的设备接口
    struct device    dev;

    /* other than negative (== assign one dynamically), bus_num is fully
     * board-specific.  usually that simplifies to being SOC-specific.
     * example:  one SOC has three SPI controllers, numbered 0..2,
     * and one board's schematics might show it using SPI-2.  software
     * would normally use bus_num=2 for that controller.
     */
////总线号
    s16            bus_num;

    /* chipselects will be integral to many controllers; some others
     * might use board-specific GPIOs.
     */
// //SPI设备的片选号
    u16            num_chipselect;
////更新SPI设备的模式和SPI设备的采样时钟 
    /* setup mode and clock, etc (spi driver may call many times) */
    int            (*setup)(struct spi_device *spi);

    /* bidirectional bulk transfers
     *
     * + The transfer() method may not sleep; its main role is
     *   just to add the message to the queue.
     * + For now there's no remove-from-queue operation, or
     *   any other request management
     * + To a given spi_device, message queueing is pure fifo
     *
     * + The master's main job is to process its message queue,
     *   selecting a chip then transferring data
     * + If there are multiple spi_device children, the i/o queue
     *   arbitration algorithm is unspecified (round robin, fifo,
     *   priority, reservations, preemption, etc)
     *
     * + Chipselect stays active during the entire message
     *   (unless modified by spi_transfer.cs_change != 0).
     * + The message transfers use clock and SPI mode parameters
     *   previously established by setup() for this device
     */
// //添加一个消息到控制器的传输队列 
//SPI的数据传输的方法

    int            (*transfer)(struct spi_device *spi,
                        struct spi_message *mesg);


    /* called on release() to free memory provided by spi_master */
    void            (*cleanup)(struct spi_device *spi);
};


















阅读(883) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~