From 4cd0ca1fe9a79d81a001ff14f14035531773fe43 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Fri, 18 Nov 2022 23:44:54 +0100 Subject: rtc: ds1307: Convert to i2c's .probe_new() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit .probe_new() doesn't get the i2c_device_id * parameter, so determine that explicitly in the probe function. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20221118224540.619276-561-uwe@kleine-koenig.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index def9b7f9d957..e86ba84df6cb 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -1712,9 +1712,9 @@ static const struct regmap_config regmap_config = { .val_bits = 8, }; -static int ds1307_probe(struct i2c_client *client, - const struct i2c_device_id *id) +static int ds1307_probe(struct i2c_client *client) { + const struct i2c_device_id *id = i2c_client_get_device_id(client); struct ds1307 *ds1307; const void *match; int err = -ENODEV; @@ -2011,7 +2011,7 @@ static struct i2c_driver ds1307_driver = { .name = "rtc-ds1307", .of_match_table = ds1307_of_match, }, - .probe = ds1307_probe, + .probe_new = ds1307_probe, .id_table = ds1307_id, }; -- cgit v1.2.3-70-g09d2 From 90226f6b17a3edcb0bddaf2f16991861c99d6a15 Mon Sep 17 00:00:00 2001 From: Doug Berger Date: Fri, 20 Jan 2023 11:01:42 -0800 Subject: rtc: brcmstb-waketimer: introduce WKTMR_ALARM_EVENT flag This commit defines bit 0 as the bit of interest within the BRCMSTB_WKTMR_EVENT register to make the implementation more readable. Signed-off-by: Doug Berger Acked-by: Florian Fainelli Link: https://lore.kernel.org/r/20230120190147.718976-2-opendmb@gmail.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-brcmstb-waketimer.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-brcmstb-waketimer.c b/drivers/rtc/rtc-brcmstb-waketimer.c index c74130e8f496..fbeb8be6664b 100644 --- a/drivers/rtc/rtc-brcmstb-waketimer.c +++ b/drivers/rtc/rtc-brcmstb-waketimer.c @@ -34,6 +34,7 @@ struct brcmstb_waketmr { }; #define BRCMSTB_WKTMR_EVENT 0x00 +#define WKTMR_ALARM_EVENT BIT(0) #define BRCMSTB_WKTMR_COUNTER 0x04 #define BRCMSTB_WKTMR_ALARM 0x08 #define BRCMSTB_WKTMR_PRESCALER 0x0C @@ -41,9 +42,17 @@ struct brcmstb_waketmr { #define BRCMSTB_WKTMR_DEFAULT_FREQ 27000000 +static inline bool brcmstb_waketmr_is_pending(struct brcmstb_waketmr *timer) +{ + u32 reg; + + reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT); + return !!(reg & WKTMR_ALARM_EVENT); +} + static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer) { - writel_relaxed(1, timer->base + BRCMSTB_WKTMR_EVENT); + writel_relaxed(WKTMR_ALARM_EVENT, timer->base + BRCMSTB_WKTMR_EVENT); (void)readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT); } @@ -147,7 +156,6 @@ static int brcmstb_waketmr_getalarm(struct device *dev, { struct brcmstb_waketmr *timer = dev_get_drvdata(dev); time64_t sec; - u32 reg; sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM); if (sec != 0) { @@ -156,8 +164,7 @@ static int brcmstb_waketmr_getalarm(struct device *dev, rtc_time64_to_tm(sec, &alarm->time); } - reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT); - alarm->pending = !!(reg & 1); + alarm->pending = brcmstb_waketmr_is_pending(timer); return 0; } -- cgit v1.2.3-70-g09d2 From 2cd98b22c1443d1f2921a371baee658da184868e Mon Sep 17 00:00:00 2001 From: Doug Berger Date: Fri, 20 Jan 2023 11:01:43 -0800 Subject: rtc: brcmstb-waketimer: non-functional code changes These changes are not intended to affect functionality, but simplify the source code. They are performed here to simplify review and reduce confusion with other changes in this set. Since set_alarm includes the alarm_irq_enable functionality call it directly from that function for simplicity (even though it does nothing at the moment). The order of the declarations is changed to prevent the need for a prototype. The function device_init_wakeup() is used to replace the functions device_set_wakeup_capable() and device_wakeup_enable() since it is equivalent. Signed-off-by: Doug Berger Acked-by: Florian Fainelli Link: https://lore.kernel.org/r/20230120190147.718976-3-opendmb@gmail.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-brcmstb-waketimer.c | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-brcmstb-waketimer.c b/drivers/rtc/rtc-brcmstb-waketimer.c index fbeb8be6664b..582c23793550 100644 --- a/drivers/rtc/rtc-brcmstb-waketimer.c +++ b/drivers/rtc/rtc-brcmstb-waketimer.c @@ -169,6 +169,16 @@ static int brcmstb_waketmr_getalarm(struct device *dev, return 0; } +/* + * Does not do much but keep the RTC class happy. We always support + * alarms. + */ +static int brcmstb_waketmr_alarm_enable(struct device *dev, + unsigned int enabled) +{ + return 0; +} + static int brcmstb_waketmr_setalarm(struct device *dev, struct rtc_wkalrm *alarm) { @@ -182,17 +192,7 @@ static int brcmstb_waketmr_setalarm(struct device *dev, brcmstb_waketmr_set_alarm(timer, sec); - return 0; -} - -/* - * Does not do much but keep the RTC class happy. We always support - * alarms. - */ -static int brcmstb_waketmr_alarm_enable(struct device *dev, - unsigned int enabled) -{ - return 0; + return brcmstb_waketmr_alarm_enable(dev, alarm->enabled); } static const struct rtc_class_ops brcmstb_waketmr_ops = { @@ -228,8 +228,7 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev) * Set wakeup capability before requesting wakeup interrupt, so we can * process boot-time "wakeups" (e.g., from S5 soft-off) */ - device_set_wakeup_capable(dev, true); - device_wakeup_enable(dev); + device_init_wakeup(dev, true); timer->irq = platform_get_irq(pdev, 0); if (timer->irq < 0) -- cgit v1.2.3-70-g09d2 From 516ae02c38ff3ae867f9b19fa050f78157e2bdae Mon Sep 17 00:00:00 2001 From: Doug Berger Date: Fri, 20 Jan 2023 11:01:44 -0800 Subject: rtc: brcmstb-waketimer: compensate for lack of wktmr disable Since the WKTMR hardware block cannot be disabled it is necessary for the driver to accommodate for associated timing hazards. This commit targets the following possibilities: A possible race between clearing a wktmr event and the alarm expiring is made one-sided by setting the alarm to its maximum value before clearing the event. Programming alarm values close to the current time may not trigger events if the counter advances while the alarm is being programmed. After programming an alarm, a check is made to ensure that it is either in the future or an expiration event is pending. Signed-off-by: Doug Berger Acked-by: Florian Fainelli Link: https://lore.kernel.org/r/20230120190147.718976-4-opendmb@gmail.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-brcmstb-waketimer.c | 52 ++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 18 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-brcmstb-waketimer.c b/drivers/rtc/rtc-brcmstb-waketimer.c index 582c23793550..c791e92532b8 100644 --- a/drivers/rtc/rtc-brcmstb-waketimer.c +++ b/drivers/rtc/rtc-brcmstb-waketimer.c @@ -31,6 +31,8 @@ struct brcmstb_waketmr { struct notifier_block reboot_notifier; struct clk *clk; u32 rate; + unsigned long rtc_alarm; + bool alarm_en; }; #define BRCMSTB_WKTMR_EVENT 0x00 @@ -52,6 +54,11 @@ static inline bool brcmstb_waketmr_is_pending(struct brcmstb_waketmr *timer) static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer) { + u32 reg; + + timer->alarm_en = false; + reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER); + writel_relaxed(reg - 1, timer->base + BRCMSTB_WKTMR_ALARM); writel_relaxed(WKTMR_ALARM_EVENT, timer->base + BRCMSTB_WKTMR_EVENT); (void)readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT); } @@ -59,12 +66,22 @@ static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer) static void brcmstb_waketmr_set_alarm(struct brcmstb_waketmr *timer, unsigned int secs) { + unsigned int now; + brcmstb_waketmr_clear_alarm(timer); /* Make sure we are actually counting in seconds */ writel_relaxed(timer->rate, timer->base + BRCMSTB_WKTMR_PRESCALER); - writel_relaxed(secs + 1, timer->base + BRCMSTB_WKTMR_ALARM); + writel_relaxed(secs, timer->base + BRCMSTB_WKTMR_ALARM); + now = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER); + + while ((int)(secs - now) <= 0 && + !brcmstb_waketmr_is_pending(timer)) { + secs = now + 1; + writel_relaxed(secs, timer->base + BRCMSTB_WKTMR_ALARM); + now = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER); + } } static irqreturn_t brcmstb_waketmr_irq(int irq, void *data) @@ -155,27 +172,30 @@ static int brcmstb_waketmr_getalarm(struct device *dev, struct rtc_wkalrm *alarm) { struct brcmstb_waketmr *timer = dev_get_drvdata(dev); - time64_t sec; - sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM); - if (sec != 0) { - /* Alarm is enabled */ - alarm->enabled = 1; - rtc_time64_to_tm(sec, &alarm->time); - } + alarm->enabled = timer->alarm_en; + rtc_time64_to_tm(timer->rtc_alarm, &alarm->time); alarm->pending = brcmstb_waketmr_is_pending(timer); return 0; } -/* - * Does not do much but keep the RTC class happy. We always support - * alarms. - */ static int brcmstb_waketmr_alarm_enable(struct device *dev, unsigned int enabled) { + struct brcmstb_waketmr *timer = dev_get_drvdata(dev); + + if (enabled && !timer->alarm_en) { + if ((int)(readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER) - + readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM)) >= 0 && + !brcmstb_waketmr_is_pending(timer)) + return -EINVAL; + timer->alarm_en = true; + } else if (!enabled && timer->alarm_en) { + timer->alarm_en = false; + } + return 0; } @@ -183,14 +203,10 @@ static int brcmstb_waketmr_setalarm(struct device *dev, struct rtc_wkalrm *alarm) { struct brcmstb_waketmr *timer = dev_get_drvdata(dev); - time64_t sec; - if (alarm->enabled) - sec = rtc_tm_to_time64(&alarm->time); - else - sec = 0; + timer->rtc_alarm = rtc_tm_to_time64(&alarm->time); - brcmstb_waketmr_set_alarm(timer, sec); + brcmstb_waketmr_set_alarm(timer, timer->rtc_alarm); return brcmstb_waketmr_alarm_enable(dev, alarm->enabled); } -- cgit v1.2.3-70-g09d2 From eae258edcb8705932c9e5c61a99f91d8235f688b Mon Sep 17 00:00:00 2001 From: Doug Berger Date: Fri, 20 Jan 2023 11:01:45 -0800 Subject: rtc: brcmstb-waketimer: rename irq to wake_irq In preparation for adding a second interrupt to service RTC interrupts, the existing interrupt is renamed from the generic 'irq' to 'wake_irq' to more clearly convey its role. It is also converted to an unsigned int. Finally, the driver message that outputs the IRQ number when registered is removed since devm_rtc_register_device() already provides a report of registration and the interrupts can be found in /proc/interrupts. Signed-off-by: Doug Berger Acked-by: Florian Fainelli Link: https://lore.kernel.org/r/20230120190147.718976-5-opendmb@gmail.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-brcmstb-waketimer.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-brcmstb-waketimer.c b/drivers/rtc/rtc-brcmstb-waketimer.c index c791e92532b8..e25f9fcd6ed1 100644 --- a/drivers/rtc/rtc-brcmstb-waketimer.c +++ b/drivers/rtc/rtc-brcmstb-waketimer.c @@ -27,7 +27,7 @@ struct brcmstb_waketmr { struct rtc_device *rtc; struct device *dev; void __iomem *base; - int irq; + unsigned int wake_irq; struct notifier_block reboot_notifier; struct clk *clk; u32 rate; @@ -117,7 +117,7 @@ static int brcmstb_waketmr_prepare_suspend(struct brcmstb_waketmr *timer) int ret = 0; if (device_may_wakeup(dev)) { - ret = enable_irq_wake(timer->irq); + ret = enable_irq_wake(timer->wake_irq); if (ret) { dev_err(dev, "failed to enable wake-up interrupt\n"); return ret; @@ -246,9 +246,10 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev) */ device_init_wakeup(dev, true); - timer->irq = platform_get_irq(pdev, 0); - if (timer->irq < 0) + ret = platform_get_irq(pdev, 0); + if (ret < 0) return -ENODEV; + timer->wake_irq = (unsigned int)ret; timer->clk = devm_clk_get(dev, NULL); if (!IS_ERR(timer->clk)) { @@ -263,7 +264,7 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev) timer->clk = NULL; } - ret = devm_request_irq(dev, timer->irq, brcmstb_waketmr_irq, 0, + ret = devm_request_irq(dev, timer->wake_irq, brcmstb_waketmr_irq, 0, "brcmstb-waketimer", timer); if (ret < 0) goto err_clk; @@ -278,8 +279,6 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev) if (ret) goto err_notifier; - dev_info(dev, "registered, with irq %d\n", timer->irq); - return 0; err_notifier: @@ -317,7 +316,7 @@ static int brcmstb_waketmr_resume(struct device *dev) if (!device_may_wakeup(dev)) return 0; - ret = disable_irq_wake(timer->irq); + ret = disable_irq_wake(timer->wake_irq); brcmstb_waketmr_clear_alarm(timer); -- cgit v1.2.3-70-g09d2 From 344f4030f6c50a9db2d03021884c4bf36191b53a Mon Sep 17 00:00:00 2001 From: Samuel Holland Date: Thu, 29 Dec 2022 15:53:19 -0600 Subject: rtc: sun6i: Always export the internal oscillator On all variants of the hardware, the internal oscillator is one possible parent for the AR100 clock. It needs to be exported so we can model that relationship correctly in the devicetree. Fixes: c56afc1844d6 ("rtc: sun6i: Expose internal oscillator through device tree") Signed-off-by: Samuel Holland Acked-by: Jernej Skrabec Link: https://lore.kernel.org/r/20221229215319.14145-1-samuel@sholland.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-sun6i.c | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c index ed5516089e9a..7038f47d77ff 100644 --- a/drivers/rtc/rtc-sun6i.c +++ b/drivers/rtc/rtc-sun6i.c @@ -136,7 +136,6 @@ struct sun6i_rtc_clk_data { unsigned int fixed_prescaler : 16; unsigned int has_prescaler : 1; unsigned int has_out_clk : 1; - unsigned int export_iosc : 1; unsigned int has_losc_en : 1; unsigned int has_auto_swt : 1; }; @@ -271,10 +270,8 @@ static void __init sun6i_rtc_clk_init(struct device_node *node, /* Yes, I know, this is ugly. */ sun6i_rtc = rtc; - /* Only read IOSC name from device tree if it is exported */ - if (rtc->data->export_iosc) - of_property_read_string_index(node, "clock-output-names", 2, - &iosc_name); + of_property_read_string_index(node, "clock-output-names", 2, + &iosc_name); rtc->int_osc = clk_hw_register_fixed_rate_with_accuracy(NULL, iosc_name, @@ -315,13 +312,10 @@ static void __init sun6i_rtc_clk_init(struct device_node *node, goto err_register; } - clk_data->num = 2; + clk_data->num = 3; clk_data->hws[0] = &rtc->hw; clk_data->hws[1] = __clk_get_hw(rtc->ext_losc); - if (rtc->data->export_iosc) { - clk_data->hws[2] = rtc->int_osc; - clk_data->num = 3; - } + clk_data->hws[2] = rtc->int_osc; of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); return; @@ -361,7 +355,6 @@ static const struct sun6i_rtc_clk_data sun8i_h3_rtc_data = { .fixed_prescaler = 32, .has_prescaler = 1, .has_out_clk = 1, - .export_iosc = 1, }; static void __init sun8i_h3_rtc_clk_init(struct device_node *node) @@ -379,7 +372,6 @@ static const struct sun6i_rtc_clk_data sun50i_h6_rtc_data = { .fixed_prescaler = 32, .has_prescaler = 1, .has_out_clk = 1, - .export_iosc = 1, .has_losc_en = 1, .has_auto_swt = 1, }; -- cgit v1.2.3-70-g09d2 From 24304a87158aab01b4ccb9b2638c2c623a9a7bd4 Mon Sep 17 00:00:00 2001 From: Doug Berger Date: Tue, 24 Jan 2023 12:14:30 -0800 Subject: rtc: brcmstb-waketimer: allow use as non-wake alarm The wake interrupt only fires when the system is in a suspend state. Fortunately we have another interrupt that fires in a non-suspend state at the L2 controller UPG_AUX_AON. Add support for this interrupt line so we can use the alarm in a non-wake context. Signed-off-by: Doug Berger Acked-by: Florian Fainelli Link: https://lore.kernel.org/r/20230124201430.2502371-3-opendmb@gmail.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-brcmstb-waketimer.c | 55 +++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-brcmstb-waketimer.c b/drivers/rtc/rtc-brcmstb-waketimer.c index e25f9fcd6ed1..1efa81cecc27 100644 --- a/drivers/rtc/rtc-brcmstb-waketimer.c +++ b/drivers/rtc/rtc-brcmstb-waketimer.c @@ -28,6 +28,7 @@ struct brcmstb_waketmr { struct device *dev; void __iomem *base; unsigned int wake_irq; + unsigned int alarm_irq; struct notifier_block reboot_notifier; struct clk *clk; u32 rate; @@ -56,6 +57,8 @@ static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer) { u32 reg; + if (timer->alarm_en && timer->alarm_irq) + disable_irq(timer->alarm_irq); timer->alarm_en = false; reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER); writel_relaxed(reg - 1, timer->base + BRCMSTB_WKTMR_ALARM); @@ -88,7 +91,25 @@ static irqreturn_t brcmstb_waketmr_irq(int irq, void *data) { struct brcmstb_waketmr *timer = data; - pm_wakeup_event(timer->dev, 0); + if (!timer->alarm_irq) + pm_wakeup_event(timer->dev, 0); + return IRQ_HANDLED; +} + +static irqreturn_t brcmstb_alarm_irq(int irq, void *data) +{ + struct brcmstb_waketmr *timer = data; + + /* Ignore spurious interrupts */ + if (!brcmstb_waketmr_is_pending(timer)) + return IRQ_HANDLED; + + if (timer->alarm_en) { + if (!device_may_wakeup(timer->dev)) + writel_relaxed(WKTMR_ALARM_EVENT, + timer->base + BRCMSTB_WKTMR_EVENT); + rtc_update_irq(timer->rtc, 1, RTC_IRQF | RTC_AF); + } return IRQ_HANDLED; } @@ -114,7 +135,7 @@ static void wktmr_read(struct brcmstb_waketmr *timer, static int brcmstb_waketmr_prepare_suspend(struct brcmstb_waketmr *timer) { struct device *dev = timer->dev; - int ret = 0; + int ret; if (device_may_wakeup(dev)) { ret = enable_irq_wake(timer->wake_irq); @@ -122,9 +143,17 @@ static int brcmstb_waketmr_prepare_suspend(struct brcmstb_waketmr *timer) dev_err(dev, "failed to enable wake-up interrupt\n"); return ret; } + if (timer->alarm_en && timer->alarm_irq) { + ret = enable_irq_wake(timer->alarm_irq); + if (ret) { + dev_err(dev, "failed to enable rtc interrupt\n"); + disable_irq_wake(timer->wake_irq); + return ret; + } + } } - return ret; + return 0; } /* If enabled as a wakeup-source, arm the timer when powering off */ @@ -192,7 +221,11 @@ static int brcmstb_waketmr_alarm_enable(struct device *dev, !brcmstb_waketmr_is_pending(timer)) return -EINVAL; timer->alarm_en = true; + if (timer->alarm_irq) + enable_irq(timer->alarm_irq); } else if (!enabled && timer->alarm_en) { + if (timer->alarm_irq) + disable_irq(timer->alarm_irq); timer->alarm_en = false; } @@ -269,6 +302,19 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev) if (ret < 0) goto err_clk; + brcmstb_waketmr_clear_alarm(timer); + + /* Attempt to initialize non-wake irq */ + ret = platform_get_irq(pdev, 1); + if (ret > 0) { + timer->alarm_irq = (unsigned int)ret; + ret = devm_request_irq(dev, timer->alarm_irq, brcmstb_alarm_irq, + IRQF_NO_AUTOEN, "brcmstb-waketimer-rtc", + timer); + if (ret < 0) + timer->alarm_irq = 0; + } + timer->reboot_notifier.notifier_call = brcmstb_waketmr_reboot; register_reboot_notifier(&timer->reboot_notifier); @@ -317,6 +363,8 @@ static int brcmstb_waketmr_resume(struct device *dev) return 0; ret = disable_irq_wake(timer->wake_irq); + if (timer->alarm_en && timer->alarm_irq) + disable_irq_wake(timer->alarm_irq); brcmstb_waketmr_clear_alarm(timer); @@ -346,4 +394,5 @@ module_platform_driver(brcmstb_waketmr_driver); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Brian Norris"); MODULE_AUTHOR("Markus Mayer"); +MODULE_AUTHOR("Doug Berger"); MODULE_DESCRIPTION("Wake-up timer driver for STB chips"); -- cgit v1.2.3-70-g09d2 From 37abc36ed2d39e57ac0fad163d061366b4a015cb Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 23 Jan 2023 21:02:07 +0100 Subject: rtc: ab-eoz9: use IRQ flags obtained from fwnode Allow the IRQ type to be passed from the device tree if available as there may be components changing the trigger type of the interrupt between the RTC and the IRQ controller. Link: https://lore.kernel.org/r/20230123200217.1236011-2-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ab-eoz9.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-ab-eoz9.c b/drivers/rtc/rtc-ab-eoz9.c index 2f8deb8c4cd3..34611f6dedcb 100644 --- a/drivers/rtc/rtc-ab-eoz9.c +++ b/drivers/rtc/rtc-ab-eoz9.c @@ -536,9 +536,14 @@ static int abeoz9_probe(struct i2c_client *client) clear_bit(RTC_FEATURE_ALARM, data->rtc->features); if (client->irq > 0) { + unsigned long irqflags = IRQF_TRIGGER_LOW; + + if (dev_fwnode(&client->dev)) + irqflags = 0; + ret = devm_request_threaded_irq(dev, client->irq, NULL, abeoz9_rtc_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + irqflags | IRQF_ONESHOT, dev_name(dev), dev); if (ret) { dev_err(dev, "failed to request alarm irq\n"); -- cgit v1.2.3-70-g09d2 From badba1e5b111c6f32038953efc8078cba3390326 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 23 Jan 2023 21:02:08 +0100 Subject: rtc: hym8563: use IRQ flags obtained from fwnode Allow the IRQ type to be passed from the device tree if available as there may be components changing the trigger type of the interrupt between the RTC and the IRQ controller. Link: https://lore.kernel.org/r/20230123200217.1236011-3-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-hym8563.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c index cc710d682121..7d5a298a9a3b 100644 --- a/drivers/rtc/rtc-hym8563.c +++ b/drivers/rtc/rtc-hym8563.c @@ -518,9 +518,14 @@ static int hym8563_probe(struct i2c_client *client) } if (client->irq > 0) { + unsigned long irqflags = IRQF_TRIGGER_LOW; + + if (dev_fwnode(&client->dev)) + irqflags = 0; + ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, hym8563_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + irqflags | IRQF_ONESHOT, client->name, hym8563); if (ret < 0) { dev_err(&client->dev, "irq %d request failed, %d\n", -- cgit v1.2.3-70-g09d2 From f181987ef4772c2d9412b43bc3d0e34fe368cddb Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 23 Jan 2023 21:02:09 +0100 Subject: rtc: m41t80: use IRQ flags obtained from fwnode Allow the IRQ type to be passed from the device tree if available as there may be components changing the trigger type of the interrupt between the RTC and the IRQ controller. Link: https://lore.kernel.org/r/20230123200217.1236011-4-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-m41t80.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index 494052dbd39f..c1963f7c424d 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -914,9 +914,14 @@ static int m41t80_probe(struct i2c_client *client) "wakeup-source"); #endif if (client->irq > 0) { + unsigned long irqflags = IRQF_TRIGGER_LOW; + + if (dev_fwnode(&client->dev)) + irqflags = 0; + rc = devm_request_threaded_irq(&client->dev, client->irq, NULL, m41t80_handle_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + irqflags | IRQF_ONESHOT, "m41t80", client); if (rc) { dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n"); -- cgit v1.2.3-70-g09d2 From 5434a4e472c71448bbdc061f21ebf1b0a2d23753 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 23 Jan 2023 21:02:10 +0100 Subject: rtc: pcf2123: use IRQ flags obtained from fwnode Allow the IRQ type to be passed from the device tree if available as there may be components changing the trigger type of the interrupt between the RTC and the IRQ controller. Link: https://lore.kernel.org/r/20230123200217.1236011-5-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2123.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index e13b5e695d06..e714661e61a9 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -413,9 +413,14 @@ static int pcf2123_probe(struct spi_device *spi) /* Register alarm irq */ if (spi->irq > 0) { + unsigned long irqflags = IRQF_TRIGGER_LOW; + + if (dev_fwnode(&spi->dev)) + irqflags = 0; + ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, pcf2123_rtc_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + irqflags | IRQF_ONESHOT, pcf2123_driver.driver.name, &spi->dev); if (!ret) device_init_wakeup(&spi->dev, true); -- cgit v1.2.3-70-g09d2 From 7e815272c8d0922ad1d0def11496ac63fa71fa78 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 23 Jan 2023 21:02:11 +0100 Subject: rtc: pcf85063: use IRQ flags obtained from fwnode Allow the IRQ type to be passed from the device tree if available as there may be components changing the trigger type of the interrupt between the RTC and the IRQ controller. Link: https://lore.kernel.org/r/20230123200217.1236011-6-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf85063.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index 754e03984f98..71a456355981 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -621,9 +621,14 @@ static int pcf85063_probe(struct i2c_client *client) clear_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features); if (config->has_alarms && client->irq > 0) { + unsigned long irqflags = IRQF_TRIGGER_LOW; + + if (dev_fwnode(&client->dev)) + irqflags = 0; + err = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf85063_rtc_handle_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + irqflags | IRQF_ONESHOT, "pcf85063", pcf85063); if (err) { dev_warn(&pcf85063->rtc->dev, -- cgit v1.2.3-70-g09d2 From 3542db1d1fd62f75eb69079d219d88170626444f Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 23 Jan 2023 21:02:12 +0100 Subject: rtc: pcf8523: use IRQ flags obtained from fwnode Allow the IRQ type to be passed from the device tree if available as there may be components changing the trigger type of the interrupt between the RTC and the IRQ controller. Link: https://lore.kernel.org/r/20230123200217.1236011-7-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf8523.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 92de99f11a7a..2e111cdb94f7 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -445,13 +445,18 @@ static int pcf8523_probe(struct i2c_client *client) clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); if (client->irq > 0) { + unsigned long irqflags = IRQF_TRIGGER_LOW; + + if (dev_fwnode(&client->dev)) + irqflags = 0; + err = regmap_write(pcf8523->regmap, PCF8523_TMR_CLKOUT_CTRL, 0x38); if (err < 0) return err; err = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf8523_irq, - IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW, + IRQF_SHARED | IRQF_ONESHOT | irqflags, dev_name(&rtc->dev), pcf8523); if (err) return err; -- cgit v1.2.3-70-g09d2 From dd7166c8ba6e27568ba1c3fa8874316150ce694c Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 23 Jan 2023 21:02:13 +0100 Subject: rtc: pcf85363: use IRQ flags obtained fromfwnode Allow the IRQ type to be passed from the device tree if available as there may be components changing the trigger type of the interrupt between the RTC and the IRQ controller. Link: https://lore.kernel.org/r/20230123200217.1236011-8-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf85363.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c index c05b722f0060..5de323acd178 100644 --- a/drivers/rtc/rtc-pcf85363.c +++ b/drivers/rtc/rtc-pcf85363.c @@ -400,12 +400,17 @@ static int pcf85363_probe(struct i2c_client *client) clear_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features); if (client->irq > 0) { + unsigned long irqflags = IRQF_TRIGGER_LOW; + + if (dev_fwnode(&client->dev)) + irqflags = 0; + regmap_write(pcf85363->regmap, CTRL_FLAGS, 0); regmap_update_bits(pcf85363->regmap, CTRL_PIN_IO, PIN_IO_INTA_OUT, PIN_IO_INTAPM); ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf85363_rtc_handle_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + irqflags | IRQF_ONESHOT, "pcf85363", client); if (ret) dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n"); -- cgit v1.2.3-70-g09d2 From 827009a8d3f80d81c6da634f4ab1a33e2d539aa4 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 23 Jan 2023 21:02:14 +0100 Subject: rtc: pcf8563: use IRQ flags obtained from fwnode Allow the IRQ type to be passed from the device tree if available as there may be components changing the trigger type of the interrupt between the RTC and the IRQ controller. Link: https://lore.kernel.org/r/20230123200217.1236011-9-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf8563.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 0a7fd9478465..7e720472213c 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -558,9 +558,14 @@ static int pcf8563_probe(struct i2c_client *client) pcf8563->rtc->set_start_time = true; if (client->irq > 0) { + unsigned long irqflags = IRQF_TRIGGER_LOW; + + if (dev_fwnode(&client->dev)) + irqflags = 0; + err = devm_request_threaded_irq(&client->dev, client->irq, NULL, pcf8563_irq, - IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW, + IRQF_SHARED | IRQF_ONESHOT | irqflags, pcf8563_driver.driver.name, client); if (err) { dev_err(&client->dev, "unable to request IRQ %d\n", -- cgit v1.2.3-70-g09d2 From bfff849f1deff5607c8fb1031be319cd88e0ecd7 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 23 Jan 2023 21:02:15 +0100 Subject: rtc: rv3029c2: use IRQ flags obtained from fwnode Allow the IRQ type to be passed from the device tree if available as there may be components changing the trigger type of the interrupt between the RTC and the IRQ controller. Link: https://lore.kernel.org/r/20230123200217.1236011-10-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rv3029c2.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index e4fdd47ae066..0852f6709a85 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -735,9 +735,14 @@ static int rv3029_probe(struct device *dev, struct regmap *regmap, int irq, return PTR_ERR(rv3029->rtc); if (rv3029->irq > 0) { + unsigned long irqflags = IRQF_TRIGGER_LOW; + + if (dev_fwnode(dev)) + irqflags = 0; + rc = devm_request_threaded_irq(dev, rv3029->irq, NULL, rv3029_handle_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + irqflags | IRQF_ONESHOT, "rv3029", dev); if (rc) { dev_warn(dev, "unable to request IRQ, alarms disabled\n"); -- cgit v1.2.3-70-g09d2 From c4b12f89f5aefe559522e4e41528a6c719fcdcdb Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 23 Jan 2023 21:02:16 +0100 Subject: rtc: rv3032: use IRQ flags obtained from fwnode Allow the IRQ type to be passed from the device tree if available as there may be components changing the trigger type of the interrupt between the RTC and the IRQ controller. Link: https://lore.kernel.org/r/20230123200217.1236011-11-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rv3032.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c index c3bee305eacc..bf6954ec5943 100644 --- a/drivers/rtc/rtc-rv3032.c +++ b/drivers/rtc/rtc-rv3032.c @@ -930,9 +930,14 @@ static int rv3032_probe(struct i2c_client *client) return PTR_ERR(rv3032->rtc); if (client->irq > 0) { + unsigned long irqflags = IRQF_TRIGGER_LOW; + + if (dev_fwnode(&client->dev)) + irqflags = 0; + ret = devm_request_threaded_irq(&client->dev, client->irq, NULL, rv3032_handle_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + irqflags | IRQF_ONESHOT, "rv3032", rv3032); if (ret) { dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n"); -- cgit v1.2.3-70-g09d2 From 11bfd6fcebfa25a77e601e68f5d4ba897e7b3047 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 23 Jan 2023 21:02:17 +0100 Subject: rtc: rv8803: use IRQ flags obtained from fwnode Allow the IRQ type to be passed from the device tree if available as there may be components changing the trigger type of the interrupt between the RTC and the IRQ controller. Link: https://lore.kernel.org/r/20230123200217.1236011-12-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rv8803.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index b581b6d5ad73..53d1de01b719 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -641,9 +641,14 @@ static int rv8803_probe(struct i2c_client *client) return PTR_ERR(rv8803->rtc); if (client->irq > 0) { + unsigned long irqflags = IRQF_TRIGGER_LOW; + + if (dev_fwnode(&client->dev)) + irqflags = 0; + err = devm_request_threaded_irq(&client->dev, client->irq, NULL, rv8803_handle_irq, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + irqflags | IRQF_ONESHOT, "rv8803", client); if (err) { dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n"); -- cgit v1.2.3-70-g09d2 From 4bbdced5db096bded4e2d10259e9a5e0070a4cb3 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 23 Jan 2023 21:02:06 +0100 Subject: rtc: rx8010: use IRQ flags obtained from fwnode Allow the IRQ type to be passed from the device tree if available as there may be components changing the trigger type of the interrupt between the RTC and the IRQ controller. Link: https://lore.kernel.org/r/20230123200217.1236011-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8010.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c index d09056570739..b9c8dad26208 100644 --- a/drivers/rtc/rtc-rx8010.c +++ b/drivers/rtc/rtc-rx8010.c @@ -394,10 +394,14 @@ static int rx8010_probe(struct i2c_client *client) return PTR_ERR(rx8010->rtc); if (client->irq > 0) { - dev_info(dev, "IRQ %d supplied\n", client->irq); + unsigned long irqflags = IRQF_TRIGGER_LOW; + + if (dev_fwnode(&client->dev)) + irqflags = 0; + err = devm_request_threaded_irq(dev, client->irq, NULL, rx8010_irq_1_handler, - IRQF_TRIGGER_LOW | IRQF_ONESHOT, + irqflags | IRQF_ONESHOT, "rx8010", client); if (err) { dev_err(dev, "unable to request IRQ\n"); -- cgit v1.2.3-70-g09d2 From 04596d4b3e0d20697193341694e8c99961702259 Mon Sep 17 00:00:00 2001 From: Uwe Kleine-König Date: Mon, 19 Dec 2022 09:14:40 +0100 Subject: rtc: max8907: Drop unused i2c include MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit rtc-max8907 is a platform driver that doesn't use any symbol provided in . So drop the include. Signed-off-by: Uwe Kleine-König Link: https://lore.kernel.org/r/20221219081440.1399791-1-u.kleine-koenig@pengutronix.de Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-max8907.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-max8907.c b/drivers/rtc/rtc-max8907.c index db3495d10274..af97140dd00a 100644 --- a/drivers/rtc/rtc-max8907.c +++ b/drivers/rtc/rtc-max8907.c @@ -9,7 +9,6 @@ */ #include -#include #include #include #include -- cgit v1.2.3-70-g09d2 From e5c594233fcf1a55a439dec103aa815cdbf392a7 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 23 Nov 2022 10:55:27 +0100 Subject: rtc: rv8803: invalidate date/time if alarm time is invalid RTC core never calls rv8803_set_alarm with an invalid alarm time, so if an invalid alarm time > 0 is set, external factors must have corrupted the RTC's alarm time and possibly other registers. Play it safe by marking the date/time invalid, so all registers are reinitialized on a ->set_time. This may cause existing setups to lose time if they so far set only date/time, but ignored that the alarm registers had an invalid date value, e.g.: rtc rtc0: invalid alarm value: 2020-3-27 7:82:0 These systems will have their ->get_time return -EINVAL till ->set_time initializes the alarm value (and sets a new time). Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer Link: https://lore.kernel.org/r/20221123095527.2771434-3-s.hauer@pengutronix.de Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rv8803.c | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c index 53d1de01b719..25c3b9e4f515 100644 --- a/drivers/rtc/rtc-rv8803.c +++ b/drivers/rtc/rtc-rv8803.c @@ -70,6 +70,7 @@ struct rv8803_data { struct mutex flags_lock; u8 ctrl; u8 backup; + u8 alarm_invalid:1; enum rv8803_type type; }; @@ -165,13 +166,13 @@ static int rv8803_regs_init(struct rv8803_data *rv8803) static int rv8803_regs_configure(struct rv8803_data *rv8803); -static int rv8803_regs_reset(struct rv8803_data *rv8803) +static int rv8803_regs_reset(struct rv8803_data *rv8803, bool full) { /* * The RV-8803 resets all registers to POR defaults after voltage-loss, * the Epson RTCs don't, so we manually reset the remainder here. */ - if (rv8803->type == rx_8803 || rv8803->type == rx_8900) { + if (full || rv8803->type == rx_8803 || rv8803->type == rx_8900) { int ret = rv8803_regs_init(rv8803); if (ret) return ret; @@ -238,6 +239,11 @@ static int rv8803_get_time(struct device *dev, struct rtc_time *tm) u8 *date = date1; int ret, flags; + if (rv8803->alarm_invalid) { + dev_warn(dev, "Corruption detected, data may be invalid.\n"); + return -EINVAL; + } + flags = rv8803_read_reg(rv8803->client, RV8803_FLAG); if (flags < 0) return flags; @@ -313,12 +319,19 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm) return flags; } - if (flags & RV8803_FLAG_V2F) { - ret = rv8803_regs_reset(rv8803); + if ((flags & RV8803_FLAG_V2F) || rv8803->alarm_invalid) { + /* + * If we sense corruption in the alarm registers, but see no + * voltage loss flag, we can't rely on other registers having + * sensible values. Reset them fully. + */ + ret = rv8803_regs_reset(rv8803, rv8803->alarm_invalid); if (ret) { mutex_unlock(&rv8803->flags_lock); return ret; } + + rv8803->alarm_invalid = false; } ret = rv8803_write_reg(rv8803->client, RV8803_FLAG, @@ -344,15 +357,33 @@ static int rv8803_get_alarm(struct device *dev, struct rtc_wkalrm *alrm) if (flags < 0) return flags; + alarmvals[0] &= 0x7f; + alarmvals[1] &= 0x3f; + alarmvals[2] &= 0x3f; + + if (!bcd_is_valid(alarmvals[0]) || + !bcd_is_valid(alarmvals[1]) || + !bcd_is_valid(alarmvals[2])) + goto err_invalid; + alrm->time.tm_sec = 0; - alrm->time.tm_min = bcd2bin(alarmvals[0] & 0x7f); - alrm->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f); - alrm->time.tm_mday = bcd2bin(alarmvals[2] & 0x3f); + alrm->time.tm_min = bcd2bin(alarmvals[0]); + alrm->time.tm_hour = bcd2bin(alarmvals[1]); + alrm->time.tm_mday = bcd2bin(alarmvals[2]); alrm->enabled = !!(rv8803->ctrl & RV8803_CTRL_AIE); alrm->pending = (flags & RV8803_FLAG_AF) && alrm->enabled; + if ((unsigned int)alrm->time.tm_mday > 31 || + (unsigned int)alrm->time.tm_hour >= 24 || + (unsigned int)alrm->time.tm_min >= 60) + goto err_invalid; + return 0; + +err_invalid: + rv8803->alarm_invalid = true; + return -EINVAL; } static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) -- cgit v1.2.3-70-g09d2 From c88db0eff9722fc2b6c4d172a50471d20e08ecc6 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Feb 2023 16:54:27 +0100 Subject: rtc: pm8xxx: fix set-alarm race Make sure to disable the alarm before updating the four alarm time registers to avoid spurious alarms during the update. Note that the disable needs to be done outside of the ctrl_reg_lock section to prevent a racing alarm interrupt from disabling the newly set alarm when the lock is released. Fixes: 9a9a54ad7aa2 ("drivers/rtc: add support for Qualcomm PMIC8xxx RTC") Cc: stable@vger.kernel.org # 3.1 Signed-off-by: Johan Hovold Reviewed-by: David Collins Link: https://lore.kernel.org/r/20230202155448.6715-2-johan+linaro@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 716e5d9ad74d..d114f0da537d 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -221,7 +221,6 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { int rc, i; u8 value[NUM_8_BIT_RTC_REGS]; - unsigned int ctrl_reg; unsigned long secs, irq_flags; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; @@ -233,6 +232,11 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) secs >>= 8; } + rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, + regs->alarm_en, 0); + if (rc) + return rc; + spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); rc = regmap_bulk_write(rtc_dd->regmap, regs->alarm_rw, value, @@ -242,19 +246,11 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) goto rtc_rw_fail; } - rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg); - if (rc) - goto rtc_rw_fail; - - if (alarm->enabled) - ctrl_reg |= regs->alarm_en; - else - ctrl_reg &= ~regs->alarm_en; - - rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg); - if (rc) { - dev_err(dev, "Write to RTC alarm control register failed\n"); - goto rtc_rw_fail; + if (alarm->enabled) { + rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, + regs->alarm_en, regs->alarm_en); + if (rc) + goto rtc_rw_fail; } dev_dbg(dev, "Alarm Set for h:m:s=%ptRt, y-m-d=%ptRdr\n", -- cgit v1.2.3-70-g09d2 From eb245631836b4843199d7176d1597759dda4ee9e Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Feb 2023 16:54:28 +0100 Subject: rtc: pm8xxx: drop spmi error messages Drop the unnecessary error messages after every spmi regmap access, which are not expected to fail. Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230202155448.6715-3-johan+linaro@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 71 ++++++++++++------------------------------------ 1 file changed, 17 insertions(+), 54 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index d114f0da537d..f49bda999e02 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -105,10 +105,8 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) alarm_enabled = 1; ctrl_reg &= ~regs->alarm_en; rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg); - if (rc) { - dev_err(dev, "Write to RTC Alarm control register failed\n"); + if (rc) goto rtc_rw_fail; - } } /* Disable RTC H/w before writing on RTC register */ @@ -120,51 +118,39 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) rtc_disabled = 1; rtc_ctrl_reg &= ~PM8xxx_RTC_ENABLE; rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg); - if (rc) { - dev_err(dev, "Write to RTC control register failed\n"); + if (rc) goto rtc_rw_fail; - } } /* Write 0 to Byte[0] */ rc = regmap_write(rtc_dd->regmap, regs->write, 0); - if (rc) { - dev_err(dev, "Write to RTC write data register failed\n"); + if (rc) goto rtc_rw_fail; - } /* Write Byte[1], Byte[2], Byte[3] */ rc = regmap_bulk_write(rtc_dd->regmap, regs->write + 1, &value[1], sizeof(value) - 1); - if (rc) { - dev_err(dev, "Write to RTC write data register failed\n"); + if (rc) goto rtc_rw_fail; - } /* Write Byte[0] */ rc = regmap_write(rtc_dd->regmap, regs->write, value[0]); - if (rc) { - dev_err(dev, "Write to RTC write data register failed\n"); + if (rc) goto rtc_rw_fail; - } /* Enable RTC H/w after writing on RTC register */ if (rtc_disabled) { rtc_ctrl_reg |= PM8xxx_RTC_ENABLE; rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg); - if (rc) { - dev_err(dev, "Write to RTC control register failed\n"); + if (rc) goto rtc_rw_fail; - } } if (alarm_enabled) { ctrl_reg |= regs->alarm_en; rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg); - if (rc) { - dev_err(dev, "Write to RTC Alarm control register failed\n"); + if (rc) goto rtc_rw_fail; - } } rtc_rw_fail: @@ -183,28 +169,22 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value, sizeof(value)); - if (rc) { - dev_err(dev, "RTC read data register failed\n"); + if (rc) return rc; - } /* * Read the LSB again and check if there has been a carry over. * If there is, redo the read operation. */ rc = regmap_read(rtc_dd->regmap, regs->read, ®); - if (rc < 0) { - dev_err(dev, "RTC read data register failed\n"); + if (rc < 0) return rc; - } if (unlikely(reg < value[0])) { rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value, sizeof(value)); - if (rc) { - dev_err(dev, "RTC read data register failed\n"); + if (rc) return rc; - } } secs = value[0] | (value[1] << 8) | (value[2] << 16) | @@ -241,10 +221,8 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) rc = regmap_bulk_write(rtc_dd->regmap, regs->alarm_rw, value, sizeof(value)); - if (rc) { - dev_err(dev, "Write to RTC ALARM register failed\n"); + if (rc) goto rtc_rw_fail; - } if (alarm->enabled) { rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, @@ -271,10 +249,8 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) rc = regmap_bulk_read(rtc_dd->regmap, regs->alarm_rw, value, sizeof(value)); - if (rc) { - dev_err(dev, "RTC alarm time read failed\n"); + if (rc) return rc; - } secs = value[0] | (value[1] << 8) | (value[2] << 16) | ((unsigned long)value[3] << 24); @@ -282,10 +258,9 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) rtc_time64_to_tm(secs, &alarm->time); rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg); - if (rc) { - dev_err(dev, "Read from RTC alarm control register failed\n"); + if (rc) return rc; - } + alarm->enabled = !!(ctrl_reg & PM8xxx_RTC_ALARM_ENABLE); dev_dbg(dev, "Alarm set for - h:m:s=%ptRt, y-m-d=%ptRdr\n", @@ -315,19 +290,15 @@ static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) ctrl_reg &= ~regs->alarm_en; rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg); - if (rc) { - dev_err(dev, "Write to RTC control register failed\n"); + if (rc) goto rtc_rw_fail; - } /* Clear Alarm register */ if (!enable) { rc = regmap_bulk_write(rtc_dd->regmap, regs->alarm_rw, value, sizeof(value)); - if (rc) { - dev_err(dev, "Clear RTC ALARM register failed\n"); + if (rc) goto rtc_rw_fail; - } } rtc_rw_fail: @@ -366,8 +337,6 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id) rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg); if (rc) { spin_unlock(&rtc_dd->ctrl_reg_lock); - dev_err(rtc_dd->rtc_dev, - "Write to alarm control register failed\n"); goto rtc_alarm_handled; } @@ -375,17 +344,11 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id) /* Clear RTC alarm register */ rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl2, &ctrl_reg); - if (rc) { - dev_err(rtc_dd->rtc_dev, - "RTC Alarm control2 register read failed\n"); + if (rc) goto rtc_alarm_handled; - } ctrl_reg |= PM8xxx_RTC_ALARM_CLEAR; rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl2, ctrl_reg); - if (rc) - dev_err(rtc_dd->rtc_dev, - "Write to RTC Alarm control2 register failed\n"); rtc_alarm_handled: return IRQ_HANDLED; -- cgit v1.2.3-70-g09d2 From 182c23bbfea3713206b0da3fbbb7350e197a92dd Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Feb 2023 16:54:29 +0100 Subject: rtc: pm8xxx: use regmap_update_bits() Switch to using regmap_update_bits() instead of open coding read-modify-write accesses. Signed-off-by: Johan Hovold Reviewed-by: David Collins Link: https://lore.kernel.org/r/20230202155448.6715-4-johan+linaro@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 87 ++++++++++++------------------------------------ 1 file changed, 22 insertions(+), 65 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index f49bda999e02..8c2847ac64f4 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -78,10 +78,10 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) { int rc, i; unsigned long secs, irq_flags; - u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0, rtc_disabled = 0; - unsigned int ctrl_reg, rtc_ctrl_reg; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; + u8 value[NUM_8_BIT_RTC_REGS]; + bool alarm_enabled; if (!rtc_dd->allow_set_time) return -ENODEV; @@ -97,31 +97,16 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); - rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg); + rc = regmap_update_bits_check(rtc_dd->regmap, regs->alarm_ctrl, + regs->alarm_en, 0, &alarm_enabled); if (rc) goto rtc_rw_fail; - if (ctrl_reg & regs->alarm_en) { - alarm_enabled = 1; - ctrl_reg &= ~regs->alarm_en; - rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg); - if (rc) - goto rtc_rw_fail; - } - /* Disable RTC H/w before writing on RTC register */ - rc = regmap_read(rtc_dd->regmap, regs->ctrl, &rtc_ctrl_reg); + rc = regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE, 0); if (rc) goto rtc_rw_fail; - if (rtc_ctrl_reg & PM8xxx_RTC_ENABLE) { - rtc_disabled = 1; - rtc_ctrl_reg &= ~PM8xxx_RTC_ENABLE; - rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg); - if (rc) - goto rtc_rw_fail; - } - /* Write 0 to Byte[0] */ rc = regmap_write(rtc_dd->regmap, regs->write, 0); if (rc) @@ -139,16 +124,14 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) goto rtc_rw_fail; /* Enable RTC H/w after writing on RTC register */ - if (rtc_disabled) { - rtc_ctrl_reg |= PM8xxx_RTC_ENABLE; - rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg); - if (rc) - goto rtc_rw_fail; - } + rc = regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE, + PM8xxx_RTC_ENABLE); + if (rc) + goto rtc_rw_fail; if (alarm_enabled) { - ctrl_reg |= regs->alarm_en; - rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg); + rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, + regs->alarm_en, regs->alarm_en); if (rc) goto rtc_rw_fail; } @@ -275,21 +258,18 @@ static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) unsigned long irq_flags; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; - unsigned int ctrl_reg; u8 value[NUM_8_BIT_RTC_REGS] = {0}; + unsigned int val; spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); - rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg); - if (rc) - goto rtc_rw_fail; - if (enable) - ctrl_reg |= regs->alarm_en; + val = regs->alarm_en; else - ctrl_reg &= ~regs->alarm_en; + val = 0; - rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg); + rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, + regs->alarm_en, val); if (rc) goto rtc_rw_fail; @@ -318,7 +298,6 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id) { struct pm8xxx_rtc *rtc_dd = dev_id; const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; - unsigned int ctrl_reg; int rc; rtc_update_irq(rtc_dd->rtc, 1, RTC_IRQF | RTC_AF); @@ -326,15 +305,8 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id) spin_lock(&rtc_dd->ctrl_reg_lock); /* Clear the alarm enable bit */ - rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg); - if (rc) { - spin_unlock(&rtc_dd->ctrl_reg_lock); - goto rtc_alarm_handled; - } - - ctrl_reg &= ~regs->alarm_en; - - rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg); + rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, + regs->alarm_en, 0); if (rc) { spin_unlock(&rtc_dd->ctrl_reg_lock); goto rtc_alarm_handled; @@ -343,13 +315,11 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id) spin_unlock(&rtc_dd->ctrl_reg_lock); /* Clear RTC alarm register */ - rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl2, &ctrl_reg); + rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl2, + PM8xxx_RTC_ALARM_CLEAR, 0); if (rc) goto rtc_alarm_handled; - ctrl_reg |= PM8xxx_RTC_ALARM_CLEAR; - rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl2, ctrl_reg); - rtc_alarm_handled: return IRQ_HANDLED; } @@ -357,22 +327,9 @@ rtc_alarm_handled: static int pm8xxx_rtc_enable(struct pm8xxx_rtc *rtc_dd) { const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; - unsigned int ctrl_reg; - int rc; - - /* Check if the RTC is on, else turn it on */ - rc = regmap_read(rtc_dd->regmap, regs->ctrl, &ctrl_reg); - if (rc) - return rc; - if (!(ctrl_reg & PM8xxx_RTC_ENABLE)) { - ctrl_reg |= PM8xxx_RTC_ENABLE; - rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg); - if (rc) - return rc; - } - - return 0; + return regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE, + PM8xxx_RTC_ENABLE); } static const struct pm8xxx_rtc_regs pm8921_regs = { -- cgit v1.2.3-70-g09d2 From 8d273f33fd090a2c270c67b6ac7fa03f5a7eee3f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Feb 2023 16:54:30 +0100 Subject: rtc: pm8xxx: drop bogus locking Since commit c8d523a4b053 ("drivers/rtc/rtc-pm8xxx.c: rework to support pm8941 rtc") which removed the shadow control register there is no need for a driver lock. Specifically, the rtc ops are serialised by rtc core and the interrupt handler only unconditionally disables the alarm using the alarm_ctrl register. Note that since only the alarm enable bit of alarm_ctrl is used after enabling the RTC at probe, the locking was not needed when doing open coded read-modify-write cycles either. Signed-off-by: Johan Hovold Reviewed-by: David Collins Link: https://lore.kernel.org/r/20230202155448.6715-5-johan+linaro@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 67 +++++++++++++++--------------------------------- 1 file changed, 21 insertions(+), 46 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 8c2847ac64f4..053a04f74a91 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -53,7 +53,6 @@ struct pm8xxx_rtc_regs { * @rtc_alarm_irq: rtc alarm irq number. * @regs: rtc registers description. * @rtc_dev: device structure. - * @ctrl_reg_lock: spinlock protecting access to ctrl_reg. */ struct pm8xxx_rtc { struct rtc_device *rtc; @@ -62,7 +61,6 @@ struct pm8xxx_rtc { int rtc_alarm_irq; const struct pm8xxx_rtc_regs *regs; struct device *rtc_dev; - spinlock_t ctrl_reg_lock; }; /* @@ -77,11 +75,11 @@ struct pm8xxx_rtc { static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) { int rc, i; - unsigned long secs, irq_flags; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; u8 value[NUM_8_BIT_RTC_REGS]; bool alarm_enabled; + unsigned long secs; if (!rtc_dd->allow_set_time) return -ENODEV; @@ -95,51 +93,46 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) secs >>= 8; } - spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); - rc = regmap_update_bits_check(rtc_dd->regmap, regs->alarm_ctrl, regs->alarm_en, 0, &alarm_enabled); if (rc) - goto rtc_rw_fail; + return rc; /* Disable RTC H/w before writing on RTC register */ rc = regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE, 0); if (rc) - goto rtc_rw_fail; + return rc; /* Write 0 to Byte[0] */ rc = regmap_write(rtc_dd->regmap, regs->write, 0); if (rc) - goto rtc_rw_fail; + return rc; /* Write Byte[1], Byte[2], Byte[3] */ rc = regmap_bulk_write(rtc_dd->regmap, regs->write + 1, &value[1], sizeof(value) - 1); if (rc) - goto rtc_rw_fail; + return rc; /* Write Byte[0] */ rc = regmap_write(rtc_dd->regmap, regs->write, value[0]); if (rc) - goto rtc_rw_fail; + return rc; /* Enable RTC H/w after writing on RTC register */ rc = regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE, PM8xxx_RTC_ENABLE); if (rc) - goto rtc_rw_fail; + return rc; if (alarm_enabled) { rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, regs->alarm_en, regs->alarm_en); if (rc) - goto rtc_rw_fail; + return rc; } -rtc_rw_fail: - spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); - - return rc; + return 0; } static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) @@ -184,9 +177,9 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { int rc, i; u8 value[NUM_8_BIT_RTC_REGS]; - unsigned long secs, irq_flags; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; + unsigned long secs; secs = rtc_tm_to_time64(&alarm->time); @@ -200,25 +193,22 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) if (rc) return rc; - spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); - rc = regmap_bulk_write(rtc_dd->regmap, regs->alarm_rw, value, sizeof(value)); if (rc) - goto rtc_rw_fail; + return rc; if (alarm->enabled) { rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, regs->alarm_en, regs->alarm_en); if (rc) - goto rtc_rw_fail; + return rc; } dev_dbg(dev, "Alarm Set for h:m:s=%ptRt, y-m-d=%ptRdr\n", &alarm->time, &alarm->time); -rtc_rw_fail: - spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); - return rc; + + return 0; } static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) @@ -255,14 +245,11 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) { int rc; - unsigned long irq_flags; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; u8 value[NUM_8_BIT_RTC_REGS] = {0}; unsigned int val; - spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); - if (enable) val = regs->alarm_en; else @@ -271,19 +258,17 @@ static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, regs->alarm_en, val); if (rc) - goto rtc_rw_fail; + return rc; /* Clear Alarm register */ if (!enable) { rc = regmap_bulk_write(rtc_dd->regmap, regs->alarm_rw, value, sizeof(value)); if (rc) - goto rtc_rw_fail; + return rc; } -rtc_rw_fail: - spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); - return rc; + return 0; } static const struct rtc_class_ops pm8xxx_rtc_ops = { @@ -302,25 +287,18 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id) rtc_update_irq(rtc_dd->rtc, 1, RTC_IRQF | RTC_AF); - spin_lock(&rtc_dd->ctrl_reg_lock); - /* Clear the alarm enable bit */ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, regs->alarm_en, 0); - if (rc) { - spin_unlock(&rtc_dd->ctrl_reg_lock); - goto rtc_alarm_handled; - } - - spin_unlock(&rtc_dd->ctrl_reg_lock); + if (rc) + goto out; /* Clear RTC alarm register */ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl2, PM8xxx_RTC_ALARM_CLEAR, 0); if (rc) - goto rtc_alarm_handled; - -rtc_alarm_handled: + goto out; +out: return IRQ_HANDLED; } @@ -398,9 +376,6 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) if (rtc_dd == NULL) return -ENOMEM; - /* Initialise spinlock to protect RTC control register */ - spin_lock_init(&rtc_dd->ctrl_reg_lock); - rtc_dd->regmap = dev_get_regmap(pdev->dev.parent, NULL); if (!rtc_dd->regmap) { dev_err(&pdev->dev, "Parent regmap unavailable.\n"); -- cgit v1.2.3-70-g09d2 From cb9bb7b2364bb5f4f51226ce1f9ec6ffda618f0a Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Feb 2023 16:54:31 +0100 Subject: rtc: pm8xxx: return IRQ_NONE on errors In the unlikely event that disabling the alarm and clearing the status ever fails, return IRQ_NONE instead of IRQ_HANDLED. Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230202155448.6715-6-johan+linaro@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 053a04f74a91..dc7e659cbb2a 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -291,14 +291,14 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id) rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, regs->alarm_en, 0); if (rc) - goto out; + return IRQ_NONE; /* Clear RTC alarm register */ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl2, PM8xxx_RTC_ALARM_CLEAR, 0); if (rc) - goto out; -out: + return IRQ_NONE; + return IRQ_HANDLED; } -- cgit v1.2.3-70-g09d2 From f081b74c1c748a7da972c782c2f974f239a9b51f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Feb 2023 16:54:32 +0100 Subject: rtc: pm8xxx: drop unused register defines Drop the original register defines which have been unused since commit c8d523a4b053 ("drivers/rtc/rtc-pm8xxx.c: rework to support pm8941 rtc"). Signed-off-by: Johan Hovold Reviewed-by: David Collins Link: https://lore.kernel.org/r/20230202155448.6715-7-johan+linaro@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index dc7e659cbb2a..90027a7cfb12 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -12,12 +12,6 @@ #include #include -/* RTC Register offsets from RTC CTRL REG */ -#define PM8XXX_ALARM_CTRL_OFFSET 0x01 -#define PM8XXX_RTC_WRITE_OFFSET 0x02 -#define PM8XXX_RTC_READ_OFFSET 0x06 -#define PM8XXX_ALARM_RW_OFFSET 0x0A - /* RTC_CTRL register bit fields */ #define PM8xxx_RTC_ENABLE BIT(7) #define PM8xxx_RTC_ALARM_CLEAR BIT(0) -- cgit v1.2.3-70-g09d2 From 79dd75661e4284169768859012a4bf6898cef758 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Feb 2023 16:54:33 +0100 Subject: rtc: pm8xxx: use unaligned le32 helpers Use the unaligned le32 helpers instead of open coding when accessing the time and alarm registers. Signed-off-by: Johan Hovold Reviewed-by: David Collins Link: https://lore.kernel.org/r/20230202155448.6715-8-johan+linaro@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 90027a7cfb12..5ff6898bcace 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -12,6 +12,8 @@ #include #include +#include + /* RTC_CTRL register bit fields */ #define PM8xxx_RTC_ENABLE BIT(7) #define PM8xxx_RTC_ALARM_CLEAR BIT(0) @@ -68,25 +70,21 @@ struct pm8xxx_rtc { */ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) { - int rc, i; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; u8 value[NUM_8_BIT_RTC_REGS]; bool alarm_enabled; unsigned long secs; + int rc; if (!rtc_dd->allow_set_time) return -ENODEV; secs = rtc_tm_to_time64(tm); + put_unaligned_le32(secs, value); dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs); - for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) { - value[i] = secs & 0xFF; - secs >>= 8; - } - rc = regmap_update_bits_check(rtc_dd->regmap, regs->alarm_ctrl, regs->alarm_en, 0, &alarm_enabled); if (rc) @@ -157,9 +155,7 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) return rc; } - secs = value[0] | (value[1] << 8) | (value[2] << 16) | - ((unsigned long)value[3] << 24); - + secs = get_unaligned_le32(value); rtc_time64_to_tm(secs, tm); dev_dbg(dev, "secs = %lu, h:m:s == %ptRt, y-m-d = %ptRdr\n", secs, tm, tm); @@ -169,18 +165,14 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - int rc, i; u8 value[NUM_8_BIT_RTC_REGS]; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; unsigned long secs; + int rc; secs = rtc_tm_to_time64(&alarm->time); - - for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) { - value[i] = secs & 0xFF; - secs >>= 8; - } + put_unaligned_le32(secs, value); rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, regs->alarm_en, 0); @@ -219,9 +211,7 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) if (rc) return rc; - secs = value[0] | (value[1] << 8) | (value[2] << 16) | - ((unsigned long)value[3] << 24); - + secs = get_unaligned_le32(value); rtc_time64_to_tm(secs, &alarm->time); rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg); -- cgit v1.2.3-70-g09d2 From c996956fcc5b7756eb04615cc36618acaa85caa9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Feb 2023 16:54:34 +0100 Subject: rtc: pm8xxx: clean up time and alarm debugging Clean up the time and alarm callback debugging by using a consistent and succinct human-readable (i.e. non-raw) format. Signed-off-by: Johan Hovold Reviewed-by: David Collins Link: https://lore.kernel.org/r/20230202155448.6715-9-johan+linaro@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 5ff6898bcace..8c364e5d3b57 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -83,7 +83,7 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) secs = rtc_tm_to_time64(tm); put_unaligned_le32(secs, value); - dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs); + dev_dbg(dev, "set time: %ptRd %ptRt (%lu)\n", tm, tm, secs); rc = regmap_update_bits_check(rtc_dd->regmap, regs->alarm_ctrl, regs->alarm_en, 0, &alarm_enabled); @@ -158,7 +158,7 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) secs = get_unaligned_le32(value); rtc_time64_to_tm(secs, tm); - dev_dbg(dev, "secs = %lu, h:m:s == %ptRt, y-m-d = %ptRdr\n", secs, tm, tm); + dev_dbg(dev, "read time: %ptRd %ptRt (%lu)\n", tm, tm, secs); return 0; } @@ -191,8 +191,7 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) return rc; } - dev_dbg(dev, "Alarm Set for h:m:s=%ptRt, y-m-d=%ptRdr\n", - &alarm->time, &alarm->time); + dev_dbg(dev, "set alarm: %ptRd %ptRt\n", &alarm->time, &alarm->time); return 0; } @@ -220,8 +219,7 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) alarm->enabled = !!(ctrl_reg & PM8xxx_RTC_ALARM_ENABLE); - dev_dbg(dev, "Alarm set for - h:m:s=%ptRt, y-m-d=%ptRdr\n", - &alarm->time, &alarm->time); + dev_dbg(dev, "read alarm: %ptRd %ptRt\n", &alarm->time, &alarm->time); return 0; } -- cgit v1.2.3-70-g09d2 From a375510efeda0dfbad205cd1de8b57f63d0779c9 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Feb 2023 16:54:35 +0100 Subject: rtc: pm8xxx: rename struct device pointer Rename the driver-data struct device pointer by dropping the "rtc" prefix which is both redundant and misleading (as this is a pointer to the platform device and not the rtc class device). Signed-off-by: Johan Hovold Reviewed-by: David Collins Link: https://lore.kernel.org/r/20230202155448.6715-10-johan+linaro@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 8c364e5d3b57..0fdbd233b10e 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -48,7 +48,7 @@ struct pm8xxx_rtc_regs { * @allow_set_time: indicates whether writing to the RTC is allowed * @rtc_alarm_irq: rtc alarm irq number. * @regs: rtc registers description. - * @rtc_dev: device structure. + * @dev: device structure */ struct pm8xxx_rtc { struct rtc_device *rtc; @@ -56,7 +56,7 @@ struct pm8xxx_rtc { bool allow_set_time; int rtc_alarm_irq; const struct pm8xxx_rtc_regs *regs; - struct device *rtc_dev; + struct device *dev; }; /* @@ -372,7 +372,7 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) "allow-set-time"); rtc_dd->regs = match->data; - rtc_dd->rtc_dev = &pdev->dev; + rtc_dd->dev = &pdev->dev; rc = pm8xxx_rtc_enable(rtc_dd); if (rc) -- cgit v1.2.3-70-g09d2 From 4727b58fc84daf6d7097ac3528a6517456a5e110 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Feb 2023 16:54:36 +0100 Subject: rtc: pm8xxx: rename alarm irq variable Clean up the driver somewhat by renaming the driver-data alarm irq variable by dropping the redundant "rtc" prefix. Signed-off-by: Johan Hovold Reviewed-by: David Collins Link: https://lore.kernel.org/r/20230202155448.6715-11-johan+linaro@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 0fdbd233b10e..ea867b20573a 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -46,7 +46,7 @@ struct pm8xxx_rtc_regs { * @rtc: rtc device for this driver. * @regmap: regmap used to access RTC registers * @allow_set_time: indicates whether writing to the RTC is allowed - * @rtc_alarm_irq: rtc alarm irq number. + * @alarm_irq: alarm irq number * @regs: rtc registers description. * @dev: device structure */ @@ -54,7 +54,7 @@ struct pm8xxx_rtc { struct rtc_device *rtc; struct regmap *regmap; bool allow_set_time; - int rtc_alarm_irq; + int alarm_irq; const struct pm8xxx_rtc_regs *regs; struct device *dev; }; @@ -364,8 +364,8 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) return -ENXIO; } - rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 0); - if (rtc_dd->rtc_alarm_irq < 0) + rtc_dd->alarm_irq = platform_get_irq(pdev, 0); + if (rtc_dd->alarm_irq < 0) return -ENXIO; rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node, @@ -391,7 +391,7 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) rtc_dd->rtc->range_max = U32_MAX; /* Request the alarm IRQ */ - rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->rtc_alarm_irq, + rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->alarm_irq, pm8xxx_alarm_trigger, IRQF_TRIGGER_RISING, "pm8xxx_rtc_alarm", rtc_dd); @@ -404,7 +404,7 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) if (rc) return rc; - rc = dev_pm_set_wake_irq(&pdev->dev, rtc_dd->rtc_alarm_irq); + rc = dev_pm_set_wake_irq(&pdev->dev, rtc_dd->alarm_irq); if (rc) return rc; -- cgit v1.2.3-70-g09d2 From 3c3326394ba420608d0665aef846b2268c9c9629 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Feb 2023 16:54:37 +0100 Subject: rtc: pm8xxx: clean up comments Clean up the driver comments somewhat and remove obsolete, incorrect or redundant ones. Signed-off-by: Johan Hovold Reviewed-by: David Collins Link: https://lore.kernel.org/r/20230202155448.6715-12-johan+linaro@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 39 +++++++++++++++++---------------------- 1 file changed, 17 insertions(+), 22 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index ea867b20573a..8a94a19e0d14 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -23,13 +23,13 @@ /** * struct pm8xxx_rtc_regs - describe RTC registers per PMIC versions - * @ctrl: base address of control register - * @write: base address of write register - * @read: base address of read register - * @alarm_ctrl: base address of alarm control register - * @alarm_ctrl2: base address of alarm control2 register - * @alarm_rw: base address of alarm read-write register - * @alarm_en: alarm enable mask + * @ctrl: address of control register + * @write: base address of write registers + * @read: base address of read registers + * @alarm_ctrl: address of alarm control register + * @alarm_ctrl2: address of alarm control2 register + * @alarm_rw: base address of alarm read-write registers + * @alarm_en: alarm enable mask */ struct pm8xxx_rtc_regs { unsigned int ctrl; @@ -42,12 +42,12 @@ struct pm8xxx_rtc_regs { }; /** - * struct pm8xxx_rtc - rtc driver internal structure - * @rtc: rtc device for this driver. - * @regmap: regmap used to access RTC registers - * @allow_set_time: indicates whether writing to the RTC is allowed + * struct pm8xxx_rtc - RTC driver internal structure + * @rtc: RTC device + * @regmap: regmap used to access registers + * @allow_set_time: whether the time can be set * @alarm_irq: alarm irq number - * @regs: rtc registers description. + * @regs: register description * @dev: device structure */ struct pm8xxx_rtc { @@ -90,7 +90,7 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) if (rc) return rc; - /* Disable RTC H/w before writing on RTC register */ + /* Disable RTC */ rc = regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE, 0); if (rc) return rc; @@ -111,7 +111,7 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) if (rc) return rc; - /* Enable RTC H/w after writing on RTC register */ + /* Enable RTC */ rc = regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE, PM8xxx_RTC_ENABLE); if (rc) @@ -242,7 +242,7 @@ static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) if (rc) return rc; - /* Clear Alarm register */ + /* Clear alarm register */ if (!enable) { rc = regmap_bulk_write(rtc_dd->regmap, regs->alarm_rw, value, sizeof(value)); @@ -269,13 +269,13 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id) rtc_update_irq(rtc_dd->rtc, 1, RTC_IRQF | RTC_AF); - /* Clear the alarm enable bit */ + /* Disable alarm */ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, regs->alarm_en, 0); if (rc) return IRQ_NONE; - /* Clear RTC alarm register */ + /* Clear alarm status */ rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl2, PM8xxx_RTC_ALARM_CLEAR, 0); if (rc) @@ -332,9 +332,6 @@ static const struct pm8xxx_rtc_regs pmk8350_regs = { .alarm_en = BIT(7), }; -/* - * Hardcoded RTC bases until IORESOURCE_REG mapping is figured out - */ static const struct of_device_id pm8xxx_id_table[] = { { .compatible = "qcom,pm8921-rtc", .data = &pm8921_regs }, { .compatible = "qcom,pm8058-rtc", .data = &pm8058_regs }, @@ -382,7 +379,6 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 1); - /* Register the RTC device */ rtc_dd->rtc = devm_rtc_allocate_device(&pdev->dev); if (IS_ERR(rtc_dd->rtc)) return PTR_ERR(rtc_dd->rtc); @@ -390,7 +386,6 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) rtc_dd->rtc->ops = &pm8xxx_rtc_ops; rtc_dd->rtc->range_max = U32_MAX; - /* Request the alarm IRQ */ rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->alarm_irq, pm8xxx_alarm_trigger, IRQF_TRIGGER_RISING, -- cgit v1.2.3-70-g09d2 From 35d9c472925748a1cb1f5b6cc8ae71cf8138e30f Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Feb 2023 16:54:38 +0100 Subject: rtc: pm8xxx: use u32 for timestamps The PMIC RTC registers are 32-bit so explicitly use u32 rather than unsigned long for timestamps to reflect the hardware. This will also help avoid unintentional range extensions when adding support for managing an external offset. Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230202155448.6715-13-johan+linaro@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 8a94a19e0d14..b1ce246c501a 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -74,7 +74,7 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; u8 value[NUM_8_BIT_RTC_REGS]; bool alarm_enabled; - unsigned long secs; + u32 secs; int rc; if (!rtc_dd->allow_set_time) @@ -83,7 +83,7 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) secs = rtc_tm_to_time64(tm); put_unaligned_le32(secs, value); - dev_dbg(dev, "set time: %ptRd %ptRt (%lu)\n", tm, tm, secs); + dev_dbg(dev, "set time: %ptRd %ptRt (%u)\n", tm, tm, secs); rc = regmap_update_bits_check(rtc_dd->regmap, regs->alarm_ctrl, regs->alarm_en, 0, &alarm_enabled); @@ -131,10 +131,10 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) { int rc; u8 value[NUM_8_BIT_RTC_REGS]; - unsigned long secs; unsigned int reg; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; + u32 secs; rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value, sizeof(value)); if (rc) @@ -158,7 +158,7 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) secs = get_unaligned_le32(value); rtc_time64_to_tm(secs, tm); - dev_dbg(dev, "read time: %ptRd %ptRt (%lu)\n", tm, tm, secs); + dev_dbg(dev, "read time: %ptRd %ptRt (%u)\n", tm, tm, secs); return 0; } @@ -168,7 +168,7 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) u8 value[NUM_8_BIT_RTC_REGS]; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; - unsigned long secs; + u32 secs; int rc; secs = rtc_tm_to_time64(&alarm->time); @@ -201,9 +201,9 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) int rc; unsigned int ctrl_reg; u8 value[NUM_8_BIT_RTC_REGS]; - unsigned long secs; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; + u32 secs; rc = regmap_bulk_read(rtc_dd->regmap, regs->alarm_rw, value, sizeof(value)); -- cgit v1.2.3-70-g09d2 From da862c3df6add928e2f51d6cadec128a9a1940f3 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Feb 2023 16:54:39 +0100 Subject: rtc: pm8xxx: refactor read_time() In preparation for adding support for setting the time by means of an externally stored offset, refactor read_time() by adding a new helper that can be used to retrieve the raw time as stored in the RTC. Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230202155448.6715-14-johan+linaro@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 54 +++++++++++++++++++++++++++++------------------- 1 file changed, 33 insertions(+), 21 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index b1ce246c501a..2f96a178595c 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -59,6 +59,37 @@ struct pm8xxx_rtc { struct device *dev; }; +static int pm8xxx_rtc_read_raw(struct pm8xxx_rtc *rtc_dd, u32 *secs) +{ + const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; + u8 value[NUM_8_BIT_RTC_REGS]; + unsigned int reg; + int rc; + + rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value, sizeof(value)); + if (rc) + return rc; + + /* + * Read the LSB again and check if there has been a carry over. + * If there has, redo the read operation. + */ + rc = regmap_read(rtc_dd->regmap, regs->read, ®); + if (rc < 0) + return rc; + + if (reg < value[0]) { + rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value, + sizeof(value)); + if (rc) + return rc; + } + + *secs = get_unaligned_le32(value); + + return 0; +} + /* * Steps to write the RTC registers. * 1. Disable alarm if enabled. @@ -129,33 +160,14 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) { - int rc; - u8 value[NUM_8_BIT_RTC_REGS]; - unsigned int reg; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); - const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; u32 secs; + int rc; - rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value, sizeof(value)); + rc = pm8xxx_rtc_read_raw(rtc_dd, &secs); if (rc) return rc; - /* - * Read the LSB again and check if there has been a carry over. - * If there is, redo the read operation. - */ - rc = regmap_read(rtc_dd->regmap, regs->read, ®); - if (rc < 0) - return rc; - - if (unlikely(reg < value[0])) { - rc = regmap_bulk_read(rtc_dd->regmap, regs->read, - value, sizeof(value)); - if (rc) - return rc; - } - - secs = get_unaligned_le32(value); rtc_time64_to_tm(secs, tm); dev_dbg(dev, "read time: %ptRd %ptRt (%u)\n", tm, tm, secs); -- cgit v1.2.3-70-g09d2 From 9e5a799138042ac8276e6744c548b0411f371600 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Feb 2023 16:54:40 +0100 Subject: rtc: pm8xxx: clean up local declarations Clean up local declarations somewhat by using the reverse xmas style consistently throughout. Signed-off-by: Johan Hovold Reviewed-by: David Collins Link: https://lore.kernel.org/r/20230202155448.6715-15-johan+linaro@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 2f96a178595c..922aef0f0241 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -177,9 +177,9 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - u8 value[NUM_8_BIT_RTC_REGS]; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; + u8 value[NUM_8_BIT_RTC_REGS]; u32 secs; int rc; @@ -210,12 +210,12 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) { - int rc; - unsigned int ctrl_reg; - u8 value[NUM_8_BIT_RTC_REGS]; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; + u8 value[NUM_8_BIT_RTC_REGS]; + unsigned int ctrl_reg; u32 secs; + int rc; rc = regmap_bulk_read(rtc_dd->regmap, regs->alarm_rw, value, sizeof(value)); @@ -238,11 +238,11 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) { - int rc; struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; u8 value[NUM_8_BIT_RTC_REGS] = {0}; unsigned int val; + int rc; if (enable) val = regs->alarm_en; @@ -355,9 +355,9 @@ MODULE_DEVICE_TABLE(of, pm8xxx_id_table); static int pm8xxx_rtc_probe(struct platform_device *pdev) { - int rc; - struct pm8xxx_rtc *rtc_dd; const struct of_device_id *match; + struct pm8xxx_rtc *rtc_dd; + int rc; match = of_match_node(pm8xxx_id_table, pdev->dev.of_node); if (!match) -- cgit v1.2.3-70-g09d2 From c94fb939e65155bc889e62396f83ef4317d643ac Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Feb 2023 16:54:41 +0100 Subject: rtc: pm8xxx: drop error messages For consistency with the rest of the driver, drop the last two error messages for conditions that should only occur during development, if ever. Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230202155448.6715-16-johan+linaro@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 922aef0f0241..eff2782beeed 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -368,10 +368,8 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) return -ENOMEM; rtc_dd->regmap = dev_get_regmap(pdev->dev.parent, NULL); - if (!rtc_dd->regmap) { - dev_err(&pdev->dev, "Parent regmap unavailable.\n"); + if (!rtc_dd->regmap) return -ENXIO; - } rtc_dd->alarm_irq = platform_get_irq(pdev, 0); if (rtc_dd->alarm_irq < 0) @@ -402,10 +400,8 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) pm8xxx_alarm_trigger, IRQF_TRIGGER_RISING, "pm8xxx_rtc_alarm", rtc_dd); - if (rc < 0) { - dev_err(&pdev->dev, "Request IRQ failed (%d)\n", rc); + if (rc < 0) return rc; - } rc = devm_rtc_register_device(rtc_dd->rtc); if (rc) -- cgit v1.2.3-70-g09d2 From 2985cda83b8107213e108f95c3cb8caa0da74918 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Tue, 31 Jan 2023 21:48:13 -0800 Subject: rtc: moxart: switch to using gpiod API Switch the driver from legacy gpio API that is deprecated to the newer gpiod API that respects line polarities described in ACPI/DT. This makes driver use standard property name for its gpios ("rtc-*-gpios" vs "gpios-rtc-*"), however there is a quirk in gpiolib to also recognize legacy names and keep compatibility with older DTSes: eaf1a29665cd ("gpiolib: of: add a quirk for legacy names in MOXA ART RTC"). Signed-off-by: Dmitry Torokhov Link: https://lore.kernel.org/r/20230201054815.4112632-1-dmitry.torokhov@gmail.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-moxart.c | 89 ++++++++++++++++++++---------------------------- 1 file changed, 36 insertions(+), 53 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c index 6b24ac9e1cfa..2247dd39ee4b 100644 --- a/drivers/rtc/rtc-moxart.c +++ b/drivers/rtc/rtc-moxart.c @@ -10,14 +10,15 @@ * Moxa Technology Co., Ltd. */ +#include #include #include #include #include #include #include -#include -#include +#include +#include #define GPIO_RTC_RESERVED 0x0C #define GPIO_RTC_DATA_SET 0x10 @@ -55,7 +56,9 @@ struct moxart_rtc { struct rtc_device *rtc; spinlock_t rtc_lock; - int gpio_data, gpio_sclk, gpio_reset; + struct gpio_desc *gpio_data; + struct gpio_desc *gpio_sclk; + struct gpio_desc *gpio_reset; }; static int day_of_year[12] = { 0, 31, 59, 90, 120, 151, 181, @@ -67,10 +70,10 @@ static void moxart_rtc_write_byte(struct device *dev, u8 data) int i; for (i = 0; i < 8; i++, data >>= 1) { - gpio_set_value(moxart_rtc->gpio_sclk, 0); - gpio_set_value(moxart_rtc->gpio_data, ((data & 1) == 1)); + gpiod_set_value(moxart_rtc->gpio_sclk, 0); + gpiod_set_value(moxart_rtc->gpio_data, ((data & 1) == 1)); udelay(GPIO_RTC_DELAY_TIME); - gpio_set_value(moxart_rtc->gpio_sclk, 1); + gpiod_set_value(moxart_rtc->gpio_sclk, 1); udelay(GPIO_RTC_DELAY_TIME); } } @@ -82,11 +85,11 @@ static u8 moxart_rtc_read_byte(struct device *dev) u8 data = 0; for (i = 0; i < 8; i++) { - gpio_set_value(moxart_rtc->gpio_sclk, 0); + gpiod_set_value(moxart_rtc->gpio_sclk, 0); udelay(GPIO_RTC_DELAY_TIME); - gpio_set_value(moxart_rtc->gpio_sclk, 1); + gpiod_set_value(moxart_rtc->gpio_sclk, 1); udelay(GPIO_RTC_DELAY_TIME); - if (gpio_get_value(moxart_rtc->gpio_data)) + if (gpiod_get_value(moxart_rtc->gpio_data)) data |= (1 << i); udelay(GPIO_RTC_DELAY_TIME); } @@ -101,15 +104,15 @@ static u8 moxart_rtc_read_register(struct device *dev, u8 cmd) local_irq_save(flags); - gpio_direction_output(moxart_rtc->gpio_data, 0); - gpio_set_value(moxart_rtc->gpio_reset, 1); + gpiod_direction_output(moxart_rtc->gpio_data, 0); + gpiod_set_value(moxart_rtc->gpio_reset, 1); udelay(GPIO_RTC_DELAY_TIME); moxart_rtc_write_byte(dev, cmd); - gpio_direction_input(moxart_rtc->gpio_data); + gpiod_direction_input(moxart_rtc->gpio_data); udelay(GPIO_RTC_DELAY_TIME); data = moxart_rtc_read_byte(dev); - gpio_set_value(moxart_rtc->gpio_sclk, 0); - gpio_set_value(moxart_rtc->gpio_reset, 0); + gpiod_set_value(moxart_rtc->gpio_sclk, 0); + gpiod_set_value(moxart_rtc->gpio_reset, 0); udelay(GPIO_RTC_DELAY_TIME); local_irq_restore(flags); @@ -124,13 +127,13 @@ static void moxart_rtc_write_register(struct device *dev, u8 cmd, u8 data) local_irq_save(flags); - gpio_direction_output(moxart_rtc->gpio_data, 0); - gpio_set_value(moxart_rtc->gpio_reset, 1); + gpiod_direction_output(moxart_rtc->gpio_data, 0); + gpiod_set_value(moxart_rtc->gpio_reset, 1); udelay(GPIO_RTC_DELAY_TIME); moxart_rtc_write_byte(dev, cmd); moxart_rtc_write_byte(dev, data); - gpio_set_value(moxart_rtc->gpio_sclk, 0); - gpio_set_value(moxart_rtc->gpio_reset, 0); + gpiod_set_value(moxart_rtc->gpio_sclk, 0); + gpiod_set_value(moxart_rtc->gpio_reset, 0); udelay(GPIO_RTC_DELAY_TIME); local_irq_restore(flags); @@ -247,53 +250,33 @@ static int moxart_rtc_probe(struct platform_device *pdev) if (!moxart_rtc) return -ENOMEM; - moxart_rtc->gpio_data = of_get_named_gpio(pdev->dev.of_node, - "gpio-rtc-data", 0); - if (!gpio_is_valid(moxart_rtc->gpio_data)) { - dev_err(&pdev->dev, "invalid gpio (data): %d\n", - moxart_rtc->gpio_data); - return moxart_rtc->gpio_data; - } - - moxart_rtc->gpio_sclk = of_get_named_gpio(pdev->dev.of_node, - "gpio-rtc-sclk", 0); - if (!gpio_is_valid(moxart_rtc->gpio_sclk)) { - dev_err(&pdev->dev, "invalid gpio (sclk): %d\n", - moxart_rtc->gpio_sclk); - return moxart_rtc->gpio_sclk; - } - - moxart_rtc->gpio_reset = of_get_named_gpio(pdev->dev.of_node, - "gpio-rtc-reset", 0); - if (!gpio_is_valid(moxart_rtc->gpio_reset)) { - dev_err(&pdev->dev, "invalid gpio (reset): %d\n", - moxart_rtc->gpio_reset); - return moxart_rtc->gpio_reset; - } - - spin_lock_init(&moxart_rtc->rtc_lock); - platform_set_drvdata(pdev, moxart_rtc); - - ret = devm_gpio_request(&pdev->dev, moxart_rtc->gpio_data, "rtc_data"); + moxart_rtc->gpio_data = devm_gpiod_get(&pdev->dev, "rtc-data", + GPIOD_IN); + ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_data); if (ret) { - dev_err(&pdev->dev, "can't get rtc_data gpio\n"); + dev_err(&pdev->dev, "can't get rtc data gpio: %d\n", ret); return ret; } - ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_sclk, - GPIOF_DIR_OUT, "rtc_sclk"); + moxart_rtc->gpio_sclk = devm_gpiod_get(&pdev->dev, "rtc-sclk", + GPIOD_ASIS); + ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_sclk); if (ret) { - dev_err(&pdev->dev, "can't get rtc_sclk gpio\n"); + dev_err(&pdev->dev, "can't get rtc sclk gpio: %d\n", ret); return ret; } - ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_reset, - GPIOF_DIR_OUT, "rtc_reset"); + moxart_rtc->gpio_reset = devm_gpiod_get(&pdev->dev, "rtc-reset", + GPIOD_ASIS); + ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_reset); if (ret) { - dev_err(&pdev->dev, "can't get rtc_reset gpio\n"); + dev_err(&pdev->dev, "can't get rtc reset gpio: %d\n", ret); return ret; } + spin_lock_init(&moxart_rtc->rtc_lock); + platform_set_drvdata(pdev, moxart_rtc); + moxart_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &moxart_rtc_ops, THIS_MODULE); -- cgit v1.2.3-70-g09d2 From d644b133f78d6d8efd36f7b1703bebca09036f0b Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 29 Jan 2023 12:04:40 +0000 Subject: rtc: jz4740: Use readl_poll_timeout Use readl_poll_timeout() from instead of using custom poll loops. The timeout settings are different, but that shouldn't be much of a problem. Instead of polling 10000 times in a close loop, it polls for one millisecond. Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20230129120442.22858-3-paul@crapouillou.net Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-jz4740.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index c383719292c7..4ee6e5ee09b1 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -7,6 +7,7 @@ #include #include +#include #include #include #include @@ -69,19 +70,15 @@ static inline uint32_t jz4740_rtc_reg_read(struct jz4740_rtc *rtc, size_t reg) static int jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc) { uint32_t ctrl; - int timeout = 10000; - do { - ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL); - } while (!(ctrl & JZ_RTC_CTRL_WRDY) && --timeout); - - return timeout ? 0 : -EIO; + return readl_poll_timeout(rtc->base + JZ_REG_RTC_CTRL, ctrl, + ctrl & JZ_RTC_CTRL_WRDY, 0, 1000); } static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc) { uint32_t ctrl; - int ret, timeout = 10000; + int ret; ret = jz4740_rtc_wait_write_ready(rtc); if (ret != 0) @@ -89,11 +86,8 @@ static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc) writel(JZ_RTC_WENR_MAGIC, rtc->base + JZ_REG_RTC_WENR); - do { - ctrl = readl(rtc->base + JZ_REG_RTC_WENR); - } while (!(ctrl & JZ_RTC_WENR_WEN) && --timeout); - - return timeout ? 0 : -EIO; + return readl_poll_timeout(rtc->base + JZ_REG_RTC_WENR, ctrl, + ctrl & JZ_RTC_WENR_WEN, 0, 1000); } static inline int jz4740_rtc_reg_write(struct jz4740_rtc *rtc, size_t reg, -- cgit v1.2.3-70-g09d2 From ff6fd3770e9687d7b849a0e826a32563bfcb98da Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 29 Jan 2023 12:04:41 +0000 Subject: rtc: jz4740: Use dev_err_probe() Use dev_err_probe() where it makes sense to simplify a bit the code. Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20230129120442.22858-4-paul@crapouillou.net Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-jz4740.c | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 4ee6e5ee09b1..9ffa764aa71e 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -329,17 +329,13 @@ static int jz4740_rtc_probe(struct platform_device *pdev) device_init_wakeup(dev, 1); ret = dev_pm_set_wake_irq(dev, irq); - if (ret) { - dev_err(dev, "Failed to set wake irq: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to set wake irq\n"); rtc->rtc = devm_rtc_allocate_device(dev); - if (IS_ERR(rtc->rtc)) { - ret = PTR_ERR(rtc->rtc); - dev_err(dev, "Failed to allocate rtc device: %d\n", ret); - return ret; - } + if (IS_ERR(rtc->rtc)) + return dev_err_probe(dev, PTR_ERR(rtc->rtc), + "Failed to allocate rtc device\n"); rtc->rtc->ops = &jz4740_rtc_ops; rtc->rtc->range_max = U32_MAX; @@ -356,10 +352,8 @@ static int jz4740_rtc_probe(struct platform_device *pdev) ret = devm_request_irq(dev, irq, jz4740_rtc_irq, 0, pdev->name, rtc); - if (ret) { - dev_err(dev, "Failed to request rtc irq: %d\n", ret); - return ret; - } + if (ret) + return dev_err_probe(dev, ret, "Failed to request rtc irq\n"); if (of_device_is_system_power_controller(np)) { dev_for_power_off = dev; -- cgit v1.2.3-70-g09d2 From 5ddfa148de8cf5491fd1c89522c7cad859db8c88 Mon Sep 17 00:00:00 2001 From: Paul Cercueil Date: Sun, 29 Jan 2023 12:04:42 +0000 Subject: rtc: jz4740: Register clock provider for the CLK32K pin On JZ4770 and JZ4780, the CLK32K pin is configurable. By default, it is configured as a GPIO in input mode, and its value can be read through GPIO PD14. With this change, clients can now request the 32 kHz clock on the CLK32K pin, through Device Tree. This clock is simply a pass-through of the input oscillator's clock with enable/disable operations. This will permit the WiFi/Bluetooth chip to work on the MIPS CI20 board, which does source one of its clocks from the CLK32K pin. Signed-off-by: Paul Cercueil Link: https://lore.kernel.org/r/20230129120442.22858-5-paul@crapouillou.net Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 2 +- drivers/rtc/rtc-jz4740.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 677d2601d305..d2b6d20a6745 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1690,7 +1690,7 @@ config RTC_DRV_MPC5121 config RTC_DRV_JZ4740 tristate "Ingenic JZ4740 SoC" depends on MIPS || COMPILE_TEST - depends on OF + depends on OF && COMMON_CLK help If you say yes here you get support for the Ingenic JZ47xx SoCs RTC controllers. diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 9ffa764aa71e..59d279e3e6f5 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -26,6 +28,7 @@ #define JZ_REG_RTC_WAKEUP_FILTER 0x24 #define JZ_REG_RTC_RESET_COUNTER 0x28 #define JZ_REG_RTC_SCRATCHPAD 0x34 +#define JZ_REG_RTC_CKPCR 0x40 /* The following are present on the jz4780 */ #define JZ_REG_RTC_WENR 0x3C @@ -45,6 +48,9 @@ #define JZ_RTC_WAKEUP_FILTER_MASK 0x0000FFE0 #define JZ_RTC_RESET_COUNTER_MASK 0x00000FE0 +#define JZ_RTC_CKPCR_CK32PULL_DIS BIT(4) +#define JZ_RTC_CKPCR_CK32CTL_EN (BIT(2) | BIT(1)) + enum jz4740_rtc_type { ID_JZ4740, ID_JZ4760, @@ -57,6 +63,8 @@ struct jz4740_rtc { struct rtc_device *rtc; + struct clk_hw clk32k; + spinlock_t lock; }; @@ -254,6 +262,7 @@ static void jz4740_rtc_power_off(void) static const struct of_device_id jz4740_rtc_of_match[] = { { .compatible = "ingenic,jz4740-rtc", .data = (void *)ID_JZ4740 }, { .compatible = "ingenic,jz4760-rtc", .data = (void *)ID_JZ4760 }, + { .compatible = "ingenic,jz4770-rtc", .data = (void *)ID_JZ4780 }, { .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 }, {}, }; @@ -295,6 +304,38 @@ static void jz4740_rtc_set_wakeup_params(struct jz4740_rtc *rtc, jz4740_rtc_reg_write(rtc, JZ_REG_RTC_RESET_COUNTER, reset_ticks); } +static int jz4740_rtc_clk32k_enable(struct clk_hw *hw) +{ + struct jz4740_rtc *rtc = container_of(hw, struct jz4740_rtc, clk32k); + + return jz4740_rtc_reg_write(rtc, JZ_REG_RTC_CKPCR, + JZ_RTC_CKPCR_CK32PULL_DIS | + JZ_RTC_CKPCR_CK32CTL_EN); +} + +static void jz4740_rtc_clk32k_disable(struct clk_hw *hw) +{ + struct jz4740_rtc *rtc = container_of(hw, struct jz4740_rtc, clk32k); + + jz4740_rtc_reg_write(rtc, JZ_REG_RTC_CKPCR, 0); +} + +static int jz4740_rtc_clk32k_is_enabled(struct clk_hw *hw) +{ + struct jz4740_rtc *rtc = container_of(hw, struct jz4740_rtc, clk32k); + u32 ckpcr; + + ckpcr = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CKPCR); + + return !!(ckpcr & JZ_RTC_CKPCR_CK32CTL_EN); +} + +static const struct clk_ops jz4740_rtc_clk32k_ops = { + .enable = jz4740_rtc_clk32k_enable, + .disable = jz4740_rtc_clk32k_disable, + .is_enabled = jz4740_rtc_clk32k_is_enabled, +}; + static int jz4740_rtc_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -364,6 +405,21 @@ static int jz4740_rtc_probe(struct platform_device *pdev) dev_warn(dev, "Poweroff handler already present!\n"); } + if (device_property_present(dev, "#clock-cells")) { + rtc->clk32k.init = CLK_HW_INIT_HW("clk32k", __clk_get_hw(clk), + &jz4740_rtc_clk32k_ops, 0); + + ret = devm_clk_hw_register(dev, &rtc->clk32k); + if (ret) + return dev_err_probe(dev, ret, + "Unable to register clk32k clock\n"); + + ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &rtc->clk32k); + if (ret) + return dev_err_probe(dev, ret, + "Unable to register clk32k clock provider\n"); + } + return 0; } -- cgit v1.2.3-70-g09d2 From eb7b85853c3866236f9cb378fc68ce5f76efbf9c Mon Sep 17 00:00:00 2001 From: Jacky Bai Date: Wed, 15 Feb 2023 10:41:16 +0800 Subject: rtc: bbnsm: Add the bbnsm rtc support The BBNSM module includes a real time counter with alarm. Add a RTC driver for this function. Signed-off-by: Jacky Bai Reviewed-by: Peng Fan Link: https://lore.kernel.org/r/20230215024117.3357341-3-ping.bai@nxp.com Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 12 +++ drivers/rtc/Makefile | 1 + drivers/rtc/rtc-nxp-bbnsm.c | 226 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 239 insertions(+) create mode 100644 drivers/rtc/rtc-nxp-bbnsm.c (limited to 'drivers/rtc') diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index d2b6d20a6745..d2a7fbc2c932 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -1786,6 +1786,18 @@ config RTC_DRV_SNVS This driver can also be built as a module, if so, the module will be called "rtc-snvs". +config RTC_DRV_BBNSM + tristate "NXP BBNSM RTC support" + select REGMAP_MMIO + depends on ARCH_MXC || COMPILE_TEST + depends on HAS_IOMEM + depends on OF + help + If you say yes here you get support for the NXP BBNSM RTC module. + + This driver can also be built as a module, if so, the module + will be called "rtc-bbnsm". + config RTC_DRV_IMX_SC depends on IMX_SCU depends on HAVE_ARM_SMCCC diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index d3c042dcbc73..0f11027a7388 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -33,6 +33,7 @@ obj-$(CONFIG_RTC_DRV_ASPEED) += rtc-aspeed.o obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o +obj-$(CONFIG_RTC_DRV_BBNSM) += rtc-nxp-bbnsm.o obj-$(CONFIG_RTC_DRV_BD70528) += rtc-bd70528.o obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o diff --git a/drivers/rtc/rtc-nxp-bbnsm.c b/drivers/rtc/rtc-nxp-bbnsm.c new file mode 100644 index 000000000000..acbfbeb8b070 --- /dev/null +++ b/drivers/rtc/rtc-nxp-bbnsm.c @@ -0,0 +1,226 @@ +// SPDX-License-Identifier: GPL-2.0+ +// +// Copyright 2022 NXP. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BBNSM_CTRL 0x8 +#define BBNSM_INT_EN 0x10 +#define BBNSM_EVENTS 0x14 +#define BBNSM_RTC_LS 0x40 +#define BBNSM_RTC_MS 0x44 +#define BBNSM_TA 0x50 + +#define RTC_EN 0x2 +#define RTC_EN_MSK 0x3 +#define TA_EN (0x2 << 2) +#define TA_DIS (0x1 << 2) +#define TA_EN_MSK (0x3 << 2) +#define RTC_INT_EN 0x2 +#define TA_INT_EN (0x2 << 2) + +#define BBNSM_EVENT_TA (0x2 << 2) + +#define CNTR_TO_SECS_SH 15 + +struct bbnsm_rtc { + struct rtc_device *rtc; + struct regmap *regmap; + int irq; + struct clk *clk; +}; + +static u32 bbnsm_read_counter(struct bbnsm_rtc *bbnsm) +{ + u32 rtc_msb, rtc_lsb; + unsigned int timeout = 100; + u32 time; + u32 tmp = 0; + + do { + time = tmp; + /* read the msb */ + regmap_read(bbnsm->regmap, BBNSM_RTC_MS, &rtc_msb); + /* read the lsb */ + regmap_read(bbnsm->regmap, BBNSM_RTC_LS, &rtc_lsb); + /* convert to seconds */ + tmp = (rtc_msb << 17) | (rtc_lsb >> 15); + } while (tmp != time && --timeout); + + return time; +} + +static int bbnsm_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev); + unsigned long time; + u32 val; + + regmap_read(bbnsm->regmap, BBNSM_CTRL, &val); + if ((val & RTC_EN_MSK) != RTC_EN) + return -EINVAL; + + time = bbnsm_read_counter(bbnsm); + rtc_time64_to_tm(time, tm); + + return 0; +} + +static int bbnsm_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev); + unsigned long time = rtc_tm_to_time64(tm); + + /* disable the RTC first */ + regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, RTC_EN_MSK, 0); + + /* write the 32bit sec time to 47 bit timer counter, leaving 15 LSBs blank */ + regmap_write(bbnsm->regmap, BBNSM_RTC_LS, time << CNTR_TO_SECS_SH); + regmap_write(bbnsm->regmap, BBNSM_RTC_MS, time >> (32 - CNTR_TO_SECS_SH)); + + /* Enable the RTC again */ + regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, RTC_EN_MSK, RTC_EN); + + return 0; +} + +static int bbnsm_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev); + u32 bbnsm_events, bbnsm_ta; + + regmap_read(bbnsm->regmap, BBNSM_TA, &bbnsm_ta); + rtc_time64_to_tm(bbnsm_ta, &alrm->time); + + regmap_read(bbnsm->regmap, BBNSM_EVENTS, &bbnsm_events); + alrm->pending = (bbnsm_events & BBNSM_EVENT_TA) ? 1 : 0; + + return 0; +} + +static int bbnsm_rtc_alarm_irq_enable(struct device *dev, unsigned int enable) +{ + struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev); + + /* enable the alarm event */ + regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, TA_EN_MSK, enable ? TA_EN : TA_DIS); + /* enable the alarm interrupt */ + regmap_update_bits(bbnsm->regmap, BBNSM_INT_EN, TA_EN_MSK, enable ? TA_EN : TA_DIS); + + return 0; +} + +static int bbnsm_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev); + unsigned long time = rtc_tm_to_time64(&alrm->time); + + /* disable the alarm */ + regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, TA_EN, TA_EN); + + /* write the seconds to TA */ + regmap_write(bbnsm->regmap, BBNSM_TA, time); + + return bbnsm_rtc_alarm_irq_enable(dev, alrm->enabled); +} + +static const struct rtc_class_ops bbnsm_rtc_ops = { + .read_time = bbnsm_rtc_read_time, + .set_time = bbnsm_rtc_set_time, + .read_alarm = bbnsm_rtc_read_alarm, + .set_alarm = bbnsm_rtc_set_alarm, + .alarm_irq_enable = bbnsm_rtc_alarm_irq_enable, +}; + +static irqreturn_t bbnsm_rtc_irq_handler(int irq, void *dev_id) +{ + struct device *dev = dev_id; + struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev); + u32 val; + + regmap_read(bbnsm->regmap, BBNSM_EVENTS, &val); + if (val & BBNSM_EVENT_TA) { + bbnsm_rtc_alarm_irq_enable(dev, false); + /* clear the alarm event */ + regmap_write_bits(bbnsm->regmap, BBNSM_EVENTS, TA_EN_MSK, BBNSM_EVENT_TA); + rtc_update_irq(bbnsm->rtc, 1, RTC_AF | RTC_IRQF); + + return IRQ_HANDLED; + } + + return IRQ_NONE; +} + +static int bbnsm_rtc_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + struct bbnsm_rtc *bbnsm; + int ret; + + bbnsm = devm_kzalloc(&pdev->dev, sizeof(*bbnsm), GFP_KERNEL); + if (!bbnsm) + return -ENOMEM; + + bbnsm->rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(bbnsm->rtc)) + return PTR_ERR(bbnsm->rtc); + + bbnsm->regmap = syscon_node_to_regmap(np->parent); + if (IS_ERR(bbnsm->regmap)) { + dev_dbg(&pdev->dev, "bbnsm get regmap failed\n"); + return PTR_ERR(bbnsm->regmap); + } + + bbnsm->irq = platform_get_irq(pdev, 0); + if (bbnsm->irq < 0) + return bbnsm->irq; + + platform_set_drvdata(pdev, bbnsm); + + /* clear all the pending events */ + regmap_write(bbnsm->regmap, BBNSM_EVENTS, 0x7A); + + device_init_wakeup(&pdev->dev, true); + dev_pm_set_wake_irq(&pdev->dev, bbnsm->irq); + + ret = devm_request_irq(&pdev->dev, bbnsm->irq, bbnsm_rtc_irq_handler, + IRQF_SHARED, "rtc alarm", &pdev->dev); + if (ret) { + dev_err(&pdev->dev, "failed to request irq %d: %d\n", + bbnsm->irq, ret); + return ret; + } + + bbnsm->rtc->ops = &bbnsm_rtc_ops; + bbnsm->rtc->range_max = U32_MAX; + + return devm_rtc_register_device(bbnsm->rtc); +} + +static const struct of_device_id bbnsm_dt_ids[] = { + { .compatible = "nxp,imx93-bbnsm-rtc" }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, bbnsm_dt_ids); + +static struct platform_driver bbnsm_rtc_driver = { + .driver = { + .name = "bbnsm_rtc", + .of_match_table = bbnsm_dt_ids, + }, + .probe = bbnsm_rtc_probe, +}; +module_platform_driver(bbnsm_rtc_driver); + +MODULE_AUTHOR("Jacky Bai "); +MODULE_DESCRIPTION("NXP BBNSM RTC Driver"); +MODULE_LICENSE("GPL"); -- cgit v1.2.3-70-g09d2 From b6ef5d4a0295bc0567021c0102d1c66f2ed212a2 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 14 Feb 2023 21:26:53 +0100 Subject: rtc: rv3028: add ACPI support The RV-3028 has been assigned the MCRY3028 ACPI ID. Link: https://lore.kernel.org/r/20230214202653.565647-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rv3028.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rv3028.c b/drivers/rtc/rtc-rv3028.c index b0099e26e3b0..ec5d7a614e2d 100644 --- a/drivers/rtc/rtc-rv3028.c +++ b/drivers/rtc/rtc-rv3028.c @@ -982,6 +982,12 @@ static int rv3028_probe(struct i2c_client *client) return 0; } +static const struct acpi_device_id rv3028_i2c_acpi_match[] = { + { "MCRY3028" }, + { } +}; +MODULE_DEVICE_TABLE(acpi, rv3028_i2c_acpi_match); + static const __maybe_unused struct of_device_id rv3028_of_match[] = { { .compatible = "microcrystal,rv3028", }, { } @@ -991,6 +997,7 @@ MODULE_DEVICE_TABLE(of, rv3028_of_match); static struct i2c_driver rv3028_driver = { .driver = { .name = "rtc-rv3028", + .acpi_match_table = rv3028_i2c_acpi_match, .of_match_table = of_match_ptr(rv3028_of_match), }, .probe_new = rv3028_probe, -- cgit v1.2.3-70-g09d2 From 2d433e9c897dcb0b70ef17b536f61430b1e151d4 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 14 Feb 2023 21:27:15 +0100 Subject: rtc: rv3032: add ACPI support The RV-3032 has been assigned the MCRY3032 ACPI ID. Link: https://lore.kernel.org/r/20230214202716.565749-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rv3032.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rv3032.c b/drivers/rtc/rtc-rv3032.c index bf6954ec5943..1ff4f2e6fa77 100644 --- a/drivers/rtc/rtc-rv3032.c +++ b/drivers/rtc/rtc-rv3032.c @@ -980,6 +980,12 @@ static int rv3032_probe(struct i2c_client *client) return 0; } +static const struct acpi_device_id rv3032_i2c_acpi_match[] = { + { "MCRY3032" }, + { } +}; +MODULE_DEVICE_TABLE(acpi, rv3032_i2c_acpi_match); + static const __maybe_unused struct of_device_id rv3032_of_match[] = { { .compatible = "microcrystal,rv3032", }, { } @@ -989,6 +995,7 @@ MODULE_DEVICE_TABLE(of, rv3032_of_match); static struct i2c_driver rv3032_driver = { .driver = { .name = "rtc-rv3032", + .acpi_match_table = rv3032_i2c_acpi_match, .of_match_table = of_match_ptr(rv3032_of_match), }, .probe_new = rv3032_probe, -- cgit v1.2.3-70-g09d2 From a783c962619271a8b905efad1d89adfec11ae0c8 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 14 Feb 2023 23:27:53 +0100 Subject: rtc: allow rtc_read_alarm without read_alarm callback .read_alarm is not necessary to read the current alarm because it is recorded in the aie_timer and so rtc_read_alarm() will never call rtc_read_alarm_internal() which is the only function calling the callback. Reported-by: Zhipeng Wang Reported-by: Marcel Ziswiler Fixes: 7ae41220ef58 ("rtc: introduce features bitfield") Tested-by: Philippe Schenker Link: https://lore.kernel.org/r/20230214222754.582582-1-alexandre.belloni@bootlin.com Signed-off-by: Alexandre Belloni --- drivers/rtc/interface.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 7c30cb3c764d..499d89150afc 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -392,7 +392,7 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) return err; if (!rtc->ops) { err = -ENODEV; - } else if (!test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->read_alarm) { + } else if (!test_bit(RTC_FEATURE_ALARM, rtc->features)) { err = -EINVAL; } else { memset(alarm, 0, sizeof(struct rtc_wkalrm)); -- cgit v1.2.3-70-g09d2 From fd9a6a13949af81062f4cd04f2c1b28ca5311e71 Mon Sep 17 00:00:00 2001 From: Javier Carrasco Date: Wed, 15 Feb 2023 09:18:15 +0100 Subject: rtc: pcf85363: add support for the quartz-load-femtofarads property The quartz oscillator load capacitance of the PCF85263 and PCF85363 can be adjusted to 6 pF, 7 pF (default) and 12.5 pF with the CL[1:0] bits in the oscillator control register (address 25h). Signed-off-by: Javier Carrasco Link: https://lore.kernel.org/r/20230215081815.3141776-3-javier.carrasco@wolfvision.net Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf85363.c | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c index 5de323acd178..8958eadf1c3e 100644 --- a/drivers/rtc/rtc-pcf85363.c +++ b/drivers/rtc/rtc-pcf85363.c @@ -101,6 +101,10 @@ #define PIN_IO_INTA_OUT 2 #define PIN_IO_INTA_HIZ 3 +#define OSC_CAP_SEL GENMASK(1, 0) +#define OSC_CAP_6000 0x01 +#define OSC_CAP_12500 0x02 + #define STOP_EN_STOP BIT(0) #define RESET_CPR 0xa4 @@ -117,6 +121,32 @@ struct pcf85x63_config { unsigned int num_nvram; }; +static int pcf85363_load_capacitance(struct pcf85363 *pcf85363, struct device_node *node) +{ + u32 load = 7000; + u8 value = 0; + + of_property_read_u32(node, "quartz-load-femtofarads", &load); + + switch (load) { + default: + dev_warn(&pcf85363->rtc->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 7000", + load); + fallthrough; + case 7000: + break; + case 6000: + value = OSC_CAP_6000; + break; + case 12500: + value = OSC_CAP_12500; + break; + } + + return regmap_update_bits(pcf85363->regmap, CTRL_OSCILLATOR, + OSC_CAP_SEL, value); +} + static int pcf85363_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct pcf85363 *pcf85363 = dev_get_drvdata(dev); @@ -372,7 +402,7 @@ static int pcf85363_probe(struct i2c_client *client) .reg_write = pcf85363_nvram_write, }, }; - int ret, i; + int ret, i, err; if (data) config = data; @@ -394,6 +424,11 @@ static int pcf85363_probe(struct i2c_client *client) if (IS_ERR(pcf85363->rtc)) return PTR_ERR(pcf85363->rtc); + err = pcf85363_load_capacitance(pcf85363, client->dev.of_node); + if (err < 0) + dev_warn(&client->dev, "failed to set xtal load capacitance: %d", + err); + pcf85363->rtc->ops = &rtc_ops; pcf85363->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; pcf85363->rtc->range_max = RTC_TIMESTAMP_END_2099; -- cgit v1.2.3-70-g09d2 From f525b210e9d4dcefb88594d50e426068e62840f4 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 10 Jan 2023 16:08:02 +0200 Subject: rtc: isl12022: Get rid of unneeded private struct isl12022 First of all, the struct rtc_device pointer is kept in the managed resources, no need to keep it outside (no users in the driver). Second, replace private struct isl12022 with a regmap. Signed-off-by: Andy Shevchenko Acked-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20230110140806.87432-2-andriy.shevchenko@linux.intel.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 56 +++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 35 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index a3b0de3393f5..44058fa27277 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -46,11 +46,6 @@ static struct i2c_driver isl12022_driver; -struct isl12022 { - struct rtc_device *rtc; - struct regmap *regmap; -}; - static umode_t isl12022_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) @@ -67,8 +62,7 @@ static umode_t isl12022_hwmon_is_visible(const void *data, */ static int isl12022_hwmon_read_temp(struct device *dev, long *mC) { - struct isl12022 *isl12022 = dev_get_drvdata(dev); - struct regmap *regmap = isl12022->regmap; + struct regmap *regmap = dev_get_drvdata(dev); u8 temp_buf[2]; int temp, ret; @@ -115,23 +109,21 @@ static const struct hwmon_chip_info isl12022_hwmon_chip_info = { static void isl12022_hwmon_register(struct device *dev) { - struct isl12022 *isl12022; + struct regmap *regmap = dev_get_drvdata(dev); struct device *hwmon; int ret; if (!IS_REACHABLE(CONFIG_HWMON)) return; - isl12022 = dev_get_drvdata(dev); - - ret = regmap_update_bits(isl12022->regmap, ISL12022_REG_BETA, + ret = regmap_update_bits(regmap, ISL12022_REG_BETA, ISL12022_BETA_TSE, ISL12022_BETA_TSE); if (ret) { dev_warn(dev, "unable to enable temperature sensor\n"); return; } - hwmon = devm_hwmon_device_register_with_info(dev, "isl12022", isl12022, + hwmon = devm_hwmon_device_register_with_info(dev, "isl12022", regmap, &isl12022_hwmon_chip_info, NULL); if (IS_ERR(hwmon)) @@ -144,8 +136,7 @@ static void isl12022_hwmon_register(struct device *dev) */ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm) { - struct isl12022 *isl12022 = dev_get_drvdata(dev); - struct regmap *regmap = isl12022->regmap; + struct regmap *regmap = dev_get_drvdata(dev); uint8_t buf[ISL12022_REG_INT + 1]; int ret; @@ -190,8 +181,7 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm) static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm) { - struct isl12022 *isl12022 = dev_get_drvdata(dev); - struct regmap *regmap = isl12022->regmap; + struct regmap *regmap = dev_get_drvdata(dev); int ret; uint8_t buf[ISL12022_REG_DW + 1]; @@ -218,8 +208,7 @@ static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm) buf[ISL12022_REG_DW] = tm->tm_wday & 0x07; - return regmap_bulk_write(isl12022->regmap, ISL12022_REG_SC, - buf, sizeof(buf)); + return regmap_bulk_write(regmap, ISL12022_REG_SC, buf, sizeof(buf)); } static const struct rtc_class_ops isl12022_rtc_ops = { @@ -235,34 +224,31 @@ static const struct regmap_config regmap_config = { static int isl12022_probe(struct i2c_client *client) { - struct isl12022 *isl12022; + struct rtc_device *rtc; + struct regmap *regmap; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; - isl12022 = devm_kzalloc(&client->dev, sizeof(struct isl12022), - GFP_KERNEL); - if (!isl12022) - return -ENOMEM; - dev_set_drvdata(&client->dev, isl12022); - - isl12022->regmap = devm_regmap_init_i2c(client, ®map_config); - if (IS_ERR(isl12022->regmap)) { + regmap = devm_regmap_init_i2c(client, ®map_config); + if (IS_ERR(regmap)) { dev_err(&client->dev, "regmap allocation failed\n"); - return PTR_ERR(isl12022->regmap); + return PTR_ERR(regmap); } + dev_set_drvdata(&client->dev, regmap); + isl12022_hwmon_register(&client->dev); - isl12022->rtc = devm_rtc_allocate_device(&client->dev); - if (IS_ERR(isl12022->rtc)) - return PTR_ERR(isl12022->rtc); + rtc = devm_rtc_allocate_device(&client->dev); + if (IS_ERR(rtc)) + return PTR_ERR(rtc); - isl12022->rtc->ops = &isl12022_rtc_ops; - isl12022->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; - isl12022->rtc->range_max = RTC_TIMESTAMP_END_2099; + rtc->ops = &isl12022_rtc_ops; + rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; + rtc->range_max = RTC_TIMESTAMP_END_2099; - return devm_rtc_register_device(isl12022->rtc); + return devm_rtc_register_device(rtc); } #ifdef CONFIG_OF -- cgit v1.2.3-70-g09d2 From 93219a4fb8bdf279f749b5eef40bef1bbe805fc3 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 10 Jan 2023 16:08:03 +0200 Subject: rtc: isl12022: Explicitly use __le16 type for ISL12022_REG_TEMP_L We are reading 10-bit value in a 16-bit register in LE format. Make this explicit by using __le16 type for it and corresponding conversion function. Signed-off-by: Andy Shevchenko Acked-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20230110140806.87432-3-andriy.shevchenko@linux.intel.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index 44058fa27277..bf1aa6f6560d 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -19,6 +19,8 @@ #include #include +#include + /* ISL register offsets */ #define ISL12022_REG_SC 0x00 #define ISL12022_REG_MN 0x01 @@ -63,17 +65,16 @@ static umode_t isl12022_hwmon_is_visible(const void *data, static int isl12022_hwmon_read_temp(struct device *dev, long *mC) { struct regmap *regmap = dev_get_drvdata(dev); - u8 temp_buf[2]; int temp, ret; + __le16 buf; - ret = regmap_bulk_read(regmap, ISL12022_REG_TEMP_L, - temp_buf, sizeof(temp_buf)); + ret = regmap_bulk_read(regmap, ISL12022_REG_TEMP_L, &buf, sizeof(buf)); if (ret) return ret; /* * Temperature is represented as a 10-bit number, unit half-Kelvins. */ - temp = (temp_buf[1] << 8) | temp_buf[0]; + temp = le16_to_cpu(buf); temp *= 500; temp -= 273000; -- cgit v1.2.3-70-g09d2 From c8ae2735cb3d28892fd734804b60e5abf1f6fa91 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 10 Jan 2023 16:08:04 +0200 Subject: rtc: isl12022: Drop unneeded OF guards and of_match_ptr() Drop unneeded OF guards and of_match_ptr(). This allows use of the driver with other types of firmware such as ACPI PRP0001 based probing. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230110140806.87432-4-andriy.shevchenko@linux.intel.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index bf1aa6f6560d..77b4763f2a70 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -14,8 +14,6 @@ #include #include #include -#include -#include #include #include @@ -46,8 +44,6 @@ #define ISL12022_BETA_TSE (1 << 7) -static struct i2c_driver isl12022_driver; - static umode_t isl12022_hwmon_is_visible(const void *data, enum hwmon_sensor_types type, u32 attr, int channel) @@ -252,14 +248,12 @@ static int isl12022_probe(struct i2c_client *client) return devm_rtc_register_device(rtc); } -#ifdef CONFIG_OF static const struct of_device_id isl12022_dt_match[] = { { .compatible = "isl,isl12022" }, /* for backward compat., don't use */ { .compatible = "isil,isl12022" }, { }, }; MODULE_DEVICE_TABLE(of, isl12022_dt_match); -#endif static const struct i2c_device_id isl12022_id[] = { { "isl12022", 0 }, @@ -270,9 +264,7 @@ MODULE_DEVICE_TABLE(i2c, isl12022_id); static struct i2c_driver isl12022_driver = { .driver = { .name = "rtc-isl12022", -#ifdef CONFIG_OF - .of_match_table = of_match_ptr(isl12022_dt_match), -#endif + .of_match_table = isl12022_dt_match, }, .probe_new = isl12022_probe, .id_table = isl12022_id, -- cgit v1.2.3-70-g09d2 From 9bb1e189d7d2c3838938efcc497333803b946081 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 10 Jan 2023 16:08:05 +0200 Subject: rtc: isl12022: Join string literals back For easy grepping on debug purposes join string literals back in the messages. While at it, drop __func__ parameter from unique enough dev_dbg() message as Dynamic Debug can retrieve this at run time. Signed-off-by: Andy Shevchenko Acked-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20230110140806.87432-5-andriy.shevchenko@linux.intel.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index 77b4763f2a70..ee38c5067ea8 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -143,16 +143,12 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm) if (buf[ISL12022_REG_SR] & (ISL12022_SR_LBAT85 | ISL12022_SR_LBAT75)) { dev_warn(dev, - "voltage dropped below %u%%, " - "date and time is not reliable.\n", + "voltage dropped below %u%%, date and time is not reliable.\n", buf[ISL12022_REG_SR] & ISL12022_SR_LBAT85 ? 85 : 75); } dev_dbg(dev, - "%s: raw data is sec=%02x, min=%02x, hr=%02x, " - "mday=%02x, mon=%02x, year=%02x, wday=%02x, " - "sr=%02x, int=%02x", - __func__, + "raw data is sec=%02x, min=%02x, hr=%02x, mday=%02x, mon=%02x, year=%02x, wday=%02x, sr=%02x, int=%02x", buf[ISL12022_REG_SC], buf[ISL12022_REG_MN], buf[ISL12022_REG_HR], -- cgit v1.2.3-70-g09d2 From 303eac653a181be59674920725142cfbdd5ba4cd Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Tue, 10 Jan 2023 16:08:06 +0200 Subject: rtc: isl12022: sort header inclusion alphabetically Sort header inclusion alphabetically for better maintenance. Signed-off-by: Andy Shevchenko Acked-by: Rasmus Villemoes Link: https://lore.kernel.org/r/20230110140806.87432-6-andriy.shevchenko@linux.intel.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12022.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c index ee38c5067ea8..e68a79b5e00e 100644 --- a/drivers/rtc/rtc-isl12022.c +++ b/drivers/rtc/rtc-isl12022.c @@ -8,14 +8,14 @@ * by Alessandro Zummo . */ -#include #include -#include -#include -#include #include -#include #include +#include +#include +#include +#include +#include #include -- cgit v1.2.3-70-g09d2 From 668a2abf91143caa226b3ccd0bd4d79ea85935a6 Mon Sep 17 00:00:00 2001 From: Ard Biesheuvel Date: Fri, 17 Feb 2023 15:23:38 +0100 Subject: rtc: efi: Avoid spamming the log on RTC read failure There are cases where the EFI runtime services may end up in a funny state, e.g., due to a crash in the variable services, and this affects other EFI runtime services as well. That means that, even though GetTime() should not return an error, there are cases where it might, and there is no point in logging such an occurrence multiple times. This works around an issue where user space -apparently- keeps hitting on /dev/rtc if it fails to read the h/w clock, resulting in a tsunami of log spam and a non-responsive system as a result. Cc: Pierre Gondois Cc: Alexandru Elisei Link: https://lore.kernel.org/all/Y2o1hdZK9GGDVJsS@monolith.localdoman/ Signed-off-by: Ard Biesheuvel Link: https://lore.kernel.org/r/20230217142338.1444509-1-ardb@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-efi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index 1e8bc6cc1e12..dc6b0f4a54e2 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -164,7 +164,7 @@ static int efi_read_time(struct device *dev, struct rtc_time *tm) if (status != EFI_SUCCESS) { /* should never happen */ - dev_err(dev, "can't read time\n"); + dev_err_once(dev, "can't read time\n"); return -EINVAL; } -- cgit v1.2.3-70-g09d2 From 38892c48e54760be41f16519456d868e14933789 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Wed, 15 Feb 2023 18:50:30 +0200 Subject: rtc: rx6110: Remove unused of_gpio,h of_gpio.h provides a single function, which is not used in this driver. Remove unused header. Signed-off-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230215165030.83621-1-andriy.shevchenko@linux.intel.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx6110.c | 1 - 1 file changed, 1 deletion(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c index 76a49838014b..37608883a796 100644 --- a/drivers/rtc/rtc-rx6110.c +++ b/drivers/rtc/rtc-rx6110.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include -- cgit v1.2.3-70-g09d2 From e90ff8ede777b98b44611b416b1ae6be94258335 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Thu, 22 Dec 2022 16:45:31 -0500 Subject: rtc: abx80x: Add nvmem support This adds support for the 256-byte internal RAM. There are two windows which can be used to access this RAM: 64 bytes at 0x40 (the "standard" address space) and 128 bytes at 0x80 (the "alternate" address space). We use the standard address space because it is also accessible over SPI (if such a port is ever done). We are limited to 32-byte reads for SMBus compatibility, so there's no advantage to using the alternate address space. There are some reserved bits in the EXTRAM register, and the datasheet doesn't say what to do with them. I've opted to skip a read/modify/write and just write the whole thing. If this driver is ever converted to regmap, this would be a good place to use regmap_update_bits. Signed-off-by: Sean Anderson Link: https://lore.kernel.org/r/20221222214532.1873718-1-sean.anderson@seco.com Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-abx80x.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c index 2e0e6432901b..f34a2e59cac7 100644 --- a/drivers/rtc/rtc-abx80x.c +++ b/drivers/rtc/rtc-abx80x.c @@ -11,6 +11,7 @@ */ #include +#include #include #include #include @@ -88,6 +89,16 @@ #define ABX8XX_TRICKLE_STANDARD_DIODE 0x8 #define ABX8XX_TRICKLE_SCHOTTKY_DIODE 0x4 +#define ABX8XX_REG_EXTRAM 0x3f +#define ABX8XX_EXTRAM_XADS GENMASK(1, 0) + +#define ABX8XX_SRAM_BASE 0x40 +#define ABX8XX_SRAM_WIN_SIZE 0x40 +#define ABX8XX_RAM_SIZE 256 + +#define NVMEM_ADDR_LOWER GENMASK(5, 0) +#define NVMEM_ADDR_UPPER GENMASK(7, 6) + static u8 trickle_resistors[] = {0, 3, 6, 11}; enum abx80x_chip {AB0801, AB0803, AB0804, AB0805, @@ -674,6 +685,68 @@ static int abx80x_setup_watchdog(struct abx80x_priv *priv) } #endif +static int abx80x_nvmem_xfer(struct abx80x_priv *priv, unsigned int offset, + void *val, size_t bytes, bool write) +{ + int ret; + + while (bytes) { + u8 extram, reg, len, lower, upper; + + lower = FIELD_GET(NVMEM_ADDR_LOWER, offset); + upper = FIELD_GET(NVMEM_ADDR_UPPER, offset); + extram = FIELD_PREP(ABX8XX_EXTRAM_XADS, upper); + reg = ABX8XX_SRAM_BASE + lower; + len = min(lower + bytes, (size_t)ABX8XX_SRAM_WIN_SIZE) - lower; + len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX); + + ret = i2c_smbus_write_byte_data(priv->client, ABX8XX_REG_EXTRAM, + extram); + if (ret) + return ret; + + if (write) + ret = i2c_smbus_write_i2c_block_data(priv->client, reg, + len, val); + else + ret = i2c_smbus_read_i2c_block_data(priv->client, reg, + len, val); + if (ret) + return ret; + + offset += len; + val += len; + bytes -= len; + } + + return 0; +} + +static int abx80x_nvmem_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + return abx80x_nvmem_xfer(priv, offset, val, bytes, false); +} + +static int abx80x_nvmem_write(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + return abx80x_nvmem_xfer(priv, offset, val, bytes, true); +} + +static int abx80x_setup_nvmem(struct abx80x_priv *priv) +{ + struct nvmem_config config = { + .type = NVMEM_TYPE_BATTERY_BACKED, + .reg_read = abx80x_nvmem_read, + .reg_write = abx80x_nvmem_write, + .size = ABX8XX_RAM_SIZE, + .priv = priv, + }; + + return devm_rtc_nvmem_register(priv->rtc, &config); +} + static const struct i2c_device_id abx80x_id[] = { { "abx80x", ABX80X }, { "ab0801", AB0801 }, @@ -840,6 +913,10 @@ static int abx80x_probe(struct i2c_client *client) return err; } + err = abx80x_setup_nvmem(priv); + if (err) + return err; + if (client->irq > 0) { dev_info(&client->dev, "IRQ %d supplied\n", client->irq); err = devm_request_threaded_irq(&client->dev, client->irq, NULL, -- cgit v1.2.3-70-g09d2 From 3ca04951b004fa184ff84369448a37bf5df98a79 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Thu, 2 Feb 2023 16:54:43 +0100 Subject: rtc: pm8xxx: add support for nvmem offset On many Qualcomm platforms the PMIC RTC control and time registers are read-only so that the RTC time can not be updated. Instead an offset needs be stored in some machine-specific non-volatile memory, which the driver can take into account. Add support for storing a 32-bit offset from the Epoch in an nvmem cell so that the RTC time can be set on such platforms. Signed-off-by: Johan Hovold Link: https://lore.kernel.org/r/20230202155448.6715-18-johan+linaro@kernel.org Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pm8xxx.c | 141 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 129 insertions(+), 12 deletions(-) (limited to 'drivers/rtc') diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index eff2782beeed..372494e82f40 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -1,8 +1,13 @@ // SPDX-License-Identifier: GPL-2.0-only -/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. +/* + * pm8xxx RTC driver + * + * Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved. + * Copyright (c) 2023, Linaro Limited */ #include #include +#include #include #include #include @@ -49,6 +54,8 @@ struct pm8xxx_rtc_regs { * @alarm_irq: alarm irq number * @regs: register description * @dev: device structure + * @nvmem_cell: nvmem cell for offset + * @offset: offset from epoch in seconds */ struct pm8xxx_rtc { struct rtc_device *rtc; @@ -57,8 +64,60 @@ struct pm8xxx_rtc { int alarm_irq; const struct pm8xxx_rtc_regs *regs; struct device *dev; + struct nvmem_cell *nvmem_cell; + u32 offset; }; +static int pm8xxx_rtc_read_nvmem_offset(struct pm8xxx_rtc *rtc_dd) +{ + size_t len; + void *buf; + int rc; + + buf = nvmem_cell_read(rtc_dd->nvmem_cell, &len); + if (IS_ERR(buf)) { + rc = PTR_ERR(buf); + dev_dbg(rtc_dd->dev, "failed to read nvmem offset: %d\n", rc); + return rc; + } + + if (len != sizeof(u32)) { + dev_dbg(rtc_dd->dev, "unexpected nvmem cell size %zu\n", len); + kfree(buf); + return -EINVAL; + } + + rtc_dd->offset = get_unaligned_le32(buf); + + kfree(buf); + + return 0; +} + +static int pm8xxx_rtc_write_nvmem_offset(struct pm8xxx_rtc *rtc_dd, u32 offset) +{ + u8 buf[sizeof(u32)]; + int rc; + + put_unaligned_le32(offset, buf); + + rc = nvmem_cell_write(rtc_dd->nvmem_cell, buf, sizeof(buf)); + if (rc < 0) { + dev_dbg(rtc_dd->dev, "failed to write nvmem offset: %d\n", rc); + return rc; + } + + return 0; +} + +static int pm8xxx_rtc_read_offset(struct pm8xxx_rtc *rtc_dd) +{ + if (!rtc_dd->nvmem_cell) + return 0; + + return pm8xxx_rtc_read_nvmem_offset(rtc_dd); +} + static int pm8xxx_rtc_read_raw(struct pm8xxx_rtc *rtc_dd, u32 *secs) { const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; @@ -90,6 +149,33 @@ static int pm8xxx_rtc_read_raw(struct pm8xxx_rtc *rtc_dd, u32 *secs) return 0; } +static int pm8xxx_rtc_update_offset(struct pm8xxx_rtc *rtc_dd, u32 secs) +{ + u32 raw_secs; + u32 offset; + int rc; + + if (!rtc_dd->nvmem_cell) + return -ENODEV; + + rc = pm8xxx_rtc_read_raw(rtc_dd, &raw_secs); + if (rc) + return rc; + + offset = secs - raw_secs; + + if (offset == rtc_dd->offset) + return 0; + + rc = pm8xxx_rtc_write_nvmem_offset(rtc_dd, offset); + if (rc) + return rc; + + rtc_dd->offset = offset; + + return 0; +} + /* * Steps to write the RTC registers. * 1. Disable alarm if enabled. @@ -99,23 +185,15 @@ static int pm8xxx_rtc_read_raw(struct pm8xxx_rtc *rtc_dd, u32 *secs) * 5. Enable rtc if disabled in step 2. * 6. Enable alarm if disabled in step 1. */ -static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) +static int __pm8xxx_rtc_set_time(struct pm8xxx_rtc *rtc_dd, u32 secs) { - struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); const struct pm8xxx_rtc_regs *regs = rtc_dd->regs; u8 value[NUM_8_BIT_RTC_REGS]; bool alarm_enabled; - u32 secs; int rc; - if (!rtc_dd->allow_set_time) - return -ENODEV; - - secs = rtc_tm_to_time64(tm); put_unaligned_le32(secs, value); - dev_dbg(dev, "set time: %ptRd %ptRt (%u)\n", tm, tm, secs); - rc = regmap_update_bits_check(rtc_dd->regmap, regs->alarm_ctrl, regs->alarm_en, 0, &alarm_enabled); if (rc) @@ -158,6 +236,27 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) return 0; } +static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ + struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); + u32 secs; + int rc; + + secs = rtc_tm_to_time64(tm); + + if (rtc_dd->allow_set_time) + rc = __pm8xxx_rtc_set_time(rtc_dd, secs); + else + rc = pm8xxx_rtc_update_offset(rtc_dd, secs); + + if (rc) + return rc; + + dev_dbg(dev, "set time: %ptRd %ptRt (%u + %u)\n", tm, tm, + secs - rtc_dd->offset, rtc_dd->offset); + return 0; +} + static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); @@ -168,10 +267,11 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) if (rc) return rc; + secs += rtc_dd->offset; rtc_time64_to_tm(secs, tm); - dev_dbg(dev, "read time: %ptRd %ptRt (%u)\n", tm, tm, secs); - + dev_dbg(dev, "read time: %ptRd %ptRt (%u + %u)\n", tm, tm, + secs - rtc_dd->offset, rtc_dd->offset); return 0; } @@ -184,6 +284,7 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) int rc; secs = rtc_tm_to_time64(&alarm->time); + secs -= rtc_dd->offset; put_unaligned_le32(secs, value); rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl, @@ -223,6 +324,7 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) return rc; secs = get_unaligned_le32(value); + secs += rtc_dd->offset; rtc_time64_to_tm(secs, &alarm->time); rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg); @@ -378,9 +480,23 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev) rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node, "allow-set-time"); + rtc_dd->nvmem_cell = devm_nvmem_cell_get(&pdev->dev, "offset"); + if (IS_ERR(rtc_dd->nvmem_cell)) { + rc = PTR_ERR(rtc_dd->nvmem_cell); + if (rc != -ENOENT) + return rc; + rtc_dd->nvmem_cell = NULL; + } + rtc_dd->regs = match->data; rtc_dd->dev = &pdev->dev; + if (!rtc_dd->allow_set_time) { + rc = pm8xxx_rtc_read_offset(rtc_dd); + if (rc) + return rc; + } + rc = pm8xxx_rtc_enable(rtc_dd); if (rc) return rc; @@ -435,3 +551,4 @@ MODULE_ALIAS("platform:rtc-pm8xxx"); MODULE_DESCRIPTION("PMIC8xxx RTC driver"); MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Anirudh Ghayal "); +MODULE_AUTHOR("Johan Hovold "); -- cgit v1.2.3-70-g09d2