#include #define RX8025T_NAME"rx8025t" //driver name,要和device name匹配
#define KBUF_SIZE32
static dev_t dev;
static struct class* rtc_class = 0;
static struct cdev* rtc_dev = 0;
static struct i2c_client* g_cli = 0;
static void __exit rx8025t_exit();
static int rx8025t_probe(struct i2c_client* cli, const struct i2c_device_id* id)
{
g_cli = cli;//因为传输的时候要指定i2c_client所以probe设备时用全局变量把它保存下来备用。
return 0;
}
static int rx8025t_remove(struct i2c_client* cli)
{
g_cli = 0; //移除设备时把i2c_client清除
return 0;
}
static int rx8025t_suspend(struct i2c_client* cli, pm_message_t mesg)
{
return 0;
}
static int rx8025t_resume(struct i2c_client* cli)
{
return 0;
}
static struct i2c_device_id rtc_id[] =
{
{RX8025T_NAME, 0},
{NULL, 0}
};
static struct i2c_driver driver_rtc =
{
.driver =
{
.name = RX8025T_NAME,
},
.id_table = rtc_id,
.probe = rx8025t_probe,
.remove = rx8025t_remove,
.suspend = rx8025t_suspend,
.resume = rx8025t_resume,
};
static ssize_t rtc_read(char* kdata, int len)
{
int ret;
struct i2c_msg msg;
msg.addr = g_cli->addr;
msg.flags = (g_cli->flags & I2C_M_TEN) | I2C_M_RD; //I2C_M_RD读模式,不带此标志默认是写
//g_cli->flags & I2C_M_TEN表示把除了I2C_M_TEN之外的位清零,不改变地址模式位的值,默认还是7位地址模式
msg.len = len;
msg.buf = kdata;
g_cli->adapter->dev.platform_data = g_cli->dev.platform_data; //设置平台数据
return ((ret = i2c_transfer(g_cli->adapter, &msg, 1)) == 1) ? len : ret; //启动i2c传输
}
static ssize_t rtc_write(char* kdata, int len)
{
int ret;
struct i2c_msg msg;
msg.flags = g_cli->flags & I2C_M_TEN; //默认写操作
msg.addr = g_cli->addr;
msg.len = len;
msg.buf = kdata;
g_cli->adapter->dev.platform_data = g_cli->dev.platform_data;
return ((ret = i2c_transfer(g_cli->adapter, &msg, 1)) == 1) ? len : ret; //启动i2c传输
}
static int rx8025t_open(struct inode* in, struct file* fi)
{
return 0;
}
static ssize_t rx8025t_read(struct file* fi, char __user *buf, size_t len, loff_t* ff)
{
ssize_t t;
char kdata[KBUF_SIZE];
if (len > KBUF_SIZE)
len = KBUF_SIZE;
t = rtc_read(kdata, len);
if (t > 0)
{
if (len > t)
len = t;
if (copy_to_user(buf, kdata, len))
{
printk(KERN_INFO "copy data error
");
return -EFAULT;
}
}
return t;
}
static ssize_t rx8025t_write(struct file* fi, const char __user *buf, size_t len, loff_t* ff)
{
char kdata[KBUF_SIZE];
if (len > KBUF_SIZE)
{
printk(KERN_INFO "input error %d > %d
", len, KBUF_SIZE);
return -EFAULT;
}
if (copy_from_user(kdata, buf, len))
{
printk(KERN_INFO "get input error
");
return -EFAULT;
}
return rtc_write(kdata, len);
}
static int rx8025t_ioctl(struct file* fi, unsigned int cmd, unsigned long data)
{
return -1;
}
static struct file_operations file_oper =
{
.owner = THIS_MODULE,
.open = rx8025t_open,
.read = rx8025t_read,
.write = rx8025t_write,
.unlocked_ioctl = rx8025t_ioctl,
};
static int __init rx8025t_init(void)
{
int ret;
rtc_class = class_create(THIS_MODULE, "rx8025t_class"); //创建设备类
if (IS_ERR(rtc_class))
{
printk("error : failed in creating class
");
return -1;
}
ret = alloc_chrdev_region(&dev, 199, 1, RX8025T_NAME);//让内核自动分配设备号
if (ret < 0)
{
class_destroy(rtc_class);
printk(KERN_INFO "alloc_chrdev_region fail
");
return ret;
}
device_create(rtc_class, NULL, dev, NULL, "%s", RX8025T_NAME);//在类下面创建设备节点
rtc_dev = cdev_alloc();
if (!rtc_dev)
{
printk(KERN_INFO "alloc cdev fail
");
ret = -1;
goto error_exit;
}
cdev_init(rtc_dev, &file_oper);//注册file_operations结构
rtc_dev->owner = THIS_MODULE;
ret = cdev_add(rtc_dev, dev, 1); //添加字符设备到系统
if (ret < 0)
{
printk(KERN_INFO "cdev add fail
");
goto error_exit;
}
return i2c_add_driver(&driver_rtc);//注册i2c driver
error_exit:
rx8025t_exit();
return ret;
}
static void __exit rx8025t_exit(void)
{
if (rtc_dev)
cdev_del(rtc_dev);//删除字符设备
if (rtc_class)
{
device_destroy(rtc_class, dev);//销毁设备
class_destroy(rtc_class);//销毁类
}
unregister_chrdev_region(dev, 1);//释放设备号
i2c_del_driver(&driver_rtc);//删除i2c driver
}
module_init(rx8025t_init);
module_exit(rx8025t_exit);
MODULE_LICENSE("GPL");
MODULE_ALIAS("I2C rx8025t");
MODULE_DESCRIPTION("rx8025t i2c slave driver");