/* 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, 1:disable 0: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); | |
if(0==enabled)//disable alarm | |
{ | |
zx234290_rtc_alarm_enable(ALARM_SECOND, 1); | |
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); | |
}; | |
/*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"); | |