驱动模块使用SPI总线范例

前两天写了一个<驱动模块使用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
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值