diff options
Diffstat (limited to 'drivers/rtc')
89 files changed, 1239 insertions, 425 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index b682651b5307..f15cddfeb897 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -192,6 +192,14 @@ config RTC_DRV_DS1374 This driver can also be built as a module. If so, the module will be called rtc-ds1374. +config RTC_DRV_DS1374_WDT + bool "Dallas/Maxim DS1374 watchdog timer" + depends on RTC_DRV_DS1374 + help + If you say Y here you will get support for the + watchdog timer in the Dallas Semiconductor DS1374 + real-time clock chips. + config RTC_DRV_DS1672 tristate "Dallas/Maxim DS1672" help @@ -979,6 +987,17 @@ config RTC_DRV_NUC900 If you say yes here you get support for the RTC subsystem of the NUC910/NUC920 used in embedded systems. +config RTC_DRV_OPAL + tristate "IBM OPAL RTC driver" + depends on PPC_POWERNV + default y + help + If you say yes here you get support for the PowerNV platform RTC + driver based on OPAL interfaces. + + This driver can also be built as a module. If so, the module + will be called rtc-opal. + comment "on-CPU RTC drivers" config RTC_DRV_DAVINCI diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index b188323c096a..c8ef3e1e6ccd 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -92,6 +92,7 @@ obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o +obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 38e26be705be..472a5adc4642 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -45,14 +45,14 @@ int rtc_hctosys_ret = -ENODEV; * system's wall clock; restore it on resume(). */ -static struct timespec old_rtc, old_system, old_delta; +static struct timespec64 old_rtc, old_system, old_delta; static int rtc_suspend(struct device *dev) { struct rtc_device *rtc = to_rtc_device(dev); struct rtc_time tm; - struct timespec delta, delta_delta; + struct timespec64 delta, delta_delta; int err; if (has_persistent_clock()) @@ -68,8 +68,8 @@ static int rtc_suspend(struct device *dev) return 0; } - getnstimeofday(&old_system); - rtc_tm_to_time(&tm, &old_rtc.tv_sec); + getnstimeofday64(&old_system); + old_rtc.tv_sec = rtc_tm_to_time64(&tm); /* @@ -78,8 +78,8 @@ static int rtc_suspend(struct device *dev) * try to compensate so the difference in system time * and rtc time stays close to constant. */ - delta = timespec_sub(old_system, old_rtc); - delta_delta = timespec_sub(delta, old_delta); + delta = timespec64_sub(old_system, old_rtc); + delta_delta = timespec64_sub(delta, old_delta); if (delta_delta.tv_sec < -2 || delta_delta.tv_sec >= 2) { /* * if delta_delta is too large, assume time correction @@ -88,7 +88,7 @@ static int rtc_suspend(struct device *dev) old_delta = delta; } else { /* Otherwise try to adjust old_system to compensate */ - old_system = timespec_sub(old_system, delta_delta); + old_system = timespec64_sub(old_system, delta_delta); } return 0; @@ -98,8 +98,8 @@ static int rtc_resume(struct device *dev) { struct rtc_device *rtc = to_rtc_device(dev); struct rtc_time tm; - struct timespec new_system, new_rtc; - struct timespec sleep_time; + struct timespec64 new_system, new_rtc; + struct timespec64 sleep_time; int err; if (has_persistent_clock()) @@ -110,7 +110,7 @@ static int rtc_resume(struct device *dev) return 0; /* snapshot the current rtc and system time at resume */ - getnstimeofday(&new_system); + getnstimeofday64(&new_system); err = rtc_read_time(rtc, &tm); if (err < 0) { pr_debug("%s: fail to read rtc time\n", dev_name(&rtc->dev)); @@ -121,7 +121,7 @@ static int rtc_resume(struct device *dev) pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev)); return 0; } - rtc_tm_to_time(&tm, &new_rtc.tv_sec); + new_rtc.tv_sec = rtc_tm_to_time64(&tm); new_rtc.tv_nsec = 0; if (new_rtc.tv_sec < old_rtc.tv_sec) { @@ -130,7 +130,7 @@ static int rtc_resume(struct device *dev) } /* calculate the RTC time delta (sleep time)*/ - sleep_time = timespec_sub(new_rtc, old_rtc); + sleep_time = timespec64_sub(new_rtc, old_rtc); /* * Since these RTC suspend/resume handlers are not called @@ -139,11 +139,11 @@ static int rtc_resume(struct device *dev) * so subtract kernel run-time between rtc_suspend to rtc_resume * to keep things accurate. */ - sleep_time = timespec_sub(sleep_time, - timespec_sub(new_system, old_system)); + sleep_time = timespec64_sub(sleep_time, + timespec64_sub(new_system, old_system)); if (sleep_time.tv_sec >= 0) - timekeeping_inject_sleeptime(&sleep_time); + timekeeping_inject_sleeptime64(&sleep_time); rtc_hctosys_ret = 0; return 0; } diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 5b2717f5dafa..45bfc28ee3aa 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -30,6 +30,14 @@ static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) else { memset(tm, 0, sizeof(struct rtc_time)); err = rtc->ops->read_time(rtc->dev.parent, tm); + if (err < 0) { + dev_err(&rtc->dev, "read_time: fail to read\n"); + return err; + } + + err = rtc_valid_tm(tm); + if (err < 0) + dev_err(&rtc->dev, "read_time: rtc_time isn't valid\n"); } return err; } @@ -891,11 +899,24 @@ again: if (next) { struct rtc_wkalrm alarm; int err; + int retry = 3; + alarm.time = rtc_ktime_to_tm(next->expires); alarm.enabled = 1; +reprogram: err = __rtc_set_alarm(rtc, &alarm); if (err == -ETIME) goto again; + else if (err) { + if (retry-- > 0) + goto reprogram; + + timer = container_of(next, struct rtc_timer, node); + timerqueue_del(&rtc->timerqueue, &timer->node); + timer->enabled = 0; + dev_err(&rtc->dev, "__rtc_set_alarm: err=%d\n", err); + goto again; + } } else rtc_alarm_disable(rtc); diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c index 0916089c7c3e..7df0579d9852 100644 --- a/drivers/rtc/rtc-88pm80x.c +++ b/drivers/rtc/rtc-88pm80x.c @@ -352,7 +352,6 @@ static int pm80x_rtc_remove(struct platform_device *pdev) static struct platform_driver pm80x_rtc_driver = { .driver = { .name = "88pm80x-rtc", - .owner = THIS_MODULE, .pm = &pm80x_rtc_pm_ops, }, .probe = pm80x_rtc_probe, diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index 0c6add1a38dc..19e53b3b8e00 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -448,7 +448,6 @@ static SIMPLE_DEV_PM_OPS(pm860x_rtc_pm_ops, pm860x_rtc_suspend, pm860x_rtc_resum static struct platform_driver pm860x_rtc_driver = { .driver = { .name = "88pm860x-rtc", - .owner = THIS_MODULE, .pm = &pm860x_rtc_pm_ops, }, .probe = pm860x_rtc_probe, diff --git a/drivers/rtc/rtc-ab3100.c b/drivers/rtc/rtc-ab3100.c index ff435343ba9f..1d0340fdb820 100644 --- a/drivers/rtc/rtc-ab3100.c +++ b/drivers/rtc/rtc-ab3100.c @@ -243,7 +243,6 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev) static struct platform_driver ab3100_rtc_driver = { .driver = { .name = "ab3100-rtc", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 727e2f5d14d9..6856f0a3a3d5 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -504,6 +504,8 @@ static int ab8500_rtc_probe(struct platform_device *pdev) return err; } + rtc->uie_unsupported = 1; + return 0; } @@ -517,7 +519,6 @@ static int ab8500_rtc_remove(struct platform_device *pdev) static struct platform_driver ab8500_rtc_driver = { .driver = { .name = "ab8500-rtc", - .owner = THIS_MODULE, }, .probe = ab8500_rtc_probe, .remove = ab8500_rtc_remove, diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c index aee3387fb099..d618d6c7ef93 100644 --- a/drivers/rtc/rtc-at32ap700x.c +++ b/drivers/rtc/rtc-at32ap700x.c @@ -277,7 +277,6 @@ static struct platform_driver at32_rtc_driver = { .remove = __exit_p(at32_rtc_remove), .driver = { .name = "at32ap700x_rtc", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 44fe83ee9bee..70a5d94cc766 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -491,7 +491,6 @@ static struct platform_driver at91_rtc_driver = { .shutdown = at91_rtc_shutdown, .driver = { .name = "at91_rtc", - .owner = THIS_MODULE, .pm = &at91_rtc_pm_ops, .of_match_table = of_match_ptr(at91_rtc_dt_ids), }, diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index abac38abd38e..6b9aaf1afc72 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -525,7 +525,6 @@ static struct platform_driver at91_rtc_driver = { .shutdown = at91_rtc_shutdown, .driver = { .name = "rtc-at91sam9", - .owner = THIS_MODULE, .pm = &at91_rtc_pm_ops, .of_match_table = of_match_ptr(at91_rtc_dt_ids), }, diff --git a/drivers/rtc/rtc-au1xxx.c b/drivers/rtc/rtc-au1xxx.c index fd25e2374d4e..84d6e026784d 100644 --- a/drivers/rtc/rtc-au1xxx.c +++ b/drivers/rtc/rtc-au1xxx.c @@ -117,7 +117,6 @@ out_err: static struct platform_driver au1xrtc_driver = { .driver = { .name = "rtc-au1xxx", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index fe4bdb06a55a..3d44b11721ea 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -434,7 +434,6 @@ static SIMPLE_DEV_PM_OPS(bfin_rtc_pm_ops, bfin_rtc_suspend, bfin_rtc_resume); static struct platform_driver bfin_rtc_driver = { .driver = { .name = "rtc-bfin", - .owner = THIS_MODULE, .pm = &bfin_rtc_pm_ops, }, .probe = bfin_rtc_probe, diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c index fc0ff87aa5df..bd170cb3361c 100644 --- a/drivers/rtc/rtc-bq4802.c +++ b/drivers/rtc/rtc-bq4802.c @@ -192,7 +192,6 @@ MODULE_ALIAS("platform:rtc-bq4802"); static struct platform_driver bq4802_driver = { .driver = { .name = "rtc-bq4802", - .owner = THIS_MODULE, }, .probe = bq4802_probe, }; diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index 869cae273799..56343b2fbc68 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -267,7 +267,6 @@ static const struct of_device_id coh901331_dt_match[] = { static struct platform_driver coh901331_driver = { .driver = { .name = "rtc-coh901331", - .owner = THIS_MODULE, .pm = &coh901331_pm_ops, .of_match_table = coh901331_dt_match, }, diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c index e5c9486cf452..613c43b7e9ae 100644 --- a/drivers/rtc/rtc-da9052.c +++ b/drivers/rtc/rtc-da9052.c @@ -265,7 +265,6 @@ static struct platform_driver da9052_rtc_driver = { .probe = da9052_rtc_probe, .driver = { .name = "da9052-rtc", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-da9055.c b/drivers/rtc/rtc-da9055.c index a825491331c8..7ec0872d5e3b 100644 --- a/drivers/rtc/rtc-da9055.c +++ b/drivers/rtc/rtc-da9055.c @@ -391,7 +391,6 @@ static struct platform_driver da9055_rtc_driver = { .probe = da9055_rtc_probe, .driver = { .name = "da9055-rtc", - .owner = THIS_MODULE, .pm = &da9055_rtc_pm_ops, }, }; diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c index 731ed1a97f59..7ffc5707f8b9 100644 --- a/drivers/rtc/rtc-da9063.c +++ b/drivers/rtc/rtc-da9063.c @@ -341,7 +341,6 @@ static struct platform_driver da9063_rtc_driver = { .probe = da9063_rtc_probe, .driver = { .name = DA9063_DRVNAME_RTC, - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index c0a3b59f65a2..c84f46168a52 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -550,7 +550,6 @@ static struct platform_driver davinci_rtc_driver = { .remove = __exit_p(davinci_rtc_remove), .driver = { .name = "rtc_davinci", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-dm355evm.c b/drivers/rtc/rtc-dm355evm.c index 1aca08394c47..94067f8eeb10 100644 --- a/drivers/rtc/rtc-dm355evm.c +++ b/drivers/rtc/rtc-dm355evm.c @@ -146,7 +146,6 @@ static int dm355evm_rtc_probe(struct platform_device *pdev) static struct platform_driver rtc_dm355evm_driver = { .probe = dm355evm_rtc_probe, .driver = { - .owner = THIS_MODULE, .name = "rtc-dm355evm", }, }; diff --git a/drivers/rtc/rtc-ds1216.c b/drivers/rtc/rtc-ds1216.c index 9c04fd2bc209..d16f550897b8 100644 --- a/drivers/rtc/rtc-ds1216.c +++ b/drivers/rtc/rtc-ds1216.c @@ -170,7 +170,6 @@ static int __init ds1216_rtc_probe(struct platform_device *pdev) static struct platform_driver ds1216_rtc_platform_driver = { .driver = { .name = "rtc-ds1216", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c index 50e109b78252..2fe537f4e2bd 100644 --- a/drivers/rtc/rtc-ds1286.c +++ b/drivers/rtc/rtc-ds1286.c @@ -356,7 +356,6 @@ static int ds1286_probe(struct platform_device *pdev) static struct platform_driver ds1286_platform_driver = { .driver = { .name = "rtc-ds1286", - .owner = THIS_MODULE, }, .probe = ds1286_probe, }; diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c index 07e8d79b4a09..6bef7a5233c4 100644 --- a/drivers/rtc/rtc-ds1302.c +++ b/drivers/rtc/rtc-ds1302.c @@ -244,7 +244,6 @@ static int __init ds1302_rtc_probe(struct platform_device *pdev) static struct platform_driver ds1302_platform_driver = { .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index bb43cf703efc..4ffabb322a9a 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -35,7 +35,7 @@ enum ds_type { ds_1388, ds_3231, m41t00, - mcp7941x, + mcp794xx, rx_8025, last_ds_type /* always last */ /* rs5c372 too? different address... */ @@ -46,7 +46,7 @@ enum ds_type { #define DS1307_REG_SECS 0x00 /* 00-59 */ # define DS1307_BIT_CH 0x80 # define DS1340_BIT_nEOSC 0x80 -# define MCP7941X_BIT_ST 0x80 +# define MCP794XX_BIT_ST 0x80 #define DS1307_REG_MIN 0x01 /* 00-59 */ #define DS1307_REG_HOUR 0x02 /* 00-23, or 1-12{am,pm} */ # define DS1307_BIT_12HR 0x40 /* in REG_HOUR */ @@ -54,7 +54,7 @@ enum ds_type { # define DS1340_BIT_CENTURY_EN 0x80 /* in REG_HOUR */ # define DS1340_BIT_CENTURY 0x40 /* in REG_HOUR */ #define DS1307_REG_WDAY 0x03 /* 01-07 */ -# define MCP7941X_BIT_VBATEN 0x08 +# define MCP794XX_BIT_VBATEN 0x08 #define DS1307_REG_MDAY 0x04 /* 01-31 */ #define DS1307_REG_MONTH 0x05 /* 01-12 */ # define DS1337_BIT_CENTURY 0x80 /* in REG_MONTH */ @@ -159,7 +159,7 @@ static struct chip_desc chips[last_ds_type] = { [ds_3231] = { .alarm = 1, }, - [mcp7941x] = { + [mcp794xx] = { .alarm = 1, /* this is battery backed SRAM */ .nvram_offset = 0x20, @@ -176,7 +176,8 @@ static const struct i2c_device_id ds1307_id[] = { { "ds1340", ds_1340 }, { "ds3231", ds_3231 }, { "m41t00", m41t00 }, - { "mcp7941x", mcp7941x }, + { "mcp7940x", mcp794xx }, + { "mcp7941x", mcp794xx }, { "pt7c4338", ds_1307 }, { "rx8025", rx_8025 }, { } @@ -439,14 +440,14 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t) buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN | DS1340_BIT_CENTURY; break; - case mcp7941x: + case mcp794xx: /* * these bits were cleared when preparing the date/time * values and need to be set again before writing the * buffer out to the device. */ - buf[DS1307_REG_SECS] |= MCP7941X_BIT_ST; - buf[DS1307_REG_WDAY] |= MCP7941X_BIT_VBATEN; + buf[DS1307_REG_SECS] |= MCP794XX_BIT_ST; + buf[DS1307_REG_WDAY] |= MCP794XX_BIT_VBATEN; break; default: break; @@ -614,26 +615,26 @@ static const struct rtc_class_ops ds13xx_rtc_ops = { /*----------------------------------------------------------------------*/ /* - * Alarm support for mcp7941x devices. + * Alarm support for mcp794xx devices. */ -#define MCP7941X_REG_CONTROL 0x07 -# define MCP7941X_BIT_ALM0_EN 0x10 -# define MCP7941X_BIT_ALM1_EN 0x20 -#define MCP7941X_REG_ALARM0_BASE 0x0a -#define MCP7941X_REG_ALARM0_CTRL 0x0d -#define MCP7941X_REG_ALARM1_BASE 0x11 -#define MCP7941X_REG_ALARM1_CTRL 0x14 -# define MCP7941X_BIT_ALMX_IF (1 << 3) -# define MCP7941X_BIT_ALMX_C0 (1 << 4) -# define MCP7941X_BIT_ALMX_C1 (1 << 5) -# define MCP7941X_BIT_ALMX_C2 (1 << 6) -# define MCP7941X_BIT_ALMX_POL (1 << 7) -# define MCP7941X_MSK_ALMX_MATCH (MCP7941X_BIT_ALMX_C0 | \ - MCP7941X_BIT_ALMX_C1 | \ - MCP7941X_BIT_ALMX_C2) - -static void mcp7941x_work(struct work_struct *work) +#define MCP794XX_REG_CONTROL 0x07 +# define MCP794XX_BIT_ALM0_EN 0x10 +# define MCP794XX_BIT_ALM1_EN 0x20 +#define MCP794XX_REG_ALARM0_BASE 0x0a +#define MCP794XX_REG_ALARM0_CTRL 0x0d +#define MCP794XX_REG_ALARM1_BASE 0x11 +#define MCP794XX_REG_ALARM1_CTRL 0x14 +# define MCP794XX_BIT_ALMX_IF (1 << 3) +# define MCP794XX_BIT_ALMX_C0 (1 << 4) +# define MCP794XX_BIT_ALMX_C1 (1 << 5) +# define MCP794XX_BIT_ALMX_C2 (1 << 6) +# define MCP794XX_BIT_ALMX_POL (1 << 7) +# define MCP794XX_MSK_ALMX_MATCH (MCP794XX_BIT_ALMX_C0 | \ + MCP794XX_BIT_ALMX_C1 | \ + MCP794XX_BIT_ALMX_C2) + +static void mcp794xx_work(struct work_struct *work) { struct ds1307 *ds1307 = container_of(work, struct ds1307, work); struct i2c_client *client = ds1307->client; @@ -642,22 +643,22 @@ static void mcp7941x_work(struct work_struct *work) mutex_lock(&ds1307->rtc->ops_lock); /* Check and clear alarm 0 interrupt flag. */ - reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_ALARM0_CTRL); + reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_ALARM0_CTRL); if (reg < 0) goto out; - if (!(reg & MCP7941X_BIT_ALMX_IF)) + if (!(reg & MCP794XX_BIT_ALMX_IF)) goto out; - reg &= ~MCP7941X_BIT_ALMX_IF; - ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_ALARM0_CTRL, reg); + reg &= ~MCP794XX_BIT_ALMX_IF; + ret = i2c_smbus_write_byte_data(client, MCP794XX_REG_ALARM0_CTRL, reg); if (ret < 0) goto out; /* Disable alarm 0. */ - reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL); + reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_CONTROL); if (reg < 0) goto out; - reg &= ~MCP7941X_BIT_ALM0_EN; - ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg); + reg &= ~MCP794XX_BIT_ALM0_EN; + ret = i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, reg); if (ret < 0) goto out; @@ -669,7 +670,7 @@ out: mutex_unlock(&ds1307->rtc->ops_lock); } -static int mcp7941x_read_alarm(struct device *dev, struct rtc_wkalrm *t) +static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t) { struct i2c_client *client = to_i2c_client(dev); struct ds1307 *ds1307 = i2c_get_clientdata(client); @@ -680,11 +681,11 @@ static int mcp7941x_read_alarm(struct device *dev, struct rtc_wkalrm *t) return -EINVAL; /* Read control and alarm 0 registers. */ - ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs); + ret = ds1307->read_block_data(client, MCP794XX_REG_CONTROL, 10, regs); if (ret < 0) return ret; - t->enabled = !!(regs[0] & MCP7941X_BIT_ALM0_EN); + t->enabled = !!(regs[0] & MCP794XX_BIT_ALM0_EN); /* Report alarm 0 time assuming 24-hour and day-of-month modes. */ t->time.tm_sec = bcd2bin(ds1307->regs[3] & 0x7f); @@ -701,14 +702,14 @@ static int mcp7941x_read_alarm(struct device *dev, struct rtc_wkalrm *t) "enabled=%d polarity=%d irq=%d match=%d\n", __func__, t->time.tm_sec, t->time.tm_min, t->time.tm_hour, t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled, - !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_POL), - !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_IF), - (ds1307->regs[6] & MCP7941X_MSK_ALMX_MATCH) >> 4); + !!(ds1307->regs[6] & MCP794XX_BIT_ALMX_POL), + !!(ds1307->regs[6] & MCP794XX_BIT_ALMX_IF), + (ds1307->regs[6] & MCP794XX_MSK_ALMX_MATCH) >> 4); return 0; } -static int mcp7941x_set_alarm(struct device *dev, struct rtc_wkalrm *t) +static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t) { struct i2c_client *client = to_i2c_client(dev); struct ds1307 *ds1307 = i2c_get_clientdata(client); @@ -725,7 +726,7 @@ static int mcp7941x_set_alarm(struct device *dev, struct rtc_wkalrm *t) t->enabled, t->pending); /* Read control and alarm 0 registers. */ - ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs); + ret = ds1307->read_block_data(client, MCP794XX_REG_CONTROL, 10, regs); if (ret < 0) return ret; @@ -738,23 +739,23 @@ static int mcp7941x_set_alarm(struct device *dev, struct rtc_wkalrm *t) regs[8] = bin2bcd(t->time.tm_mon) + 1; /* Clear the alarm 0 interrupt flag. */ - regs[6] &= ~MCP7941X_BIT_ALMX_IF; + regs[6] &= ~MCP794XX_BIT_ALMX_IF; /* Set alarm match: second, minute, hour, day, date, month. */ - regs[6] |= MCP7941X_MSK_ALMX_MATCH; + regs[6] |= MCP794XX_MSK_ALMX_MATCH; if (t->enabled) - regs[0] |= MCP7941X_BIT_ALM0_EN; + regs[0] |= MCP794XX_BIT_ALM0_EN; else - regs[0] &= ~MCP7941X_BIT_ALM0_EN; + regs[0] &= ~MCP794XX_BIT_ALM0_EN; - ret = ds1307->write_block_data(client, MCP7941X_REG_CONTROL, 10, regs); + ret = ds1307->write_block_data(client, MCP794XX_REG_CONTROL, 10, regs); if (ret < 0) return ret; return 0; } -static int mcp7941x_alarm_irq_enable(struct device *dev, unsigned int enabled) +static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct i2c_client *client = to_i2c_client(dev); struct ds1307 *ds1307 = i2c_get_clientdata(client); @@ -763,24 +764,24 @@ static int mcp7941x_alarm_irq_enable(struct device *dev, unsigned int enabled) if (!test_bit(HAS_ALARM, &ds1307->flags)) return -EINVAL; - reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL); + reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_CONTROL); if (reg < 0) return reg; if (enabled) - reg |= MCP7941X_BIT_ALM0_EN; + reg |= MCP794XX_BIT_ALM0_EN; else - reg &= ~MCP7941X_BIT_ALM0_EN; + reg &= ~MCP794XX_BIT_ALM0_EN; - return i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg); + return i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, reg); } -static const struct rtc_class_ops mcp7941x_rtc_ops = { +static const struct rtc_class_ops mcp794xx_rtc_ops = { .read_time = ds1307_get_time, .set_time = ds1307_set_time, - .read_alarm = mcp7941x_read_alarm, - .set_alarm = mcp7941x_set_alarm, - .alarm_irq_enable = mcp7941x_alarm_irq_enable, + .read_alarm = mcp794xx_read_alarm, + .set_alarm = mcp794xx_set_alarm, + .alarm_irq_enable = mcp794xx_alarm_irq_enable, }; /*----------------------------------------------------------------------*/ @@ -1049,10 +1050,10 @@ static int ds1307_probe(struct i2c_client *client, case ds_1388: ds1307->offset = 1; /* Seconds starts at 1 */ break; - case mcp7941x: - rtc_ops = &mcp7941x_rtc_ops; + case mcp794xx: + rtc_ops = &mcp794xx_rtc_ops; if (ds1307->client->irq > 0 && chip->alarm) { - INIT_WORK(&ds1307->work, mcp7941x_work); + INIT_WORK(&ds1307->work, mcp794xx_work); want_irq = true; } break; @@ -1117,18 +1118,18 @@ read_rtc: dev_warn(&client->dev, "SET TIME!\n"); } break; - case mcp7941x: + case mcp794xx: /* make sure that the backup battery is enabled */ - if (!(ds1307->regs[DS1307_REG_WDAY] & MCP7941X_BIT_VBATEN)) { + if (!(ds1307->regs[DS1307_REG_WDAY] & MCP794XX_BIT_VBATEN)) { i2c_smbus_write_byte_data(client, DS1307_REG_WDAY, ds1307->regs[DS1307_REG_WDAY] - | MCP7941X_BIT_VBATEN); + | MCP794XX_BIT_VBATEN); } /* clock halted? turn it on, so clock can tick. */ - if (!(tmp & MCP7941X_BIT_ST)) { + if (!(tmp & MCP794XX_BIT_ST)) { i2c_smbus_write_byte_data(client, DS1307_REG_SECS, - MCP7941X_BIT_ST); + MCP794XX_BIT_ST); dev_warn(&client->dev, "SET TIME!\n"); goto read_rtc; } diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 9e6e14fb53d7..8605fde394b2 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -4,6 +4,7 @@ * Based on code by Randy Vinson <rvinson@mvista.com>, * which was based on the m41t00.c by Mark Greer <mgreer@mvista.com>. * + * Copyright (C) 2014 Rose Technology * Copyright (C) 2006-2007 Freescale Semiconductor * * 2005 (c) MontaVista Software, Inc. This file is licensed under @@ -26,6 +27,13 @@ #include <linux/workqueue.h> #include <linux/slab.h> #include <linux/pm.h> +#ifdef CONFIG_RTC_DRV_DS1374_WDT +#include <linux/fs.h> +#include <linux/ioctl.h> +#include <linux/miscdevice.h> +#include <linux/reboot.h> +#include <linux/watchdog.h> +#endif #define DS1374_REG_TOD0 0x00 /* Time of Day */ #define DS1374_REG_TOD1 0x01 @@ -49,6 +57,14 @@ static const struct i2c_device_id ds1374_id[] = { }; MODULE_DEVICE_TABLE(i2c, ds1374_id); +#ifdef CONFIG_OF +static const struct of_device_id ds1374_of_match[] = { + { .compatible = "dallas,ds1374" }, + { } +}; +MODULE_DEVICE_TABLE(of, ds1374_of_match); +#endif + struct ds1374 { struct i2c_client *client; struct rtc_device *rtc; @@ -162,6 +178,7 @@ static int ds1374_set_time(struct device *dev, struct rtc_time *time) return ds1374_write_rtc(client, itime, DS1374_REG_TOD0, 4); } +#ifndef CONFIG_RTC_DRV_DS1374_WDT /* The ds1374 has a decrementer for an alarm, rather than a comparator. * If the time of day is changed, then the alarm will need to be * reset. @@ -263,6 +280,7 @@ out: mutex_unlock(&ds1374->mutex); return ret; } +#endif static irqreturn_t ds1374_irq(int irq, void *dev_id) { @@ -307,6 +325,7 @@ unlock: mutex_unlock(&ds1374->mutex); } +#ifndef CONFIG_RTC_DRV_DS1374_WDT static int ds1374_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct i2c_client *client = to_i2c_client(dev); @@ -331,15 +350,260 @@ out: mutex_unlock(&ds1374->mutex); return ret; } +#endif static const struct rtc_class_ops ds1374_rtc_ops = { .read_time = ds1374_read_time, .set_time = ds1374_set_time, +#ifndef CONFIG_RTC_DRV_DS1374_WDT .read_alarm = ds1374_read_alarm, .set_alarm = ds1374_set_alarm, .alarm_irq_enable = ds1374_alarm_irq_enable, +#endif +}; + +#ifdef CONFIG_RTC_DRV_DS1374_WDT +/* + ***************************************************************************** + * + * Watchdog Driver + * + ***************************************************************************** + */ +static struct i2c_client *save_client; +/* Default margin */ +#define WD_TIMO 131762 + +#define DRV_NAME "DS1374 Watchdog" + +static int wdt_margin = WD_TIMO; +static unsigned long wdt_is_open; +module_param(wdt_margin, int, 0); +MODULE_PARM_DESC(wdt_margin, "Watchdog timeout in seconds (default 32s)"); + +static const struct watchdog_info ds1374_wdt_info = { + .identity = "DS1374 WTD", + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | + WDIOF_MAGICCLOSE, }; +static int ds1374_wdt_settimeout(unsigned int timeout) +{ + int ret = -ENOIOCTLCMD; + int cr; + + ret = cr = i2c_smbus_read_byte_data(save_client, DS1374_REG_CR); + if (ret < 0) + goto out; + + /* Disable any existing watchdog/alarm before setting the new one */ + cr &= ~DS1374_REG_CR_WACE; + + ret = i2c_smbus_write_byte_data(save_client, DS1374_REG_CR, cr); + if (ret < 0) + goto out; + + /* Set new watchdog time */ + ret = ds1374_write_rtc(save_client, timeout, DS1374_REG_WDALM0, 3); + if (ret) { + pr_info("rtc-ds1374 - couldn't set new watchdog time\n"); + goto out; + } + + /* Enable watchdog timer */ + cr |= DS1374_REG_CR_WACE | DS1374_REG_CR_WDALM; + cr &= ~DS1374_REG_CR_AIE; + + ret = i2c_smbus_write_byte_data(save_client, DS1374_REG_CR, cr); + if (ret < 0) + goto out; + + return 0; +out: + return ret; +} + + +/* + * Reload the watchdog timer. (ie, pat the watchdog) + */ +static void ds1374_wdt_ping(void) +{ + u32 val; + int ret = 0; + + ret = ds1374_read_rtc(save_client, &val, DS1374_REG_WDALM0, 3); + if (ret) + pr_info("WD TICK FAIL!!!!!!!!!! %i\n", ret); +} + +static void ds1374_wdt_disable(void) +{ + int ret = -ENOIOCTLCMD; + int cr; + + cr = i2c_smbus_read_byte_data(save_client, DS1374_REG_CR); + /* Disable watchdog timer */ + cr &= ~DS1374_REG_CR_WACE; + + ret = i2c_smbus_write_byte_data(save_client, DS1374_REG_CR, cr); +} + +/* + * Watchdog device is opened, and watchdog starts running. + */ +static int ds1374_wdt_open(struct inode *inode, struct file *file) +{ + struct ds1374 *ds1374 = i2c_get_clientdata(save_client); + + if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) { + mutex_lock(&ds1374->mutex); + if (test_and_set_bit(0, &wdt_is_open)) { + mutex_unlock(&ds1374->mutex); + return -EBUSY; + } + /* + * Activate + */ + wdt_is_open = 1; + mutex_unlock(&ds1374->mutex); + return nonseekable_open(inode, file); + } + return -ENODEV; +} + +/* + * Close the watchdog device. + */ +static int ds1374_wdt_release(struct inode *inode, struct file *file) +{ + if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) + clear_bit(0, &wdt_is_open); + + return 0; +} + +/* + * Pat the watchdog whenever device is written to. + */ +static ssize_t ds1374_wdt_write(struct file *file, const char __user *data, + size_t len, loff_t *ppos) +{ + if (len) { + ds1374_wdt_ping(); + return 1; + } + return 0; +} + +static ssize_t ds1374_wdt_read(struct file *file, char __user *data, + size_t len, loff_t *ppos) +{ + return 0; +} + +/* + * Handle commands from user-space. + */ +static long ds1374_wdt_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int new_margin, options; + + switch (cmd) { + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info __user *)arg, + &ds1374_wdt_info, sizeof(ds1374_wdt_info)) ? -EFAULT : 0; + + case WDIOC_GETSTATUS: + case WDIOC_GETBOOTSTATUS: + return put_user(0, (int __user *)arg); + case WDIOC_KEEPALIVE: + ds1374_wdt_ping(); + return 0; + case WDIOC_SETTIMEOUT: + if (get_user(new_margin, (int __user *)arg)) + return -EFAULT; + + if (new_margin < 1 || new_margin > 16777216) + return -EINVAL; + + wdt_margin = new_margin; + ds1374_wdt_settimeout(new_margin); + ds1374_wdt_ping(); + /* fallthrough */ + case WDIOC_GETTIMEOUT: + return put_user(wdt_margin, (int __user *)arg); + case WDIOC_SETOPTIONS: + if (copy_from_user(&options, (int __user *)arg, sizeof(int))) + return -EFAULT; + + if (options & WDIOS_DISABLECARD) { + pr_info("rtc-ds1374: disable watchdog\n"); + ds1374_wdt_disable(); + } + + if (options & WDIOS_ENABLECARD) { + pr_info("rtc-ds1374: enable watchdog\n"); + ds1374_wdt_settimeout(wdt_margin); + ds1374_wdt_ping(); + } + + return -EINVAL; + } + return -ENOTTY; +} + +static long ds1374_wdt_unlocked_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + int ret; + struct ds1374 *ds1374 = i2c_get_clientdata(save_client); + + mutex_lock(&ds1374->mutex); + ret = ds1374_wdt_ioctl(file, cmd, arg); + mutex_unlock(&ds1374->mutex); + + return ret; +} + +static int ds1374_wdt_notify_sys(struct notifier_block *this, + unsigned long code, void *unused) +{ + if (code == SYS_DOWN || code == SYS_HALT) + /* Disable Watchdog */ + ds1374_wdt_disable(); + return NOTIFY_DONE; +} + +static const struct file_operations ds1374_wdt_fops = { + .owner = THIS_MODULE, + .read = ds1374_wdt_read, + .unlocked_ioctl = ds1374_wdt_unlocked_ioctl, + .write = ds1374_wdt_write, + .open = ds1374_wdt_open, + .release = ds1374_wdt_release, + .llseek = no_llseek, +}; + +static struct miscdevice ds1374_miscdev = { + .minor = WATCHDOG_MINOR, + .name = "watchdog", + .fops = &ds1374_wdt_fops, +}; + +static struct notifier_block ds1374_wdt_notifier = { + .notifier_call = ds1374_wdt_notify_sys, +}; + +#endif /*CONFIG_RTC_DRV_DS1374_WDT*/ +/* + ***************************************************************************** + * + * Driver Interface + * + ***************************************************************************** + */ static int ds1374_probe(struct i2c_client *client, const struct i2c_device_id *id) { @@ -378,12 +642,33 @@ static int ds1374_probe(struct i2c_client *client, return PTR_ERR(ds1374->rtc); } +#ifdef CONFIG_RTC_DRV_DS1374_WDT + save_client = client; + ret = misc_register(&ds1374_miscdev); + if (ret) + return ret; + ret = register_reboot_notifier(&ds1374_wdt_notifier); + if (ret) { + misc_deregister(&ds1374_miscdev); + return ret; + } + ds1374_wdt_settimeout(131072); +#endif + return 0; } static int ds1374_remove(struct i2c_client *client) { struct ds1374 *ds1374 = i2c_get_clientdata(client); +#ifdef CONFIG_RTC_DRV_DS1374_WDT + int res; + + res = misc_deregister(&ds1374_miscdev); + if (!res) + ds1374_miscdev.parent = NULL; + unregister_reboot_notifier(&ds1374_wdt_notifier); +#endif if (client->irq > 0) { mutex_lock(&ds1374->mutex); diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index b13d1399b81a..7415c2b4d6e8 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -561,7 +561,6 @@ static struct platform_driver ds1511_rtc_driver = { .remove = ds1511_rtc_remove, .driver = { .name = "ds1511", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index ab56893aac73..a24e091bcb41 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -351,7 +351,6 @@ static struct platform_driver ds1553_rtc_driver = { .remove = ds1553_rtc_remove, .driver = { .name = "rtc-ds1553", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 9822715db8ba..0f8d8ace1515 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -230,7 +230,6 @@ static struct platform_driver ds1742_rtc_driver = { .remove = ds1742_rtc_remove, .driver = { .name = "rtc-ds1742", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(ds1742_rtc_of_match), }, }; diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c index fc209dc4e245..7885edd3d507 100644 --- a/drivers/rtc/rtc-ds2404.c +++ b/drivers/rtc/rtc-ds2404.c @@ -274,7 +274,6 @@ static struct platform_driver rtc_device_driver = { .remove = rtc_remove, .driver = { .name = "ds2404", - .owner = THIS_MODULE, }, }; module_platform_driver(rtc_device_driver); diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index 53b589dc34eb..b37b0c80bd5a 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -226,7 +226,6 @@ static int __init efi_rtc_probe(struct platform_device *dev) static struct platform_driver efi_rtc_driver = { .driver = { .name = "rtc-efi", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 5e4f5dc40ba5..de325d68c7e4 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -174,7 +174,6 @@ static int ep93xx_rtc_remove(struct platform_device *pdev) static struct platform_driver ep93xx_rtc_driver = { .driver = { .name = "ep93xx-rtc", - .owner = THIS_MODULE, }, .probe = ep93xx_rtc_probe, .remove = ep93xx_rtc_remove, diff --git a/drivers/rtc/rtc-generic.c b/drivers/rtc/rtc-generic.c index 9b6725ebbfb2..e782ebd719b2 100644 --- a/drivers/rtc/rtc-generic.c +++ b/drivers/rtc/rtc-generic.c @@ -51,7 +51,6 @@ static int __init generic_rtc_probe(struct platform_device *dev) static struct platform_driver generic_rtc_driver = { .driver = { .name = "rtc-generic", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 965a9da70867..ae7c2ba440cf 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -331,7 +331,6 @@ static struct platform_driver hid_time_platform_driver = { .id_table = hid_time_ids, .driver = { .name = KBUILD_MODNAME, - .owner = THIS_MODULE, }, .probe = hid_time_probe, .remove = hid_time_remove, diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c index cd741c77e085..42f5570f42f8 100644 --- a/drivers/rtc/rtc-imxdi.c +++ b/drivers/rtc/rtc-imxdi.c @@ -499,7 +499,6 @@ MODULE_DEVICE_TABLE(of, dryice_dt_ids); static struct platform_driver dryice_rtc_driver = { .driver = { .name = "imxdi_rtc", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(dryice_dt_ids), }, .remove = __exit_p(dryice_rtc_remove), diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c index 455b601d731d..6e1fcfb5d7e6 100644 --- a/drivers/rtc/rtc-isl12057.c +++ b/drivers/rtc/rtc-isl12057.c @@ -41,6 +41,7 @@ #define ISL12057_REG_RTC_DW 0x03 /* Day of the Week */ #define ISL12057_REG_RTC_DT 0x04 /* Date */ #define ISL12057_REG_RTC_MO 0x05 /* Month */ +#define ISL12057_REG_RTC_MO_CEN BIT(7) /* Century bit */ #define ISL12057_REG_RTC_YR 0x06 /* Year */ #define ISL12057_RTC_SEC_LEN 7 @@ -88,7 +89,7 @@ static void isl12057_rtc_regs_to_tm(struct rtc_time *tm, u8 *regs) tm->tm_min = bcd2bin(regs[ISL12057_REG_RTC_MN]); if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_MIL) { /* AM/PM */ - tm->tm_hour = bcd2bin(regs[ISL12057_REG_RTC_HR] & 0x0f); + tm->tm_hour = bcd2bin(regs[ISL12057_REG_RTC_HR] & 0x1f); if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_PM) tm->tm_hour += 12; } else { /* 24 hour mode */ @@ -97,26 +98,37 @@ static void isl12057_rtc_regs_to_tm(struct rtc_time *tm, u8 *regs) tm->tm_mday = bcd2bin(regs[ISL12057_REG_RTC_DT]); tm->tm_wday = bcd2bin(regs[ISL12057_REG_RTC_DW]) - 1; /* starts at 1 */ - tm->tm_mon = bcd2bin(regs[ISL12057_REG_RTC_MO]) - 1; /* starts at 1 */ + tm->tm_mon = bcd2bin(regs[ISL12057_REG_RTC_MO] & 0x1f) - 1; /* ditto */ tm->tm_year = bcd2bin(regs[ISL12057_REG_RTC_YR]) + 100; + + /* Check if years register has overflown from 99 to 00 */ + if (regs[ISL12057_REG_RTC_MO] & ISL12057_REG_RTC_MO_CEN) + tm->tm_year += 100; } static int isl12057_rtc_tm_to_regs(u8 *regs, struct rtc_time *tm) { + u8 century_bit; + /* * The clock has an 8 bit wide bcd-coded register for the year. + * It also has a century bit encoded in MO flag which provides + * information about overflow of year register from 99 to 00. * tm_year is an offset from 1900 and we are interested in the - * 2000-2099 range, so any value less than 100 is invalid. + * 2000-2199 range, so any value less than 100 or larger than + * 299 is invalid. */ - if (tm->tm_year < 100) + if (tm->tm_year < 100 || tm->tm_year > 299) return -EINVAL; + century_bit = (tm->tm_year > 199) ? ISL12057_REG_RTC_MO_CEN : 0; + regs[ISL12057_REG_RTC_SC] = bin2bcd(tm->tm_sec); regs[ISL12057_REG_RTC_MN] = bin2bcd(tm->tm_min); regs[ISL12057_REG_RTC_HR] = bin2bcd(tm->tm_hour); /* 24-hour format */ regs[ISL12057_REG_RTC_DT] = bin2bcd(tm->tm_mday); - regs[ISL12057_REG_RTC_MO] = bin2bcd(tm->tm_mon + 1); - regs[ISL12057_REG_RTC_YR] = bin2bcd(tm->tm_year - 100); + regs[ISL12057_REG_RTC_MO] = bin2bcd(tm->tm_mon + 1) | century_bit; + regs[ISL12057_REG_RTC_YR] = bin2bcd(tm->tm_year % 100); regs[ISL12057_REG_RTC_DW] = bin2bcd(tm->tm_wday + 1); return 0; @@ -152,17 +164,33 @@ static int isl12057_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct isl12057_rtc_data *data = dev_get_drvdata(dev); u8 regs[ISL12057_RTC_SEC_LEN]; + unsigned int sr; int ret; mutex_lock(&data->lock); + ret = regmap_read(data->regmap, ISL12057_REG_SR, &sr); + if (ret) { + dev_err(dev, "%s: unable to read oscillator status flag (%d)\n", + __func__, ret); + goto out; + } else { + if (sr & ISL12057_REG_SR_OSF) { + ret = -ENODATA; + goto out; + } + } + ret = regmap_bulk_read(data->regmap, ISL12057_REG_RTC_SC, regs, ISL12057_RTC_SEC_LEN); + if (ret) + dev_err(dev, "%s: unable to read RTC time section (%d)\n", + __func__, ret); + +out: mutex_unlock(&data->lock); - if (ret) { - dev_err(dev, "%s: RTC read failed\n", __func__); + if (ret) return ret; - } isl12057_rtc_regs_to_tm(tm, regs); @@ -182,10 +210,24 @@ static int isl12057_rtc_set_time(struct device *dev, struct rtc_time *tm) mutex_lock(&data->lock); ret = regmap_bulk_write(data->regmap, ISL12057_REG_RTC_SC, regs, ISL12057_RTC_SEC_LEN); - mutex_unlock(&data->lock); + if (ret) { + dev_err(dev, "%s: unable to write RTC time section (%d)\n", + __func__, ret); + goto out; + } - if (ret) - dev_err(dev, "%s: RTC write failed\n", __func__); + /* + * Now that RTC time has been updated, let's clear oscillator + * failure flag, if needed. + */ + ret = regmap_update_bits(data->regmap, ISL12057_REG_SR, + ISL12057_REG_SR_OSF, 0); + if (ret < 0) + dev_err(dev, "%s: unable to clear osc. failure bit (%d)\n", + __func__, ret); + +out: + mutex_unlock(&data->lock); return ret; } @@ -203,15 +245,8 @@ static int isl12057_check_rtc_status(struct device *dev, struct regmap *regmap) ret = regmap_update_bits(regmap, ISL12057_REG_INT, ISL12057_REG_INT_EOSC, 0); if (ret < 0) { - dev_err(dev, "Unable to enable oscillator\n"); - return ret; - } - - /* Clear oscillator failure bit if needed */ - ret = regmap_update_bits(regmap, ISL12057_REG_SR, - ISL12057_REG_SR_OSF, 0); - if (ret < 0) { - dev_err(dev, "Unable to clear oscillator failure bit\n"); + dev_err(dev, "%s: unable to enable oscillator (%d)\n", + __func__, ret); return ret; } @@ -219,7 +254,8 @@ static int isl12057_check_rtc_status(struct device *dev, struct regmap *regmap) ret = regmap_update_bits(regmap, ISL12057_REG_SR, ISL12057_REG_SR_A1F, 0); if (ret < 0) { - dev_err(dev, "Unable to clear alarm bit\n"); + dev_err(dev, "%s: unable to clear alarm bit (%d)\n", + __func__, ret); return ret; } @@ -253,7 +289,8 @@ static int isl12057_probe(struct i2c_client *client, regmap = devm_regmap_init_i2c(client, &isl12057_rtc_regmap_config); if (IS_ERR(regmap)) { ret = PTR_ERR(regmap); - dev_err(dev, "regmap allocation failed: %d\n", ret); + dev_err(dev, "%s: regmap allocation failed (%d)\n", + __func__, ret); return ret; } diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 08f5160fb6d4..b2bcfc0bf2e5 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -299,7 +299,6 @@ static struct platform_driver jz4740_rtc_driver = { .probe = jz4740_rtc_probe, .driver = { .name = "jz4740-rtc", - .owner = THIS_MODULE, .pm = JZ4740_RTC_PM_OPS, }, }; diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c index c4cf05731118..e6bfb9c42a10 100644 --- a/drivers/rtc/rtc-lib.c +++ b/drivers/rtc/rtc-lib.c @@ -45,16 +45,20 @@ int rtc_year_days(unsigned int day, unsigned int month, unsigned int year) } EXPORT_SYMBOL(rtc_year_days); + /* + * rtc_time_to_tm64 - Converts time64_t to rtc_time. * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. */ -void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) +void rtc_time64_to_tm(time64_t time, struct rtc_time *tm) { unsigned int month, year; + unsigned long secs; int days; - days = time / 86400; - time -= (unsigned int) days * 86400; + /* time must be positive */ + days = div_s64(time, 86400); + secs = time - (unsigned int) days * 86400; /* day of the week, 1970-01-01 was a Thursday */ tm->tm_wday = (days + 4) % 7; @@ -81,14 +85,14 @@ void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) tm->tm_mon = month; tm->tm_mday = days + 1; - tm->tm_hour = time / 3600; - time -= tm->tm_hour * 3600; - tm->tm_min = time / 60; - tm->tm_sec = time - tm->tm_min * 60; + tm->tm_hour = secs / 3600; + secs -= tm->tm_hour * 3600; + tm->tm_min = secs / 60; + tm->tm_sec = secs - tm->tm_min * 60; tm->tm_isdst = 0; } -EXPORT_SYMBOL(rtc_time_to_tm); +EXPORT_SYMBOL(rtc_time64_to_tm); /* * Does the rtc_time represent a valid date/time? @@ -109,24 +113,22 @@ int rtc_valid_tm(struct rtc_time *tm) EXPORT_SYMBOL(rtc_valid_tm); /* + * rtc_tm_to_time64 - Converts rtc_time to time64_t. * Convert Gregorian date to seconds since 01-01-1970 00:00:00. */ -int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) +time64_t rtc_tm_to_time64(struct rtc_time *tm) { - *time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + return mktime64(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); - return 0; } -EXPORT_SYMBOL(rtc_tm_to_time); +EXPORT_SYMBOL(rtc_tm_to_time64); /* * Convert rtc_time to ktime */ ktime_t rtc_tm_to_ktime(struct rtc_time tm) { - time_t time; - rtc_tm_to_time(&tm, &time); - return ktime_set(time, 0); + return ktime_set(rtc_tm_to_time64(&tm), 0); } EXPORT_SYMBOL_GPL(rtc_tm_to_ktime); @@ -135,14 +137,14 @@ EXPORT_SYMBOL_GPL(rtc_tm_to_ktime); */ struct rtc_time rtc_ktime_to_tm(ktime_t kt) { - struct timespec ts; + struct timespec64 ts; struct rtc_time ret; - ts = ktime_to_timespec(kt); + ts = ktime_to_timespec64(kt); /* Round up any ns */ if (ts.tv_nsec) ts.tv_sec++; - rtc_time_to_tm(ts.tv_sec, &ret); + rtc_time64_to_tm(ts.tv_sec, &ret); return ret; } EXPORT_SYMBOL_GPL(rtc_ktime_to_tm); diff --git a/drivers/rtc/rtc-lp8788.c b/drivers/rtc/rtc-lp8788.c index 4ff6c73253b3..e20e7bd822e0 100644 --- a/drivers/rtc/rtc-lp8788.c +++ b/drivers/rtc/rtc-lp8788.c @@ -316,7 +316,6 @@ static struct platform_driver lp8788_rtc_driver = { .probe = lp8788_rtc_probe, .driver = { .name = LP8788_DEV_RTC, - .owner = THIS_MODULE, }, }; module_platform_driver(lp8788_rtc_driver); diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c index f130c08c98f8..f923f7324788 100644 --- a/drivers/rtc/rtc-lpc32xx.c +++ b/drivers/rtc/rtc-lpc32xx.c @@ -379,7 +379,6 @@ static struct platform_driver lpc32xx_rtc_driver = { .remove = lpc32xx_rtc_remove, .driver = { .name = RTC_NAME, - .owner = THIS_MODULE, .pm = LPC32XX_RTC_PM_OPS, .of_match_table = of_match_ptr(lpc32xx_rtc_match), }, diff --git a/drivers/rtc/rtc-ls1x.c b/drivers/rtc/rtc-ls1x.c index 682ecb094839..8445e564094a 100644 --- a/drivers/rtc/rtc-ls1x.c +++ b/drivers/rtc/rtc-ls1x.c @@ -188,7 +188,6 @@ err: static struct platform_driver ls1x_rtc_driver = { .driver = { .name = "ls1x-rtc", - .owner = THIS_MODULE, }, .probe = ls1x_rtc_probe, }; diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c index 411adb3f86a1..c62b51217ecf 100644 --- a/drivers/rtc/rtc-m48t35.c +++ b/drivers/rtc/rtc-m48t35.c @@ -181,7 +181,6 @@ static int m48t35_probe(struct platform_device *pdev) static struct platform_driver m48t35_platform_driver = { .driver = { .name = "rtc-m48t35", - .owner = THIS_MODULE, }, .probe = m48t35_probe, }; diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 11880c1e9dac..90abb5bd589c 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -504,7 +504,6 @@ MODULE_ALIAS("platform:rtc-m48t59"); static struct platform_driver m48t59_rtc_driver = { .driver = { .name = "rtc-m48t59", - .owner = THIS_MODULE, }, .probe = m48t59_rtc_probe, .remove = m48t59_rtc_remove, diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 32f64c942621..a17b7a3ceece 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -169,7 +169,6 @@ static int m48t86_rtc_probe(struct platform_device *dev) static struct platform_driver m48t86_rtc_platform_driver = { .driver = { .name = "rtc-m48t86", - .owner = THIS_MODULE, }, .probe = m48t86_rtc_probe, }; diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c index cf73e969c8cc..9d71328e59b9 100644 --- a/drivers/rtc/rtc-max77686.c +++ b/drivers/rtc/rtc-max77686.c @@ -513,7 +513,6 @@ static const struct platform_device_id rtc_id[] = { static struct platform_driver max77686_rtc_driver = { .driver = { .name = "max77686-rtc", - .owner = THIS_MODULE, .pm = &max77686_rtc_pm_ops, }, .probe = max77686_rtc_probe, diff --git a/drivers/rtc/rtc-max77802.c b/drivers/rtc/rtc-max77802.c index 566471335b33..7f8adf8d6feb 100644 --- a/drivers/rtc/rtc-max77802.c +++ b/drivers/rtc/rtc-max77802.c @@ -488,7 +488,6 @@ static const struct platform_device_id rtc_id[] = { static struct platform_driver max77802_rtc_driver = { .driver = { .name = "max77802-rtc", - .owner = THIS_MODULE, .pm = &max77802_rtc_pm_ops, }, .probe = max77802_rtc_probe, diff --git a/drivers/rtc/rtc-max8907.c b/drivers/rtc/rtc-max8907.c index 3032178bd9e6..19c29b72598d 100644 --- a/drivers/rtc/rtc-max8907.c +++ b/drivers/rtc/rtc-max8907.c @@ -215,7 +215,6 @@ static int max8907_rtc_probe(struct platform_device *pdev) static struct platform_driver max8907_rtc_driver = { .driver = { .name = "max8907-rtc", - .owner = THIS_MODULE, }, .probe = max8907_rtc_probe, }; diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c index 951d1a78e190..16d129a0bb3b 100644 --- a/drivers/rtc/rtc-max8925.c +++ b/drivers/rtc/rtc-max8925.c @@ -314,7 +314,6 @@ static SIMPLE_DEV_PM_OPS(max8925_rtc_pm_ops, max8925_rtc_suspend, max8925_rtc_re static struct platform_driver max8925_rtc_driver = { .driver = { .name = "max8925-rtc", - .owner = THIS_MODULE, .pm = &max8925_rtc_pm_ops, }, .probe = max8925_rtc_probe, diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c index 0777c01b58e0..67fbe559d535 100644 --- a/drivers/rtc/rtc-max8997.c +++ b/drivers/rtc/rtc-max8997.c @@ -523,7 +523,6 @@ static const struct platform_device_id rtc_id[] = { static struct platform_driver max8997_rtc_driver = { .driver = { .name = "max8997-rtc", - .owner = THIS_MODULE, }, .probe = max8997_rtc_probe, .shutdown = max8997_rtc_shutdown, diff --git a/drivers/rtc/rtc-max8998.c b/drivers/rtc/rtc-max8998.c index f098ad8382de..5726ef7bd56e 100644 --- a/drivers/rtc/rtc-max8998.c +++ b/drivers/rtc/rtc-max8998.c @@ -313,7 +313,6 @@ static const struct platform_device_id max8998_rtc_id[] = { static struct platform_driver max8998_rtc_driver = { .driver = { .name = "max8998-rtc", - .owner = THIS_MODULE, }, .probe = max8998_rtc_probe, .id_table = max8998_rtc_id, diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c index 0765606a2d14..5bce904b7ee6 100644 --- a/drivers/rtc/rtc-mc13xxx.c +++ b/drivers/rtc/rtc-mc13xxx.c @@ -370,7 +370,6 @@ static struct platform_driver mc13xxx_rtc_driver = { .remove = mc13xxx_rtc_remove, .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c index c31846238871..73759c9a4527 100644 --- a/drivers/rtc/rtc-moxart.c +++ b/drivers/rtc/rtc-moxart.c @@ -317,7 +317,6 @@ static struct platform_driver moxart_rtc_driver = { .probe = moxart_rtc_probe, .driver = { .name = "moxart-rtc", - .owner = THIS_MODULE, .of_match_table = moxart_rtc_match, }, }; diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index 3b965ad6f4d5..1767e18d5bd4 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -411,7 +411,6 @@ static const struct of_device_id mpc5121_rtc_match[] = { static struct platform_driver mpc5121_rtc_driver = { .driver = { .name = "mpc5121-rtc", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(mpc5121_rtc_match), }, .probe = mpc5121_rtc_probe, diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c index 426cb5189daa..9bf877bdf836 100644 --- a/drivers/rtc/rtc-msm6242.c +++ b/drivers/rtc/rtc-msm6242.c @@ -225,7 +225,6 @@ static int __init msm6242_rtc_probe(struct platform_device *pdev) static struct platform_driver msm6242_rtc_driver = { .driver = { .name = "rtc-msm6242", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index 6aaec2fc7c0d..423762241042 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -329,7 +329,6 @@ static struct platform_driver mv_rtc_driver = { .remove = __exit_p(mv_rtc_remove), .driver = { .name = "rtc-mv", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(rtc_mv_of_match_table), }, }; diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 419874fefa4b..3c3f8d10ab43 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -489,7 +489,6 @@ static struct platform_driver mxc_rtc_driver = { .driver = { .name = "mxc_rtc", .pm = &mxc_rtc_pm_ops, - .owner = THIS_MODULE, }, .id_table = imx_rtc_devtype, .probe = mxc_rtc_probe, diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c index a53da0958e95..09fc1c19f0df 100644 --- a/drivers/rtc/rtc-nuc900.c +++ b/drivers/rtc/rtc-nuc900.c @@ -262,7 +262,6 @@ static int __init nuc900_rtc_probe(struct platform_device *pdev) static struct platform_driver nuc900_rtc_driver = { .driver = { .name = "nuc900-rtc", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 21142e6574a9..8e5851aa4369 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -1,10 +1,11 @@ /* - * TI OMAP1 Real Time Clock interface for Linux + * TI OMAP Real Time Clock interface for Linux * * Copyright (C) 2003 MontaVista Software, Inc. * Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com> * * Copyright (C) 2006 David Brownell (new RTC framework) + * Copyright (C) 2014 Johan Hovold <johan@kernel.org> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -25,7 +26,8 @@ #include <linux/pm_runtime.h> #include <linux/io.h> -/* The OMAP1 RTC is a year/month/day/hours/minutes/seconds BCD clock +/* + * The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock * with century-range alarm matching, driven by the 32kHz clock. * * The main user-visible ways it differs from PC RTCs are by omitting @@ -39,10 +41,6 @@ * the SoC). See the BOARD-SPECIFIC CUSTOMIZATION comment. */ -#define DRIVER_NAME "omap_rtc" - -#define OMAP_RTC_BASE 0xfffb4800 - /* RTC registers */ #define OMAP_RTC_SECONDS_REG 0x00 #define OMAP_RTC_MINUTES_REG 0x04 @@ -72,6 +70,15 @@ #define OMAP_RTC_IRQWAKEEN 0x7c +#define OMAP_RTC_ALARM2_SECONDS_REG 0x80 +#define OMAP_RTC_ALARM2_MINUTES_REG 0x84 +#define OMAP_RTC_ALARM2_HOURS_REG 0x88 +#define OMAP_RTC_ALARM2_DAYS_REG 0x8c +#define OMAP_RTC_ALARM2_MONTHS_REG 0x90 +#define OMAP_RTC_ALARM2_YEARS_REG 0x94 + +#define OMAP_RTC_PMIC_REG 0x98 + /* OMAP_RTC_CTRL_REG bit fields: */ #define OMAP_RTC_CTRL_SPLIT BIT(7) #define OMAP_RTC_CTRL_DISABLE BIT(6) @@ -84,6 +91,7 @@ /* OMAP_RTC_STATUS_REG bit fields: */ #define OMAP_RTC_STATUS_POWER_UP BIT(7) +#define OMAP_RTC_STATUS_ALARM2 BIT(7) #define OMAP_RTC_STATUS_ALARM BIT(6) #define OMAP_RTC_STATUS_1D_EVENT BIT(5) #define OMAP_RTC_STATUS_1H_EVENT BIT(4) @@ -93,6 +101,7 @@ #define OMAP_RTC_STATUS_BUSY BIT(0) /* OMAP_RTC_INTERRUPTS_REG bit fields: */ +#define OMAP_RTC_INTERRUPTS_IT_ALARM2 BIT(4) #define OMAP_RTC_INTERRUPTS_IT_ALARM BIT(3) #define OMAP_RTC_INTERRUPTS_IT_TIMER BIT(2) @@ -102,61 +111,82 @@ /* OMAP_RTC_IRQWAKEEN bit fields: */ #define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN BIT(1) +/* OMAP_RTC_PMIC bit fields: */ +#define OMAP_RTC_PMIC_POWER_EN_EN BIT(16) + /* OMAP_RTC_KICKER values */ #define KICK0_VALUE 0x83e70b13 #define KICK1_VALUE 0x95a4f1e0 -#define OMAP_RTC_HAS_KICKER BIT(0) - -/* - * Few RTC IP revisions has special WAKE-EN Register to enable Wakeup - * generation for event Alarm. - */ -#define OMAP_RTC_HAS_IRQWAKEEN BIT(1) +struct omap_rtc_device_type { + bool has_32kclk_en; + bool has_kicker; + bool has_irqwakeen; + bool has_pmic_mode; + bool has_power_up_reset; +}; -/* - * Some RTC IP revisions (like those in AM335x and DRA7x) need - * the 32KHz clock to be explicitly enabled. - */ -#define OMAP_RTC_HAS_32KCLK_EN BIT(2) +struct omap_rtc { + struct rtc_device *rtc; + void __iomem *base; + int irq_alarm; + int irq_timer; + u8 interrupts_reg; + bool is_pmic_controller; + const struct omap_rtc_device_type *type; +}; -static void __iomem *rtc_base; +static inline u8 rtc_read(struct omap_rtc *rtc, unsigned int reg) +{ + return readb(rtc->base + reg); +} -#define rtc_read(addr) readb(rtc_base + (addr)) -#define rtc_write(val, addr) writeb(val, rtc_base + (addr)) +static inline u32 rtc_readl(struct omap_rtc *rtc, unsigned int reg) +{ + return readl(rtc->base + reg); +} -#define rtc_writel(val, addr) writel(val, rtc_base + (addr)) +static inline void rtc_write(struct omap_rtc *rtc, unsigned int reg, u8 val) +{ + writeb(val, rtc->base + reg); +} +static inline void rtc_writel(struct omap_rtc *rtc, unsigned int reg, u32 val) +{ + writel(val, rtc->base + reg); +} -/* we rely on the rtc framework to handle locking (rtc->ops_lock), +/* + * We rely on the rtc framework to handle locking (rtc->ops_lock), * so the only other requirement is that register accesses which * require BUSY to be clear are made with IRQs locally disabled */ -static void rtc_wait_not_busy(void) +static void rtc_wait_not_busy(struct omap_rtc *rtc) { - int count = 0; - u8 status; + int count; + u8 status; /* BUSY may stay active for 1/32768 second (~30 usec) */ for (count = 0; count < 50; count++) { - status = rtc_read(OMAP_RTC_STATUS_REG); - if ((status & (u8)OMAP_RTC_STATUS_BUSY) == 0) + status = rtc_read(rtc, OMAP_RTC_STATUS_REG); + if (!(status & OMAP_RTC_STATUS_BUSY)) break; udelay(1); } /* now we have ~15 usec to read/write various registers */ } -static irqreturn_t rtc_irq(int irq, void *rtc) +static irqreturn_t rtc_irq(int irq, void *dev_id) { - unsigned long events = 0; - u8 irq_data; + struct omap_rtc *rtc = dev_id; + unsigned long events = 0; + u8 irq_data; - irq_data = rtc_read(OMAP_RTC_STATUS_REG); + irq_data = rtc_read(rtc, OMAP_RTC_STATUS_REG); /* alarm irq? */ if (irq_data & OMAP_RTC_STATUS_ALARM) { - rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG); + rtc_write(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM); events |= RTC_IRQF | RTC_AF; } @@ -164,23 +194,21 @@ static irqreturn_t rtc_irq(int irq, void *rtc) if (irq_data & OMAP_RTC_STATUS_1S_EVENT) events |= RTC_IRQF | RTC_UF; - rtc_update_irq(rtc, 1, events); + rtc_update_irq(rtc->rtc, 1, events); return IRQ_HANDLED; } static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { + struct omap_rtc *rtc = dev_get_drvdata(dev); u8 reg, irqwake_reg = 0; - struct platform_device *pdev = to_platform_device(dev); - const struct platform_device_id *id_entry = - platform_get_device_id(pdev); local_irq_disable(); - rtc_wait_not_busy(); - reg = rtc_read(OMAP_RTC_INTERRUPTS_REG); - if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) - irqwake_reg = rtc_read(OMAP_RTC_IRQWAKEEN); + rtc_wait_not_busy(rtc); + reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); + if (rtc->type->has_irqwakeen) + irqwake_reg = rtc_read(rtc, OMAP_RTC_IRQWAKEEN); if (enabled) { reg |= OMAP_RTC_INTERRUPTS_IT_ALARM; @@ -189,10 +217,10 @@ static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM; irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; } - rtc_wait_not_busy(); - rtc_write(reg, OMAP_RTC_INTERRUPTS_REG); - if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) - rtc_write(irqwake_reg, OMAP_RTC_IRQWAKEEN); + rtc_wait_not_busy(rtc); + rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg); + if (rtc->type->has_irqwakeen) + rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg); local_irq_enable(); return 0; @@ -230,39 +258,47 @@ static void bcd2tm(struct rtc_time *tm) tm->tm_year = bcd2bin(tm->tm_year) + 100; } +static void omap_rtc_read_time_raw(struct omap_rtc *rtc, struct rtc_time *tm) +{ + tm->tm_sec = rtc_read(rtc, OMAP_RTC_SECONDS_REG); + tm->tm_min = rtc_read(rtc, OMAP_RTC_MINUTES_REG); + tm->tm_hour = rtc_read(rtc, OMAP_RTC_HOURS_REG); + tm->tm_mday = rtc_read(rtc, OMAP_RTC_DAYS_REG); + tm->tm_mon = rtc_read(rtc, OMAP_RTC_MONTHS_REG); + tm->tm_year = rtc_read(rtc, OMAP_RTC_YEARS_REG); +} static int omap_rtc_read_time(struct device *dev, struct rtc_time *tm) { + struct omap_rtc *rtc = dev_get_drvdata(dev); + /* we don't report wday/yday/isdst ... */ local_irq_disable(); - rtc_wait_not_busy(); - - tm->tm_sec = rtc_read(OMAP_RTC_SECONDS_REG); - tm->tm_min = rtc_read(OMAP_RTC_MINUTES_REG); - tm->tm_hour = rtc_read(OMAP_RTC_HOURS_REG); - tm->tm_mday = rtc_read(OMAP_RTC_DAYS_REG); - tm->tm_mon = rtc_read(OMAP_RTC_MONTHS_REG); - tm->tm_year = rtc_read(OMAP_RTC_YEARS_REG); - + rtc_wait_not_busy(rtc); + omap_rtc_read_time_raw(rtc, tm); local_irq_enable(); bcd2tm(tm); + return 0; } static int omap_rtc_set_time(struct device *dev, struct rtc_time *tm) { + struct omap_rtc *rtc = dev_get_drvdata(dev); + if (tm2bcd(tm) < 0) return -EINVAL; + local_irq_disable(); - rtc_wait_not_busy(); + rtc_wait_not_busy(rtc); - rtc_write(tm->tm_year, OMAP_RTC_YEARS_REG); - rtc_write(tm->tm_mon, OMAP_RTC_MONTHS_REG); - rtc_write(tm->tm_mday, OMAP_RTC_DAYS_REG); - rtc_write(tm->tm_hour, OMAP_RTC_HOURS_REG); - rtc_write(tm->tm_min, OMAP_RTC_MINUTES_REG); - rtc_write(tm->tm_sec, OMAP_RTC_SECONDS_REG); + rtc_write(rtc, OMAP_RTC_YEARS_REG, tm->tm_year); + rtc_write(rtc, OMAP_RTC_MONTHS_REG, tm->tm_mon); + rtc_write(rtc, OMAP_RTC_DAYS_REG, tm->tm_mday); + rtc_write(rtc, OMAP_RTC_HOURS_REG, tm->tm_hour); + rtc_write(rtc, OMAP_RTC_MINUTES_REG, tm->tm_min); + rtc_write(rtc, OMAP_RTC_SECONDS_REG, tm->tm_sec); local_irq_enable(); @@ -271,48 +307,50 @@ static int omap_rtc_set_time(struct device *dev, struct rtc_time *tm) static int omap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) { + struct omap_rtc *rtc = dev_get_drvdata(dev); + u8 interrupts; + local_irq_disable(); - rtc_wait_not_busy(); + rtc_wait_not_busy(rtc); - alm->time.tm_sec = rtc_read(OMAP_RTC_ALARM_SECONDS_REG); - alm->time.tm_min = rtc_read(OMAP_RTC_ALARM_MINUTES_REG); - alm->time.tm_hour = rtc_read(OMAP_RTC_ALARM_HOURS_REG); - alm->time.tm_mday = rtc_read(OMAP_RTC_ALARM_DAYS_REG); - alm->time.tm_mon = rtc_read(OMAP_RTC_ALARM_MONTHS_REG); - alm->time.tm_year = rtc_read(OMAP_RTC_ALARM_YEARS_REG); + alm->time.tm_sec = rtc_read(rtc, OMAP_RTC_ALARM_SECONDS_REG); + alm->time.tm_min = rtc_read(rtc, OMAP_RTC_ALARM_MINUTES_REG); + alm->time.tm_hour = rtc_read(rtc, OMAP_RTC_ALARM_HOURS_REG); + alm->time.tm_mday = rtc_read(rtc, OMAP_RTC_ALARM_DAYS_REG); + alm->time.tm_mon = rtc_read(rtc, OMAP_RTC_ALARM_MONTHS_REG); + alm->time.tm_year = rtc_read(rtc, OMAP_RTC_ALARM_YEARS_REG); local_irq_enable(); bcd2tm(&alm->time); - alm->enabled = !!(rtc_read(OMAP_RTC_INTERRUPTS_REG) - & OMAP_RTC_INTERRUPTS_IT_ALARM); + + interrupts = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); + alm->enabled = !!(interrupts & OMAP_RTC_INTERRUPTS_IT_ALARM); return 0; } static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) { + struct omap_rtc *rtc = dev_get_drvdata(dev); u8 reg, irqwake_reg = 0; - struct platform_device *pdev = to_platform_device(dev); - const struct platform_device_id *id_entry = - platform_get_device_id(pdev); if (tm2bcd(&alm->time) < 0) return -EINVAL; local_irq_disable(); - rtc_wait_not_busy(); + rtc_wait_not_busy(rtc); - rtc_write(alm->time.tm_year, OMAP_RTC_ALARM_YEARS_REG); - rtc_write(alm->time.tm_mon, OMAP_RTC_ALARM_MONTHS_REG); - rtc_write(alm->time.tm_mday, OMAP_RTC_ALARM_DAYS_REG); - rtc_write(alm->time.tm_hour, OMAP_RTC_ALARM_HOURS_REG); - rtc_write(alm->time.tm_min, OMAP_RTC_ALARM_MINUTES_REG); - rtc_write(alm->time.tm_sec, OMAP_RTC_ALARM_SECONDS_REG); + rtc_write(rtc, OMAP_RTC_ALARM_YEARS_REG, alm->time.tm_year); + rtc_write(rtc, OMAP_RTC_ALARM_MONTHS_REG, alm->time.tm_mon); + rtc_write(rtc, OMAP_RTC_ALARM_DAYS_REG, alm->time.tm_mday); + rtc_write(rtc, OMAP_RTC_ALARM_HOURS_REG, alm->time.tm_hour); + rtc_write(rtc, OMAP_RTC_ALARM_MINUTES_REG, alm->time.tm_min); + rtc_write(rtc, OMAP_RTC_ALARM_SECONDS_REG, alm->time.tm_sec); - reg = rtc_read(OMAP_RTC_INTERRUPTS_REG); - if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) - irqwake_reg = rtc_read(OMAP_RTC_IRQWAKEEN); + reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); + if (rtc->type->has_irqwakeen) + irqwake_reg = rtc_read(rtc, OMAP_RTC_IRQWAKEEN); if (alm->enabled) { reg |= OMAP_RTC_INTERRUPTS_IT_ALARM; @@ -321,15 +359,79 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM; irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; } - rtc_write(reg, OMAP_RTC_INTERRUPTS_REG); - if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) - rtc_write(irqwake_reg, OMAP_RTC_IRQWAKEEN); + rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg); + if (rtc->type->has_irqwakeen) + rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg); local_irq_enable(); return 0; } +static struct omap_rtc *omap_rtc_power_off_rtc; + +/* + * omap_rtc_poweroff: RTC-controlled power off + * + * The RTC can be used to control an external PMIC via the pmic_power_en pin, + * which can be configured to transition to OFF on ALARM2 events. + * + * Notes: + * The two-second alarm offset is the shortest offset possible as the alarm + * registers must be set before the next timer update and the offset + * calculation is too heavy for everything to be done within a single access + * period (~15 us). + * + * Called with local interrupts disabled. + */ +static void omap_rtc_power_off(void) +{ + struct omap_rtc *rtc = omap_rtc_power_off_rtc; + struct rtc_time tm; + unsigned long now; + u32 val; + + /* enable pmic_power_en control */ + val = rtc_readl(rtc, OMAP_RTC_PMIC_REG); + rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN); + + /* set alarm two seconds from now */ + omap_rtc_read_time_raw(rtc, &tm); + bcd2tm(&tm); + rtc_tm_to_time(&tm, &now); + rtc_time_to_tm(now + 2, &tm); + + if (tm2bcd(&tm) < 0) { + dev_err(&rtc->rtc->dev, "power off failed\n"); + return; + } + + rtc_wait_not_busy(rtc); + + rtc_write(rtc, OMAP_RTC_ALARM2_SECONDS_REG, tm.tm_sec); + rtc_write(rtc, OMAP_RTC_ALARM2_MINUTES_REG, tm.tm_min); + rtc_write(rtc, OMAP_RTC_ALARM2_HOURS_REG, tm.tm_hour); + rtc_write(rtc, OMAP_RTC_ALARM2_DAYS_REG, tm.tm_mday); + rtc_write(rtc, OMAP_RTC_ALARM2_MONTHS_REG, tm.tm_mon); + rtc_write(rtc, OMAP_RTC_ALARM2_YEARS_REG, tm.tm_year); + + /* + * enable ALARM2 interrupt + * + * NOTE: this fails on AM3352 if rtc_write (writeb) is used + */ + val = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); + rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG, + val | OMAP_RTC_INTERRUPTS_IT_ALARM2); + + /* + * Wait for alarm to trigger (within two seconds) and external PMIC to + * power off the system. Add a 500 ms margin for external latencies + * (e.g. debounce circuits). + */ + mdelay(2500); +} + static struct rtc_class_ops omap_rtc_ops = { .read_time = omap_rtc_read_time, .set_time = omap_rtc_set_time, @@ -338,137 +440,140 @@ static struct rtc_class_ops omap_rtc_ops = { .alarm_irq_enable = omap_rtc_alarm_irq_enable, }; -static int omap_rtc_alarm; -static int omap_rtc_timer; +static const struct omap_rtc_device_type omap_rtc_default_type = { + .has_power_up_reset = true, +}; -#define OMAP_RTC_DATA_AM3352_IDX 1 -#define OMAP_RTC_DATA_DA830_IDX 2 +static const struct omap_rtc_device_type omap_rtc_am3352_type = { + .has_32kclk_en = true, + .has_kicker = true, + .has_irqwakeen = true, + .has_pmic_mode = true, +}; -static struct platform_device_id omap_rtc_devtype[] = { +static const struct omap_rtc_device_type omap_rtc_da830_type = { + .has_kicker = true, +}; + +static const struct platform_device_id omap_rtc_id_table[] = { { - .name = DRIVER_NAME, - }, - [OMAP_RTC_DATA_AM3352_IDX] = { + .name = "omap_rtc", + .driver_data = (kernel_ulong_t)&omap_rtc_default_type, + }, { .name = "am3352-rtc", - .driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN | - OMAP_RTC_HAS_32KCLK_EN, - }, - [OMAP_RTC_DATA_DA830_IDX] = { + .driver_data = (kernel_ulong_t)&omap_rtc_am3352_type, + }, { .name = "da830-rtc", - .driver_data = OMAP_RTC_HAS_KICKER, - }, - {}, + .driver_data = (kernel_ulong_t)&omap_rtc_da830_type, + }, { + /* sentinel */ + } }; -MODULE_DEVICE_TABLE(platform, omap_rtc_devtype); +MODULE_DEVICE_TABLE(platform, omap_rtc_id_table); static const struct of_device_id omap_rtc_of_match[] = { - { .compatible = "ti,da830-rtc", - .data = &omap_rtc_devtype[OMAP_RTC_DATA_DA830_IDX], - }, - { .compatible = "ti,am3352-rtc", - .data = &omap_rtc_devtype[OMAP_RTC_DATA_AM3352_IDX], - }, - {}, + { + .compatible = "ti,am3352-rtc", + .data = &omap_rtc_am3352_type, + }, { + .compatible = "ti,da830-rtc", + .data = &omap_rtc_da830_type, + }, { + /* sentinel */ + } }; MODULE_DEVICE_TABLE(of, omap_rtc_of_match); static int __init omap_rtc_probe(struct platform_device *pdev) { - struct resource *res; - struct rtc_device *rtc; - u8 reg, new_ctrl; + struct omap_rtc *rtc; + struct resource *res; + u8 reg, mask, new_ctrl; const struct platform_device_id *id_entry; const struct of_device_id *of_id; + int ret; - of_id = of_match_device(omap_rtc_of_match, &pdev->dev); - if (of_id) - pdev->id_entry = of_id->data; + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; - id_entry = platform_get_device_id(pdev); - if (!id_entry) { - dev_err(&pdev->dev, "no matching device entry\n"); - return -ENODEV; + of_id = of_match_device(omap_rtc_of_match, &pdev->dev); + if (of_id) { + rtc->type = of_id->data; + rtc->is_pmic_controller = rtc->type->has_pmic_mode && + of_property_read_bool(pdev->dev.of_node, + "system-power-controller"); + } else { + id_entry = platform_get_device_id(pdev); + rtc->type = (void *)id_entry->driver_data; } - omap_rtc_timer = platform_get_irq(pdev, 0); - if (omap_rtc_timer <= 0) { - pr_debug("%s: no update irq?\n", pdev->name); + rtc->irq_timer = platform_get_irq(pdev, 0); + if (rtc->irq_timer <= 0) return -ENOENT; - } - omap_rtc_alarm = platform_get_irq(pdev, 1); - if (omap_rtc_alarm <= 0) { - pr_debug("%s: no alarm irq?\n", pdev->name); + rtc->irq_alarm = platform_get_irq(pdev, 1); + if (rtc->irq_alarm <= 0) return -ENOENT; - } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - rtc_base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(rtc_base)) - return PTR_ERR(rtc_base); + rtc->base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rtc->base)) + return PTR_ERR(rtc->base); + + platform_set_drvdata(pdev, rtc); /* Enable the clock/module so that we can access the registers */ pm_runtime_enable(&pdev->dev); pm_runtime_get_sync(&pdev->dev); - if (id_entry->driver_data & OMAP_RTC_HAS_KICKER) { - rtc_writel(KICK0_VALUE, OMAP_RTC_KICK0_REG); - rtc_writel(KICK1_VALUE, OMAP_RTC_KICK1_REG); - } - - rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &omap_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - pr_debug("%s: can't register RTC device, err %ld\n", - pdev->name, PTR_ERR(rtc)); - goto fail0; + if (rtc->type->has_kicker) { + rtc_writel(rtc, OMAP_RTC_KICK0_REG, KICK0_VALUE); + rtc_writel(rtc, OMAP_RTC_KICK1_REG, KICK1_VALUE); } - platform_set_drvdata(pdev, rtc); - /* clear pending irqs, and set 1/second periodic, - * which we'll use instead of update irqs + /* + * disable interrupts + * + * NOTE: ALARM2 is not cleared on AM3352 if rtc_write (writeb) is used */ - rtc_write(0, OMAP_RTC_INTERRUPTS_REG); + rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG, 0); /* enable RTC functional clock */ - if (id_entry->driver_data & OMAP_RTC_HAS_32KCLK_EN) - rtc_writel(OMAP_RTC_OSC_32KCLK_EN, OMAP_RTC_OSC_REG); + if (rtc->type->has_32kclk_en) { + reg = rtc_read(rtc, OMAP_RTC_OSC_REG); + rtc_writel(rtc, OMAP_RTC_OSC_REG, + reg | OMAP_RTC_OSC_32KCLK_EN); + } /* clear old status */ - reg = rtc_read(OMAP_RTC_STATUS_REG); - if (reg & (u8) OMAP_RTC_STATUS_POWER_UP) { - pr_info("%s: RTC power up reset detected\n", - pdev->name); - rtc_write(OMAP_RTC_STATUS_POWER_UP, OMAP_RTC_STATUS_REG); - } - if (reg & (u8) OMAP_RTC_STATUS_ALARM) - rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG); + reg = rtc_read(rtc, OMAP_RTC_STATUS_REG); - /* handle periodic and alarm irqs */ - if (devm_request_irq(&pdev->dev, omap_rtc_timer, rtc_irq, 0, - dev_name(&rtc->dev), rtc)) { - pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n", - pdev->name, omap_rtc_timer); - goto fail0; - } - if ((omap_rtc_timer != omap_rtc_alarm) && - (devm_request_irq(&pdev->dev, omap_rtc_alarm, rtc_irq, 0, - dev_name(&rtc->dev), rtc))) { - pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n", - pdev->name, omap_rtc_alarm); - goto fail0; + mask = OMAP_RTC_STATUS_ALARM; + + if (rtc->type->has_pmic_mode) + mask |= OMAP_RTC_STATUS_ALARM2; + + if (rtc->type->has_power_up_reset) { + mask |= OMAP_RTC_STATUS_POWER_UP; + if (reg & OMAP_RTC_STATUS_POWER_UP) + dev_info(&pdev->dev, "RTC power up reset detected\n"); } + if (reg & mask) + rtc_write(rtc, OMAP_RTC_STATUS_REG, reg & mask); + /* On boards with split power, RTC_ON_NOFF won't reset the RTC */ - reg = rtc_read(OMAP_RTC_CTRL_REG); - if (reg & (u8) OMAP_RTC_CTRL_STOP) - pr_info("%s: already running\n", pdev->name); + reg = rtc_read(rtc, OMAP_RTC_CTRL_REG); + if (reg & OMAP_RTC_CTRL_STOP) + dev_info(&pdev->dev, "already running\n"); /* force to 24 hour mode */ - new_ctrl = reg & (OMAP_RTC_CTRL_SPLIT|OMAP_RTC_CTRL_AUTO_COMP); + new_ctrl = reg & (OMAP_RTC_CTRL_SPLIT | OMAP_RTC_CTRL_AUTO_COMP); new_ctrl |= OMAP_RTC_CTRL_STOP; - /* BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE: + /* + * BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE: * * - Device wake-up capability setting should come through chip * init logic. OMAP1 boards should initialize the "wakeup capable" @@ -482,36 +587,70 @@ static int __init omap_rtc_probe(struct platform_device *pdev) * is write-only, and always reads as zero...) */ + if (new_ctrl & OMAP_RTC_CTRL_SPLIT) + dev_info(&pdev->dev, "split power mode\n"); + + if (reg != new_ctrl) + rtc_write(rtc, OMAP_RTC_CTRL_REG, new_ctrl); + device_init_wakeup(&pdev->dev, true); - if (new_ctrl & (u8) OMAP_RTC_CTRL_SPLIT) - pr_info("%s: split power mode\n", pdev->name); + rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &omap_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc->rtc)) { + ret = PTR_ERR(rtc->rtc); + goto err; + } - if (reg != new_ctrl) - rtc_write(new_ctrl, OMAP_RTC_CTRL_REG); + /* handle periodic and alarm irqs */ + ret = devm_request_irq(&pdev->dev, rtc->irq_timer, rtc_irq, 0, + dev_name(&rtc->rtc->dev), rtc); + if (ret) + goto err; + + if (rtc->irq_timer != rtc->irq_alarm) { + ret = devm_request_irq(&pdev->dev, rtc->irq_alarm, rtc_irq, 0, + dev_name(&rtc->rtc->dev), rtc); + if (ret) + goto err; + } + + if (rtc->is_pmic_controller) { + if (!pm_power_off) { + omap_rtc_power_off_rtc = rtc; + pm_power_off = omap_rtc_power_off; + } + } return 0; -fail0: - if (id_entry->driver_data & OMAP_RTC_HAS_KICKER) - rtc_writel(0, OMAP_RTC_KICK0_REG); +err: + device_init_wakeup(&pdev->dev, false); + if (rtc->type->has_kicker) + rtc_writel(rtc, OMAP_RTC_KICK0_REG, 0); pm_runtime_put_sync(&pdev->dev); pm_runtime_disable(&pdev->dev); - return -EIO; + + return ret; } static int __exit omap_rtc_remove(struct platform_device *pdev) { - const struct platform_device_id *id_entry = - platform_get_device_id(pdev); + struct omap_rtc *rtc = platform_get_drvdata(pdev); + + if (pm_power_off == omap_rtc_power_off && + omap_rtc_power_off_rtc == rtc) { + pm_power_off = NULL; + omap_rtc_power_off_rtc = NULL; + } device_init_wakeup(&pdev->dev, 0); /* leave rtc running, but disable irqs */ - rtc_write(0, OMAP_RTC_INTERRUPTS_REG); + rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0); - if (id_entry->driver_data & OMAP_RTC_HAS_KICKER) - rtc_writel(0, OMAP_RTC_KICK0_REG); + if (rtc->type->has_kicker) + rtc_writel(rtc, OMAP_RTC_KICK0_REG, 0); /* Disable the clock/module */ pm_runtime_put_sync(&pdev->dev); @@ -521,20 +660,21 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) } #ifdef CONFIG_PM_SLEEP -static u8 irqstat; - static int omap_rtc_suspend(struct device *dev) { - irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG); + struct omap_rtc *rtc = dev_get_drvdata(dev); - /* FIXME the RTC alarm is not currently acting as a wakeup event + rtc->interrupts_reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); + + /* + * FIXME: the RTC alarm is not currently acting as a wakeup event * source on some platforms, and in fact this enable() call is just * saving a flag that's never used... */ if (device_may_wakeup(dev)) - enable_irq_wake(omap_rtc_alarm); + enable_irq_wake(rtc->irq_alarm); else - rtc_write(0, OMAP_RTC_INTERRUPTS_REG); + rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0); /* Disable the clock/module */ pm_runtime_put_sync(dev); @@ -544,13 +684,15 @@ static int omap_rtc_suspend(struct device *dev) static int omap_rtc_resume(struct device *dev) { + struct omap_rtc *rtc = dev_get_drvdata(dev); + /* Enable the clock/module so that we can access the registers */ pm_runtime_get_sync(dev); if (device_may_wakeup(dev)) - disable_irq_wake(omap_rtc_alarm); + disable_irq_wake(rtc->irq_alarm); else - rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG); + rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, rtc->interrupts_reg); return 0; } @@ -560,23 +702,31 @@ static SIMPLE_DEV_PM_OPS(omap_rtc_pm_ops, omap_rtc_suspend, omap_rtc_resume); static void omap_rtc_shutdown(struct platform_device *pdev) { - rtc_write(0, OMAP_RTC_INTERRUPTS_REG); + struct omap_rtc *rtc = platform_get_drvdata(pdev); + u8 mask; + + /* + * Keep the ALARM interrupt enabled to allow the system to power up on + * alarm events. + */ + mask = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG); + mask &= OMAP_RTC_INTERRUPTS_IT_ALARM; + rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, mask); } -MODULE_ALIAS("platform:omap_rtc"); static struct platform_driver omap_rtc_driver = { .remove = __exit_p(omap_rtc_remove), .shutdown = omap_rtc_shutdown, .driver = { - .name = DRIVER_NAME, - .owner = THIS_MODULE, + .name = "omap_rtc", .pm = &omap_rtc_pm_ops, .of_match_table = omap_rtc_of_match, }, - .id_table = omap_rtc_devtype, + .id_table = omap_rtc_id_table, }; module_platform_driver_probe(omap_rtc_driver, omap_rtc_probe); +MODULE_ALIAS("platform:omap_rtc"); MODULE_AUTHOR("George G. Davis (and others)"); MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c new file mode 100644 index 000000000000..95f652165fe9 --- /dev/null +++ b/drivers/rtc/rtc-opal.c @@ -0,0 +1,261 @@ +/* + * IBM OPAL RTC driver + * Copyright (C) 2014 IBM + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. + */ + +#define DRVNAME "rtc-opal" +#define pr_fmt(fmt) DRVNAME ": " fmt + +#include <linux/module.h> +#include <linux/err.h> +#include <linux/rtc.h> +#include <linux/delay.h> +#include <linux/bcd.h> +#include <linux/platform_device.h> +#include <linux/of.h> +#include <asm/opal.h> +#include <asm/firmware.h> + +static void opal_to_tm(u32 y_m_d, u64 h_m_s_ms, struct rtc_time *tm) +{ + tm->tm_year = ((bcd2bin(y_m_d >> 24) * 100) + + bcd2bin((y_m_d >> 16) & 0xff)) - 1900; + tm->tm_mon = bcd2bin((y_m_d >> 8) & 0xff) - 1; + tm->tm_mday = bcd2bin(y_m_d & 0xff); + tm->tm_hour = bcd2bin((h_m_s_ms >> 56) & 0xff); + tm->tm_min = bcd2bin((h_m_s_ms >> 48) & 0xff); + tm->tm_sec = bcd2bin((h_m_s_ms >> 40) & 0xff); + + GregorianDay(tm); +} + +static void tm_to_opal(struct rtc_time *tm, u32 *y_m_d, u64 *h_m_s_ms) +{ + *y_m_d |= ((u32)bin2bcd((tm->tm_year + 1900) / 100)) << 24; + *y_m_d |= ((u32)bin2bcd((tm->tm_year + 1900) % 100)) << 16; + *y_m_d |= ((u32)bin2bcd((tm->tm_mon + 1))) << 8; + *y_m_d |= ((u32)bin2bcd(tm->tm_mday)); + + *h_m_s_ms |= ((u64)bin2bcd(tm->tm_hour)) << 56; + *h_m_s_ms |= ((u64)bin2bcd(tm->tm_min)) << 48; + *h_m_s_ms |= ((u64)bin2bcd(tm->tm_sec)) << 40; +} + +static int opal_get_rtc_time(struct device *dev, struct rtc_time *tm) +{ + long rc = OPAL_BUSY; + u32 y_m_d; + u64 h_m_s_ms; + __be32 __y_m_d; + __be64 __h_m_s_ms; + + while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { + rc = opal_rtc_read(&__y_m_d, &__h_m_s_ms); + if (rc == OPAL_BUSY_EVENT) + opal_poll_events(NULL); + else + msleep(10); + } + + if (rc != OPAL_SUCCESS) + return -EIO; + + y_m_d = be32_to_cpu(__y_m_d); + h_m_s_ms = be64_to_cpu(__h_m_s_ms); + opal_to_tm(y_m_d, h_m_s_ms, tm); + + return 0; +} + +static int opal_set_rtc_time(struct device *dev, struct rtc_time *tm) +{ + long rc = OPAL_BUSY; + u32 y_m_d = 0; + u64 h_m_s_ms = 0; + + tm_to_opal(tm, &y_m_d, &h_m_s_ms); + while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) { + rc = opal_rtc_write(y_m_d, h_m_s_ms); + if (rc == OPAL_BUSY_EVENT) + opal_poll_events(NULL); + else + msleep(10); + } + + return rc == OPAL_SUCCESS ? 0 : -EIO; +} + +/* + * TPO Timed Power-On + * + * TPO get/set OPAL calls care about the hour and min and to make it consistent + * with the rtc utility time conversion functions, we use the 'u64' to store + * its value and perform bit shift by 32 before use.. + */ +static int opal_get_tpo_time(struct device *dev, struct rtc_wkalrm *alarm) +{ + __be32 __y_m_d, __h_m; + struct opal_msg msg; + int rc, token; + u64 h_m_s_ms; + u32 y_m_d; + + token = opal_async_get_token_interruptible(); + if (token < 0) { + if (token != -ERESTARTSYS) + pr_err("Failed to get the async token\n"); + + return token; + } + + rc = opal_tpo_read(token, &__y_m_d, &__h_m); + if (rc != OPAL_ASYNC_COMPLETION) { + rc = -EIO; + goto exit; + } + + rc = opal_async_wait_response(token, &msg); + if (rc) { + rc = -EIO; + goto exit; + } + + rc = be64_to_cpu(msg.params[1]); + if (rc != OPAL_SUCCESS) { + rc = -EIO; + goto exit; + } + + y_m_d = be32_to_cpu(__y_m_d); + h_m_s_ms = ((u64)be32_to_cpu(__h_m) << 32); + opal_to_tm(y_m_d, h_m_s_ms, &alarm->time); + +exit: + opal_async_release_token(token); + return rc; +} + +/* Set Timed Power-On */ +static int opal_set_tpo_time(struct device *dev, struct rtc_wkalrm *alarm) +{ + u64 h_m_s_ms = 0, token; + struct opal_msg msg; + u32 y_m_d = 0; + int rc; + + tm_to_opal(&alarm->time, &y_m_d, &h_m_s_ms); + + token = opal_async_get_token_interruptible(); + if (token < 0) { + if (token != -ERESTARTSYS) + pr_err("Failed to get the async token\n"); + + return token; + } + + /* TPO, we care about hour and minute */ + rc = opal_tpo_write(token, y_m_d, + (u32)((h_m_s_ms >> 32) & 0xffff0000)); + if (rc != OPAL_ASYNC_COMPLETION) { + rc = -EIO; + goto exit; + } + + rc = opal_async_wait_response(token, &msg); + if (rc) { + rc = -EIO; + goto exit; + } + + rc = be64_to_cpu(msg.params[1]); + if (rc != OPAL_SUCCESS) + rc = -EIO; + +exit: + opal_async_release_token(token); + return rc; +} + +static const struct rtc_class_ops opal_rtc_ops = { + .read_time = opal_get_rtc_time, + .set_time = opal_set_rtc_time, + .read_alarm = opal_get_tpo_time, + .set_alarm = opal_set_tpo_time, +}; + +static int opal_rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtc; + + if (pdev->dev.of_node && of_get_property(pdev->dev.of_node, "has-tpo", + NULL)) + device_set_wakeup_capable(&pdev->dev, true); + + rtc = devm_rtc_device_register(&pdev->dev, DRVNAME, &opal_rtc_ops, + THIS_MODULE); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); + + rtc->uie_unsupported = 1; + + return 0; +} + +static const struct of_device_id opal_rtc_match[] = { + { + .compatible = "ibm,opal-rtc", + }, + { } +}; +MODULE_DEVICE_TABLE(of, opal_rtc_match); + +static const struct platform_device_id opal_rtc_driver_ids[] = { + { + .name = "opal-rtc", + }, + { } +}; +MODULE_DEVICE_TABLE(platform, opal_rtc_driver_ids); + +static struct platform_driver opal_rtc_driver = { + .probe = opal_rtc_probe, + .id_table = opal_rtc_driver_ids, + .driver = { + .name = DRVNAME, + .owner = THIS_MODULE, + .of_match_table = opal_rtc_match, + }, +}; + +static int __init opal_rtc_init(void) +{ + if (!firmware_has_feature(FW_FEATURE_OPAL)) + return -ENODEV; + + return platform_driver_register(&opal_rtc_driver); +} + +static void __exit opal_rtc_exit(void) +{ + platform_driver_unregister(&opal_rtc_driver); +} + +MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>"); +MODULE_DESCRIPTION("IBM OPAL RTC driver"); +MODULE_LICENSE("GPL"); + +module_init(opal_rtc_init); +module_exit(opal_rtc_exit); diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c index 4dfe2d793fa3..3b01d567496d 100644 --- a/drivers/rtc/rtc-palmas.c +++ b/drivers/rtc/rtc-palmas.c @@ -363,7 +363,6 @@ static struct platform_driver palmas_rtc_driver = { .probe = palmas_rtc_probe, .remove = palmas_rtc_remove, .driver = { - .owner = THIS_MODULE, .name = "palmas-rtc", .pm = &palmas_rtc_pm_ops, .of_match_table = of_match_ptr(of_palmas_rtc_match), diff --git a/drivers/rtc/rtc-pcap.c b/drivers/rtc/rtc-pcap.c index 40b5c630bc7d..c4433240d8a9 100644 --- a/drivers/rtc/rtc-pcap.c +++ b/drivers/rtc/rtc-pcap.c @@ -184,7 +184,6 @@ static struct platform_driver pcap_rtc_driver = { .remove = __exit_p(pcap_rtc_remove), .driver = { .name = "pcap-rtc", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index c2ef0a22ee94..96fb32e7d6f8 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -28,6 +28,7 @@ #define PCF8563_REG_ST2 0x01 #define PCF8563_BIT_AIE (1 << 1) #define PCF8563_BIT_AF (1 << 3) +#define PCF8563_BITS_ST2_N (7 << 5) #define PCF8563_REG_SC 0x02 /* datetime */ #define PCF8563_REG_MN 0x03 @@ -41,6 +42,13 @@ #define PCF8563_REG_CLKO 0x0D /* clock out */ #define PCF8563_REG_TMRC 0x0E /* timer control */ +#define PCF8563_TMRC_ENABLE BIT(7) +#define PCF8563_TMRC_4096 0 +#define PCF8563_TMRC_64 1 +#define PCF8563_TMRC_1 2 +#define PCF8563_TMRC_1_60 3 +#define PCF8563_TMRC_MASK 3 + #define PCF8563_REG_TMR 0x0F /* timer */ #define PCF8563_SC_LV 0x80 /* low voltage */ @@ -118,22 +126,21 @@ static int pcf8563_write_block_data(struct i2c_client *client, static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on) { - unsigned char buf[2]; + unsigned char buf; int err; - err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, buf + 1); + err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf); if (err < 0) return err; if (on) - buf[1] |= PCF8563_BIT_AIE; + buf |= PCF8563_BIT_AIE; else - buf[1] &= ~PCF8563_BIT_AIE; + buf &= ~PCF8563_BIT_AIE; - buf[1] &= ~PCF8563_BIT_AF; - buf[0] = PCF8563_REG_ST2; + buf &= ~(PCF8563_BIT_AF | PCF8563_BITS_ST2_N); - err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, buf + 1); + err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf); if (err < 0) { dev_err(&client->dev, "%s: write error\n", __func__); return -EIO; @@ -336,8 +343,8 @@ static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm) __func__, buf[0], buf[1], buf[2], buf[3]); tm->time.tm_min = bcd2bin(buf[0] & 0x7F); - tm->time.tm_hour = bcd2bin(buf[1] & 0x7F); - tm->time.tm_mday = bcd2bin(buf[2] & 0x1F); + tm->time.tm_hour = bcd2bin(buf[1] & 0x3F); + tm->time.tm_mday = bcd2bin(buf[2] & 0x3F); tm->time.tm_wday = bcd2bin(buf[3] & 0x7); tm->time.tm_mon = -1; tm->time.tm_year = -1; @@ -361,6 +368,14 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) struct i2c_client *client = to_i2c_client(dev); unsigned char buf[4]; int err; + unsigned long alarm_time; + + /* The alarm has no seconds, round up to nearest minute */ + if (tm->time.tm_sec) { + rtc_tm_to_time(&tm->time, &alarm_time); + alarm_time += 60-tm->time.tm_sec; + rtc_time_to_tm(alarm_time, &tm->time); + } dev_dbg(dev, "%s, min=%d hour=%d wday=%d mday=%d " "enabled=%d pending=%d\n", __func__, @@ -381,6 +396,7 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm) static int pcf8563_irq_enable(struct device *dev, unsigned int enabled) { + dev_dbg(dev, "%s: en=%d\n", __func__, enabled); return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled); } @@ -398,6 +414,8 @@ static int pcf8563_probe(struct i2c_client *client, { struct pcf8563 *pcf8563; int err; + unsigned char buf; + unsigned char alm_pending; dev_dbg(&client->dev, "%s\n", __func__); @@ -415,6 +433,22 @@ static int pcf8563_probe(struct i2c_client *client, pcf8563->client = client; device_set_wakeup_capable(&client->dev, 1); + /* Set timer to lowest frequency to save power (ref Haoyu datasheet) */ + buf = PCF8563_TMRC_1_60; + err = pcf8563_write_block_data(client, PCF8563_REG_TMRC, 1, &buf); + if (err < 0) { + dev_err(&client->dev, "%s: write error\n", __func__); + return err; + } + + err = pcf8563_get_alarm_mode(client, NULL, &alm_pending); + if (err < 0) { + dev_err(&client->dev, "%s: read error\n", __func__); + return err; + } + if (alm_pending) + pcf8563_set_alarm_mode(client, 0); + pcf8563->rtc = devm_rtc_device_register(&client->dev, pcf8563_driver.driver.name, &pcf8563_rtc_ops, THIS_MODULE); @@ -435,6 +469,9 @@ static int pcf8563_probe(struct i2c_client *client, } + /* the pcf8563 alarm only supports a minute accuracy */ + pcf8563->rtc->uie_unsupported = 1; + return 0; } diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 5adcf111fc14..795fcbd02ea3 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -531,7 +531,6 @@ static struct platform_driver pm8xxx_rtc_driver = { .probe = pm8xxx_rtc_probe, .driver = { .name = "rtc-pm8xxx", - .owner = THIS_MODULE, .pm = &pm8xxx_rtc_pm_ops, .of_match_table = pm8xxx_id_table, }, diff --git a/drivers/rtc/rtc-ps3.c b/drivers/rtc/rtc-ps3.c index 554ada5e9b76..6a8f5d758eac 100644 --- a/drivers/rtc/rtc-ps3.c +++ b/drivers/rtc/rtc-ps3.c @@ -74,7 +74,6 @@ static int __init ps3_rtc_probe(struct platform_device *dev) static struct platform_driver ps3_rtc_driver = { .driver = { .name = "rtc-ps3", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c index 1cff2a21db67..c0a6e638c672 100644 --- a/drivers/rtc/rtc-puv3.c +++ b/drivers/rtc/rtc-puv3.c @@ -328,7 +328,6 @@ static struct platform_driver puv3_rtc_driver = { .remove = puv3_rtc_remove, .driver = { .name = "PKUnity-v3-RTC", - .owner = THIS_MODULE, .pm = &puv3_rtc_pm_ops, } }; diff --git a/drivers/rtc/rtc-rc5t583.c b/drivers/rtc/rtc-rc5t583.c index e53e9b1c69b3..f28d57788951 100644 --- a/drivers/rtc/rtc-rc5t583.c +++ b/drivers/rtc/rtc-rc5t583.c @@ -310,7 +310,6 @@ static struct platform_driver rc5t583_rtc_driver = { .probe = rc5t583_rtc_probe, .remove = rc5t583_rtc_remove, .driver = { - .owner = THIS_MODULE, .name = "rtc-rc5t583", .pm = &rc5t583_rtc_pm_ops, }, diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c index 89d073679267..b548551f385c 100644 --- a/drivers/rtc/rtc-rp5c01.c +++ b/drivers/rtc/rtc-rp5c01.c @@ -273,7 +273,6 @@ static int __exit rp5c01_rtc_remove(struct platform_device *dev) static struct platform_driver rp5c01_rtc_driver = { .driver = { .name = "rtc-rp5c01", - .owner = THIS_MODULE, }, .remove = __exit_p(rp5c01_rtc_remove), }; diff --git a/drivers/rtc/rtc-rs5c313.c b/drivers/rtc/rtc-rs5c313.c index 68f7856422f1..5f48167c802a 100644 --- a/drivers/rtc/rtc-rs5c313.c +++ b/drivers/rtc/rtc-rs5c313.c @@ -381,7 +381,6 @@ static int rs5c313_rtc_probe(struct platform_device *pdev) static struct platform_driver rs5c313_rtc_platform_driver = { .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, }, .probe = rs5c313_rtc_probe, }; diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 806072238c00..4241eeab3386 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -896,7 +896,6 @@ static struct platform_driver s3c_rtc_driver = { .remove = s3c_rtc_remove, .driver = { .name = "s3c-rtc", - .owner = THIS_MODULE, .pm = &s3c_rtc_pm_ops, .of_match_table = of_match_ptr(s3c_rtc_dt_match), }, diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 8754c33361e8..b5e7c4670205 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -837,7 +837,6 @@ static const struct platform_device_id s5m_rtc_id[] = { static struct platform_driver s5m_rtc_driver = { .driver = { .name = "s5m-rtc", - .owner = THIS_MODULE, .pm = &s5m_rtc_pm_ops, }, .probe = s5m_rtc_probe, diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index d0d2b047658b..2b81dd4baf17 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -782,7 +782,6 @@ static SIMPLE_DEV_PM_OPS(sh_rtc_pm_ops, sh_rtc_suspend, sh_rtc_resume); static struct platform_driver sh_rtc_platform_driver = { .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .pm = &sh_rtc_pm_ops, }, .remove = __exit_p(sh_rtc_remove), diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c index 76e38007ba90..edc3b43282d4 100644 --- a/drivers/rtc/rtc-sirfsoc.c +++ b/drivers/rtc/rtc-sirfsoc.c @@ -47,6 +47,7 @@ struct sirfsoc_rtc_drv { unsigned irq_wake; /* Overflow for every 8 years extra time */ u32 overflow_rtc; + spinlock_t lock; #ifdef CONFIG_PM u32 saved_counter; u32 saved_overflow_rtc; @@ -61,7 +62,7 @@ static int sirfsoc_rtc_read_alarm(struct device *dev, rtcdrv = dev_get_drvdata(dev); - local_irq_disable(); + spin_lock_irq(&rtcdrv->lock); rtc_count = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); @@ -84,7 +85,8 @@ static int sirfsoc_rtc_read_alarm(struct device *dev, if (sirfsoc_rtc_iobrg_readl( rtcdrv->rtc_base + RTC_STATUS) & SIRFSOC_RTC_AL0E) alrm->enabled = 1; - local_irq_enable(); + + spin_unlock_irq(&rtcdrv->lock); return 0; } @@ -99,7 +101,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, if (alrm->enabled) { rtc_tm_to_time(&(alrm->time), &rtc_alarm); - local_irq_disable(); + spin_lock_irq(&rtcdrv->lock); rtc_status_reg = sirfsoc_rtc_iobrg_readl( rtcdrv->rtc_base + RTC_STATUS); @@ -123,14 +125,15 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, rtc_status_reg |= SIRFSOC_RTC_AL0E; sirfsoc_rtc_iobrg_writel( rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS); - local_irq_enable(); + + spin_unlock_irq(&rtcdrv->lock); } else { /* * if this function was called with enabled=0 * then it could mean that the application is * trying to cancel an ongoing alarm */ - local_irq_disable(); + spin_lock_irq(&rtcdrv->lock); rtc_status_reg = sirfsoc_rtc_iobrg_readl( rtcdrv->rtc_base + RTC_STATUS); @@ -146,7 +149,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, rtcdrv->rtc_base + RTC_STATUS); } - local_irq_enable(); + spin_unlock_irq(&rtcdrv->lock); } return 0; @@ -209,12 +212,38 @@ static int sirfsoc_rtc_ioctl(struct device *dev, unsigned int cmd, } } +static int sirfsoc_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) +{ + unsigned long rtc_status_reg = 0x0; + struct sirfsoc_rtc_drv *rtcdrv; + + rtcdrv = dev_get_drvdata(dev); + + spin_lock_irq(&rtcdrv->lock); + + rtc_status_reg = sirfsoc_rtc_iobrg_readl( + rtcdrv->rtc_base + RTC_STATUS); + if (enabled) + rtc_status_reg |= SIRFSOC_RTC_AL0E; + else + rtc_status_reg &= ~SIRFSOC_RTC_AL0E; + + sirfsoc_rtc_iobrg_writel(rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS); + + spin_unlock_irq(&rtcdrv->lock); + + return 0; + +} + static const struct rtc_class_ops sirfsoc_rtc_ops = { .read_time = sirfsoc_rtc_read_time, .set_time = sirfsoc_rtc_set_time, .read_alarm = sirfsoc_rtc_read_alarm, .set_alarm = sirfsoc_rtc_set_alarm, - .ioctl = sirfsoc_rtc_ioctl + .ioctl = sirfsoc_rtc_ioctl, + .alarm_irq_enable = sirfsoc_rtc_alarm_irq_enable }; static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata) @@ -223,6 +252,8 @@ static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata) unsigned long rtc_status_reg = 0x0; unsigned long events = 0x0; + spin_lock(&rtcdrv->lock); + rtc_status_reg = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_STATUS); /* this bit will be set ONLY if an alarm was active * and it expired NOW @@ -240,6 +271,9 @@ static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata) rtc_status_reg &= ~(SIRFSOC_RTC_AL0E); } sirfsoc_rtc_iobrg_writel(rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS); + + spin_unlock(&rtcdrv->lock); + /* this should wake up any apps polling/waiting on the read * after setting the alarm */ @@ -267,6 +301,8 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev) if (rtcdrv == NULL) return -ENOMEM; + spin_lock_init(&rtcdrv->lock); + err = of_property_read_u32(np, "reg", &rtcdrv->rtc_base); if (err) { dev_err(&pdev->dev, "unable to find base address of rtc node in dtb\n"); @@ -286,14 +322,6 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev) rtc_div = ((32768 / RTC_HZ) / 2) - 1; sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV); - rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, - &sirfsoc_rtc_ops, THIS_MODULE); - if (IS_ERR(rtcdrv->rtc)) { - err = PTR_ERR(rtcdrv->rtc); - dev_err(&pdev->dev, "can't register RTC device\n"); - return err; - } - /* 0x3 -> RTC_CLK */ sirfsoc_rtc_iobrg_writel(SIRFSOC_RTC_CLK, rtcdrv->rtc_base + RTC_CLOCK_SWITCH); @@ -308,6 +336,14 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev) rtcdrv->overflow_rtc = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE); + rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &sirfsoc_rtc_ops, THIS_MODULE); + if (IS_ERR(rtcdrv->rtc)) { + err = PTR_ERR(rtcdrv->rtc); + dev_err(&pdev->dev, "can't register RTC device\n"); + return err; + } + rtcdrv->irq = platform_get_irq(pdev, 0); err = devm_request_irq( &pdev->dev, @@ -408,7 +444,6 @@ static SIMPLE_DEV_PM_OPS(sirfsoc_rtc_pm_ops, static struct platform_driver sirfsoc_rtc_driver = { .driver = { .name = "sirfsoc-rtc", - .owner = THIS_MODULE, .pm = &sirfsoc_rtc_pm_ops, .of_match_table = sirfsoc_rtc_of_match, }, diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index fa384fe28988..0479e807a776 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c @@ -17,6 +17,7 @@ #include <linux/of_device.h> #include <linux/platform_device.h> #include <linux/rtc.h> +#include <linux/clk.h> /* These register offsets are relative to LP (Low Power) range */ #define SNVS_LPCR 0x04 @@ -39,6 +40,7 @@ struct snvs_rtc_data { void __iomem *ioaddr; int irq; spinlock_t lock; + struct clk *clk; }; static u32 rtc_read_lp_counter(void __iomem *ioaddr) @@ -260,6 +262,18 @@ static int snvs_rtc_probe(struct platform_device *pdev) if (data->irq < 0) return data->irq; + data->clk = devm_clk_get(&pdev->dev, "snvs-rtc"); + if (IS_ERR(data->clk)) { + data->clk = NULL; + } else { + ret = clk_prepare_enable(data->clk); + if (ret) { + dev_err(&pdev->dev, + "Could not prepare or enable the snvs clock\n"); + return ret; + } + } + platform_set_drvdata(pdev, data); spin_lock_init(&data->lock); @@ -280,7 +294,7 @@ static int snvs_rtc_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "failed to request irq %d: %d\n", data->irq, ret); - return ret; + goto error_rtc_device_register; } data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, @@ -288,10 +302,16 @@ static int snvs_rtc_probe(struct platform_device *pdev) if (IS_ERR(data->rtc)) { ret = PTR_ERR(data->rtc); dev_err(&pdev->dev, "failed to register rtc: %d\n", ret); - return ret; + goto error_rtc_device_register; } return 0; + +error_rtc_device_register: + if (data->clk) + clk_disable_unprepare(data->clk); + + return ret; } #ifdef CONFIG_PM_SLEEP @@ -302,21 +322,41 @@ static int snvs_rtc_suspend(struct device *dev) if (device_may_wakeup(dev)) enable_irq_wake(data->irq); + if (data->clk) + clk_disable_unprepare(data->clk); + return 0; } static int snvs_rtc_resume(struct device *dev) { struct snvs_rtc_data *data = dev_get_drvdata(dev); + int ret; if (device_may_wakeup(dev)) disable_irq_wake(data->irq); + if (data->clk) { + ret = clk_prepare_enable(data->clk); + if (ret) + return ret; + } + return 0; } -#endif -static SIMPLE_DEV_PM_OPS(snvs_rtc_pm_ops, snvs_rtc_suspend, snvs_rtc_resume); +static const struct dev_pm_ops snvs_rtc_pm_ops = { + .suspend_noirq = snvs_rtc_suspend, + .resume_noirq = snvs_rtc_resume, +}; + +#define SNVS_RTC_PM_OPS (&snvs_rtc_pm_ops) + +#else + +#define SNVS_RTC_PM_OPS NULL + +#endif static const struct of_device_id snvs_dt_ids[] = { { .compatible = "fsl,sec-v4.0-mon-rtc-lp", }, @@ -327,8 +367,7 @@ MODULE_DEVICE_TABLE(of, snvs_dt_ids); static struct platform_driver snvs_rtc_driver = { .driver = { .name = "snvs_rtc", - .owner = THIS_MODULE, - .pm = &snvs_rtc_pm_ops, + .pm = SNVS_RTC_PM_OPS, .of_match_table = snvs_dt_ids, }, .probe = snvs_rtc_probe, diff --git a/drivers/rtc/rtc-starfire.c b/drivers/rtc/rtc-starfire.c index f7d8a6db8078..83a057a03060 100644 --- a/drivers/rtc/rtc-starfire.c +++ b/drivers/rtc/rtc-starfire.c @@ -54,7 +54,6 @@ static int __init starfire_rtc_probe(struct platform_device *pdev) static struct platform_driver starfire_rtc_driver = { .driver = { .name = "rtc-starfire", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c index 35ed49ea1f81..0e93b714ee41 100644 --- a/drivers/rtc/rtc-stk17ta8.c +++ b/drivers/rtc/rtc-stk17ta8.c @@ -358,7 +358,6 @@ static struct platform_driver stk17ta8_rtc_driver = { .remove = stk17ta8_rtc_remove, .driver = { .name = "stk17ta8", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index ea96492357b0..2939cdcb2688 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -341,7 +341,6 @@ static struct platform_driver stmp3xxx_rtcdrv = { .remove = stmp3xxx_rtc_remove, .driver = { .name = "stmp3xxx-rtc", - .owner = THIS_MODULE, .pm = &stmp3xxx_rtc_pm_ops, .of_match_table = rtc_dt_ids, }, diff --git a/drivers/rtc/rtc-sun4v.c b/drivers/rtc/rtc-sun4v.c index bc97ff91341d..7c696c12f28f 100644 --- a/drivers/rtc/rtc-sun4v.c +++ b/drivers/rtc/rtc-sun4v.c @@ -95,7 +95,6 @@ static int __init sun4v_rtc_probe(struct platform_device *pdev) static struct platform_driver sun4v_rtc_driver = { .driver = { .name = "rtc-sun4v", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c index b6f21f73d508..6e678fa4dfaf 100644 --- a/drivers/rtc/rtc-sunxi.c +++ b/drivers/rtc/rtc-sunxi.c @@ -511,7 +511,6 @@ static struct platform_driver sunxi_rtc_driver = { .remove = sunxi_rtc_remove, .driver = { .name = "sunxi-rtc", - .owner = THIS_MODULE, .of_match_table = sunxi_rtc_dt_ids, }, }; diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c index 76af92ad5a8a..d948277057d8 100644 --- a/drivers/rtc/rtc-tegra.c +++ b/drivers/rtc/rtc-tegra.c @@ -420,7 +420,6 @@ static struct platform_driver tegra_rtc_driver = { .shutdown = tegra_rtc_shutdown, .driver = { .name = "tegra_rtc", - .owner = THIS_MODULE, .of_match_table = tegra_rtc_dt_match, .pm = &tegra_rtc_pm_ops, }, diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index 6599c20bc454..8f86fa91de1a 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -129,7 +129,6 @@ static struct platform_driver test_driver = { .remove = test_remove, .driver = { .name = "rtc-test", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-tile.c b/drivers/rtc/rtc-tile.c index ff9632eb79f2..0b60867d8390 100644 --- a/drivers/rtc/rtc-tile.c +++ b/drivers/rtc/rtc-tile.c @@ -94,7 +94,6 @@ static int tile_rtc_probe(struct platform_device *dev) static struct platform_driver tile_rtc_platform_driver = { .driver = { .name = "rtc-tile", - .owner = THIS_MODULE, }, .probe = tile_rtc_probe, }; diff --git a/drivers/rtc/rtc-tps6586x.c b/drivers/rtc/rtc-tps6586x.c index 426901cef14f..3b6ce80a769c 100644 --- a/drivers/rtc/rtc-tps6586x.c +++ b/drivers/rtc/rtc-tps6586x.c @@ -337,7 +337,6 @@ static SIMPLE_DEV_PM_OPS(tps6586x_pm_ops, tps6586x_rtc_suspend, static struct platform_driver tps6586x_rtc_driver = { .driver = { .name = "tps6586x-rtc", - .owner = THIS_MODULE, .pm = &tps6586x_pm_ops, }, .probe = tps6586x_rtc_probe, diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index 2583349fbde5..f42aa2b2dcba 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -326,7 +326,6 @@ static struct platform_driver tps65910_rtc_driver = { .probe = tps65910_rtc_probe, .remove = tps65910_rtc_remove, .driver = { - .owner = THIS_MODULE, .name = "tps65910-rtc", .pm = &tps65910_rtc_pm_ops, }, diff --git a/drivers/rtc/rtc-tps80031.c b/drivers/rtc/rtc-tps80031.c index 3e400dce2d06..27e254cde715 100644 --- a/drivers/rtc/rtc-tps80031.c +++ b/drivers/rtc/rtc-tps80031.c @@ -324,7 +324,6 @@ static SIMPLE_DEV_PM_OPS(tps80031_pm_ops, tps80031_rtc_suspend, static struct platform_driver tps80031_rtc_driver = { .driver = { .name = "tps80031-rtc", - .owner = THIS_MODULE, .pm = &tps80031_pm_ops, }, .probe = tps80031_rtc_probe, diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 1915464e4cd6..5baea3f54926 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -608,7 +608,6 @@ static struct platform_driver twl4030rtc_driver = { .remove = twl_rtc_remove, .shutdown = twl_rtc_shutdown, .driver = { - .owner = THIS_MODULE, .name = "twl_rtc", .pm = &twl_rtc_pm_ops, .of_match_table = of_match_ptr(twl_rtc_of_match), diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c index 2e678c681b13..cb7f94ede516 100644 --- a/drivers/rtc/rtc-tx4939.c +++ b/drivers/rtc/rtc-tx4939.c @@ -287,7 +287,6 @@ static struct platform_driver tx4939_rtc_driver = { .remove = __exit_p(tx4939_rtc_remove), .driver = { .name = "tx4939rtc", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index 25222cdccdc6..bfbfa7ed7bbf 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -382,7 +382,6 @@ static struct platform_driver rtc_device_driver = { .remove = rtc_remove, .driver = { .name = "v3020", - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index 88c9c92e89fd..f64c282275b3 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -375,7 +375,6 @@ static struct platform_driver rtc_platform_driver = { .probe = rtc_probe, .driver = { .name = rtc_name, - .owner = THIS_MODULE, }, }; diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index 051da968da6d..a58b6d17e6f0 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -277,7 +277,6 @@ static struct platform_driver vt8500_rtc_driver = { .remove = vt8500_rtc_remove, .driver = { .name = "vt8500-rtc", - .owner = THIS_MODULE, .of_match_table = wmt_dt_ids, }, }; diff --git a/drivers/rtc/rtc-xgene.c b/drivers/rtc/rtc-xgene.c index 14129cc85bdb..65b432a096fe 100644 --- a/drivers/rtc/rtc-xgene.c +++ b/drivers/rtc/rtc-xgene.c @@ -264,7 +264,6 @@ static struct platform_driver xgene_rtc_driver = { .probe = xgene_rtc_probe, .remove = xgene_rtc_remove, .driver = { - .owner = THIS_MODULE, .name = "xgene-rtc", .pm = &xgene_rtc_pm_ops, .of_match_table = of_match_ptr(xgene_rtc_of_match), |