SPI的模拟驱动

 

#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;
}

希望,对大家有帮助,通过我的测试没有问题,大家在调试的过程可以与我沟通!

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值