From 2fb07a10e0aa699ddb12aba1459208579bdc9802 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 23 Jun 2015 11:15:10 -0500 Subject: [PATCH 01/90] rtc: ds1307: Convert to threaded IRQ The driver currently emulates the concept of threaded IRQ using a workqueue, which it really does not need to. Instead, switch over to threaded_irq handlers which is meant precisely for the same purpose. Signed-off-by: Felipe Balbi Signed-off-by: Nishanth Menon Reviewed-by: Grygorii Strashko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 59 +++++++++++++--------------------------- 1 file changed, 19 insertions(+), 40 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 6e76de1856fc..8ea496e54a2e 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -114,7 +114,6 @@ struct ds1307 { #define HAS_ALARM 1 /* bit 1 == irq claimed */ struct i2c_client *client; struct rtc_device *rtc; - struct work_struct work; 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 +310,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 +341,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 +613,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 +645,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 +876,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 +944,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 +1033,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,8 +1156,9 @@ read_rtc: } if (want_irq) { - err = request_irq(client->irq, ds1307_irq, IRQF_SHARED, - ds1307->rtc->name, client); + err = request_threaded_irq(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"); @@ -1231,10 +1212,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)) { + if (test_and_clear_bit(HAS_ALARM, &ds1307->flags)) free_irq(client->irq, client); - cancel_work_sync(&ds1307->work); - } if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram); From c5983191362af5ef7a627d8811a45f0fd01a3582 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 23 Jun 2015 11:15:11 -0500 Subject: [PATCH 02/90] rtc: ds1307: Switch to managed irq allocation Since we are not doing anything fancy in remove function that requires us to sequence IRQ free operation, we might as well switch over to devm_ equivalent of managed IRQ allocation and remove the explicit free_irq since it'd be done automatically at remove. Signed-off-by: Nishanth Menon Acked-by: Felipe Balbi Reviewed-by: Grygorii Strashko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 8ea496e54a2e..0a98d8a52791 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1156,9 +1156,10 @@ read_rtc: } if (want_irq) { - err = request_threaded_irq(client->irq, NULL, irq_handler, - IRQF_SHARED | IRQF_ONESHOT, - ds1307->rtc->name, client); + 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"); @@ -1212,9 +1213,6 @@ 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); - if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags)) sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram); From eac7237fd8432e232af3c407e667dbdc17ebf1d8 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 23 Jun 2015 11:15:12 -0500 Subject: [PATCH 03/90] rtc: ds1307: Sort the headers It is always a good practice to keep the #includes sorted Signed-off-by: Nishanth Menon Acked-by: Felipe Balbi Reviewed-by: Grygorii Strashko Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 0a98d8a52791..b03880fc32b5 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -11,14 +11,14 @@ * published by the Free Software Foundation. */ -#include -#include -#include -#include -#include -#include #include +#include +#include +#include #include +#include +#include +#include /* * We can't determine type by probing, but if we expect pre-Linux code From 7abea617a4bae178da0f42983998c779ec2f732d Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 24 Jun 2015 11:26:54 -0500 Subject: [PATCH 04/90] rtc: ds1307: Support optional wakeup interrupt source With the recent pinctrl-single changes, SoCs such as Texas Instrument's OMAP processors can treat wake-up events from deeper idle states as interrupts. Let's add support for the optional second interrupt for wake-up using the generic wakeirq support added in commit 4990d4fe327b ("PM / Wakeirq: Add automated device wake IRQ handling") Finally, to pass the wake-up interrupt in the dts file, interrupts-extended property needs to be passed. This is similar in approach to commit 2a0b965cfb6e ("serial: omap: Add support for optional wake-up") + ee83bd3b6483 ("serial: omap: Switch wake-up interrupt to generic wakeirq") Signed-off-by: Nishanth Menon Reviewed-by: Grygorii Strashko Acked-by: Tony Lindgren Acked-by: Felipe Balbi Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 36 +++++++++++++++++++++++++++++++++--- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index b03880fc32b5..e16989c48a90 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -15,6 +15,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -114,6 +117,7 @@ struct ds1307 { #define HAS_ALARM 1 /* bit 1 == irq claimed */ struct i2c_client *client; struct rtc_device *rtc; + 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, @@ -1156,6 +1160,8 @@ read_rtc: } if (want_irq) { + struct device_node *node = client->dev.of_node; + err = devm_request_threaded_irq(&client->dev, client->irq, NULL, irq_handler, IRQF_SHARED | IRQF_ONESHOT, @@ -1163,13 +1169,34 @@ read_rtc: 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); + 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; + + 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, @@ -1213,6 +1240,9 @@ static int ds1307_remove(struct i2c_client *client) { struct ds1307 *ds1307 = i2c_get_clientdata(client); + 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); From 508db592e2f54d731bf2f5eabd9642a1a566f276 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Tue, 7 Jul 2015 11:16:14 +0530 Subject: [PATCH 05/90] rtc: ds1685: Use module_platform_driver Use module_platform_driver for drivers whose init and exit functions only register and unregister, respectively. A simplified version of the Coccinelle semantic patch that performs this transformation is as follows: @a@ identifier f, x; @@ -static f(...) { return platform_driver_register(&x); } @b depends on a@ identifier e, a.x; @@ -static e(...) { platform_driver_unregister(&x); } @c depends on a && b@ identifier a.f; declarer name module_init; @@ -module_init(f); @d depends on a && b && c@ identifier b.e, a.x; declarer name module_exit; declarer name module_platform_driver; @@ -module_exit(e); +module_platform_driver(x); Signed-off-by: Vaishali Thakkar Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1685.c | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) 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); /* ----------------------------------------------------------------------- */ From 617f6f7ef5bfe8c0ac580243c3da9a836c6e39bf Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Wed, 8 Jul 2015 12:26:47 +0530 Subject: [PATCH 06/90] rtc: bq32k: remove redundant check removing below static analysis error: (error) Possible null pointer dereference: client if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) ^^^^^^^ Error comes because client is dereferenced before NULL check. So probably NULL this check is not required. Signed-off-by: Maninder Singh Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-bq32k.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c index 92679df6d6e2..409de9f1b604 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, From 4ab82103131777b9aabb6ba31aead6e5b0293b32 Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Thu, 9 Jul 2015 12:25:51 +0530 Subject: [PATCH 07/90] rtc: 88pm80x: add device tree support Along with DT support, this patch also cleans up the unnecessary code around 'rtc_wakeup' initialization. Signed-off-by: Chao Xie Signed-off-by: Vaibhav Hiremath Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-88pm80x.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) 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); From 821f51c4da869706356ddecfeeac286bf4df9b98 Mon Sep 17 00:00:00 2001 From: Andrea Scian Date: Tue, 16 Jun 2015 11:35:19 +0200 Subject: [PATCH 08/90] rtc: use rtc_valid_tm() error code when reading date/time There's a wrong comment in some RTC drivers that say it's better to ignore rtc_valid_tm() when reading RTC timestamp. However this is wrong and is better to return to the userspace the error if timestamp is not valid. Signed-off-by: Andrea Scian Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 7 +------ drivers/rtc/rtc-pcf2123.c | 8 +------- drivers/rtc/rtc-pcf2127.c | 8 +------- 3 files changed, 3 insertions(+), 20 deletions(-) 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-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..350c5c7cb678 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -88,13 +88,7 @@ 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) From 653ebd75e9e469e99a40ab14128d915386dc78c6 Mon Sep 17 00:00:00 2001 From: Andrea Scian Date: Tue, 16 Jun 2015 11:39:47 +0200 Subject: [PATCH 09/90] rtc: pcf2127: use OFS flag to detect unreliable date and warn the user The PCF2127 datasheet states that it's wrong to say that the date in unreliable if BLF (battery low flag) is set but instead, OSF (seconds register) should be used to check if oscillator, for any reason, stopped. Battery may be low (usually below 2V5 threshold) but the date may be anyway correct (typically date is unreliable when input voltage is below 1V2). Signed-off-by: Andrea Scian Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 350c5c7cb678..baf45c9ca65e 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, @@ -93,6 +107,7 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *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; @@ -106,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); @@ -126,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; } @@ -138,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))) From b28845433eb9c205c381ed69b09167d6ae5aac1c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:39:50 +0900 Subject: [PATCH 10/90] rtc: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ab-b5ze-s3.c | 1 - drivers/rtc/rtc-bq32k.c | 1 - drivers/rtc/rtc-ds1307.c | 1 - drivers/rtc/rtc-ds1374.c | 1 - drivers/rtc/rtc-ds3232.c | 1 - drivers/rtc/rtc-fm3130.c | 1 - drivers/rtc/rtc-hym8563.c | 1 - drivers/rtc/rtc-isl12057.c | 1 - drivers/rtc/rtc-pcf2127.c | 1 - drivers/rtc/rtc-pcf85063.c | 1 - drivers/rtc/rtc-pcf8523.c | 1 - drivers/rtc/rtc-pcf8563.c | 1 - drivers/rtc/rtc-pcf8583.c | 1 - drivers/rtc/rtc-rx8025.c | 1 - drivers/rtc/rtc-rx8581.c | 1 - 15 files changed, 15 deletions(-) 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 409de9f1b604..0299988b4f13 100644 --- a/drivers/rtc/rtc-bq32k.c +++ b/drivers/rtc/rtc-bq32k.c @@ -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-ds1307.c b/drivers/rtc/rtc-ds1307.c index e16989c48a90..c51bc0a65afc 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1252,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 72c933375233..6d8665647eee 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -708,7 +708,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-ds3232.c b/drivers/rtc/rtc-ds3232.c index 7e48e532214f..18f062f2a634 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -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-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-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index baf45c9ca65e..4b11d31f7174 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -231,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, From 045c6fdd37a01d950c0f5ca64733b53b184fe91b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:39:51 +0900 Subject: [PATCH 11/90] rtc: Drop owner assignment from platform_driver platform_driver does not need to set an owner because platform_driver_register() will set it. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-opal.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c index 7061dcae2b09..417d7b4a5cd8 100644 --- a/drivers/rtc/rtc-opal.c +++ b/drivers/rtc/rtc-opal.c @@ -236,7 +236,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, }, }; From dcb9372b34c9de90672e4cf811d7c3a8519320aa Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Sat, 11 Jul 2015 19:28:50 +0200 Subject: [PATCH 12/90] doc: dt: add documentation for nxp,lpc1788-rtc Document NXP LPC178x/18xx/408x/43xx bindings Signed-off-by: Joachim Eastwood Signed-off-by: Alexandre Belloni --- .../bindings/rtc/nxp,lpc1788-rtc.txt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/nxp,lpc1788-rtc.txt 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..3c97bd180592 --- /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 clock specifiers 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"; +}; From c28b42e3aee03fe869a3f73039cf92686ccbc8fb Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Sat, 11 Jul 2015 19:28:49 +0200 Subject: [PATCH 13/90] rtc: add rtc-lpc24xx driver Add driver for the RTC found on NXP LPC178x/18xx/408x/43xx devices. The RTC provides calendar and clock functionality together with alarm interrupt support. Signed-off-by: Joachim Eastwood Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 12 ++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-lpc24xx.c | 310 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 323 insertions(+) create mode 100644 drivers/rtc/rtc-lpc24xx.c 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/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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +/* 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 "); +MODULE_DESCRIPTION("RTC driver for the LPC178x/18xx/408x/43xx SoCs"); +MODULE_LICENSE("GPL"); From f4a2eecb3ff9f51b179b213e7cc3766f920f2dc5 Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Tue, 14 Jul 2015 13:28:28 +0530 Subject: [PATCH 14/90] rtc: opal: Enable alarms only when opal supports tpo rtc-opal driver provides support for rtc alarms via timed-power-on(tpo). However some Power platforms like BML use a fake rtc clock and don't support tpo. Such platforms are indicated by the missing 'has-tpo' property in the device tree. Current implementation however enables callback for rtc_class_ops.read/set alarm irrespective of the tpo support from the platform. This results in a failed opal call when kernel tries to read an existing alarms via opal_get_tpo_time during rtc device registration. This patch fixes this issue by setting opal_rtc_ops.read/set_alarm callback pointers only when tpo is supported. Acked-by: Michael Neuling Acked-by: Neelesh Gupta Signed-off-by: Vaibhav Jain Acked-by: Stewart Smith Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-opal.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c index 417d7b4a5cd8..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); From dfe6c04aa289de06df95d888719af63d1d4c982d Mon Sep 17 00:00:00 2001 From: Guo Zeng Date: Tue, 14 Jul 2015 01:31:38 +0000 Subject: [PATCH 15/90] rtc: sirfsoc: move to regmap APIs from platform-specific APIs The current codes use CSR platform specific API exported by machine codes to read/write RTC registers. they are: sirfsoc_rtc_iobrg_readl() sirfsoc_rtc_iobrg_writel() commit b1999477ed91 ("ARM: prima2: move to use REGMAP APIs for rtciobrg") moves to regmap support, now we can move to use regmap APIs in RTC driver. Signed-off-by: Guo Zeng Signed-off-by: Barry Song Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sirfsoc.c | 107 +++++++++++++++++++++++--------------- 1 file changed, 64 insertions(+), 43 deletions(-) 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 #include #include +#include #include @@ -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); From 6706664d92ea841913d5fcfd06c290fbe6d33bd2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 20 Jul 2015 16:02:49 -0700 Subject: [PATCH 16/90] rtc: class: fix double free in rtc_register_device() error path Commit 59cca865f21e ("drivers/rtc/class.c: fix device_register() error handling") correctly noted that naked kfree() should not be used after failed device_register() call, however, while it added the needed put_device() it forgot to remove the original kfree() causing double-free. Cc: Vasiliy Kulikov Signed-off-by: Dmitry Torokhov Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/class.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index ea2a315df6b7..eb82ec2a21bd 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); From c3b399a4b6703a04ef6eb3efe35ff12163e409e0 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 20 Jul 2015 16:02:50 -0700 Subject: [PATCH 17/90] rtc: class: remove unnecessary device_get() in rtc_device_unregister Technically the address of rtc->dev can never be NULL, so get_device() can never fail. Also caller of rtc_device_unregister() supposed to be the owner of the device and thus have a valid reference. Therefore call to get_device() is not needed here. Signed-off-by: Dmitry Torokhov Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/class.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index eb82ec2a21bd..de7707f7e766 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -266,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); From 1e4cd62558c293bc51cc179d676b708683a29c12 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 20 Jul 2015 16:02:51 -0700 Subject: [PATCH 18/90] rtc: dev: properly manage lifetime of dev and cdev in rtc device struct rtc embeds both struct dev and struct cdev. Unfortunately character device structure may outlive the parent rtc structure unless we set it up as parent of character device so that it will stay pinned until character device is freed. Signed-off-by: Dmitry Torokhov Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-dev.c | 1 + 1 file changed, 1 insertion(+) 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) From 0d9030a2c3214cf8f9bfff84204e0f5ba5e790d7 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Fri, 5 Jun 2015 16:59:43 +0300 Subject: [PATCH 19/90] rtc: fix drivers that consider 0 as a valid IRQ in client->irq Since dab472eb931b ("i2c / ACPI: Use 0 to indicate that device does not have interrupt assigned"), 0 is not a valid i2c client irq anymore, so change all driver's checks accordingly. The same issue occurs when the device is instantiated via device tree with no IRQ, or from the i2c sysfs interface, even before the patch above. Signed-off-by: Octavian Purdila Reviewed-by: Mika Westerberg Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1374.c | 4 ++-- drivers/rtc/rtc-ds3232.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 6d8665647eee..7067232ba507 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -688,7 +688,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; } @@ -697,7 +697,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; } diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index 18f062f2a634..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); From f2284f9c900a47961883b88064933a89b5dd5f46 Mon Sep 17 00:00:00 2001 From: Henri Roosen Date: Fri, 24 Jul 2015 10:16:06 +0200 Subject: [PATCH 20/90] rtc: rx8025: remove obsolete local_irq_disable() and local_irq_enable() for rtc_update_irq() Since commit e6229bec25be ("rtc: make rtc_update_irq callable with irqs enabled") rtc_update_irq() is callable with irqs enabled. Signed-off-by: Henri Roosen Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index a297542e2f8a..6fe87702fcff 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -161,9 +161,7 @@ static void rx8025_work(struct work_struct *work) if (status & RX8025_BIT_CTRL2_CTFG) { /* periodic */ status &= ~RX8025_BIT_CTRL2_CTFG; - local_irq_disable(); rtc_update_irq(rx8025->rtc, 1, RTC_PF | RTC_IRQF); - local_irq_enable(); } if (status & RX8025_BIT_CTRL2_DAFG) { @@ -172,9 +170,7 @@ static void rx8025_work(struct work_struct *work) if (rx8025_write_reg(client, RX8025_REG_CTRL1, rx8025->ctrl1 & ~RX8025_BIT_CTRL1_DALE)) goto out; - local_irq_disable(); rtc_update_irq(rx8025->rtc, 1, RTC_AF | RTC_IRQF); - local_irq_enable(); } /* acknowledge IRQ */ From df100c017ea9f1a6a517c3fba84f8507973c004e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Jul 2015 16:01:06 -0700 Subject: [PATCH 21/90] rtc: make rtc_does_wakealarm() return boolean Users of rtc_does_wakealarm() return value treat it as boolean so let's change the signature accordingly. Signed-off-by: Dmitry Torokhov Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sysfs.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index babd43bf3ddc..2fbc11bb4352 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -230,10 +230,11 @@ static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, * suspend-to-disk. So: no attribute unless that side effect is possible. * (Userspace may disable that mechanism later.) */ -static inline int rtc_does_wakealarm(struct rtc_device *rtc) +static bool rtc_does_wakealarm(struct rtc_device *rtc) { if (!device_can_wakeup(rtc->dev.parent)) - return 0; + return false; + return rtc->ops->set_alarm != NULL; } From a17ccd1c6a327e5b468358e8352a6af004261473 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Jul 2015 16:01:07 -0700 Subject: [PATCH 22/90] rtc: switch wakealarm attribute to DEVICE_ATTR_RW Instead of using older style DEVICE_ATTR for wakealarm attribute let's switch to using DEVICE_ATTR_RW that ensures consistent across the kernel permissions on the attribute. Signed-off-by: Dmitry Torokhov Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sysfs.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index 2fbc11bb4352..e3ce1dc92b65 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -134,8 +134,7 @@ static struct attribute *rtc_attrs[] = { ATTRIBUTE_GROUPS(rtc); static ssize_t -rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr, - char *buf) +wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf) { ssize_t retval; unsigned long alarm; @@ -159,7 +158,7 @@ rtc_sysfs_show_wakealarm(struct device *dev, struct device_attribute *attr, } static ssize_t -rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, +wakealarm_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t n) { ssize_t retval; @@ -221,8 +220,7 @@ rtc_sysfs_set_wakealarm(struct device *dev, struct device_attribute *attr, retval = rtc_set_alarm(rtc, &alm); return (retval < 0) ? retval : n; } -static DEVICE_ATTR(wakealarm, S_IRUGO | S_IWUSR, - rtc_sysfs_show_wakealarm, rtc_sysfs_set_wakealarm); +static DEVICE_ATTR_RW(wakealarm); /* The reason to trigger an alarm with no process watching it (via sysfs) From 3ee2c40b7ac2bf121aaa1176d8ac25b6a26e3a94 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Jul 2015 16:01:08 -0700 Subject: [PATCH 23/90] rtc: switch to using is_visible() to control sysfs attributes Instead of creating wakealarm attribute manually, after the device has been registered, let's rely on facilities provided by the attribute groups to control which attributes are visible and which are not. This allows to create all needed attributes at once, at the same time that we register RTC class device. Signed-off-by: Dmitry Torokhov Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/class.c | 4 +-- drivers/rtc/rtc-core.h | 19 +++---------- drivers/rtc/rtc-sysfs.c | 59 +++++++++++++++++++++-------------------- 3 files changed, 34 insertions(+), 48 deletions(-) diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index de7707f7e766..de86578bcd6d 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -202,6 +202,7 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, rtc->max_user_freq = 64; rtc->dev.parent = dev; rtc->dev.class = rtc_class; + rtc->dev.groups = rtc_get_dev_attribute_groups(); rtc->dev.release = rtc_device_release; mutex_init(&rtc->ops_lock); @@ -240,7 +241,6 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev, } rtc_dev_add_device(rtc); - rtc_sysfs_add_device(rtc); rtc_proc_add_device(rtc); dev_info(dev, "rtc core: registered %s as %s\n", @@ -271,7 +271,6 @@ void rtc_device_unregister(struct rtc_device *rtc) * 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); @@ -360,7 +359,6 @@ static int __init rtc_init(void) } rtc_class->pm = RTC_CLASS_DEV_PM_OPS; rtc_dev_init(); - rtc_sysfs_init(rtc_class); return 0; } diff --git a/drivers/rtc/rtc-core.h b/drivers/rtc/rtc-core.h index 5f9df7430a22..a098aea197fc 100644 --- a/drivers/rtc/rtc-core.h +++ b/drivers/rtc/rtc-core.h @@ -48,23 +48,10 @@ static inline void rtc_proc_del_device(struct rtc_device *rtc) #endif #ifdef CONFIG_RTC_INTF_SYSFS - -extern void __init rtc_sysfs_init(struct class *); -extern void rtc_sysfs_add_device(struct rtc_device *rtc); -extern void rtc_sysfs_del_device(struct rtc_device *rtc); - +const struct attribute_group **rtc_get_dev_attribute_groups(void); #else - -static inline void rtc_sysfs_init(struct class *rtc) +static inline const struct attribute_group **rtc_get_dev_attribute_groups(void) { + return NULL; } - -static inline void rtc_sysfs_add_device(struct rtc_device *rtc) -{ -} - -static inline void rtc_sysfs_del_device(struct rtc_device *rtc) -{ -} - #endif diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c index e3ce1dc92b65..7273855ed02e 100644 --- a/drivers/rtc/rtc-sysfs.c +++ b/drivers/rtc/rtc-sysfs.c @@ -122,17 +122,6 @@ hctosys_show(struct device *dev, struct device_attribute *attr, char *buf) } static DEVICE_ATTR_RO(hctosys); -static struct attribute *rtc_attrs[] = { - &dev_attr_name.attr, - &dev_attr_date.attr, - &dev_attr_time.attr, - &dev_attr_since_epoch.attr, - &dev_attr_max_user_freq.attr, - &dev_attr_hctosys.attr, - NULL, -}; -ATTRIBUTE_GROUPS(rtc); - static ssize_t wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -222,6 +211,16 @@ wakealarm_store(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RW(wakealarm); +static struct attribute *rtc_attrs[] = { + &dev_attr_name.attr, + &dev_attr_date.attr, + &dev_attr_time.attr, + &dev_attr_since_epoch.attr, + &dev_attr_max_user_freq.attr, + &dev_attr_hctosys.attr, + &dev_attr_wakealarm.attr, + NULL, +}; /* The reason to trigger an alarm with no process watching it (via sysfs) * is its side effect: waking from a system state like suspend-to-RAM or @@ -236,29 +235,31 @@ static bool rtc_does_wakealarm(struct rtc_device *rtc) return rtc->ops->set_alarm != NULL; } - -void rtc_sysfs_add_device(struct rtc_device *rtc) +static umode_t rtc_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) { - int err; + struct device *dev = container_of(kobj, struct device, kobj); + struct rtc_device *rtc = to_rtc_device(dev); + umode_t mode = attr->mode; - /* not all RTCs support both alarms and wakeup */ - if (!rtc_does_wakealarm(rtc)) - return; + if (attr == &dev_attr_wakealarm.attr) + if (!rtc_does_wakealarm(rtc)) + mode = 0; - err = device_create_file(&rtc->dev, &dev_attr_wakealarm); - if (err) - dev_err(rtc->dev.parent, - "failed to create alarm attribute, %d\n", err); + return mode; } -void rtc_sysfs_del_device(struct rtc_device *rtc) -{ - /* REVISIT did we add it successfully? */ - if (rtc_does_wakealarm(rtc)) - device_remove_file(&rtc->dev, &dev_attr_wakealarm); -} +static struct attribute_group rtc_attr_group = { + .is_visible = rtc_attr_is_visible, + .attrs = rtc_attrs, +}; -void __init rtc_sysfs_init(struct class *rtc_class) +static const struct attribute_group *rtc_attr_groups[] = { + &rtc_attr_group, + NULL +}; + +const struct attribute_group **rtc_get_dev_attribute_groups(void) { - rtc_class->dev_groups = rtc_groups; + return rtc_attr_groups; } From d7f9777de884daf5721211bddfd21e7c8c156b17 Mon Sep 17 00:00:00 2001 From: Henry Chen Date: Thu, 30 Jul 2015 22:53:14 +0800 Subject: [PATCH 24/90] rtc: mt6397: implement suspend/resume function in rtc-mt6397 driver Implement the suspend/resume function in order to control rtc's irq_wake flag and handle as wakeup source. Signed-off-by: Henry Chen Acked-by: Eddie Huang Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-mt6397.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index eab230be5a54..30c926b36361 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -373,6 +373,31 @@ static int mtk_rtc_remove(struct platform_device *pdev) return 0; } +#ifdef CONFIG_PM_SLEEP +static int mt6397_rtc_suspend(struct device *dev) +{ + struct mt6397_rtc *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + enable_irq_wake(rtc->irq); + + return 0; +} + +static int mt6397_rtc_resume(struct device *dev) +{ + struct mt6397_rtc *rtc = dev_get_drvdata(dev); + + if (device_may_wakeup(dev)) + disable_irq_wake(rtc->irq); + + return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(mt6397_pm_ops, mt6397_rtc_suspend, + mt6397_rtc_resume); + static const struct of_device_id mt6397_rtc_of_match[] = { { .compatible = "mediatek,mt6397-rtc", }, { } @@ -382,6 +407,7 @@ static struct platform_driver mtk_rtc_driver = { .driver = { .name = "mt6397-rtc", .of_match_table = mt6397_rtc_of_match, + .pm = &mt6397_pm_ops, }, .probe = mtk_rtc_probe, .remove = mtk_rtc_remove, From 80ca3277bc7f398e3315af996443464dac5d4b88 Mon Sep 17 00:00:00 2001 From: S Twiss Date: Tue, 21 Jul 2015 11:29:07 +0100 Subject: [PATCH 25/90] rtc: da9063: Add DA9062 RTC capability to DA9063 RTC driver Add DA9062 RTC support into the existing DA9063 RTC driver component by using generic access tables for common register and bit mask definitions. The following change will add generic register and bit mask support to the DA9063 RTC. The changes are slightly complicated by requiring support for three register sets: DA9063-AD, DA9063-BB and DA9062-AA. The following alterations have been made to the DA9063 RTC: - Addition of a da9063_compatible_rtc_regmap structure to hold all generic registers and bitmasks for this type of RTC component. - A re-write of struct da9063 to use pointers for regmap and compatible registers/masks definitions - Addition of a of_device_id table for DA9063 and DA9062 defaults - Refactoring functions to use struct da9063_compatible_rtc accesses to generic registers/masks instead of using defines from registers.h - Re-work of da9063_rtc_probe() to use of_match_node() and dev_get_regmap() to provide initialisation of generic registers and masks and access to regmap Signed-off-by: Steve Twiss Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 6 +- drivers/rtc/rtc-da9063.c | 391 ++++++++++++++++++++++++++++----------- 2 files changed, 282 insertions(+), 115 deletions(-) diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index e132ccbec515..35ea04c50a5c 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -945,11 +945,11 @@ config RTC_DRV_DA9055 will be called rtc-da9055 config RTC_DRV_DA9063 - tristate "Dialog Semiconductor DA9063 RTC" - depends on MFD_DA9063 + tristate "Dialog Semiconductor DA9063/DA9062 RTC" + depends on MFD_DA9063 || MFD_DA9062 help If you say yes here you will get support for the RTC subsystem - of the Dialog Semiconductor DA9063. + for the Dialog Semiconductor PMIC chips DA9063 and DA9062. This driver can also be built as a module. If so, the module will be called "rtc-da9063". diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c index 7ffc5707f8b9..5f38a5c84b56 100644 --- a/drivers/rtc/rtc-da9063.c +++ b/drivers/rtc/rtc-da9063.c @@ -12,15 +12,18 @@ * Library General Public License for more details. */ +#include +#include +#include #include #include -#include +#include #include -#include +#include #include #include -#include -#include + +#include #include #include @@ -29,99 +32,230 @@ #define YEARS_FROM_DA9063(year) ((year) + 100) #define MONTHS_FROM_DA9063(month) ((month) - 1) -#define RTC_ALARM_DATA_LEN (DA9063_AD_REG_ALARM_Y - DA9063_AD_REG_ALARM_MI + 1) - -#define RTC_DATA_LEN (DA9063_REG_COUNT_Y - DA9063_REG_COUNT_S + 1) -#define RTC_SEC 0 -#define RTC_MIN 1 -#define RTC_HOUR 2 -#define RTC_DAY 3 -#define RTC_MONTH 4 -#define RTC_YEAR 5 - -struct da9063_rtc { - struct rtc_device *rtc_dev; - struct da9063 *hw; - struct rtc_time alarm_time; - bool rtc_sync; - int alarm_year; - int alarm_start; - int alarm_len; - int data_start; +enum { + RTC_SEC = 0, + RTC_MIN = 1, + RTC_HOUR = 2, + RTC_DAY = 3, + RTC_MONTH = 4, + RTC_YEAR = 5, + RTC_DATA_LEN }; -static void da9063_data_to_tm(u8 *data, struct rtc_time *tm) +struct da9063_compatible_rtc_regmap { + /* REGS */ + int rtc_enable_reg; + int rtc_enable_32k_crystal_reg; + int rtc_alarm_secs_reg; + int rtc_alarm_year_reg; + int rtc_count_secs_reg; + int rtc_count_year_reg; + int rtc_event_reg; + /* MASKS */ + int rtc_enable_mask; + int rtc_crystal_mask; + int rtc_event_alarm_mask; + int rtc_alarm_on_mask; + int rtc_alarm_status_mask; + int rtc_tick_on_mask; + int rtc_ready_to_read_mask; + int rtc_count_sec_mask; + int rtc_count_min_mask; + int rtc_count_hour_mask; + int rtc_count_day_mask; + int rtc_count_month_mask; + int rtc_count_year_mask; + /* ALARM CONFIG */ + int rtc_data_start; + int rtc_alarm_len; +}; + +struct da9063_compatible_rtc { + struct rtc_device *rtc_dev; + struct rtc_time alarm_time; + struct regmap *regmap; + const struct da9063_compatible_rtc_regmap *config; + bool rtc_sync; +}; + +static const struct da9063_compatible_rtc_regmap da9063_ad_regs = { + /* REGS */ + .rtc_enable_reg = DA9063_REG_CONTROL_E, + .rtc_alarm_secs_reg = DA9063_AD_REG_ALARM_MI, + .rtc_alarm_year_reg = DA9063_AD_REG_ALARM_Y, + .rtc_count_secs_reg = DA9063_REG_COUNT_S, + .rtc_count_year_reg = DA9063_REG_COUNT_Y, + .rtc_event_reg = DA9063_REG_EVENT_A, + /* MASKS */ + .rtc_enable_mask = DA9063_RTC_EN, + .rtc_crystal_mask = DA9063_CRYSTAL, + .rtc_enable_32k_crystal_reg = DA9063_REG_EN_32K, + .rtc_event_alarm_mask = DA9063_E_ALARM, + .rtc_alarm_on_mask = DA9063_ALARM_ON, + .rtc_alarm_status_mask = DA9063_ALARM_STATUS_ALARM | + DA9063_ALARM_STATUS_TICK, + .rtc_tick_on_mask = DA9063_TICK_ON, + .rtc_ready_to_read_mask = DA9063_RTC_READ, + .rtc_count_sec_mask = DA9063_COUNT_SEC_MASK, + .rtc_count_min_mask = DA9063_COUNT_MIN_MASK, + .rtc_count_hour_mask = DA9063_COUNT_HOUR_MASK, + .rtc_count_day_mask = DA9063_COUNT_DAY_MASK, + .rtc_count_month_mask = DA9063_COUNT_MONTH_MASK, + .rtc_count_year_mask = DA9063_COUNT_YEAR_MASK, + /* ALARM CONFIG */ + .rtc_data_start = RTC_MIN, + .rtc_alarm_len = RTC_DATA_LEN - 1, +}; + +static const struct da9063_compatible_rtc_regmap da9063_bb_regs = { + /* REGS */ + .rtc_enable_reg = DA9063_REG_CONTROL_E, + .rtc_alarm_secs_reg = DA9063_BB_REG_ALARM_S, + .rtc_alarm_year_reg = DA9063_BB_REG_ALARM_Y, + .rtc_count_secs_reg = DA9063_REG_COUNT_S, + .rtc_count_year_reg = DA9063_REG_COUNT_Y, + .rtc_event_reg = DA9063_REG_EVENT_A, + /* MASKS */ + .rtc_enable_mask = DA9063_RTC_EN, + .rtc_crystal_mask = DA9063_CRYSTAL, + .rtc_enable_32k_crystal_reg = DA9063_REG_EN_32K, + .rtc_event_alarm_mask = DA9063_E_ALARM, + .rtc_alarm_on_mask = DA9063_ALARM_ON, + .rtc_alarm_status_mask = DA9063_ALARM_STATUS_ALARM | + DA9063_ALARM_STATUS_TICK, + .rtc_tick_on_mask = DA9063_TICK_ON, + .rtc_ready_to_read_mask = DA9063_RTC_READ, + .rtc_count_sec_mask = DA9063_COUNT_SEC_MASK, + .rtc_count_min_mask = DA9063_COUNT_MIN_MASK, + .rtc_count_hour_mask = DA9063_COUNT_HOUR_MASK, + .rtc_count_day_mask = DA9063_COUNT_DAY_MASK, + .rtc_count_month_mask = DA9063_COUNT_MONTH_MASK, + .rtc_count_year_mask = DA9063_COUNT_YEAR_MASK, + /* ALARM CONFIG */ + .rtc_data_start = RTC_SEC, + .rtc_alarm_len = RTC_DATA_LEN, +}; + +static const struct da9063_compatible_rtc_regmap da9062_aa_regs = { + /* REGS */ + .rtc_enable_reg = DA9062AA_CONTROL_E, + .rtc_alarm_secs_reg = DA9062AA_ALARM_S, + .rtc_alarm_year_reg = DA9062AA_ALARM_Y, + .rtc_count_secs_reg = DA9062AA_COUNT_S, + .rtc_count_year_reg = DA9062AA_COUNT_Y, + .rtc_event_reg = DA9062AA_EVENT_A, + /* MASKS */ + .rtc_enable_mask = DA9062AA_RTC_EN_MASK, + .rtc_crystal_mask = DA9062AA_CRYSTAL_MASK, + .rtc_enable_32k_crystal_reg = DA9062AA_EN_32K, + .rtc_event_alarm_mask = DA9062AA_M_ALARM_MASK, + .rtc_alarm_on_mask = DA9062AA_ALARM_ON_MASK, + .rtc_alarm_status_mask = (0x02 << 6), + .rtc_tick_on_mask = DA9062AA_TICK_ON_MASK, + .rtc_ready_to_read_mask = DA9062AA_RTC_READ_MASK, + .rtc_count_sec_mask = DA9062AA_COUNT_SEC_MASK, + .rtc_count_min_mask = DA9062AA_COUNT_MIN_MASK, + .rtc_count_hour_mask = DA9062AA_COUNT_HOUR_MASK, + .rtc_count_day_mask = DA9062AA_COUNT_DAY_MASK, + .rtc_count_month_mask = DA9062AA_COUNT_MONTH_MASK, + .rtc_count_year_mask = DA9062AA_COUNT_YEAR_MASK, + /* ALARM CONFIG */ + .rtc_data_start = RTC_SEC, + .rtc_alarm_len = RTC_DATA_LEN, +}; + +static const struct of_device_id da9063_compatible_reg_id_table[] = { + { .compatible = "dlg,da9063-rtc", .data = &da9063_bb_regs }, + { .compatible = "dlg,da9062-rtc", .data = &da9062_aa_regs }, + { }, +}; + +static void da9063_data_to_tm(u8 *data, struct rtc_time *tm, + struct da9063_compatible_rtc *rtc) { - tm->tm_sec = data[RTC_SEC] & DA9063_COUNT_SEC_MASK; - tm->tm_min = data[RTC_MIN] & DA9063_COUNT_MIN_MASK; - tm->tm_hour = data[RTC_HOUR] & DA9063_COUNT_HOUR_MASK; - tm->tm_mday = data[RTC_DAY] & DA9063_COUNT_DAY_MASK; + const struct da9063_compatible_rtc_regmap *config = rtc->config; + + tm->tm_sec = data[RTC_SEC] & config->rtc_count_sec_mask; + tm->tm_min = data[RTC_MIN] & config->rtc_count_min_mask; + tm->tm_hour = data[RTC_HOUR] & config->rtc_count_hour_mask; + tm->tm_mday = data[RTC_DAY] & config->rtc_count_day_mask; tm->tm_mon = MONTHS_FROM_DA9063(data[RTC_MONTH] & - DA9063_COUNT_MONTH_MASK); + config->rtc_count_month_mask); tm->tm_year = YEARS_FROM_DA9063(data[RTC_YEAR] & - DA9063_COUNT_YEAR_MASK); + config->rtc_count_year_mask); } -static void da9063_tm_to_data(struct rtc_time *tm, u8 *data) +static void da9063_tm_to_data(struct rtc_time *tm, u8 *data, + struct da9063_compatible_rtc *rtc) { - data[RTC_SEC] &= ~DA9063_COUNT_SEC_MASK; - data[RTC_SEC] |= tm->tm_sec & DA9063_COUNT_SEC_MASK; + const struct da9063_compatible_rtc_regmap *config = rtc->config; - data[RTC_MIN] &= ~DA9063_COUNT_MIN_MASK; - data[RTC_MIN] |= tm->tm_min & DA9063_COUNT_MIN_MASK; + data[RTC_SEC] &= ~config->rtc_count_sec_mask; + data[RTC_SEC] |= tm->tm_sec & config->rtc_count_sec_mask; - data[RTC_HOUR] &= ~DA9063_COUNT_HOUR_MASK; - data[RTC_HOUR] |= tm->tm_hour & DA9063_COUNT_HOUR_MASK; + data[RTC_MIN] &= ~config->rtc_count_min_mask; + data[RTC_MIN] |= tm->tm_min & config->rtc_count_min_mask; - data[RTC_DAY] &= ~DA9063_COUNT_DAY_MASK; - data[RTC_DAY] |= tm->tm_mday & DA9063_COUNT_DAY_MASK; + data[RTC_HOUR] &= ~config->rtc_count_hour_mask; + data[RTC_HOUR] |= tm->tm_hour & config->rtc_count_hour_mask; - data[RTC_MONTH] &= ~DA9063_COUNT_MONTH_MASK; + data[RTC_DAY] &= ~config->rtc_count_day_mask; + data[RTC_DAY] |= tm->tm_mday & config->rtc_count_day_mask; + + data[RTC_MONTH] &= ~config->rtc_count_month_mask; data[RTC_MONTH] |= MONTHS_TO_DA9063(tm->tm_mon) & - DA9063_COUNT_MONTH_MASK; + config->rtc_count_month_mask; - data[RTC_YEAR] &= ~DA9063_COUNT_YEAR_MASK; + data[RTC_YEAR] &= ~config->rtc_count_year_mask; data[RTC_YEAR] |= YEARS_TO_DA9063(tm->tm_year) & - DA9063_COUNT_YEAR_MASK; + config->rtc_count_year_mask; } static int da9063_rtc_stop_alarm(struct device *dev) { - struct da9063_rtc *rtc = dev_get_drvdata(dev); + struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev); + const struct da9063_compatible_rtc_regmap *config = rtc->config; - return regmap_update_bits(rtc->hw->regmap, rtc->alarm_year, - DA9063_ALARM_ON, 0); + return regmap_update_bits(rtc->regmap, + config->rtc_alarm_year_reg, + config->rtc_alarm_on_mask, + 0); } static int da9063_rtc_start_alarm(struct device *dev) { - struct da9063_rtc *rtc = dev_get_drvdata(dev); + struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev); + const struct da9063_compatible_rtc_regmap *config = rtc->config; - return regmap_update_bits(rtc->hw->regmap, rtc->alarm_year, - DA9063_ALARM_ON, DA9063_ALARM_ON); + return regmap_update_bits(rtc->regmap, + config->rtc_alarm_year_reg, + config->rtc_alarm_on_mask, + config->rtc_alarm_on_mask); } static int da9063_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct da9063_rtc *rtc = dev_get_drvdata(dev); + struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev); + const struct da9063_compatible_rtc_regmap *config = rtc->config; unsigned long tm_secs; unsigned long al_secs; u8 data[RTC_DATA_LEN]; int ret; - ret = regmap_bulk_read(rtc->hw->regmap, DA9063_REG_COUNT_S, + ret = regmap_bulk_read(rtc->regmap, + config->rtc_count_secs_reg, data, RTC_DATA_LEN); if (ret < 0) { dev_err(dev, "Failed to read RTC time data: %d\n", ret); return ret; } - if (!(data[RTC_SEC] & DA9063_RTC_READ)) { + if (!(data[RTC_SEC] & config->rtc_ready_to_read_mask)) { dev_dbg(dev, "RTC not yet ready to be read by the host\n"); return -EINVAL; } - da9063_data_to_tm(data, tm); + da9063_data_to_tm(data, tm, rtc); rtc_tm_to_time(tm, &tm_secs); rtc_tm_to_time(&rtc->alarm_time, &al_secs); @@ -137,12 +271,14 @@ static int da9063_rtc_read_time(struct device *dev, struct rtc_time *tm) static int da9063_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct da9063_rtc *rtc = dev_get_drvdata(dev); + struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev); + const struct da9063_compatible_rtc_regmap *config = rtc->config; u8 data[RTC_DATA_LEN]; int ret; - da9063_tm_to_data(tm, data); - ret = regmap_bulk_write(rtc->hw->regmap, DA9063_REG_COUNT_S, + da9063_tm_to_data(tm, data, rtc); + ret = regmap_bulk_write(rtc->regmap, + config->rtc_count_secs_reg, data, RTC_DATA_LEN); if (ret < 0) dev_err(dev, "Failed to set RTC time data: %d\n", ret); @@ -152,26 +288,31 @@ static int da9063_rtc_set_time(struct device *dev, struct rtc_time *tm) static int da9063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { - struct da9063_rtc *rtc = dev_get_drvdata(dev); + struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev); + const struct da9063_compatible_rtc_regmap *config = rtc->config; u8 data[RTC_DATA_LEN]; int ret; unsigned int val; data[RTC_SEC] = 0; - ret = regmap_bulk_read(rtc->hw->regmap, rtc->alarm_start, - &data[rtc->data_start], rtc->alarm_len); + ret = regmap_bulk_read(rtc->regmap, + config->rtc_alarm_secs_reg, + &data[config->rtc_data_start], + config->rtc_alarm_len); if (ret < 0) return ret; - da9063_data_to_tm(data, &alrm->time); + da9063_data_to_tm(data, &alrm->time, rtc); - alrm->enabled = !!(data[RTC_YEAR] & DA9063_ALARM_ON); + alrm->enabled = !!(data[RTC_YEAR] & config->rtc_alarm_on_mask); - ret = regmap_read(rtc->hw->regmap, DA9063_REG_EVENT_A, &val); + ret = regmap_read(rtc->regmap, + config->rtc_event_reg, + &val); if (ret < 0) return ret; - if (val & (DA9063_E_ALARM)) + if (val & config->rtc_event_alarm_mask) alrm->pending = 1; else alrm->pending = 0; @@ -181,11 +322,12 @@ static int da9063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) { - struct da9063_rtc *rtc = dev_get_drvdata(dev); + struct da9063_compatible_rtc *rtc = dev_get_drvdata(dev); + const struct da9063_compatible_rtc_regmap *config = rtc->config; u8 data[RTC_DATA_LEN]; int ret; - da9063_tm_to_data(&alrm->time, data); + da9063_tm_to_data(&alrm->time, data, rtc); ret = da9063_rtc_stop_alarm(dev); if (ret < 0) { @@ -193,14 +335,16 @@ static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; } - ret = regmap_bulk_write(rtc->hw->regmap, rtc->alarm_start, - &data[rtc->data_start], rtc->alarm_len); + ret = regmap_bulk_write(rtc->regmap, + config->rtc_alarm_secs_reg, + &data[config->rtc_data_start], + config->rtc_alarm_len); if (ret < 0) { dev_err(dev, "Failed to write alarm: %d\n", ret); return ret; } - da9063_data_to_tm(data, &rtc->alarm_time); + da9063_data_to_tm(data, &rtc->alarm_time, rtc); if (alrm->enabled) { ret = da9063_rtc_start_alarm(dev); @@ -213,7 +357,8 @@ static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; } -static int da9063_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +static int da9063_rtc_alarm_irq_enable(struct device *dev, + unsigned int enabled) { if (enabled) return da9063_rtc_start_alarm(dev); @@ -223,10 +368,13 @@ static int da9063_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) static irqreturn_t da9063_alarm_event(int irq, void *data) { - struct da9063_rtc *rtc = data; + struct da9063_compatible_rtc *rtc = data; + const struct da9063_compatible_rtc_regmap *config = rtc->config; - regmap_update_bits(rtc->hw->regmap, rtc->alarm_year, - DA9063_ALARM_ON, 0); + regmap_update_bits(rtc->regmap, + config->rtc_alarm_year_reg, + config->rtc_alarm_on_mask, + 0); rtc->rtc_sync = true; rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF); @@ -244,72 +392,92 @@ static const struct rtc_class_ops da9063_rtc_ops = { static int da9063_rtc_probe(struct platform_device *pdev) { - struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); - struct da9063_rtc *rtc; + struct da9063_compatible_rtc *rtc; + const struct da9063_compatible_rtc_regmap *config; + const struct of_device_id *match; int irq_alarm; u8 data[RTC_DATA_LEN]; int ret; - ret = regmap_update_bits(da9063->regmap, DA9063_REG_CONTROL_E, - DA9063_RTC_EN, DA9063_RTC_EN); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to enable RTC\n"); - goto err; - } + if (!pdev->dev.of_node) + return -ENXIO; - ret = regmap_update_bits(da9063->regmap, DA9063_REG_EN_32K, - DA9063_CRYSTAL, DA9063_CRYSTAL); - if (ret < 0) { - dev_err(&pdev->dev, "Failed to run 32kHz oscillator\n"); - goto err; - } + match = of_match_node(da9063_compatible_reg_id_table, + pdev->dev.of_node); rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); if (!rtc) return -ENOMEM; - if (da9063->variant_code == PMIC_DA9063_AD) { - rtc->alarm_year = DA9063_AD_REG_ALARM_Y; - rtc->alarm_start = DA9063_AD_REG_ALARM_MI; - rtc->alarm_len = RTC_ALARM_DATA_LEN; - rtc->data_start = RTC_MIN; - } else { - rtc->alarm_year = DA9063_BB_REG_ALARM_Y; - rtc->alarm_start = DA9063_BB_REG_ALARM_S; - rtc->alarm_len = RTC_DATA_LEN; - rtc->data_start = RTC_SEC; + rtc->config = match->data; + if (of_device_is_compatible(pdev->dev.of_node, "dlg,da9063-rtc")) { + struct da9063 *chip = dev_get_drvdata(pdev->dev.parent); + + if (chip->variant_code == PMIC_DA9063_AD) + rtc->config = &da9063_ad_regs; } - ret = regmap_update_bits(da9063->regmap, rtc->alarm_start, - DA9063_ALARM_STATUS_TICK | DA9063_ALARM_STATUS_ALARM, - 0); + rtc->regmap = dev_get_regmap(pdev->dev.parent, NULL); + if (!rtc->regmap) { + dev_warn(&pdev->dev, "Parent regmap unavailable.\n"); + return -ENXIO; + } + + config = rtc->config; + ret = regmap_update_bits(rtc->regmap, + config->rtc_enable_reg, + config->rtc_enable_mask, + config->rtc_enable_mask); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to enable RTC\n"); + return ret; + } + + ret = regmap_update_bits(rtc->regmap, + config->rtc_enable_32k_crystal_reg, + config->rtc_crystal_mask, + config->rtc_crystal_mask); + if (ret < 0) { + dev_err(&pdev->dev, "Failed to run 32kHz oscillator\n"); + return ret; + } + + ret = regmap_update_bits(rtc->regmap, + config->rtc_alarm_secs_reg, + config->rtc_alarm_status_mask, + 0); if (ret < 0) { dev_err(&pdev->dev, "Failed to access RTC alarm register\n"); - goto err; + return ret; } - ret = regmap_update_bits(da9063->regmap, rtc->alarm_start, + ret = regmap_update_bits(rtc->regmap, + config->rtc_alarm_secs_reg, DA9063_ALARM_STATUS_ALARM, DA9063_ALARM_STATUS_ALARM); if (ret < 0) { dev_err(&pdev->dev, "Failed to access RTC alarm register\n"); - goto err; + return ret; } - ret = regmap_update_bits(da9063->regmap, rtc->alarm_year, - DA9063_TICK_ON, 0); + ret = regmap_update_bits(rtc->regmap, + config->rtc_alarm_year_reg, + config->rtc_tick_on_mask, + 0); if (ret < 0) { dev_err(&pdev->dev, "Failed to disable TICKs\n"); - goto err; + return ret; } data[RTC_SEC] = 0; - ret = regmap_bulk_read(da9063->regmap, rtc->alarm_start, - &data[rtc->data_start], rtc->alarm_len); + ret = regmap_bulk_read(rtc->regmap, + config->rtc_alarm_secs_reg, + &data[config->rtc_data_start], + config->rtc_alarm_len); if (ret < 0) { dev_err(&pdev->dev, "Failed to read initial alarm data: %d\n", ret); - goto err; + return ret; } platform_set_drvdata(pdev, rtc); @@ -322,18 +490,16 @@ static int da9063_rtc_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n", irq_alarm, ret); - goto err; + return ret; } - rtc->hw = da9063; rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC, &da9063_rtc_ops, THIS_MODULE); if (IS_ERR(rtc->rtc_dev)) return PTR_ERR(rtc->rtc_dev); - da9063_data_to_tm(data, &rtc->alarm_time); + da9063_data_to_tm(data, &rtc->alarm_time, rtc); rtc->rtc_sync = false; -err: return ret; } @@ -341,6 +507,7 @@ static struct platform_driver da9063_rtc_driver = { .probe = da9063_rtc_probe, .driver = { .name = DA9063_DRVNAME_RTC, + .of_match_table = da9063_compatible_reg_id_table, }, }; From 88b8d33b1c6aadba553c998db91c4b36be0fac52 Mon Sep 17 00:00:00 2001 From: Adrian Huang Date: Mon, 6 Jul 2015 12:19:12 +0800 Subject: [PATCH 26/90] rtc: cmos: Cancel alarm timer if alarm time is equal to now+1 seconds Steps to reproduce the problem: 1) Enable RTC wake-up option in BIOS Setup 2) Issue one of these commands in the OS: "poweroff" or "shutdown -h now" 3) System will shut down and then reboot automatically Root-cause of the issue: 1) During the shutdown process, the hwclock utility is used to save the system clock to hardware clock (RTC). 2) The hwclock utility invokes ioctl() with RTC_UIE_ON. The kernel configures the RTC alarm for the periodic interrupt (every 1 second). 3) The hwclock uitlity closes the /dev/rtc0 device, and the kernel disables the RTC alarm irq (AIE bit of Register B) via ioctl() with RTC_UIE_OFF. But, the configured alarm time is the current_time + 1. 4) After the next 1 second is elapsed, the AF (alarm interrupt flag) of Register C is set. 5) The S5 handler in BIOS is invoked to configure alarm registers (enable AIE bit and configure alarm date/time). But, BIOS does not clear the previous interrupt status during alarm configuration. Therefore, "AF=AIE=1" causes the rtc device to trigger an interrupt. 6) So, the machine reboots automatically right after shutdown. This patch cancels the alarm timer if the following condictions are met (suggested by Alexandre): 1) The configured alarm time is equal to current_time + 1 seconds. 2) The AIE timer is not in use. The member 'alarm_expires' is introduced in struct cmos_rtc because of the following reasons: 1) The configured alarm time can be retrieved from cmos_read_alarm(), but we need to take the 'wrapped timestamp' and 'time rollover' into consideration. The function __rtc_read_alarm() eliminates the concerns. To avoid the duplicated code in the lower level RTC driver, invoking __rtc_read_alarm from the lower level RTC driver is not encouraged. Moreover, the compilation error 'the undefined __rtc_read_alarm" is observed if the lower level RTC driver is compiled as a kernel module. 2) The uie_rtctimer.node.expires and aie_timer.node.expires can be retrieved for the configured alarm time. But, the problem is that either of them might configure the CMOS alarm time. We cannot make sure UIE timer or AIE tiemr configured the CMOS alarm time before. (uie_rtctimer or aie_timer is enabled and then is disabled). 3) The patch introduces the member 'alarm_expires' to keep the newly configured alarm time, so the above-mentioned concerns can be eliminated. The issue goes away after 20-time shutdown tests. Signed-off-by: Adrian Huang Tested-by: Egbert Eich Tested-by: Diego Ercolani Cc: Borislav Petkov Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cmos.c | 64 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index a82556a0757a..5ac9a5da8522 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -51,6 +51,7 @@ struct cmos_rtc { struct device *dev; int irq; struct resource *iomem; + time64_t alarm_expires; void (*wake_on)(struct device *); void (*wake_off)(struct device *); @@ -377,6 +378,8 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) spin_unlock_irq(&rtc_lock); + cmos->alarm_expires = rtc_tm_to_time64(&t->time); + return 0; } @@ -860,6 +863,51 @@ static void __exit cmos_do_remove(struct device *dev) cmos->dev = NULL; } +static int cmos_aie_poweroff(struct device *dev) +{ + struct cmos_rtc *cmos = dev_get_drvdata(dev); + struct rtc_time now; + time64_t t_now; + int retval = 0; + unsigned char rtc_control; + + if (!cmos->alarm_expires) + return -EINVAL; + + spin_lock_irq(&rtc_lock); + rtc_control = CMOS_READ(RTC_CONTROL); + spin_unlock_irq(&rtc_lock); + + /* We only care about the situation where AIE is disabled. */ + if (rtc_control & RTC_AIE) + return -EBUSY; + + cmos_read_time(dev, &now); + t_now = rtc_tm_to_time64(&now); + + /* + * When enabling "RTC wake-up" in BIOS setup, the machine reboots + * automatically right after shutdown on some buggy boxes. + * This automatic rebooting issue won't happen when the alarm + * time is larger than now+1 seconds. + * + * If the alarm time is equal to now+1 seconds, the issue can be + * prevented by cancelling the alarm. + */ + if (cmos->alarm_expires == t_now + 1) { + struct rtc_wkalrm alarm; + + /* Cancel the AIE timer by configuring the past time. */ + rtc_time64_to_tm(t_now - 1, &alarm.time); + alarm.enabled = 0; + retval = cmos_set_alarm(dev, &alarm); + } else if (cmos->alarm_expires > t_now + 1) { + retval = -EBUSY; + } + + return retval; +} + #ifdef CONFIG_PM static int cmos_suspend(struct device *dev) @@ -1094,8 +1142,12 @@ static void cmos_pnp_shutdown(struct pnp_dev *pnp) struct device *dev = &pnp->dev; struct cmos_rtc *cmos = dev_get_drvdata(dev); - if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev)) - return; + if (system_state == SYSTEM_POWER_OFF) { + int retval = cmos_poweroff(dev); + + if (cmos_aie_poweroff(dev) < 0 && !retval) + return; + } cmos_do_shutdown(cmos->irq); } @@ -1200,8 +1252,12 @@ static void cmos_platform_shutdown(struct platform_device *pdev) struct device *dev = &pdev->dev; struct cmos_rtc *cmos = dev_get_drvdata(dev); - if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev)) - return; + if (system_state == SYSTEM_POWER_OFF) { + int retval = cmos_poweroff(dev); + + if (cmos_aie_poweroff(dev) < 0 && !retval) + return; + } cmos_do_shutdown(cmos->irq); } From 8109d44f7604cd5ab833ea09da98703f6eb16460 Mon Sep 17 00:00:00 2001 From: Adrian Huang Date: Mon, 6 Jul 2015 12:19:13 +0800 Subject: [PATCH 27/90] rtc: cmos: Revert "rtc-cmos: Add an alarm disable quirk" Commit d5a1c7e3fc38 ("rtc-cmos: Add an alarm disable quirk") that added a special quirk is not needed because [PATCH 1/2] of this patchset makes the kernel more robust: rtc-cmos: Cancel alarm timer if alarm time is equal to now+1 seconds Signed-off-by: Adrian Huang Tested-by: Egbert Eich Tested-by: Diego Ercolani Cc: Borislav Petkov Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cmos.c | 50 ------------------------------------------ 1 file changed, 50 deletions(-) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 5ac9a5da8522..c2e90c62a59c 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -41,7 +41,6 @@ #include #include #include -#include /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */ #include @@ -383,50 +382,6 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) return 0; } -/* - * Do not disable RTC alarm on shutdown - workaround for b0rked BIOSes. - */ -static bool alarm_disable_quirk; - -static int __init set_alarm_disable_quirk(const struct dmi_system_id *id) -{ - alarm_disable_quirk = true; - pr_info("BIOS has alarm-disable quirk - RTC alarms disabled\n"); - return 0; -} - -static const struct dmi_system_id rtc_quirks[] __initconst = { - /* https://bugzilla.novell.com/show_bug.cgi?id=805740 */ - { - .callback = set_alarm_disable_quirk, - .ident = "IBM Truman", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_NAME, "4852570"), - }, - }, - /* https://bugzilla.novell.com/show_bug.cgi?id=812592 */ - { - .callback = set_alarm_disable_quirk, - .ident = "Gigabyte GA-990XA-UD3", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, - "Gigabyte Technology Co., Ltd."), - DMI_MATCH(DMI_PRODUCT_NAME, "GA-990XA-UD3"), - }, - }, - /* http://permalink.gmane.org/gmane.linux.kernel/1604474 */ - { - .callback = set_alarm_disable_quirk, - .ident = "Toshiba Satellite L300", - .matches = { - DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), - DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L300"), - }, - }, - {} -}; - static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) { struct cmos_rtc *cmos = dev_get_drvdata(dev); @@ -435,9 +390,6 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled) if (!is_valid_irq(cmos->irq)) return -EINVAL; - if (alarm_disable_quirk) - return 0; - spin_lock_irqsave(&rtc_lock, flags); if (enabled) @@ -1299,8 +1251,6 @@ static int __init cmos_init(void) platform_driver_registered = true; } - dmi_check_system(rtc_quirks); - if (retval == 0) return 0; From 1c4fc2955ad37afb0d75ed5a67bad94c1529b0cf Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 30 Jul 2015 18:18:46 +0200 Subject: [PATCH 28/90] rtc: Export OF module alias information in missing drivers The I2C core always reports the MODALIAS uevent as "i2c: Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ab-b5ze-s3.c | 1 + drivers/rtc/rtc-isl12022.c | 1 + drivers/rtc/rtc-isl12057.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/rtc/rtc-ab-b5ze-s3.c b/drivers/rtc/rtc-ab-b5ze-s3.c index 0fb1d767afa9..a319bf1e49de 100644 --- a/drivers/rtc/rtc-ab-b5ze-s3.c +++ b/drivers/rtc/rtc-ab-b5ze-s3.c @@ -1009,6 +1009,7 @@ static const struct of_device_id abb5zes3_dt_match[] = { { .compatible = "abracon,abb5zes3" }, { }, }; +MODULE_DEVICE_TABLE(of, abb5zes3_dt_match); #endif static const struct i2c_device_id abb5zes3_id[] = { diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index 372627136786..839d1fd63cd7 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -274,6 +274,7 @@ static const struct of_device_id isl12022_dt_match[] = { { .compatible = "isil,isl12022" }, { }, }; +MODULE_DEVICE_TABLE(of, isl12022_dt_match); #endif static const struct i2c_device_id isl12022_id[] = { diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c index ee3e8dbcacaf..a0462e5430c7 100644 --- a/drivers/rtc/rtc-isl12057.c +++ b/drivers/rtc/rtc-isl12057.c @@ -648,6 +648,7 @@ static const struct of_device_id isl12057_dt_match[] = { { .compatible = "isil,isl12057" }, { }, }; +MODULE_DEVICE_TABLE(of, isl12057_dt_match); #endif static const struct i2c_device_id isl12057_id[] = { From 27675ef03c0535158b77af76591920fe041ebf14 Mon Sep 17 00:00:00 2001 From: Leo Yan Date: Wed, 29 Jul 2015 14:13:40 +0800 Subject: [PATCH 29/90] rtc: pl031: fix typo for author email The email address missed character ">", so add it. Signed-off-by: Leo Yan Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pl031.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 99181fff88fd..41dcb7ddb906 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -476,6 +476,6 @@ static struct amba_driver pl031_driver = { module_amba_driver(pl031_driver); -MODULE_AUTHOR("Deepak Saxena "); MODULE_DESCRIPTION("ARM AMBA PL031 RTC Driver"); MODULE_LICENSE("GPL"); From ffe60fcfda98a3e4f51bc1e02ff5412a7e1c9c79 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 28 Jul 2015 21:46:15 +0200 Subject: [PATCH 30/90] rtc: at91sam9: properly handle error case In case of a probe error, it is possible to abort after issuing clk_prepare_enable(). Ensure the clock is disabled and unprepared in that case. Signed-off-by: Alexandre Belloni Acked-by: Boris Brezillon Acked-by: Nicolas Ferre --- drivers/rtc/rtc-at91sam9.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 5ccaee32df72..152cd816cc43 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -451,8 +451,10 @@ static int at91_rtc_probe(struct platform_device *pdev) rtc->rtcdev = devm_rtc_device_register(&pdev->dev, pdev->name, &at91_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc->rtcdev)) - return PTR_ERR(rtc->rtcdev); + if (IS_ERR(rtc->rtcdev)) { + ret = PTR_ERR(rtc->rtcdev); + goto err_clk; + } /* register irq handler after we know what name we'll use */ ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt, @@ -460,7 +462,7 @@ static int at91_rtc_probe(struct platform_device *pdev) dev_name(&rtc->rtcdev->dev), rtc); if (ret) { dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq); - return ret; + goto err_clk; } /* NOTE: sam9260 rev A silicon has a ROM bug which resets the @@ -474,6 +476,11 @@ static int at91_rtc_probe(struct platform_device *pdev) dev_name(&rtc->rtcdev->dev)); return 0; + +err_clk: + clk_disable_unprepare(rtc->sclk); + + return ret; } /* From 73ab31ce1bbc64c590b2a2d58364942adfa11a3f Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 28 Jul 2015 21:47:57 +0200 Subject: [PATCH 31/90] rtc: at91sam9: remove useless check rtc->sclk necessarily points to a valid clocks at this point. Else the probe would have aborted. Signed-off-by: Alexandre Belloni Acked-by: Boris Brezillon Acked-by: Nicolas Ferre --- drivers/rtc/rtc-at91sam9.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 152cd816cc43..0a8485ac3864 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -494,8 +494,7 @@ static int at91_rtc_remove(struct platform_device *pdev) /* disable all interrupts */ rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN)); - if (!IS_ERR(rtc->sclk)) - clk_disable_unprepare(rtc->sclk); + clk_disable_unprepare(rtc->sclk); return 0; } From 6932ff5395e3a2541fba696b38dc71393cf7ce57 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 28 Jul 2015 21:49:24 +0200 Subject: [PATCH 32/90] rtc: at91sam9: sort headers alphabetically Sort included headers alphabetically. Signed-off-by: Alexandre Belloni Acked-by: Boris Brezillon Acked-by: Nicolas Ferre --- drivers/rtc/rtc-at91sam9.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 0a8485ac3864..23f721d049b2 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -11,20 +11,20 @@ * 2 of the License, or (at your option) any later version. */ -#include -#include -#include -#include -#include +#include #include #include -#include -#include #include +#include #include +#include +#include +#include #include +#include +#include #include -#include +#include /* * This driver uses two configurable hardware resources that live in the From 8918bd8a5f6c37963ba04ae79ad6488108894ab9 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 28 Jul 2015 21:51:10 +0200 Subject: [PATCH 33/90] rtc: at91sam9: get sclk rate after enabling it See help for clk_get_rate(): "obtain the current clock rate (in Hz) for a clock source. This is only valid once the clock source has been enabled." It currently returns the correct value but that may not stay that way. Signed-off-by: Alexandre Belloni Acked-by: Boris Brezillon Acked-by: Nicolas Ferre --- drivers/rtc/rtc-at91sam9.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 23f721d049b2..f9e85ace5e71 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -425,18 +425,19 @@ static int at91_rtc_probe(struct platform_device *pdev) if (IS_ERR(rtc->sclk)) return PTR_ERR(rtc->sclk); - sclk_rate = clk_get_rate(rtc->sclk); - if (!sclk_rate || sclk_rate > AT91_RTT_RTPRES) { - dev_err(&pdev->dev, "Invalid slow clock rate\n"); - return -EINVAL; - } - ret = clk_prepare_enable(rtc->sclk); if (ret) { dev_err(&pdev->dev, "Could not enable slow clock\n"); return ret; } + sclk_rate = clk_get_rate(rtc->sclk); + if (!sclk_rate || sclk_rate > AT91_RTT_RTPRES) { + dev_err(&pdev->dev, "Invalid slow clock rate\n"); + ret = -EINVAL; + goto err_clk; + } + mr = rtt_readl(rtc, MR); /* unless RTT is counting at 1 Hz, re-initialize it */ From 74000eb14a173f427240b90363580c686a675ddf Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Wed, 29 Jul 2015 02:01:33 +0200 Subject: [PATCH 34/90] rtc: at91rm9200: sort headers alphabetically Sort included headers alphabetically. Signed-off-by: Alexandre Belloni Acked-by: Boris Brezillon Acked-by: Nicolas Ferre --- drivers/rtc/rtc-at91rm9200.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 35efd3f75b18..c4062d9f1bdd 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -18,20 +18,20 @@ * */ -#include -#include -#include -#include -#include #include -#include -#include -#include #include +#include +#include #include -#include +#include +#include #include +#include +#include +#include +#include #include +#include #include #include "rtc-at91rm9200.h" From e7cba884af366f49ab7b7f5157e690357addebba Mon Sep 17 00:00:00 2001 From: viresh kumar Date: Fri, 31 Jul 2015 16:23:43 +0530 Subject: [PATCH 35/90] rtc: Drop (un)likely before IS_ERR(_OR_NULL) IS_ERR(_OR_NULL) already contain an 'unlikely' compiler flag and there is no need to do that again from its callers. Drop it. gemini driver was using likely() for a failure case while the rtc driver is getting registered. That looks wrong and it should really be unlikely. But because we are killing all the unlikely() flags, lets kill that too. Signed-off-by: Viresh Kumar Acked-by: Hans Ulli Kroll Signed-off-by: Alexandre Belloni --- drivers/rtc/interface.c | 2 +- drivers/rtc/rtc-bfin.c | 2 +- drivers/rtc/rtc-gemini.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 11b639067312..5836751b8203 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -564,7 +564,7 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer) void rtc_update_irq(struct rtc_device *rtc, unsigned long num, unsigned long events) { - if (unlikely(IS_ERR_OR_NULL(rtc))) + if (IS_ERR_OR_NULL(rtc)) return; pm_stay_awake(rtc->dev.parent); diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 3d44b11721ea..535a5f9338d0 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -361,7 +361,7 @@ static int bfin_rtc_probe(struct platform_device *pdev) /* Register our RTC with the RTC framework */ rtc->rtc_dev = devm_rtc_device_register(dev, pdev->name, &bfin_rtc_ops, THIS_MODULE); - if (unlikely(IS_ERR(rtc->rtc_dev))) + if (IS_ERR(rtc->rtc_dev)) return PTR_ERR(rtc->rtc_dev); /* Grab the IRQ and init the hardware */ diff --git a/drivers/rtc/rtc-gemini.c b/drivers/rtc/rtc-gemini.c index 35f4486738fc..2fed93e1114a 100644 --- a/drivers/rtc/rtc-gemini.c +++ b/drivers/rtc/rtc-gemini.c @@ -148,7 +148,7 @@ static int gemini_rtc_probe(struct platform_device *pdev) rtc->rtc_dev = rtc_device_register(pdev->name, dev, &gemini_rtc_ops, THIS_MODULE); - if (likely(IS_ERR(rtc->rtc_dev))) + if (IS_ERR(rtc->rtc_dev)) return PTR_ERR(rtc->rtc_dev); return 0; From 202cc98acf96de1c3897194e1ed5ae1c80c8b0f3 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Fri, 31 Jul 2015 15:01:04 +0530 Subject: [PATCH 36/90] rtc: gemini: fix ptr_ret.cocci warnings drivers/rtc/rtc-gemini.c:151:1-3: WARNING: PTR_ERR_OR_ZERO can be used Use PTR_ERR_OR_ZERO rather than if(IS_ERR(...)) + PTR_ERR Generated by: scripts/coccinelle/api/ptr_ret.cocci Signed-off-by: Fengguang Wu Signed-off-by: Viresh Kumar Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-gemini.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-gemini.c b/drivers/rtc/rtc-gemini.c index 2fed93e1114a..e84184647d15 100644 --- a/drivers/rtc/rtc-gemini.c +++ b/drivers/rtc/rtc-gemini.c @@ -148,10 +148,7 @@ static int gemini_rtc_probe(struct platform_device *pdev) rtc->rtc_dev = rtc_device_register(pdev->name, dev, &gemini_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc->rtc_dev)) - return PTR_ERR(rtc->rtc_dev); - - return 0; + return PTR_ERR_OR_ZERO(rtc->rtc_dev); } static int gemini_rtc_remove(struct platform_device *pdev) From 11f67a8bbf65872c3e9edc70242420a8c314a860 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 31 Jul 2015 11:39:51 +0200 Subject: [PATCH 37/90] rtc: at91rm9200: get and use slow clock Commit dca1a4b5ff6e ("clk: at91: keep slow clk enabled to prevent system hang") added a workaround for the slow clock as it is not properly handled by its users. Get and use the slow clock as it is necessary for the at91rm9200 rtc. Acked-by: Boris Brezillon Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-at91rm9200.c | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index c4062d9f1bdd..cb62e214b52a 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -19,6 +19,7 @@ */ #include +#include #include #include #include @@ -59,6 +60,7 @@ static bool suspended; static DEFINE_SPINLOCK(suspended_lock); static unsigned long cached_events; static u32 at91_rtc_imr; +static struct clk *sclk; static void at91_rtc_write_ier(u32 mask) { @@ -407,6 +409,16 @@ static int __init at91_rtc_probe(struct platform_device *pdev) return -ENOMEM; } + sclk = devm_clk_get(&pdev->dev, NULL); + if (IS_ERR(sclk)) + return PTR_ERR(sclk); + + ret = clk_prepare_enable(sclk); + if (ret) { + dev_err(&pdev->dev, "Could not enable slow clock\n"); + return ret; + } + at91_rtc_write(AT91_RTC_CR, 0); at91_rtc_write(AT91_RTC_MR, 0); /* 24 hour mode */ @@ -420,7 +432,7 @@ static int __init at91_rtc_probe(struct platform_device *pdev) "at91_rtc", pdev); if (ret) { dev_err(&pdev->dev, "IRQ %d already in use.\n", irq); - return ret; + goto err_clk; } /* cpu init code should really have flagged this device as @@ -431,8 +443,10 @@ static int __init at91_rtc_probe(struct platform_device *pdev) rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &at91_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) - return PTR_ERR(rtc); + if (IS_ERR(rtc)) { + ret = PTR_ERR(rtc); + goto err_clk; + } platform_set_drvdata(pdev, rtc); /* enable SECEV interrupt in order to initialize at91_rtc_upd_rdy @@ -442,6 +456,11 @@ static int __init at91_rtc_probe(struct platform_device *pdev) dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n"); return 0; + +err_clk: + clk_disable_unprepare(sclk); + + return ret; } /* @@ -454,6 +473,8 @@ static int __exit at91_rtc_remove(struct platform_device *pdev) AT91_RTC_SECEV | AT91_RTC_TIMEV | AT91_RTC_CALEV); + clk_disable_unprepare(sclk); + return 0; } From 3c217e51d8a272b9301058fe845d6c69cc0651cb Mon Sep 17 00:00:00 2001 From: Sylvain Chouleur Date: Mon, 8 Jun 2015 11:45:19 +0200 Subject: [PATCH 38/90] rtc: cmos: century support If century field is supported by the RTC CMOS device, then we should use it and then do not consider years greater that 169 as an error. For information, the year field of the rtc_time structure contains the value to add to 1970 to obtain the current year. This was a hack to be able to support years for 1970 to 2069. This patch remains compatible with this implementation. Signed-off-by: Sylvain Chouleur Signed-off-by: Alexandre Belloni --- include/asm-generic/rtc.h | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h index fa86f240c874..4e3b6558331e 100644 --- a/include/asm-generic/rtc.h +++ b/include/asm-generic/rtc.h @@ -16,6 +16,9 @@ #include #include #include +#ifdef CONFIG_ACPI +#include +#endif #define RTC_PIE 0x40 /* periodic interrupt enable */ #define RTC_AIE 0x20 /* alarm interrupt enable */ @@ -46,6 +49,7 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time) { unsigned char ctrl; unsigned long flags; + unsigned char century = 0; #ifdef CONFIG_MACH_DECSTATION unsigned int real_year; @@ -78,6 +82,11 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time) time->tm_year = CMOS_READ(RTC_YEAR); #ifdef CONFIG_MACH_DECSTATION real_year = CMOS_READ(RTC_DEC_YEAR); +#endif +#ifdef CONFIG_ACPI + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && + acpi_gbl_FADT.century) + century = CMOS_READ(acpi_gbl_FADT.century); #endif ctrl = CMOS_READ(RTC_CONTROL); spin_unlock_irqrestore(&rtc_lock, flags); @@ -90,12 +99,16 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time) time->tm_mday = bcd2bin(time->tm_mday); time->tm_mon = bcd2bin(time->tm_mon); time->tm_year = bcd2bin(time->tm_year); + century = bcd2bin(century); } #ifdef CONFIG_MACH_DECSTATION time->tm_year += real_year - 72; #endif + if (century) + time->tm_year += (century - 19) * 100; + /* * Account for differences between how the RTC uses the values * and how they are defined in a struct rtc_time; @@ -122,6 +135,7 @@ static inline int __set_rtc_time(struct rtc_time *time) #ifdef CONFIG_MACH_DECSTATION unsigned int real_yrs, leap_yr; #endif + unsigned char century = 0; yrs = time->tm_year; mon = time->tm_mon + 1; /* tm_mon starts at zero */ @@ -150,6 +164,15 @@ static inline int __set_rtc_time(struct rtc_time *time) yrs = 73; } #endif + +#ifdef CONFIG_ACPI + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && + acpi_gbl_FADT.century) { + century = (yrs + 1900) / 100; + yrs %= 100; + } +#endif + /* These limits and adjustments are independent of * whether the chip is in binary mode or not. */ @@ -169,6 +192,7 @@ static inline int __set_rtc_time(struct rtc_time *time) day = bin2bcd(day); mon = bin2bcd(mon); yrs = bin2bcd(yrs); + century = bin2bcd(century); } save_control = CMOS_READ(RTC_CONTROL); @@ -185,6 +209,11 @@ static inline int __set_rtc_time(struct rtc_time *time) CMOS_WRITE(hrs, RTC_HOURS); CMOS_WRITE(min, RTC_MINUTES); CMOS_WRITE(sec, RTC_SECONDS); +#ifdef CONFIG_ACPI + if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && + acpi_gbl_FADT.century) + CMOS_WRITE(century, acpi_gbl_FADT.century); +#endif CMOS_WRITE(save_control, RTC_CONTROL); CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT); From a3781639e148497d7381d8786aaefe9f8b7e3028 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:26 +0300 Subject: [PATCH 39/90] rtc: cmos: clean up cmos_nvram_read()/cmos_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-cmos.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index c2e90c62a59c..8f7034ba7d9e 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -467,13 +467,6 @@ cmos_nvram_read(struct file *filp, struct kobject *kobj, { int retval; - if (unlikely(off >= attr->size)) - return 0; - if (unlikely(off < 0)) - return -EINVAL; - if ((off + count) > attr->size) - count = attr->size - off; - off += NVRAM_OFFSET; spin_lock_irq(&rtc_lock); for (retval = 0; count; count--, off++, retval++) { @@ -498,12 +491,6 @@ cmos_nvram_write(struct file *filp, struct kobject *kobj, int retval; cmos = dev_get_drvdata(container_of(kobj, struct device, kobj)); - if (unlikely(off >= attr->size)) - return -EFBIG; - if (unlikely(off < 0)) - return -EINVAL; - if ((off + count) > attr->size) - count = attr->size - off; /* NOTE: on at least PCs and Ataris, the boot firmware uses a * checksum on part of the NVRAM data. That's currently ignored From 273e03041e6d48024a57682cbf7b61510f74ec64 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:27 +0300 Subject: [PATCH 40/90] rtc: ds1305: clean up ds1305_nvram_read()/ds1305_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller size in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1305.c | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 12b07158a366..baa5d047f9c8 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -538,15 +538,6 @@ ds1305_nvram_read(struct file *filp, struct kobject *kobj, spi = container_of(kobj, struct spi_device, dev.kobj); - if (unlikely(off >= DS1305_NVRAM_LEN)) - return 0; - if (count >= DS1305_NVRAM_LEN) - count = DS1305_NVRAM_LEN; - if ((off + count) > DS1305_NVRAM_LEN) - count = DS1305_NVRAM_LEN - off; - if (unlikely(!count)) - return count; - addr = DS1305_NVRAM + off; msg_init(&m, x, &addr, count, NULL, buf); @@ -569,15 +560,6 @@ ds1305_nvram_write(struct file *filp, struct kobject *kobj, spi = container_of(kobj, struct spi_device, dev.kobj); - if (unlikely(off >= DS1305_NVRAM_LEN)) - return -EFBIG; - if (count >= DS1305_NVRAM_LEN) - count = DS1305_NVRAM_LEN; - if ((off + count) > DS1305_NVRAM_LEN) - count = DS1305_NVRAM_LEN - off; - if (unlikely(!count)) - return count; - addr = (DS1305_WRITE | DS1305_NVRAM) + off; msg_init(&m, x, &addr, count, buf, NULL); From ca7c14d3a1ab1932732c506e32ab5b189b9c0a16 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:28 +0300 Subject: [PATCH 41/90] rtc: ds1307: clean up ds1307_nvram_read()/ds1307_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index c51bc0a65afc..a705e6490808 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -782,13 +782,6 @@ ds1307_nvram_read(struct file *filp, struct kobject *kobj, client = kobj_to_i2c_client(kobj); ds1307 = i2c_get_clientdata(client); - if (unlikely(off >= ds1307->nvram->size)) - return 0; - if ((off + count) > ds1307->nvram->size) - count = ds1307->nvram->size - off; - if (unlikely(!count)) - return count; - result = ds1307->read_block_data(client, ds1307->nvram_offset + off, count, buf); if (result < 0) @@ -808,13 +801,6 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj, client = kobj_to_i2c_client(kobj); ds1307 = i2c_get_clientdata(client); - if (unlikely(off >= ds1307->nvram->size)) - return -EFBIG; - if ((off + count) > ds1307->nvram->size) - count = ds1307->nvram->size - off; - if (unlikely(!count)) - return count; - result = ds1307->write_block_data(client, ds1307->nvram_offset + off, count, buf); if (result < 0) { From f4843b19d2c7b5effd25e2a65b487d02bf55e96f Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:29 +0300 Subject: [PATCH 42/90] rtc: ds1343: clean up ds1343_nvram_read()/ds1343_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1343.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/drivers/rtc/rtc-ds1343.c b/drivers/rtc/rtc-ds1343.c index ae9f997223b1..79a06dd3c185 100644 --- a/drivers/rtc/rtc-ds1343.c +++ b/drivers/rtc/rtc-ds1343.c @@ -162,12 +162,6 @@ static ssize_t ds1343_nvram_write(struct file *filp, struct kobject *kobj, struct device *dev = kobj_to_dev(kobj); struct ds1343_priv *priv = dev_get_drvdata(dev); - if (unlikely(!count)) - return count; - - if ((count + off) > DS1343_NVRAM_LEN) - count = DS1343_NVRAM_LEN - off; - address = DS1343_NVRAM + off; ret = regmap_bulk_write(priv->map, address, buf, count); @@ -187,12 +181,6 @@ static ssize_t ds1343_nvram_read(struct file *filp, struct kobject *kobj, struct device *dev = kobj_to_dev(kobj); struct ds1343_priv *priv = dev_get_drvdata(dev); - if (unlikely(!count)) - return count; - - if ((count + off) > DS1343_NVRAM_LEN) - count = DS1343_NVRAM_LEN - off; - address = DS1343_NVRAM + off; ret = regmap_bulk_read(priv->map, address, buf, count); From 8ccba14233000f48639aad4cab55ed7b61260db5 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Wed, 5 Aug 2015 21:12:58 +0300 Subject: [PATCH 43/90] rtc: ds1511: clean up ds1511_nvram_read()/ds1511_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c The change enables burst mode of access to SRAM for any read()/write() operations, it is worth to mention that this may influence on userspace, for instance prior to the change read(fd, buf, 1); read(fd, buf + 1, 1); and read(fd, buf, 2); sequences of syscalls over DS1511's sysfs "nvram" fd led to different DS1511 state changes and/or buf content, if some userspace applications are written specifically for DS1511 and exploit this strange "feature", they may be impacted. Also the change corrects NVRAM size accessible to userspace from 255 bytes to 256 bytes. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1511.c | 42 +++++----------------------------------- 1 file changed, 5 insertions(+), 37 deletions(-) diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index 7415c2b4d6e8..da3d04ce83bd 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -64,7 +64,7 @@ enum ds1511reg { #define DS1511_KIE 0x04 #define DS1511_WDE 0x02 #define DS1511_WDS 0x01 -#define DS1511_RAM_MAX 0xff +#define DS1511_RAM_MAX 0x100 #define RTC_CMD DS1511_CONTROL_B #define RTC_CMD1 DS1511_CONTROL_A @@ -159,7 +159,7 @@ ds1511_wdog_set(unsigned long deciseconds) /* * set wdog enable and wdog 'steering' bit to issue a reset */ - rtc_write(DS1511_WDE | DS1511_WDS, RTC_CMD); + rtc_write(rtc_read(RTC_CMD) | DS1511_WDE | DS1511_WDS, RTC_CMD); } void @@ -407,26 +407,10 @@ ds1511_nvram_read(struct file *filp, struct kobject *kobj, { ssize_t count; - /* - * if count is more than one, turn on "burst" mode - * turn it off when you're done - */ - if (size > 1) - rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD); - - if (pos > DS1511_RAM_MAX) - pos = DS1511_RAM_MAX; - - if (size + pos > DS1511_RAM_MAX + 1) - size = DS1511_RAM_MAX - pos + 1; - rtc_write(pos, DS1511_RAMADDR_LSB); - for (count = 0; size > 0; count++, size--) + for (count = 0; count < size; count++) *buf++ = rtc_read(DS1511_RAMDATA); - if (count > 1) - rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD); - return count; } @@ -437,26 +421,10 @@ ds1511_nvram_write(struct file *filp, struct kobject *kobj, { ssize_t count; - /* - * if count is more than one, turn on "burst" mode - * turn it off when you're done - */ - if (size > 1) - rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD); - - if (pos > DS1511_RAM_MAX) - pos = DS1511_RAM_MAX; - - if (size + pos > DS1511_RAM_MAX + 1) - size = DS1511_RAM_MAX - pos + 1; - rtc_write(pos, DS1511_RAMADDR_LSB); - for (count = 0; size > 0; count++, size--) + for (count = 0; count < size; count++) rtc_write(*buf++, DS1511_RAMDATA); - if (count > 1) - rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD); - return count; } @@ -490,7 +458,7 @@ static int ds1511_rtc_probe(struct platform_device *pdev) /* * turn on the clock and the crystal, etc. */ - rtc_write(0, RTC_CMD); + rtc_write(DS1511_BME, RTC_CMD); rtc_write(0, RTC_CMD1); /* * clear the wdog counter From a9118d77b3be366c4843446d671a52ccfddcc15c Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:31 +0300 Subject: [PATCH 44/90] rtc: ds1553: clean up ds1553_nvram_read()/ds1553_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1553.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index a24e091bcb41..38422ab4ec5a 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -245,7 +245,7 @@ static ssize_t ds1553_nvram_read(struct file *filp, struct kobject *kobj, void __iomem *ioaddr = pdata->ioaddr; ssize_t count; - for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--) + for (count = 0; count < size; count++) *buf++ = readb(ioaddr + pos++); return count; } @@ -260,7 +260,7 @@ static ssize_t ds1553_nvram_write(struct file *filp, struct kobject *kobj, void __iomem *ioaddr = pdata->ioaddr; ssize_t count; - for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--) + for (count = 0; count < size; count++) writeb(*buf++, ioaddr + pos++); return count; } From c472d7ded2dfbe7da29531a9c9e6b951e5658605 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:32 +0300 Subject: [PATCH 45/90] rtc: ds1742: clean up ds1742_nvram_read()/ds1742_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1742.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 0f8d8ace1515..c5168b3bcf1a 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -134,7 +134,7 @@ static ssize_t ds1742_nvram_read(struct file *filp, struct kobject *kobj, void __iomem *ioaddr = pdata->ioaddr_nvram; ssize_t count; - for (count = 0; size > 0 && pos < pdata->size_nvram; count++, size--) + for (count = 0; count < size; count++) *buf++ = readb(ioaddr + pos++); return count; } @@ -149,7 +149,7 @@ static ssize_t ds1742_nvram_write(struct file *filp, struct kobject *kobj, void __iomem *ioaddr = pdata->ioaddr_nvram; ssize_t count; - for (count = 0; size > 0 && pos < pdata->size_nvram; count++, size--) + for (count = 0; count < size; count++) writeb(*buf++, ioaddr + pos++); return count; } From 99be3e371b2ac03b936044139be10cf0c7b9cc58 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Wed, 5 Aug 2015 21:13:02 +0300 Subject: [PATCH 46/90] rtc: m48t59: clean up m48t59_nvram_read()/m48t59_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Spinlock acquisition/release is moved out of the loop body to get atomic states of NVRAM reading and writing operations. Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-m48t59.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 90abb5bd589c..d99a705bec07 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -345,11 +345,12 @@ static ssize_t m48t59_nvram_read(struct file *filp, struct kobject *kobj, ssize_t cnt = 0; unsigned long flags; - for (; size > 0 && pos < pdata->offset; cnt++, size--) { - spin_lock_irqsave(&m48t59->lock, flags); + spin_lock_irqsave(&m48t59->lock, flags); + + for (; cnt < size; cnt++) *buf++ = M48T59_READ(cnt); - spin_unlock_irqrestore(&m48t59->lock, flags); - } + + spin_unlock_irqrestore(&m48t59->lock, flags); return cnt; } @@ -365,11 +366,12 @@ static ssize_t m48t59_nvram_write(struct file *filp, struct kobject *kobj, ssize_t cnt = 0; unsigned long flags; - for (; size > 0 && pos < pdata->offset; cnt++, size--) { - spin_lock_irqsave(&m48t59->lock, flags); + spin_lock_irqsave(&m48t59->lock, flags); + + for (; cnt < size; cnt++) M48T59_WRITE(*buf++, cnt); - spin_unlock_irqrestore(&m48t59->lock, flags); - } + + spin_unlock_irqrestore(&m48t59->lock, flags); return cnt; } From d1cf4bdee8e574c0d2b7ce9fa8d9cd89c0ac761a Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:34 +0300 Subject: [PATCH 47/90] rtc: rp5c01: clean up rp5c01_nvram_read()/rp5c01_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rp5c01.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c index b548551f385c..026035373ae6 100644 --- a/drivers/rtc/rtc-rp5c01.c +++ b/drivers/rtc/rtc-rp5c01.c @@ -170,7 +170,7 @@ static ssize_t rp5c01_nvram_read(struct file *filp, struct kobject *kobj, spin_lock_irq(&priv->lock); - for (count = 0; size > 0 && pos < RP5C01_MODE; count++, size--) { + for (count = 0; count < size; count++) { u8 data; rp5c01_write(priv, @@ -200,7 +200,7 @@ static ssize_t rp5c01_nvram_write(struct file *filp, struct kobject *kobj, spin_lock_irq(&priv->lock); - for (count = 0; size > 0 && pos < RP5C01_MODE; count++, size--) { + for (count = 0; count < size; count++) { u8 data = *buf++; rp5c01_write(priv, From ecc663c3d0dc181fd15e4d60753024d180fd7e8f Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:35 +0300 Subject: [PATCH 48/90] rtc: stk17ta8: clean up stk17ta8_nvram_read()/stk17ta8_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stk17ta8.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c index 0e93b714ee41..ba6a83b5b5c9 100644 --- a/drivers/rtc/rtc-stk17ta8.c +++ b/drivers/rtc/rtc-stk17ta8.c @@ -254,7 +254,7 @@ static ssize_t stk17ta8_nvram_read(struct file *filp, struct kobject *kobj, void __iomem *ioaddr = pdata->ioaddr; ssize_t count; - for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--) + for (count = 0; count < size; count++) *buf++ = readb(ioaddr + pos++); return count; } @@ -269,7 +269,7 @@ static ssize_t stk17ta8_nvram_write(struct file *filp, struct kobject *kobj, void __iomem *ioaddr = pdata->ioaddr; ssize_t count; - for (count = 0; size > 0 && pos < RTC_OFFSET; count++, size--) + for (count = 0; count < size; count++) writeb(*buf++, ioaddr + pos++); return count; } From 824625d3926f0caf4753426d2b24a8fc08a406c8 Mon Sep 17 00:00:00 2001 From: Vladimir Zapolskiy Date: Mon, 27 Jul 2015 00:48:36 +0300 Subject: [PATCH 49/90] rtc: tx4939: clean up tx4939_rtc_nvram_read()/tx4939_rtc_nvram_write() The change removes redundant sysfs binary file boundary checks, since this task is already done on caller side in fs/sysfs/file.c Signed-off-by: Vladimir Zapolskiy Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-tx4939.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c index cb7f94ede516..560d9a5e0225 100644 --- a/drivers/rtc/rtc-tx4939.c +++ b/drivers/rtc/rtc-tx4939.c @@ -199,8 +199,7 @@ static ssize_t tx4939_rtc_nvram_read(struct file *filp, struct kobject *kobj, ssize_t count; spin_lock_irq(&pdata->lock); - for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE; - count++, size--) { + for (count = 0; count < size; count++) { __raw_writel(pos++, &rtcreg->adr); *buf++ = __raw_readl(&rtcreg->dat); } @@ -218,8 +217,7 @@ static ssize_t tx4939_rtc_nvram_write(struct file *filp, struct kobject *kobj, ssize_t count; spin_lock_irq(&pdata->lock); - for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE; - count++, size--) { + for (count = 0; count < size; count++) { __raw_writel(pos++, &rtcreg->adr); __raw_writel(*buf++, &rtcreg->dat); } From 15d3bdc23eb54c50b2a5f143325fe83c3ab0dd27 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 24 Jul 2015 15:50:23 +0200 Subject: [PATCH 50/90] rtc: rx8025: remove useless headers and reorder them Remove the useless includes and order the remaining ones alphabetically. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 6fe87702fcff..a943e1c08263 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -18,13 +18,10 @@ * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. */ -#include -#include -#include -#include #include #include -#include +#include +#include #include /* Register definitions */ From b6a57c955c362cb9d6ace991cdd77376849abb44 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 24 Jul 2015 15:59:43 +0200 Subject: [PATCH 51/90] rtc: rx8025: Convert to threaded IRQ The driver currently emulates the concept of threaded IRQ using a workqueue, switch to threaded IRQ instead. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 37 ++++--------------------------------- 1 file changed, 4 insertions(+), 33 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index a943e1c08263..d8737713135d 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -71,9 +71,7 @@ MODULE_DEVICE_TABLE(i2c, rx8025_id); struct rx8025_data { struct i2c_client *client; struct rtc_device *rtc; - struct work_struct work; u8 ctrl1; - unsigned exiting:1; }; static int rx8025_read_reg(struct i2c_client *client, int number, u8 *value) @@ -128,26 +126,12 @@ static int rx8025_write_regs(struct i2c_client *client, return ret; } -static irqreturn_t rx8025_irq(int irq, void *dev_id) +static irqreturn_t rx8025_handle_irq(int irq, void *dev_id) { struct i2c_client *client = dev_id; struct rx8025_data *rx8025 = i2c_get_clientdata(client); - - disable_irq_nosync(irq); - schedule_work(&rx8025->work); - return IRQ_HANDLED; -} - -static void rx8025_work(struct work_struct *work) -{ - struct rx8025_data *rx8025 = container_of(work, struct rx8025_data, - work); - struct i2c_client *client = rx8025->client; - struct mutex *lock = &rx8025->rtc->ops_lock; u8 status; - mutex_lock(lock); - if (rx8025_read_reg(client, RX8025_REG_CTRL2, &status)) goto out; @@ -175,10 +159,7 @@ static void rx8025_work(struct work_struct *work) status | RX8025_BIT_CTRL2_XST); out: - if (!rx8025->exiting) - enable_irq(client->irq); - - mutex_unlock(lock); + return IRQ_HANDLED; } static int rx8025_get_time(struct device *dev, struct rtc_time *dt) @@ -550,7 +531,6 @@ static int rx8025_probe(struct i2c_client *client, rx8025->client = client; i2c_set_clientdata(client, rx8025); - INIT_WORK(&rx8025->work, rx8025_work); err = rx8025_init_client(client, &need_reset); if (err) @@ -574,7 +554,7 @@ static int rx8025_probe(struct i2c_client *client, if (client->irq > 0) { dev_info(&client->dev, "IRQ %d supplied\n", client->irq); - err = request_irq(client->irq, rx8025_irq, + err = request_threaded_irq(client->irq, NULL, rx8025_handle_irq, 0, "rx8025", client); if (err) { dev_err(&client->dev, "unable to request IRQ\n"); @@ -602,17 +582,8 @@ errout: static int rx8025_remove(struct i2c_client *client) { - struct rx8025_data *rx8025 = i2c_get_clientdata(client); - struct mutex *lock = &rx8025->rtc->ops_lock; - - if (client->irq > 0) { - mutex_lock(lock); - rx8025->exiting = 1; - mutex_unlock(lock); - + if (client->irq > 0) free_irq(client->irq, client); - cancel_work_sync(&rx8025->work); - } rx8025_sysfs_unregister(&client->dev); return 0; From f0b63a1d5a4a4d9d60fe728ede0fa78ec5aab8be Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 24 Jul 2015 16:07:30 +0200 Subject: [PATCH 52/90] rtc: rx8025: switch to managed irq allocation Use devm_request_threaded_irq() so it is not necessary to call free_irq() explicitly. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index d8737713135d..be91e922a139 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -554,8 +554,9 @@ static int rx8025_probe(struct i2c_client *client, if (client->irq > 0) { dev_info(&client->dev, "IRQ %d supplied\n", client->irq); - err = request_threaded_irq(client->irq, NULL, rx8025_handle_irq, - 0, "rx8025", client); + err = devm_request_threaded_irq(&client->dev, client->irq, NULL, + rx8025_handle_irq, 0, "rx8025", + client); if (err) { dev_err(&client->dev, "unable to request IRQ\n"); goto errout; @@ -567,14 +568,10 @@ static int rx8025_probe(struct i2c_client *client, err = rx8025_sysfs_register(&client->dev); if (err) - goto errout_irq; + goto errout; return 0; -errout_irq: - if (client->irq > 0) - free_irq(client->irq, client); - errout: dev_err(&adapter->dev, "probing for rx8025 failed\n"); return err; @@ -582,9 +579,6 @@ errout: static int rx8025_remove(struct i2c_client *client) { - if (client->irq > 0) - free_irq(client->irq, client); - rx8025_sysfs_unregister(&client->dev); return 0; } From dbcce7cf1eb95c704faa3fff1acc974010c8e5a4 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Fri, 24 Jul 2015 16:12:10 +0200 Subject: [PATCH 53/90] rtc: rx8025: remove useless probe error message It is useless to print a message when probe fails as the user is already aware that it failed. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index be91e922a139..612b6876cbd5 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -513,20 +513,18 @@ static int rx8025_probe(struct i2c_client *client, { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct rx8025_data *rx8025; - int err, need_reset = 0; + int err = 0, need_reset = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) { dev_err(&adapter->dev, "doesn't support required functionality\n"); - err = -EIO; - goto errout; + return -EIO; } rx8025 = devm_kzalloc(&client->dev, sizeof(*rx8025), GFP_KERNEL); if (!rx8025) { - err = -ENOMEM; - goto errout; + return -ENOMEM; } rx8025->client = client; @@ -534,7 +532,7 @@ static int rx8025_probe(struct i2c_client *client, err = rx8025_init_client(client, &need_reset); if (err) - goto errout; + return err; if (need_reset) { struct rtc_time tm; @@ -547,9 +545,8 @@ static int rx8025_probe(struct i2c_client *client, rx8025->rtc = devm_rtc_device_register(&client->dev, client->name, &rx8025_rtc_ops, THIS_MODULE); if (IS_ERR(rx8025->rtc)) { - err = PTR_ERR(rx8025->rtc); dev_err(&client->dev, "unable to register the class device\n"); - goto errout; + return PTR_ERR(rx8025->rtc); } if (client->irq > 0) { @@ -559,7 +556,7 @@ static int rx8025_probe(struct i2c_client *client, client); if (err) { dev_err(&client->dev, "unable to request IRQ\n"); - goto errout; + return err; } } @@ -567,13 +564,6 @@ static int rx8025_probe(struct i2c_client *client, rx8025->rtc->max_user_freq = 1; err = rx8025_sysfs_register(&client->dev); - if (err) - goto errout; - - return 0; - -errout: - dev_err(&adapter->dev, "probing for rx8025 failed\n"); return err; } From 2ddd18693cb93126077bd072884dffca423c1e27 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sat, 25 Jul 2015 11:50:22 +0200 Subject: [PATCH 54/90] rtc: rx8025: use BIT() Use BIT() instead of hand coding. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 612b6876cbd5..52683eda1da2 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -19,6 +19,7 @@ * version 2 as published by the Free Software Foundation. */ #include +#include #include #include #include @@ -45,17 +46,17 @@ #define RX8025_BIT_CTRL1_CT (7 << 0) /* 1 Hz periodic level irq */ #define RX8025_BIT_CTRL1_CT_1HZ 4 -#define RX8025_BIT_CTRL1_TEST (1 << 3) -#define RX8025_BIT_CTRL1_1224 (1 << 5) -#define RX8025_BIT_CTRL1_DALE (1 << 6) -#define RX8025_BIT_CTRL1_WALE (1 << 7) +#define RX8025_BIT_CTRL1_TEST BIT(3) +#define RX8025_BIT_CTRL1_1224 BIT(5) +#define RX8025_BIT_CTRL1_DALE BIT(6) +#define RX8025_BIT_CTRL1_WALE BIT(7) -#define RX8025_BIT_CTRL2_DAFG (1 << 0) -#define RX8025_BIT_CTRL2_WAFG (1 << 1) -#define RX8025_BIT_CTRL2_CTFG (1 << 2) -#define RX8025_BIT_CTRL2_PON (1 << 4) -#define RX8025_BIT_CTRL2_XST (1 << 5) -#define RX8025_BIT_CTRL2_VDET (1 << 6) +#define RX8025_BIT_CTRL2_DAFG BIT(0) +#define RX8025_BIT_CTRL2_WAFG BIT(1) +#define RX8025_BIT_CTRL2_CTFG BIT(2) +#define RX8025_BIT_CTRL2_PON BIT(4) +#define RX8025_BIT_CTRL2_XST BIT(5) +#define RX8025_BIT_CTRL2_VDET BIT(6) /* Clock precision adjustment */ #define RX8025_ADJ_RESOLUTION 3050 /* in ppb */ From 32672c55951b2633bb93ec6f12734cf17e9d3a14 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sat, 25 Jul 2015 12:07:37 +0200 Subject: [PATCH 55/90] rtc: rx8025: only handle dates between 2000 and 2099 The hardware is only capable of handling dates between 2000 and 2099, enforce that. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 52683eda1da2..3612362b65ac 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -188,10 +188,7 @@ static int rx8025_get_time(struct device *dev, struct rtc_time *dt) dt->tm_mday = bcd2bin(date[RX8025_REG_MDAY] & 0x3f); dt->tm_mon = bcd2bin(date[RX8025_REG_MONTH] & 0x1f) - 1; - dt->tm_year = bcd2bin(date[RX8025_REG_YEAR]); - - if (dt->tm_year < 70) - dt->tm_year += 100; + dt->tm_year = bcd2bin(date[RX8025_REG_YEAR]) + 100; dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, dt->tm_sec, dt->tm_min, dt->tm_hour, @@ -205,11 +202,8 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt) struct rx8025_data *rx8025 = dev_get_drvdata(dev); u8 date[7]; - /* - * BUG: The HW assumes every year that is a multiple of 4 to be a leap - * year. Next time this is wrong is 2100, which will not be a leap - * year. - */ + if ((dt->tm_year < 100) || (dt->tm_year > 199)) + return -EINVAL; /* * Here the read-only bits are written as "0". I'm not sure if that @@ -226,7 +220,7 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt) date[RX8025_REG_WDAY] = bin2bcd(dt->tm_wday); date[RX8025_REG_MDAY] = bin2bcd(dt->tm_mday); date[RX8025_REG_MONTH] = bin2bcd(dt->tm_mon + 1); - date[RX8025_REG_YEAR] = bin2bcd(dt->tm_year % 100); + date[RX8025_REG_YEAR] = bin2bcd(dt->tm_year - 100); dev_dbg(dev, "%s: write 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", From 2e10e74df72ff0f8ea65eb1ee6e39ed8278a91bf Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sat, 25 Jul 2015 15:54:59 +0200 Subject: [PATCH 56/90] rtc: rx8025: fix transfer mode The datasheet specifies that transfer mode must be 0 for write and either 0x4 (simplified read) or 0 (standard read). 0x8 is not specified, use standard mode. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 3612362b65ac..771558602409 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -77,7 +77,7 @@ struct rx8025_data { static int rx8025_read_reg(struct i2c_client *client, int number, u8 *value) { - int ret = i2c_smbus_read_byte_data(client, (number << 4) | 0x08); + int ret = i2c_smbus_read_byte_data(client, number << 4); if (ret < 0) { dev_err(&client->dev, "Unable to read register #%d\n", number); @@ -91,7 +91,7 @@ static int rx8025_read_reg(struct i2c_client *client, int number, u8 *value) static int rx8025_read_regs(struct i2c_client *client, int number, u8 length, u8 *values) { - int ret = i2c_smbus_read_i2c_block_data(client, (number << 4) | 0x08, + int ret = i2c_smbus_read_i2c_block_data(client, number << 4, length, values); if (ret != length) { @@ -117,7 +117,7 @@ static int rx8025_write_reg(struct i2c_client *client, int number, u8 value) static int rx8025_write_regs(struct i2c_client *client, int number, u8 length, u8 *values) { - int ret = i2c_smbus_write_i2c_block_data(client, (number << 4) | 0x08, + int ret = i2c_smbus_write_i2c_block_data(client, number << 4, length, values); if (ret) From 6f0a8cfebb898b88fb0d934d7a44a6d4c98d5285 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sun, 26 Jul 2015 10:13:31 +0200 Subject: [PATCH 57/90] rtc: rx8025: don't reset the time Stop setting the time to epoch when it is invalid. The proper way to handle that is to return an error when it is invalid instead of returning an incorrect value. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 771558602409..d158a640299e 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -166,9 +166,23 @@ out: static int rx8025_get_time(struct device *dev, struct rtc_time *dt) { struct rx8025_data *rx8025 = dev_get_drvdata(dev); - u8 date[7]; + u8 date[7], ctrl; int err; + err = rx8025_read_reg(rx8025->client, RX8025_REG_CTRL2, &ctrl); + if (err) + return err; + + if (ctrl & RX8025_BIT_CTRL2_PON) { + dev_warn(dev, "power-on reset detected, date is invalid\n"); + return -EINVAL; + } + + if (!(ctrl & RX8025_BIT_CTRL2_XST)) { + dev_warn(dev, "crystal stopped, date is invalid\n"); + return -EINVAL; + } + err = rx8025_read_regs(rx8025->client, RX8025_REG_SEC, 7, date); if (err) return err; @@ -230,7 +244,7 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt) return rx8025_write_regs(rx8025->client, RX8025_REG_SEC, 7, date); } -static int rx8025_init_client(struct i2c_client *client, int *need_reset) +static int rx8025_init_client(struct i2c_client *client) { struct rx8025_data *rx8025 = i2c_get_clientdata(client); u8 ctrl[2], ctrl2; @@ -247,19 +261,19 @@ static int rx8025_init_client(struct i2c_client *client, int *need_reset) if (ctrl[1] & RX8025_BIT_CTRL2_PON) { dev_warn(&client->dev, "power-on reset was detected, " "you may have to readjust the clock\n"); - *need_reset = 1; + need_clear = 1; } if (ctrl[1] & RX8025_BIT_CTRL2_VDET) { dev_warn(&client->dev, "a power voltage drop was detected, " "you may have to readjust the clock\n"); - *need_reset = 1; + need_clear = 1; } if (!(ctrl[1] & RX8025_BIT_CTRL2_XST)) { dev_warn(&client->dev, "Oscillation stop was detected," "you may have to readjust the clock\n"); - *need_reset = 1; + need_clear = 1; } if (ctrl[1] & (RX8025_BIT_CTRL2_DAFG | RX8025_BIT_CTRL2_WAFG)) { @@ -270,7 +284,7 @@ static int rx8025_init_client(struct i2c_client *client, int *need_reset) if (!(ctrl[1] & RX8025_BIT_CTRL2_CTFG)) need_clear = 1; - if (*need_reset || need_clear) { + if (need_clear) { ctrl2 = ctrl[0]; ctrl2 &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET | RX8025_BIT_CTRL2_CTFG | RX8025_BIT_CTRL2_WAFG | @@ -508,7 +522,7 @@ static int rx8025_probe(struct i2c_client *client, { struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); struct rx8025_data *rx8025; - int err = 0, need_reset = 0; + int err = 0; if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) { @@ -525,18 +539,10 @@ static int rx8025_probe(struct i2c_client *client, rx8025->client = client; i2c_set_clientdata(client, rx8025); - err = rx8025_init_client(client, &need_reset); + err = rx8025_init_client(client); if (err) return err; - if (need_reset) { - struct rtc_time tm; - dev_info(&client->dev, - "bad conditions detected, resetting date\n"); - rtc_time_to_tm(0, &tm); /* 1970/1/1 */ - rx8025_set_time(&client->dev, &tm); - } - rx8025->rtc = devm_rtc_device_register(&client->dev, client->name, &rx8025_rtc_ops, THIS_MODULE); if (IS_ERR(rx8025->rtc)) { From fd9061fb497926c0e62bf1c7ff727801499fd2ea Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 4 Aug 2015 00:40:25 +0200 Subject: [PATCH 58/90] rtc: rx8025: cleanup accessors Remove useless error messages, at that point, the user already knows something went wrong but will not be able to do anything about it anyway. It is also highly unlikely that some registers are readable/writable but not some other ones. Also, transform rx8025_read_reg to be more resemblant to i2c_smbus_read_byte_data() Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 85 +++++++++++++++------------------------- 1 file changed, 31 insertions(+), 54 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index d158a640299e..bf96f40fd200 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -75,65 +75,43 @@ struct rx8025_data { u8 ctrl1; }; -static int rx8025_read_reg(struct i2c_client *client, int number, u8 *value) +static s32 rx8025_read_reg(const struct i2c_client *client, u8 number) { - int ret = i2c_smbus_read_byte_data(client, number << 4); - - if (ret < 0) { - dev_err(&client->dev, "Unable to read register #%d\n", number); - return ret; - } - - *value = ret; - return 0; + return i2c_smbus_read_byte_data(client, number << 4); } -static int rx8025_read_regs(struct i2c_client *client, - int number, u8 length, u8 *values) +static int rx8025_read_regs(const struct i2c_client *client, + u8 number, u8 length, u8 *values) { - int ret = i2c_smbus_read_i2c_block_data(client, number << 4, - length, values); - - if (ret != length) { - dev_err(&client->dev, "Unable to read registers #%d..#%d\n", - number, number + length - 1); + int ret = i2c_smbus_read_i2c_block_data(client, number << 4, length, + values); + if (ret != length) return ret < 0 ? ret : -EIO; - } return 0; } -static int rx8025_write_reg(struct i2c_client *client, int number, u8 value) +static s32 rx8025_write_reg(const struct i2c_client *client, u8 number, + u8 value) { - int ret = i2c_smbus_write_byte_data(client, number << 4, value); - - if (ret) - dev_err(&client->dev, "Unable to write register #%d\n", - number); - - return ret; + return i2c_smbus_write_byte_data(client, number << 4, value); } -static int rx8025_write_regs(struct i2c_client *client, - int number, u8 length, u8 *values) +static s32 rx8025_write_regs(const struct i2c_client *client, + u8 number, u8 length, const u8 *values) { - int ret = i2c_smbus_write_i2c_block_data(client, number << 4, - length, values); - - if (ret) - dev_err(&client->dev, "Unable to write registers #%d..#%d\n", - number, number + length - 1); - - return ret; + return i2c_smbus_write_i2c_block_data(client, number << 4, + length, values); } static irqreturn_t rx8025_handle_irq(int irq, void *dev_id) { struct i2c_client *client = dev_id; struct rx8025_data *rx8025 = i2c_get_clientdata(client); - u8 status; + int status; - if (rx8025_read_reg(client, RX8025_REG_CTRL2, &status)) + status = rx8025_read_reg(client, RX8025_REG_CTRL2); + if (status < 0) goto out; if (!(status & RX8025_BIT_CTRL2_XST)) @@ -166,12 +144,12 @@ out: static int rx8025_get_time(struct device *dev, struct rtc_time *dt) { struct rx8025_data *rx8025 = dev_get_drvdata(dev); - u8 date[7], ctrl; - int err; + u8 date[7]; + int ctrl, err; - err = rx8025_read_reg(rx8025->client, RX8025_REG_CTRL2, &ctrl); - if (err) - return err; + ctrl = rx8025_read_reg(rx8025->client, RX8025_REG_CTRL2); + if (ctrl < 0) + return ctrl; if (ctrl & RX8025_BIT_CTRL2_PON) { dev_warn(dev, "power-on reset detected, date is invalid\n"); @@ -302,8 +280,8 @@ static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t) { struct rx8025_data *rx8025 = dev_get_drvdata(dev); struct i2c_client *client = rx8025->client; - u8 ctrl2, ald[2]; - int err; + u8 ald[2]; + int ctrl2, err; if (client->irq <= 0) return -EINVAL; @@ -312,9 +290,9 @@ static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t) if (err) return err; - err = rx8025_read_reg(client, RX8025_REG_CTRL2, &ctrl2); - if (err) - return err; + ctrl2 = rx8025_read_reg(client, RX8025_REG_CTRL2); + if (ctrl2 < 0) + return ctrl2; dev_dbg(dev, "%s: read alarm 0x%02x 0x%02x ctrl2 %02x\n", __func__, ald[0], ald[1], ctrl2); @@ -435,12 +413,11 @@ static struct rtc_class_ops rx8025_rtc_ops = { static int rx8025_get_clock_adjust(struct device *dev, int *adj) { struct i2c_client *client = to_i2c_client(dev); - u8 digoff; - int err; + int digoff; - err = rx8025_read_reg(client, RX8025_REG_DIGOFF, &digoff); - if (err) - return err; + digoff = rx8025_read_reg(client, RX8025_REG_DIGOFF); + if (digoff < 0) + return digoff; *adj = digoff >= 64 ? digoff - 128 : digoff; if (*adj > 0) From 8a06513df55ef10baf80f55d13786eb29efa4fa6 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 4 Aug 2015 00:45:37 +0200 Subject: [PATCH 59/90] rtc: rx8025: continue without alarm when irq request fails Instead of bailing out, disable alarms and continue when devm_request_threaded_irq() fails. This allows to still provide some functionality. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index bf96f40fd200..ab5fb4fe2a83 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -533,8 +533,8 @@ static int rx8025_probe(struct i2c_client *client, rx8025_handle_irq, 0, "rx8025", client); if (err) { - dev_err(&client->dev, "unable to request IRQ\n"); - return err; + dev_err(&client->dev, "unable to request IRQ, alarms disabled\n"); + client->irq = 0; } } From a27c7bf657cb4ab893328359b66a584251be6cac Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 4 Aug 2015 10:46:22 +0200 Subject: [PATCH 60/90] rtc: rx8025: fix rx8025_init_client() rx8025_init_client is modifying ctrl[0] and writing it to RX8025_REG_CTRL2 but ctrl[0] is actually RX8025_REG_CTRL1. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index ab5fb4fe2a83..22ce08d6e807 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -263,7 +263,7 @@ static int rx8025_init_client(struct i2c_client *client) need_clear = 1; if (need_clear) { - ctrl2 = ctrl[0]; + ctrl2 = ctrl[1]; ctrl2 &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET | RX8025_BIT_CTRL2_CTFG | RX8025_BIT_CTRL2_WAFG | RX8025_BIT_CTRL2_DAFG); From 8c4a4467cda299491eff64640c891a0b2926cb76 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 4 Aug 2015 10:48:20 +0200 Subject: [PATCH 61/90] rtc: rx8025: reset validity when setting time Wait for the user to set the time to reset the validity bits. Until then, the time may be invalid. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 22ce08d6e807..340133a5d907 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -104,6 +104,19 @@ static s32 rx8025_write_regs(const struct i2c_client *client, length, values); } +static int rx8025_reset_validity(struct i2c_client *client) +{ + int ctrl2 = rx8025_read_reg(client, RX8025_REG_CTRL2); + + if (ctrl2 < 0) + return ctrl2; + + ctrl2 &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET); + + return rx8025_write_reg(client, RX8025_REG_CTRL2, + ctrl2 | RX8025_BIT_CTRL2_XST); +} + static irqreturn_t rx8025_handle_irq(int irq, void *dev_id) { struct i2c_client *client = dev_id; @@ -133,10 +146,6 @@ static irqreturn_t rx8025_handle_irq(int irq, void *dev_id) rtc_update_irq(rx8025->rtc, 1, RTC_AF | RTC_IRQF); } - /* acknowledge IRQ */ - rx8025_write_reg(client, RX8025_REG_CTRL2, - status | RX8025_BIT_CTRL2_XST); - out: return IRQ_HANDLED; } @@ -193,6 +202,7 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt) { struct rx8025_data *rx8025 = dev_get_drvdata(dev); u8 date[7]; + int ret; if ((dt->tm_year < 100) || (dt->tm_year > 199)) return -EINVAL; @@ -219,7 +229,11 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt) __func__, date[0], date[1], date[2], date[3], date[4], date[5], date[6]); - return rx8025_write_regs(rx8025->client, RX8025_REG_SEC, 7, date); + ret = rx8025_write_regs(rx8025->client, RX8025_REG_SEC, 7, date); + if (ret < 0) + return ret; + + return rx8025_reset_validity(rx8025->client); } static int rx8025_init_client(struct i2c_client *client) @@ -239,19 +253,16 @@ static int rx8025_init_client(struct i2c_client *client) if (ctrl[1] & RX8025_BIT_CTRL2_PON) { dev_warn(&client->dev, "power-on reset was detected, " "you may have to readjust the clock\n"); - need_clear = 1; } if (ctrl[1] & RX8025_BIT_CTRL2_VDET) { dev_warn(&client->dev, "a power voltage drop was detected, " "you may have to readjust the clock\n"); - need_clear = 1; } if (!(ctrl[1] & RX8025_BIT_CTRL2_XST)) { dev_warn(&client->dev, "Oscillation stop was detected," "you may have to readjust the clock\n"); - need_clear = 1; } if (ctrl[1] & (RX8025_BIT_CTRL2_DAFG | RX8025_BIT_CTRL2_WAFG)) { @@ -264,10 +275,8 @@ static int rx8025_init_client(struct i2c_client *client) if (need_clear) { ctrl2 = ctrl[1]; - ctrl2 &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET | - RX8025_BIT_CTRL2_CTFG | RX8025_BIT_CTRL2_WAFG | + ctrl2 &= ~(RX8025_BIT_CTRL2_CTFG | RX8025_BIT_CTRL2_WAFG | RX8025_BIT_CTRL2_DAFG); - ctrl2 |= RX8025_BIT_CTRL2_XST; err = rx8025_write_reg(client, RX8025_REG_CTRL2, ctrl2); } From 4b33d36b670e7166e8a082e050bfb241ba65271f Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 4 Aug 2015 10:56:50 +0200 Subject: [PATCH 62/90] rtc: rx8025: remove useless initialization irq_freq is already initialized to 1 in rtc_device_register() Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 340133a5d907..f9b86b92943f 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -547,7 +547,6 @@ static int rx8025_probe(struct i2c_client *client, } } - rx8025->rtc->irq_freq = 1; rx8025->rtc->max_user_freq = 1; err = rx8025_sysfs_register(&client->dev); From 5c66e1e0b79bd63dcdfbc03b80823522643a1f14 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 4 Aug 2015 11:24:33 +0200 Subject: [PATCH 63/90] rtc: rx8025: fix RX8025_BIT_CTRL2_CTFG initialization RX8025_BIT_CTRL2_CTFG was set to 0 only when it was already 0. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index f9b86b92943f..f3f1de26c228 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -270,7 +270,7 @@ static int rx8025_init_client(struct i2c_client *client) need_clear = 1; } - if (!(ctrl[1] & RX8025_BIT_CTRL2_CTFG)) + if (ctrl[1] & RX8025_BIT_CTRL2_CTFG) need_clear = 1; if (need_clear) { From efbbb4fd6b6fe0d3d2cfb3c5bbcdf00f1995cb60 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 4 Aug 2015 11:33:59 +0200 Subject: [PATCH 64/90] rtc: rx8025: check time validity when necessary Check time validity when reading time as this is when we need to know. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 58 ++++++++++++++++++++-------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index f3f1de26c228..24c3d69ce1b9 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -104,6 +104,31 @@ static s32 rx8025_write_regs(const struct i2c_client *client, length, values); } +static int rx8025_check_validity(struct device *dev) +{ + struct rx8025_data *rx8025 = dev_get_drvdata(dev); + int ctrl2; + + ctrl2 = rx8025_read_reg(rx8025->client, RX8025_REG_CTRL2); + if (ctrl2 < 0) + return ctrl2; + + if (ctrl2 & RX8025_BIT_CTRL2_VDET) + dev_warn(dev, "power voltage drop detected\n"); + + if (ctrl2 & RX8025_BIT_CTRL2_PON) { + dev_warn(dev, "power-on reset detected, date is invalid\n"); + return -EINVAL; + } + + if (!(ctrl2 & RX8025_BIT_CTRL2_XST)) { + dev_warn(dev, "crystal stopped, date is invalid\n"); + return -EINVAL; + } + + return 0; +} + static int rx8025_reset_validity(struct i2c_client *client) { int ctrl2 = rx8025_read_reg(client, RX8025_REG_CTRL2); @@ -154,21 +179,11 @@ static int rx8025_get_time(struct device *dev, struct rtc_time *dt) { struct rx8025_data *rx8025 = dev_get_drvdata(dev); u8 date[7]; - int ctrl, err; + int err; - ctrl = rx8025_read_reg(rx8025->client, RX8025_REG_CTRL2); - if (ctrl < 0) - return ctrl; - - if (ctrl & RX8025_BIT_CTRL2_PON) { - dev_warn(dev, "power-on reset detected, date is invalid\n"); - return -EINVAL; - } - - if (!(ctrl & RX8025_BIT_CTRL2_XST)) { - dev_warn(dev, "crystal stopped, date is invalid\n"); - return -EINVAL; - } + err = rx8025_check_validity(dev); + if (err) + return err; err = rx8025_read_regs(rx8025->client, RX8025_REG_SEC, 7, date); if (err) @@ -250,21 +265,6 @@ static int rx8025_init_client(struct i2c_client *client) /* Keep test bit zero ! */ rx8025->ctrl1 = ctrl[0] & ~RX8025_BIT_CTRL1_TEST; - if (ctrl[1] & RX8025_BIT_CTRL2_PON) { - dev_warn(&client->dev, "power-on reset was detected, " - "you may have to readjust the clock\n"); - } - - if (ctrl[1] & RX8025_BIT_CTRL2_VDET) { - dev_warn(&client->dev, "a power voltage drop was detected, " - "you may have to readjust the clock\n"); - } - - if (!(ctrl[1] & RX8025_BIT_CTRL2_XST)) { - dev_warn(&client->dev, "Oscillation stop was detected," - "you may have to readjust the clock\n"); - } - if (ctrl[1] & (RX8025_BIT_CTRL2_DAFG | RX8025_BIT_CTRL2_WAFG)) { dev_warn(&client->dev, "Alarm was detected\n"); need_clear = 1; From 0c6e718389305cbc4cd9b8e3fd4b4173bd1127e6 Mon Sep 17 00:00:00 2001 From: Nadav Haklai Date: Thu, 6 Aug 2015 17:18:48 +0200 Subject: [PATCH 65/90] rtc: armada38x: Align RTC set time procedure with the official errata According to the Armada38x functional errata FE-3124064, writing to the RTC TIME register may fail. As a workaround, after writing to RTC TIME register, issue a dummy write of 0x0 twice to the RTC Status register. This is the updated implementation of the Errata that eliminates the need of the long 100ms delay during the RTC set time procedure. [gregory.clement@free-electrons.com]: removed the mutex and use the spinlock again Signed-off-by: Nadav Haklai Reviewed-by: Neta Zur Hershkovits Signed-off-by: Gregory CLEMENT Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-armada38x.c | 32 ++++++++++++-------------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index 2b08cac62f07..06c6bd5eab41 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -40,13 +40,6 @@ struct armada38x_rtc { void __iomem *regs; void __iomem *regs_soc; spinlock_t lock; - /* - * While setting the time, the RTC TIME register should not be - * accessed. Setting the RTC time involves sleeping during - * 100ms, so a mutex instead of a spinlock is used to protect - * it - */ - struct mutex mutex_time; int irq; }; @@ -64,9 +57,9 @@ static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset) static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct armada38x_rtc *rtc = dev_get_drvdata(dev); - unsigned long time, time_check; + unsigned long time, time_check, flags; - mutex_lock(&rtc->mutex_time); + spin_lock_irqsave(&rtc->lock, flags); time = readl(rtc->regs + RTC_TIME); /* * WA for failing time set attempts. As stated in HW ERRATA if @@ -77,7 +70,7 @@ static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm) if ((time_check - time) > 1) time_check = readl(rtc->regs + RTC_TIME); - mutex_unlock(&rtc->mutex_time); + spin_unlock_irqrestore(&rtc->lock, flags); rtc_time_to_tm(time_check, tm); @@ -88,23 +81,23 @@ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm) { struct armada38x_rtc *rtc = dev_get_drvdata(dev); int ret = 0; - unsigned long time; + unsigned long time, flags; ret = rtc_tm_to_time(tm, &time); if (ret) goto out; /* - * Setting the RTC time not always succeeds. According to the - * errata we need to first write on the status register and - * then wait for 100ms before writing to the time register to be - * sure that the data will be taken into account. + * According to errata FE-3124064, Write to RTC TIME register + * may fail. As a workaround, after writing to RTC TIME + * register, issue a dummy write of 0x0 twice to RTC Status + * register. */ - mutex_lock(&rtc->mutex_time); - rtc_delayed_write(0, rtc, RTC_STATUS); - msleep(100); + spin_lock_irqsave(&rtc->lock, flags); rtc_delayed_write(time, rtc, RTC_TIME); - mutex_unlock(&rtc->mutex_time); + rtc_delayed_write(0, rtc, RTC_STATUS); + rtc_delayed_write(0, rtc, RTC_STATUS); + spin_unlock_irqrestore(&rtc->lock, flags); out: return ret; @@ -229,7 +222,6 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev) return -ENOMEM; spin_lock_init(&rtc->lock); - mutex_init(&rtc->mutex_time); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc"); rtc->regs = devm_ioremap_resource(&pdev->dev, res); From 1955f213a68323f7348fc06461017c7675efe6c1 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Aug 2015 16:33:39 +0200 Subject: [PATCH 66/90] rtc: at91sam9: include linux/of.h This driver is using device tree but is not including of.h Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-at91sam9.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index f9e85ace5e71..16492e2baf5e 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include From 80e274e96e5bc4ddf9ee4b31ab6f4a2a9fa08040 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 10 Aug 2015 16:33:40 +0200 Subject: [PATCH 67/90] rtc: at91sam9: remove useless include Definitions from linux/platform_data/atmel.h are not used, remove the include. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-at91sam9.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 16492e2baf5e..7206e2fa4383 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include From 1fb1c35f56bb6ab4a65920c648154b0f78f634a5 Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Wed, 12 Aug 2015 19:21:46 +0900 Subject: [PATCH 68/90] rtc: s3c: fix disabled clocks for alarm The clock enable/disable codes for alarm have been removed from commit 24e1455493da ("drivers/rtc/rtc-s3c.c: delete duplicate clock control") and the clocks are disabled even if alarm is set, so alarm interrupt can't happen. The s3c_rtc_setaie function can be called several times with 'enabled' argument having same value, so it needs to check whether clocks are enabled or not. Signed-off-by: Joonyoung Shim Cc: # v4.1 Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s3c.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index a0f832362199..2e709e239dbc 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -39,6 +39,7 @@ struct s3c_rtc { void __iomem *base; struct clk *rtc_clk; struct clk *rtc_src_clk; + bool clk_disabled; struct s3c_rtc_data *data; @@ -71,9 +72,12 @@ static void s3c_rtc_enable_clk(struct s3c_rtc *info) unsigned long irq_flags; spin_lock_irqsave(&info->alarm_clk_lock, irq_flags); - clk_enable(info->rtc_clk); - if (info->data->needs_src_clk) - clk_enable(info->rtc_src_clk); + if (info->clk_disabled) { + clk_enable(info->rtc_clk); + if (info->data->needs_src_clk) + clk_enable(info->rtc_src_clk); + info->clk_disabled = false; + } spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags); } @@ -82,9 +86,12 @@ static void s3c_rtc_disable_clk(struct s3c_rtc *info) unsigned long irq_flags; spin_lock_irqsave(&info->alarm_clk_lock, irq_flags); - if (info->data->needs_src_clk) - clk_disable(info->rtc_src_clk); - clk_disable(info->rtc_clk); + if (!info->clk_disabled) { + if (info->data->needs_src_clk) + clk_disable(info->rtc_src_clk); + clk_disable(info->rtc_clk); + info->clk_disabled = true; + } spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags); } @@ -128,6 +135,11 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled) s3c_rtc_disable_clk(info); + if (enabled) + s3c_rtc_enable_clk(info); + else + s3c_rtc_disable_clk(info); + return 0; } From 7f23a93661eb5caa373f75a145cec14331a8caaa Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 11 Aug 2015 20:28:19 +0900 Subject: [PATCH 69/90] rtc: s3c: add missing clk control It's missed to call clk_unprepare() about info->rtc_src_clk in s3c_rtc_remove and to call clk_disable_unprepare about info->rtc_clk in error routine of s3c_rtc_probe. Signed-off-by: Joonyoung Shim Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s3c.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 2e709e239dbc..3ee961529b5b 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -422,6 +422,8 @@ static int s3c_rtc_remove(struct platform_device *pdev) s3c_rtc_setaie(info->dev, 0); + if (info->data->needs_src_clk) + clk_unprepare(info->rtc_src_clk); clk_unprepare(info->rtc_clk); info->rtc_clk = NULL; @@ -494,6 +496,7 @@ static int s3c_rtc_probe(struct platform_device *pdev) if (IS_ERR(info->rtc_src_clk)) { dev_err(&pdev->dev, "failed to find rtc source clock\n"); + clk_disable_unprepare(info->rtc_clk); return PTR_ERR(info->rtc_src_clk); } clk_prepare_enable(info->rtc_src_clk); From 27b15e31dbc5f4d7fc93e6acaa898cbfd1cf74ea Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Tue, 11 Aug 2015 20:28:20 +0900 Subject: [PATCH 70/90] rtc: s3c: remove unnecessary NULL assignment It's unnecessary the code that assigns info->rtc_clk to NULL in s3c_rtc_remove. Signed-off-by: Joonyoung Shim Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s3c.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 3ee961529b5b..7cc8f73a3fe8 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -425,7 +425,6 @@ static int s3c_rtc_remove(struct platform_device *pdev) if (info->data->needs_src_clk) clk_unprepare(info->rtc_src_clk); clk_unprepare(info->rtc_clk); - info->rtc_clk = NULL; return 0; } From dc2280ebf45bfa4fbc4b1588a6642aa33454a9b8 Mon Sep 17 00:00:00 2001 From: Wang Dongsheng Date: Wed, 12 Aug 2015 17:14:13 +0800 Subject: [PATCH 71/90] rtc: ds3232: fix WARNING trace in resume function If ds3232 work on some platform that is not implementing irq_set_wake, ds3232 will get a WARNING trace in resume. So fix ds3232->suspended state to false when irq_set_irq_wake return error. WARNING: CPU: 0 PID: 729 at kernel/irq/manage.c:604 irq_set_irq_wake+0x4b/0x8c() Unbalanced IRQ 201 wake disable Modules linked in: CPU: 0 PID: 729 Comm: sh Not tainted 3.12.19-rt30+ #25 [<800107d9>] (unwind_backtrace+0x1/0x88) from [<8000e4ef>] (show_stack+0xb/0xc) [<8000e4ef>] (show_stack+0xb/0xc) from [<802b5fa9>] (dump_stack+0x4d/0x60) [<802b5fa9>] (dump_stack+0x4d/0x60) from [<800186dd>] (warn_slowpath_common+0x45/0x64) [<800186dd>] (warn_slowpath_common+0x45/0x64) from [<80018717>] (warn_slowpath_fmt+0x1b/0x24) [<80018717>] (warn_slowpath_fmt+0x1b/0x24) from [<8003a8d3>] (irq_set_irq_wake+0x4b/0x8c) [<8003a8d3>] (irq_set_irq_wake+0x4b/0x8c) from [<80204fcb>] (ds3232_resume+0x2d/0x36) [<80204fcb>] (ds3232_resume+0x2d/0x36) from [<801954c7>] (dpm_run_callback.isra.13+0xb/0x28) [<801954c7>] (dpm_run_callback.isra.13+0xb/0x28) from [<80195b1b>] (device_resume+0x7b/0xa2) [<80195b1b>] (device_resume+0x7b/0xa2) from [<80195f0f>] (dpm_resume+0xbb/0x19c) [<80195f0f>] (dpm_resume+0xbb/0x19c) from [<801960d9>] (dpm_resume_end+0x9/0x12) [<801960d9>] (dpm_resume_end+0x9/0x12) from [<80037e1d>] (suspend_devices_and_enter+0x17d/0x1d0) [<80037e1d>] (suspend_devices_and_enter+0x17d/0x1d0) from [<80037ee1>] (pm_suspend+0x71/0x128) [<80037ee1>] (pm_suspend+0x71/0x128) from [<80037449>] (state_store+0x6d/0x80) [<80037449>] (state_store+0x6d/0x80) from [<800af4d5>] (sysfs_write_file+0x9f/0xde) [<800af4d5>] (sysfs_write_file+0x9f/0xde) from [<8007a437>] (vfs_write+0x7b/0x104) [<8007a437>] (vfs_write+0x7b/0x104) from [<8007a7f7>] (SyS_write+0x27/0x48) [<8007a7f7>] (SyS_write+0x27/0x48) from [<8000c121>] (ret_fast_syscall+0x1/0x44) Signed-off-by: Wang Dongsheng Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds3232.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index a8702dda0f26..4e99ace66f74 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -463,7 +463,10 @@ static int ds3232_suspend(struct device *dev) if (device_can_wakeup(dev)) { ds3232->suspended = true; - irq_set_irq_wake(client->irq, 1); + if (irq_set_irq_wake(client->irq, 1)) { + dev_warn_once(dev, "Cannot set wakeup source\n"); + ds3232->suspended = false; + } } return 0; From 8c0961ba7c9356186a0606a391f08e2ecb491a57 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 12 May 2015 16:23:23 -0500 Subject: [PATCH 72/90] rtc: sa1100: prepare to share sa1100_rtc_ops Factor out the RTC initialization from the platform device specific parts in order to share the RTC device ops with other drivers. Specifically, it will be shared with rtc-pxa driver. Signed-off-by: Rob Herring Cc: Robert Jarzmik Cc: Russell King Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: rtc-linux@googlegroups.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sa1100.c | 59 ++++++++++++++++++++-------------------- drivers/rtc/rtc-sa1100.h | 19 +++++++++++++ 2 files changed, 49 insertions(+), 29 deletions(-) create mode 100644 drivers/rtc/rtc-sa1100.h diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index b6e1ca08c2c0..abc19abd5f2d 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -42,17 +42,12 @@ #include #endif +#include "rtc-sa1100.h" + #define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 #define RTC_FREQ 1024 -struct sa1100_rtc { - spinlock_t lock; - int irq_1hz; - int irq_alarm; - struct rtc_device *rtc; - struct clk *clk; -}; static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) { @@ -223,29 +218,18 @@ static const struct rtc_class_ops sa1100_rtc_ops = { .alarm_irq_enable = sa1100_rtc_alarm_irq_enable, }; -static int sa1100_rtc_probe(struct platform_device *pdev) +int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info) { struct rtc_device *rtc; - struct sa1100_rtc *info; - int irq_1hz, irq_alarm, ret = 0; + int ret; - irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz"); - irq_alarm = platform_get_irq_byname(pdev, "rtc alarm"); - if (irq_1hz < 0 || irq_alarm < 0) - return -ENODEV; + spin_lock_init(&info->lock); - info = devm_kzalloc(&pdev->dev, sizeof(struct sa1100_rtc), GFP_KERNEL); - if (!info) - return -ENOMEM; info->clk = devm_clk_get(&pdev->dev, NULL); if (IS_ERR(info->clk)) { dev_err(&pdev->dev, "failed to find rtc clock source\n"); return PTR_ERR(info->clk); } - info->irq_1hz = irq_1hz; - info->irq_alarm = irq_alarm; - spin_lock_init(&info->lock); - platform_set_drvdata(pdev, info); ret = clk_prepare_enable(info->clk); if (ret) @@ -265,14 +249,11 @@ static int sa1100_rtc_probe(struct platform_device *pdev) RCNR = 0; } - device_init_wakeup(&pdev->dev, 1); - rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &sa1100_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - ret = PTR_ERR(rtc); - goto err_dev; + clk_disable_unprepare(info->clk); + return PTR_ERR(rtc); } info->rtc = rtc; @@ -301,9 +282,29 @@ static int sa1100_rtc_probe(struct platform_device *pdev) RTSR = RTSR_AL | RTSR_HZ; return 0; -err_dev: - clk_disable_unprepare(info->clk); - return ret; +} +EXPORT_SYMBOL_GPL(sa1100_rtc_init); + +static int sa1100_rtc_probe(struct platform_device *pdev) +{ + struct sa1100_rtc *info; + int irq_1hz, irq_alarm; + + irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz"); + irq_alarm = platform_get_irq_byname(pdev, "rtc alarm"); + if (irq_1hz < 0 || irq_alarm < 0) + return -ENODEV; + + info = devm_kzalloc(&pdev->dev, sizeof(struct sa1100_rtc), GFP_KERNEL); + if (!info) + return -ENOMEM; + info->irq_1hz = irq_1hz; + info->irq_alarm = irq_alarm; + + platform_set_drvdata(pdev, info); + device_init_wakeup(&pdev->dev, 1); + + return sa1100_rtc_init(pdev, info); } static int sa1100_rtc_remove(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-sa1100.h b/drivers/rtc/rtc-sa1100.h new file mode 100644 index 000000000000..665d054740a1 --- /dev/null +++ b/drivers/rtc/rtc-sa1100.h @@ -0,0 +1,19 @@ +#ifndef __RTC_SA1100_H__ +#define __RTC_SA1100_H__ + +#include + +struct clk; +struct platform_device; + +struct sa1100_rtc { + spinlock_t lock; + int irq_1hz; + int irq_alarm; + struct rtc_device *rtc; + struct clk *clk; +}; + +int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info); + +#endif From 3cdf4ad9633e3ca616617e76b46915c02cba426b Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Wed, 13 May 2015 09:20:04 -0500 Subject: [PATCH 73/90] rtc: pxa: convert to use shared sa1100 functions Currently, the rtc-sa1100 and rtc-pxa drivers co-exist as rtc-pxa has a superset of functionality. Having 2 drivers sharing the same memory resource is not allowed by the driver model if resources are properly declared. This problem was avoided by not adding memory resources to the SA1100 RTC driver, but that prevents clean-up of the SA1100 driver. This commit converts the PXA RTC to use the exported SA1100 RTC functions. Now the sa1100-rtc and pxa-rtc devices are mutually exclusive, so we must remove the sa1100-rtc from pxa27x and pxa3xx. Signed-off-by: Rob Herring Cc: Daniel Mack Cc: Haojian Zhuang Cc: Robert Jarzmik Cc: Russell King Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: linux-arm-kernel@lists.infradead.org Cc: rtc-linux@googlegroups.com Signed-off-by: Alexandre Belloni --- arch/arm/mach-pxa/pxa27x.c | 1 - arch/arm/mach-pxa/pxa3xx.c | 1 - drivers/rtc/Kconfig | 12 +++++---- drivers/rtc/rtc-pxa.c | 51 ++++++++++++++++++-------------------- 4 files changed, 31 insertions(+), 34 deletions(-) diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c index e6aae9e8adfb..221260d5d109 100644 --- a/arch/arm/mach-pxa/pxa27x.c +++ b/arch/arm/mach-pxa/pxa27x.c @@ -282,7 +282,6 @@ static struct platform_device *devices[] __initdata = { &pxa_device_asoc_ssp2, &pxa_device_asoc_ssp3, &pxa_device_asoc_platform, - &sa1100_device_rtc, &pxa_device_rtc, &pxa27x_device_ssp1, &pxa27x_device_ssp2, diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c index 165638462a2f..ce0f8d6242e2 100644 --- a/arch/arm/mach-pxa/pxa3xx.c +++ b/arch/arm/mach-pxa/pxa3xx.c @@ -394,7 +394,6 @@ static struct platform_device *devices[] __initdata = { &pxa_device_asoc_ssp3, &pxa_device_asoc_ssp4, &pxa_device_asoc_platform, - &sa1100_device_rtc, &pxa_device_rtc, &pxa3xx_device_ssp1, &pxa3xx_device_ssp2, diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 35ea04c50a5c..0f65a222a48a 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1306,11 +1306,13 @@ config RTC_DRV_GENERIC just say Y. config RTC_DRV_PXA - tristate "PXA27x/PXA3xx" - depends on ARCH_PXA - help - If you say Y here you will get access to the real time clock - built into your PXA27x or PXA3xx CPU. + tristate "PXA27x/PXA3xx" + depends on ARCH_PXA + select RTC_DRV_SA1100 + help + If you say Y here you will get access to the real time clock + built into your PXA27x or PXA3xx CPU. This RTC is actually 2 RTCs + consisting of an SA1100 compatible RTC and the extended PXA RTC. This RTC driver uses PXA RTC registers available since pxa27x series (RDxR, RYxR) instead of legacy RCNR, RTAR. diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index 4561f375327d..fb9b3a7d2266 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -32,6 +32,8 @@ #include +#include "rtc-sa1100.h" + #define RTC_DEF_DIVIDER (32768 - 1) #define RTC_DEF_TRIM 0 #define MAXFREQ_PERIODIC 1000 @@ -86,10 +88,9 @@ __raw_writel((value), (pxa_rtc)->base + (reg)) struct pxa_rtc { + struct sa1100_rtc sa1100_rtc; struct resource *ress; void __iomem *base; - int irq_1Hz; - int irq_Alrm; struct rtc_device *rtc; spinlock_t lock; /* Protects this structure */ }; @@ -184,25 +185,25 @@ static int pxa_rtc_open(struct device *dev) struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); int ret; - ret = request_irq(pxa_rtc->irq_1Hz, pxa_rtc_irq, 0, + ret = request_irq(pxa_rtc->sa1100_rtc.irq_1hz, pxa_rtc_irq, 0, "rtc 1Hz", dev); if (ret < 0) { - dev_err(dev, "can't get irq %i, err %d\n", pxa_rtc->irq_1Hz, - ret); + dev_err(dev, "can't get irq %i, err %d\n", + pxa_rtc->sa1100_rtc.irq_1hz, ret); goto err_irq_1Hz; } - ret = request_irq(pxa_rtc->irq_Alrm, pxa_rtc_irq, 0, + ret = request_irq(pxa_rtc->sa1100_rtc.irq_alarm, pxa_rtc_irq, 0, "rtc Alrm", dev); if (ret < 0) { - dev_err(dev, "can't get irq %i, err %d\n", pxa_rtc->irq_Alrm, - ret); + dev_err(dev, "can't get irq %i, err %d\n", + pxa_rtc->sa1100_rtc.irq_alarm, ret); goto err_irq_Alrm; } return 0; err_irq_Alrm: - free_irq(pxa_rtc->irq_1Hz, dev); + free_irq(pxa_rtc->sa1100_rtc.irq_1hz, dev); err_irq_1Hz: return ret; } @@ -215,8 +216,8 @@ static void pxa_rtc_release(struct device *dev) rtsr_clear_bits(pxa_rtc, RTSR_PIALE | RTSR_RDALE1 | RTSR_HZE); spin_unlock_irq(&pxa_rtc->lock); - free_irq(pxa_rtc->irq_Alrm, dev); - free_irq(pxa_rtc->irq_1Hz, dev); + free_irq(pxa_rtc->sa1100_rtc.irq_1hz, dev); + free_irq(pxa_rtc->sa1100_rtc.irq_alarm, dev); } static int pxa_alarm_irq_enable(struct device *dev, unsigned int enabled) @@ -320,12 +321,13 @@ static int __init pxa_rtc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct pxa_rtc *pxa_rtc; + struct sa1100_rtc *sa1100_rtc; int ret; - u32 rttr; pxa_rtc = devm_kzalloc(dev, sizeof(*pxa_rtc), GFP_KERNEL); if (!pxa_rtc) return -ENOMEM; + sa1100_rtc = &pxa_rtc->sa1100_rtc; spin_lock_init(&pxa_rtc->lock); platform_set_drvdata(pdev, pxa_rtc); @@ -336,13 +338,13 @@ static int __init pxa_rtc_probe(struct platform_device *pdev) return -ENXIO; } - pxa_rtc->irq_1Hz = platform_get_irq(pdev, 0); - if (pxa_rtc->irq_1Hz < 0) { + sa1100_rtc->irq_1hz = platform_get_irq(pdev, 0); + if (sa1100_rtc->irq_1hz < 0) { dev_err(dev, "No 1Hz IRQ resource defined\n"); return -ENXIO; } - pxa_rtc->irq_Alrm = platform_get_irq(pdev, 1); - if (pxa_rtc->irq_Alrm < 0) { + sa1100_rtc->irq_alarm = platform_get_irq(pdev, 1); + if (sa1100_rtc->irq_alarm < 0) { dev_err(dev, "No alarm IRQ resource defined\n"); return -ENXIO; } @@ -354,15 +356,10 @@ static int __init pxa_rtc_probe(struct platform_device *pdev) return -ENOMEM; } - /* - * If the clock divider is uninitialized then reset it to the - * default value to get the 1Hz clock. - */ - if (rtc_readl(pxa_rtc, RTTR) == 0) { - rttr = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); - rtc_writel(pxa_rtc, RTTR, rttr); - dev_warn(dev, "warning: initializing default clock" - " divider/trim value\n"); + ret = sa1100_rtc_init(pdev, sa1100_rtc); + if (!ret) { + dev_err(dev, "Unable to init SA1100 RTC sub-device\n"); + return ret; } rtsr_clear_bits(pxa_rtc, RTSR_PIALE | RTSR_RDALE1 | RTSR_HZE); @@ -402,7 +399,7 @@ static int pxa_rtc_suspend(struct device *dev) struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); if (device_may_wakeup(dev)) - enable_irq_wake(pxa_rtc->irq_Alrm); + enable_irq_wake(pxa_rtc->sa1100_rtc.irq_alarm); return 0; } @@ -411,7 +408,7 @@ static int pxa_rtc_resume(struct device *dev) struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); if (device_may_wakeup(dev)) - disable_irq_wake(pxa_rtc->irq_Alrm); + disable_irq_wake(pxa_rtc->sa1100_rtc.irq_alarm); return 0; } #endif From 2c4fabec8790384b91473aa3d0d28d4407168ef9 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 2 Feb 2015 17:50:32 -0600 Subject: [PATCH 74/90] ARM: pxa: add memory resource to SA1100 RTC device The drivers for the SA1100 and PXA RTCs are now mutually exclusive, so add the memory resource for the sa1100-rtc device. Since the memory resource is already present in the pxa_rtc_resources, that makes sa1100_rtc_resources and pxa_rtc_resources equivalent, so use pxa_rtc_resources for both devices and remove the duplicate sa1100_rtc_resources. Signed-off-by: Rob Herring Cc: Daniel Mack Cc: Haojian Zhuang Acked-by: Robert Jarzmik Cc: Russell King Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Alexandre Belloni --- arch/arm/mach-pxa/devices.c | 18 ++---------------- 1 file changed, 2 insertions(+), 16 deletions(-) diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c index e6ce669b54af..c62473235a13 100644 --- a/arch/arm/mach-pxa/devices.c +++ b/arch/arm/mach-pxa/devices.c @@ -440,25 +440,11 @@ struct platform_device pxa_device_rtc = { .resource = pxa_rtc_resources, }; -static struct resource sa1100_rtc_resources[] = { - { - .start = IRQ_RTC1Hz, - .end = IRQ_RTC1Hz, - .name = "rtc 1Hz", - .flags = IORESOURCE_IRQ, - }, { - .start = IRQ_RTCAlrm, - .end = IRQ_RTCAlrm, - .name = "rtc alarm", - .flags = IORESOURCE_IRQ, - }, -}; - struct platform_device sa1100_device_rtc = { .name = "sa1100-rtc", .id = -1, - .num_resources = ARRAY_SIZE(sa1100_rtc_resources), - .resource = sa1100_rtc_resources, + .num_resources = ARRAY_SIZE(pxa_rtc_resources), + .resource = pxa_rtc_resources, }; static struct resource pxa_ac97_resources[] = { From 90d0ae8e9583355725583e9d1ff0ebdc97936f39 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 3 Feb 2015 14:44:51 -0600 Subject: [PATCH 75/90] rtc: sa1100/pxa: convert to run-time register mapping SA1100 and PXA differ only in register offsets which are currently hardcoded in a machine specific header. Some arm64 platforms (PXA1928) have this RTC block as well (and not the PXA270 variant). Convert the driver to use ioremap and set the register offsets dynamically. Since we are touching all the register accesses, convert them all to readl_relaxed/writel_relaxed. Signed-off-by: Rob Herring Acked-by: Robert Jarzmik Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: rtc-linux@googlegroups.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pxa.c | 4 ++ drivers/rtc/rtc-sa1100.c | 82 +++++++++++++++++++++++++++------------- drivers/rtc/rtc-sa1100.h | 4 ++ 3 files changed, 63 insertions(+), 27 deletions(-) diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index fb9b3a7d2266..fe4985b54608 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -356,6 +356,10 @@ static int __init pxa_rtc_probe(struct platform_device *pdev) return -ENOMEM; } + sa1100_rtc->rcnr = pxa_rtc->base + 0x0; + sa1100_rtc->rtsr = pxa_rtc->base + 0x8; + sa1100_rtc->rtar = pxa_rtc->base + 0x4; + sa1100_rtc->rttr = pxa_rtc->base + 0xc; ret = sa1100_rtc_init(pdev, sa1100_rtc); if (!ret) { dev_err(dev, "Unable to init SA1100 RTC sub-device\n"); diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index abc19abd5f2d..c2187bf6c7e4 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -35,12 +35,10 @@ #include #include -#include -#include - -#if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP) -#include -#endif +#define RTSR_HZE BIT(3) /* HZ interrupt enable */ +#define RTSR_ALE BIT(2) /* RTC alarm interrupt enable */ +#define RTSR_HZ BIT(1) /* HZ rising-edge detected */ +#define RTSR_AL BIT(0) /* RTC alarm detected */ #include "rtc-sa1100.h" @@ -58,16 +56,16 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) spin_lock(&info->lock); - rtsr = RTSR; + rtsr = readl_relaxed(info->rtsr); /* clear interrupt sources */ - RTSR = 0; + writel_relaxed(0, info->rtsr); /* Fix for a nasty initialization problem the in SA11xx RTSR register. * See also the comments in sa1100_rtc_probe(). */ if (rtsr & (RTSR_ALE | RTSR_HZE)) { /* This is the original code, before there was the if test * above. This code does not clear interrupts that were not * enabled. */ - RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2); + writel_relaxed((RTSR_AL | RTSR_HZ) & (rtsr >> 2), info->rtsr); } else { /* For some reason, it is possible to enter this routine * without interruptions enabled, it has been tested with @@ -76,13 +74,13 @@ static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id) * This situation leads to an infinite "loop" of interrupt * routine calling and as a result the processor seems to * lock on its first call to open(). */ - RTSR = RTSR_AL | RTSR_HZ; + writel_relaxed(RTSR_AL | RTSR_HZ, info->rtsr); } /* clear alarm interrupt if it has occurred */ if (rtsr & RTSR_AL) rtsr &= ~RTSR_ALE; - RTSR = rtsr & (RTSR_ALE | RTSR_HZE); + writel_relaxed(rtsr & (RTSR_ALE | RTSR_HZE), info->rtsr); /* update irq data & counter */ if (rtsr & RTSR_AL) @@ -130,7 +128,7 @@ static void sa1100_rtc_release(struct device *dev) struct sa1100_rtc *info = dev_get_drvdata(dev); spin_lock_irq(&info->lock); - RTSR = 0; + writel_relaxed(0, info->rtsr); spin_unlock_irq(&info->lock); free_irq(info->irq_alarm, dev); @@ -139,39 +137,46 @@ static void sa1100_rtc_release(struct device *dev) static int sa1100_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) { + u32 rtsr; struct sa1100_rtc *info = dev_get_drvdata(dev); spin_lock_irq(&info->lock); + rtsr = readl_relaxed(info->rtsr); if (enabled) - RTSR |= RTSR_ALE; + rtsr |= RTSR_ALE; else - RTSR &= ~RTSR_ALE; + rtsr &= ~RTSR_ALE; + writel_relaxed(rtsr, info->rtsr); spin_unlock_irq(&info->lock); return 0; } static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm) { - rtc_time_to_tm(RCNR, tm); + struct sa1100_rtc *info = dev_get_drvdata(dev); + + rtc_time_to_tm(readl_relaxed(info->rcnr), tm); return 0; } static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm) { + struct sa1100_rtc *info = dev_get_drvdata(dev); unsigned long time; int ret; ret = rtc_tm_to_time(tm, &time); if (ret == 0) - RCNR = time; + writel_relaxed(time, info->rcnr); return ret; } static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) { u32 rtsr; + struct sa1100_rtc *info = dev_get_drvdata(dev); - rtsr = RTSR; + rtsr = readl_relaxed(info->rtsr); alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0; alrm->pending = (rtsr & RTSR_AL) ? 1 : 0; return 0; @@ -187,12 +192,13 @@ static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) ret = rtc_tm_to_time(&alrm->time, &time); if (ret != 0) goto out; - RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL); - RTAR = time; + writel_relaxed(readl_relaxed(info->rtsr) & + (RTSR_HZE | RTSR_ALE | RTSR_AL), info->rtsr); + writel_relaxed(time, info->rtar); if (alrm->enabled) - RTSR |= RTSR_ALE; + writel_relaxed(readl_relaxed(info->rtsr) | RTSR_ALE, info->rtsr); else - RTSR &= ~RTSR_ALE; + writel_relaxed(readl_relaxed(info->rtsr) & ~RTSR_ALE, info->rtsr); out: spin_unlock_irq(&info->lock); @@ -201,8 +207,10 @@ out: static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq) { - seq_printf(seq, "trim/divider\t\t: 0x%08x\n", (u32) RTTR); - seq_printf(seq, "RTSR\t\t\t: 0x%08x\n", (u32)RTSR); + struct sa1100_rtc *info = dev_get_drvdata(dev); + + seq_printf(seq, "trim/divider\t\t: 0x%08x\n", readl_relaxed(info->rttr)); + seq_printf(seq, "RTSR\t\t\t: 0x%08x\n", readl_relaxed(info->rtsr)); return 0; } @@ -241,12 +249,12 @@ int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info) * If the clock divider is uninitialized then reset it to the * default value to get the 1Hz clock. */ - if (RTTR == 0) { - RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); + if (readl_relaxed(info->rttr) == 0) { + writel_relaxed(RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16), info->rttr); dev_warn(&pdev->dev, "warning: " "initializing default clock divider/trim value\n"); /* The current RTC value probably doesn't make sense either */ - RCNR = 0; + writel_relaxed(0, info->rcnr); } rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &sa1100_rtc_ops, @@ -279,7 +287,7 @@ int sa1100_rtc_init(struct platform_device *pdev, struct sa1100_rtc *info) * * Notice that clearing bit 1 and 0 is accomplished by writting ONES to * the corresponding bits in RTSR. */ - RTSR = RTSR_AL | RTSR_HZ; + writel_relaxed(RTSR_AL | RTSR_HZ, info->rtsr); return 0; } @@ -288,6 +296,8 @@ EXPORT_SYMBOL_GPL(sa1100_rtc_init); static int sa1100_rtc_probe(struct platform_device *pdev) { struct sa1100_rtc *info; + struct resource *iores; + void __iomem *base; int irq_1hz, irq_alarm; irq_1hz = platform_get_irq_byname(pdev, "rtc 1Hz"); @@ -301,6 +311,24 @@ static int sa1100_rtc_probe(struct platform_device *pdev) info->irq_1hz = irq_1hz; info->irq_alarm = irq_alarm; + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + base = devm_ioremap_resource(&pdev->dev, iores); + if (IS_ERR(base)) + return PTR_ERR(base); + + if (IS_ENABLED(CONFIG_ARCH_SA1100) || + of_device_is_compatible(pdev->dev.of_node, "mrvl,sa1100-rtc")) { + info->rcnr = base + 0x04; + info->rtsr = base + 0x10; + info->rtar = base + 0x00; + info->rttr = base + 0x08; + } else { + info->rcnr = base + 0x0; + info->rtsr = base + 0x8; + info->rtar = base + 0x4; + info->rttr = base + 0xc; + } + platform_set_drvdata(pdev, info); device_init_wakeup(&pdev->dev, 1); diff --git a/drivers/rtc/rtc-sa1100.h b/drivers/rtc/rtc-sa1100.h index 665d054740a1..2c79c0c57822 100644 --- a/drivers/rtc/rtc-sa1100.h +++ b/drivers/rtc/rtc-sa1100.h @@ -8,6 +8,10 @@ struct platform_device; struct sa1100_rtc { spinlock_t lock; + void __iomem *rcnr; + void __iomem *rtar; + void __iomem *rtsr; + void __iomem *rttr; int irq_1hz; int irq_alarm; struct rtc_device *rtc; From d6679c48c13ce896a428d392ffe8a62ad6a75b77 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 3 Feb 2015 14:46:29 -0600 Subject: [PATCH 76/90] ARM: sa1100: remove unused RTC register definitions Now that register definitions have been moved to the driver, we can remove them from machine specific code. Signed-off-by: Rob Herring Cc: Russell King Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Alexandre Belloni --- arch/arm/mach-sa1100/include/mach/SA-1100.h | 34 --------------------- 1 file changed, 34 deletions(-) diff --git a/arch/arm/mach-sa1100/include/mach/SA-1100.h b/arch/arm/mach-sa1100/include/mach/SA-1100.h index 0ac6cc08a19c..7972617cca64 100644 --- a/arch/arm/mach-sa1100/include/mach/SA-1100.h +++ b/arch/arm/mach-sa1100/include/mach/SA-1100.h @@ -857,40 +857,6 @@ #define OIER_E3 OIER_E (3) /* match interrupt Enable 3 */ -/* - * Real-Time Clock (RTC) control registers - * - * Registers - * RTAR Real-Time Clock (RTC) Alarm Register (read/write). - * RCNR Real-Time Clock (RTC) CouNt Register (read/write). - * RTTR Real-Time Clock (RTC) Trim Register (read/write). - * RTSR Real-Time Clock (RTC) Status Register (read/write). - * - * Clocks - * frtx, Trtx Frequency, period of the real-time clock crystal - * (32.768 kHz nominal). - * frtc, Trtc Frequency, period of the real-time clock counter - * (1 Hz nominal). - */ - -#define RTAR __REG(0x90010000) /* RTC Alarm Reg. */ -#define RCNR __REG(0x90010004) /* RTC CouNt Reg. */ -#define RTTR __REG(0x90010008) /* RTC Trim Reg. */ -#define RTSR __REG(0x90010010) /* RTC Status Reg. */ - -#define RTTR_C Fld (16, 0) /* clock divider Count - 1 */ -#define RTTR_D Fld (10, 16) /* trim Delete count */ - /* frtc = (1023*(C + 1) - D)*frtx/ */ - /* (1023*(C + 1)^2) */ - /* Trtc = (1023*(C + 1)^2)*Trtx/ */ - /* (1023*(C + 1) - D) */ - -#define RTSR_AL 0x00000001 /* ALarm detected */ -#define RTSR_HZ 0x00000002 /* 1 Hz clock detected */ -#define RTSR_ALE 0x00000004 /* ALarm interrupt Enable */ -#define RTSR_HZE 0x00000008 /* 1 Hz clock interrupt Enable */ - - /* * Power Manager (PM) control registers * From 7b758ef4440cd581e8207d762af635c644c85f81 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Tue, 3 Feb 2015 14:54:01 -0600 Subject: [PATCH 77/90] ARM: mmp: remove unused RTC register definitions Now that register definitions have been moved to the driver, regs-rtc.h is no longer used and can be removed. Signed-off-by: Rob Herring Cc: Eric Miao Cc: Haojian Zhuang Cc: Russell King Cc: linux-arm-kernel@lists.infradead.org Signed-off-by: Alexandre Belloni --- arch/arm/mach-mmp/include/mach/regs-rtc.h | 23 ----------------------- 1 file changed, 23 deletions(-) delete mode 100644 arch/arm/mach-mmp/include/mach/regs-rtc.h diff --git a/arch/arm/mach-mmp/include/mach/regs-rtc.h b/arch/arm/mach-mmp/include/mach/regs-rtc.h deleted file mode 100644 index 5bff886a3941..000000000000 --- a/arch/arm/mach-mmp/include/mach/regs-rtc.h +++ /dev/null @@ -1,23 +0,0 @@ -#ifndef __ASM_MACH_REGS_RTC_H -#define __ASM_MACH_REGS_RTC_H - -#include - -#define RTC_VIRT_BASE (APB_VIRT_BASE + 0x10000) -#define RTC_REG(x) (*((volatile u32 __iomem *)(RTC_VIRT_BASE + (x)))) - -/* - * Real Time Clock - */ - -#define RCNR RTC_REG(0x00) /* RTC Count Register */ -#define RTAR RTC_REG(0x04) /* RTC Alarm Register */ -#define RTSR RTC_REG(0x08) /* RTC Status Register */ -#define RTTR RTC_REG(0x0C) /* RTC Timer Trim Register */ - -#define RTSR_HZE (1 << 3) /* HZ interrupt enable */ -#define RTSR_ALE (1 << 2) /* RTC alarm interrupt enable */ -#define RTSR_HZ (1 << 1) /* HZ rising-edge detected */ -#define RTSR_AL (1 << 0) /* RTC alarm detected */ - -#endif /* __ASM_MACH_REGS_RTC_H */ From e66ce07a9692f492580820640b446971dff97a74 Mon Sep 17 00:00:00 2001 From: Rob Herring Date: Mon, 1 Jun 2015 07:53:01 -0500 Subject: [PATCH 78/90] ARM: config: Switch PXA27x platforms to use PXA RTC driver With the SA1100 and PXA RTC drivers be mutually exclusive and no longer sharing hardware, PXA27x/PXA3xx platforms must use the PXA RTC driver as the SA1100 platform device is no longer registered. This change should be almost transparent to userspace. Former users of pxa-rtc should be aware that 2 RTCs will be available on their kernels, rtc0 being sa1100-rtc and rtc1 being pxa-rtc. Any userspace relying on the fact that rtc0 was pxa-rtc should be fixed. As a consequence: - the first reboot after the switch will have the wrong time, - on dual boot platform where the other OS programs some logic into the sa1100 rtc IP, a lack of fix in userspace, ie. a kernel changing sa1100-rtc thinking it is pxa-rtc could have dire consequence, such as wiping the other OS data partition. (Thanks to Robert Jarmik for help on the above commit text.) Signed-off-by: Rob Herring Acked-by: Robert Jarzmik Cc: Daniel Mack Cc: Haojian Zhuang Cc: Sergey Lapin Cc: Russell King Cc: Mike Rapoport Cc: Philipp Zabel Signed-off-by: Alexandre Belloni --- arch/arm/configs/cm_x2xx_defconfig | 2 +- arch/arm/configs/em_x270_defconfig | 2 +- arch/arm/configs/magician_defconfig | 2 +- arch/arm/configs/palmz72_defconfig | 2 +- arch/arm/configs/pcm027_defconfig | 2 +- arch/arm/configs/trizeps4_defconfig | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/arch/arm/configs/cm_x2xx_defconfig b/arch/arm/configs/cm_x2xx_defconfig index dc01c049a520..3b32d5fd9326 100644 --- a/arch/arm/configs/cm_x2xx_defconfig +++ b/arch/arm/configs/cm_x2xx_defconfig @@ -157,7 +157,7 @@ CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_V3020=y -CONFIG_RTC_DRV_SA1100=y +CONFIG_RTC_DRV_PXA=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y CONFIG_INOTIFY=y diff --git a/arch/arm/configs/em_x270_defconfig b/arch/arm/configs/em_x270_defconfig index 4560c9ca6636..8e10df7ba1b4 100644 --- a/arch/arm/configs/em_x270_defconfig +++ b/arch/arm/configs/em_x270_defconfig @@ -157,7 +157,7 @@ CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_V3020=y -CONFIG_RTC_DRV_SA1100=y +CONFIG_RTC_DRV_PXA=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y CONFIG_INOTIFY=y diff --git a/arch/arm/configs/magician_defconfig b/arch/arm/configs/magician_defconfig index 557dd291288b..a5b4920cd6d4 100644 --- a/arch/arm/configs/magician_defconfig +++ b/arch/arm/configs/magician_defconfig @@ -150,7 +150,7 @@ CONFIG_LEDS_TRIGGERS=y CONFIG_LEDS_TRIGGER_BACKLIGHT=y CONFIG_RTC_CLASS=y CONFIG_RTC_DEBUG=y -CONFIG_RTC_DRV_SA1100=y +CONFIG_RTC_DRV_PXA=y CONFIG_EXT2_FS=y CONFIG_INOTIFY=y CONFIG_MSDOS_FS=m diff --git a/arch/arm/configs/palmz72_defconfig b/arch/arm/configs/palmz72_defconfig index 4baa83c1c577..83c135e19aba 100644 --- a/arch/arm/configs/palmz72_defconfig +++ b/arch/arm/configs/palmz72_defconfig @@ -67,7 +67,7 @@ CONFIG_MMC=y CONFIG_MMC_DEBUG=y CONFIG_MMC_PXA=y CONFIG_RTC_CLASS=y -CONFIG_RTC_DRV_SA1100=y +CONFIG_RTC_DRV_PXA=y CONFIG_EXT2_FS=y CONFIG_EXT3_FS=y # CONFIG_DNOTIFY is not set diff --git a/arch/arm/configs/pcm027_defconfig b/arch/arm/configs/pcm027_defconfig index 0a847d04ddc1..b5624e325817 100644 --- a/arch/arm/configs/pcm027_defconfig +++ b/arch/arm/configs/pcm027_defconfig @@ -82,7 +82,7 @@ CONFIG_MMC=y CONFIG_MMC_PXA=y CONFIG_RTC_CLASS=y CONFIG_RTC_DRV_PCF8563=m -CONFIG_RTC_DRV_SA1100=m +CONFIG_RTC_DRV_PXA=m CONFIG_EXT2_FS=m CONFIG_EXT3_FS=m # CONFIG_DNOTIFY is not set diff --git a/arch/arm/configs/trizeps4_defconfig b/arch/arm/configs/trizeps4_defconfig index 932ee4e4a13a..4bc870028035 100644 --- a/arch/arm/configs/trizeps4_defconfig +++ b/arch/arm/configs/trizeps4_defconfig @@ -177,7 +177,7 @@ CONFIG_NEW_LEDS=y CONFIG_RTC_CLASS=y # CONFIG_RTC_HCTOSYS is not set CONFIG_RTC_DRV_PCF8583=m -CONFIG_RTC_DRV_SA1100=y +CONFIG_RTC_DRV_PXA=y CONFIG_EXT2_FS=y CONFIG_EXT2_FS_XATTR=y CONFIG_EXT2_FS_POSIX_ACL=y From a038c3aa9f3afe9ab97a75827789859fb4af5767 Mon Sep 17 00:00:00 2001 From: Bibek Basu Date: Fri, 14 Aug 2015 20:44:02 +0200 Subject: [PATCH 79/90] rtc: as3722: correct month value The RTC month value is 1-indexed, but the kernel assumes it is 0-indexed. This may result in the RTC not rolling over correctly. Signed-off-by: Bibek Basu Signed-off-by: Felix Janda Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-as3722.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-as3722.c b/drivers/rtc/rtc-as3722.c index 9f38eda69154..56cc5821118b 100644 --- a/drivers/rtc/rtc-as3722.c +++ b/drivers/rtc/rtc-as3722.c @@ -45,7 +45,7 @@ static void as3722_time_to_reg(u8 *rbuff, struct rtc_time *tm) rbuff[1] = bin2bcd(tm->tm_min); rbuff[2] = bin2bcd(tm->tm_hour); rbuff[3] = bin2bcd(tm->tm_mday); - rbuff[4] = bin2bcd(tm->tm_mon); + rbuff[4] = bin2bcd(tm->tm_mon + 1); rbuff[5] = bin2bcd(tm->tm_year - (AS3722_RTC_START_YEAR - 1900)); } @@ -55,7 +55,7 @@ static void as3722_reg_to_time(u8 *rbuff, struct rtc_time *tm) tm->tm_min = bcd2bin(rbuff[1] & 0x7F); tm->tm_hour = bcd2bin(rbuff[2] & 0x3F); tm->tm_mday = bcd2bin(rbuff[3] & 0x3F); - tm->tm_mon = bcd2bin(rbuff[4] & 0x1F); + tm->tm_mon = bcd2bin(rbuff[4] & 0x1F) - 1; tm->tm_year = (AS3722_RTC_START_YEAR - 1900) + bcd2bin(rbuff[5] & 0x7F); return; } From 12ece40d9196e01961192fc25cfdaf22392520de Mon Sep 17 00:00:00 2001 From: Suneel Garapati Date: Wed, 19 Aug 2015 15:23:21 +0530 Subject: [PATCH 80/90] devicetree: bindings: rtc: add bindings for xilinx zynqmp rtc adds file for description on device node bindings for RTC found on Xilinx Zynq Ultrascale+ MPSoC. Signed-off-by: Suneel Garapati Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/xlnx-rtc.txt | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 Documentation/devicetree/bindings/rtc/xlnx-rtc.txt diff --git a/Documentation/devicetree/bindings/rtc/xlnx-rtc.txt b/Documentation/devicetree/bindings/rtc/xlnx-rtc.txt new file mode 100644 index 000000000000..0df6f016b1b7 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/xlnx-rtc.txt @@ -0,0 +1,25 @@ +* Xilinx Zynq Ultrascale+ MPSoC Real Time Clock + +RTC controller for the Xilinx Zynq MPSoC Real Time Clock +Separate IRQ lines for seconds and alarm + +Required properties: +- compatible: Should be "xlnx,zynqmp-rtc" +- reg: Physical base address of the controller and length + of memory mapped region. +- interrupts: IRQ lines for the RTC. +- interrupt-names: interrupt line names eg. "sec" "alarm" + +Optional: +- calibration: calibration value for 1 sec period which will + be programmed directly to calibration register + +Example: +rtc: rtc@ffa60000 { + compatible = "xlnx,zynqmp-rtc"; + reg = <0x0 0xffa60000 0x100>; + interrupt-parent = <&gic>; + interrupts = <0 26 4>, <0 27 4>; + interrupt-names = "alarm", "sec"; + calibration = <0x198233>; +}; From 11143c19eb57a8aee4335e57b21f2897b9fff294 Mon Sep 17 00:00:00 2001 From: Suneel Garapati Date: Wed, 19 Aug 2015 15:23:22 +0530 Subject: [PATCH 81/90] rtc: add xilinx zynqmp rtc driver Add support for RTC controller found on Xilinx Zynq Ultrascale+ MPSoC platform. Signed-off-by: Suneel Garapati Acked-by: Moritz Fischer Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 7 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-zynqmp.c | 279 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 287 insertions(+) create mode 100644 drivers/rtc/rtc-zynqmp.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 0f65a222a48a..9d4290617cee 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1116,6 +1116,13 @@ config RTC_DRV_OPAL This driver can also be built as a module. If so, the module will be called rtc-opal. +config RTC_DRV_ZYNQMP + tristate "Xilinx Zynq Ultrascale+ MPSoC RTC" + depends on OF + help + If you say yes here you get support for the RTC controller found on + Xilinx Zynq Ultrascale+ MPSoC. + comment "on-CPU RTC drivers" config RTC_DRV_DAVINCI diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 279738449a8d..e491eb524434 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -159,3 +159,4 @@ obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o +obj-$(CONFIG_RTC_DRV_ZYNQMP) += rtc-zynqmp.o diff --git a/drivers/rtc/rtc-zynqmp.c b/drivers/rtc/rtc-zynqmp.c new file mode 100644 index 000000000000..8b28762f06df --- /dev/null +++ b/drivers/rtc/rtc-zynqmp.c @@ -0,0 +1,279 @@ +/* + * Xilinx Zynq Ultrascale+ MPSoC Real Time Clock Driver + * + * Copyright (C) 2015 Xilinx, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. If not, see . + * + */ + +#include +#include +#include +#include +#include +#include +#include + +/* RTC Registers */ +#define RTC_SET_TM_WR 0x00 +#define RTC_SET_TM_RD 0x04 +#define RTC_CALIB_WR 0x08 +#define RTC_CALIB_RD 0x0C +#define RTC_CUR_TM 0x10 +#define RTC_CUR_TICK 0x14 +#define RTC_ALRM 0x18 +#define RTC_INT_STS 0x20 +#define RTC_INT_MASK 0x24 +#define RTC_INT_EN 0x28 +#define RTC_INT_DIS 0x2C +#define RTC_CTRL 0x40 + +#define RTC_FR_EN BIT(20) +#define RTC_FR_DATSHIFT 16 +#define RTC_TICK_MASK 0xFFFF +#define RTC_INT_SEC BIT(0) +#define RTC_INT_ALRM BIT(1) +#define RTC_OSC_EN BIT(24) + +#define RTC_CALIB_DEF 0x198233 +#define RTC_CALIB_MASK 0x1FFFFF +#define RTC_SEC_MAX_VAL 0xFFFFFFFF + +struct xlnx_rtc_dev { + struct rtc_device *rtc; + void __iomem *reg_base; + int alarm_irq; + int sec_irq; +}; + +static int xlnx_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); + unsigned long new_time; + + new_time = rtc_tm_to_time64(tm); + + if (new_time > RTC_SEC_MAX_VAL) + return -EINVAL; + + writel(new_time, xrtcdev->reg_base + RTC_SET_TM_WR); + + return 0; +} + +static int xlnx_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); + + rtc_time64_to_tm(readl(xrtcdev->reg_base + RTC_CUR_TM), tm); + + return rtc_valid_tm(tm); +} + +static int xlnx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); + + rtc_time64_to_tm(readl(xrtcdev->reg_base + RTC_ALRM), &alrm->time); + alrm->enabled = readl(xrtcdev->reg_base + RTC_INT_MASK) & RTC_INT_ALRM; + + return 0; +} + +static int xlnx_rtc_alarm_irq_enable(struct device *dev, u32 enabled) +{ + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); + + if (enabled) + writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_EN); + else + writel(RTC_INT_ALRM, xrtcdev->reg_base + RTC_INT_DIS); + + return 0; +} + +static int xlnx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev); + unsigned long alarm_time; + + alarm_time = rtc_tm_to_time64(&alrm->time); + + if (alarm_time > RTC_SEC_MAX_VAL) + return -EINVAL; + + writel((u32)alarm_time, (xrtcdev->reg_base + RTC_ALRM)); + + xlnx_rtc_alarm_irq_enable(dev, alrm->enabled); + + return 0; +} + +static void xlnx_init_rtc(struct xlnx_rtc_dev *xrtcdev, u32 calibval) +{ + /* + * Based on crystal freq of 33.330 KHz + * set the seconds counter and enable, set fractions counter + * to default value suggested as per design spec + * to correct RTC delay in frequency over period of time. + */ + calibval &= RTC_CALIB_MASK; + writel(calibval, (xrtcdev->reg_base + RTC_CALIB_WR)); +} + +static const struct rtc_class_ops xlnx_rtc_ops = { + .set_time = xlnx_rtc_set_time, + .read_time = xlnx_rtc_read_time, + .read_alarm = xlnx_rtc_read_alarm, + .set_alarm = xlnx_rtc_set_alarm, + .alarm_irq_enable = xlnx_rtc_alarm_irq_enable, +}; + +static irqreturn_t xlnx_rtc_interrupt(int irq, void *id) +{ + struct xlnx_rtc_dev *xrtcdev = (struct xlnx_rtc_dev *)id; + unsigned int status; + + status = readl(xrtcdev->reg_base + RTC_INT_STS); + /* Check if interrupt asserted */ + if (!(status & (RTC_INT_SEC | RTC_INT_ALRM))) + return IRQ_NONE; + + /* Clear interrupt */ + writel(status, xrtcdev->reg_base + RTC_INT_STS); + + if (status & RTC_INT_SEC) + rtc_update_irq(xrtcdev->rtc, 1, RTC_IRQF | RTC_UF); + if (status & RTC_INT_ALRM) + rtc_update_irq(xrtcdev->rtc, 1, RTC_IRQF | RTC_AF); + + return IRQ_HANDLED; +} + +static int xlnx_rtc_probe(struct platform_device *pdev) +{ + struct xlnx_rtc_dev *xrtcdev; + struct resource *res; + int ret; + unsigned int calibvalue; + + xrtcdev = devm_kzalloc(&pdev->dev, sizeof(*xrtcdev), GFP_KERNEL); + if (!xrtcdev) + return -ENOMEM; + + platform_set_drvdata(pdev, xrtcdev); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + xrtcdev->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(xrtcdev->reg_base)) + return PTR_ERR(xrtcdev->reg_base); + + xrtcdev->alarm_irq = platform_get_irq_byname(pdev, "alarm"); + if (xrtcdev->alarm_irq < 0) { + dev_err(&pdev->dev, "no irq resource\n"); + return xrtcdev->alarm_irq; + } + ret = devm_request_irq(&pdev->dev, xrtcdev->alarm_irq, + xlnx_rtc_interrupt, 0, + dev_name(&pdev->dev), xrtcdev); + if (ret) { + dev_err(&pdev->dev, "request irq failed\n"); + return ret; + } + + xrtcdev->sec_irq = platform_get_irq_byname(pdev, "sec"); + if (xrtcdev->sec_irq < 0) { + dev_err(&pdev->dev, "no irq resource\n"); + return xrtcdev->sec_irq; + } + ret = devm_request_irq(&pdev->dev, xrtcdev->sec_irq, + xlnx_rtc_interrupt, 0, + dev_name(&pdev->dev), xrtcdev); + if (ret) { + dev_err(&pdev->dev, "request irq failed\n"); + return ret; + } + + ret = of_property_read_u32(pdev->dev.of_node, "calibration", + &calibvalue); + if (ret) + calibvalue = RTC_CALIB_DEF; + + xlnx_init_rtc(xrtcdev, calibvalue); + + device_init_wakeup(&pdev->dev, 1); + + xrtcdev->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, + &xlnx_rtc_ops, THIS_MODULE); + return PTR_ERR_OR_ZERO(xrtcdev->rtc); +} + +static int xlnx_rtc_remove(struct platform_device *pdev) +{ + xlnx_rtc_alarm_irq_enable(&pdev->dev, 0); + device_init_wakeup(&pdev->dev, 0); + + return 0; +} + +static int __maybe_unused xlnx_rtc_suspend(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xlnx_rtc_dev *xrtcdev = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + enable_irq_wake(xrtcdev->alarm_irq); + else + xlnx_rtc_alarm_irq_enable(dev, 0); + + return 0; +} + +static int __maybe_unused xlnx_rtc_resume(struct device *dev) +{ + struct platform_device *pdev = to_platform_device(dev); + struct xlnx_rtc_dev *xrtcdev = platform_get_drvdata(pdev); + + if (device_may_wakeup(&pdev->dev)) + disable_irq_wake(xrtcdev->alarm_irq); + else + xlnx_rtc_alarm_irq_enable(dev, 1); + + return 0; +} + +static SIMPLE_DEV_PM_OPS(xlnx_rtc_pm_ops, xlnx_rtc_suspend, xlnx_rtc_resume); + +static const struct of_device_id xlnx_rtc_of_match[] = { + {.compatible = "xlnx,zynqmp-rtc" }, + { } +}; +MODULE_DEVICE_TABLE(of, xlnx_rtc_of_match); + +static struct platform_driver xlnx_rtc_driver = { + .probe = xlnx_rtc_probe, + .remove = xlnx_rtc_remove, + .driver = { + .name = KBUILD_MODNAME, + .pm = &xlnx_rtc_pm_ops, + .of_match_table = xlnx_rtc_of_match, + }, +}; + +module_platform_driver(xlnx_rtc_driver); + +MODULE_DESCRIPTION("Xilinx Zynq MPSoC RTC driver"); +MODULE_AUTHOR("Xilinx Inc."); +MODULE_LICENSE("GPL v2"); From ff02c0444b83201ff76cc49deccac8cf2bffc7bc Mon Sep 17 00:00:00 2001 From: Joonyoung Shim Date: Fri, 21 Aug 2015 18:43:41 +0900 Subject: [PATCH 82/90] rtc: s5m: fix to update ctrl register According to datasheet, the S2MPS13X and S2MPS14X should update write buffer via setting WUDR bit to high after ctrl register is written. If not, ALARM interrupt of rtc-s5m doesn't happen first time when i use tools/testing/selftests/timers/rtctest.c test program and hour format is used to 12 hour mode in Odroid-XU3 board. One more issue is the RTC doesn't keep time on Odroid-XU3 board when i turn on board after power off even if RTC battery is connected. It can be solved as setting WUDR & RUDR bits to high at the same time after RTC_CTRL register is written. It's same with condition of only writing ALARM registers, so this is for only S2MPS14 and we should set WUDR & A_UDR bits to high on S2MPS13. I can't find any reasonable description about this like fix from datasheet, but can find similar codes from rtc driver source of hardkernel kernel and vendor kernel. Signed-off-by: Joonyoung Shim Cc: # v3.16 Reviewed-by: Krzysztof Kozlowski Tested-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s5m.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index 8c70d785ba73..ab60287ee72d 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -635,6 +635,16 @@ static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) case S2MPS13X: data[0] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); ret = regmap_write(info->regmap, info->regs->ctrl, data[0]); + if (ret < 0) + break; + + /* + * Should set WUDR & (RUDR or AUDR) bits to high after writing + * RTC_CTRL register like writing Alarm registers. We can't find + * the description from datasheet but vendor code does that + * really. + */ + ret = s5m8767_rtc_set_alarm_reg(info); break; default: From fff51e771eafc3b4fa6daf1372fd4a4023bb402b Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 18 Aug 2015 15:11:14 +0530 Subject: [PATCH 83/90] ARM: dts: AM437x: Add the internal and external clock nodes for rtc rtc can either be supplied from internal 32k clock or external crystal generated 32k clock. Internal clock is SOC specific and the external clock is board dependent. Adding the corresponding nodes. Signed-off-by: Keerthy Acked-by: Tony Lindgren Signed-off-by: Alexandre Belloni --- Documentation/devicetree/bindings/rtc/rtc-omap.txt | 4 ++++ arch/arm/boot/dts/am4372.dtsi | 2 ++ arch/arm/boot/dts/am437x-gp-evm.dts | 13 +++++++++++++ arch/arm/boot/dts/am437x-idk-evm.dts | 9 +++++++++ arch/arm/boot/dts/am437x-sk-evm.dts | 9 +++++++++ 5 files changed, 37 insertions(+) diff --git a/Documentation/devicetree/bindings/rtc/rtc-omap.txt b/Documentation/devicetree/bindings/rtc/rtc-omap.txt index 43a83668673a..bf7d11ae9bea 100644 --- a/Documentation/devicetree/bindings/rtc/rtc-omap.txt +++ b/Documentation/devicetree/bindings/rtc/rtc-omap.txt @@ -16,6 +16,8 @@ Required properties: Optional properties: - system-power-controller: whether the rtc is controlling the system power through pmic_power_en +- clocks: Any internal or external clocks feeding in to rtc +- clock-names: Corresponding names of the clocks Example: @@ -26,4 +28,6 @@ rtc@1c23000 { 19>; interrupt-parent = <&intc>; system-power-controller; + clocks = <&clk_32k_rtc>, <&clk_32768_ck>; + clock-names = "ext-clk", "int-clk"; }; diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi index 564900b9fcce..0447c04a40cc 100644 --- a/arch/arm/boot/dts/am4372.dtsi +++ b/arch/arm/boot/dts/am4372.dtsi @@ -358,6 +358,8 @@ interrupts = ; ti,hwmods = "rtc"; + clocks = <&clk_32768_ck>; + clock-names = "int-clk"; status = "disabled"; }; diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts index 215775dc6948..22038f21f228 100644 --- a/arch/arm/boot/dts/am437x-gp-evm.dts +++ b/arch/arm/boot/dts/am437x-gp-evm.dts @@ -112,6 +112,13 @@ clock-frequency = <12000000>; }; + /* fixed 32k external oscillator clock */ + clk_32k_rtc: clk_32k_rtc { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + sound0: sound@0 { compatible = "simple-audio-card"; simple-audio-card,name = "AM437x-GP-EVM"; @@ -941,3 +948,9 @@ tx-num-evt = <32>; rx-num-evt = <32>; }; + +&rtc { + clocks = <&clk_32k_rtc>, <&clk_32768_ck>; + clock-names = "ext-clk", "int-clk"; + status = "okay"; +}; diff --git a/arch/arm/boot/dts/am437x-idk-evm.dts b/arch/arm/boot/dts/am437x-idk-evm.dts index 378344271746..af25801418b4 100644 --- a/arch/arm/boot/dts/am437x-idk-evm.dts +++ b/arch/arm/boot/dts/am437x-idk-evm.dts @@ -110,6 +110,13 @@ gpios = <&gpio4 2 GPIO_ACTIVE_LOW>; }; }; + + /* fixed 32k external oscillator clock */ + clk_32k_rtc: clk_32k_rtc { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; }; &am43xx_pinmux { @@ -394,6 +401,8 @@ }; &rtc { + clocks = <&clk_32k_rtc>, <&clk_32768_ck>; + clock-names = "ext-clk", "int-clk"; status = "okay"; }; diff --git a/arch/arm/boot/dts/am437x-sk-evm.dts b/arch/arm/boot/dts/am437x-sk-evm.dts index 22af44894c66..7da7c2da4af1 100644 --- a/arch/arm/boot/dts/am437x-sk-evm.dts +++ b/arch/arm/boot/dts/am437x-sk-evm.dts @@ -24,6 +24,13 @@ display0 = &lcd0; }; + /* fixed 32k external oscillator clock */ + clk_32k_rtc: clk_32k_rtc { + #clock-cells = <0>; + compatible = "fixed-clock"; + clock-frequency = <32768>; + }; + backlight { compatible = "pwm-backlight"; pwms = <&ecap0 0 50000 PWM_POLARITY_INVERTED>; @@ -697,6 +704,8 @@ }; &rtc { + clocks = <&clk_32k_rtc>, <&clk_32768_ck>; + clock-names = "ext-clk", "int-clk"; status = "okay"; }; From 532409aa1ba8b69d5a3dea159d4b1bd9adbd7a46 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 18 Aug 2015 15:11:15 +0530 Subject: [PATCH 84/90] rtc: omap: Add internal clock enabling support The rtc can be clocked by an internal 32K clock. Adding the support to enable the same. Signed-off-by: Keerthy Acked-by: Tony Lindgren Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-omap.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 8b6355ffaff9..f31c0127dae0 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -25,6 +25,7 @@ #include #include #include +#include /* * The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock @@ -132,6 +133,7 @@ struct omap_rtc_device_type { struct omap_rtc { struct rtc_device *rtc; void __iomem *base; + struct clk *clk; int irq_alarm; int irq_timer; u8 interrupts_reg; @@ -553,6 +555,11 @@ static int omap_rtc_probe(struct platform_device *pdev) if (rtc->irq_alarm <= 0) return -ENOENT; + rtc->clk = devm_clk_get(&pdev->dev, "int-clk"); + + if (!IS_ERR(rtc->clk)) + clk_prepare_enable(rtc->clk); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); rtc->base = devm_ioremap_resource(&pdev->dev, res); if (IS_ERR(rtc->base)) @@ -681,6 +688,9 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 0); + if (!IS_ERR(rtc->clk)) + clk_disable_unprepare(rtc->clk); + rtc->type->unlock(rtc); /* leave rtc running, but disable irqs */ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0); From 399cf0f63f6f24d7a837fbfbc801010cb6e77579 Mon Sep 17 00:00:00 2001 From: Keerthy Date: Tue, 18 Aug 2015 15:11:16 +0530 Subject: [PATCH 85/90] rtc: omap: Add external clock enabling support Configure the clock source to external clock if available. External clock is preferred as it can be ticking during suspend. Signed-off-by: Keerthy Acked-by: Tony Lindgren Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-omap.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index f31c0127dae0..ec2e9c5fb993 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -108,6 +108,7 @@ /* OMAP_RTC_OSC_REG bit fields: */ #define OMAP_RTC_OSC_32KCLK_EN BIT(6) +#define OMAP_RTC_OSC_SEL_32KCLK_SRC BIT(3) /* OMAP_RTC_IRQWAKEEN bit fields: */ #define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN BIT(1) @@ -138,6 +139,7 @@ struct omap_rtc { int irq_timer; u8 interrupts_reg; bool is_pmic_controller; + bool has_ext_clk; const struct omap_rtc_device_type *type; }; @@ -555,7 +557,11 @@ static int omap_rtc_probe(struct platform_device *pdev) if (rtc->irq_alarm <= 0) return -ENOENT; - rtc->clk = devm_clk_get(&pdev->dev, "int-clk"); + rtc->clk = devm_clk_get(&pdev->dev, "ext-clk"); + if (!IS_ERR(rtc->clk)) + rtc->has_ext_clk = true; + else + rtc->clk = devm_clk_get(&pdev->dev, "int-clk"); if (!IS_ERR(rtc->clk)) clk_prepare_enable(rtc->clk); @@ -634,6 +640,16 @@ static int omap_rtc_probe(struct platform_device *pdev) if (reg != new_ctrl) rtc_write(rtc, OMAP_RTC_CTRL_REG, new_ctrl); + /* + * If we have the external clock then switch to it so we can keep + * ticking across suspend. + */ + if (rtc->has_ext_clk) { + reg = rtc_read(rtc, OMAP_RTC_OSC_REG); + rtc_write(rtc, OMAP_RTC_OSC_REG, + reg | OMAP_RTC_OSC_SEL_32KCLK_SRC); + } + rtc->type->lock(rtc); device_init_wakeup(&pdev->dev, true); @@ -679,6 +695,7 @@ err: static int __exit omap_rtc_remove(struct platform_device *pdev) { struct omap_rtc *rtc = platform_get_drvdata(pdev); + u8 reg; if (pm_power_off == omap_rtc_power_off && omap_rtc_power_off_rtc == rtc) { @@ -695,6 +712,12 @@ static int __exit omap_rtc_remove(struct platform_device *pdev) /* leave rtc running, but disable irqs */ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0); + if (rtc->has_ext_clk) { + reg = rtc_read(rtc, OMAP_RTC_OSC_REG); + reg &= ~OMAP_RTC_OSC_SEL_32KCLK_SRC; + rtc_write(rtc, OMAP_RTC_OSC_REG, reg); + } + rtc->type->lock(rtc); /* Disable the clock/module */ From 63074cc3d4b8367aa6d9dc5520b88ca6557d32fa Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 27 Aug 2015 12:34:32 +0200 Subject: [PATCH 86/90] rtc: Fix module autoload for rtc-{ab8500,max8997,s5m} drivers These platform drivers have a platform device ID table but the module alias information is not created so module autoloading will not work. Signed-off-by: Javier Martinez Canillas Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ab8500.c | 1 + drivers/rtc/rtc-max8997.c | 1 + drivers/rtc/rtc-s5m.c | 1 + 3 files changed, 3 insertions(+) diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 133d2e2e1a25..8537d1e3a995 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -446,6 +446,7 @@ static const struct platform_device_id ab85xx_rtc_ids[] = { { "ab8500-rtc", (kernel_ulong_t)&ab8500_rtc_ops, }, { "ab8540-rtc", (kernel_ulong_t)&ab8540_rtc_ops, }, }; +MODULE_DEVICE_TABLE(platform, ab85xx_rtc_ids); static int ab8500_rtc_probe(struct platform_device *pdev) { diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c index 9e02bcda0c09..db984d4bf952 100644 --- a/drivers/rtc/rtc-max8997.c +++ b/drivers/rtc/rtc-max8997.c @@ -521,6 +521,7 @@ static const struct platform_device_id rtc_id[] = { { "max8997-rtc", 0 }, {}, }; +MODULE_DEVICE_TABLE(platform, rtc_id); static struct platform_driver max8997_rtc_driver = { .driver = { diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c index ab60287ee72d..f2504b4eef34 100644 --- a/drivers/rtc/rtc-s5m.c +++ b/drivers/rtc/rtc-s5m.c @@ -807,6 +807,7 @@ static const struct platform_device_id s5m_rtc_id[] = { { "s2mps14-rtc", S2MPS14X }, { }, }; +MODULE_DEVICE_TABLE(platform, s5m_rtc_id); static struct platform_driver s5m_rtc_driver = { .driver = { From 73798d5c41fdb434ccbeeec76afc8106869a98c3 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Thu, 27 Aug 2015 13:52:02 +0200 Subject: [PATCH 87/90] rtc: Fix module autoload for OF platform drivers These platform drivers have a OF device ID table but the OF module alias information is not created so module autoloading won't work. Signed-off-by: Javier Martinez Canillas Acked-by: Andrew Lunn Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-armada38x.c | 1 + drivers/rtc/rtc-coh901331.c | 1 + drivers/rtc/rtc-da9063.c | 1 + drivers/rtc/rtc-moxart.c | 1 + drivers/rtc/rtc-mpc5121.c | 1 + drivers/rtc/rtc-mt6397.c | 1 + drivers/rtc/rtc-mv.c | 1 + drivers/rtc/rtc-vt8500.c | 1 + 8 files changed, 8 insertions(+) diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c index 06c6bd5eab41..9a3f2a6f512e 100644 --- a/drivers/rtc/rtc-armada38x.c +++ b/drivers/rtc/rtc-armada38x.c @@ -295,6 +295,7 @@ static const struct of_device_id armada38x_rtc_of_match_table[] = { { .compatible = "marvell,armada-380-rtc", }, {} }; +MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table); #endif static struct platform_driver armada38x_rtc_driver = { diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index 56343b2fbc68..101b7a240e0f 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -263,6 +263,7 @@ static const struct of_device_id coh901331_dt_match[] = { { .compatible = "stericsson,coh901331" }, {}, }; +MODULE_DEVICE_TABLE(of, coh901331_dt_match); static struct platform_driver coh901331_driver = { .driver = { diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c index 5f38a5c84b56..00a8f7f4f87c 100644 --- a/drivers/rtc/rtc-da9063.c +++ b/drivers/rtc/rtc-da9063.c @@ -169,6 +169,7 @@ static const struct of_device_id da9063_compatible_reg_id_table[] = { { .compatible = "dlg,da9062-rtc", .data = &da9062_aa_regs }, { }, }; +MODULE_DEVICE_TABLE(of, da9063_compatible_reg_id_table); static void da9063_data_to_tm(u8 *data, struct rtc_time *tm, struct da9063_compatible_rtc *rtc) diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c index 73759c9a4527..07b30a373a92 100644 --- a/drivers/rtc/rtc-moxart.c +++ b/drivers/rtc/rtc-moxart.c @@ -312,6 +312,7 @@ static const struct of_device_id moxart_rtc_match[] = { { .compatible = "moxa,moxart-rtc" }, { }, }; +MODULE_DEVICE_TABLE(of, moxart_rtc_match); static struct platform_driver moxart_rtc_driver = { .probe = moxart_rtc_probe, diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index 1767e18d5bd4..4ca4daa0b8f3 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -406,6 +406,7 @@ static const struct of_device_id mpc5121_rtc_match[] = { { .compatible = "fsl,mpc5200-rtc", }, {}, }; +MODULE_DEVICE_TABLE(of, mpc5121_rtc_match); #endif static struct platform_driver mpc5121_rtc_driver = { diff --git a/drivers/rtc/rtc-mt6397.c b/drivers/rtc/rtc-mt6397.c index 30c926b36361..06a5c52b292f 100644 --- a/drivers/rtc/rtc-mt6397.c +++ b/drivers/rtc/rtc-mt6397.c @@ -402,6 +402,7 @@ static const struct of_device_id mt6397_rtc_of_match[] = { { .compatible = "mediatek,mt6397-rtc", }, { } }; +MODULE_DEVICE_TABLE(of, mt6397_rtc_of_match); static struct platform_driver mtk_rtc_driver = { .driver = { diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index 7f50d2ef7f6e..79bb28617d45 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -324,6 +324,7 @@ static const struct of_device_id rtc_mv_of_match_table[] = { { .compatible = "marvell,orion-rtc", }, {} }; +MODULE_DEVICE_TABLE(of, rtc_mv_of_match_table); #endif static struct platform_driver mv_rtc_driver = { diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index a58b6d17e6f0..27e896995e9b 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -271,6 +271,7 @@ static const struct of_device_id wmt_dt_ids[] = { { .compatible = "via,vt8500-rtc", }, {} }; +MODULE_DEVICE_TABLE(of, wmt_dt_ids); static struct platform_driver vt8500_rtc_driver = { .probe = vt8500_rtc_probe, From d78908d9717b627a261b1bfe6feb67181e12752e Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Mon, 10 Aug 2015 09:47:45 -0300 Subject: [PATCH 88/90] rtc: ds1374: Remove unused variable Remove unused variable 'res' and fix the following build warning: drivers/rtc/rtc-ds1374.c:667:6: warning: unused variable 'res' [-Wunused-variable] Reported-by: Olof's autobuilder Signed-off-by: Fabio Estevam Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1374.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 7067232ba507..3b3049c8c9e0 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -664,8 +664,6 @@ static int ds1374_remove(struct i2c_client *client) { struct ds1374 *ds1374 = i2c_get_clientdata(client); #ifdef CONFIG_RTC_DRV_DS1374_WDT - int res; - misc_deregister(&ds1374_miscdev); ds1374_miscdev.parent = NULL; unregister_reboot_notifier(&ds1374_wdt_notifier); From 8a67e93153f03a8d205727c0aeacb5524a414f77 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Fri, 4 Sep 2015 08:58:05 -0300 Subject: [PATCH 89/90] rtc: ab8500: Add a sentinel to ab85xx_rtc_ids[] Add a sentinel to ab85xx_rtc_ids[] in order to fix the following error: drivers/rtc/rtc-ab8500: struct platform_device_id is 24 bytes. The last of 2 is: 0x61 0x62 0x38 0x35 0x34 0x30 0x2d 0x72 0x74 0x63 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x8c FATAL: drivers/rtc/rtc-ab8500: struct platform_device_id is not terminated with a NULL entry! Reported-by: Andrey Ryabinin Reported-by: Olof's autobuilder Signed-off-by: Fabio Estevam Reviewed-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ab8500.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 8537d1e3a995..51407c4c7bd2 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -445,6 +445,7 @@ static const struct rtc_class_ops ab8540_rtc_ops = { static const struct platform_device_id ab85xx_rtc_ids[] = { { "ab8500-rtc", (kernel_ulong_t)&ab8500_rtc_ops, }, { "ab8540-rtc", (kernel_ulong_t)&ab8540_rtc_ops, }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(platform, ab85xx_rtc_ids); From 5f1b2f77646fc0ef2f36fc554f5722a1381d0892 Mon Sep 17 00:00:00 2001 From: Mitja Spes Date: Wed, 2 Sep 2015 10:02:29 +0200 Subject: [PATCH 90/90] rtc: abx80x: fix RTC write bit Fix RTC write bit as per application manual Cc: stable@vger.kernel.org # 4.1+ Signed-off-by: Mitja Spes Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-abx80x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index 4337c3bc6ace..afea84c7a155 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -28,7 +28,7 @@ #define ABX8XX_REG_WD 0x07 #define ABX8XX_REG_CTRL1 0x10 -#define ABX8XX_CTRL_WRITE BIT(1) +#define ABX8XX_CTRL_WRITE BIT(0) #define ABX8XX_CTRL_12_24 BIT(6) #define ABX8XX_REG_CFG_KEY 0x1f