From 1c375d919ea8fdea61586722cc8114df0d7f9218 Mon Sep 17 00:00:00 2001 From: lw Date: Mon, 30 Jul 2012 14:59:31 +0800 Subject: [PATCH] phonepad:improve rtc-tps65910 code --- drivers/mfd/tps65910-irq.c | 16 +- drivers/mfd/tps65910.c | 105 ++- drivers/regulator/tps65910-regulator.c | 42 +- drivers/rtc/rtc-tps65910.c | 1029 ++++++++++++------------ include/linux/mfd/tps65910.h | 13 +- 5 files changed, 651 insertions(+), 554 deletions(-) mode change 100644 => 100755 drivers/mfd/tps65910-irq.c mode change 100644 => 100755 drivers/regulator/tps65910-regulator.c mode change 100644 => 100755 include/linux/mfd/tps65910.h diff --git a/drivers/mfd/tps65910-irq.c b/drivers/mfd/tps65910-irq.c old mode 100644 new mode 100755 index c9ed5c00a621..bcec38371c94 --- a/drivers/mfd/tps65910-irq.c +++ b/drivers/mfd/tps65910-irq.c @@ -45,7 +45,7 @@ static irqreturn_t tps65910_irq(int irq, void *irq_data) u32 irq_mask; u8 reg; int i; - + tps65910->read(tps65910, TPS65910_INT_STS, 1, ®); irq_sts = reg; tps65910->read(tps65910, TPS65910_INT_STS2, 1, ®); @@ -169,17 +169,27 @@ int tps65910_irq_init(struct tps65910 *tps65910, int irq, { int ret, cur_irq; int flags = IRQF_ONESHOT; + u8 reg; if (!irq) { dev_warn(tps65910->dev, "No interrupt support, no core IRQ\n"); - return -EINVAL; + return 0; } if (!pdata || !pdata->irq_base) { dev_warn(tps65910->dev, "No interrupt support, no IRQ base\n"); - return -EINVAL; + return 0; } + /* Clear unattended interrupts */ + tps65910->read(tps65910, TPS65910_INT_STS, 1, ®); + tps65910->write(tps65910, TPS65910_INT_STS, 1, ®); + tps65910->read(tps65910, TPS65910_INT_STS2, 1, ®); + tps65910->write(tps65910, TPS65910_INT_STS2, 1, ®); + tps65910->read(tps65910, TPS65910_INT_STS3, 1, ®); + tps65910->write(tps65910, TPS65910_INT_STS3, 1, ®); + + /* Mask top level interrupts */ tps65910->irq_mask = 0xFFFFFF; mutex_init(&tps65910->irq_lock); diff --git a/drivers/mfd/tps65910.c b/drivers/mfd/tps65910.c index 1f3d30a938ec..b000f3ba9b7b 100755 --- a/drivers/mfd/tps65910.c +++ b/drivers/mfd/tps65910.c @@ -44,7 +44,7 @@ static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg, struct i2c_client *i2c = tps65910->i2c_client; struct i2c_msg xfer[2]; int ret; - + int i; /* Write register */ xfer[0].addr = i2c->addr; @@ -61,7 +61,8 @@ static int tps65910_i2c_read(struct tps65910 *tps65910, u8 reg, xfer[1].scl_rate = 200*1000; ret = i2c_transfer(i2c->adapter, xfer, 2); - //printk("%s:reg=0x%x,value=0x%x\n",__func__,reg,*(char *)dest); + //for(i=0;i= 0) @@ -77,15 +78,17 @@ static int tps65910_i2c_write(struct tps65910 *tps65910, u8 reg, /* we add 1 byte for device register */ u8 msg[TPS65910_MAX_REGISTER + 1]; int ret; + int i; if (bytes > TPS65910_MAX_REGISTER) return -EINVAL; - - //printk("%s:reg=0x%x,value=0x%x\n",__func__,reg,*(char *)&src); msg[0] = reg; memcpy(&msg[1], src, bytes); + //for(i=0;iread(tps65910, reg, 1, &val); + if (err < 0) + return err; + + return val; +} + +static inline int tps65910_write(struct tps65910 *tps65910, u8 reg, u8 val) +{ + return tps65910->write(tps65910, reg, 1, &val); +} + +int tps65910_reg_read(struct tps65910 *tps65910, u8 reg) +{ + int data; + + mutex_lock(&tps65910->io_mutex); + + data = tps65910_read(tps65910, reg); + if (data < 0) + dev_err(tps65910->dev, "Read from reg 0x%x failed\n", reg); + + mutex_unlock(&tps65910->io_mutex); + return data; +} +EXPORT_SYMBOL_GPL(tps65910_reg_read); + +int tps65910_reg_write(struct tps65910 *tps65910, u8 reg, u8 val) +{ + int err; + + mutex_lock(&tps65910->io_mutex); + + err = tps65910_write(tps65910, reg, val); + if (err < 0) + dev_err(tps65910->dev, "Write for reg 0x%x failed\n", reg); + + mutex_unlock(&tps65910->io_mutex); + return err; +} +EXPORT_SYMBOL_GPL(tps65910_reg_write); + +/** + * tps65910_bulk_read: Read multiple tps65910 registers + * + * @tps65910: Device to read from + * @reg: First register + * @count: Number of registers + * @buf: Buffer to fill. + */ +int tps65910_bulk_read(struct tps65910 *tps65910, u8 reg, + int count, u8 *buf) +{ + int ret; + + mutex_lock(&tps65910->io_mutex); + + ret = tps65910->read(tps65910, reg, count, buf); + + mutex_unlock(&tps65910->io_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(tps65910_bulk_read); + +int tps65910_bulk_write(struct tps65910 *tps65910, u8 reg, + int count, u8 *buf) +{ + int ret; + + mutex_lock(&tps65910->io_mutex); + + ret = tps65910->write(tps65910, reg, count, buf); + + mutex_unlock(&tps65910->io_mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(tps65910_bulk_write); + + + + int tps65910_set_bits(struct tps65910 *tps65910, u8 reg, u8 mask) { u8 data; @@ -130,7 +221,7 @@ int tps65910_clear_bits(struct tps65910 *tps65910, u8 reg, u8 mask) goto out; } - data &= mask; + data &= ~mask; err = tps65910_i2c_write(tps65910, reg, 1, &data); if (err) dev_err(tps65910->dev, "write to reg %x failed\n", reg); @@ -158,7 +249,7 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, return -ENOMEM; init_data->irq = pmic_plat_data->irq; - init_data->irq_base = pmic_plat_data->irq; + init_data->irq_base = pmic_plat_data->irq_base; tps65910 = kzalloc(sizeof(struct tps65910), GFP_KERNEL); if (tps65910 == NULL) @@ -201,7 +292,7 @@ static int tps65910_i2c_probe(struct i2c_client *i2c, goto err; } } - + printk("%s:irq=%d,irq_base=%d\n",__func__,init_data->irq,init_data->irq_base); return ret; err: diff --git a/drivers/regulator/tps65910-regulator.c b/drivers/regulator/tps65910-regulator.c old mode 100644 new mode 100755 index ca736adfada0..0739da51efd2 --- a/drivers/regulator/tps65910-regulator.c +++ b/drivers/regulator/tps65910-regulator.c @@ -402,7 +402,7 @@ out: return err; } -static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg) +static int tps65910_pmic_reg_read(struct tps65910_reg *pmic, u8 reg) { int data; @@ -416,7 +416,7 @@ static int tps65910_reg_read(struct tps65910_reg *pmic, u8 reg) return data; } -static int tps65910_reg_write(struct tps65910_reg *pmic, u8 reg, u8 val) +static int tps65910_pmic_reg_write(struct tps65910_reg *pmic, u8 reg, u8 val) { int err; @@ -507,7 +507,7 @@ static int tps65910_is_enabled(struct regulator_dev *dev) if (reg < 0) return reg; - value = tps65910_reg_read(pmic, reg); + value = tps65910_pmic_reg_read(pmic, reg); if (value < 0) return value; @@ -580,7 +580,7 @@ static unsigned int tps65910_get_mode(struct regulator_dev *dev) if (reg < 0) return reg; - value = tps65910_reg_read(pmic, reg); + value = tps65910_pmic_reg_read(pmic, reg); if (value < 0) return value; @@ -600,28 +600,28 @@ static int tps65910_get_voltage_dcdc_sel(struct regulator_dev *dev) switch (id) { case TPS65910_REG_VDD1: - opvsel = tps65910_reg_read(pmic, TPS65910_VDD1_OP); - mult = tps65910_reg_read(pmic, TPS65910_VDD1); + opvsel = tps65910_pmic_reg_read(pmic, TPS65910_VDD1_OP); + mult = tps65910_pmic_reg_read(pmic, TPS65910_VDD1); mult = (mult & VDD1_VGAIN_SEL_MASK) >> VDD1_VGAIN_SEL_SHIFT; - srvsel = tps65910_reg_read(pmic, TPS65910_VDD1_SR); + srvsel = tps65910_pmic_reg_read(pmic, TPS65910_VDD1_SR); sr = opvsel & VDD1_OP_CMD_MASK; opvsel &= VDD1_OP_SEL_MASK; srvsel &= VDD1_SR_SEL_MASK; vselmax = 75; break; case TPS65910_REG_VDD2: - opvsel = tps65910_reg_read(pmic, TPS65910_VDD2_OP); - mult = tps65910_reg_read(pmic, TPS65910_VDD2); + opvsel = tps65910_pmic_reg_read(pmic, TPS65910_VDD2_OP); + mult = tps65910_pmic_reg_read(pmic, TPS65910_VDD2); mult = (mult & VDD2_VGAIN_SEL_MASK) >> VDD2_VGAIN_SEL_SHIFT; - srvsel = tps65910_reg_read(pmic, TPS65910_VDD2_SR); + srvsel = tps65910_pmic_reg_read(pmic, TPS65910_VDD2_SR); sr = opvsel & VDD2_OP_CMD_MASK; opvsel &= VDD2_OP_SEL_MASK; srvsel &= VDD2_SR_SEL_MASK; vselmax = 75; break; case TPS65911_REG_VDDCTRL: - opvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_OP); - srvsel = tps65910_reg_read(pmic, TPS65911_VDDCTRL_SR); + opvsel = tps65910_pmic_reg_read(pmic, TPS65911_VDDCTRL_OP); + srvsel = tps65910_pmic_reg_read(pmic, TPS65911_VDDCTRL_SR); sr = opvsel & VDDCTRL_OP_CMD_MASK; opvsel &= VDDCTRL_OP_SEL_MASK; srvsel &= VDDCTRL_SR_SEL_MASK; @@ -661,7 +661,7 @@ static int tps65910_get_voltage(struct regulator_dev *dev) if (reg < 0) return reg; - value = tps65910_reg_read(pmic, reg); + value = tps65910_pmic_reg_read(pmic, reg); if (value < 0) return value; @@ -700,7 +700,7 @@ static int tps65911_get_voltage(struct regulator_dev *dev) reg = pmic->get_ctrl_reg(id); - value = tps65910_reg_read(pmic, reg); + value = tps65910_pmic_reg_read(pmic, reg); switch (id) { case TPS65911_REG_LDO1: @@ -759,7 +759,7 @@ static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev, tps65910_modify_bits(pmic, TPS65910_VDD1, (dcdc_mult << VDD1_VGAIN_SEL_SHIFT), VDD1_VGAIN_SEL_MASK); - tps65910_reg_write(pmic, TPS65910_VDD1_OP, vsel); + tps65910_pmic_reg_write(pmic, TPS65910_VDD1_OP, vsel); break; case TPS65910_REG_VDD2: dcdc_mult = (selector / VDD1_2_NUM_VOLT_FINE) + 1; @@ -770,11 +770,11 @@ static int tps65910_set_voltage_dcdc_sel(struct regulator_dev *dev, tps65910_modify_bits(pmic, TPS65910_VDD2, (dcdc_mult << VDD2_VGAIN_SEL_SHIFT), VDD1_VGAIN_SEL_MASK); - tps65910_reg_write(pmic, TPS65910_VDD2_OP, vsel); + tps65910_pmic_reg_write(pmic, TPS65910_VDD2_OP, vsel); break; case TPS65911_REG_VDDCTRL: vsel = selector + 3; - tps65910_reg_write(pmic, TPS65911_VDDCTRL_OP, vsel); + tps65910_pmic_reg_write(pmic, TPS65911_VDDCTRL_OP, vsel); } return 0; @@ -1090,18 +1090,18 @@ static int tps65910_set_ext_sleep_config(struct tps65910_reg *pmic, (tps65910_chip_id(mfd) == TPS65911))) { int op_reg_add = pmic->get_ctrl_reg(id) + 1; int sr_reg_add = pmic->get_ctrl_reg(id) + 2; - int opvsel = tps65910_reg_read(pmic, op_reg_add); - int srvsel = tps65910_reg_read(pmic, sr_reg_add); + int opvsel = tps65910_pmic_reg_read(pmic, op_reg_add); + int srvsel = tps65910_pmic_reg_read(pmic, sr_reg_add); if (opvsel & VDD1_OP_CMD_MASK) { u8 reg_val = srvsel & VDD1_OP_SEL_MASK; - ret = tps65910_reg_write(pmic, op_reg_add, reg_val); + ret = tps65910_pmic_reg_write(pmic, op_reg_add, reg_val); if (ret < 0) { dev_err(mfd->dev, "Error in configuring op register\n"); return ret; } } - ret = tps65910_reg_write(pmic, sr_reg_add, 0); + ret = tps65910_pmic_reg_write(pmic, sr_reg_add, 0); if (ret < 0) { dev_err(mfd->dev, "Error in settting sr register\n"); return ret; diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index 93290a16ad22..43e9235c67c0 100755 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -1,35 +1,31 @@ /* - * rtc-tps65910.c -- TPS65910 Real Time Clock interface + * Real Time Clock driver for Wolfson Microelectronics tps65910 * - * Copyright (C) 2010 Mistral Solutions Pvt Ltd. - * Author: Umesh K + * Copyright (C) 2009 Wolfson Microelectronics PLC. * - * Based on rtc-twl.c + * Author: Mark Brown + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. */ -#include -#include -#include #include -#include +#include +#include #include +#include #include -#include #include +#include +#include #include -#include #include +#include +#include -#if 0 -#define DBG(x...) printk(KERN_INFO x) -#else -#define DBG(x...) -#endif /* RTC Definitions */ /* RTC_CTRL_REG bitfields */ @@ -60,647 +56,640 @@ #define BIT_RTC_PWDN 0x40 /* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */ -#define ALL_TIME_REGS 6 - -/* - * Supports 1 byte read from TPS65910 RTC register. - */ -static int tps65910_rtc_read_u8(u8 *data, u8 reg) -{ - int ret; - - ret = tps65910_i2c_read_u8(TPS65910_I2C_ID0, data, reg); - - if (ret < 0) - pr_err("tps65910_rtc: Could not read TPS65910" - "register %X - error %d\n", reg, ret); - return ret; -} - -/* - * Supports 1 byte write to TPS65910 RTC registers. - */ -static int tps65910_rtc_write_u8(u8 data, u8 reg) -{ - int ret; +#define ALL_TIME_REGS 7 +#define ALL_ALM_REGS 6 - ret = tps65910_i2c_write_u8(TPS65910_I2C_ID0, data, reg); - if (ret < 0) - pr_err("tps65910_rtc: Could not write TPS65910" - "register %X - error %d\n", reg, ret); - return ret; -} -/* - * Cache the value for timer/alarm interrupts register; this is - * only changed by callers holding rtc ops lock (or resume). - */ -static unsigned char rtc_irq_bits; +#define RTC_SET_TIME_RETRIES 5 +#define RTC_GET_TIME_RETRIES 5 -/* - * Enable 1/second update and/or alarm interrupts. - */ -static int set_rtc_irq_bit(unsigned char bit) -{ - unsigned char val; - int ret; - - val = rtc_irq_bits | bit; - val |= bit; - ret = tps65910_rtc_write_u8(val, TPS65910_REG_RTC_INTERRUPTS); - if (ret == 0) - rtc_irq_bits = val; - return ret; -} +struct tps65910_rtc { + struct tps65910 *tps65910; + struct rtc_device *rtc; + unsigned int alarm_enabled:1; +}; /* - * Disable update and/or alarm interrupts. + * Read current time and date in RTC */ -static int mask_rtc_irq_bit(unsigned char bit) -{ - unsigned char val; - int ret; - - val = rtc_irq_bits & ~bit; - ret = tps65910_rtc_write_u8(val, TPS65910_REG_RTC_INTERRUPTS); - if (ret == 0) - rtc_irq_bits = val; - - return ret; -} - -static int tps65910_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) -{ - int ret; - - if (enabled) - ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); - else - ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); - - return ret; -} - -static int tps65910_rtc_update_irq_enable(struct device *dev, unsigned enabled) +static int tps65910_rtc_readtime(struct device *dev, struct rtc_time *tm) { + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev); + struct tps65910 *tps65910 = tps65910_rtc->tps65910; int ret; + int count = 0; + unsigned char rtc_data[ALL_TIME_REGS + 1]; + u8 rtc_ctl; - if (enabled) - ret = set_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); - else - ret = mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); + /*Dummy read*/ + ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL); + + /* Has the RTC been programmed? */ + ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL); + if (ret < 0) { + dev_err(dev, "Failed to read RTC control: %d\n", ret); + return ret; + } - return ret; -} + rtc_ctl = ret & (~BIT_RTC_CTRL_REG_RTC_V_OPT_M); -#if 1 /* Debugging periodic interrupts */ -/* - * We will just handle setting the frequency and make use the framework for - * reading the periodic interupts. - * - * @freq: Current periodic IRQ freq: - * bit 0: every second - * bit 1: every minute - * bit 2: every hour - * bit 3: every day - */ + ret = tps65910_reg_write(tps65910, TPS65910_RTC_CTRL, rtc_ctl); + if (ret < 0) { + dev_err(dev, "Failed to write RTC control: %d\n", ret); + return ret; + } -static int tps65910_rtc_irq_set_freq(struct device *dev, int freq) -{ - struct rtc_device *rtc = dev_get_drvdata(dev); + + /* Read twice to make sure we don't read a corrupt, partially + * incremented, value. + */ + do { + ret = tps65910_bulk_read(tps65910, TPS65910_SECONDS, + ALL_TIME_REGS, rtc_data); + if (ret != 0) + continue; + + tm->tm_sec = bcd2bin(rtc_data[0]); + tm->tm_min = bcd2bin(rtc_data[1]); + tm->tm_hour = bcd2bin(rtc_data[2]); + tm->tm_mday = bcd2bin(rtc_data[3]); + tm->tm_mon = bcd2bin(rtc_data[4]) - 1; + tm->tm_year = bcd2bin(rtc_data[5]) + 100; + tm->tm_wday = bcd2bin(rtc_data[6]); + + dev_dbg(dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", + 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, tm->tm_wday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + + return ret; - if (freq < 0 || freq > 3) - return -EINVAL; + } while (++count < RTC_GET_TIME_RETRIES); + dev_err(dev, "Timed out reading current time\n"); - rtc->irq_freq = freq; - /* set rtc irq freq to user defined value */ - set_rtc_irq_bit(freq); + return -EIO; - return 0; } -#endif /* - * Gets current TPS65910 RTC time and date parameters. - * - * The RTC's time/alarm representation is not what gmtime(3) requires - * Linux to use: - * - * - Months are 1..12 vs Linux 0-11 - * - Years are 0..99 vs Linux 1900..N (we assume 21st century) + * Set current time and date in RTC */ -static int tps65910_rtc_read_time(struct device *dev, struct rtc_time *tm) +static int tps65910_rtc_set_time(struct device *dev, struct rtc_time *tm) { - unsigned char rtc_data[ALL_TIME_REGS + 1]; + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev); + struct tps65910 *tps65910 = tps65910_rtc->tps65910; int ret; - u8 save_control; - - tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); - ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); - if (ret < 0) - return ret; - - save_control &= ~BIT_RTC_CTRL_REG_RTC_V_OPT_M; - - ret = tps65910_rtc_write_u8(save_control, TPS65910_REG_RTC_CTRL); - if (ret < 0) - return ret; - - ret = tps65910_rtc_read_u8(&rtc_data[0], TPS65910_REG_SECONDS); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_read_u8(&rtc_data[1], TPS65910_REG_MINUTES); + u8 rtc_ctl; + unsigned char rtc_data[ALL_TIME_REGS + 1]; + + rtc_data[0] = bin2bcd(tm->tm_sec); + rtc_data[1] = bin2bcd(tm->tm_min); + rtc_data[2] = bin2bcd(tm->tm_hour); + rtc_data[3] = bin2bcd(tm->tm_mday); + rtc_data[4] = bin2bcd(tm->tm_mon + 1); + rtc_data[5] = bin2bcd(tm->tm_year - 100); + rtc_data[6] = bin2bcd(tm->tm_wday); + + /*Dummy read*/ + ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL); + + /* Stop RTC while updating the TC registers */ + ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL); if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); + dev_err(dev, "Failed to read RTC control: %d\n", ret); return ret; } - ret = tps65910_rtc_read_u8(&rtc_data[2], TPS65910_REG_HOURS); + + rtc_ctl = ret & (~BIT_RTC_CTRL_REG_STOP_RTC_M); + + ret = tps65910_reg_write(tps65910, TPS65910_RTC_CTRL, rtc_ctl); if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); + dev_err(dev, "Failed to write RTC control: %d\n", ret); return ret; } - ret = tps65910_rtc_read_u8(&rtc_data[3], TPS65910_REG_DAYS); + + /* update all the time registers in one shot */ + ret = tps65910_bulk_write(tps65910, TPS65910_SECONDS, + ALL_TIME_REGS, rtc_data); if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); + dev_err(dev, "Failed to read RTC times: %d\n", ret); return ret; } - ret = tps65910_rtc_read_u8(&rtc_data[4], TPS65910_REG_MONTHS); + + /*Dummy read*/ + ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL); + + /* Start RTC again */ + ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL); if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); + dev_err(dev, "Failed to read RTC control: %d\n", ret); return ret; } - ret = tps65910_rtc_read_u8(&rtc_data[5], TPS65910_REG_YEARS); + + rtc_ctl = ret | BIT_RTC_CTRL_REG_STOP_RTC_M; + + ret = tps65910_reg_write(tps65910, TPS65910_RTC_CTRL, rtc_ctl); if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); + dev_err(dev, "Failed to write RTC control: %d\n", ret); return ret; } - tm->tm_sec = bcd2bin(rtc_data[0]); - tm->tm_min = bcd2bin(rtc_data[1]); - tm->tm_hour = bcd2bin(rtc_data[2]); - tm->tm_mday = bcd2bin(rtc_data[3]); - tm->tm_mon = bcd2bin(rtc_data[4]) - 1; - tm->tm_year = bcd2bin(rtc_data[5]) + 100; - - DBG("%s [%d]tm_wday=%d \n",__FUNCTION__,__LINE__,tm->tm_wday); - DBG("%s [%d]tm_sec=%d \n",__FUNCTION__,__LINE__,tm->tm_sec); - DBG("%s [%d]tm_min=%d \n",__FUNCTION__,__LINE__,tm->tm_min); - DBG("%s [%d]tm_hour=%d \n",__FUNCTION__,__LINE__,tm->tm_hour); - DBG("%s [%d]tm_mday=%d \n",__FUNCTION__,__LINE__,tm->tm_mday); - DBG("%s [%d]tm_mon=%d \n",__FUNCTION__,__LINE__,tm->tm_mon); - DBG("%s [%d]tm_year=%d \n",__FUNCTION__,__LINE__,tm->tm_year); - - return ret; + return 0; } -static int tps65910_rtc_set_time(struct device *dev, struct rtc_time *tm) +/* + * Read alarm time and date in RTC + */ +static int tps65910_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) { - unsigned char save_control; - unsigned char rtc_data[ALL_TIME_REGS + 1]; + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev); int ret; + unsigned char alrm_data[ALL_ALM_REGS + 1]; - DBG("%s [%d]tm_wday=%d \n",__FUNCTION__,__LINE__,tm->tm_wday); - DBG("%s [%d]tm_sec=%d \n",__FUNCTION__,__LINE__,tm->tm_sec); - DBG("%s [%d]tm_min=%d \n",__FUNCTION__,__LINE__,tm->tm_min); - DBG("%s [%d]tm_hour=%d \n",__FUNCTION__,__LINE__,tm->tm_hour); - DBG("%s [%d]tm_mday=%d \n",__FUNCTION__,__LINE__,tm->tm_mday); - DBG("%s [%d]tm_mon=%d \n",__FUNCTION__,__LINE__,tm->tm_mon); - DBG("%s [%d]tm_year=%d \n",__FUNCTION__,__LINE__,tm->tm_year); + ret = tps65910_bulk_read(tps65910_rtc->tps65910, TPS65910_ALARM_SECONDS, + ALL_ALM_REGS, alrm_data); + if (ret != 0) { + dev_err(dev, "Failed to read alarm time: %d\n", ret); + return ret; + } - rtc_data[1] = bin2bcd(tm->tm_sec); - rtc_data[2] = bin2bcd(tm->tm_min); - rtc_data[3] = bin2bcd(tm->tm_hour); - rtc_data[4] = bin2bcd(tm->tm_mday); - rtc_data[5] = bin2bcd(tm->tm_mon + 1); - rtc_data[6] = bin2bcd(tm->tm_year - 100); + /* some of these fields may be wildcard/"match all" */ + alrm->time.tm_sec = bcd2bin(alrm_data[0]); + alrm->time.tm_min = bcd2bin(alrm_data[1]); + alrm->time.tm_hour = bcd2bin(alrm_data[2]); + alrm->time.tm_mday = bcd2bin(alrm_data[3]); + alrm->time.tm_mon = bcd2bin(alrm_data[4]) - 1; + alrm->time.tm_year = bcd2bin(alrm_data[5]) + 100; + + ret = tps65910_reg_read(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS); + if (ret < 0) { + dev_err(dev, "Failed to read RTC control: %d\n", ret); + return ret; + } - /*Dummy read*/ - ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); + if (ret & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) + alrm->enabled = 1; + else + alrm->enabled = 0; - /* Stop RTC while updating the TC registers */ - ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); - if (ret < 0) - goto out; + return 0; +} - save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M; +static int tps65910_rtc_stop_alarm(struct tps65910_rtc *tps65910_rtc) +{ + tps65910_rtc->alarm_enabled = 0; - tps65910_rtc_write_u8(save_control, TPS65910_REG_RTC_CTRL); + return tps65910_clear_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS, + BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); - /* update all the time registers in one shot */ - ret = tps65910_rtc_write_u8(rtc_data[1], TPS65910_REG_SECONDS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(rtc_data[2], TPS65910_REG_MINUTES); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(rtc_data[3], TPS65910_REG_HOURS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(rtc_data[4], TPS65910_REG_DAYS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(rtc_data[5], TPS65910_REG_MONTHS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(rtc_data[6], TPS65910_REG_YEARS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } +} - /*Dummy read*/ - ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); +static int tps65910_rtc_start_alarm(struct tps65910_rtc *tps65910_rtc) +{ + tps65910_rtc->alarm_enabled = 1; - ret = tps65910_rtc_read_u8(&save_control, TPS65910_REG_RTC_CTRL); - if (ret < 0) - goto out; - /* Start back RTC */ - save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M; - ret = tps65910_rtc_write_u8(save_control, TPS65910_REG_RTC_CTRL); + return tps65910_set_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS, + BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); -out: - return ret; } -/* - * Gets current TPS65910 RTC alarm time. - */ -static int tps65910_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +static int tps65910_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) { - unsigned char rtc_data[ALL_TIME_REGS + 1]; + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev); int ret; + unsigned char alrm_data[ALL_TIME_REGS + 1]; - ret = tps65910_rtc_read_u8(&rtc_data[0], TPS65910_REG_ALARM_SECONDS); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_read_u8(&rtc_data[1], TPS65910_REG_ALARM_MINUTES); + ret = tps65910_rtc_stop_alarm(tps65910_rtc); if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); + dev_err(dev, "Failed to stop alarm: %d\n", ret); return ret; } - ret = tps65910_rtc_read_u8(&rtc_data[2], TPS65910_REG_ALARM_HOURS); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_read_u8(&rtc_data[3], TPS65910_REG_ALARM_DAYS); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_read_u8(&rtc_data[4], TPS65910_REG_ALARM_MONTHS); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); + + alrm_data[0] = bin2bcd(alrm->time.tm_sec); + alrm_data[1] = bin2bcd(alrm->time.tm_min); + alrm_data[2] = bin2bcd(alrm->time.tm_hour); + alrm_data[3] = bin2bcd(alrm->time.tm_mday); + alrm_data[4] = bin2bcd(alrm->time.tm_mon + 1); + alrm_data[5] = bin2bcd(alrm->time.tm_year - 100); + + ret = tps65910_bulk_write(tps65910_rtc->tps65910, TPS65910_ALARM_SECONDS, + ALL_ALM_REGS, alrm_data); + if (ret != 0) { + dev_err(dev, "Failed to read alarm time: %d\n", ret); return ret; } - ret = tps65910_rtc_read_u8(&rtc_data[5], TPS65910_REG_ALARM_YEARS); - if (ret < 0) { - dev_err(dev, "rtc_read_time error %d\n", ret); - return ret; + + if (alrm->enabled) { + ret = tps65910_rtc_start_alarm(tps65910_rtc); + if (ret < 0) { + dev_err(dev, "Failed to start alarm: %d\n", ret); + return ret; + } } - /* some of these fields may be wildcard/"match all" */ - alm->time.tm_sec = bcd2bin(rtc_data[0]); - alm->time.tm_min = bcd2bin(rtc_data[1]); - alm->time.tm_hour = bcd2bin(rtc_data[2]); - alm->time.tm_mday = bcd2bin(rtc_data[3]); - alm->time.tm_mon = bcd2bin(rtc_data[4]) - 1; - alm->time.tm_year = bcd2bin(rtc_data[5]) + 100; + return 0; +} - /* report cached alarm enable state */ - if (rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) - alm->enabled = 1; +static int tps65910_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev); - return ret; + if (enabled) + return tps65910_rtc_start_alarm(tps65910_rtc); + else + return tps65910_rtc_stop_alarm(tps65910_rtc); } -static int tps65910_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +static int tps65910_rtc_update_irq_enable(struct device *dev, + unsigned int enabled) { - unsigned char alarm_data[ALL_TIME_REGS + 1]; - int ret; + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev); - ret = tps65910_rtc_alarm_irq_enable(dev, 0); - if (ret) - goto out; + if (enabled) + return tps65910_set_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS, + BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); + else + return tps65910_clear_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS, + BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); +} - alarm_data[1] = bin2bcd(alm->time.tm_sec); - alarm_data[2] = bin2bcd(alm->time.tm_min); - alarm_data[3] = bin2bcd(alm->time.tm_hour); - alarm_data[4] = bin2bcd(alm->time.tm_mday); - alarm_data[5] = bin2bcd(alm->time.tm_mon + 1); - alarm_data[6] = bin2bcd(alm->time.tm_year - 100); +/* + * We will just handle setting the frequency and make use the framework for + * reading the periodic interupts. + * + * @freq: Current periodic IRQ freq: + * bit 0: every second + * bit 1: every minute + * bit 2: every hour + * bit 3: every day + */ +static int tps65910_rtc_irq_set_freq(struct device *dev, int freq) +{ + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(dev); + int ret; + u8 rtc_ctl; + + if (freq < 0 || freq > 3) + return -EINVAL; - /* update all the alarm registers in one shot */ - ret = tps65910_rtc_write_u8(alarm_data[1], TPS65910_REG_ALARM_SECONDS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(alarm_data[2], TPS65910_REG_ALARM_MINUTES); + ret = tps65910_reg_read(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS); if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); + dev_err(dev, "Failed to read RTC interrupt: %d\n", ret); return ret; } - ret = tps65910_rtc_write_u8(alarm_data[3], TPS65910_REG_ALARM_HOURS); + + rtc_ctl = ret | freq; + + ret = tps65910_reg_write(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS, rtc_ctl); if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); + dev_err(dev, "Failed to write RTC control: %d\n", ret); return ret; } - ret = tps65910_rtc_write_u8(alarm_data[4], TPS65910_REG_ALARM_DAYS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(alarm_data[5], TPS65910_REG_ALARM_MONTHS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - ret = tps65910_rtc_write_u8(alarm_data[6], TPS65910_REG_ALARM_YEARS); - if (ret < 0) { - dev_err(dev, "rtc_write_time error %d\n", ret); - return ret; - } - - if (alm->enabled) - ret = tps65910_rtc_alarm_irq_enable(dev, 1); -out: + return ret; } -struct work_struct rtc_wq; -unsigned long rtc_events; -struct rtc_device *global_rtc; -void tps65910_rtc_work(void *data) +static irqreturn_t tps65910_alm_irq(int irq, void *data) { - int res; - u8 rd_reg; - unsigned long events = 0; + struct tps65910_rtc *tps65910_rtc = data; - DBG("Enter::%s %d\n",__FUNCTION__,__LINE__); + rtc_update_irq(tps65910_rtc->rtc, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} - res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_INT_STS); +static irqreturn_t tps65910_per_irq(int irq, void *data) +{ + struct tps65910_rtc *tps65910_rtc = data; - if (res < 0) - goto out; - /* - * Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG. - * only one (ALARM or RTC) interrupt source may be enabled - * at time, we also could check our results - * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM] - */ - if (rd_reg & TPS65910_RTC_ALARM_IT) { - res = tps65910_rtc_write_u8(rd_reg | TPS65910_RTC_ALARM_IT, - TPS65910_REG_INT_STS); - if (res < 0) - goto out; - - /*Dummy read -- mandatory for status register*/ - res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS); - mdelay(100); - res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS); - res = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_RTC_STATUS); - - rtc_events |= RTC_IRQF | RTC_AF; - } else if (rd_reg & TPS65910_RTC_PERIOD_IT) { - res = tps65910_rtc_write_u8(rd_reg | TPS65910_RTC_PERIOD_IT, - TPS65910_REG_INT_STS); - if (res < 0) - goto out; - - /*Dummy read -- mandatory for status register*/ - res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS); - mdelay(100); - res = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS); - rd_reg &= 0xC3; - res = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_RTC_STATUS); - rtc_events |= RTC_IRQF | RTC_UF; - } -out: - /* Notify RTC core on event */ - events = rtc_events; - rtc_update_irq(global_rtc, 1, events); + rtc_update_irq(tps65910_rtc->rtc, 1, RTC_IRQF | RTC_UF); + + //printk("%s:irq=%d\n",__func__,irq); + return IRQ_HANDLED; } -static struct rtc_class_ops tps65910_rtc_ops = { - .read_time = tps65910_rtc_read_time, - .set_time = tps65910_rtc_set_time, - .read_alarm = tps65910_rtc_read_alarm, - .set_alarm = tps65910_rtc_set_alarm, +static const struct rtc_class_ops tps65910_rtc_ops = { + .read_time = tps65910_rtc_readtime, + //.set_mmss = tps65910_rtc_set_mmss, + .set_time = tps65910_rtc_set_time, + .read_alarm = tps65910_rtc_readalarm, + .set_alarm = tps65910_rtc_setalarm, .alarm_irq_enable = tps65910_rtc_alarm_irq_enable, -// .update_irq_enable = tps65910_rtc_update_irq_enable, -// .irq_set_freq = tps65910_rtc_irq_set_freq, + //.update_irq_enable = tps65910_rtc_update_irq_enable, + //.irq_set_freq = tps65910_rtc_irq_set_freq, }; -static int __devinit tps65910_rtc_probe(struct platform_device *pdev) +#ifdef CONFIG_PM +/* Turn off the alarm if it should not be a wake source. */ +static int tps65910_rtc_suspend(struct device *dev) { - struct rtc_device *rtc; - int ret = 0, stop_run = 0; - u8 rd_reg; - struct rtc_time tm_def = { // 2011.1.1 12:00:00 Saturday - .tm_wday = 6, - .tm_year = 111, - .tm_mon = 0, - .tm_mday = 1, - .tm_hour = 12, - .tm_min = 0, - .tm_sec = 0, - }; - - rtc = rtc_device_register(pdev->name, - &pdev->dev, &tps65910_rtc_ops, THIS_MODULE); - - if (IS_ERR(rtc)) { - ret = PTR_ERR(rtc); - dev_err(&pdev->dev, "can't register TPS65910 RTC device,\ - err %ld\n", PTR_ERR(rtc)); - goto out0; + struct platform_device *pdev = to_platform_device(dev); + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(&pdev->dev); + int ret; + + if (tps65910_rtc->alarm_enabled && device_may_wakeup(&pdev->dev)) + ret = tps65910_rtc_start_alarm(tps65910_rtc); + else + ret = tps65910_rtc_stop_alarm(tps65910_rtc); + + if (ret != 0) + dev_err(&pdev->dev, "Failed to update RTC alarm: %d\n", ret); + + return 0; +} + +/* Enable the alarm if it should be enabled (in case it was disabled to + * prevent use as a wake source). + */ +static int tps65910_rtc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(&pdev->dev); + int ret; + if (tps65910_rtc->alarm_enabled) { + ret = tps65910_rtc_start_alarm(tps65910_rtc); + if (ret != 0) + dev_err(&pdev->dev, + "Failed to restart RTC alarm: %d\n", ret); } - printk(KERN_INFO "TPS65910 RTC device successfully registered\n"); - platform_set_drvdata(pdev, rtc); - /* Take rtc out of reset */ - tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_DEVCTRL); - rd_reg &= ~BIT_RTC_PWDN; - ret = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_DEVCTRL); + return 0; +} - /* Dummy read to ensure that the register gets updated. - * Please refer tps65910 TRM table:25 for details - */ - stop_run = 0; - ret = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_STATUS); +/* Unconditionally disable the alarm */ +static int tps65910_rtc_freeze(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct tps65910_rtc *tps65910_rtc = dev_get_drvdata(&pdev->dev); + int ret; + + ret = tps65910_rtc_stop_alarm(tps65910_rtc); + if (ret != 0) + dev_err(&pdev->dev, "Failed to stop RTC alarm: %d\n", ret); + + return 0; +} +#else +#define tps65910_rtc_suspend NULL +#define tps65910_rtc_resume NULL +#define tps65910_rtc_freeze NULL +#endif + +struct platform_device *g_pdev; +static int tps65910_rtc_probe(struct platform_device *pdev) +{ + struct tps65910 *tps65910 = dev_get_drvdata(pdev->dev.parent); + struct tps65910_rtc *tps65910_rtc; + int per_irq; + int alm_irq; + int ret = 0; + u8 rtc_ctl; + + struct rtc_time tm; + struct rtc_time tm_def = { // 2012.1.1 12:00:00 Saturday + .tm_wday = 6, + .tm_year = 111, + .tm_mon = 0, + .tm_mday = 1, + .tm_hour = 12, + .tm_min = 0, + .tm_sec = 0, + }; + + tps65910_rtc = kzalloc(sizeof(*tps65910_rtc), GFP_KERNEL); + if (tps65910_rtc == NULL) + return -ENOMEM; + + platform_set_drvdata(pdev, tps65910_rtc); + tps65910_rtc->tps65910 = tps65910; + per_irq = tps65910->irq_base + TPS65910_IRQ_RTC_PERIOD; + alm_irq = tps65910->irq_base + TPS65910_IRQ_RTC_ALARM; + + /* Take rtc out of reset */ + ret = tps65910_reg_read(tps65910, TPS65910_DEVCTRL); if (ret < 0) { - printk(KERN_ERR "TPS65910 RTC STATUS REG READ FAILED\n"); - goto out1; + dev_err(&pdev->dev, "Failed to read TPS65910_DEVCTRL: %d\n", ret); + return ret; } - if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M) { - dev_warn(&pdev->dev, "Power up reset detected.\n"); - // cwz:if rtc power up reset, set default time. - printk(KERN_INFO "TPS65910 RTC set to default time\n"); - tps65910_rtc_set_time(&rtc->dev, &tm_def); + if(ret & BIT_RTC_PWDN) + { + rtc_ctl = ret & (~BIT_RTC_PWDN); + + ret = tps65910_reg_write(tps65910, TPS65910_DEVCTRL, rtc_ctl); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to write RTC control: %d\n", ret); + return ret; + } } - if (!(rd_reg & BIT_RTC_STATUS_REG_RUN_M)) { - dev_warn(&pdev->dev, "RTC stop run.\n"); - stop_run = 1; + + /*start rtc default*/ + ret = tps65910_reg_read(tps65910, TPS65910_RTC_CTRL); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to read RTC control: %d\n", ret); + return ret; } - if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M) - dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n"); - /* Clear RTC Power up reset and pending alarm interrupts */ - ret = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_RTC_STATUS); - if (ret < 0) - goto out1; + if(!(ret & BIT_RTC_CTRL_REG_STOP_RTC_M)) + { + rtc_ctl = ret | BIT_RTC_CTRL_REG_STOP_RTC_M; - ret = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_INT_STS); + ret = tps65910_reg_write(tps65910, TPS65910_RTC_CTRL, rtc_ctl); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to write RTC control: %d\n", ret); + return ret; + } + } + + ret = tps65910_reg_read(tps65910, TPS65910_RTC_STATUS); if (ret < 0) { - printk(KERN_ERR "TPS65910 RTC STATUS REG READ FAILED\n"); - goto out1; + dev_err(&pdev->dev, "Failed to read RTC status: %d\n", ret); + return ret; + } + + /*set init time*/ + ret = tps65910_rtc_readtime(&pdev->dev, &tm); + if (ret) + { + dev_err(&pdev->dev, "Failed to read RTC time\n"); + return ret; + } + + ret = rtc_valid_tm(&tm); + if (ret) { + dev_err(&pdev->dev,"invalid date/time and init time\n"); + tps65910_rtc_set_time(&pdev->dev, &tm_def); // 2011-01-01 12:00:00 + dev_info(&pdev->dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", + 1900 + tm_def.tm_year, tm_def.tm_mon + 1, tm_def.tm_mday, tm_def.tm_wday, + tm_def.tm_hour, tm_def.tm_min, tm_def.tm_sec); } - if (rd_reg & 0x40) { - printk(KERN_INFO "pending alarm interrupt!!! clearing!!!"); - tps65910_rtc_write_u8(rd_reg, TPS65910_REG_INT_STS); + device_init_wakeup(&pdev->dev, 1); + + tps65910_rtc->rtc = rtc_device_register("tps65910", &pdev->dev, + &tps65910_rtc_ops, THIS_MODULE); + if (IS_ERR(tps65910_rtc->rtc)) { + ret = PTR_ERR(tps65910_rtc->rtc); + goto err; } - global_rtc = rtc; - - /* Link RTC IRQ handler to TPS65910 Core */ - //tps65910_add_irq_work(TPS65910_RTC_ALARM_IRQ, tps65910_rtc_work); - //tps65910_add_irq_work(TPS65910_RTC_PERIOD_IRQ, tps65910_rtc_work); - - /* Check RTC module status, Enable if it is off */ - if (stop_run) { - dev_info(&pdev->dev, "Enabling TPS65910-RTC.\n"); - // cwz:if rtc stop, set default time, then enable rtc - printk(KERN_INFO "TPS65910 RTC set to default time\n"); - tps65910_rtc_set_time(&rtc->dev, &tm_def); - ret = tps65910_rtc_read_u8(&rd_reg, TPS65910_REG_RTC_CTRL); - if (ret < 0) - goto out1; - - rd_reg |= BIT_RTC_CTRL_REG_STOP_RTC_M; - ret = tps65910_rtc_write_u8(rd_reg, TPS65910_REG_RTC_CTRL); - if (ret < 0) - goto out1; + /*request rtc and alarm irq of tps65910*/ + ret = request_threaded_irq(per_irq, NULL, tps65910_per_irq, + IRQF_TRIGGER_RISING, "RTC period", + tps65910_rtc); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request periodic IRQ %d: %d\n", + per_irq, ret); } - /* init cached IRQ enable bits */ - ret = tps65910_rtc_read_u8(&rtc_irq_bits, TPS65910_REG_RTC_INTERRUPTS); - if (ret < 0) - goto out1; + ret = request_threaded_irq(alm_irq, NULL, tps65910_alm_irq, + IRQF_TRIGGER_RISING, "RTC alarm", + tps65910_rtc); + if (ret != 0) { + dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n", + alm_irq, ret); + } - tps65910_rtc_write_u8(0x3F, TPS65910_REG_INT_MSK); - return ret; + //for rtc irq test + //tps65910_set_bits(tps65910_rtc->tps65910, TPS65910_RTC_INTERRUPTS, + // BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); + + g_pdev = pdev; + + printk("%s:ok\n",__func__); + + return 0; -out1: - rtc_device_unregister(rtc); -out0: +err: + kfree(tps65910_rtc); return ret; } -/* - * Disable all TPS65910 RTC module interrupts. - * Sets status flag to free. - */ static int __devexit tps65910_rtc_remove(struct platform_device *pdev) { - /* leave rtc running, but disable irqs */ - struct rtc_device *rtc = platform_get_drvdata(pdev); - int irq = platform_get_irq(pdev, 0); - - mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M); - mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); - + struct tps65910_rtc *tps65910_rtc = platform_get_drvdata(pdev); + int per_irq = tps65910_rtc->tps65910->irq_base + TPS65910_IRQ_RTC_PERIOD; + int alm_irq = tps65910_rtc->tps65910->irq_base + TPS65910_IRQ_RTC_ALARM; - free_irq(irq, rtc); + free_irq(alm_irq, tps65910_rtc); + free_irq(per_irq, tps65910_rtc); + rtc_device_unregister(tps65910_rtc->rtc); + kfree(tps65910_rtc); - rtc_device_unregister(rtc); - platform_set_drvdata(pdev, NULL); return 0; } -static void tps65910_rtc_shutdown(struct platform_device *pdev) -{ - /* mask timer interrupts, but leave alarm interrupts on to enable - * power-on when alarm is triggered - */ - mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); -} +static const struct dev_pm_ops tps65910_rtc_pm_ops = { + .suspend = tps65910_rtc_suspend, + .resume = tps65910_rtc_resume, -#ifdef CONFIG_PM + .freeze = tps65910_rtc_freeze, + .thaw = tps65910_rtc_resume, + .restore = tps65910_rtc_resume, -static unsigned char irqstat; + .poweroff = tps65910_rtc_suspend, +}; -static -int tps65910_rtc_suspend(struct platform_device *pdev, pm_message_t state) -{ - irqstat = rtc_irq_bits; - mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M); - return 0; -} +static struct platform_driver tps65910_rtc_driver = { + .probe = tps65910_rtc_probe, + .remove = __devexit_p(tps65910_rtc_remove), + .driver = { + .name = "tps65910-rtc", + .pm = &tps65910_rtc_pm_ops, + }, +}; -static int tps65910_rtc_resume(struct platform_device *pdev) +static ssize_t rtc_tps65910_test_write(struct file *file, + const char __user *buf, size_t count, loff_t *offset) { - set_rtc_irq_bit(irqstat); - return 0; + char nr_buf[8]; + int nr = 0, ret; + struct platform_device *pdev; + struct rtc_time tm; + + if(count > 3) + return -EFAULT; + ret = copy_from_user(nr_buf, buf, count); + if(ret < 0) + return -EFAULT; + + sscanf(nr_buf, "%d", &nr); + if(nr >= 2 || nr < 0) + { + printk("%s:data is error\n",__func__); + return -EFAULT; + } + + if(!g_pdev) + return -EFAULT; + else + pdev = g_pdev; + + if(nr == 0) + { + tm.tm_wday = 6; + tm.tm_year = 111; + tm.tm_mon = 0; + tm.tm_mday = 1; + tm.tm_hour = 12; + tm.tm_min = 0; + tm.tm_sec = 0; + + ret = tps65910_rtc_set_time(&pdev->dev, &tm); // 2011-01-01 12:00:00 + if (ret) + { + dev_err(&pdev->dev, "Failed to set RTC time\n"); + return -EFAULT; + } + + } + + /*set init time*/ + ret = tps65910_rtc_readtime(&pdev->dev, &tm); + if (ret) + dev_err(&pdev->dev, "Failed to read RTC time\n"); + else + dev_info(&pdev->dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", + 1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday, tm.tm_wday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + + if(!ret) + printk("%s:ok\n",__func__); + else + printk("%s:error\n",__func__); + + return count; } -#else -#define tps65910_rtc_suspend NULL -#define tps65910_rtc_resume NULL -#endif - +static const struct file_operations rtc_tps65910_test_fops = { + .write = rtc_tps65910_test_write, +}; -static struct platform_driver tps65910rtc_driver = { - .probe = tps65910_rtc_probe, - .remove = __devexit_p(tps65910_rtc_remove), - .shutdown = tps65910_rtc_shutdown, - .suspend = tps65910_rtc_suspend, - .resume = tps65910_rtc_resume, - .driver = { - .owner = THIS_MODULE, - .name = "tps65910_rtc", - }, +static struct miscdevice rtc_tps65910_test_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "rtc_tps65910_test", + .fops = &rtc_tps65910_test_fops, }; -//extern int board_wm831x ; + static int __init tps65910_rtc_init(void) { -// if (board_wm831x == 1) -// { -// printk("board with wm831 not tps65910,so skip register tps65910\n"); -// return 0; -// } - - return platform_driver_register(&tps65910rtc_driver); + misc_register(&rtc_tps65910_test_misc); + return platform_driver_register(&tps65910_rtc_driver); } module_init(tps65910_rtc_init); static void __exit tps65910_rtc_exit(void) -{ - platform_driver_unregister(&tps65910rtc_driver); +{ + misc_deregister(&rtc_tps65910_test_misc); + platform_driver_unregister(&tps65910_rtc_driver); } module_exit(tps65910_rtc_exit); -MODULE_ALIAS("platform:tps65910_rtc"); -MODULE_AUTHOR("cwz