现在的位置: 首页 > 综合 > 正文

i2c驱动之at24c08(1)

2013年10月09日 ⁄ 综合 ⁄ 共 5141字 ⁄ 字号 评论关闭
/*
*该驱动为new style方式
*驱动安装后,输入命令创建设备节点:mknod /dev/at24c08 c 250 1
*需在内核中的mach-mini2440.c中添加板级信息注册这个i2c设备,
*且注册的设备名必须和本文件中id_table的设备名一致;
在mach-mini2440.c中添加如下代码,并重新编译内核
0x50为at24c08设备的地址,"at24c08"为在板级信息中添加的i2c设备的名称;
static struct i2c_board_info i2c_devices[] __initdata = { 
  { I2C_BOARD_INFO("at24c08", 0x50), }, 
}; 
static void __init mini2440_machine_init(void) 
{ 
  i2c_register_board_info(0,i2c_devices,ARRAY_SIZE(i2c_devices)); //在函数中新加的注册信息
  s3c24xx_fb_set_platdata(&mini2440_fb_info); 
  s3c_i2c0_set_platdata(NULL); 
  s3c_device_nand.dev.platform_data = &mini2440_nand_info; //添加 
  platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices)); 
  //smdk_machine_init(); 
} 
*/

#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/slab.h>
#include <linux/list.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <asm/uaccess.h>

#define AT24C08_MAJOR 250   //主设备号不能为89,为什么?
static int at24c08_major = AT24C08_MAJOR; 
/**自定义的设备数据结构**/
struct at24c08_dev
{
   struct i2c_client *client;
   char name[30];
   unsigned short current_pointer;
   struct cdev cdev;
};
struct at24c08_dev *at24c08_devp;

static int at24c08_open(struct inode *inode, struct file *file) 
{ 
  file->private_data = at24c08_devp; 
  return 0; 
} 
 
static ssize_t at24c08_read(struct file *file, char *buf, size_t count, loff_t *ppos) 
{ 
  int i = 0; 
  int transferred = 0; 
  int ret, my_buf[512]; 
  struct at24c08_dev *dev = (struct at24c08_dev *)file->private_data; 
  dev->current_pointer = *ppos; 
  if  (i2c_check_functionality(dev->client->adapter, 
I2C_FUNC_SMBUS_READ_BYTE_DATA)) { 
    while (transferred < count){ 
      ret = i2c_smbus_read_byte_data(dev->client,dev->current_pointer + i ); 
      my_buf[i++] = (unsigned short)ret; 
      transferred += 1; 
    } 
    copy_to_user(buf, (void *)my_buf, transferred); 
    dev->current_pointer += transferred; 
  } 
return transferred; 
} 
 
