全志 添加外挂RTC Hym8563
add 添加外挂RTC hym8563diff --git a/lichee/linux-3.10/arch/arm/configs/sun8iw11p1smp_androidm_defconfig b/lichee/linux-3.10/arch/arm/configs/sun8iw11p1smp_androidm_defconfig
index ae8b7ec..ad2e2c2 100755
--- a/lichee/linux-3.10/arch/arm/configs/sun8iw11p1smp_androidm_defconfig
+++ b/lichee/linux-3.10/arch/arm/configs/sun8iw11p1smp_androidm_defconfig
@@ -2801,7 +2801,7 @@ CONFIG_RTC_INTF_DEV=y# CONFIG_RTC_DRV_ISL12022 is not set# CONFIG_RTC_DRV_X1205 is not set# CONFIG_RTC_DRV_PCF8523 is not set
-# CONFIG_RTC_DRV_PCF8563 is not set
+CONFIG_RTC_DRV_PCF8563=y# CONFIG_RTC_DRV_PCF8583 is not set# CONFIG_RTC_DRV_M41T80 is not set# CONFIG_RTC_DRV_BQ32K is not set
@@ -2847,7 +2847,7 @@ CONFIG_RTC_INTF_DEV=y## on-CPU RTC drivers#
-CONFIG_RTC_DRV_SUNXI=y
+#CONFIG_RTC_DRV_SUNXI=y# CONFIG_RTC_DRV_SNVS is not set#
diff --git a/lichee/linux-3.10/drivers/rtc/rtc-pcf8563.c b/lichee/linux-3.10/drivers/rtc/rtc-pcf8563.c
old mode 100644
new mode 100755
index 97b354a..b9f4a92
--- a/lichee/linux-3.10/drivers/rtc/rtc-pcf8563.c
+++ b/lichee/linux-3.10/drivers/rtc/rtc-pcf8563.c
@@ -20,287 +20,767 @@#include <linux/slab.h>#include <linux/module.h>#include <linux/of.h>
+#include <linux/delay.h>
+#include <linux/wakelock.h>
+#include <linux/of_gpio.h>
+#include <linux/irqdomain.h>#define DRV_VERSION "0.4.3"-#define PCF8563_REG_ST1 0x00 /* status */
-#define PCF8563_REG_ST2 0x01
+#define RTC_CTL1 0x00
+#define RTC_CTL2 0x01
+#define RTC_SEC 0x02
+#define RTC_MIN 0x03
+#define RTC_HOUR 0x04
+#define RTC_DAY 0x05
+#define RTC_WEEK 0x06
+#define RTC_MON 0x07
+#define RTC_YEAR 0x08
+#define RTC_A_MIN 0x09
+#define RTC_A_HOUR 0x0A
+#define RTC_A_DAY 0x0B
+#define RTC_A_WEEK 0x0C
+#define RTC_CLKOUT 0x0D
+#define RTC_T_CTL 0x0E
+#define RTC_T_COUNT 0x0F
+#define CENTURY 0x80
+#define TI 0x10
+#define AF 0x08
+#define TF 0x04
+#define AIE 0x02
+#define TIE 0x01
+#define FE 0x80
+#define TE 0x80
+#define FD1 0x02
+#define FD0 0x01
+#define TD1 0x02
+#define TD0 0x01
+#define VL 0x80
+
+#define HYM8563_REG_LEN 0x10
+#define HYM8563_RTC_SECTION_LEN 0x07
+#define RTC_SPEED 200 * 1000
+unsigned int g_crtc_used = 0;
+static unsigned char crtc_twi_id = 0;
+
+struct hym8563 {
+ int irq;
+ struct i2c_client *client;
+ struct mutex mutex;
+ struct rtc_device *rtc;
+ struct rtc_wkalrm alarm;
+ struct wake_lock wake_lock;
+};
+static struct i2c_client *gClient = NULL;-#define PCF8563_REG_SC 0x02 /* datetime */
-#define PCF8563_REG_MN 0x03
-#define PCF8563_REG_HR 0x04
-#define PCF8563_REG_DM 0x05
-#define PCF8563_REG_DW 0x06
-#define PCF8563_REG_MO 0x07
-#define PCF8563_REG_YR 0x08
+static int i2c_master_reg8_send(const struct i2c_client *client, const char reg, const char *buf, int count, int scl_rate)
+{
+ struct i2c_adapter *adap=client->adapter;
+ struct i2c_msg msg;
+ int ret;
+ char *tx_buf = (char *)kzalloc(count + 1, GFP_KERNEL);
+ if(!tx_buf)
+ return -ENOMEM;
+ tx_buf[0] = reg;
+ memcpy(tx_buf+1, buf, count); -#define PCF8563_REG_AMN 0x09 /* alarm */
-#define PCF8563_REG_AHR 0x0A
-#define PCF8563_REG_ADM 0x0B
-#define PCF8563_REG_ADW 0x0C
+ msg.addr = client->addr;
+ msg.flags = client->flags;
+ msg.len = count + 1;
+ msg.buf = (char *)tx_buf;
+ //msg.scl_rate = scl_rate;-#define PCF8563_REG_CLKO 0x0D /* clock out */
-#define PCF8563_REG_TMRC 0x0E /* timer control */
-#define PCF8563_REG_TMR 0x0F /* timer */
+ ret = i2c_transfer(adap, &msg, 1);
+ kfree(tx_buf);
+ return (ret == 1) ? count : ret;-#define PCF8563_SC_LV 0x80 /* low voltage */
-#define PCF8563_MO_C 0x80 /* century */
+}
+
+static int i2c_master_reg8_recv(const struct i2c_client *client, const char reg, char *buf, int count, int scl_rate)
+{
+ struct i2c_adapter *adap=client->adapter;
+ struct i2c_msg msgs[2];
+ int ret;
+ char reg_buf = reg;
+
+ msgs[0].addr = client->addr;
+ msgs[0].flags = client->flags;
+ msgs[0].len = 1;
+ msgs[0].buf = ®_buf;
+ //msgs[0].scl_rate = scl_rate;
+
+ msgs[1].addr = client->addr;
+ msgs[1].flags = client->flags | I2C_M_RD;
+ msgs[1].len = count;
+ msgs[1].buf = (char *)buf;
+ //msgs[1].scl_rate = scl_rate;
+
+ ret = i2c_transfer(adap, msgs, 2);
+
+ return (ret == 2)? count : ret;
+}-static struct i2c_driver pcf8563_driver;-struct pcf8563 {
- struct rtc_device *rtc;
- /*
- * The meaning of MO_C bit varies by the chip type.
- * From PCF8563 datasheet: this bit is toggled when the years
- * register overflows from 99 to 00
- * 0 indicates the century is 20xx
- * 1 indicates the century is 19xx
- * From RTC8564 datasheet: this bit indicates change of
- * century. When the year digit data overflows from 99 to 00,
- * this bit is set. By presetting it to 0 while still in the
- * 20th century, it will be set in year 2000, ...
- * There seems no reliable way to know how the system use this
- * bit. So let's do it heuristically, assuming we are live in
- * 1970...2069.
- */
- int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
- int voltage_low; /* incicates if a low_voltage was detected */
-};-/*
- * In the routines that deal directly with the pcf8563 hardware, we use
- * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
- */
-static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
+static int hym8563_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], unsigned len)
+{
+ int ret;
+ ret = i2c_master_reg8_recv(client, reg, buf, len, RTC_SPEED);
+ return ret;
+}
+
+static int hym8563_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], __u16 len){
- struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
- unsigned char buf[13] = { PCF8563_REG_ST1 };
-
- struct i2c_msg msgs[] = {
- {/* setup read ptr */
- .addr = client->addr,
- .len = 1,
- .buf = buf
- },
- {/* read status + date */
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = 13,
- .buf = buf
- },
- };
-
- /* read registers */
- if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
- dev_err(&client->dev, "%s: read error\n", __func__);
- return -EIO;
+ int ret;
+ ret = i2c_master_reg8_send(client, reg, buf, (int)len, RTC_SPEED);
+ return ret;
+}
+
+
+int hym8563_enable_count(struct i2c_client *client, int en)
+{
+ struct hym8563 *hym8563 = i2c_get_clientdata(client);
+ u8 regs[2];
+
+ if (!hym8563)
+ return -1;
+
+ if (en) {
+ hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1);
+ regs[0] |= TIE;
+ hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1);
+ regs[0] = 0;
+ regs[0] |= (TE | TD1);
+ hym8563_i2c_set_regs(client, RTC_T_CTL, regs, 1);
+ }
+ else {
+ hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1);
+ regs[0] &= ~TIE;
+ hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1);
+ regs[0] = 0;
+ regs[0] |= (TD0 | TD1);
+ hym8563_i2c_set_regs(client, RTC_T_CTL, regs, 1);}
+ return 0;
+}
+
+//0 < sec <=255
+int hym8563_set_count(struct i2c_client *client, int sec)
+{
+ struct hym8563 *hym8563 = i2c_get_clientdata(client);
+ u8 regs[2];
+
+ if (!hym8563)
+ return -1;
+
+ if (sec >= 255)
+ regs[0] = 255;
+ else if (sec <= 1)
+ regs[0] = 1;
+ else
+ regs[0] = sec;
+
+ hym8563_i2c_set_regs(client, RTC_T_COUNT, regs, 1);
+
+ return 0;
+}- if (buf[PCF8563_REG_SC] & PCF8563_SC_LV) {
- pcf8563->voltage_low = 1;
- dev_info(&client->dev,
- "low voltage detected, date/time is not reliable.\n");
+
+/*the init of the hym8563 at first time */
+static int hym8563_init_device(struct i2c_client *client)
+{
+ struct hym8563 *hym8563 = i2c_get_clientdata(client);
+ u8 regs[2];
+ int sr;
+
+ mutex_lock(&hym8563->mutex);
+ regs[0]=0;
+ sr = hym8563_i2c_set_regs(client, RTC_CTL1, regs, 1);
+ if (sr < 0)
+ goto exit;
+
+ //disable clkout
+ regs[0] = 0x80;
+ sr = hym8563_i2c_set_regs(client, RTC_CLKOUT, regs, 1);
+ if (sr < 0)
+ goto exit;
+
+ /*enable alarm && count interrupt*/
+ sr = hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1);
+ if (sr < 0)
+ goto exit;
+ regs[0] = 0x0;
+ regs[0] |= (AIE | TIE);
+ sr = hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1);
+ if (sr < 0)
+ goto exit;
+ sr = hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1);
+ if (sr < 0)
+ goto exit;
+
+ sr = hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1);
+ if (sr < 0) {
+ pr_err("read CTL2 err\n");
+ goto exit;
+ }
+
+ if(regs[0] & (AF|TF))
+ {
+ regs[0] &= ~(AF|TF);
+ sr = hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1);}
+
+exit:
+ mutex_unlock(&hym8563->mutex);
+
+ return sr;
+}
+
+static int hym8563_read_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+ struct hym8563 *hym8563 = i2c_get_clientdata(client);
+ u8 regs[HYM8563_RTC_SECTION_LEN] = { 0, };
+ mutex_lock(&hym8563->mutex);
+// for (i = 0; i < HYM8563_RTC_SECTION_LEN; i++) {
+// hym8563_i2c_read_regs(client, RTC_SEC+i, ®s[i], 1);
+// }
+ hym8563_i2c_read_regs(client, RTC_SEC, regs, HYM8563_RTC_SECTION_LEN);
+
+ mutex_unlock(&hym8563->mutex);
+
+ tm->tm_sec = bcd2bin(regs[0x00] & 0x7F);
+ tm->tm_min = bcd2bin(regs[0x01] & 0x7F);
+ tm->tm_hour = bcd2bin(regs[0x02] & 0x3F);
+ tm->tm_mday = bcd2bin(regs[0x03] & 0x3F);
+ tm->tm_wday = bcd2bin(regs[0x04] & 0x07);
+
+ tm->tm_mon = bcd2bin(regs[0x05] & 0x1F) ;
+ tm->tm_mon -= 1; //inorder to cooperate the systerm time
+
+ tm->tm_year = bcd2bin(regs[0x06] & 0xFF);
+ if(regs[5] & 0x80)
+ tm->tm_year += 1900;
+ else
+ tm->tm_year += 2000;
+
+ tm->tm_year -= 1900; //inorder to cooperate the systerm time
+ if(tm->tm_year < 0)
+ tm->tm_year = 0;
+ tm->tm_isdst = 0;
+
+ printk("%4d-%02d-%02d(%d) %02d:%02d:%02d\n",
+ 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ return 0;
+}
+
+static int hym8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ return hym8563_read_datetime(to_i2c_client(dev), tm);
+}- dev_dbg(&client->dev,
- "%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, "
- "mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
- __func__,
- buf[0], buf[1], buf[2], buf[3],
- buf[4], buf[5], buf[6], buf[7],
- buf[8]);
-
-
- tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F);
- tm->tm_min = bcd2bin(buf[PCF8563_REG_MN] & 0x7F);
- tm->tm_hour = bcd2bin(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */
- tm->tm_mday = bcd2bin(buf[PCF8563_REG_DM] & 0x3F);
- tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;
- tm->tm_mon = bcd2bin(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
- tm->tm_year = bcd2bin(buf[PCF8563_REG_YR]);
- if (tm->tm_year < 70)
- tm->tm_year += 100; /* assume we are in 1970...2069 */
- /* detect the polarity heuristically. see note above. */
- pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?
- (tm->tm_year >= 100) : (tm->tm_year < 100);
-
- dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
- "mday=%d, mon=%d, year=%d, wday=%d\n",
- __func__,
- tm->tm_sec, tm->tm_min, tm->tm_hour,
- tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
-
- /* the clock can give out invalid datetime, but we cannot return
- * -EINVAL otherwise hwclock will refuse to set the time on bootup.
- */
- if (rtc_valid_tm(tm) < 0)
- dev_err(&client->dev, "retrieved date/time is not valid.\n");
+static int hym8563_set_time(struct i2c_client *client, struct rtc_time *tm)
+{
+ struct hym8563 *hym8563 = i2c_get_clientdata(client);
+ u8 regs[HYM8563_RTC_SECTION_LEN] = { 0, };
+ u8 mon_day;
+ //u8 ret = 0;
+
+ printk("%4d-%02d-%02d(%d) %02d:%02d:%02d\n",
+ 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+ mon_day = rtc_month_days((tm->tm_mon), tm->tm_year + 1900);
+
+ if(tm->tm_sec >= 60 || tm->tm_sec < 0 ) //set sec
+ regs[0x00] = bin2bcd(0x00);
+ else
+ regs[0x00] = bin2bcd(tm->tm_sec);
+
+ if(tm->tm_min >= 60 || tm->tm_min < 0 ) //set min
+ regs[0x01] = bin2bcd(0x00);
+ else
+ regs[0x01] = bin2bcd(tm->tm_min);
+
+ if(tm->tm_hour >= 24 || tm->tm_hour < 0 ) //set hour
+ regs[0x02] = bin2bcd(0x00);
+ else
+ regs[0x02] = bin2bcd(tm->tm_hour);
+
+ if((tm->tm_mday) > mon_day) //if the input month day is bigger than the biggest day of this month, set the biggest day
+ regs[0x03] = bin2bcd(mon_day);
+ else if((tm->tm_mday) > 0)
+ regs[0x03] = bin2bcd(tm->tm_mday);
+ else if((tm->tm_mday) <= 0)
+ regs[0x03] = bin2bcd(0x01);
+
+ if( tm->tm_year >= 200) // year >= 2100
+ regs[0x06] = bin2bcd(99); //year = 2099
+ else if(tm->tm_year >= 100) // 2000 <= year < 2100
+ regs[0x06] = bin2bcd(tm->tm_year - 100);
+ else if(tm->tm_year >= 0){ // 1900 <= year < 2000
+ regs[0x06] = bin2bcd(tm->tm_year);
+ regs[0x05] |= 0x80;
+ }else{ // year < 1900
+ regs[0x06] = bin2bcd(0); //year = 1900
+ regs[0x05] |= 0x80;
+ }
+ regs[0x04] = bin2bcd(tm->tm_wday); //set the weekday
+ regs[0x05] = (regs[0x05] & 0x80)| (bin2bcd(tm->tm_mon + 1) & 0x7F); //set the month
+
+ mutex_lock(&hym8563->mutex);
+// for(i=0;i<HYM8563_RTC_SECTION_LEN;i++){
+// ret = hym8563_i2c_set_regs(client, RTC_SEC+i, ®s[i], 1);
+// }
+ hym8563_i2c_set_regs(client, RTC_SEC, regs, HYM8563_RTC_SECTION_LEN);
+
+ mutex_unlock(&hym8563->mutex);return 0;}-static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
+static int hym8563_rtc_set_time(struct device *dev, struct rtc_time *tm){
- struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
- int i, err;
- unsigned char buf[9];
-
- dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
- "mday=%d, mon=%d, year=%d, wday=%d\n",
- __func__,
- tm->tm_sec, tm->tm_min, tm->tm_hour,
- tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
-
- /* hours, minutes and seconds */
- buf[PCF8563_REG_SC] = bin2bcd(tm->tm_sec);
- buf[PCF8563_REG_MN] = bin2bcd(tm->tm_min);
- buf[PCF8563_REG_HR] = bin2bcd(tm->tm_hour);
-
- buf[PCF8563_REG_DM] = bin2bcd(tm->tm_mday);
-
- /* month, 1 - 12 */
- buf[PCF8563_REG_MO] = bin2bcd(tm->tm_mon + 1);
-
- /* year and century */
- buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year % 100);
- if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
- buf[PCF8563_REG_MO] |= PCF8563_MO_C;
-
- buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
-
- /* write register's data */
- for (i = 0; i < 7; i++) {
- unsigned char data[2] = { PCF8563_REG_SC + i,
- buf[PCF8563_REG_SC + i] };
-
- err = i2c_master_send(client, data, sizeof(data));
- if (err != sizeof(data)) {
- dev_err(&client->dev,
- "%s: err=%d addr=%02x, data=%02x\n",
- __func__, err, data[0], data[1]);
- return -EIO;
+ return hym8563_set_time(to_i2c_client(dev), tm);
+}
+
+static int hym8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct hym8563 *hym8563 = i2c_get_clientdata(client);
+ u8 regs[4] = { 0, };
+
+ printk("enter\n");
+ mutex_lock(&hym8563->mutex);
+ hym8563_i2c_read_regs(client, RTC_A_MIN, regs, 4);
+ regs[0] = 0x0;
+ regs[0] |= TIE;
+ hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1);
+ mutex_unlock(&hym8563->mutex);
+ return 0;
+}
+
+static int hym8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct hym8563 *hym8563 = i2c_get_clientdata(client);
+ struct rtc_time now, *tm = &alarm->time;
+ u8 regs[4] = { 0, };
+ u8 mon_day;
+ unsigned long alarm_sec, now_sec;
+ int diff_sec = 0;
+
+ printk("%4d-%02d-%02d(%d) %02d:%02d:%02d enabled %d\n",
+ 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, tm->tm_wday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec, alarm->enabled);
+
+
+ hym8563_read_datetime(client, &now);
+
+
+ mutex_lock(&hym8563->mutex);
+ rtc_tm_to_time(tm, &alarm_sec);
+ rtc_tm_to_time(&now, &now_sec);
+
+ diff_sec = alarm_sec - now_sec;
+
+ if((diff_sec > 0) && (diff_sec < 256))
+ {
+ printk("%s:diff_sec= %ds , use time\n",__func__, diff_sec);
+
+ if (alarm->enabled == 1)
+ {
+ hym8563_set_count(client, diff_sec);
+ hym8563_enable_count(client, 1);}
+
+ else
+ {
+ hym8563_enable_count(client, 0);
+ }
+
+ }
+ else
+ {
+ printk("%s:diff_sec= %ds , use alarm\n",__func__, diff_sec);
+ hym8563_enable_count(client, 0);
+
+ if(tm->tm_sec > 0)
+ {
+ rtc_tm_to_time(tm, &alarm_sec);
+ rtc_time_to_tm(alarm_sec, tm);
+ }
+
+ hym8563->alarm = *alarm;
+
+ regs[0] = 0x0;
+ hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1);
+ mon_day = rtc_month_days(tm->tm_mon, tm->tm_year + 1900);
+ hym8563_i2c_read_regs(client, RTC_A_MIN, regs, 4);
+
+ if (tm->tm_min >= 60 || tm->tm_min < 0) //set min
+ regs[0x00] = bin2bcd(0x00) & 0x7f;
+ else
+ regs[0x00] = bin2bcd(tm->tm_min) & 0x7f;
+ if (tm->tm_hour >= 24 || tm->tm_hour < 0) //set hour
+ regs[0x01] = bin2bcd(0x00) & 0x7f;
+ else
+ regs[0x01] = bin2bcd(tm->tm_hour) & 0x7f;
+ regs[0x03] = bin2bcd (tm->tm_wday) & 0x7f;
+
+ /* if the input month day is bigger than the biggest day of this month, set the biggest day */
+ if (tm->tm_mday > mon_day)
+ regs[0x02] = bin2bcd(mon_day) & 0x7f;
+ else if (tm->tm_mday > 0)
+ regs[0x02] = bin2bcd(tm->tm_mday) & 0x7f;
+ else if (tm->tm_mday <= 0)
+ regs[0x02] = bin2bcd(0x01) & 0x7f;
+
+ hym8563_i2c_set_regs(client, RTC_A_MIN, regs, 4);
+ hym8563_i2c_read_regs(client, RTC_A_MIN, regs, 4);
+ hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1);
+ if (alarm->enabled == 1)
+ regs[0] |= AIE;
+ else
+ regs[0] &= 0x0;
+ hym8563_i2c_set_regs(client, RTC_CTL2, regs, 1);
+ hym8563_i2c_read_regs(client, RTC_CTL2, regs, 1);
+
+ if(diff_sec <= 0)
+ {
+ pr_info("alarm sec <= now sec\n");
+ }
+}
+
+ mutex_unlock(&hym8563->mutex);return 0;}-#ifdef CONFIG_RTC_INTF_DEV
-static int pcf8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
+static int hym8563_i2c_open_alarm(struct i2c_client *client){
- struct pcf8563 *pcf8563 = i2c_get_clientdata(to_i2c_client(dev));
- struct rtc_time tm;
+ u8 data;
+ hym8563_i2c_read_regs(client, RTC_CTL2, &data, 1);
+ data |= AIE;
+ hym8563_i2c_set_regs(client, RTC_CTL2, &data, 1);- switch (cmd) {
- case RTC_VL_READ:
- if (pcf8563->voltage_low)
- dev_info(dev, "low voltage detected, date/time is not reliable.\n");
+ return 0;
+}- if (copy_to_user((void __user *)arg, &pcf8563->voltage_low,
- sizeof(int)))
- return -EFAULT;
- return 0;
- case RTC_VL_CLR:
- /*
- * Clear the VL bit in the seconds register in case
- * the time has not been set already (which would
- * have cleared it). This does not really matter
- * because of the cached voltage_low value but do it
- * anyway for consistency.
- */
- if (pcf8563_get_datetime(to_i2c_client(dev), &tm))
- pcf8563_set_datetime(to_i2c_client(dev), &tm);
-
- /* Clear the cached value. */
- pcf8563->voltage_low = 0;
+static int hym8563_i2c_close_alarm(struct i2c_client *client)
+{
+ u8 data;
+ hym8563_i2c_read_regs(client, RTC_CTL2, &data, 1);
+ data &= ~AIE;
+ hym8563_i2c_set_regs(client, RTC_CTL2, &data, 1);- return 0;
+ return 0;
+}
+
+static int hym8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+
+ switch (cmd) {
+ case RTC_AIE_OFF:
+ if(hym8563_i2c_close_alarm(client) < 0)
+ goto err;
+ break;
+ case RTC_AIE_ON:
+ if(hym8563_i2c_open_alarm(client))
+ goto err;
+ break;default:return -ENOIOCTLCMD;
- }
+ }
+ return 0;
+err:
+ return -EIO;}#else
-#define pcf8563_rtc_ioctl NULL
+#define hym8563_rtc_ioctl NULL#endif-static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
+#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
+static int hym8563_rtc_proc(struct device *dev, struct seq_file *seq){
- return pcf8563_get_datetime(to_i2c_client(dev), tm);
+ return 0;}
+#else
+#define hym8563_rtc_proc NULL
+#endif-static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
+static irqreturn_t hym8563_wakeup_irq(int irq, void *data){
- return pcf8563_set_datetime(to_i2c_client(dev), tm);
+ struct hym8563 *hym8563 = data;
+ struct i2c_client *client = hym8563->client;
+ u8 value;
+
+ mutex_lock(&hym8563->mutex);
+ hym8563_i2c_read_regs(client, RTC_CTL2, &value, 1);
+ value &= ~(AF|TF);
+ hym8563_i2c_set_regs(client, RTC_CTL2, &value, 1);
+ mutex_unlock(&hym8563->mutex);
+
+ rtc_update_irq(hym8563->rtc, 1, RTC_IRQF | RTC_AF | RTC_UF);
+
+ //printk("%s:irq=%d\n",__func__,irq);
+ return IRQ_HANDLED;}-static const struct rtc_class_ops pcf8563_rtc_ops = {
- .ioctl = pcf8563_rtc_ioctl,
- .read_time = pcf8563_rtc_read_time,
- .set_time = pcf8563_rtc_set_time,
+static const struct rtc_class_ops hym8563_rtc_ops = {
+ .read_time = hym8563_rtc_read_time,
+ .set_time = hym8563_rtc_set_time,
+ .read_alarm = hym8563_rtc_read_alarm,
+ .set_alarm = hym8563_rtc_set_alarm,
+ .ioctl = hym8563_rtc_ioctl,
+ .proc = hym8563_rtc_proc};-static int pcf8563_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int hym8563_probe(struct i2c_client *client, const struct i2c_device_id *id){
- struct pcf8563 *pcf8563;
-
- dev_dbg(&client->dev, "%s\n", __func__);
-
+ int rc = 0;
+ u8 reg = 0;
+ struct hym8563 *hym8563;
+ struct rtc_device *rtc = NULL;
+ struct rtc_time tm_read, tm = {
+ .tm_wday = 6,
+ .tm_year = 111,
+ .tm_mon = 0,
+ .tm_mday = 1,
+ .tm_hour = 12,
+ .tm_min = 0,
+ .tm_sec = 0,
+ };
+
+ struct device_node *np = of_find_node_by_name(NULL,"crtc");
+ unsigned long irq_flags = 0;
+ int result;
+ printk("hym8563_probe\n");if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))return -ENODEV;
-
- pcf8563 = devm_kzalloc(&client->dev, sizeof(struct pcf8563),
- GFP_KERNEL);
- if (!pcf8563)
+
+ hym8563 = devm_kzalloc(&client->dev,sizeof(*hym8563), GFP_KERNEL);
+ if (!hym8563) {return -ENOMEM;
+ }- dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+ gClient = client;
+ hym8563->client = client;
+ hym8563->alarm.enabled = 0;
+ client->irq = 0;
+ mutex_init(&hym8563->mutex);
+ wake_lock_init(&hym8563->wake_lock, WAKE_LOCK_SUSPEND, "rtc_hym8563");
+ i2c_set_clientdata(client, hym8563);
+
+ hym8563_init_device(client);
+ hym8563_enable_count(client, 0);
+
+ // check power down
+ printk("hym8563_probe 11\n");
+ hym8563_i2c_read_regs(client,RTC_SEC,®,1);
+ if (reg&0x80) {
+ dev_info(&client->dev, "clock/calendar information is no longer guaranteed\n");
+ hym8563_set_time(client, &tm);
+ }
+printk("hym8563_probe reg=0x%x\n",reg);
+ hym8563_read_datetime(client, &tm_read); //read time from hym8563
+
+ if(((tm_read.tm_year < 70) | (tm_read.tm_year > 137 )) | (tm_read.tm_mon == -1) | (rtc_valid_tm(&tm_read) != 0)) //if the hym8563 haven't initialized
+ {
+ hym8563_set_time(client, &tm); //initialize the hym8563
+ }
+ if(!np){
+ printk("rtc hym8563_probe can't get irq gpio\n");
+ }else {
+ printk("rtc hym8563_probe get irq gpio\n");
+ client->irq = of_get_named_gpio_flags(np, "crtc_irq_gpio", 0,(enum of_gpio_flags *)&irq_flags);
+ if(client->irq >= 0)
+ {
+ printk("rtc hym8563_probe get irq\n");
+ hym8563->irq = gpio_to_irq(client->irq);
+ //result = devm_request_irq(&client->dev, hym8563->irq, hym8563_wakeup_irq,
+ // irq_flags | IRQF_ONESHOT, client->dev.driver->name, hym8563);
+ result = devm_request_threaded_irq(&client->dev, hym8563->irq, NULL, hym8563_wakeup_irq, irq_flags | IRQF_ONESHOT, client->dev.driver->name,hym8563 );
+ if (result) {
+ printk( "%s:fail rtc to request irq = %d, ret = 0x%x\n",__func__, hym8563->irq, result);
+ goto exit;
+ }
+ enable_irq_wake(hym8563->irq);
+ device_init_wakeup(&client->dev, 1);
+ }
+ }
+ //device_init_wakeup(&client->dev, 1);
+ rtc = devm_rtc_device_register(&client->dev,
+ client->name,
+ &hym8563_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc)) {
+ rc = PTR_ERR(rtc);
+ rtc = NULL;
+ goto exit;
+ }
+ hym8563->rtc = rtc;
+printk("hym8563_probe ok\n");
+ return 0;- i2c_set_clientdata(client, pcf8563);
+exit:
+ if (hym8563) {
+ wake_lock_destroy(&hym8563->wake_lock);
+ }
+ return rc;
+}- pcf8563->rtc = devm_rtc_device_register(&client->dev,
- pcf8563_driver.driver.name,
- &pcf8563_rtc_ops, THIS_MODULE);
+static int hym8563_remove(struct i2c_client *client)
+{
+ struct hym8563 *hym8563 = i2c_get_clientdata(client);- if (IS_ERR(pcf8563->rtc))
- return PTR_ERR(pcf8563->rtc);
+ wake_lock_destroy(&hym8563->wake_lock);return 0;}-static int pcf8563_remove(struct i2c_client *client)
+
+void hym8563_shutdown(struct i2c_client * client)
+{ u8 regs[2];
+ int ret;
+ //disable clkout
+ regs[0] = 0x00;
+ ret=hym8563_i2c_set_regs(client, RTC_CLKOUT, regs, 1);
+ if(ret<0)
+ printk("rtc shutdown is error\n");
+}
+
+static int pcf8563_detect(struct i2c_client *new_client, struct i2c_board_info *info){
- return 0;
+ struct i2c_adapter *adapter = new_client->adapter;
+
+ printk(" richard rtc pcf8563_detect: %s:bus[%d] addr[0x%x]\n", __func__, adapter->nr, new_client->addr);
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ if (crtc_twi_id == adapter->nr) {
+ printk("rtc pcf8563_detect crtc_twi_id=%d\n",crtc_twi_id);
+ strlcpy(info->type, "rtc_hym8563", I2C_NAME_SIZE);
+ return 0;
+ }
+
+ return -ENODEV;}-static const struct i2c_device_id pcf8563_id[] = {
- { "pcf8563", 0 },
- { "rtc8564", 0 },
+
+static const struct i2c_device_id hym8563_id[] = {
+ { "rtc_hym8563", 0 },{ }};
-MODULE_DEVICE_TABLE(i2c, pcf8563_id);
+MODULE_DEVICE_TABLE(i2c, hym8563_id);-#ifdef CONFIG_OF
-static const struct of_device_id pcf8563_of_match[] = {
- { .compatible = "nxp,pcf8563" },
- {}
+static struct of_device_id rtc_dt_ids[] = {
+ { .compatible = "rtc,hym8563" },
+ {},};
-MODULE_DEVICE_TABLE(of, pcf8563_of_match);
-#endif-static struct i2c_driver pcf8563_driver = {
+static const unsigned short normal_i2c[] = { 0x51, I2C_CLIENT_END };
+struct i2c_driver hym8563_driver = {
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,.driver = {
- .name = "rtc-pcf8563",
+ .name = "rtc_hym8563",.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(pcf8563_of_match),
+ .of_match_table = of_match_ptr(rtc_dt_ids),},
- .probe = pcf8563_probe,
- .remove = pcf8563_remove,
- .id_table = pcf8563_id,
+ .probe = hym8563_probe,
+ .remove = hym8563_remove,
+ .detect = pcf8563_detect,
+ //.shutdown=hym8563_shutdown,
+ .id_table = hym8563_id,
+ .address_list = normal_i2c,};-module_i2c_driver(pcf8563_driver);
+
+
+static int crtc_fetch_sysconfig_para()
+{
+ int ret = -1;
+
+
+ struct device_node *np = NULL;
+ np = of_find_node_by_name(NULL,"crtc");
+ if (!np) {
+ printk("ERROR! get crtc failed, func:%s, line:%d\n",__FUNCTION__, __LINE__);
+ goto devicetree_get_item_err;
+ }
+printk("crtc crtc_fetch_sysconfig_para\n");
+ if (!of_device_is_available(np)) {
+ printk("%s: crtc is not used\n", __func__);
+ goto devicetree_get_item_err;
+ }else {
+ g_crtc_used = 1;
+ }
+printk("crtc crtc_fetch_sysconfig_para crtc_used=%d\n",g_crtc_used);
+ if(1 == g_crtc_used){
+ ret = of_property_read_u32(np, "crtc_twi_id", &crtc_twi_id);
+ if (ret) {
+ pr_err("get crtc_twi_id is fail, %d\n", ret);
+ goto devicetree_get_item_err;
+ }
+
+ }else{
+ pr_err("%s crtc_unused \n",__func__);
+ }
+printk("crtc crtc_fetch_sysconfig_para 2\n");
+ return ret;
+
+devicetree_get_item_err:
+printk("crtc crtc_fetch_sysconfig_para 3\n");
+ ret = -1;
+ return ret;
+
+}
+
+static int __init rtc_pcf8563_init(void)
+{
+ int ret;
+
+
+ if (crtc_fetch_sysconfig_para()) {
+ printk("fetch_crtc_sysconfig_para failed!\n");
+ return -1;
+ }
+ printk("step4 : rtc_pcf8563_init crtc_used=%d,crtc_twi_id=%d\n",g_crtc_used,crtc_twi_id);
+
+ if (g_crtc_used == 0) {
+ printk("*** crtc_used set to 0 !\n");
+ return -1;
+ }
+//gadap = i2c_get_adapter(crtc_twi_id);
+ ret = i2c_add_driver(&hym8563_driver);
+ if (ret < 0) {
+ printk("add pcf8563 i2c driver failed\n");
+ return -ENODEV;
+ }
+ /*ret = i2c_register_board_info(crtc_twi_id, pcf8563_i2c_board_info, ARRAY_SIZE(pcf8563_i2c_board_info));
+ if (ret < 0) {
+ printk("rtc_i2c_board_info add failed\n");
+ return ret;
+ }
+*/
+printk("step4 : rtc_pcf8563_init ok\n");
+ return (ret);
+}
+
+/*----------------------------------------------------------------------------*/
+static void __exit rtc_pcf8563_exit(void)
+{
+
+ i2c_del_driver(&hym8563_driver);
+}
+
+module_init(rtc_pcf8563_init);
+module_exit(rtc_pcf8563_exit);
+//module_i2c_driver(pcf8563_driver);MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");
diff --git a/lichee/linux-3.10/drivers/rtc/rtc-pcf8563123.c b/lichee/linux-3.10/drivers/rtc/rtc-pcf8563123.c
new file mode 100755
index 0000000..e22f7bf
--- /dev/null
+++ b/lichee/linux-3.10/drivers/rtc/rtc-pcf8563123.c
@@ -0,0 +1,415 @@
+/*
+ * An I2C driver for the Philips PCF8563 RTC
+ * Copyright 2005-06 Tower Technologies
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ * Maintainers: http://www.nslu2-linux.org/
+ *
+ * based on the other drivers in this same directory.
+ *
+ * http://www.semiconductors.philips.com/acrobat/datasheets/PCF8563-04.pdf
+ *
+ * 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.
+ */
+
+#include <linux/i2c.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/of.h>
+
+#define DRV_VERSION "0.4.3"
+
+#define PCF8563_REG_ST1 0x00 /* status */
+#define PCF8563_REG_ST2 0x01
+
+#define PCF8563_REG_SC 0x02 /* datetime */
+#define PCF8563_REG_MN 0x03
+#define PCF8563_REG_HR 0x04
+#define PCF8563_REG_DM 0x05
+#define PCF8563_REG_DW 0x06
+#define PCF8563_REG_MO 0x07
+#define PCF8563_REG_YR 0x08
+
+#define PCF8563_REG_AMN 0x09 /* alarm */
+#define PCF8563_REG_AHR 0x0A
+#define PCF8563_REG_ADM 0x0B
+#define PCF8563_REG_ADW 0x0C
+
+#define PCF8563_REG_CLKO 0x0D /* clock out */
+#define PCF8563_REG_TMRC 0x0E /* timer control */
+#define PCF8563_REG_TMR 0x0F /* timer */
+
+#define PCF8563_SC_LV 0x80 /* low voltage */
+#define PCF8563_MO_C 0x80 /* century */
+
+static struct i2c_driver pcf8563_driver;
+struct i2c_adapter *gadap;
+static unsigned char crtc_twi_id = 0;
+unsigned int g_crtc_used = 0;
+struct pcf8563 {
+ struct rtc_device *rtc;
+ /*
+ * The meaning of MO_C bit varies by the chip type.
+ * From PCF8563 datasheet: this bit is toggled when the years
+ * register overflows from 99 to 00
+ * 0 indicates the century is 20xx
+ * 1 indicates the century is 19xx
+ * From RTC8564 datasheet: this bit indicates change of
+ * century. When the year digit data overflows from 99 to 00,
+ * this bit is set. By presetting it to 0 while still in the
+ * 20th century, it will be set in year 2000, ...
+ * There seems no reliable way to know how the system use this
+ * bit. So let's do it heuristically, assuming we are live in
+ * 1970...2069.
+ */
+ int c_polarity; /* 0: MO_C=1 means 19xx, otherwise MO_C=1 means 20xx */
+ int voltage_low; /* incicates if a low_voltage was detected */
+};
+
+/*
+ * In the routines that deal directly with the pcf8563 hardware, we use
+ * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
+ */
+static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+ struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
+ unsigned char buf[13] = { PCF8563_REG_ST1 };
+
+ struct i2c_msg msgs[] = {
+ {/* setup read ptr */
+ .addr = client->addr,
+ .len = 1,
+ .buf = buf
+ },
+ {/* read status + date */
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 13,
+ .buf = buf
+ },
+ };
+
+ /* read registers */
+ if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
+ dev_err(&client->dev, "%s: read error\n", __func__);
+ return -EIO;
+ }
+
+ if (buf[PCF8563_REG_SC] & PCF8563_SC_LV) {
+ pcf8563->voltage_low = 1;
+ dev_info(&client->dev,
+ "low voltage detected, date/time is not reliable.\n");
+ }
+
+ dev_dbg(&client->dev,
+ "%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, "
+ "mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
+ __func__,
+ buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7],
+ buf[8]);
+
+
+ tm->tm_sec = bcd2bin(buf[PCF8563_REG_SC] & 0x7F);
+ tm->tm_min = bcd2bin(buf[PCF8563_REG_MN] & 0x7F);
+ tm->tm_hour = bcd2bin(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */
+ tm->tm_mday = bcd2bin(buf[PCF8563_REG_DM] & 0x3F);
+ tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;
+ tm->tm_mon = bcd2bin(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
+ tm->tm_year = bcd2bin(buf[PCF8563_REG_YR]);
+ if (tm->tm_year < 70)
+ tm->tm_year += 100; /* assume we are in 1970...2069 */
+ /* detect the polarity heuristically. see note above. */
+ pcf8563->c_polarity = (buf[PCF8563_REG_MO] & PCF8563_MO_C) ?
+ (tm->tm_year >= 100) : (tm->tm_year < 100);
+
+ dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+ "mday=%d, mon=%d, year=%d, wday=%d\n",
+ __func__,
+ tm->tm_sec, tm->tm_min, tm->tm_hour,
+ tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+ /* the clock can give out invalid datetime, but we cannot return
+ * -EINVAL otherwise hwclock will refuse to set the time on bootup.
+ */
+ if (rtc_valid_tm(tm) < 0)
+ dev_err(&client->dev, "retrieved date/time is not valid.\n");
+
+ return 0;
+}
+
+static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+ struct pcf8563 *pcf8563 = i2c_get_clientdata(client);
+ int i, err;
+ unsigned char buf[9];
+
+ dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
+ "mday=%d, mon=%d, year=%d, wday=%d\n",
+ __func__,
+ tm->tm_sec, tm->tm_min, tm->tm_hour,
+ tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+ /* hours, minutes and seconds */
+ buf[PCF8563_REG_SC] = bin2bcd(tm->tm_sec);
+ buf[PCF8563_REG_MN] = bin2bcd(tm->tm_min);
+ buf[PCF8563_REG_HR] = bin2bcd(tm->tm_hour);
+
+ buf[PCF8563_REG_DM] = bin2bcd(tm->tm_mday);
+
+ /* month, 1 - 12 */
+ buf[PCF8563_REG_MO] = bin2bcd(tm->tm_mon + 1);
+
+ /* year and century */
+ buf[PCF8563_REG_YR] = bin2bcd(tm->tm_year % 100);
+ if (pcf8563->c_polarity ? (tm->tm_year >= 100) : (tm->tm_year < 100))
+ buf[PCF8563_REG_MO] |= PCF8563_MO_C;
+
+ buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
+
+ /* write register's data */
+ for (i = 0; i < 7; i++) {
+ unsigned char data[2] = { PCF8563_REG_SC + i,
+ buf[PCF8563_REG_SC + i] };
+
+ err = i2c_master_send(client, data, sizeof(data));
+ if (err != sizeof(data)) {
+ dev_err(&client->dev,
+ "%s: err=%d addr=%02x, data=%02x\n",
+ __func__, err, data[0], data[1]);
+ return -EIO;
+ }
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_RTC_INTF_DEV
+static int pcf8563_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ struct pcf8563 *pcf8563 = i2c_get_clientdata(to_i2c_client(dev));
+ struct rtc_time tm;
+
+ switch (cmd) {
+ case RTC_VL_READ:
+ if (pcf8563->voltage_low)
+ dev_info(dev, "low voltage detected, date/time is not reliable.\n");
+
+ if (copy_to_user((void __user *)arg, &pcf8563->voltage_low,
+ sizeof(int)))
+ return -EFAULT;
+ return 0;
+ case RTC_VL_CLR:
+ /*
+ * Clear the VL bit in the seconds register in case
+ * the time has not been set already (which would
+ * have cleared it). This does not really matter
+ * because of the cached voltage_low value but do it
+ * anyway for consistency.
+ */
+ if (pcf8563_get_datetime(to_i2c_client(dev), &tm))
+ pcf8563_set_datetime(to_i2c_client(dev), &tm);
+
+ /* Clear the cached value. */
+ pcf8563->voltage_low = 0;
+
+ return 0;
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+#else
+#define pcf8563_rtc_ioctl NULL
+#endif
+
+static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ return pcf8563_get_datetime(to_i2c_client(dev), tm);
+}
+
+static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ return pcf8563_set_datetime(to_i2c_client(dev), tm);
+}
+
+static const struct rtc_class_ops pcf8563_rtc_ops = {
+ .ioctl = pcf8563_rtc_ioctl,
+ .read_time = pcf8563_rtc_read_time,
+ .set_time = pcf8563_rtc_set_time,
+};
+
+static int pcf8563_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct pcf8563 *pcf8563;
+
+ dev_dbg(&client->dev, "%s\n", __func__);
+printk("rtc pcf8563_probe\n");
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ return -ENODEV;
+printk("rtc pcf8563_probe 1\n");
+ pcf8563 = devm_kzalloc(&client->dev, sizeof(struct pcf8563),
+ GFP_KERNEL);
+ if (!pcf8563)
+ return -ENOMEM;
+printk("rtc pcf8563_probe 2\n");
+ dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+
+ i2c_set_clientdata(client, pcf8563);
+
+ pcf8563->rtc = devm_rtc_device_register(&client->dev,
+ pcf8563_driver.driver.name,
+ &pcf8563_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(pcf8563->rtc))
+ return PTR_ERR(pcf8563->rtc);
+printk("rtc pcf8563_probe ok\n");
+ return 0;
+}
+
+static int pcf8563_detect(struct i2c_client *new_client, struct i2c_board_info *info)
+{
+ struct i2c_adapter *adapter = new_client->adapter;
+
+ printk(" richard rtc pcf8563_detect: %s:bus[%d] addr[0x%x]\n", __func__, adapter->nr, new_client->addr);
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ if (crtc_twi_id == adapter->nr) {
+ printk("rtc pcf8563_detect crtc_twi_id=%d\n",crtc_twi_id);
+ strlcpy(info->type, "pcf8563", I2C_NAME_SIZE);
+ return 0;
+ }
+
+ return -ENODEV;
+}
+
+static int pcf8563_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+static const struct i2c_device_id pcf8563_id[] = {
+ { "pcf8563", 0 },
+ //{ "rtc8564", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, pcf8563_id);
+
+//#ifdef CONFIG_OF
+static const struct of_device_id pcf8563_of_match[] = {
+ { .compatible = "pcf8563", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pcf8563_of_match);
+//#endif
+static const unsigned short normal_i2c[] = { 0x51, I2C_CLIENT_END };
+static struct i2c_driver pcf8563_driver = {
+ .class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+ .driver = {
+ .name = "pcf8563",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(pcf8563_of_match),
+ },
+ .probe = pcf8563_probe,
+ .remove = pcf8563_remove,
+ .detect = pcf8563_detect,
+ .id_table = pcf8563_id,
+ .address_list = normal_i2c,
+};
+
+static int crtc_fetch_sysconfig_para()
+{
+ int ret = -1;
+
+
+ struct device_node *np = NULL;
+ np = of_find_node_by_name(NULL,"crtc");
+ if (!np) {
+ printk("ERROR! get crtc failed, func:%s, line:%d\n",__FUNCTION__, __LINE__);
+ goto devicetree_get_item_err;
+ }
+printk("crtc crtc_fetch_sysconfig_para\n");
+ if (!of_device_is_available(np)) {
+ printk("%s: crtc is not used\n", __func__);
+ goto devicetree_get_item_err;
+ }else {
+ g_crtc_used = 1;
+ }
+printk("crtc crtc_fetch_sysconfig_para crtc_used=%d\n",g_crtc_used);
+ if(1 == g_crtc_used){
+ ret = of_property_read_u32(np, "crtc_twi_id", &crtc_twi_id);
+ if (ret) {
+ pr_err("get crtc_twi_id is fail, %d\n", ret);
+ goto devicetree_get_item_err;
+ }
+
+ }else{
+ pr_err("%s crtc_unused \n",__func__);
+ }
+printk("crtc crtc_fetch_sysconfig_para 2\n");
+ return ret;
+
+devicetree_get_item_err:
+printk("crtc crtc_fetch_sysconfig_para 3\n");
+ ret = -1;
+ return ret;
+
+}
+static struct i2c_board_info __initdata pcf8563_i2c_board_info[] = {
+ {
+ .type = "pcf8563",
+ .addr = 0x51,
+ },
+};
+static int __init rtc_pcf8563_init(void)
+{
+ int ret;
+
+
+ if (crtc_fetch_sysconfig_para()) {
+ printk("fetch_crtc_sysconfig_para failed!\n");
+ return -1;
+ }
+ printk("step4 : rtc_pcf8563_init crtc_used=%d,crtc_twi_id=%d\n",g_crtc_used,crtc_twi_id);
+
+ if (g_crtc_used == 0) {
+ printk("*** crtc_used set to 0 !\n");
+ return -1;
+ }
+//gadap = i2c_get_adapter(crtc_twi_id);
+ ret = i2c_add_driver(&pcf8563_driver);
+ if (ret < 0) {
+ printk("add pcf8563 i2c driver failed\n");
+ return -ENODEV;
+ }
+ /*ret = i2c_register_board_info(crtc_twi_id, pcf8563_i2c_board_info, ARRAY_SIZE(pcf8563_i2c_board_info));
+ if (ret < 0) {
+ printk("rtc_i2c_board_info add failed\n");
+ return ret;
+ }
+*/
+printk("step4 : rtc_pcf8563_init ok\n");
+ return (ret);
+}
+
+/*----------------------------------------------------------------------------*/
+static void __exit rtc_pcf8563_exit(void)
+{
+
+ i2c_del_driver(&pcf8563_driver);
+}
+
+module_init(rtc_pcf8563_init);
+module_exit(rtc_pcf8563_exit);
+//module_i2c_driver(pcf8563_driver);
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
diff --git a/lichee/linux-3.10/drivers/rtc/rtc-sunxi.c b/lichee/linux-3.10/drivers/rtc/rtc-sunxi.c
index a47ac21..075dc1b 100755
--- a/lichee/linux-3.10/drivers/rtc/rtc-sunxi.c
+++ b/lichee/linux-3.10/drivers/rtc/rtc-sunxi.c
@@ -448,17 +448,20 @@ static int sunxi_rtc_probe(struct platform_device *pdev)dev_err(&pdev->dev, "Unable to setup RTC data\n");return -ENODEV;}
-
+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);if (!chip)return -ENOMEM;
-
+ platform_set_drvdata(pdev, chip);chip->dev = &pdev->dev;res = platform_get_resource(pdev, IORESOURCE_MEM, 0);chip->base = devm_ioremap_resource(&pdev->dev, res);
-
+
+ //modify
+ writel(0, chip->base + SUNXI_VDD_RTC);
+ if (IS_ERR(chip->base))return PTR_ERR(chip->base);@@ -541,7 +544,7 @@ static int sunxi_rtc_probe(struct platform_device *pdev)dev_info(&pdev->dev, "RTC enabled\n");return 0;
-
+ fail:pm_runtime_put_sync(&pdev->dev);pm_runtime_disable(&pdev->dev);
diff --git a/lichee/linux-3.10/drivers/rtc/rtc-sunxi.h b/lichee/linux-3.10/drivers/rtc/rtc-sunxi.h
old mode 100644
new mode 100755
index 165ef5e..caf1e11
--- a/lichee/linux-3.10/drivers/rtc/rtc-sunxi.h
+++ b/lichee/linux-3.10/drivers/rtc/rtc-sunxi.h
@@ -23,6 +23,8 @@#define SUNXI_ALARM_CONFIG 0x0050#define SUNXI_ALRM_WAKEUP_OUTPUT_EN BIT(0)+#define SUNXI_VDD_RTC 0x0190
+/* alarm0 which based on seconds can power on system,* while alarm1 can't, so alarm1 is not used.*/
全志 添加外挂RTC Hym8563相关推荐
- 电脑本地视频怎么添加外挂字幕-奇它博客
我们通过网盘(天翼网盘.迅雷盘等)下载的高画质电影没有字幕或者没有中文字幕的时候,可以通过下载外挂字幕的方法来换字幕.当然如果视频本身使用了内嵌字幕,那么内嵌字幕是无法被替换的.电脑本地视频怎么添加外 ...
- 杰理之添加外挂 flash 驱动及实现音乐播放功能
功能简单说明:在音乐模式下实现播放外挂 flash 里面的歌曲的功能,操作方式与 SD 卡,U 盘一致. 注意:flash 需预先把音乐文件和 fat 文件系统烧录进 flash.目前不支持写操作. ...
- 杰里之AC692x 添加外挂 flash 驱动及实现音乐播放功能篇
功能简单说明:在音乐模式下实现播放外挂 flash 里面的歌曲的功能,操作方式与 SD 卡,U 盘一致. 注意:flash 需预先把音乐文件和 fat 文件系统烧录进 flash.目前不支持写操作. ...
- Linux添加PCF8563 RTC支持
文章目录 1. 添加驱动支持 2. 添加设备树 3. 测试 原文链接:https://blog.csdn.net/WXXGoodJob/article/details/88692949 SOC:RK3 ...
- RK3288下添加PCF8563 RTC支持
SOC:RK3288 kernel:Linux4.4 1. 添加驱动支持 Device Drivers ---> [*] Real Time Clock ---> [*] Set ...
- 树莓派3B添加DS1307 RTC时钟模块
前段时间用树莓派做了一个小项目,到实施阶段后才突然发现树莓派没有硬件时钟,最后在某宝找到了时钟模块,商家只提供硬件,不提供技术服务,只能百度搜索配置方法,最后参照树莓派 3B+ 安装 DS1307 R ...
- 全志 添加PWM7参数
添加pwm7的参数diff --git a/lichee/linux-3.10/arch/arm/boot/dts/sun8iw11p1.dtsi b/lichee/linux-3.10/arch/a ...
- 杰理之添加外挂 flash 驱动及实现音乐播放功能【篇】
功能简单说明:在音乐模式下实现播放外挂 flash 里面的歌曲的功能,操作方式与 SD 卡,U 盘一致. 注意:flash 需预先把音乐文件和 fat 文件系统烧录进 flash.目前不支持写操作.
- 全志 添加TP休眠触摸唤醒 Patch
add TP触摸屏唤醒diff --git a/android/frameworks/base/packages/SettingsProvider/res/values/defaults.xml b/ ...
最新文章
- 数据结构与算法(8-2)有序表查找(折半查找(二分查找)、插值查找)
- BeanUtils使用
- php5.3.0以上出现Strict Standards错误
- MATLAB实战系列(二十八)-用matlab爬取火车票信息
- 关于jQuery的$.getJSON乱码问题
- 【MFC】在工具栏中添加编辑框
- 关于 ABAP 调试器里的 16 进制值的显示问题
- 学习RUNOOB.COM进度一
- linux 查看本机网关地址,linux查看服务器网关地址
- Kiwi浏览器 MIUI禁第三方广告 ADB停用系统应用
- php 数组重复最多,PHP获取数组中重复最多元素的简单示例
- 线路板铜厚测试软件,厚铜线路板的铜厚是如何实现的
- 深度学习模型提升模型效果的常见方法
- Ubuntu 12.04安装及配置vsftp步骤
- 读书笔记18:命令模式
- 服务器显示跨域请求,出现跨域问题的原因及其解决方法
- python aiml开发文档_Python AIML搭建聊天机器人
- Origin画甘特图-II
- PS、PR、AE、AI、AU区别
- 冰点还原密码查看工具