Merge tag 'rtc-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 6 Nov 2023 02:49:40 +0000 (18:49 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 6 Nov 2023 02:49:40 +0000 (18:49 -0800)
Pull RTC updates from Alexandre Belloni:
 "There is a new driver for the RTC of the Mstar SSD202D SoC. The
  rtc7301 driver gains support for byte addresses to support the
  USRobotics USR8200. Then we have many non user visible changes and
  typo fixes.

  Summary:

  Subsytem:
   - convert platform drivers to remove_new
   - prevent modpost warnings for unremovable platform drivers

  New driver:
   - Mstar SSD202D

  Drivers:
   - brcmstb-waketimer: support level alarm_irq
   - ep93xx: add DT support
   - rtc7301: support byte-addressed IO"

* tag 'rtc-6.7' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (28 commits)
  dt-bindings: rtc: Add Mstar SSD202D RTC
  rtc: Add support for the SSD202D RTC
  rtc: at91rm9200: annotate at91_rtc_remove with __exit again
  dt-bindings: rtc: microcrystal,rv3032: Document wakeup-source property
  dt-bindings: rtc: pcf8523: Convert to YAML
  dt-bindings: rtc: mcp795: move to trivial-rtc
  rtc: ep93xx: add DT support for Cirrus EP93xx
  dt-bindings: rtc: Add Cirrus EP93xx
  dt-bindings: rtc: pcf2123: convert to YAML
  rtc: efi: fixed typo in efi_procfs()
  rtc: omap: Use device_get_match_data()
  rtc: pcf85363: fix wrong mask/val parameters in regmap_update_bits call
  rtc: rtc7301: Support byte-addressed IO
  rtc: rtc7301: Rewrite bindings in schema
  rtc: sh: Convert to platform remove callback returning void
  rtc: pxa: Convert to platform remove callback returning void
  rtc: mv: Convert to platform remove callback returning void
  rtc: imxdi: Convert to platform remove callback returning void
  rtc: at91rm9200: Convert to platform remove callback returning void
  rtc: pcap: Drop no-op remove function
  ...

26 files changed:
Documentation/devicetree/bindings/rtc/cirrus,ep9301-rtc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/epson,rtc7301.txt [deleted file]
Documentation/devicetree/bindings/rtc/epson,rtc7301.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/maxim,mcp795.txt [deleted file]
Documentation/devicetree/bindings/rtc/microcrystal,rv3032.yaml
Documentation/devicetree/bindings/rtc/mstar,ssd202d-rtc.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/nxp,pcf2123.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/nxp,pcf8523.txt [deleted file]
Documentation/devicetree/bindings/rtc/nxp,pcf8523.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/nxp,rtc-2123.txt [deleted file]
Documentation/devicetree/bindings/rtc/trivial-rtc.yaml
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-brcmstb-waketimer.c
drivers/rtc/rtc-efi.c
drivers/rtc/rtc-ep93xx.c
drivers/rtc/rtc-imxdi.c
drivers/rtc/rtc-mv.c
drivers/rtc/rtc-omap.c
drivers/rtc/rtc-pcap.c
drivers/rtc/rtc-pcf85363.c
drivers/rtc/rtc-pxa.c
drivers/rtc/rtc-r7301.c
drivers/rtc/rtc-sh.c
drivers/rtc/rtc-ssd202d.c [new file with mode: 0644]

