PowerPC + Linux2.6.25平台下的SPI驱动架构分析
Sailor_forever sailing_9806#163.com
(本原创文章发表于Sailor_forever 的个人blog,未经本人许可,不得用于商业用途。任何个人、媒体、其他网站不得私自抄袭;网络媒体转载请注明出处,增加原文链接,否则属于侵权行为。如 有任何问题,请留言或者发邮件给sailing_9806#163.com)
http://blog.csdn.net/sailor_8318/archive/2010/10/31/5977733.aspx
【摘要】本文以PowerPC+Linux 2.6.25 平台为例,详细分析了SPI总线的驱动架构。首先介绍了SPI的总体架构,从用户的角度将其分为三个层面,不同的开发者只需要关注相应的层面即可。然后分析了主要数据结构及其之间的相互关系,接着分析了不同层的具体实现,最后以一款SPI接口的时钟芯片为例讲述了如何在用户空间访问SPI驱动。对于ARM + Linux平台,只有平台依赖层即总线控制器驱动有差异。
【关键字】PowerPC, SPI, Master, Slave, spidev
目录
1 SPI概述 3
2 SPI总体架构 3
2.1 硬件抽象层 3
2.2 平台依赖层 3
2.3 用户接口层 3
3 主要的数据结构 4
3.1 Spi_master 4
3.2 SPI_driver 5
3.3 Spi_device 6
4 平台依赖层-总线控制器驱动 7
4.1 platform device 8
4.2 platform driver 11
4.3 SPI Master 14
5 硬件抽象层-SPI core 14
5.1 总线初始化 14
5.2 Master注册 15
5.3 驱动注册 19
5.4 数据传输 19
6 用户接口层-SPI设备驱动 21
6.1 统一的设备模型 21
6.1.1 关键数据结构 21
6.1.2 初始化 22
6.1.3 Open及release 24
6.1.4 数据收发 25
6.2 特定的设备驱动 36
6.2.1 关键数据结构 37
6.2.2 初始化 38
6.2.3 数据收发 42
7 驱动访问示例 42
7.1.1 写操作 43
7.1.2 读操作 43
8 参考鸣谢 44
1 SPI概述
SPI的通信原理很简单,它以主从方式工作,这种模式通常有一个主设备和一个或多个从设备,需要至少4根线,事实上3根也可以(单向传输时或者硬件复用两根数据线),也是所有基于SPI的设备共有的,它们是MISO、MOSI、SCK、CS。
(1)SDO – 主设备数据输出,从设备数据输入
(2)MISO– 主设备数据输入,从设备数据输出
(3)SCK – 时钟信号,由主设备产生
(4)CS – 从设备使能信号,由主设备控制
其中CS是控制芯片是否被选中的,也就是说只有片选信号为预先规定的使能信号时(高电位或低电位),对此芯片的操作才有效,这就允许在同一总线上连接多个SPI设备成为可能。接下来就负责通讯的3根线了,通讯是通过数据交换完成的。SPI是串行通讯协议,也就是说数据是一位一位从MSB或者LSB开始传输的,这就是SCK时钟线存在的原因,由SCK提供时钟脉冲,MISO、MOSI则基于此脉冲完成数据传输。 SPI支持4-32bits的串行数据传输,支持MSB和LSB,每次数据传输时当从设备的大小端发生变化时需要重新设置SPI Master的大小端。
2 SPI总体架构
在2.6的Linux内核中,SPI的驱动架构分为如下三个层次:硬件抽象层、平台依赖层和用户接口层。
2.1 硬件抽象层
SPI-bitbang.c和SPI.c为其主体框架代码,提供了核心数据结构的定义、SPI控制器驱动和设备驱动的注册、注销管理等API。其为硬件平台无关层,向下屏蔽了物理总线控制器的差异,定义了统一的访问策略和接口;其向上提供了统一的接口,以便SPI设备驱动通过总线控制器进行数据收发。
2.2 平台依赖层
SPI总线Master就是一条SPI总线的控制器(所谓控制是相对于本CPU来说的),在物理上连接若干SPI从设备。在Linux驱动中,每种处理器平台有自己的控制器驱动,属于平台移植相关层。PowerPC平台来说,其是spi_mpc83xx.c。其按照核心层定义的接口实现了spi_master。
2.3 用户接口层
设备驱动层为用户接口层,其为用户提供了通过SPI总线访问具体设备的接口。
3 主要的数据结构
3.1 Spi_master
spi_master是对某一条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.
*/
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.
*/
u16 num_chipselect;
/* 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
*/
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);
};
3.2 SPI_driver
http://lxr.linux.no/#linux+v2.6.25/include/linux/SPI.h#L105
/**
* struct spi_driver - Host side "protocol" driver
* @probe: Binds this driver to the spi device. Drivers can verify
* that the device is actually present, and may need to configure
* characteristics (such as bits_per_word) which weren't needed for
* the initial configuration done during system setup.
* @remove: Unbinds this driver from the spi device
* @shutdown: Standard shutdown callback used during system state
* transitions such as powerdown/halt and kexec
* @suspend: Standard suspend callback used during system state transitions
* @resume: Standard resume callback used during system state transitions
* @driver: SPI device drivers should initialize the name and owner
* field of this structure.
*
* This represents the kind of device driver that uses SPI messages to
* interact with the hardware at the other end of a SPI link. It's called
* a "protocol" driver because it works through messages rather than talking
* directly to SPI hardware (which is what the underlying SPI controller
* driver does to pass those messages). These protocols are defined in the
* specification for the device(s) supported by the driver.
*
* As a rule, those device protocols represent the lowest level interface
* supported by a driver, and it will support upper level interfaces too.
* Examples of such upper levels include frameworks like MTD, networking,
* MMC, RTC, filesystem character device nodes, and hardware monitoring.
*/
struct spi_driver {
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;
};
Driver是为device服务的,SPI_driver注册时会扫描SPI bus上的设备,进行驱动和设备的绑定。
3.3 Spi_device
http://lxr.linux.no/#linux+v2.6.25/include/linux/SPI.h#L168
/**
* struct spi_device - Master side proxy for an SPI slave device
* @dev: Driver model representation of the device.
* @master: SPI controller used with the device.
* @max_speed_hz: Maximum clock rate to be used with this chip
* (on this board); may be changed by the device's driver.
* The spi_transfer.speed_hz can override this for each transfer.
* @chip_select: Chipselect, distinguishing chips handled by @master.
* @mode: The spi mode defines how data is clocked out and in.
* This may be changed by the device's driver.
* The "active low" default for chipselect mode can be overridden
* (by specifying SPI_CS_HIGH) as can the "MSB first" default for
* each word in a transfer (by specifying SPI_LSB_FIRST).
* @bits_per_word: Data transfers involve one or more words; word sizes
* like eight or 12 bits are common. In-memory wordsizes are
* powers of two bytes (e.g. 20 bit samples use 32 bits).
* This may be changed by the device's driver, or left at the
* default (0) indicating protocol words are eight bit bytes.
* The spi_transfer.bits_per_word can override this for each transfer.
* @irq: Negative, or the number passed to request_irq() to receive
* interrupts from this device.
* @controller_state: Controller's runtime state
* @controller_data: Board-specific definitions for controller, such as
* FIFO initialization parameters; from board_info.controller_data
*
* A @spi_device is used to interchange data between an SPI slave
* (usually a discrete chip) and CPU memory.
*
* In @dev, the platform_data is used to hold information about this
* device that's meaningful to the device's protocol driver, but not
* to its controller. One example might be an identifier for a chip
* variant with slightly different functionality; another might be
* information about how this particular board wires the chip's pins.
*/
struct spi_device {
struct device dev;
struct spi_master *master;
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 */
u8 bits_per_word;
int irq;
void *controller_state;
void *controller_data;
。。。
};
spi_device对应着SPI总线上某个特定的slave。每个slave都有特定的大小端、速率及传输位宽,各个slave相互之间无干扰。
4 平台依赖层-总线控制器驱动
总线控制器驱动,本质上就是实现了具体的总线传输算法并向核心层注册了控制器。主要分为三个层面,platform device,platform driver及与SPI core的接口层。
Linux内核的所有SPI控制器驱动程序都在driver/SPI/下面,MPC8xxx驱动是spi_mpc83xx.c。
4.1 platform device
2.6内核中硬件资源的注册都采用了platform device的机制。对于PowerPC来说,其硬件资源是通过DTS来描述的。
spi@7000 {
cell-index = <0>;
compatible = "fsl,spi";
reg = <0x7000 0x1000>;
interrupts = <16 0x8>;
interrupt-parent = <&ipic>;
mode = "cpu";
};
中断号、中断触发电平、寄存器的基地址及范围等信息会在设备树中描述了,此后只需利用platform_get_resource等标准接口自动获取即可,实现了驱动和资源的分离。Cell-index标识了总线编号,也就是SPI master的编号。
随后在系统启动阶段会解析DTB文件,将相关资源注册到Platform bus上。
http://lxr.linux.no/#linux+v2.6.25/arch/powerpc/sysdev/fsl_soc.c#L454
int __init fsl_spi_init(struct spi_board_info *board_infos,
unsigned int num_board_infos,
void (*activate_cs)(u8 cs, u8 polarity),
void (*deactivate_cs)(u8 cs, u8 polarity))
{
u32 sysclk = -1;
int ret;
。。。。。
if (sysclk == -1) {
struct device_node *np;
const u32 *freq;
int size;
np = of_find_node_by_type(NULL, "soc"); //获得SOC中注册的总线频率
if (!np)
return -ENODEV;
freq = of_get_property(np, "clock-frequency", &size);
if (!freq || size != sizeof(*freq) || *freq == 0) {
freq = of_get_property(np, "bus-frequency", &size);
if (!freq || size != sizeof(*freq) || *freq == 0) {
of_node_put(np);
return -ENODEV;
}
}
sysclk = *freq;
of_node_put(np);
}
ret = of_fsl_spi_probe(NULL, "fsl,spi", sysclk, board_infos,
num_board_infos, activate_cs, deactivate_cs);
if (!ret)
of_fsl_spi_probe("spi", "fsl_spi", sysclk, board_infos,
num_board_infos, activate_cs, deactivate_cs);
return spi_register_board_info(board_infos, num_board_infos); //将SPI board info注册进系统SPI设备列表中
}
static int __init of_fsl_spi_probe(char *type, char *compatible, u32 sysclk,
struct spi_board_info *board_infos,
unsigned int num_board_infos,
void (*activate_cs)(u8 cs, u8 polarity),
void (*deactivate_cs)(u8 cs, u8 polarity))
{
struct device_node *np;
unsigned int i = 0;
for_each_compatible_node(np, type, compatible) { //根据compatible属性"fsl,spi"查找相关device node节点
int ret;
unsigned int j;
const void *prop;
struct resource res[2];
struct platform_device *pdev;
struct fsl_spi_platform_data pdata = { //板级相关的SPI片选实现函数
.activate_cs = activate_cs,
.deactivate_cs = deactivate_cs,
};
memset(res, 0, sizeof(res));
pdata.sysclk = sysclk;
prop = of_get_property(np, "reg", NULL);
if (!prop)
goto err;
pdata.bus_num = *(u32 *)prop; //reg是寄存器的范围,如何与总线编号挂钩的呢?
prop = of_get_property(np, "cell-index", NULL);
if (prop)
i = *(u32 *)prop;
prop = of_get_property(np, "mode", NULL);
if (prop && !strcmp(prop, "cpu-qe"))
pdata.qe_mode = 1;
for (j = 0; j < num_board_infos; j++) { //根据板级移植相关的board info指定的bus num进行匹配
if (board_infos[j].bus_num == pdata.bus_num)
pdata.max_chipselect++;
}
if (!pdata.max_chipselect)
continue;
ret = of_address_to_resource(np, 0, &res[0]);
if (ret)
goto err;
ret = of_irq_to_resource(np, 0, &res[1]);
if (ret == NO_IRQ)
goto err;
pdev = platform_device_alloc("mpc83xx_spi", i); //以mpc83xx_spi为name申请platform device,后续的platform driver将以mpc83xx_spi为匹配因子
if (!pdev)
goto err;
ret = platform_device_add_data(pdev, &pdata, sizeof(pdata)); //将pdata等特定的属性添加到platform device中,以供相应的platform driver检测。
if (ret)
goto unreg;
ret = platform_device_add_resources(pdev, res,
ARRAY_SIZE(res));
if (ret)
goto unreg;
ret = platform_device_add(pdev); //将SPI相关的platform device添加到platform bus上
if (ret)
goto unreg;
goto next;
unreg:
platform_device_del(pdev);
err:
pr_err("%s: registration failed/n", np->full_name);
next:
i++;
}
return i;
}
4.2 platform driver
static struct platform_driver mpc83xx_spi_driver = {
.remove = __exit_p(mpc83xx_spi_remove),
.driver = {
.name = "mpc83xx_spi",
.owner = THIS_MODULE,
},
};
static int __init mpc83xx_spi_init(void)
{
return platform_driver_probe(&mpc83xx_spi_driver, mpc83xx_spi_probe);
}
static void __exit mpc83xx_spi_exit(void)
{
platform_driver_unregister(&mpc83xx_spi_driver);
}
mpc83xx_spi_driver注册时会扫描platform bus上的所有设备,匹配因子是mpc83xx_spi,匹配成功后调用mpc83xx_spi_probe将设备和驱动绑定起来,具体过程参加《详解Linux2.6内核中基于platform机制的驱动模型》,随后向系统注册一个adapter。
http://blog.csdn.net/sailor_8318/archive/2010/01/29/5267698.aspx
static int __init mpc83xx_spi_probe(struct platform_device *dev)
{
struct spi_master *master;
struct mpc83xx_spi *mpc83xx_spi;
struct fsl_spi_platform_data *pdata;
struct resource *r;
u32 regval;
int ret = 0;
/* Get resources(memory, IRQ) associated with the device */
master = spi_alloc_master(&dev->dev, sizeof(struct mpc83xx_spi)); // 分配一个SPI Master
if (master == NULL) {
ret = -ENOMEM;
goto err;
}
platform_set_drvdata(dev, master);
pdata = dev->dev.platform_data; //获得platform device注册的特定资源
if (pdata == NULL) {
ret = -ENODEV;
goto free_master;
}
r = platform_get_resource(dev, IORESOURCE_MEM, 0);
if (r == NULL) {
ret = -ENODEV;
goto free_master;
}
mpc83xx_spi = spi_master_get_devdata(master);
mpc83xx_spi->bitbang.master = spi_master_get(master);
mpc83xx_spi->bitbang.chipselect = mpc83xx_spi_chipselect;
mpc83xx_spi->bitbang.setup_transfer = mpc83xx_spi_setup_transfer;
mpc83xx_spi->bitbang.txrx_bufs = mpc83xx_spi_bufs;
mpc83xx_spi->activate_cs = pdata->activate_cs;
mpc83xx_spi->deactivate_cs = pdata->deactivate_cs; // 将特定的片选实现函数保存到mpc83xx_spi中
mpc83xx_spi->qe_mode = pdata->qe_mode;
mpc83xx_spi->get_rx = mpc83xx_spi_rx_buf_u8;
mpc83xx_spi->get_tx = mpc83xx_spi_tx_buf_u8;
mpc83xx_spi->spibrg = pdata->sysclk;
mpc83xx_spi->rx_shift = 0;
mpc83xx_spi->tx_shift = 0;
if (mpc83xx_spi->qe_mode) {
mpc83xx_spi->rx_shift = 16;
mpc83xx_spi->tx_shift = 24;
}
mpc83xx_spi->bitbang.master->setup = mpc83xx_spi_setup;
init_completion(&mpc83xx_spi->done);
mpc83xx_spi->base = ioremap(r->start, r->end - r->start + 1);
if (mpc83xx_spi->base == NULL) {
ret = -ENOMEM;
goto put_master;
}
mpc83xx_spi->irq = platform_get_irq(dev, 0); //从platform device中获得相应的寄存器和中断等信息
if (mpc83xx_spi->irq < 0) {
ret = -ENXIO;
goto unmap_io;
}
/* Register for SPI Interrupt */
ret = request_irq(mpc83xx_spi->irq, mpc83xx_spi_irq,
0, "mpc83xx_spi", mpc83xx_spi);
if (ret != 0)
goto unmap_io;
master->bus_num = pdata->bus_num;
master->num_chipselect = pdata->max_chipselect;
/* SPI controller initializations */
mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, 0);
mpc83xx_spi_write_reg(&mpc83xx_spi->base->mask, 0);
mpc83xx_spi_write_reg(&mpc83xx_spi->base->command, 0);
mpc83xx_spi_write_reg(&mpc83xx_spi->base->event, 0xffffffff);
/* Enable SPI interface */
regval = pdata->initial_spmode | SPMODE_INIT_VAL | SPMODE_ENABLE;
if (pdata->qe_mode)
regval |= SPMODE_OP;
mpc83xx_spi_write_reg(&mpc83xx_spi->base->mode, regval);
ret = spi_bitbang_start(&mpc83xx_spi->bitbang); //MPC83xx系列将在spi_bitbang_start中注册SPI master
if (ret != 0)
goto free_irq;
printk(KERN_INFO
"%s: MPC83xx SPI Controller driver at 0x%p (irq = %d)/n",
dev->dev.bus_id, mpc83xx_spi->base, mpc83xx_spi->irq);
return ret;
free_irq:
free_irq(mpc83xx_spi->irq, mpc83xx_spi);
unmap_io:
iounmap(mpc83xx_spi->base);
put_master:
spi_master_put(master);
free_master:
kfree(master);
err:
return ret;
}
4.3 SPI Master
每一个SPI master都要实现setup、transfer及cleanup等。
static int mpc83xx_spi_setup(struct spi_device *spi)
static int mpc83xx_spi_bufs(struct spi_device *spi, struct spi_transfer *t)
mpc83xx_spi->bitbang.txrx_bufs = mpc83xx_spi_bufs;
MPC837x SPI Master的具体实现待续。
5 硬件抽象层-SPI core
5.1 总线初始化
static int __init spi_init(void)
{
int status;
buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
if (!buf) {
status = -ENOMEM;
goto err0;
}
status = bus_register(&spi_bus_type);
if (status < 0)
goto err1;
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;
}
/* board_info is normally registered in arch_initcall(),
* but even essential drivers wait till later
*
* REVISIT only boardinfo really needs static linking. the rest (device and
* driver registration) _could_ be dynamically linked (modular) ... costs
* include needing to have boardinfo data structures be much more public.
*/
subsys_initcall(spi_init);
关于被subsys_initcall修饰的spi_init何时初始化,请参考下文《详解Linux2.6内核中基于platform机制的驱动模型》
http://blog.csdn.net/sailor_8318/archive/2010/01/29/5267698.aspx
此时platform bus及platform device已经注册完毕,因此SPI控制器的相关资源已经就绪。
5.2 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.
*/
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.
*/
snprintf(master->dev.bus_id, sizeof master->dev.bus_id,
"spi%u", master->bus_num);
status = device_add(&master->dev);
if (status < 0)
goto done;
dev_dbg(dev, "registered master %s%s/n", master->dev.bus_id,
dynamic ? " (dynamic)" : "");
/* populate children from any spi device tables */
scan_boardinfo(master);
status = 0;
done:
return status;
}
EXPORT_SYMBOL_GPL(spi_register_master);
static void scan_boardinfo(struct spi_master *master)
{
struct boardinfo *bi;
mutex_lock(&board_lock);
list_for_each_entry(bi, &board_list, list) {//board list已经在platform device注册时初始化
struct spi_board_info *chip = bi->board_info;
unsigned n;
for (n = bi->n_board_info; n > 0; n--, chip++) {
if (chip->bus_num != master->bus_num) //Master的总线号和相应slave所在的总线号匹配
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
* 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;
struct device *dev = master->dev.parent;
int status;
/* NOTE: caller did any chip->bus_num checks necessary.
*/
/* Chipselects are numbered 0..max; validate. */
if (chip->chip_select >= master->num_chipselect) {
dev_err(dev, "cs%d > max %d/n",
chip->chip_select,
master->num_chipselect);
return NULL;
}
if (!spi_master_get(master))
return NULL;
proxy = kzalloc(sizeof *proxy, GFP_KERNEL); //分配一个SPI device
if (!proxy) {
dev_err(dev, "can't alloc dev for cs%d/n",
chip->chip_select);
goto fail;
}
proxy->master = master; // SPI slave所依附的SPI Master
proxy->chip_select = chip->chip_select; // 保存board info中特定的属性,板级移植需要关注
proxy->max_speed_hz = chip->max_speed_hz;
proxy->mode = chip->mode;
proxy->irq = chip->irq;
proxy->modalias = chip->modalias;
snprintf(proxy->dev.bus_id, sizeof proxy->dev.bus_id,
"%s.%u", master->dev.bus_id,
chip->chip_select);
proxy->dev.parent = dev;
proxy->dev.bus = &spi_bus_type; //此设备所依附的总线为SPI
proxy->dev.platform_data = (void *) chip->platform_data;
proxy->controller_data = chip->controller_data;
proxy->controller_state = NULL;
proxy->dev.release = spidev_release;
/* drivers may modify this initial i/o setup */
status = master->setup(proxy);
if (status < 0) {
dev_err(dev, "can't %s %s, status %d/n",
"setup", proxy->dev.bus_id, status);
goto fail;
}
/* driver core catches callers that misbehave by defining
* devices that already exist.
*/
status = device_register(&proxy->dev); // 将该SPI device挂接到SPI总线上
if (status < 0) {
dev_err(dev, "can't %s %s, status %d/n",
"add", proxy->dev.bus_id, status);
goto fail;
}
dev_dbg(dev, "registered child %s/n", proxy->dev.bus_id);
return proxy;
fail:
spi_master_put(master);
kfree(proxy);
return NULL;
}
EXPORT_SYMBOL_GPL(spi_new_device);
5.3 驱动注册
/**
* 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 driver采用内核通用的驱动模型,其流程和platform driver的注册过程类似,请请参考下文《详解Linux2.6内核中基于platform机制的驱动模型》
http://blog.csdn.net/sailor_8318/archive/2010/01/29/5267698.aspx
5.4 数据传输
/**
* spi_sync - blocking/synchronous SPI data transfers
* @spi: device with which data will be exchanged
* @message: describes the data transfers
* Context: can sleep
*
* This call may only be used from a context that may sleep. The sleep
* is non-interruptible, and has no timeout. Low-overhead controller
* drivers may DMA directly into and out of the message buffers.
*
* Note that the SPI device's chip select is active during the message,
* and then is normally disabled between messages. Drivers for some
* frequently-used devices may want to minimize costs of selecting a chip,
* by leaving it selected in anticipation that the next message will go
* to the same chip. (That may increase power usage.)
*
* Also, the caller is guaranteeing that the memory associated with the
* message will not be freed before this call returns.
*
* It returns zero on success, else a negative error code.
*/
int spi_sync(struct spi_device *spi, struct spi_message *message)
{
DECLARE_COMPLETION_ONSTACK(done);
int status;
message->complete = spi_complete;
message->context = &done;
status = spi_async(spi, message);
if (status == 0) {
wait_for_completion(&done);
status = message->status;
}
message->context = NULL;
return status;
}
EXPORT_SYMBOL_GPL(spi_sync);
同步接口,待数据收发完毕后才返回,只能在非中断上下文中使用。
/**
* spi_async - asynchronous SPI transfer
* @spi: device with which data will be exchanged
* @message: describes the data transfers, including completion callback
* Context: any (irqs may be blocked, etc)
*
* This call may be used in_irq and other contexts which can't sleep,
* as well as from task contexts which can sleep.
*
* The completion callback is invoked in a context which can't sleep.
* Before that invocation, the value of message->status is undefined.
* When the callback is issued, message->status holds either zero (to
* indicate complete success) or a negative error code. After that
* callback returns, the driver which issued the transfer request may
* deallocate the associated memory; it's no longer in use by any SPI
* core or controller driver code.
*
* Note that although all messages to a spi_device are handled in
* FIFO order, messages may go to different devices in other orders.
* Some device might be higher priority, or have various "hard" access
* time requirements, for example.
*
* On detection of any fault during the transfer, processing of
* the entire message is aborted, and the device is deselected.
* Until returning from the associated message completion callback,
* no other spi_message queued to that device will be processed.
* (This rule applies equally to all the synchronous transfer calls,
* which are wrappers around this core asynchronous primitive.)
*/
static inline int spi_async(struct spi_device *spi, struct spi_message *message)
{
message->spi = spi;
return spi->master->transfer(spi, message);
}
异步接口,根据spi device找到其所在的spi master,用master所特定的transfer函数实现数据收发。
核心层提供的通用数据收发接口,屏蔽了底层差异。
6 用户接口层-SPI设备驱动
6.1 统一的设备模型
此驱动模型是针对SPI Slave的,只有注册board info时modalias是spidev的才能由此驱动访问。访问各个slave的基本框架是一致的,具体的差异将由从设备号来体现。
6.1.1 关键数据结构
static struct spi_driver spidev_spi = {
.driver = {
.name = "spidev",
.owner = THIS_MODULE,
},
.probe = spidev_probe,
.remove = __devexit_p(spidev_remove),
};
定义了一个标准的SPI_driver。
struct spidev_data {
struct device dev;
struct spi_device *spi;
struct list_head device_entry;
struct mutex buf_lock;
unsigned users;
u8 *buffer;
};
static LIST_HEAD(device_list);
static DEFINE_MUTEX(device_list_lock);
定义了一个SPI dev列表,每个slave对应一个struct spidev_data, 以device_entry为节点连接在device_list上。
static struct file_operations spidev_fops = {
.owner = THIS_MODULE,
.write = spidev_write,
.read = spidev_read,
.ioctl = spidev_ioctl,
.open = spidev_open,
.release = spidev_release,
};
任意一个需要和用户空间通信的驱动必备的数据结构,其定义了具体的读写操作方法。
6.1.2 初始化
http://lxr.linux.no/#linux+v2.6.25/drivers/SPI/SPI-dev.c#L607
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);
status = register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
if (status < 0)
return status;
status = class_register(&spidev_class);
if (status < 0) {
unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
return status;
}
status = spi_register_driver(&spidev_spi);
if (status < 0) {
class_unregister(&spidev_class);
unregister_chrdev(SPIDEV_MAJOR, spidev_spi.driver.name);
}
return status;
}
module_init(spidev_init);
首先注册了一个字符型设备驱动,然后注册spi_driver,其将在SPI总线上查找对应的设备,根据关键字spidev进行匹配,匹配成功后将调用spi_driver的probe方法,即spidev_probe,将驱动和每一个salve绑定起来,并建立对应的dev设备节点,同时维护了一个spidev_data链表。
static int 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;
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) {
spidev->dev.parent = &spi->dev;
spidev->dev.class = &spidev_class;
spidev->dev.devt = MKDEV(SPIDEV_MAJOR, minor); //各个slave的从设备号是从0依次递增的
snprintf(spidev->dev.bus_id, sizeof spidev->dev.bus_id,
"spidev%d.%d",
spi->master->bus_num, spi->chip_select);
status = device_register(&spidev->dev);
} else {
dev_dbg(&spi->dev, "no minor number available!/n");
status = -ENODEV;
}
if (status == 0) {
set_bit(minor, minors);
dev_set_drvdata(&spi->dev, spidev);
list_add(&spidev->device_entry, &device_list); // 将该SPI dev添加到SPI device列表中
}
mutex_unlock(&device_list_lock);
if (status != 0)
kfree(spidev);
return status;
}
以SPI_MAJOR和动态从设备号为主从设备号注册设备节点,如果系统有udev或者是hotplug,那么就会在/dev下自动创建相关的设备节点了,其名称命名方式为spidevB.C,B为总线编号,C为片选序号。
6.1.3 Open及release
static int spidev_open(struct inode *inode, struct file *filp)
{
struct spidev_data *spidev;
int status = -ENXIO;
mutex_lock(&device_list_lock);
list_for_each_entry(spidev, &device_list, device_entry) {
if (spidev->dev.devt == inode->i_rdev) { // 根据设备节点号进行匹配查找对应的spidev_data节点从而找到相应的从设备
status = 0;
break;
}
}
if (status == 0) {
if (!spidev->buffer) {
spidev->buffer = kmalloc(bufsiz, GFP_KERNEL); // 为每个slave分配了一段缓冲区
if (!spidev->buffer) {
dev_dbg(&spidev->spi->dev, "open/ENOMEM/n");
status = -ENOMEM;
}
}
if (status == 0) {
spidev->users++; // 访问该SPI slave的user加1
filp->private_data = spidev; //面向对象的典型应用,将特定数据保存在filp->private_data中,其他函数可以直接从filp->private_data中取出需要的东西,避免过多的使用全局变量来传递信息
nonseekable_open(inode, filp);
}
} else
pr_debug("spidev: nothing for minor %d/n", iminor(inode));
mutex_unlock(&device_list_lock);
return status;
}
static int spidev_release(struct inode *inode, struct file *filp)
{
struct spidev_data *spidev;
int status = 0;
mutex_lock(&device_list_lock);
spidev = filp->private_data;
filp->private_data = NULL;
spidev->users--;
if (!spidev->users) { // 无用户再访问该slave时才释放其buffer
kfree(spidev->buffer);
spidev->buffer = NULL;
}
mutex_unlock(&device_list_lock);
return status;
}
Open操作是用户空间程序和内核驱动交换的第一步,最终返回给用户空间的就是struct file结构体。对于SPI 驱动来说,用户空间所获得的就是spidev这个关键信息。
6.1.4 数据收发
对于SPI驱动来说,数据收发有两种途径,read/write或者ioctl方式。但无论哪种方式,最终都是构造一个spi_message。
/**
* struct spi_message - one multi-segment SPI transaction
* @transfers: list of transfer segments in this transaction
* @spi: SPI device to which the transaction is queued
* @is_dma_mapped: if true, the caller provided both dma and cpu virtual
* addresses for each transfer buffer
* @complete: called to report transaction completions
* @context: the argument to complete() when it's called
* @actual_length: the total number of bytes that were transferred in all
* successful segments
* @status: zero for success, else negative errno
* @queue: for use by whichever driver currently owns the message
* @state: for use by whichever driver currently owns the message
*
* A @spi_message is used to execute an atomic sequence of data transfers,
* each represented by a struct spi_transfer. The sequence is "atomic"
* in the sense that no other spi_message may use that SPI bus until that
* sequence completes. On some systems, many such sequences can execute
* as single programmed DMA transfer. On all systems, these messages are
* queued, and might complete after transactions to other devices. Messages
* sent to a given spi_device are always executed in FIFO order.
*
*/
struct spi_message {
struct list_head transfers; // 所包含的spi_transfer链表
struct spi_device *spi; // 消息所发往的对象
unsigned is_dma_mapped:1;
/* completion is reported through a callback */
void (*complete)(void *context); //消息发送完毕后的回调函数
void *context;
unsigned actual_length;
int status;
/* for optional use by whatever driver currently owns the
* spi_message ... between calls to spi_async and then later
* complete(), that's the spi_master controller driver.
*/
struct list_head queue; // spi_message会由SPI Maser驱动统一组织成链表,顺序处理,以此防止各个spi slave同时访问总线而导致冲突
void *state;
};
spi_message 包含了一系列spi_transfer,在所有的spi_transfer发送完毕前,SPI总线一直被占据,其间不会出现总线冲突,因此一个spi_message是一个原子系列,这种特性非常利于复杂的SPI通信协议,如先发送命令字然后才能读取数据。
/*
* I/O INTERFACE between SPI controller and protocol drivers
*
* Protocol drivers use a queue of spi_messages, each transferring data
* between the controller and memory buffers.
*
* The spi_messages themselves consist of a series of read+write transfer
* segments. Those segments always read the same number of bits as they
* write; but one or the other is easily ignored by passing a null buffer
* pointer. (This is unlike most types of I/O API, because SPI hardware
* is full duplex.)
*
*/
/**
* struct spi_transfer - a read/write buffer pair
* @tx_buf: data to be written (dma-safe memory), or NULL
* @rx_buf: data to be read (dma-safe memory), or NULL
* @tx_dma: DMA address of tx_buf, if @spi_message.is_dma_mapped
* @rx_dma: DMA address of rx_buf, if @spi_message.is_dma_mapped
* @len: size of rx and tx buffers (in bytes)
* @speed_hz: Select a speed other then the device default for this
* transfer. If 0 the default (from @spi_device) is used.
* @bits_per_word: select a bits_per_word other then the device default
* for this transfer. If 0 the default (from @spi_device) is used.
* @cs_change: affects chipselect after this transfer completes
* @delay_usecs: microseconds to delay after this transfer before
* (optionally) changing the chipselect status, then starting
* the next transfer or completing this @spi_message.
* @transfer_list: transfers are sequenced through @spi_message.transfers
*
* SPI transfers always write the same number of bytes as they read.
* Protocol drivers should always provide @rx_buf and/or @tx_buf.
*
* If the transmit buffer is null, zeroes will be shifted out
* while filling @rx_buf. If the receive buffer is null, the data
* shifted in will be discarded. Only "len" bytes shift out (or in).
* It's an error to try to shift out a partial word. (For example, by
* shifting out three bytes with word size of sixteen or twenty bits;
* the former uses two bytes per word, the latter uses four bytes.)
*
* In-memory data values are always in native CPU byte order, translated
* from the wire byte order (big-endian except with SPI_LSB_FIRST). So
* for example when bits_per_word is sixteen, buffers are 2N bytes long
* (@len = 2N) and hold N sixteen bit words in CPU byte order.
*
* When the word size of the SPI transfer is not a power-of-two multiple
* of eight bits, those in-memory words include extra bits. In-memory
* words are always seen by protocol drivers as right-justified, so the
* undefined (rx) or unused (tx) bits are always the most significant bits.
*
* All SPI transfers start with the relevant chipselect active. Normally
* it stays selected until after the last transfer in a message. Drivers
* can affect the chipselect signal using cs_change.
*
* (i) If the transfer isn't the last one in the message, this flag is
* used to make the chipselect briefly go inactive in the middle of the
* message. Toggling chipselect in this way may be needed to terminate
* a chip command, letting a single spi_message perform all of group of
* chip transactions together.
*
* (ii) When the transfer is the last one in the message, the chip may
* stay selected until the next transfer. On multi-device SPI busses
* with nothing blocking messages going to other devices, this is just
* a performance hint; starting a message to another device deselects
* this one. But in other cases, this can be used to ensure correctness.
* Some devices need protocol transactions to be built from a series of
* spi_message submissions, where the content of one message is determined
* by the results of previous messages and where the whole transaction
* ends when the chipselect goes intactive.
*
* The code that submits an spi_message (and its spi_transfers)
* to the lower layers is responsible for managing its memory.
* Zero-initialize every field you don't set up explicitly, to
* insulate against future API updates. After you submit a message
* and its transfers, ignore them until its completion callback.
*/
struct spi_transfer {
const void *tx_buf;
void *rx_buf;
unsigned len;
dma_addr_t tx_dma;
dma_addr_t rx_dma;
unsigned cs_change:1;
u8 bits_per_word;
u16 delay_usecs;
u32 speed_hz;
struct list_head transfer_list;
};
一个spi_transfer是以某种特性如速率、延时及字长连续传输的最小单位。因为SPI是全双工总线,只要总线上有数据传输,则MOSI和MISO上同时有数据采样,对于SPI 控制器来说,其收发缓冲区中都有数据,但是对于用户来说,其可以灵活的选择tx_buf和rx_buf的设置。当发送数据时,tx_buf必须设置为待发送的数据,rx_buf可以为null或者指向无用的缓冲区,即不关心MISO的数据。而当接收数据时,rx_buf必须指向接收缓冲区,而tx_buf可以为Null,则MOSI上为全0,或者tx_buf指向不会引起从设备异常相应的数据。Len为待发送或者接收的数据长度。当一系列spi_transfer构成一个spi_message时,cs_change的设置非常讲究。当cs_change为0即不变时,则可以连续对同一个设备进行数据收发;当cs_change为1时通常用来停止command的传输而随后进行数据接收。因此cs_change可以利用SPI总线构造复杂的通信协议。
对于SPI总线协议来说,传输单位可以是4-32之间的任意bits,但对于SPI控制器来说,bits_per_word只能是8/16/32,即需要取整,待收发的数据在内存里都是以主机字节序右对齐存储,SPI控制器会自动根据传输单位及大小端进行转换。
对于read/write方式来说,如果不采用board info中的默认设置,则必须先通过ioctl方式设置该从设备特定的大小端、bits per word及速率等特性,后续数据传输时将一直采用此设置。
read/write与用户空间的接口是buf和count,分别为收发的相应数据指针和数据长度。
/* Read-only message with current device setup */
static ssize_t spidev_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos)
{
struct spidev_data *spidev;
struct spi_device *spi;
ssize_t status = 0;
/* chipselect only toggles at start or end of operation */ // 在count个数据发送期间,该slave的片选一直有效
if (count > bufsiz)
return -EMSGSIZE;
spidev = filp->private_data;
spi = spidev->spi;
mutex_lock(&spidev->buf_lock); // 对同一个SPI slave的互斥访问
status = spi_read(spi, spidev->buffer, count);
if (status == 0) {
unsigned long missing;
missing = copy_to_user(buf, spidev->buffer, count);
if (count && missing == count)
status = -EFAULT;
else
status = count - missing;
}
mutex_unlock(&spidev->buf_lock);
return status;
}
/**
* spi_read - SPI synchronous read
* @spi: device from which data will be read
* @buf: data buffer
* @len: data buffer size
* Context: can sleep
*
* This reads the buffer and returns zero or a negative error code.
* Callable only from contexts that can sleep.
*/
static inline int spi_read(struct spi_device *spi, u8 *buf, size_t len)
{
struct spi_transfer t = {
.rx_buf = buf,
.len = len,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
return spi_sync(spi, &m);
}
自动构建一个spi_message,其只包含一个spi_transfer。
/* Write-only message with current device setup */
static ssize_t spidev_write(struct file *filp, const char __user *buf,
size_t count, loff_t *f_pos)
{
struct spidev_data *spidev;
struct spi_device *spi;
ssize_t status = 0;
unsigned long missing;
/* chipselect only toggles at start or end of operation */
if (count > bufsiz)
return -EMSGSIZE;
spidev = filp->private_data;
spi = spidev->spi;
mutex_lock(&spidev->buf_lock);
missing = copy_from_user(spidev->buffer, buf, count); // 将待发送的数据从用户空间拷贝至内核空间
if (missing == 0) {
status = spi_write(spi, spidev->buffer, count);
if (status == 0)
status = count;
} else
status = -EFAULT;
mutex_unlock(&spidev->buf_lock);
return status;
}
对于ioctl方式,默认情况下就是进行数据收发。
IO ctrl方式与用户空间的接口为spi_ioc_transfer,其数据结构如下:
/**
* struct spi_ioc_transfer - describes a single SPI transfer
* @tx_buf: Holds pointer to userspace buffer with transmit data, or null.
* If no data is provided, zeroes are shifted out.
* @rx_buf: Holds pointer to userspace buffer for receive data, or null.
* @len: Length of tx and rx buffers, in bytes.
* @speed_hz: Temporary override of the device's bitrate.
* @bits_per_word: Temporary override of the device's wordsize.
* @delay_usecs: If nonzero, how long to delay after the last bit transfer
* before optionally deselecting the device before the next transfer.
* @cs_change: True to deselect device before starting the next transfer.
*
* This structure is mapped directly to the kernel spi_transfer structure;
* the fields have the same meanings, except of course that the pointers
* are in a different address space (and may be of different sizes in some
* cases, such as 32-bit i386 userspace over a 64-bit x86_64 kernel).
* Zero-initialize the structure, including currently unused fields, to
* accomodate potential future updates.
*
* SPI_IOC_MESSAGE gives userspace the equivalent of kernel spi_sync().
* Pass it an array of related transfers, they'll execute together.
* Each transfer may be half duplex (either direction) or full duplex.
*
* struct spi_ioc_transfer mesg[4];
* ...
* status = ioctl(fd, SPI_IOC_MESSAGE(4), mesg);
*
* So for example one transfer might send a nine bit command (right aligned
* in a 16-bit word), the next could read a block of 8-bit data before
* terminating that command by temporarily deselecting the chip; the next
* could send a different nine bit command (re-selecting the chip), and the
* last transfer might write some register values.
*/
struct spi_ioc_transfer {
__u64 tx_buf;
__u64 rx_buf;
__u32 len;
__u32 speed_hz;
__u16 delay_usecs;
__u8 bits_per_word;
__u8 cs_change;
__u32 pad;
};
spi_ioc_transfer可以动态的改变各种传输特性,并且可以将多个spi_ioc_transfer组织成一个message连续传输,比read/write方式提供了更多灵活性。
static int spidev_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
int err = 0;
int retval = 0;
struct spidev_data *spidev;
struct spi_device *spi;
u32 tmp;
unsigned n_ioc;
struct spi_ioc_transfer *ioc;
/* Check type and command number */
if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC)
return -ENOTTY;
/* Check access direction once here; don't repeat below.
* IOC_DIR is from the user perspective, while access_ok is
* from the kernel perspective; so they look reversed.
*/
if (_IOC_DIR(cmd) & _IOC_READ)
err = !access_ok(VERIFY_WRITE,
(void __user *)arg, _IOC_SIZE(cmd));
if (err == 0 && _IOC_DIR(cmd) & _IOC_WRITE)
err = !access_ok(VERIFY_READ,
(void __user *)arg, _IOC_SIZE(cmd));
if (err)
return -EFAULT;
spidev = filp->private_data;
spi = spidev->spi; // 找到对应的struct spi_device
switch (cmd) {
/* read requests */ // 读取该slave的相关属性
case SPI_IOC_RD_MODE:
。
case SPI_IOC_RD_LSB_FIRST:
。
case SPI_IOC_RD_BITS_PER_WORD:
。
case SPI_IOC_RD_MAX_SPEED_HZ:
retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);
break;
/* write requests */
case SPI_IOC_WR_MODE:
retval = __get_user(tmp, (u8 __user *)arg);
if (retval == 0) {
u8 save = spi->mode;
if (tmp & ~SPI_MODE_MASK) {
retval = -EINVAL;
break;
}
tmp |= spi->mode & ~SPI_MODE_MASK;
spi->mode = (u8)tmp; //更新相关属性
retval = spi_setup(spi); //使相关属性生效,在此不设置也可以,因为每次传输时都会重新设置SPI master
if (retval < 0)
spi->mode = save;
else
dev_dbg(&spi->dev, "spi mode %02x/n", tmp);
}
break;
case SPI_IOC_WR_LSB_FIRST:
。。。
case SPI_IOC_WR_BITS_PER_WORD:
。。。
case SPI_IOC_WR_MAX_SPEED_HZ:
。。。
default:
/* segmented and/or full-duplex I/O request */
if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))
|| _IOC_DIR(cmd) != _IOC_WRITE)
return -ENOTTY;
tmp = _IOC_SIZE(cmd);
if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {
retval = -EINVAL;
break;
}
n_ioc = tmp / sizeof(struct spi_ioc_transfer);
if (n_ioc == 0)
break;
/* copy into scratch area */
ioc = kmalloc(tmp, GFP_KERNEL);
if (!ioc) {
retval = -ENOMEM;
break;
}
if (__copy_from_user(ioc, (void __user *)arg, tmp)) {
kfree(ioc);
retval = -EFAULT;
break;
}
/* translate to spi_message, execute */
retval = spidev_message(spidev, ioc, n_ioc);
kfree(ioc);
break;
}
return retval;
}
static int spidev_message(struct spidev_data *spidev,
struct spi_ioc_transfer *u_xfers, unsigned n_xfers)
{
struct spi_message msg;
struct spi_transfer *k_xfers;
struct spi_transfer *k_tmp;
struct spi_ioc_transfer *u_tmp;
struct spi_device *spi = spidev->spi;
unsigned n, total;
u8 *buf;
int status = -EFAULT;
spi_message_init(&msg);
k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);
if (k_xfers == NULL)
return -ENOMEM;
/* Construct spi_message, copying any tx data to bounce buffer.
* We walk the array of user-provided transfers, using each one
* to initialize a kernel version of the same transfer.
*/
mutex_lock(&spidev->buf_lock);
buf = spidev->buffer;
total = 0;
for (n = n_xfers, k_tmp = k_xfers, u_tmp = u_xfers;
n;
n--, k_tmp++, u_tmp++) {
k_tmp->len = u_tmp->len;
total += k_tmp->len;
if (total > bufsiz) {
status = -EMSGSIZE;
goto done;
}
if (u_tmp->rx_buf) {
k_tmp->rx_buf = buf;
if (!access_ok(VERIFY_WRITE, (u8 __user *)
(uintptr_t) u_tmp->rx_buf,
u_tmp->len))
goto done;
}
if (u_tmp->tx_buf) {
k_tmp->tx_buf = buf;
if (copy_from_user(buf, (const u8 __user *)
(uintptr_t) u_tmp->tx_buf,
u_tmp->len))
goto done;
}
buf += k_tmp->len;
// 将用户指定的传输属性保存起来,构成内核 spi_transfer
k_tmp->cs_change = !!u_tmp->cs_change;
k_tmp->bits_per_word = u_tmp->bits_per_word;
k_tmp->delay_usecs = u_tmp->delay_usecs;
k_tmp->speed_hz = u_tmp->speed_hz;
spi_message_add_tail(k_tmp, &msg); // 将多个spi_transfer组织为spi_message
}
status = spi_sync(spi, &msg);
if (status < 0)
goto done;
/* copy any rx data out of bounce buffer */
buf = spidev->buffer;
for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
if (u_tmp->rx_buf) { //当用户设置了rx buf时才将数据拷贝到用户空间
if (__copy_to_user((u8 __user *)
(uintptr_t) u_tmp->rx_buf, buf,
u_tmp->len)) {
status = -EFAULT;
goto done;
}
}
buf += u_tmp->len;
}
status = total;
done:
mutex_unlock(&spidev->buf_lock);
kfree(k_xfers);
return status;
}
6.2 特定的设备驱动
原则上所有的SPI从设备都可以通过上述统一的设备模型spidev来访问,但SPI 总线上传输的是透明的数据,而对于某些SPI从设备,其数据传输需要遵循一定的格式,如果用spidev来访问,则用户需要组织好所有的spi_transfer,对一般用户来说可能比较复杂。为了提供更加user friendly的接口,可以对特定SPI从设备的访问进行再次封装。
如SPI接口的MMC卡,其数据的转换较为复杂,为了减少用户空间的转换,提供了专用的MMC驱动供用户程序访问,其向上屏蔽了具体MMC芯片的差异。
下面以drivers/mmc/host/mmc_spi.c为例来进行讲述。
6.2.1 关键数据结构
struct mmc_spi_host {
struct mmc_host *mmc;
struct spi_device *spi; // MMC卡对应的SPI 设备
unsigned char power_mode;
u16 powerup_msecs;
struct mmc_spi_platform_data *pdata;
/* for bulk data transfers */
struct spi_transfer token, t, crc, early_status; //SD/MMC卡协议对应的各种transfer
struct spi_message m;
/* for status readback */
struct spi_transfer status;
struct spi_message readback;
/* underlying DMA-aware controller, or null */
struct device *dma_dev;
/* buffer used for commands and for message "overhead" */
struct scratch *data;
dma_addr_t data_dma;
/* Specs say to write ones most of the time, even when the card
* has no need to read its input data; and many cards won't care.
* This is our source of those ones.
*/
void *ones;
dma_addr_t ones_dma;
};
mmc_spi_host描述了一个基于SPI总线的MMC卡设备。
static struct spi_driver mmc_spi_driver = {
.driver = {
.name = "mmc_spi",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = mmc_spi_probe,
.remove = __devexit_p(mmc_spi_remove),
};
特定的mmc_spi_driver,但其本质上是spi_driver,和SPI 设备匹配的关键字是mmc_spi。
6.2.2 初始化
static int __init mmc_spi_init(void)
{
return spi_register_driver(&mmc_spi_driver);
}
module_init(mmc_spi_init);
static void __exit mmc_spi_exit(void)
{
spi_unregister_driver(&mmc_spi_driver);
}
调用spi_register_driver向SPI总线上注册mmc_spi_driver,根据mmc_spi进行匹配,匹配成功后将自动调用mmc_spi_probe。
static int mmc_spi_probe(struct spi_device *spi)
{
void *ones;
struct mmc_host *mmc;
struct mmc_spi_host *host;
int status;
/* MMC and SD specs only seem to care that sampling is on the
* rising edge ... meaning SPI modes 0 or 3. So either SPI mode
* should be legit. We'll use mode 0 since it seems to be a
* bit less troublesome on some hardware ... unclear why.
*/
spi->mode = SPI_MODE_0;
spi->bits_per_word = 8;
status = spi_setup(spi);
if (status < 0) {
dev_dbg(&spi->dev, "needs SPI mode %02x, %d KHz; %d/n",
spi->mode, spi->max_speed_hz / 1000,
status);
return status;
}
/* We can use the bus safely iff nobody else will interfere with us.
* Most commands consist of one SPI message to issue a command, then
* several more to collect its response, then possibly more for data
* transfer. Clocking access to other devices during that period will
* corrupt the command execution.
*
*/
if (spi->master->num_chipselect > 1) {
struct count_children cc;
cc.n = 0;
cc.bus = spi->dev.bus;
status = device_for_each_child(spi->dev.parent, &cc,
maybe_count_child);
if (status < 0) {
dev_err(&spi->dev, "can't share SPI bus/n");
return status;
}
dev_warn(&spi->dev, "ASSUMING SPI bus stays unshared!/n");
}
/* We need a supply of ones to transmit. This is the only time
* the CPU touches these, so cache coherency isn't a concern.
*
* NOTE if many systems use more than one MMC-over-SPI connector
* it'd save some memory to share this. That's evidently rare.
*/
status = -ENOMEM;
ones = kmalloc(MMC_SPI_BLOCKSIZE, GFP_KERNEL);
if (!ones)
goto nomem;
memset(ones, 0xff, MMC_SPI_BLOCKSIZE);
mmc = mmc_alloc_host(sizeof(*host), &spi->dev);
if (!mmc)
goto nomem;
mmc->ops = &mmc_spi_ops;
mmc->max_blk_size = MMC_SPI_BLOCKSIZE;
/* As long as we keep track of the number of successfully
* transmitted blocks, we're good for multiwrite.
*/
mmc->caps = MMC_CAP_SPI | MMC_CAP_MULTIWRITE;
/* SPI doesn't need the lowspeed device identification thing for
* MMC or SD cards, since it never comes up in open drain mode.
* That's good; some SPI masters can't handle very low speeds!
*
* However, low speed SDIO cards need not handle over 400 KHz;
* that's the only reason not to use a few MHz for f_min (until
* the upper layer reads the target frequency from the CSD).
*/
mmc->f_min = 400000;
mmc->f_max = spi->max_speed_hz;
host = mmc_priv(mmc);
host->mmc = mmc;
host->spi = spi;
host->ones = ones;
/* Platform data is used to hook up things like card sensing
* and power switching gpios.
*/
host->pdata = spi->dev.platform_data;
if (host->pdata)
mmc->ocr_avail = host->pdata->ocr_mask;
if (!mmc->ocr_avail) {
dev_warn(&spi->dev, "ASSUMING 3.2-3.4 V slot power/n");
mmc->ocr_avail = MMC_VDD_32_33|MMC_VDD_33_34;
}
if (host->pdata && host->pdata->setpower) {
host->powerup_msecs = host->pdata->powerup_msecs;
if (!host->powerup_msecs || host->powerup_msecs > 250)
host->powerup_msecs = 250;
}
dev_set_drvdata(&spi->dev, mmc);
/* preallocate dma buffers */
host->data = kmalloc(sizeof(*host->data), GFP_KERNEL);
if (!host->data)
goto fail_nobuf1;
if (spi->master->dev.parent->dma_mask) {
struct device *dev = spi->master->dev.parent;
host->dma_dev = dev;
host->ones_dma = dma_map_single(dev, ones,
MMC_SPI_BLOCKSIZE, DMA_TO_DEVICE);
host->data_dma = dma_map_single(dev, host->data,
sizeof(*host->data), DMA_BIDIRECTIONAL);
/* REVISIT in theory those map operations can fail... */
dma_sync_single_for_cpu(host->dma_dev,
host->data_dma, sizeof(*host->data),
DMA_BIDIRECTIONAL);
}
/* setup message for status/busy readback */
spi_message_init(&host->readback);
host->readback.is_dma_mapped = (host->dma_dev != NULL);
spi_message_add_tail(&host->status, &host->readback);
host->status.tx_buf = host->ones;
host->status.tx_dma = host->ones_dma;
host->status.rx_buf = &host->data->status;
host->status.rx_dma = host->data_dma + offsetof(struct scratch, status);
host->status.cs_change = 1;
/* register card detect irq */
if (host->pdata && host->pdata->init) {
status = host->pdata->init(&spi->dev, mmc_spi_detect_irq, mmc);
if (status != 0)
goto fail_glue_init;
}
status = mmc_add_host(mmc);
if (status != 0)
goto fail_add_host;
dev_info(&spi->dev, "SD/MMC host %s%s%s%s/n",
mmc->class_dev.bus_id,
host->dma_dev ? "" : ", no DMA",
(host->pdata && host->pdata->get_ro)
? "" : ", no WP",
(host->pdata && host->pdata->setpower)
? "" : ", no poweroff");
return 0;
fail_add_host:
mmc_remove_host (mmc);
fail_glue_init:
if (host->dma_dev)
dma_unmap_single(host->dma_dev, host->data_dma,
sizeof(*host->data), DMA_BIDIRECTIONAL);
kfree(host->data);
fail_nobuf1:
mmc_free_host(mmc);
dev_set_drvdata(&spi->dev, NULL);
nomem:
kfree(ones);
return status;
}
其主要功能是注册一个struct mmc_host,最终的数据访问是由其他子系统发起的。
6.2.3 数据收发
TBD
7 驱动访问示例
下面以一款TI 的SPI接口的时钟芯片62002为例来讲述用户空间如何访问SPI设备。
62002支持32bits、LSB访问模式。内部寄存器为28bits,其他4bits为地址位。
支持的读写命令如下:
Xxxx为待写的数据,read command中AAAA为待访问的寄存器地址。
7.1.1 写操作
62002写操作通常比较简单,时序如下,
struct spi_ioc_transfer write = {
.tx_buf = (int)dout,
.rx_buf = NULL, //写操作时,忽略MISO
.len = sizeof(long),
.delay_usecs = 0,
.speed_hz = 500000,
.bits_per_word = 32,
.cs_change = 1,
};
Dout = data << 4 + address; // 待发送的数据Dout由28bits的data field和4位地址域构成。
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &write);
7.1.2 读操作
62002的读操作较复杂,需要先发送写命令指定待读的内部寄存器地址,然后再发起总线的读操作。时序如下:
SPI Master发送读命令后,抬起SPI片选,62002解码读命令中的寄存器地址。当SPI Master再次通过片选选中62002时,62002在MISO上发出待读的数据。
因此需要在总线上连续进行两次数据传输,即两个spi_ioc_transfer 。
struct spi_ioc_transfer read[2] = {
{
.tx_buf = (int)dout,
.rx_buf = NULL, //发送读命令时,忽略MISO
.len = sizeof(long),
.delay_usecs = 0,
.speed_hz = 500000,
.bits_per_word = 32,
.cs_change = 1,
},
{
.tx_buf = NULL, //读取数据时,忽略MOSI,总线上默然发送的是0
.rx_buf = (int)din,
.len = sizeof(long),
.delay_usecs = 0,
.speed_hz = 500000,
.bits_per_word = 32,
.cs_change = 1,
}
}
第一个spi_ioc_transfer发送读命令,第二个spi_ioc_transfer读取数据。
ret = ioctl(fd, SPI_IOC_MESSAGE(2), read);
两个spi_ioc_transfer将构成一个spi_message,其在内核中是一个原子序列,将连续占用总线直至两个spi_ioc_transfer发送完毕。
第一个spi_ioc_transfer的cs_change一定要置为1,即spi_transfer发送完毕后片选要发生变化,由低到高,这样才满足62002的时序。
8 参考鸣谢
http://blog.csdn.net/sailor_8318/archive/2010/09/25/5905988.aspx