diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-18 12:10:45 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-01-18 12:10:45 -0800 |
commit | c38dec71664dadb15094151f53886abb69f8f9e6 (patch) | |
tree | afd6aaa893cd4d7d740679826c7f0c252764e4c8 /drivers/rtc | |
parent | d43fb9f3c5dff281dd72bea5cd2e91386fdc33a8 (diff) | |
parent | 079062b28fb4c58e30d024fdf974e00de53158fd (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/Kconfig | 10 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-abx80x.c | 146 | ||||
-rw-r--r-- | drivers/rtc/rtc-cmos.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-da9063.c | 23 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1305.c | 8 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1307.c | 17 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1685.c | 22 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds2404.c | 4 | ||||
-rw-r--r-- | drivers/rtc/rtc-efi.c | 66 | ||||
-rw-r--r-- | drivers/rtc/rtc-gemini.c | 1 | ||||
-rw-r--r-- | drivers/rtc/rtc-imxdi.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-lpc32xx.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-pcf8523.c | 11 | ||||
-rw-r--r-- | drivers/rtc/rtc-proc.c | 8 | ||||
-rw-r--r-- | drivers/rtc/rtc-rv8803.c | 3 | ||||
-rw-r--r-- | drivers/rtc/rtc-rx8010.c | 523 | ||||
-rw-r--r-- | drivers/rtc/rtc-s5m.c | 138 | ||||
-rw-r--r-- | drivers/rtc/rtc-sunxi.c | 18 | ||||
-rw-r--r-- | drivers/rtc/rtc-sysfs.c | 11 | ||||
-rw-r--r-- | drivers/rtc/rtc-v3020.c | 6 |
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 |