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

来源:互联网 发布:gre知乎 编辑:程序博客网 时间:2024/06/06 03:39

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 dljinitial*******************************************************************************/#ifndef __my_SPI_H__#define __my_SPI_H__#ifdef __cplusplusextern "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_MAJOR227#define xxxx_DEV_MINOR0#define xxxx_DEV_NAME"ttySPI"#define SPI_FIFO_BATYE_PER_TIMES 32typedef 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 dljinitial*******************************************************************************/#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#include <linux/irq.h>#include <linux/wait.h>#include <linux/stat.h>#include <linux/ioctl.h>#include <linux/delay.h>#include <linux/slab.h>#include <linux/device.h>#include <linux/platform_device.h>#include <linux/vmalloc.h>#include <linux/io.h>#include <mach/board.h>#include <linux/gpio.h>#include "mach/mt_gpio.h"#include <mach/mt_gpt.h>#include <mach/mt_pm_ldo.h>#include <mach/mt_typedefs.h>#include <mach/upmu_common.h>#include <mach/upmu_hw.h>#include <mach/mt_spi.h>#include <net/sock.h>#include <net/netlink.h>#include <cust_eint.h>#include <cust_eint_md1.h>#include <linux/spi/spi.h>#include <linux/mutex.h>#include <linux/poll.h>#include <linux/sched.h>#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_transfertransfer;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<len; i++){my_spi_dbg("0x%x  ",(int)buf[i]);}my_spi_dbg("\n");return status;}unsigned char SPI_opt_func(unsigned char *buffer, size_t count, int flag){int i = 0;size_t times = 0;unsigned char ret = 1;size_t left = 0;times = count/SPI_FIFO_BATYE_PER_TIMES;for(i=0; i<times; i++){ret = xxxx_spi_op(&buffer[i*SPI_FIFO_BATYE_PER_TIMES], SPI_FIFO_BATYE_PER_TIMES, flag);if(ret){return ret;}}if(count % SPI_FIFO_BATYE_PER_TIMES != 0){left = count - times*SPI_FIFO_BATYE_PER_TIMES;}ret = xxxx_spi_op(&buffer[times*SPI_FIFO_BATYE_PER_TIMES], left, flag);return ret;}unsigned char RFSendPacket(unsigned char *txBuffer, size_t BuffLen){unsigned char ret;ret = SPI_opt_func(txBuffer, BuffLen, SPI_SEND); // Write TX datamdelay(5);return ret;}static int xxxx_open(struct inode *inode, struct file *filp){return 0;}static int xxxx_release(struct inode *inode, struct file *filp){return 0;}static ssize_t xxxx_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos){unsigned char *recv_buf = NULL;size_t data_len = 0;wait_event_interruptible(read_waiter, xxxx_read_flag != 0);xxxx_read_flag = 0;data_len = RFReceivePacket(&recv_buf, pkt_len);up(&xxxx_sem);if(data_len > 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("<xxxx>------------------------ %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 pktif(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 0int ret = 0;    my_spi_dbg("<xxxx>------------------------ %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;#endifmy_spi_dbg("<xxxx>------------------------ %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("<xxxx> mt_set_gpio_dir failed\n");return;}if(mt_set_gpio_pull_enable(GPIO_xxxx_EINT_PIN, GPIO_PULL_ENABLE)!=0){my_spi_dbg("<xxxx> 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("<xxxx> 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> ---------------my_probe, MAJOR = %d\n", xxxx_DEV_MAJOR);// 1. register character deviceret = register_chrdev(xxxx_DEV_MAJOR, xxxx_DEV_NAME, &xxxx_fops);if(ret){my_spi_err("<my> register_chrdev(my_DEV) failed\n");goto error;}// 2. class createxxxx_class = class_create(THIS_MODULE, xxxx_DEV_NAME);if(IS_ERR(xxxx_class)){my_spi_err("<my> class create failed\n");goto error;}// 3. device createxxxx_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> ----------------my_spi_init\n");result = platform_device_register(&my_device);if(result){return result;}my_spi_dbg("<my> 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> 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");



2 1
原创粉丝点击