s5pv210 eeprom at24cxx 驱动

1,mach-x210.c

/* I2C0 */
static struct i2c_board_info i2c_devs0[] __initdata = {
#ifdef CONFIG_SND_SOC_WM8580
	{
		I2C_BOARD_INFO("wm8580", 0x1b),
	},
#endif

#ifdef CONFIG_EEPROM_at240cxx
{
	I2C_BOARD_INFO("at240c64", (0xa0>>1)),
},
#endif

};

2,  at24cxx_e2prom_i2c_dev.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/fs.h>

#include <asm/uaccess.h>

#define AT24C16  2047
#define AT24C64  8191
#define EE_TYPE  AT24C64
#define IIC_ADDR 0x50


//设计一个驱动针对不同的设备的不同数据(私有)
struct e2prom_private{
    char *name; //描述
    int size;   //容量
    int version;//版本
};

int at24_i2c_e2prom_open (struct inode *inode, struct file *filp)
{
    printk("------%s--------\n", __FUNCTION__);
    //一般也是做初始化

    return 0;
}

//设计一个全局的设备对象
struct i2c_e2prom_global{
    struct i2c_client *client;//描述了一个从设备的信息---从设备地址,名字
    struct e2prom_private *private;
    struct miscdevice i2c_misc;
};



//全局的指针
struct i2c_e2prom_global *at24_dev;

//i2c_master_recv(const struct i2c_client * client, char * buf, int count);
int at24_i2c_recv(const struct i2c_client * client, char * buf, int count)
{
    int ret;
    struct i2c_adapter *adapter = client->adapter;//描述控制器, 比如编号,算法

    struct i2c_msg msg;//传输的数据包 

    msg.addr = client->addr;//数据包传输給哪个从设备
    msg.flags = I2C_M_RD; //读还是写--  1读,0写
    msg.len = count;//数据大小bytes
    msg.buf = buf;

    //参数1--适配器,来自于client
    //参数2--传输的消息体--数据包
    //参数3--消息体的个数
    //返回值--正确为消息的个数,错误为负数
    //i2c_transfer(struct i2c_adapter * adap, struct i2c_msg * msgs, int num)
    ret = i2c_transfer(adapter,  &msg,  1);

    return ret==1?count:ret;

}

//重写类似于i2c_master_send/i2c_master_recv的方法
int at24_i2c_send(struct i2c_client *client,char *buf, int count)
{
    int ret;
    //i2c_adapter描述控制器,比如编号,算法
    struct i2c_adapter *adapter = client->adapter;

    struct i2c_msg msg;
    msg.addr = client->addr;
    msg.buf = buf;
    msg.flags = 0;
    msg.len = count;

    //参数1--适配器,来自于client
    //参数2--传输的消息体--数据包
    //参数3--消息体的个数
    ret = i2c_transfer(adapter, &msg, 1);

    return ret==1?count:ret;
}

ssize_t at24_i2c_e2prom_read (struct file *filp, char __user *buf,  size_t count, loff_t *fops)
{
	size_t ee_addr;
    printk("------%s--------\n", __FUNCTION__);
    int ret;
	char temp2[4];

    //简单的参数判断
    if(count <0 || count > at24_dev->private->size)
        return -EINVAL;
	
    //动态的分配一个空间,用于存放从硬件获取到的数据
    char *temp = kzalloc(count, GFP_KERNEL);
	
    // 1,从用户空间得到数据
    ret = copy_from_user(temp, buf, count);
    if(ret > 0)
    {
        printk("copy_from_user error\n");
        ret = -EFAULT;
        goto err_free;
    }
	ee_addr = (temp[0]<<8)+temp[1];
	

    //i2c_master_recv(const struct i2c_client * client, char * buf, int count);
    //i2c_master_send(const struct i2c_client * client, const char * buf, int count);
    // 1,从硬件中获取数据
    //printk("client addr = %X\n", client->addr);
    
	if(EE_TYPE>AT24C16)
	{
		temp2[0] = ee_addr>>8;
		temp2[1] = ee_addr%256;
		at24_i2c_send(at24_dev->client,temp2,2);
			
	}
	else
	{
		at24_dev->client->addr = IIC_ADDR+((ee_addr/256));
		at24_i2c_send(at24_dev->client,temp2,1);
		temp2[0] = ee_addr%256;
		at24_dev->client->addr = IIC_ADDR;
	}
	
    ret = at24_i2c_recv(at24_dev->client,  temp,  count);
    if(ret < 0)
    {
        printk("at24_i2c_recv error\n");
        goto err_free;
    }
    // 2, 将数据传递给用户
    ret = copy_to_user(buf, temp, count);
    if(ret > 0)
        {
            printk("copy to user error\n");
            ret = -EFAULT;
            goto err_free;

        }
    kfree(temp);

    return count;
err_free:
    kfree(temp);
    return ret;

}



