Linux中SPI子系统
SPI注册控制器信息
devices-da8xx.c
static struct platform_device da850_spi1_device = {
.name = "spi_davinci",
.id = 1,
.resource = da850_spi1_resources,
.num_resources = ARRAY_SIZE(da850_spi1_resources),
.dev = {
.platform_data = &da850_spi1_pdata,
},
};
void __init da850_init_spi1(unsigned chipselect_mask,
struct spi_board_info *info, unsigned len)
{
spi_register_board_info(info, len);
platform_device_register(&da850_spi1_device);
}
SPI控制器信息的驱动匹配
davinci_spi.c
static struct platform_driver davinci_spi_driver = {
.driver.name = "spi_davinci",
.remove = __exit_p(davinci_spi_remove),
.suspend = davinci_spi_suspend,
.resume = davinci_spi_resume,
};
static int __init davinci_spi_init(void)
{
return platform_driver_probe(&davinci_spi_driver, davinci_spi_probe);
}
SPI设备信息的注册
board-da850-evm.c
static struct spi_board_info da850_spi_board_info[] = {
[0] = {
.modalias = "m25p80",
.platform_data = &spi_flash_data,
.mode = SPI_MODE_0,
.max_speed_hz = 10000000, /* max sample rate at 3V */
.bus_num = 1,
.chip_select = 0,
},
};
<!--注册-->
da850_init_spi1(BIT(0), da850_spi_board_info,
ARRAY_SIZE(da850_spi_board_info));
SPI设备驱动的匹配
此处以m25p80为例
static int __devinit m25p_probe(struct spi_device *spi)
{
const struct spi_device_id *id = spi_get_device_id(spi);
struct flash_platform_data *data;
struct m25p *flash;
struct flash_info *info;
unsigned i;
***
flash->spi = spi;
***
}
static struct spi_driver m25p80_driver = {
.driver = {
.name = "m25p80",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.id_table = m25p_ids,
.probe = m25p_probe,
.remove = __devexit_p(m25p_remove),
/* REVISIT: many of these chips have deep power-down modes, which
* should clearly be entered on suspend() to minimize power use.
* And also when they're otherwise idle...
*/
};
static int __init m25p80_init(void)
{
return spi_register_driver(&m25p80_driver);
}
SPI设备的读写
此处以m25p80为例
static int write_sr(struct m25p *flash, u8 val)
{
flash->command[0] = OPCODE_WRSR;
flash->command[1] = val;
return spi_write(flash->spi, flash->command, 2);
}
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\n",
dev_name(&flash->spi->dev), __func__, "from",
(u32)from, len);
***
spi_sync(flash->spi, &m);
***
}
static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
struct m25p *flash = mtd_to_m25p(mtd);
u32 page_offset, page_size;
struct spi_transfer t[2];
struct spi_message m;
***
spi_sync(flash->spi, &m);
***
}
SPI驱动中的读写接口
//<!--SPI的写接口-->
static inline int
spi_write(struct spi_device *spi, const u8 *buf, size_t len)
{
struct spi_transfer t = {
.tx_buf = buf,
.len = len,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
return spi_sync(spi, &m);
}
//<!--SPI的读接口-->
static inline int
spi_read(struct spi_device *spi, u8 *buf, size_t len)
{
struct spi_transfer t = {
.rx_buf = buf,
.len = len,
};
struct spi_message m;
spi_message_init(&m);
spi_message_add_tail(&t, &m);
return spi_sync(spi, &m);
}
<!--先写1字节,在读1字节-->
static inline ssize_t spi_w8r8(struct spi_device *spi, u8 cmd);
<!--先写1字节,在读2字节-->
static inline ssize_t spi_w8r16(struct spi_device *spi, u8 cmd);
<!--先写n_tx字节,在读n_rx字节-->
extern int spi_write_then_read(struct spi_device *spi,
const u8 *txbuf, unsigned n_tx,
u8 *rxbuf, unsigned n_rx);
SPI的中断
待续
参考分析
https://www.cnblogs.com/lknlfy/p/3265019.html