diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2015-07-24 14:20:42 +1000 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2015-07-24 14:20:42 +1000 |
commit | 3132e645860a96bad81b63412440cd51345d488a (patch) | |
tree | d0a5b0dec80d3c4bfdd0e94ca04b11f8398fd45e | |
parent | fdb2f755e878d3f804f36085625f23172417b08f (diff) | |
parent | 2f27941335c02d61d93f673b46c71b3f1c944f00 (diff) |
Merge remote-tracking branch 'rtc/rtc-next'
27 files changed, 532 insertions, 188 deletions
diff --git a/Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.txt b/Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.txt new file mode 100644 index 000000000000..ad41a040432c --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.txt @@ -0,0 +1,21 @@ +NXP LPC1788 real-time clock + +The LPC1788 RTC provides calendar and clock functionality +together with periodic tick and alarm interrupt support. + +Required properties: +- compatible : must contain "nxp,lpc1788-rtc" +- reg : Specifies base physical address and size of the registers. +- interrupts : A single interrupt specifier. +- clocks : Must contain entries for rtc and register clock +- clock-names : Must contain "rtc" and "reg" + See ../clocks/clock-bindings.txt for details. + +Example: +rtc: rtc@40046000 { + compatible = "nxp,lpc1788-rtc"; + reg = <0x40046000 0x1000>; + interrupts = <47>; + clocks = <&creg_clk 0>, <&ccu1 CLK_CPU_BUS>; + clock-names = "rtc", "reg"; +}; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 533bfa3b6039..e132ccbec515 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1456,6 +1456,18 @@ config RTC_DRV_JZ4740 This driver can also be buillt as a module. If so, the module will be called rtc-jz4740. +config RTC_DRV_LPC24XX + tristate "NXP RTC for LPC178x/18xx/408x/43xx" + depends on ARCH_LPC18XX || COMPILE_TEST + depends on OF && HAS_IOMEM + help + This enables support for the NXP RTC found which can be found on + NXP LPC178x/18xx/408x/43xx devices. + + If you have one of the devices above enable this driver to use + the hardware RTC. This driver can also be buillt as a module. If + so, the module will be called rtc-lpc24xx. + config RTC_DRV_LPC32XX depends on ARCH_LPC32XX tristate "NXP LPC32XX RTC" diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 1b09a62fcf4b..279738449a8d 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -74,6 +74,7 @@ obj-$(CONFIG_RTC_DRV_ISL12057) += rtc-isl12057.o obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o +obj-$(CONFIG_RTC_DRV_LPC24XX) += rtc-lpc24xx.o obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o obj-$(CONFIG_RTC_DRV_LOONGSON1) += rtc-ls1x.o obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index ea2a315df6b7..de7707f7e766 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -234,8 +234,9 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, err = device_register(&rtc->dev); if (err) { + /* This will free both memory and the ID */ put_device(&rtc->dev); - goto exit_kfree; + goto exit; } rtc_dev_add_device(rtc); @@ -247,9 +248,6 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, return rtc; -exit_kfree: - kfree(rtc); - exit_ida: ida_simple_remove(&rtc_ida, id); @@ -268,19 +266,18 @@ EXPORT_SYMBOL_GPL(rtc_device_register); */ void rtc_device_unregister(struct rtc_device *rtc) { - if (get_device(&rtc->dev) != NULL) { - mutex_lock(&rtc->ops_lock); - /* remove innards of this RTC, then disable it, before - * letting any rtc_class_open() users access it again - */ - rtc_sysfs_del_device(rtc); - rtc_dev_del_device(rtc); - rtc_proc_del_device(rtc); - device_unregister(&rtc->dev); - rtc->ops = NULL; - mutex_unlock(&rtc->ops_lock); - put_device(&rtc->dev); - } + mutex_lock(&rtc->ops_lock); + /* + * Remove innards of this RTC, then disable it, before + * letting any rtc_class_open() users access it again + */ + rtc_sysfs_del_device(rtc); + rtc_dev_del_device(rtc); + rtc_proc_del_device(rtc); + device_del(&rtc->dev); + rtc->ops = NULL; + mutex_unlock(&rtc->ops_lock); + put_device(&rtc->dev); } EXPORT_SYMBOL_GPL(rtc_device_unregister); diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c index 7df0579d9852..466bf7f9a285 100644 --- a/drivers/rtc/rtc-88pm80x.c +++ b/drivers/rtc/rtc-88pm80x.c @@ -251,17 +251,26 @@ static SIMPLE_DEV_PM_OPS(pm80x_rtc_pm_ops, pm80x_rtc_suspend, pm80x_rtc_resume); static int pm80x_rtc_probe(struct platform_device *pdev) { struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent); - struct pm80x_platform_data *pm80x_pdata = - dev_get_platdata(pdev->dev.parent); - struct pm80x_rtc_pdata *pdata = NULL; + struct pm80x_rtc_pdata *pdata = dev_get_platdata(&pdev->dev); struct pm80x_rtc_info *info; + struct device_node *node = pdev->dev.of_node; struct rtc_time tm; unsigned long ticks = 0; int ret; - pdata = dev_get_platdata(&pdev->dev); - if (pdata == NULL) - dev_warn(&pdev->dev, "No platform data!\n"); + if (!pdata && !node) { + dev_err(&pdev->dev, + "pm80x-rtc requires platform data or of_node\n"); + return -EINVAL; + } + + if (!pdata) { + pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + } info = devm_kzalloc(&pdev->dev, sizeof(struct pm80x_rtc_info), GFP_KERNEL); @@ -327,11 +336,8 @@ static int pm80x_rtc_probe(struct platform_device *pdev) regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_RTC1_USE_XO, PM800_RTC1_USE_XO); - if (pm80x_pdata) { - pdata = pm80x_pdata->rtc; - if (pdata) - info->rtc_dev->dev.platform_data = &pdata->rtc_wakeup; - } + /* remember whether this power up is caused by PMIC RTC or not */ + info->rtc_dev->dev.platform_data = &pdata->rtc_wakeup; device_init_wakeup(&pdev->dev, 1); diff --git a/drivers/rtc/rtc-ab-b5ze-s3.c b/drivers/rtc/rtc-ab-b5ze-s3.c index b5cbc1bf5a3e..0fb1d767afa9 100644 --- a/drivers/rtc/rtc-ab-b5ze-s3.c +++ b/drivers/rtc/rtc-ab-b5ze-s3.c @@ -1020,7 +1020,6 @@ MODULE_DEVICE_TABLE(i2c, abb5zes3_id); static struct i2c_driver abb5zes3_driver = { .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .pm = &abb5zes3_rtc_pm_ops, .of_match_table = of_match_ptr(abb5zes3_dt_match), }, diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c index 92679df6d6e2..0299988b4f13 100644 --- a/drivers/rtc/rtc-bq32k.c +++ b/drivers/rtc/rtc-bq32k.c @@ -212,7 +212,7 @@ static int bq32k_probe(struct i2c_client *client, if (error) return error; - if (client && client->dev.of_node) + if (client->dev.of_node) trickle_charger_of_init(dev, client->dev.of_node); rtc = devm_rtc_device_register(&client->dev, bq32k_driver.driver.name, @@ -234,7 +234,6 @@ MODULE_DEVICE_TABLE(i2c, bq32k_id); static struct i2c_driver bq32k_driver = { .driver = { .name = "bq32k", - .owner = THIS_MODULE, }, .probe = bq32k_probe, .id_table = bq32k_id, diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 799c34bcb26f..a6d9434addf6 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -477,6 +477,7 @@ void rtc_dev_prepare(struct rtc_device *rtc) cdev_init(&rtc->char_dev, &rtc_dev_fops); rtc->char_dev.owner = rtc->owner; + rtc->char_dev.kobj.parent = &rtc->dev.kobj; } void rtc_dev_add_device(struct rtc_device *rtc) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 6e76de1856fc..c51bc0a65afc 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -11,14 +11,17 @@ * published by the Free Software Foundation. */ -#include <linux/module.h> +#include <linux/bcd.h> +#include <linux/i2c.h> #include <linux/init.h> +#include <linux/module.h> +#include <linux/of_device.h> +#include <linux/of_irq.h> +#include <linux/pm_wakeirq.h> +#include <linux/rtc/ds1307.h> +#include <linux/rtc.h> #include <linux/slab.h> -#include <linux/i2c.h> #include <linux/string.h> -#include <linux/rtc.h> -#include <linux/bcd.h> -#include <linux/rtc/ds1307.h> /* * We can't determine type by probing, but if we expect pre-Linux code @@ -114,7 +117,7 @@ struct ds1307 { #define HAS_ALARM 1 /* bit 1 == irq claimed */ struct i2c_client *client; struct rtc_device *rtc; - struct work_struct work; + int wakeirq; s32 (*read_block_data)(const struct i2c_client *client, u8 command, u8 length, u8 *values); s32 (*write_block_data)(const struct i2c_client *client, u8 command, @@ -311,27 +314,17 @@ static s32 ds1307_native_smbus_read_block_data(const struct i2c_client *client, /*----------------------------------------------------------------------*/ /* - * The IRQ logic includes a "real" handler running in IRQ context just - * long enough to schedule this workqueue entry. We need a task context - * to talk to the RTC, since I2C I/O calls require that; and disable the - * IRQ until we clear its status on the chip, so that this handler can - * work with any type of triggering (not just falling edge). - * * The ds1337 and ds1339 both have two alarms, but we only use the first * one (with a "seconds" field). For ds1337 we expect nINTA is our alarm * signal; ds1339 chips have only one alarm signal. */ -static void ds1307_work(struct work_struct *work) +static irqreturn_t ds1307_irq(int irq, void *dev_id) { - struct ds1307 *ds1307; - struct i2c_client *client; - struct mutex *lock; + struct i2c_client *client = dev_id; + struct ds1307 *ds1307 = i2c_get_clientdata(client); + struct mutex *lock = &ds1307->rtc->ops_lock; int stat, control; - ds1307 = container_of(work, struct ds1307, work); - client = ds1307->client; - lock = &ds1307->rtc->ops_lock; - mutex_lock(lock); stat = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS); if (stat < 0) @@ -352,18 +345,8 @@ static void ds1307_work(struct work_struct *work) } out: - if (test_bit(HAS_ALARM, &ds1307->flags)) - enable_irq(client->irq); mutex_unlock(lock); -} - -static irqreturn_t ds1307_irq(int irq, void *dev_id) -{ - struct i2c_client *client = dev_id; - struct ds1307 *ds1307 = i2c_get_clientdata(client); - disable_irq_nosync(irq); - schedule_work(&ds1307->work); return IRQ_HANDLED; } @@ -634,13 +617,14 @@ static const struct rtc_class_ops ds13xx_rtc_ops = { MCP794XX_BIT_ALMX_C1 | \ MCP794XX_BIT_ALMX_C2) -static void mcp794xx_work(struct work_struct *work) +static irqreturn_t mcp794xx_irq(int irq, void *dev_id) { - struct ds1307 *ds1307 = container_of(work, struct ds1307, work); - struct i2c_client *client = ds1307->client; + struct i2c_client *client = dev_id; + struct ds1307 *ds1307 = i2c_get_clientdata(client); + struct mutex *lock = &ds1307->rtc->ops_lock; int reg, ret; - mutex_lock(&ds1307->rtc->ops_lock); + mutex_lock(lock); /* Check and clear alarm 0 interrupt flag. */ reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_ALARM0_CTRL); @@ -665,9 +649,9 @@ static void mcp794xx_work(struct work_struct *work) rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF); out: - if (test_bit(HAS_ALARM, &ds1307->flags)) - enable_irq(client->irq); - mutex_unlock(&ds1307->rtc->ops_lock); + mutex_unlock(lock); + + return IRQ_HANDLED; } static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t) @@ -896,6 +880,8 @@ static int ds1307_probe(struct i2c_client *client, bool want_irq = false; unsigned char *buf; struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev); + irq_handler_t irq_handler = ds1307_irq; + static const int bbsqi_bitpos[] = { [ds_1337] = 0, [ds_1339] = DS1339_BIT_BBSQI, @@ -962,8 +948,6 @@ static int ds1307_probe(struct i2c_client *client, * running on Vbackup (BBSQI/BBSQW) */ if (ds1307->client->irq > 0 && chip->alarm) { - INIT_WORK(&ds1307->work, ds1307_work); - ds1307->regs[0] |= DS1337_BIT_INTCN | bbsqi_bitpos[ds1307->type]; ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE); @@ -1053,7 +1037,7 @@ static int ds1307_probe(struct i2c_client *client, case mcp794xx: rtc_ops = &mcp794xx_rtc_ops; if (ds1307->client->irq > 0 && chip->alarm) { - INIT_WORK(&ds1307->work, mcp794xx_work); + irq_handler = mcp794xx_irq; want_irq = true; } break; @@ -1176,18 +1160,43 @@ read_rtc: } if (want_irq) { - err = request_irq(client->irq, ds1307_irq, IRQF_SHARED, - ds1307->rtc->name, client); + struct device_node *node = client->dev.of_node; + + err = devm_request_threaded_irq(&client->dev, + client->irq, NULL, irq_handler, + IRQF_SHARED | IRQF_ONESHOT, + ds1307->rtc->name, client); if (err) { client->irq = 0; dev_err(&client->dev, "unable to request IRQ!\n"); - } else { + goto no_irq; + } + + set_bit(HAS_ALARM, &ds1307->flags); + dev_dbg(&client->dev, "got IRQ %d\n", client->irq); + + /* Currently supported by OF code only! */ + if (!node) + goto no_irq; + + err = of_irq_get(node, 1); + if (err <= 0) { + if (err == -EPROBE_DEFER) + goto exit; + goto no_irq; + } + ds1307->wakeirq = err; - set_bit(HAS_ALARM, &ds1307->flags); - dev_dbg(&client->dev, "got IRQ %d\n", client->irq); + err = dev_pm_set_dedicated_wake_irq(&client->dev, + ds1307->wakeirq); + if (err) { + dev_err(&client->dev, "unable to setup wakeIRQ %d!\n", + err); + goto exit; } } +no_irq: if (chip->nvram_size) { ds1307->nvram = devm_kzalloc(&client->dev, @@ -1231,10 +1240,8 @@ static int ds1307_remove(struct i2c_client *client) { struct ds1307 *ds1307 = i2c_get_clientdata(client); - if (test_and_clear_bit(HAS_ALARM, &ds1307->flags)) { - free_irq(client->irq, client); - cancel_work_sync(&ds1307->work); - } + if (ds1307->wakeirq) + dev_pm_clear_wake_irq(&client->dev); if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram); @@ -1245,7 +1252,6 @@ static int ds1307_remove(struct i2c_client *client) static struct i2c_driver ds1307_driver = { .driver = { .name = "rtc-ds1307", - .owner = THIS_MODULE, }, .probe = ds1307_probe, .remove = ds1307_remove, diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 167783fa7ac1..418c6b81e26d 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -689,7 +689,7 @@ static int ds1374_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - if (client->irq >= 0 && device_may_wakeup(&client->dev)) + if (client->irq > 0 && device_may_wakeup(&client->dev)) enable_irq_wake(client->irq); return 0; } @@ -698,7 +698,7 @@ static int ds1374_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); - if (client->irq >= 0 && device_may_wakeup(&client->dev)) + if (client->irq > 0 && device_may_wakeup(&client->dev)) disable_irq_wake(client->irq); return 0; } @@ -709,7 +709,6 @@ static SIMPLE_DEV_PM_OPS(ds1374_pm, ds1374_suspend, ds1374_resume); static struct i2c_driver ds1374_driver = { .driver = { .name = "rtc-ds1374", - .owner = THIS_MODULE, .pm = &ds1374_pm, }, .probe = ds1374_probe, diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c index 818a3635a8c8..05a51ef52703 100644 --- a/drivers/rtc/rtc-ds1685.c +++ b/drivers/rtc/rtc-ds1685.c @@ -2145,27 +2145,7 @@ static struct platform_driver ds1685_rtc_driver = { .probe = ds1685_rtc_probe, .remove = ds1685_rtc_remove, }; - -/** - * ds1685_rtc_init - rtc module init. - */ -static int __init -ds1685_rtc_init(void) -{ - return platform_driver_register(&ds1685_rtc_driver); -} - -/** - * ds1685_rtc_exit - rtc module exit. - */ -static void __exit -ds1685_rtc_exit(void) -{ - platform_driver_unregister(&ds1685_rtc_driver); -} - -module_init(ds1685_rtc_init); -module_exit(ds1685_rtc_exit); +module_platform_driver(ds1685_rtc_driver); /* ----------------------------------------------------------------------- */ diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 7e48e532214f..a8702dda0f26 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -443,7 +443,7 @@ static int ds3232_remove(struct i2c_client *client) { struct ds3232 *ds3232 = i2c_get_clientdata(client); - if (client->irq >= 0) { + if (client->irq > 0) { mutex_lock(&ds3232->mutex); ds3232->exiting = 1; mutex_unlock(&ds3232->mutex); @@ -500,7 +500,6 @@ MODULE_DEVICE_TABLE(i2c, ds3232_id); static struct i2c_driver ds3232_driver = { .driver = { .name = "rtc-ds3232", - .owner = THIS_MODULE, .pm = &ds3232_pm_ops, }, .probe = ds3232_probe, diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c index 83c3b3029fa7..576eadbba296 100644 --- a/drivers/rtc/rtc-fm3130.c +++ b/drivers/rtc/rtc-fm3130.c @@ -523,7 +523,6 @@ exit_free: static struct i2c_driver fm3130_driver = { .driver = { .name = "rtc-fm3130", - .owner = THIS_MODULE, }, .probe = fm3130_probe, .id_table = fm3130_id, diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c index e9da7959d3fe..097325d96db5 100644 --- a/drivers/rtc/rtc-hym8563.c +++ b/drivers/rtc/rtc-hym8563.c @@ -599,7 +599,6 @@ MODULE_DEVICE_TABLE(of, hym8563_dt_idtable); static struct i2c_driver hym8563_driver = { .driver = { .name = "rtc-hym8563", - .owner = THIS_MODULE, .pm = &hym8563_pm_ops, .of_match_table = hym8563_dt_idtable, }, diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index f9b082784b90..372627136786 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -151,12 +151,7 @@ static int isl12022_get_datetime(struct i2c_client *client, struct rtc_time *tm) tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); - /* The clock can give out invalid datetime, but we cannot return - * -EINVAL otherwise hwclock will refuse to set the time on bootup. */ - if (rtc_valid_tm(tm) < 0) - dev_err(&client->dev, "retrieved date and time is invalid.\n"); - - return 0; + return rtc_valid_tm(tm); } static int isl12022_set_datetime(struct i2c_client *client, struct rtc_time *tm) diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c index da818d3337ce..ee3e8dbcacaf 100644 --- a/drivers/rtc/rtc-isl12057.c +++ b/drivers/rtc/rtc-isl12057.c @@ -659,7 +659,6 @@ MODULE_DEVICE_TABLE(i2c, isl12057_id); static struct i2c_driver isl12057_driver = { .driver = { .name = DRV_NAME, - .owner = THIS_MODULE, .pm = &isl12057_rtc_pm_ops, .of_match_table = of_match_ptr(isl12057_dt_match), }, diff --git a/drivers/rtc/rtc-lpc24xx.c b/drivers/rtc/rtc-lpc24xx.c new file mode 100644 index 000000000000..59d99596fdeb --- /dev/null +++ b/drivers/rtc/rtc-lpc24xx.c @@ -0,0 +1,310 @@ +/* + * RTC driver for NXP LPC178x/18xx/43xx Real-Time Clock (RTC) + * + * Copyright (C) 2011 NXP Semiconductors + * Copyright (C) 2015 Joachim Eastwood <manabian@gmail.com> + * + * 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. + * + */ + +#include <linux/clk.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> + +/* LPC24xx RTC register offsets and bits */ +#define LPC24XX_ILR 0x00 +#define LPC24XX_RTCCIF BIT(0) +#define LPC24XX_RTCALF BIT(1) +#define LPC24XX_CTC 0x04 +#define LPC24XX_CCR 0x08 +#define LPC24XX_CLKEN BIT(0) +#define LPC178X_CCALEN BIT(4) +#define LPC24XX_CIIR 0x0c +#define LPC24XX_AMR 0x10 +#define LPC24XX_ALARM_DISABLE 0xff +#define LPC24XX_CTIME0 0x14 +#define LPC24XX_CTIME1 0x18 +#define LPC24XX_CTIME2 0x1c +#define LPC24XX_SEC 0x20 +#define LPC24XX_MIN 0x24 +#define LPC24XX_HOUR 0x28 +#define LPC24XX_DOM 0x2c +#define LPC24XX_DOW 0x30 +#define LPC24XX_DOY 0x34 +#define LPC24XX_MONTH 0x38 +#define LPC24XX_YEAR 0x3c +#define LPC24XX_ALSEC 0x60 +#define LPC24XX_ALMIN 0x64 +#define LPC24XX_ALHOUR 0x68 +#define LPC24XX_ALDOM 0x6c +#define LPC24XX_ALDOW 0x70 +#define LPC24XX_ALDOY 0x74 +#define LPC24XX_ALMON 0x78 +#define LPC24XX_ALYEAR 0x7c + +/* Macros to read fields in consolidated time (CT) registers */ +#define CT0_SECS(x) (((x) >> 0) & 0x3f) +#define CT0_MINS(x) (((x) >> 8) & 0x3f) +#define CT0_HOURS(x) (((x) >> 16) & 0x1f) +#define CT0_DOW(x) (((x) >> 24) & 0x07) +#define CT1_DOM(x) (((x) >> 0) & 0x1f) +#define CT1_MONTH(x) (((x) >> 8) & 0x0f) +#define CT1_YEAR(x) (((x) >> 16) & 0xfff) +#define CT2_DOY(x) (((x) >> 0) & 0xfff) + +#define rtc_readl(dev, reg) readl((dev)->rtc_base + (reg)) +#define rtc_writel(dev, reg, val) writel((val), (dev)->rtc_base + (reg)) + +struct lpc24xx_rtc { + void __iomem *rtc_base; + struct rtc_device *rtc; + struct clk *clk_rtc; + struct clk *clk_reg; +}; + +static int lpc24xx_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct lpc24xx_rtc *rtc = dev_get_drvdata(dev); + + /* Disable RTC during update */ + rtc_writel(rtc, LPC24XX_CCR, LPC178X_CCALEN); + + rtc_writel(rtc, LPC24XX_SEC, tm->tm_sec); + rtc_writel(rtc, LPC24XX_MIN, tm->tm_min); + rtc_writel(rtc, LPC24XX_HOUR, tm->tm_hour); + rtc_writel(rtc, LPC24XX_DOW, tm->tm_wday); + rtc_writel(rtc, LPC24XX_DOM, tm->tm_mday); + rtc_writel(rtc, LPC24XX_DOY, tm->tm_yday); + rtc_writel(rtc, LPC24XX_MONTH, tm->tm_mon); + rtc_writel(rtc, LPC24XX_YEAR, tm->tm_year); + + rtc_writel(rtc, LPC24XX_CCR, LPC24XX_CLKEN | LPC178X_CCALEN); + + return 0; +} + +static int lpc24xx_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct lpc24xx_rtc *rtc = dev_get_drvdata(dev); + u32 ct0, ct1, ct2; + + ct0 = rtc_readl(rtc, LPC24XX_CTIME0); + ct1 = rtc_readl(rtc, LPC24XX_CTIME1); + ct2 = rtc_readl(rtc, LPC24XX_CTIME2); + + tm->tm_sec = CT0_SECS(ct0); + tm->tm_min = CT0_MINS(ct0); + tm->tm_hour = CT0_HOURS(ct0); + tm->tm_wday = CT0_DOW(ct0); + tm->tm_mon = CT1_MONTH(ct1); + tm->tm_mday = CT1_DOM(ct1); + tm->tm_year = CT1_YEAR(ct1); + tm->tm_yday = CT2_DOY(ct2); + + return rtc_valid_tm(tm); +} + +static int lpc24xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + struct lpc24xx_rtc *rtc = dev_get_drvdata(dev); + struct rtc_time *tm = &wkalrm->time; + + tm->tm_sec = rtc_readl(rtc, LPC24XX_ALSEC); + tm->tm_min = rtc_readl(rtc, LPC24XX_ALMIN); + tm->tm_hour = rtc_readl(rtc, LPC24XX_ALHOUR); + tm->tm_mday = rtc_readl(rtc, LPC24XX_ALDOM); + tm->tm_wday = rtc_readl(rtc, LPC24XX_ALDOW); + tm->tm_yday = rtc_readl(rtc, LPC24XX_ALDOY); + tm->tm_mon = rtc_readl(rtc, LPC24XX_ALMON); + tm->tm_year = rtc_readl(rtc, LPC24XX_ALYEAR); + + wkalrm->enabled = rtc_readl(rtc, LPC24XX_AMR) == 0; + wkalrm->pending = !!(rtc_readl(rtc, LPC24XX_ILR) & LPC24XX_RTCCIF); + + return rtc_valid_tm(&wkalrm->time); +} + +static int lpc24xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + struct lpc24xx_rtc *rtc = dev_get_drvdata(dev); + struct rtc_time *tm = &wkalrm->time; + + /* Disable alarm irq during update */ + rtc_writel(rtc, LPC24XX_AMR, LPC24XX_ALARM_DISABLE); + + rtc_writel(rtc, LPC24XX_ALSEC, tm->tm_sec); + rtc_writel(rtc, LPC24XX_ALMIN, tm->tm_min); + rtc_writel(rtc, LPC24XX_ALHOUR, tm->tm_hour); + rtc_writel(rtc, LPC24XX_ALDOM, tm->tm_mday); + rtc_writel(rtc, LPC24XX_ALDOW, tm->tm_wday); + rtc_writel(rtc, LPC24XX_ALDOY, tm->tm_yday); + rtc_writel(rtc, LPC24XX_ALMON, tm->tm_mon); + rtc_writel(rtc, LPC24XX_ALYEAR, tm->tm_year); + + if (wkalrm->enabled) + rtc_writel(rtc, LPC24XX_AMR, 0); + + return 0; +} + +static int lpc24xx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) +{ + struct lpc24xx_rtc *rtc = dev_get_drvdata(dev); + + if (enable) + rtc_writel(rtc, LPC24XX_AMR, 0); + else + rtc_writel(rtc, LPC24XX_AMR, LPC24XX_ALARM_DISABLE); + + return 0; +} + +static irqreturn_t lpc24xx_rtc_interrupt(int irq, void *data) +{ + unsigned long events = RTC_IRQF; + struct lpc24xx_rtc *rtc = data; + u32 rtc_iir; + + /* Check interrupt cause */ + rtc_iir = rtc_readl(rtc, LPC24XX_ILR); + if (rtc_iir & LPC24XX_RTCALF) { + events |= RTC_AF; + rtc_writel(rtc, LPC24XX_AMR, LPC24XX_ALARM_DISABLE); + } + + /* Clear interrupt status and report event */ + rtc_writel(rtc, LPC24XX_ILR, rtc_iir); + rtc_update_irq(rtc->rtc, 1, events); + + return IRQ_HANDLED; +} + +static const struct rtc_class_ops lpc24xx_rtc_ops = { + .read_time = lpc24xx_rtc_read_time, + .set_time = lpc24xx_rtc_set_time, + .read_alarm = lpc24xx_rtc_read_alarm, + .set_alarm = lpc24xx_rtc_set_alarm, + .alarm_irq_enable = lpc24xx_rtc_alarm_irq_enable, +}; + +static int lpc24xx_rtc_probe(struct platform_device *pdev) +{ + struct lpc24xx_rtc *rtc; + struct resource *res; + int irq, ret; + + rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); + if (!rtc) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + rtc->rtc_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(rtc->rtc_base)) + return PTR_ERR(rtc->rtc_base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_warn(&pdev->dev, "can't get interrupt resource\n"); + return irq; + } + + rtc->clk_rtc = devm_clk_get(&pdev->dev, "rtc"); + if (IS_ERR(rtc->clk_rtc)) { + dev_err(&pdev->dev, "error getting rtc clock\n"); + return PTR_ERR(rtc->clk_rtc); + } + + rtc->clk_reg = devm_clk_get(&pdev->dev, "reg"); + if (IS_ERR(rtc->clk_reg)) { + dev_err(&pdev->dev, "error getting reg clock\n"); + return PTR_ERR(rtc->clk_reg); + } + + ret = clk_prepare_enable(rtc->clk_rtc); + if (ret) { + dev_err(&pdev->dev, "unable to enable rtc clock\n"); + return ret; + } + + ret = clk_prepare_enable(rtc->clk_reg); + if (ret) { + dev_err(&pdev->dev, "unable to enable reg clock\n"); + goto disable_rtc_clk; + } + + platform_set_drvdata(pdev, rtc); + + /* Clear any pending interrupts */ + rtc_writel(rtc, LPC24XX_ILR, LPC24XX_RTCCIF | LPC24XX_RTCALF); + + /* Enable RTC count */ + rtc_writel(rtc, LPC24XX_CCR, LPC24XX_CLKEN | LPC178X_CCALEN); + + ret = devm_request_irq(&pdev->dev, irq, lpc24xx_rtc_interrupt, 0, + pdev->name, rtc); + if (ret < 0) { + dev_warn(&pdev->dev, "can't request interrupt\n"); + goto disable_clks; + } + + rtc->rtc = devm_rtc_device_register(&pdev->dev, "lpc24xx-rtc", + &lpc24xx_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc->rtc)) { + dev_err(&pdev->dev, "can't register rtc device\n"); + ret = PTR_ERR(rtc->rtc); + goto disable_clks; + } + + return 0; + +disable_clks: + clk_disable_unprepare(rtc->clk_reg); +disable_rtc_clk: + clk_disable_unprepare(rtc->clk_rtc); + return ret; +} + +static int lpc24xx_rtc_remove(struct platform_device *pdev) +{ + struct lpc24xx_rtc *rtc = platform_get_drvdata(pdev); + + /* Ensure all interrupt sources are masked */ + rtc_writel(rtc, LPC24XX_AMR, LPC24XX_ALARM_DISABLE); + rtc_writel(rtc, LPC24XX_CIIR, 0); + + rtc_writel(rtc, LPC24XX_CCR, LPC178X_CCALEN); + + clk_disable_unprepare(rtc->clk_rtc); + clk_disable_unprepare(rtc->clk_reg); + + return 0; +} + +static const struct of_device_id lpc24xx_rtc_match[] = { + { .compatible = "nxp,lpc1788-rtc" }, + { } +}; +MODULE_DEVICE_TABLE(of, lpc24xx_rtc_match); + +static struct platform_driver lpc24xx_rtc_driver = { + .probe = lpc24xx_rtc_probe, + .remove = lpc24xx_rtc_remove, + .driver = { + .name = "lpc24xx-rtc", + .of_match_table = lpc24xx_rtc_match, + }, +}; +module_platform_driver(lpc24xx_rtc_driver); + +MODULE_AUTHOR("Kevin Wells <wellsk40@gmail.com>"); +MODULE_DESCRIPTION("RTC driver for the LPC178x/18xx/408x/43xx SoCs"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c index 7061dcae2b09..6fbf9e617151 100644 --- a/drivers/rtc/rtc-opal.c +++ b/drivers/rtc/rtc-opal.c @@ -190,11 +190,9 @@ exit: return rc; } -static const struct rtc_class_ops opal_rtc_ops = { +static 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) @@ -202,8 +200,11 @@ 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)) + NULL)) { device_set_wakeup_capable(&pdev->dev, true); + opal_rtc_ops.read_alarm = opal_get_tpo_time; + opal_rtc_ops.set_alarm = opal_set_tpo_time; + } rtc = devm_rtc_device_register(&pdev->dev, DRVNAME, &opal_rtc_ops, THIS_MODULE); @@ -236,7 +237,6 @@ static struct platform_driver opal_rtc_driver = { .id_table = opal_rtc_driver_ids, .driver = { .name = DRVNAME, - .owner = THIS_MODULE, .of_match_table = opal_rtc_match, }, }; diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index 8a7556cbcb7f..1c47650fe624 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -165,13 +165,7 @@ static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm) tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); - /* the clock can give out invalid datetime, but we cannot return - * -EINVAL otherwise hwclock will refuse to set the time on bootup. - */ - if (rtc_valid_tm(tm) < 0) - dev_err(dev, "retrieved date/time is not valid.\n"); - - return 0; + return rtc_valid_tm(tm); } static int pcf2123_rtc_set_time(struct device *dev, struct rtc_time *tm) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 9bd842e97749..4b11d31f7174 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -33,11 +33,14 @@ #define PCF2127_REG_MO (0x08) #define PCF2127_REG_YR (0x09) +#define PCF2127_OSF BIT(7) /* Oscillator Fail flag */ + static struct i2c_driver pcf2127_driver; struct pcf2127 { struct rtc_device *rtc; int voltage_low; /* indicates if a low_voltage was detected */ + int oscillator_failed; /* OSF was detected and date is unreliable */ }; /* @@ -59,7 +62,18 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) if (buf[PCF2127_REG_CTRL3] & 0x04) { pcf2127->voltage_low = 1; dev_info(&client->dev, - "low voltage detected, date/time is not reliable.\n"); + "low voltage detected, check/replace RTC battery.\n"); + } + + if (buf[PCF2127_REG_SC] & PCF2127_OSF) { + /* + * no need clear the flag here, + * it will be cleared once the new date is saved + */ + pcf2127->oscillator_failed = 1; + dev_warn(&client->dev, + "oscillator stop detected, date/time is not reliable\n"); + return -EINVAL; } dev_dbg(&client->dev, @@ -88,17 +102,12 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); - /* the clock can give out invalid datetime, but we cannot return - * -EINVAL otherwise hwclock will refuse to set the time on bootup. - */ - if (rtc_valid_tm(tm) < 0) - dev_err(&client->dev, "retrieved date/time is not valid.\n"); - - return 0; + return rtc_valid_tm(tm); } static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) { + struct pcf2127 *pcf2127 = i2c_get_clientdata(client); unsigned char buf[8]; int i = 0, err; @@ -112,7 +121,7 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) buf[i++] = PCF2127_REG_SC; /* hours, minutes and seconds */ - buf[i++] = bin2bcd(tm->tm_sec); + buf[i++] = bin2bcd(tm->tm_sec); /* this will also clear OSF flag */ buf[i++] = bin2bcd(tm->tm_min); buf[i++] = bin2bcd(tm->tm_hour); buf[i++] = bin2bcd(tm->tm_mday); @@ -132,6 +141,9 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) return -EIO; } + /* clear OSF flag in client data */ + pcf2127->oscillator_failed = 0; + return 0; } @@ -144,7 +156,9 @@ static int pcf2127_rtc_ioctl(struct device *dev, switch (cmd) { case RTC_VL_READ: if (pcf2127->voltage_low) - dev_info(dev, "low voltage detected, date/time is not reliable.\n"); + dev_info(dev, "low voltage detected, check/replace battery\n"); + if (pcf2127->oscillator_failed) + dev_info(dev, "oscillator stop detected, date/time is not reliable\n"); if (copy_to_user((void __user *)arg, &pcf2127->voltage_low, sizeof(int))) @@ -217,7 +231,6 @@ MODULE_DEVICE_TABLE(of, pcf2127_of_match); static struct i2c_driver pcf2127_driver = { .driver = { .name = "rtc-pcf2127", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(pcf2127_of_match), }, .probe = pcf2127_probe, diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 6a12bf62c504..b6d73dd881f2 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -189,7 +189,6 @@ MODULE_DEVICE_TABLE(of, pcf85063_of_match); static struct i2c_driver pcf85063_driver = { .driver = { .name = "rtc-pcf85063", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(pcf85063_of_match), }, .probe = pcf85063_probe, diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 4cdb64be061b..e7ebcc0b7e59 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -334,7 +334,6 @@ MODULE_DEVICE_TABLE(of, pcf8523_of_match); static struct i2c_driver pcf8523_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(pcf8523_of_match), }, .probe = pcf8523_probe, diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 8bba022be946..e569243db57e 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -483,7 +483,6 @@ MODULE_DEVICE_TABLE(of, pcf8563_of_match); static struct i2c_driver pcf8563_driver = { .driver = { .name = "rtc-pcf8563", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(pcf8563_of_match), }, .probe = pcf8563_probe, diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index 5911a6dca291..7ca9e8871d77 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c @@ -309,7 +309,6 @@ MODULE_DEVICE_TABLE(i2c, pcf8583_id); static struct i2c_driver pcf8583_driver = { .driver = { .name = "pcf8583", - .owner = THIS_MODULE, }, .probe = pcf8583_probe, .id_table = pcf8583_id, diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index e6298e02b400..a297542e2f8a 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -628,7 +628,6 @@ static int rx8025_remove(struct i2c_client *client) static struct i2c_driver rx8025_driver = { .driver = { .name = "rtc-rx8025", - .owner = THIS_MODULE, }, .probe = rx8025_probe, .remove = rx8025_remove, diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c index de8d9c427782..161e25d016c3 100644 --- a/drivers/rtc/rtc-rx8581.c +++ b/drivers/rtc/rtc-rx8581.c @@ -315,7 +315,6 @@ MODULE_DEVICE_TABLE(i2c, rx8581_id); static struct i2c_driver rx8581_driver = { .driver = { .name = "rtc-rx8581", - .owner = THIS_MODULE, }, .probe = rx8581_probe, .id_table = rx8581_id, diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c index edc3b43282d4..7367f617145c 100644 --- a/drivers/rtc/rtc-sirfsoc.c +++ b/drivers/rtc/rtc-sirfsoc.c @@ -13,6 +13,7 @@ #include <linux/slab.h> #include <linux/io.h> #include <linux/of.h> +#include <linux/regmap.h> #include <linux/rtc/sirfsoc_rtciobrg.h> @@ -48,12 +49,27 @@ struct sirfsoc_rtc_drv { /* Overflow for every 8 years extra time */ u32 overflow_rtc; spinlock_t lock; + struct regmap *regmap; #ifdef CONFIG_PM u32 saved_counter; u32 saved_overflow_rtc; #endif }; +static u32 sirfsoc_rtc_readl(struct sirfsoc_rtc_drv *rtcdrv, u32 offset) +{ + u32 val; + + regmap_read(rtcdrv->regmap, rtcdrv->rtc_base + offset, &val); + return val; +} + +static void sirfsoc_rtc_writel(struct sirfsoc_rtc_drv *rtcdrv, + u32 offset, u32 val) +{ + regmap_write(rtcdrv->regmap, rtcdrv->rtc_base + offset, val); +} + static int sirfsoc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { @@ -64,9 +80,9 @@ static int sirfsoc_rtc_read_alarm(struct device *dev, spin_lock_irq(&rtcdrv->lock); - rtc_count = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); + rtc_count = sirfsoc_rtc_readl(rtcdrv, RTC_CN); - rtc_alarm = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_ALARM0); + rtc_alarm = sirfsoc_rtc_readl(rtcdrv, RTC_ALARM0); memset(alrm, 0, sizeof(struct rtc_wkalrm)); /* @@ -82,8 +98,7 @@ static int sirfsoc_rtc_read_alarm(struct device *dev, rtc_time_to_tm(rtcdrv->overflow_rtc << (BITS_PER_LONG - RTC_SHIFT) | rtc_alarm >> RTC_SHIFT, &(alrm->time)); - if (sirfsoc_rtc_iobrg_readl( - rtcdrv->rtc_base + RTC_STATUS) & SIRFSOC_RTC_AL0E) + if (sirfsoc_rtc_readl(rtcdrv, RTC_STATUS) & SIRFSOC_RTC_AL0E) alrm->enabled = 1; spin_unlock_irq(&rtcdrv->lock); @@ -103,8 +118,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, spin_lock_irq(&rtcdrv->lock); - rtc_status_reg = sirfsoc_rtc_iobrg_readl( - rtcdrv->rtc_base + RTC_STATUS); + rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS); if (rtc_status_reg & SIRFSOC_RTC_AL0E) { /* * An ongoing alarm in progress - ingore it and not @@ -113,8 +127,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, dev_info(dev, "An old alarm was set, will be replaced by a new one\n"); } - sirfsoc_rtc_iobrg_writel( - rtc_alarm << RTC_SHIFT, rtcdrv->rtc_base + RTC_ALARM0); + sirfsoc_rtc_writel(rtcdrv, RTC_ALARM0, rtc_alarm << RTC_SHIFT); rtc_status_reg &= ~0x07; /* mask out the lower status bits */ /* * This bit RTC_AL sets it as a wake-up source for Sleep Mode @@ -123,8 +136,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, rtc_status_reg |= SIRFSOC_RTC_AL0; /* enable the RTC alarm interrupt */ rtc_status_reg |= SIRFSOC_RTC_AL0E; - sirfsoc_rtc_iobrg_writel( - rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS); + sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, rtc_status_reg); spin_unlock_irq(&rtcdrv->lock); } else { @@ -135,8 +147,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, */ spin_lock_irq(&rtcdrv->lock); - rtc_status_reg = sirfsoc_rtc_iobrg_readl( - rtcdrv->rtc_base + RTC_STATUS); + rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS); if (rtc_status_reg & SIRFSOC_RTC_AL0E) { /* clear the RTC status register's alarm bit */ rtc_status_reg &= ~0x07; @@ -145,8 +156,8 @@ static int sirfsoc_rtc_set_alarm(struct device *dev, /* Clear the Alarm enable bit */ rtc_status_reg &= ~(SIRFSOC_RTC_AL0E); - sirfsoc_rtc_iobrg_writel(rtc_status_reg, - rtcdrv->rtc_base + RTC_STATUS); + sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, + rtc_status_reg); } spin_unlock_irq(&rtcdrv->lock); @@ -167,9 +178,9 @@ static int sirfsoc_rtc_read_time(struct device *dev, * fail, read several times to make sure get stable value. */ do { - tmp_rtc = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); + tmp_rtc = sirfsoc_rtc_readl(rtcdrv, RTC_CN); cpu_relax(); - } while (tmp_rtc != sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN)); + } while (tmp_rtc != sirfsoc_rtc_readl(rtcdrv, RTC_CN)); rtc_time_to_tm(rtcdrv->overflow_rtc << (BITS_PER_LONG - RTC_SHIFT) | tmp_rtc >> RTC_SHIFT, tm); @@ -187,10 +198,8 @@ static int sirfsoc_rtc_set_time(struct device *dev, rtcdrv->overflow_rtc = rtc_time >> (BITS_PER_LONG - RTC_SHIFT); - sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc, - rtcdrv->rtc_base + RTC_SW_VALUE); - sirfsoc_rtc_iobrg_writel( - rtc_time << RTC_SHIFT, rtcdrv->rtc_base + RTC_CN); + sirfsoc_rtc_writel(rtcdrv, RTC_SW_VALUE, rtcdrv->overflow_rtc); + sirfsoc_rtc_writel(rtcdrv, RTC_CN, rtc_time << RTC_SHIFT); return 0; } @@ -222,14 +231,13 @@ static int sirfsoc_rtc_alarm_irq_enable(struct device *dev, spin_lock_irq(&rtcdrv->lock); - rtc_status_reg = sirfsoc_rtc_iobrg_readl( - rtcdrv->rtc_base + RTC_STATUS); + rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, 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); + sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, rtc_status_reg); spin_unlock_irq(&rtcdrv->lock); @@ -254,7 +262,7 @@ static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata) spin_lock(&rtcdrv->lock); - rtc_status_reg = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_STATUS); + rtc_status_reg = sirfsoc_rtc_readl(rtcdrv, RTC_STATUS); /* this bit will be set ONLY if an alarm was active * and it expired NOW * So this is being used as an ASSERT @@ -270,7 +278,8 @@ static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata) /* Clear the Alarm enable bit */ rtc_status_reg &= ~(SIRFSOC_RTC_AL0E); } - sirfsoc_rtc_iobrg_writel(rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS); + + sirfsoc_rtc_writel(rtcdrv, RTC_STATUS, rtc_status_reg); spin_unlock(&rtcdrv->lock); @@ -287,6 +296,13 @@ static const struct of_device_id sirfsoc_rtc_of_match[] = { { .compatible = "sirf,prima2-sysrtc"}, {}, }; + +const struct regmap_config sysrtc_regmap_config = { + .reg_bits = 32, + .val_bits = 32, + .fast_io = true, +}; + MODULE_DEVICE_TABLE(of, sirfsoc_rtc_of_match); static int sirfsoc_rtc_probe(struct platform_device *pdev) @@ -314,27 +330,35 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev) /* Register rtc alarm as a wakeup source */ device_init_wakeup(&pdev->dev, 1); + rtcdrv->regmap = devm_regmap_init_iobg(&pdev->dev, + &sysrtc_regmap_config); + if (IS_ERR(rtcdrv->regmap)) { + err = PTR_ERR(rtcdrv->regmap); + dev_err(&pdev->dev, "Failed to allocate register map: %d\n", + err); + return err; + } + /* * Set SYS_RTC counter in RTC_HZ HZ Units * We are using 32K RTC crystal (32768 / RTC_HZ / 2) -1 * If 16HZ, therefore RTC_DIV = 1023; */ rtc_div = ((32768 / RTC_HZ) / 2) - 1; - sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV); + sirfsoc_rtc_writel(rtcdrv, RTC_DIV, rtc_div); /* 0x3 -> RTC_CLK */ - sirfsoc_rtc_iobrg_writel(SIRFSOC_RTC_CLK, - rtcdrv->rtc_base + RTC_CLOCK_SWITCH); + sirfsoc_rtc_writel(rtcdrv, RTC_CLOCK_SWITCH, SIRFSOC_RTC_CLK); /* reset SYS RTC ALARM0 */ - sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM0); + sirfsoc_rtc_writel(rtcdrv, RTC_ALARM0, 0x0); /* reset SYS RTC ALARM1 */ - sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM1); + sirfsoc_rtc_writel(rtcdrv, RTC_ALARM1, 0x0); /* Restore RTC Overflow From Register After Command Reboot */ rtcdrv->overflow_rtc = - sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE); + sirfsoc_rtc_readl(rtcdrv, RTC_SW_VALUE); rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &sirfsoc_rtc_ops, THIS_MODULE); @@ -372,10 +396,10 @@ static int sirfsoc_rtc_suspend(struct device *dev) { struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev); rtcdrv->overflow_rtc = - sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE); + sirfsoc_rtc_readl(rtcdrv, RTC_SW_VALUE); rtcdrv->saved_counter = - sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); + sirfsoc_rtc_readl(rtcdrv, RTC_CN); rtcdrv->saved_overflow_rtc = rtcdrv->overflow_rtc; if (device_may_wakeup(dev) && !enable_irq_wake(rtcdrv->irq)) rtcdrv->irq_wake = 1; @@ -392,12 +416,10 @@ static int sirfsoc_rtc_resume(struct device *dev) * if resume from snapshot and the rtc power is lost, * restroe the rtc settings */ - if (SIRFSOC_RTC_CLK != sirfsoc_rtc_iobrg_readl( - rtcdrv->rtc_base + RTC_CLOCK_SWITCH)) { + if (SIRFSOC_RTC_CLK != sirfsoc_rtc_readl(rtcdrv, RTC_CLOCK_SWITCH)) { u32 rtc_div; /* 0x3 -> RTC_CLK */ - sirfsoc_rtc_iobrg_writel(SIRFSOC_RTC_CLK, - rtcdrv->rtc_base + RTC_CLOCK_SWITCH); + sirfsoc_rtc_writel(rtcdrv, RTC_CLOCK_SWITCH, SIRFSOC_RTC_CLK); /* * Set SYS_RTC counter in RTC_HZ HZ Units * We are using 32K RTC crystal (32768 / RTC_HZ / 2) -1 @@ -405,13 +427,13 @@ static int sirfsoc_rtc_resume(struct device *dev) */ rtc_div = ((32768 / RTC_HZ) / 2) - 1; - sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV); + sirfsoc_rtc_writel(rtcdrv, RTC_DIV, rtc_div); /* reset SYS RTC ALARM0 */ - sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM0); + sirfsoc_rtc_writel(rtcdrv, RTC_ALARM0, 0x0); /* reset SYS RTC ALARM1 */ - sirfsoc_rtc_iobrg_writel(0x0, rtcdrv->rtc_base + RTC_ALARM1); + sirfsoc_rtc_writel(rtcdrv, RTC_ALARM1, 0x0); } rtcdrv->overflow_rtc = rtcdrv->saved_overflow_rtc; @@ -419,15 +441,14 @@ static int sirfsoc_rtc_resume(struct device *dev) * if current counter is small than previous, * it means overflow in sleep */ - tmp = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN); + tmp = sirfsoc_rtc_readl(rtcdrv, RTC_CN); if (tmp <= rtcdrv->saved_counter) rtcdrv->overflow_rtc++; /* *PWRC Value Be Changed When Suspend, Restore Overflow * In Memory To Register */ - sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc, - rtcdrv->rtc_base + RTC_SW_VALUE); + sirfsoc_rtc_writel(rtcdrv, RTC_SW_VALUE, rtcdrv->overflow_rtc); if (device_may_wakeup(dev) && rtcdrv->irq_wake) { disable_irq_wake(rtcdrv->irq); |