Merge tag 'rtc-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
Pull RTC updates from Alexandre Belloni: "RTC for 4.8 Cleanups: - huge cleanup of rtc-generic and char/genrtc this allowed to cleanup rtc-cmos, rtc-sh, rtc-m68k, rtc-powerpc and rtc-parisc - move mn10300 to rtc-cmos Subsystem: - fix wakealarms after hibernate - multiples fixes for rctest - simplify implementations of .read_alarm New drivers: - Maxim MAX6916 Drivers: - ds1307: fix weekday - m41t80: add wakeup support - pcf85063: add support for PCF85063A variant - rv8803: extend i2c fix and other fixes - s35390a: fix alarm reading, this fixes instant reboot after shutdown for QNAP TS-41x - s3c: clock fixes" * tag 'rtc-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (65 commits) rtc: rv8803: Clear V1F when setting the time rtc: rv8803: Stop the clock while setting the time rtc: rv8803: Always apply the I²C workaround rtc: rv8803: Fix read day of week rtc: rv8803: Remove the check for valid time rtc: rv8803: Kconfig: Indicate rx8900 support rtc: asm9260: remove .owner field for driver rtc: at91sam9: Fix missing spin_lock_init() rtc: m41t80: add suspend handlers for alarm IRQ rtc: m41t80: make it a real error message rtc: pcf85063: Add support for the PCF85063A device rtc: pcf85063: fix year range rtc: hym8563: in .read_alarm set .tm_sec to 0 to signal minute accuracy rtc: explicitly set tm_sec = 0 for drivers with minute accurancy rtc: s3c: Add s3c_rtc_{enable/disable}_clk in s3c_rtc_setfreq() rtc: s3c: Remove unnecessary call to disable already disabled clock rtc: abx80x: use devm_add_action_or_reset() rtc: m41t80: use devm_add_action_or_reset() rtc: fix a typo and reduce three empty lines to one rtc: s35390a: improve two comments in .set_alarm ...
This commit is contained in:
@@ -5,6 +5,10 @@
|
||||
config RTC_LIB
|
||||
bool
|
||||
|
||||
config RTC_MC146818_LIB
|
||||
bool
|
||||
select RTC_LIB
|
||||
|
||||
menuconfig RTC_CLASS
|
||||
bool "Real Time Clock"
|
||||
default n
|
||||
@@ -574,10 +578,10 @@ config RTC_DRV_EM3027
|
||||
will be called rtc-em3027.
|
||||
|
||||
config RTC_DRV_RV8803
|
||||
tristate "Micro Crystal RV8803"
|
||||
tristate "Micro Crystal RV8803, Epson RX8900"
|
||||
help
|
||||
If you say yes here you get support for the Micro Crystal
|
||||
RV8803 RTC chips.
|
||||
If you say yes here you get support for the Micro Crystal RV8803 and
|
||||
Epson RX8900 RTC chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-rv8803.
|
||||
@@ -670,6 +674,18 @@ config RTC_DRV_DS1390
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-ds1390.
|
||||
|
||||
config RTC_DRV_MAX6916
|
||||
tristate "Maxim MAX6916"
|
||||
help
|
||||
If you say yes here you will get support for the
|
||||
Maxim MAX6916 SPI RTC chip.
|
||||
|
||||
This driver only supports the RTC feature, and not other chip
|
||||
features such as alarms.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-max6916.
|
||||
|
||||
config RTC_DRV_R9701
|
||||
tristate "Epson RTC-9701JE"
|
||||
help
|
||||
@@ -795,8 +811,9 @@ comment "Platform RTC drivers"
|
||||
|
||||
config RTC_DRV_CMOS
|
||||
tristate "PC-style 'CMOS'"
|
||||
depends on X86 || ARM || M32R || PPC || MIPS || SPARC64
|
||||
depends on X86 || ARM || M32R || PPC || MIPS || SPARC64 || MN10300
|
||||
default y if X86
|
||||
select RTC_MC146818_LIB
|
||||
help
|
||||
Say "yes" here to get direct support for the real time clock
|
||||
found in every PC or ACPI-based system, and some other boards.
|
||||
@@ -815,6 +832,7 @@ config RTC_DRV_CMOS
|
||||
config RTC_DRV_ALPHA
|
||||
bool "Alpha PC-style CMOS"
|
||||
depends on ALPHA
|
||||
select RTC_MC146818_LIB
|
||||
default y
|
||||
help
|
||||
Direct support for the real-time clock found on every Alpha
|
||||
|
@@ -8,6 +8,7 @@ obj-$(CONFIG_RTC_LIB) += rtc-lib.o
|
||||
obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o
|
||||
obj-$(CONFIG_RTC_SYSTOHC) += systohc.o
|
||||
obj-$(CONFIG_RTC_CLASS) += rtc-core.o
|
||||
obj-$(CONFIG_RTC_MC146818_LIB) += rtc-mc146818-lib.o
|
||||
rtc-core-y := class.o interface.o
|
||||
|
||||
ifdef CONFIG_RTC_DRV_EFI
|
||||
@@ -85,6 +86,7 @@ obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
|
||||
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX6916) += rtc-max6916.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o
|
||||
|
@@ -104,7 +104,17 @@ static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *al
|
||||
else if (!rtc->ops->read_alarm)
|
||||
err = -EINVAL;
|
||||
else {
|
||||
memset(alarm, 0, sizeof(struct rtc_wkalrm));
|
||||
alarm->enabled = 0;
|
||||
alarm->pending = 0;
|
||||
alarm->time.tm_sec = -1;
|
||||
alarm->time.tm_min = -1;
|
||||
alarm->time.tm_hour = -1;
|
||||
alarm->time.tm_mday = -1;
|
||||
alarm->time.tm_mon = -1;
|
||||
alarm->time.tm_year = -1;
|
||||
alarm->time.tm_wday = -1;
|
||||
alarm->time.tm_yday = -1;
|
||||
alarm->time.tm_isdst = -1;
|
||||
err = rtc->ops->read_alarm(rtc->dev.parent, alarm);
|
||||
}
|
||||
|
||||
@@ -383,7 +393,7 @@ int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
|
||||
rtc->aie_timer.period = ktime_set(0, 0);
|
||||
|
||||
/* Alarm has to be enabled & in the futrure for us to enqueue it */
|
||||
/* Alarm has to be enabled & in the future for us to enqueue it */
|
||||
if (alarm->enabled && (rtc_tm_to_ktime(now).tv64 <
|
||||
rtc->aie_timer.node.expires.tv64)) {
|
||||
|
||||
@@ -395,8 +405,6 @@ int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_initialize_alarm);
|
||||
|
||||
|
||||
|
||||
int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
|
||||
{
|
||||
int err = mutex_lock_interruptible(&rtc->ops_lock);
|
||||
@@ -748,9 +756,23 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
|
||||
*/
|
||||
static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
|
||||
{
|
||||
struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
|
||||
struct rtc_time tm;
|
||||
ktime_t now;
|
||||
|
||||
timer->enabled = 1;
|
||||
__rtc_read_time(rtc, &tm);
|
||||
now = rtc_tm_to_ktime(tm);
|
||||
|
||||
/* Skip over expired timers */
|
||||
while (next) {
|
||||
if (next->expires.tv64 >= now.tv64)
|
||||
break;
|
||||
next = timerqueue_iterate_next(next);
|
||||
}
|
||||
|
||||
timerqueue_add(&rtc->timerqueue, &timer->node);
|
||||
if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) {
|
||||
if (!next) {
|
||||
struct rtc_wkalrm alarm;
|
||||
int err;
|
||||
alarm.time = rtc_ktime_to_tm(timer->node.expires);
|
||||
|
@@ -643,17 +643,15 @@ static int abx80x_probe(struct i2c_client *client,
|
||||
return err;
|
||||
}
|
||||
|
||||
err = devm_add_action(&client->dev, rtc_calib_remove_sysfs_group,
|
||||
&client->dev);
|
||||
if (err) {
|
||||
rtc_calib_remove_sysfs_group(&client->dev);
|
||||
err = devm_add_action_or_reset(&client->dev,
|
||||
rtc_calib_remove_sysfs_group,
|
||||
&client->dev);
|
||||
if (err)
|
||||
dev_err(&client->dev,
|
||||
"Failed to add sysfs cleanup action: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int abx80x_remove(struct i2c_client *client)
|
||||
|
@@ -343,7 +343,6 @@ static struct platform_driver asm9260_rtc_driver = {
|
||||
.remove = asm9260_rtc_remove,
|
||||
.driver = {
|
||||
.name = "asm9260-rtc",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = asm9260_dt_ids,
|
||||
},
|
||||
};
|
||||
|
@@ -375,6 +375,7 @@ static int at91_rtc_probe(struct platform_device *pdev)
|
||||
if (!rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&rtc->lock);
|
||||
rtc->irq = irq;
|
||||
|
||||
/* platform setup code should have handled this; sigh */
|
||||
|
@@ -43,7 +43,7 @@
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
|
||||
#include <asm-generic/rtc.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
struct cmos_rtc {
|
||||
struct rtc_device *rtc;
|
||||
@@ -190,10 +190,10 @@ static inline void cmos_write_bank2(unsigned char val, unsigned char addr)
|
||||
static int cmos_read_time(struct device *dev, struct rtc_time *t)
|
||||
{
|
||||
/* REVISIT: if the clock has a "century" register, use
|
||||
* that instead of the heuristic in get_rtc_time().
|
||||
* that instead of the heuristic in mc146818_get_time().
|
||||
* That'll make Y3K compatility (year > 2070) easy!
|
||||
*/
|
||||
get_rtc_time(t);
|
||||
mc146818_get_time(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -205,7 +205,7 @@ static int cmos_set_time(struct device *dev, struct rtc_time *t)
|
||||
* takes effect exactly 500ms after we write the register.
|
||||
* (Also queueing and other delays before we get this far.)
|
||||
*/
|
||||
return set_rtc_time(t);
|
||||
return mc146818_set_time(t);
|
||||
}
|
||||
|
||||
static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
@@ -220,8 +220,6 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
* Some also support day and month, for alarms up to a year in
|
||||
* the future.
|
||||
*/
|
||||
t->time.tm_mday = -1;
|
||||
t->time.tm_mon = -1;
|
||||
|
||||
spin_lock_irq(&rtc_lock);
|
||||
t->time.tm_sec = CMOS_READ(RTC_SECONDS_ALARM);
|
||||
@@ -272,7 +270,6 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
}
|
||||
}
|
||||
}
|
||||
t->time.tm_year = -1;
|
||||
|
||||
t->enabled = !!(rtc_control & RTC_AIE);
|
||||
t->pending = 0;
|
||||
@@ -630,7 +627,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
|
||||
address_space = 64;
|
||||
#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) \
|
||||
|| defined(__sparc__) || defined(__mips__) \
|
||||
|| defined(__powerpc__)
|
||||
|| defined(__powerpc__) || defined(CONFIG_MN10300)
|
||||
address_space = 128;
|
||||
#else
|
||||
#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
|
||||
@@ -1142,14 +1139,14 @@ static __init void cmos_of_init(struct platform_device *pdev)
|
||||
if (val)
|
||||
CMOS_WRITE(be32_to_cpup(val), RTC_FREQ_SELECT);
|
||||
|
||||
get_rtc_time(&time);
|
||||
cmos_read_time(&pdev->dev, &time);
|
||||
ret = rtc_valid_tm(&time);
|
||||
if (ret) {
|
||||
struct rtc_time def_time = {
|
||||
.tm_year = 1,
|
||||
.tm_mday = 1,
|
||||
};
|
||||
set_rtc_time(&def_time);
|
||||
cmos_set_time(&pdev->dev, &def_time);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
@@ -85,6 +85,7 @@ static int da9052_read_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm)
|
||||
rtc_tm->tm_mday = v[0][2] & DA9052_RTC_DAY;
|
||||
rtc_tm->tm_hour = v[0][1] & DA9052_RTC_HOUR;
|
||||
rtc_tm->tm_min = v[0][0] & DA9052_RTC_MIN;
|
||||
rtc_tm->tm_sec = 0;
|
||||
|
||||
ret = rtc_valid_tm(rtc_tm);
|
||||
return ret;
|
||||
|
@@ -74,6 +74,7 @@ static int da9055_read_alarm(struct da9055 *da9055, struct rtc_time *rtc_tm)
|
||||
rtc_tm->tm_mday = v[2] & DA9055_RTC_ALM_DAY;
|
||||
rtc_tm->tm_hour = v[1] & DA9055_RTC_ALM_HOUR;
|
||||
rtc_tm->tm_min = v[0] & DA9055_RTC_ALM_MIN;
|
||||
rtc_tm->tm_sec = 0;
|
||||
|
||||
return rtc_valid_tm(rtc_tm);
|
||||
}
|
||||
|
@@ -388,6 +388,8 @@ static int davinci_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
u8 day0, day1;
|
||||
unsigned long flags;
|
||||
|
||||
alm->time.tm_sec = 0;
|
||||
|
||||
spin_lock_irqsave(&davinci_rtc_lock, flags);
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
|
@@ -16,7 +16,7 @@
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/ds1286.h>
|
||||
#include <linux/rtc/ds1286.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@@ -313,13 +313,6 @@ static int ds1305_get_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
alm->time.tm_sec = bcd2bin(buf[DS1305_SEC]);
|
||||
alm->time.tm_min = bcd2bin(buf[DS1305_MIN]);
|
||||
alm->time.tm_hour = bcd2hour(buf[DS1305_HOUR]);
|
||||
alm->time.tm_mday = -1;
|
||||
alm->time.tm_mon = -1;
|
||||
alm->time.tm_year = -1;
|
||||
/* next three fields are unused by Linux */
|
||||
alm->time.tm_wday = -1;
|
||||
alm->time.tm_mday = -1;
|
||||
alm->time.tm_isdst = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@@ -482,11 +482,6 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
t->time.tm_min = bcd2bin(ds1307->regs[1] & 0x7f);
|
||||
t->time.tm_hour = bcd2bin(ds1307->regs[2] & 0x3f);
|
||||
t->time.tm_mday = bcd2bin(ds1307->regs[3] & 0x3f);
|
||||
t->time.tm_mon = -1;
|
||||
t->time.tm_year = -1;
|
||||
t->time.tm_wday = -1;
|
||||
t->time.tm_yday = -1;
|
||||
t->time.tm_isdst = -1;
|
||||
|
||||
/* ... and status */
|
||||
t->enabled = !!(ds1307->regs[7] & DS1337_BIT_A1IE);
|
||||
@@ -602,6 +597,8 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
|
||||
* Alarm support for mcp794xx devices.
|
||||
*/
|
||||
|
||||
#define MCP794XX_REG_WEEKDAY 0x3
|
||||
#define MCP794XX_REG_WEEKDAY_WDAY_MASK 0x7
|
||||
#define MCP794XX_REG_CONTROL 0x07
|
||||
# define MCP794XX_BIT_ALM0_EN 0x10
|
||||
# define MCP794XX_BIT_ALM1_EN 0x20
|
||||
@@ -1231,13 +1228,16 @@ static int ds1307_probe(struct i2c_client *client,
|
||||
{
|
||||
struct ds1307 *ds1307;
|
||||
int err = -ENODEV;
|
||||
int tmp;
|
||||
int tmp, wday;
|
||||
struct chip_desc *chip = &chips[id->driver_data];
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
bool want_irq = false;
|
||||
bool ds1307_can_wakeup_device = false;
|
||||
unsigned char *buf;
|
||||
struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
struct rtc_time tm;
|
||||
unsigned long timestamp;
|
||||
|
||||
irq_handler_t irq_handler = ds1307_irq;
|
||||
|
||||
static const int bbsqi_bitpos[] = {
|
||||
@@ -1526,6 +1526,27 @@ read_rtc:
|
||||
bin2bcd(tmp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Some IPs have weekday reset value = 0x1 which might not correct
|
||||
* hence compute the wday using the current date/month/year values
|
||||
*/
|
||||
ds1307_get_time(&client->dev, &tm);
|
||||
wday = tm.tm_wday;
|
||||
timestamp = rtc_tm_to_time64(&tm);
|
||||
rtc_time64_to_tm(timestamp, &tm);
|
||||
|
||||
/*
|
||||
* Check if reset wday is different from the computed wday
|
||||
* If different then set the wday which we computed using
|
||||
* timestamp
|
||||
*/
|
||||
if (wday != tm.tm_wday) {
|
||||
wday = i2c_smbus_read_byte_data(client, MCP794XX_REG_WEEKDAY);
|
||||
wday = wday & ~MCP794XX_REG_WEEKDAY_WDAY_MASK;
|
||||
wday = wday | (tm.tm_wday + 1);
|
||||
i2c_smbus_write_byte_data(client, MCP794XX_REG_WEEKDAY, wday);
|
||||
}
|
||||
|
||||
if (want_irq) {
|
||||
device_set_wakeup_capable(&client->dev, true);
|
||||
set_bit(HAS_ALARM, &ds1307->flags);
|
||||
|
@@ -504,12 +504,6 @@ static int ds1343_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
alarm->time.tm_hour = priv->alarm_hour < 0 ? 0 : priv->alarm_hour;
|
||||
alarm->time.tm_mday = priv->alarm_mday < 0 ? 0 : priv->alarm_mday;
|
||||
|
||||
alarm->time.tm_mon = -1;
|
||||
alarm->time.tm_year = -1;
|
||||
alarm->time.tm_wday = -1;
|
||||
alarm->time.tm_yday = -1;
|
||||
alarm->time.tm_isdst = -1;
|
||||
|
||||
out:
|
||||
mutex_unlock(&priv->mutex);
|
||||
return res;
|
||||
|
@@ -102,6 +102,26 @@ ds1685_rtc_bin2bcd(struct ds1685_priv *rtc, u8 val, u8 bin_mask, u8 bcd_mask)
|
||||
return (val & bin_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* s1685_rtc_check_mday - check validity of the day of month.
|
||||
* @rtc: pointer to the ds1685 rtc structure.
|
||||
* @mday: day of month.
|
||||
*
|
||||
* Returns -EDOM if the day of month is not within 1..31 range.
|
||||
*/
|
||||
static inline int
|
||||
ds1685_rtc_check_mday(struct ds1685_priv *rtc, u8 mday)
|
||||
{
|
||||
if (rtc->bcd_mode) {
|
||||
if (mday < 0x01 || mday > 0x31 || (mday & 0x0f) > 0x09)
|
||||
return -EDOM;
|
||||
} else {
|
||||
if (mday < 1 || mday > 31)
|
||||
return -EDOM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ds1685_rtc_switch_to_bank0 - switch the rtc to bank 0.
|
||||
* @rtc: pointer to the ds1685 rtc structure.
|
||||
@@ -377,6 +397,7 @@ ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
|
||||
u8 seconds, minutes, hours, mday, ctrlb, ctrlc;
|
||||
int ret;
|
||||
|
||||
/* Fetch the alarm info from the RTC alarm registers. */
|
||||
ds1685_rtc_begin_data_access(rtc);
|
||||
@@ -388,34 +409,29 @@ ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
ctrlc = rtc->read(rtc, RTC_CTRL_C);
|
||||
ds1685_rtc_end_data_access(rtc);
|
||||
|
||||
/* Check month date. */
|
||||
if (!(mday >= 1) && (mday <= 31))
|
||||
return -EDOM;
|
||||
/* Check the month date for validity. */
|
||||
ret = ds1685_rtc_check_mday(rtc, mday);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Check the three alarm bytes.
|
||||
*
|
||||
* The Linux RTC system doesn't support the "don't care" capability
|
||||
* of this RTC chip. We check for it anyways in case support is
|
||||
* added in the future.
|
||||
* added in the future and only assign when we care.
|
||||
*/
|
||||
if (unlikely(seconds >= 0xc0))
|
||||
alrm->time.tm_sec = -1;
|
||||
else
|
||||
if (likely(seconds < 0xc0))
|
||||
alrm->time.tm_sec = ds1685_rtc_bcd2bin(rtc, seconds,
|
||||
RTC_SECS_BCD_MASK,
|
||||
RTC_SECS_BIN_MASK);
|
||||
|
||||
if (unlikely(minutes >= 0xc0))
|
||||
alrm->time.tm_min = -1;
|
||||
else
|
||||
if (likely(minutes < 0xc0))
|
||||
alrm->time.tm_min = ds1685_rtc_bcd2bin(rtc, minutes,
|
||||
RTC_MINS_BCD_MASK,
|
||||
RTC_MINS_BIN_MASK);
|
||||
|
||||
if (unlikely(hours >= 0xc0))
|
||||
alrm->time.tm_hour = -1;
|
||||
else
|
||||
if (likely(hours < 0xc0))
|
||||
alrm->time.tm_hour = ds1685_rtc_bcd2bin(rtc, hours,
|
||||
RTC_HRS_24_BCD_MASK,
|
||||
RTC_HRS_24_BIN_MASK);
|
||||
@@ -423,11 +439,6 @@ ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
/* Write the data to rtc_wkalrm. */
|
||||
alrm->time.tm_mday = ds1685_rtc_bcd2bin(rtc, mday, RTC_MDAY_BCD_MASK,
|
||||
RTC_MDAY_BIN_MASK);
|
||||
alrm->time.tm_mon = -1;
|
||||
alrm->time.tm_year = -1;
|
||||
alrm->time.tm_wday = -1;
|
||||
alrm->time.tm_yday = -1;
|
||||
alrm->time.tm_isdst = -1;
|
||||
alrm->enabled = !!(ctrlb & RTC_CTRL_B_AIE);
|
||||
alrm->pending = !!(ctrlc & RTC_CTRL_C_AF);
|
||||
|
||||
@@ -445,6 +456,7 @@ ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
|
||||
u8 ctrlb, seconds, minutes, hours, mday;
|
||||
int ret;
|
||||
|
||||
/* Fetch the alarm info and convert to BCD. */
|
||||
seconds = ds1685_rtc_bin2bcd(rtc, alrm->time.tm_sec,
|
||||
@@ -461,8 +473,9 @@ ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
RTC_MDAY_BCD_MASK);
|
||||
|
||||
/* Check the month date for validity. */
|
||||
if (!(mday >= 1) && (mday <= 31))
|
||||
return -EDOM;
|
||||
ret = ds1685_rtc_check_mday(rtc, mday);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Check the three alarm bytes.
|
||||
|
@@ -13,7 +13,7 @@
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/rtc-ds2404.h>
|
||||
#include <linux/platform_data/rtc-ds2404.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/slab.h>
|
||||
|
@@ -197,12 +197,6 @@ static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
alarm->time.tm_hour = bcd2bin(buf[2] & 0x7F);
|
||||
alarm->time.tm_mday = bcd2bin(buf[3] & 0x7F);
|
||||
|
||||
alarm->time.tm_mon = -1;
|
||||
alarm->time.tm_year = -1;
|
||||
alarm->time.tm_wday = -1;
|
||||
alarm->time.tm_yday = -1;
|
||||
alarm->time.tm_isdst = -1;
|
||||
|
||||
alarm->enabled = !!(control & DS3232_REG_CR_A1IE);
|
||||
alarm->pending = !!(stat & DS3232_REG_SR_A1F);
|
||||
|
||||
|
@@ -259,6 +259,12 @@ static const struct rtc_class_ops efi_rtc_ops = {
|
||||
static int __init efi_rtc_probe(struct platform_device *dev)
|
||||
{
|
||||
struct rtc_device *rtc;
|
||||
efi_time_t eft;
|
||||
efi_time_cap_t cap;
|
||||
|
||||
/* First check if the RTC is usable */
|
||||
if (efi.get_time(&eft, &cap) != EFI_SUCCESS)
|
||||
return -ENODEV;
|
||||
|
||||
rtc = devm_rtc_device_register(&dev->dev, "rtc-efi", &efi_rtc_ops,
|
||||
THIS_MODULE);
|
||||
|
@@ -9,44 +9,10 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#if defined(CONFIG_M68K) || defined(CONFIG_PARISC) || \
|
||||
defined(CONFIG_PPC) || defined(CONFIG_SUPERH32)
|
||||
#include <asm/rtc.h>
|
||||
|
||||
static int generic_get_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
unsigned int ret = get_rtc_time(tm);
|
||||
|
||||
if (ret & RTC_BATT_BAD)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return rtc_valid_tm(tm);
|
||||
}
|
||||
|
||||
static int generic_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
if (set_rtc_time(tm) < 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops generic_rtc_ops = {
|
||||
.read_time = generic_get_time,
|
||||
.set_time = generic_set_time,
|
||||
};
|
||||
#else
|
||||
#define generic_rtc_ops *(struct rtc_class_ops*)NULL
|
||||
#endif
|
||||
|
||||
static int __init generic_rtc_probe(struct platform_device *dev)
|
||||
{
|
||||
struct rtc_device *rtc;
|
||||
const struct rtc_class_ops *ops;
|
||||
|
||||
ops = dev_get_platdata(&dev->dev);
|
||||
if (!ops)
|
||||
ops = &generic_rtc_ops;
|
||||
const struct rtc_class_ops *ops = dev_get_platdata(&dev->dev);
|
||||
|
||||
rtc = devm_rtc_device_register(&dev->dev, "rtc-generic",
|
||||
ops, THIS_MODULE);
|
||||
|
@@ -198,7 +198,7 @@ static int hym8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
return ret;
|
||||
|
||||
/* The alarm only has a minute accuracy */
|
||||
alm_tm->tm_sec = -1;
|
||||
alm_tm->tm_sec = 0;
|
||||
|
||||
alm_tm->tm_min = (buf[0] & HYM8563_ALM_BIT_DISABLE) ?
|
||||
-1 :
|
||||
@@ -213,9 +213,6 @@ static int hym8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
-1 :
|
||||
bcd2bin(buf[3] & HYM8563_WEEKDAY_MASK);
|
||||
|
||||
alm_tm->tm_mon = -1;
|
||||
alm_tm->tm_year = -1;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, HYM8563_CTL2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@@ -245,8 +245,7 @@ static int isl12057_rtc_update_alarm(struct device *dev, int enable)
|
||||
static int isl12057_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct isl12057_rtc_data *data = dev_get_drvdata(dev);
|
||||
struct rtc_time rtc_tm, *alarm_tm = &alarm->time;
|
||||
unsigned long rtc_secs, alarm_secs;
|
||||
struct rtc_time *alarm_tm = &alarm->time;
|
||||
u8 regs[ISL12057_A1_SEC_LEN];
|
||||
unsigned int ir;
|
||||
int ret;
|
||||
@@ -264,36 +263,6 @@ static int isl12057_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
alarm_tm->tm_min = bcd2bin(regs[1] & 0x7f);
|
||||
alarm_tm->tm_hour = bcd2bin(regs[2] & 0x3f);
|
||||
alarm_tm->tm_mday = bcd2bin(regs[3] & 0x3f);
|
||||
alarm_tm->tm_wday = -1;
|
||||
|
||||
/*
|
||||
* The alarm section does not store year/month. We use the ones in rtc
|
||||
* section as a basis and increment month and then year if needed to get
|
||||
* alarm after current time.
|
||||
*/
|
||||
ret = _isl12057_rtc_read_time(dev, &rtc_tm);
|
||||
if (ret)
|
||||
goto err_unlock;
|
||||
|
||||
alarm_tm->tm_year = rtc_tm.tm_year;
|
||||
alarm_tm->tm_mon = rtc_tm.tm_mon;
|
||||
|
||||
ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
|
||||
if (ret)
|
||||
goto err_unlock;
|
||||
|
||||
ret = rtc_tm_to_time(alarm_tm, &alarm_secs);
|
||||
if (ret)
|
||||
goto err_unlock;
|
||||
|
||||
if (alarm_secs < rtc_secs) {
|
||||
if (alarm_tm->tm_mon == 11) {
|
||||
alarm_tm->tm_mon = 0;
|
||||
alarm_tm->tm_year += 1;
|
||||
} else {
|
||||
alarm_tm->tm_mon += 1;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regmap_read(data->regmap, ISL12057_REG_INT, &ir);
|
||||
if (ret) {
|
||||
|
@@ -244,7 +244,7 @@ static int m41t80_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
|
||||
retval = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, flags);
|
||||
if (retval < 0) {
|
||||
dev_info(dev, "Unable to enable alarm IRQ %d\n", retval);
|
||||
dev_err(dev, "Unable to enable alarm IRQ %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
return 0;
|
||||
@@ -320,10 +320,8 @@ static int m41t80_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
alrm->time.tm_sec = bcd2bin(alarmvals[4] & 0x7f);
|
||||
alrm->time.tm_min = bcd2bin(alarmvals[3] & 0x7f);
|
||||
alrm->time.tm_hour = bcd2bin(alarmvals[2] & 0x3f);
|
||||
alrm->time.tm_wday = -1;
|
||||
alrm->time.tm_mday = bcd2bin(alarmvals[1] & 0x3f);
|
||||
alrm->time.tm_mon = bcd2bin(alarmvals[0] & 0x3f);
|
||||
alrm->time.tm_year = -1;
|
||||
|
||||
alrm->enabled = !!(alarmvals[0] & M41T80_ALMON_AFE);
|
||||
alrm->pending = (flags & M41T80_FLAGS_AF) && alrm->enabled;
|
||||
@@ -337,6 +335,30 @@ static struct rtc_class_ops m41t80_rtc_ops = {
|
||||
.proc = m41t80_rtc_proc,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int m41t80_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
if (client->irq >= 0 && device_may_wakeup(dev))
|
||||
enable_irq_wake(client->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int m41t80_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
if (client->irq >= 0 && device_may_wakeup(dev))
|
||||
disable_irq_wake(client->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(m41t80_pm, m41t80_suspend, m41t80_resume);
|
||||
|
||||
static ssize_t flags_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@@ -831,10 +853,9 @@ static int m41t80_probe(struct i2c_client *client,
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = devm_add_action(&client->dev, m41t80_remove_sysfs_group,
|
||||
&client->dev);
|
||||
rc = devm_add_action_or_reset(&client->dev, m41t80_remove_sysfs_group,
|
||||
&client->dev);
|
||||
if (rc) {
|
||||
m41t80_remove_sysfs_group(&client->dev);
|
||||
dev_err(&client->dev,
|
||||
"Failed to add sysfs cleanup action: %d\n", rc);
|
||||
return rc;
|
||||
@@ -873,6 +894,7 @@ static int m41t80_remove(struct i2c_client *client)
|
||||
static struct i2c_driver m41t80_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-m41t80",
|
||||
.pm = &m41t80_pm,
|
||||
},
|
||||
.probe = m41t80_probe,
|
||||
.remove = m41t80_remove,
|
||||
|
@@ -16,7 +16,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/m48t86.h>
|
||||
#include <linux/platform_data/rtc-m48t86.h>
|
||||
#include <linux/bcd.h>
|
||||
|
||||
#define M48T86_REG_SEC 0x00
|
||||
|
164
drivers/rtc/rtc-max6916.c
Normal file
164
drivers/rtc/rtc-max6916.c
Normal file
@@ -0,0 +1,164 @@
|
||||
/* rtc-max6916.c
|
||||
*
|
||||
* Driver for MAXIM max6916 Low Current, SPI Compatible
|
||||
* Real Time Clock
|
||||
*
|
||||
* Author : Venkat Prashanth B U <venkat.prashanth2498@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/bcd.h>
|
||||
|
||||
/* Registers in max6916 rtc */
|
||||
|
||||
#define MAX6916_SECONDS_REG 0x01
|
||||
#define MAX6916_MINUTES_REG 0x02
|
||||
#define MAX6916_HOURS_REG 0x03
|
||||
#define MAX6916_DATE_REG 0x04
|
||||
#define MAX6916_MONTH_REG 0x05
|
||||
#define MAX6916_DAY_REG 0x06
|
||||
#define MAX6916_YEAR_REG 0x07
|
||||
#define MAX6916_CONTROL_REG 0x08
|
||||
#define MAX6916_STATUS_REG 0x0C
|
||||
#define MAX6916_CLOCK_BURST 0x3F
|
||||
|
||||
static int max6916_read_reg(struct device *dev, unsigned char address,
|
||||
unsigned char *data)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
*data = address | 0x80;
|
||||
|
||||
return spi_write_then_read(spi, data, 1, data, 1);
|
||||
}
|
||||
|
||||
static int max6916_write_reg(struct device *dev, unsigned char address,
|
||||
unsigned char data)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
unsigned char buf[2];
|
||||
|
||||
buf[0] = address & 0x7F;
|
||||
buf[1] = data;
|
||||
|
||||
return spi_write_then_read(spi, buf, 2, NULL, 0);
|
||||
}
|
||||
|
||||
static int max6916_read_time(struct device *dev, struct rtc_time *dt)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
int err;
|
||||
unsigned char buf[8];
|
||||
|
||||
buf[0] = MAX6916_CLOCK_BURST | 0x80;
|
||||
|
||||
err = spi_write_then_read(spi, buf, 1, buf, 8);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dt->tm_sec = bcd2bin(buf[0]);
|
||||
dt->tm_min = bcd2bin(buf[1]);
|
||||
dt->tm_hour = bcd2bin(buf[2] & 0x3F);
|
||||
dt->tm_mday = bcd2bin(buf[3]);
|
||||
dt->tm_mon = bcd2bin(buf[4]) - 1;
|
||||
dt->tm_wday = bcd2bin(buf[5]) - 1;
|
||||
dt->tm_year = bcd2bin(buf[6]) + 100;
|
||||
|
||||
return rtc_valid_tm(dt);
|
||||
}
|
||||
|
||||
static int max6916_set_time(struct device *dev, struct rtc_time *dt)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
unsigned char buf[9];
|
||||
|
||||
if (dt->tm_year < 100 || dt->tm_year > 199) {
|
||||
dev_err(&spi->dev, "Year must be between 2000 and 2099. It's %d.\n",
|
||||
dt->tm_year + 1900);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
buf[0] = MAX6916_CLOCK_BURST & 0x7F;
|
||||
buf[1] = bin2bcd(dt->tm_sec);
|
||||
buf[2] = bin2bcd(dt->tm_min);
|
||||
buf[3] = (bin2bcd(dt->tm_hour) & 0X3F);
|
||||
buf[4] = bin2bcd(dt->tm_mday);
|
||||
buf[5] = bin2bcd(dt->tm_mon + 1);
|
||||
buf[6] = bin2bcd(dt->tm_wday + 1);
|
||||
buf[7] = bin2bcd(dt->tm_year % 100);
|
||||
buf[8] = bin2bcd(0x00);
|
||||
|
||||
/* write the rtc settings */
|
||||
return spi_write_then_read(spi, buf, 9, NULL, 0);
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops max6916_rtc_ops = {
|
||||
.read_time = max6916_read_time,
|
||||
.set_time = max6916_set_time,
|
||||
};
|
||||
|
||||
static int max6916_probe(struct spi_device *spi)
|
||||
{
|
||||
struct rtc_device *rtc;
|
||||
unsigned char data;
|
||||
int res;
|
||||
|
||||
/* spi setup with max6916 in mode 3 and bits per word as 8 */
|
||||
spi->mode = SPI_MODE_3;
|
||||
spi->bits_per_word = 8;
|
||||
spi_setup(spi);
|
||||
|
||||
/* RTC Settings */
|
||||
res = max6916_read_reg(&spi->dev, MAX6916_SECONDS_REG, &data);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
/* Disable the write protect of rtc */
|
||||
max6916_read_reg(&spi->dev, MAX6916_CONTROL_REG, &data);
|
||||
data = data & ~(1 << 7);
|
||||
max6916_write_reg(&spi->dev, MAX6916_CONTROL_REG, data);
|
||||
|
||||
/*Enable oscillator,disable oscillator stop flag, glitch filter*/
|
||||
max6916_read_reg(&spi->dev, MAX6916_STATUS_REG, &data);
|
||||
data = data & 0x1B;
|
||||
max6916_write_reg(&spi->dev, MAX6916_STATUS_REG, data);
|
||||
|
||||
/* display the settings */
|
||||
max6916_read_reg(&spi->dev, MAX6916_CONTROL_REG, &data);
|
||||
dev_info(&spi->dev, "MAX6916 RTC CTRL Reg = 0x%02x\n", data);
|
||||
|
||||
max6916_read_reg(&spi->dev, MAX6916_STATUS_REG, &data);
|
||||
dev_info(&spi->dev, "MAX6916 RTC Status Reg = 0x%02x\n", data);
|
||||
|
||||
rtc = devm_rtc_device_register(&spi->dev, "max6916",
|
||||
&max6916_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
spi_set_drvdata(spi, rtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver max6916_driver = {
|
||||
.driver = {
|
||||
.name = "max6916",
|
||||
},
|
||||
.probe = max6916_probe,
|
||||
};
|
||||
module_spi_driver(max6916_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MAX6916 SPI RTC DRIVER");
|
||||
MODULE_AUTHOR("Venkat Prashanth B U <venkat.prashanth2498@gmail.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
198
drivers/rtc/rtc-mc146818-lib.c
Normal file
198
drivers/rtc/rtc-mc146818-lib.c
Normal file
@@ -0,0 +1,198 @@
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
#include <linux/acpi.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Returns true if a clock update is in progress
|
||||
*/
|
||||
static inline unsigned char mc146818_is_updating(void)
|
||||
{
|
||||
unsigned char uip;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
uip = (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
return uip;
|
||||
}
|
||||
|
||||
unsigned int mc146818_get_time(struct rtc_time *time)
|
||||
{
|
||||
unsigned char ctrl;
|
||||
unsigned long flags;
|
||||
unsigned char century = 0;
|
||||
|
||||
#ifdef CONFIG_MACH_DECSTATION
|
||||
unsigned int real_year;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* read RTC once any update in progress is done. The update
|
||||
* can take just over 2ms. We wait 20ms. There is no need to
|
||||
* to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
|
||||
* If you need to know *exactly* when a second has started, enable
|
||||
* periodic update complete interrupts, (via ioctl) and then
|
||||
* immediately read /dev/rtc which will block until you get the IRQ.
|
||||
* Once the read clears, read the RTC time (again via ioctl). Easy.
|
||||
*/
|
||||
if (mc146818_is_updating())
|
||||
mdelay(20);
|
||||
|
||||
/*
|
||||
* Only the values that we read from the RTC are set. We leave
|
||||
* tm_wday, tm_yday and tm_isdst untouched. Even though the
|
||||
* RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
|
||||
* by the RTC when initially set to a non-zero value.
|
||||
*/
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
time->tm_sec = CMOS_READ(RTC_SECONDS);
|
||||
time->tm_min = CMOS_READ(RTC_MINUTES);
|
||||
time->tm_hour = CMOS_READ(RTC_HOURS);
|
||||
time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
|
||||
time->tm_mon = CMOS_READ(RTC_MONTH);
|
||||
time->tm_year = CMOS_READ(RTC_YEAR);
|
||||
#ifdef CONFIG_MACH_DECSTATION
|
||||
real_year = CMOS_READ(RTC_DEC_YEAR);
|
||||
#endif
|
||||
#ifdef CONFIG_ACPI
|
||||
if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
|
||||
acpi_gbl_FADT.century)
|
||||
century = CMOS_READ(acpi_gbl_FADT.century);
|
||||
#endif
|
||||
ctrl = CMOS_READ(RTC_CONTROL);
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
|
||||
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
|
||||
{
|
||||
time->tm_sec = bcd2bin(time->tm_sec);
|
||||
time->tm_min = bcd2bin(time->tm_min);
|
||||
time->tm_hour = bcd2bin(time->tm_hour);
|
||||
time->tm_mday = bcd2bin(time->tm_mday);
|
||||
time->tm_mon = bcd2bin(time->tm_mon);
|
||||
time->tm_year = bcd2bin(time->tm_year);
|
||||
century = bcd2bin(century);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MACH_DECSTATION
|
||||
time->tm_year += real_year - 72;
|
||||
#endif
|
||||
|
||||
if (century)
|
||||
time->tm_year += (century - 19) * 100;
|
||||
|
||||
/*
|
||||
* Account for differences between how the RTC uses the values
|
||||
* and how they are defined in a struct rtc_time;
|
||||
*/
|
||||
if (time->tm_year <= 69)
|
||||
time->tm_year += 100;
|
||||
|
||||
time->tm_mon--;
|
||||
|
||||
return RTC_24H;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mc146818_get_time);
|
||||
|
||||
/* Set the current date and time in the real time clock. */
|
||||
int mc146818_set_time(struct rtc_time *time)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned char mon, day, hrs, min, sec;
|
||||
unsigned char save_control, save_freq_select;
|
||||
unsigned int yrs;
|
||||
#ifdef CONFIG_MACH_DECSTATION
|
||||
unsigned int real_yrs, leap_yr;
|
||||
#endif
|
||||
unsigned char century = 0;
|
||||
|
||||
yrs = time->tm_year;
|
||||
mon = time->tm_mon + 1; /* tm_mon starts at zero */
|
||||
day = time->tm_mday;
|
||||
hrs = time->tm_hour;
|
||||
min = time->tm_min;
|
||||
sec = time->tm_sec;
|
||||
|
||||
if (yrs > 255) /* They are unsigned */
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
#ifdef CONFIG_MACH_DECSTATION
|
||||
real_yrs = yrs;
|
||||
leap_yr = ((!((yrs + 1900) % 4) && ((yrs + 1900) % 100)) ||
|
||||
!((yrs + 1900) % 400));
|
||||
yrs = 72;
|
||||
|
||||
/*
|
||||
* We want to keep the year set to 73 until March
|
||||
* for non-leap years, so that Feb, 29th is handled
|
||||
* correctly.
|
||||
*/
|
||||
if (!leap_yr && mon < 3) {
|
||||
real_yrs--;
|
||||
yrs = 73;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
|
||||
acpi_gbl_FADT.century) {
|
||||
century = (yrs + 1900) / 100;
|
||||
yrs %= 100;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* These limits and adjustments are independent of
|
||||
* whether the chip is in binary mode or not.
|
||||
*/
|
||||
if (yrs > 169) {
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (yrs >= 100)
|
||||
yrs -= 100;
|
||||
|
||||
if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
|
||||
|| RTC_ALWAYS_BCD) {
|
||||
sec = bin2bcd(sec);
|
||||
min = bin2bcd(min);
|
||||
hrs = bin2bcd(hrs);
|
||||
day = bin2bcd(day);
|
||||
mon = bin2bcd(mon);
|
||||
yrs = bin2bcd(yrs);
|
||||
century = bin2bcd(century);
|
||||
}
|
||||
|
||||
save_control = CMOS_READ(RTC_CONTROL);
|
||||
CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
|
||||
save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
|
||||
CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
|
||||
|
||||
#ifdef CONFIG_MACH_DECSTATION
|
||||
CMOS_WRITE(real_yrs, RTC_DEC_YEAR);
|
||||
#endif
|
||||
CMOS_WRITE(yrs, RTC_YEAR);
|
||||
CMOS_WRITE(mon, RTC_MONTH);
|
||||
CMOS_WRITE(day, RTC_DAY_OF_MONTH);
|
||||
CMOS_WRITE(hrs, RTC_HOURS);
|
||||
CMOS_WRITE(min, RTC_MINUTES);
|
||||
CMOS_WRITE(sec, RTC_SECONDS);
|
||||
#ifdef CONFIG_ACPI
|
||||
if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
|
||||
acpi_gbl_FADT.century)
|
||||
CMOS_WRITE(century, acpi_gbl_FADT.century);
|
||||
#endif
|
||||
|
||||
CMOS_WRITE(save_control, RTC_CONTROL);
|
||||
CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
|
||||
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mc146818_set_time);
|
@@ -32,11 +32,11 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sfi.h>
|
||||
|
||||
#include <asm-generic/rtc.h>
|
||||
#include <asm/intel_scu_ipc.h>
|
||||
#include <asm/intel-mid.h>
|
||||
#include <asm/intel_mid_vrtc.h>
|
||||
@@ -149,14 +149,6 @@ static int mrst_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
if (mrst->irq <= 0)
|
||||
return -EIO;
|
||||
|
||||
/* Basic alarms only support hour, minute, and seconds fields.
|
||||
* Some also support day and month, for alarms up to a year in
|
||||
* the future.
|
||||
*/
|
||||
t->time.tm_mday = -1;
|
||||
t->time.tm_mon = -1;
|
||||
t->time.tm_year = -1;
|
||||
|
||||
/* vRTC only supports binary mode */
|
||||
spin_lock_irq(&rtc_lock);
|
||||
t->time.tm_sec = vrtc_cmos_read(RTC_SECONDS_ALARM);
|
||||
|
@@ -96,7 +96,7 @@
|
||||
#define CD_TMR_TE BIT(3) /* Countdown timer enable */
|
||||
|
||||
/* PCF2123_REG_OFFSET BITS */
|
||||
#define OFFSET_SIGN_BIT BIT(6) /* 2's complement sign bit */
|
||||
#define OFFSET_SIGN_BIT 6 /* 2's complement sign bit */
|
||||
#define OFFSET_COARSE BIT(7) /* Coarse mode offset */
|
||||
#define OFFSET_STEP (2170) /* Offset step in parts per billion */
|
||||
|
||||
@@ -217,7 +217,7 @@ static int pcf2123_read_offset(struct device *dev, long *offset)
|
||||
if (reg & OFFSET_COARSE)
|
||||
reg <<= 1; /* multiply by 2 and sign extend */
|
||||
else
|
||||
reg |= (reg & OFFSET_SIGN_BIT) << 1; /* sign extend only */
|
||||
reg = sign_extend32(reg, OFFSET_SIGN_BIT);
|
||||
|
||||
*offset = ((long)reg) * OFFSET_STEP;
|
||||
|
||||
|
@@ -16,6 +16,16 @@
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/*
|
||||
* Information for this driver was pulled from the following datasheets.
|
||||
*
|
||||
* http://www.nxp.com/documents/data_sheet/PCF85063A.pdf
|
||||
* http://www.nxp.com/documents/data_sheet/PCF85063TP.pdf
|
||||
*
|
||||
* PCF85063A -- Rev. 6 — 18 November 2015
|
||||
* PCF85063TP -- Rev. 4 — 6 May 2015
|
||||
*/
|
||||
|
||||
#define PCF85063_REG_CTRL1 0x00 /* status */
|
||||
#define PCF85063_REG_CTRL1_STOP BIT(5)
|
||||
#define PCF85063_REG_CTRL2 0x01
|
||||
@@ -55,10 +65,22 @@ static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* In the routines that deal directly with the pcf85063 hardware, we use
|
||||
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
|
||||
*/
|
||||
static int pcf85063_start_clock(struct i2c_client *client, u8 ctrl1)
|
||||
{
|
||||
s32 ret;
|
||||
|
||||
/* start the clock */
|
||||
ctrl1 &= PCF85063_REG_CTRL1_STOP;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ctrl1);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Failing to start the clock\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
{
|
||||
int rc;
|
||||
@@ -90,8 +112,7 @@ static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
tm->tm_wday = regs[4] & 0x07;
|
||||
tm->tm_mon = bcd2bin(regs[5] & 0x1F) - 1; /* rtc mn 1-12 */
|
||||
tm->tm_year = bcd2bin(regs[6]);
|
||||
if (tm->tm_year < 70)
|
||||
tm->tm_year += 100; /* assume we are in 1970...2069 */
|
||||
tm->tm_year += 100;
|
||||
|
||||
return rtc_valid_tm(tm);
|
||||
}
|
||||
@@ -99,13 +120,17 @@ static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
{
|
||||
int rc;
|
||||
u8 regs[8];
|
||||
u8 regs[7];
|
||||
u8 ctrl1;
|
||||
|
||||
if ((tm->tm_year < 100) || (tm->tm_year > 199))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* to accurately set the time, reset the divider chain and keep it in
|
||||
* reset state until all time/date registers are written
|
||||
*/
|
||||
rc = pcf85063_stop_clock(client, ®s[7]);
|
||||
rc = pcf85063_stop_clock(client, &ctrl1);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
@@ -125,14 +150,7 @@ static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
regs[5] = bin2bcd(tm->tm_mon + 1);
|
||||
|
||||
/* year and century */
|
||||
regs[6] = bin2bcd(tm->tm_year % 100);
|
||||
|
||||
/*
|
||||
* after all time/date registers are written, let the 'address auto
|
||||
* increment' feature wrap around and write register CTRL1 to re-enable
|
||||
* the clock divider chain again
|
||||
*/
|
||||
regs[7] &= ~PCF85063_REG_CTRL1_STOP;
|
||||
regs[6] = bin2bcd(tm->tm_year - 100);
|
||||
|
||||
/* write all registers at once */
|
||||
rc = i2c_smbus_write_i2c_block_data(client, PCF85063_REG_SC,
|
||||
@@ -142,6 +160,15 @@ static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the control register as a separate action since the size of
|
||||
* the register space is different between the PCF85063TP and
|
||||
* PCF85063A devices. The rollover point can not be used.
|
||||
*/
|
||||
rc = pcf85063_start_clock(client, ctrl1);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@@ -341,14 +341,11 @@ static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
|
||||
"%s: raw data is min=%02x, hr=%02x, mday=%02x, wday=%02x\n",
|
||||
__func__, buf[0], buf[1], buf[2], buf[3]);
|
||||
|
||||
tm->time.tm_sec = 0;
|
||||
tm->time.tm_min = bcd2bin(buf[0] & 0x7F);
|
||||
tm->time.tm_hour = bcd2bin(buf[1] & 0x3F);
|
||||
tm->time.tm_mday = bcd2bin(buf[2] & 0x3F);
|
||||
tm->time.tm_wday = bcd2bin(buf[3] & 0x7);
|
||||
tm->time.tm_mon = -1;
|
||||
tm->time.tm_year = -1;
|
||||
tm->time.tm_yday = -1;
|
||||
tm->time.tm_isdst = -1;
|
||||
|
||||
err = pcf8563_get_alarm_mode(client, &tm->enabled, &tm->pending);
|
||||
if (err < 0)
|
||||
|
@@ -128,6 +128,7 @@ static int rc5t583_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
return ret;
|
||||
}
|
||||
|
||||
alm->time.tm_sec = 0;
|
||||
alm->time.tm_min = bcd2bin(alarm_data[0]);
|
||||
alm->time.tm_hour = bcd2bin(alarm_data[1]);
|
||||
alm->time.tm_mday = bcd2bin(alarm_data[2]);
|
||||
|
@@ -341,12 +341,6 @@ static int rs5c_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
t->time.tm_sec = 0;
|
||||
t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f);
|
||||
t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]);
|
||||
t->time.tm_mday = -1;
|
||||
t->time.tm_mon = -1;
|
||||
t->time.tm_year = -1;
|
||||
t->time.tm_wday = -1;
|
||||
t->time.tm_yday = -1;
|
||||
t->time.tm_isdst = -1;
|
||||
|
||||
/* ... and status */
|
||||
t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE);
|
||||
|
@@ -13,12 +13,15 @@
|
||||
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#define RV8803_I2C_TRY_COUNT 4
|
||||
|
||||
#define RV8803_SEC 0x00
|
||||
#define RV8803_MIN 0x01
|
||||
#define RV8803_HOUR 0x02
|
||||
@@ -56,19 +59,85 @@ struct rv8803_data {
|
||||
u8 ctrl;
|
||||
};
|
||||
|
||||
static int rv8803_read_reg(const struct i2c_client *client, u8 reg)
|
||||
{
|
||||
int try = RV8803_I2C_TRY_COUNT;
|
||||
s32 ret;
|
||||
|
||||
/*
|
||||
* There is a 61µs window during which the RTC does not acknowledge I2C
|
||||
* transfers. In that case, ensure that there are multiple attempts.
|
||||
*/
|
||||
do
|
||||
ret = i2c_smbus_read_byte_data(client, reg);
|
||||
while ((ret == -ENXIO || ret == -EIO) && --try);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "Unable to read register 0x%02x\n", reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rv8803_read_regs(const struct i2c_client *client,
|
||||
u8 reg, u8 count, u8 *values)
|
||||
{
|
||||
int try = RV8803_I2C_TRY_COUNT;
|
||||
s32 ret;
|
||||
|
||||
do
|
||||
ret = i2c_smbus_read_i2c_block_data(client, reg, count, values);
|
||||
while ((ret == -ENXIO || ret == -EIO) && --try);
|
||||
if (ret != count) {
|
||||
dev_err(&client->dev,
|
||||
"Unable to read registers 0x%02x..0x%02x\n",
|
||||
reg, reg + count - 1);
|
||||
return ret < 0 ? ret : -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rv8803_write_reg(const struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
int try = RV8803_I2C_TRY_COUNT;
|
||||
s32 ret;
|
||||
|
||||
do
|
||||
ret = i2c_smbus_write_byte_data(client, reg, value);
|
||||
while ((ret == -ENXIO || ret == -EIO) && --try);
|
||||
if (ret)
|
||||
dev_err(&client->dev, "Unable to write register 0x%02x\n", reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rv8803_write_regs(const struct i2c_client *client,
|
||||
u8 reg, u8 count, const u8 *values)
|
||||
{
|
||||
int try = RV8803_I2C_TRY_COUNT;
|
||||
s32 ret;
|
||||
|
||||
do
|
||||
ret = i2c_smbus_write_i2c_block_data(client, reg, count,
|
||||
values);
|
||||
while ((ret == -ENXIO || ret == -EIO) && --try);
|
||||
if (ret)
|
||||
dev_err(&client->dev,
|
||||
"Unable to write registers 0x%02x..0x%02x\n",
|
||||
reg, reg + count - 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct i2c_client *client = dev_id;
|
||||
struct rv8803_data *rv8803 = i2c_get_clientdata(client);
|
||||
unsigned long events = 0;
|
||||
int flags, try = 0;
|
||||
int flags;
|
||||
|
||||
mutex_lock(&rv8803->flags_lock);
|
||||
|
||||
do {
|
||||
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
|
||||
try++;
|
||||
} while ((flags == -ENXIO) && (try < 3));
|
||||
flags = rv8803_read_reg(client, RV8803_FLAG);
|
||||
if (flags <= 0) {
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
return IRQ_NONE;
|
||||
@@ -100,9 +169,8 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
|
||||
|
||||
if (events) {
|
||||
rtc_update_irq(rv8803->rtc, 1, events);
|
||||
i2c_smbus_write_byte_data(client, RV8803_FLAG, flags);
|
||||
i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL,
|
||||
rv8803->ctrl);
|
||||
rv8803_write_reg(client, RV8803_FLAG, flags);
|
||||
rv8803_write_reg(rv8803->client, RV8803_CTRL, rv8803->ctrl);
|
||||
}
|
||||
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
@@ -118,7 +186,7 @@ static int rv8803_get_time(struct device *dev, struct rtc_time *tm)
|
||||
u8 *date = date1;
|
||||
int ret, flags;
|
||||
|
||||
flags = i2c_smbus_read_byte_data(rv8803->client, RV8803_FLAG);
|
||||
flags = rv8803_read_reg(rv8803->client, RV8803_FLAG);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
|
||||
@@ -127,16 +195,14 @@ static int rv8803_get_time(struct device *dev, struct rtc_time *tm)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(rv8803->client, RV8803_SEC,
|
||||
7, date);
|
||||
if (ret != 7)
|
||||
return ret < 0 ? ret : -EIO;
|
||||
ret = rv8803_read_regs(rv8803->client, RV8803_SEC, 7, date);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if ((date1[RV8803_SEC] & 0x7f) == bin2bcd(59)) {
|
||||
ret = i2c_smbus_read_i2c_block_data(rv8803->client, RV8803_SEC,
|
||||
7, date2);
|
||||
if (ret != 7)
|
||||
return ret < 0 ? ret : -EIO;
|
||||
ret = rv8803_read_regs(rv8803->client, RV8803_SEC, 7, date2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if ((date2[RV8803_SEC] & 0x7f) != bin2bcd(59))
|
||||
date = date2;
|
||||
@@ -145,23 +211,33 @@ static int rv8803_get_time(struct device *dev, struct rtc_time *tm)
|
||||
tm->tm_sec = bcd2bin(date[RV8803_SEC] & 0x7f);
|
||||
tm->tm_min = bcd2bin(date[RV8803_MIN] & 0x7f);
|
||||
tm->tm_hour = bcd2bin(date[RV8803_HOUR] & 0x3f);
|
||||
tm->tm_wday = ffs(date[RV8803_WEEK] & 0x7f);
|
||||
tm->tm_wday = ilog2(date[RV8803_WEEK] & 0x7f);
|
||||
tm->tm_mday = bcd2bin(date[RV8803_DAY] & 0x3f);
|
||||
tm->tm_mon = bcd2bin(date[RV8803_MONTH] & 0x1f) - 1;
|
||||
tm->tm_year = bcd2bin(date[RV8803_YEAR]) + 100;
|
||||
|
||||
return rtc_valid_tm(tm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct rv8803_data *rv8803 = dev_get_drvdata(dev);
|
||||
u8 date[7];
|
||||
int flags, ret;
|
||||
int ctrl, flags, ret;
|
||||
|
||||
if ((tm->tm_year < 100) || (tm->tm_year > 199))
|
||||
return -EINVAL;
|
||||
|
||||
ctrl = rv8803_read_reg(rv8803->client, RV8803_CTRL);
|
||||
if (ctrl < 0)
|
||||
return ctrl;
|
||||
|
||||
/* Stop the clock */
|
||||
ret = rv8803_write_reg(rv8803->client, RV8803_CTRL,
|
||||
ctrl | RV8803_CTRL_RESET);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
date[RV8803_SEC] = bin2bcd(tm->tm_sec);
|
||||
date[RV8803_MIN] = bin2bcd(tm->tm_min);
|
||||
date[RV8803_HOUR] = bin2bcd(tm->tm_hour);
|
||||
@@ -170,21 +246,26 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
|
||||
date[RV8803_MONTH] = bin2bcd(tm->tm_mon + 1);
|
||||
date[RV8803_YEAR] = bin2bcd(tm->tm_year - 100);
|
||||
|
||||
ret = i2c_smbus_write_i2c_block_data(rv8803->client, RV8803_SEC,
|
||||
7, date);
|
||||
if (ret < 0)
|
||||
ret = rv8803_write_regs(rv8803->client, RV8803_SEC, 7, date);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Restart the clock */
|
||||
ret = rv8803_write_reg(rv8803->client, RV8803_CTRL,
|
||||
ctrl & ~RV8803_CTRL_RESET);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&rv8803->flags_lock);
|
||||
|
||||
flags = i2c_smbus_read_byte_data(rv8803->client, RV8803_FLAG);
|
||||
flags = rv8803_read_reg(rv8803->client, RV8803_FLAG);
|
||||
if (flags < 0) {
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
return flags;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG,
|
||||
flags & ~RV8803_FLAG_V2F);
|
||||
ret = rv8803_write_reg(rv8803->client, RV8803_FLAG,
|
||||
flags & ~(RV8803_FLAG_V1F | RV8803_FLAG_V2F));
|
||||
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
|
||||
@@ -198,22 +279,18 @@ static int rv8803_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
u8 alarmvals[3];
|
||||
int flags, ret;
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(client, RV8803_ALARM_MIN,
|
||||
3, alarmvals);
|
||||
if (ret != 3)
|
||||
return ret < 0 ? ret : -EIO;
|
||||
ret = rv8803_read_regs(client, RV8803_ALARM_MIN, 3, alarmvals);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
|
||||
flags = rv8803_read_reg(client, RV8803_FLAG);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
|
||||
alrm->time.tm_sec = 0;
|
||||
alrm->time.tm_min = bcd2bin(alarmvals[0] & 0x7f);
|
||||
alrm->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f);
|
||||
alrm->time.tm_wday = -1;
|
||||
alrm->time.tm_mday = bcd2bin(alarmvals[2] & 0x3f);
|
||||
alrm->time.tm_mon = -1;
|
||||
alrm->time.tm_year = -1;
|
||||
|
||||
alrm->enabled = !!(rv8803->ctrl & RV8803_CTRL_AIE);
|
||||
alrm->pending = (flags & RV8803_FLAG_AF) && alrm->enabled;
|
||||
@@ -239,10 +316,10 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
mutex_lock(&rv8803->flags_lock);
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(client, RV8803_FLAG, 2, ctrl);
|
||||
if (ret != 2) {
|
||||
ret = rv8803_read_regs(client, RV8803_FLAG, 2, ctrl);
|
||||
if (ret) {
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
return ret < 0 ? ret : -EIO;
|
||||
return ret;
|
||||
}
|
||||
|
||||
alarmvals[0] = bin2bcd(alrm->time.tm_min);
|
||||
@@ -251,8 +328,8 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
if (rv8803->ctrl & (RV8803_CTRL_AIE | RV8803_CTRL_UIE)) {
|
||||
rv8803->ctrl &= ~(RV8803_CTRL_AIE | RV8803_CTRL_UIE);
|
||||
err = i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL,
|
||||
rv8803->ctrl);
|
||||
err = rv8803_write_reg(rv8803->client, RV8803_CTRL,
|
||||
rv8803->ctrl);
|
||||
if (err) {
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
return err;
|
||||
@@ -260,13 +337,12 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
}
|
||||
|
||||
ctrl[1] &= ~RV8803_FLAG_AF;
|
||||
err = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG, ctrl[1]);
|
||||
err = rv8803_write_reg(rv8803->client, RV8803_FLAG, ctrl[1]);
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = i2c_smbus_write_i2c_block_data(rv8803->client, RV8803_ALARM_MIN,
|
||||
3, alarmvals);
|
||||
err = rv8803_write_regs(rv8803->client, RV8803_ALARM_MIN, 3, alarmvals);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -276,8 +352,8 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
if (rv8803->rtc->aie_timer.enabled)
|
||||
rv8803->ctrl |= RV8803_CTRL_AIE;
|
||||
|
||||
err = i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL,
|
||||
rv8803->ctrl);
|
||||
err = rv8803_write_reg(rv8803->client, RV8803_CTRL,
|
||||
rv8803->ctrl);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@@ -306,21 +382,20 @@ static int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
}
|
||||
|
||||
mutex_lock(&rv8803->flags_lock);
|
||||
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
|
||||
flags = rv8803_read_reg(client, RV8803_FLAG);
|
||||
if (flags < 0) {
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
return flags;
|
||||
}
|
||||
flags &= ~(RV8803_FLAG_AF | RV8803_FLAG_UF);
|
||||
err = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags);
|
||||
err = rv8803_write_reg(client, RV8803_FLAG, flags);
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (ctrl != rv8803->ctrl) {
|
||||
rv8803->ctrl = ctrl;
|
||||
err = i2c_smbus_write_byte_data(client, RV8803_CTRL,
|
||||
rv8803->ctrl);
|
||||
err = rv8803_write_reg(client, RV8803_CTRL, rv8803->ctrl);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@@ -336,7 +411,7 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
|
||||
|
||||
switch (cmd) {
|
||||
case RTC_VL_READ:
|
||||
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
|
||||
flags = rv8803_read_reg(client, RV8803_FLAG);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
|
||||
@@ -355,16 +430,16 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
|
||||
|
||||
case RTC_VL_CLR:
|
||||
mutex_lock(&rv8803->flags_lock);
|
||||
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
|
||||
flags = rv8803_read_reg(client, RV8803_FLAG);
|
||||
if (flags < 0) {
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
return flags;
|
||||
}
|
||||
|
||||
flags &= ~(RV8803_FLAG_V1F | RV8803_FLAG_V2F);
|
||||
ret = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags);
|
||||
ret = rv8803_write_reg(client, RV8803_FLAG, flags);
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
@@ -382,8 +457,8 @@ static ssize_t rv8803_nvram_write(struct file *filp, struct kobject *kobj,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, RV8803_RAM, buf[0]);
|
||||
if (ret < 0)
|
||||
ret = rv8803_write_reg(client, RV8803_RAM, buf[0]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 1;
|
||||
@@ -397,7 +472,7 @@ static ssize_t rv8803_nvram_read(struct file *filp, struct kobject *kobj,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, RV8803_RAM);
|
||||
ret = rv8803_read_reg(client, RV8803_RAM);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@@ -427,7 +502,7 @@ static int rv8803_probe(struct i2c_client *client,
|
||||
{
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
struct rv8803_data *rv8803;
|
||||
int err, flags, try = 0;
|
||||
int err, flags;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK)) {
|
||||
@@ -444,16 +519,7 @@ static int rv8803_probe(struct i2c_client *client,
|
||||
rv8803->client = client;
|
||||
i2c_set_clientdata(client, rv8803);
|
||||
|
||||
/*
|
||||
* There is a 60µs window where the RTC may not reply on the i2c bus in
|
||||
* that case, the transfer is not ACKed. In that case, ensure there are
|
||||
* multiple attempts.
|
||||
*/
|
||||
do {
|
||||
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
|
||||
try++;
|
||||
} while ((flags == -ENXIO) && (try < 3));
|
||||
|
||||
flags = rv8803_read_reg(client, RV8803_FLAG);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
|
||||
@@ -488,12 +554,7 @@ static int rv8803_probe(struct i2c_client *client,
|
||||
return PTR_ERR(rv8803->rtc);
|
||||
}
|
||||
|
||||
try = 0;
|
||||
do {
|
||||
err = i2c_smbus_write_byte_data(rv8803->client, RV8803_EXT,
|
||||
RV8803_EXT_WADA);
|
||||
try++;
|
||||
} while ((err == -ENXIO) && (try < 3));
|
||||
err = rv8803_write_reg(rv8803->client, RV8803_EXT, RV8803_EXT_WADA);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@@ -272,15 +272,9 @@ static int rx8010_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
t->time.tm_min = bcd2bin(alarmvals[0] & 0x7f);
|
||||
t->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f);
|
||||
|
||||
if (alarmvals[2] & RX8010_ALARM_AE)
|
||||
t->time.tm_mday = -1;
|
||||
else
|
||||
if (!(alarmvals[2] & RX8010_ALARM_AE))
|
||||
t->time.tm_mday = bcd2bin(alarmvals[2] & 0x7f);
|
||||
|
||||
t->time.tm_wday = -1;
|
||||
t->time.tm_mon = -1;
|
||||
t->time.tm_year = -1;
|
||||
|
||||
t->enabled = !!(rx8010->ctrlreg & RX8010_CTRL_AIE);
|
||||
t->pending = (flagreg & RX8010_FLAG_AF) && t->enabled;
|
||||
|
||||
|
@@ -319,11 +319,6 @@ static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
t->time.tm_hour = bcd2bin(ald[1] & 0x1f) % 12
|
||||
+ (ald[1] & 0x20 ? 12 : 0);
|
||||
|
||||
t->time.tm_wday = -1;
|
||||
t->time.tm_mday = -1;
|
||||
t->time.tm_mon = -1;
|
||||
t->time.tm_year = -1;
|
||||
|
||||
dev_dbg(dev, "%s: date: %ds %dm %dh %dmd %dm %dy\n",
|
||||
__func__,
|
||||
t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#include <linux/bitrev.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define S35390A_CMD_STATUS1 0
|
||||
#define S35390A_CMD_STATUS2 1
|
||||
@@ -34,10 +35,14 @@
|
||||
#define S35390A_ALRM_BYTE_HOURS 1
|
||||
#define S35390A_ALRM_BYTE_MINS 2
|
||||
|
||||
/* flags for STATUS1 */
|
||||
#define S35390A_FLAG_POC 0x01
|
||||
#define S35390A_FLAG_BLD 0x02
|
||||
#define S35390A_FLAG_INT2 0x04
|
||||
#define S35390A_FLAG_24H 0x40
|
||||
#define S35390A_FLAG_RESET 0x80
|
||||
|
||||
/* flag for STATUS2 */
|
||||
#define S35390A_FLAG_TEST 0x01
|
||||
|
||||
#define S35390A_INT2_MODE_MASK 0xF0
|
||||
@@ -94,19 +99,63 @@ static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s35390a_reset(struct s35390a *s35390a)
|
||||
/*
|
||||
* Returns <0 on error, 0 if rtc is setup fine and 1 if the chip was reset.
|
||||
* To keep the information if an irq is pending, pass the value read from
|
||||
* STATUS1 to the caller.
|
||||
*/
|
||||
static int s35390a_reset(struct s35390a *s35390a, char *status1)
|
||||
{
|
||||
char buf[1];
|
||||
char buf;
|
||||
int ret;
|
||||
unsigned initcount = 0;
|
||||
|
||||
if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf)) < 0)
|
||||
return -EIO;
|
||||
ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, status1, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!(buf[0] & (S35390A_FLAG_POC | S35390A_FLAG_BLD)))
|
||||
if (*status1 & S35390A_FLAG_POC)
|
||||
/*
|
||||
* Do not communicate for 0.5 seconds since the power-on
|
||||
* detection circuit is in operation.
|
||||
*/
|
||||
msleep(500);
|
||||
else if (!(*status1 & S35390A_FLAG_BLD))
|
||||
/*
|
||||
* If both POC and BLD are unset everything is fine.
|
||||
*/
|
||||
return 0;
|
||||
|
||||
buf[0] |= (S35390A_FLAG_RESET | S35390A_FLAG_24H);
|
||||
buf[0] &= 0xf0;
|
||||
return s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf));
|
||||
/*
|
||||
* At least one of POC and BLD are set, so reinitialise chip. Keeping
|
||||
* this information in the hardware to know later that the time isn't
|
||||
* valid is unfortunately not possible because POC and BLD are cleared
|
||||
* on read. So the reset is best done now.
|
||||
*
|
||||
* The 24H bit is kept over reset, so set it already here.
|
||||
*/
|
||||
initialize:
|
||||
*status1 = S35390A_FLAG_24H;
|
||||
buf = S35390A_FLAG_RESET | S35390A_FLAG_24H;
|
||||
ret = s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (buf & (S35390A_FLAG_POC | S35390A_FLAG_BLD)) {
|
||||
/* Try up to five times to reset the chip */
|
||||
if (initcount < 5) {
|
||||
++initcount;
|
||||
goto initialize;
|
||||
} else
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int s35390a_disable_test_mode(struct s35390a *s35390a)
|
||||
@@ -217,12 +266,12 @@ static int s35390a_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alm)
|
||||
alm->time.tm_min, alm->time.tm_hour, alm->time.tm_mday,
|
||||
alm->time.tm_mon, alm->time.tm_year, alm->time.tm_wday);
|
||||
|
||||
/* disable interrupt */
|
||||
/* disable interrupt (which deasserts the irq line) */
|
||||
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* clear pending interrupt, if any */
|
||||
/* clear pending interrupt (in STATUS1 only), if any */
|
||||
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &sts, sizeof(sts));
|
||||
if (err < 0)
|
||||
return err;
|
||||
@@ -242,6 +291,8 @@ static int s35390a_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alm)
|
||||
|
||||
if (alm->time.tm_wday != -1)
|
||||
buf[S35390A_ALRM_BYTE_WDAY] = bin2bcd(alm->time.tm_wday) | 0x80;
|
||||
else
|
||||
buf[S35390A_ALRM_BYTE_WDAY] = 0;
|
||||
|
||||
buf[S35390A_ALRM_BYTE_HOURS] = s35390a_hr2reg(s35390a,
|
||||
alm->time.tm_hour) | 0x80;
|
||||
@@ -269,23 +320,43 @@ static int s35390a_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alm)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (bitrev8(sts) != S35390A_INT2_MODE_ALARM)
|
||||
return -EINVAL;
|
||||
if ((bitrev8(sts) & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) {
|
||||
/*
|
||||
* When the alarm isn't enabled, the register to configure
|
||||
* the alarm time isn't accessible.
|
||||
*/
|
||||
alm->enabled = 0;
|
||||
return 0;
|
||||
} else {
|
||||
alm->enabled = 1;
|
||||
}
|
||||
|
||||
err = s35390a_get_reg(s35390a, S35390A_CMD_INT2_REG1, buf, sizeof(buf));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* This chip returns the bits of each byte in reverse order */
|
||||
for (i = 0; i < 3; ++i) {
|
||||
for (i = 0; i < 3; ++i)
|
||||
buf[i] = bitrev8(buf[i]);
|
||||
buf[i] &= ~0x80;
|
||||
}
|
||||
|
||||
alm->time.tm_wday = bcd2bin(buf[S35390A_ALRM_BYTE_WDAY]);
|
||||
alm->time.tm_hour = s35390a_reg2hr(s35390a,
|
||||
buf[S35390A_ALRM_BYTE_HOURS]);
|
||||
alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS]);
|
||||
/*
|
||||
* B0 of the three matching registers is an enable flag. Iff it is set
|
||||
* the configured value is used for matching.
|
||||
*/
|
||||
if (buf[S35390A_ALRM_BYTE_WDAY] & 0x80)
|
||||
alm->time.tm_wday =
|
||||
bcd2bin(buf[S35390A_ALRM_BYTE_WDAY] & ~0x80);
|
||||
|
||||
if (buf[S35390A_ALRM_BYTE_HOURS] & 0x80)
|
||||
alm->time.tm_hour =
|
||||
s35390a_reg2hr(s35390a,
|
||||
buf[S35390A_ALRM_BYTE_HOURS] & ~0x80);
|
||||
|
||||
if (buf[S35390A_ALRM_BYTE_MINS] & 0x80)
|
||||
alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS] & ~0x80);
|
||||
|
||||
/* alarm triggers always at s=0 */
|
||||
alm->time.tm_sec = 0;
|
||||
|
||||
dev_dbg(&client->dev, "%s: alm is mins=%d, hours=%d, wday=%d\n",
|
||||
__func__, alm->time.tm_min, alm->time.tm_hour,
|
||||
@@ -327,11 +398,11 @@ static struct i2c_driver s35390a_driver;
|
||||
static int s35390a_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int err;
|
||||
int err, err_reset;
|
||||
unsigned int i;
|
||||
struct s35390a *s35390a;
|
||||
struct rtc_time tm;
|
||||
char buf[1];
|
||||
char buf, status1;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
err = -ENODEV;
|
||||
@@ -360,29 +431,35 @@ static int s35390a_probe(struct i2c_client *client,
|
||||
}
|
||||
}
|
||||
|
||||
err = s35390a_reset(s35390a);
|
||||
if (err < 0) {
|
||||
err_reset = s35390a_reset(s35390a, &status1);
|
||||
if (err_reset < 0) {
|
||||
err = err_reset;
|
||||
dev_err(&client->dev, "error resetting chip\n");
|
||||
goto exit_dummy;
|
||||
}
|
||||
|
||||
err = s35390a_disable_test_mode(s35390a);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "error disabling test mode\n");
|
||||
goto exit_dummy;
|
||||
}
|
||||
|
||||
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf));
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "error checking 12/24 hour mode\n");
|
||||
goto exit_dummy;
|
||||
}
|
||||
if (buf[0] & S35390A_FLAG_24H)
|
||||
if (status1 & S35390A_FLAG_24H)
|
||||
s35390a->twentyfourhour = 1;
|
||||
else
|
||||
s35390a->twentyfourhour = 0;
|
||||
|
||||
if (s35390a_get_datetime(client, &tm) < 0)
|
||||
if (status1 & S35390A_FLAG_INT2) {
|
||||
/* disable alarm (and maybe test mode) */
|
||||
buf = 0;
|
||||
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &buf, 1);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "error disabling alarm");
|
||||
goto exit_dummy;
|
||||
}
|
||||
} else {
|
||||
err = s35390a_disable_test_mode(s35390a);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "error disabling test mode\n");
|
||||
goto exit_dummy;
|
||||
}
|
||||
}
|
||||
|
||||
if (err_reset > 0 || s35390a_get_datetime(client, &tm) < 0)
|
||||
dev_warn(&client->dev, "clock needs to be set\n");
|
||||
|
||||
device_set_wakeup_capable(&client->dev, 1);
|
||||
@@ -395,6 +472,10 @@ static int s35390a_probe(struct i2c_client *client,
|
||||
err = PTR_ERR(s35390a->rtc);
|
||||
goto exit_dummy;
|
||||
}
|
||||
|
||||
if (status1 & S35390A_FLAG_INT2)
|
||||
rtc_update_irq(s35390a->rtc, 1, RTC_AF);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_dummy:
|
||||
|
@@ -149,12 +149,14 @@ static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq)
|
||||
if (!is_power_of_2(freq))
|
||||
return -EINVAL;
|
||||
|
||||
s3c_rtc_enable_clk(info);
|
||||
spin_lock_irq(&info->pie_lock);
|
||||
|
||||
if (info->data->set_freq)
|
||||
info->data->set_freq(info, freq);
|
||||
|
||||
spin_unlock_irq(&info->pie_lock);
|
||||
s3c_rtc_disable_clk(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -264,35 +266,23 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
/* decode the alarm enable field */
|
||||
if (alm_en & S3C2410_RTCALM_SECEN)
|
||||
alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
|
||||
else
|
||||
alm_tm->tm_sec = -1;
|
||||
|
||||
if (alm_en & S3C2410_RTCALM_MINEN)
|
||||
alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
|
||||
else
|
||||
alm_tm->tm_min = -1;
|
||||
|
||||
if (alm_en & S3C2410_RTCALM_HOUREN)
|
||||
alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
|
||||
else
|
||||
alm_tm->tm_hour = -1;
|
||||
|
||||
if (alm_en & S3C2410_RTCALM_DAYEN)
|
||||
alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
|
||||
else
|
||||
alm_tm->tm_mday = -1;
|
||||
|
||||
if (alm_en & S3C2410_RTCALM_MONEN) {
|
||||
alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
|
||||
alm_tm->tm_mon -= 1;
|
||||
} else {
|
||||
alm_tm->tm_mon = -1;
|
||||
}
|
||||
|
||||
if (alm_en & S3C2410_RTCALM_YEAREN)
|
||||
alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
|
||||
else
|
||||
alm_tm->tm_year = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -577,8 +567,6 @@ static int s3c_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
s3c_rtc_setfreq(info, 1);
|
||||
|
||||
s3c_rtc_disable_clk(info);
|
||||
|
||||
return 0;
|
||||
|
||||
err_nortc:
|
||||
|
@@ -481,7 +481,6 @@ static int sh_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
||||
tm->tm_mon = sh_rtc_read_alarm_value(rtc, RMONAR);
|
||||
if (tm->tm_mon > 0)
|
||||
tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */
|
||||
tm->tm_year = 0xffff;
|
||||
|
||||
wkalrm->enabled = (readb(rtc->regbase + RCR1) & RCR1_AIE) ? 1 : 0;
|
||||
|
||||
@@ -500,52 +499,13 @@ static inline void sh_rtc_write_alarm_value(struct sh_rtc *rtc,
|
||||
writeb(bin2bcd(value) | AR_ENB, rtc->regbase + reg_off);
|
||||
}
|
||||
|
||||
static int sh_rtc_check_alarm(struct rtc_time *tm)
|
||||
{
|
||||
/*
|
||||
* The original rtc says anything > 0xc0 is "don't care" or "match
|
||||
* all" - most users use 0xff but rtc-dev uses -1 for the same thing.
|
||||
* The original rtc doesn't support years - some things use -1 and
|
||||
* some 0xffff. We use -1 to make out tests easier.
|
||||
*/
|
||||
if (tm->tm_year == 0xffff)
|
||||
tm->tm_year = -1;
|
||||
if (tm->tm_mon >= 0xff)
|
||||
tm->tm_mon = -1;
|
||||
if (tm->tm_mday >= 0xff)
|
||||
tm->tm_mday = -1;
|
||||
if (tm->tm_wday >= 0xff)
|
||||
tm->tm_wday = -1;
|
||||
if (tm->tm_hour >= 0xff)
|
||||
tm->tm_hour = -1;
|
||||
if (tm->tm_min >= 0xff)
|
||||
tm->tm_min = -1;
|
||||
if (tm->tm_sec >= 0xff)
|
||||
tm->tm_sec = -1;
|
||||
|
||||
if (tm->tm_year > 9999 ||
|
||||
tm->tm_mon >= 12 ||
|
||||
tm->tm_mday == 0 || tm->tm_mday >= 32 ||
|
||||
tm->tm_wday >= 7 ||
|
||||
tm->tm_hour >= 24 ||
|
||||
tm->tm_min >= 60 ||
|
||||
tm->tm_sec >= 60)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct sh_rtc *rtc = platform_get_drvdata(pdev);
|
||||
unsigned int rcr1;
|
||||
struct rtc_time *tm = &wkalrm->time;
|
||||
int mon, err;
|
||||
|
||||
err = sh_rtc_check_alarm(tm);
|
||||
if (unlikely(err < 0))
|
||||
return err;
|
||||
int mon;
|
||||
|
||||
spin_lock_irq(&rtc->lock);
|
||||
|
||||
|
@@ -179,12 +179,6 @@ static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
if (sec == 0) {
|
||||
/* alarm is disabled. */
|
||||
alarm->enabled = 0;
|
||||
alarm->time.tm_mon = -1;
|
||||
alarm->time.tm_mday = -1;
|
||||
alarm->time.tm_year = -1;
|
||||
alarm->time.tm_hour = -1;
|
||||
alarm->time.tm_min = -1;
|
||||
alarm->time.tm_sec = -1;
|
||||
} else {
|
||||
/* alarm is enabled. */
|
||||
alarm->enabled = 1;
|
||||
|
@@ -25,7 +25,7 @@
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/rtc-v3020.h>
|
||||
#include <linux/platform_data/rtc-v3020.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/slab.h>
|
||||
|
Reference in New Issue
Block a user