diff --git a/Documentation/devicetree/bindings/rtc/cirrus,ep9301-rtc.yaml b/Documentation/devicetree/bindings/rtc/cirrus,ep9301-rtc.yaml
new file mode 100644 (file)
index 0000000..a95f6af
--- /dev/null
@@ -0,0 +1,42 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/cirrus,ep9301-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Cirrus EP93xx Real Time Clock controller
+
+maintainers:
+  - Hartley Sweeten <hsweeten@visionengravers.com>
+  - Alexander Sverdlin <alexander.sverdlin@gmail.com>
+
+allOf:
+  - $ref: rtc.yaml#
+
+properties:
+  compatible:
+    oneOf:
+      - const: cirrus,ep9301-rtc
+      - items:
+          - enum:
+              - cirrus,ep9302-rtc
+              - cirrus,ep9307-rtc
+              - cirrus,ep9312-rtc
+              - cirrus,ep9315-rtc
+          - const: cirrus,ep9301-rtc
+
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    rtc@80920000 {
+        compatible = "cirrus,ep9301-rtc";
+        reg = <0x80920000 0x100>;
+    };
diff --git a/Documentation/devicetree/bindings/rtc/epson,rtc7301.txt b/Documentation/devicetree/bindings/rtc/epson,rtc7301.txt
deleted file mode 100644 (file)
index 5f9df3f..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-EPSON TOYOCOM RTC-7301SF/DG
-
-Required properties:
-
-- compatible: Should be "epson,rtc7301sf" or "epson,rtc7301dg"
-- reg: Specifies base physical address and size of the registers.
-- interrupts: A single interrupt specifier.
-
-Example:
-
-rtc: rtc@44a00000 {
-       compatible = "epson,rtc7301dg";
-       reg = <0x44a00000 0x10000>;
-       interrupt-parent = <&axi_intc_0>;
-       interrupts = <3 2>;
-};
diff --git a/Documentation/devicetree/bindings/rtc/epson,rtc7301.yaml b/Documentation/devicetree/bindings/rtc/epson,rtc7301.yaml
new file mode 100644 (file)
index 0000000..bdb5cad
--- /dev/null
@@ -0,0 +1,51 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/epson,rtc7301.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Epson Toyocom RTC-7301SF/DG
+
+description:
+  The only difference between the two variants is the packaging.
+  The DG variant is a DIL package, and the SF variant is a flat
+  package.
+
+maintainers:
+  - Akinobu Mita <akinobu.mita@gmail.com>
+
+properties:
+  compatible:
+    enum:
+      - epson,rtc7301dg
+      - epson,rtc7301sf
+
+  reg:
+    maxItems: 1
+
+  reg-io-width:
+    description:
+      The size (in bytes) of the IO accesses that should be performed
+      on the device.
+    enum: [1, 4]
+    default: 4
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/irq.h>
+    rtc: rtc@44a00000 {
+        compatible = "epson,rtc7301dg";
+        reg = <0x44a00000 0x10000>;
+        reg-io-width = <4>;
+        interrupt-parent = <&axi_intc_0>;
+        interrupts = <3 2>;
+    };
diff --git a/Documentation/devicetree/bindings/rtc/maxim,mcp795.txt b/Documentation/devicetree/bindings/rtc/maxim,mcp795.txt
deleted file mode 100644 (file)
index a59fdd8..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-* Maxim MCP795         SPI Serial Real-Time Clock
-
-Required properties:
-- compatible: Should contain "maxim,mcp795".
-- reg: SPI address for chip
-
-Example:
-       mcp795: rtc@0 {
-               compatible = "maxim,mcp795";
-               reg = <0>;
-       };
index 27a9de1..7680089 100644 (file)
@@ -38,6 +38,8 @@ properties:
       - 3000
       - 4400
 
+  wakeup-source: true
+
 required:
   - compatible
   - reg
diff --git a/Documentation/devicetree/bindings/rtc/mstar,ssd202d-rtc.yaml b/Documentation/devicetree/bindings/rtc/mstar,ssd202d-rtc.yaml
new file mode 100644 (file)
index 0000000..4c1f22e
--- /dev/null
@@ -0,0 +1,35 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/mstar,ssd202d-rtc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Mstar SSD202D Real Time Clock
+
+maintainers:
+  - Daniel Palmer <daniel@0x0f.com>
+  - Romain Perier <romain.perier@gmail.com>
+
+allOf:
+  - $ref: rtc.yaml#
+
+properties:
+  compatible:
+    enum:
+      - mstar,ssd202d-rtc
+  reg:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    rtc@6800 {
+        compatible = "mstar,ssd202d-rtc";
+        reg = <0x6800 0x200>;
+    };
+...
diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf2123.yaml b/Documentation/devicetree/bindings/rtc/nxp,pcf2123.yaml
new file mode 100644 (file)
index 0000000..96e377a
--- /dev/null
@@ -0,0 +1,47 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/nxp,pcf2123.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP PCF2123 SPI Real Time Clock
+
+maintainers:
+  - Javier Carrasco <javier.carrasco.cruz@gmail.com>
+
+allOf:
+  - $ref: /schemas/spi/spi-peripheral-props.yaml#
+  - $ref: rtc.yaml#
+
+properties:
+  compatible:
+    enum:
+      - nxp,pcf2123
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    spi {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        rtc@3 {
+            compatible = "nxp,pcf2123";
+            reg = <3>;
+            interrupts = <GIC_SPI 130 IRQ_TYPE_LEVEL_LOW>;
+            spi-cs-high;
+        };
+    };
+...
diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf8523.txt b/Documentation/devicetree/bindings/rtc/nxp,pcf8523.txt
deleted file mode 100644 (file)
index 0b1080c..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-* NXP PCF8523 Real Time Clock
-
-Required properties:
-- compatible: Should contain "nxp,pcf8523".
-- reg: I2C address for chip.
-
-Optional property:
-- quartz-load-femtofarads: The capacitive load of the quartz(x-tal),
-  expressed in femto Farad (fF). Valid values are 7000 and 12500.
-  Default value (if no value is specified) is 12500fF.
-
-Example:
-
-pcf8523: rtc@68 {
-       compatible = "nxp,pcf8523";
-       reg = <0x68>;
-       quartz-load-femtofarads = <7000>;
-};
diff --git a/Documentation/devicetree/bindings/rtc/nxp,pcf8523.yaml b/Documentation/devicetree/bindings/rtc/nxp,pcf8523.yaml
new file mode 100644 (file)
index 0000000..d11c8bc
--- /dev/null
@@ -0,0 +1,45 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/rtc/nxp,pcf8523.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NXP PCF8523 Real Time Clock
+
+maintainers:
+  - Sam Ravnborg <sam@ravnborg.org>
+
+allOf:
+  - $ref: rtc.yaml#
+
+properties:
+  compatible:
+    const: nxp,pcf8523
+
+  reg:
+    maxItems: 1
+
+  quartz-load-femtofarads:
+    description:
+      The capacitive load of the crystal, expressed in femto Farad (fF).
+    enum: [ 7000, 12500 ]
+    default: 12500
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        rtc@68 {
+            compatible = "nxp,pcf8523";
+            reg = <0x68>;
+            quartz-load-femtofarads = <7000>;
+        };
+    };
diff --git a/Documentation/devicetree/bindings/rtc/nxp,rtc-2123.txt b/Documentation/devicetree/bindings/rtc/nxp,rtc-2123.txt
deleted file mode 100644 (file)
index 7371f52..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-NXP PCF2123 SPI Real Time Clock
-
-Required properties:
-- compatible: should be: "nxp,pcf2123"
-                      or "microcrystal,rv2123"
-- reg: should be the SPI slave chipselect address
-
-Optional properties:
-- spi-cs-high: PCF2123 needs chipselect high
-
-Example:
-
-pcf2123: rtc@3 {
-       compatible = "nxp,pcf2123"
-       reg = <3>
-       spi-cs-high;
-};
index 2a65f31..c9e3c52 100644 (file)
@@ -45,6 +45,8 @@ properties:
       - isil,isl1208
       # Intersil ISL1218 Low Power RTC with Battery Backed SRAM
       - isil,isl1218
