===============================
本文系本站原创,欢迎转载!
转载请注明出处:http://blog.csdn.net/gdt_a20
===============================
相比于前面介绍的i2c子系统,spi子系统相对简单,和i2c的结构也很相似,这里主要介绍一下平台无关部分的代码。先概括的说一下,spi总线或者说是spi控制器用结构体struct spi_master来表述,而一般不会明显的主动实现这个结构而是借助板级的一些信息结构,利用spi的模型填充,存在板级信息的一条链表board_list,上面挂接着板级spi设备的描述信息,其挂接的结构是struct boardinfo,这个结构内部嵌入了具体的板级spi设备所需信息结构struct spi_board_info,对于要操控的spi设备,用struct spidev_data来描述,内嵌了具体设备信息结构struct spi_device,并通过struct spi_device->device_entry成员挂接到全局spi设备链表device_list,结构struct spi_device就是根据前面board_list上所挂的信息填充的,而driver端比较简单,用struct spi_driver来描述,一会儿会看到该结构和标准的platform非常相似,总括的说下一般编写流程:对于soc,spi控制器一般注册成platform,当driver匹配后,会根据platform_device等信息构造出spi_master,一般发生在driver的probe函数,并且注册该master,在master的注册过程中会去遍历board_list找到bus号相同的spi设备信息,并实例化它,好了先就说这么多,下面先看一下具体的数据结构。
一、spi相关的数据结构
先看一下spi设备的板级信息填充的结构:
struct boardinfo { struct list_head list; //用于挂接到链表头board_list上 unsigned n_board_info; //设备信息号,spi_board_info成员的编号 struct spi_board_info board_info[0]; //内嵌的spi_board_info结构 }; //其中内嵌的描述spi设备的具体信息的结构struct spi_board_info为: struct spi_board_info { /* the device name and module name are coupled, like platform_bus; * "modalias" is normally the driver name. * * platform_data goes to spi_device.dev.platform_data, * controller_data goes to spi_device.controller_data, * irq is copied too */ char modalias[SPI_NAME_SIZE]; //名字 const void *platform_data; //如同注释写的指向spi_device.dev.platform_data void *controller_data; //指向spi_device.controller_data int irq; //中断号 /* slower signaling on noisy or low voltage boards */ u32 max_speed_hz; //时钟速率 /* bus_num is board specific and matches the bus_num of some * spi_master that will probably be registered later. * * chip_select reflects how this chip is wired to that master; * it's less than num_chipselect. */ u16 bus_num; //所在的spi总线编号 u16 chip_select; /* mode becomes spi_device.mode, and is essential for chips * where the default of SPI_CS_HIGH = 0 is wrong. */ u8 mode; //模式 /* ... may need additional spi_device chip config data here. * avoid stuff protocol drivers can set; but include stuff * needed to behave without being bound to a driver: * - quirks like clock rate mattering when not selected */ };
利用boardinfo->list成员会将自身挂接到全局的board_list链表上。
再来看一下spi控制器的表述结构:
struct spi_master { struct device dev; //内嵌的标准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. */ u16 num_chipselect; /* some SPI controllers pose alignment requirements on DMAable * buffers; let protocol drivers know about these requirements. */ u16 dma_alignment; //dma对其要求 /* spi_device.mode flags understood by this controller driver */ u16 mode_bits; //代表操作的spi_device.mode /* other constraints relevant to this driver */ u16 flags; //另外的一些标志 #define SPI_MASTER_HALF_DUPLEX BIT(0) /* can't do full duplex */ #define SPI_MASTER_NO_RX BIT(1) /* can't do buffer read */ #define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */ /* lock and mutex for SPI bus locking */ spinlock_t bus_lock_spinlock; struct mutex bus_lock_mutex; /* flag indicating that the SPI bus is locked for exclusive use */ bool bus_lock_flag; /* Setup mode and clock, etc (spi driver may call many times). * * IMPORTANT: this may be called when transfers to another * device are active. DO NOT UPDATE SHARED REGISTERS in ways * which could break those transfers. */ 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 */ 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); };
而对于要操控的spi总线上的设备,其表述结构为:
struct spi_device { struct device dev; //内嵌标准device结构体 struct spi_master *master; //spi主控制器 u32 max_speed_hz; //时钟速率 u8 chip_select; //设备编号 u8 mode; //模式 #define SPI_CPHA 0x01 /* clock phase */ #define SPI_CPOL 0x02 /* clock polarity */ #define SPI_MODE_0 (0|0) /* (original MicroWire) */ #define SPI_MODE_1 (0|SPI_CPHA) #define SPI_MODE_2 (SPI_CPOL|0) #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) #define SPI_CS_HIGH 0x04 /* chipselect active high? */ #define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ #define SPI_3WIRE 0x10 /* SI/SO signals shared */ #define SPI_LOOP 0x20 /* loopback mode */ #define SPI_NO_CS 0x40 /* 1 dev/bus, no chipselect */ #define SPI_READY 0x80 /* slave pulls low to pause */ u8 bits_per_word; int irq; //中断号 void *controller_state; //控制状态 void *controller_data; //私有数据 char modalias[SPI_NAME_SIZE]; //名字 /* * likely need more hooks for more protocol options affecting how * the controller talks to each chip, like: * - memory packing (12 bit samples into low bits, others zeroed) * - priority * - drop chipselect after each word * - chipselect delays * - ... */ };
再看一下对于spi设备结构更高层次的表述结构:
struct spidev_data { dev_t devt; spinlock_t spi_lock; struct spi_device *spi; //指向spi设备结构 struct list_head device_entry; //spi设备链表device_list挂接点 /* buffer is NULL unless this device is open (users > 0) */ struct mutex buf_lock; unsigned users; u8 *buffer; };
而driver端的表述结构struct spi_driver,具体如下:
struct spi_driver { const struct spi_device_id *id_table; //匹配的设备表 int (*probe)(struct spi_device *spi); int (*remove)(struct spi_device *spi); void (*shutdown)(struct spi_device *spi); int (*suspend)(struct spi_device *spi, pm_message_t mesg); int (*resume)(struct spi_device *spi); struct device_driver driver; };
是不是很标准?哈,好了,关于相关的数据结构就先介绍这么多。
二、spi核心代码的初始化分析
首先看一下spi总线的注册代码很简单,位于driver/spi/spi.c下:static int __init spi_init(void) { int status; //其中buf为static u8 *buf, //SPI_BUFSIZ为#define SPI_BUFSIZ max(32,SMP_CACHE_BYTES) buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL); if (!buf) { status = -ENOMEM; goto err0; } //注册spi_bus status = bus_register(&spi_bus_type); if (status < 0) goto err1; //在sys/class下产生spi_master这个节点,用于自动产生设备节点 //下面挂接的是控制器的节点 status = class_register(&spi_master_class); if (status < 0) goto err2; return 0; err2: bus_unregister(&spi_bus_type); err1: kfree(buf); buf = NULL; err0: return status; } //其中注册bus结构为 struct bus_type spi_bus_type = { .name = "spi", .dev_attrs = spi_dev_attrs, .match = spi_match_device, //匹配函数 .uevent = spi_uevent, .suspend = spi_suspend, .resume = spi_resume, }; //类函数为 static struct class spi_master_class = { .name = "spi_master", .owner = THIS_MODULE, .dev_release = spi_master_release, }; //顺便把driver与device的匹配函数也一起分析了吧,很简单 static int spi_match_device(struct device *dev, struct device_driver *drv) { const struct spi_device *spi = to_spi_device(dev); const struct spi_driver *sdrv = to_spi_driver(drv); /* Attempt an OF style match */ //利用of表进行匹配 if (of_driver_match_device(dev, drv)) return 1; //利用id表进行匹配 if (sdrv->id_table) return !!spi_match_id(sdrv->id_table, spi); //利用名字进行匹配 return strcmp(spi->modalias, drv->name) == 0; }
再看一下driver的注册,spi_register_driver函数:
int spi_register_driver(struct spi_driver *sdrv) { //很类似于platfor的注册,很简单, //就不具体介绍了 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; //注册标准的driver,此时会去匹配bus设备链表上 //支持的device,找到会调用相应函数 return driver_register(&sdrv->driver); }
还有个板级信息的添加函数:
int __init spi_register_board_info(struct spi_board_info const *info, unsigned n) { struct boardinfo *bi; 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); mutex_unlock(&board_lock); return 0; }
函数很简单,利用定义的spi_board_info信息,填充了boardinfo结构,并挂到board_list链表。
最后来看一下一个重量级函数,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 */ //支持的设备数量为0,出错返回 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 */ //控制器编号(总线编号)不能小于0 master->bus_num = atomic_dec_return(&dyn_bus_id); dynamic = 1; } spin_lock_init(&master->bus_lock_spinlock); mutex_init(&master->bus_lock_mutex); master->bus_lock_flag = 0; /* register the device, then userspace will see it. * registration fails if the bus ID is in use. */ //设置master->dev的名字,形式为spi+bus_num,如:spi0 dev_set_name(&master->dev, "spi%u", master->bus_num); //注册master内嵌的标准device结构 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设备 scan_boardinfo(master); status = 0; /* Register devices from the device tree */ of_register_spi_devices(master); done: return status; } //先来看scan_boardinfo这个分支 static void scan_boardinfo(struct spi_master *master) { struct boardinfo *bi; mutex_lock(&board_lock); //找到我们注册的spi相关的板级信息结构体 //还记得board_list吧 list_for_each_entry(bi, &board_list, list) { struct spi_board_info *chip = bi->board_info; unsigned n; //因为可能存在多个spi总线,因此spi信息结构也会有 //多个,找到bus号匹配的就对了 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函数 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). */ //为需要实例化的设备分配内存 //同时会将bus成员制定为spi_bus_type,parent //指定为该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总线 status = spi_add_device(proxy); if (status < 0) { spi_dev_put(proxy); return NULL; } return proxy; } //继续spi_add_device函数 int spi_add_device(struct spi_device *spi) { static DEFINE_MUTEX(spi_add_lock); struct device *dev = spi->master->dev.parent; struct device *d; int status; /* Chipselects are numbered 0..max; validate. */ //spi设备的编号不能大于master定义的最大数目 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; } /* Set the bus ID string */ //设备节点名字,形式:spi0.0 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); //确保设备不会重复注册 d = bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev)); if (d != NULL) { dev_err(dev, "chipselect %d already in use/n", spi->chip_select); put_device(d); 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... */ //设置spi模式和时钟速率 //会调用spi->master->setup函数设置 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; } /* 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; } //最后看下spi_setup函数 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 */ //必须和当前的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; //最后调用控制器平台相关的setup成员设置该spi设备 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; } //回头看下一开始下面的那个分支of_register_spi_devices void of_register_spi_devices(struct spi_master *master) { struct spi_device *spi; struct device_node *nc; const __be32 *prop; int rc; int len; //如果定义了of_node成员才会走该分支 if (!master->dev.of_node) return; //从控制器master->dev.of_node中去获取注册SPI设备spi_device的信息,然 //后分配结构体spi_device并注册 for_each_child_of_node(master->dev.of_node, nc) { /* Alloc an spi_device */ spi = spi_alloc_device(master); if (!spi) { dev_err(&master->dev, "spi_device alloc error for %s/n", nc->full_name); spi_dev_put(spi); continue; } /* Select device driver */ if (of_modalias_node(nc, spi->modalias, sizeof(spi->modalias)) < 0) { dev_err(&master->dev, "cannot find modalias for %s/n", nc->full_name); spi_dev_put(spi); continue; } /* Device address */ prop = of_get_property(nc, "reg", &len); if (!prop || len < sizeof(*prop)) { dev_err(&master->dev, "%s has no 'reg' property/n", nc->full_name); spi_dev_put(spi); continue; } spi->chip_select = be32_to_cpup(prop); /* Mode (clock phase/polarity/etc.) */ if (of_find_property(nc, "spi-cpha", NULL)) spi->mode |= SPI_CPHA; if (of_find_property(nc, "spi-cpol", NULL)) spi->mode |= SPI_CPOL; if (of_find_property(nc, "spi-cs-high", NULL)) spi->mode |= SPI_CS_HIGH; /* Device speed */ prop = of_get_property(nc, "spi-max-frequency", &len); if (!prop || len < sizeof(*prop)) { dev_err(&master->dev, "%s has no 'spi-max-frequency' property/n", nc->full_name); spi_dev_put(spi); continue; } spi->max_speed_hz = be32_to_cpup(prop); /* IRQ */ spi->irq = irq_of_parse_and_map(nc, 0); /* Store a pointer to the node in the device structure */ of_node_get(nc); spi->dev.of_node = nc; /* Register the new device */ request_module(spi->modalias); rc = spi_add_device(spi); if (rc) { dev_err(&master->dev, "spi_device register error %s/n", nc->full_name); spi_dev_put(spi); } } }
三、spi设备文件的自动产生代码分析
这部分代码相当于注册了一个spi实际driver,既是核心平台无关代码,又是个具体实例,我们来看下一下具体做了什么,也好学习一spi_driver的各部分具体都需要做些什么,代码位于driver/spi/spidev.c下:
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); //注册主设备号为153的spi字符设备,spidev_fops结构下面会介绍 //暂且不表 status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops); if (status < 0) return status; //在sys/class下产生spidev这个节点,udev会利用其在dev下产生spidev //这个设备节点 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驱动,该函数上面已经分析过 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; } //先看一下spidev_spi_driver具体的结构 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. */ }; //利用bus的match函数匹配成功后将首先调用spidev_probe函数,我们具体看下该函数: static int __devinit spidev_probe(struct spi_device *spi) { struct spidev_data *spidev; int status; unsigned long minor; /* Allocate driver data */ //申请spidev_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); //找到一个最小的次设备号 //addr为内存区的起始地址,size为要查找的最大长度 //返回第一个位为0的位号 minor = find_first_zero_bit(minors, N_SPI_MINORS); if (minor < N_SPI_MINORS) { struct device *dev; //下面两句用于在sys/class/spidev下产生类似于 //spidev%d.%d形式的节点,这样,udev等工具就可以 //自动在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; } //如果成功标明刚才的次设备号已被占用 //并且将该设备挂接到device_list链表 if (status == 0) { set_bit(minor, minors); list_add(&spidev->device_entry, &device_list); } mutex_unlock(&device_list_lock); //设置spi->dev->p = spidev if (status == 0) spi_set_drvdata(spi, spidev); else kfree(spidev); return status; }
当我们利用板级信息添加一个设备的时候,该driver如果匹配到这个设备,那么就会自动为其创建设备节点,封装spidev_data
信息,并且挂到全局设备链表device_list。
最后看一下刚才注册的字符设备的统一操作集:
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, }; //按应用的操作顺序先看下open函数 static int spidev_open(struct inode *inode, struct file *filp) { struct spidev_data *spidev; int status = -ENXIO; mutex_lock(&device_list_lock); //遍历spi设备链表device_list,根据设备号找到spidev_data结构 list_for_each_entry(spidev, &device_list, device_entry) { if (spidev->devt == inode->i_rdev) { status = 0; break; } } if (status == 0) { //buffer为空,为其申请内存 if (!spidev->buffer) { spidev->buffer = kmalloc(bufsiz, GFP_KERNEL); if (!spidev->buffer) { dev_dbg(&spidev->spi->dev, "open/ENOMEM/n"); status = -ENOMEM; } } //设备用户使用量+1 if (status == 0) { spidev->users++; //传到filp的私有成员,在read,write的时候可以从其得到该结构 filp->private_data = spidev; nonseekable_open(inode, filp); } } else pr_debug("spidev: nothing for minor %d/n", iminor(inode)); mutex_unlock(&device_list_lock); return status; } //再看read函数 static ssize_t spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { struct spidev_data *spidev; ssize_t status = 0; /* chipselect only toggles at start or end of operation */ if (count > bufsiz) return -EMSGSIZE; //得到传递的结构 spidev = filp->private_data; mutex_lock(&spidev->buf_lock); //调用具体的读函数 status = spidev_sync_read(spidev, count); if (status > 0) { unsigned long missing; //将得到的信息传递给用户 missing = copy_to_user(buf, spidev->buffer, status); if (missing == status) status = -EFAULT; else status = status - missing; } mutex_unlock(&spidev->buf_lock); return status; } //跟进spidev_sync_read函数,下面的操作比较直白,简要分析下 //只关注主流程 static inline ssize_t spidev_sync_read(struct spidev_data *spidev, size_t len) { //临时传输操作结构 struct spi_transfer t = { .rx_buf = spidev->buffer, .len = len, }; //传输所用的信息结构 struct spi_message m; //初始化该结构 spi_message_init(&m); //加到请求队列尾 spi_message_add_tail(&t, &m); //调用spidev_sync继续 return spidev_sync(spidev, &m); } //继续spidev_sync函数 static ssize_t spidev_sync(struct spidev_data *spidev, struct spi_message *message) { DECLARE_COMPLETION_ONSTACK(done); int status; message->complete = spidev_complete; //设置个完成量 message->context = &done; spin_lock_irq(&spidev->spi_lock); if (spidev->spi == NULL) status = -ESHUTDOWN; else //继续调用spi_async函数 status = spi_async(spidev->spi, message); spin_unlock_irq(&spidev->spi_lock); if (status == 0) { //等待完成 wait_for_completion(&done); status = message->status; if (status == 0) status = message->actual_length; } return status; } //spi_async函数 int spi_async(struct spi_device *spi, struct spi_message *message) { struct spi_master *master = spi->master; int ret; unsigned long flags; spin_lock_irqsave(&master->bus_lock_spinlock, flags); if (master->bus_lock_flag) ret = -EBUSY; else //好长...继续跟进 ret = __spi_async(spi, message); spin_unlock_irqrestore(&master->bus_lock_spinlock, flags); return ret; } //__spi_async函数 static int __spi_async(struct spi_device *spi, struct spi_message *message) { struct spi_master *master = spi->master; /* Half-duplex links include original MicroWire, and ones with * only one data pin like SPI_3WIRE (switches direction) or where * either MOSI or MISO is missing. They can also be caused by * software limitations. */ if ((master->flags & SPI_MASTER_HALF_DUPLEX) || (spi->mode & SPI_3WIRE)) { struct spi_transfer *xfer; unsigned flags = master->flags; list_for_each_entry(xfer, &message->transfers, transfer_list) { if (xfer->rx_buf && xfer->tx_buf) return -EINVAL; if ((flags & SPI_MASTER_NO_TX) && xfer->tx_buf) return -EINVAL; if ((flags & SPI_MASTER_NO_RX) && xfer->rx_buf) return -EINVAL; } } message->spi = spi; message->status = -EINPROGRESS; //最后调用master->transfer具体的平台相关的结构 return master->transfer(spi, message); }
read函数就分析到此,至于write函数就不具体分析了,流程是相似的!
四、总结
根据前面的积累,这次简要分析了下spi设备驱动的模型,由于和i2c很相似,就不给出具体框图了,后面有时间会结合具体平台分析一下spi的实例,这次就到这里了 @^.^@