驱动模块使用SPI总线范例

    技术2025-10-10  4

    前两天写了一个<驱动模块使用I2C总线范例>。由于SPI和I2C类似,加上有空闲时间,故参考之前写的I2C实现了这个SPI模块。代码如下,这个代码未经调试,我目前的板子没有用到SPI接口,但是总体架构应该没错的。

    #include <linux/init.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/errno.h> #include <linux/init.h> #include <linux/list.h> #include <linux/smp_lock.h> #include <linux/spi/spi.h> struct spi_api { struct list_head list; struct spi_device *spi; }; #define SPI_MINORS 32 #define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH / | SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP / | SPI_NO_CS | SPI_READY) static LIST_HEAD(spi_api_list); static DEFINE_SPINLOCK(spi_api_list_lock); static struct spi_api *get_spi_api(int bus_id) { struct spi_api *spi_api; spin_lock(&spi_api_list_lock); list_for_each_entry(spi_api, &spi_api_list, list) { if (spi_api->spi->master->bus_num == bus_id) goto found; } spi_api = NULL; found: spin_unlock(&spi_api_list_lock); return spi_api; } static struct spi_api *add_spi_api(struct spi_device *spi) { struct spi_api *spi_api; if (spi->master->bus_num >= SPI_MINORS) { printk(KERN_ERR "spi_api: Out of device minors (%d)/n", spi->master->bus_num); return NULL; } spi_api = kzalloc(sizeof(*spi_api), GFP_KERNEL); if (!spi_api) return NULL; spi_api->spi = spi; spin_lock(&spi_api_list_lock); list_add_tail(&spi_api->list, &spi_api_list); spin_unlock(&spi_api_list_lock); return spi_api; } static void del_spi_api(struct spi_api *spi_api) { spin_lock(&spi_api_list_lock); list_del(&spi_api->list); spin_unlock(&spi_api_list_lock); kfree(spi_api); } static int spi_api_do_set(int bus_id, u8 mode, u8 bits_per_word, u8 max_speed_hz) { struct spi_device *spi; struct spi_api *spi_api = get_spi_api(bus_id); if (!spi_api) return -ENODEV; spi = spi_api->spi; spi->mode &= ~SPI_MODE_MASK; spi->mode |= mode; spi->bits_per_word = bits_per_word; spi->max_speed_hz = max_speed_hz; return spi_setup(spi); } static int spi_api_do_write(int bus_id, const u8 *buf, size_t len) { struct spi_api *spi_api = get_spi_api(bus_id); if (!spi_api) return -ENODEV; return spi_write(spi_api->spi, buf, len); } static int spi_api_do_read(int bus_id, u8 *buf, size_t len) { struct spi_api *spi_api = get_spi_api(bus_id); if (!spi_api) return -ENODEV; return spi_read(spi_api->spi, buf, len); } static int spi_api_do_write_then_read(int bus_id, const u8 *txbuf, unsigned n_tx, u8 *rxbuf, unsigned n_rx) { struct spi_api *spi_api = get_spi_api(bus_id); if (!spi_api) return -ENODEV; return spi_write_then_read(spi_api->spi, txbuf, n_tx, rxbuf, n_rx); } static int spi_api_probe(struct spi_device *spi) { add_spi_api(spi); printk(KERN_INFO "spi_api_probe device[%d]/n", spi->master->bus_num); return 0; } static int spi_api_remove(struct spi_device *spi) { struct spi_api * spi_api = get_spi_api(spi->master->bus_num); if (spi_api) del_spi_api(spi_api); return 0; } static struct spi_driver spi_api_driver = { .driver = { .name = "SPI-API", .owner = THIS_MODULE, }, .probe = spi_api_probe, .remove = spi_api_remove, }; static int __init spi_api_init(void) { int ret = spi_register_driver(&spi_api_driver); if (ret) { printk(KERN_ERR "[%s] Driver registration failed, module not inserted./n", __func__); return ret; } printk("spi_api_init/n"); return 0 ; } static void __exit spi_api_exit(void) { spi_unregister_driver(&spi_api_driver); } MODULE_AUTHOR("Loon, <sepnic@gmail.com>"); MODULE_DESCRIPTION("SPI spi_api Driver"); MODULE_LICENSE("GPL"); module_init(spi_api_init); module_exit(spi_api_exit); EXPORT_SYMBOL_GPL(spi_api_do_set); EXPORT_SYMBOL_GPL(spi_api_do_write); EXPORT_SYMBOL_GPL(spi_api_do_read); EXPORT_SYMBOL_GPL(spi_api_do_write_then_read);

    最新回复(0)