+      # SPI-BUS INTERFACE REAL TIME CLOCK MODULE
+      - maxim,mcp795
       # Real Time Clock Module with I2C-Bus
       - microcrystal,rv3029
       # Real Time Clock
index d750243..3814e08 100644 (file)
@@ -1351,7 +1351,7 @@ config RTC_DRV_DIGICOLOR
 
 config RTC_DRV_IMXDI
        tristate "Freescale IMX DryIce Real Time Clock"
-       depends on ARCH_MXC
+       depends on ARCH_MXC || COMPILE_TEST
        depends on OF
        help
           Support for Freescale IMX DryIce RTC
@@ -1984,4 +1984,15 @@ config RTC_DRV_POLARFIRE_SOC
          This driver can also be built as a module, if so, the module
          will be called "rtc-mpfs".
 
+config RTC_DRV_SSD202D
+       tristate "SigmaStar SSD202D RTC"
+       depends on ARCH_MSTARV7 || COMPILE_TEST
+       default ARCH_MSTARV7
+       help
+         If you say yes here you get support for the SigmaStar SSD202D On-Chip
+         Real Time Clock.
+
+         This driver can also be built as a module, if so, the module
+         will be called "rtc-ssd20xd".
+
 endif # RTC_CLASS
index fd20988..7b03c3a 100644 (file)
@@ -103,6 +103,7 @@ obj-$(CONFIG_RTC_DRV_MESON) += rtc-meson.o
 obj-$(CONFIG_RTC_DRV_MOXART)   += rtc-moxart.o
 obj-$(CONFIG_RTC_DRV_MPC5121)  += rtc-mpc5121.o
 obj-$(CONFIG_RTC_DRV_MSC313)   += rtc-msc313.o
+obj-$(CONFIG_RTC_DRV_SSD202D)  += rtc-ssd202d.o
 obj-$(CONFIG_RTC_DRV_MSM6242)  += rtc-msm6242.o
 obj-$(CONFIG_RTC_DRV_MT2712)   += rtc-mt2712.o
 obj-$(CONFIG_RTC_DRV_MT6397)   += rtc-mt6397.o
index add4f71..c16fe71 100644 (file)
@@ -558,7 +558,7 @@ err_clk:
 /*
  * Disable and remove the RTC driver
  */
-static int __exit at91_rtc_remove(struct platform_device *pdev)
+static void __exit at91_rtc_remove(struct platform_device *pdev)
 {
        /* Disable all interrupts */
        at91_rtc_write_idr(AT91_RTC_ACKUPD | AT91_RTC_ALARM |
@@ -566,8 +566,6 @@ static int __exit at91_rtc_remove(struct platform_device *pdev)
                                        AT91_RTC_CALEV);
 
        clk_disable_unprepare(sclk);
-
-       return 0;
 }
 
 static void at91_rtc_shutdown(struct platform_device *pdev)
@@ -635,8 +633,14 @@ static int at91_rtc_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume);
 
