1、linux下的spi协议框架
一般spi-core以下的spi_master有芯片厂家开发完成。因此只需要完成SPI协议基础上的二次开发,比方说基于SPI协议实现网络数据的传输,或者SPI外围器件的控制,或者blalalala
2、代码框架
2.1、dts的配置,生成spi_master
/*配置GPIO口模式为SPI模式*/
spixxx_pins: spixxx_pins{
anyka,pins = <15 16 25 26 >;
anyka,function = <2 2 3 3 >;
anyka,pull = <0x00000010>;
};
&spi1 {
pinctrl-names = "default";
pinctrl-0 = <&spixxx_pins>;
cs-gpios = <&gpio 10 1>;
status = "okay";
spidev: my_xxx@0 {
compatible = "test,my_xxx";
spi-max-frequency = <12000000>;
reg = <0>;
};
};
2.2、代码框架
创建一个字符设备驱动,在字符设备驱动中调用spi接口完成数据的读写
#include <linux/init.h>
#include <linux/module.h>
#include <linux/ioctl.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/list.h>
#include <linux/errno.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/compat.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/spi/spi.h>
#include <linux/spi/spidev.h>
extern struct my_xxx_dev g_my_xxx_init __attribute__((weak));
struct my_xxx_dev g_my_xxx_init;
static struct my_xxx_dev *g_my_xxx_dev = NULL;
int my_xxx_open(struct inode *node, struct file *filp)
{
// struct my_xxx_dev *my_xxx_dev = container_of(filp->private_data, struct my_xxx_dev, misc_dev);
return 0;
}
int my_xxx_release(struct inode *node, struct file *filp)
{
// struct my_xxx_dev *my_xxx_dev = container_of(filp->private_data, struct my_xxx_dev, misc_dev);
return 0;
}
static ssize_t my_xxx_read(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
{
char data[10] = {0x00};
struct spi_transfer *t;
struct spi_message m;
struct my_xxx_dev *my_xxx_dev = container_of(filp->private_data, struct my_xxx_dev, misc_dev);
struct spi_device *spi = (struct spi_device *)my_xxx_dev->private_data;
mutex_lock(&my_xxx_dev->buf_lock);
t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);
if(t == NULL) {
printk("kzalloc spi_transfer error!\r\n");
return -1;
}
t->rx_buf = data;
t->len = 10;
spi_message_init(&m);
spi_message_add_tail(t, &m);
ret = spi_sync(spi, &m);
if(ret < 0) {
printk("spi_sync failed!\r\n");
kfree(t);
mutex_unlock(&my_xxx_dev->buf_lock);
return -1;
}
if (copy_to_user(buf, (void *)data, status) {
printk("error: copy from user\n");
mutex_unlock(&my_xxx_dev->buf_lock);
return -1;
}
kfree(t);
mutex_unlock(&my_xxx_dev->buf_lock);
return 0;
}
static ssize_t my_xxx_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos)
{
int ret = 0;
struct spi_transfer *t;
struct spi_message m;
struct my_xxx_dev *my_xxx_dev = container_of(filp->private_data, struct my_xxx_dev, misc_dev);
struct spi_device *spi = (struct spi_device *)my_xxx_dev->private_data;
mutex_lock(&my_xxx_dev->buf_lock);
if (copy_from_user(my_xxx_dev->data, (void *)buf, count)) {
printk("error: copy from user\n");
return -1;
}
t = kzalloc(sizeof(struct spi_transfer), GFP_KERNEL);
if(t == NULL) {
printk("kzalloc spi_transfer error!\r\n");
mutex_unlock(&my_xxx_dev->buf_lock);
return -1;
}
t->tx_buf = my_xxx_dev->data;
t->len = count;
t->tx_nbits = my_xxx_dev->tx_nbits;
spi->mode = ((my_xxx_dev->tx_nbits) == 0x02) ? SPI_TX_DUAL : (((my_xxx_dev->tx_nbits) == 0x04) ? SPI_TX_QUAD : SPI_MODE_0);
spi_message_init(&m);
spi_message_add_tail(t, &m);
ret = spi_sync(spi, &m);
if(ret < 0) {
printk("spi_sync failed!\r\n");
kfree(t);
mutex_unlock(&my_xxx_dev->buf_lock);
return -1;
}
kfree(t);
mutex_unlock(&my_xxx_dev->buf_lock);
return 0;
}
int my_xxx_ioctl(struct file *filp, unsigned int cmd, unsigned long int arg)
{
unsigned long int speed_hz = 0;
struct my_xxx_dev *my_xxx_dev = container_of(filp->private_data, struct my_xxx_dev, misc_dev);
struct spi_device *spi = (struct spi_device *)my_xxx_dev->private_data;
if(copy_from_user(&speed_hz, (void *)arg, sizeof(speed_hz))) {
printk("copy mparam data error\n");
return -1;
}
mutex_lock(&my_xxx_dev->buf_lock);
switch(cmd) {
case 0:
spi->max_speed_hz = speed_hz;
spi_setup(spi);
break;
default:
break;
}
mutex_unlock(&my_xxx_dev->buf_lock);
return 0;
}
struct file_operations my_xxx_fops = {
.owner = THIS_MODULE,
.open = my_xxx_open,
.release = my_xxx_release,
.read = my_xxx_read,
.write = my_xxx_write,
.unlocked_ioctl = my_xxx_ioctl,
};
static int my_xxx_probe(struct spi_device *spi)
{
int ret = 0;
printk("spi driver and device was matched!\n");
g_my_xxx_dev = kzalloc(sizeof(struct my_xxx_dev), GFP_KERNEL);
if (!g_my_xxx_dev) {
printk("kmalloc stepmotor dev fail.\n");
return -1;
}
memcpy(g_my_xxx_dev, &g_my_xxx_init, sizeof(struct my_xxx_dev));
g_my_xxx_dev->misc_dev.minor = MISC_DYNAMIC_MINOR;
g_my_xxx_dev->misc_dev.name = my_xxx_DEV_NAME;
g_my_xxx_dev->misc_dev.fops = &my_xxx_fops;
ret = misc_register(&g_my_xxx_dev->misc_dev);
if(unlikely(ret < 0)) {
printk("register misc fail\n");
}
mutex_init(&g_my_xxx_dev->buf_lock);
spi->mode = SPI_MODE_0;
spi_setup(spi);
g_my_xxx_dev->private_data = spi;
return ret;
}
static int my_xxx_remove(struct spi_device *spi)
{
misc_deregister(&g_my_xxx_dev->misc_dev);
kfree(g_my_xxx_dev);
g_my_xxx_dev = NULL;
return 0;
}
static const struct spi_device_id my_xxx_id_table[] =
{
{
"test,my_xxx", 0},
{
},
};
static const struct of_device_id my_xxx_of_match[] =
{
{
.compatible = "test,my_xxx"},
{
},
};
static struct spi_driver my_xxx_driver =
{
.probe = my_xxx_probe,
.remove = my_xxx_remove,
.driver = {
.name = "my_xxx",
.owner = THIS_MODULE,
.of_match_table = my_xxx_of_match,
},
.id_table = my_xxx_id_table,
};
int my_xxx_init(void)
{
spi_register_driver(&my_xxx_driver);
printk("%s module is installed\n", __func__);
return 0;
}
void my_xxx_exit(void)
{
spi_unregister_driver(&my_xxx_driver);
printk("%s module is removed.\n", __func__);
return;
}