Linux下的SPI总线驱动(二)
版权所有,转载请说明转自 http://my.csdn.net/weiqing1981127
四.SPI内核代码分析
我们已经讲过SPI驱动的移植,SPI控制设备和SPI接口设备的注册,SPI控制设备驱动和SPI接口设备驱动的注册。在移植时候,我们配置的选项告诉我们有些文件已经编入内核,那些就是SPI驱动的比较重要的文件。其中spi.c是SPI初始化和核心代码。spi_gpio.c是IO模拟SPI接口代码。spi_s3c24xx.c是s3c24xx系列芯片的SPI控制器驱动,它向更上层的SPI核心层(spi.c)提供接口用来控制芯片的SPI控制器,是一个被其他驱动使用的驱动。spi_s3c24xx_gpio.c允许用户指定3个gpio口,分别充当spi_clk、spi_mosi和spi_miso接口,模拟标准的spi总线。spidev.c是在核心层基础之上将SPI控制器模拟成一个字符型的驱动,向文件系统提供标准的文件系统接口,用来操作对应的SPI控制器。
通过这些代码的分析,我们可以获得三个知识:其一,更清楚的理解设备和驱动的注册。其二,掌握SPI数据的传输过程。三,更清晰的明白SPI各个文件的功能
我们先看spi.c
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); //SPI总线注册
if (status < 0)
goto err1;
status = class_register(&spi_master_class); //SPI类注册
if (status < 0)
goto err2;
return 0;
err2:
bus_unregister(&spi_bus_type);
err1:
kfree(buf);
buf = NULL;
err0:
return status;
}
上面的总线注册让我们联想到前面讲SPI接口设备注册和SPI接口设备驱动注册时候,在那里我们看到将它们都注册到我们现在这里注册的SPI总线上来的。
然后我们在spi.c中定义了几个函数
spi_write_then_read spi_sync spi_async spi_setup
spi_busnum_to_master spi_unregister_master spi_register_master
spi_alloc_master spi_new_device spi_add_device
spi_alloc_device spi_register_driver spi_get_device_id
其次我们看看spi_bitbang.c
这个文件里主要定义了几个函数
spi_bitbang_stop spi_bitbang_start spi_bitbang_transfer
spi_bitbang_setup spi_bitbang_cleanup spi_bitbang_setup_transfer
然后看看spi_s3c24xx.c
前面我们已经知道spi_s3c24xx.c中,我们注册了SPI控制器驱动,注册了SPI接口设备。现在,我们好好读读这个文件,看看怎么由这个SPI控制器驱动到注册这个SPI接口设备的。
static struct platform_driver s3c24xx_spi_driver = {
.remove = __exit_p(s3c24xx_spi_remove),
.driver = {
.name = "s3c2410-spi",
.owner = THIS_MODULE,
.pm = S3C24XX_SPI_PMOPS,
},
};
static int __init s3c24xx_spi_init(void)
{
return platform_driver_probe(&s3c24xx_spi_driver, s3c24xx_spi_probe);
}
这个平台设备s3c24xx_spi_driver就是我们说的SPI控制器驱动,现在我们把精力集中在s3c24xx_spi_probe上吧
static int __init s3c24xx_spi_probe(struct platform_device *pdev)
{
struct s3c2410_spi_info *pdata;
struct s3c24xx_spi *hw;
struct spi_master *master;
struct resource *res;
int err = 0;
// 分配master+ s3c24xx_spi大小的数据,把s3c24xx_spi设为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;
}
hw = spi_master_get_devdata(master); //从master中获得s3c24xx_spi
memset(hw, 0, sizeof(struct s3c24xx_spi)); //清空s3c24xx_spi
hw->master = spi_master_get(master);
//驱动移植的时候需要实现的重要结构,初始化为&s3c2410_spi0_platdata
hw->pdata = pdata = pdev->dev.platform_data;
hw->dev = &pdev->dev;
if (pdata == NULL) {
dev_err(&pdev->dev, "No platform data supplied\n");
err = -ENOENT;
goto err_no_pdata;
}
platform_set_drvdata(pdev, hw); //设置平台的私有数据为s3c24xx_spi
init_completion(&hw->done);
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH;
master->num_chipselect = hw->pdata->num_cs; //该总线上的设备数
master->bus_num = pdata->bus_num; //总线号
hw->bitbang.master = hw->master;
//spi_bitbang专门负责数据的传输
//此处不定义除s3c24xx_spi_chipsel外其他函数也可以,那样会在spi_bitbang.c中定义
hw->bitbang.setup_transfer = s3c24xx_spi_setupxfer;
hw->bitbang.chipselect = s3c24xx_spi_chipsel;
hw->bitbang.txrx_bufs = s3c24xx_spi_txrx;
hw->master->setup = s3c24xx_spi_setup;
hw->master->cleanup = s3c24xx_spi_cleanup;
dev_dbg(hw->dev, "bitbang at %p\n", &hw->bitbang);
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, resource_size(res),
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, resource_size(res)); //读取寄存器基址
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;
}
if (!pdata->set_cs) {
if (pdata->pin_cs < 0) {
dev_err(&pdev->dev, "No chipselect pin\n");
goto err_register;
}
err = gpio_request(pdata->pin_cs, dev_name(&pdev->dev)); //申请中断
if (err) {
dev_err(&pdev->dev, "Failed to get gpio for cs\n");
goto err_register;
}
hw->set_cs = s3c24xx_spi_gpiocs; //如果私有数据没定义set_cs,则调用内核中函数
gpio_direction_output(pdata->pin_cs, 1);
} else
hw->set_cs = pdata->set_cs; //如果私有数据没定义了set_cs就调用之
//初始化设置寄存器,包括对SPIMOSI,SPIMISO,SPICLK引脚的设置
s3c24xx_spi_initialsetup(hw);
err = spi_bitbang_start(&hw->bitbang); //注册SPI接口设备
if (err) {
dev_err(&pdev->dev, "Failed to register SPI master\n");
goto err_register;
}
return 0;
err_register:
if (hw->set_cs == s3c24xx_spi_gpiocs)
gpio_free(pdata->pin_cs);
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;
}
总结下,在s3c24xx_spi_probe中,我们主要做了如下几个事情:其一,申请了spi_master,将s3c24xx_spi作为其私有数据,同时,s3c24xx_spi也作为了平台设备的私有数据。其二,对spi_master和s3c24xx_spi下的bitbang分别进行了初始化。其三,读取寄存器基址和中断号,申请中断。其四,初始化寄存器,包括对SPIMOSI,SPIMISO,SPICLK引脚的设置。其五,注册SPI接口设备。
未来我们主要研究中断函数和如何注册SPI接口设备的函数,这里,我们先看看如何注册SPI接口的函数spi_bitbang_start
int spi_bitbang_start(struct spi_bitbang *bitbang)
{
int status;
if (!bitbang->master || !bitbang->chipselect)
return -EINVAL;
//动态创建一个work_struct结构,它的处理函数是bitbang_work
INIT_WORK(&bitbang->work, bitbang_work);
spin_lock_init(&bitbang->lock);
INIT_LIST_HEAD(&bitbang->queue);
if (!bitbang->master->mode_bits)
bitbang->master->mode_bits = SPI_CPOL | SPI_CPHA | bitbang->flags;
if (!bitbang->master->transfer) // spi的数据传输就是用这个方法
bitbang->master->transfer = spi_bitbang_transfer;
if (!bitbang->txrx_bufs) { // 在spi_s3c24xx.c中的probe中已经定义,故跳过
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;
}
} else if (!bitbang->master->setup)
return -EINVAL;
bitbang->busy = 0;
//调用create_singlethread_workqueue创建单个工作线程
bitbang->workqueue = create_singlethread_workqueue(
dev_name(bitbang->master->dev.parent));
if (bitbang->workqueue == NULL) {
status = -EBUSY;
goto err1;
}
status = spi_register_master(bitbang->master); //注册SPI接口设备
if (status < 0)
goto err2;
return status;
err2:
destroy_workqueue(bitbang->workqueue);
err1:
return status;
}
我们跟踪spi_bitbang_start中的spi_register_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;
if (master->num_chipselect == 0)
return -EINVAL;
if (master->bus_num < 0) {
master->bus_num = atomic_dec_return(&dyn_bus_id);
dynamic = 1;
}
//将spi添加到内核,这也是sys/class/Spi_master下产生Spi0,Spi1的原因
dev_set_name(&master->dev, "spi%u", master->bus_num);
status = device_add(&master->dev);
if (status < 0)
goto done;
dev_dbg(dev, "registered master %s%s\n", dev_name(&master->dev),
dynamic ? " (dynamic)" : "");
scan_boardinfo(master);
status = 0;
done:
return status;
}
这里主要跟踪spi_register_master中的scan_boardinfo函数
static void scan_boardinfo(struct spi_master *master)
{
struct boardinfo *bi;
mutex_lock(&board_lock);
//遍历所有挂在board_list上的 boardinfo
list_for_each_entry(bi, &board_list, list) {
//遍历每个boardinfo管理的spi_board_info
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;
(void) spi_new_device(master, chip); //创建SPI接口设备
}
}
mutex_unlock(&board_lock);
}
所以,在SPI控制器驱动注册的时候不但注册这个主机控制器的驱动,还要遍历这个SPI接口设备链表,比较接口设备总线号是否与控制器总线号一致,将接口设备总线号一致的接口设备spi_device全部注册进内核。
现在看看scan_boardinfo中创建新设备的函数spi_new_device
struct spi_device *spi_new_device(struct spi_master *master,
struct spi_board_info *chip)
{
struct spi_device *proxy;
int status;
proxy = spi_alloc_device(master); //分配spi_device
if (!proxy)
return NULL;
WARN_ON(strlen(chip->modalias) >= sizeof(proxy->modalias));
//初始化spi_device的各个字段
proxy->chip_select = chip->chip_select;
proxy->max_speed_hz = chip->max_speed_hz;
proxy->mode = chip->mode;
proxy->irq = chip->irq;
//获得spi_device的名字,移植时在mach-smdk2440.c中的s3c2410_spi0_board中设定的
strlcpy(proxy->modalias, chip->modalias, sizeof(proxy->modalias));
proxy->dev.platform_data = (void *) chip->platform_data;
proxy->controller_data = chip->controller_data;
proxy->controller_state = NULL;
status = spi_add_device(proxy); //主要完成将spi_device添加到内核
if (status < 0) {
spi_dev_put(proxy);
return NULL;
}
return proxy;
}
之前我们说过spi_new_device中的分配spi_device函数会调用spi->dev.bus = &spi_bus_type;设置SPI接口设备的总线类型为spi_bus_type,这样便于与SPI接口设备驱动相联系。
好了,现在我们看看spi_new_device中将spi_device添加到内核的函数spi_add_device
int spi_add_device(struct spi_device *spi)
{
static DEFINE_MUTEX(spi_add_lock);
struct device *dev = spi->master->dev.parent;
int status;
if (spi->chip_select >= spi->master->num_chipselect) {
dev_err(dev, "cs%d >= max %d\n",
spi->chip_select,
spi->master->num_chipselect);
return -EINVAL;
}
//设置是spi_device在Linux设备驱动模型中的name,也就是spi0.0 dev_set_name(&spi->dev, "%s.%u", dev_name(&spi->master->dev),
spi->chip_select);
mutex_lock(&spi_add_lock);
//如果总线上挂的设备已经有这个名字,则设置状态忙碌,并退出
if (bus_find_device_by_name(&spi_bus_type, NULL, dev_name(&spi->dev))
!= NULL) {
dev_err(dev, "chipselect %d already in use\n",
spi->chip_select);
status = -EBUSY;
goto done;
}
status = spi_setup(spi); // 对spi_device的时钟等进行设置
if (status < 0) {
dev_err(dev, "can't %s %s, status %d\n",
"setup", dev_name(&spi->dev), status);
goto done;
}
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_add_device中对spi_device的时钟等进行设置函数spi_setup
status = spi->master->setup(spi);而我们知道master所指向的setup在spi_s3c24xx.c中定义为 s3c24xx_spi_setup,我们跟踪这个函数会看到ret = s3c24xx_spi_update_state(spi, NULL);
接着看看s3c24xx_spi_update_state
static int s3c24xx_spi_update_state(struct spi_device *spi,
struct spi_transfer *t)
{
struct s3c24xx_spi *hw = to_hw(spi);
struct s3c24xx_spi_devstate *cs = spi->controller_state;
unsigned int bpw;
unsigned int hz;
unsigned int div;
unsigned long clk;
//设置了每字长的位数和发送速度
bpw = t ? t->bits_per_word : spi->bits_per_word;
hz = t ? t->speed_hz : spi->max_speed_hz;
if (!bpw)
bpw = 8;
if (!hz)
hz = spi->max_speed_hz;
if (bpw != 8) {
dev_err(&spi->dev, "invalid bits-per-word (%d)\n", bpw);
return -EINVAL;
}
if (spi->mode != cs->mode) {
u8 spcon = SPCON_DEFAULT;
if (spi->mode & SPI_CPHA)
spcon |= S3C2410_SPCON_CPHA_FMTB;
if (spi->mode & SPI_CPOL)
spcon |= S3C2410_SPCON_CPOL_HIGH;
cs->mode = spi->mode;
cs->spcon = spcon;
}
if (cs->hz != hz) {
clk = clk_get_rate(hw->clk); //设置分频值
div = DIV_ROUND_UP(clk, hz * 2) - 1;
if (div > 255)
div = 255;
dev_dbg(&spi->dev, "pre-scaler=%d (wanted %d, got %ld)\n",
div, hz, clk / (2 * (div + 1)));
cs->hz = hz;
cs->sppre = div;
}
return 0;
}
好了,到此为止,我们跟着spi_s3c24xx.c中s3c24xx_spi_probe已经走完了,看到了SPI接口设备注册的整个流程。
接着看看spidev.c
我们知道spidev.c里面,我们注册了SPI接口设备驱动,并且添加了字符设备,为用户提供接口。
static const struct file_operations spidev_fops = {
.owner = THIS_MODULE,
.write = spidev_write,
.read = spidev_read,
.unlocked_ioctl = spidev_ioctl,
.open = spidev_open,
.release = spidev_release,
};
我们一个个的看看这些函数,看看怎么实现数据传输的吧。
static int spidev_open(struct inode *inode, struct file *filp)
{
struct spidev_data *spidev;
int status = -ENXIO;
lock_kernel();
mutex_lock(&device_list_lock);
list_for_each_entry(spidev, &device_list, device_entry) {//从接口设备链表中获取接口设备
if (spidev->devt == inode->i_rdev) {
status = 0;
break;
}
}
if (status == 0) {
if (!spidev->buffer) { //如果没申请缓冲区就去申请缓冲区
spidev->buffer = kmalloc(bufsiz, GFP_KERNEL);
if (!spidev->buffer) {
dev_dbg(&spidev->spi->dev, "open/ENOMEM\n");
status = -ENOMEM;
}
}
if (status == 0) { //如果初次使用就把使用次数加一
spidev->users++;
filp->private_data = spidev; //把spidev作为文件的私有数据
nonseekable_open(inode, filp);
}
} else
pr_debug("spidev: nothing for minor %d\n", iminor(inode));
mutex_unlock(&device_list_lock);
unlock_kernel();
return status;
}
这个open函数很简单,主要就是从接口设备链表中获取spidev设备,并对其初始化。好了,我们重点看看ioctl函数
static long spidev_ioctl(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;
if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC) //查看这个命令的幻数字段是否为'k'
return -ENOTTY;
//如果方向是用户空间从内核读,即内核向用户空间写,检查用户空间的地址是否有效
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; //从文件的私有数据中获取spidev
spin_lock_irq(&spidev->spi_lock);
spi = spi_dev_get(spidev->spi); //从spidev中获取spi_device
spin_unlock_irq(&spidev->spi_lock);
if (spi == NULL)
return -ESHUTDOWN;
mutex_lock(&spidev->buf_lock);
switch (cmd) {
case SPI_IOC_RD_MODE:
//因为已经进行了地址是否有效的检查
//所以这里使用__put_user,__get_user,__copy_from_user可以节省几个时钟周期
retval = __put_user(spi->mode & SPI_MODE_MASK,
(__u8 __user *)arg);
break;
case SPI_IOC_RD_LSB_FIRST:
retval = __put_user((spi->mode & SPI_LSB_FIRST) ? 1 : 0,
(__u8 __user *)arg);
break;
case SPI_IOC_RD_BITS_PER_WORD:
retval = __put_user(spi->bits_per_word, (__u8 __user *)arg);
break;
case SPI_IOC_RD_MAX_SPEED_HZ:
retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);
break;
case SPI_IOC_WR_MODE: //设置SPI模式
retval = __get_user(tmp, (u8 __user *)arg);
if (retval == 0) {
u8 save = spi->mode; //保存老的SPI模式
if (tmp & ~SPI_MODE_MASK) {
retval = -EINVAL;
break;
}
tmp |= spi->mode & ~SPI_MODE_MASK;
spi->mode = (u8)tmp;
retval = spi_setup(spi); //设置新的SPI模式
if (retval < 0)
spi->mode = save;
else
dev_dbg(&spi->dev, "spi mode %02x\n", tmp);
}
break;
case SPI_IOC_WR_LSB_FIRST:
retval = __get_user(tmp, (__u8 __user *)arg);
if (retval == 0) {
u8 save = spi->mode;
if (tmp)
spi->mode |= SPI_LSB_FIRST;
else
spi->mode &= ~SPI_LSB_FIRST;
retval = spi_setup(spi);
if (retval < 0)
spi->mode = save;
else
dev_dbg(&spi->dev, "%csb first\n",
tmp ? 'l' : 'm');
}
break;
case SPI_IOC_WR_BITS_PER_WORD: //写入几比特代表一个字
retval = __get_user(tmp, (__u8 __user *)arg);
if (retval == 0) {
u8 save = spi->bits_per_word;
spi->bits_per_word = tmp;
retval = spi_setup(spi);
if (retval < 0)
spi->bits_per_word = save;
else
dev_dbg(&spi->dev, "%d bits per word\n", tmp);
}
break;
case SPI_IOC_WR_MAX_SPEED_HZ: //写传输速度
retval = __get_user(tmp, (__u32 __user *)arg);
if (retval == 0) {
u32 save = spi->max_speed_hz;
spi->max_speed_hz = tmp;
retval = spi_setup(spi);
if (retval < 0)
spi->max_speed_hz = save;
else
dev_dbg(&spi->dev, "%d Hz (max)\n", tmp);
}
break;
default:
if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))
|| _IOC_DIR(cmd) != _IOC_WRITE) {
retval = -ENOTTY;
break;
}
tmp = _IOC_SIZE(cmd); //得到用户空间数据的大小
//如果这些数据不能分成spi_ioc_transfer的整数倍,则不能进行传输
//spi_io_transfer是对spi_transfer的映射
if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {
retval = -EINVAL;
break;
}
n_ioc = tmp / sizeof(struct spi_ioc_transfer); //计算出能分多少个spi_ioc_transfer
if (n_ioc == 0)
break;
ioc = kmalloc(tmp, GFP_KERNEL); //在内核中分配装载这些数据的内存空间
if (!ioc) {
retval = -ENOMEM;
break;
}
if (__copy_from_user(ioc, (void __user *)arg, tmp)) { //把用户空间的数据拷贝过来
kfree(ioc);
retval = -EFAULT;
break;
}
retval = spidev_message(spidev, ioc, n_ioc); //进行数据传输
kfree(ioc);
break;
}
mutex_unlock(&spidev->buf_lock);
spi_dev_put(spi);
return retval;
}
在这个ioctl函数中,我们可以设置工作模式,可以设置bit/word,可以设置波特率,当然当其他命令进来会执行数据传输函数spidev_message,那么我们就跟踪看看这个函数如何实现数据传输的吧
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;
unsigned n, total;
u8 *buf;
int status = -EFAULT;
spi_message_init(&msg); //初始化spi_message的tranfers链表头
//分配n个spi_transfer的内存空间,一个spi_message由多个数据段spi_transfer组成
k_xfers = kcalloc(n_xfers, sizeof(*k_tmp), GFP_KERNEL);
if (k_xfers == NULL)
return -ENOMEM;
buf = spidev->buffer; //获得缓冲区
total = 0;
//这个for循环的主要任务是将所有的spi_transfer组装成一个spi_message
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;
}
//spi_transfer是一个读写的buffer对,如果是要接收则把buffer给接收的rx_buf
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;
}
//如果要传输,这个buffer给tx_buf使用,从用户空间拷过来要传输的数据
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; //指向下一段内存
//最后一个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_transfer通过它的transfer_list字段挂到spi_message的transfer队列上
spi_message_add_tail(k_tmp, &msg);
}
status = spidev_sync(spidev, &msg); //调用底层的传输函数
if (status < 0)
goto done;
buf = spidev->buffer;
//把传输数据拷贝到用户空间打印出来,可以查看是否传输成功
for (n = n_xfers, u_tmp = u_xfers; n; n--, u_tmp++) {
if (u_tmp->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:
kfree(k_xfers);
return status;
}
其实在上面这个spidev_message函数中,我们由spi_ioc_transfer映射到spi_transfer,同时初始化spi_message,将所有的spi_transfer组装成一个spi_message,最后调用调用底层的传输函数spidev_sync进行传输spi_message。好了,我们现在有必要看看这个底层传输函数
static ssize_t spidev_sync(struct spidev_data *spidev, struct spi_message *message)
{
DECLARE_COMPLETION_ONSTACK(done); //声明并初始化一个完成量
int status;
message->complete = spidev_complete; //指定spi_message使用的唤醒完成量函数
message->context = &done;
spin_lock_irq(&spidev->spi_lock);
if (spidev->spi == NULL)
status = -ESHUTDOWN;
else
status = spi_async(spidev->spi, message); //调用spi核心中的函数进行数据传输
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;
}
在spidev_sync函数中,我们调用核心层传输函数,并且设置完成量,等待完成量被唤醒。spidev_sync的入口参数是spidev_data和spi_message,该函数中,我们最终调用SPI核心层数据传输函数spi_async,入口参数是spi_device和spi_message,继续看
int spi_async(struct spi_device *spi, struct spi_message *message)
{
struct spi_master *master = spi->master; //由spi_device获取spi_master
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;
return master->transfer(spi, message); //真正的传输函数调用
}
核心层只是个包装,其真正的传输函数还是需要其他层来实现的。spi_async中我们最终调用master->transfer(spi, message);而该函数在spi_bitbang.c的spi_bitbang_start函数中曾经执行bitbang->master->transfer = spi_bitbang_transfer,所以我们看看spi_bitbang_transfer
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;
//在spi_alloc_master函数中调用spi_master_set_devdata把struct s3c24xx_spi存放起来
//struct spi_bitbang正是struct s3c24xx_spi结构所包含的第一个结构
bitbang = spi_master_get_devdata(spi->master);
spin_lock_irqsave(&bitbang->lock, flags);
if (!spi->max_speed_hz)
status = -ENETDOWN;
else {
//把message加入到bitbang的等待队列中
list_add_tail(&m->queue, &bitbang->queue);
//把bitbang-work加入bitbang->workqueue中,调度运行
queue_work(bitbang->workqueue, &bitbang->work);
}
spin_unlock_irqrestore(&bitbang->lock, flags);
return status;
}
根据spi_bitbang_transfer我们知道,最终我们把bitbang-work加入bitbang->workqueue中,等待内核调用,而bitbang-work在spi_bitbang_start函数中定义为bitbang_work,我们现在看看bitbang_work,也就是我们把这个数据传输交给了等待队列,等待内核调用bitbang_work
static void bitbang_work(struct work_struct *work)
{
struct spi_bitbang *bitbang =container_of(work, struct spi_bitbang, work);
unsigned long flags;
int do_setup = -1;
int (*setup_transfer)(struct spi_device *,
struct spi_transfer *);
setup_transfer = bitbang->setup_transfer;
spin_lock_irqsave(&bitbang->lock, flags);
bitbang->busy = 1; //设置成忙状态
while (!list_empty(&bitbang->queue)) { //对bitqueue中的每一个spi_message进行处理
struct spi_message *m;
struct spi_device *spi;
unsigned nsecs;
struct spi_transfer *t = NULL;
unsigned tmp;
unsigned cs_change;
int status;
m = container_of(bitbang->queue.next, struct spi_message,queue);v//从链表中获取
list_del_init(&m->queue); //从链表中删除spi_message
spin_unlock_irqrestore(&bitbang->lock, flags);
nsecs = 100;
spi = m->spi;
tmp = 0;
cs_change = 1;
status = 0;
list_for_each_entry (t, &m->transfers, transfer_list) { //获取spi_transfer
if (t->speed_hz || t->bits_per_word)
do_setup = 1;
if (do_setup != 0) {
if (!setup_transfer) {
status = -ENOPROTOOPT;
break;
}
status = setup_transfer(spi, t); //传输前期准备
if (status < 0)
break;
}
if (cs_change) {
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;
}
if (t->len) {
if (!m->is_dma_mapped)
t->rx_dma = t->tx_dma = 0;
status = bitbang->txrx_bufs(spi, t); //调用bitbang->txrx_bufs进行数据传输
}
if (status > 0)
m->actual_length += status;
if (status != t->len) {
if (status >= 0)
status = -EREMOTEIO;
break;
}
status = 0;
if (t->delay_usecs)
udelay(t->delay_usecs);
if (!cs_change)
continue;
if (t->transfer_list.next == &m->transfers) //链表遍历完毕,退出循环
break;
ndelay(nsecs);
bitbang->chipselect(spi, BITBANG_CS_INACTIVE);
ndelay(nsecs);
}
m->status = status; //所有spi_message传输完毕
m->complete(m->context); //传输完成,唤醒刚才的那个完成变量,调用完成函数
if (do_setup == 1)
setup_transfer(spi, NULL);
do_setup = 0;
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);
}
在bitbang_work中,我们主要知道要调用一个bitbang->txrx_bufs的传输函数,在spi_s3c24xx.c中定义为s3c24xx_spi_txrx。另外我们还需要关注一下传输完毕后调用了m->complete(m->context),也就是调用完成函数spidev_complete,这里面只有一条代码complete(arg);所以当数据传输完毕调用完成函数就可以返回到spidev_sync中的wait_for_completion(&done);好了,我们只剩下跟踪s3c24xx_spi_txrx了
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传输的数据数目
init_completion(&hw->done); //初始化了完成量
//只需发送第一个字节(如果发送为空,则发送0xff),中断中就会自动发送完其他字节(并//接受数据) 直到所有数据发送完毕且所有数据接收完毕才返回
writeb(hw_txbyte(hw, 0), hw->regs + S3C2410_SPTDAT);
wait_for_completion(&hw->done); //等待完成量被唤醒
return hw->count;
}
static inline unsigned int hw_txbyte(struct s3c24xx_spi *hw, int count)
{
//如果还有数据没接收完且要发送的数据经已发送完毕,发送空数据0xFF
return hw->tx ? hw->tx[count] : 0;
}
下面来分析下中断函数s3c24xx_spi_irq
static irqreturn_t s3c24xx_spi_irq(int irq, void *dev)
{
struct s3c24xx_spi *hw = dev;
unsigned int spsta = readb(hw->regs + S3C2410_SPSTA); //读取spi的状态寄存器
unsigned int count = hw->count;
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); //接收数据
if (count < hw->len) //如果count小于需要发送或接收数据的数目,发送其他数据
writeb(hw_txbyte(hw, count), hw->regs + S3C2410_SPTDAT);
else
complete(&hw->done); //发送接收完毕,通知s3c24xx_spi_txrx函数
irq_done:
return IRQ_HANDLED;
}
注意SPI总线数据传输时候,写和读数据是分开两个阶段来进行的,写数据的时候不读数据,读数据的时候发送空数据0xff,这样由主控产生时钟信号。