-static struct platform_driver at91_rtc_driver = {
-       .remove         = __exit_p(at91_rtc_remove),
+/*
+ * at91_rtc_remove() lives in .exit.text. For drivers registered via
+ * module_platform_driver_probe() this is ok because they cannot get unbound at
+ * runtime. So mark the driver struct with __refdata to prevent modpost
+ * triggering a section mismatch warning.
+ */
+static struct platform_driver at91_rtc_driver __refdata = {
+       .remove_new     = __exit_p(at91_rtc_remove),
        .shutdown       = at91_rtc_shutdown,
        .driver         = {
                .name   = "at91_rtc",
index 3cdc015..1a65a4e 100644 (file)
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright Â© 2014-2017 Broadcom
+ * Copyright Â© 2014-2023 Broadcom
  */
 
 #define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
@@ -34,6 +34,7 @@ struct brcmstb_waketmr {
        u32 rate;
        unsigned long rtc_alarm;
        bool alarm_en;
+       bool alarm_expired;
 };
 
 #define BRCMSTB_WKTMR_EVENT            0x00
@@ -64,6 +65,11 @@ static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer)
        writel_relaxed(reg - 1, timer->base + BRCMSTB_WKTMR_ALARM);
        writel_relaxed(WKTMR_ALARM_EVENT, timer->base + BRCMSTB_WKTMR_EVENT);
        (void)readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
+       if (timer->alarm_expired) {
+               timer->alarm_expired = false;
+               /* maintain call balance */
+               enable_irq(timer->alarm_irq);
+       }
 }
 
 static void brcmstb_waketmr_set_alarm(struct brcmstb_waketmr *timer,
@@ -105,10 +111,17 @@ static irqreturn_t brcmstb_alarm_irq(int irq, void *data)
                return IRQ_HANDLED;
 
        if (timer->alarm_en) {
-               if (!device_may_wakeup(timer->dev))
+               if (device_may_wakeup(timer->dev)) {
+                       disable_irq_nosync(irq);
+                       timer->alarm_expired = true;
+               } else {
                        writel_relaxed(WKTMR_ALARM_EVENT,
                                       timer->base + BRCMSTB_WKTMR_EVENT);
+               }
                rtc_update_irq(timer->rtc, 1, RTC_IRQF | RTC_AF);
+       } else {
+               writel_relaxed(WKTMR_ALARM_EVENT,
+                              timer->base + BRCMSTB_WKTMR_EVENT);
        }
 
        return IRQ_HANDLED;
@@ -221,8 +234,14 @@ static int brcmstb_waketmr_alarm_enable(struct device *dev,
                    !brcmstb_waketmr_is_pending(timer))
                        return -EINVAL;
                timer->alarm_en = true;
-               if (timer->alarm_irq)
+               if (timer->alarm_irq) {
+                       if (timer->alarm_expired) {
+                               timer->alarm_expired = false;
+                               /* maintain call balance */
+                               enable_irq(timer->alarm_irq);
+                       }
                        enable_irq(timer->alarm_irq);
+               }
        } else if (!enabled && timer->alarm_en) {
                if (timer->alarm_irq)
                        disable_irq(timer->alarm_irq);
@@ -352,6 +371,17 @@ static int brcmstb_waketmr_suspend(struct device *dev)
        return brcmstb_waketmr_prepare_suspend(timer);
 }
 
+static int brcmstb_waketmr_suspend_noirq(struct device *dev)
+{
+       struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
+
+       /* Catch any alarms occurring prior to noirq */
+       if (timer->alarm_expired && device_may_wakeup(dev))
+               return -EBUSY;
+
+       return 0;
+}
+
 static int brcmstb_waketmr_resume(struct device *dev)
 {
        struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
@@ -368,10 +398,17 @@ static int brcmstb_waketmr_resume(struct device *dev)
 
        return ret;
 }
+#else
+#define brcmstb_waketmr_suspend                NULL
+#define brcmstb_waketmr_suspend_noirq  NULL
+#define brcmstb_waketmr_resume         NULL
 #endif /* CONFIG_PM_SLEEP */
 
-static SIMPLE_DEV_PM_OPS(brcmstb_waketmr_pm_ops,
-                        brcmstb_waketmr_suspend, brcmstb_waketmr_resume);
+static const struct dev_pm_ops brcmstb_waketmr_pm_ops = {
+       .suspend        = brcmstb_waketmr_suspend,
+       .suspend_noirq  = brcmstb_waketmr_suspend_noirq,
+       .resume         = brcmstb_waketmr_resume,
+};
 
 static const __maybe_unused struct of_device_id brcmstb_waketmr_of_match[] = {
        { .compatible = "brcm,brcmstb-waketimer" },
index dc6b0f4..fa8bf82 100644 (file)
@@ -227,7 +227,7 @@ static int efi_procfs(struct device *dev, struct seq_file *seq)
                           enabled == 1 ? "yes" : "no",
                           pending == 1 ? "yes" : "no");
 
-               if (eft.timezone == EFI_UNSPECIFIED_TIMEZONE)
+               if (alm.timezone == EFI_UNSPECIFIED_TIMEZONE)
                        seq_puts(seq, "Timezone\t: unspecified\n");
                else
                        /* XXX fixme: convert to string? */
index acae7f1..1fdd20d 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/module.h>
+#include <linux/mod_devicetable.h>
 #include <linux/rtc.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
@@ -148,9 +149,16 @@ static int ep93xx_rtc_probe(struct platform_device *pdev)
        return devm_rtc_register_device(ep93xx_rtc->rtc);
 }
 
