SPI总线由Motorola公司推出的同步串行总线,全双工工作模式,用于CPU与各种外围器件进行全双工、同步串行通讯。硬件由SCLK,MOSI,MISO及SS/CS(Slave Select/Chip Select,主机发出,拉低有效)组成,简略图如下:
SPI总线工作方式有四种,由时钟信号的极性及相位组合而成,
CPOL: 时钟极性选择,为0时SPI总线空闲为低电平,为1时SPI总线空闲为高电平。
CPHA:时钟相位选择,为0时在SCK第一个跳变沿采样,为1时在SCK第二个跳变沿采样。
MTK平台SPI的数据传输模式有:
1. FIFO,支持一次传输32bytes。
2. DMA,一次最多支持1024B,支持多次传输(length=loop*1024,1≤loop≤256)。
3. SPI控制器只有一个片选信号,故只支持一个从设备。
MTK SPI代码架构与MTK-I2C类似,不做进一步介绍。
下面是驱动代码的示例:
/*****************************************************************************
Copyright(c) 2012 NMI Inc. All Rights Reserved
File name : my-spi.h
Description : NM326 host interface
History :
----------------------------------------------------------------------
2015/02/02 dlj initial
*******************************************************************************/
#ifndef __my_SPI_H__
#define __my_SPI_H__
#ifdef __cplusplus
extern "C" {
#endif
#define my_SPI_DEBUG
#ifdef my_SPI_DEBUG
#define my_spi_dbg(fmt...) printk(fmt)
#else
#define my_spi_dbg(fmt, ...)
#endif
#define my_spi_err(fmt, ...) printk(fmt)
#define xxxx_DEV_MAJOR 227
#define xxxx_DEV_MINOR 0
#define xxxx_DEV_NAME "ttySPI"
#define SPI_FIFO_BATYE_PER_TIMES 32
typedef enum
{
SPI_SEND = 0,
SPI_RECV = 1,
}SPI_MODE;
typedef enum
{
NO_RESPONE = 0x00,
OP_RIGHT = 0x01,
OP_WRONG = 0x02,
}SPI_RESPONE;
extern void mt_eint_mask(unsigned int eint_num);
extern void mt_eint_unmask(unsigned int eint_num);
extern void mt_eint_set_hw_debounce(unsigned int eint_num, unsigned int ms);
extern void mt_eint_set_polarity(unsigned int eint_num, unsigned int pol);
extern unsigned int mt_eint_set_sens(unsigned int eint_num, unsigned int sens);
extern void mt_eint_registration(unsigned int eint_num, unsigned int flow, void (EINT_FUNC_PTR)(void), unsigned int is_auto_umask);
size_t RFReceivePacket(unsigned char **recv_buf, size_t pktLen);
#endif // __NMI_HW_H__
/*****************************************************************************
Copyright(c) 2012 my Inc. All Rights Reserved
File name : my-spi.c
Description : NM326 host interface
History :
----------------------------------------------------------------------
2015/02/02 dlj initial
*******************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "mach/mt_gpio.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "cust_gpio_usage.h"
#include "my-spi.h"
static unsigned char yyyy_spibuff_head[5] = {0x55,0xaa,0x00,0x00,0x00};
static size_t pkt_len = 0;
static unsigned char respone_flag = NO_RESPONE;
static DEFINE_MUTEX(my_spi_lock);
static unsigned char recv_tmp_buf[SPI_FIFO_BATYE_PER_TIMES] = {0};
static struct spi_device *xxxx_spi;
static struct class *xxxx_class;
static int sleep_time = HZ;
static int conn_state_flag = 0;
struct task_struct *xxxx_thread = NULL;
static DECLARE_WAIT_QUEUE_HEAD(interrupt_waiter);
static int xxxx_interrupt_flag = 0;
static DECLARE_WAIT_QUEUE_HEAD(read_waiter);
static int xxxx_read_flag = 0;
static DECLARE_WAIT_QUEUE_HEAD(write_waiter);
static int xxxx_write_flag = 0;
struct semaphore xxxx_sem;
static struct mt_chip_conf spi_xxxx_conf = {
.setuptime = 10000,
.holdtime = 0,
.high_time = 50,//165,//40,//335, //10--6m 15--4m 20--3m 30--2m [ 60--1m 120--0.5m 300--0.2m]
.low_time = 50,//165,//40,//335,
.cs_idletime = 20,
.ulthgh_thrsh = 0,
.cpol = 1,
.cpha = 1,
.tx_mlsb = 1,
.rx_mlsb = 1,
.tx_endian = 0,
.rx_endian = 0,
.com_mod = FIFO_TRANSFER,
.pause = 0,
.finish_intr = 1,
.deassert = 0,
.ulthigh = 0,
.tckdly = 0,
};
void SPI_SS_L(void)
{
mt_set_gpio_out(GPIO_SPI_CS_PIN, GPIO_OUT_ZERO);
}
void SPI_SS_H(void)
{
mt_set_gpio_out(GPIO_SPI_CS_PIN, GPIO_OUT_ONE);
}
uint8_t SPI_CrcCheck8(uint8_t *str,int len,uint8_t poly)
{
unsigned char reg_crc;
unsigned char s_crcchk;
s_crcchk = 0;
reg_crc = 0x00;
while(len--){
unsigned char c=*str++;
reg_crc ^= c;
for(s_crcchk = 0; s_crcchk < 8; s_crcchk ++)
{
if(reg_crc & 0x01)
{
reg_crc >>=1;
reg_crc = reg_crc^poly;
}
else
{
reg_crc = reg_crc >> 1;
}
}
}
return reg_crc;
}
unsigned char xxxx_spi_op(u8 *buf, size_t len, int flag)
{
struct spi_message msg;
struct spi_transfer transfer;
unsigned char status = 0;
int i = 0;
memset(&transfer, 0, sizeof(transfer));
SPI_SS_L();
spi_message_init(&msg);
msg.spi = xxxx_spi;
if(flag == SPI_SEND)
{
memset(recv_tmp_buf, 0, SPI_FIFO_BATYE_PER_TIMES);
transfer.tx_buf = (unsigned char *)buf;
transfer.rx_buf = recv_tmp_buf;
}
if(flag == SPI_RECV)
{
memset(recv_tmp_buf, 0xff, SPI_FIFO_BATYE_PER_TIMES);
transfer.tx_buf = recv_tmp_buf;
transfer.rx_buf = (unsigned char *)buf;
}
transfer.len = len;
spi_message_add_tail(&transfer, &msg);
status = spi_sync(xxxx_spi, &msg);
SPI_SS_H();
my_spi_dbg("xxxx_spi_op-----------status= %d\n",status);
my_spi_dbg("xxxx_spi_op------msg start---len= %d\n",(int)len);
for(i=0; i 0)
{
if(data_len > count)
{
data_len = count;
}
if(copy_to_user(buf, recv_buf, data_len) < 0)
{
data_len = 0;
}
}
kfree(recv_buf);
return data_len;
}
static ssize_t xxxx_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos)
{
unsigned char *tmp_buf = NULL;
int datalen = 0;
ssize_t ret = 0;
tmp_buf = (unsigned char *)kmalloc(count+6, GFP_KERNEL);
if(tmp_buf == NULL)
{
my_spi_err("xxxx_write: kmalloc failed\n");
goto ERR2;
}
memset(tmp_buf, 0, count+6);
yyyy_spibuff_head[2] = 0xfe;
datalen = count + 1;
yyyy_spibuff_head[3] = (0xff00&datalen)>>8;
yyyy_spibuff_head[4] = 0x00ff&datalen;
memcpy(tmp_buf, &yyyy_spibuff_head, 5);
/* move data from user area to kernel area */
if(copy_from_user(&tmp_buf[5], buf, count) < 0)
{
my_spi_err("xxxx_write: copy_from_user failed\n");
goto ERR1;
}
*(tmp_buf + count + 5) = SPI_CrcCheck8(tmp_buf,count+5,0xf8);
if(down_interruptible(&xxxx_sem))
{
my_spi_err("xxxx_write: ERESTARTSYS\n");
goto ERR1;
}
up(&xxxx_sem);
/* write data to SPI Controller */
if(RFSendPacket(tmp_buf, count+6))
{
my_spi_err("xxxx_write: RFSendPacket failed\n");
goto ERR1;
}
wait_event_interruptible(write_waiter, xxxx_write_flag != 0);
xxxx_write_flag = 0;
mutex_lock(&my_spi_lock);
if(respone_flag == OP_RIGHT)
{
ret = count;
}
mutex_unlock(&my_spi_lock);
ERR1:
kfree(tmp_buf);
ERR2:
respone_flag = NO_RESPONE;
return ret;
}
static const struct file_operations xxxx_fops = {
.owner = THIS_MODULE,
.open = xxxx_open,
.release = xxxx_release,
.read = xxxx_read,
.write = xxxx_write,
};
/******************************************************************************/
static ssize_t xxxx_show_conn_state(struct device* dev,
struct device_attribute *attr, char *buf)
{
ssize_t res;
res = snprintf(buf, PAGE_SIZE, "%d\n", conn_state_flag);
return res;
}
/******************************************************************************/
static ssize_t xxxx_show_stime(struct device* dev,
struct device_attribute *attr, char *buf)
{
ssize_t res;
res = snprintf(buf, PAGE_SIZE, "%d\n", sleep_time);
return res;
}
/******************************************************************************/
static ssize_t xxxx_store_stime(struct device* dev, struct device_attribute *attr,
const char *buf, size_t count)
{
if (!dev)
{
my_spi_err("dev is null!!\n");
return 0;
}
sleep_time = simple_strtol(buf, NULL, 10);
my_spi_dbg("content: '%s', length = %d, sleep_time = %d\n", buf, (int)count, sleep_time);
return count;
}
static ssize_t xxxx_show_spi(struct device* dev,
struct device_attribute *attr, char *buf)
{
struct mt_chip_conf *chip_config;
ssize_t res;
chip_config = &spi_xxxx_conf;
res = snprintf(buf, PAGE_SIZE, "high_time=%d,low_time=%d,cpol=%d,cpha=%d,com_mod=%d\n", \
chip_config->high_time,chip_config->low_time,chip_config->cpol,chip_config->cpha,chip_config->com_mod);
return res;
}
static ssize_t xxxx_store_spi(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct mt_chip_conf *chip_config;
u32 setuptime, holdtime, high_time, low_time;
u32 cs_idletime, ulthgh_thrsh;
int cpol, cpha,tx_mlsb, rx_mlsb, tx_endian, sample_sel, cs_pol;
int rx_endian, com_mod, pause, finish_intr;
int deassert, tckdly, ulthigh;
chip_config = &spi_xxxx_conf;
if (!chip_config) {
my_spi_dbg ( "chip_config is NULL.\n");
chip_config = kzalloc ( sizeof ( struct mt_chip_conf ), GFP_KERNEL );
if ( !chip_config )
return -ENOMEM;
}
if (!strncmp(buf, "-h", 2 ) ) {
my_spi_dbg("Please input the parameters for this device.\n");
} else if ( !strncmp(buf, "-w", 2 ) ) {
buf += 3;
if (!buf) {
my_spi_err("buf is NULL.\n");
goto out;
}
if (!strncmp(buf, "setuptime=",10) && (1 == sscanf(buf+10, "%d", &setuptime))) {
my_spi_dbg("setuptime is:%d\n", setuptime);
chip_config->setuptime=setuptime;
}else if (!strncmp(buf, "holdtime=", 9)&&(1==sscanf(buf+9, "%d", &holdtime))) {
my_spi_dbg("Set holdtime is:%d\n", holdtime);
chip_config->holdtime=holdtime;
}else if (!strncmp(buf, "high_time=", 10)&&(1==sscanf(buf+10, "%d", &high_time))) {
my_spi_dbg("Set high_time is:%d\n", high_time);
chip_config->high_time=high_time;
}else if (!strncmp(buf, "low_time=", 9)&&(1==sscanf(buf+9, "%d", &low_time))) {
my_spi_dbg("Set low_time is:%d\n", low_time);
chip_config->low_time=low_time;
}else if (!strncmp(buf, "cs_idletime=", 12)&&(1==sscanf(buf+12, "%d", &cs_idletime))) {
my_spi_dbg("Set cs_idletime is:%d\n", cs_idletime);
chip_config->cs_idletime=cs_idletime;
}else if (!strncmp(buf, "ulthgh_thrsh=", 13)&&(1==sscanf(buf+13, "%d", &ulthgh_thrsh))) {
my_spi_dbg("Set slwdown_thrsh is:%d\n", ulthgh_thrsh);
chip_config->ulthgh_thrsh=ulthgh_thrsh;
}else if (!strncmp(buf, "cpol=", 5) && (1 == sscanf(buf+5, "%d", &cpol))){
my_spi_dbg("Set cpol is:%d\n", cpol);
chip_config->cpol = cpol;
}else if (!strncmp(buf, "cpha=", 5) && (1 == sscanf(buf+5, "%d", &cpha))) {
my_spi_dbg("Set cpha is:%d\n", cpha);
chip_config->cpha = cpha;
}else if (!strncmp(buf, "tx_mlsb=", 8)&&(1==sscanf(buf+8, "%d", &tx_mlsb))) {
my_spi_dbg("Set tx_mlsb is:%d\n", tx_mlsb);
chip_config->tx_mlsb=tx_mlsb;
}else if (!strncmp(buf, "rx_mlsb=", 8)&&(1==sscanf(buf+8, "%d", &rx_mlsb))) {
my_spi_dbg("Set rx_mlsb is:%d\n", rx_mlsb);
chip_config->rx_mlsb=rx_mlsb;
}else if (!strncmp(buf, "tx_endian=", 10)&&(1==sscanf(buf+10, "%d", &tx_endian))) {
my_spi_dbg("Set tx_endian is:%d\n", tx_endian);
chip_config->tx_endian=tx_endian;
}else if (!strncmp(buf, "rx_endian=", 10)&&(1==sscanf(buf+10, "%d", &rx_endian))) {
my_spi_dbg("Set rx_endian is:%d\n", rx_endian);
chip_config->rx_endian=rx_endian;
}else if (!strncmp(buf, "com_mod=", 8)&&(1==sscanf(buf+8, "%d", &com_mod))) {
chip_config->com_mod=com_mod;
my_spi_dbg("Set com_mod is:%d\n", com_mod);
}else if (!strncmp(buf, "pause=", 6)&&(1==sscanf(buf+6, "%d", &pause))) {
my_spi_dbg("Set pause is:%d\n", pause);
chip_config->pause=pause;
}else if (!strncmp(buf, "finish_intr=", 12)&&(1==sscanf(buf+12, "%d", &finish_intr))) {
my_spi_dbg("Set finish_intr is:%d\n", finish_intr);
chip_config->finish_intr=finish_intr;
}else if (!strncmp(buf, "deassert=", 9)&&(1==sscanf(buf+9, "%d", &deassert))) {
my_spi_dbg("Set deassert is:%d\n", deassert);
chip_config->deassert=deassert;
}else if (!strncmp(buf, "ulthigh=", 8 ) && ( 1 == sscanf(buf+8, "%d", &ulthigh))) {
my_spi_dbg("Set ulthigh is:%d\n", ulthigh);
chip_config->ulthigh=ulthigh;
}else if (!strncmp(buf, "tckdly=",7) && ( 1 == sscanf(buf+7, "%d", &tckdly))) {
my_spi_dbg("Set tckdly is:%d\n", tckdly);
chip_config->tckdly=tckdly;
}else if (!strncmp(buf, "sample_sel=", 11 ) && ( 1 == sscanf(buf+11, "%d", &sample_sel))) {
my_spi_dbg("Set sample_sel is:%d\n", sample_sel);
chip_config->sample_sel=sample_sel;
}else if (!strncmp(buf, "cs_pol=",7) && ( 1 == sscanf(buf+7, "%d", &cs_pol))) {
my_spi_dbg("Set cs_pol is:%d\n", cs_pol);
chip_config->cs_pol=cs_pol;
}else {
my_spi_err("Wrong parameters.\n");
goto out;
}
spi_setup( xxxx_spi );
}
out:
return count;
}
DEVICE_ATTR(stime, S_IWUSR | S_IWGRP | S_IRUGO, xxxx_show_stime, xxxx_store_stime);
DEVICE_ATTR(conn_state, S_IRUGO, xxxx_show_conn_state, NULL);
DEVICE_ATTR(spi_par, S_IWUSR | S_IWGRP | S_IRUGO, xxxx_show_spi, xxxx_store_spi);
static struct device_attribute *xxxx_attr_list[] = {
&dev_attr_stime,
&dev_attr_conn_state,
&dev_attr_spi_par,
};
static int my_create_attr(struct device *dev)
{
int idx, err = 0;
int num = (int)(sizeof(xxxx_attr_list)/sizeof(xxxx_attr_list[0]));
if (!dev)
{
return -EINVAL;
}
for (idx = 0; idx < num; idx++)
{
if ((err = device_create_file(dev, xxxx_attr_list[idx])))
{
my_spi_err("device_create_file\n");
break;
}
}
return err;
}
void RFReceivePacket_respone(unsigned char respone)
{
unsigned char respone_head[5] = {0x55,0xaa,0x00,0x00,0x00};
respone_head[2] = respone;
/* write data to SPI Controller */
if(RFSendPacket(respone_head, 5))
{
my_spi_err("RFReceivePacket_respone: RFSendPacket failed\n");
}
return;
}
size_t RFReceivePacket(unsigned char **recv_buf, size_t pktLen)
{
size_t ret = 0;
unsigned char *crc_check_buf = NULL;
unsigned char respone;
my_spi_dbg(" ------------------RFReceivePacket----------------.\n");
my_spi_dbg("RFReceivePacket: pktLen = %d\n", (int)pktLen);
*recv_buf = (unsigned char *)kmalloc(pktLen, GFP_KERNEL);
crc_check_buf = (unsigned char *)kmalloc(pktLen+5, GFP_KERNEL);
if(*recv_buf != NULL && crc_check_buf != NULL)
{
memset(*recv_buf, 0, pktLen);
memset(crc_check_buf, 0, pktLen+5);
if(SPI_opt_func(*recv_buf, pktLen, SPI_RECV))
{
my_spi_err("RFReceivePacket: SPI_opt_func failed\n");
goto OUT;
}
crc_check_buf[0] = 0x55;
crc_check_buf[1] = 0xaa;
crc_check_buf[2] = 0xfe;
crc_check_buf[3] = (0xff00&pktLen)>>8;
crc_check_buf[4] = 0x00ff&pktLen;
memcpy(&crc_check_buf[5], *recv_buf, pktLen);
if(crc_check_buf[pktLen+4] == SPI_CrcCheck8(crc_check_buf, pktLen+4, 0xf8))
{
respone = OP_RIGHT;
//send data to user, &recv_buf[5]
ret = pktLen - 1;
}
else
{
respone = OP_WRONG;
}
udelay(100);
RFReceivePacket_respone(respone);
}
else
{
my_spi_err("RFReceivePacket: kmalloc failed\n");
}
OUT:
kfree(crc_check_buf);
return ret;
}
void xxxx_interrupt_handler(void)
{
my_spi_dbg("------------------------ %s\n", __FUNCTION__);
down_interruptible(&xxxx_sem);
xxxx_interrupt_flag = 1;
wake_up_interruptible(&interrupt_waiter);
}
static void xxxx_interrupt_distribute(void)
{
unsigned char buf[5] = {0};
unsigned char sem_flag = 1;
xxxx_spi_op(buf, 5, SPI_RECV);
//judge is legal pkt
if(buf[0] == 0x55 && buf[1] == 0xaa)
{
my_spi_dbg("get_PKTLen: buf[2] = 0x%x\n", (int)buf[2]);
if(buf[2] == 0xfe)
{
pkt_len = (size_t)((buf[3] << 8) | buf[4]);
xxxx_read_flag = 1;
wake_up_interruptible(&read_waiter);
sem_flag = 0;
}
else
{
if(buf[2] == OP_RIGHT)
{
mutex_lock(&my_spi_lock);
respone_flag = OP_RIGHT;
mutex_unlock(&my_spi_lock);
}
else if(buf[2] == OP_WRONG)
{
mutex_lock(&my_spi_lock);
respone_flag = OP_WRONG;
mutex_unlock(&my_spi_lock);
}
xxxx_write_flag = 1;
wake_up_interruptible(&write_waiter);
}
}
else
{
my_spi_err("get_PKTLen: pkt is not legal\n");
}
if(sem_flag)
{
up(&xxxx_sem);
}
return;
}
static int xxxx_interrupt_proc(void *unused)
{
do
{
set_current_state(TASK_INTERRUPTIBLE);
wait_event_interruptible(interrupt_waiter, xxxx_interrupt_flag != 0);
xxxx_interrupt_flag = 0;
set_current_state(TASK_RUNNING);
xxxx_interrupt_distribute();
} while (!kthread_should_stop());
return 0;
}
void xxxx_gpio_interrupt_reg(void)
{
#if 0
int ret = 0;
my_spi_dbg("------------------------ %s\n", __FUNCTION__);
if (ret = gpio_is_valid(GPIO_xxxx_EINT_PIN))
{
ret = gpio_request(GPIO_xxxx_EINT_PIN, "xxxx int pin");
if (ret)
goto err;
ret = gpio_direction_input(GPIO_xxxx_EINT_PIN);
if (ret)
goto err2;
ret = request_irq(gpio_to_irq(GPIO_xxxx_EINT_PIN),
xxxx_interrupt_handler, IRQF_TRIGGER_FALLING,
"xxxx recv message", NULL);
if (ret)
{
my_spi_err("gpio_direction_input failed\n");
goto err2;
}
return 0;
}
else
{
my_spi_err("GPIO_xxxx_EINT_PIN is invalid\n");
}
err2:
if (gpio_is_valid(GPIO_xxxx_EINT_PIN))
gpio_free(GPIO_xxxx_EINT_PIN);
my_spi_err("gpio_direction_input failed\n");
err:
my_spi_err("gpio_request failed\n");
return ret;
#endif
my_spi_dbg("------------------------ %s\n", __FUNCTION__);
mt_set_gpio_mode(GPIO_xxxx_EINT_PIN, GPIO_xxxx_EINT_PIN_M_EINT);
if(mt_set_gpio_dir(GPIO_xxxx_EINT_PIN, GPIO_DIR_IN)!=0)
{
my_spi_dbg(" mt_set_gpio_dir failed\n");
return;
}
if(mt_set_gpio_pull_enable(GPIO_xxxx_EINT_PIN, GPIO_PULL_ENABLE)!=0)
{
my_spi_dbg(" mt_set_gpio_pull_enable failed\n");
return;
}
if(mt_set_gpio_pull_select(GPIO_xxxx_EINT_PIN, GPIO_PULL_DOWN)!=0)
{
my_spi_dbg(" mt_set_gpio_pull_select failed\n");
return;
}
msleep(50);
mt_eint_set_hw_debounce(CUST_EINT_xxxx_NUM, CUST_EINT_xxxx_DEBOUNCE_CN);
mt_eint_registration(CUST_EINT_xxxx_NUM, CUST_EINT_xxxx_TYPE, xxxx_interrupt_handler, 1);
mt_eint_unmask(CUST_EINT_xxxx_NUM);
return;
}
void xxxx_gpio_init(void)
{
mt_set_gpio_mode(GPIO_SPI_CS_PIN, GPIO_MODE_00);
mt_set_gpio_dir(GPIO_SPI_CS_PIN, GPIO_DIR_OUT);
mt_set_gpio_out(GPIO_SPI_CS_PIN, GPIO_OUT_ONE);
mt_set_gpio_mode(GPIO_SPI_SCK_PIN, GPIO_SPI_SCK_PIN_M_SPI_CKA);
mt_set_gpio_pull_enable(GPIO_SPI_SCK_PIN, GPIO_PULL_ENABLE);
mt_set_gpio_pull_select(GPIO_SPI_SCK_PIN, GPIO_PULL_DOWN);
mt_set_gpio_mode(GPIO_SPI_MISO_PIN, GPIO_SPI_MISO_PIN_M_SPI_MIA);
mt_set_gpio_pull_enable(GPIO_SPI_MISO_PIN, GPIO_PULL_ENABLE);
mt_set_gpio_pull_select(GPIO_SPI_MISO_PIN, GPIO_PULL_UP);
mt_set_gpio_mode(GPIO_SPI_MOSI_PIN, GPIO_SPI_MOSI_PIN_M_SPI_MOA);
mt_set_gpio_pull_enable(GPIO_SPI_MOSI_PIN, GPIO_PULL_ENABLE);
mt_set_gpio_pull_select(GPIO_SPI_MOSI_PIN, GPIO_PULL_UP);
}
static int my_probe(struct platform_device *pdev)
{
int ret = 0;
struct device *xxxx_dev;
my_spi_dbg(" ---------------my_probe, MAJOR = %d\n", xxxx_DEV_MAJOR);
// 1. register character device
ret = register_chrdev(xxxx_DEV_MAJOR, xxxx_DEV_NAME, &xxxx_fops);
if(ret)
{
my_spi_err(" register_chrdev(my_DEV) failed\n");
goto error;
}
// 2. class create
xxxx_class = class_create(THIS_MODULE, xxxx_DEV_NAME);
if(IS_ERR(xxxx_class))
{
my_spi_err(" class create failed\n");
goto error;
}
// 3. device create
xxxx_dev = device_create(xxxx_class, NULL, MKDEV(xxxx_DEV_MAJOR, xxxx_DEV_MINOR), NULL, xxxx_DEV_NAME);
if (my_create_attr(xxxx_dev))
{
class_destroy(xxxx_class);
goto error;
}
xxxx_gpio_init();
return 0;
error:
if (ret == 0)
{
unregister_chrdev(xxxx_DEV_MAJOR, xxxx_DEV_NAME);
}
return -1;
}
static int my_remove(struct platform_device *pdev)
{
return 0;
}
static int my_suspend(struct platform_device *pdev, pm_message_t mesg)
{
return 0;
}
static int my_resume(struct platform_device *pdev)
{
return 0;
}
static int xxxx_spi_probe(struct spi_device *spi)
{
int retval = 0;
my_spi_dbg(" ------------------xxxx_spi_probe\n");
xxxx_spi = spi;
xxxx_spi->mode = (SPI_MODE_0) ;
xxxx_spi->bits_per_word = 8 ;
retval = spi_setup( xxxx_spi );
if( retval != 0 ) {
my_spi_err( "spi_setup xxxx_spi ERROR : \n");
}
else {
my_spi_dbg( "Done : %d\n", retval );
}
return 0;
}
static int xxxx_spi_remove(struct spi_device *spi)
{
return 0;
}
struct platform_device my_device = {
.name = "xxxx",
.id = -1,
};
static struct platform_driver my_driver = {
.probe = my_probe,
.remove = my_remove,
.suspend = my_suspend,
.resume = my_resume,
.driver = {
.name = "xxxx"
},
};
static struct spi_driver xxxx_spi_driver = {
.driver = {
.name = "xxxxspi",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = xxxx_spi_probe,
.remove = xxxx_spi_remove,
};
static const char banner[] __initdata = "xxxx SPI Driver Version 1.0\n";
static struct spi_board_info spi_board_info[] = {
{
.modalias = "xxxxspi",
.bus_num = 0,
.max_speed_hz = 10*1000*1000,
.chip_select = 0,
.mode = SPI_MODE_0,
.controller_data = (void*)&spi_xxxx_conf,
},
};
static int __init my_spi_init(void)
{
int result = 0;
my_spi_dbg(" ----------------my_spi_init\n");
result = platform_device_register(&my_device);
if(result)
{
return result;
}
my_spi_dbg(" platform_device_register, success \n");
result = platform_driver_register(&my_driver);
if(result)
{
return result;
}
spi_register_board_info(spi_board_info,ARRAY_SIZE(spi_board_info));
result = spi_register_driver( &xxxx_spi_driver );
if( result < 0 )
{
my_spi_err( "spi_register_driver ERROR\n" );
return result;
}
xxxx_gpio_interrupt_reg();
xxxx_thread = kthread_run(xxxx_interrupt_proc, 0, "xxxx");
if (IS_ERR(xxxx_thread))
{
result = PTR_ERR(xxxx_thread);
my_spi_err("------------------failed to create kernel thread: \n");
return result;
}
sema_init(&xxxx_sem, 1);
conn_state_flag = 1;
my_spi_dbg(" my_spi_init, success \n");
return result;
}
static void __exit my_spi_exit(void)
{
my_spi_dbg("my_spi_exit \n");
unregister_chrdev(xxxx_DEV_MAJOR, xxxx_DEV_NAME);
device_destroy(xxxx_class, MKDEV(xxxx_DEV_MAJOR, xxxx_DEV_MINOR));
class_destroy(xxxx_class);
platform_driver_unregister(&my_driver);
spi_unregister_driver( &xxxx_spi_driver );
}
module_init(my_spi_init);
module_exit(my_spi_exit);
MODULE_LICENSE("Dual BSD/GPL");