From 2fb07a10e0aa699ddb12aba1459208579bdc9802 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Tue, 23 Jun 2015 11:15:10 -0500 Subject: 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(-) (limited to 'drivers') 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); -- cgit v1.2.3 From c5983191362af5ef7a627d8811a45f0fd01a3582 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 23 Jun 2015 11:15:11 -0500 Subject: 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(-) (limited to 'drivers') 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); -- cgit v1.2.3 From eac7237fd8432e232af3c407e667dbdc17ebf1d8 Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Tue, 23 Jun 2015 11:15:12 -0500 Subject: 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 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers') 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 /* * We can't determine type by probing, but if we expect pre-Linux code -- cgit v1.2.3 From 7abea617a4bae178da0f42983998c779ec2f732d Mon Sep 17 00:00:00 2001 From: Nishanth Menon Date: Wed, 24 Jun 2015 11:26:54 -0500 Subject: 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(-) (limited to 'drivers') 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); -- cgit v1.2.3 From 508db592e2f54d731bf2f5eabd9642a1a566f276 Mon Sep 17 00:00:00 2001 From: Vaishali Thakkar Date: Tue, 7 Jul 2015 11:16:14 +0530 Subject: 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(-) (limited to 'drivers') 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); /* ----------------------------------------------------------------------- */ -- cgit v1.2.3 From 617f6f7ef5bfe8c0ac580243c3da9a836c6e39bf Mon Sep 17 00:00:00 2001 From: Maninder Singh Date: Wed, 8 Jul 2015 12:26:47 +0530 Subject: 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(-) (limited to 'drivers') 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, -- cgit v1.2.3 From 4ab82103131777b9aabb6ba31aead6e5b0293b32 Mon Sep 17 00:00:00 2001 From: Vaibhav Hiremath Date: Thu, 9 Jul 2015 12:25:51 +0530 Subject: 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(-) (limited to 'drivers') 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); -- cgit v1.2.3 From 821f51c4da869706356ddecfeeac286bf4df9b98 Mon Sep 17 00:00:00 2001 From: Andrea Scian Date: Tue, 16 Jun 2015 11:35:19 +0200 Subject: 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(-) (limited to 'drivers') 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) -- cgit v1.2.3 From 653ebd75e9e469e99a40ab14128d915386dc78c6 Mon Sep 17 00:00:00 2001 From: Andrea Scian Date: Tue, 16 Jun 2015 11:39:47 +0200 Subject: 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(-) (limited to 'drivers') 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))) -- cgit v1.2.3 From b28845433eb9c205c381ed69b09167d6ae5aac1c Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:39:50 +0900 Subject: 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(-) (limited to 'drivers') 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, -- cgit v1.2.3 From 045c6fdd37a01d950c0f5ca64733b53b184fe91b Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 15:39:51 +0900 Subject: 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(-) (limited to 'drivers') 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, }, }; -- cgit v1.2.3 From c28b42e3aee03fe869a3f73039cf92686ccbc8fb Mon Sep 17 00:00:00 2001 From: Joachim Eastwood Date: Sat, 11 Jul 2015 19:28:49 +0200 Subject: 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 (limited to 'drivers') 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"); -- cgit v1.2.3 From f4a2eecb3ff9f51b179b213e7cc3766f920f2dc5 Mon Sep 17 00:00:00 2001 From: Vaibhav Jain Date: Tue, 14 Jul 2015 13:28:28 +0530 Subject: 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(-) (limited to 'drivers') 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); -- cgit v1.2.3 From dfe6c04aa289de06df95d888719af63d1d4c982d Mon Sep 17 00:00:00 2001 From: Guo Zeng Date: Tue, 14 Jul 2015 01:31:38 +0000 Subject: 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(-) (limited to 'drivers') 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); -- cgit v1.2.3 From 6706664d92ea841913d5fcfd06c290fbe6d33bd2 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 20 Jul 2015 16:02:49 -0700 Subject: 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(-) (limited to 'drivers') 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); -- cgit v1.2.3 From c3b399a4b6703a04ef6eb3efe35ff12163e409e0 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 20 Jul 2015 16:02:50 -0700 Subject: 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(-) (limited to 'drivers') 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); -- cgit v1.2.3 From 1e4cd62558c293bc51cc179d676b708683a29c12 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Mon, 20 Jul 2015 16:02:51 -0700 Subject: 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(+) (limited to 'drivers') 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) -- cgit v1.2.3 From 0d9030a2c3214cf8f9bfff84204e0f5ba5e790d7 Mon Sep 17 00:00:00 2001 From: Octavian Purdila Date: Fri, 5 Jun 2015 16:59:43 +0300 Subject: 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(-) (limited to 'drivers') 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); -- cgit v1.2.3 From f2284f9c900a47961883b88064933a89b5dd5f46 Mon Sep 17 00:00:00 2001 From: Henri Roosen Date: Fri, 24 Jul 2015 10:16:06 +0200 Subject: 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(-) (limited to 'drivers') 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 */ -- cgit v1.2.3 From df100c017ea9f1a6a517c3fba84f8507973c004e Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Thu, 23 Jul 2015 16:01:06 -0700 Subject: 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