Merge commit 'v2.6.26' into bkl-removal
This commit is contained in:
@@ -256,6 +256,17 @@ config RTC_DRV_S35390A
|
||||
This driver can also be built as a module. If so the module
|
||||
will be called rtc-s35390a.
|
||||
|
||||
config RTC_DRV_FM3130
|
||||
tristate "Ramtron FM3130"
|
||||
help
|
||||
If you say Y here you will get support for the
|
||||
Ramtron FM3130 RTC chips.
|
||||
Ramtron FM3130 is a chip with two separate devices inside,
|
||||
RTC clock and FRAM. This driver provides only RTC functionality.
|
||||
|
||||
This driver can also be built as a module. If so the module
|
||||
will be called rtc-fm3130.
|
||||
|
||||
endif # I2C
|
||||
|
||||
comment "SPI RTC drivers"
|
||||
@@ -534,4 +545,12 @@ config RTC_DRV_RS5C313
|
||||
help
|
||||
If you say yes here you get support for the Ricoh RS5C313 RTC chips.
|
||||
|
||||
config RTC_DRV_PPC
|
||||
tristate "PowerPC machine dependent RTC support"
|
||||
depends on PPC_MERGE
|
||||
help
|
||||
The PowerPC kernel has machine-specific functions for accessing
|
||||
the RTC. This exposes that functionality through the generic RTC
|
||||
class.
|
||||
|
||||
endif # RTC_CLASS
|
||||
|
@@ -31,6 +31,7 @@ obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
|
||||
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
|
||||
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
|
||||
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
|
||||
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
|
||||
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
|
||||
obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
|
||||
obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
|
||||
@@ -41,6 +42,7 @@ obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
|
||||
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
|
||||
obj-$(CONFIG_RTC_DRV_PL031) += rtc-pl031.o
|
||||
obj-$(CONFIG_RTC_DRV_PPC) += rtc-ppc.o
|
||||
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
|
||||
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
|
||||
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
|
||||
|
@@ -126,12 +126,25 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
int err;
|
||||
struct rtc_time before, now;
|
||||
int first_time = 1;
|
||||
unsigned long t_now, t_alm;
|
||||
enum { none, day, month, year } missing = none;
|
||||
unsigned days;
|
||||
|
||||
/* The lower level RTC driver may not be capable of filling
|
||||
* in all fields of the rtc_time struct (eg. rtc-cmos),
|
||||
* and so might instead return -1 in some fields.
|
||||
* We deal with that here by grabbing a current RTC timestamp
|
||||
* and using values from that for any missing (-1) values.
|
||||
/* The lower level RTC driver may return -1 in some fields,
|
||||
* creating invalid alarm->time values, for reasons like:
|
||||
*
|
||||
* - The hardware may not be capable of filling them in;
|
||||
* many alarms match only on time-of-day fields, not
|
||||
* day/month/year calendar data.
|
||||
*
|
||||
* - Some hardware uses illegal values as "wildcard" match
|
||||
* values, which non-Linux firmware (like a BIOS) may try
|
||||
* to set up as e.g. "alarm 15 minutes after each hour".
|
||||
* Linux uses only oneshot alarms.
|
||||
*
|
||||
* When we see that here, we deal with it by using values from
|
||||
* a current RTC timestamp for any missing (-1) values. The
|
||||
* RTC driver prevents "periodic alarm" modes.
|
||||
*
|
||||
* But this can be racey, because some fields of the RTC timestamp
|
||||
* may have wrapped in the interval since we read the RTC alarm,
|
||||
@@ -174,6 +187,10 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
if (!alarm->enabled)
|
||||
return 0;
|
||||
|
||||
/* full-function RTCs won't have such missing fields */
|
||||
if (rtc_valid_tm(&alarm->time) == 0)
|
||||
return 0;
|
||||
|
||||
/* get the "after" timestamp, to detect wrapped fields */
|
||||
err = rtc_read_time(rtc, &now);
|
||||
if (err < 0)
|
||||
@@ -183,22 +200,85 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
} while ( before.tm_min != now.tm_min
|
||||
|| before.tm_hour != now.tm_hour
|
||||
|| before.tm_mon != now.tm_mon
|
||||
|| before.tm_year != now.tm_year
|
||||
|| before.tm_isdst != now.tm_isdst);
|
||||
|| before.tm_year != now.tm_year);
|
||||
|
||||
/* Fill in any missing alarm fields using the timestamp */
|
||||
/* Fill in the missing alarm fields using the timestamp; we
|
||||
* know there's at least one since alarm->time is invalid.
|
||||
*/
|
||||
if (alarm->time.tm_sec == -1)
|
||||
alarm->time.tm_sec = now.tm_sec;
|
||||
if (alarm->time.tm_min == -1)
|
||||
alarm->time.tm_min = now.tm_min;
|
||||
if (alarm->time.tm_hour == -1)
|
||||
alarm->time.tm_hour = now.tm_hour;
|
||||
if (alarm->time.tm_mday == -1)
|
||||
|
||||
/* For simplicity, only support date rollover for now */
|
||||
if (alarm->time.tm_mday == -1) {
|
||||
alarm->time.tm_mday = now.tm_mday;
|
||||
if (alarm->time.tm_mon == -1)
|
||||
missing = day;
|
||||
}
|
||||
if (alarm->time.tm_mon == -1) {
|
||||
alarm->time.tm_mon = now.tm_mon;
|
||||
if (alarm->time.tm_year == -1)
|
||||
if (missing == none)
|
||||
missing = month;
|
||||
}
|
||||
if (alarm->time.tm_year == -1) {
|
||||
alarm->time.tm_year = now.tm_year;
|
||||
if (missing == none)
|
||||
missing = year;
|
||||
}
|
||||
|
||||
/* with luck, no rollover is needed */
|
||||
rtc_tm_to_time(&now, &t_now);
|
||||
rtc_tm_to_time(&alarm->time, &t_alm);
|
||||
if (t_now < t_alm)
|
||||
goto done;
|
||||
|
||||
switch (missing) {
|
||||
|
||||
/* 24 hour rollover ... if it's now 10am Monday, an alarm that
|
||||
* that will trigger at 5am will do so at 5am Tuesday, which
|
||||
* could also be in the next month or year. This is a common
|
||||
* case, especially for PCs.
|
||||
*/
|
||||
case day:
|
||||
dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day");
|
||||
t_alm += 24 * 60 * 60;
|
||||
rtc_time_to_tm(t_alm, &alarm->time);
|
||||
break;
|
||||
|
||||
/* Month rollover ... if it's the 31th, an alarm on the 3rd will
|
||||
* be next month. An alarm matching on the 30th, 29th, or 28th
|
||||
* may end up in the month after that! Many newer PCs support
|
||||
* this type of alarm.
|
||||
*/
|
||||
case month:
|
||||
dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month");
|
||||
do {
|
||||
if (alarm->time.tm_mon < 11)
|
||||
alarm->time.tm_mon++;
|
||||
else {
|
||||
alarm->time.tm_mon = 0;
|
||||
alarm->time.tm_year++;
|
||||
}
|
||||
days = rtc_month_days(alarm->time.tm_mon,
|
||||
alarm->time.tm_year);
|
||||
} while (days < alarm->time.tm_mday);
|
||||
break;
|
||||
|
||||
/* Year rollover ... easy except for leap years! */
|
||||
case year:
|
||||
dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year");
|
||||
do {
|
||||
alarm->time.tm_year++;
|
||||
} while (!rtc_valid_tm(&alarm->time));
|
||||
break;
|
||||
|
||||
default:
|
||||
dev_warn(&rtc->dev, "alarm rollover not handled\n");
|
||||
}
|
||||
|
||||
done:
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_read_alarm);
|
||||
|
@@ -94,8 +94,11 @@ static int at32_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct rtc_at32ap700x *rtc = dev_get_drvdata(dev);
|
||||
|
||||
spin_lock_irq(&rtc->lock);
|
||||
rtc_time_to_tm(rtc->alarm_time, &alrm->time);
|
||||
alrm->pending = rtc_readl(rtc, IMR) & RTC_BIT(IMR_TOPI) ? 1 : 0;
|
||||
alrm->enabled = rtc_readl(rtc, IMR) & RTC_BIT(IMR_TOPI) ? 1 : 0;
|
||||
alrm->pending = rtc_readl(rtc, ISR) & RTC_BIT(ISR_TOPI) ? 1 : 0;
|
||||
spin_unlock_irq(&rtc->lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -119,7 +122,7 @@ static int at32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
spin_lock_irq(&rtc->lock);
|
||||
rtc->alarm_time = alarm_unix_time;
|
||||
rtc_writel(rtc, TOP, rtc->alarm_time);
|
||||
if (alrm->pending)
|
||||
if (alrm->enabled)
|
||||
rtc_writel(rtc, CTRL, rtc_readl(rtc, CTRL)
|
||||
| RTC_BIT(CTRL_TOPEN));
|
||||
else
|
||||
|
@@ -905,19 +905,7 @@ static struct pnp_driver cmos_pnp_driver = {
|
||||
.resume = cmos_pnp_resume,
|
||||
};
|
||||
|
||||
static int __init cmos_init(void)
|
||||
{
|
||||
return pnp_register_driver(&cmos_pnp_driver);
|
||||
}
|
||||
module_init(cmos_init);
|
||||
|
||||
static void __exit cmos_exit(void)
|
||||
{
|
||||
pnp_unregister_driver(&cmos_pnp_driver);
|
||||
}
|
||||
module_exit(cmos_exit);
|
||||
|
||||
#else /* no PNP */
|
||||
#endif /* CONFIG_PNP */
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
@@ -958,20 +946,33 @@ static struct platform_driver cmos_platform_driver = {
|
||||
|
||||
static int __init cmos_init(void)
|
||||
{
|
||||
#ifdef CONFIG_PNP
|
||||
if (pnp_platform_devices)
|
||||
return pnp_register_driver(&cmos_pnp_driver);
|
||||
else
|
||||
return platform_driver_probe(&cmos_platform_driver,
|
||||
cmos_platform_probe);
|
||||
#else
|
||||
return platform_driver_probe(&cmos_platform_driver,
|
||||
cmos_platform_probe);
|
||||
#endif /* CONFIG_PNP */
|
||||
}
|
||||
module_init(cmos_init);
|
||||
|
||||
static void __exit cmos_exit(void)
|
||||
{
|
||||
#ifdef CONFIG_PNP
|
||||
if (pnp_platform_devices)
|
||||
pnp_unregister_driver(&cmos_pnp_driver);
|
||||
else
|
||||
platform_driver_unregister(&cmos_platform_driver);
|
||||
#else
|
||||
platform_driver_unregister(&cmos_platform_driver);
|
||||
#endif /* CONFIG_PNP */
|
||||
}
|
||||
module_exit(cmos_exit);
|
||||
|
||||
|
||||
#endif /* !PNP */
|
||||
|
||||
MODULE_AUTHOR("David Brownell");
|
||||
MODULE_DESCRIPTION("Driver for PC-style 'CMOS' RTCs");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@@ -42,7 +42,7 @@
|
||||
#define DS1374_REG_TCR 0x09 /* Trickle Charge */
|
||||
|
||||
static const struct i2c_device_id ds1374_id[] = {
|
||||
{ "rtc-ds1374", 0 },
|
||||
{ "ds1374", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, ds1374_id);
|
||||
|
501
drivers/rtc/rtc-fm3130.c
Normal file
501
drivers/rtc/rtc-fm3130.c
Normal file
@@ -0,0 +1,501 @@
|
||||
/*
|
||||
* rtc-fm3130.c - RTC driver for Ramtron FM3130 I2C chip.
|
||||
*
|
||||
* Copyright (C) 2008 Sergey Lapin
|
||||
* Based on ds1307 driver by James Chapman and David Brownell
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/bcd.h>
|
||||
|
||||
#define FM3130_RTC_CONTROL (0x0)
|
||||
#define FM3130_CAL_CONTROL (0x1)
|
||||
#define FM3130_RTC_SECONDS (0x2)
|
||||
#define FM3130_RTC_MINUTES (0x3)
|
||||
#define FM3130_RTC_HOURS (0x4)
|
||||
#define FM3130_RTC_DAY (0x5)
|
||||
#define FM3130_RTC_DATE (0x6)
|
||||
#define FM3130_RTC_MONTHS (0x7)
|
||||
#define FM3130_RTC_YEARS (0x8)
|
||||
|
||||
#define FM3130_ALARM_SECONDS (0x9)
|
||||
#define FM3130_ALARM_MINUTES (0xa)
|
||||
#define FM3130_ALARM_HOURS (0xb)
|
||||
#define FM3130_ALARM_DATE (0xc)
|
||||
#define FM3130_ALARM_MONTHS (0xd)
|
||||
#define FM3130_ALARM_WP_CONTROL (0xe)
|
||||
|
||||
#define FM3130_CAL_CONTROL_BIT_nOSCEN (1 << 7) /* Osciallator enabled */
|
||||
#define FM3130_RTC_CONTROL_BIT_LB (1 << 7) /* Low battery */
|
||||
#define FM3130_RTC_CONTROL_BIT_AF (1 << 6) /* Alarm flag */
|
||||
#define FM3130_RTC_CONTROL_BIT_CF (1 << 5) /* Century overflow */
|
||||
#define FM3130_RTC_CONTROL_BIT_POR (1 << 4) /* Power on reset */
|
||||
#define FM3130_RTC_CONTROL_BIT_AEN (1 << 3) /* Alarm enable */
|
||||
#define FM3130_RTC_CONTROL_BIT_CAL (1 << 2) /* Calibration mode */
|
||||
#define FM3130_RTC_CONTROL_BIT_WRITE (1 << 1) /* W=1 -> write mode W=0 normal */
|
||||
#define FM3130_RTC_CONTROL_BIT_READ (1 << 0) /* R=1 -> read mode R=0 normal */
|
||||
|
||||
#define FM3130_CLOCK_REGS 7
|
||||
#define FM3130_ALARM_REGS 5
|
||||
|
||||
struct fm3130 {
|
||||
u8 reg_addr_time;
|
||||
u8 reg_addr_alarm;
|
||||
u8 regs[15];
|
||||
struct i2c_msg msg[4];
|
||||
struct i2c_client *client;
|
||||
struct rtc_device *rtc;
|
||||
int data_valid;
|
||||
int alarm;
|
||||
};
|
||||
static const struct i2c_device_id fm3130_id[] = {
|
||||
{ "fm3130", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, fm3130_id);
|
||||
|
||||
#define FM3130_MODE_NORMAL 0
|
||||
#define FM3130_MODE_WRITE 1
|
||||
#define FM3130_MODE_READ 2
|
||||
|
||||
static void fm3130_rtc_mode(struct device *dev, int mode)
|
||||
{
|
||||
struct fm3130 *fm3130 = dev_get_drvdata(dev);
|
||||
|
||||
fm3130->regs[FM3130_RTC_CONTROL] =
|
||||
i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL);
|
||||
switch (mode) {
|
||||
case FM3130_MODE_NORMAL:
|
||||
fm3130->regs[FM3130_RTC_CONTROL] &=
|
||||
~(FM3130_RTC_CONTROL_BIT_WRITE |
|
||||
FM3130_RTC_CONTROL_BIT_READ);
|
||||
break;
|
||||
case FM3130_MODE_WRITE:
|
||||
fm3130->regs[FM3130_RTC_CONTROL] |= FM3130_RTC_CONTROL_BIT_WRITE;
|
||||
break;
|
||||
case FM3130_MODE_READ:
|
||||
fm3130->regs[FM3130_RTC_CONTROL] |= FM3130_RTC_CONTROL_BIT_READ;
|
||||
break;
|
||||
default:
|
||||
dev_dbg(dev, "invalid mode %d\n", mode);
|
||||
break;
|
||||
}
|
||||
/* Checking for alarm */
|
||||
if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) {
|
||||
fm3130->alarm = 1;
|
||||
fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF;
|
||||
}
|
||||
i2c_smbus_write_byte_data(fm3130->client,
|
||||
FM3130_RTC_CONTROL, fm3130->regs[FM3130_RTC_CONTROL]);
|
||||
}
|
||||
|
||||
static int fm3130_get_time(struct device *dev, struct rtc_time *t)
|
||||
{
|
||||
struct fm3130 *fm3130 = dev_get_drvdata(dev);
|
||||
int tmp;
|
||||
|
||||
if (!fm3130->data_valid) {
|
||||
/* We have invalid data in RTC, probably due
|
||||
to battery faults or other problems. Return EIO
|
||||
for now, it will allow us to set data later insted
|
||||
of error during probing which disables device */
|
||||
return -EIO;
|
||||
}
|
||||
fm3130_rtc_mode(dev, FM3130_MODE_READ);
|
||||
|
||||
/* read the RTC date and time registers all at once */
|
||||
tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
|
||||
fm3130->msg, 2);
|
||||
if (tmp != 2) {
|
||||
dev_err(dev, "%s error %d\n", "read", tmp);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
fm3130_rtc_mode(dev, FM3130_MODE_NORMAL);
|
||||
|
||||
dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x"
|
||||
"%02x %02x %02x %02x %02x %02x %02x\n",
|
||||
"read",
|
||||
fm3130->regs[0], fm3130->regs[1],
|
||||
fm3130->regs[2], fm3130->regs[3],
|
||||
fm3130->regs[4], fm3130->regs[5],
|
||||
fm3130->regs[6], fm3130->regs[7],
|
||||
fm3130->regs[8], fm3130->regs[9],
|
||||
fm3130->regs[0xa], fm3130->regs[0xb],
|
||||
fm3130->regs[0xc], fm3130->regs[0xd],
|
||||
fm3130->regs[0xe]);
|
||||
|
||||
t->tm_sec = BCD2BIN(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
|
||||
t->tm_min = BCD2BIN(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
|
||||
tmp = fm3130->regs[FM3130_RTC_HOURS] & 0x3f;
|
||||
t->tm_hour = BCD2BIN(tmp);
|
||||
t->tm_wday = BCD2BIN(fm3130->regs[FM3130_RTC_DAY] & 0x07) - 1;
|
||||
t->tm_mday = BCD2BIN(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
|
||||
tmp = fm3130->regs[FM3130_RTC_MONTHS] & 0x1f;
|
||||
t->tm_mon = BCD2BIN(tmp) - 1;
|
||||
|
||||
/* assume 20YY not 19YY, and ignore CF bit */
|
||||
t->tm_year = BCD2BIN(fm3130->regs[FM3130_RTC_YEARS]) + 100;
|
||||
|
||||
dev_dbg(dev, "%s secs=%d, mins=%d, "
|
||||
"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
|
||||
"read", t->tm_sec, t->tm_min,
|
||||
t->tm_hour, t->tm_mday,
|
||||
t->tm_mon, t->tm_year, t->tm_wday);
|
||||
|
||||
/* initial clock setting can be undefined */
|
||||
return rtc_valid_tm(t);
|
||||
}
|
||||
|
||||
|
||||
static int fm3130_set_time(struct device *dev, struct rtc_time *t)
|
||||
{
|
||||
struct fm3130 *fm3130 = dev_get_drvdata(dev);
|
||||
int tmp, i;
|
||||
u8 *buf = fm3130->regs;
|
||||
|
||||
dev_dbg(dev, "%s secs=%d, mins=%d, "
|
||||
"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
|
||||
"write", t->tm_sec, t->tm_min,
|
||||
t->tm_hour, t->tm_mday,
|
||||
t->tm_mon, t->tm_year, t->tm_wday);
|
||||
|
||||
/* first register addr */
|
||||
buf[FM3130_RTC_SECONDS] = BIN2BCD(t->tm_sec);
|
||||
buf[FM3130_RTC_MINUTES] = BIN2BCD(t->tm_min);
|
||||
buf[FM3130_RTC_HOURS] = BIN2BCD(t->tm_hour);
|
||||
buf[FM3130_RTC_DAY] = BIN2BCD(t->tm_wday + 1);
|
||||
buf[FM3130_RTC_DATE] = BIN2BCD(t->tm_mday);
|
||||
buf[FM3130_RTC_MONTHS] = BIN2BCD(t->tm_mon + 1);
|
||||
|
||||
/* assume 20YY not 19YY */
|
||||
tmp = t->tm_year - 100;
|
||||
buf[FM3130_RTC_YEARS] = BIN2BCD(tmp);
|
||||
|
||||
dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x"
|
||||
"%02x %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
"write", buf[0], buf[1], buf[2], buf[3],
|
||||
buf[4], buf[5], buf[6], buf[7],
|
||||
buf[8], buf[9], buf[0xa], buf[0xb],
|
||||
buf[0xc], buf[0xd], buf[0xe]);
|
||||
|
||||
fm3130_rtc_mode(dev, FM3130_MODE_WRITE);
|
||||
|
||||
/* Writing time registers, we don't support multibyte transfers */
|
||||
for (i = 0; i < FM3130_CLOCK_REGS; i++) {
|
||||
i2c_smbus_write_byte_data(fm3130->client,
|
||||
FM3130_RTC_SECONDS + i,
|
||||
fm3130->regs[FM3130_RTC_SECONDS + i]);
|
||||
}
|
||||
|
||||
fm3130_rtc_mode(dev, FM3130_MODE_NORMAL);
|
||||
|
||||
/* We assume here that data are valid once written */
|
||||
if (!fm3130->data_valid)
|
||||
fm3130->data_valid = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fm3130_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct fm3130 *fm3130 = dev_get_drvdata(dev);
|
||||
int tmp;
|
||||
struct rtc_time *tm = &alrm->time;
|
||||
/* read the RTC alarm registers all at once */
|
||||
tmp = i2c_transfer(to_i2c_adapter(fm3130->client->dev.parent),
|
||||
&fm3130->msg[2], 2);
|
||||
if (tmp != 2) {
|
||||
dev_err(dev, "%s error %d\n", "read", tmp);
|
||||
return -EIO;
|
||||
}
|
||||
dev_dbg(dev, "alarm read %02x %02x %02x %02x %02x\n",
|
||||
fm3130->regs[FM3130_ALARM_SECONDS],
|
||||
fm3130->regs[FM3130_ALARM_MINUTES],
|
||||
fm3130->regs[FM3130_ALARM_HOURS],
|
||||
fm3130->regs[FM3130_ALARM_DATE],
|
||||
fm3130->regs[FM3130_ALARM_MONTHS]);
|
||||
|
||||
|
||||
tm->tm_sec = BCD2BIN(fm3130->regs[FM3130_ALARM_SECONDS] & 0x7F);
|
||||
tm->tm_min = BCD2BIN(fm3130->regs[FM3130_ALARM_MINUTES] & 0x7F);
|
||||
tm->tm_hour = BCD2BIN(fm3130->regs[FM3130_ALARM_HOURS] & 0x3F);
|
||||
tm->tm_mday = BCD2BIN(fm3130->regs[FM3130_ALARM_DATE] & 0x3F);
|
||||
tm->tm_mon = BCD2BIN(fm3130->regs[FM3130_ALARM_MONTHS] & 0x1F);
|
||||
if (tm->tm_mon > 0)
|
||||
tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */
|
||||
dev_dbg(dev, "%s secs=%d, mins=%d, "
|
||||
"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
|
||||
"read alarm", tm->tm_sec, tm->tm_min,
|
||||
tm->tm_hour, tm->tm_mday,
|
||||
tm->tm_mon, tm->tm_year, tm->tm_wday);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fm3130_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct fm3130 *fm3130 = dev_get_drvdata(dev);
|
||||
struct rtc_time *tm = &alrm->time;
|
||||
int i;
|
||||
|
||||
dev_dbg(dev, "%s secs=%d, mins=%d, "
|
||||
"hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
|
||||
"write alarm", tm->tm_sec, tm->tm_min,
|
||||
tm->tm_hour, tm->tm_mday,
|
||||
tm->tm_mon, tm->tm_year, tm->tm_wday);
|
||||
|
||||
if (tm->tm_sec != -1)
|
||||
fm3130->regs[FM3130_ALARM_SECONDS] =
|
||||
BIN2BCD(tm->tm_sec) | 0x80;
|
||||
|
||||
if (tm->tm_min != -1)
|
||||
fm3130->regs[FM3130_ALARM_MINUTES] =
|
||||
BIN2BCD(tm->tm_min) | 0x80;
|
||||
|
||||
if (tm->tm_hour != -1)
|
||||
fm3130->regs[FM3130_ALARM_HOURS] =
|
||||
BIN2BCD(tm->tm_hour) | 0x80;
|
||||
|
||||
if (tm->tm_mday != -1)
|
||||
fm3130->regs[FM3130_ALARM_DATE] =
|
||||
BIN2BCD(tm->tm_mday) | 0x80;
|
||||
|
||||
if (tm->tm_mon != -1)
|
||||
fm3130->regs[FM3130_ALARM_MONTHS] =
|
||||
BIN2BCD(tm->tm_mon + 1) | 0x80;
|
||||
|
||||
dev_dbg(dev, "alarm write %02x %02x %02x %02x %02x\n",
|
||||
fm3130->regs[FM3130_ALARM_SECONDS],
|
||||
fm3130->regs[FM3130_ALARM_MINUTES],
|
||||
fm3130->regs[FM3130_ALARM_HOURS],
|
||||
fm3130->regs[FM3130_ALARM_DATE],
|
||||
fm3130->regs[FM3130_ALARM_MONTHS]);
|
||||
/* Writing time registers, we don't support multibyte transfers */
|
||||
for (i = 0; i < FM3130_ALARM_REGS; i++) {
|
||||
i2c_smbus_write_byte_data(fm3130->client,
|
||||
FM3130_ALARM_SECONDS + i,
|
||||
fm3130->regs[FM3130_ALARM_SECONDS + i]);
|
||||
}
|
||||
fm3130->regs[FM3130_RTC_CONTROL] =
|
||||
i2c_smbus_read_byte_data(fm3130->client, FM3130_RTC_CONTROL);
|
||||
/* Checking for alarm */
|
||||
if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) {
|
||||
fm3130->alarm = 1;
|
||||
fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF;
|
||||
}
|
||||
if (alrm->enabled) {
|
||||
i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL,
|
||||
(fm3130->regs[FM3130_RTC_CONTROL] &
|
||||
~(FM3130_RTC_CONTROL_BIT_CAL)) |
|
||||
FM3130_RTC_CONTROL_BIT_AEN);
|
||||
} else {
|
||||
i2c_smbus_write_byte_data(fm3130->client, FM3130_RTC_CONTROL,
|
||||
fm3130->regs[FM3130_RTC_CONTROL] &
|
||||
~(FM3130_RTC_CONTROL_BIT_AEN));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops fm3130_rtc_ops = {
|
||||
.read_time = fm3130_get_time,
|
||||
.set_time = fm3130_set_time,
|
||||
.read_alarm = fm3130_read_alarm,
|
||||
.set_alarm = fm3130_set_alarm,
|
||||
};
|
||||
|
||||
static struct i2c_driver fm3130_driver;
|
||||
|
||||
static int __devinit fm3130_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct fm3130 *fm3130;
|
||||
int err = -ENODEV;
|
||||
int tmp;
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
|
||||
if (!i2c_check_functionality(adapter,
|
||||
I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
|
||||
return -EIO;
|
||||
|
||||
fm3130 = kzalloc(sizeof(struct fm3130), GFP_KERNEL);
|
||||
|
||||
if (!fm3130)
|
||||
return -ENOMEM;
|
||||
|
||||
fm3130->client = client;
|
||||
i2c_set_clientdata(client, fm3130);
|
||||
fm3130->reg_addr_time = FM3130_RTC_SECONDS;
|
||||
fm3130->reg_addr_alarm = FM3130_ALARM_SECONDS;
|
||||
|
||||
/* Messages to read time */
|
||||
fm3130->msg[0].addr = client->addr;
|
||||
fm3130->msg[0].flags = 0;
|
||||
fm3130->msg[0].len = 1;
|
||||
fm3130->msg[0].buf = &fm3130->reg_addr_time;
|
||||
|
||||
fm3130->msg[1].addr = client->addr;
|
||||
fm3130->msg[1].flags = I2C_M_RD;
|
||||
fm3130->msg[1].len = FM3130_CLOCK_REGS;
|
||||
fm3130->msg[1].buf = &fm3130->regs[FM3130_RTC_SECONDS];
|
||||
|
||||
/* Messages to read alarm */
|
||||
fm3130->msg[2].addr = client->addr;
|
||||
fm3130->msg[2].flags = 0;
|
||||
fm3130->msg[2].len = 1;
|
||||
fm3130->msg[2].buf = &fm3130->reg_addr_alarm;
|
||||
|
||||
fm3130->msg[3].addr = client->addr;
|
||||
fm3130->msg[3].flags = I2C_M_RD;
|
||||
fm3130->msg[3].len = FM3130_ALARM_REGS;
|
||||
fm3130->msg[3].buf = &fm3130->regs[FM3130_ALARM_SECONDS];
|
||||
|
||||
fm3130->data_valid = 0;
|
||||
|
||||
tmp = i2c_transfer(adapter, fm3130->msg, 4);
|
||||
if (tmp != 4) {
|
||||
pr_debug("read error %d\n", tmp);
|
||||
err = -EIO;
|
||||
goto exit_free;
|
||||
}
|
||||
|
||||
fm3130->regs[FM3130_RTC_CONTROL] =
|
||||
i2c_smbus_read_byte_data(client, FM3130_RTC_CONTROL);
|
||||
fm3130->regs[FM3130_CAL_CONTROL] =
|
||||
i2c_smbus_read_byte_data(client, FM3130_CAL_CONTROL);
|
||||
|
||||
/* Checking for alarm */
|
||||
if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_AF) {
|
||||
fm3130->alarm = 1;
|
||||
fm3130->regs[FM3130_RTC_CONTROL] &= ~FM3130_RTC_CONTROL_BIT_AF;
|
||||
}
|
||||
|
||||
/* Disabling calibration mode */
|
||||
if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_CAL)
|
||||
i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
|
||||
fm3130->regs[FM3130_RTC_CONTROL] &
|
||||
~(FM3130_RTC_CONTROL_BIT_CAL));
|
||||
dev_warn(&client->dev, "Disabling calibration mode!\n");
|
||||
|
||||
/* Disabling read and write modes */
|
||||
if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_WRITE ||
|
||||
fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_READ)
|
||||
i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
|
||||
fm3130->regs[FM3130_RTC_CONTROL] &
|
||||
~(FM3130_RTC_CONTROL_BIT_READ |
|
||||
FM3130_RTC_CONTROL_BIT_WRITE));
|
||||
dev_warn(&client->dev, "Disabling READ or WRITE mode!\n");
|
||||
|
||||
/* oscillator off? turn it on, so clock can tick. */
|
||||
if (fm3130->regs[FM3130_CAL_CONTROL] & FM3130_CAL_CONTROL_BIT_nOSCEN)
|
||||
i2c_smbus_write_byte_data(client, FM3130_CAL_CONTROL,
|
||||
fm3130->regs[FM3130_CAL_CONTROL] &
|
||||
~(FM3130_CAL_CONTROL_BIT_nOSCEN));
|
||||
|
||||
/* oscillator fault? clear flag, and warn */
|
||||
if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_LB)
|
||||
dev_warn(&client->dev, "Low battery!\n");
|
||||
|
||||
/* oscillator fault? clear flag, and warn */
|
||||
if (fm3130->regs[FM3130_RTC_CONTROL] & FM3130_RTC_CONTROL_BIT_POR) {
|
||||
i2c_smbus_write_byte_data(client, FM3130_RTC_CONTROL,
|
||||
fm3130->regs[FM3130_RTC_CONTROL] &
|
||||
~FM3130_RTC_CONTROL_BIT_POR);
|
||||
dev_warn(&client->dev, "SET TIME!\n");
|
||||
}
|
||||
/* ACS is controlled by alarm */
|
||||
i2c_smbus_write_byte_data(client, FM3130_ALARM_WP_CONTROL, 0x80);
|
||||
|
||||
/* TODO */
|
||||
/* TODO need to sanity check alarm */
|
||||
tmp = fm3130->regs[FM3130_RTC_SECONDS];
|
||||
tmp = BCD2BIN(tmp & 0x7f);
|
||||
if (tmp > 60)
|
||||
goto exit_bad;
|
||||
tmp = BCD2BIN(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
|
||||
if (tmp > 60)
|
||||
goto exit_bad;
|
||||
|
||||
tmp = BCD2BIN(fm3130->regs[FM3130_RTC_DATE] & 0x3f);
|
||||
if (tmp == 0 || tmp > 31)
|
||||
goto exit_bad;
|
||||
|
||||
tmp = BCD2BIN(fm3130->regs[FM3130_RTC_MONTHS] & 0x1f);
|
||||
if (tmp == 0 || tmp > 12)
|
||||
goto exit_bad;
|
||||
|
||||
tmp = fm3130->regs[FM3130_RTC_HOURS];
|
||||
|
||||
fm3130->data_valid = 1;
|
||||
|
||||
exit_bad:
|
||||
if (!fm3130->data_valid)
|
||||
dev_dbg(&client->dev,
|
||||
"%s: %02x %02x %02x %02x %02x %02x %02x %02x"
|
||||
"%02x %02x %02x %02x %02x %02x %02x\n",
|
||||
"bogus registers",
|
||||
fm3130->regs[0], fm3130->regs[1],
|
||||
fm3130->regs[2], fm3130->regs[3],
|
||||
fm3130->regs[4], fm3130->regs[5],
|
||||
fm3130->regs[6], fm3130->regs[7],
|
||||
fm3130->regs[8], fm3130->regs[9],
|
||||
fm3130->regs[0xa], fm3130->regs[0xb],
|
||||
fm3130->regs[0xc], fm3130->regs[0xd],
|
||||
fm3130->regs[0xe]);
|
||||
|
||||
/* We won't bail out here because we just got invalid data.
|
||||
Time setting from u-boot doesn't work anyway */
|
||||
fm3130->rtc = rtc_device_register(client->name, &client->dev,
|
||||
&fm3130_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(fm3130->rtc)) {
|
||||
err = PTR_ERR(fm3130->rtc);
|
||||
dev_err(&client->dev,
|
||||
"unable to register the class device\n");
|
||||
goto exit_free;
|
||||
}
|
||||
return 0;
|
||||
exit_free:
|
||||
kfree(fm3130);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __devexit fm3130_remove(struct i2c_client *client)
|
||||
{
|
||||
struct fm3130 *fm3130 = i2c_get_clientdata(client);
|
||||
|
||||
rtc_device_unregister(fm3130->rtc);
|
||||
kfree(fm3130);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct i2c_driver fm3130_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-fm3130",
|
||||
.owner = THIS_MODULE,
|
||||
},
|
||||
.probe = fm3130_probe,
|
||||
.remove = __devexit_p(fm3130_remove),
|
||||
.id_table = fm3130_id,
|
||||
};
|
||||
|
||||
static int __init fm3130_init(void)
|
||||
{
|
||||
return i2c_add_driver(&fm3130_driver);
|
||||
}
|
||||
module_init(fm3130_init);
|
||||
|
||||
static void __exit fm3130_exit(void)
|
||||
{
|
||||
i2c_del_driver(&fm3130_driver);
|
||||
}
|
||||
module_exit(fm3130_exit);
|
||||
|
||||
MODULE_DESCRIPTION("RTC driver for FM3130");
|
||||
MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@@ -302,6 +302,7 @@ static int pcf8563_remove(struct i2c_client *client)
|
||||
|
||||
static const struct i2c_device_id pcf8563_id[] = {
|
||||
{ "pcf8563", 0 },
|
||||
{ "rtc8564", 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pcf8563_id);
|
||||
|
69
drivers/rtc/rtc-ppc.c
Normal file
69
drivers/rtc/rtc-ppc.c
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* RTC driver for ppc_md RTC functions
|
||||
*
|
||||
* © 2007 Red Hat, Inc.
|
||||
*
|
||||
* Author: David Woodhouse <dwmw2@infradead.org>
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <asm/machdep.h>
|
||||
|
||||
static int ppc_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
ppc_md.get_rtc_time(tm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ppc_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
return ppc_md.set_rtc_time(tm);
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops ppc_rtc_ops = {
|
||||
.set_time = ppc_rtc_set_time,
|
||||
.read_time = ppc_rtc_read_time,
|
||||
};
|
||||
|
||||
static struct rtc_device *rtc;
|
||||
static struct platform_device *ppc_rtc_pdev;
|
||||
|
||||
static int __init ppc_rtc_init(void)
|
||||
{
|
||||
if (!ppc_md.get_rtc_time || !ppc_md.set_rtc_time)
|
||||
return -ENODEV;
|
||||
|
||||
ppc_rtc_pdev = platform_device_register_simple("ppc-rtc", 0, NULL, 0);
|
||||
if (IS_ERR(ppc_rtc_pdev))
|
||||
return PTR_ERR(ppc_rtc_pdev);
|
||||
|
||||
rtc = rtc_device_register("ppc_md", &ppc_rtc_pdev->dev,
|
||||
&ppc_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc)) {
|
||||
platform_device_unregister(ppc_rtc_pdev);
|
||||
return PTR_ERR(rtc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit ppc_rtc_exit(void)
|
||||
{
|
||||
rtc_device_unregister(rtc);
|
||||
platform_device_unregister(ppc_rtc_pdev);
|
||||
}
|
||||
|
||||
module_init(ppc_rtc_init);
|
||||
module_exit(ppc_rtc_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("David Woodhouse <dwmw2@infradead.org>");
|
||||
MODULE_DESCRIPTION("Generic RTC class driver for PowerPC");
|
@@ -331,14 +331,14 @@ static int sa1100_rtc_probe(struct platform_device *pdev)
|
||||
RCNR = 0;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops,
|
||||
THIS_MODULE);
|
||||
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
return 0;
|
||||
|
@@ -71,6 +71,7 @@
|
||||
#define X1205_SR_RTCF 0x01 /* Clock failure */
|
||||
#define X1205_SR_WEL 0x02 /* Write Enable Latch */
|
||||
#define X1205_SR_RWEL 0x04 /* Register Write Enable */
|
||||
#define X1205_SR_AL0 0x20 /* Alarm 0 match */
|
||||
|
||||
#define X1205_DTR_DTR0 0x01
|
||||
#define X1205_DTR_DTR1 0x02
|
||||
@@ -78,6 +79,8 @@
|
||||
|
||||
#define X1205_HR_MIL 0x80 /* Set in ccr.hour for 24 hr mode */
|
||||
|
||||
#define X1205_INT_AL0E 0x20 /* Alarm 0 enable */
|
||||
|
||||
static struct i2c_driver x1205_driver;
|
||||
|
||||
/*
|
||||
@@ -89,8 +92,8 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
|
||||
unsigned char reg_base)
|
||||
{
|
||||
unsigned char dt_addr[2] = { 0, reg_base };
|
||||
|
||||
unsigned char buf[8];
|
||||
int i;
|
||||
|
||||
struct i2c_msg msgs[] = {
|
||||
{ client->addr, 0, 2, dt_addr }, /* setup read ptr */
|
||||
@@ -98,7 +101,7 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
|
||||
};
|
||||
|
||||
/* read date registers */
|
||||
if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
|
||||
if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
|
||||
dev_err(&client->dev, "%s: read error\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -110,6 +113,11 @@ static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
|
||||
buf[0], buf[1], buf[2], buf[3],
|
||||
buf[4], buf[5], buf[6], buf[7]);
|
||||
|
||||
/* Mask out the enable bits if these are alarm registers */
|
||||
if (reg_base < X1205_CCR_BASE)
|
||||
for (i = 0; i <= 4; i++)
|
||||
buf[i] &= 0x7F;
|
||||
|
||||
tm->tm_sec = BCD2BIN(buf[CCR_SEC]);
|
||||
tm->tm_min = BCD2BIN(buf[CCR_MIN]);
|
||||
tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
|
||||
@@ -138,7 +146,7 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
|
||||
};
|
||||
|
||||
/* read status register */
|
||||
if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
|
||||
if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
|
||||
dev_err(&client->dev, "%s: read error\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -147,10 +155,11 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
|
||||
}
|
||||
|
||||
static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
|
||||
int datetoo, u8 reg_base)
|
||||
int datetoo, u8 reg_base, unsigned char alm_enable)
|
||||
{
|
||||
int i, xfer;
|
||||
int i, xfer, nbytes;
|
||||
unsigned char buf[8];
|
||||
unsigned char rdata[10] = { 0, reg_base };
|
||||
|
||||
static const unsigned char wel[3] = { 0, X1205_REG_SR,
|
||||
X1205_SR_WEL };
|
||||
@@ -189,6 +198,11 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
|
||||
buf[CCR_Y2K] = BIN2BCD(tm->tm_year / 100);
|
||||
}
|
||||
|
||||
/* If writing alarm registers, set compare bits on registers 0-4 */
|
||||
if (reg_base < X1205_CCR_BASE)
|
||||
for (i = 0; i <= 4; i++)
|
||||
buf[i] |= 0x80;
|
||||
|
||||
/* this sequence is required to unlock the chip */
|
||||
if ((xfer = i2c_master_send(client, wel, 3)) != 3) {
|
||||
dev_err(&client->dev, "%s: wel - %d\n", __func__, xfer);
|
||||
@@ -200,19 +214,57 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* write register's data */
|
||||
for (i = 0; i < (datetoo ? 8 : 3); i++) {
|
||||
unsigned char rdata[3] = { 0, reg_base + i, buf[i] };
|
||||
|
||||
xfer = i2c_master_send(client, rdata, 3);
|
||||
/* write register's data */
|
||||
if (datetoo)
|
||||
nbytes = 8;
|
||||
else
|
||||
nbytes = 3;
|
||||
for (i = 0; i < nbytes; i++)
|
||||
rdata[2+i] = buf[i];
|
||||
|
||||
xfer = i2c_master_send(client, rdata, nbytes+2);
|
||||
if (xfer != nbytes+2) {
|
||||
dev_err(&client->dev,
|
||||
"%s: result=%d addr=%02x, data=%02x\n",
|
||||
__func__,
|
||||
xfer, rdata[1], rdata[2]);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* If we wrote to the nonvolatile region, wait 10msec for write cycle*/
|
||||
if (reg_base < X1205_CCR_BASE) {
|
||||
unsigned char al0e[3] = { 0, X1205_REG_INT, 0 };
|
||||
|
||||
msleep(10);
|
||||
|
||||
/* ...and set or clear the AL0E bit in the INT register */
|
||||
|
||||
/* Need to set RWEL again as the write has cleared it */
|
||||
xfer = i2c_master_send(client, rwel, 3);
|
||||
if (xfer != 3) {
|
||||
dev_err(&client->dev,
|
||||
"%s: xfer=%d addr=%02x, data=%02x\n",
|
||||
"%s: aloe rwel - %d\n",
|
||||
__func__,
|
||||
xfer, rdata[1], rdata[2]);
|
||||
xfer);
|
||||
return -EIO;
|
||||
}
|
||||
};
|
||||
|
||||
if (alm_enable)
|
||||
al0e[2] = X1205_INT_AL0E;
|
||||
|
||||
xfer = i2c_master_send(client, al0e, 3);
|
||||
if (xfer != 3) {
|
||||
dev_err(&client->dev,
|
||||
"%s: al0e - %d\n",
|
||||
__func__,
|
||||
xfer);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/* and wait 10msec again for this write to complete */
|
||||
msleep(10);
|
||||
}
|
||||
|
||||
/* disable further writes */
|
||||
if ((xfer = i2c_master_send(client, diswe, 3)) != 3) {
|
||||
@@ -230,9 +282,9 @@ static int x1205_fix_osc(struct i2c_client *client)
|
||||
|
||||
tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
|
||||
|
||||
if ((err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE)) < 0)
|
||||
dev_err(&client->dev,
|
||||
"unable to restart the oscillator\n");
|
||||
err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE, 0);
|
||||
if (err < 0)
|
||||
dev_err(&client->dev, "unable to restart the oscillator\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -248,7 +300,7 @@ static int x1205_get_dtrim(struct i2c_client *client, int *trim)
|
||||
};
|
||||
|
||||
/* read dtr register */
|
||||
if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
|
||||
if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
|
||||
dev_err(&client->dev, "%s: read error\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -280,7 +332,7 @@ static int x1205_get_atrim(struct i2c_client *client, int *trim)
|
||||
};
|
||||
|
||||
/* read atr register */
|
||||
if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
|
||||
if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
|
||||
dev_err(&client->dev, "%s: read error\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
@@ -403,14 +455,33 @@ static int x1205_validate_client(struct i2c_client *client)
|
||||
|
||||
static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
return x1205_get_datetime(to_i2c_client(dev),
|
||||
&alrm->time, X1205_ALM0_BASE);
|
||||
int err;
|
||||
unsigned char intreg, status;
|
||||
static unsigned char int_addr[2] = { 0, X1205_REG_INT };
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_msg msgs[] = {
|
||||
{ client->addr, 0, 2, int_addr }, /* setup read ptr */
|
||||
{ client->addr, I2C_M_RD, 1, &intreg }, /* read INT register */
|
||||
};
|
||||
|
||||
/* read interrupt register and status register */
|
||||
if (i2c_transfer(client->adapter, &msgs[0], 2) != 2) {
|
||||
dev_err(&client->dev, "%s: read error\n", __func__);
|
||||
return -EIO;
|
||||
}
|
||||
err = x1205_get_status(client, &status);
|
||||
if (err == 0) {
|
||||
alrm->pending = (status & X1205_SR_AL0) ? 1 : 0;
|
||||
alrm->enabled = (intreg & X1205_INT_AL0E) ? 1 : 0;
|
||||
err = x1205_get_datetime(client, &alrm->time, X1205_ALM0_BASE);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
|
||||
static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
return x1205_set_datetime(to_i2c_client(dev),
|
||||
&alrm->time, 1, X1205_ALM0_BASE);
|
||||
&alrm->time, 1, X1205_ALM0_BASE, alrm->enabled);
|
||||
}
|
||||
|
||||
static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
@@ -422,7 +493,7 @@ static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
return x1205_set_datetime(to_i2c_client(dev),
|
||||
tm, 1, X1205_CCR_BASE);
|
||||
tm, 1, X1205_CCR_BASE, 0);
|
||||
}
|
||||
|
||||
static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
|
||||
|
Reference in New Issue
Block a user