这几天在看一些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就要发布了,好兴奋的说.