From patchwork Mon Jan 12 08:16:50 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnaud Ebalard X-Patchwork-Id: 5608841 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 5ABDF9F358 for ; Mon, 12 Jan 2015 08:19:31 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E259220260 for ; Mon, 12 Jan 2015 08:19:29 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 70BEF20253 for ; Mon, 12 Jan 2015 08:19:28 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1YAaBb-00067N-Bl; Mon, 12 Jan 2015 08:17:19 +0000 Received: from 36.223.133.77.rev.sfr.net ([77.133.223.36] helo=smtp.natisbad.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1YAaBR-0005rp-Dw for linux-arm-kernel@lists.infradead.org; Mon, 12 Jan 2015 08:17:11 +0000 Received: by smtp.natisbad.org (Postfix, from userid 109) id B20DE1700452; Mon, 12 Jan 2015 09:16:45 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=natisbad.org; s=mail; t=1421050606; bh=0t7LNe/n2i1hBdJ3iwI7aFl6Hfv35sQXeJj0ABImKSw=; h=From:To:Cc:Subject:In-Reply-To:References:Date:From; b=QqhyE1uUAlNQeUBKHKHs6IGfL9vEg7a73iSD1ubpxMcxBCr950TOev7SjC2y0hyWj 5sPRTlNo42mSfqW8pFnY2QXkGDAsolGVd1Z2W2dFEM7AHfqEBx5SobZFXnzRA8nI8P VykCrQGs5SCChVfcGJb65tHu3gPpvO7ue//JKPGQ= X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Spam-Level: X-Spam-Status: No, score=-4.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_MED, T_DKIM_INVALID, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 Received: from small (localhost [IPv6:::1]) by smtp.natisbad.org (Postfix) with ESMTP id D64551700D2F; Mon, 12 Jan 2015 09:12:18 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=natisbad.org; s=mail; t=1421050340; bh=0t7LNe/n2i1hBdJ3iwI7aFl6Hfv35sQXeJj0ABImKSw=; h=From:To:Cc:Subject:In-Reply-To:References:Date:From; b=RFqH1f7TZPkrhQ8xRRLutP4qxr8QK3JSHpr/oMoozLahybOxV60XLOmKlTjpIc2WW 4qwgonzGcvxUFWcZD+ZB5TG8e8prPAIepOSCqT31RQX+uBCXU47EzsEnHigQlzQpw9 9ZdbcYq7VXd/spdQVr76AMr2w7B3hKgZTXHqyE8E= X-Hashcash: 1:20:150112:akpm@linux-foundation.org::Y/mKSKPwBP8ml+Ca:0000000000000000000000000000000000002Thi X-Hashcash: 1:20:150112:mark.rutland@arm.com::JUH+e7zWlqckHJN6:000000000000000000000000000000000000000001cwQ X-Hashcash: 1:20:150112:a.zummo@towertech.it::Gad2jd2Mw2NLhsQz:000000000000000000000000000000000000000005pvD X-Hashcash: 1:20:150112:peter.huewe@infineon.com::Tm/xITUnh86+73Ys:00000000000000000000000000000000000002mWb X-Hashcash: 1:20:150112:linus.walleij@linaro.org::3kjo6i2K0wBDaDcV:000000000000000000000000000000000000041mg X-Hashcash: 1:20:150112:treding@nvidia.com::mM8b8N9opsL1A6If:00000000000000000000000000000000000000000003KZL X-Hashcash: 1:20:150112:broonie@kernel.org::yDHQmJIY0jjO7Alc:00000000000000000000000000000000000000000003qe0 X-Hashcash: 1:20:150112:arnd@arndb.de::oLuhtHAYxgtE56DR:0000CQuv X-Hashcash: 1:20:150112:rob.herring@calxeda.com::4iz5vFe9UM08pmUg:00000000000000000000000000000000000000GX93 X-Hashcash: 1:20:150112:pawel.moll@arm.com::u9o0u7l4CnpUQKh5:00000000000000000000000000000000000000000005SMF X-Hashcash: 1:20:150112:swarren@wwwdotorg.org::P8ESV1D5pAEWjmWS:0000000000000000000000000000000000000000410P X-Hashcash: 1:20:150112:ijc+devicetree@hellion.org.uk::/1kwo1x/1vYkp+iU:000000000000000000000000000000008hoy X-Hashcash: 1:20:150112:grant.likely@linaro.org::hrUCBXpoRunzW0O+:000000000000000000000000000000000000006AGe X-Hashcash: 1:20:150112:devicetree@vger.kernel.org::7X/OQlxS4dKypHwZ:000000000000000000000000000000000000Qe7 X-Hashcash: 1:20:150112:linux-doc@vger.kernel.org::ogNr7tawxEzUWl2A:0000000000000000000000000000000000001FSX X-Hashcash: 1:20:150112:rob@landley.net::EDEJeH0KVui/zdbK:008SRI X-Hashcash: 1:20:150112:rtc-linux@googlegroups.com::l7VP6lua+D1leGSB:000000000000000000000000000000000009jgy X-Hashcash: 1:20:150112:jason@lakedaemon.net::CPRhZJ/mIFSk6nWs:000000000000000000000000000000000000000001HeI X-Hashcash: 1:20:150112:linux@roeck-us.net::sljXjYWEsrUO7A5J:00000000000000000000000000000000000000000001+oT X-Hashcash: 1:20:150112:jgunthorpe@obsidianresearch.com::ZMmh2cqeWsDUoDvj:0000000000000000000000000000000FdP X-Hashcash: 1:20:150112:galak@codeaurora.org::OfaAlkopcOfsg/YO:0000000000000000000000000000000000000000011yZ X-Hashcash: 1:20:150112:linux-arm-kernel@lists.infradead.org::rbVjg+PF9EtxZJkg:00000000000000000000000009LFp From: Arnaud Ebalard To: Andrew Morton Subject: [PATCHv0 3/3] rtc: rtc-ab-b5ze-s3: Add sub-minute alarm support In-Reply-To: References: Message-Id: <0182b5dc16f9e26e4dc58c778211afa3612211c0.1421045942.git.arno@natisbad.org> Date: Mon, 12 Jan 2015 09:16:50 +0100 User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/24.3 (gnu/linux) MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20150112_001709_899089_0D84E403 X-CRM114-Status: GOOD ( 26.41 ) X-Spam-Score: 0.3 (/) Cc: Mark Rutland , Alessandro Zummo , Pawel Moll , Arnd Bergmann , Stephen Warren , rtc-linux@googlegroups.com, Linus Walleij , Ian Campbell , linux-doc@vger.kernel.org, Rob Herring , Jason Gunthorpe , devicetree@vger.kernel.org, Mark Brown , linux-arm-kernel@lists.infradead.org, Rob Landley , Kumar Gala , Grant Likely , Peter Huewe , Thierry Reding , Guenter Roeck , Jason Cooper X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Abracon AB-RTCMC-32.768kHz-B5ZE-S3 alarm is only accurate to the minute. For that reason, UIE mode is currently not supported by the driver. But the device provides a watchdog timer which can be coupled with the alarm mechanism to extend support and provide sub-minute alarm capability. This patch implements that extension. More precisely, it makes use of the watchdog timer for alarms which are less that four minutes in the future (with second accuracy) and use standard alarm mechanism for other alarms (with minute accuracy). Signed-off-by: Arnaud Ebalard --- drivers/rtc/rtc-ab-b5ze-s3.c | 311 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 275 insertions(+), 36 deletions(-) diff --git a/drivers/rtc/rtc-ab-b5ze-s3.c b/drivers/rtc/rtc-ab-b5ze-s3.c index 6b73051cfef7..f5cab5328a8a 100644 --- a/drivers/rtc/rtc-ab-b5ze-s3.c +++ b/drivers/rtc/rtc-ab-b5ze-s3.c @@ -133,6 +133,7 @@ struct abb5zes3_rtc_data { int irq; bool battery_low; + bool timer_alarm; /* current alarm is via timer A */ }; /* @@ -192,6 +193,22 @@ static int _abb5zes3_rtc_update_alarm(struct device *dev, bool enable) return ret; } +/* Enable or disable timer (watchdog timer A interrupt generation) */ +static int _abb5zes3_rtc_update_timer(struct device *dev, bool enable) +{ + struct abb5zes3_rtc_data *data = dev_get_drvdata(dev); + int ret; + + ret = regmap_update_bits(data->regmap, ABB5ZES3_REG_CTRL2, + ABB5ZES3_REG_CTRL2_WTAIE, + enable ? ABB5ZES3_REG_CTRL2_WTAIE : 0); + if (ret) + dev_err(dev, "%s: writing timer INT failed (%d)\n", + __func__, ret); + + return ret; +} + /* * Note: we only read, so regmap inner lock protection is sufficient, i.e. * we do not need driver's main lock protection. @@ -277,7 +294,92 @@ static int abb5zes3_rtc_set_time(struct device *dev, struct rtc_time *tm) return ret; } -static int abb5zes3_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +/* + * Set provided TAQ and Timer A registers (TIMA_CLK and TIMA) based on + * given number of seconds. + */ +static inline void sec_to_timer_a(u8 secs, u8 *taq, u8 *timer_a) +{ + *taq = ABB5ZES3_REG_TIMA_CLK_TAQ1; /* 1Hz */ + *timer_a = secs; +} + +/* + * Return current number of seconds in Timer A. As we only use + * timer A with a 1Hz freq, this is what we expect to have. + */ +static inline int sec_from_timer_a(u8 *secs, u8 taq, u8 timer_a) +{ + if (taq != ABB5ZES3_REG_TIMA_CLK_TAQ1) /* 1Hz */ + return -EINVAL; + + *secs = timer_a; + + return 0; +} + +/* + * Read alarm currently configured via a watchdog timer using timer A. This + * is done by reading current RTC time and adding remaining timer time. + */ +static int _abb5zes3_rtc_read_timer(struct device *dev, + struct rtc_wkalrm *alarm) +{ + struct abb5zes3_rtc_data *data = dev_get_drvdata(dev); + struct rtc_time rtc_tm, *alarm_tm = &alarm->time; + u8 regs[ABB5ZES3_TIMA_SEC_LEN + 1]; + unsigned long rtc_secs; + unsigned int reg; + u8 timer_secs; + int ret; + + /* + * Instead of doing two separate calls, because they are consecutive, + * we grab both clockout register and Timer A section. The latter is + * used to decide if timer A is enabled (as a watchdog timer). + */ + ret = regmap_bulk_read(data->regmap, ABB5ZES3_REG_TIM_CLK, regs, + ABB5ZES3_TIMA_SEC_LEN + 1); + if (ret) { + dev_err(dev, "%s: reading Timer A section failed (%d)\n", + __func__, ret); + goto err; + } + + /* get current time ... */ + ret = _abb5zes3_rtc_read_time(dev, &rtc_tm); + if (ret) + goto err; + + /* ... convert to seconds ... */ + ret = rtc_tm_to_time(&rtc_tm, &rtc_secs); + if (ret) + goto err; + + /* ... add remaining timer A time ... */ + ret = sec_from_timer_a(&timer_secs, regs[1], regs[2]); + if (ret) + goto err; + + /* ... and convert back. */ + rtc_time_to_tm(rtc_secs + timer_secs, alarm_tm); + + ret = regmap_read(data->regmap, ABB5ZES3_REG_CTRL2, ®); + if (ret) { + dev_err(dev, "%s: reading ctrl reg failed (%d)\n", + __func__, ret); + goto err; + } + + alarm->enabled = !!(reg & ABB5ZES3_REG_CTRL2_WTAIE); + +err: + return ret; +} + +/* Read alarm currently configured via a RTC alarm registers. */ +static int _abb5zes3_rtc_read_alarm(struct device *dev, + struct rtc_wkalrm *alarm) { struct abb5zes3_rtc_data *data = dev_get_drvdata(dev); struct rtc_time rtc_tm, *alarm_tm = &alarm->time; @@ -286,7 +388,6 @@ static int abb5zes3_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) unsigned int reg; int ret; - mutex_lock(&data->lock); ret = regmap_bulk_read(data->regmap, ABB5ZES3_REG_ALRM_MN, regs, ABB5ZES3_ALRM_SEC_LEN); if (ret) { @@ -340,13 +441,39 @@ static int abb5zes3_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) alarm->enabled = !!(reg & ABB5ZES3_REG_CTRL1_AIE); err: + return ret; +} + +/* + * As the Alarm mechanism supported by the chip is only accurate to the + * minute, we use the watchdog timer mechanism provided by timer A + * (up to 256 seconds w/ a second accuracy) for low alarm values (below + * 4 minutes). Otherwise, we use the common alarm mechanism provided + * by the chip. In order for that to work, we keep track of currently + * configured timer type via 'timer_alarm' flag in our private data + * structure. + */ +static int abb5zes3_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct abb5zes3_rtc_data *data = dev_get_drvdata(dev); + int ret; + + mutex_lock(&data->lock); + if (data->timer_alarm) + ret = _abb5zes3_rtc_read_timer(dev, alarm); + else + ret = _abb5zes3_rtc_read_alarm(dev, alarm); mutex_unlock(&data->lock); return ret; } -/* ALARM is only accurate to the minute (not the second) */ -static int abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +/* + * Set alarm using chip alarm mechanism. It is only accurate to the + * minute (not the second). The function expects alarm interrupt to + * be disabled. + */ +static int _abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) { struct abb5zes3_rtc_data *data = dev_get_drvdata(dev); struct rtc_time *alarm_tm = &alarm->time; @@ -355,7 +482,6 @@ static int abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) struct rtc_time rtc_tm; int ret, enable = 1; - mutex_lock(&data->lock); ret = _abb5zes3_rtc_read_time(dev, &rtc_tm); if (ret) goto err; @@ -397,18 +523,13 @@ static int abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) } } - /* Disable the alarm before modifying it */ - ret = _abb5zes3_rtc_update_alarm(dev, 0); - if (ret < 0) { - dev_err(dev, "%s: unable to disable the alarm (%d)\n", - __func__, ret); - goto err; - } - - /* Program alarm registers */ - regs[0] = bin2bcd(alarm_tm->tm_min) & 0x7f; /* minute */ - regs[1] = bin2bcd(alarm_tm->tm_hour) & 0x3f; /* hour */ - regs[2] = bin2bcd(alarm_tm->tm_mday) & 0x3f; /* day of the month */ + /* + * Program all alarm registers but DW one. For each register, setting + * MSB to 0 enables associated alarm. + */ + regs[0] = bin2bcd(alarm_tm->tm_min) & 0x7f; + regs[1] = bin2bcd(alarm_tm->tm_hour) & 0x3f; + regs[2] = bin2bcd(alarm_tm->tm_mday) & 0x3f; regs[3] = ABB5ZES3_REG_ALRM_DW_AE; /* do not match day of the week */ ret = regmap_bulk_write(data->regmap, ABB5ZES3_REG_ALRM_MN, regs, @@ -419,15 +540,115 @@ static int abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) goto err; } - /* Enable or disable alarm */ + /* Record currently configured alarm is not a timer */ + data->timer_alarm = 0; + + /* Enable or disable alarm interrupt generation */ ret = _abb5zes3_rtc_update_alarm(dev, enable); err: - mutex_unlock(&data->lock); + return ret; +} + +/* + * Set alarm using timer watchdog (via timer A) mechanism. The function expects + * timer A interrupt to be disabled. + */ +static int _abb5zes3_rtc_set_timer(struct device *dev, struct rtc_wkalrm *alarm, + u8 secs) +{ + struct abb5zes3_rtc_data *data = dev_get_drvdata(dev); + u8 regs[ABB5ZES3_TIMA_SEC_LEN]; + u8 mask = ABB5ZES3_REG_TIM_CLK_TAC0 | ABB5ZES3_REG_TIM_CLK_TAC1; + int ret = 0; + + /* Program given number of seconds to Timer A registers */ + sec_to_timer_a(secs, ®s[0], ®s[1]); + ret = regmap_bulk_write(data->regmap, ABB5ZES3_REG_TIMA_CLK, regs, + ABB5ZES3_TIMA_SEC_LEN); + if (ret < 0) { + dev_err(dev, "%s: writing timer section failed\n", __func__); + goto err; + } + /* Configure Timer A as a watchdog timer */ + ret = regmap_update_bits(data->regmap, ABB5ZES3_REG_TIM_CLK, + mask, ABB5ZES3_REG_TIM_CLK_TAC1); + if (ret) + dev_err(dev, "%s: failed to update timer\n", __func__); + + /* Record currently configured alarm is a timer */ + data->timer_alarm = 1; + + /* Enable or disable timer interrupt generation */ + ret = _abb5zes3_rtc_update_timer(dev, alarm->enabled); + +err: return ret; } +/* + * The chip has an alarm which is only accurate to the minute. In order to + * handle alarms below that limit, we use the watchdog timer function of + * timer A. More precisely, the timer method is used for alarms below 240 + * seconds. + */ +static int abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ + struct abb5zes3_rtc_data *data = dev_get_drvdata(dev); + struct rtc_time *alarm_tm = &alarm->time; + unsigned long rtc_secs, alarm_secs; + struct rtc_time rtc_tm; + int ret; + + mutex_lock(&data->lock); + ret = _abb5zes3_rtc_read_time(dev, &rtc_tm); + if (ret) + goto err; + + ret = rtc_tm_to_time(&rtc_tm, &rtc_secs); + if (ret) + goto err; + + ret = rtc_tm_to_time(alarm_tm, &alarm_secs); + if (ret) + goto err; + + /* Let's first disable both the alarm and the timer interrupts */ + ret = _abb5zes3_rtc_update_alarm(dev, false); + if (ret < 0) { + dev_err(dev, "%s: unable to disable alarm (%d)\n", __func__, + ret); + goto err; + } + ret = _abb5zes3_rtc_update_timer(dev, false); + if (ret < 0) { + dev_err(dev, "%s: unable to disable timer (%d)\n", __func__, + ret); + goto err; + } + + data->timer_alarm = 0; + + /* + * Let's now configure the alarm; if we are expected to ring in + * more than 240s, then we setup an alarm. Otherwise, a timer. + */ + if ((alarm_secs > rtc_secs) && ((alarm_secs - rtc_secs) <= 240)) + ret = _abb5zes3_rtc_set_timer(dev, alarm, + alarm_secs - rtc_secs); + else + ret = _abb5zes3_rtc_set_alarm(dev, alarm); + + err: + mutex_unlock(&data->lock); + + if (ret) + dev_err(dev, "%s: unable to configure alarm (%d)\n", __func__, + ret); + + return ret; + } /* Enable or disable battery low irq generation */ static inline int _abb5zes3_rtc_battery_low_irq_enable(struct regmap *regmap, @@ -446,7 +667,7 @@ static inline int _abb5zes3_rtc_battery_low_irq_enable(struct regmap *regmap, static int abb5zes3_rtc_check_setup(struct device *dev) { struct abb5zes3_rtc_data *data = dev_get_drvdata(dev); - struct regmap *regmap = data->regmap; + struct regmap *regmap = data->regmap; unsigned int reg; int ret; u8 mask; @@ -579,7 +800,10 @@ static int abb5zes3_rtc_alarm_irq_enable(struct device *dev, if (rtc_data->irq) { mutex_lock(&rtc_data->lock); - ret = _abb5zes3_rtc_update_alarm(dev, enable); + if (rtc_data->timer_alarm) + ret = _abb5zes3_rtc_update_timer(dev, enable); + else + ret = _abb5zes3_rtc_update_alarm(dev, enable); mutex_unlock(&rtc_data->lock); } @@ -629,6 +853,23 @@ static irqreturn_t _abb5zes3_rtc_interrupt(int irq, void *data) handled = IRQ_HANDLED; } + /* Check watchdog Timer A flag */ + if (regs[ABB5ZES3_REG_CTRL2] & ABB5ZES3_REG_CTRL2_WTAF) { + dev_dbg(dev, "RTC timer!\n"); + + rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF); + + /* + * Acknowledge and disable the alarm. Note: WTAF + * flag had been cleared when reading CTRL2 + */ + _abb5zes3_rtc_update_timer(dev, 0); + + rtc_data->timer_alarm = 0; + + handled = IRQ_HANDLED; + } + return handled; } @@ -655,24 +896,28 @@ static int abb5zes3_probe(struct i2c_client *client, if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA | - I2C_FUNC_SMBUS_I2C_BLOCK)) - return -ENODEV; + I2C_FUNC_SMBUS_I2C_BLOCK)) { + ret = -ENODEV; + goto err; + } regmap = devm_regmap_init_i2c(client, &abb5zes3_rtc_regmap_config); if (IS_ERR(regmap)) { ret = PTR_ERR(regmap); dev_err(dev, "%s: regmap allocation failed: %d\n", __func__, ret); - return ret; + goto err; } ret = abb5zes3_i2c_validate_chip(regmap); if (ret) - return ret; + goto err; data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); - if (!data) - return -ENOMEM; + if (!data) { + ret = -ENOMEM; + goto err; + } mutex_init(&data->lock); data->regmap = regmap; @@ -680,7 +925,7 @@ static int abb5zes3_probe(struct i2c_client *client, ret = abb5zes3_rtc_check_setup(dev); if (ret) - return ret; + goto err; if (client->irq > 0) { ret = devm_request_threaded_irq(dev, client->irq, NULL, @@ -705,16 +950,9 @@ static int abb5zes3_probe(struct i2c_client *client, dev_err(dev, "%s: unable to register RTC device (%d)\n", __func__, ret); device_init_wakeup(dev, false); + goto err; } - /* - * AB-B5Z5E only supports a coarse granularity alarm (one minute - * resolution up to one month) so we cannot support UIE mode - * using the device's alarm. Note it should be feasible to support - * such a feature using one of the two timers the device provides. - */ - data->rtc->uie_unsupported = 1; - /* Enable battery low detection interrupt if battery not already low */ if (!data->battery_low && data->irq) { ret = _abb5zes3_rtc_battery_low_irq_enable(regmap, true); @@ -723,6 +961,7 @@ static int abb5zes3_probe(struct i2c_client *client, "generation failed (%d)\n", __func__, ret); } +err: return ret; }