Linux SPI驱动分主机驱动和设备驱动,主机驱动往往由厂商实现好,第三方开发员直接开发设备驱动即可。下面不阐述SPI子系统及驱动相关的架构,直接上一个SPI接口的温度传感器(TMP125)驱动来理解SPI驱动如何运作。这里也涉及Linux 驱动模型的知识。
在板级文件增加SPI设备信息:
static struct omap2_mcspi_device_config ads7846_mcspi_config = {
.turbo_mode = 0,
.single_channel = 1, /* 0: slave, 1: master */
};
static struct omap2_mcspi_device_config tmp125_mcspi_config = {
.turbo_mode = 0,
.single_channel = 1, /* 0: slave, 1: master */
};
static struct spi_board_info omap3evm_spi_board_info[] = {
[0] = {
.modalias = "ads7846",
.bus_num = 1,
.chip_select = 0,
.max_speed_hz = 1500000,
.controller_data = &ads7846_mcspi_config,
.irq = OMAP_GPIO_IRQ(OMAP3_EVM_TS_GPIO),
.platform_data = &ads7846_config,
},
[1] = {
.modalias = "tmp125",
.bus_num = 2,
.chip_select = 0,
.max_speed_hz = 2000000,
.controller_data = &tmp125_mcspi_config,
},
};
这里需注意设备挂在CPU哪个SPI控制器上,及所在片选序号。这里笔者的TMP125挂在CPU的SPI2控制器上,片选为CS0。
在板级初始化函数中注册SPI设备信息:
spi_register_board_info(omap3evm_spi_board_info,
ARRAY_SIZE(omap3evm_spi_board_info));
实现SPI设备端的驱动:
tmp_driver.h文件
#ifndef TMP_DRIVER_H
#define TMP_DRIVER_H
#define LINUX2637_KERNEL 1
//#define MACR_DEBUG
#ifdef MACR_DEBUG
#define DEBUG_PRK(fmt,arg...) printk(KERN_INFO fmt,##arg)
#else
#define DEBUG_PRK(fmt,arg...) ;
#endif
#define MACR_DEV_NAME "RFODNCC_TMP"
struct tmp125
{
dev_t devt;
struct list_head device_entry;
char phys[32];
char name[32];
struct spi_device *spi;
struct regulator *reg;
struct spi_transfer xfer;
struct spi_message msg;
struct cdev dev;
struct class *dev_class;
spinlock_t spin_lock;
struct mutex buf_lock;
const struct file_operations *fop;
int major_num;
};
#define SPI_CPHA 0x01
#define SPI_CPOL 0x02
#define SPI_MODE_0 (0|0)
#define SPI_MODE_1 (0|SPI_CPHA)
#define SPI_MODE_2 (SPI_CPOL|0)
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH 0x04
#define SPI_LSB_FIRST 0x08
#define SPI_3WIRE 0x10
#define SPI_LOOP 0x20
#define SPI_NO_CS 0x40
#define SPI_READY 0x80
#define SPI_MODE_MASK (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH \
| SPI_LSB_FIRST | SPI_3WIRE | SPI_LOOP \
| SPI_NO_CS | SPI_READY)
/* IOCTL commands */
#define SPI_IOC_MAGIC 'k'
/* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */
#define SPI_MSGSIZE(N) \
((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */
#define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC, 1, __u8)
#define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC, 1, __u8)
/* Read / Write SPI bit justification */
#define SPI_IOC_RD_LSB_FIRST _IOR(SPI_IOC_MAGIC, 2, __u8)
#define SPI_IOC_WR_LSB_FIRST _IOW(SPI_IOC_MAGIC, 2, __u8)