| /* 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); | |
| #ifdef _USE_VEHICLE_DC | |
| printk("rtc get time only probe ok!\n"); | |
| #else | |
| 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); | |
| #endif | |
| 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"); | |