linux spi 平台驱动6,linux 2.6.28之spi平台驱动spi_sam.c的初始化代码

module_init(sam_spi_init);

static int __init sam_spi_init(void)

{

dbg_printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);

//在match函数匹配成功的情况下, 系统将调用相应的probe函数,此处是直接在模块初始化时直接调用probe?

returnplatform_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 voidhandle_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)函数中调用//初始化工作队列并将其与处理函数绑定

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

};

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值