#include <linux/mm.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/rtc.h> /* get the user-level API */
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/delay.h>
#include <linux/kdev_t.h>
#include <linux/types.h>
#include <linux/cdev.h>
#include <linux/platform_device.h>
#include <linux/version.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/moduleparam.h>
#include <linux/errno.h>
#include <linux/ioctl.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/mutex.h>
#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/pci.h>
#include <linux/input.h>
#include <asm/atomic.h>
#include <asm/unistd.h>
#include <asm/uaccess.h>
#include <asm/mach/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/leds.h>
#include <asm/mach-types.h>
#include <mach/at91_pio.h>
#include <mach/gpio.h>
#include <mach/hardware.h>
#include <mach/hardware.h>
//boy
/* Read / Write of SPI mode (SPI_MODE_0..SPI_MODE_3) */
#define SPI_READ_MODE _IOR('D', 1, long)
#define SPI_WRITE_MODE _IOW('D', 1, long)
#define SPI_IOC_RD_LSB_FIRST _IOR('D', 2, int)
#define SPI_IOC_WR_LSB_FIRST _IOW('D', 2, int)
/*
通过测试成功 AT91 的开发板 内核是2.6.27
*/
#define DEVICE_NAME "spi" /* 加载模式后,执行”cat /proc/devices”命令看到的设备名称 */
#define SPI_MAJOR 231 /* */
///
#define SPI_CLK_H (at91_set_gpio_value(AT91_PIN_PA2, 1))
#define SPI_CLK_L (at91_set_gpio_value(AT91_PIN_PA2, 0))
#define SPI_MOSI_H (at91_set_gpio_value(AT91_PIN_PA1, 1))
#define SPI_MOSI_L (at91_set_gpio_value(AT91_PIN_PA1, 0))
///
/*
struct spi_dev
{
struct class_device *class_dev;
struct class *class;
struct cdev cdev;
};
*/
static void __iomem *pio_base;
void spi_delay(int num)
{
int i;
while(num--)
{
for(i = 0;i<100;i++);
}
}
int SpiWrite(unsigned char data)
{
int i;
unsigned char datat;
datat = data;
unsigned char mask[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
//printk(KERN_INFO "DATA = 0x%02X\n",datat);//3 8 boy
for(i=7; i >= 0; i--)
{
SPI_CLK_L; /*把clock线拉低,模拟一个时钟*/
if((data & mask[i]) >> i) /*把数据送上DATA线*/
SPI_MOSI_H;
else
SPI_MOSI_L;
测试把MOSI于MISO连接在一起可以进行测试,要注意因为写的东西没有保存所以读和写要在一个函数里面就可以了//
//if((readl(pio_base + PIO_PDSR) & mask[i]) >> i)//把数据送上DATA线 ?读寄存器是不行的,不知道原因
/*if(at91_get_gpio_value(AT91_PIN_PA0)==1)
{
printk(DEVICE_NAME " PA0=1\n");
}
else
{
printk(DEVICE_NAME " PA0=0\n");
}
*/
测试读数据
spi_delay(10); /*等待适当的时间,以等待数据稳定*/
SPI_CLK_H; /*拉高clock线,让设备端接收数据*/
spi_delay(10);
}
//printk(DEVICE_NAME " spiwrite\n");
return 1;
}
int SpiRead(unsigned char *data)
{
int i;
unsigned char dataa=0x29;
unsigned char mask[] = {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
for(i=7; i >= 0; i--)
{
SPI_CLK_L; //把clock线拉低,模拟一个时钟
//if((readl(pio_base + PIO_PDSR) & mask[i]) >> i)//把数据送上DATA线 ?读寄存器是不行的,不知道原因,有机会研究
if(at91_get_gpio_value(AT91_PIN_PA0)==1)//读I/O就可以了 真他妈的搞不懂
{
*data |= 0x1<<i;
printk(DEVICE_NAME " PA0=1\n");
}
else
{
*data &= ~(0x1<<i);
printk(DEVICE_NAME " PA0=0\n");
}
spi_delay(10); //等待适当的时间,以等待数据稳定
SPI_CLK_H; //拉高clock线,让设备端接收数据
spi_delay(10);
}
//printk(DEVICE_NAME " spiread\n");
return 1;
}
static int spi_open(struct inode *inode, struct file *file)
{
printk(DEVICE_NAME " S5PC100_LEDS_OPEN \n");
at91_set_A_periph(AT91_PIN_PA0, 1); /* SPI0_MISO */
at91_set_A_periph(AT91_PIN_PA1, 1); /* SPI0_MOSI */
at91_set_A_periph(AT91_PIN_PA2, 1); /* SPI1_SPCK */
at91_set_gpio_output(AT91_PIN_PA2, 1); /* I/O 口设置*/
at91_set_deglitch(AT91_PIN_PA2, 1);
at91_set_gpio_output(AT91_PIN_PA1, 1); /* I/O 口设置*/
at91_set_deglitch(AT91_PIN_PA1, 1);
at91_set_gpio_input(AT91_PIN_PA0, 1); /* I/O 口设置*/
at91_set_deglitch(AT91_PIN_PA1, 1);
//at91_set_gpio_value(AT91_PIN_PA0, 1); /*设置为0 */
//writel(0x00000040, pio_base + PIO_PER); //PIO的使能寄存器 表示向该寄存器写入0x00000040的数据
//writel(0x00000040, pio_base + PIO_PUER); //pull—up 使能寄存器 表示向该寄存器写入0x00000040的数据
//writel(0x00000040, pio_base + PIO_OER); //输出使能寄存器 表示向该寄存器写入0x00000040的数据
pio_base = ioremap(0xFFFFF400,512); //PIOA开始的地址 以及空间512字节
//#define SPI_MISO_DATA (pio_base + PIO_PDSR)
printk(DEVICE_NAME " LEDS_OPEN_END\n");
return 0;
}
static int spi_write(struct file *file, const char __user *buf, size_t count)
{
int i;
unsigned char missing;
unsigned char *buffer;
ssize_t status = 0;
printk(KERN_INFO "Spi_write\n");
buffer = kmalloc(count*sizeof(char), GFP_KERNEL);
missing=copy_from_user(buffer,buf, count);
if(missing != 0) status = -EFAULT;
printk(KERN_INFO "count =%d\n",count);
for(i=0;i<count;i++)
{
SpiWrite(*buffer++);
}
printk(KERN_INFO "Spi_write\n");
//kfree(buffer);
// printk(KERN_INFO "readl(pio_base + PIO_PDSR) = 0x%02X\n",(unsigned char)(readl(pio_base + PIO_PDSR)));
return status;
}
static int spi_read(struct file *file, const char __user *buf, size_t count)
{
int i;
unsigned char missing;
unsigned char *buffer;
ssize_t status = 0;
printk(KERN_INFO "Spi_write\n");
buffer = kmalloc(count*sizeof(char), GFP_KERNEL);
for(i=0;i<count;i++)
{
SpiRead(buffer++);
printk(KERN_INFO "DATA = 0x%02X\n",*(--buffer));//3 8 boy
}
missing=copy_to_user(buf,buffer, count);//boy
if(missing != 0) status = -EFAULT;
printk(KERN_INFO "Spi_read\n");
///kfree(buffer);
return status;
}
//应用程序对设备文件/dev/leds执行ioclt(...)时,就会调用s3c2410_leds_ioctl函数
static int spi_ioctl(
struct inode *inode,
struct file *file,
unsigned int cmd,
//const char __user *arg
unsigned long arg)
{
/*unsigned char buffer[10]={0};
int missing = 0;
missing=copy_from_user(buffer,arg, sizeof(arg));
if(missing != 0) return -EFAULT;
*/
// printk(DEVICE_NAME"leds_ioctl\n");
switch(cmd) {
case SPI_READ_MODE:
// 设置指定引脚的输出电平为0
printk(DEVICE_NAME" IOCTL_LED_ON\n");
SPI_MOSI_H;
printk(DEVICE_NAME" LED1_ON\n");
return 0;
break;
case SPI_WRITE_MODE:
printk(DEVICE_NAME" IOCTL_LED_OFF\n");
SPI_MOSI_L;
printk(DEVICE_NAME" LED1_OFF\n");
return 0;
break;
default:
printk(DEVICE_NAME" leds_ioctl_default\n");
return -EINVAL;
return 0;
}
}
static struct file_operations S5PC100_leds_fops = {
.owner = THIS_MODULE,
.open = spi_open,
.ioctl = spi_ioctl,
.read = spi_read,
.write = spi_write,
//.release = adc_release,
};
//struct spi_dev *at91_spi;
static int spi_init(void)
{
printk(DEVICE_NAME "S5PC100_LEDS_INIT\n");
int ret;
ret = register_chrdev(SPI_MAJOR, DEVICE_NAME, &S5PC100_leds_fops);
printk(DEVICE_NAME " S5PC100_LEDS_INIT_END\n");
return ret;
}
static void spi_exit(void)
{
unregister_chrdev(SPI_MAJOR, DEVICE_NAME);
printk(DEVICE_NAME "s5pc100_leds_exit\n");
}
module_init(spi_init);
module_exit(spi_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("luckyboy");
//表示在make menuconfig 里面可以选着
/*****Kconfig****************************
config ATSAM9G20_SPI
tristate "spi"
default m
******************************************/
/****Makeflie*****************************
obj-$(CONFIG_ATSAM9G20_SPI) +=spi.o
******************************************/
该驱动没有动态加载功能
//所以要执行 mknod /dev/spi c 231 0
//表示编译为模块
/****Makeflie*****************************
obj-m +=leds.o
******************************************/
以上是我的spi的模拟驱动,下面是测试代码
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#define SPI_READ_MODE _IOR('D', 1, long)
#define SPI_WRITE_MODE _IOW('D', 1, long)
#define SPI_IOC_RD_LSB_FIRST _IOR('D', 2, int)
#define SPI_IOC_WR_LSB_FIRST _IOW('D', 2, int)
/成功的测试程序/
int main(int argc, char *argv[])
{
int fd,ret,i=0,counter=0;
char TX_buf[1]={0x25};
char RX_buf[5] ={0};
char bits[2] = {0x98,0x99};
//打开/dev/leds0设备文件
fd = open("/dev/spi",O_RDWR);// ceshi led
if(fd <0 )
{
perror("open device spi::");
exit(1);
}
else
printf("open device sucess::\n");
while(counter < 10)
{
if(write(fd,TX_buf,1)<0)
{
perror("write wrong::");
exit(1);
}
if(read(fd,RX_buf,sizeof(TX_buf)/sizeof(TX_buf[0]))<0)
{
perror("read wrong::");
exit(1);
}
//ioctl(fd,SPI_READ_MODE,NULL);
// for(i=0;i<1;i++)
//{
//printf("read byte is: 0x%02X\n",RX_buf[0]);
// }
//ioctl(fd,SPI_WRITE_MODE,NULL);
counter++;
}
if((close(fd)<0))
{
perror("close ");
exit(1);
}
return ret;
}
希望,对大家有帮助,通过我的测试没有问题,大家在调试的过程可以与我沟通!