MTK SPI总线简单介绍及驱动示例

SPI总线由Motorola公司推出的同步串行总线,全双工工作模式,用于CPU与各种外围器件进行全双工、同步串行通讯。硬件由SCLKMOSIMISOSS/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");




你可能感兴趣的:(work)