summaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-01-18 12:10:45 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2016-01-18 12:10:45 -0800
commitc38dec71664dadb15094151f53886abb69f8f9e6 (patch)
treeafd6aaa893cd4d7d740679826c7f0c252764e4c8 /drivers/rtc
parentd43fb9f3c5dff281dd72bea5cd2e91386fdc33a8 (diff)
parent079062b28fb4c58e30d024fdf974e00de53158fd (diff)
Merge tag 'rtc-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
Pull RTC updates from Alexandre Belloni: "Core: - fix module reference count in rtc-proc - Replace simple_strtoul by kstrtoul New driver: - Epson RX8010SJ Subsystem wide cleanups: - use %ph for short hex dumps - constify *_chip_ops structures Drivers: - abx80x: Microcrystal rv1805 support, alarm support - cmos: prevent kernel warning on IRQ flags mismatch - s5m: various cleanups - rv8803: rx8900 compatibility, small error path fix - sunxi: various cleanups - lpc32xx: remove irq > NR_IRQS check from probe() - imxdi: fix spelling mistake in warning message - ds1685: don't try to micromanage sysfs output size - da9063: avoid writing undefined data to rtc - gemini: Remove unnecessary platform_set_drvdata() - efi: add efi_procfs in efi_rtc_ops - pcf8523: refuse to write dates later than 2099" * tag 'rtc-4.5' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (24 commits) rtc: cmos: prevent kernel warning on IRQ flags mismatch rtc: rtc-ds2404: constify ds2404_chip_ops structures rtc: s5m: Make register configuration per S2MPS device to remove exceptions rtc: s5m: Add separate field for storing auto-cleared mask in register config rtc: s5m: Cleanup by removing useless 'rtc' prefix from fields rtc: Replace simple_strtoul by kstrtoul rtc: abx80x: add alarm support rtc: abx80x: Add Microcrystal rv1805 support rtc: v3020: constify v3020_chip_ops structures rtc: rv8803: Extend compatibility with the rx8900 rtc: rv8803: fix handling return value of i2c_smbus_read_byte_data rtc: Add Epson RX8010SJ RTC driver rtc: lpc32xx: remove irq > NR_IRQS check from probe() rtc: imxdi: fix spelling mistake in warning message rtc: ds1685: don't try to micromanage sysfs output size rtc: use %ph for short hex dumps rtc: da9063: avoid writing undefined data to rtc rtc: sunxi: use of_device_get_match_data rtc: sunxi: constify the data_year_param structure rtc: sunxi: fix signedness issues ...
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig10
-rw-r--r--drivers/rtc/Makefile1
-rw-r--r--drivers/rtc/rtc-abx80x.c146
-rw-r--r--drivers/rtc/rtc-cmos.c2
-rw-r--r--drivers/rtc/rtc-da9063.c23
-rw-r--r--drivers/rtc/rtc-ds1305.c8
-rw-r--r--drivers/rtc/rtc-ds1307.c17
-rw-r--r--drivers/rtc/rtc-ds1685.c22
-rw-r--r--drivers/rtc/rtc-ds2404.c4
-rw-r--r--drivers/rtc/rtc-efi.c66
-rw-r--r--drivers/rtc/rtc-gemini.c1
-rw-r--r--drivers/rtc/rtc-imxdi.c2
-rw-r--r--drivers/rtc/rtc-lpc32xx.c2
-rw-r--r--drivers/rtc/rtc-pcf8523.c11
-rw-r--r--drivers/rtc/rtc-proc.c8
-rw-r--r--drivers/rtc/rtc-rv8803.c3
-rw-r--r--drivers/rtc/rtc-rx8010.c523
-rw-r--r--drivers/rtc/rtc-s5m.c138
-rw-r--r--drivers/rtc/rtc-sunxi.c18
-rw-r--r--drivers/rtc/rtc-sysfs.c11
-rw-r--r--drivers/rtc/rtc-v3020.c6
21 files changed, 892 insertions, 130 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 2a524244afec..376322f71fd5 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -558,6 +558,16 @@ config RTC_DRV_FM3130
This driver can also be built as a module. If so the module
will be called rtc-fm3130.
+config RTC_DRV_RX8010
+ tristate "Epson RX8010SJ"
+ depends on I2C
+ help
+ If you say yes here you get support for the Epson RX8010SJ RTC
+ chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-rx8010.
+
config RTC_DRV_RX8581
tristate "Epson RX-8581"
help
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 231f76451615..62d61b26ca7e 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -128,6 +128,7 @@ obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o
obj-$(CONFIG_RTC_DRV_RV8803) += rtc-rv8803.o
obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o
+obj-$(CONFIG_RTC_DRV_RX8010) += rtc-rx8010.o
obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o
obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o
obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o
diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c
index afea84c7a155..d41bbcd653f6 100644
--- a/drivers/rtc/rtc-abx80x.c
+++ b/drivers/rtc/rtc-abx80x.c
@@ -27,10 +27,28 @@
#define ABX8XX_REG_YR 0x06
#define ABX8XX_REG_WD 0x07
+#define ABX8XX_REG_AHTH 0x08
+#define ABX8XX_REG_ASC 0x09
+#define ABX8XX_REG_AMN 0x0a
+#define ABX8XX_REG_AHR 0x0b
+#define ABX8XX_REG_ADA 0x0c
+#define ABX8XX_REG_AMO 0x0d
+#define ABX8XX_REG_AWD 0x0e
+
+#define ABX8XX_REG_STATUS 0x0f
+#define ABX8XX_STATUS_AF BIT(2)
+
#define ABX8XX_REG_CTRL1 0x10
#define ABX8XX_CTRL_WRITE BIT(0)
+#define ABX8XX_CTRL_ARST BIT(2)
#define ABX8XX_CTRL_12_24 BIT(6)
+#define ABX8XX_REG_IRQ 0x12
+#define ABX8XX_IRQ_AIE BIT(2)
+#define ABX8XX_IRQ_IM_1_4 (0x3 << 5)
+
+#define ABX8XX_REG_CD_TIMER_CTL 0x18
+
#define ABX8XX_REG_CFG_KEY 0x1f
#define ABX8XX_CFG_KEY_MISC 0x9d
@@ -63,8 +81,6 @@ static struct abx80x_cap abx80x_caps[] = {
[ABX80X] = {.pn = 0}
};
-static struct i2c_driver abx80x_driver;
-
static int abx80x_enable_trickle_charger(struct i2c_client *client,
u8 trickle_cfg)
{
@@ -148,9 +164,111 @@ static int abx80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
return 0;
}
+static irqreturn_t abx80x_handle_irq(int irq, void *dev_id)
+{
+ struct i2c_client *client = dev_id;
+ struct rtc_device *rtc = i2c_get_clientdata(client);
+ int status;
+
+ status = i2c_smbus_read_byte_data(client, ABX8XX_REG_STATUS);
+ if (status < 0)
+ return IRQ_NONE;
+
+ if (status & ABX8XX_STATUS_AF)
+ rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF);
+
+ i2c_smbus_write_byte_data(client, ABX8XX_REG_STATUS, 0);
+
+ return IRQ_HANDLED;
+}
+
+static int abx80x_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ unsigned char buf[7];
+
+ int irq_mask, err;
+
+ if (client->irq <= 0)
+ return -EINVAL;
+
+ err = i2c_smbus_read_i2c_block_data(client, ABX8XX_REG_ASC,
+ sizeof(buf), buf);
+ if (err)
+ return err;
+
+ irq_mask = i2c_smbus_read_byte_data(client, ABX8XX_REG_IRQ);
+ if (irq_mask < 0)
+ return irq_mask;
+
+ t->time.tm_sec = bcd2bin(buf[0] & 0x7F);
+ t->time.tm_min = bcd2bin(buf[1] & 0x7F);
+ t->time.tm_hour = bcd2bin(buf[2] & 0x3F);
+ t->time.tm_mday = bcd2bin(buf[3] & 0x3F);
+ t->time.tm_mon = bcd2bin(buf[4] & 0x1F) - 1;
+ t->time.tm_wday = buf[5] & 0x7;
+
+ t->enabled = !!(irq_mask & ABX8XX_IRQ_AIE);
+ t->pending = (buf[6] & ABX8XX_STATUS_AF) && t->enabled;
+
+ return err;
+}
+
+static int abx80x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ u8 alarm[6];
+ int err;
+
+ if (client->irq <= 0)
+ return -EINVAL;
+
+ alarm[0] = 0x0;
+ alarm[1] = bin2bcd(t->time.tm_sec);
+ alarm[2] = bin2bcd(t->time.tm_min);
+ alarm[3] = bin2bcd(t->time.tm_hour);
+ alarm[4] = bin2bcd(t->time.tm_mday);
+ alarm[5] = bin2bcd(t->time.tm_mon + 1);
+
+ err = i2c_smbus_write_i2c_block_data(client, ABX8XX_REG_AHTH,
+ sizeof(alarm), alarm);
+ if (err < 0) {
+ dev_err(&client->dev, "Unable to write alarm registers\n");
+ return -EIO;
+ }
+
+ if (t->enabled) {
+ err = i2c_smbus_write_byte_data(client, ABX8XX_REG_IRQ,
+ (ABX8XX_IRQ_IM_1_4 |
+ ABX8XX_IRQ_AIE));
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int abx80x_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ int err;
+
+ if (enabled)
+ err = i2c_smbus_write_byte_data(client, ABX8XX_REG_IRQ,
+ (ABX8XX_IRQ_IM_1_4 |
+ ABX8XX_IRQ_AIE));
+ else
+ err = i2c_smbus_write_byte_data(client, ABX8XX_REG_IRQ,
+ ABX8XX_IRQ_IM_1_4);
+ return err;
+}
+
static const struct rtc_class_ops abx80x_rtc_ops = {
.read_time = abx80x_rtc_read_time,
.set_time = abx80x_rtc_set_time,
+ .read_alarm = abx80x_read_alarm,
+ .set_alarm = abx80x_set_alarm,
+ .alarm_irq_enable = abx80x_alarm_irq_enable,
};
static int abx80x_dt_trickle_cfg(struct device_node *np)
@@ -225,7 +343,8 @@ static int abx80x_probe(struct i2c_client *client,
}
err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CTRL1,
- ((data & ~ABX8XX_CTRL_12_24) |
+ ((data & ~(ABX8XX_CTRL_12_24 |
+ ABX8XX_CTRL_ARST)) |
ABX8XX_CTRL_WRITE));
if (err < 0) {
dev_err(&client->dev, "Unable to write control register\n");
@@ -260,7 +379,12 @@ static int abx80x_probe(struct i2c_client *client,
abx80x_enable_trickle_charger(client, trickle_cfg);
}
- rtc = devm_rtc_device_register(&client->dev, abx80x_driver.driver.name,
+ err = i2c_smbus_write_byte_data(client, ABX8XX_REG_CD_TIMER_CTL,
+ BIT(2));
+ if (err)
+ return err;
+
+ rtc = devm_rtc_device_register(&client->dev, "abx8xx",
&abx80x_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
@@ -268,6 +392,19 @@ static int abx80x_probe(struct i2c_client *client,
i2c_set_clientdata(client, rtc);
+ if (client->irq > 0) {
+ dev_info(&client->dev, "IRQ %d supplied\n", client->irq);
+ err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+ abx80x_handle_irq,
+ IRQF_SHARED | IRQF_ONESHOT,
+ "abx8xx",
+ client);
+ if (err) {
+ dev_err(&client->dev, "unable to request IRQ, alarms disabled\n");
+ client->irq = 0;
+ }
+ }
+
return 0;
}
@@ -286,6 +423,7 @@ static const struct i2c_device_id abx80x_id[] = {
{ "ab1803", AB1803 },
{ "ab1804", AB1804 },
{ "ab1805", AB1805 },
+ { "rv1805", AB1805 },
{ }
};
MODULE_DEVICE_TABLE(i2c, abx80x_id);
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index 8f7034ba7d9e..84fb541038be 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -725,7 +725,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
rtc_cmos_int_handler = cmos_interrupt;
retval = request_irq(rtc_irq, rtc_cmos_int_handler,
- 0, dev_name(&cmos_rtc.rtc->dev),
+ IRQF_SHARED, dev_name(&cmos_rtc.rtc->dev),
cmos_rtc.rtc);
if (retval < 0) {
dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c
index d6c853bbfa9f..f85cae240f12 100644
--- a/drivers/rtc/rtc-da9063.c
+++ b/drivers/rtc/rtc-da9063.c
@@ -191,24 +191,13 @@ static void da9063_tm_to_data(struct rtc_time *tm, u8 *data,
{
const struct da9063_compatible_rtc_regmap *config = rtc->config;
- data[RTC_SEC] &= ~config->rtc_count_sec_mask;
- data[RTC_SEC] |= tm->tm_sec & config->rtc_count_sec_mask;
-
- data[RTC_MIN] &= ~config->rtc_count_min_mask;
- data[RTC_MIN] |= tm->tm_min & config->rtc_count_min_mask;
-
- data[RTC_HOUR] &= ~config->rtc_count_hour_mask;
- data[RTC_HOUR] |= tm->tm_hour & config->rtc_count_hour_mask;
-
- data[RTC_DAY] &= ~config->rtc_count_day_mask;
- data[RTC_DAY] |= tm->tm_mday & config->rtc_count_day_mask;
-
- data[RTC_MONTH] &= ~config->rtc_count_month_mask;
- data[RTC_MONTH] |= MONTHS_TO_DA9063(tm->tm_mon) &
+ data[RTC_SEC] = tm->tm_sec & config->rtc_count_sec_mask;
+ data[RTC_MIN] = tm->tm_min & config->rtc_count_min_mask;
+ data[RTC_HOUR] = tm->tm_hour & config->rtc_count_hour_mask;
+ data[RTC_DAY] = tm->tm_mday & config->rtc_count_day_mask;
+ data[RTC_MONTH] = MONTHS_TO_DA9063(tm->tm_mon) &
config->rtc_count_month_mask;
-
- data[RTC_YEAR] &= ~config->rtc_count_year_mask;
- data[RTC_YEAR] |= YEARS_TO_DA9063(tm->tm_year) &
+ data[RTC_YEAR] = YEARS_TO_DA9063(tm->tm_year) &
config->rtc_count_year_mask;
}
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c
index 85706a9f82c9..f39691eea736 100644
--- a/drivers/rtc/rtc-ds1305.c
+++ b/drivers/rtc/rtc-ds1305.c
@@ -186,9 +186,7 @@ static int ds1305_get_time(struct device *dev, struct rtc_time *time)
if (status < 0)
return status;
- dev_vdbg(dev, "%s: %02x %02x %02x, %02x %02x %02x %02x\n",
- "read", buf[0], buf[1], buf[2], buf[3],
- buf[4], buf[5], buf[6]);
+ dev_vdbg(dev, "%s: %3ph, %4ph\n", "read", &buf[0], &buf[3]);
/* Decode the registers */
time->tm_sec = bcd2bin(buf[DS1305_SEC]);
@@ -232,9 +230,7 @@ static int ds1305_set_time(struct device *dev, struct rtc_time *time)
*bp++ = bin2bcd(time->tm_mon + 1);
*bp++ = bin2bcd(time->tm_year - 100);
- dev_dbg(dev, "%s: %02x %02x %02x, %02x %02x %02x %02x\n",
- "write", buf[1], buf[2], buf[3],
- buf[4], buf[5], buf[6], buf[7]);
+ dev_dbg(dev, "%s: %3ph, %4ph\n", "write", &buf[1], &buf[4]);
/* use write-then-read since dma from stack is nonportable */
return spi_write_then_read(ds1305->spi, buf, sizeof(buf),
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index aa705bb4748c..cf685f67b391 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -460,13 +460,8 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
return -EIO;
}
- dev_dbg(dev, "%s: %02x %02x %02x %02x, %02x %02x %02x, %02x %02x\n",
- "alarm read",
- ds1307->regs[0], ds1307->regs[1],
- ds1307->regs[2], ds1307->regs[3],
- ds1307->regs[4], ds1307->regs[5],
- ds1307->regs[6], ds1307->regs[7],
- ds1307->regs[8]);
+ dev_dbg(dev, "%s: %4ph, %3ph, %2ph\n", "alarm read",
+ &ds1307->regs[0], &ds1307->regs[4], &ds1307->regs[7]);
/*
* report alarm time (ALARM1); assume 24 hour and day-of-month modes,
@@ -522,12 +517,8 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
control = ds1307->regs[7];
status = ds1307->regs[8];
- dev_dbg(dev, "%s: %02x %02x %02x %02x, %02x %02x %02x, %02x %02x\n",
- "alarm set (old status)",
- ds1307->regs[0], ds1307->regs[1],
- ds1307->regs[2], ds1307->regs[3],
- ds1307->regs[4], ds1307->regs[5],
- ds1307->regs[6], control, status);
+ dev_dbg(dev, "%s: %4ph, %3ph, %02x %02x\n", "alarm set (old status)",
+ &ds1307->regs[0], &ds1307->regs[4], control, status);
/* set ALARM1, using 24 hour and day-of-month modes */
buf[0] = bin2bcd(t->time.tm_sec);
diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c
index 05a51ef52703..535050fc5e9f 100644
--- a/drivers/rtc/rtc-ds1685.c
+++ b/drivers/rtc/rtc-ds1685.c
@@ -853,7 +853,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
"Periodic Rate\t: %s\n"
"SQW Freq\t: %s\n"
#ifdef CONFIG_RTC_DS1685_PROC_REGS
- "Serial #\t: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"
+ "Serial #\t: %8phC\n"
"Register Status\t:\n"
" Ctrl A\t: UIP DV2 DV1 DV0 RS3 RS2 RS1 RS0\n"
"\t\t: %s\n"
@@ -872,7 +872,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
" Ctrl 4B\t: ABE E32k CS RCE PRS RIE WIE KSE\n"
"\t\t: %s\n",
#else
- "Serial #\t: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ "Serial #\t: %8phC\n",
#endif
model,
((ctrla & RTC_CTRL_A_DV1) ? "enabled" : "disabled"),
@@ -888,7 +888,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
(!((ctrl4b & RTC_CTRL_4B_E32K)) ?
ds1685_rtc_sqw_freq[(ctrla & RTC_CTRL_A_RS_MASK)] : "32768Hz"),
#ifdef CONFIG_RTC_DS1685_PROC_REGS
- ssn[0], ssn[1], ssn[2], ssn[3], ssn[4], ssn[5], ssn[6], ssn[7],
+ ssn,
ds1685_rtc_print_regs(ctrla, bits[0]),
ds1685_rtc_print_regs(ctrlb, bits[1]),
ds1685_rtc_print_regs(ctrlc, bits[2]),
@@ -896,7 +896,7 @@ ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
ds1685_rtc_print_regs(ctrl4a, bits[4]),
ds1685_rtc_print_regs(ctrl4b, bits[5]));
#else
- ssn[0], ssn[1], ssn[2], ssn[3], ssn[4], ssn[5], ssn[6], ssn[7]);
+ ssn);
#endif
return 0;
}
@@ -1114,7 +1114,7 @@ ds1685_rtc_sysfs_battery_show(struct device *dev,
ctrld = rtc->read(rtc, RTC_CTRL_D);
- return snprintf(buf, 13, "%s\n",
+ return sprintf(buf, "%s\n",
(ctrld & RTC_CTRL_D_VRT) ? "ok" : "not ok or N/A");
}
static DEVICE_ATTR(battery, S_IRUGO, ds1685_rtc_sysfs_battery_show, NULL);
@@ -1137,7 +1137,7 @@ ds1685_rtc_sysfs_auxbatt_show(struct device *dev,
ctrl4a = rtc->read(rtc, RTC_EXT_CTRL_4A);
ds1685_rtc_switch_to_bank0(rtc);
- return snprintf(buf, 13, "%s\n",
+ return sprintf(buf, "%s\n",
(ctrl4a & RTC_CTRL_4A_VRT2) ? "ok" : "not ok or N/A");
}
static DEVICE_ATTR(auxbatt, S_IRUGO, ds1685_rtc_sysfs_auxbatt_show, NULL);
@@ -1160,11 +1160,7 @@ ds1685_rtc_sysfs_serial_show(struct device *dev,
ds1685_rtc_get_ssn(rtc, ssn);
ds1685_rtc_switch_to_bank0(rtc);
- return snprintf(buf, 24, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
- ssn[0], ssn[1], ssn[2], ssn[3], ssn[4], ssn[5],
- ssn[6], ssn[7]);
-
- return 0;
+ return sprintf(buf, "%8phC\n", ssn);
}
static DEVICE_ATTR(serial, S_IRUGO, ds1685_rtc_sysfs_serial_show, NULL);
@@ -1287,7 +1283,7 @@ ds1685_rtc_sysfs_ctrl_regs_show(struct device *dev,
tmp = rtc->read(rtc, reg_info->reg) & reg_info->bit;
ds1685_rtc_switch_to_bank0(rtc);
- return snprintf(buf, 2, "%d\n", (tmp ? 1 : 0));
+ return sprintf(buf, "%d\n", (tmp ? 1 : 0));
}
/**
@@ -1623,7 +1619,7 @@ ds1685_rtc_sysfs_time_regs_show(struct device *dev,
tmp = ds1685_rtc_bcd2bin(rtc, tmp, bcd_reg_info->mask,
bin_reg_info->mask);
- return snprintf(buf, 4, "%d\n", tmp);
+ return sprintf(buf, "%d\n", tmp);
}
/**
diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c
index 7885edd3d507..16310fe79d76 100644
--- a/drivers/rtc/rtc-ds2404.c
+++ b/drivers/rtc/rtc-ds2404.c
@@ -48,7 +48,7 @@ struct ds2404_gpio {
struct ds2404 {
struct ds2404_gpio *gpio;
- struct ds2404_chip_ops *ops;
+ const struct ds2404_chip_ops *ops;
struct rtc_device *rtc;
};
@@ -95,7 +95,7 @@ static void ds2404_gpio_unmap(struct ds2404 *chip)
gpio_free(ds2404_gpio[i].gpio);
}
-static struct ds2404_chip_ops ds2404_gpio_ops = {
+static const struct ds2404_chip_ops ds2404_gpio_ops = {
.map_io = ds2404_gpio_map,
.unmap_io = ds2404_gpio_unmap,
};
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
index 3806961b4348..96d38609d803 100644
--- a/drivers/rtc/rtc-efi.c
+++ b/drivers/rtc/rtc-efi.c
@@ -191,11 +191,69 @@ static int efi_set_time(struct device *dev, struct rtc_time *tm)
return status == EFI_SUCCESS ? 0 : -EINVAL;
}
+static int efi_procfs(struct device *dev, struct seq_file *seq)
+{
+ efi_time_t eft, alm;
+ efi_time_cap_t cap;
+ efi_bool_t enabled, pending;
+
+ memset(&eft, 0, sizeof(eft));
+ memset(&alm, 0, sizeof(alm));
+ memset(&cap, 0, sizeof(cap));
+
+ efi.get_time(&eft, &cap);
+ efi.get_wakeup_time(&enabled, &pending, &alm);
+
+ seq_printf(seq,
+ "Time\t\t: %u:%u:%u.%09u\n"
+ "Date\t\t: %u-%u-%u\n"
+ "Daylight\t: %u\n",
+ eft.hour, eft.minute, eft.second, eft.nanosecond,
+ eft.year, eft.month, eft.day,
+ eft.daylight);
+
+ if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
+ seq_puts(seq, "Timezone\t: unspecified\n");
+ else
+ /* XXX fixme: convert to string? */
+ seq_printf(seq, "Timezone\t: %u\n", eft.timezone);
+
+ seq_printf(seq,
+ "Alarm Time\t: %u:%u:%u.%09u\n"
+ "Alarm Date\t: %u-%u-%u\n"
+ "Alarm Daylight\t: %u\n"
+ "Enabled\t\t: %s\n"
+ "Pending\t\t: %s\n",
+ alm.hour, alm.minute, alm.second, alm.nanosecond,
+ alm.year, alm.month, alm.day,
+ alm.daylight,
+ enabled == 1 ? "yes" : "no",
+ pending == 1 ? "yes" : "no");
+
+ if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
+ seq_puts(seq, "Timezone\t: unspecified\n");
+ else
+ /* XXX fixme: convert to string? */
+ seq_printf(seq, "Timezone\t: %u\n", alm.timezone);
+
+ /*
+ * now prints the capabilities
+ */
+ seq_printf(seq,
+ "Resolution\t: %u\n"
+ "Accuracy\t: %u\n"
+ "SetstoZero\t: %u\n",
+ cap.resolution, cap.accuracy, cap.sets_to_zero);
+
+ return 0;
+}
+
static const struct rtc_class_ops efi_rtc_ops = {
- .read_time = efi_read_time,
- .set_time = efi_set_time,
- .read_alarm = efi_read_alarm,
- .set_alarm = efi_set_alarm,
+ .read_time = efi_read_time,
+ .set_time = efi_set_time,
+ .read_alarm = efi_read_alarm,
+ .set_alarm = efi_set_alarm,
+ .proc = efi_procfs,
};
static int __init efi_rtc_probe(struct platform_device *dev)
diff --git a/drivers/rtc/rtc-gemini.c b/drivers/rtc/rtc-gemini.c
index e84184647d15..f46b6d46a51b 100644
--- a/drivers/rtc/rtc-gemini.c
+++ b/drivers/rtc/rtc-gemini.c
@@ -156,7 +156,6 @@ static int gemini_rtc_remove(struct platform_device *pdev)
struct gemini_rtc *rtc = platform_get_drvdata(pdev);
rtc_device_unregister(rtc->rtc_dev);
- platform_set_drvdata(pdev, NULL);
return 0;
}
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c
index 7bffd7f0e306..8d8049bdfaf6 100644
--- a/drivers/rtc/rtc-imxdi.c
+++ b/drivers/rtc/rtc-imxdi.c
@@ -303,7 +303,7 @@ static int di_handle_invalid_state(struct imxdi_dev *imxdi, u32 dsr)
sec = readl(imxdi->ioaddr + DTCMR);
if (sec != 0)
dev_warn(&imxdi->pdev->dev,
- "The security violation has happend at %u seconds\n",
+ "The security violation has happened at %u seconds\n",
sec);
/*
* the timer cannot be set/modified if
diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c
index f923f7324788..887871c3d526 100644
--- a/drivers/rtc/rtc-lpc32xx.c
+++ b/drivers/rtc/rtc-lpc32xx.c
@@ -205,7 +205,7 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev)
u32 tmp;
rtcirq = platform_get_irq(pdev, 0);
- if (rtcirq < 0 || rtcirq >= NR_IRQS) {
+ if (rtcirq < 0) {
dev_warn(&pdev->dev, "Can't get interrupt resource\n");
rtcirq = -1;
}
diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c
index e7ebcc0b7e59..988566caaaa6 100644
--- a/drivers/rtc/rtc-pcf8523.c
+++ b/drivers/rtc/rtc-pcf8523.c
@@ -219,6 +219,17 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm)
u8 regs[8];
int err;
+ /*
+ * The hardware can only store values between 0 and 99 in it's YEAR
+ * register (with 99 overflowing to 0 on increment).
+ * After 2100-02-28 we could start interpreting the year to be in the
+ * interval [2100, 2199], but there is no path to switch in a smooth way
+ * because the chip handles YEAR=0x00 (and the out-of-spec
+ * YEAR=0xa0) as a leap year, but 2100 isn't.
+ */
+ if (tm->tm_year < 100 || tm->tm_year >= 200)
+ return -EINVAL;
+
err = pcf8523_stop_rtc(client);
if (err < 0)
return err;
diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c
index ffa69e1c9245..31e7e23cc5be 100644
--- a/drivers/rtc/rtc-proc.c
+++ b/drivers/rtc/rtc-proc.c
@@ -112,19 +112,21 @@ static int rtc_proc_open(struct inode *inode, struct file *file)
int ret;
struct rtc_device *rtc = PDE_DATA(inode);
- if (!try_module_get(THIS_MODULE))
+ if (!try_module_get(rtc->owner))
return -ENODEV;
ret = single_open(file, rtc_proc_show, rtc);
if (ret)
- module_put(THIS_MODULE);
+ module_put(rtc->owner);
return ret;
}
static int rtc_proc_release(struct inode *inode, struct file *file)
{
int res = single_release(inode, file);
- module_put(THIS_MODULE);
+ struct rtc_device *rtc = PDE_DATA(inode);
+
+ module_put(rtc->owner);
return res;
}
diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c
index e7329e21bfe3..7155c0816aa6 100644
--- a/drivers/rtc/rtc-rv8803.c
+++ b/drivers/rtc/rtc-rv8803.c
@@ -61,7 +61,7 @@ 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;
- u8 flags;
+ int flags;
spin_lock(&rv8803->flags_lock);
@@ -502,6 +502,7 @@ static int rv8803_remove(struct i2c_client *client)
static const struct i2c_device_id rv8803_id[] = {
{ "rv8803", 0 },
+ { "rx8900", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rv8803_id);
diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c
new file mode 100644
index 000000000000..772d221ec2d9
--- /dev/null
+++ b/drivers/rtc/rtc-rx8010.c
@@ -0,0 +1,523 @@
+/*
+ * Driver for the Epson RTC module RX-8010 SJ
+ *
+ * Copyright(C) Timesys Corporation 2015
+ * Copyright(C) General Electric Company 2015
+ *
+ * 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/bcd.h>
+#include <linux/bitops.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/rtc.h>
+
+#define RX8010_SEC 0x10
+#define RX8010_MIN 0x11
+#define RX8010_HOUR 0x12
+#define RX8010_WDAY 0x13
+#define RX8010_MDAY 0x14
+#define RX8010_MONTH 0x15
+#define RX8010_YEAR 0x16
+#define RX8010_YEAR 0x16
+#define RX8010_RESV17 0x17
+#define RX8010_ALMIN 0x18
+#define RX8010_ALHOUR 0x19
+#define RX8010_ALWDAY 0x1A
+#define RX8010_TCOUNT0 0x1B
+#define RX8010_TCOUNT1 0x1C
+#define RX8010_EXT 0x1D
+#define RX8010_FLAG 0x1E
+#define RX8010_CTRL 0x1F
+/* 0x20 to 0x2F are user registers */
+#define RX8010_RESV30 0x30
+#define RX8010_RESV31 0x32
+#define RX8010_IRQ 0x32
+
+#define RX8010_EXT_WADA BIT(3)
+
+#define RX8010_FLAG_VLF BIT(1)
+#define RX8010_FLAG_AF BIT(3)
+#define RX8010_FLAG_TF BIT(4)
+#define RX8010_FLAG_UF BIT(5)
+
+#define RX8010_CTRL_AIE BIT(3)
+#define RX8010_CTRL_UIE BIT(5)
+#define RX8010_CTRL_STOP BIT(6)
+#define RX8010_CTRL_TEST BIT(7)
+
+#define RX8010_ALARM_AE BIT(7)
+
+static const struct i2c_device_id rx8010_id[] = {
+ { "rx8010", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rx8010_id);
+
+struct rx8010_data {
+ struct i2c_client *client;
+ struct rtc_device *rtc;
+ u8 ctrlreg;
+ spinlock_t flags_lock;
+};
+
+static irqreturn_t rx8010_irq_1_handler(int irq, void *dev_id)
+{
+ struct i2c_client *client = dev_id;
+ struct rx8010_data *rx8010 = i2c_get_clientdata(client);
+ int flagreg;
+
+ spin_lock(&rx8010->flags_lock);
+
+ flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG);
+
+ if (flagreg <= 0) {
+ spin_unlock(&rx8010->flags_lock);
+ return IRQ_NONE;
+ }
+
+ if (flagreg & RX8010_FLAG_VLF)
+ dev_warn(&client->dev, "Frequency stop detected\n");
+
+ if (flagreg & RX8010_FLAG_TF) {
+ flagreg &= ~RX8010_FLAG_TF;
+ rtc_update_irq(rx8010->rtc, 1, RTC_PF | RTC_IRQF);
+ }
+
+ if (flagreg & RX8010_FLAG_AF) {
+ flagreg &= ~RX8010_FLAG_AF;
+ rtc_update_irq(rx8010->rtc, 1, RTC_AF | RTC_IRQF);
+ }
+
+ if (flagreg & RX8010_FLAG_UF) {
+ flagreg &= ~RX8010_FLAG_UF;
+ rtc_update_irq(rx8010->rtc, 1, RTC_UF | RTC_IRQF);
+ }
+
+ i2c_smbus_write_byte_data(client, RX8010_FLAG, flagreg);
+
+ spin_unlock(&rx8010->flags_lock);
+ return IRQ_HANDLED;
+}
+
+static int rx8010_get_time(struct device *dev, struct rtc_time *dt)
+{
+ struct rx8010_data *rx8010 = dev_get_drvdata(dev);
+ u8 date[7];
+ int flagreg;
+ int err;
+
+ flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG);
+ if (flagreg < 0)
+ return flagreg;
+
+ if (flagreg & RX8010_FLAG_VLF) {
+ dev_warn(dev, "Frequency stop detected\n");
+ return -EINVAL;
+ }
+
+ err = i2c_smbus_read_i2c_block_data(rx8010->client, RX8010_SEC,
+ 7, date);
+ if (err != 7)
+ return err < 0 ? err : -EIO;
+
+ dt->tm_sec = bcd2bin(date[RX8010_SEC - RX8010_SEC] & 0x7f);
+ dt->tm_min = bcd2bin(date[RX8010_MIN - RX8010_SEC] & 0x7f);
+ dt->tm_hour = bcd2bin(date[RX8010_HOUR - RX8010_SEC] & 0x3f);
+ dt->tm_mday = bcd2bin(date[RX8010_MDAY - RX8010_SEC] & 0x3f);
+ dt->tm_mon = bcd2bin(date[RX8010_MONTH - RX8010_SEC] & 0x1f) - 1;
+ dt->tm_year = bcd2bin(date[RX8010_YEAR - RX8010_SEC]) + 100;
+ dt->tm_wday = ffs(date[RX8010_WDAY - RX8010_SEC] & 0x7f);
+
+ return rtc_valid_tm(dt);
+}
+
+static int rx8010_set_time(struct device *dev, struct rtc_time *dt)
+{
+ struct rx8010_data *rx8010 = dev_get_drvdata(dev);
+ u8 date[7];
+ int ctrl, flagreg;
+ int ret;
+ unsigned long irqflags;
+
+ if ((dt->tm_year < 100) || (dt->tm_year > 199))
+ return -EINVAL;
+
+ /* set STOP bit before changing clock/calendar */
+ ctrl = i2c_smbus_read_byte_data(rx8010->client, RX8010_CTRL);
+ if (ctrl < 0)
+ return ctrl;
+ rx8010->ctrlreg = ctrl | RX8010_CTRL_STOP;
+ ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL,
+ rx8010->ctrlreg);
+ if (ret < 0)
+ return ret;
+
+ date[RX8010_SEC - RX8010_SEC] = bin2bcd(dt->tm_sec);
+ date[RX8010_MIN - RX8010_SEC] = bin2bcd(dt->tm_min);
+ date[RX8010_HOUR - RX8010_SEC] = bin2bcd(dt->tm_hour);
+ date[RX8010_MDAY - RX8010_SEC] = bin2bcd(dt->tm_mday);
+ date[RX8010_MONTH - RX8010_SEC] = bin2bcd(dt->tm_mon + 1);
+ date[RX8010_YEAR - RX8010_SEC] = bin2bcd(dt->tm_year - 100);
+ date[RX8010_WDAY - RX8010_SEC] = bin2bcd(1 << dt->tm_wday);
+
+ ret = i2c_smbus_write_i2c_block_data(rx8010->client,
+ RX8010_SEC, 7, date);
+ if (ret < 0)
+ return ret;
+
+ /* clear STOP bit after changing clock/calendar */
+ ctrl = i2c_smbus_read_byte_data(rx8010->client, RX8010_CTRL);
+ if (ctrl < 0)
+ return ctrl;
+ rx8010->ctrlreg = ctrl & ~RX8010_CTRL_STOP;
+ ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL,
+ rx8010->ctrlreg);
+ if (ret < 0)
+ return ret;
+
+ spin_lock_irqsave(&rx8010->flags_lock, irqflags);
+
+ flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG);
+ if (flagreg < 0) {
+ spin_unlock_irqrestore(&rx8010->flags_lock, irqflags);
+ return flagreg;
+ }
+
+ if (flagreg & RX8010_FLAG_VLF)
+ ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG,
+ flagreg & ~RX8010_FLAG_VLF);
+
+ spin_unlock_irqrestore(&rx8010->flags_lock, irqflags);
+
+ return 0;
+}
+
+static int rx8010_init_client(struct i2c_client *client)
+{
+ struct rx8010_data *rx8010 = i2c_get_clientdata(client);
+ u8 ctrl[2];
+ int need_clear = 0, err = 0;
+
+ /* Initialize reserved registers as specified in datasheet */
+ err = i2c_smbus_write_byte_data(client, RX8010_RESV17, 0xD8);
+ if (err < 0)
+ return err;
+
+ err = i2c_smbus_write_byt