SPI驱动程序设计

       研究了几天驱动程序设计,终于把程序调通了,现在把一些资料和心得记录如下,当作自己的工作笔记。该程序是基于mini2440开发板的,只是一个简单的基本程序,并没有将所有的东西考虑进去,希望大家谅解。其间参考了很多网络资源,有的部分甚至没有修改,如初始化等,在这一并表示感谢。(有事情,下次再写了,先给出原程序和测试测序)

 

linux的驱动程序设计主要是要填充file_operations结构体,以及设备和程序的注册,具体解释网上很多了,我也有一些资料,但是没办法上传给大家,这里就不细说了,再有现在好像内核的驱动多是基于platform的,本人正在学习,希望能和大家交流。

 

驱动程序:

 

#include <asm/arch/regs-gpio.h>

#include <asm/hardware.h>

#include <linux/kernel.h>

#include <linux/module.h>

#include <linux/init.h>

#include <linux/mm.h>

#include <linux/fs.h>

#include <linux/types.h>

#include <linux/delay.h>

#include <linux/moduleparam.h>

#include <linux/slab.h>

#include <linux/errno.h>

#include <linux/ioctl.h>

#include <linux/cdev.h>

#include <linux/string.h>

#include <linux/list.h>

#include <linux/pci.h>

#include <asm/uaccess.h>

#include <asm/atomic.h>

#include <asm/unistd.h>

#include <asm/io.h>

#include <linux/devfs_fs_kernel.h>

#include <linux/poll.h>

#define DEVICE_NAME "SPI"//设备名

#define SPI_MAJOR 200//主设备号

 

//相关寄存器虚拟地址映射,通过映射,就可以给寄存器直接赋值了

 

//当然内核中提供了很多操作寄存器的内核函数,可以达到同样的功能

 

//这些函数在gpio.c文件中,arch/arm/mach-s3c2410目录下,可能会有差别,可以自己搜索一下

 

//s3c2410_gpio_cfgpin()的作用是规定io口的用途:如作为外部功能模块(10),还是普通输入口(00),还是普通的输

 

//出口(01)s3c2440通常用两位来决定一个端口的功能,具体参见手册。

 

//s3c2410_gpio_pullup()该函数设置是否要内部电阻上拉:0不上拉,1上拉

 

//s3c2410_gpio_setpin()该函数向端口输出数据

 

//s3c2410_gpio_setcfg()读取端口配置

 

//还有功能函数set_gpio_bitclr_gpio_bitset_gpio_ctrlwrite_gpio_bitread_gpio_bit等,网上有很多关于这

 

//些函数的具体用法

 

#define r_clkcon     *(volatile unsigned long *)ioremap(0x4C00000c,4)//相关寄存器虚拟地址映射

 

#define spi_gpgcon   *(volatile unsigned long *)ioremap(0x56000060,4) //端口G控制寄存器

#define spi_gpgdat   *(volatile unsigned long *)ioremap(0x56000064,4)  //端口G的数据寄存器

#define spi_gpgup    *(volatile unsigned long *)ioremap(0x56000068,4) //端口G的上拉电阻控制寄存器

 

#define spi_gpecon   *(volatile unsigned long *)ioremap(0x56000040,4) //端口E

#define spi_gpedat   *(volatile unsigned long *)ioremap(0x56000044,4) 

#define spi_gpeup    *(volatile unsigned long *)ioremap(0x56000048,4)  

                                                                                                                

#define spi_spcon0   *(volatile unsigned long *)ioremap(0x59000000,4)  //spi相关寄存器

#define spi_spsta0   *(volatile unsigned long *)ioremap(0x59000004,4)

#define spi_sppin0   *(volatile unsigned long *)ioremap(0x59000008,4) 

#define spi_sppre0   *(volatile unsigned long *)ioremap(0x5900000c,4) 

#define spi_sptdat0  *(volatile unsigned long *)ioremap(0x59000010,4) 

#define spi_sprdat0  *(volatile unsigned long *)ioremap(0x59000014,4)

 

#define spi_gpbcon   *(volatile unsigned long *)ioremap(0x56000010,4) 

#define spi_gpbdat   *(volatile unsigned long *)ioremap(0x56000014,4) 

#define spi_gpbup    *(volatile unsigned long *)ioremap(0x56000018,4)

 

static  char dataTx[2]="";

static  char dataRx[2]="";

 

 

 

static int s3c2440_spi_close(struct inode *inode,struct file *filp) 

{

 printk("s3c2410-spi closed/n"); 

 return 0; 

}

 

 

 

 

static int s3c2440_spi_open(struct inode *inode,struct file *filp) 

