[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,&reg_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, &reg_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, &reg_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");

+