以下先从下到上的进行分析:
driver/spi下有两个底层相关的spi驱动程序:
spi_s3c24xx.c和spi_s3c24xx_gpio.c
其中spi_s3c24xx.c是基于s3c24xx下相应的spi接口的驱动程序,spi_s3c24xx_gpio.c允许用户指定3个gpio口,分别充当spi_clk、spi_mosi和spi_miso接口,模拟标准的spi总线。
s3c2410自带了两个spi接口(spi0和spi1),在此我只研究基于s3c2410下spi接口的驱动程序spi_s3c24xx.c。
首先从spi驱动的检测函数进行分析:
static int s3c24xx_spi_probe (struct platform_device *pdev)
{
struct s3c24xx_spi *hw;
struct spi_master *master;
struct spi_board_info *bi;
struct resource *res;
int err = 0;
int i;
/* pi_alloc_master函数申请了struct spi_master+struct s3c24xx_spi大小的数据,
* spi_master_get_devdata和spi_master_get分别取出struct s3c24xx_spi和struct spi_master结构指针
*/
master = spi_alloc_master(&pdev->dev, sizeof(struct s3c24xx_spi));
if (master == NULL) {
dev_err(&pdev->dev, "No memory for spi_master\n");
err = -ENOMEM;
goto err_nomem;
}
/* 填充struct spi_master结构 */
hw = spi_master_get_devdata(master);
memset(hw, 0, sizeof(struct s3c24xx_spi));
hw->master = spi_master_get(master);
hw->pdata = pdev->dev.platform_data;
hw->dev = &pdev->dev;
if (hw->pdata == NULL) {
dev_err(&pdev->dev, "No platform data supplied\n");
err = -ENOENT;
goto err_no_pdata;
}
platform_set_drvdata(pdev, hw);//dev_set_drvdata(&pdev->dev, hw)
init_completion(&hw->done);
/* setup the state for the bitbang driver */
/* 填充hw->bitbang结构(hw->bitbang结构充当一个中间层,相当与input system的input_handle struct) */
hw->bitbang.master = hw->master;
hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;
hw->bitbang.chipselect = s3c24xx_spi_chipsel;
hw->bitbang.txrx_bufs = s3c24xx_spi_txrx;
hw->bitbang.master->setup = s3c24xx_spi_setup;
dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);
/* find and map our resources */
/* 申请spi所用到的资源:io、irq、时钟等 */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(&pdev->dev, "Cannot get IORESOURCE_MEM\n");
err = -ENOENT;
goto err_no_iores;
}
hw->ioarea = request_mem_region(res->start, (res->end - res->start)+1,
pdev->name);
if (hw->ioarea == NULL) {
dev_err(&pdev->dev, "Cannot reserve region\n");
err = -ENXIO;
goto err_no_iores;
}
hw->regs = ioremap(res->start, (res->end - res->start)+1);
if (hw->regs == NULL) {
dev_err(&pdev->dev, "Cannot map IO\n");
err = -ENXIO;
goto err_no_iomap;
}
hw->irq = platform_get_irq(pdev, 0);
if (hw->irq < 0) {
dev_err(&pdev->dev, "No IRQ specified\n");
err = -ENOENT;
goto err_no_irq;
}
err = request_irq(hw->irq, s3c24xx_spi_irq, 0, pdev->name, hw);
if (err) {
dev_err(&pdev->dev, "Cannot claim IRQ\n");
goto err_no_irq;
}
hw->clk = clk_get(&pdev->dev, "spi");
if (IS_ERR(hw->clk)) {
dev_err(&pdev->dev, "No clock for device\n");
err = PTR_ERR(hw->clk);
goto err_no_clk;
}
/* for the moment, permanently enable the clock */
clk_enable(hw->clk);
/* program defaults into the registers */
/* 初始化spi相关的寄存器 */
writeb(0xff, hw->regs + S3C2410_SPPRE);
writeb(SPPIN_DEFAULT, hw->regs + S3C2410_SPPIN);
writeb(SPCON_DEFAULT, hw->regs + S3C2410_SPCON);
/* add by lfc */
s3c2410_gpio_setpin(S3C2410_GPE13, 0);
s3c2410_gpio_setpin(S3C2410_GPE12, 0);
s3c2410_gpio_cfgpin(S3C2410_GPE13, S3C2410_GPE13_SPICLK0);
s3c2410_gpio_cfgpin(S3C2410_GPE12, S3C2410_GPE12_SPIMOSI0);
s3c2410_gpio_cfgpin(S3C2410_GPE11, S3C2410_GPE11_SPIMISO0);
/* end add */
/* setup any gpio we can */
/* 片选 */
if (!hw->pdata->set_cs) {
s3c2410_gpio_setpin(hw->pdata->pin_cs, 1);
s3c2410_gpio_cfgpin(hw->pdata->pin_cs, S3C2410_GPIO_OUTPUT);
}
/* register our spi controller */
/* 最终通过调用spi_register_master来注册spi控制器(驱动) */
err = spi_bitbang_start(&hw->bitbang);
if (err) {
dev_err(&pdev->dev, "Failed to register SPI master\n");
goto err_register;
}
dev_dbg(hw->dev, "shutdown=%d\n", hw->bitbang.shutdown);
/* register all the devices associated */
/* 注册所用使用本spi驱动的设备 */
bi = &hw->pdata->board_info[0];
for (i = 0; i < hw->pdata->board_size; i++, bi++) {
dev_info(hw->dev, "registering %s\n", bi->modalias);
bi->controller_data = hw;
spi_new_device(master, bi);
}
return 0;
err_register:
clk_disable(hw->clk);
clk_put(hw->clk);
err_no_clk:
free_irq(hw->irq, hw);
err_no_irq:
iounmap(hw->regs);
err_no_iomap:
release_resource(hw->ioarea);
kfree(hw->ioarea);
err_no_iores:
err_no_pdata:
spi_master_put(hw->master);;
err_nomem:
return err;
}
/*
* spi_alloc_master - allocate SPI master controller
* @dev: the controller, possibly using the platform_bus
* @size: how much driver-private data to preallocate; the pointer to this
* memory is in the class_data field of the returned class_device,
* accessible with spi_master_get_devdata().
*
* This call is used only by SPI master controller drivers, which are the
* only ones directly touching chip registers. It's how they allocate
* an spi_master structure, prior to calling spi_register_master().
*
* This must be called from context that can sleep. It returns the SPI
* master structure on success, else NULL.
*
* The caller is responsible for assigning the bus number and initializing
* the master's methods before calling spi_register_master(); and (after errors
* adding the device) calling spi_master_put() to prevent a memory leak.
*/
/*注释已经写得很清楚了,本函数旨在分配spi_master struct
*其中,device为主控制设备,size为需要预分配的设备私有数据大小
*该函数被spi主控制器驱动所调用,用于在调用spi_register_master注册主控制器前
*分配spi_master struct,分配bus number和初始化主控制器的操作方法
*注意在分配spi_master struct的时候多分配了大小为size的设备私有数据
*并通过spi_master_set_devdata函数把其放到class_data field里,以后可以通过spi_master_get_devdata来访问
*/
struct spi_master * __init_or_module
spi_alloc_master (struct device *dev, unsigned size)
{
struct spi_master *master;
if (!dev)
return NULL;
master = kzalloc(size + sizeof *master, SLAB_KERNEL);
if (!master)
return NULL;
class_device_initialize(&master->cdev);
master->cdev.class = &spi_master_class;
master->cdev.dev = get_device(dev);
spi_master_set_devdata(master, &master[1]);
return master;
}
/*
* spi_bitbang_start - start up a polled/bitbanging SPI master driver
* @bitbang: driver handle
*
* Caller should have zero-initialized all parts of the structure, and then
* provided callbacks for chip selection and I/O loops. If the master has
* a transfer method, its final step should call spi_bitbang_transfer; or,
* that's the default if the transfer routine is not initialized. It should
* also set up the bus number and number of chipselects.
*
* For i/o loops, provide callbacks either per-word (for bitbanging, or for
* hardware that basically exposes a shift register) or per-spi_transfer
* (which takes better advantage of hardware like fifos or DMA engines).
*
* Drivers using per-word I/O loops should use (or call) spi_bitbang_setup and
* spi_bitbang_cleanup to handle those spi master methods. Those methods are
* the defaults if the bitbang->txrx_bufs routine isn't initialized.
*
* This routine registers the spi_master, which will process requests in a
* dedicated task, keeping IRQs unblocked most of the time. To stop
* processing those requests, call spi_bitbang_stop().
*/
int spi_bitbang_start (struct spi_bitbang *bitbang)
{
int status;
if (!bitbang->master || !bitbang->chipselect)
return -EINVAL;
/*bitbang_work
* 初始化a work,后面再create_singlethread_workqueue,
* 等到有数据要传输的时候,在spi_bitbang_transfer函数中通过调用queue_work(bitbang->workqueue, &bitbang->work)
* 把work扔进workqueue中调度运行
* 这是内核的一贯做法,在mmc/sd驱动中也是这样处理的^_^
*/
INIT_WORK(&bitbang->work, bitbang_work, bitbang);
/* 初始化自旋锁和链表头,以后用到 */
spin_lock_init(&bitbang->lock);
spi_new_device INIT_LIST_HEAD(&bitbang->queue);
if (!bitbang->master->transfer)
bitbang->master->transfer = spi_bitbang_transfer; //spi数据的传输就是通过调用这个方法来实现的
/* spi_s3c24xx.c驱动中有相应的txrx_bufs处理方法,在bitbang_work中被调用 */
if (!bitbang->txrx_bufs) {
bitbang->use_dma = 0;
bitbang->txrx_bufs = spi_bitbang_bufs;
if (!bitbang->master->setup) {
if (!bitbang->setup_transfer)
bitbang->setup_transfer =
spi_bitbang_setup_transfer;
bitbang->master->setup = spi_bitbang_setup;
bitbang->master->cleanup = spi_bitbang_cleanup;
}
/* spi_s3c24xx.c驱动中有相应的setup处理方法,在稍后的spi_new_device中被调用 */
} else if (!bitbang->master->setup)
return -EINVAL;
/* this task is the only thing to touch the SPI bits */
bitbang->busy = 0;
/* 创建工作者进程 */
bitbang->workqueue = create_singlethread_workqueue(
bitbang->master->cdev.dev->bus_id);
if (bitbang->workqueue == NULL) {
status = -EBUSY;
goto err1;
}
/* driver may get busy before register() returns, especially
* if someone registered boardinfo for devices
*/
status = spi_register_master(bitbang->master);
if (status < 0)
goto err2;
return status;
err2:
destroy_workqueue(bitbang->workqueue);
err1:
return status;
}
/**
* spi_register_master - register SPI master controller
* @master: initialized master, originally from spi_alloc_master()
*
* 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 __init_or_module
spi_register_master (struct spi_master *master)
{
static atomic_t dyn_bus_id = ATOMIC_INIT((1<<16) - 1);
struct device *dev = master->cdev.dev;
int status = -ENODEV;
int dynamic = 0;
if (!dev)
return -ENODEV;
/* convention: dynamically assigned bus IDs count down from the max */
if (master->bus_num < 0) {
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->cdev.class_id, sizeof master->cdev.class_id,
"spi%u", master->bus_num);
status = class_device_add(&master->cdev); //注册设备
if (status < 0)
goto done;
dev_dbg(dev, "registered master %s%s\n", master->cdev.class_id,
dynamic ? " (dynamic)" : "");
/* 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
*/
/*
* scan board_list for spi_board_info which is registered by spi_register_board_info
* 很可惜,s3c24xx的spi驱动中不支持spi_register_board_info这种标准方式注册方式,而是直接调用spi_new_device内部函数
*/
后记:
如果像atmel那样,初始化的时候调用 spi_register_board_info函数注册spi设备信息,那么
调用 spi_register_master注册spi控制器的时候,就可以通过调用 scan_boardinfo函数,完成spi设备的注册了^_^。
static void __init_or_module
scan_boardinfo (struct spi_master *master)
{
struct boardinfo *bi;
struct device *dev = master->cdev.dev;
down(&board_lock);
list_for_each_entry(bi, &board_list, list) {
struct spi_board_info *chip = bi->board_info;
unsigned n;
for (n = bi->n_board_info; n > 0; n--, chip++) {
if (chip->bus_num != master->bus_num)
continue;
/* some controllers only have one chip, so they
* might not use chipselects. otherwise, the
* chipselects are numbered 0..max.
*/
if (chip->chip_select >= master->num_chipselect
&& master->num_chipselect) {
dev_dbg(dev, "cs%d > max %d\n",
chip->chip_select,
master->num_chipselect);
continue;
}
(void) spi_new_device(master, chip);
}
}
up(&board_lock);
}
/*
* Board-specific early init code calls this (probably during arch_initcall)
* with segments of the SPI device table. Any device nodes are created later,
* after the relevant parent SPI controller (bus_num) is defined. We keep
* this table of devices forever, so that reloading a controller driver will
* not make Linux forget about these hard-wired devices.
*
* Other code can also call this, e.g. a particular add-on board might provide
* SPI devices through its expansion connector, so code initializing that board
* would naturally declare its SPI devices.
*
* The board info passed can safely be __initdata ... but be careful of
* any embedded pointers (platform_data, etc), they're copied as-is.
*/
int __init
spi_register_board_info (struct spi_board_info const *info, unsigned n)
{
struct boardinfo *bi;
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);
down(&board_lock);
list_add_tail(&bi->list, &board_list);
up(&board_lock);
return 0;
}
/* 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).
*/
struct spi_device *__init_or_module
spi_new_device (struct spi_master *master, struct spi_board_info *chip)
{
struct spi_device *proxy; //这个结构很重要,以后就是通过这个结构来操作实际的spi设备的
struct device *dev = master->cdev.dev;
int status;
/* NOTE: caller did any chip->bus_num checks necessary */
if (!spi_master_get(master))
return NULL;
proxy = kzalloc(sizeof *proxy, GFP_KERNEL);
if (!proxy) {
dev_err(dev, "can't alloc dev for cs%d\n",
chip->chip_select);
goto fail;
}
/* 初始化spi_device 结构各成员 */
proxy->master = master;
proxy->chip_select = chip->chip_select;
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->cdev.class_id,
chip->chip_select);
proxy->dev.parent = dev;
proxy->dev.bus = &spi_bus_type;
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 default i/o setup */
/* 调用master->setup(即s3c24xx_spi_setup)函数初始化spi设备 */
status = master->setup(proxy);
if (status < 0) {
dev_dbg(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); //真正注册原始设备
if (status < 0) {
dev_dbg(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;
}
好了,至此spi主控制器(驱动)和板上spi设备注册完毕,以后要使用spi来传输数据的话,只要先获得spi设备结构,然后就可以利用它来和spi驱动打交道了(就好像你要操作一个文件,先要获取文件句柄一样,明白吧^_^)
static int s3c24xx_spi_setup (struct spi_device *spi)
{
int ret;
/* 进行一些检查性操作 */
if (!spi->bits_per_word)
spi->bits_per_word = 8;
if ((spi->mode & SPI_LSB_FIRST) != 0)
return -EINVAL;
ret = s3c24xx_spi_setupxfer(spi, NULL);
if (ret < 0) {
dev_err(&spi->dev, "setupxfer returned %d\n", ret);
return ret;
}
dev_dbg(&spi->dev, "%s: mode %d, %u bpw, %d hz\n",
__FUNCTION__, spi->mode, spi->bits_per_word,
spi->max_speed_hz);
return 0;
}
static int s3c24xx_spi_setupxfer (struct spi_device *spi,
struct spi_transfer *t)
{
struct s3c24xx_spi *hw = to_hw(spi);
unsigned int bpw;
unsigned int hz;
unsigned int div;
bpw = t ? t->bits_per_word : spi->bits_per_word;
hz = t ? t->speed_hz : spi->max_speed_hz;
if (bpw != 8) {
dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);
return -EINVAL;
}
div = clk_get_rate(hw->clk) / hz;
/* is clk = pclk / (2 * (pre+1)), or is it
* clk = (pclk * 2) / ( pre + 1) */
div = (div / 2) - 1; //求出预分频值
if (div < 0)
div = 1;
if (div > 255)
div = 255;
dev_dbg(&spi->dev, "setting pre-scaler to %d (hz %d)\n", div, hz);
writeb(div, hw->regs + S3C2410_SPPRE); //设置预分频值
spin_lock(&hw->bitbang.lock);
if (!hw->bitbang.busy) {
hw->bitbang.chipselect(spi, BITBANG_CS_INACTIVE); //修改时钟,先禁用spi
/* need to ndelay for 0.5 clocktick ? */
}
spin_unlock(&hw->bitbang.lock);
return 0;
}
static void s3c24xx_spi_chipsel (struct spi_device *spi, int value)
{
struct s3c24xx_spi *hw = to_hw(spi);
unsigned int cspol = spi->mode & SPI_CS_HIGH ? 1 : 0;
unsigned int spcon;
switch (value) {
case BITBANG_CS_INACTIVE:
/* 禁用spi(禁用片选) */
if (hw->pdata->set_cs)
hw->pdata->set_cs(hw->pdata, value, cspol);
else
s3c2410_gpio_setpin(hw->pdata->pin_cs, cspol ^ 1);
break;
case BITBANG_CS_ACTIVE:
/*
* 启用spi:根据需要设置寄存器并启用使能片选
* (如果spi_board_info中没有设置相应的mode选项的话,那就只能使用默认值SPPIN_DEFAULT和SPCON_DEFAULT了)
*/
spcon = readb(hw->regs + S3C2410_SPCON);
if (spi->mode & SPI_CPHA)
spcon |= S3C2410_SPCON_CPHA_FMTB;
else
spcon &= ~S3C2410_SPCON_CPHA_FMTB;
if (spi->mode & SPI_CPOL)
spcon |= S3C2410_SPCON_CPOL_HIGH;
else
spcon &= ~S3C2410_SPCON_CPOL_HIGH;
spcon |= S3C2410_SPCON_ENSCK;
/* write new configration */
writeb(spcon, hw->regs + S3C2410_SPCON);
if (hw->pdata->set_cs)
hw->pdata->set_cs(hw->pdata, value, cspol);
else
s3c2410_gpio_setpin(hw->pdata->pin_cs, cspol);
break;
}
}
====================================================================
上文从下到上的介绍了spi子系统,现在反过来从上到下的来介绍spi子系统的使用:
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);
}
后记:
static int spi_drv_probe(struct device *dev)
{
const struct spi_driver *sdrv = to_spi_driver(dev->driver);
return sdr->probe(to_spi_device(dev));
}
然后你就可以在该spi设备驱动的probe函数里面进行必要的初始化工作了。
2.6内核的典型做法,不直接使用原始设备驱动,而是使用包装后的抽象设备驱动spi_driver,
间接与原始设备驱动建立联系,并最终通过调用driver_register来注册原始设备驱动(要充分理解2.6内核的抽象化思想)。
注:
以后我们也不会直接与原始设备打交道了,而是通过spi_device来间接操作spi设备了^_^
/**
* spi_write_then_read - SPI synchronous write followed by read
* @spi: device with which data will be exchanged
* @txbuf: data to be written (need not be dma-safe)
* @n_tx: size of txbuf, in bytes
* @rxbuf: buffer into which data will be read
* @n_rx: size of rxbuf, in bytes (need not be dma-safe)
*
* This performs a half duplex MicroWire style transaction with the
* device, sending txbuf and then reading rxbuf. The return value
* is zero for success, else a negative errno status code.
* This call may only be used from a context that may sleep.
*
* Parameters to this routine are always copied using a small buffer;
* performance-sensitive or bulk transfer code should instead use
* spi_{async,sync}() calls with dma-safe buffers.
*/
/*
* spi_write_then_read比较简单,容易说明spi的使用,用它来作例子比较合适
*/
int spi_write_then_read(struct spi_device *spi,
const u8 *txbuf, unsigned n_tx,
u8 *rxbuf, unsigned n_rx)
{
static DECLARE_MUTEX(lock);
int status;
struct spi_message message;
struct spi_transfer x[2];
u8 *local_buf;
/* Use preallocated DMA-safe buffer. We can't avoid copying here,
* (as a pure convenience thing), but we can keep heap costs
* out of the hot path ...
*/
if ((n_tx + n_rx) > SPI_BUFSIZ)//SPI_BUFSIZ == 32
return -EINVAL;
/* 这里初始化message结构里面用于存放struct spi_transfer指针的链表头 */
spi_message_init(&message);//INIT_LIST_HEAD(&message->transfers);
memset(x, 0, sizeof x);
/* 留意到没有:tx和rx个占一个工作添加到message的struct spi_transfer链表里,稍后被bitbang_work从链表里提出来处理(后面会讲到) */
if (n_tx) {
x[0].len = n_tx;
spi_message_add_tail(&x[0], &message);//list_add_tail(&t->transfer_list, &m->transfers);
}
if (n_rx) {
x[1].len = n_rx;
spi_message_add_tail(&x[1], &message);
}
/* ... unless someone else is using the pre-allocated buffer */
/* 如果有人在用这个预分配的缓存,那没办法了,只能再分配一个临时的,用完再释放掉 */
if (down_trylock(&lock)) {
local_buf = kmalloc(SPI_BUFSIZ, GFP_KERNEL);
if (!local_buf)
return -ENOMEM;
} else
local_buf = buf;//否则就采用预分配的缓存吧
/* local_buf的前部分用来存放要发送的数据,后部分用来存放接收到的数据 */
memcpy(local_buf, txbuf, n_tx);
x[0].tx_buf = local_buf;
x[1].rx_buf = local_buf + n_tx;
/* do the i/o */
status = spi_sync(spi, &message);//同步io,等待spi传输完成,然后返回用户所接收的数据和状态
if (status == 0) {
memcpy(rxbuf, x[1].rx_buf, n_rx);
status = message.status;
}
if (x[0].tx_buf == buf)//如果使用的是预分配的缓存,释放锁好让其它人使用
up(&lock);
else
kfree(local_buf);//如果使用的是临时申请的缓存,释放之
return status;
}
/*
* spi_sync - blocking/synchronous SPI data transfers
* @spi: device with which data will be exchanged
* @message: describes the data transfers
*
* 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.
*
* The return value is a negative error code if the message could not be
* submitted, else zero. When the value is zero, then message->status is
* also defined: it's the completion code for the transfer, either zero
* or a negative error code from the controller driver.
*/
int spi_sync(struct spi_device *spi, struct spi_message *message)
{
DECLARE_COMPLETION_ONSTACK(done);//声明一个完成变量
int status;
message->complete = spi_complete;//spi传输完成后的回调函数
message->context = &done;
status = spi_async(spi, message);
if (status == 0)
wait_for_completion(&done);//等待spi传输,调用spi_complete后返回
message->context = NULL;
return status;
}
/*
* spi_async -- asynchronous SPI transfer
* @spi: device with which data will be exchanged
* @message: describes the data transfers, including completion callback
*
* 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)
{
printk("spi_async\n");
message->spi = spi;
return spi->master->transfer(spi, message);//调用spi_bitbang_transfer传输数据
}
/*
* spi_bitbang_transfer - default submit to transfer queue
*/
int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m)
{
struct spi_bitbang *bitbang;
unsigned long flags;
int status = 0;
m->actual_length = 0;
m->status = -EINPROGRESS;
bitbang = spi_master_get_devdata(spi->master);
/*
* 还记得spi_alloc_master函数中调用spi_master_set_devdata把struct s3c24xx_spi结构存放起来吧?
* 而struct spi_bitbang结构正是struct s3c24xx_spi结构所包含的第一个结构
*/
if (bitbang->shutdown)
return -ESHUTDOWN;
spin_lock_irqsave(&bitbang->lock, flags);
if (!spi->max_speed_hz)
status = -ENETDOWN;
else {
list_add_tail(&m->queue, &bitbang->queue);//把message加入到bitang的等待队列中
queue_work(bitbang->workqueue, &bitbang->work);//把bitbang-work加入bitbang->workqueue中,调度运行
}
spin_unlock_irqrestore(&bitbang->lock, flags);
return status;
}
好了,稍微总结一下:
spi的读写请求通过:spi_transfer->spi_message->spi_bitbang添加都bitbang->queue中,被bitbang->work反方向提取出来执行(后面会提到)。
通过queue_work(bitbang->workqueue, &bitbang->work)把bitbang-work加入bitbang->workqueue后,在某个合适的时间,bitbang->work将被调度运行,bitbang_work函数将被调用:
/*
* SECOND PART ... simple transfer queue runner.
*
* This costs a task context per controller, running the queue by
* performing each transfer in sequence. Smarter hardware can queue
* several DMA transfers at once, and process several controller queues
* in parallel; this driver doesn't match such hardware very well.
*
* Drivers can provide word-at-a-time i/o primitives, or provide
* transfer-at-a-time ones to leverage dma or fifo hardware.
*/
static void bitbang_work(void *_bitbang)
{
struct spi_bitbang *bitbang = _bitbang;
unsigned long flags;
spin_lock_irqsave(&bitbang->lock, flags);
bitbang->busy = 1;//置忙标志
while (!list_empty(&bitbang->queue)) { //遍历bitbang->queue链表
struct spi_message *m;
struct spi_device *spi;
unsigned nsecs;
struct spi_transfer *t = NULL;
unsigned tmp;
unsigned cs_change;
int status;
int (*setup_transfer)(struct spi_device *,
struct spi_transfer *);
m = container_of(bitbang->queue.next, struct spi_message, queue);//获取spi_message结构
list_del_init(&m->queue);//把spi_messae从queue里删除
spin_unlock_irqrestore(&bitbang->lock, flags);
/* FIXME this is made-up ... the correct value is known to
* word-at-a-time bitbang code, and presumably chipselect()
* should enforce these requirements too?
*/
nsecs = 100;
spi = m->spi;
tmp = 0;
cs_change = 1;
status = 0;
setup_transfer = NULL;
list_for_each_entry (t, &m->transfers, transfer_list) {//从spi_message结构的transfers链表中获取spi_transfer结构
if (bitbang->shutdown) {
status = -ESHUTDOWN;
break;
}
/* override or restore speed and wordsize */
/* 本messae传输中,需要重设条件,调用setup_transfer函数 */
if (t->speed_hz || t->bits_per_word) {
setup_transfer = bitbang->setup_transfer;
if (!setup_transfer) {
status = -ENOPROTOOPT;
break;
}
}
if (setup_transfer) {
status = setup_transfer(spi, t);
if (status < 0)
break;
}
/* set up default clock polarity, and activate chip;
* this implicitly updates clock and spi modes as
* previously recorded for this device via setup().
* (and also deselects any other chip that might be
* selected ...)
*/
if (cs_change) { //片选激活spi
bitbang->chipselect(spi, BITBANG_CS_ACTIVE);
ndelay(nsecs);
}
cs_change = t->cs_change;
if (!t->tx_buf && !t->rx_buf && t->len) {
status = -EINVAL;
break;
}
/* transfer data. the lower level code handles any
* new dma mappings it needs. our caller always gave
* us dma-safe buffers.
*/
if (t->len) {
/* REVISIT dma API still needs a designated
* DMA_ADDR_INVALID; ~0 might be better.
*/
if (!m->is_dma_mapped)
t->rx_dma = t->tx_dma = 0;
status = bitbang->txrx_bufs(spi, t);//调用s3c24xx_spi_txrx开始传输数据
}
if (status != t->len) {
if (status > 0)
status = -EMSGSIZE;
break;
}
m->actual_length += status;
status = 0;
/* protocol tweaks before next transfer */
if (t->delay_usecs)
udelay(t->delay_usecs);
if (!cs_change)
continue;//不用重新片选,继续下一个message的传输
if (t->transfer_list.next == &m->transfers)//链表遍历完毕,退出循环
break;
/* sometimes a short mid-message deselect of the chip
* may be needed to terminate a mode or command
*/
ndelay(nsecs);
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);//需要重新片选的话...
ndelay(nsecs);
}
m->status = status;//所用spi_message传输完毕
m->complete(m->context);//应答返回变量,通知等待spi传输完毕的进程(具体来说就是spi_sync函数了)
/* restore speed and wordsize */
/* 前面重设过条件的,在这恢复之 */
if (setup_transfer)
setup_transfer(spi, NULL);
/* normally deactivate chipselect ... unless no error and
* cs_change has hinted that the next message will probably
* be for this chip too.
*/
if (!(status == 0 && cs_change)) {
ndelay(nsecs);
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
ndelay(nsecs);
}
spin_lock_irqsave(&bitbang->lock, flags);//重新获取自旋锁,遍历工作者队列的下一个工作
}
bitbang->busy = 0;//处理完毕,清除忙标志
spin_unlock_irqrestore(&bitbang->lock, flags);
}
static int s3c24xx_spi_txrx(struct spi_device *spi, struct spi_transfer *t)
{
struct s3c24xx_spi *hw = to_hw(spi);
dev_dbg(&spi->dev, "txrx: tx %p, rx %p, len %d\n",
t->tx_buf, t->rx_buf, t->len);
hw->tx = t->tx_buf;//发送指针
hw->rx = t->rx_buf;//接收指针
hw->len = t->len;//需要发送/接收的数据数目
hw->count = 0;//存放实际spi传输的数据数目
/* send the first byte */
writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT);
wait_for_completion(&hw->done);
/*
* 非常有意思,这里虽然只发送第一字节,可是中断里会帮你发送完其它的字节(并接收数据),
* 直到所有的数据发送完毕且所要接收的数据接收完毕(首要)才返回
*/
return hw->count;
}
static irqreturn_t s3c24xx_spi_irq(int irq, void *dev, struct pt_regs *regs)
{
struct s3c24xx_spi *hw = dev;
unsigned int spsta = readb(hw->regs + S3C2410_SPSTA);
unsigned int count = hw->count;
if (hw->len){
if (spsta & S3C2410_SPSTA_DCOL) {
dev_dbg(hw->dev, "data-collision\n");//检测冲突
complete(&hw->done);
goto irq_done;
}
if (!(spsta & S3C2410_SPSTA_READY)) {
dev_dbg(hw->dev, "spi not ready for tx?\n");//设备忙
complete(&hw->done);
goto irq_done;
}
hw->count++;
if (hw->rx)
hw->rx[count] = readb(hw->regs + S3C2410_SPRDAT);//接收数据
count++;
if (count < hw->len)
writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);//发送其它数据(或空数据0xFF)
else
complete(&hw->done);//发送接收完毕,通知s3c24xx_spi_txrx函数
}
irq_done:
return IRQ_HANDLED;
}
static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
{
return hw->tx ? hw->tx[count] : 0xff;
//如果还有数据没接收完且要发送的数据经已发送完毕,发送空数据0xFF
}
注:
这里要注意的是:在spi提供的write_then_read函数中,写和读数据是分开两个阶段来进行的(写数据的时候不读数据;读数据的时候发送空数据0xff)。
总结:
简单的spi子系统大致就是这样,相对比较简单易懂,具体的应用可以参考一下代spi接口的触摸屏控制芯片驱动:
driver/input/touchscreen/ads7846.c
不过看明白它需要多花些时间了,因为毕竟这个驱动不仅和spi子系统打交道而且还和input子系统打交道,可不是那么容易应付的哦^_^
后记:
1、关于spi的使用,可以参考一下这个帖子:、
http://www.linuxforum.net/forum/gshowflat.php?Cat=&Board=embedded&Number=646262&page=1&view=collapsed&sb=5&o=all&fpart=
具体是另外编写一个设备驱动,还需要在设备配置文件(旧版本则为dev.c文件)中添加一些结构,来添加一个设备(使用spi总线驱动),而我们另外编写的设备驱动则与这个新添加的设备通过名字来关联(名字很难重要),那我们就可以通过这个另外编写的设备驱动来操作spi总线了,详细使用情况我在这个贴上有说,就不再重复提了:
http://www.linuxforum.net/forum/showflat.php?Cat=&Board=embedded&Number=665008&page=7&view=collapsed&sb=5&o=0&fpart=
2、其实内核已经提供了这样的一个参考程序了,就是spidev,所以不用另外编写设备驱动了,选上spidev直接使用就可以了^_^