#include <linux/errno.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/i2c.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/ioport.h> #include <asm/uaccess.h> #include <bsp.h> #include <asm/io.h> #include <linux/types.h> #include <linux/fs.h> #include <linux/device.h> #include <linux/spinlock.h> #include <linux/cdev.h>
#define I2C_ACCESS_CTRL_MAJOR 207 #define IOCTL_I2C_WRITE _IO(I2C_ACCESS_CTRL_MAJOR, 1) #define IOCTL_I2C_READ _IO(I2C_ACCESS_CTRL_MAJOR, 2)
static struct class * cls_i2c_access; struct i2c_access_dev { struct cdev cdev; }; static struct i2c_access_dev * i2c_devp;
struct i2c_client * i2c_access_client = NULL; static struct i2c_driver i2c_access_driver; #define SENSOR_DEVICE_I2C 0x45 static unsigned short probe[] = { 0, SENSOR_DEVICE_I2C, I2C_CLIENT_END }; static unsigned short dummy[] = {I2C_CLIENT_END};
static struct i2c_client_address_data addr_data = { .normal_i2c = dummy, .probe = probe, .ignore = dummy, }; struct i2c_reg { unsigned char reg; unsigned char val; };
static int i2c_write(u8 reg, u8 val) { unsigned char data[25]; unsigned char bytes;
data[0]= reg; data[1]=val; bytes = 2;
if (i2c_master_send(i2c_access_client, data, bytes) == bytes) { mdelay(1); return 0; } else { printk("write error!!!! \n"); return -EIO; } }
static u8 i2c_read(u8 reg) { int ret; u8 data; ret = i2c_master_send(i2c_access_client, ®, 1); if (ret < 0) return ret; ret = i2c_master_recv(i2c_access_client, &data, 1); if (ret != 1){ printk(KERN_WARNING "Error while reading i2c\n"); return -EIO; } return data; }
static int i2c_control_open(struct inode *inode, struct file *file) {
return 0; }
static int i2c_control_release(struct inode *inode, struct file *file) { return 0; }
static int i2c_control_ioctl(struct inode *inode, struct file *file,unsigned int cmd, unsigned long arg) { u8 val; struct i2c_reg i2c_data; switch(cmd){ case IOCTL_I2C_WRITE: if (copy_from_user((void *)&i2c_data,(const void *)arg, sizeof(struct i2c_reg))) { printk("(%s:%d) cannot copy data from user !!!\n", __func__, __LINE__); return -EFAULT; } i2c_write(i2c_data.reg, i2c_data.val); break; case IOCTL_I2C_READ: if (copy_from_user((void *)&i2c_data, arg, sizeof(struct i2c_reg))) { printk("(%s:%d) cannot copy data from user !!!\n", __func__, __LINE__); return -EFAULT; } i2c_data.val = i2c_read(i2c_data.reg); if (copy_to_user((void *)arg,(void *)&i2c_data, sizeof(struct i2c_reg))) { printk("(%s:%d) cannot copy data to user !!!\n", __func__, __LINE__); return -EFAULT; } break; default: printk("(%s:%d) unknown ioctl cmd (0x%x)\n", __func__, __LINE__, cmd); return -EINVAL;
}
return 0; }
static struct file_operations i2c_control_fops = { .owner = THIS_MODULE, .open = i2c_control_open, .ioctl = i2c_control_ioctl, .release = i2c_control_release, }; static int i2c_access_probe(struct i2c_adapter *adap, int addr, int kind) { struct i2c_client *i2c; int ret;
i2c = kzalloc(sizeof(*i2c), GFP_KERNEL); if (!i2c) return -ENOMEM; strcpy(i2c->name, "i2c_access"); i2c->flags = 0; i2c->addr = addr; i2c->adapter = adap; i2c->driver = &i2c_access_driver;
i2c_access_client = i2c;
/* attach i2c client device */ ret = i2c_attach_client(i2c); if (ret < 0) { printk("%s: failed to attach codec at addr %x\n", __func__, addr); goto err; }
return ret; err: kfree(i2c); return ret; } static int i2c_access_attach(struct i2c_adapter *adap) { return i2c_probe(adap, &addr_data, i2c_access_probe); }
static int i2c_access_detach(struct i2c_client *client) { i2c_detach_client(client);
if(i2c_access_client) { kfree(i2c_access_client); i2c_access_client = NULL; } return 0; }
static struct i2c_driver i2c_access_driver = { .driver = { .name = "tcc-i2c-access", .owner = THIS_MODULE, }, .id = -1, .attach_adapter = i2c_access_attach, .detach_client = i2c_access_detach, .command = NULL, };
static int __init i2c_access_init(void) { int ret = 0; dev_t devno; int reg_val,reg_tref,reg_tmref; printk(KERN_INFO "Register i2c access driver.\n");
ret = i2c_add_driver(&i2c_access_driver); if (ret != 0){ printk(KERN_ERR "Failed to register I2C client.\n"); return ENODEV; } devno = MKDEV(I2C_ACCESS_CTRL_MAJOR, 0); ret = register_chrdev_region(devno, 1, "i2c_access");
if (ret){ printk(KERN_INFO "register i2c_access_driver failed"); return -ENODEV; }
i2c_devp = (struct i2c_access_dev *)kmalloc(sizeof(struct i2c_access_dev), GFP_KERNEL); if (NULL == i2c_devp){ printk(KERN_INFO "i2c_access:kmalloc failed"); ret=-ENOMEM; goto fail_malloc; } memset(i2c_devp,0,sizeof(struct i2c_access_dev)); cdev_init(&i2c_devp->cdev, &i2c_control_fops); i2c_devp->cdev.owner = THIS_MODULE; ret = cdev_add(&i2c_devp->cdev, devno, 1); if(ret) { printk(KERN_INFO "adding cdev failed"); ret=-ENOMEM; goto fail_cdev; } cls_i2c_access=class_create(THIS_MODULE, "i2c_access"); device_create(cls_i2c_access,NULL,devno,NULL,"i2c_access"); return 0; fail_cdev: kfree(i2c_devp); fail_malloc: unregister_chrdev_region(devno,1); return ret; } static void __exit i2c_access_exit(void) { dev_t devno; printk(KERN_INFO "Unregister i2c access driver.\n"); devno = MKDEV(I2C_ACCESS_CTRL_MAJOR, 0); device_destroy(cls_i2c_access,devno); class_destroy(cls_i2c_access); cdev_del(&i2c_devp->cdev); kfree(i2c_devp); unregister_chrdev_region(devno, 1); }
module_init(i2c_access_init); module_exit(i2c_access_exit);
MODULE_LICENSE("GPL"); MODULE_AUTHOR("J.H.Luo"); MODULE_VERSION("0.1"); MODULE_DESCRIPTION("i2c access driver");
|