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 <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_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<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 data mdelay(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 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("<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; #endif my_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 device ret = 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 create xxxx_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 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> ----------------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");