📄 rtc8025.c
字号:
/*
* linux/drivers/i2c/chips/rtc8025.c
*
* Copyright (C) 2007 arming
*
* based on linux/drivers/i2c/chips/rtc8564.c
* Copyright (C) 2002-2004 Stefan Eletzhofer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* Driver for system3's EPSON RTC 8025 chip
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/bcd.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/rtc.h>
#include <linux/spinlock.h>
#include <linux/fs.h>
#include <asm/uaccess.h>
#include <asm/rtc.h>
#include <asm/mach/time.h>
#include "rtc8025.h"
//#define RTC_RD_WB 0x13
//#define RTC_SET_WB 0x14
//#define DEBUG 1
static unsigned short normal_i2c[] = { 0x32, I2C_CLIENT_END };
I2C_CLIENT_INSMOD_1(rx8025);
static int rx8025_attach_adapter(struct i2c_adapter *adapter);
static int rx8025_detect(struct i2c_adapter *adapter, int address, int kind);
static int rx8025_init_client(struct i2c_client *client);
static int rx8025_detach_client(struct i2c_client *client);
static struct i2c_driver rx8025_driver = {
.owner = THIS_MODULE,
.name = "rx8025-rtc",
.id = I2C_DRIVERID_RTC8025,
.flags = I2C_DF_NOTIFY,
.attach_adapter = &rx8025_attach_adapter,
.detach_client = &rx8025_detach_client,
};
static struct i2c_client *rx8025_rtcclient = NULL;
struct rx8025_data {
struct i2c_client client;
struct list_head list;
};
static LIST_HEAD(rx8025_clients);
static DECLARE_MUTEX(rx8025_lock);
static int rx8025_get_wb(char *val)
{
u8 command[2] = { RX8025_REG_DIGOFF << 4 | 0x08, 4};
int err;
struct i2c_msg msg[] = {
{
.addr = rx8025_rtcclient->addr,
.len = 1,
.buf = command,
}, {
.addr = rx8025_rtcclient->addr,
.flags = I2C_M_RD,
.len = ARRAY_SIZE(command) - 1,
.buf = command + 1,
}
};
if(down_interruptible(&rx8025_lock))
return -ERESTARTSYS;
if (!rx8025_rtcclient) {
err = -EIO;
goto errout_unlock;
}
if (!val) {
dev_err(&rx8025_rtcclient->dev,
"rx8025_get_rtctime: passed in wb == NULL\n");
err = -EINVAL;
goto errout_unlock;
}
if ((err = i2c_transfer(rx8025_rtcclient->adapter, msg, 2)) < 2) {
err = err >= 0 ? -EIO : err;
goto errout_unlock;
}
up(&rx8025_lock);
dev_dbg(&rx8025_rtcclient->dev,
"rx8025_get_wb: read 0x%02x\n", command[1]);
//printk("wb addr is 0x%x\n", command[0]);
//printk("read from wb is 0x%x\n", command[1]);
(*val) = command[1];
dev_dbg(&rx8025_rtcclient->dev,
"rx8025_get_wb: result: 0x%02x\n", *val);
return 0;
errout_unlock:
up(&rx8025_lock);
return err;
}
static int rx8025_set_wb(char *val)
{
u8 command[2] = { RX8025_REG_DIGOFF << 4, };
int err;
struct i2c_msg msg = {
.addr = rx8025_rtcclient->addr,
.len = 2,
.buf = command,
};
if(down_interruptible(&rx8025_lock))
return -ERESTARTSYS;
if (!rx8025_rtcclient) {
err = -EIO;
goto errout_unlock;
}
if (!val) {
dev_err(&rx8025_rtcclient->dev,
"rx8025_get_rtctime: passed in wb == NULL\n");
err = -EINVAL;
goto errout_unlock;
}
//printk("set wb value before write is 0x%x\n",(*val));
/*if ((*val)<0 || (*val)>127) {
dev_err(&rx8025_rtcclient->dev,
"rx8025_set_wb: passed in wb outof range\n");
err = -EINVAL;
goto errout_unlock;
}*/
command[1] = *val;
//printk("the wb set is 0x%x", command[1]);
dev_dbg(&rx8025_rtcclient->dev,
"rx8025_set_wb: send 0x%02x 0x%02x\n", command[0], command[1]);
if ((err = i2c_transfer(rx8025_rtcclient->adapter, &msg, 1)) < 1) {
err = err >= 0 ? -EIO : err;
goto errout_unlock;
}
up(&rx8025_lock);
return 0;
errout_unlock:
up(&rx8025_lock);
return err;
}
static int rx8025_get_rtctime(struct rtc_time *dt)
{
u8 command = RX8025_REG_CTRL1 << 4 | 0x08;
u8 result[9] = { 0, };
int i, err;
struct i2c_msg msg[] = {
{
.len = 1,
.buf = &command,
}, {
.flags = I2C_M_RD,
.len = ARRAY_SIZE(result),
.buf = result,
}
};
if(down_interruptible(&rx8025_lock))
return -ERESTARTSYS;
if (!rx8025_rtcclient) {
err = -EIO;
goto errout_unlock;
}
if (!dt) {
dev_err(&rx8025_rtcclient->dev,
"rx8025_get_rtctime: passed in dt == NULL\n");
err = -EINVAL;
goto errout_unlock;
}
for (i = 0; i < ARRAY_SIZE(msg); ++i)
msg[i].addr = rx8025_rtcclient->addr;
if ((err = i2c_transfer(rx8025_rtcclient->adapter, msg, 2)) < 2) {
err = err >= 0 ? -EIO : err;
goto errout_unlock;
}
up(&rx8025_lock);
dev_dbg(&rx8025_rtcclient->dev,
"rx8025_get_rtctime: read 0x%02x 0x%02x 0x%02x 0x%02x"
" 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", result[0],
result[1], result[2], result[3], result[4], result[5],
result[6], result[7], result[8]);
dt->tm_sec = BCD2BIN(result[2 + RX8025_REG_SEC]);
dt->tm_min = BCD2BIN(result[2 + RX8025_REG_MIN]);
if (result[0] | RX8025_BIT_CTRL1_1224)
dt->tm_hour = BCD2BIN(result[2 + RX8025_REG_HOUR]);
else
dt->tm_hour = BCD2BIN(result[2 + RX8025_REG_HOUR] & 0x1f) % 12
+ (result[2 + RX8025_REG_HOUR] & 0x20 ? 12 : 0);
dt->tm_wday = BCD2BIN(result[2 + RX8025_REG_WDAY]);
dt->tm_mday = BCD2BIN(result[2 + RX8025_REG_MDAY]);
dt->tm_mon = BCD2BIN(result[2 + RX8025_REG_MONTH]) - 1;
dt->tm_year = BCD2BIN(result[2 + RX8025_REG_YEAR]);
if (dt->tm_year < 70)
dt->tm_year += 100;
dev_dbg(&rx8025_rtcclient->dev,
"rx8025_get_rtctime: "
"result: %ds %dm %dh %dwd %dmd %dm %dy\n",
dt->tm_sec, dt->tm_min, dt->tm_hour, dt->tm_wday,
dt->tm_mday, dt->tm_mon, dt->tm_year);
return 0;
errout_unlock:
up(&rx8025_lock);
return err;
}
static int rx8025_set_rtctime(struct rtc_time *dt)
{
u8 command[8] = { RX8025_REG_SEC << 4, };
int err;
s32 ctrl1;
struct i2c_msg msg = {
.len = 8,
.buf = command,
};
if(down_interruptible(&rx8025_lock))
return -ERESTARTSYS;
if (!rx8025_rtcclient) {
err = -EIO;
goto errout_unlock;
}
if (!dt) {
dev_err(&rx8025_rtcclient->dev,
"rx8025_set_rtctime: passed in dt == NULL\n");
err = -EINVAL;
goto errout_unlock;
}
if (dt->tm_sec < 0 || dt->tm_sec >= 60) {
dev_err(&rx8025_rtcclient->dev,
"rx8025_set_rtctime: seconds out of range: %d\n",
dt->tm_sec);
err = -EINVAL;
goto errout_unlock;
}
if (dt->tm_min < 0 || dt->tm_min >= 60) {
dev_err(&rx8025_rtcclient->dev,
"rx8025_set_rtctime: minutes out of range: %d\n",
dt->tm_min);
err = -EINVAL;
goto errout_unlock;
}
if (dt->tm_hour < 0 || dt->tm_hour >= 24) {
dev_err(&rx8025_rtcclient->dev,
"rx8025_set_rtctime: hours out of range: %d\n",
dt->tm_hour);
err = -EINVAL;
goto errout_unlock;
}
if (dt->tm_wday < 0 || dt->tm_wday >= 7) {
dev_err(&rx8025_rtcclient->dev,
"rx8025_set_rtctime: hours out of range: %d\n",
dt->tm_wday);
err = -EINVAL;
goto errout_unlock;
}
if (dt->tm_mon < 0 || dt->tm_mon >= 12) {
dev_err(&rx8025_rtcclient->dev,
"rx8025_set_rtctime: month out of range: %d\n",
dt->tm_mon);
err = -EINVAL;
goto errout_unlock;
}
if (dt->tm_year < 70 || dt->tm_year >= 170) {
dev_err(&rx8025_rtcclient->dev,
"rx8025_set_rtctime: year out of range: %d\n",
dt->tm_year);
err = -EINVAL;
goto errout_unlock;
}
if (dt->tm_mday > 31 ||
((dt->tm_mon == 3 || dt->tm_mon == 5 ||
dt->tm_mon == 8 || dt->tm_mon == 10)
&& dt->tm_mday > 30) ||
(dt->tm_mon == 1 && dt->tm_mday > 28 +
(dt->tm_year & 3 ? 0 : 1))) {
dev_err(&rx8025_rtcclient->dev,
"rx8025_set_rtctime: day out of range (with month=%d, "
"year=%d): %d\n", dt->tm_mon, dt->tm_year, dt->tm_mon);
err = -EINVAL;
goto errout_unlock;
}
if ((ctrl1 = i2c_smbus_read_byte_data(rx8025_rtcclient,
RX8025_REG_CTRL1 << 4)) < 0) {
dev_err(&rx8025_rtcclient->dev,
"rx8025_set_rtctime: failed to read out "
"RX8025_REG_CTRL1\n");
err = -EINVAL;
goto errout_unlock;
}
dev_dbg(&rx8025_rtcclient->dev,
"rx8025_set_rtctime: ctrl1=0x%x\n", ctrl1);
/*
* Here the read-only bits are written as "0". I'm not sure if that
* is sound.
*/
command[1 + RX8025_REG_SEC] = BIN2BCD(dt->tm_sec);
command[1 + RX8025_REG_MIN] = BIN2BCD(dt->tm_min);
if (ctrl1 & RX8025_BIT_CTRL1_1224)
command[1 + RX8025_REG_HOUR] = BIN2BCD(dt->tm_hour);
else
command[1 + RX8025_REG_HOUR] = (dt->tm_hour >= 12 ? 1 << 5 : 0) |
BIN2BCD((dt->tm_hour + 11) % 12 + 1);
command[1 + RX8025_REG_WDAY] = BIN2BCD(dt->tm_wday);
command[1 + RX8025_REG_MDAY] = BIN2BCD(dt->tm_mday);
command[1 + RX8025_REG_MONTH] = BIN2BCD(dt->tm_mon + 1);
command[1 + RX8025_REG_YEAR] = BIN2BCD(dt->tm_year % 100);
msg.addr = rx8025_rtcclient->addr;
dev_dbg(&rx8025_rtcclient->dev,
"rx8025_set_rtctime: send 0x%02x 0x%02x 0x%02x 0x%02x"
" 0x%02x 0x%02x 0x%02x 0x%02x\n", command[0],
command[1], command[2], command[3], command[4],
command[5], command[6], command[7]);
if ((err = i2c_transfer(rx8025_rtcclient->adapter, &msg, 1)) < 1) {
err = err >= 0 ? -EIO : err;
goto errout_unlock;
}
up(&rx8025_lock);
return 0;
errout_unlock:
up(&rx8025_lock);
return err;
}
// a by xjr 2007.1.26 b
static int rx8025_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
unsigned long arg)
{
struct rtc_time tm;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -