From 4d8318bc97a1c37142d0e7618061f09b37d319b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 9 Sep 2015 11:29:10 +0200 Subject: [PATCH 01/23] rtc: pcf2127: make module license match the file header MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The header of the pcf2127 driver specifies GPL v2 only as license, so use "GPL v2" as module license specifier instead of "GPL" as the latter means "GNU Public License v2 or later". Signed-off-by: Uwe Kleine-König Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 4b11d31f7174..a26bae60826c 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -241,5 +241,5 @@ module_i2c_driver(pcf2127_driver); MODULE_AUTHOR("Renaud Cerrato "); MODULE_DESCRIPTION("NXP PCF2127 RTC driver"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_VERSION(DRV_VERSION); From e21a47ff4dcef8c5fb57758035b266299b184146 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Wed, 16 Sep 2015 09:16:51 +0200 Subject: [PATCH 02/23] rtc: rtctest: enabling UIE for a chip that doesn't support it returns EINVAL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Calling ioctl(..., RTC_UIE_ON, ...) without CONFIG_RTC_INTF_DEV_UIE_EMUL either ends in rtc_update_irq_enable if rtc->uie_unsupported is true or in __rtc_set_alarm in the if (!rtc->ops->set_alarm) branch. In both cases the return value is -EINVAL. So check for that one instead of ENOTTY. Signed-off-by: Uwe Kleine-König Signed-off-by: Alexandre Belloni --- tools/testing/selftests/timers/rtctest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/testing/selftests/timers/rtctest.c b/tools/testing/selftests/timers/rtctest.c index d80ae852334d..624bce51b27d 100644 --- a/tools/testing/selftests/timers/rtctest.c +++ b/tools/testing/selftests/timers/rtctest.c @@ -61,7 +61,7 @@ int main(int argc, char **argv) /* Turn on update interrupts (one per second) */ retval = ioctl(fd, RTC_UIE_ON, 0); if (retval == -1) { - if (errno == ENOTTY) { + if (errno == EINVAL) { fprintf(stderr, "\n...Update IRQs not supported.\n"); goto test_READ; From 2ec68825fc55d1ddeb04ab861f3bfdbaa8e9f3c4 Mon Sep 17 00:00:00 2001 From: Ivan Grimaldi Date: Fri, 18 Sep 2015 17:27:56 +0200 Subject: [PATCH 03/23] rtc: ds1390: fix ds1390_get_reg return value spi_write_then_read puts in rx_buf the received data starting from the first byte of the rx_buf Signed-off-by: Ivan Grimaldi Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1390.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c index e67bfcb3a1aa..a4303b43a36a 100644 --- a/drivers/rtc/rtc-ds1390.c +++ b/drivers/rtc/rtc-ds1390.c @@ -62,7 +62,7 @@ static int ds1390_get_reg(struct device *dev, unsigned char address, if (status != 0) return status; - *data = chip->txrx_buf[1]; + *data = chip->txrx_buf[0]; return 0; } From fa395fb8fc3206cdd70b046e0b98168576cc71ef Mon Sep 17 00:00:00 2001 From: Ivan Grimaldi Date: Fri, 18 Sep 2015 17:27:57 +0200 Subject: [PATCH 04/23] rtc: ds1390: Add trickle charger device tree binding Introduce a device tree binding for specifying the trickle charger configuration for ds1390. Signed-off-by: Ivan Grimaldi Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/dallas,ds1390.txt | 18 ++++++ drivers/rtc/Kconfig | 4 +- drivers/rtc/rtc-ds1390.c | 63 +++++++++++++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/rtc/dallas,ds1390.txt diff --git a/Documentation/devicetree/bindings/rtc/dallas,ds1390.txt b/Documentation/devicetree/bindings/rtc/dallas,ds1390.txt new file mode 100644 index 000000000000..8e76f2648796 --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/dallas,ds1390.txt @@ -0,0 +1,18 @@ +* Dallas DS1390 SPI Serial Real-Time Clock + +Required properties: +- compatible: Should contain "dallas,ds1390". +- reg: SPI address for chip + +Optional properties: +- trickle-resistor-ohms : Selected resistor for trickle charger + Values usable for ds1390 are 250, 2000, 4000 + Should be given if trickle charger should be enabled +- trickle-diode-disable : Do not use internal trickle charger diode + Should be given if internal trickle charger diode should be disabled +Example: + ds1390: rtc@68 { + compatible = "dallas,ds1390"; + trickle-resistor-ohms = <250>; + reg = <0>; + }; diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 9d4290617cee..57c2dbc4f438 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -666,8 +666,8 @@ config RTC_DRV_DS1390 If you say yes here you get support for the Dallas/Maxim DS1390/93/94 chips. - This driver only supports the RTC feature, and not other chip - features such as alarms and trickle charging. + This driver supports the RTC feature and trickle charging but not + other chip features such as alarms. This driver can also be built as a module. If so, the module will be called rtc-ds1390. diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c index a4303b43a36a..b2b9454aa7a2 100644 --- a/drivers/rtc/rtc-ds1390.c +++ b/drivers/rtc/rtc-ds1390.c @@ -20,6 +20,7 @@ #include #include #include +#include #define DS1390_REG_100THS 0x00 #define DS1390_REG_SECONDS 0x01 @@ -40,11 +41,31 @@ #define DS1390_REG_STATUS 0x0E #define DS1390_REG_TRICKLE 0x0F +#define DS1390_TRICKLE_CHARGER_ENABLE 0xA0 +#define DS1390_TRICKLE_CHARGER_250_OHM 0x01 +#define DS1390_TRICKLE_CHARGER_2K_OHM 0x02 +#define DS1390_TRICKLE_CHARGER_4K_OHM 0x03 +#define DS1390_TRICKLE_CHARGER_NO_DIODE 0x04 +#define DS1390_TRICKLE_CHARGER_DIODE 0x08 + struct ds1390 { struct rtc_device *rtc; u8 txrx_buf[9]; /* cmd + 8 registers */ }; +static void ds1390_set_reg(struct device *dev, unsigned char address, + unsigned char data) +{ + struct spi_device *spi = to_spi_device(dev); + unsigned char buf[2]; + + /* MSB must be '1' to write */ + buf[0] = address | 0x80; + buf[1] = data; + + spi_write(spi, buf, 2); +} + static int ds1390_get_reg(struct device *dev, unsigned char address, unsigned char *data) { @@ -67,6 +88,45 @@ static int ds1390_get_reg(struct device *dev, unsigned char address, return 0; } +static void ds1390_trickle_of_init(struct spi_device *spi) +{ + u32 ohms = 0; + u8 value; + + if (of_property_read_u32(spi->dev.of_node, "trickle-resistor-ohms", + &ohms)) + goto out; + + /* Enable charger */ + value = DS1390_TRICKLE_CHARGER_ENABLE; + if (of_property_read_bool(spi->dev.of_node, "trickle-diode-disable")) + value |= DS1390_TRICKLE_CHARGER_NO_DIODE; + else + value |= DS1390_TRICKLE_CHARGER_DIODE; + + /* Resistor select */ + switch (ohms) { + case 250: + value |= DS1390_TRICKLE_CHARGER_250_OHM; + break; + case 2000: + value |= DS1390_TRICKLE_CHARGER_2K_OHM; + break; + case 4000: + value |= DS1390_TRICKLE_CHARGER_4K_OHM; + break; + default: + dev_warn(&spi->dev, + "Unsupported ohm value %02ux in dt\n", ohms); + return; + } + + ds1390_set_reg(&spi->dev, DS1390_REG_TRICKLE, value); + +out: + return; +} + static int ds1390_read_time(struct device *dev, struct rtc_time *dt) { struct spi_device *spi = to_spi_device(dev); @@ -143,6 +203,9 @@ static int ds1390_probe(struct spi_device *spi) return res; } + if (spi->dev.of_node) + ds1390_trickle_of_init(spi); + chip->rtc = devm_rtc_device_register(&spi->dev, "ds1390", &ds1390_rtc_ops, THIS_MODULE); if (IS_ERR(chip->rtc)) { From c35300941656508d37315625d276c5a104823505 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Mon, 21 Sep 2015 15:33:56 +0200 Subject: [PATCH 05/23] rtc: opal: fix type of token The variable can take signed values. The problem has been detected using proposed semantic patch scripts/coccinelle/tests/unsigned_lesser_than_zero.cocci [1]. [1]: http://permalink.gmane.org/gmane.linux.kernel/2038576 Signed-off-by: Andrzej Hajda Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-opal.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c index 6fbf9e617151..590e1a45e0b2 100644 --- a/drivers/rtc/rtc-opal.c +++ b/drivers/rtc/rtc-opal.c @@ -152,10 +152,10 @@ exit: /* Set Timed Power-On */ static int opal_set_tpo_time(struct device *dev, struct rtc_wkalrm *alarm) { - u64 h_m_s_ms = 0, token; + u64 h_m_s_ms = 0; struct opal_msg msg; u32 y_m_d = 0; - int rc; + int token, rc; tm_to_opal(&alarm->time, &y_m_d, &h_m_s_ms); From eff6dd41c2240f49e562b89d50ed3e86485cc4ad Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 21 Sep 2015 16:46:57 +0100 Subject: [PATCH 06/23] rtc: pl031: remove misuse of IRQF_NO_SUSPEND flag The IRQF_NO_SUSPEND flag is used to identify the interrupts that should be left enabled so as to allow them to work as expected during the suspend-resume cycle, but doesn't guarantee that it will wake the system from a suspended state, enable_irq_wake is recommended to be used for the wakeup. This patch removes the use of IRQF_NO_SUSPEND flags and uses newly introduce PM wakeup APIs dev_pm_{set,clear}_wake_irq. Cc: Linus Walleij Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: rtc-linux@googlegroups.com Signed-off-by: Sudeep Holla Acked-by: Linus Walleij Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pl031.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 41dcb7ddb906..e1687e19c59f 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -23,6 +23,7 @@ #include #include #include +#include #include /* @@ -305,6 +306,8 @@ static int pl031_remove(struct amba_device *adev) { struct pl031_local *ldata = dev_get_drvdata(&adev->dev); + dev_pm_clear_wake_irq(&adev->dev); + device_init_wakeup(&adev->dev, false); free_irq(adev->irq[0], ldata); rtc_device_unregister(ldata->rtc); iounmap(ldata->base); @@ -370,7 +373,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) } } - device_init_wakeup(&adev->dev, 1); + device_init_wakeup(&adev->dev, true); ldata->rtc = rtc_device_register("pl031", &adev->dev, ops, THIS_MODULE); if (IS_ERR(ldata->rtc)) { @@ -383,7 +386,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id) ret = -EIO; goto out_no_irq; } - + dev_pm_set_wake_irq(&adev->dev, adev->irq[0]); return 0; out_no_irq: @@ -408,7 +411,6 @@ static struct pl031_vendor_data arm_pl031 = { .set_alarm = pl031_set_alarm, .alarm_irq_enable = pl031_alarm_irq_enable, }, - .irqflags = IRQF_NO_SUSPEND, }; /* The First ST derivative */ @@ -422,7 +424,6 @@ static struct pl031_vendor_data stv1_pl031 = { }, .clockwatch = true, .st_weekday = true, - .irqflags = IRQF_NO_SUSPEND, }; /* And the second ST derivative */ @@ -439,8 +440,10 @@ static struct pl031_vendor_data stv2_pl031 = { /* * This variant shares the IRQ with another block and must not * suspend that IRQ line. + * TODO check if it shares with IRQF_NO_SUSPEND user, else we can + * remove IRQF_COND_SUSPEND */ - .irqflags = IRQF_SHARED | IRQF_NO_SUSPEND, + .irqflags = IRQF_SHARED | IRQF_COND_SUSPEND, }; static struct amba_id pl031_ids[] = { From 93a6f9168f2fbeb5bb000ba079e17a11bedc1a62 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 21 Sep 2015 16:46:58 +0100 Subject: [PATCH 07/23] rtc: ab8500: remove misuse of IRQF_NO_SUSPEND flag The IRQF_NO_SUSPEND flag is used to identify the interrupts that should be left enabled so as to allow them to work as expected during the suspend-resume cycle, but doesn't guarantee that it will wake the system from a suspended state, enable_irq_wake is recommended to be used for the wakeup. This patch removes the use of IRQF_NO_SUSPEND flags and uses newly introduce PM wakeup APIs dev_pm_{set,clear}_wake_irq. Cc: Linus Walleij Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: rtc-linux@googlegroups.com Signed-off-by: Sudeep Holla Acked-by: Linus Walleij Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ab8500.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 51407c4c7bd2..24a0af650a1b 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -18,6 +18,7 @@ #include #include #include +#include #define AB8500_RTC_SOFF_STAT_REG 0x00 #define AB8500_RTC_CC_CONF_REG 0x01 @@ -493,11 +494,12 @@ static int ab8500_rtc_probe(struct platform_device *pdev) } err = devm_request_threaded_irq(&pdev->dev, irq, NULL, - rtc_alarm_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT, + rtc_alarm_handler, IRQF_ONESHOT, "ab8500-rtc", rtc); if (err < 0) return err; + dev_pm_set_wake_irq(&pdev->dev, irq); platform_set_drvdata(pdev, rtc); err = ab8500_sysfs_rtc_register(&pdev->dev); @@ -513,6 +515,8 @@ static int ab8500_rtc_probe(struct platform_device *pdev) static int ab8500_rtc_remove(struct platform_device *pdev) { + dev_pm_clear_wake_irq(&pdev->dev); + device_init_wakeup(&pdev->dev, false); ab8500_sysfs_rtc_unregister(&pdev->dev); return 0; From caff0cc419d764287675e55bb46405c6e1fe43ee Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Mon, 21 Sep 2015 16:47:02 +0100 Subject: [PATCH 08/23] rtc: ds1343: remove misuse of IRQF_NO_SUSPEND flag The IRQF_NO_SUSPEND flag is used to identify the interrupts that should be left enabled so as to allow them to work as expected during the suspend-resume cycle, but doesn't guarantee that it will wake the system from a suspended state, enable_irq_wake is recommended to be used for the wakeup. This patch removes the use of IRQF_NO_SUSPEND flags and uses newly introduce PM wakeup APIs dev_pm_{set,clear}_wake_irq. Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: rtc-linux@googlegroups.com Signed-off-by: Sudeep Holla Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1343.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/rtc/rtc-ds1343.c b/drivers/rtc/rtc-ds1343.c index 79a06dd3c185..615ce5c370eb 100644 --- a/drivers/rtc/rtc-ds1343.c +++ b/drivers/rtc/rtc-ds1343.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #define DS1343_DRV_VERSION "01.00" @@ -663,15 +664,15 @@ static int ds1343_probe(struct spi_device *spi) if (priv->irq >= 0) { res = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, - ds1343_thread, - IRQF_NO_SUSPEND | IRQF_ONESHOT, + ds1343_thread, IRQF_ONESHOT, "ds1343", priv); if (res) { priv->irq = -1; dev_err(&spi->dev, "unable to request irq for rtc ds1343\n"); } else { - device_set_wakeup_capable(&spi->dev, 1); + device_init_wakeup(&spi->dev, true); + dev_pm_set_wake_irq(&spi->dev, spi->irq); } } @@ -692,6 +693,8 @@ static int ds1343_remove(struct spi_device *spi) priv->irqen &= ~RTC_AF; mutex_unlock(&priv->mutex); + dev_pm_clear_wake_irq(&spi->dev); + device_init_wakeup(&spi->dev, false); devm_free_irq(&spi->dev, spi->irq, priv); } From b1f9d790b59dc04f8813a49a92ddd8651770ffee Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Sat, 26 Sep 2015 16:25:28 +0200 Subject: [PATCH 09/23] rtc: rx8025: remove unnecessary braces braces {} are not necessary for single statement blocks Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-rx8025.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 24c3d69ce1b9..bd911bafb809 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -65,6 +65,7 @@ static const struct i2c_device_id rx8025_id[] = { { "rx8025", 0 }, + { "rv8803", 1 }, { } }; MODULE_DEVICE_TABLE(i2c, rx8025_id); @@ -518,9 +519,8 @@ static int rx8025_probe(struct i2c_client *client, } rx8025 = devm_kzalloc(&client->dev, sizeof(*rx8025), GFP_KERNEL); - if (!rx8025) { + if (!rx8025) return -ENOMEM; - } rx8025->client = client; i2c_set_clientdata(client, rx8025); From 5413eaba5ae093b0704b5458696922f6518adac4 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Tue, 29 Sep 2015 23:02:46 +0200 Subject: [PATCH 10/23] rtc: pcf85063: return an error when date is invalid Return an error when the date is invalid as the policy should be implemented there. Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf85063.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/drivers/rtc/rtc-pcf85063.c b/drivers/rtc/rtc-pcf85063.c index b6d73dd881f2..63334cbeca41 100644 --- a/drivers/rtc/rtc-pcf85063.c +++ b/drivers/rtc/rtc-pcf85063.c @@ -80,13 +80,7 @@ static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm) pcf85063->c_polarity = (buf[PCF85063_REG_MO] & PCF85063_MO_C) ? (tm->tm_year >= 100) : (tm->tm_year < 100); - /* the clock can give out invalid datetime, but we cannot return - * -EINVAL otherwise hwclock will refuse to set the time on bootup. - */ - if (rtc_valid_tm(tm) < 0) - dev_err(&client->dev, "retrieved date/time is not valid.\n"); - - return 0; + return rtc_valid_tm(tm); } static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm) From ce006ca6d3158466f7d4b32736b8d9c70fd11526 Mon Sep 17 00:00:00 2001 From: Steve Twiss Date: Fri, 2 Oct 2015 11:21:11 +0100 Subject: [PATCH 11/23] rtc: da9063: GPL copyright inconsistency fix Fix misleading and inconsistent copyright header wording. Alter the copyright header text and MODULE_LICENSE macro to ensure the GPL v2 licence description is correctly represented. It will remove the incorrectly LGPL worded text. Words such as "Library" from the line "GNU Library General Public License"; and replace the word "library" with "program" in several other places. The copyright should match the GPL v2 description as specified in the GNU license found here: http://www.gnu.org/licenses/gpl-2.0.html It should also match this copyright text with the correct MODULE_LICENSE macro text as found in the kernel: include/linux/module.h In this case "GNU Public License v2 or later" is linked with "GPL". Signed-off-by: Steve Twiss Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-da9063.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c index 00a8f7f4f87c..284b587da65c 100644 --- a/drivers/rtc/rtc-da9063.c +++ b/drivers/rtc/rtc-da9063.c @@ -1,15 +1,15 @@ /* rtc-da9063.c - Real time clock device driver for DA9063 - * Copyright (C) 2013-14 Dialog Semiconductor Ltd. + * Copyright (C) 2013-2015 Dialog Semiconductor Ltd. * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. * - * This library is distributed in the hope that it will be useful, + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. */ #include @@ -516,5 +516,5 @@ module_platform_driver(da9063_rtc_driver); MODULE_AUTHOR("S Twiss "); MODULE_DESCRIPTION("Real time clock device driver for Dialog DA9063"); -MODULE_LICENSE("GPL v2"); +MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:" DA9063_DRVNAME_RTC); From 24417829936d82b03b156e0d036c3b8f25aa93fd Mon Sep 17 00:00:00 2001 From: Harald Geyer Date: Fri, 2 Oct 2015 20:18:01 +0000 Subject: [PATCH 12/23] rtc: stmp3xxx: unify register access macros Use STMP_OFFSET_REG_(SET|CLR) instead of defining _SET and _CLR for STMP3XXX_RTC_CTRL and STMP3XXX_RTC_PERSISTENT0 - no functional changes. Signed-off-by: Harald Geyer Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-stmp3xxx.c | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index eb09eddf39b8..ca54d039da31 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -32,8 +32,6 @@ #include #define STMP3XXX_RTC_CTRL 0x0 -#define STMP3XXX_RTC_CTRL_SET 0x4 -#define STMP3XXX_RTC_CTRL_CLR 0x8 #define STMP3XXX_RTC_CTRL_ALARM_IRQ_EN 0x00000001 #define STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN 0x00000002 #define STMP3XXX_RTC_CTRL_ALARM_IRQ 0x00000004 @@ -52,8 +50,6 @@ #define STMP3XXX_RTC_WATCHDOG 0x50 #define STMP3XXX_RTC_PERSISTENT0 0x60 -#define STMP3XXX_RTC_PERSISTENT0_SET 0x64 -#define STMP3XXX_RTC_PERSISTENT0_CLR 0x68 #define STMP3XXX_RTC_PERSISTENT0_CLOCKSOURCE (1 << 0) #define STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN (1 << 1) #define STMP3XXX_RTC_PERSISTENT0_ALARM_EN (1 << 2) @@ -179,7 +175,7 @@ static irqreturn_t stmp3xxx_rtc_interrupt(int irq, void *dev_id) if (status & STMP3XXX_RTC_CTRL_ALARM_IRQ) { writel(STMP3XXX_RTC_CTRL_ALARM_IRQ, - rtc_data->io + STMP3XXX_RTC_CTRL_CLR); + rtc_data->io + STMP3XXX_RTC_CTRL + STMP_OFFSET_REG_CLR); rtc_update_irq(rtc_data->rtc, 1, RTC_AF | RTC_IRQF); return IRQ_HANDLED; } @@ -194,15 +190,17 @@ static int stmp3xxx_alarm_irq_enable(struct device *dev, unsigned int enabled) if (enabled) { writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN, - rtc_data->io + STMP3XXX_RTC_PERSISTENT0_SET); + rtc_data->io + STMP3XXX_RTC_PERSISTENT0 + + STMP_OFFSET_REG_SET); writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, - rtc_data->io + STMP3XXX_RTC_CTRL_SET); + rtc_data->io + STMP3XXX_RTC_CTRL + STMP_OFFSET_REG_SET); } else { writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN, - rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR); + rtc_data->io + STMP3XXX_RTC_PERSISTENT0 + + STMP_OFFSET_REG_CLR); writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, - rtc_data->io + STMP3XXX_RTC_CTRL_CLR); + rtc_data->io + STMP3XXX_RTC_CTRL + STMP_OFFSET_REG_CLR); } return 0; } @@ -245,7 +243,7 @@ static int stmp3xxx_rtc_remove(struct platform_device *pdev) return 0; writel(STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, - rtc_data->io + STMP3XXX_RTC_CTRL_CLR); + rtc_data->io + STMP3XXX_RTC_CTRL + STMP_OFFSET_REG_CLR); return 0; } @@ -334,16 +332,17 @@ static int stmp3xxx_rtc_probe(struct platform_device *pdev) STMP3XXX_RTC_PERSISTENT0_CLOCKSOURCE; } - writel(pers0_set, rtc_data->io + STMP3XXX_RTC_PERSISTENT0_SET); + writel(pers0_set, rtc_data->io + STMP3XXX_RTC_PERSISTENT0 + + STMP_OFFSET_REG_SET); writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE | pers0_clr, - rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR); + rtc_data->io + STMP3XXX_RTC_PERSISTENT0 + STMP_OFFSET_REG_CLR); writel(STMP3XXX_RTC_CTRL_ONEMSEC_IRQ_EN | STMP3XXX_RTC_CTRL_ALARM_IRQ_EN, - rtc_data->io + STMP3XXX_RTC_CTRL_CLR); + rtc_data->io + STMP3XXX_RTC_CTRL + STMP_OFFSET_REG_CLR); rtc_data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &stmp3xxx_rtc_ops, THIS_MODULE); @@ -376,7 +375,7 @@ static int stmp3xxx_rtc_resume(struct device *dev) writel(STMP3XXX_RTC_PERSISTENT0_ALARM_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE_EN | STMP3XXX_RTC_PERSISTENT0_ALARM_WAKE, - rtc_data->io + STMP3XXX_RTC_PERSISTENT0_CLR); + rtc_data->io + STMP3XXX_RTC_PERSISTENT0 + STMP_OFFSET_REG_CLR); return 0; } #endif From f97cfddc886bc8f9d4302447f8773239bed854c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Oct 2015 11:17:19 +0200 Subject: [PATCH 13/23] rtc: pcf2127: fix reading uninitialized value on RTC_READ_VL ioctl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The flag reported on the RTC_READ_VL ioctl is only initialized when the date is read out. So the voltage low value doesn't represent reality but the status at the time the date was read (or 0 if the date was not read yet). Moreover when userspace requests a value via an ioctl there is no added benefit to also make a prosa representation of this (and other) values appear in the kernel log so remove the calls to dev_info and the driver data members to track their state. Signed-off-by: Uwe Kleine-König Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 40 +++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index a26bae60826c..d83b2d8e3c2b 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -24,7 +24,10 @@ #define PCF2127_REG_CTRL1 (0x00) /* Control Register 1 */ #define PCF2127_REG_CTRL2 (0x01) /* Control Register 2 */ + #define PCF2127_REG_CTRL3 (0x02) /* Control Register 3 */ +#define PCF2127_REG_CTRL3_BLF BIT(2) + #define PCF2127_REG_SC (0x03) /* datetime */ #define PCF2127_REG_MN (0x04) #define PCF2127_REG_HR (0x05) @@ -39,8 +42,6 @@ static struct i2c_driver pcf2127_driver; struct pcf2127 { struct rtc_device *rtc; - int voltage_low; /* indicates if a low_voltage was detected */ - int oscillator_failed; /* OSF was detected and date is unreliable */ }; /* @@ -49,7 +50,6 @@ struct pcf2127 { */ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) { - struct pcf2127 *pcf2127 = i2c_get_clientdata(client); unsigned char buf[10] = { PCF2127_REG_CTRL1 }; /* read registers */ @@ -59,18 +59,15 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) return -EIO; } - if (buf[PCF2127_REG_CTRL3] & 0x04) { - pcf2127->voltage_low = 1; + if (buf[PCF2127_REG_CTRL3] & PCF2127_REG_CTRL3_BLF) dev_info(&client->dev, "low voltage detected, check/replace RTC battery.\n"); - } if (buf[PCF2127_REG_SC] & PCF2127_OSF) { /* * no need clear the flag here, * it will be cleared once the new date is saved */ - pcf2127->oscillator_failed = 1; dev_warn(&client->dev, "oscillator stop detected, date/time is not reliable\n"); return -EINVAL; @@ -107,7 +104,6 @@ static int pcf2127_get_datetime(struct i2c_client *client, struct rtc_time *tm) static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) { - struct pcf2127 *pcf2127 = i2c_get_clientdata(client); unsigned char buf[8]; int i = 0, err; @@ -141,9 +137,6 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) return -EIO; } - /* clear OSF flag in client data */ - pcf2127->oscillator_failed = 0; - return 0; } @@ -151,17 +144,28 @@ static int pcf2127_set_datetime(struct i2c_client *client, struct rtc_time *tm) static int pcf2127_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { - struct pcf2127 *pcf2127 = i2c_get_clientdata(to_i2c_client(dev)); + struct i2c_client *client = to_i2c_client(dev); + unsigned char buf = PCF2127_REG_CTRL3; + int touser; + int ret; switch (cmd) { case RTC_VL_READ: - if (pcf2127->voltage_low) - dev_info(dev, "low voltage detected, check/replace battery\n"); - if (pcf2127->oscillator_failed) - dev_info(dev, "oscillator stop detected, date/time is not reliable\n"); + ret = i2c_master_send(client, &buf, 1); + if (!ret) + ret = -EIO; + if (ret < 0) + return ret; - if (copy_to_user((void __user *)arg, &pcf2127->voltage_low, - sizeof(int))) + ret = i2c_master_recv(client, &buf, 1); + if (!ret) + ret = -EIO; + if (ret < 0) + return ret; + + touser = buf & PCF2127_REG_CTRL3_BLF ? 1 : 0; + + if (copy_to_user((void __user *)arg, &touser, sizeof(int))) return -EFAULT; return 0; default: From 3cfcb50b48029d84038208a98d1b85ad0dfa8172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Uwe=20Kleine-K=C3=B6nig?= Date: Fri, 2 Oct 2015 11:17:20 +0200 Subject: [PATCH 14/23] rtc: pcf2127: remove useless driver version MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A driver version is only really sensible for oot drivers. Also the dev_info about having found a chip only signals that allocating the driver data succeeded and so isn't worth much. Signed-off-by: Uwe Kleine-König Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-pcf2127.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index d83b2d8e3c2b..629bfdf8c745 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -20,8 +20,6 @@ #include #include -#define DRV_VERSION "0.0.1" - #define PCF2127_REG_CTRL1 (0x00) /* Control Register 1 */ #define PCF2127_REG_CTRL2 (0x01) /* Control Register 2 */ @@ -207,8 +205,6 @@ static int pcf2127_probe(struct i2c_client *client, if (!pcf2127) return -ENOMEM; - dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); - i2c_set_clientdata(client, pcf2127); pcf2127->rtc = devm_rtc_device_register(&client->dev, @@ -246,4 +242,3 @@ module_i2c_driver(pcf2127_driver); MODULE_AUTHOR("Renaud Cerrato "); MODULE_DESCRIPTION("NXP PCF2127 RTC driver"); MODULE_LICENSE("GPL v2"); -MODULE_VERSION(DRV_VERSION); From 921372bf5a7c03a05de25a083b852c6b5d9d97a7 Mon Sep 17 00:00:00 2001 From: Wenyou Yang Date: Mon, 12 Oct 2015 16:39:23 +0800 Subject: [PATCH 15/23] rtc: at91rm9200: clear RTC alarm status flag prior to suspending As said in the SAMA5D2 datasheet, "Prior to instructing the device to enter ULP mode 1, ... and the internal sources of wake-up must be cleared." This patch is to clear the RTC alarm status flag prior to suspending to avoid the erroneous wake-up activity, as it is often used as the wake-up source for the ULP mode 1. Signed-off-by: Wenyou Yang Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-at91rm9200.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index cb62e214b52a..b60fd477778f 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -495,6 +495,8 @@ static int at91_rtc_suspend(struct device *dev) /* this IRQ is shared with DBGU and other hardware which isn't * necessarily doing PM like we are... */ + at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM); + at91_rtc_imr = at91_rtc_read_imr() & (AT91_RTC_ALARM|AT91_RTC_SECEV); if (at91_rtc_imr) { From dbb812b141f3bf3dbea75353da799da3d3373d53 Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Mon, 12 Oct 2015 15:14:05 +0200 Subject: [PATCH 16/23] rtc: davinci: remove incorrect reference to probe function The davinci rtc driver uses the module_platform_driver_probe() helper to call the probe function and mark it as __init, but it also puts a reference into its davinci_rtc_driver function. This will crash if we ever get a deferred probe and the probe function is called again after the init section has been removed. kbuild warns about this: WARNING: vmlinux.o(.data+0x1aa2b4): Section mismatch in reference from the variable davinci_rtc_driver to the function .init.text:davinci_rtc_probe() The variable davinci_rtc_driver references the function __init davinci_rtc_probe() This patch removes the .probe callback from the platform driver, which avoids those problems. Signed-off-by: Arnd Bergmann Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-davinci.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index c84f46168a52..c5432bf64e1c 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -546,7 +546,6 @@ static int __exit davinci_rtc_remove(struct platform_device *pdev) } static struct platform_driver davinci_rtc_driver = { - .probe = davinci_rtc_probe, .remove = __exit_p(davinci_rtc_remove), .driver = { .name = "rtc_davinci", From a39a6405d5f949bc651694028a55d74c514ef1f9 Mon Sep 17 00:00:00 2001 From: Heiko Schocher Date: Fri, 16 Oct 2015 13:31:29 +0200 Subject: [PATCH 17/23] rtc: pcf8563: add CLKOUT to common clock framework Add the clkout output clk to the common clock framework. Disable the CLKOUT of the RTC after power-up. After power-up/reset of the RTC, CLKOUT is enabled by default, with CLKOUT enabled the RTC chip has 2-3 times higher power consumption. Signed-off-by: Heiko Schocher Signed-off-by: Alexandre Belloni --- .../devicetree/bindings/rtc/pcf8563.txt | 25 +++ drivers/rtc/rtc-pcf8563.c | 170 +++++++++++++++++- 2 files changed, 194 insertions(+), 1 deletion(-) create mode 100644 Documentation/devicetree/bindings/rtc/pcf8563.txt diff --git a/Documentation/devicetree/bindings/rtc/pcf8563.txt b/Documentation/devicetree/bindings/rtc/pcf8563.txt new file mode 100644 index 000000000000..72f6d2c9665e --- /dev/null +++ b/Documentation/devicetree/bindings/rtc/pcf8563.txt @@ -0,0 +1,25 @@ +* Philips PCF8563/Epson RTC8564 Real Time Clock + +Philips PCF8563/Epson RTC8564 Real Time Clock + +Required properties: +see: Documentation/devicetree/bindings/i2c/trivial-devices.txt + +Optional property: +- #clock-cells: Should be 0. +- clock-output-names: + overwrite the default clock name "pcf8563-clkout" + +Example: + +pcf8563: pcf8563@51 { + compatible = "nxp,pcf8563"; + reg = <0x51>; + #clock-cells = <0>; +}; + +device { +... + clocks = <&pcf8563>; +... +}; diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index e569243db57e..c8f95b8e463a 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -14,6 +14,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -40,7 +41,14 @@ #define PCF8563_REG_AMN 0x09 /* alarm */ -#define PCF8563_REG_CLKO 0x0D /* clock out */ +#define PCF8563_REG_CLKO 0x0D /* clock out */ +#define PCF8563_REG_CLKO_FE 0x80 /* clock out enabled */ +#define PCF8563_REG_CLKO_F_MASK 0x03 /* frequenc mask */ +#define PCF8563_REG_CLKO_F_32768HZ 0x00 +#define PCF8563_REG_CLKO_F_1024HZ 0x01 +#define PCF8563_REG_CLKO_F_32HZ 0x02 +#define PCF8563_REG_CLKO_F_1HZ 0x03 + #define PCF8563_REG_TMRC 0x0E /* timer control */ #define PCF8563_TMRC_ENABLE BIT(7) #define PCF8563_TMRC_4096 0 @@ -76,6 +84,9 @@ struct pcf8563 { int voltage_low; /* incicates if a low_voltage was detected */ struct i2c_client *client; +#ifdef CONFIG_COMMON_CLK + struct clk_hw clkout_hw; +#endif }; static int pcf8563_read_block_data(struct i2c_client *client, unsigned char reg, @@ -390,6 +401,158 @@ static int pcf8563_irq_enable(struct device *dev, unsigned int enabled) return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled); } +#ifdef CONFIG_COMMON_CLK +/* + * Handling of the clkout + */ + +#define clkout_hw_to_pcf8563(_hw) container_of(_hw, struct pcf8563, clkout_hw) + +static int clkout_rates[] = { + 32768, + 1024, + 32, + 1, +}; + +static unsigned long pcf8563_clkout_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); + struct i2c_client *client = pcf8563->client; + unsigned char buf; + int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf); + + if (ret < 0) + return 0; + + buf &= PCF8563_REG_CLKO_F_MASK; + return clkout_rates[ret]; +} + +static long pcf8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) + if (clkout_rates[i] <= rate) + return clkout_rates[i]; + + return 0; +} + +static int pcf8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); + struct i2c_client *client = pcf8563->client; + unsigned char buf; + int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf); + int i; + + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) + if (clkout_rates[i] == rate) { + buf &= ~PCF8563_REG_CLKO_F_MASK; + buf |= i; + ret = pcf8563_write_block_data(client, + PCF8563_REG_CLKO, 1, + &buf); + return ret; + } + + return -EINVAL; +} + +static int pcf8563_clkout_control(struct clk_hw *hw, bool enable) +{ + struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); + struct i2c_client *client = pcf8563->client; + unsigned char buf; + int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf); + + if (ret < 0) + return ret; + + if (enable) + buf |= PCF8563_REG_CLKO_FE; + else + buf &= ~PCF8563_REG_CLKO_FE; + + ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf); + return ret; +} + +static int pcf8563_clkout_prepare(struct clk_hw *hw) +{ + return pcf8563_clkout_control(hw, 1); +} + +static void pcf8563_clkout_unprepare(struct clk_hw *hw) +{ + pcf8563_clkout_control(hw, 0); +} + +static int pcf8563_clkout_is_prepared(struct clk_hw *hw) +{ + struct pcf8563 *pcf8563 = clkout_hw_to_pcf8563(hw); + struct i2c_client *client = pcf8563->client; + unsigned char buf; + int ret = pcf8563_read_block_data(client, PCF8563_REG_CLKO, 1, &buf); + + if (ret < 0) + return ret; + + return !!(buf & PCF8563_REG_CLKO_FE); +} + +static const struct clk_ops pcf8563_clkout_ops = { + .prepare = pcf8563_clkout_prepare, + .unprepare = pcf8563_clkout_unprepare, + .is_prepared = pcf8563_clkout_is_prepared, + .recalc_rate = pcf8563_clkout_recalc_rate, + .round_rate = pcf8563_clkout_round_rate, + .set_rate = pcf8563_clkout_set_rate, +}; + +static struct clk *pcf8563_clkout_register_clk(struct pcf8563 *pcf8563) +{ + struct i2c_client *client = pcf8563->client; + struct device_node *node = client->dev.of_node; + struct clk *clk; + struct clk_init_data init; + int ret; + unsigned char buf; + + /* disable the clkout output */ + buf = 0; + ret = pcf8563_write_block_data(client, PCF8563_REG_CLKO, 1, &buf); + if (ret < 0) + return ERR_PTR(ret); + + init.name = "pcf8563-clkout"; + init.ops = &pcf8563_clkout_ops; + init.flags = CLK_IS_ROOT; + init.parent_names = NULL; + init.num_parents = 0; + pcf8563->clkout_hw.init = &init; + + /* optional override of the clockname */ + of_property_read_string(node, "clock-output-names", &init.name); + + /* register the clock */ + clk = devm_clk_register(&client->dev, &pcf8563->clkout_hw); + + if (!IS_ERR(clk)) + of_clk_add_provider(node, of_clk_src_simple_get, clk); + + return clk; +} +#endif + static const struct rtc_class_ops pcf8563_rtc_ops = { .ioctl = pcf8563_rtc_ioctl, .read_time = pcf8563_rtc_read_time, @@ -459,6 +622,11 @@ static int pcf8563_probe(struct i2c_client *client, } +#ifdef CONFIG_COMMON_CLK + /* register clk in common clk framework */ + pcf8563_clkout_register_clk(pcf8563); +#endif + /* the pcf8563 alarm only supports a minute accuracy */ pcf8563->rtc->uie_unsupported = 1; From 7a96f2874c524a0f42b8c8f2ac03da3f02c96194 Mon Sep 17 00:00:00 2001 From: Fabio Estevam Date: Sun, 18 Oct 2015 22:06:22 -0200 Subject: [PATCH 18/23] rtc: isl1208: Pass the IRQF_ONESHOT flag Since commit 1c6c69525b40eb76de8adf039409722015927dc3 ("genirq: Reject bogus threaded irq requests") threaded IRQs without a primary handler need to be requested with IRQF_ONESHOT, otherwise the request will fail. So pass the IRQF_ONESHOT flag in this case. The semantic patch that makes this change is available in scripts/coccinelle/misc/irqf_oneshot.cocci Signed-off-by: Fabio Estevam Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl1208.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index aa3b8f1b34d9..b57a304ff62c 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -638,7 +638,7 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id) if (client->irq > 0) { rc = devm_request_threaded_irq(&client->dev, client->irq, NULL, isl1208_rtc_interrupt, - IRQF_SHARED, + IRQF_SHARED | IRQF_ONESHOT, isl1208_driver.driver.name, client); if (!rc) { From 347e40f0302c7e817e64256284b9e69a8b2711d2 Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 21 Oct 2015 11:10:00 +0100 Subject: [PATCH 19/23] rtc: opal: enable support for the stardard "wakeup-source" property Though the opal rtc driver should and will continue to support the legacy "has-tpo" property to enable RTC as the wakeup source, we need to add support for the new standard property "wakeup-source" This patch adds support for "wakeup-source" property in addition to the existing "has-tpo" property. Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: rtc-linux@googlegroups.com Signed-off-by: Sudeep Holla Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-opal.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-opal.c b/drivers/rtc/rtc-opal.c index 590e1a45e0b2..df39ce02a99d 100644 --- a/drivers/rtc/rtc-opal.c +++ b/drivers/rtc/rtc-opal.c @@ -199,8 +199,9 @@ static int opal_rtc_probe(struct platform_device *pdev) { struct rtc_device *rtc; - if (pdev->dev.of_node && of_get_property(pdev->dev.of_node, "has-tpo", - NULL)) { + if (pdev->dev.of_node && + (of_property_read_bool(pdev->dev.of_node, "wakeup-source") || + of_property_read_bool(pdev->dev.of_node, "has-tpo")/* legacy */)) { device_set_wakeup_capable(&pdev->dev, true); opal_rtc_ops.read_alarm = opal_get_tpo_time; opal_rtc_ops.set_alarm = opal_set_tpo_time; From f4b6722248e4991a65e545d6b19e4497202e8a8a Mon Sep 17 00:00:00 2001 From: Sudeep Holla Date: Wed, 21 Oct 2015 11:10:01 +0100 Subject: [PATCH 20/23] rtc: isl12057: enable support for the standard "wakeup-source" property Though the isl12057 rtc driver should and will continue to support the legacy "isil,irq2-can-wakeup-machine" property to enable RTC as the wakeup source, we need to add support for the new standard property "wakeup-source". This patch adds support for "wakeup-source" property in addition to the existing "isil,irq2-can-wakeup-machine" property. Cc: Alessandro Zummo Cc: Alexandre Belloni Cc: rtc-linux@googlegroups.com Signed-off-by: Sudeep Holla Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-isl12057.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c index a0462e5430c7..54328d4ac0d3 100644 --- a/drivers/rtc/rtc-isl12057.c +++ b/drivers/rtc/rtc-isl12057.c @@ -466,9 +466,8 @@ static int isl12057_check_rtc_status(struct device *dev, struct regmap *regmap) * is for instance the case on ReadyNAS 102, 104 and 2120. On those * devices with no IRQ driectly connected to the SoC, the RTC chip * can be forced as a wakeup source by stating that explicitly in - * the device's .dts file using the "isil,irq2-can-wakeup-machine" - * boolean property. This will guarantee 'wakealarm' sysfs entry is - * available on the device. + * the device's .dts file using the "wakeup-source" boolean property. + * This will guarantee 'wakealarm' sysfs entry is available on the device. * * The function below returns 1, i.e. the capability of the chip to * wakeup the device, based on IRQ availability or if the boolean @@ -479,8 +478,9 @@ static bool isl12057_can_wakeup_machine(struct device *dev) { struct isl12057_rtc_data *data = dev_get_drvdata(dev); - return (data->irq || of_property_read_bool(dev->of_node, - "isil,irq2-can-wakeup-machine")); + return data->irq || of_property_read_bool(dev->of_node, "wakeup-source") + || of_property_read_bool(dev->of_node, /* legacy */ + "isil,irq2-can-wakeup-machine"); } #else static bool isl12057_can_wakeup_machine(struct device *dev) From 62c8c20af92ea312ecb22cec4e83082e5843076b Mon Sep 17 00:00:00 2001 From: Tero Kristo Date: Fri, 23 Oct 2015 09:29:57 +0300 Subject: [PATCH 21/23] rtc: ds1307: Fix alarm programming for mcp794xx mcp794xx alarm registers must be written in BCD format. However, the alarm programming logic neglected this by adding one to the value after bin2bcd conversion has been already done, writing bad values to month register in case the alarm being set is in October. In this case, the alarm month value becomes 0x0a instead of the expected 0x10. Fix by moving the +1 addition within the bin2bcd call also. Fixes: 1d1945d261a2 ("drivers/rtc/rtc-ds1307.c: add alarm support for mcp7941x chips") Signed-off-by: Tero Kristo Acked-by: Nishanth Menon Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-ds1307.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index a705e6490808..188006c55ce0 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -718,9 +718,9 @@ static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t) regs[3] = bin2bcd(t->time.tm_sec); regs[4] = bin2bcd(t->time.tm_min); regs[5] = bin2bcd(t->time.tm_hour); - regs[6] = bin2bcd(t->time.tm_wday) + 1; + regs[6] = bin2bcd(t->time.tm_wday + 1); regs[7] = bin2bcd(t->time.tm_mday); - regs[8] = bin2bcd(t->time.tm_mon) + 1; + regs[8] = bin2bcd(t->time.tm_mon + 1); /* Clear the alarm 0 interrupt flag. */ regs[6] &= ~MCP794XX_BIT_ALMX_IF; From fb4ac3c14b07a6fd33a399845273661172ed282d Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Sun, 1 Nov 2015 20:49:04 +0900 Subject: [PATCH 22/23] rtc: s3c: Set year, month, day value for setting alarm This patch sets year, month, day value for set_alarm function. The current driver omits to set the values. This fixes setting wake alarm for dates different than current day. Without the patch the alarm scheduled for tomorrow would fire today on chosen time. Signed-off-by: Donggeun Kim Signed-off-by: MyungJoo Ham Signed-off-by: KyungMin Park [k.kozlowski: Rebase and test the patch, update commit message] Signed-off-by: Krzysztof Kozlowski Signed-off-by: Alexandre Belloni --- drivers/rtc/rtc-s3c.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 7cc8f73a3fe8..ffb860d18701 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -302,6 +302,7 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) struct s3c_rtc *info = dev_get_drvdata(dev); struct rtc_time *tm = &alrm->time; unsigned int alrm_en; + int year = tm->tm_year - 100; dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n", alrm->enabled, @@ -328,6 +329,21 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR); } + if (year < 100 && year >= 0) { + alrm_en |= S3C2410_RTCALM_YEAREN; + writeb(bin2bcd(year), info->base + S3C2410_ALMYEAR); + } + + if (tm->tm_mon < 12 && tm->tm_mon >= 0) { + alrm_en |= S3C2410_RTCALM_MONEN; + writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_ALMMON); + } + + if (tm->tm_mday <= 31 && tm->tm_mday >= 1) { + alrm_en |= S3C2410_RTCALM_DAYEN; + writeb(bin2bcd(tm->tm_mday), info->base + S3C2410_ALMDATE); + } + dev_dbg(dev, "setting S3C2410_RTCALM to %08x\n", alrm_en); writeb(alrm_en, info->base + S3C2410_RTCALM); From 1e3929ef0e1c4c7127b785ce7a236965b3739406 Mon Sep 17 00:00:00 2001 From: Alexandre Belloni Date: Mon, 2 Nov 2015 23:48:32 +0100 Subject: [PATCH 23/23] rtc: Add a driver for Micro Crystal RV8803 This driver supports the following functions: - reading and settings time - alarms when connected to an IRQ - reading and clearing the voltage low flags - nvram Signed-off-by: Alexandre Belloni --- drivers/rtc/Kconfig | 9 + drivers/rtc/Makefile | 1 + drivers/rtc/rtc-rv8803.c | 521 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 531 insertions(+) create mode 100644 drivers/rtc/rtc-rv8803.c diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 57c2dbc4f438..2a524244afec 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -593,6 +593,15 @@ config RTC_DRV_RV3029C2 This driver can also be built as a module. If so, the module will be called rtc-rv3029c2. +config RTC_DRV_RV8803 + tristate "Micro Crystal RV8803" + help + If you say yes here you get support for the Micro Crystal + RV8803 RTC chips. + + This driver can also be built as a module. If so, the module + will be called rtc-rv8803. + config RTC_DRV_S5M tristate "Samsung S2M/S5M series" depends on MFD_SEC_CORE diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index e491eb524434..231f76451615 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -126,6 +126,7 @@ obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o +obj-$(CONFIG_RTC_DRV_RV8803) += rtc-rv8803.o obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o diff --git a/drivers/rtc/rtc-rv8803.c b/drivers/rtc/rtc-rv8803.c new file mode 100644 index 000000000000..e7329e21bfe3 --- /dev/null +++ b/drivers/rtc/rtc-rv8803.c @@ -0,0 +1,521 @@ +/* + * RTC driver for the Micro Crystal RV8803 + * + * Copyright (C) 2015 Micro Crystal SA + * + * Alexandre Belloni + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#define RV8803_SEC 0x00 +#define RV8803_MIN 0x01 +#define RV8803_HOUR 0x02 +#define RV8803_WEEK 0x03 +#define RV8803_DAY 0x04 +#define RV8803_MONTH 0x05 +#define RV8803_YEAR 0x06 +#define RV8803_RAM 0x07 +#define RV8803_ALARM_MIN 0x08 +#define RV8803_ALARM_HOUR 0x09 +#define RV8803_ALARM_WEEK_OR_DAY 0x0A +#define RV8803_EXT 0x0D +#define RV8803_FLAG 0x0E +#define RV8803_CTRL 0x0F + +#define RV8803_EXT_WADA BIT(6) + +#define RV8803_FLAG_V1F BIT(0) +#define RV8803_FLAG_V2F BIT(1) +#define RV8803_FLAG_AF BIT(3) +#define RV8803_FLAG_TF BIT(4) +#define RV8803_FLAG_UF BIT(5) + +#define RV8803_CTRL_RESET BIT(0) + +#define RV8803_CTRL_EIE BIT(2) +#define RV8803_CTRL_AIE BIT(3) +#define RV8803_CTRL_TIE BIT(4) +#define RV8803_CTRL_UIE BIT(5) + +struct rv8803_data { + struct i2c_client *client; + struct rtc_device *rtc; + spinlock_t flags_lock; + u8 ctrl; +}; + +static irqreturn_t rv8803_handle_irq(int irq, void *dev_id) +{ + struct i2c_client *client = dev_id; + struct rv8803_data *rv8803 = i2c_get_clientdata(client); + unsigned long events = 0; + u8 flags; + + spin_lock(&rv8803->flags_lock); + + flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); + if (flags <= 0) { + spin_unlock(&rv8803->flags_lock); + return IRQ_NONE; + } + + if (flags & RV8803_FLAG_V1F) + dev_warn(&client->dev, "Voltage low, temperature compensation stopped.\n"); + + if (flags & RV8803_FLAG_V2F) + dev_warn(&client->dev, "Voltage low, data loss detected.\n"); + + if (flags & RV8803_FLAG_TF) { + flags &= ~RV8803_FLAG_TF; + rv8803->ctrl &= ~RV8803_CTRL_TIE; + events |= RTC_PF; + } + + if (flags & RV8803_FLAG_AF) { + flags &= ~RV8803_FLAG_AF; + rv8803->ctrl &= ~RV8803_CTRL_AIE; + events |= RTC_AF; + } + + if (flags & RV8803_FLAG_UF) { + flags &= ~RV8803_FLAG_UF; + rv8803->ctrl &= ~RV8803_CTRL_UIE; + events |= RTC_UF; + } + + if (events) { + rtc_update_irq(rv8803->rtc, 1, events); + i2c_smbus_write_byte_data(client, RV8803_FLAG, flags); + i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL, + rv8803->ctrl); + } + + spin_unlock(&rv8803->flags_lock); + + return IRQ_HANDLED; +} + +static int rv8803_get_time(struct device *dev, struct rtc_time *tm) +{ + struct rv8803_data *rv8803 = dev_get_drvdata(dev); + u8 date1[7]; + u8 date2[7]; + u8 *date = date1; + int ret, flags; + + flags = i2c_smbus_read_byte_data(rv8803->client, RV8803_FLAG); + if (flags < 0) + return flags; + + if (flags & RV8803_FLAG_V2F) { + dev_warn(dev, "Voltage low, data is invalid.\n"); + return -EINVAL; + } + + ret = i2c_smbus_read_i2c_block_data(rv8803->client, RV8803_SEC, + 7, date); + if (ret != 7) + return ret < 0 ? ret : -EIO; + + if ((date1[RV8803_SEC] & 0x7f) == bin2bcd(59)) { + ret = i2c_smbus_read_i2c_block_data(rv8803->client, RV8803_SEC, + 7, date2); + if (ret != 7) + return ret < 0 ? ret : -EIO; + + if ((date2[RV8803_SEC] & 0x7f) != bin2bcd(59)) + date = date2; + } + + tm->tm_sec = bcd2bin(date[RV8803_SEC] & 0x7f); + tm->tm_min = bcd2bin(date[RV8803_MIN] & 0x7f); + tm->tm_hour = bcd2bin(date[RV8803_HOUR] & 0x3f); + tm->tm_wday = ffs(date[RV8803_WEEK] & 0x7f); + tm->tm_mday = bcd2bin(date[RV8803_DAY] & 0x3f); + tm->tm_mon = bcd2bin(date[RV8803_MONTH] & 0x1f) - 1; + tm->tm_year = bcd2bin(date[RV8803_YEAR]) + 100; + + return rtc_valid_tm(tm); +} + +static int rv8803_set_time(struct device *dev, struct rtc_time *tm) +{ + struct rv8803_data *rv8803 = dev_get_drvdata(dev); + u8 date[7]; + int flags, ret; + unsigned long irqflags; + + if ((tm->tm_year < 100) || (tm->tm_year > 199)) + return -EINVAL; + + date[RV8803_SEC] = bin2bcd(tm->tm_sec); + date[RV8803_MIN] = bin2bcd(tm->tm_min); + date[RV8803_HOUR] = bin2bcd(tm->tm_hour); + date[RV8803_WEEK] = 1 << (tm->tm_wday); + date[RV8803_DAY] = bin2bcd(tm->tm_mday); + date[RV8803_MONTH] = bin2bcd(tm->tm_mon + 1); + date[RV8803_YEAR] = bin2bcd(tm->tm_year - 100); + + ret = i2c_smbus_write_i2c_block_data(rv8803->client, RV8803_SEC, + 7, date); + if (ret < 0) + return ret; + + spin_lock_irqsave(&rv8803->flags_lock, irqflags); + + flags = i2c_smbus_read_byte_data(rv8803->client, RV8803_FLAG); + if (flags < 0) { + spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + return flags; + } + + ret = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG, + flags & ~RV8803_FLAG_V2F); + + spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + + return ret; +} + +static int rv8803_get_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct rv8803_data *rv8803 = dev_get_drvdata(dev); + struct i2c_client *client = rv8803->client; + u8 alarmvals[3]; + int flags, ret; + + ret = i2c_smbus_read_i2c_block_data(client, RV8803_ALARM_MIN, + 3, alarmvals); + if (ret != 3) + return ret < 0 ? ret : -EIO; + + flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); + if (flags < 0) + return flags; + + alrm->time.tm_sec = 0; + alrm->time.tm_min = bcd2bin(alarmvals[0] & 0x7f); + alrm->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f); + alrm->time.tm_wday = -1; + alrm->time.tm_mday = bcd2bin(alarmvals[2] & 0x3f); + alrm->time.tm_mon = -1; + alrm->time.tm_year = -1; + + alrm->enabled = !!(rv8803->ctrl & RV8803_CTRL_AIE); + alrm->pending = (flags & RV8803_FLAG_AF) && alrm->enabled; + + return 0; +} + +static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rv8803_data *rv8803 = dev_get_drvdata(dev); + u8 alarmvals[3]; + u8 ctrl[2]; + int ret, err; + unsigned long irqflags; + + /* The alarm has no seconds, round up to nearest minute */ + if (alrm->time.tm_sec) { + time64_t alarm_time = rtc_tm_to_time64(&alrm->time); + + alarm_time += 60 - alrm->time.tm_sec; + rtc_time64_to_tm(alarm_time, &alrm->time); + } + + spin_lock_irqsave(&rv8803->flags_lock, irqflags); + + ret = i2c_smbus_read_i2c_block_data(client, RV8803_FLAG, 2, ctrl); + if (ret != 2) { + spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + return ret < 0 ? ret : -EIO; + } + + alarmvals[0] = bin2bcd(alrm->time.tm_min); + alarmvals[1] = bin2bcd(alrm->time.tm_hour); + alarmvals[2] = bin2bcd(alrm->time.tm_mday); + + if (rv8803->ctrl & (RV8803_CTRL_AIE | RV8803_CTRL_UIE)) { + rv8803->ctrl &= ~(RV8803_CTRL_AIE | RV8803_CTRL_UIE); + err = i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL, + rv8803->ctrl); + if (err) { + spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + return err; + } + } + + ctrl[1] &= ~RV8803_FLAG_AF; + err = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG, ctrl[1]); + spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + if (err) + return err; + + err = i2c_smbus_write_i2c_block_data(rv8803->client, RV8803_ALARM_MIN, + 3, alarmvals); + if (err) + return err; + + if (alrm->enabled) { + if (rv8803->rtc->uie_rtctimer.enabled) + rv8803->ctrl |= RV8803_CTRL_UIE; + if (rv8803->rtc->aie_timer.enabled) + rv8803->ctrl |= RV8803_CTRL_AIE; + + err = i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL, + rv8803->ctrl); + if (err) + return err; + } + + return 0; +} + +static int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rv8803_data *rv8803 = dev_get_drvdata(dev); + int ctrl, flags, err; + unsigned long irqflags; + + ctrl = rv8803->ctrl; + + if (enabled) { + if (rv8803->rtc->uie_rtctimer.enabled) + ctrl |= RV8803_CTRL_UIE; + if (rv8803->rtc->aie_timer.enabled) + ctrl |= RV8803_CTRL_AIE; + } else { + if (!rv8803->rtc->uie_rtctimer.enabled) + ctrl &= ~RV8803_CTRL_UIE; + if (!rv8803->rtc->aie_timer.enabled) + ctrl &= ~RV8803_CTRL_AIE; + } + + spin_lock_irqsave(&rv8803->flags_lock, irqflags); + flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); + if (flags < 0) { + spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + return flags; + } + flags &= ~(RV8803_FLAG_AF | RV8803_FLAG_UF); + err = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags); + spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + if (err) + return err; + + if (ctrl != rv8803->ctrl) { + rv8803->ctrl = ctrl; + err = i2c_smbus_write_byte_data(client, RV8803_CTRL, + rv8803->ctrl); + if (err) + return err; + } + + return 0; +} + +static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct i2c_client *client = to_i2c_client(dev); + struct rv8803_data *rv8803 = dev_get_drvdata(dev); + int flags, ret = 0; + unsigned long irqflags; + + switch (cmd) { + case RTC_VL_READ: + flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); + if (flags < 0) + return flags; + + if (flags & RV8803_FLAG_V1F) + dev_warn(&client->dev, "Voltage low, temperature compensation stopped.\n"); + + if (flags & RV8803_FLAG_V2F) + dev_warn(&client->dev, "Voltage low, data loss detected.\n"); + + flags &= RV8803_FLAG_V1F | RV8803_FLAG_V2F; + + if (copy_to_user((void __user *)arg, &flags, sizeof(int))) + return -EFAULT; + + return 0; + + case RTC_VL_CLR: + spin_lock_irqsave(&rv8803->flags_lock, irqflags); + flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); + if (flags < 0) { + spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + return flags; + } + + flags &= ~(RV8803_FLAG_V1F | RV8803_FLAG_V2F); + ret = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags); + spin_unlock_irqrestore(&rv8803->flags_lock, irqflags); + if (ret < 0) + return ret; + + return 0; + + default: + return -ENOIOCTLCMD; + } +} + +static ssize_t rv8803_nvram_write(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = kobj_to_dev(kobj); + struct i2c_client *client = to_i2c_client(dev); + int ret; + + ret = i2c_smbus_write_byte_data(client, RV8803_RAM, buf[0]); + if (ret < 0) + return ret; + + return 1; +} + +static ssize_t rv8803_nvram_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *attr, + char *buf, loff_t off, size_t count) +{ + struct device *dev = kobj_to_dev(kobj); + struct i2c_client *client = to_i2c_client(dev); + int ret; + + ret = i2c_smbus_read_byte_data(client, RV8803_RAM); + if (ret < 0) + return ret; + + buf[0] = ret; + + return 1; +} + +static struct bin_attribute rv8803_nvram_attr = { + .attr = { + .name = "nvram", + .mode = S_IRUGO | S_IWUSR, + }, + .size = 1, + .read = rv8803_nvram_read, + .write = rv8803_nvram_write, +}; + +static struct rtc_class_ops rv8803_rtc_ops = { + .read_time = rv8803_get_time, + .set_time = rv8803_set_time, + .ioctl = rv8803_ioctl, +}; + +static int rv8803_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct rv8803_data *rv8803; + int err, flags; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA | + I2C_FUNC_SMBUS_I2C_BLOCK)) { + dev_err(&adapter->dev, "doesn't support I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK\n"); + return -EIO; + } + + rv8803 = devm_kzalloc(&client->dev, sizeof(struct rv8803_data), + GFP_KERNEL); + if (!rv8803) + return -ENOMEM; + + rv8803->client = client; + i2c_set_clientdata(client, rv8803); + + flags = i2c_smbus_read_byte_data(client, RV8803_FLAG); + if (flags < 0) + return flags; + + if (flags & RV8803_FLAG_V1F) + dev_warn(&client->dev, "Voltage low, temperature compensation stopped.\n"); + + if (flags & RV8803_FLAG_V2F) + dev_warn(&client->dev, "Voltage low, data loss detected.\n"); + + if (flags & RV8803_FLAG_AF) + dev_warn(&client->dev, "An alarm maybe have been missed.\n"); + + if (client->irq > 0) { + err = devm_request_threaded_irq(&client->dev, client->irq, + NULL, rv8803_handle_irq, + IRQF_TRIGGER_LOW | IRQF_ONESHOT, + "rv8803", client); + if (err) { + dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n"); + client->irq = 0; + } else { + rv8803_rtc_ops.read_alarm = rv8803_get_alarm; + rv8803_rtc_ops.set_alarm = rv8803_set_alarm; + rv8803_rtc_ops.alarm_irq_enable = rv8803_alarm_irq_enable; + } + } + + rv8803->rtc = devm_rtc_device_register(&client->dev, client->name, + &rv8803_rtc_ops, THIS_MODULE); + if (IS_ERR(rv8803->rtc)) { + dev_err(&client->dev, "unable to register the class device\n"); + return PTR_ERR(rv8803->rtc); + } + + err = i2c_smbus_write_byte_data(rv8803->client, RV8803_EXT, + RV8803_EXT_WADA); + if (err) + return err; + + err = device_create_bin_file(&client->dev, &rv8803_nvram_attr); + if (err) + return err; + + rv8803->rtc->max_user_freq = 1; + + return 0; +} + +static int rv8803_remove(struct i2c_client *client) +{ + device_remove_bin_file(&client->dev, &rv8803_nvram_attr); + + return 0; +} + +static const struct i2c_device_id rv8803_id[] = { + { "rv8803", 0 }, + { } +}; +MODULE_DEVICE_TABLE(i2c, rv8803_id); + +static struct i2c_driver rv8803_driver = { + .driver = { + .name = "rtc-rv8803", + }, + .probe = rv8803_probe, + .remove = rv8803_remove, + .id_table = rv8803_id, +}; +module_i2c_driver(rv8803_driver); + +MODULE_AUTHOR("Alexandre Belloni "); +MODULE_DESCRIPTION("Micro Crystal RV8803 RTC driver"); +MODULE_LICENSE("GPL v2");