ssize_t at24_i2c_e2prom_write (struct file *filp, const char __user *buf, size_t count, loff_t *fpos)
{
	size_t ee_addr;
    printk("------%s--------\n", __FUNCTION__);
    int ret;
    //简单的参数判断
    if(count < 0 || count > at24_dev->private->size)
		return -EINVAL;
	
    //动态的分配一个空间
    char *temp = kzalloc(count, GFP_KERNEL);
      
    // 1,从用户空间得到数据
    ret = copy_from_user(temp, buf, count);
    if(ret > 0)
    {
        printk("copy_from_user error\n");
        ret = -EFAULT;
        goto err_free;
    }
	ee_addr = (temp[0]<<8)+temp[1];

	if(EE_TYPE>AT24C16)
	{
		ret = at24_i2c_send(at24_dev->client,temp,count);	
	}
	else
	{
		at24_dev->client->addr = IIC_ADDR+((ee_addr/256));
		temp[1] = ee_addr%256;
		ret = at24_i2c_send(at24_dev->client,temp+1,count-1);
		at24_dev->client->addr = IIC_ADDR;
	}

    // 2, 将数据写入到硬件
    //ret =at24_i2c_send(at24_dev->client,  temp+2,  count);
    if(ret < 0)
    {
        printk("at24_i2c_send error\n");
        goto err_free;
    }

    kfree(temp);

    return count;

err_free:
    kfree(temp);
    return ret;
}

int at24_i2c_e2prom_close (struct inode *inode, struct file *flip)
{
    printk("------%s--------\n", __FUNCTION__);
    return 0;   
}



const struct file_operations at24_i2c_fops = {
    .open = at24_i2c_e2prom_open,
    .read = at24_i2c_e2prom_read,
    .write = at24_i2c_e2prom_write,
    .release = at24_i2c_e2prom_close,
};

int at24_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)//为什么是id
{ 
 printk("-------%s-------\n",__FUNCTION__);
    printk("client name = %s\n", id->name);//
    printk("client addr = %X\n", client->addr);
    struct e2prom_private *p = (struct e2prom_private *)id->driver_data;

    printk("name descriptoin : %s \n", p->name);
    printk("size : %d \n", p->size);
    printk("verison  : 0x%x \n", p->version);

    at24_dev = kzalloc(sizeof(struct i2c_e2prom_global), GFP_KERNEL);//GFP_KERNEL

    //记录当前匹配之后的i2c client
    at24_dev->client = client;
    at24_dev->private = (struct e2prom_private *)id->driver_data;

    //实现fops
    at24_dev->i2c_misc.fops = &at24_i2c_fops;
    at24_dev->i2c_misc.minor = 199;           //MISC_DYNAMIC_MINOR,
    at24_dev->i2c_misc.name = "i2c_e2prom"; //指定设备节点的名字 /dev/i2c_e2prom

    //注册一个混杂设备驱动,函数里面已经封装了申请设备号,创建设备文件等过程
    misc_register(&at24_dev->i2c_misc);

    // 4,根据实际情况去初始化从设备硬件---at24 上电就可以工作

    return 0;

}

int at24_i2c_remove(struct i2c_client *client)
{
    printk("------%s--------\n", __FUNCTION__);
    misc_deregister(&at24_dev->i2c_misc);
    kfree(at24_dev);

    return 0;
}


struct e2prom_private c02_private = {
    .name = "at240c02 in test LZH",
    .size = 256,
    .version = 0x1234,
};

struct e2prom_private c04_private = {
    .name = "at240c04 in test LZH",
    .size = 512,
    .version = 0x4444,
};

