[T106][ZXW-22]7520V3SCV2.01.01.02P42U09_VEC_V0.8_AP_VEC origin source commit
Change-Id: Ic6e05d89ecd62fc34f82b23dcf306c93764aec4b
diff --git a/ap/os/linux/linux-3.4.x/drivers/rtc/zx234290-rtc.c b/ap/os/linux/linux-3.4.x/drivers/rtc/zx234290-rtc.c
new file mode 100644
index 0000000..ddfa780
--- /dev/null
+++ b/ap/os/linux/linux-3.4.x/drivers/rtc/zx234290-rtc.c
@@ -0,0 +1,1185 @@
+/* drivers/rtc/zx234290_rtc.c
+ *
+ * Copyright (c) 2013 Sanechips Co., Ltd.
+ *
+ * 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.
+ *
+ * zx234290 Internal RTC Driver
+*/
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/clk.h>
+#include <linux/log2.h>
+#include <linux/of.h>
+#include <linux/delay.h>
+#include <linux/irq.h>
+#include <linux/mfd/zx234290.h>
+#include <asm/irq.h>
+#include "mach/iomap.h"
+#include <linux/gpio.h>
+#include <mach/gpio.h>
+#include "zx234290-rtc.h"
+
+#include <linux/semaphore.h>
+
+//#define GPIOFUNC_GPIO 0
+//#define GPIOFUNC_FUNC 1
+//#define PIN_PMU_INT ZX29_GPIO_47
+static struct platform_device *g_rtcdev;
+
+static int zx234290_rtc_enable(struct device *dev, int enable);
+int zx234290_rtc_settimer(int sec);
+int zx234290_rtc_set_second_timer(int seconds);
+
+#define ZX234290_BITFVAL(var, lsh) ( (var) << (lsh) )
+#define ZX234290_BITFMASK(wid, lsh) ( ((1U << (wid)) - 1) << (lsh) )
+#define ZX234290_BITFEXT(var, wid, lsh) ((var & ZX234290_BITFMASK(wid, lsh)) >> (lsh))
+static struct rtc_device *g_rtc;
+int CycleTimes = 0;
+int surplus = 0;
+int timer_remain=0;
+//#define ZX234290_GPIO_NUM 10
+
+typedef enum
+{
+ TIMER_COUNT_4096 = 0,
+ TIMER_COUNT_64 = 1, /* 64 DEFAULT */
+ TIMER_COUNT_1 = 2, /* 1 */
+ TIMER_COUNT_1_60 = 3, /* 1/60 */
+
+ TIMER_COUNT_MAX
+}zx234290_timercount;
+
+typedef enum
+{
+ ALARM_MINUTE = 0,
+ ALARM_HOUR = 1,
+ ALARM_DAY = 2,
+ ALARM_WEEKDAY = 3,
+ ALARM_SECOND = 4,
+ ALARM_MAX
+}zx234290_alarm_type;
+
+typedef enum
+{
+ ZX234290_SET_TIMER =( 'r'<<24|'t'<<16|'c'<<8|0),
+ ZX234290_GET_TIMER,
+ ZX234290_TIMER_ENABLED,
+ ZX234290_GET_TIMER_REMAIN,
+ ZX234290_GET_TIMER_STATUS,
+ ZX234290_CYCLE_ENABLE,
+ ZX234290_FUNCTION_MAX
+
+}zx234290_rtc_timer;
+
+typedef struct _zx234290_rtc
+{
+ struct zx234290 *zx234290;
+}zx234290_rtc_data;
+
+zx234290_rtc_data zx234290_rtc;
+static int zx234290_rtc_irqno = NO_IRQ;
+
+static volatile long timer_sema_flag=0;
+#define TIMER_SEMA_START_BIT 0 /*set timer before get timer.*/
+#define TIMER_SEMA_WAIT_BIT 1 /*mutex semaphore, up semaphore must be after down semaphore.*/
+
+struct semaphore timerSemaphore;
+
+
+struct rtc_time tempTime = {0};
+
+int zx234290_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm);
+static int zx234290_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm);
+
+static int zx234290_rtc_write_register(unsigned char addr, unsigned char data, unsigned char mask)
+{
+ int ret = 0;
+ unsigned char content = 0;
+
+ ret = zx234290_reg_read(zx234290_rtc.zx234290, addr);
+ if (ret < 0)
+ {
+ return -1;
+ }
+
+ content = (unsigned char)ret;
+ content &= ~mask;
+ content |= data & mask;
+ ret = zx234290_reg_write(zx234290_rtc.zx234290, addr, content);
+ if (ret != 0)
+ {
+ return ret;
+ }
+
+ return ret;
+}
+
+static int zx234290_rtc_read_register(unsigned char reg, unsigned char *dest)
+{
+ int ret;
+
+ ret = zx234290_reg_read(zx234290_rtc.zx234290, reg);
+ if (ret < 0)
+ return ret;
+
+ *dest = (unsigned char)ret;
+
+ return 0;
+}
+
+//++added by ys
+//send alarm irq event to app when alarm come.
+void zte_send_alarm_irq_event(void)
+{
+ char event_string[100] = {0};
+ char *envp[] = { event_string, NULL };
+
+ struct rtc_time rtc_tm;
+ struct rtc_wkalrm alrm;
+ unsigned long sec;
+// time_t sec;
+
+ zx234290_rtc_gettime(NULL, &rtc_tm);
+ zx234290_rtc_getalarm(NULL, &alrm);
+ alrm.time.tm_year = rtc_tm.tm_year;
+ alrm.time.tm_mon = rtc_tm.tm_mon;
+ rtc_tm_to_time(&(alrm.time), &sec);
+/*
+ printk("read alarm %04d.%02d.%02d %02d:%02d:%02d wday %d, sec %lu\n",
+ alrm.time.tm_year, alrm.time.tm_mon, alrm.time.tm_mday,
+ alrm.time.tm_hour, alrm.time.tm_min, alrm.time.tm_sec, alrm.time.tm_wday, sec);
+*/
+
+ sprintf(event_string,"PMIC RTC ALARM IRQ COME, sec:%lu", sec);
+
+ if(strlen(event_string))
+ kobject_uevent_env(&g_rtcdev->dev.kobj, KOBJ_CHANGE,envp);
+}
+
+void zte_send_timer_irq_event(void)
+{
+ char event_string[100] = {0};
+ char *envp[] = { event_string, NULL };
+// printk(KERN_INFO "zx234290_rtc: send_timer_irq_event\n" );
+
+ sprintf(event_string,"PMIC RTC TIMER IRQ COME");
+
+ if(strlen(event_string))
+ kobject_uevent_env(&g_rtcdev->dev.kobj, KOBJ_CHANGE,envp);
+
+ //printk(KERN_INFO "[yuwei]send_timer_irq_event. uevent\n");
+}
+void zte_send_min_irq_event(void)
+{
+ char event_string[100] = {0};
+ char *envp[] = { event_string, NULL };
+// printk(KERN_INFO "zx234290_rtc: send_min_irq_event\n" );
+
+ sprintf(event_string,"PMIC RTC MIN IRQ COME");
+
+ if(strlen(event_string))
+ kobject_uevent_env(&g_rtcdev->dev.kobj, KOBJ_CHANGE,envp);
+
+}
+void zte_send_hour_irq_event(void)
+{
+ char event_string[100] = {0};
+ char *envp[] = { event_string, NULL };
+// printk(KERN_INFO "zx234290_rtc: send_hour_irq_event\n" );
+
+ sprintf(event_string,"PMIC RTC HOUR IRQ COME");
+
+ if(strlen(event_string))
+ kobject_uevent_env(&g_rtcdev->dev.kobj, KOBJ_CHANGE,envp);
+
+}
+//++end
+
+
+
+/*alarm and timer countdown irq*/
+static irqreturn_t zx234290_rtc_alarmirq(int irq, void *id)
+{
+ struct rtc_device *rdev = id;
+ unsigned char reg_val = 0, mask = 0;
+ unsigned char reg_val_ctrl2 = 0;
+
+ zx234290_rtc_read_register(ZX234290_REG_ADDR_RTC_CTRL2,®_val_ctrl2);
+ //printk(KERN_INFO "zx234290_rtc_alarmirq:CycleTimes=%d,surplus=%d,timerFlag=%d.\n",CycleTimes,surplus,timerFlag);
+ //printk(KERN_INFO "zx234290_rtc_alarmirq:value(0x31) =%d.\n",reg_val_ctrl2);
+
+ /*alarm int*/
+ if((reg_val_ctrl2&0x08) == 0x08)
+ //if((reg_val_ctrl2>>ZX234290_RTC_AF_LSH)&0x1 == 0x1)
+ {
+ /*clear AF bit*/
+ mask = ZX234290_BITFMASK(ZX234290_RTC_AF_WID, ZX234290_RTC_AF_LSH);
+ reg_val= ZX234290_BITFVAL(0, ZX234290_RTC_AF_LSH);
+ zx234290_rtc_write_register(ZX234290_REG_ADDR_RTC_CTRL2, reg_val, mask);
+
+ rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF);
+
+ zte_send_alarm_irq_event();
+ }
+ /*timer int*/
+ if((reg_val_ctrl2&0x04) == 0x04)
+ //else if((reg_val_ctrl2>>ZX234290_RTC_TF_LSH)&0x1 == 0x1)
+ {
+ /*clear TF bit*/
+ mask = ZX234290_BITFMASK(ZX234290_RTC_TF_WID, ZX234290_RTC_TF_LSH);
+ reg_val= ZX234290_BITFVAL(0, ZX234290_RTC_TF_LSH);
+ zx234290_rtc_write_register(ZX234290_REG_ADDR_RTC_CTRL2, reg_val, mask);
+
+ rtc_update_irq(rdev, 1, RTC_AF | RTC_IRQF);
+
+// printk(KERN_INFO "zx234290_rtc_alarmirq ,remain seconds=%ld,flag=0x%lx\n",timer_remain,timer_sema_flag);
+ if(timer_remain){
+ zx234290_rtc_set_second_timer(min(timer_remain,255));
+ timer_remain -= min(timer_remain,255);
+ }
+ else{
+ if(test_and_clear_bit(TIMER_SEMA_WAIT_BIT, &timer_sema_flag)){
+ up(&timerSemaphore);
+ printk(KERN_INFO "zx234290_rtc_alarmirq semaphore.\n");
+ }
+ zte_send_timer_irq_event();
+ clear_bit(TIMER_SEMA_START_BIT, &timer_sema_flag);
+ }
+
+ }
+
+// printk(KERN_INFO "zx234290_rtc: irq = %d, REG(0x31) =0x%x.\n", irq, reg_val_ctrl2);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t zx234290_rtc_minirq(int irq, void *id)
+{
+ struct rtc_device *rdev = id;
+
+ rtc_update_irq(rdev, 1, RTC_UF | RTC_IRQF);
+ zte_send_min_irq_event();
+ return IRQ_HANDLED;
+}
+static irqreturn_t zx234290_rtc_hourirq(int irq, void *id)
+{
+ struct rtc_device *rdev = id;
+
+ rtc_update_irq(rdev, 1, RTC_UF | RTC_IRQF);
+ zte_send_hour_irq_event();
+ return IRQ_HANDLED;
+}
+/*alarm enable/disable, 0:disable 1:enable*/
+int zx234290_rtc_alarm_enable(zx234290_alarm_type type, unsigned int enabled)
+{
+ int ret = 0;
+ unsigned char reg_addr=0, reg_val=0, mask=0;
+ switch(type)
+ {
+ case ALARM_MINUTE:
+ reg_addr = ZX234290_REG_ADDR_ALARM_MINUTE;
+ break;
+ case ALARM_HOUR:
+ reg_addr = ZX234290_REG_ADDR_ALARM_HOUR;
+ break;
+ case ALARM_DAY:
+ reg_addr = ZX234290_REG_ADDR_ALARM_DAY;
+ break;
+ case ALARM_WEEKDAY:
+ reg_addr = ZX234290_REG_ADDR_ALARM_WEEK;
+ break;
+ case ALARM_SECOND:
+ reg_addr = ZX234290_REG_ADDR_ALARM_SECOND;
+ break;
+ default:
+ reg_addr = ZX234290_REG_ADDR_ALARM_MINUTE;
+ break;
+ }
+
+ reg_val = ZX234290_BITFVAL(enabled, ZX234290_RTC_AlARM_ACTIVATED_LSH);
+ mask = ZX234290_BITFMASK(ZX234290_RTC_AlARM_ACTIVATED_WID, ZX234290_RTC_AlARM_ACTIVATED_LSH);
+ ret = zx234290_rtc_write_register(reg_addr, reg_val, mask);
+ return ret;
+}
+
+/*timer counter set*/
+int zx234290_rtc_set_timercounter(unsigned char cnt)
+{
+ int ret = 0;
+ unsigned char reg_addr=0, reg_val=0, mask=0;
+
+ reg_addr = ZX234290_REG_ADDR_TIMER_CNT;
+ reg_val = ZX234290_BITFVAL(cnt, ZX234290_RTC_TIMER_CNT_LSH);
+ mask = ZX234290_BITFMASK(ZX234290_RTC_TIMER_CNT_WID, ZX234290_RTC_TIMER_CNT_LSH);
+ ret = zx234290_rtc_write_register(reg_addr, reg_val, mask);
+
+ return ret;
+}
+
+/*
+ TIMER_COUNT_4096 = 0,
+ TIMER_COUNT_64 = 1,
+ TIMER_COUNT_1 = 2,
+ TIMER_COUNT_1_60 = 3,
+*/
+int zx234290_rtc_set_clock_frequency(zx234290_timercount td)
+{
+ int ret = 0;
+ unsigned char reg_addr=0, reg_val=0, mask=0;
+
+ reg_addr = ZX234290_REG_ADDR_TIMER_CTRL;
+ reg_val = ZX234290_BITFVAL(td, ZX234290_RTC_TIMER_TD_LSH);
+ mask = ZX234290_BITFMASK(ZX234290_RTC_TIMER_TD_WID, ZX234290_RTC_TIMER_TD_LSH);
+ ret = zx234290_rtc_write_register(reg_addr, reg_val, mask);
+
+ return ret;
+}
+
+static int zx234290_rtc_setaie(struct device *dev, unsigned int enabled)
+{
+ int ret = 0;
+ int reg_val=0, mask=0;
+
+ pr_debug("%s: aie=%d\n", __func__, enabled);
+
+ /*enable/disable AIE bit*/
+ mask = ZX234290_BITFMASK(ZX234290_RTC_AIE_WID, ZX234290_RTC_AIE_LSH);
+ reg_val= ZX234290_BITFVAL(enabled, ZX234290_RTC_AIE_LSH);
+ ret = zx234290_rtc_write_register(ZX234290_REG_ADDR_RTC_CTRL2, reg_val, mask);
+ if (ret != 0)
+ {
+ return ret;
+ }
+
+ /*clear AF bit*/
+ mask = ZX234290_BITFMASK(ZX234290_RTC_AF_WID, ZX234290_RTC_AF_LSH);
+ reg_val= ZX234290_BITFVAL(0, ZX234290_RTC_AF_LSH);
+ ret = zx234290_rtc_write_register(ZX234290_REG_ADDR_RTC_CTRL2, reg_val, mask);
+ if (ret != 0)
+ {
+ return ret;
+ }
+
+ /*mask/unmask alarm int*/
+ /*
+ mask = ZX234290_BITFMASK(ZX234290_RTC_ALARM_INT_MASK_WID, ZX234290_RTC_ALARM_INT_MASK_LSH);
+ if(enabled)
+ {
+ reg_val= ZX234290_BITFVAL(0, ZX234290_RTC_ALARM_INT_MASK_LSH);
+ }
+ else
+ {
+ reg_val= ZX234290_BITFVAL(1, ZX234290_RTC_ALARM_INT_MASK_LSH);
+ }
+
+ ret = zx234290_rtc_write_register(ZX234290_REG_ADDR_INTB_MASK, reg_val, mask);
+ if (ret != 0)
+ {
+ return ret;
+ }
+ */
+
+ return ret;
+}
+
+static int zx234290_rtc_settie(struct device *dev, unsigned int enabled)
+{
+ int ret = 0;
+ int reg_val=0, mask=0;
+ /*enable/disable TIE bit*/
+ mask = ZX234290_BITFMASK(ZX234290_RTC_TIE_WID, ZX234290_RTC_TIE_LSH);
+ reg_val= ZX234290_BITFVAL(enabled, ZX234290_RTC_TIE_LSH);
+ ret = zx234290_rtc_write_register(ZX234290_REG_ADDR_RTC_CTRL2, reg_val, mask);
+ if (ret != 0)
+ {
+ return ret;
+ }
+ return 0;
+}
+static int zx234290_rtc_setuie(struct device *dev, unsigned int enabled)
+{
+ int nRet = 0;
+ int reg_val=0, mask=0;
+ pr_debug("%s: uie=%d\n", __func__, enabled);
+ /*
+ mask = ZX234290_BITFMASK(ZX234290_RTC_TIMER_INT_EN_WID, ZX234290_RTC_TIMER_INT_EN_LSH);
+ reg_val= ZX234290_BITFVAL(enabled, ZX234290_RTC_TIMER_INT_EN_LSH);
+ nRet = zx234290_rtc_write_register(ZX234290_REG_ADDR_RTC_CTRL2, reg_val, mask);
+ if (nRet != 0)
+ {
+ return nRet;
+ }
+ */
+ mask = ZX234290_BITFMASK(ZX234290_RTC_ONE_MINUTE_INT_MASK_WID, ZX234290_RTC_ONE_MINUTE_INT_MASK_LSH);
+ if(enabled)
+ {
+ reg_val= ZX234290_BITFVAL(0, ZX234290_RTC_ONE_MINUTE_INT_MASK_LSH);
+ }
+ else
+ {
+ reg_val= ZX234290_BITFVAL(1, ZX234290_RTC_ONE_MINUTE_INT_MASK_LSH);
+ }
+
+ nRet = zx234290_rtc_write_register(ZX234290_REG_ADDR_INTB_MASK, reg_val, mask);
+
+ mask = ZX234290_BITFMASK(ZX234290_RTC_ONE_HOUR_INT_MASK_WID, ZX234290_RTC_ONE_HOUR_INT_MASK_LSH);
+ if(enabled)
+ {
+ reg_val= ZX234290_BITFVAL(0, ZX234290_RTC_ONE_HOUR_INT_MASK_LSH);
+ }
+ else
+ {
+ reg_val= ZX234290_BITFVAL(1, ZX234290_RTC_ONE_HOUR_INT_MASK_LSH);
+ }
+
+ nRet = zx234290_rtc_write_register(ZX234290_REG_ADDR_INTB_MASK, reg_val, mask);
+
+ return nRet;
+}
+
+static int zx234290_rtc_getvalue(unsigned char reg, unsigned char *dest, unsigned char width, unsigned char offset)
+{
+ int nRet = 0;
+ unsigned char val;
+ nRet = zx234290_rtc_read_register(reg, dest);
+ if (nRet != 0)
+ {
+ return nRet;
+ }
+ val = *dest;
+ val = ZX234290_BITFEXT(val,width, offset);
+ *dest = val;
+ return nRet;
+}
+
+static int zx234290_rtc_setvalue(unsigned char addr, unsigned char data, unsigned char width, unsigned char offset)
+{
+ int nRet = 0;
+ unsigned char reg_val=0, mask=0;
+ reg_val = ZX234290_BITFVAL(data, offset);
+ mask = ZX234290_BITFMASK(width, offset);
+ nRet = zx234290_rtc_write_register(addr, reg_val, mask);
+ return nRet;
+}
+
+
+int zx234290_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
+{
+ unsigned char day, mon, year, wday, sec, min, hour;
+ unsigned char CenturyIndicate = 0;
+ unsigned int have_retried = 0;
+ if(rtc_tm == NULL)
+ {
+ return -1;
+ }
+retry_get_time:
+
+ zx234290_rtc_getvalue(ZX234290_REG_ADDR_SECONDS, &sec, ZX234290_RTC_TIME_SECONDS_WID, ZX234290_RTC_TIME_SECONDS_LSH);
+ zx234290_rtc_getvalue(ZX234290_REG_ADDR_MINUTES, &min, ZX234290_RTC_TIME_MINUTES_WID, ZX234290_RTC_TIME_MINUTES_LSH);
+ zx234290_rtc_getvalue(ZX234290_REG_ADDR_HOURS, &hour, ZX234290_RTC_TIME_HOURS_WID, ZX234290_RTC_TIME_HOURS_LSH);
+ zx234290_rtc_getvalue(ZX234290_REG_ADDR_DAY, &day, ZX234290_RTC_TIME_DAYS_WID, ZX234290_RTC_TIME_DAYS_LSH);
+ zx234290_rtc_getvalue(ZX234290_REG_ADDR_MONTH, &mon, ZX234290_RTC_TIME_MONTHS_WID, ZX234290_RTC_TIME_MONTHS_LSH);
+ zx234290_rtc_getvalue(ZX234290_REG_ADDR_YEAR, &year, ZX234290_RTC_TIME_YEAR_WID, ZX234290_RTC_TIME_YEAR_LSH);
+ zx234290_rtc_getvalue(ZX234290_REG_ADDR_WEEK, &wday, ZX234290_RTC_TIME_WEEKDAY_WID, ZX234290_RTC_TIME_WEEKDAY_LSH);
+ zx234290_rtc_getvalue(ZX234290_REG_ADDR_MONTH, &CenturyIndicate, ZX234290_RTC_TIME_CENTURY_WID, ZX234290_RTC_TIME_CENTURY_LSH);
+
+
+ if (sec == 0 && !have_retried)
+ {
+ have_retried = 1;
+ goto retry_get_time;
+ }
+ rtc_tm->tm_sec = bcd2bin(sec);
+ rtc_tm->tm_min = bcd2bin(min);
+ rtc_tm->tm_hour = bcd2bin(hour);
+ rtc_tm->tm_mday = bcd2bin(day);
+ rtc_tm->tm_mon = bcd2bin(mon);
+ rtc_tm->tm_year = bcd2bin(year);//+2000;
+ rtc_tm->tm_wday = bcd2bin(wday);
+ rtc_tm->tm_yday = rtc_year_days(rtc_tm->tm_mday, rtc_tm->tm_mon , rtc_tm->tm_year);
+ if(CenturyIndicate == 0)
+ {
+ rtc_tm->tm_year += 100;
+ }
+ rtc_tm->tm_mon -= 1;
+ rtc_tm->tm_isdst = 0;
+ pr_debug("read time %04d.%02d.%02d %02d:%02d:%02d\n",
+ rtc_tm->tm_year, rtc_tm->tm_mon+1, rtc_tm->tm_mday,
+ rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
+
+ return rtc_valid_tm(rtc_tm);
+}
+
+static int zx234290_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+ int ret = 0;
+ unsigned char day, mon, year, wday, sec, min, hour, CenturyIndicate;
+ unsigned char reg_val=0, mask=0;
+ //int year = tm->tm_year - 100;
+ pr_debug("set time %04d.%02d.%02d %02d:%02d:%02d\n",
+ tm->tm_year, tm->tm_mon+1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
+ if(tm->tm_year >= 200)
+ {
+ return -1;
+
+ }else if(tm->tm_year >= 100)
+ {
+ year = tm->tm_year - 100;
+ CenturyIndicate = 0; /*indicate 21 ÊÀ¼Í 20xx*/
+ }
+ else
+ {
+ year = tm->tm_year;
+ CenturyIndicate = 1; /*indicate 20 ÊÀ¼Í 19xx*/
+ }
+ /* we get around y2k by simply not supporting it */
+ sec = bin2bcd(tm->tm_sec);
+ reg_val = ZX234290_BITFVAL(sec, ZX234290_RTC_TIME_SECONDS_LSH);
+ mask = ZX234290_BITFMASK(ZX234290_RTC_TIME_SECONDS_WID, ZX234290_RTC_TIME_SECONDS_LSH);
+ ret = zx234290_rtc_write_register(ZX234290_REG_ADDR_SECONDS, reg_val, mask);
+
+ min = bin2bcd(tm->tm_min);
+ reg_val = ZX234290_BITFVAL(min, ZX234290_RTC_TIME_MINUTES_LSH);
+ mask = ZX234290_BITFMASK(ZX234290_RTC_TIME_MINUTES_WID, ZX234290_RTC_TIME_MINUTES_LSH);
+ ret += zx234290_rtc_write_register(ZX234290_REG_ADDR_MINUTES, reg_val, mask);
+
+ hour = bin2bcd(tm->tm_hour);
+ reg_val = ZX234290_BITFVAL(hour, ZX234290_RTC_TIME_HOURS_LSH);
+ mask = ZX234290_BITFMASK(ZX234290_RTC_TIME_HOURS_WID, ZX234290_RTC_TIME_HOURS_LSH);
+ ret += zx234290_rtc_write_register(ZX234290_REG_ADDR_HOURS, reg_val, mask);
+
+ day = bin2bcd(tm->tm_mday);
+ reg_val = ZX234290_BITFVAL(day, ZX234290_RTC_TIME_DAYS_LSH);
+ mask = ZX234290_BITFMASK(ZX234290_RTC_TIME_DAYS_WID, ZX234290_RTC_TIME_DAYS_LSH);
+ ret += zx234290_rtc_write_register(ZX234290_REG_ADDR_DAY, reg_val, mask);
+
+ mon = bin2bcd(tm->tm_mon+1);
+ reg_val = ZX234290_BITFVAL(mon, ZX234290_RTC_TIME_MONTHS_LSH);
+ mask = ZX234290_BITFMASK(ZX234290_RTC_TIME_MONTHS_WID, ZX234290_RTC_TIME_MONTHS_LSH);
+ ret += zx234290_rtc_write_register(ZX234290_REG_ADDR_MONTH, reg_val, mask);
+
+ reg_val = ZX234290_BITFVAL(CenturyIndicate, ZX234290_RTC_TIME_CENTURY_LSH);
+ mask = ZX234290_BITFMASK(ZX234290_RTC_TIME_CENTURY_WID, ZX234290_RTC_TIME_CENTURY_LSH);
+ ret += zx234290_rtc_write_register(ZX234290_REG_ADDR_MONTH, reg_val, mask);
+
+ year = bin2bcd(year);
+ reg_val = ZX234290_BITFVAL(year, ZX234290_RTC_TIME_YEAR_LSH);
+ mask = ZX234290_BITFMASK(ZX234290_RTC_TIME_YEAR_WID, ZX234290_RTC_TIME_YEAR_LSH);
+ ret += zx234290_rtc_write_register(ZX234290_REG_ADDR_YEAR, reg_val, mask);
+
+ wday = bin2bcd(tm->tm_wday);
+ reg_val = ZX234290_BITFVAL(wday, ZX234290_RTC_TIME_WEEKDAY_LSH);
+ mask = ZX234290_BITFMASK(ZX234290_RTC_TIME_WEEKDAY_WID, ZX234290_RTC_TIME_WEEKDAY_LSH);
+ ret += zx234290_rtc_write_register(ZX234290_REG_ADDR_WEEK, reg_val, mask);
+
+ return ret;
+}
+
+static int zx234290_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct rtc_time *alm_tm = &alrm->time;
+ unsigned char second, day, wday, min, hour;
+ unsigned char reg_val=0, mask=0;
+ if(alrm == NULL)
+ {
+ return -1;
+ }
+ zx234290_rtc_getvalue(ZX234290_REG_ADDR_ALARM_SECOND, &second, ZX234290_RTC_AlARM_SECOND_WID, ZX234290_RTC_AlARM_SECOND_LSH);
+ zx234290_rtc_getvalue(ZX234290_REG_ADDR_ALARM_MINUTE, &min, ZX234290_RTC_AlARM_MINUTES_WID, ZX234290_RTC_AlARM_MINUTES_LSH);
+ zx234290_rtc_getvalue(ZX234290_REG_ADDR_ALARM_HOUR, &hour, ZX234290_RTC_AlARM_HOURS_WID, ZX234290_RTC_AlARM_HOURS_LSH);
+ zx234290_rtc_getvalue(ZX234290_REG_ADDR_ALARM_DAY, &day, ZX234290_RTC_AlARM_DAYS_WID, ZX234290_RTC_AlARM_DAYS_LSH);
+ zx234290_rtc_getvalue(ZX234290_REG_ADDR_ALARM_WEEK, &wday, ZX234290_RTC_AlARM_WEEKDAY_WID, ZX234290_RTC_AlARM_WEEKDAY_LSH);
+
+ mask = ZX234290_BITFMASK(ZX234290_RTC_ALARM_INT_EN_WID, ZX234290_RTC_ALARM_INT_EN_LSH);
+ zx234290_rtc_read_register(ZX234290_REG_ADDR_RTC_CTRL2, ®_val);
+ alrm->enabled = (reg_val & mask)? 1 : 0;
+
+ pr_debug("read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n",
+ alrm->enabled,
+ 1900 + alm_tm->tm_year, alm_tm->tm_mon+1, alm_tm->tm_mday,
+ alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
+ /* decode the alarm enable field */
+ if(alrm->enabled)
+ {
+ //alm_tm->tm_sec = 0; //bcd2bin(alm_tm->tm_sec);
+ alm_tm->tm_sec = bcd2bin(second);//yuxiang
+ alm_tm->tm_min = bcd2bin(min);
+ alm_tm->tm_hour = bcd2bin(hour);
+ alm_tm->tm_mday = bcd2bin(day);
+ alm_tm->tm_wday = bcd2bin(wday);
+ }
+ else
+ {
+ alm_tm->tm_sec = -1;
+ alm_tm->tm_min = -1;
+ alm_tm->tm_hour = -1;
+ alm_tm->tm_mday = -1;
+ alm_tm->tm_mon = -1;
+ alm_tm->tm_year = -1;
+ }
+
+ return 0;
+}
+
+static int zx234290_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct rtc_time *tm = &alrm->time;
+ //unsigned long expires;
+ unsigned char sec, min, hour, mday, wday;
+ //rtc_tm_to_time(tm, &expires);
+ //expires = roundup(expires, 60);
+ //rtc_time_to_tm(expires, tm);
+ //tm->tm_sec = 0;
+
+ if (tm->tm_sec < 60 && tm->tm_sec >= 0)//yuxiang
+ {
+ sec = bin2bcd(tm->tm_sec);
+ zx234290_rtc_setvalue(ZX234290_REG_ADDR_ALARM_SECOND, sec, ZX234290_RTC_AlARM_SECOND_WID, ZX234290_RTC_AlARM_SECOND_LSH);
+ zx234290_rtc_alarm_enable(ALARM_SECOND, 0);
+ }
+ else
+ {
+ zx234290_rtc_alarm_enable(ALARM_SECOND, 1);
+ }
+
+ if (tm->tm_min < 60 && tm->tm_min >= 0)
+ {
+ min = bin2bcd(tm->tm_min);
+ zx234290_rtc_setvalue(ZX234290_REG_ADDR_ALARM_MINUTE, min, ZX234290_RTC_AlARM_MINUTES_WID, ZX234290_RTC_AlARM_MINUTES_LSH);
+ zx234290_rtc_alarm_enable(ALARM_MINUTE, 0);
+ }
+ else
+ {
+ zx234290_rtc_alarm_enable(ALARM_MINUTE, 1);
+ }
+ if (tm->tm_hour < 24 && tm->tm_hour >= 0)
+ {
+ hour = bin2bcd(tm->tm_hour);
+ zx234290_rtc_setvalue(ZX234290_REG_ADDR_ALARM_HOUR, hour, ZX234290_RTC_AlARM_HOURS_WID, ZX234290_RTC_AlARM_HOURS_LSH);
+ zx234290_rtc_alarm_enable(ALARM_HOUR, 0);
+ }
+ else
+ {
+ zx234290_rtc_alarm_enable(ALARM_HOUR, 1);
+ }
+ if(tm->tm_mday < 32 && tm->tm_mday > 0)
+ {
+ mday = bin2bcd(tm->tm_mday);
+ zx234290_rtc_setvalue(ZX234290_REG_ADDR_ALARM_DAY, mday, ZX234290_RTC_AlARM_DAYS_WID, ZX234290_RTC_AlARM_DAYS_LSH);
+ zx234290_rtc_alarm_enable(ALARM_DAY, 0);
+ }
+ else
+ {
+ zx234290_rtc_alarm_enable(ALARM_DAY, 1);
+ }
+ if(tm->tm_wday < 7 && tm->tm_wday >= 0)
+ {
+ wday = bin2bcd(tm->tm_wday);
+ zx234290_rtc_setvalue(ZX234290_REG_ADDR_ALARM_WEEK, wday, ZX234290_RTC_AlARM_WEEKDAY_WID, ZX234290_RTC_AlARM_WEEKDAY_LSH);
+ zx234290_rtc_alarm_enable(ALARM_WEEKDAY, 0);
+ }
+ else
+ {
+ zx234290_rtc_alarm_enable(ALARM_WEEKDAY, 1);
+ }
+ zx234290_rtc_setaie(dev, alrm->enabled);
+ return 0;
+}
+
+static int zx234290_rtc_request_irq(struct platform_device *pdev, struct rtc_device *rtc)
+{
+ int ret = -1;
+ //zx234290_rtc.zx234290->irq_base = PMIC_INT_START;
+ ret = request_threaded_irq(zx234290_rtc.zx234290->irq_base + ZX234290_INT_RTC_ALRM,
+ NULL, zx234290_rtc_alarmirq, 0, "zx234290-rtc alarm", rtc);
+ if (ret)
+ {
+ dev_err(&pdev->dev, "IRQ%d error %d\n", zx234290_rtc.zx234290->irq_base + ZX234290_INT_RTC_ALRM, ret);
+ goto err_alarm_irq;
+ }
+ ret = request_threaded_irq(zx234290_rtc.zx234290->irq_base + ZX234290_INT_RTC_HOUR,
+ NULL, zx234290_rtc_hourirq, 0, "zx234290-rtc hour", rtc);
+ if (ret)
+ {
+ dev_err(&pdev->dev, "IRQ%d error %d\n", zx234290_rtc.zx234290->irq_base + ZX234290_INT_RTC_HOUR, ret);
+ goto err_hour_irq;
+ }
+ ret = request_threaded_irq(zx234290_rtc.zx234290->irq_base + ZX234290_INT_RTC_MIN,
+ NULL, zx234290_rtc_minirq, 0, "zx234290-rtc min", rtc);
+ if (ret)
+ {
+ dev_err(&pdev->dev, "IRQ%d error %d\n", zx234290_rtc.zx234290->irq_base + ZX234290_INT_RTC_MIN, ret);
+ goto err_min_irq;
+ }
+
+ return 0;
+
+ err_min_irq:
+ free_irq(zx234290_rtc.zx234290->irq_base + ZX234290_INT_RTC_MIN, rtc);
+ err_hour_irq:
+ free_irq(zx234290_rtc.zx234290->irq_base + ZX234290_INT_RTC_HOUR, rtc);
+ err_alarm_irq:
+ free_irq(zx234290_rtc.zx234290->irq_base + ZX234290_INT_RTC_ALRM, rtc);
+
+ return ret;
+}
+
+#if 1
+
+static int zx234290_rtc_set_second_alarm_int(struct device *dev, unsigned int enabled)
+{
+ int nRet = 0;
+
+ int ret = 0;
+ int reg_addr=0, mask=0;
+ unsigned char reg_val=0;
+ int bIsOn = 0;
+
+ #if 0
+ pr_debug("%s: aie=%d\n", __func__, enabled);
+ mask = ZX234290_BITFMASK(ZX234290_RTC_ALARM_INT_EN_WID, ZX234290_RTC_ALARM_INT_EN_LSH);
+ reg_val= ZX234290_BITFVAL(enabled, ZX234290_RTC_ALARM_INT_EN_LSH);
+ nRet = zx234290_rtc_write_register(ZX234290_REG_ADDR_RTC_CTRL2, reg_val, mask);
+ if (nRet != 0)
+ {
+ return nRet;
+ }
+ mask = ZX234290_BITFMASK(ZX234290_RTC_ALARM_AF_WID, ZX234290_RTC_ALARM_AF_LSH);
+ reg_val= ZX234290_BITFVAL(0, ZX234290_RTC_ALARM_AF_LSH);
+ zx234290_rtc_write_register(ZX234290_REG_ADDR_RTC_CTRL2, reg_val, mask);
+ mask = ZX234290_BITFMASK(ZX234290_RTC_ALARM_INT_MASK_WID, ZX234290_RTC_ALARM_INT_MASK_LSH);
+ if(enabled)
+ {
+ reg_val= ZX234290_BITFVAL(0, ZX234290_RTC_ALARM_INT_MASK_LSH);
+ }
+ else
+ {
+ reg_val= ZX234290_BITFVAL(1, ZX234290_RTC_ALARM_INT_MASK_LSH);
+ }
+ nRet = zx234290_rtc_write_register(ZX234290_REG_ADDR_INTB_MASK, reg_val, mask);
+ #endif
+ if(enabled)
+ bIsOn = 0;//active
+ else
+ bIsOn = 1;//inactive
+
+ reg_addr = ZX234290_REG_ADDR_INTB_MASK;
+ reg_val = ZX234290_BITFVAL(enabled, ZX234290_RTC_ALARM_INT_MASK_LSH);
+ mask = ZX234290_BITFMASK(ZX234290_RTC_ALARM_INT_MASK_WID, ZX234290_RTC_ALARM_INT_MASK_LSH);
+ ret = zx234290_rtc_write_register(reg_addr,reg_val, mask);
+ zx234290_rtc_read_register(0x03, ®_val);
+
+// printk(KERN_INFO "zx234290_rtc_ioctl:0x03 = %x.\n",reg_val);
+#if 0
+ reg_addr = ZX234290_REG_ADDR_RTC_CTRL2;
+ reg_val = ZX234290_BITFVAL(enabled, ZX234290_RTC_ALARM_INT_EN_LSH);
+ mask = ZX234290_BITFMASK(ZX234290_RTC_ALARM_INT_EN_WID, ZX234290_RTC_ALARM_INT_EN_LSH);
+ ret = zx234290_rtc_write_register(slv_addr,reg_val, mask);
+ reg_addr = ZX234290_REG_ADDR_RTC_CTRL2;
+ reg_val = ZX234290_BITFVAL(enabled, 2);
+ mask = ZX234290_BITFMASK(1, 2);
+ ret = zx234290_rtc_write_register(slv_addr,reg_val, mask);
+#endif
+ return nRet;
+}
+
+//static DECLARE_MUTEX(timerSemaphore);
+
+
+
+int zx234290_rtc_gettimer(void)
+{
+ int ret = -EPERM;
+
+ if(!test_and_set_bit(TIMER_SEMA_WAIT_BIT, &timer_sema_flag))
+ ret = down_interruptible(&timerSemaphore);
+
+ clear_bit(TIMER_SEMA_WAIT_BIT, &timer_sema_flag);
+
+ if(!ret){
+// printk(KERN_INFO "zx234290_rtc_gettimer:get semaphore success.\n");
+
+ zx234290_rtc_enable(g_rtc->dev.parent, 0);
+ zx234290_rtc_settie(g_rtc->dev.parent, 0);
+ zx234290_rtc_set_second_alarm_int(g_rtc->dev.parent, 1);
+
+ //zx234290_rtc_set_clock_frequency(TIMER_COUNT_1);
+ return 0;
+ }
+ else{
+ // printk(KERN_INFO "zx234290_rtc_gettimer:get semaphore ret is %d.\n", ret);
+
+ return ret;
+ }
+}
+
+int zx234290_rtc_set_second_timer(int seconds)
+{
+ int mask = 0;
+ unsigned char reg_val=0;
+ //int value = 0;
+
+ mask = ZX234290_BITFMASK(ZX234290_RTC_TIMER_INT_EN_WID, 2);
+ reg_val= ZX234290_BITFVAL(0, 2);
+ zx234290_rtc_write_register(ZX234290_REG_ADDR_RTC_CTRL2, reg_val, mask);
+ zx234290_rtc_set_timercounter(seconds);
+ zx234290_rtc_set_clock_frequency(TIMER_COUNT_1);
+ zx234290_rtc_enable(g_rtc->dev.parent, 1);
+ zx234290_rtc_settie(g_rtc->dev.parent, 1);
+ zx234290_rtc_set_second_alarm_int(g_rtc->dev.parent, 0);
+#if 0
+ zx234290_rtc_read_register(0x01, &value);
+ printk(KERN_INFO "zx234290_rtc_ioctl:0x01 = %x.\n",value);
+ zx234290_rtc_read_register(0x03, &value);
+ printk(KERN_INFO "zx234290_rtc_ioctl:0x03 = %x.\n",value);
+ zx234290_rtc_read_register(0x05, &value);
+ printk(KERN_INFO "zx234290_rtc_ioctl:0x05 = %x.\n",value);
+ zx234290_rtc_read_register(0x30, &value);
+ printk(KERN_INFO "zx234290_rtc_ioctl:0x30 = %x.\n",value);
+ zx234290_rtc_read_register(0x31, &value);
+ printk(KERN_INFO "zx234290_rtc_ioctl:0x31 = %x.\n",value);
+ zx234290_rtc_read_register(0x3E, &value);
+ printk(KERN_INFO "zx234290_rtc_ioctl:0x3E = %x.\n",value);
+ zx234290_rtc_read_register(0x3F, &value);
+ printk(KERN_INFO "zx234290_rtc_ioctl:0x3F = %x.\n",value);
+#endif
+ return 0;
+}
+
+void printf_rtc_log(void)
+{
+ unsigned char value = 0;
+
+ zx234290_rtc_read_register(0x01, &value);
+ printk(KERN_INFO "printf_rtc_log:0x01 = %x.\n",value);
+ zx234290_rtc_read_register(0x03, &value);
+ printk(KERN_INFO "printf_rtc_log:0x03 = %x.\n",value);
+ zx234290_rtc_read_register(0x05, &value);
+ printk(KERN_INFO "printf_rtc_log:0x05 = %x.\n",value);
+ zx234290_rtc_read_register(0x30, &value);
+ printk(KERN_INFO "printf_rtc_log:0x30 = %x.\n",value);
+ zx234290_rtc_read_register(0x31, &value);
+ printk(KERN_INFO "printf_rtc_log:0x31 = %x.\n",value);
+ zx234290_rtc_read_register(0x3E, &value);
+ printk(KERN_INFO "printf_rtc_log:0x3E = %x.\n",value);
+ zx234290_rtc_read_register(0x3F, &value);
+ printk(KERN_INFO "printf_rtc_log:0x3F = %x.\n",value);
+}
+
+static int zx234290_rtc_set_alarm_enable(struct device *dev, unsigned int enabled)
+{
+ int nRet = 0;
+ int reg_val=0, mask=0;
+
+ mask = ZX234290_BITFMASK(ZX234290_RTC_ALARM_INT_EN_WID, ZX234290_RTC_ALARM_INT_EN_LSH);
+ reg_val= ZX234290_BITFVAL(enabled, ZX234290_RTC_ALARM_INT_EN_LSH);
+
+ nRet = zx234290_rtc_write_register(ZX234290_REG_ADDR_RTC_CTRL2, reg_val, mask);
+
+ mask = ZX234290_BITFMASK(1, 0);
+ reg_val= ZX234290_BITFVAL(0, 0);
+
+ nRet = zx234290_rtc_write_register(0x03, reg_val, mask);
+
+ mask = ZX234290_BITFMASK(2, 2);
+ reg_val= ZX234290_BITFVAL(0, 2);
+
+ nRet = zx234290_rtc_write_register(0x31, reg_val, mask);
+ return 0;
+}
+
+
+int zx234290_rtc_disable_timer_alarm(void)
+{
+ zx234290_rtc_enable(g_rtc->dev.parent, 0);
+ zx234290_rtc_settie(g_rtc->dev.parent, 0);
+ zx234290_rtc_set_alarm_enable(g_rtc->dev.parent, 0);
+ zx234290_rtc_alarm_enable(ALARM_MINUTE,1);
+ zx234290_rtc_alarm_enable(ALARM_HOUR,1);
+ zx234290_rtc_alarm_enable(ALARM_DAY,1);
+ zx234290_rtc_alarm_enable(ALARM_WEEKDAY,1);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(zx234290_rtc_disable_timer_alarm);
+
+/****get value of rtc timer cnt ****/
+unsigned char zx234290_rtc_gettimer_cnt_remain(void)
+{
+ unsigned char timercnt_remain=0;
+ zx234290_rtc_getvalue(ZX234290_REG_ADDR_TIMER_CNT, &timercnt_remain, ZX234290_RTC_TIMER_CNT_WID, ZX234290_RTC_TIMER_CNT_LSH);
+ return timercnt_remain;
+}
+
+
+
+
+static int zx234290_rtc_ioctl(struct device *dev,zx234290_rtc_timer cmd,unsigned long arg)
+{
+ int err = 0;
+ unsigned int seconds;
+ unsigned char timercnt_remain = 0;
+ unsigned int seconds_remain = 0;
+ void __user *uarg = (void __user *) arg;
+// printk(KERN_INFO "zx234290_rtc_ioctl:cmd=%d[%c%c%c%d]arg=%ld.\n",cmd, (cmd>>24)&0xff,(cmd>>16)&0xff,(cmd>>8)&0xff,cmd&0xff,arg);
+ switch(cmd)
+ {
+ case ZX234290_SET_TIMER:
+ {
+ seconds = arg;
+
+ if(seconds){
+ set_bit(TIMER_SEMA_START_BIT, &timer_sema_flag);
+
+ timer_remain = seconds;
+
+ zx234290_rtc_set_second_timer(min(timer_remain,255));
+ timer_remain -= min(timer_remain,255);
+// printk(KERN_INFO "ZX234290_SET_TIMER:set timer=%d, remain=%d.\n", seconds,timer_remain);
+ }
+
+ else/* if(seconds == 0)*/{
+// printk(KERN_INFO "ZX234290_SET_TIMER(seconds == %ld):timerSemaphore=0x%x.\n",seconds,timerSemaphore);
+ zx234290_rtc_enable(g_rtc->dev.parent, 0);
+ zx234290_rtc_settie(g_rtc->dev.parent, 0);
+// printf_rtc_log();
+ {
+ if(test_and_clear_bit(TIMER_SEMA_WAIT_BIT, &timer_sema_flag))
+ up(&timerSemaphore);
+ }
+
+ clear_bit(TIMER_SEMA_START_BIT, &timer_sema_flag);
+ }
+
+ seconds = 0;
+ break;
+ }
+ #if 1
+ case ZX234290_GET_TIMER:
+ {
+
+ if(test_bit(TIMER_SEMA_START_BIT, &timer_sema_flag)){
+ err = zx234290_rtc_gettimer();
+// printk(KERN_INFO "ZX234290_GET_TIMER.ret=%d\n",err);
+ }
+ //else
+ // printk(KERN_INFO "ZX234290_GET_TIMER.has not setting timer, return=%d\n",err);
+
+ break;
+ }
+ #endif
+
+ case ZX234290_TIMER_ENABLED:
+ {
+ seconds = arg;
+ // printk(KERN_INFO "ZX234290_TIMER_ENABLED:cmd=%d,senconds=%d.\n", cmd,seconds);
+ if(seconds == 0) {
+ zx234290_rtc_enable(g_rtc->dev.parent, 0);
+ zx234290_rtc_settie(g_rtc->dev.parent, 0);
+// printf_rtc_log();
+ if(test_and_clear_bit(TIMER_SEMA_WAIT_BIT, &timer_sema_flag))
+ up(&timerSemaphore);
+
+ clear_bit(TIMER_SEMA_START_BIT, &timer_sema_flag);
+ }
+ break;
+ }
+ case ZX234290_GET_TIMER_REMAIN:
+ {
+ timercnt_remain = zx234290_rtc_gettimer_cnt_remain();
+
+ seconds_remain = timer_remain + timercnt_remain;
+ // printk(KERN_INFO "ZX234290_GET_TIMER_REMAIN:cmd=%d.remain=%d\n", cmd,seconds_remain);
+ err = put_user(seconds_remain,(unsigned long __user *)uarg);
+ break;
+ }
+ case ZX234290_CYCLE_ENABLE:
+ {
+ seconds = arg;
+ // printk(KERN_INFO "ZX234290_CYCLE_ENABLE:cmd=%d,enable=%d.\n", cmd,seconds);
+ zx234290_rtc_setuie(g_rtc->dev.parent, seconds);
+ break;
+ }
+ default:
+ err=ENOIOCTLCMD;
+ break;
+ }
+ return err;
+}
+
+static int zx234290_rtc_enable(struct device *dev, int enable)
+{
+ int ret = 0;
+ int reg_val=0, mask=0;
+
+ reg_val = ZX234290_BITFVAL(enable, ZX234290_RTC_TIMER_EN_LSH);
+ mask = ZX234290_BITFMASK(ZX234290_RTC_TIMER_EN_WID, ZX234290_RTC_TIMER_EN_LSH);
+ ret = zx234290_rtc_write_register(ZX234290_REG_ADDR_TIMER_CTRL, reg_val, mask);
+
+ return ret;
+}
+
+/* ÉèÖÃRTCÄÚ²¿µ¹¼ÆÊ±¶¨Ê±Æ÷,ÓÃÓÚʵÏֹػúºó¶¨Ê±¿ª»ú */
+int zx234290_rtc_settimer(int sec)
+{
+ int mask = 0;
+ unsigned char reg_val=0;
+ //int value = 0;
+
+ mask = ZX234290_BITFMASK(ZX234290_RTC_TIMER_INT_EN_WID, 2);
+ reg_val= ZX234290_BITFVAL(0, 2);
+ zx234290_rtc_write_register(ZX234290_REG_ADDR_RTC_CTRL2, reg_val, mask);
+ zx234290_rtc_set_timercounter(sec);
+ zx234290_rtc_enable(g_rtc->dev.parent, 1);
+ zx234290_rtc_settie(g_rtc->dev.parent, 1);
+ zx234290_rtc_setaie(g_rtc->dev.parent, 0);
+ #if 0
+ zx234290_rtc_read_register(0x30, &value);
+ printk(KERN_INFO "zx234290_rtc_ioctl:0x30 = %x.\n",value);
+ zx234290_rtc_read_register(0x31, &value);
+ printk(KERN_INFO "zx234290_rtc_ioctl:0x31 = %x.\n",value);
+ zx234290_rtc_read_register(0x3E, &value);
+ printk(KERN_INFO "zx234290_rtc_ioctl:0x3E = %x.\n",value);
+ zx234290_rtc_read_register(0x3F, &value);
+ printk(KERN_INFO "zx234290_rtc_ioctl:0x3F = %x.\n",value);
+ //printk("zx234290_rtc_settimer is called! \n");
+ #endif
+ return 0;
+}
+EXPORT_SYMBOL_GPL(zx234290_rtc_settimer);
+
+#endif
+
+static const struct rtc_class_ops zx234290_rtcops = {
+ .read_time = zx234290_rtc_gettime,
+ .set_time = zx234290_rtc_settime,
+ .read_alarm = zx234290_rtc_getalarm,
+ .set_alarm = zx234290_rtc_setalarm,
+ .alarm_irq_enable = zx234290_rtc_setaie,
+ .ioctl = zx234290_rtc_ioctl,
+};
+static int zx234290_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc;
+ struct rtc_time rtc_tm;
+ int ret;
+ g_rtcdev = pdev;
+ zx234290_rtc.zx234290 = dev_get_drvdata(pdev->dev.parent);
+ if(NULL==zx234290_rtc.zx234290)
+ return -EINVAL;
+
+ zx234290_rtc_set_timercounter(128);
+ zx234290_rtc_set_clock_frequency(TIMER_COUNT_1);
+ device_init_wakeup(&pdev->dev, 1);
+ rtc = rtc_device_register("zx234290", &pdev->dev, &zx234290_rtcops, THIS_MODULE); /* register RTC and exit */
+ if (IS_ERR(rtc))
+ {
+ dev_err(&pdev->dev, "cannot attach rtc\n");
+ ret = PTR_ERR(rtc);
+ goto err_nortc;
+ }
+ g_rtc = rtc;
+ zx234290_rtc_gettime(NULL, &rtc_tm); /* Check RTC Time */
+ tempTime = rtc_tm;
+ if (rtc_valid_tm(&rtc_tm) < 0)
+ {
+ rtc_tm.tm_year = 100;
+ rtc_tm.tm_mon = 0;
+ rtc_tm.tm_mday = 1;
+ rtc_tm.tm_hour = 0;
+ rtc_tm.tm_min = 0;
+ rtc_tm.tm_sec = 0;
+ rtc_tm.tm_wday= 6;
+ zx234290_rtc_settime(NULL, &rtc_tm);
+ dev_warn(&pdev->dev, "warning: invalid RTC value so initializing it\n");
+ }
+ else
+ {
+ rtc_tm = rtc_ktime_to_tm(rtc_tm_to_ktime(rtc_tm));
+ zx234290_rtc_settime(NULL, &rtc_tm);
+ }
+ rtc->max_user_freq = 64; //32768;//32k clock
+ zx234290_rtc_irqno = zx234290_rtc.zx234290->chip_irq;
+ platform_set_drvdata(pdev, rtc);
+ ret = zx234290_rtc_request_irq(pdev, rtc);
+ if (ret)
+ {
+ dev_err(&pdev->dev, "IRQ request error!\n");
+ goto err_irq;
+ }
+ zx234290_rtc_write_register(ZX234290_REG_ADDR_RTC_CTRL1, 0, 0xff);
+ zx234290_rtc_setuie(&pdev->dev, 0);
+ zx234290_rtc_enable(&pdev->dev, 0);
+ sema_init(&timerSemaphore,0);
+ //zx234290_rtc_ioctl(NULL,ZX234290_SET_TIMER,20);
+ return 0;
+ err_irq:
+ platform_set_drvdata(pdev, NULL);
+ err_nortc:
+ rtc_device_unregister(rtc);
+ return ret;
+}
+static int zx234290_rtc_remove(struct platform_device *pdev)
+{
+ struct rtc_device *rtc = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+ rtc_device_unregister(rtc);
+ zx234290_rtc_setuie(&pdev->dev, 0);
+ zx234290_rtc.zx234290 = NULL;
+
+ return 0;
+}
+static int zx234290_rtc_resume(struct platform_device *pdev)
+{
+ int irq=0;
+ struct zx234290_board *pmic_plat_data = zx234290_rtc.zx234290->dev->platform_data;
+ irq=gpio_to_irq(pmic_plat_data->irq_gpio_num);
+ enable_irq(irq);
+ zx234290_rtc_setuie(&pdev->dev, 1);
+
+ return 0;
+}
+static int zx234290_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ int irq=0;
+ struct zx234290_board *pmic_plat_data = zx234290_rtc.zx234290->dev->platform_data;
+ //irq=gpio_to_irq(PIN_PMU_INT);
+ irq=gpio_to_irq(pmic_plat_data->irq_gpio_num);
+ disable_irq_nosync(irq);
+ zx234290_rtc_setuie(&pdev->dev, 0);
+
+ return 0;
+}
+
+
+static struct platform_driver zx234290_rtc_driver =
+{
+ .probe = zx234290_rtc_probe,
+ .remove = zx234290_rtc_remove,
+ .suspend = zx234290_rtc_suspend,
+ .resume = zx234290_rtc_resume,
+ .driver = {
+ .name = "zx234290-rtc",
+ .owner = THIS_MODULE,
+ },
+};
+
+
+module_platform_driver(zx234290_rtc_driver);
+
+MODULE_DESCRIPTION("ZX234290 RTC Driver");
+MODULE_AUTHOR("yuxiang");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:zx234290-rtc");
+