+static const struct of_device_id ep93xx_rtc_of_ids[] = {
+       { .compatible = "cirrus,ep9301-rtc" },
+       { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ep93xx_rtc_of_ids);
+
 static struct platform_driver ep93xx_rtc_driver = {
        .driver         = {
                .name   = "ep93xx-rtc",
+               .of_match_table = ep93xx_rtc_of_ids,
        },
        .probe          = ep93xx_rtc_probe,
 };
index 4b712e5..284011c 100644 (file)
@@ -830,7 +830,7 @@ err:
        return rc;
 }
 
-static int __exit dryice_rtc_remove(struct platform_device *pdev)
+static void __exit dryice_rtc_remove(struct platform_device *pdev)
 {
        struct imxdi_dev *imxdi = platform_get_drvdata(pdev);
 
@@ -840,8 +840,6 @@ static int __exit dryice_rtc_remove(struct platform_device *pdev)
        writel(0, imxdi->ioaddr + DIER);
 
        clk_disable_unprepare(imxdi->clk);
-
-       return 0;
 }
 
 static const struct of_device_id dryice_dt_ids[] = {
@@ -851,12 +849,18 @@ static const struct of_device_id dryice_dt_ids[] = {
 
 MODULE_DEVICE_TABLE(of, dryice_dt_ids);
 
-static struct platform_driver dryice_rtc_driver = {
+/*
+ * dryice_rtc_remove() lives in .exit.text. For drivers registered via
+ * module_platform_driver_probe() this is ok because they cannot get unbound at
+ * runtime. So mark the driver struct with __refdata to prevent modpost
+ * triggering a section mismatch warning.
+ */
+static struct platform_driver dryice_rtc_driver __refdata = {
        .driver = {
                   .name = "imxdi_rtc",
                   .of_match_table = dryice_dt_ids,
                   },
-       .remove = __exit_p(dryice_rtc_remove),
+       .remove_new = __exit_p(dryice_rtc_remove),
 };
 
 module_platform_driver_probe(dryice_rtc_driver, dryice_rtc_probe);
index 6c526e2..db31da5 100644 (file)
@@ -282,7 +282,7 @@ out:
        return ret;
 }
 
-static int __exit mv_rtc_remove(struct platform_device *pdev)
+static void __exit mv_rtc_remove(struct platform_device *pdev)
 {
        struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
 
@@ -291,8 +291,6 @@ static int __exit mv_rtc_remove(struct platform_device *pdev)
 
        if (!IS_ERR(pdata->clk))
                clk_disable_unprepare(pdata->clk);
-
-       return 0;
 }
 
 #ifdef CONFIG_OF
@@ -303,8 +301,14 @@ static const struct of_device_id rtc_mv_of_match_table[] = {
 MODULE_DEVICE_TABLE(of, rtc_mv_of_match_table);
 #endif
 
-static struct platform_driver mv_rtc_driver = {
-       .remove         = __exit_p(mv_rtc_remove),
+/*
+ * mv_rtc_remove() lives in .exit.text. For drivers registered via
+ * module_platform_driver_probe() this is ok because they cannot get unbound at
+ * runtime. So mark the driver struct with __refdata to prevent modpost
+ * triggering a section mismatch warning.
+ */
+static struct platform_driver mv_rtc_driver __refdata = {
+       .remove_new     = __exit_p(mv_rtc_remove),
        .driver         = {
                .name   = "rtc-mv",
                .of_match_table = of_match_ptr(rtc_mv_of_match_table),
index 5b10ab0..c6155c4 100644 (file)
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/of_device.h>
 #include <linux/pinctrl/pinctrl.h>
 #include <linux/pinctrl/pinconf.h>
 #include <linux/pinctrl/pinconf-generic.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/property.h>
 #include <linux/rtc.h>
 #include <linux/rtc/rtc-omap.h>
 
@@ -729,16 +729,14 @@ static int omap_rtc_probe(struct platform_device *pdev)
        struct omap_rtc *rtc;
        u8 reg, mask, new_ctrl;
        const struct platform_device_id *id_entry;
-       const struct of_device_id *of_id;
        int ret;
 
        rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
        if (!rtc)
                return -ENOMEM;
 
-       of_id = of_match_device(omap_rtc_of_match, &pdev->dev);
-       if (of_id) {
-               rtc->type = of_id->data;
+       rtc->type = device_get_match_data(&pdev->dev);
+       if (rtc->type) {
                rtc->is_pmic_controller = rtc->type->has_pmic_mode &&
                        of_device_is_system_power_controller(pdev->dev.of_node);
        } else {
index 8c7a98a..d665161 100644 (file)
@@ -166,13 +166,7 @@ static int __init pcap_rtc_probe(struct platform_device *pdev)
        return devm_rtc_register_device(pcap_rtc->rtc);
 }
 
-static int __exit pcap_rtc_remove(struct platform_device *pdev)
-{
-       return 0;
-}
-
 static struct platform_driver pcap_rtc_driver = {
-       .remove = __exit_p(pcap_rtc_remove),
        .driver = {
                .name  = "pcap-rtc",
        },
index 0619467..540042b 100644 (file)
@@ -438,7 +438,7 @@ static int pcf85363_probe(struct i2c_client *client)
        if (client->irq > 0 || wakeup_source) {
                regmap_write(pcf85363->regmap, CTRL_FLAGS, 0);
                regmap_update_bits(pcf85363->regmap, CTRL_PIN_IO,
-                                  PIN_IO_INTA_OUT, PIN_IO_INTAPM);
+                                  PIN_IO_INTAPM, PIN_IO_INTA_OUT);
        }
 
        if (client->irq > 0) {
index e400c78..cdb39fc 100644 (file)
@@ -365,12 +365,11 @@ static int __init pxa_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int __exit pxa_rtc_remove(struct platform_device *pdev)
+static void __exit pxa_rtc_remove(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
 
        pxa_rtc_release(dev);
-       return 0;
 }
 
 #ifdef CONFIG_OF
@@ -403,8 +402,14 @@ static int pxa_rtc_resume(struct device *dev)
 
 static SIMPLE_DEV_PM_OPS(pxa_rtc_pm_ops, pxa_rtc_suspend, pxa_rtc_resume);
 
-static struct platform_driver pxa_rtc_driver = {
-       .remove         = __exit_p(pxa_rtc_remove),
+/*
+ * pxa_rtc_remove() lives in .exit.text. For drivers registered via
+ * module_platform_driver_probe() this is ok because they cannot get unbound at
+ * runtime. So mark the driver struct with __refdata to prevent modpost
+ * triggering a section mismatch warning.
+ */
+static struct platform_driver pxa_rtc_driver __refdata = {
+       .remove_new     = __exit_p(pxa_rtc_remove),
        .driver         = {
                .name   = "pxa-rtc",
                .of_match_table = of_match_ptr(pxa_rtc_dt_ids),
index 5dbaeb7..ef913cf 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/delay.h>
+#include <linux/property.h>
 #include <linux/regmap.h>
 #include <linux/platform_device.h>
 #include <linux/rtc.h>
@@ -55,12 +56,23 @@ struct rtc7301_priv {
        u8 bank;
 };
 
-static const struct regmap_config rtc7301_regmap_config = {
+/*
+ * When the device is memory-mapped, some platforms pack the registers into
+ * 32-bit access using the lower 8 bits at each 4-byte stride, while others
+ * expose them as simply consecutive bytes.
+ */
+static const struct regmap_config rtc7301_regmap_32_config = {
        .reg_bits = 32,
        .val_bits = 8,
        .reg_stride = 4,
 };
 
+static const struct regmap_config rtc7301_regmap_8_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .reg_stride = 1,
+};
+
 static u8 rtc7301_read(struct rtc7301_priv *priv, unsigned int reg)
 {
        int reg_stride = regmap_get_reg_stride(priv->regmap);
@@ -356,7 +368,9 @@ static int __init rtc7301_rtc_probe(struct platform_device *dev)
        void __iomem *regs;
        struct rtc7301_priv *priv;
        struct rtc_device *rtc;
+       static const struct regmap_config *mapconf;
        int ret;
+       u32 val;
 
        priv = devm_kzalloc(&dev->dev, sizeof(*priv), GFP_KERNEL);
        if (!priv)
@@ -366,8 +380,25 @@ static int __init rtc7301_rtc_probe(struct platform_device *dev)
        if (IS_ERR(regs))
                return PTR_ERR(regs);
 
+       ret = device_property_read_u32(&dev->dev, "reg-io-width", &val);
+       if (ret)
+               /* Default to 32bit accesses */
+               val = 4;
+
+       switch (val) {
+       case 1:
+               mapconf = &rtc7301_regmap_8_config;
+               break;
+       case 4:
+               mapconf = &rtc7301_regmap_32_config;
+               break;
+       default:
+               dev_err(&dev->dev, "invalid reg-io-width %d\n", val);
+               return -EINVAL;
+       }
+
        priv->regmap = devm_regmap_init_mmio(&dev->dev, regs,
-                                            &rtc7301_regmap_config);
+                                            mapconf);
        if (IS_ERR(priv->regmap))
                return PTR_ERR(priv->regmap);
 
index cd146b5..27a191f 100644 (file)
@@ -469,7 +469,7 @@ static int __init sh_rtc_probe(struct platform_device *pdev)
 {
        struct sh_rtc *rtc;
        struct resource *res;
-       char clk_name[6];
+       char clk_name[14];
        int clk_id, ret;
 
        rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
@@ -620,7 +620,7 @@ err_unmap:
        return ret;
 }
 
-static int __exit sh_rtc_remove(struct platform_device *pdev)
+static void __exit sh_rtc_remove(struct platform_device *pdev)
 {
        struct sh_rtc *rtc = platform_get_drvdata(pdev);
 
@@ -628,8 +628,6 @@ static int __exit sh_rtc_remove(struct platform_device *pdev)
        sh_rtc_setcie(&pdev->dev, 0);
 
        clk_disable(rtc->clk);
-
-       return 0;
 }
 
 static void sh_rtc_set_irq_wake(struct device *dev, int enabled)
@@ -668,13 +666,19 @@ static const struct of_device_id sh_rtc_of_match[] = {
 };
 MODULE_DEVICE_TABLE(of, sh_rtc_of_match);
 
-static struct platform_driver sh_rtc_platform_driver = {
+/*
+ * sh_rtc_remove() lives in .exit.text. For drivers registered via
+ * module_platform_driver_probe() this is ok because they cannot get unbound at
+ * runtime. So mark the driver struct with __refdata to prevent modpost
+ * triggering a section mismatch warning.
+ */
+static struct platform_driver sh_rtc_platform_driver __refdata = {
        .driver         = {
                .name   = DRV_NAME,
                .pm     = &sh_rtc_pm_ops,
                .of_match_table = sh_rtc_of_match,
        },
-       .remove         = __exit_p(sh_rtc_remove),
+       .remove_new     = __exit_p(sh_rtc_remove),
 };
 
 module_platform_driver_probe(sh_rtc_platform_driver, sh_rtc_probe);
diff --git a/drivers/rtc/rtc-ssd202d.c b/drivers/rtc/rtc-ssd202d.c
new file mode 100644 (file)
index 0000000..ed64932
--- /dev/null
@@ -0,0 +1,249 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Real time clocks driver for MStar/SigmaStar SSD202D SoCs.
+ *
+ * (C) 2021 Daniel Palmer
+ * (C) 2023 Romain Perier
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/regmap.h>
+#include <linux/pm.h>
+
+#define REG_CTRL       0x0
+#define REG_CTRL1      0x4
+#define REG_ISO_CTRL   0xc
+#define REG_WRDATA_L   0x10
+#define REG_WRDATA_H   0x14
+#define REG_ISOACK     0x20
+#define REG_RDDATA_L   0x24
+#define REG_RDDATA_H   0x28
+#define REG_RDCNT_L    0x30
+#define REG_RDCNT_H    0x34
+#define REG_CNT_TRIG   0x38
+#define REG_PWRCTRL    0x3c
+#define REG_RTC_TEST   0x54
+
+#define CNT_RD_TRIG_BIT BIT(0)
+#define CNT_RD_BIT BIT(0)
+#define BASE_WR_BIT BIT(1)
+#define BASE_RD_BIT BIT(2)
+#define CNT_RST_BIT BIT(3)
+#define ISO_CTRL_ACK_MASK BIT(3)
+#define ISO_CTRL_ACK_SHIFT 3
+#define SW0_WR_BIT BIT(5)
+#define SW1_WR_BIT BIT(6)
+#define SW0_RD_BIT BIT(7)
+#define SW1_RD_BIT BIT(8)
+
+#define ISO_CTRL_MASK GENMASK(2, 0)
+
+struct ssd202d_rtc {
+       struct rtc_device *rtc_dev;
+       void __iomem *base;
+};
+
+static u8 read_iso_en(void __iomem *base)
+{
+       return readb(base + REG_RTC_TEST) & 0x1;
+}
+
+static u8 read_iso_ctrl_ack(void __iomem *base)
+{
+       return (readb(base + REG_ISOACK) & ISO_CTRL_ACK_MASK) >> ISO_CTRL_ACK_SHIFT;
+}
+
+static int ssd202d_rtc_isoctrl(struct ssd202d_rtc *priv)
+{
+       static const unsigned int sequence[] = { 0x0, 0x1, 0x3, 0x7, 0x5, 0x1, 0x0 };
+       unsigned int val;
+       struct device *dev = &priv->rtc_dev->dev;
+       int i, ret;
+
+       /*
+        * This gates iso_en by writing a special sequence of bytes to iso_ctrl
+        * and ensuring that it has been correctly applied by reading iso_ctrl_ack
+        */
+       for (i = 0; i < ARRAY_SIZE(sequence); i++) {
+               writeb(sequence[i] & ISO_CTRL_MASK, priv->base +  REG_ISO_CTRL);
+
+               ret = read_poll_timeout(read_iso_ctrl_ack, val, val == (i % 2), 100,
+                                       20 * 100, true, priv->base);
+               if (ret) {
+                       dev_dbg(dev, "Timeout waiting for ack byte %i (%x) of sequence\n", i,
+                               sequence[i]);
+                       return ret;
+               }
+       }
+
+       /*
+        * At this point iso_en should be raised for 1ms
+        */
+       ret = read_poll_timeout(read_iso_en, val, val, 100, 22 * 100, true, priv->base);
+       if (ret)
+               dev_dbg(dev, "Timeout waiting for iso_en\n");
+       mdelay(2);
+       return 0;
+}
+
+static void ssd202d_rtc_read_reg(struct ssd202d_rtc *priv, unsigned int reg,
+                                unsigned int field, unsigned int *base)
+{
+       unsigned int l, h;
+       u16 val;
+
+       /* Ask for the content of an RTC value into RDDATA by gating iso_en,
+        * then iso_en is gated and the content of RDDATA can be read
+        */
+       val = readw(priv->base + reg);
+       writew(val | field, priv->base + reg);
+       ssd202d_rtc_isoctrl(priv);
+       writew(val & ~field, priv->base + reg);
+
+       l = readw(priv->base + REG_RDDATA_L);
+       h = readw(priv->base + REG_RDDATA_H);
+
+       *base = (h << 16) | l;
+}
+
+static void ssd202d_rtc_write_reg(struct ssd202d_rtc *priv, unsigned int reg,
+                                 unsigned int field, u32 base)
+{
+       u16 val;
+
+       /* Set the content of an RTC value from WRDATA by gating iso_en */
+       val = readw(priv->base + reg);
+       writew(val | field, priv->base + reg);
+       writew(base, priv->base + REG_WRDATA_L);
+       writew(base >> 16, priv->base + REG_WRDATA_H);
+       ssd202d_rtc_isoctrl(priv);
+       writew(val & ~field, priv->base + reg);
+}
+
+static int ssd202d_rtc_read_counter(struct ssd202d_rtc *priv, unsigned int *counter)
+{
+       unsigned int l, h;
+       u16 val;
+
+       val = readw(priv->base + REG_CTRL1);
+       writew(val | CNT_RD_BIT, priv->base + REG_CTRL1);
+       ssd202d_rtc_isoctrl(priv);
+       writew(val & ~CNT_RD_BIT, priv->base + REG_CTRL1);
+
+       val = readw(priv->base + REG_CTRL1);
+       writew(val | CNT_RD_TRIG_BIT, priv->base + REG_CNT_TRIG);
+       writew(val & ~CNT_RD_TRIG_BIT, priv->base + REG_CNT_TRIG);
+
+       l = readw(priv->base + REG_RDCNT_L);
+       h = readw(priv->base + REG_RDCNT_H);
+
+       *counter = (h << 16) | l;
+
+       return 0;
+}
+
+static int ssd202d_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct ssd202d_rtc *priv = dev_get_drvdata(dev);
+       unsigned int sw0, base, counter;
+       u32 seconds;
+       int ret;
+
+       /* Check that RTC is enabled by SW */
+       ssd202d_rtc_read_reg(priv, REG_CTRL, SW0_RD_BIT, &sw0);
+       if (sw0 != 1)
+               return -EINVAL;
+
+       /* Get RTC base value from RDDATA */
+       ssd202d_rtc_read_reg(priv, REG_CTRL, BASE_RD_BIT, &base);
+       /* Get RTC counter value from RDDATA */
+       ret = ssd202d_rtc_read_counter(priv, &counter);
+       if (ret)
+               return ret;
+
+       seconds = base + counter;
+
+       rtc_time64_to_tm(seconds, tm);
+
+       return 0;
+}
+
+static int ssd202d_rtc_reset_counter(struct ssd202d_rtc *priv)
+{
+       u16 val;
+
+       val = readw(priv->base + REG_CTRL);
+       writew(val | CNT_RST_BIT, priv->base + REG_CTRL);
+       ssd202d_rtc_isoctrl(priv);
+       writew(val & ~CNT_RST_BIT, priv->base + REG_CTRL);
+       ssd202d_rtc_isoctrl(priv);
+
+       return 0;
+}
+
+static int ssd202d_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct ssd202d_rtc *priv = dev_get_drvdata(dev);
+       unsigned long seconds = rtc_tm_to_time64(tm);
+
+       ssd202d_rtc_write_reg(priv, REG_CTRL, BASE_WR_BIT, seconds);
+       ssd202d_rtc_reset_counter(priv);
+       ssd202d_rtc_write_reg(priv, REG_CTRL, SW0_WR_BIT, 1);
+
+       return 0;
+}
+
+static const struct rtc_class_ops ssd202d_rtc_ops = {
+       .read_time = ssd202d_rtc_read_time,
+       .set_time = ssd202d_rtc_set_time,
+};
+
+static int ssd202d_rtc_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct ssd202d_rtc *priv;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(struct ssd202d_rtc), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->base = devm_platform_ioremap_resource(pdev, 0);
+       if (IS_ERR(priv->base))
+               return PTR_ERR(priv->base);
+
+       priv->rtc_dev = devm_rtc_allocate_device(dev);
+       if (IS_ERR(priv->rtc_dev))
+               return PTR_ERR(priv->rtc_dev);
+
+       priv->rtc_dev->ops = &ssd202d_rtc_ops;
+       priv->rtc_dev->range_max = U32_MAX;
+
+       platform_set_drvdata(pdev, priv);
+
+       return devm_rtc_register_device(priv->rtc_dev);
+}
+
+static const struct of_device_id ssd202d_rtc_of_match_table[] = {
+       { .compatible = "mstar,ssd202d-rtc" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ssd202d_rtc_of_match_table);
+
+static struct platform_driver ssd202d_rtc_driver = {
+       .probe = ssd202d_rtc_probe,
+       .driver = {
+               .name = "ssd202d-rtc",
+               .of_match_table = ssd202d_rtc_of_match_table,
+       },
+};
+module_platform_driver(ssd202d_rtc_driver);
+
+MODULE_AUTHOR("Daniel Palmer <daniel@thingy.jp>");
+MODULE_AUTHOR("Romain Perier <romain.perier@gmail.com>");
+MODULE_DESCRIPTION("MStar SSD202D RTC Driver");
+MODULE_LICENSE("GPL");