struct e2prom_private c08_private = {
    .name = "at240c08 in test LZH",
    .size = 2014,
    .version = 0x4321,
};
struct e2prom_private c64_private = {
    .name = "at240c08 in test LZH",
    .size = 8192,
    .version = 0x1111,
};



//名字必须与内核中的arch/arm/mach-s5pv210/mach-smdkv210.c中i2c_board_info结构体对应 
const struct i2c_device_id at24_i2c_id_table[] = {
    {"at240c2",(unsigned long)&c02_private},//注意
    {"at240c4",(unsigned long)&c04_private},
    {"at240c8",(unsigned long)&c08_private},
	{"at240c64",(unsigned long)&c64_private},
};

//描述了一个从设备的操作方法
struct i2c_driver at24_i2c_drv = {
    .probe = at24_i2c_probe,
    .remove = at24_i2c_remove,
    .driver = {                     //父类,一定要初始化
        .name = "at24_drv_LZH",     //该名字不会用于进行匹配#
    },                              //主要的作用是用来产生一个文件 /sys/bus/i2c/drivers/at24_drv
    .id_table = at24_i2c_id_table,  //用于和i2c client进行匹配的名字列表
};

static int __init at24_drv_init(void)
{
    //注册一个i2c driver
    return i2c_add_driver(&at24_i2c_drv);

}

static void __exit at24_drv_exit(void)
{
    i2c_del_driver(&at24_i2c_drv);
}

module_init(at24_drv_init);
module_exit(at24_drv_exit);
MODULE_LICENSE("GPL");				// 描述模块的许可证
MODULE_AUTHOR("aston");				// 描述模块的作者
MODULE_DESCRIPTION("module test");	// 描述模块的介绍信息
MODULE_ALIAS("alias xxx");			// 描述模块的别名信息

 

3, \drivers\misc\eeprom\Makefile

obj-$(CONFIG_EEPROM_at240cxx)	+= at24cxx_e2prom_i2c_drv.o

4,\drivers\misc\eeprom\Kconfig

config EEPROM_at240cxx
	tristate "EEPROM at240cxx support"
	help
	  This is a driver for the EEPROM chipsets at240cxx.
	  The driver supports both read as well as write commands.

	  If unsure, say N. 

5, 将i2c core层和i2c adapter控制器层编译进内核 
make menuconfig 
Device Drivers —> 
              <*> I2C support —> // i2c-core.c 
                            I2C Hardware Bus support —> 
                                        <*> S3C2410 I2C Driver 

Device Drivers —> 

                     [*] Misc devices  ---> 

                                 EEPROM support  ---> 

                                          <*> EEPROM at240cxx support

6,app应用。

#include <linux/i2c-dev.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

void print_usage(char *str)
{
    printf("%s r     : read at24c02 addresss 0\n", str);
    printf("%s w val : write at24c02 addresss 0\n", str);
}

int main(int argc,char **argv)
{
    int fd;
    unsigned char val;//字节
	int i;
    int  res;
    char wbuf[10];
    char rbuf[10];

    if (argc < 2)
    {
        print_usage(argv[0]);
        exit(1);
    }

    /*打开设备文件*/
    fd = open("/dev/i2c_e2prom", O_RDWR);
    if (fd < 0) 
    {
        perror("open failed");
        exit(1);
    }
    if (strcmp(argv[1], "r") == 0)
    {
		rbuf[0] = 0;//地址高8位
		rbuf[1] = 16;//地址第8位
        if (read(fd, rbuf, 32) != 32)
        {
            perror("read failed");
            exit(1);
        } else {
			printf("rbuf:");
			for(i=0;i<32;i++)
				printf("%x ",rbuf[i]);
			printf("\n\n");
        }   
    }
    else if ((strcmp(argv[1], "w") == 0) && (argc == 3))
    {
        //  ./test  w  0x99
        val = strtoul(argv[2], NULL, 0);        

        wbuf[0] = 0;  //地址高8位
        wbuf[1] = 16;  //地址低8位
        wbuf[2] = val;  //数据
        wbuf[3] = 0x1b;
        wbuf[4] = 0x2b;
        wbuf[5] = 0x3b;
		wbuf[6] = 0x4b;
        if (write(fd, wbuf, 7)!=5) 
        {
            perror("write failed");
            exit(1);
        }             
        printf("write data ok!\n");

    }

    close(fd);
    return 0;
}



 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值