/********************************************
*说明:本实验是针对tiny6410的SPI驱动程序 *
* 简单读取操作 *
*内核选取:linux-2.6.38 *
*硬件要求:SPI1 MISO和MOSI互联 *
*写作时间:2014/6/10 *
*编辑作者:gflytu@163.com *
********************************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <plat/regs-timer.h>
#include <plat/regs-adc.h>
#define SPI_NAME "tiny6410_spi1"
static int SPI_MAJOR= 55;
//static int spi_major=0;//主设备号为0表示动态分配主设备号,自定义次设备号。MKDEV()表示主次合并为设备号
struct spi_dev
{
struct cdev cdev;
char dataTx[4];
char dataRx[4];
};
struct spi_dev *spi_devp;
static void __iomem *base_addr0;
static void __iomem *base_addr1;
static void __iomem *base_addr2;
static void __iomem *base_addr3;
//IO 物理地址
#define S3C6410_PCLK 0x7e00f034
#define S3C6410_SCLK 0x7e00f038
#define S3C6410_GPC 0x7f008040
#define S3C6410_SPI 0x7f00c000
//S3C6410_CLKCON 部分
#define SPI_PCLK (*(volatile unsigned long *)(base_addr0 + 0x00))
#define SPI_SCLK (*(volatile unsigned long *)(base_addr1 + 0x00))
//GPC 控制寄存器部分
//GPC 11、12、13 脚分别对应SPI的MISO、MOSI、CLK 端口
#define GPCCON (*(volatile unsigned long *)(base_addr2 + 0x00))
#define GPCDAT (*(volatile unsigned long *)(base_addr2 + 0x04))
#define GPCUP (*(volatile unsigned long *)(base_addr2 + 0x08))
//SPI 控制寄存器部分
#define CH_CFG (*(volatile unsigned long *)(base_addr3 + 0x00))
#define CLK_CFG (*(volatile unsigned long *)(base_addr3 + 0x04))
#define MODE_CFG (*(volatile unsigned long *)(base_addr3 + 0x08))
#define SLAVE_SEL (*(volatile unsigned long *)(base_addr3 + 0x0c))
#define SPI_INT_EN (*(volatile unsigned long *)(base_addr3 + 0x10))
#define SPI_STATUS (*(volatile unsigned long *)(base_addr3 + 0x14))
#define SPI_TX_DATA (*(volatile unsigned long *)(base_addr3 + 0x18))
#define SPI_RX_DATA (*(volatile unsigned long *)(base_addr3 + 0x1c))
#define PACKET_CNT (*(volatile unsigned long *)(base_addr3 + 0x20))
#define SWAP_CONFIG (*(volatile unsigned long *)(base_addr3 + 0x28))
//打开SPI RX TX 通道
#define SPI_TXRX_ON() (CH_CFG |= 0x3)
#define SPI_TXRX_OFF() (CH_CFG &= ~0x3)
//SPI 输入输出的判忙状态引脚
//#define SPI_TX_READY (((SPI_STATUS) & 0x1) == 0x1)
//#define SPI_RX_READY (((SPI_STATUS >> 1) & 0x1) == 0x1)
#define SPI_TX_DONE (((SPI_STATUS >> 21) & 0x1) == 0x1)
#define SPI_CS_LOW() (SLAVE_SEL &= ~0x01) //有效选择
#define SPI_CS_HIGH() (SLAVE_SEL |= 0x01) //无效选择
/********************************************************/
static void delay(unsigned int i)
{
volatile unsigned int x = 0;
for(; x < i; x++);
}
static void spi_init_function(void)
{
//使能GPC 11、12、13对应的 MISO0,MOSI0,SCK0 = 11 0x0000FC00*/
GPCCON &= ~((7 << 16) | (7 << 20) | (7 << 24) | (7 << 28));
GPCCON |= ((2 << 16) | (2 << 20) | (2 << 24) | (2 << 28));
//GPCUP 设置;全部disable
GPCUP &= ~(0xff << 0);
//GPCDAT 设置位0
GPCDAT &= ~(0xff << 0);
//使能时钟控制寄存器CLKCON 21位使能SPI0
SPI_PCLK |= (1 << 22);
SPI_SCLK |= (1 << 21);
printk("s3c6410_pclk=%08lu\n",SPI_PCLK);
printk("s3c6410_sclk=%08lu\n",SPI_SCLK);
/*SPI 寄存器部分*/
//高速模式关闭 选择主控 以及传递方式
CH_CFG = ((0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2));
//设置PCLK模式 enable CLK 以及频率设置
CLK_CFG = ((0 << 9) | (1 << 8) | (0x20 << 0));
//
MODE_CFG = ((0 << 29) | (0 << 19) | (0 << 17) | (1 << 11) | (1 << 5)
| (0 << 2) | (0 << 1) | (0 << 0));
SLAVE_SEL = (0x01);
SPI_INT_EN = (0x00);
PACKET_CNT = (1 << 16);
//SWAP_CONFIG = ((0 << 4) | (1 << 5) | (0 << 0) | (1 << 1));
}
static int spi_open(struct inode *inode,struct file *filp)
{
filp->private_data=spi_devp;
spi_init_function();
//SPI_TXRX_ON();
printk("-----------------------------------\n");
printk("tiny6410 SPI Init over!\n");
printk("-----------------------------------\n");
return 0;
}
static int spi_release(struct inode *inode,struct file *filp)
{
//释放掉在写函数操作里面申请的缓存空间
printk("SPI1 release OK!\n");
return 0;
}
#if 1
//向SPI寄存器SPI_SPTDAT1中写数据
static void writeByte(const char data)
{
volatile int j = 0;
//printk("write data is %c\n",data);
SPI_TX_DATA = data;
while(!SPI_TX_DONE);
//for(j = 0; j < 0xff; j++);
}
//从SPI寄存器SPI_SPRDAT1中读取数据
static char readByte(void)
{
char ch = 0;
ch = SPI_RX_DATA;
return ch;
}
static void write_buffer(const char *datatx,char *datarx, int count)
{
int i;
struct spi_dev *dev;
//启动SPI的TX RX通道
SPI_TXRX_ON();
SPI_CS_LOW();
delay(100);
//writeByte(reg);
//从info中读取数据
for(i=0; i < count; i++){
writeByte(datatx[i]);
delay(1000);
datarx[i]=readByte();
printk("receive data %d is %c\n",i,datarx[i]);
delay(1000);
}
//关掉SPI的通道
SPI_CS_HIGH();
SPI_TXRX_OFF();
}
static void clear_info(void)
{
int count = 0;
int i = 0;
count =(SPI_STATUS >> 13) & 0x7f;
printk("In clear_info RX_INFO_SIZE is:%d\n",count);
//释放掉无关的数据
for(i = 0; i < count; i++)
printk("clear info %d is:%02X\n", i, readByte());
}
#endif
//接收数据并把数据发送到应用空间
static ssize_t spi_read(struct file *filp,char __user *buf,size_t count)
{
struct spi_dev *dev=filp->private_data;
/*volatile char spiRxData[4];
int i;
for(i=0;i<4;i++)
{
if((SPI_INT_EN>>1)&0x1)
dev->dataRx[i]=readByte();
spiRxData[i]=dev->dataRx[i];
printk("read data %d is %c\n",i,dev->dataRx[i]);
}*/
copy_to_user(buf,dev->dataRx,count);
return 0;/* struct spi_dev *dev=filp->private_data;
int i;
int count1=0;
//启动SPI的TX RX通道
SPI_TXRX_ON();
SPI_CS_LOW();
//delay(5000);
clear_info();
count1 =(PACKET_CNT) & 0xff;
printk("RX_INFO_SIZE is:%d\n",count1);
if(count1) {
//从RX_INFO寄存器中读取数据
for(i = 0; i < 4; i++) {
dev->dataRx[i] = readByte();
//data = (data << 8) +(unsigned long)save_data;
printk("dev->dataRx=%02X\n",dev->dataRx[i]);
}
}else {
count1 = 0;
}
copy_to_user(buf,dev->dataRx,count);
//关掉SPI的通道
SPI_CS_HIGH();
SPI_TXRX_OFF();
return 0; */
}
//发送数据并把数据从用户空间发送到内核
static ssize_t spi_write(struct file *filp,const char __user *buf,
size_t count)
{
volatile int endSpiTx=0;
//volatile char spiTxData[4];
//int config;
int i=0;
//volatile char *spiTxStr,*spiRxStr;
unsigned char string;
//unsigned int port_status;
struct spi_dev *dev=filp->private_data;
//filp->private_data;
//获得设备结构体的指针
copy_from_user(dev->dataTx,buf,count);
write_buffer(dev->dataTx,dev->dataRx,count);
printk("receive form user is %s\n",dev->dataTx);
return 0;
}
static const struct file_operations spi_fops =
{
.owner = THIS_MODULE,
.open = spi_open,
.read = spi_read,
.release = spi_release,
.write = spi_write,
};
static void spi_setup_cdev(struct spi_dev *dev,int index)
{
int err,devno=MKDEV(SPI_MAJOR,index);
cdev_init(&dev->cdev,&spi_fops);
//cdev_init(&spi_dev,&spi_fops);
dev->cdev.owner=THIS_MODULE;
dev->cdev.ops=&spi_fops;
err=cdev_add(&dev->cdev,devno,1);
if(err)
printk("error\n");
printk("-----------------------------------\n");
}
static int __init spi_init(void)
{
int ret;
//映射时钟控制寄存器CLKCON
if((base_addr0 = ioremap(S3C6410_PCLK, 0x04)) == NULL){
printk(" base_addr0 ioremap failed\n");
return -1;
}
//映射部分
if((base_addr1 = ioremap(S3C6410_SCLK, 0x04)) == NULL){
printk(" base_addr1 ioremap failed\n");
return -1;
}
//映射GPC 寄存器地址
if((base_addr2 = ioremap(S3C6410_GPC, 0x10)) == NULL){
printk(" base_addr2 ioremap failed\n");
return -1;
}
//映射SPI 寄存器地址
if((base_addr3 = ioremap(S3C6410_SPI, 0x30)) == NULL){
printk(" base_addr3 ioremap failed\n");
return -1;
}
dev_t devno=MKDEV(SPI_MAJOR,0);
if(SPI_MAJOR)//申请设备号
ret=register_chrdev_region(devno,1,SPI_NAME);
else //动态申请设备号
{
ret=alloc_chrdev_region(&devno,0,1,SPI_NAME);
SPI_MAJOR=MAJOR(devno);
}
if(ret<0)
return ret;
//动态申请设备结构体内存
spi_devp=kmalloc(sizeof(struct spi_dev),GFP_KERNEL);
if(!spi_devp)//申请失败
{
ret=-ENOMEM;
goto fail_malloc;
}
memset(spi_devp,0,sizeof(struct spi_dev));
spi_setup_cdev(spi_devp,0);
printk("init spi success!\n");
return 0;
fail_malloc:
unregister_chrdev_region(devno,1);
return ret;
}
static void __exit spi_exit(void)
{
unregister_chrdev(SPI_MAJOR,SPI_NAME);
}
module_init(spi_init);
module_exit(spi_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("GFLYTU");
MODULE_DESCRIPTION("SPI_DRIVRE");
*说明:本实验是针对tiny6410的SPI驱动程序 *
* 简单读取操作 *
*内核选取:linux-2.6.38 *
*硬件要求:SPI1 MISO和MOSI互联 *
*写作时间:2014/6/10 *
*编辑作者:gflytu@163.com *
********************************************/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/serio.h>
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/wait.h>
#include <linux/sched.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
#include <mach/map.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
#include <plat/regs-timer.h>
#include <plat/regs-adc.h>
#define SPI_NAME "tiny6410_spi1"
static int SPI_MAJOR= 55;
//static int spi_major=0;//主设备号为0表示动态分配主设备号,自定义次设备号。MKDEV()表示主次合并为设备号
struct spi_dev
{
struct cdev cdev;
char dataTx[4];
char dataRx[4];
};
struct spi_dev *spi_devp;
static void __iomem *base_addr0;
static void __iomem *base_addr1;
static void __iomem *base_addr2;
static void __iomem *base_addr3;
//IO 物理地址
#define S3C6410_PCLK 0x7e00f034
#define S3C6410_SCLK 0x7e00f038
#define S3C6410_GPC 0x7f008040
#define S3C6410_SPI 0x7f00c000
//S3C6410_CLKCON 部分
#define SPI_PCLK (*(volatile unsigned long *)(base_addr0 + 0x00))
#define SPI_SCLK (*(volatile unsigned long *)(base_addr1 + 0x00))
//GPC 控制寄存器部分
//GPC 11、12、13 脚分别对应SPI的MISO、MOSI、CLK 端口
#define GPCCON (*(volatile unsigned long *)(base_addr2 + 0x00))
#define GPCDAT (*(volatile unsigned long *)(base_addr2 + 0x04))
#define GPCUP (*(volatile unsigned long *)(base_addr2 + 0x08))
//SPI 控制寄存器部分
#define CH_CFG (*(volatile unsigned long *)(base_addr3 + 0x00))
#define CLK_CFG (*(volatile unsigned long *)(base_addr3 + 0x04))
#define MODE_CFG (*(volatile unsigned long *)(base_addr3 + 0x08))
#define SLAVE_SEL (*(volatile unsigned long *)(base_addr3 + 0x0c))
#define SPI_INT_EN (*(volatile unsigned long *)(base_addr3 + 0x10))
#define SPI_STATUS (*(volatile unsigned long *)(base_addr3 + 0x14))
#define SPI_TX_DATA (*(volatile unsigned long *)(base_addr3 + 0x18))
#define SPI_RX_DATA (*(volatile unsigned long *)(base_addr3 + 0x1c))
#define PACKET_CNT (*(volatile unsigned long *)(base_addr3 + 0x20))
#define SWAP_CONFIG (*(volatile unsigned long *)(base_addr3 + 0x28))
//打开SPI RX TX 通道
#define SPI_TXRX_ON() (CH_CFG |= 0x3)
#define SPI_TXRX_OFF() (CH_CFG &= ~0x3)
//SPI 输入输出的判忙状态引脚
//#define SPI_TX_READY (((SPI_STATUS) & 0x1) == 0x1)
//#define SPI_RX_READY (((SPI_STATUS >> 1) & 0x1) == 0x1)
#define SPI_TX_DONE (((SPI_STATUS >> 21) & 0x1) == 0x1)
#define SPI_CS_LOW() (SLAVE_SEL &= ~0x01) //有效选择
#define SPI_CS_HIGH() (SLAVE_SEL |= 0x01) //无效选择
/********************************************************/
static void delay(unsigned int i)
{
volatile unsigned int x = 0;
for(; x < i; x++);
}
static void spi_init_function(void)
{
//使能GPC 11、12、13对应的 MISO0,MOSI0,SCK0 = 11 0x0000FC00*/
GPCCON &= ~((7 << 16) | (7 << 20) | (7 << 24) | (7 << 28));
GPCCON |= ((2 << 16) | (2 << 20) | (2 << 24) | (2 << 28));
//GPCUP 设置;全部disable
GPCUP &= ~(0xff << 0);
//GPCDAT 设置位0
GPCDAT &= ~(0xff << 0);
//使能时钟控制寄存器CLKCON 21位使能SPI0
SPI_PCLK |= (1 << 22);
SPI_SCLK |= (1 << 21);
printk("s3c6410_pclk=%08lu\n",SPI_PCLK);
printk("s3c6410_sclk=%08lu\n",SPI_SCLK);
/*SPI 寄存器部分*/
//高速模式关闭 选择主控 以及传递方式
CH_CFG = ((0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2));
//设置PCLK模式 enable CLK 以及频率设置
CLK_CFG = ((0 << 9) | (1 << 8) | (0x20 << 0));
//
MODE_CFG = ((0 << 29) | (0 << 19) | (0 << 17) | (1 << 11) | (1 << 5)
| (0 << 2) | (0 << 1) | (0 << 0));
SLAVE_SEL = (0x01);
SPI_INT_EN = (0x00);
PACKET_CNT = (1 << 16);
//SWAP_CONFIG = ((0 << 4) | (1 << 5) | (0 << 0) | (1 << 1));
}
static int spi_open(struct inode *inode,struct file *filp)
{
filp->private_data=spi_devp;
spi_init_function();
//SPI_TXRX_ON();
printk("-----------------------------------\n");
printk("tiny6410 SPI Init over!\n");
printk("-----------------------------------\n");
return 0;
}
static int spi_release(struct inode *inode,struct file *filp)
{
//释放掉在写函数操作里面申请的缓存空间
printk("SPI1 release OK!\n");
return 0;
}
#if 1
//向SPI寄存器SPI_SPTDAT1中写数据
static void writeByte(const char data)
{
volatile int j = 0;
//printk("write data is %c\n",data);
SPI_TX_DATA = data;
while(!SPI_TX_DONE);
//for(j = 0; j < 0xff; j++);
}
//从SPI寄存器SPI_SPRDAT1中读取数据
static char readByte(void)
{
char ch = 0;
ch = SPI_RX_DATA;
return ch;
}
static void write_buffer(const char *datatx,char *datarx, int count)
{
int i;
struct spi_dev *dev;
//启动SPI的TX RX通道
SPI_TXRX_ON();
SPI_CS_LOW();
delay(100);
//writeByte(reg);
//从info中读取数据
for(i=0; i < count; i++){
writeByte(datatx[i]);
delay(1000);
datarx[i]=readByte();
printk("receive data %d is %c\n",i,datarx[i]);
delay(1000);
}
//关掉SPI的通道
SPI_CS_HIGH();
SPI_TXRX_OFF();
}
static void clear_info(void)
{
int count = 0;
int i = 0;
count =(SPI_STATUS >> 13) & 0x7f;
printk("In clear_info RX_INFO_SIZE is:%d\n",count);
//释放掉无关的数据
for(i = 0; i < count; i++)
printk("clear info %d is:%02X\n", i, readByte());
}
#endif
//接收数据并把数据发送到应用空间
static ssize_t spi_read(struct file *filp,char __user *buf,size_t count)
{
struct spi_dev *dev=filp->private_data;
/*volatile char spiRxData[4];
int i;
for(i=0;i<4;i++)
{
if((SPI_INT_EN>>1)&0x1)
dev->dataRx[i]=readByte();
spiRxData[i]=dev->dataRx[i];
printk("read data %d is %c\n",i,dev->dataRx[i]);
}*/
copy_to_user(buf,dev->dataRx,count);
return 0;/* struct spi_dev *dev=filp->private_data;
int i;
int count1=0;
//启动SPI的TX RX通道
SPI_TXRX_ON();
SPI_CS_LOW();
//delay(5000);
clear_info();
count1 =(PACKET_CNT) & 0xff;
printk("RX_INFO_SIZE is:%d\n",count1);
if(count1) {
//从RX_INFO寄存器中读取数据
for(i = 0; i < 4; i++) {
dev->dataRx[i] = readByte();
//data = (data << 8) +(unsigned long)save_data;
printk("dev->dataRx=%02X\n",dev->dataRx[i]);
}
}else {
count1 = 0;
}
copy_to_user(buf,dev->dataRx,count);
//关掉SPI的通道
SPI_CS_HIGH();
SPI_TXRX_OFF();
return 0; */
}
//发送数据并把数据从用户空间发送到内核
static ssize_t spi_write(struct file *filp,const char __user *buf,
size_t count)
{
volatile int endSpiTx=0;
//volatile char spiTxData[4];
//int config;
int i=0;
//volatile char *spiTxStr,*spiRxStr;
unsigned char string;
//unsigned int port_status;
struct spi_dev *dev=filp->private_data;
//filp->private_data;
//获得设备结构体的指针
copy_from_user(dev->dataTx,buf,count);
write_buffer(dev->dataTx,dev->dataRx,count);
printk("receive form user is %s\n",dev->dataTx);
return 0;
}
static const struct file_operations spi_fops =
{
.owner = THIS_MODULE,
.open = spi_open,
.read = spi_read,
.release = spi_release,
.write = spi_write,
};
static void spi_setup_cdev(struct spi_dev *dev,int index)
{
int err,devno=MKDEV(SPI_MAJOR,index);
cdev_init(&dev->cdev,&spi_fops);
//cdev_init(&spi_dev,&spi_fops);
dev->cdev.owner=THIS_MODULE;
dev->cdev.ops=&spi_fops;
err=cdev_add(&dev->cdev,devno,1);
if(err)
printk("error\n");
printk("-----------------------------------\n");
}
static int __init spi_init(void)
{
int ret;
//映射时钟控制寄存器CLKCON
if((base_addr0 = ioremap(S3C6410_PCLK, 0x04)) == NULL){
printk(" base_addr0 ioremap failed\n");
return -1;
}
//映射部分
if((base_addr1 = ioremap(S3C6410_SCLK, 0x04)) == NULL){
printk(" base_addr1 ioremap failed\n");
return -1;
}
//映射GPC 寄存器地址
if((base_addr2 = ioremap(S3C6410_GPC, 0x10)) == NULL){
printk(" base_addr2 ioremap failed\n");
return -1;
}
//映射SPI 寄存器地址
if((base_addr3 = ioremap(S3C6410_SPI, 0x30)) == NULL){
printk(" base_addr3 ioremap failed\n");
return -1;
}
dev_t devno=MKDEV(SPI_MAJOR,0);
if(SPI_MAJOR)//申请设备号
ret=register_chrdev_region(devno,1,SPI_NAME);
else //动态申请设备号
{
ret=alloc_chrdev_region(&devno,0,1,SPI_NAME);
SPI_MAJOR=MAJOR(devno);
}
if(ret<0)
return ret;
//动态申请设备结构体内存
spi_devp=kmalloc(sizeof(struct spi_dev),GFP_KERNEL);
if(!spi_devp)//申请失败
{
ret=-ENOMEM;
goto fail_malloc;
}
memset(spi_devp,0,sizeof(struct spi_dev));
spi_setup_cdev(spi_devp,0);
printk("init spi success!\n");
return 0;
fail_malloc:
unregister_chrdev_region(devno,1);
return ret;
}
static void __exit spi_exit(void)
{
unregister_chrdev(SPI_MAJOR,SPI_NAME);
}
module_init(spi_init);
module_exit(spi_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("GFLYTU");
MODULE_DESCRIPTION("SPI_DRIVRE");