* Re: [PATCH] rtc: omap: Support scratch registers
From: Keerthy @ 2017-11-08 8:32 UTC (permalink / raw)
To: Alexandre Belloni; +Cc: Sekhar Nori, linux-rtc, linux-kernel, Linux OMAP List
In-Reply-To: <79f52c27-1c6a-c4ec-9635-d05eec635661@ti.com>
On Wednesday 08 November 2017 02:01 PM, Keerthy wrote:
>
>
> On Wednesday 08 November 2017 01:51 PM, Alexandre Belloni wrote:
>> On 08/11/2017 at 13:36:15 +0530, Keerthy wrote:
>>>
>>>
>>> On Wednesday 08 November 2017 12:46 PM, Alexandre Belloni wrote:
>>>> On 08/11/2017 at 12:38:05 +0530, Keerthy wrote:
>>>>>
>>>>>
>>>>> On Wednesday 08 November 2017 11:57 AM, Alexandre Belloni wrote:
>>>>>> Hi,
>>>>>>
>>>>>> On 08/11/2017 at 11:30:45 +0530, Keerthy wrote:
>>>>>>>>>> +static int omap_rtc_scratch_read(void *priv, unsigned int offset, void *_val,
>>>>>>>>>> + size_t bytes)
>>>>>>>>>> +{
>>>>>>>>>> + struct omap_rtc *rtc = priv;
>>>>>>>>>> + u32 *val = _val;
>>>>>>>>>> + int i;
>>>>>>>>>> +
>>>>>>>>>> + for (i = 0; i < bytes / 4; i++)
>>>>>>>>>> + val[i] = rtc_readl(rtc,
>>>>>>>>>> + OMAP_RTC_SCRATCH0_REG + offset + (i * 4));
>>>>>>>
>>>>>>> Can the offset be the Scratch register number instead of bytes offset?
>>>>>>> More intuitive to me.
>>>>>>>
>>>>>>> So that one can request using offset as 0, 1, 2 instead of 0, 4, 8?
>>>>>>>
>>>>>>
>>>>>> Well, the offset is coming from the nvmem core, itself getting it from
>>>>>> the Linux file API (and it is in bytes). However, you have the guarantee
>>>>>> that it will be aligned on a word, see:
>>>>>> http://elixir.free-electrons.com/linux/latest/source/drivers/nvmem/core.c#L88
>>>>>
>>>>> Okay Alexandre. Thanks for clarifying. Looks good to me.
>>>>> I have tested on AM437X-GP-EVM.
>>>>>
>>>>
>>>> If needed, you can define nvmem cells (and I guess that is what you
>>>> want):
>>>> http://elixir.free-electrons.com/linux/latest/source/Documentation/devicetree/bindings/nvmem/nvmem.txt
>>>
>>> With this patch we cannot still use nvmem_device_write and
>>> nvmem_device_read as the nvmem_device is still not registered.
>>>
>>> How can a driver write to scratch pad registers? Should we be calling
>>> nvmem_register in the probe?
>>
>> It is not needed, it is registered by rtc_nvmem_register().
>
> Let me go through the chain:
>
> rtc_register_device -> __rtc_register_device --> rtc_nvmem_register ->
> rtc_nvram_register
>
> I am seeing that for rtc-omap driver there is rtc_register_device call
I mean there NO rtc_register_device call.
> and i see that rtc_nvmem_register is not getting called.
>
> Should we add rtc_register_device in probe of rtc-omap?
>
>>
>> nvmem_device_read/write are working because that is what I'm using to
>> implement the old sysfs ABI with rtc_nvram_read/write.
>>
^ permalink raw reply
* Re: [PATCH] rtc: omap: Support scratch registers
From: Alexandre Belloni @ 2017-11-08 8:35 UTC (permalink / raw)
To: Keerthy; +Cc: Sekhar Nori, linux-rtc, linux-kernel, Linux OMAP List
In-Reply-To: <c24e76cc-ba52-3d26-7dce-5c9ed7e68db1@ti.com>
On 08/11/2017 at 14:02:31 +0530, Keerthy wrote:
>
>
> On Wednesday 08 November 2017 02:01 PM, Keerthy wrote:
> >
> >
> > On Wednesday 08 November 2017 01:51 PM, Alexandre Belloni wrote:
> >> On 08/11/2017 at 13:36:15 +0530, Keerthy wrote:
> >>>
> >>>
> >>> On Wednesday 08 November 2017 12:46 PM, Alexandre Belloni wrote:
> >>>> On 08/11/2017 at 12:38:05 +0530, Keerthy wrote:
> >>>>>
> >>>>>
> >>>>> On Wednesday 08 November 2017 11:57 AM, Alexandre Belloni wrote:
> >>>>>> Hi,
> >>>>>>
> >>>>>> On 08/11/2017 at 11:30:45 +0530, Keerthy wrote:
> >>>>>>>>>> +static int omap_rtc_scratch_read(void *priv, unsigned int offset, void *_val,
> >>>>>>>>>> + size_t bytes)
> >>>>>>>>>> +{
> >>>>>>>>>> + struct omap_rtc *rtc = priv;
> >>>>>>>>>> + u32 *val = _val;
> >>>>>>>>>> + int i;
> >>>>>>>>>> +
> >>>>>>>>>> + for (i = 0; i < bytes / 4; i++)
> >>>>>>>>>> + val[i] = rtc_readl(rtc,
> >>>>>>>>>> + OMAP_RTC_SCRATCH0_REG + offset + (i * 4));
> >>>>>>>
> >>>>>>> Can the offset be the Scratch register number instead of bytes offset?
> >>>>>>> More intuitive to me.
> >>>>>>>
> >>>>>>> So that one can request using offset as 0, 1, 2 instead of 0, 4, 8?
> >>>>>>>
> >>>>>>
> >>>>>> Well, the offset is coming from the nvmem core, itself getting it from
> >>>>>> the Linux file API (and it is in bytes). However, you have the guarantee
> >>>>>> that it will be aligned on a word, see:
> >>>>>> http://elixir.free-electrons.com/linux/latest/source/drivers/nvmem/core.c#L88
> >>>>>
> >>>>> Okay Alexandre. Thanks for clarifying. Looks good to me.
> >>>>> I have tested on AM437X-GP-EVM.
> >>>>>
> >>>>
> >>>> If needed, you can define nvmem cells (and I guess that is what you
> >>>> want):
> >>>> http://elixir.free-electrons.com/linux/latest/source/Documentation/devicetree/bindings/nvmem/nvmem.txt
> >>>
> >>> With this patch we cannot still use nvmem_device_write and
> >>> nvmem_device_read as the nvmem_device is still not registered.
> >>>
> >>> How can a driver write to scratch pad registers? Should we be calling
> >>> nvmem_register in the probe?
> >>
> >> It is not needed, it is registered by rtc_nvmem_register().
> >
> > Let me go through the chain:
> >
> > rtc_register_device -> __rtc_register_device --> rtc_nvmem_register ->
> > rtc_nvram_register
> >
> > I am seeing that for rtc-omap driver there is rtc_register_device call
>
> I mean there NO rtc_register_device call.
>
> > and i see that rtc_nvmem_register is not getting called.
> >
> > Should we add rtc_register_device in probe of rtc-omap?
> >
Do you also have that patch:
https://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git/commit/?h=rtc-next&id=57072758623fa4f3019bce65e2b00f24af8dfdd7
?
> >>
> >> nvmem_device_read/write are working because that is what I'm using to
> >> implement the old sysfs ABI with rtc_nvram_read/write.
> >>
--
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* Re: [PATCH] rtc: omap: Support scratch registers
From: Keerthy @ 2017-11-08 8:48 UTC (permalink / raw)
To: Alexandre Belloni; +Cc: Sekhar Nori, linux-rtc, linux-kernel, Linux OMAP List
In-Reply-To: <20171108083533.5ibx43biwk7exlnc@piout.net>
On Wednesday 08 November 2017 02:05 PM, Alexandre Belloni wrote:
> On 08/11/2017 at 14:02:31 +0530, Keerthy wrote:
>>
>>
>> On Wednesday 08 November 2017 02:01 PM, Keerthy wrote:
>>>
>>>
>>> On Wednesday 08 November 2017 01:51 PM, Alexandre Belloni wrote:
>>>> On 08/11/2017 at 13:36:15 +0530, Keerthy wrote:
>>>>>
>>>>>
>>>>> On Wednesday 08 November 2017 12:46 PM, Alexandre Belloni wrote:
>>>>>> On 08/11/2017 at 12:38:05 +0530, Keerthy wrote:
>>>>>>>
>>>>>>>
>>>>>>> On Wednesday 08 November 2017 11:57 AM, Alexandre Belloni wrote:
>>>>>>>> Hi,
>>>>>>>>
>>>>>>>> On 08/11/2017 at 11:30:45 +0530, Keerthy wrote:
>>>>>>>>>>>> +static int omap_rtc_scratch_read(void *priv, unsigned int offset, void *_val,
>>>>>>>>>>>> + size_t bytes)
>>>>>>>>>>>> +{
>>>>>>>>>>>> + struct omap_rtc *rtc = priv;
>>>>>>>>>>>> + u32 *val = _val;
>>>>>>>>>>>> + int i;
>>>>>>>>>>>> +
>>>>>>>>>>>> + for (i = 0; i < bytes / 4; i++)
>>>>>>>>>>>> + val[i] = rtc_readl(rtc,
>>>>>>>>>>>> + OMAP_RTC_SCRATCH0_REG + offset + (i * 4));
>>>>>>>>>
>>>>>>>>> Can the offset be the Scratch register number instead of bytes offset?
>>>>>>>>> More intuitive to me.
>>>>>>>>>
>>>>>>>>> So that one can request using offset as 0, 1, 2 instead of 0, 4, 8?
>>>>>>>>>
>>>>>>>>
>>>>>>>> Well, the offset is coming from the nvmem core, itself getting it from
>>>>>>>> the Linux file API (and it is in bytes). However, you have the guarantee
>>>>>>>> that it will be aligned on a word, see:
>>>>>>>> http://elixir.free-electrons.com/linux/latest/source/drivers/nvmem/core.c#L88
>>>>>>>
>>>>>>> Okay Alexandre. Thanks for clarifying. Looks good to me.
>>>>>>> I have tested on AM437X-GP-EVM.
>>>>>>>
>>>>>>
>>>>>> If needed, you can define nvmem cells (and I guess that is what you
>>>>>> want):
>>>>>> http://elixir.free-electrons.com/linux/latest/source/Documentation/devicetree/bindings/nvmem/nvmem.txt
>>>>>
>>>>> With this patch we cannot still use nvmem_device_write and
>>>>> nvmem_device_read as the nvmem_device is still not registered.
>>>>>
>>>>> How can a driver write to scratch pad registers? Should we be calling
>>>>> nvmem_register in the probe?
>>>>
>>>> It is not needed, it is registered by rtc_nvmem_register().
>>>
>>> Let me go through the chain:
>>>
>>> rtc_register_device -> __rtc_register_device --> rtc_nvmem_register ->
>>> rtc_nvram_register
>>>
>>> I am seeing that for rtc-omap driver there is rtc_register_device call
>>
>> I mean there NO rtc_register_device call.
>>
>>> and i see that rtc_nvmem_register is not getting called.
>>>
>>> Should we add rtc_register_device in probe of rtc-omap?
>>>
>
> Do you also have that patch:
> https://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git/commit/?h=rtc-next&id=57072758623fa4f3019bce65e2b00f24af8dfdd7
>
> ?
Ah! Now everything falls in place :-). I did not receive this patch. I
believe i need to add a patch so linux-omap list gets Cc'd whenever
rtc-omap driver is touched.
Thanks a bunch!
>
>>>>
>>>> nvmem_device_read/write are working because that is what I'm using to
>>>> implement the old sysfs ABI with rtc_nvram_read/write.
>>>>
>
^ permalink raw reply
* [PATCH v2 1/2] dt-bindings: rtc: Add Spreadtrum SC27xx RTC documentation
From: Baolin Wang @ 2017-11-08 9:16 UTC (permalink / raw)
To: a.zummo, alexandre.belloni, robh+dt, mark.rutland
Cc: devicetree, linux-kernel, linux-rtc, broonie, baolin.wang,
baolin.wang
This patch adds the binding documentation for Spreadtrum SC27xx series
RTC device.
Signed-off-by: Baolin Wang <baolin.wang@spreadtrum.com>
---
Changes since v1:
- Use a specific chip name as compatible string.
- Remove useless alias.
- Add the parent MFD node.
---
.../devicetree/bindings/rtc/sprd,sc27xx-rtc.txt | 27 ++++++++++++++++++++
1 file changed, 27 insertions(+)
create mode 100644 Documentation/devicetree/bindings/rtc/sprd,sc27xx-rtc.txt
diff --git a/Documentation/devicetree/bindings/rtc/sprd,sc27xx-rtc.txt b/Documentation/devicetree/bindings/rtc/sprd,sc27xx-rtc.txt
new file mode 100644
index 0000000..7c170da
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/sprd,sc27xx-rtc.txt
@@ -0,0 +1,27 @@
+Spreadtrum SC27xx Real Time Clock
+
+Required properties:
+- compatible: should be "sprd,sc2731-rtc".
+- reg: address offset of rtc register.
+- interrupt-parent: phandle for the interrupt controller.
+- interrupts: rtc alarm interrupt.
+
+Example:
+
+ sc2731_pmic: pmic@0 {
+ compatible = "sprd,sc2731";
+ reg = <0>;
+ spi-max-frequency = <26000000>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rtc@280 {
+ compatible = "sprd,sc2731-rtc";
+ reg = <0x280>;
+ interrupt-parent = <&sc2731_pmic>;
+ interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 2/2] rtc: sprd: Add Spreadtrum RTC driver
From: Baolin Wang @ 2017-11-08 9:16 UTC (permalink / raw)
To: a.zummo, alexandre.belloni, robh+dt, mark.rutland
Cc: devicetree, linux-kernel, linux-rtc, broonie, baolin.wang,
baolin.wang
In-Reply-To: <c65b61e5e37cb43214973cb3e479ce06c4a73395.1510132279.git.baolin.wang@spreadtrum.com>
This patch adds the Spreadtrum RTC driver, which embedded in the
Spreadtrum SC27xx series PMICs.
Signed-off-by: Baolin Wang <baolin.wang@spreadtrum.com>
---
Changes since v1:
- Change file name.
- Should depend on the MFD parent.
- Add more help documentation.
- Remove regmap wrapper functions.
- Modify the mothod of setting alarm.
- Remove set_mmss64() method.
- Remove checking RTC power-down.
- Optimize lock/unlock alarm.
---
drivers/rtc/Kconfig | 11 +
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-sc27xx.c | 600 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 612 insertions(+)
create mode 100644 drivers/rtc/rtc-sc27xx.c
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e0e58f3..8c240e7 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1174,6 +1174,17 @@ config RTC_DRV_WM8350
This driver can also be built as a module. If so, the module
will be called "rtc-wm8350".
+config RTC_DRV_SC27XX
+ tristate "Spreadtrum SC27xx RTC"
+ depends on MFD_SC27XX_PMIC || COMPILE_TEST
+ help
+ If you say Y here you will get support for the RTC subsystem
+ of the Spreadtrum SC27xx series PMICs. The SC27xx series PMICs
+ includes the SC2720, SC2721, SC2723, SC2730 and SC2731 chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-sc27xx.
+
config RTC_DRV_SPEAR
tristate "SPEAR ST RTC"
depends on PLAT_SPEAR || COMPILE_TEST
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 7230014..f9b857f 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -143,6 +143,7 @@ obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o
obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
+obj-$(CONFIG_RTC_DRV_SC27XX) += rtc-sc27xx.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o
obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
diff --git a/drivers/rtc/rtc-sc27xx.c b/drivers/rtc/rtc-sc27xx.c
new file mode 100644
index 0000000..f1b673d
--- /dev/null
+++ b/drivers/rtc/rtc-sc27xx.c
@@ -0,0 +1,600 @@
+/*
+ * Copyright (C) 2017 Spreadtrum Communications Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+
+#define SPRD_RTC_SEC_CNT_VALUE 0x0
+#define SPRD_RTC_MIN_CNT_VALUE 0x4
+#define SPRD_RTC_HOUR_CNT_VALUE 0x8
+#define SPRD_RTC_DAY_CNT_VALUE 0xc
+#define SPRD_RTC_SEC_CNT_UPD 0x10
+#define SPRD_RTC_MIN_CNT_UPD 0x14
+#define SPRD_RTC_HOUR_CNT_UPD 0x18
+#define SPRD_RTC_DAY_CNT_UPD 0x1c
+#define SPRD_RTC_SEC_ALM_UPD 0x20
+#define SPRD_RTC_MIN_ALM_UPD 0x24
+#define SPRD_RTC_HOUR_ALM_UPD 0x28
+#define SPRD_RTC_DAY_ALM_UPD 0x2c
+#define SPRD_RTC_INT_EN 0x30
+#define SPRD_RTC_INT_RAW_STS 0x34
+#define SPRD_RTC_INT_CLR 0x38
+#define SPRD_RTC_INT_MASK_STS 0x3C
+#define SPRD_RTC_SEC_ALM_VALUE 0x40
+#define SPRD_RTC_MIN_ALM_VALUE 0x44
+#define SPRD_RTC_HOUR_ALM_VALUE 0x48
+#define SPRD_RTC_DAY_ALM_VALUE 0x4c
+#define SPRD_RTC_SPG_VALUE 0x50
+#define SPRD_RTC_SPG_UPD 0x54
+#define SPRD_RTC_SEC_AUXALM_UPD 0x60
+#define SPRD_RTC_MIN_AUXALM_UPD 0x64
+#define SPRD_RTC_HOUR_AUXALM_UPD 0x68
+#define SPRD_RTC_DAY_AUXALM_UPD 0x6c
+
+/* BIT & MASK definition for SPRD_RTC_INT_* registers */
+#define SPRD_RTC_SEC_EN BIT(0)
+#define SPRD_RTC_MIN_EN BIT(1)
+#define SPRD_RTC_HOUR_EN BIT(2)
+#define SPRD_RTC_DAY_EN BIT(3)
+#define SPRD_RTC_ALARM_EN BIT(4)
+#define SPRD_RTC_HRS_FORMAT_EN BIT(5)
+#define SPRD_RTC_AUXALM_EN BIT(6)
+#define SPRD_RTC_SPG_UPD_EN BIT(7)
+#define SPRD_RTC_SEC_UPD_EN BIT(8)
+#define SPRD_RTC_MIN_UPD_EN BIT(9)
+#define SPRD_RTC_HOUR_UPD_EN BIT(10)
+#define SPRD_RTC_DAY_UPD_EN BIT(11)
+#define SPRD_RTC_ALMSEC_UPD_EN BIT(12)
+#define SPRD_RTC_ALMMIN_UPD_EN BIT(13)
+#define SPRD_RTC_ALMHOUR_UPD_EN BIT(14)
+#define SPRD_RTC_ALMDAY_UPD_EN BIT(15)
+#define SPRD_RTC_INT_MASK GENMASK(15, 0)
+
+#define SPRD_RTC_TIME_INT_MASK \
+ (SPRD_RTC_SEC_UPD_EN | SPRD_RTC_MIN_UPD_EN | \
+ SPRD_RTC_HOUR_UPD_EN | SPRD_RTC_DAY_UPD_EN)
+
+#define SPRD_RTC_ALMTIME_INT_MASK \
+ (SPRD_RTC_ALMSEC_UPD_EN | SPRD_RTC_ALMMIN_UPD_EN | \
+ SPRD_RTC_ALMHOUR_UPD_EN | SPRD_RTC_ALMDAY_UPD_EN)
+
+#define SPRD_RTC_ALM_INT_MASK \
+ (SPRD_RTC_SEC_EN | SPRD_RTC_MIN_EN | \
+ SPRD_RTC_HOUR_EN | SPRD_RTC_DAY_EN | \
+ SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN)
+
+/* second/minute/hour/day values mask definition */
+#define SPRD_RTC_SEC_MASK GENMASK(5, 0)
+#define SPRD_RTC_MIN_MASK GENMASK(5, 0)
+#define SPRD_RTC_HOUR_MASK GENMASK(4, 0)
+#define SPRD_RTC_DAY_MASK GENMASK(15, 0)
+
+/* alarm lock definition for SPRD_RTC_SPG_UPD register */
+#define SPRD_RTC_ALMLOCK_MASK GENMASK(7, 0)
+#define SPRD_RTC_ALM_UNLOCK 0xa5
+#define SPRD_RTC_ALM_LOCK (~SPRD_RTC_ALM_UNLOCK & \
+ SPRD_RTC_ALMLOCK_MASK)
+
+/* SPG values definition for SPRD_RTC_SPG_UPD register */
+#define SPRD_RTC_POWEROFF_ALM_FLAG BIT(8)
+#define SPRD_RTC_POWER_RESET_FLAG BIT(9)
+
+/* timeout of synchronizing time and alarm registers (us) */
+#define SPRD_RTC_POLL_TIMEOUT 200000
+#define SPRD_RTC_POLL_DELAY_US 20000
+
+struct sprd_rtc {
+ struct rtc_device *rtc;
+ struct regmap *regmap;
+ struct device *dev;
+ u32 base;
+ int irq;
+};
+
+/*
+ * The Spreadtrum RTC controller has 3 groups registers, including time, normal
+ * alarm and auxiliary alarm. The time group registers are used to set RTC time,
+ * the normal alarm registers are used to set normal alarm, and the auxiliary
+ * alarm registers are used to set auxiliary alarm. Both alarm event and
+ * auxiliary alarm event can wake up system from deep sleep, but only alarm
+ * event can power up system from power down status.
+ */
+enum sprd_rtc_reg_types {
+ SPRD_RTC_TIME,
+ SPRD_RTC_ALARM,
+ SPRD_RTC_AUX_ALARM,
+};
+
+static int sprd_rtc_clear_alarm_ints(struct sprd_rtc *rtc)
+{
+ return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
+ SPRD_RTC_ALM_INT_MASK);
+}
+
+static int sprd_rtc_disable_ints(struct sprd_rtc *rtc)
+{
+ int ret;
+
+ ret = regmap_update_bits(rtc->regmap, rtc->base + SPRD_RTC_INT_EN,
+ SPRD_RTC_INT_MASK, 0);
+ if (ret)
+ return ret;
+
+ return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
+ SPRD_RTC_INT_MASK);
+}
+
+static int sprd_rtc_lock_alarm(struct sprd_rtc *rtc, bool lock)
+{
+ int ret;
+ u32 val;
+
+ ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_SPG_VALUE, &val);
+ if (ret)
+ return ret;
+
+ val &= ~(SPRD_RTC_ALMLOCK_MASK | SPRD_RTC_POWEROFF_ALM_FLAG);
+ if (lock)
+ val |= SPRD_RTC_ALM_LOCK;
+ else
+ val |= SPRD_RTC_ALM_UNLOCK | SPRD_RTC_POWEROFF_ALM_FLAG;
+
+ ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_SPG_UPD, val);
+ if (ret)
+ return ret;
+
+ /* wait until the SPG value is updated successfully */
+ ret = regmap_read_poll_timeout(rtc->regmap,
+ rtc->base + SPRD_RTC_INT_RAW_STS, val,
+ (val & SPRD_RTC_SPG_UPD_EN),
+ SPRD_RTC_POLL_DELAY_US,
+ SPRD_RTC_POLL_TIMEOUT);
+ if (ret) {
+ dev_err(rtc->dev, "failed to update SPG value:%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sprd_rtc_get_secs(struct sprd_rtc *rtc, enum sprd_rtc_reg_types type,
+ time64_t *secs)
+{
+ u32 sec_reg, min_reg, hour_reg, day_reg;
+ u32 val, sec, min, hour, day;
+ int ret;
+
+ switch (type) {
+ case SPRD_RTC_TIME:
+ sec_reg = SPRD_RTC_SEC_CNT_VALUE;
+ min_reg = SPRD_RTC_MIN_CNT_VALUE;
+ hour_reg = SPRD_RTC_HOUR_CNT_VALUE;
+ day_reg = SPRD_RTC_DAY_CNT_VALUE;
+ break;
+ case SPRD_RTC_ALARM:
+ sec_reg = SPRD_RTC_SEC_ALM_VALUE;
+ min_reg = SPRD_RTC_MIN_ALM_VALUE;
+ hour_reg = SPRD_RTC_HOUR_ALM_VALUE;
+ day_reg = SPRD_RTC_DAY_ALM_VALUE;
+ break;
+ case SPRD_RTC_AUX_ALARM:
+ sec_reg = SPRD_RTC_SEC_AUXALM_UPD;
+ min_reg = SPRD_RTC_MIN_AUXALM_UPD;
+ hour_reg = SPRD_RTC_HOUR_AUXALM_UPD;
+ day_reg = SPRD_RTC_DAY_AUXALM_UPD;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_read(rtc->regmap, rtc->base + sec_reg, &val);
+ if (ret)
+ return ret;
+
+ sec = val & SPRD_RTC_SEC_MASK;
+
+ ret = regmap_read(rtc->regmap, rtc->base + min_reg, &val);
+ if (ret)
+ return ret;
+
+ min = val & SPRD_RTC_MIN_MASK;
+
+ ret = regmap_read(rtc->regmap, rtc->base + hour_reg, &val);
+ if (ret)
+ return ret;
+
+ hour = val & SPRD_RTC_HOUR_MASK;
+
+ ret = regmap_read(rtc->regmap, rtc->base + day_reg, &val);
+ if (ret)
+ return ret;
+
+ day = val & SPRD_RTC_DAY_MASK;
+ *secs = (((time64_t)(day * 24) + hour) * 60 + min) * 60 + sec;
+ return 0;
+}
+
+static int sprd_rtc_set_secs(struct sprd_rtc *rtc, enum sprd_rtc_reg_types type,
+ time64_t secs)
+{
+ u32 sec_reg, min_reg, hour_reg, day_reg, sts_mask;
+ u32 sec, min, hour, day, val;
+ int ret, rem;
+
+ /* convert seconds to RTC time format */
+ day = div_s64_rem(secs, 86400, &rem);
+ hour = rem / 3600;
+ rem -= hour * 3600;
+ min = rem / 60;
+ sec = rem - min * 60;
+
+ switch (type) {
+ case SPRD_RTC_TIME:
+ sec_reg = SPRD_RTC_SEC_CNT_UPD;
+ min_reg = SPRD_RTC_MIN_CNT_UPD;
+ hour_reg = SPRD_RTC_HOUR_CNT_UPD;
+ day_reg = SPRD_RTC_DAY_CNT_UPD;
+ sts_mask = SPRD_RTC_TIME_INT_MASK;
+ break;
+ case SPRD_RTC_ALARM:
+ sec_reg = SPRD_RTC_SEC_ALM_UPD;
+ min_reg = SPRD_RTC_MIN_ALM_UPD;
+ hour_reg = SPRD_RTC_HOUR_ALM_UPD;
+ day_reg = SPRD_RTC_DAY_ALM_UPD;
+ sts_mask = SPRD_RTC_ALMTIME_INT_MASK;
+ break;
+ case SPRD_RTC_AUX_ALARM:
+ sec_reg = SPRD_RTC_SEC_AUXALM_UPD;
+ min_reg = SPRD_RTC_MIN_AUXALM_UPD;
+ hour_reg = SPRD_RTC_HOUR_AUXALM_UPD;
+ day_reg = SPRD_RTC_DAY_AUXALM_UPD;
+ sts_mask = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_write(rtc->regmap, rtc->base + sec_reg, sec);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(rtc->regmap, rtc->base + min_reg, min);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(rtc->regmap, rtc->base + hour_reg, hour);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(rtc->regmap, rtc->base + day_reg, day);
+ if (ret)
+ return ret;
+
+ if (type == SPRD_RTC_AUX_ALARM)
+ return 0;
+
+ /*
+ * Since the time and normal alarm registers are put in always-power-on
+ * region supplied by VDDRTC, then these registers changing time will
+ * be very long, about 125ms. Thus here we should wait until all
+ * values are updated successfully.
+ */
+ ret = regmap_read_poll_timeout(rtc->regmap,
+ rtc->base + SPRD_RTC_INT_RAW_STS, val,
+ ((val & sts_mask) == sts_mask),
+ SPRD_RTC_POLL_DELAY_US,
+ SPRD_RTC_POLL_TIMEOUT);
+ if (ret < 0) {
+ dev_err(rtc->dev, "set time/alarm values timeout\n");
+ return ret;
+ }
+
+ return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
+ sts_mask);
+}
+
+static int sprd_rtc_read_aux_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct sprd_rtc *rtc = dev_get_drvdata(dev);
+ time64_t secs;
+ u32 val;
+ int ret;
+
+ ret = sprd_rtc_get_secs(rtc, SPRD_RTC_AUX_ALARM, &secs);
+ if (ret)
+ return ret;
+
+ rtc_time64_to_tm(secs, &alrm->time);
+
+ ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_EN, &val);
+ if (ret)
+ return ret;
+
+ alrm->enabled = !!(val & SPRD_RTC_AUXALM_EN);
+
+ ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_RAW_STS, &val);
+ if (ret)
+ return ret;
+
+ alrm->pending = !!(val & SPRD_RTC_AUXALM_EN);
+ return 0;
+}
+
+static int sprd_rtc_set_aux_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct sprd_rtc *rtc = dev_get_drvdata(dev);
+ time64_t secs = rtc_tm_to_time64(&alrm->time);
+ int ret;
+
+ /* clear the auxiliary alarm interrupt status */
+ ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
+ SPRD_RTC_AUXALM_EN);
+ if (ret)
+ return ret;
+
+ ret = sprd_rtc_set_secs(rtc, SPRD_RTC_AUX_ALARM, secs);
+ if (ret)
+ return ret;
+
+ if (alrm->enabled) {
+ ret = regmap_update_bits(rtc->regmap,
+ rtc->base + SPRD_RTC_INT_EN,
+ SPRD_RTC_AUXALM_EN,
+ SPRD_RTC_AUXALM_EN);
+ } else {
+ ret = regmap_update_bits(rtc->regmap,
+ rtc->base + SPRD_RTC_INT_EN,
+ SPRD_RTC_AUXALM_EN, 0);
+ }
+
+ return ret;
+}
+
+static int sprd_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct sprd_rtc *rtc = dev_get_drvdata(dev);
+ time64_t secs;
+ int ret;
+
+ ret = sprd_rtc_get_secs(rtc, SPRD_RTC_TIME, &secs);
+ if (ret)
+ return ret;
+
+ rtc_time64_to_tm(secs, tm);
+ return rtc_valid_tm(tm);
+}
+
+static int sprd_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct sprd_rtc *rtc = dev_get_drvdata(dev);
+ time64_t secs = rtc_tm_to_time64(tm);
+
+ return sprd_rtc_set_secs(rtc, SPRD_RTC_TIME, secs);
+}
+
+static int sprd_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct sprd_rtc *rtc = dev_get_drvdata(dev);
+ time64_t secs;
+ int ret;
+ u32 val;
+
+ /*
+ * If aie_timer is enabled, we should get the normal alarm time.
+ * Otherwise we should get auxiliary alarm time.
+ */
+ if (rtc->rtc && rtc->rtc->aie_timer.enabled == 0)
+ return sprd_rtc_read_aux_alarm(dev, alrm);
+
+ ret = sprd_rtc_get_secs(rtc, SPRD_RTC_ALARM, &secs);
+ if (ret)
+ return ret;
+
+ rtc_time64_to_tm(secs, &alrm->time);
+
+ ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_EN, &val);
+ if (ret)
+ return ret;
+
+ alrm->enabled = !!(val & SPRD_RTC_ALARM_EN);
+
+ ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_RAW_STS, &val);
+ if (ret)
+ return ret;
+
+ alrm->pending = !!(val & SPRD_RTC_ALARM_EN);
+ return 0;
+}
+
+static int sprd_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct sprd_rtc *rtc = dev_get_drvdata(dev);
+ time64_t secs = rtc_tm_to_time64(&alrm->time);
+ struct rtc_time aie_time =
+ rtc_ktime_to_tm(rtc->rtc->aie_timer.node.expires);
+ int ret;
+
+ /*
+ * We have 2 groups alarms: normal alarm and auxiliary alarm. Since
+ * both normal alarm event and auxiliary alarm event can wake up system
+ * from deep sleep, but only alarm event can power up system from power
+ * down status. Moreover we do not need to poll about 125ms when
+ * updating auxiliary alarm registers. Thus we usually set auxiliary
+ * alarm when wake up system from deep sleep, and for other scenarios,
+ * we should set normal alarm with polling status.
+ *
+ * So here we check if the alarm time is set by aie_timer, if yes, we
+ * should set normal alarm, if not, we should set auxiliary alarm which
+ * means it is just a wake event.
+ */
+ if (!rtc->rtc->aie_timer.enabled || rtc_tm_sub(&aie_time, &alrm->time))
+ return sprd_rtc_set_aux_alarm(dev, alrm);
+
+ /* clear the alarm interrupt status firstly */
+ ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
+ SPRD_RTC_ALARM_EN);
+ if (ret)
+ return ret;
+
+ ret = sprd_rtc_set_secs(rtc, SPRD_RTC_ALARM, secs);
+ if (ret)
+ return ret;
+
+ if (alrm->enabled) {
+ ret = regmap_update_bits(rtc->regmap,
+ rtc->base + SPRD_RTC_INT_EN,
+ SPRD_RTC_ALARM_EN,
+ SPRD_RTC_ALARM_EN);
+ if (ret)
+ return ret;
+
+ /* unlock the alarm to enable the alarm function. */
+ ret = sprd_rtc_lock_alarm(rtc, false);
+ } else {
+ regmap_update_bits(rtc->regmap,
+ rtc->base + SPRD_RTC_INT_EN,
+ SPRD_RTC_ALARM_EN, 0);
+
+ /*
+ * Lock the alarm function in case fake alarm event will power
+ * up systems.
+ */
+ ret = sprd_rtc_lock_alarm(rtc, true);
+ }
+
+ return ret;
+}
+
+static int sprd_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct sprd_rtc *rtc = dev_get_drvdata(dev);
+ int ret;
+
+ if (enabled) {
+ ret = regmap_update_bits(rtc->regmap,
+ rtc->base + SPRD_RTC_INT_EN,
+ SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN,
+ SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN);
+ if (ret)
+ return ret;
+
+ ret = sprd_rtc_lock_alarm(rtc, false);
+ } else {
+ regmap_update_bits(rtc->regmap, rtc->base + SPRD_RTC_INT_EN,
+ SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN, 0);
+
+ ret = sprd_rtc_lock_alarm(rtc, true);
+ }
+
+ return ret;
+}
+
+static const struct rtc_class_ops sprd_rtc_ops = {
+ .read_time = sprd_rtc_read_time,
+ .set_time = sprd_rtc_set_time,
+ .read_alarm = sprd_rtc_read_alarm,
+ .set_alarm = sprd_rtc_set_alarm,
+ .alarm_irq_enable = sprd_rtc_alarm_irq_enable,
+};
+
+static irqreturn_t sprd_rtc_handler(int irq, void *dev_id)
+{
+ struct sprd_rtc *rtc = dev_id;
+ int ret;
+
+ ret = sprd_rtc_clear_alarm_ints(rtc);
+ if (ret)
+ return IRQ_RETVAL(ret);
+
+ rtc_update_irq(rtc->rtc, 1, RTC_AF | RTC_IRQF);
+ return IRQ_HANDLED;
+}
+
+static int sprd_rtc_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct sprd_rtc *rtc;
+ int ret;
+
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!rtc->regmap)
+ return -ENODEV;
+
+ ret = of_property_read_u32(node, "reg", &rtc->base);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get RTC base address\n");
+ return ret;
+ }
+
+ rtc->irq = platform_get_irq(pdev, 0);
+ if (rtc->irq < 0) {
+ dev_err(&pdev->dev, "failed to get RTC irq number\n");
+ return rtc->irq;
+ }
+
+ rtc->dev = &pdev->dev;
+ platform_set_drvdata(pdev, rtc);
+
+ /* Clear all RTC interrupts and disable all RTC interrupts */
+ ret = sprd_rtc_disable_ints(rtc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to disable RTC interrupts\n");
+ return ret;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
+ sprd_rtc_handler,
+ IRQF_ONESHOT | IRQF_EARLY_RESUME,
+ pdev->name, rtc);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request RTC irq\n");
+ return ret;
+ }
+
+ rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &sprd_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtc))
+ return PTR_ERR(rtc->rtc);
+
+ device_init_wakeup(&pdev->dev, 1);
+ return 0;
+}
+
+static int sprd_rtc_remove(struct platform_device *pdev)
+{
+ device_init_wakeup(&pdev->dev, 0);
+ return 0;
+}
+
+static const struct of_device_id sprd_rtc_of_match[] = {
+ { .compatible = "sprd,sc2731-rtc", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sprd_rtc_of_match);
+
+static struct platform_driver sprd_rtc_driver = {
+ .driver = {
+ .name = "sprd-rtc",
+ .of_match_table = sprd_rtc_of_match,
+ },
+ .probe = sprd_rtc_probe,
+ .remove = sprd_rtc_remove,
+};
+module_platform_driver(sprd_rtc_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Spreadtrum RTC Device Driver");
+MODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>");
--
1.7.9.5
^ permalink raw reply related
* [PATCH] rtc: x-gene: mark PM functions as __maybe_unused
From: Arnd Bergmann @ 2017-11-08 12:08 UTC (permalink / raw)
To: Alessandro Zummo, Alexandre Belloni
Cc: Arnd Bergmann, Loc Ho, Mark Brown, linux-rtc, linux-kernel
The new xgene_rtc_alarm_irq_enabled() function is only accessed
from PM code, which is inside of an #ifdef; this causes a harmless
build warning when CONFIG_PM is disabled:
drivers/rtc/rtc-xgene.c:108:12: error: 'xgene_rtc_alarm_irq_enabled' defined but not used [-Werror=unused-function]
Just remove the #ifdef and use __maybe_unused annotations instead,
to make the code more robust here.
Fixes: 9f8f1c8b727d ("rtc: Fix suspend/resume for APM X-Gene SoC RTC driver")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
drivers/rtc/rtc-xgene.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/rtc/rtc-xgene.c b/drivers/rtc/rtc-xgene.c
index 360eae24a8c8..0c34d3b81279 100644
--- a/drivers/rtc/rtc-xgene.c
+++ b/drivers/rtc/rtc-xgene.c
@@ -221,8 +221,7 @@ static int xgene_rtc_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
-static int xgene_rtc_suspend(struct device *dev)
+static int __maybe_unused xgene_rtc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev);
@@ -246,7 +245,7 @@ static int xgene_rtc_suspend(struct device *dev)
return 0;
}
-static int xgene_rtc_resume(struct device *dev)
+static int __maybe_unused xgene_rtc_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev);
@@ -271,7 +270,6 @@ static int xgene_rtc_resume(struct device *dev)
return 0;
}
-#endif
static SIMPLE_DEV_PM_OPS(xgene_rtc_pm_ops, xgene_rtc_suspend, xgene_rtc_resume);
--
2.9.0
^ permalink raw reply related
* Re: [PATCH] rtc: x-gene: mark PM functions as __maybe_unused
From: Loc Ho @ 2017-11-08 17:26 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Alessandro Zummo, Alexandre Belloni, Mark Brown, linux-rtc,
Linux Kernel Mailing List
In-Reply-To: <20171108120815.3175571-1-arnd@arndb.de>
Hi,
> The new xgene_rtc_alarm_irq_enabled() function is only accessed
> from PM code, which is inside of an #ifdef; this causes a harmless
> build warning when CONFIG_PM is disabled:
>
> drivers/rtc/rtc-xgene.c:108:12: error: 'xgene_rtc_alarm_irq_enabled' defined but not used [-Werror=unused-function]
>
> Just remove the #ifdef and use __maybe_unused annotations instead,
> to make the code more robust here.
It sounds like desire to merge in the suspend/resume support as this
is in linux-next 14 hours ago.
Reviewed-by: Loc Ho <lho@apm.com>
-Loc
^ permalink raw reply
* [PATCH v2] rtc: rx8010: Fix for incorrect return value
From: Akshay Bhat @ 2017-11-08 19:58 UTC (permalink / raw)
To: a.zummo, alexandre.belloni; +Cc: linux-rtc, linux-kernel, Akshay Bhat
The err variable is not being reset after a successful read. Explicitly
return 0 at the end of function call to account for all return paths.
Reported-by: Jens-Peter Oswald <oswald@lre.de>
Signed-off-by: Akshay Bhat <akshay.bhat@timesys.com>
---
v2: Address comments from Alexandre Belloni
- Return 0 at end of function instead of resetting err variable
drivers/rtc/rtc-rx8010.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/rtc/rtc-rx8010.c b/drivers/rtc/rtc-rx8010.c
index 2e06e5f..5c5938a 100644
--- a/drivers/rtc/rtc-rx8010.c
+++ b/drivers/rtc/rtc-rx8010.c
@@ -247,7 +247,7 @@ static int rx8010_init_client(struct i2c_client *client)
rx8010->ctrlreg = (ctrl[1] & ~RX8010_CTRL_TEST);
- return err;
+ return 0;
}
static int rx8010_read_alarm(struct device *dev, struct rtc_wkalrm *t)
@@ -276,7 +276,7 @@ static int rx8010_read_alarm(struct device *dev, struct rtc_wkalrm *t)
t->enabled = !!(rx8010->ctrlreg & RX8010_CTRL_AIE);
t->pending = (flagreg & RX8010_FLAG_AF) && t->enabled;
- return err;
+ return 0;
}
static int rx8010_set_alarm(struct device *dev, struct rtc_wkalrm *t)
--
2.7.4
^ permalink raw reply related
* Re: [PATCH 3/3] rtc: rx8010: Fix for incorrect return value
From: Akshay Bhat @ 2017-11-08 20:00 UTC (permalink / raw)
To: Alexandre Belloni; +Cc: Alessandro Zummo, linux-rtc, linux-kernel
In-Reply-To: <20171108023000.4oepp5pyz32c7sr3@piout.net>
On Tue, Nov 7, 2017 at 9:30 PM, Alexandre Belloni
<alexandre.belloni@free-electrons.com> wrote:
> On 03/11/2017 at 13:32:41 -0400, Akshay Bhat wrote:
>> if (err != 2)
>> return err < 0 ? err : -EIO;
>> + err = 0;
>
> Isn't it simpler to make the function return 0 instead of err at the end?
Makes sense, fixed in v2 patch, thanks.
^ permalink raw reply
* Re: [PATCH] rtc: x-gene: mark PM functions as __maybe_unused
From: Alexandre Belloni @ 2017-11-09 0:17 UTC (permalink / raw)
To: Arnd Bergmann
Cc: Alessandro Zummo, Loc Ho, Mark Brown, linux-rtc, linux-kernel
In-Reply-To: <20171108120815.3175571-1-arnd@arndb.de>
On 08/11/2017 at 13:08:10 +0100, Arnd Bergmann wrote:
> The new xgene_rtc_alarm_irq_enabled() function is only accessed
> from PM code, which is inside of an #ifdef; this causes a harmless
> build warning when CONFIG_PM is disabled:
>
> drivers/rtc/rtc-xgene.c:108:12: error: 'xgene_rtc_alarm_irq_enabled' defined but not used [-Werror=unused-function]
>
> Just remove the #ifdef and use __maybe_unused annotations instead,
> to make the code more robust here.
>
> Fixes: 9f8f1c8b727d ("rtc: Fix suspend/resume for APM X-Gene SoC RTC driver")
> Signed-off-by: Arnd Bergmann <arnd@arndb.de>
> ---
> drivers/rtc/rtc-xgene.c | 6 ++----
> 1 file changed, 2 insertions(+), 4 deletions(-)
>
Applied, thanks.
--
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* Re: [PATCH v2] rtc: rx8010: Fix for incorrect return value
From: Alexandre Belloni @ 2017-11-09 0:18 UTC (permalink / raw)
To: Akshay Bhat; +Cc: a.zummo, linux-rtc, linux-kernel
In-Reply-To: <1510171094-4859-1-git-send-email-akshay.bhat@timesys.com>
On 08/11/2017 at 14:58:14 -0500, Akshay Bhat wrote:
> The err variable is not being reset after a successful read. Explicitly
> return 0 at the end of function call to account for all return paths.
>
> Reported-by: Jens-Peter Oswald <oswald@lre.de>
> Signed-off-by: Akshay Bhat <akshay.bhat@timesys.com>
> ---
> v2: Address comments from Alexandre Belloni
> - Return 0 at end of function instead of resetting err variable
>
> drivers/rtc/rtc-rx8010.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
Applied, thanks.
--
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* Re: [PATCH v2 2/2] rtc: sprd: Add Spreadtrum RTC driver
From: Alexandre Belloni @ 2017-11-09 1:26 UTC (permalink / raw)
To: Baolin Wang
Cc: a.zummo, robh+dt, mark.rutland, devicetree, linux-kernel,
linux-rtc, broonie, baolin.wang
In-Reply-To: <6482283a3ae8c6ec35d0a7a078420151a69b8aca.1510132279.git.baolin.wang@spreadtrum.com>
Hi,
On 08/11/2017 at 17:16:15 +0800, Baolin Wang wrote:
> +static int sprd_rtc_read_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct sprd_rtc *rtc = dev_get_drvdata(dev);
> + time64_t secs;
> + int ret;
> +
I would have expected a check for SPRD_RTC_POWER_RESET_FLAG here.
> + ret = sprd_rtc_get_secs(rtc, SPRD_RTC_TIME, &secs);
> + if (ret)
> + return ret;
> +
> + rtc_time64_to_tm(secs, tm);
> + return rtc_valid_tm(tm);
> +}
> +
> +static int sprd_rtc_set_time(struct device *dev, struct rtc_time *tm)
> +{
> + struct sprd_rtc *rtc = dev_get_drvdata(dev);
> + time64_t secs = rtc_tm_to_time64(tm);
> +
And you need to reset SPRD_RTC_POWER_RESET_FLAG here
> + return sprd_rtc_set_secs(rtc, SPRD_RTC_TIME, secs);
> +}
> +
--
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* Re: [PATCH v2 2/2] rtc: sprd: Add Spreadtrum RTC driver
From: Baolin Wang @ 2017-11-09 1:53 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Baolin Wang, Alessandro Zummo, Rob Herring, Mark Rutland,
devicetree, LKML, linux-rtc, Mark Brown
In-Reply-To: <20171109012653.32zkqyh5p4jqhftr@piout.net>
Hi Alexandre,
On 9 November 2017 at 09:26, Alexandre Belloni
<alexandre.belloni@free-electrons.com> wrote:
> Hi,
>
> On 08/11/2017 at 17:16:15 +0800, Baolin Wang wrote:
>> +static int sprd_rtc_read_time(struct device *dev, struct rtc_time *tm)
>> +{
>> + struct sprd_rtc *rtc = dev_get_drvdata(dev);
>> + time64_t secs;
>> + int ret;
>> +
>
> I would have expected a check for SPRD_RTC_POWER_RESET_FLAG here.
Actually I want to create one separate patch to add this feature. But
like you suggested, I can add this checking in here in next version.
Thanks for your suggestion.
>
>
>> + ret = sprd_rtc_get_secs(rtc, SPRD_RTC_TIME, &secs);
>> + if (ret)
>> + return ret;
>> +
>> + rtc_time64_to_tm(secs, tm);
>> + return rtc_valid_tm(tm);
>> +}
>> +
>> +static int sprd_rtc_set_time(struct device *dev, struct rtc_time *tm)
>> +{
>> + struct sprd_rtc *rtc = dev_get_drvdata(dev);
>> + time64_t secs = rtc_tm_to_time64(tm);
>> +
>
> And you need to reset SPRD_RTC_POWER_RESET_FLAG here
>
>> + return sprd_rtc_set_secs(rtc, SPRD_RTC_TIME, secs);
>> +}
>> +
--
Baolin.wang
Best Regards
^ permalink raw reply
* Re: DryIce , RTC not working on imx53.
From: Alexandre Belloni @ 2017-11-09 3:03 UTC (permalink / raw)
To: Patrick Brünn
Cc: Vellemans, Noel, linux-arm-kernel@lists.infradead.org,
linux-rtc@vger.kernel.org
In-Reply-To: <3BB206AB2B1BD448954845CE6FF69A8E01B8E754AA@NT-Mail07.beckhoff.com>
On 12/10/2017 at 07:50:41 +0000, Patrick Brünn wrote:
> I am seeing a lot of interrupts with kernel 4.14-rc4 (jessie and stretch), but they seem to be unhandled:
> root@CX9020:~# uname -a
> Linux CX9020 4.14.0-rc4+ #151 PREEMPT Wed Oct 11 10:40:34 CEST 2017 armv7l GNU/Linux
> root@CX9020:~# hwclock -D -r
> hwclock from util-linux 2.29.2
> Using the /dev interface to the clock.
> Last drift adjustment done at 1490885082 seconds after 1969
> Last calibration done at 1490885082 seconds after 1969
> Hardware clock is on UTC time
> Assuming hardware clock is kept in UTC time.
> Waiting for clock tick...
> [ 26.795437] irq 40: nobody cared (try booting with the "irqpoll" option)
> [ 26.802696] handlers:
> [ 26.805031] [<c06029e8>] dryice_irq
> [ 26.808584] Disabling IRQ #40
> select() to /dev/rtc to wait for clock tick timed out...synchronization failed
> root@CX9020:~# cat /proc/interrupts
> CPU0
> 17: 4276 tzic 1 Edge mmc0
> 18: 52 tzic 2 Edge mmc1
> 22: 0 tzic 6 Edge sdma
> 30: 176 tzic 14 Edge 53f80200.usb
> 40: 100000 tzic 24 Edge 53fa4000.srtc
> 48: 268 tzic 32 Edge 53fc0000.serial
> 55: 2288 tzic 39 Edge i.MX Timer Tick
> 74: 0 tzic 58 Edge 53f98000.wdog
> 79: 278 tzic 63 Edge 63fc4000.i2c
> 93: 0 tzic 77 Edge arm-pmu
> 103: 662 tzic 87 Edge 63fec000.ethernet
> 145: 0 gpio-mxc 1 Edge 50004000.esdhc cd
> 148: 0 gpio-mxc 4 Edge 50008000.esdhc cd
> 368: 674 IPU 23 Edge imx_drm
> 369: 0 IPU 28 Edge imx_drm
> Err: 0
>
> I added some tracing to dryice_irq() and saw that most of the time (if not all the time) dsr == DSR_MCO /* monotonic clock overflow */ with dier vary between 0x110, 0x10 and even 0x0.
> I don't know what's the right thing to do, to recover from DSR_MCO. " return IRQ_HANDLED" will stop the nobody cared message but hwclock still times out.
>
hwclock times out because the alarm is not working properly. Can you
check whether rtctest is working?
--
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* [PATCH v3 2/2] rtc: sprd: Add Spreadtrum RTC driver
From: Baolin Wang @ 2017-11-09 3:34 UTC (permalink / raw)
To: a.zummo, alexandre.belloni, robh+dt, mark.rutland
Cc: devicetree, linux-kernel, linux-rtc, broonie, baolin.wang,
baolin.wang
In-Reply-To: <c65b61e5e37cb43214973cb3e479ce06c4a73395.1510198341.git.baolin.wang@spreadtrum.com>
This patch adds the Spreadtrum RTC driver, which embedded in the
Spreadtrum SC27xx series PMICs.
Signed-off-by: Baolin Wang <baolin.wang@spreadtrum.com>
---
Changes since v2:
- Add checking if RTC values are valid.
Changes since v1:
- Change file name.
- Should depend on the MFD parent.
- Add more help documentation.
- Remove regmap wrapper functions.
- Modify the mothod of setting alarm.
- Remove set_mmss64() method.
- Remove checking RTC power-down.
- Optimize lock/unlock alarm.
---
drivers/rtc/Kconfig | 11 +
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-sc27xx.c | 662 ++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 674 insertions(+)
create mode 100644 drivers/rtc/rtc-sc27xx.c
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index e0e58f3..8c240e7 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -1174,6 +1174,17 @@ config RTC_DRV_WM8350
This driver can also be built as a module. If so, the module
will be called "rtc-wm8350".
+config RTC_DRV_SC27XX
+ tristate "Spreadtrum SC27xx RTC"
+ depends on MFD_SC27XX_PMIC || COMPILE_TEST
+ help
+ If you say Y here you will get support for the RTC subsystem
+ of the Spreadtrum SC27xx series PMICs. The SC27xx series PMICs
+ includes the SC2720, SC2721, SC2723, SC2730 and SC2731 chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-sc27xx.
+
config RTC_DRV_SPEAR
tristate "SPEAR ST RTC"
depends on PLAT_SPEAR || COMPILE_TEST
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 7230014..f9b857f 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -143,6 +143,7 @@ obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o
obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
+obj-$(CONFIG_RTC_DRV_SC27XX) += rtc-sc27xx.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o
obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
diff --git a/drivers/rtc/rtc-sc27xx.c b/drivers/rtc/rtc-sc27xx.c
new file mode 100644
index 0000000..d544d52
--- /dev/null
+++ b/drivers/rtc/rtc-sc27xx.c
@@ -0,0 +1,662 @@
+/*
+ * Copyright (C) 2017 Spreadtrum Communications Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+
+#define SPRD_RTC_SEC_CNT_VALUE 0x0
+#define SPRD_RTC_MIN_CNT_VALUE 0x4
+#define SPRD_RTC_HOUR_CNT_VALUE 0x8
+#define SPRD_RTC_DAY_CNT_VALUE 0xc
+#define SPRD_RTC_SEC_CNT_UPD 0x10
+#define SPRD_RTC_MIN_CNT_UPD 0x14
+#define SPRD_RTC_HOUR_CNT_UPD 0x18
+#define SPRD_RTC_DAY_CNT_UPD 0x1c
+#define SPRD_RTC_SEC_ALM_UPD 0x20
+#define SPRD_RTC_MIN_ALM_UPD 0x24
+#define SPRD_RTC_HOUR_ALM_UPD 0x28
+#define SPRD_RTC_DAY_ALM_UPD 0x2c
+#define SPRD_RTC_INT_EN 0x30
+#define SPRD_RTC_INT_RAW_STS 0x34
+#define SPRD_RTC_INT_CLR 0x38
+#define SPRD_RTC_INT_MASK_STS 0x3C
+#define SPRD_RTC_SEC_ALM_VALUE 0x40
+#define SPRD_RTC_MIN_ALM_VALUE 0x44
+#define SPRD_RTC_HOUR_ALM_VALUE 0x48
+#define SPRD_RTC_DAY_ALM_VALUE 0x4c
+#define SPRD_RTC_SPG_VALUE 0x50
+#define SPRD_RTC_SPG_UPD 0x54
+#define SPRD_RTC_SEC_AUXALM_UPD 0x60
+#define SPRD_RTC_MIN_AUXALM_UPD 0x64
+#define SPRD_RTC_HOUR_AUXALM_UPD 0x68
+#define SPRD_RTC_DAY_AUXALM_UPD 0x6c
+
+/* BIT & MASK definition for SPRD_RTC_INT_* registers */
+#define SPRD_RTC_SEC_EN BIT(0)
+#define SPRD_RTC_MIN_EN BIT(1)
+#define SPRD_RTC_HOUR_EN BIT(2)
+#define SPRD_RTC_DAY_EN BIT(3)
+#define SPRD_RTC_ALARM_EN BIT(4)
+#define SPRD_RTC_HRS_FORMAT_EN BIT(5)
+#define SPRD_RTC_AUXALM_EN BIT(6)
+#define SPRD_RTC_SPG_UPD_EN BIT(7)
+#define SPRD_RTC_SEC_UPD_EN BIT(8)
+#define SPRD_RTC_MIN_UPD_EN BIT(9)
+#define SPRD_RTC_HOUR_UPD_EN BIT(10)
+#define SPRD_RTC_DAY_UPD_EN BIT(11)
+#define SPRD_RTC_ALMSEC_UPD_EN BIT(12)
+#define SPRD_RTC_ALMMIN_UPD_EN BIT(13)
+#define SPRD_RTC_ALMHOUR_UPD_EN BIT(14)
+#define SPRD_RTC_ALMDAY_UPD_EN BIT(15)
+#define SPRD_RTC_INT_MASK GENMASK(15, 0)
+
+#define SPRD_RTC_TIME_INT_MASK \
+ (SPRD_RTC_SEC_UPD_EN | SPRD_RTC_MIN_UPD_EN | \
+ SPRD_RTC_HOUR_UPD_EN | SPRD_RTC_DAY_UPD_EN)
+
+#define SPRD_RTC_ALMTIME_INT_MASK \
+ (SPRD_RTC_ALMSEC_UPD_EN | SPRD_RTC_ALMMIN_UPD_EN | \
+ SPRD_RTC_ALMHOUR_UPD_EN | SPRD_RTC_ALMDAY_UPD_EN)
+
+#define SPRD_RTC_ALM_INT_MASK \
+ (SPRD_RTC_SEC_EN | SPRD_RTC_MIN_EN | \
+ SPRD_RTC_HOUR_EN | SPRD_RTC_DAY_EN | \
+ SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN)
+
+/* second/minute/hour/day values mask definition */
+#define SPRD_RTC_SEC_MASK GENMASK(5, 0)
+#define SPRD_RTC_MIN_MASK GENMASK(5, 0)
+#define SPRD_RTC_HOUR_MASK GENMASK(4, 0)
+#define SPRD_RTC_DAY_MASK GENMASK(15, 0)
+
+/* alarm lock definition for SPRD_RTC_SPG_UPD register */
+#define SPRD_RTC_ALMLOCK_MASK GENMASK(7, 0)
+#define SPRD_RTC_ALM_UNLOCK 0xa5
+#define SPRD_RTC_ALM_LOCK (~SPRD_RTC_ALM_UNLOCK & \
+ SPRD_RTC_ALMLOCK_MASK)
+
+/* SPG values definition for SPRD_RTC_SPG_UPD register */
+#define SPRD_RTC_POWEROFF_ALM_FLAG BIT(8)
+#define SPRD_RTC_POWER_RESET_FLAG BIT(9)
+
+/* timeout of synchronizing time and alarm registers (us) */
+#define SPRD_RTC_POLL_TIMEOUT 200000
+#define SPRD_RTC_POLL_DELAY_US 20000
+
+struct sprd_rtc {
+ struct rtc_device *rtc;
+ struct regmap *regmap;
+ struct device *dev;
+ u32 base;
+ int irq;
+ bool valid;
+};
+
+/*
+ * The Spreadtrum RTC controller has 3 groups registers, including time, normal
+ * alarm and auxiliary alarm. The time group registers are used to set RTC time,
+ * the normal alarm registers are used to set normal alarm, and the auxiliary
+ * alarm registers are used to set auxiliary alarm. Both alarm event and
+ * auxiliary alarm event can wake up system from deep sleep, but only alarm
+ * event can power up system from power down status.
+ */
+enum sprd_rtc_reg_types {
+ SPRD_RTC_TIME,
+ SPRD_RTC_ALARM,
+ SPRD_RTC_AUX_ALARM,
+};
+
+static int sprd_rtc_clear_alarm_ints(struct sprd_rtc *rtc)
+{
+ return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
+ SPRD_RTC_ALM_INT_MASK);
+}
+
+static int sprd_rtc_disable_ints(struct sprd_rtc *rtc)
+{
+ int ret;
+
+ ret = regmap_update_bits(rtc->regmap, rtc->base + SPRD_RTC_INT_EN,
+ SPRD_RTC_INT_MASK, 0);
+ if (ret)
+ return ret;
+
+ return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
+ SPRD_RTC_INT_MASK);
+}
+
+static int sprd_rtc_lock_alarm(struct sprd_rtc *rtc, bool lock)
+{
+ int ret;
+ u32 val;
+
+ ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_SPG_VALUE, &val);
+ if (ret)
+ return ret;
+
+ val &= ~(SPRD_RTC_ALMLOCK_MASK | SPRD_RTC_POWEROFF_ALM_FLAG);
+ if (lock)
+ val |= SPRD_RTC_ALM_LOCK;
+ else
+ val |= SPRD_RTC_ALM_UNLOCK | SPRD_RTC_POWEROFF_ALM_FLAG;
+
+ ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_SPG_UPD, val);
+ if (ret)
+ return ret;
+
+ /* wait until the SPG value is updated successfully */
+ ret = regmap_read_poll_timeout(rtc->regmap,
+ rtc->base + SPRD_RTC_INT_RAW_STS, val,
+ (val & SPRD_RTC_SPG_UPD_EN),
+ SPRD_RTC_POLL_DELAY_US,
+ SPRD_RTC_POLL_TIMEOUT);
+ if (ret) {
+ dev_err(rtc->dev, "failed to update SPG value:%d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sprd_rtc_get_secs(struct sprd_rtc *rtc, enum sprd_rtc_reg_types type,
+ time64_t *secs)
+{
+ u32 sec_reg, min_reg, hour_reg, day_reg;
+ u32 val, sec, min, hour, day;
+ int ret;
+
+ switch (type) {
+ case SPRD_RTC_TIME:
+ sec_reg = SPRD_RTC_SEC_CNT_VALUE;
+ min_reg = SPRD_RTC_MIN_CNT_VALUE;
+ hour_reg = SPRD_RTC_HOUR_CNT_VALUE;
+ day_reg = SPRD_RTC_DAY_CNT_VALUE;
+ break;
+ case SPRD_RTC_ALARM:
+ sec_reg = SPRD_RTC_SEC_ALM_VALUE;
+ min_reg = SPRD_RTC_MIN_ALM_VALUE;
+ hour_reg = SPRD_RTC_HOUR_ALM_VALUE;
+ day_reg = SPRD_RTC_DAY_ALM_VALUE;
+ break;
+ case SPRD_RTC_AUX_ALARM:
+ sec_reg = SPRD_RTC_SEC_AUXALM_UPD;
+ min_reg = SPRD_RTC_MIN_AUXALM_UPD;
+ hour_reg = SPRD_RTC_HOUR_AUXALM_UPD;
+ day_reg = SPRD_RTC_DAY_AUXALM_UPD;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_read(rtc->regmap, rtc->base + sec_reg, &val);
+ if (ret)
+ return ret;
+
+ sec = val & SPRD_RTC_SEC_MASK;
+
+ ret = regmap_read(rtc->regmap, rtc->base + min_reg, &val);
+ if (ret)
+ return ret;
+
+ min = val & SPRD_RTC_MIN_MASK;
+
+ ret = regmap_read(rtc->regmap, rtc->base + hour_reg, &val);
+ if (ret)
+ return ret;
+
+ hour = val & SPRD_RTC_HOUR_MASK;
+
+ ret = regmap_read(rtc->regmap, rtc->base + day_reg, &val);
+ if (ret)
+ return ret;
+
+ day = val & SPRD_RTC_DAY_MASK;
+ *secs = (((time64_t)(day * 24) + hour) * 60 + min) * 60 + sec;
+ return 0;
+}
+
+static int sprd_rtc_set_secs(struct sprd_rtc *rtc, enum sprd_rtc_reg_types type,
+ time64_t secs)
+{
+ u32 sec_reg, min_reg, hour_reg, day_reg, sts_mask;
+ u32 sec, min, hour, day, val;
+ int ret, rem;
+
+ /* convert seconds to RTC time format */
+ day = div_s64_rem(secs, 86400, &rem);
+ hour = rem / 3600;
+ rem -= hour * 3600;
+ min = rem / 60;
+ sec = rem - min * 60;
+
+ switch (type) {
+ case SPRD_RTC_TIME:
+ sec_reg = SPRD_RTC_SEC_CNT_UPD;
+ min_reg = SPRD_RTC_MIN_CNT_UPD;
+ hour_reg = SPRD_RTC_HOUR_CNT_UPD;
+ day_reg = SPRD_RTC_DAY_CNT_UPD;
+ sts_mask = SPRD_RTC_TIME_INT_MASK;
+ break;
+ case SPRD_RTC_ALARM:
+ sec_reg = SPRD_RTC_SEC_ALM_UPD;
+ min_reg = SPRD_RTC_MIN_ALM_UPD;
+ hour_reg = SPRD_RTC_HOUR_ALM_UPD;
+ day_reg = SPRD_RTC_DAY_ALM_UPD;
+ sts_mask = SPRD_RTC_ALMTIME_INT_MASK;
+ break;
+ case SPRD_RTC_AUX_ALARM:
+ sec_reg = SPRD_RTC_SEC_AUXALM_UPD;
+ min_reg = SPRD_RTC_MIN_AUXALM_UPD;
+ hour_reg = SPRD_RTC_HOUR_AUXALM_UPD;
+ day_reg = SPRD_RTC_DAY_AUXALM_UPD;
+ sts_mask = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_write(rtc->regmap, rtc->base + sec_reg, sec);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(rtc->regmap, rtc->base + min_reg, min);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(rtc->regmap, rtc->base + hour_reg, hour);
+ if (ret)
+ return ret;
+
+ ret = regmap_write(rtc->regmap, rtc->base + day_reg, day);
+ if (ret)
+ return ret;
+
+ if (type == SPRD_RTC_AUX_ALARM)
+ return 0;
+
+ /*
+ * Since the time and normal alarm registers are put in always-power-on
+ * region supplied by VDDRTC, then these registers changing time will
+ * be very long, about 125ms. Thus here we should wait until all
+ * values are updated successfully.
+ */
+ ret = regmap_read_poll_timeout(rtc->regmap,
+ rtc->base + SPRD_RTC_INT_RAW_STS, val,
+ ((val & sts_mask) == sts_mask),
+ SPRD_RTC_POLL_DELAY_US,
+ SPRD_RTC_POLL_TIMEOUT);
+ if (ret < 0) {
+ dev_err(rtc->dev, "set time/alarm values timeout\n");
+ return ret;
+ }
+
+ return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
+ sts_mask);
+}
+
+static int sprd_rtc_read_aux_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct sprd_rtc *rtc = dev_get_drvdata(dev);
+ time64_t secs;
+ u32 val;
+ int ret;
+
+ ret = sprd_rtc_get_secs(rtc, SPRD_RTC_AUX_ALARM, &secs);
+ if (ret)
+ return ret;
+
+ rtc_time64_to_tm(secs, &alrm->time);
+
+ ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_EN, &val);
+ if (ret)
+ return ret;
+
+ alrm->enabled = !!(val & SPRD_RTC_AUXALM_EN);
+
+ ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_RAW_STS, &val);
+ if (ret)
+ return ret;
+
+ alrm->pending = !!(val & SPRD_RTC_AUXALM_EN);
+ return 0;
+}
+
+static int sprd_rtc_set_aux_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct sprd_rtc *rtc = dev_get_drvdata(dev);
+ time64_t secs = rtc_tm_to_time64(&alrm->time);
+ int ret;
+
+ /* clear the auxiliary alarm interrupt status */
+ ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
+ SPRD_RTC_AUXALM_EN);
+ if (ret)
+ return ret;
+
+ ret = sprd_rtc_set_secs(rtc, SPRD_RTC_AUX_ALARM, secs);
+ if (ret)
+ return ret;
+
+ if (alrm->enabled) {
+ ret = regmap_update_bits(rtc->regmap,
+ rtc->base + SPRD_RTC_INT_EN,
+ SPRD_RTC_AUXALM_EN,
+ SPRD_RTC_AUXALM_EN);
+ } else {
+ ret = regmap_update_bits(rtc->regmap,
+ rtc->base + SPRD_RTC_INT_EN,
+ SPRD_RTC_AUXALM_EN, 0);
+ }
+
+ return ret;
+}
+
+static int sprd_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct sprd_rtc *rtc = dev_get_drvdata(dev);
+ time64_t secs;
+ int ret;
+
+ if (!rtc->valid) {
+ dev_warn(dev, "RTC values are invalid\n");
+ return -EINVAL;
+ }
+
+ ret = sprd_rtc_get_secs(rtc, SPRD_RTC_TIME, &secs);
+ if (ret)
+ return ret;
+
+ rtc_time64_to_tm(secs, tm);
+ return rtc_valid_tm(tm);
+}
+
+static int sprd_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct sprd_rtc *rtc = dev_get_drvdata(dev);
+ time64_t secs = rtc_tm_to_time64(tm);
+ u32 val;
+ int ret;
+
+ ret = sprd_rtc_set_secs(rtc, SPRD_RTC_TIME, secs);
+ if (ret)
+ return ret;
+
+ if (!rtc->valid) {
+ /*
+ * Set SPRD_RTC_POWER_RESET_FLAG to indicate now RTC has valid
+ * time values.
+ */
+ ret = regmap_update_bits(rtc->regmap,
+ rtc->base + SPRD_RTC_SPG_UPD,
+ SPRD_RTC_POWER_RESET_FLAG,
+ SPRD_RTC_POWER_RESET_FLAG);
+ if (ret)
+ return ret;
+
+ ret = regmap_read_poll_timeout(rtc->regmap,
+ rtc->base + SPRD_RTC_INT_RAW_STS,
+ val, (val & SPRD_RTC_SPG_UPD_EN),
+ SPRD_RTC_POLL_DELAY_US,
+ SPRD_RTC_POLL_TIMEOUT);
+ if (ret) {
+ dev_err(rtc->dev, "failed to update SPG value:%d\n",
+ ret);
+ return ret;
+ }
+
+ rtc->valid = true;
+ }
+
+ return 0;
+}
+
+static int sprd_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct sprd_rtc *rtc = dev_get_drvdata(dev);
+ time64_t secs;
+ int ret;
+ u32 val;
+
+ /*
+ * If aie_timer is enabled, we should get the normal alarm time.
+ * Otherwise we should get auxiliary alarm time.
+ */
+ if (rtc->rtc && rtc->rtc->aie_timer.enabled == 0)
+ return sprd_rtc_read_aux_alarm(dev, alrm);
+
+ ret = sprd_rtc_get_secs(rtc, SPRD_RTC_ALARM, &secs);
+ if (ret)
+ return ret;
+
+ rtc_time64_to_tm(secs, &alrm->time);
+
+ ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_EN, &val);
+ if (ret)
+ return ret;
+
+ alrm->enabled = !!(val & SPRD_RTC_ALARM_EN);
+
+ ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_RAW_STS, &val);
+ if (ret)
+ return ret;
+
+ alrm->pending = !!(val & SPRD_RTC_ALARM_EN);
+ return 0;
+}
+
+static int sprd_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct sprd_rtc *rtc = dev_get_drvdata(dev);
+ time64_t secs = rtc_tm_to_time64(&alrm->time);
+ struct rtc_time aie_time =
+ rtc_ktime_to_tm(rtc->rtc->aie_timer.node.expires);
+ int ret;
+
+ /*
+ * We have 2 groups alarms: normal alarm and auxiliary alarm. Since
+ * both normal alarm event and auxiliary alarm event can wake up system
+ * from deep sleep, but only alarm event can power up system from power
+ * down status. Moreover we do not need to poll about 125ms when
+ * updating auxiliary alarm registers. Thus we usually set auxiliary
+ * alarm when wake up system from deep sleep, and for other scenarios,
+ * we should set normal alarm with polling status.
+ *
+ * So here we check if the alarm time is set by aie_timer, if yes, we
+ * should set normal alarm, if not, we should set auxiliary alarm which
+ * means it is just a wake event.
+ */
+ if (!rtc->rtc->aie_timer.enabled || rtc_tm_sub(&aie_time, &alrm->time))
+ return sprd_rtc_set_aux_alarm(dev, alrm);
+
+ /* clear the alarm interrupt status firstly */
+ ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
+ SPRD_RTC_ALARM_EN);
+ if (ret)
+ return ret;
+
+ ret = sprd_rtc_set_secs(rtc, SPRD_RTC_ALARM, secs);
+ if (ret)
+ return ret;
+
+ if (alrm->enabled) {
+ ret = regmap_update_bits(rtc->regmap,
+ rtc->base + SPRD_RTC_INT_EN,
+ SPRD_RTC_ALARM_EN,
+ SPRD_RTC_ALARM_EN);
+ if (ret)
+ return ret;
+
+ /* unlock the alarm to enable the alarm function. */
+ ret = sprd_rtc_lock_alarm(rtc, false);
+ } else {
+ regmap_update_bits(rtc->regmap,
+ rtc->base + SPRD_RTC_INT_EN,
+ SPRD_RTC_ALARM_EN, 0);
+
+ /*
+ * Lock the alarm function in case fake alarm event will power
+ * up systems.
+ */
+ ret = sprd_rtc_lock_alarm(rtc, true);
+ }
+
+ return ret;
+}
+
+static int sprd_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct sprd_rtc *rtc = dev_get_drvdata(dev);
+ int ret;
+
+ if (enabled) {
+ ret = regmap_update_bits(rtc->regmap,
+ rtc->base + SPRD_RTC_INT_EN,
+ SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN,
+ SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN);
+ if (ret)
+ return ret;
+
+ ret = sprd_rtc_lock_alarm(rtc, false);
+ } else {
+ regmap_update_bits(rtc->regmap, rtc->base + SPRD_RTC_INT_EN,
+ SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN, 0);
+
+ ret = sprd_rtc_lock_alarm(rtc, true);
+ }
+
+ return ret;
+}
+
+static const struct rtc_class_ops sprd_rtc_ops = {
+ .read_time = sprd_rtc_read_time,
+ .set_time = sprd_rtc_set_time,
+ .read_alarm = sprd_rtc_read_alarm,
+ .set_alarm = sprd_rtc_set_alarm,
+ .alarm_irq_enable = sprd_rtc_alarm_irq_enable,
+};
+
+static irqreturn_t sprd_rtc_handler(int irq, void *dev_id)
+{
+ struct sprd_rtc *rtc = dev_id;
+ int ret;
+
+ ret = sprd_rtc_clear_alarm_ints(rtc);
+ if (ret)
+ return IRQ_RETVAL(ret);
+
+ rtc_update_irq(rtc->rtc, 1, RTC_AF | RTC_IRQF);
+ return IRQ_HANDLED;
+}
+
+static int sprd_rtc_check_power_down(struct sprd_rtc *rtc)
+{
+ u32 val;
+ int ret;
+
+ ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_SPG_VALUE, &val);
+ if (ret)
+ return ret;
+
+ /*
+ * If the SPRD_RTC_POWER_RESET_FLAG was not set, which means the RTC has
+ * been powered down, so the RTC time values are invalid.
+ */
+ rtc->valid = (val & SPRD_RTC_POWER_RESET_FLAG) ? true : false;
+ return 0;
+}
+
+static int sprd_rtc_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct sprd_rtc *rtc;
+ int ret;
+
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+ if (!rtc->regmap)
+ return -ENODEV;
+
+ ret = of_property_read_u32(node, "reg", &rtc->base);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get RTC base address\n");
+ return ret;
+ }
+
+ rtc->irq = platform_get_irq(pdev, 0);
+ if (rtc->irq < 0) {
+ dev_err(&pdev->dev, "failed to get RTC irq number\n");
+ return rtc->irq;
+ }
+
+ rtc->dev = &pdev->dev;
+ platform_set_drvdata(pdev, rtc);
+
+ /* clear all RTC interrupts and disable all RTC interrupts */
+ ret = sprd_rtc_disable_ints(rtc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to disable RTC interrupts\n");
+ return ret;
+ }
+
+ /* check if RTC time values are valid */
+ ret = sprd_rtc_check_power_down(rtc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to check RTC time values\n");
+ return ret;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
+ sprd_rtc_handler,
+ IRQF_ONESHOT | IRQF_EARLY_RESUME,
+ pdev->name, rtc);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to request RTC irq\n");
+ return ret;
+ }
+
+ rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &sprd_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtc))
+ return PTR_ERR(rtc->rtc);
+
+ device_init_wakeup(&pdev->dev, 1);
+ return 0;
+}
+
+static int sprd_rtc_remove(struct platform_device *pdev)
+{
+ device_init_wakeup(&pdev->dev, 0);
+ return 0;
+}
+
+static const struct of_device_id sprd_rtc_of_match[] = {
+ { .compatible = "sprd,sc2731-rtc", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, sprd_rtc_of_match);
+
+static struct platform_driver sprd_rtc_driver = {
+ .driver = {
+ .name = "sprd-rtc",
+ .of_match_table = sprd_rtc_of_match,
+ },
+ .probe = sprd_rtc_probe,
+ .remove = sprd_rtc_remove,
+};
+module_platform_driver(sprd_rtc_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Spreadtrum RTC Device Driver");
+MODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>");
--
1.7.9.5
^ permalink raw reply related
* [PATCH v3 1/2] dt-bindings: rtc: Add Spreadtrum SC27xx RTC documentation
From: Baolin Wang @ 2017-11-09 3:34 UTC (permalink / raw)
To: a.zummo, alexandre.belloni, robh+dt, mark.rutland
Cc: devicetree, linux-kernel, linux-rtc, broonie, baolin.wang,
baolin.wang
This patch adds the binding documentation for Spreadtrum SC27xx series
RTC device.
Signed-off-by: Baolin Wang <baolin.wang@spreadtrum.com>
---
Changes since v2:
- No updates.
Changes since v1:
- Use a specific chip name as compatible string.
- Remove useless alias.
- Add the parent MFD node.
---
.../devicetree/bindings/rtc/sprd,sc27xx-rtc.txt | 27 ++++++++++++++++++++
1 file changed, 27 insertions(+)
create mode 100644 Documentation/devicetree/bindings/rtc/sprd,sc27xx-rtc.txt
diff --git a/Documentation/devicetree/bindings/rtc/sprd,sc27xx-rtc.txt b/Documentation/devicetree/bindings/rtc/sprd,sc27xx-rtc.txt
new file mode 100644
index 0000000..7c170da
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/sprd,sc27xx-rtc.txt
@@ -0,0 +1,27 @@
+Spreadtrum SC27xx Real Time Clock
+
+Required properties:
+- compatible: should be "sprd,sc2731-rtc".
+- reg: address offset of rtc register.
+- interrupt-parent: phandle for the interrupt controller.
+- interrupts: rtc alarm interrupt.
+
+Example:
+
+ sc2731_pmic: pmic@0 {
+ compatible = "sprd,sc2731";
+ reg = <0>;
+ spi-max-frequency = <26000000>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ rtc@280 {
+ compatible = "sprd,sc2731-rtc";
+ reg = <0x280>;
+ interrupt-parent = <&sc2731_pmic>;
+ interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
--
1.7.9.5
^ permalink raw reply related
* [PATCH] rtc: Use time64_t variables to set time/alarm from sysfs
From: Baolin Wang @ 2017-11-09 7:09 UTC (permalink / raw)
To: a.zummo, alexandre.belloni
Cc: linux-rtc, linux-kernel, arnd, broonie, baolin.wang
Use time64_t variables and related APIs for sysfs interfaces to
support setting time or alarm after the year 2038 on 32-bit system.
Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
---
drivers/rtc/rtc-sysfs.c | 25 +++++++++++++------------
1 file changed, 13 insertions(+), 12 deletions(-)
diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c
index e364550..92ff2ed 100644
--- a/drivers/rtc/rtc-sysfs.c
+++ b/drivers/rtc/rtc-sysfs.c
@@ -72,9 +72,10 @@
retval = rtc_read_time(to_rtc_device(dev), &tm);
if (retval == 0) {
- unsigned long time;
- rtc_tm_to_time(&tm, &time);
- retval = sprintf(buf, "%lu\n", time);
+ time64_t time;
+
+ time = rtc_tm_to_time64(&tm);
+ retval = sprintf(buf, "%lld\n", time);
}
return retval;
@@ -132,7 +133,7 @@
wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf)
{
ssize_t retval;
- unsigned long alarm;
+ time64_t alarm;
struct rtc_wkalrm alm;
/* Don't show disabled alarms. For uniformity, RTC alarms are
@@ -145,8 +146,8 @@
*/
retval = rtc_read_alarm(to_rtc_device(dev), &alm);
if (retval == 0 && alm.enabled) {
- rtc_tm_to_time(&alm.time, &alarm);
- retval = sprintf(buf, "%lu\n", alarm);
+ alarm = rtc_tm_to_time64(&alm.time);
+ retval = sprintf(buf, "%lld\n", alarm);
}
return retval;
@@ -157,8 +158,8 @@
const char *buf, size_t n)
{
ssize_t retval;
- unsigned long now, alarm;
- unsigned long push = 0;
+ time64_t now, alarm;
+ time64_t push = 0;
struct rtc_wkalrm alm;
struct rtc_device *rtc = to_rtc_device(dev);
const char *buf_ptr;
@@ -170,7 +171,7 @@
retval = rtc_read_time(rtc, &alm.time);
if (retval < 0)
return retval;
- rtc_tm_to_time(&alm.time, &now);
+ now = rtc_tm_to_time64(&alm.time);
buf_ptr = buf;
if (*buf_ptr == '+') {
@@ -181,7 +182,7 @@
} else
adjust = 1;
}
- retval = kstrtoul(buf_ptr, 0, &alarm);
+ retval = kstrtos64(buf_ptr, 0, &alarm);
if (retval)
return retval;
if (adjust) {
@@ -197,7 +198,7 @@
return retval;
if (alm.enabled) {
if (push) {
- rtc_tm_to_time(&alm.time, &push);
+ push = rtc_tm_to_time64(&alm.time);
alarm += push;
} else
return -EBUSY;
@@ -212,7 +213,7 @@
*/
alarm = now + 300;
}
- rtc_time_to_tm(alarm, &alm.time);
+ rtc_time64_to_tm(alarm, &alm.time);
retval = rtc_set_alarm(rtc, &alm);
return (retval < 0) ? retval : n;
--
1.7.9.5
^ permalink raw reply related
* RE: DryIce , RTC not working on imx53.
From: Patrick Brünn @ 2017-11-09 9:59 UTC (permalink / raw)
To: Alexandre Belloni
Cc: Vellemans, Noel, linux-arm-kernel@lists.infradead.org,
linux-rtc@vger.kernel.org
In-Reply-To: <20171109030327.anzo47xayxckn47r@piout.net>
>From: Alexandre Belloni [mailto:alexandre.belloni@free-electrons.com]
>Sent: Donnerstag, 9. November 2017 04:03
>
>hwclock times out because the alarm is not working properly. Can you
>check whether rtctest is working?
>
You mean "tools/testing/selftests/timers/rtctest", right?
I just run it and it's stuck at "Counting 5 update (1/sec) interrupts from reading /dev/rtc0:"
Kernel log shows a new message for each try I restart rtctest.
[ 1032.349562] imxdi_rtc 53fa4000.srtc: Write-wait timeout val = 0x5a042418 reg = 0x00000008"
Regards, Patrick
Beckhoff Automation GmbH & Co. KG | Managing Director: Dipl. Phys. Hans Beckhoff
Registered office: Verl, Germany | Register court: Guetersloh HRA 7075
^ permalink raw reply
* Re: [PATCH] rtc: Use time64_t variables to set time/alarm from sysfs
From: Arnd Bergmann @ 2017-11-09 10:38 UTC (permalink / raw)
To: Baolin Wang
Cc: Alessandro Zummo, Alexandre Belloni, linux-rtc,
Linux Kernel Mailing List, Mark Brown
In-Reply-To: <672d468478f3f67ef22e027460c59918dc581818.1510211132.git.baolin.wang@linaro.org>
On Thu, Nov 9, 2017 at 8:09 AM, Baolin Wang <baolin.wang@linaro.org> wrote:
> Use time64_t variables and related APIs for sysfs interfaces to
> support setting time or alarm after the year 2038 on 32-bit system.
>
> Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
Looks good,
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
^ permalink raw reply
* Re: [PATCH] rtc: Use time64_t variables to set time/alarm from sysfs
From: Alexandre Belloni @ 2017-11-10 8:58 UTC (permalink / raw)
To: Baolin Wang; +Cc: a.zummo, linux-rtc, linux-kernel, arnd, broonie
In-Reply-To: <672d468478f3f67ef22e027460c59918dc581818.1510211132.git.baolin.wang@linaro.org>
On 09/11/2017 at 15:09:20 +0800, Baolin Wang wrote:
> Use time64_t variables and related APIs for sysfs interfaces to
> support setting time or alarm after the year 2038 on 32-bit system.
>
> Signed-off-by: Baolin Wang <baolin.wang@linaro.org>
> ---
> drivers/rtc/rtc-sysfs.c | 25 +++++++++++++------------
> 1 file changed, 13 insertions(+), 12 deletions(-)
>
Applied, thanks.
--
Alexandre Belloni, Free Electrons
Embedded Linux and Kernel engineering
http://free-electrons.com
^ permalink raw reply
* [PATCH 1/2] rtc: at91rm9200: stop calculating yday in at91_rtc_readalarm
From: Alexandre Belloni @ 2017-11-10 8:59 UTC (permalink / raw)
To: linux-rtc
Cc: Nicolas Ferre, linux-arm-kernel, linux-kernel, Alexandre Belloni
Calculating yday in the read_alarm callback is useless as this value is
never used later. Also, it was buggy anyway because at the time this is
done, tm_year is always 0 as the alarm register doesn't hold the year.
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
drivers/rtc/rtc-at91rm9200.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index e221b78b6f10..e84f5ec4faf6 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -208,7 +208,6 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
struct rtc_time *tm = &alrm->time;
at91_rtc_decodetime(AT91_RTC_TIMALR, AT91_RTC_CALALR, tm);
- tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
tm->tm_year = at91_alarm_year - 1900;
alrm->enabled = (at91_rtc_read_imr() & AT91_RTC_ALARM)
--
2.15.0
^ permalink raw reply related
* [PATCH 2/2] rtc: at91rm9200: fix reading alarm value
From: Alexandre Belloni @ 2017-11-10 8:59 UTC (permalink / raw)
To: linux-rtc
Cc: Nicolas Ferre, linux-arm-kernel, linux-kernel, Alexandre Belloni
In-Reply-To: <20171110085931.32347-1-alexandre.belloni@free-electrons.com>
When alarm value is read at boot time, at91_alarm_year is not yet set to
the proper value so the year is always set to 1900.
This results in that kind of message at boot:
rtc rtc0: invalid alarm value: 1900-1-14 2:11:39
There is no way to recover from that as the alarm is now only read when
booting.
Instead, rely on the rtc core to figure out the proper year.
Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
---
drivers/rtc/rtc-at91rm9200.c | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index e84f5ec4faf6..de81ecedd571 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -42,8 +42,6 @@
#define at91_rtc_write(field, val) \
writel_relaxed((val), at91_rtc_regs + field)
-#define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */
-
struct at91_rtc_config {
bool use_shadow_imr;
};
@@ -51,7 +49,6 @@ struct at91_rtc_config {
static const struct at91_rtc_config *at91_rtc_config;
static DECLARE_COMPLETION(at91_rtc_updated);
static DECLARE_COMPLETION(at91_rtc_upd_rdy);
-static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
static void __iomem *at91_rtc_regs;
static int irq;
static DEFINE_SPINLOCK(at91_rtc_lock);
@@ -131,8 +128,7 @@ static void at91_rtc_decodetime(unsigned int timereg, unsigned int calreg,
/*
* The Calendar Alarm register does not have a field for
- * the year - so these will return an invalid value. When an
- * alarm is set, at91_alarm_year will store the current year.
+ * the year - so these will return an invalid value.
*/
tm->tm_year = bcd2bin(date & AT91_RTC_CENT) * 100; /* century */
tm->tm_year += bcd2bin((date & AT91_RTC_YEAR) >> 8); /* year */
@@ -208,14 +204,14 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
struct rtc_time *tm = &alrm->time;
at91_rtc_decodetime(AT91_RTC_TIMALR, AT91_RTC_CALALR, tm);
- tm->tm_year = at91_alarm_year - 1900;
+ tm->tm_year = -1;
alrm->enabled = (at91_rtc_read_imr() & AT91_RTC_ALARM)
? 1 : 0;
- dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
- 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
- tm->tm_hour, tm->tm_min, tm->tm_sec);
+ dev_dbg(dev, "%s(): %02d-%02d %02d:%02d:%02d %sabled\n", __func__,
+ tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
+ alrm->enabled ? "en" : "dis");
return 0;
}
@@ -229,8 +225,6 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, &tm);
- at91_alarm_year = tm.tm_year;
-
tm.tm_mon = alrm->time.tm_mon;
tm.tm_mday = alrm->time.tm_mday;
tm.tm_hour = alrm->time.tm_hour;
@@ -254,7 +248,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
}
dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
- at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
+ tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
tm.tm_min, tm.tm_sec);
return 0;
--
2.15.0
^ permalink raw reply related
* Re: [PATCH 1/2] rtc: at91rm9200: stop calculating yday in at91_rtc_readalarm
From: Nicolas Ferre @ 2017-11-10 13:41 UTC (permalink / raw)
To: Alexandre Belloni, linux-rtc; +Cc: linux-arm-kernel, linux-kernel
In-Reply-To: <20171110085931.32347-1-alexandre.belloni@free-electrons.com>
On 10/11/2017 at 09:59, Alexandre Belloni wrote:
> Calculating yday in the read_alarm callback is useless as this value is
> never used later. Also, it was buggy anyway because at the time this is
> done, tm_year is always 0 as the alarm register doesn't hold the year.
>
> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
> ---
> drivers/rtc/rtc-at91rm9200.c | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
> index e221b78b6f10..e84f5ec4faf6 100644
> --- a/drivers/rtc/rtc-at91rm9200.c
> +++ b/drivers/rtc/rtc-at91rm9200.c
> @@ -208,7 +208,6 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
> struct rtc_time *tm = &alrm->time;
>
> at91_rtc_decodetime(AT91_RTC_TIMALR, AT91_RTC_CALALR, tm);
> - tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
> tm->tm_year = at91_alarm_year - 1900;
>
> alrm->enabled = (at91_rtc_read_imr() & AT91_RTC_ALARM)
>
--
Nicolas Ferre
^ permalink raw reply
* Re: [PATCH 2/2] rtc: at91rm9200: fix reading alarm value
From: Nicolas Ferre @ 2017-11-10 14:55 UTC (permalink / raw)
To: Alexandre Belloni, linux-rtc; +Cc: linux-arm-kernel, linux-kernel
In-Reply-To: <20171110085931.32347-2-alexandre.belloni@free-electrons.com>
On 10/11/2017 at 09:59, Alexandre Belloni wrote:
> When alarm value is read at boot time, at91_alarm_year is not yet set to
> the proper value so the year is always set to 1900.
>
> This results in that kind of message at boot:
> rtc rtc0: invalid alarm value: 1900-1-14 2:11:39
>
> There is no way to recover from that as the alarm is now only read when
> booting.
>
> Instead, rely on the rtc core to figure out the proper year.
>
> Signed-off-by: Alexandre Belloni <alexandre.belloni@free-electrons.com>
Acked-by: Nicolas Ferre <nicolas.ferre@microchip.com>
> ---
> drivers/rtc/rtc-at91rm9200.c | 18 ++++++------------
> 1 file changed, 6 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
> index e84f5ec4faf6..de81ecedd571 100644
> --- a/drivers/rtc/rtc-at91rm9200.c
> +++ b/drivers/rtc/rtc-at91rm9200.c
> @@ -42,8 +42,6 @@
> #define at91_rtc_write(field, val) \
> writel_relaxed((val), at91_rtc_regs + field)
>
> -#define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */
> -
> struct at91_rtc_config {
> bool use_shadow_imr;
> };
> @@ -51,7 +49,6 @@ struct at91_rtc_config {
> static const struct at91_rtc_config *at91_rtc_config;
> static DECLARE_COMPLETION(at91_rtc_updated);
> static DECLARE_COMPLETION(at91_rtc_upd_rdy);
> -static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
> static void __iomem *at91_rtc_regs;
> static int irq;
> static DEFINE_SPINLOCK(at91_rtc_lock);
> @@ -131,8 +128,7 @@ static void at91_rtc_decodetime(unsigned int timereg, unsigned int calreg,
>
> /*
> * The Calendar Alarm register does not have a field for
> - * the year - so these will return an invalid value. When an
> - * alarm is set, at91_alarm_year will store the current year.
> + * the year - so these will return an invalid value.
> */
> tm->tm_year = bcd2bin(date & AT91_RTC_CENT) * 100; /* century */
> tm->tm_year += bcd2bin((date & AT91_RTC_YEAR) >> 8); /* year */
> @@ -208,14 +204,14 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
> struct rtc_time *tm = &alrm->time;
>
> at91_rtc_decodetime(AT91_RTC_TIMALR, AT91_RTC_CALALR, tm);
> - tm->tm_year = at91_alarm_year - 1900;
> + tm->tm_year = -1;
>
> alrm->enabled = (at91_rtc_read_imr() & AT91_RTC_ALARM)
> ? 1 : 0;
>
> - dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
> - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
> - tm->tm_hour, tm->tm_min, tm->tm_sec);
> + dev_dbg(dev, "%s(): %02d-%02d %02d:%02d:%02d %sabled\n", __func__,
> + tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
> + alrm->enabled ? "en" : "dis");
>
> return 0;
> }
> @@ -229,8 +225,6 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
>
> at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, &tm);
>
> - at91_alarm_year = tm.tm_year;
> -
> tm.tm_mon = alrm->time.tm_mon;
> tm.tm_mday = alrm->time.tm_mday;
> tm.tm_hour = alrm->time.tm_hour;
> @@ -254,7 +248,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
> }
>
> dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
> - at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
> + tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
> tm.tm_min, tm.tm_sec);
>
> return 0;
>
--
Nicolas Ferre
^ permalink raw reply
* [rtc-linux] [PATCH v4 0/2] Add support for cros-ec-rtc driver.
From: Enric Balletbo i Serra @ 2017-11-10 21:55 UTC (permalink / raw)
To: Lee Jones, bleung
Cc: Guenter Roeck, Gwendal Grignou, linux-kernel, linux-iio,
rtc-linux
Dear all,
This is an attempt to revive some patches from that [1] patchset, some
of them are still under discussion but I think there is no reason to not
have the other two in this fourth version to land upstream meanwhile we
discuss about the others.
[1] https://lkml.org/lkml/2017/7/12/182
Changes since v3:
* Rebased an retested with current mainline using a Samsung Chromebook Plus
* Removed from patchset
* 1/4 mfd: cros_ec: Get rid of cros_ec_check_features from cros_ec_dev.
* 4/4 mfd: cros_ec: add RTC as mfd subdevice.
Changes since v2:
- Rebase on top of mainline.
- Removed patch 'mfd: cros-ec: Fix host command buffer size' from series
as was already picked.
Changes since v1:
- Removed patch 'iio: cros_ec_sensors: Fix return value to get raw and
calibbias data' from series as was already picked.
- Removed patch 'iio: cros_ec_sensors: Fix return value to get raw and
calibbias data' from series as was already picked.
- Patch 2/5: Acked-by: Jonathan Cameron <***@kernel.org>
Best regards,
Enric
Stephen Barber (2):
mfd: cros_ec: Introduce RTC commands and events definitions.
rtc: cros-ec: add cros-ec-rtc driver.
drivers/rtc/Kconfig | 10 +
drivers/rtc/Makefile | 1 +
drivers/rtc/rtc-cros-ec.c | 413 +++++++++++++++++++++++++++++++++++
include/linux/mfd/cros_ec_commands.h | 8 +
4 files changed, 432 insertions(+)
create mode 100644 drivers/rtc/rtc-cros-ec.c
--
2.9.3
--
You received this message because you are subscribed to "rtc-linux".
Membership options at http://groups.google.com/group/rtc-linux .
Please read http://groups.google.com/group/rtc-linux/web/checklist
before submitting a driver.
---
You received this message because you are subscribed to the Google Groups "rtc-linux" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rtc-linux+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox