1
2
2.1
2.2
- struct
spi_master { -
struct device dev; -
s16 bus_num;
-
u16 num_chipselect; -
int (*setup)(struct spi_device *spi); -
int (*transfer)(struct spi_device *spi, struct spi_message *mesg); -
void (*cleanup)(struct spi_device *spi); - };
2.3
- 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; - };
- struct
spi_device { -
struct device dev; -
struct spi_master *master; -
u32 max_speed_hz; -
u8 chip_select; -
u8 mode; -
u8 bits_per_word; -
int irq; -
void *controller_state; -
void *controller_data; -
char modalias[32]; - };
通常来说spi_device对应着SPI总线上某个特定的slave。并且spi_device封装了一个spi_master结构体。spi_device结构体包含了私有的特定的slave设备特性,包括它最大的频率,片选那个,输入输出模式等等
3
SPI控制器具有以下特征:
4 spi_device以下一系列的操作是在platform板文件中完成!
这个结构体记录了SPI外设使用的主机控制器序号、片选信号、数据比特率、SPI传输方式等
构建的操作是以下的两个步骤:
1.
static structspi_board_info s3c_spi_devs[] __initdata ={
{
.modalias ="m25p10a",
.mode =SPI_MODE_0,
.max_speed_hz= 1000000,
.bus_num =0,
.chip_select= 0,
.controller_data= &smdk_spi0_csi[SMDK_MMCSPI_CS],
},
};
2.
而这个info在init函数调用的时候会初始化:
spi_register_board_info(s3c_spi_devs,ARRAY_SIZE(s3c_spi_devs));
spi_register_board_info(s3c_spi_devs,ARRAY_SIZE(s3c_spi_devs));//注册spi_board_info。这个代码会把spi_board_info注册到链表board_list上。spi_device封装了一个spi_master结构体,事实上spi_master的注册会在spi_register_board_info之后,spi_master注册的过程中会调用scan_boardinfo扫描board_list,找到挂接在它上面的spi设备,然后创建并注册spi_device。
至此spi_device就构建并注册完成了!!!!!!!!!!!!!
5spi_driver的构建与注册
driver有几个重要的结构体:spi_driver、spi_transfer、spi_message
driver有几个重要的函数
static structspi_driver
.driver ={
};
//spidriver的注册
spi_register_driver(&m25p80_driver);
在有匹配的spi_device时,会调用m25p_probe
probe里完成了spi_transfer、spi_message的构建;
spi_message_init、spi_message_add_tail、spi_sync、spi_write_then_read函数的调用
例如:
-
*/ - static
int m25p10a_read( struct m25p10a *flash, loff_t from, -
size_t len, char *buf ) - {
-
int r_count = 0, i; -
struct spi_transfer st[2]; -
struct spi_message msg; -
-
spi_message_init( &msg ); -
memset( st, 0, sizeof(st) ); -
-
flash->cmd[0] = CMD_READ_BYTES; -
flash->cmd[1] = from >> 16; -
flash->cmd[2] = from >> 8; -
flash->cmd[3] = from; -
-
st[ 0 ].tx_buf = flash->cmd; -
st[ 0 ].len = CMD_SZ; -
spi_message_add_tail( &st[0], &msg ); -
-
st[ 1 ].rx_buf = buf; -
st[ 1 ].len = len; -
spi_message_add_tail( &st[1], &msg ); -
-
mutex_lock( &flash->lock ); -
-
-
if (wait_till_ready(flash)) { -
mutex_unlock( &flash->lock ); -
return -1; -
} -
-
spi_sync( flash->spi, &msg ); -
r_count = msg.actual_length - CMD_SZ; -
printk( "in (%s): read %d bytes\n", __func__, r_count ); -
for( i = 0; i <</span> r_count; i++ ) { -
printk( "0xx\n", buf[ i ] ); -
} -
-
mutex_unlock( &flash->lock );
-
return 0; - }
- static
int m25p10a_write( struct m25p10a *flash, loff_t to, -
size_t len, const char *buf ) - {
-
int w_count = 0, i, page_offset; -
-
struct spi_transfer st[2]; -
-
struct spi_message msg;
-
write_enable( flash ); //写使能 -
-
memset( st, 0, sizeof(st) ); -
-
flash->cmd[0] = CMD_PAGE_PROGRAM; -
flash->cmd[1] = to >> 16; -
flash->cmd[2] = to >> 8; -
flash->cmd[3] = to; -
-
st[ 0 ].tx_buf = flash->cmd; -
st[ 0 ].len = CMD_SZ; -
//填充spi_transfer,将transfer放在队列后面 -
spi_message_add_tail( &st[0], &msg ); -
-
st[ 1 ].tx_buf = buf; -
st[ 1 ].len = len; -
spi_message_add_tail( &st[1], &msg ); -
-
-
spi_sync( flash->spi, &msg ); 调用spi_master发送spi_message -
-
return 0; - }
-
- static
int m25p10a_probe(struct spi_device *spi) - {
-
int ret = 0; -
struct m25p10a *flash; -
char buf[ 256 ]; -
flash = kzalloc( sizeof(struct m25p10a), GFP_KERNEL ); -
flash->spi = spi; -
-
spi_set_drvdata( spi, flash );
-
memset( buf, 0x7, 256 ); -
m25p10a_write( flash, 0, 20, buf); //0地址写入20个7 -
memset( buf, 0, 256 ); -
m25p10a_read( flash, 0, 25, buf ); //0地址读出25个数 -
-
return 0; - }
到目前为止,完成了SPI的驱动和应用
简而言之,SPI驱动的编写分为:
1.spi_device就构建并注册
spi_register_board_info(s3c_spi_devs,ARRAY_SIZE(s3c_spi_devs));//注册spi_board_info。这个代码会把spi_board_info注册到链表board_list上。spi_device封装了一个spi_master结构体,事实上spi_master的注册会在spi_register_board_info之后,spi_master注册的过程中会调用scan_boardinfo扫描board_list,找到挂接在它上面的spi设备,然后创建并注册spi_device。
2.
(1)
static structspi_driver
.driver ={
};
(2)//spi_driver的注册
spi_register_driver(&m25p80_driver);当匹配了spi_device以后调用probe
(3)实现probe操作: