linux SPI bitbang 小结
来源:互联网 发布:上海知柚网络有限公司 编辑:程序博客网 时间:2024/06/05 17:48
前段时间同事调试 SPI 驱动, 遇到个问题来问我, 帮忙澄清了并顺便看了下SPI bitbang的驱动代码流程, 小结在此. 内核版本 3.6.4
本文所有文字都是原创, 转发请注明出处.
她的问题是这样的" 如果bitbang结构体不是排在第一个的话, 会有kernel warning出现." 以s3c24xx_spi 为例.
/* bitbang has to be first */
struct spi_bitbang bitbang;
struct completion done;
void __iomem *regs;
int irq;
int len;
int count;
struct fiq_handler fiq_handler;
enum spi_fiq_mode fiq_mode;
unsigned char fiq_inuse;
unsigned char fiq_claimed;
void (*set_cs)(struct s3c2410_spi_info *spi,
int cs, int pol);
/* data buffers */
const unsigned char *tx;
unsigned char *rx;
struct clk *clk;
struct resource *ioarea;
struct spi_master *master;
struct spi_device *curdev;
struct device *dev;
struct s3c2410_spi_info *pdata;
};
如果不放在结构体中第一个成员的位置的话, 就会出kernel warning.
WARNING: at kernel/workqueue.c:991 __queue_work+0x338/0x36c()
Modules linked in:
Call Trace:
[<806ac75c>] dump_stack+0x8/0x34
[<80123e6c>] warn_slowpath_common+0x78/0xa4
[<80123eb0>] warn_slowpath_null+0x18/0x24
[<80143714>] __queue_work+0x338/0x36c
[<801437b4>] queue_work_on+0x44/0x8c
[<803c230c>] spi_bitbang_transfer+0xa4/0xd8
[<803c02b0>] spi_async_locked+0x20/0x4c
[<803c0700>] __spi_sync+0x54/0xbc
[<803d3e1c>] mmc_spi_readbytes+0x54/0xc8
[<803d3ee8>] mmc_spi_skip+0x58/0xf4
[<803d40d0>] mmc_spi_set_ios+0x14c/0x434
[<803c6520>] mmc_power_up+0x1e0/0x268
[<803c68b8>] mmc_start_host+0x30/0x58
[<803c742c>] mmc_add_host+0x64/0xa0
[<803d5ec8>] mmc_spi_probe+0x3bc/0x60c
[<8038d5e4>] driver_probe_device+0x118/0x498
[<8038da20>] __driver_attach+0xbc/0xc4
[<8038b808>] bus_for_each_dev+0x70/0xac
[<8038c1e0>] bus_add_driver+0x1d0/0x2bc
[<8038e204>] driver_register+0x74/0x17c
[<80100440>] do_one_initcall+0x40/0x1e0
---[ end trace fe3505dcf96ad417 ]---
分析方式不外乎顺推和倒推, 从workqueue倒退, 检查这个flag, 但是这个flag根本不会被置起来, 说明不是workqueue机制的问题.
那就顺推, 检查spi_bitbang的驱动, 结果发现在spi-bitbang.c的驱动中, 函数spi_bitbang_setup和spi_bitbang_transfer都调用到了
spi_master_get_devdata 去得到spi_bitbang, 但是实际上在spi_master_set_devdata的时候, 是整个结构体的.
int spi_bitbang_setup(struct spi_device *spi)
{
struct spi_bitbang_cs *cs = spi->controller_state;
struct spi_bitbang *bitbang;
int retval;
unsigned long flags;
bitbang = spi_master_get_devdata(spi->master);
if (!cs) {
cs = kzalloc(sizeof *cs, GFP_KERNEL);
if (!cs)
return -ENOMEM;
spi->controller_state = cs;
}
...
}
struct spi_master *spi_alloc_master(struct device *dev, unsigned size)
{
struct spi_master *master;
if (!dev)
return NULL;
master = kzalloc(size + sizeof *master, GFP_KERNEL);
if (!master)
return NULL;
device_initialize(&master->dev);
master->bus_num = -1;
master->num_chipselect = 1;
master->dev.class = &spi_master_class;
master->dev.parent = get_device(dev);
spi_master_set_devdata(master, &master[1]); // 这个master[1] 其实就是struct s3c24xx_spi, 所以要求bitbang是第一个成员
return master;
}
static int __devinit 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 = 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;
}
...
}
由于这个隐式转换的问题, 所以要求spi_bitbang是结构体内的第一个成员, 否则就会出各种意料不到的问题.
当然也可以自己修改下代码, 避免这个问题.
重要的结构体有: spi_device, spi_driver, spi_master, spi_transfer, spi_message
spi device和spi master的挂载是通过bus_num的匹配来实现的.
3. probe部分的流程
driver_probe_device
real_probe
spi_drv_probe(sdrv->driver.probe ) //是device_driver结构体里面的probe
sdrv->probe (spidev_probe) //是spi_driver结构体里面的probe
device_release_driver
__device_release_driver
drv->remove(dev); //spi_drv_remove
sdrv->remove //spidev_remove
4. transfer 流程
spi_read/spi_write
spi_sync
spi_async
master->transfer //可以是自己的transfer, 也可以是spi_bitbang_transfer(驱动没有赋值的系统默认)
5. spi_bitbang_transfer 流程
queue_work(bitbang->workqueue, &bitbang->work); //bitbang_work
bitbang->txrx_bufs(spi, t);
spi_bitbang_bufs //默认
cs->txrx_bufs
bitbang_txrx_8 // 16 //32
cs->txrx_word //bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)] 函数指针数组
spi_gpio_txrx_word_mode0
bitbang_txrx_be_cpha0
- linux SPI bitbang 小结
- spi bitbang实现原理分析
- spi bitbang实现原理分析
- bitbang
- 【转】什么是SPI的bitbang / bit bang / bit-bang / bitbanging
- 什么是SPI的bitbang / bit bang / bit-bang / bitbanging
- linux驱动之spi学习小结
- 转载_【整理】什么是SPI的bitbang / bit bang / bit-bang / bitbanging(转)
- LPC2300系列SPI小结
- SPI调试小结
- uart,iic,spi小结
- linux spi
- Linux SPI
- [笔记分享] [SPI] SPI 协议小结
- [笔记分享] [SPI] MSM8X60 SPI 小结
- SPI和I2C调试小结
- linux spi驱动
- linux spi驱动分析
- iOS 关于placeholder字体,颜色问题
- jdk与jre的区别
- HDInsight如何创建Hadoop集群
- ./nginx: error while loading shared libraries: libpcre.so.1
- 黑马程序员——Foundation框架——集合类(NSSet、NSArray等)(二)
- linux SPI bitbang 小结
- php开发安卓服务器之 php封装json xml通用app数据通信接口
- JAVA不借助第三个变量实现两个变量交换的思考
- cocos2d-x类型转换(CCstring int string char UTF-8互转)
- Android 编程下模拟 HOME 键效果
- 指针(Pointer)和引用(Reference)的区别
- WLAN 驱动解析
- linux之SQL语句简明教程---UNION ALL
- Go 语言基本类型总结