static ssize_t at24c08_write(struct file *file, char *buf, size_t count, loff_t *ppos) 
{ 
  int i = 0; 
  int transferred = 0; 
  int ret, my_buf[512]; 
  
  struct at24c08_dev *dev = (struct at24c08_dev *)file->private_data; 
  dev->current_pointer = *ppos; 
  if (i2c_check_functionality(dev->client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) { 
  //判断适配器能力
    copy_from_user(my_buf, buf, count);  
    while (transferred < count){ 
      ret = i2c_smbus_write_byte_data(dev->client,dev->current_pointer + i,my_buf[i]); 
  //i2c_smbus_write_byte_data是从设备指定偏移处写入一个字节
	  i += 1; 
      transferred += 1; 
    } 
    dev->current_pointer += transferred; 
  } 
return transferred; 
} 

static int at24c08_ioctl(struct inode *inodep, struct file *file, unsigned int cmd, unsigned long 
arg) 
{ 
  return 0; 
} 
 
static int at24c08_release(struct inode *inodep, struct file *file) 
{ 
  file->private_data = NULL; 
  return 0; 
}

static const struct file_operations at24c08_fops = { 
  .owner    = THIS_MODULE, 
  .open    = at24c08_open, 
  .read  = at24c08_read, 
  .write    = at24c08_write, 
  .ioctl    = at24c08_ioctl, 
  .release = at24c08_release, 
}; 

static void at24c08_setup_cdev(struct at24c08_dev *dev, int index) 
{

      int err;
	  dev_t devnum=MKDEV(at24c08_major,index);  //index=1;
	  cdev_init(&dev->cdev,&at24c08_fops);
      dev->cdev.owner = THIS_MODULE;
	  err=cdev_add(&dev->cdev,devnum,1);
      if (err) 
           printk(KERN_NOTICE"Error %d adding at24c08b %d", err, index);
	  
}

static int __devinit at24c08_probe(struct i2c_client *client,struct i2c_device_id *id)
{
   printk(KERN_INFO"start at24c08 probe\n");
   int ret;
   dev_t devnum=MKDEV(at24c08_major,1);
   if(at24c08_major) 
    ret = register_chrdev_region(devnum, 1, "at24c08"); //执行probe后才注册设备
  else { 
    ret = alloc_chrdev_region(&devnum, 0, 1, "at24c08"); 
    at24c08_major = MAJOR(devnum); 
  }

  if (ret < 0) 
    return ret; 
  at24c08_devp = kmalloc(sizeof(struct at24c08_dev), GFP_KERNEL); 
  if (!at24c08_devp){ 
    ret = -ENOMEM; 
    goto fail_malloc; 
  } 
  memset(at24c08_devp, 0, sizeof(struct at24c08_dev)); 
  at24c08_devp->client=client;
  at24c08_setup_cdev(at24c08_devp,1);//前面注册设备后需添加设置设备
  return 0; 
  
fail_malloc: 
  unregister_chrdev_region(devnum, 1); 
  return ret;

  
}
static const struct i2c_device_id at24c08_id[]=
{
{"at24c08",0},  //该名称必须与板级信息中的名称一致才会调用Probe函数
{}
};
static struct i2c_driver at24c08_driver=
{
    .driver={
     .name="at24c08",
     .owner=THIS_MODULE;
	},
    .probe=at24c08_probe,
    .remove=__devexit_p(at24c08_remove),
    .id_table=at24c08_id,
};
static int __init at24c08_init()
{
   printk(KERN_INFO"Init the module success\n");
   return i2c_add_driver(&at24c08_driver); //初始化中添加i2c设备驱动,在执行probe后才注册
}
static void at24c08_exit()
{
   printk(KERN_INFO"exit the module success\n");
   return i2c_del_driver(&at24c08_driver);
}


module_param(at24c08_major, int, S_IRUGO); 
MODULE_AUTHOR("Xie");

module_init(at24c08_init); 
module_exit(at24c08_exit);
/*
*测试程序如下:
*交叉编译后在mini2440开发板上运行。
*交叉编译命令为arm-linux-gcc -static i2c-app.c -o 24c08-app3
*经测试,当输入的参数为4个以下时只能读到一个数,5~8个时读到2个数,9~12个时读到3个数;
*输入参数形式为:  ./程序名 数值1 数值2 数值3 ...;数值为写入设备的十六进制值
*
*/
#include <stdio.h> 
#include <linux/types.h> 
#include <stdlib.h> 
#include <fcntl.h> 
#include <unistd.h> 
#include <sys/types.h> 
 
int main(int argc, char **argv) 
{ 
  int i,j; 
  unsigned int value[100]; 
 
  int fd;     
  fd = open("/dev/at24c08", O_RDWR);   //打开设备
  if(fd < 0) { 
           printf("Open at24c08b Device Faild!\n"); 
           exit(1); 
       } 
printf("you has input %d parament\n",argc);
j=argc-1;
for(i=0;i<j;i++)
 { 
  sscanf(argv[i+1],"%x",&value[i]);    //将输入的数作为值存入value数组中
  printf("value[%d]=%x\n",i,value[i]);


}
  write(fd, value, j);                 //将value数组的值写入设备
  for(i = 0; i < j; i++)  
    printf("write reg[%d] data: %x to at24c08\n", i, value[i]);  
  printf("#########################################\n"); 
  sleep(1); 


  for(i=0;i<j;i++)
         value[i]=0;                  //清0
  
  read(fd, value, j);                 //从设备中读入j个字节的值到数组
  for(i = 0; i < j; i++)  
    printf("read reg[%d] data: %x to at24c08\n", i, value[i]);  
       
  close(fd);  
  return 0; 
} 
/*
当只写入一个数值时,能正确读出来:

当写入2个数值时,只读出来一个,不知道什么原因。
./24c08-app3 0x24 0x30
*/

抱歉!评论已关闭.