📄 rtc8025.c
字号:
char wb;
void __user *uarg = (void __user *)arg;
int ret = -EINVAL;
switch(cmd){
case RTC_RD_TIME:
ret = rx8025_get_rtctime(&tm);
if (ret)
break;
ret = copy_to_user(uarg, &tm, sizeof(tm));
if (ret)
ret = -EFAULT;
break;
case RTC_SET_TIME:
if (!capable(CAP_SYS_TIME)) {
ret = -EACCES;
break;
}
ret = copy_from_user(&tm, uarg, sizeof(tm));
if (ret) {
ret = -EFAULT;
break;
}
ret = rx8025_set_rtctime(&tm);
break;
case RTC_RD_WB:
ret = rx8025_get_wb(&wb);
if (ret)
break;
//printk(KERN_ALERT "read wb is 0x%x\n", wb);
ret = copy_to_user(uarg, &wb, sizeof(wb));
if (ret)
ret = -EFAULT;
break;
case RTC_SET_WB:
ret = copy_from_user(&wb, uarg, sizeof(wb));
//printk(KERN_ALERT "ioctl set is 0x%x\n", wb);
if (ret) {
ret = -EFAULT;
break;
}
ret = rx8025_set_wb(&wb);
break;
}
return ret;
}
static struct file_operations rx8025_fops = {
.owner = THIS_MODULE,
.ioctl = rx8025_ioctl,
};
static struct miscdevice rx8025_miscdev = {
.minor = RTC8025_MINOR,
.name = RTC8025_NAME,
.fops = &rx8025_fops,
};
// a by xjr 2007.1.26 e
// m by xjr 2007.1.26 b
/*
static struct rtc_ops rx8025_rtc_ops = {
.owner = THIS_MODULE,
.read_time = rx8025_get_rtctime,
.set_time = rx8025_set_rtctime,
};
*/
// m by xjr 2007.1.26 e
static int rx8025_attach_adapter(struct i2c_adapter *adapter)
{
return i2c_probe(adapter, &addr_data, &rx8025_detect);
}
static int rx8025_detect(struct i2c_adapter *adapter, int address, int kind)
{
int err = 0;
struct rx8025_data *data;
struct i2c_client *new_client;
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
dev_dbg(&adapter->dev, "doesn't support full I2C\n");
goto errout;
}
if (!(data = kzalloc(sizeof(*data), GFP_KERNEL))) {
dev_dbg(&adapter->dev, "failed to alloc memory\n");
err = -ENOMEM;
goto errout;
}
new_client = &data->client;
i2c_set_clientdata(new_client, data);
new_client->addr = address;
new_client->adapter = adapter;
new_client->driver = &rx8025_driver;
new_client->flags = 0;
INIT_LIST_HEAD(&data->list);
if (kind == 0)
kind = rx8025;
if (kind < 0) {
u8 command = RX8025_REG_SEC << 4 | 0x08;
u8 result[8] ;
int err;
/* a by cui 200704012 */
/* fisrt read register RX8025_REG_MONTH
if bit 7 isn't "0" then clear it*/
result[0] = RX8025_REG_MONTH<<4 | 0x08;
result[1] = 0xff;
struct i2c_msg msg1[] = {
{
.addr = address,
.len = 1,
.buf = result,
}, {
.addr = address,
.flags = I2C_M_RD,
.len = 1,
.buf = result + 1,
}
};
if ( (err = i2c_transfer(adapter, msg1, 2)) < 2) {
err = err >= 0 ? 0 : err;
goto errout_free;
}
if(result[1] &0x80) {
result[0] = RX8025_REG_MONTH<<4 | 0x08;
result[1] &= 0x7f;
msg1[0].addr = address;
msg1[0].len = 2;
msg1[0].buf=result;
msg1[0].flags = 0;
if ( (err = i2c_transfer(adapter, msg1, 1)) < 1) {
err = err >= 0 ? 0 : err;
goto errout_free;
}
}
/* fisrt read register RX8025_REG_DIGOFF
if bit 7 isn't "0" then clear it*/
result[0] = RX8025_REG_DIGOFF<<4 | 0x08;
result[1] = 0xff;
struct i2c_msg msg2[] = {
{
.addr = address,
.len = 1,
.buf = result,
}, {
.addr = address,
.flags = I2C_M_RD,
.len = 1,
.buf = result + 1,
}
};
if ( (err = i2c_transfer(adapter, msg2, 2)) < 2) {
err = err >= 0 ? 0 : err;
goto errout_free;
}
if(result[1] &0x80) {
result[0] = RX8025_REG_DIGOFF<<4 | 0x08;
result[1] &= 0x7f;
msg1[0].addr = address;
msg1[0].len = 2;
msg1[0].buf=result;
msg1[0].flags = 0;
if ( (err = i2c_transfer(adapter, msg2, 1)) < 1) {
err = err >= 0 ? 0 : err;
goto errout_free;
}
}
/* continue detect */
struct i2c_msg msg[] = {
{
.addr = address,
.len = 1,
.buf = &command,
}, {
.addr = address,
.flags = I2C_M_RD,
.len = ARRAY_SIZE(result),
.buf = result,
}
};
if ((err = i2c_transfer(adapter, msg, ARRAY_SIZE(msg)))
< ARRAY_SIZE(msg)) {
err = err >= 0 ? 0 : err;
goto errout_free;
}
/* bits 7 of RX8025_REG_MONTH and RX8025_REG_DIGOFF
* "should be set as "0". Their value when read will be "0""
*
* There are serveral more read-only bits who's "value when
* read is always "0"" according to the spec, but setting them
* yields a "1" sometimes.
*/
if (((result[RX8025_REG_MONTH] | result[RX8025_REG_DIGOFF])
& 0x80)) {
dev_dbg(&adapter->dev, "RX8025_REG_MONTH = %x, "
"RX8025_REG_DIGOFF = %x\n",
result[RX8025_REG_MONTH],
result[RX8025_REG_DIGOFF]);
goto errout_free;
}
kind = rx8025;
}
BUG_ON(kind != rx8025);
strlcpy(new_client->name, "rx8025", I2C_NAME_SIZE);
if(down_interruptible(&rx8025_lock)) {
err = -ERESTARTSYS;
goto errout_free;
}
if ((err = i2c_attach_client(new_client)))
goto errout_unlock;
list_add(&data->list, &rx8025_clients);
if ((err = rx8025_init_client(new_client)))
goto errout_detach;
if (!rx8025_rtcclient) {
rx8025_rtcclient = new_client;
// m by xjr 2007.1.26 b
/*
if ((err = register_rtc(&rx8025_rtc_ops))) {
rx8025_rtcclient = NULL;
printk(KERN_ERR "Failed to register rtc device\n");
}
*/
if ((err = misc_register(&rx8025_miscdev))){
rx8025_rtcclient = NULL;
printk(KERN_ERR "Failed to register rtc8025 device\n");
}
// m by xjr 2007.1.26 e
}
up(&rx8025_lock);
printk(KERN_INFO "loaded driver for RX-8025 SA/NB on addr %d\n",
address);
return 0;
errout_detach:
rx8025_detach_client(new_client);
errout_unlock:
up(&rx8025_lock);
errout_free:
kfree(data);
errout:
dev_dbg(&adapter->dev, "Failed to detect rx8025\n");
return err;
}
static int rx8025_init_client(struct i2c_client *client)
{
u8 command[3] = { RX8025_REG_CTRL1 << 4 | 0x08, };
int err;
struct i2c_msg msg[] = {
{
.addr = client->addr,
.len = 1,
.buf = command,
}, {
.addr = client->addr,
.flags = I2C_M_RD,
.len = ARRAY_SIZE(command) - 1,
.buf = command + 1,
}
};
if ((err = i2c_transfer(client->adapter, msg, 2)) < 2) {
err = err >= 0 ? -EIO : err;
goto errout;
}
/* Assert 24-hour mode */
command[1] |= RX8025_BIT_CTRL1_1224;
/* disable Alarm D and Alarm W */
command[1] &= ~(RX8025_BIT_CTRL1_DALE | RX8025_BIT_CTRL1_WALE);
if (command[2] & RX8025_BIT_CTRL2_PON)
dev_warn(&client->dev, "power-on reset was detected, "
"you may have to readjust the clock\n");
if (command[2] & RX8025_BIT_CTRL2_VDET)
dev_warn(&client->dev, "a power voltage drop was detected, "
"you may have to readjust the clock\n");
command[2] &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET);
command[0] = RX8025_REG_CTRL1 << 4;
msg[0].len = ARRAY_SIZE(command);
if ((err = i2c_transfer(client->adapter, msg, 1)) < 1) {
err = err >= 0 ? -EIO : err;
goto errout;
}
return 0;
errout:
return err;
}
static int rx8025_detach_client(struct i2c_client *client)
{
int err;
struct rx8025_data *data = i2c_get_clientdata(client);
if(down_interruptible(&rx8025_lock))
return -ERESTARTSYS;
BUG_ON(list_empty(&rx8025_clients));
if (rx8025_rtcclient == client) {
struct list_head *lh = rx8025_clients.next;
if (list_entry(lh, struct rx8025_data, list) == data)
lh = lh->next;
if (lh == &rx8025_clients) {
// m by xjr 2007.1.26 b
//unregister_rtc(&rx8025_rtc_ops);
misc_deregister(&rx8025_miscdev);
// m by xjr 2007.1.26 e
rx8025_rtcclient = NULL;
} else
rx8025_rtcclient = &data->client;
}
if ((err = i2c_detach_client(client))) {
up(&rx8025_lock);
return err;
}
list_del(&data->list);
up(&rx8025_lock);
kfree(data);
return 0;
}
static int __init rx8025_init(void)
{
printk("rx8025_init\n");
return i2c_add_driver(&rx8025_driver);
}
static void __exit rx8025_exit(void)
{
i2c_del_driver(&rx8025_driver);
}
MODULE_AUTHOR("arming <xjr555@sina.com>");
MODULE_DESCRIPTION("EPSON RX8025 RTC Driver");
MODULE_LICENSE("GPL");
module_init(rx8025_init);
module_exit(rx8025_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -