这几天在看一些SPI设备驱动,不求甚解地去做,就是把事情往更深入的层面去说事...
用片段代码,来说明问题,有时候更容易的理解一些事情.
static int read_sr(struct m25p *flash)
{
ssize_t retval;
u8 code = OPCODE_RDSR;
u8 val;
/*
设备号:flash->spi
要发送的内容:&code
要发送的长度:1
要接受的内容:&val
要接受的长度:1
*/
retval = spi_write_then_read(flash->spi, &code, 1, &val, 1);
if (retval < 0) {
dev_err(&flash->spi->dev, "error %d reading SR
",
(int) retval);
return retval;
}
return val;
}
发当然也有后面发0x00,前面发一个字的.
static const struct spi_device_id *__devinit jedec_probe(struct spi_device *spi)
{
int tmp;
u8 code = OPCODE_RDID;
u8 id[5];
u32 jedec;
u16 ext_jedec;
struct flash_info *info;
/* JEDEC also defines an optional "extended device information"
* string for after vendor-specific data, after the three bytes
* we use here. Supporting some chips might require using it.
*/
tmp = spi_write_then_read(spi, &code, 1, id, 5);
if (tmp < 0) {
DEBUG(MTD_DEBUG_LEVEL0, "%s: error %d reading JEDEC ID
",
dev_name(&spi->dev), tmp);
return NULL;
}
另外也有函数,只发不收:
static int write_sr(struct m25p *flash, u8 val)
{
flash->command[0] = OPCODE_WRSR;
flash->command[1] = val;
/*
设备号:flash->spi
要发送的内容:flash->command
要发送的长度:2
*/
return spi_write(flash->spi, flash->command, 2);
}
当然,对应还有spi_read呢,当然高级一点,用spi_message_add_tail,把东西塞进去,首先要有这个结构体:
struct spi_transfer {
/* it's ok if tx_buf == rx_buf (right?)
* for MicroWire, one buffer must be null
* buffers must work with dma_*map_single() calls, unless
* spi_message.is_dma_mapped reports a pre-existing mapping
*/
const void *tx_buf;
void *rx_buf;
unsigned len;
dma_addr_t tx_dma;
dma_addr_t rx_dma;
struct sg_table tx_sg;
struct sg_table rx_sg;
unsigned cs_change:1;
unsigned tx_nbits:3;
unsigned rx_nbits:3;
#define SPI_NBITS_SINGLE 0x01 /* 1bit transfer */
#define SPI_NBITS_DUAL 0x02 /* 2bits transfer */
#define SPI_NBITS_QUAD 0x04 /* 4bits transfer */
u8 bits_per_word;
u16 delay_usecs;
u32 speed_hz;
struct list_head transfer_list;
};
然后填要发送的数据,然后发送,如下函数:
static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct m25p *flash = mtd_to_m25p(mtd);
struct spi_transfer t[2];
struct spi_message m;
DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd
",
dev_name(&flash->spi->dev), __func__, "from",
(u32)from, len);
/* sanity checks */
if (!len)
return 0;
if (from + len > flash->mtd.size)
return -EINVAL;
/*
用于初始化spi_message这个结构体,结构体填充.
*/
spi_message_init(&m);
memset(t, 0, (sizeof t));
/* NOTE:
* OPCODE_FAST_READ (if available) is faster.
* Should add 1 byte DUMMY_BYTE.
*/
/*
填充两次发送序列.
*/
t[0].tx_buf = flash->command;
t[0].len = m25p_cmdsz(flash) + FAST_READ_DUMMY_BYTE;
spi_message_add_tail(&t[0], &m);
t[1].rx_buf = buf;
t[1].len = len;
spi_message_add_tail(&t[1], &m);
/* Byte count starts at zero. */
if (retlen)
*retlen = 0;
mutex_lock(&flash->lock);
/* Wait till previous write/erase is done. */
if (wait_till_ready(flash)) {
/* REVISIT status return?? */
mutex_unlock(&flash->lock);
return 1;
}
/* FIXME switch to OPCODE_FAST_READ. It's required for higher
* clocks; and at this writing, every chip this driver handles
* supports that opcode.
*/
/* Set up the write data buffer. */
flash->command[0] = OPCODE_READ;
m25p_addr2cmd(flash, from, flash->command);
/*
同步API发送SPI数据.
*/
spi_sync(flash->spi, &m);
*retlen = m.actual_length - m25p_cmdsz(flash) - FAST_READ_DUMMY_BYTE;
mutex_unlock(&flash->lock);
return 0;
}
如果使用异步方式,就需要修改spi_message结构体,加入一个回调函数.其中tx_buf填写了,肯定就是发送填写的内容,否则发送0x00,然后收到的,肯定就存到rxbuf里头了.但是说实话,用async的应用也不多.但只是阻塞就有点塞CPU了,也不绿色低碳环保.找来找去,只能找到一个2046的程序.但是此函数实在有点庞大...截取部分:
x++; packet->pwrdown = PWRDOWN; x->tx_buf = &packet->pwrdown; x->len = 1; spi_message_add_tail(x, m); x++; x->rx_buf = &packet->dummy; x->len = 2; CS_CHANGE(*x); spi_message_add_tail(x, m); m->complete = ads7846_rx; m->context = ts;
如果完成传输,调用函数ads7846_rx,这个函数传入参数应该是void型的,如下~
static void ads7846_rx(void *ads)
{
struct ads7846 *ts = ads;
struct ads7846_packet *packet = ts->packet;
unsigned Rt;
u16 x, y, z1, z2;
/* ads7846_rx_val() did in-place conversion (including byteswap) from
* on-the-wire format as part of debouncing to get stable readings.
*/
x = packet->tc.x;
y = packet->tc.y;
z1 = packet->tc.z1;
z2 = packet->tc.z2;
那么,模式等等哪里设置呢,当然是板级设置文件哈,举个栗子:
static struct spi_board_info eb_spi_devices[] = {
{ /* RTC Dallas DS1306 */
.modalias = "rtc-ds1305",
.chip_select = 3,
.mode = SPI_CS_HIGH | SPI_CPOL | SPI_CPHA,
.max_speed_hz = 500000,
.bus_num = 0,
.irq = AT572D940HF_ID_IRQ1,
.platform_data = (void *) &ds1306_data,
},
#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
{ /* Dataflash card */
.modalias = "mtd_dataflash",
.chip_select = 0,
.max_speed_hz = 15 * 1000 * 1000,
.bus_num = 0,
},
#endif
};
好吧,今天就分析到这儿吧.这个月Windows 10就要发布了,好兴奋的说.