linux中spi驱动框架

linux中spi驱动框架

linux下的SPI总线驱动在driver/spi目录中。

SPI驱动分为三层

SPI核心层  drivers/spi/spi.c 与平台无关

SPI控制器驱动层

SPI设备驱动层


每层的主要结构体和函数

SPI控制器驱动层(include/linux/spi/spi.h)

struct spi_master {
  struct device dev;
  s16 bus_num;//控制器对应的SPI总线号
  u16 num_chipselect;//支持片选数量
  int (* setup) (struct spi_device *spi);//SPI模式设备,在spi_add_device中调用
  int (* transfer) (struct spi_device *spi,struct spi_message *mesg);//读写方法的函数,可能会睡眠
  void (* cleanup) (struct spi_device *spi);//注销时候调用
};  
 
 

SPI设备驱动层

spi_device对应某个特定的slave

struct spi_driver {
  int (* probe) (struct spi_device *spi);//匹配时调用,完成spi_transfer,spi_message,spi_message_init,spi_meassage_add_tail,spi_sync,spi_write_then_read的调用
  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;
};
 
 
struct spi_device {
  struct device dev;
  struct spi_master * master;
  u32 max_speed_hz;
  u8 chip_select;
  u8 mode;
#define SPI_CPHA	0x01
#define SPI_CPOL	0x02
#define SPI_MODE_0	(0|0)
#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
#define SPI_LSB_FIRST	0x08
#define SPI_3WIRE	0x10
#define SPI_LOOP	0x20
  u8 bits_per_word;
  int irq;
  void * controller_state;
  void * controller_data;
  const char * modalias;
};  
 
 
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;
}; 
 
 
int spi_register_driver (	struct spi_driver *  	sdrv);

 
 
struct spi_message {
  struct list_head transfers;
  struct spi_device * spi;
  unsigned is_dma_mapped:1;
  void (* complete) (void *context);
  void * context;
  unsigned actual_length;
  int status;
  struct list_head queue;
  void * state;
};  
 
 
在每次使用spi_message可以使用函数:
void spi_message_init(structspi_message *m);
来初始化。
向spi_message添加transfers可以使用spi_message_add_tail()函数:
void spi_message_add_tail(structspi_transfer *t, struct spi_message *m);
一旦你准备好了spi_message,就可以使用spi_async()来向SPI系统提交了:
int spi_async(struct spi_device *spi,struct spi_message *message);
因为是异步的,一提交就立马返回了,这也就是说需要同步机制(complete就是了)。他确保不会睡眠,可安全的在中断handler或其他不可休眠的代码中调用。稍后会念念他的好的。
使用spi_async()需要注意的是,在complete()未返回前不要轻易访问你一提交的spi_transfer中的buffer。也不能释放SPI系统正在使用的buffer。一旦你的complete返回了,这些buffer就又是你的了。
使用完成回调机制稍显复杂,可以使用SPI系统提供的另一个同步版本:spi_sync():
int spi_sync(struct spi_device *spi,struct spi_message *message);
因为是同步的,spi_sync提交完spi_message后不会立即返回,会一直等待其被处理。一旦返回就可以重新使用buffer了。spi_sync()在drivers/spi/spi.c中实现,其调用了spi_async(),并休眠直至complete返回。

spi_device的板信息用spi_board_info来描述,在init函数调用时会初始化。

struct spi_board_info {
  char modalias[KOBJ_NAME_LEN];
  const void * platform_data;
  void * controller_data;
  int irq;
  u32 max_speed_hz;
  u16 bus_num;
  u16 chip_select;
  u8 mode;
};  
 
 
int __init spi_register_board_info (	struct spi_board_info const *  	info,
 	unsigned  	n);

 
 
会把spi_board_info注册到链表board_list上。

之后,spi_master注册会调用scan_board_info扫描board_list找到挂接在它上面的spi设备。

然后创建并注册spi_device.

一个结构体spi_board_info对应着一个SPI设备spi_device

struct boardinfo{
	struct list_head list;
        struct spi_board_info board_info;
}
static LIST_HEAD(board_list);
static LIST_HEAD(spi_master_list);//初始化一个空链表

#define LIST_HEAD(name)

struct list_head name=LIST_HEAD_INIT(name)

#define LIST_HEAD_INIT(name)  {&(name),&(name)}

struct list_head {struct list_head* next,*prev;};

struct device_driver结构体被定义在/include/linux/device.h,原型是:

struct device_driver {
    const char        *name;
    struct bus_type        *bus;
<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">module</span>        *<span class="hljs-title">owner</span>;</span>
<span class="hljs-keyword">const</span> <span class="hljs-keyword">char</span>        *mod_name;    <span class="hljs-comment">/* used for built-in modules */</span>

<span class="hljs-keyword">bool</span> suppress_bind_attrs;    <span class="hljs-comment">/* disables bind/unbind via sysfs */</span>

<span class="hljs-keyword">int</span> (*probe) (struct device *dev);
<span class="hljs-keyword">int</span> (*remove) (struct device *dev);
<span class="hljs-keyword">void</span> (*shutdown) (struct device *dev);
<span class="hljs-keyword">int</span> (*suspend) (struct device *dev, <span class="hljs-keyword">pm_message_t</span> state);
<span class="hljs-keyword">int</span> (*resume) (struct device *dev);
<span class="hljs-keyword">const</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">attribute_group</span> **<span class="hljs-title">groups</span>;</span>

<span class="hljs-keyword">const</span> <span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">dev_pm_ops</span> *<span class="hljs-title">pm</span>;</span>

<span class="hljs-class"><span class="hljs-keyword">struct</span> <span class="hljs-title">driver_private</span> *<span class="hljs-title">p</span>;</span>

};


举例SPI驱动

spi_device设备

spi_board_info

init入口调用,spi_register_board_info(S3C_SPI_devs,ARRAY_SIZE(S3C_SPI_devs));

会把spi_board_info注册到board_list链表上。

之后会创建并注册spi_device


spi_driver驱动

1、声明并设置spi_driver结构体

2、注册spi_register_driver(&spi_driver);

3、实现probe操作,spi_transfer,spi_message的构建

spi_message_init,spi_message_add_tail,spi_sync调用

3.1、定义并设置 spi_transfer结构体

3.2、定义spi_message结构体

3.3、初始化meg,spi_message_init(&meg);

3.4、将st放入message队列spi_message_add_tail(&st,&meg);

3.5、将message与spi_device关联,发送meg,spi_sync(spi_device,&meg);





阅读更多
  • 1
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值