{ int config;

  int value;

  printk("spi open begin../n");

  r_clkcon |= 0x40000;//这句必须最先设置,否则由于spi模块没有时钟,后续的操作都不能实现

  value=(int)r_clkcon;

  printk("r_CLKCON=0x%x/n",value);

  /gb

 spi_gpbcon &=0xffff0;

 spi_gpbcon |=0x00005;//GB0/GB1=OUTPUT

 spi_gpbdat |=0x0001;//EN=1

 spi_gpbdat &=0x7ffc;//STC=0

 spi_gpbup   &=0x7ffb;

 

  //gb

    

 

 

  spi_gpgcon &=0xFFFFFFCF;//GPGCON-2=11 ,

 

  spi_gpgcon |=0x00000030; 

  value=(int)spi_gpgcon; 

  printk("spi_gpgcon=0x%x/n",value);

 

  spi_gpgup &= 0xFFFB;//GPGUP-2=1

  spi_gpgup |=0x0004; 

  value=(int)spi_gpgup; 

  printk("spi_gpgup=0x%x/n",value);

 

 /*********************************************************

  spi_gpecon &=0xF03FFFFF;//GPECON-11,12,13=10 

  spi_gpecon |=0x05000000;  //0xa8

  value=(int)spi_gpecon; 

  printk("spi_gpecon=0x%x/n",value);

**********************************************************/

 

  spi_gpecon &=0xF03FFFFF;//GPECON-11,12,13=10 

  spi_gpecon |=0x0A800000; 

  value=(int)spi_gpecon; 

  printk("spi_gpecon=0x%x/n",value);

 

  spi_gpeup &=0xC7FF;//GPEUP-13=1 GPGUP-12,11=0  

  spi_gpeup |=0x2000; 

  value=(int)spi_gpeup; 

  printk("spi_gpeup=0x%x/n",value);

  printk("config SPI.../n");

 

 //  spi_spcon0=0x00;

 

  config=(int)spi_spcon0; 

  printk("spi_spcon0=0x%x/n",config); 

 

  spi_sppin0=(0<<2)|(0<<1)|(0<<0); 

  config=(int)spi_sppin0; 

  printk("spi_sppin0=0x%x/n",config);

spi_sppre0=0xFF;//SPI Baud Rate Prescaler Register,Baud Rate=PCLK/2/(Prescaler value+1);

//spi_spcon0=(0<<6)|(0<<5)|(1<<4)|(1<<3)|(0<<2)|(0<<1)|(0<<0); 

 

  printk("Open spi successfully/n");

 

  return 0; 

 

}

 

static ssize_t s3c2440_spi_write(struct file *filp,const char __user *buf,size_t count,loff_t *f_ops) 

{

 int spcon;

 char i=0;

 

copy_from_user(dataTx,buf,sizeof(dataTx));

 

 

/*****************************

tx=dataTx[0];

spi_gpedat &=0xc7ff;

 

for(i=0;i<8;i++)

{

spi_gpedat &=0xdfff;

udelay(10);

if(tx&0x80)

{

spi_gpedat |=0x1000;

}

else

{

spi_gpedat &=0xefff;

}

udelay(10);

spi_gpedat |=0x2000;

udelay(10);

tx=tx<<1;

}

****/

//spcon=(int)spi_spsta0;       

     printk("spi_spsta%d/n",(int)spi_spsta0);//the first sta

 spi_sptdat0=dataTx[0];

 // spcon=(int)spi_spsta0;       

     printk("spi_spsta%d/n",(int)spi_spsta0);//the first sta

 

spi_spcon0=(0<<6)|(0<<5)|(1<<4)|(1<<3)|(1<<2)|(0<<1)|(0<<0);//必须先使能spi时钟

//spcon=(int)spi_spsta0;       

//printk("spi_spsta%d/n",spcon);//the first sta

 for(i=0;i<10;i++)//这是手册要求的,必须要做

 {

  spi_sptdat0=0xff;

 }

  printk("spi_spsta%d/n",(int)spi_spsta0);//the first sta

 //spi_gpgdat &=0xfffb;

 

         if((spi_spsta0&0x01)==1) //data Tx/Rx ready   

           {  

           

                    spi_sptdat0=dataTx[0];  

    // spcon=(int)spi_spsta0;       

     printk("spi_spsta%d/n",(char)spi_spsta0);//the first sta

 

                    printk("txt char=%d/n",dataTx[0]);

        printk("txt char=%c/n",dataTx[0]);

     spcon=(int)spi_sptdat0;

     printk("spi_sptdat0=%d/n",spcon);

    

spi_gpbdat |=0x0002;//STC=1

udelay(10);

spi_gpbdat &=0x7ffe;//EN=0

 

 

   spcon=(int)spi_spcon0;

   printk("spi_spcon=0x%x/n",spcon);

   spcon=(int)spi_spsta0;       

   printk("spi_spsta%d/n",spcon);//the first sta

   //spi_spcon0=(0<<6)|(0<<5)|(0<<4)|(1<<3)|(0<<2)|(0<<1)|(0<<0); 

   //spi_spcon0=0x00;  //Polling,dis-sck,master,low,format A,nomal

 // udelay(10);

 

   return 0;

}

 

//填充file_operations结构体

 

static struct file_operations s3c2410_spi_fops = {

.owner = THIS_MODULE,

.open  =s3c2440_spi_open,

.write =s3c2440_spi_write,

.release=s3c2440_spi_close,

};

 

static int __init dev_init(void)

{

int ret;

ret = register_chrdev(SPI_MAJOR,DEVICE_NAME,&s3c2410_spi_fops);//设备注册

if(ret < 0)

{

printk(DEVICE_NAME "can't get major number/n");

return ret;

}

devfs_mk_cdev(MKDEV(SPI_MAJOR, 0), S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,DEVICE_NAME);

printk (DEVICE_NAME"/tinitialized/n");

return 0;

}

 

static void __exit dev_exit(void)

{

devfs_remove(DEVICE_NAME);

unregister_chrdev(SPI_MAJOR, DEVICE_NAME);

printk("Good-bye, SPI module was removed!/n");

}

module_init(dev_init);

module_exit(dev_exit);

MODULE_LICENSE("GPL");

MODULE_AUTHOR("FriendlyARM Inc.");

 

驱动程序写完之后,模仿mini2440hello_module驱动,完成添加,编译和加载即可

 

测试程序

 

#include <stdio.h>

#include <string.h>

#include <sys/types.h>

#include <errno.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <termios.h>

#include <stdlib.h>

int main()

{

  int fd;

  char gao=0xaa;

  printf("now spi testing");

  fd = open("/dev/SPI", O_RDWR);

  if (fd<0)

  {

   perror("Can't Open SPI Port");

   return -1;

  }

  sleep(10);

  while(1)

  {

   write(fd,gao,sizeof(gao));

   printf("testing");

   sleep(1);

  }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值