blob: 480f740b6147a67fe1ff6849c7e87b9c8f923127 [file] [log] [blame]
/* 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, 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, &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");