]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'rtc-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 28 Feb 2017 03:59:21 +0000 (19:59 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 28 Feb 2017 03:59:21 +0000 (19:59 -0800)
Pull RTC updates from Alexandre Belloni:
 "Subsystem:
   - constify rtc_class_ops structures

 New driver:
   - STM32

 Drivers:
   - armada38x: fix errata, Armada 7K/8K support
   - ds3232: fix wakeup support
   - gemini: DT support
   - m48t86: huge cleanup and platform_data removal
   - mcp795: alarm support
   - sun6i: proper oscillator handling
   - tegra: proper clock handling
   - tps65910: calibration support"

* tag 'rtc-4.11' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (44 commits)
  rtc: ds3232: Call device_init_wakeup before device_register
  rtc: pcf2127: bulk read only date and time registers.
  rtc: armada38x: Add support for Armada 7K/8K
  rtc: armada38x: Prepare driver to manage different versions
  rtc: ds3232: Add regmap max_register definition.
  rtc: ds3232: Cleanup whitespace around register and bit definitions.
  rtc: m48t86: remove unused platform_data
  ARM: Orion5x: ts78xx: allow rtc-m48t86 to manage it's own resources
  ARM: Orion5x: ts78xx: remove RTC detection
  ARM: ep93xx: ts72xx: allow rtc-m48t86 to manage its own resources
  rtc: m48t86: verify that the RTC is actually present
  rtc: m48t86: add NVRAM support
  rtc: m48t86: allow driver to manage its resources
  rtc: m48t86: shorten register name defines
  bindings: rtc: correct wrong reference in required properties
  rtc: sun6i: Fix return value check in sun6i_rtc_clk_init()
  rtc: sun6i: extend test coverage
  rtc: sun6i: Fix compatibility with old DT binding
  rtc: snvs: add a missing write sync
  rtc: bq32000: add support to enable disable the trickle charge FET bypass
  ...

35 files changed:
Documentation/ABI/testing/sysfs-bus-i2c-devices-bq32k [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/armada-380-rtc.txt
Documentation/devicetree/bindings/rtc/cortina,gemini.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/imxdi-rtc.txt
Documentation/devicetree/bindings/rtc/maxim,ds3231.txt
Documentation/devicetree/bindings/rtc/pcf8563.txt
Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/sun6i-rtc.txt
arch/arm/mach-ep93xx/ts72xx.c
arch/arm/mach-ep93xx/ts72xx.h
arch/arm/mach-orion5x/ts78xx-setup.c
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/rtc-armada38x.c
drivers/rtc/rtc-au1xxx.c
drivers/rtc/rtc-bfin.c
drivers/rtc/rtc-bq32k.c
drivers/rtc/rtc-dm355evm.c
drivers/rtc/rtc-ds3232.c
drivers/rtc/rtc-gemini.c
drivers/rtc/rtc-imxdi.c
drivers/rtc/rtc-ls1x.c
drivers/rtc/rtc-m48t86.c
drivers/rtc/rtc-mcp795.c
drivers/rtc/rtc-mxc.c
drivers/rtc/rtc-pcf2127.c
drivers/rtc/rtc-rx8010.c
drivers/rtc/rtc-sh.c
drivers/rtc/rtc-snvs.c
drivers/rtc/rtc-stm32.c [new file with mode: 0644]
drivers/rtc/rtc-sun6i.c
drivers/rtc/rtc-tegra.c
drivers/rtc/rtc-tps65910.c
include/linux/mfd/tps65910.h
include/linux/platform_data/rtc-m48t86.h [deleted file]

diff --git a/Documentation/ABI/testing/sysfs-bus-i2c-devices-bq32k b/Documentation/ABI/testing/sysfs-bus-i2c-devices-bq32k
new file mode 100644 (file)
index 0000000..398b258
--- /dev/null
@@ -0,0 +1,7 @@
+What:          /sys/bus/i2c/devices/.../trickle_charge_bypass
+Date:          Jan 2017
+KernelVersion: 4.11
+Contact:       Enric Balletbo i Serra <eballetbo@gmail.com>
+Description:    Attribute for enable/disable the trickle charge bypass
+               The trickle_charge_bypass attribute allows the userspace to
+                enable/disable the Trickle charge FET bypass.
index 2eb9d4ee7dc07d579cb25ac0dd135662cd682fe6..c3c9a1226f9aa622702d590f593618506509b3b6 100644 (file)
@@ -1,9 +1,11 @@
-* Real Time Clock of the Armada 38x SoCs
+* Real Time Clock of the Armada 38x/7K/8K SoCs
 
-RTC controller for the Armada 38x SoCs
+RTC controller for the Armada 38x, 7K and 8K SoCs
 
 Required properties:
-- compatible : Should be "marvell,armada-380-rtc"
+- compatible : Should be one of the following:
+       "marvell,armada-380-rtc" for Armada 38x SoC
+       "marvell,armada-8k-rtc" for Aramda 7K/8K SoCs
 - reg: a list of base address and size pairs, one for each entry in
   reg-names
 - reg names: should contain:
diff --git a/Documentation/devicetree/bindings/rtc/cortina,gemini.txt b/Documentation/devicetree/bindings/rtc/cortina,gemini.txt
new file mode 100644 (file)
index 0000000..4ce4e79
--- /dev/null
@@ -0,0 +1,14 @@
+* Cortina Systems Gemini RTC
+
+Gemini SoC real-time clock.
+
+Required properties:
+- compatible : Should be "cortina,gemini-rtc"
+
+Examples:
+
+rtc@45000000 {
+       compatible = "cortina,gemini-rtc";
+       reg = <0x45000000 0x100>;
+       interrupts = <17 IRQ_TYPE_LEVEL_HIGH>;
+};
index c9d80d7da14129ac656cabadcb8cbca5ba7339b9..323cf26374cb14dff4284fb8cdbe4e27270b8107 100644 (file)
@@ -8,10 +8,13 @@ Required properties:
   region.
 - interrupts: rtc alarm interrupt
 
+Optional properties:
+- interrupts: dryice security violation interrupt
+
 Example:
 
 rtc@80056000 {
        compatible = "fsl,imx53-rtc", "fsl,imx25-rtc";
        reg = <0x80056000 2000>;
-       interrupts = <29>;
+       interrupts = <29 56>;
 };
index 1ad4c1c2b3b378299fe376463f30308e41c5a89e..85be53a421809c0b8e04c6bf1dfa9833ff84a99d 100644 (file)
@@ -1,7 +1,8 @@
 * Maxim DS3231 Real Time Clock
 
 Required properties:
-see: Documentation/devicetree/bindings/i2c/trivial-admin-guide/devices.rst
+- compatible: Should contain "maxim,ds3231".
+- reg: I2C address for chip.
 
 Optional property:
 - #clock-cells: Should be 1.
index 086c998c556108134e111e69067156768d7e77f8..36984acbb383c275c57a25ff0d8cf756292ed45d 100644 (file)
@@ -3,7 +3,8 @@
 Philips PCF8563/Epson RTC8564 Real Time Clock
 
 Required properties:
-see: Documentation/devicetree/bindings/i2c/trivial-admin-guide/devices.rst
+- compatible: Should contain "nxp,pcf8563".
+- reg: I2C address for chip.
 
 Optional property:
 - #clock-cells: Should be 0.
diff --git a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
new file mode 100644 (file)
index 0000000..e2837b9
--- /dev/null
@@ -0,0 +1,27 @@
+STM32 Real Time Clock
+
+Required properties:
+- compatible: "st,stm32-rtc".
+- reg: address range of rtc register set.
+- clocks: reference to the clock entry ck_rtc.
+- interrupt-parent: phandle for the interrupt controller.
+- interrupts: rtc alarm interrupt.
+- st,syscfg: phandle for pwrcfg, mandatory to disable/enable backup domain
+  (RTC registers) write protection.
+
+Optional properties (to override default ck_rtc parent clock):
+- assigned-clocks: reference to the ck_rtc clock entry.
+- assigned-clock-parents: phandle of the new parent clock of ck_rtc.
+
+Example:
+
+       rtc: rtc@40002800 {
+               compatible = "st,stm32-rtc";
+               reg = <0x40002800 0x400>;
+               clocks = <&rcc 1 CLK_RTC>;
+               assigned-clocks = <&rcc 1 CLK_RTC>;
+               assigned-clock-parents = <&rcc 1 CLK_LSE>;
+               interrupt-parent = <&exti>;
+               interrupts = <17 1>;
+               st,syscfg = <&pwrcfg>;
+       };
index f007e428a1ab277b6d38e2dae8c102a0d8ef3920..945934918b71fc127da6729f38b6498884ad5fca 100644 (file)
@@ -8,10 +8,20 @@ Required properties:
                  memory mapped region.
 - interrupts   : IRQ lines for the RTC alarm 0 and alarm 1, in that order.
 
+Required properties for new device trees
+- clocks       : phandle to the 32kHz external oscillator
+- clock-output-names : name of the LOSC clock created
+- #clock-cells  : must be equals to 1. The RTC provides two clocks: the
+                 LOSC and its external output, with index 0 and 1
+                 respectively.
+
 Example:
 
 rtc: rtc@01f00000 {
        compatible = "allwinner,sun6i-a31-rtc";
        reg = <0x01f00000 0x54>;
        interrupts = <0 40 4>, <0 41 4>;
+       clock-output-names = "osc32k";
+       clocks = <&ext_osc32k>;
+       #clock-cells = <1>;
 };
index 3b39ea353d3075b687a6f30a4688bab8994ab625..8a5b6f059498d4c53d664ab7fa0407026e02498c 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
-#include <linux/platform_data/rtc-m48t86.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 
@@ -45,16 +44,6 @@ static struct map_desc ts72xx_io_desc[] __initdata = {
                .pfn            = __phys_to_pfn(TS72XX_OPTIONS2_PHYS_BASE),
                .length         = TS72XX_OPTIONS2_SIZE,
                .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)TS72XX_RTC_INDEX_VIRT_BASE,
-               .pfn            = __phys_to_pfn(TS72XX_RTC_INDEX_PHYS_BASE),
-               .length         = TS72XX_RTC_INDEX_SIZE,
-               .type           = MT_DEVICE,
-       }, {
-               .virtual        = (unsigned long)TS72XX_RTC_DATA_VIRT_BASE,
-               .pfn            = __phys_to_pfn(TS72XX_RTC_DATA_PHYS_BASE),
-               .length         = TS72XX_RTC_DATA_SIZE,
-               .type           = MT_DEVICE,
        }
 };
 
@@ -179,31 +168,22 @@ static void __init ts72xx_register_flash(void)
        }
 }
 
+/*************************************************************************
+ * RTC M48T86
+ *************************************************************************/
+#define TS72XX_RTC_INDEX_PHYS_BASE     (EP93XX_CS1_PHYS_BASE + 0x00800000)
+#define TS72XX_RTC_DATA_PHYS_BASE      (EP93XX_CS1_PHYS_BASE + 0x01700000)
 
-static unsigned char ts72xx_rtc_readbyte(unsigned long addr)
-{
-       __raw_writeb(addr, TS72XX_RTC_INDEX_VIRT_BASE);
-       return __raw_readb(TS72XX_RTC_DATA_VIRT_BASE);
-}
-
-static void ts72xx_rtc_writebyte(unsigned char value, unsigned long addr)
-{
-       __raw_writeb(addr, TS72XX_RTC_INDEX_VIRT_BASE);
-       __raw_writeb(value, TS72XX_RTC_DATA_VIRT_BASE);
-}
-
-static struct m48t86_ops ts72xx_rtc_ops = {
-       .readbyte       = ts72xx_rtc_readbyte,
-       .writebyte      = ts72xx_rtc_writebyte,
+static struct resource ts72xx_rtc_resources[] = {
+       DEFINE_RES_MEM(TS72XX_RTC_INDEX_PHYS_BASE, 0x01),
+       DEFINE_RES_MEM(TS72XX_RTC_DATA_PHYS_BASE, 0x01),
 };
 
 static struct platform_device ts72xx_rtc_device = {
        .name           = "rtc-m48t86",
        .id             = -1,
-       .dev            = {
-               .platform_data  = &ts72xx_rtc_ops,
-       },
-       .num_resources  = 0,
+       .resource       = ts72xx_rtc_resources,
+       .num_resources  = ARRAY_SIZE(ts72xx_rtc_resources),
 };
 
 static struct resource ts72xx_wdt_resources[] = {
index 071feaa30adc6094a995738a0b812a7f0b7b5a34..2255ba29fdd64d4bdc3102a69869184972a31f60 100644 (file)
@@ -9,8 +9,6 @@
  * febff000    22000000        4K      model number register (bits 0-2)
  * febfe000    22400000        4K      options register
  * febfd000    22800000        4K      options register #2
- * febf9000    10800000        4K      TS-5620 RTC index register
- * febf8000    11700000        4K      TS-5620 RTC data register
  */
 
 #define TS72XX_MODEL_PHYS_BASE         0x22000000
 #define TS72XX_OPTIONS2_TS9420         0x04
 #define TS72XX_OPTIONS2_TS9420_BOOT    0x02
 
-
-#define TS72XX_RTC_INDEX_VIRT_BASE     IOMEM(0xfebf9000)
-#define TS72XX_RTC_INDEX_PHYS_BASE     0x10800000
-#define TS72XX_RTC_INDEX_SIZE          0x00001000
-
-#define TS72XX_RTC_DATA_VIRT_BASE      IOMEM(0xfebf8000)
-#define TS72XX_RTC_DATA_PHYS_BASE      0x11700000
-#define TS72XX_RTC_DATA_SIZE           0x00001000
-
 #define TS72XX_WDT_CONTROL_PHYS_BASE   0x23800000
 #define TS72XX_WDT_FEED_PHYS_BASE      0x23c00000
 
index 8d597267d0c457530ca097b0730f251fd2d4c7bd..7ef80a8304c0c3ce96f3120e285914fce49b89e8 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/platform_device.h>
 #include <linux/mv643xx_eth.h>
 #include <linux/ata_platform.h>
-#include <linux/platform_data/rtc-m48t86.h>
 #include <linux/mtd/nand.h>
 #include <linux/mtd/partitions.h>
 #include <linux/timeriomem-rng.h>
@@ -80,79 +79,38 @@ static struct mv_sata_platform_data ts78xx_sata_data = {
 /*****************************************************************************
  * RTC M48T86 - nicked^Wborrowed from arch/arm/mach-ep93xx/ts72xx.c
  ****************************************************************************/
-#define TS_RTC_CTRL    (TS78XX_FPGA_REGS_VIRT_BASE + 0x808)
-#define TS_RTC_DATA    (TS78XX_FPGA_REGS_VIRT_BASE + 0x80c)
+#define TS_RTC_CTRL    (TS78XX_FPGA_REGS_PHYS_BASE + 0x808)
+#define TS_RTC_DATA    (TS78XX_FPGA_REGS_PHYS_BASE + 0x80c)
 
-static unsigned char ts78xx_ts_rtc_readbyte(unsigned long addr)
-{
-       writeb(addr, TS_RTC_CTRL);
-       return readb(TS_RTC_DATA);
-}
-
-static void ts78xx_ts_rtc_writebyte(unsigned char value, unsigned long addr)
-{
-       writeb(addr, TS_RTC_CTRL);
-       writeb(value, TS_RTC_DATA);
-}
-
-static struct m48t86_ops ts78xx_ts_rtc_ops = {
-       .readbyte       = ts78xx_ts_rtc_readbyte,
-       .writebyte      = ts78xx_ts_rtc_writebyte,
+static struct resource ts78xx_ts_rtc_resources[] = {
+       DEFINE_RES_MEM(TS_RTC_CTRL, 0x01),
+       DEFINE_RES_MEM(TS_RTC_DATA, 0x01),
 };
 
 static struct platform_device ts78xx_ts_rtc_device = {
        .name           = "rtc-m48t86",
        .id             = -1,
-       .dev            = {
-               .platform_data  = &ts78xx_ts_rtc_ops,
-       },
-       .num_resources  = 0,
+       .resource       = ts78xx_ts_rtc_resources,
+       .num_resources  = ARRAY_SIZE(ts78xx_ts_rtc_resources),
 };
 
-/*
- * TS uses some of the user storage space on the RTC chip so see if it is
- * present; as it's an optional feature at purchase time and not all boards
- * will have it present
- *
- * I've used the method TS use in their rtc7800.c example for the detection
- *
- * TODO: track down a guinea pig without an RTC to see if we can work out a
- *             better RTC detection routine
- */
 static int ts78xx_ts_rtc_load(void)
 {
        int rc;
-       unsigned char tmp_rtc0, tmp_rtc1;
-
-       tmp_rtc0 = ts78xx_ts_rtc_readbyte(126);
-       tmp_rtc1 = ts78xx_ts_rtc_readbyte(127);
-
-       ts78xx_ts_rtc_writebyte(0x00, 126);
-       ts78xx_ts_rtc_writebyte(0x55, 127);
-       if (ts78xx_ts_rtc_readbyte(127) == 0x55) {
-               ts78xx_ts_rtc_writebyte(0xaa, 127);
-               if (ts78xx_ts_rtc_readbyte(127) == 0xaa
-                               && ts78xx_ts_rtc_readbyte(126) == 0x00) {
-                       ts78xx_ts_rtc_writebyte(tmp_rtc0, 126);
-                       ts78xx_ts_rtc_writebyte(tmp_rtc1, 127);
-
-                       if (ts78xx_fpga.supports.ts_rtc.init == 0) {
-                               rc = platform_device_register(&ts78xx_ts_rtc_device);
-                               if (!rc)
-                                       ts78xx_fpga.supports.ts_rtc.init = 1;
-                       } else
-                               rc = platform_device_add(&ts78xx_ts_rtc_device);
-
-                       if (rc)
-                               pr_info("RTC could not be registered: %d\n",
-                                       rc);
-                       return rc;
-               }
+
+       if (ts78xx_fpga.supports.ts_rtc.init == 0) {
+               rc = platform_device_register(&ts78xx_ts_rtc_device);
+               if (!rc)
+                       ts78xx_fpga.supports.ts_rtc.init = 1;
+       } else {
+               rc = platform_device_add(&ts78xx_ts_rtc_device);
        }
 
-       pr_info("RTC not found\n");
-       return -ENODEV;
-};
+       if (rc)
+               pr_info("RTC could not be registered: %d\n", rc);
+
+       return rc;
+}
 
 static void ts78xx_ts_rtc_unload(void)
 {
index 5dc673dc948785a79da8d070954323b9357385c1..ee1b0e9dde79a9ec4720c516a697fd5de1e72fcf 100644 (file)
@@ -1434,9 +1434,10 @@ config RTC_DRV_SUN4V
          based RTC on SUN4V systems.
 
 config RTC_DRV_SUN6I
-       tristate "Allwinner A31 RTC"
-       default MACH_SUN6I || MACH_SUN8I || COMPILE_TEST
-       depends on ARCH_SUNXI
+       bool "Allwinner A31 RTC"
+       default MACH_SUN6I || MACH_SUN8I
+       depends on COMMON_CLK
+       depends on ARCH_SUNXI || COMPILE_TEST
        help
          If you say Y here you will get support for the RTC found in
          some Allwinner SoCs like the A31 or the A64.
@@ -1719,6 +1720,17 @@ config RTC_DRV_R7301
           This driver can also be built as a module. If so, the module
           will be called rtc-r7301.
 
+config RTC_DRV_STM32
+       tristate "STM32 RTC"
+       select REGMAP_MMIO
+       depends on ARCH_STM32 || COMPILE_TEST
+       help
+          If you say yes here you get support for the STM32 On-Chip
+          Real Time Clock.
+
+          This driver can also be built as a module, if so, the module
+          will be called "rtc-stm32".
+
 comment "HID Sensor RTC drivers"
 
 config RTC_DRV_HID_SENSOR_TIME
index f13ab1c5c222c269e711786e74f5a99a258150a5..f07297b1460a06f2ed33c2b6b2ff11196f6955b0 100644 (file)
@@ -145,6 +145,7 @@ obj-$(CONFIG_RTC_DRV_SNVS)  += rtc-snvs.o
 obj-$(CONFIG_RTC_DRV_SPEAR)    += rtc-spear.o
 obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
 obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
+obj-$(CONFIG_RTC_DRV_STM32)    += rtc-stm32.o
 obj-$(CONFIG_RTC_DRV_STMP)     += rtc-stmp3xxx.o
 obj-$(CONFIG_RTC_DRV_ST_LPC)   += rtc-st-lpc.o
 obj-$(CONFIG_RTC_DRV_SUN4V)    += rtc-sun4v.o
index 9a3f2a6f512e014b60b86974bdd6875e95e643ad..21f355c37eab53cd4de0668e7250d1d578344e71 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/rtc.h>
 
 #define RTC_STATUS_ALARM1          BIT(0)
 #define RTC_STATUS_ALARM2          BIT(1)
 #define RTC_IRQ1_CONF      0x4
-#define RTC_IRQ1_AL_EN             BIT(0)
-#define RTC_IRQ1_FREQ_EN           BIT(1)
-#define RTC_IRQ1_FREQ_1HZ          BIT(2)
+#define RTC_IRQ2_CONF      0x8
+#define RTC_IRQ_AL_EN              BIT(0)
+#define RTC_IRQ_FREQ_EN                    BIT(1)
+#define RTC_IRQ_FREQ_1HZ           BIT(2)
+
 #define RTC_TIME           0xC
 #define RTC_ALARM1         0x10
-
-#define SOC_RTC_INTERRUPT   0x8
-#define SOC_RTC_ALARM1         BIT(0)
-#define SOC_RTC_ALARM2         BIT(1)
-#define SOC_RTC_ALARM1_MASK    BIT(2)
-#define SOC_RTC_ALARM2_MASK    BIT(3)
+#define RTC_ALARM2         0x14
+
+/* Armada38x SoC registers  */
+#define RTC_38X_BRIDGE_TIMING_CTL   0x0
+#define RTC_38X_PERIOD_OFFS            0
+#define RTC_38X_PERIOD_MASK            (0x3FF << RTC_38X_PERIOD_OFFS)
+#define RTC_38X_READ_DELAY_OFFS                26
+#define RTC_38X_READ_DELAY_MASK                (0x1F << RTC_38X_READ_DELAY_OFFS)
+
+/* Armada 7K/8K registers  */
+#define RTC_8K_BRIDGE_TIMING_CTL0    0x0
+#define RTC_8K_WRCLK_PERIOD_OFFS       0
+#define RTC_8K_WRCLK_PERIOD_MASK       (0xFFFF << RTC_8K_WRCLK_PERIOD_OFFS)
+#define RTC_8K_WRCLK_SETUP_OFFS                16
+#define RTC_8K_WRCLK_SETUP_MASK                (0xFFFF << RTC_8K_WRCLK_SETUP_OFFS)
+#define RTC_8K_BRIDGE_TIMING_CTL1   0x4
+#define RTC_8K_READ_DELAY_OFFS         0
+#define RTC_8K_READ_DELAY_MASK         (0xFFFF << RTC_8K_READ_DELAY_OFFS)
+
+#define RTC_8K_ISR                 0x10
+#define RTC_8K_IMR                 0x14
+#define RTC_8K_ALARM2                  BIT(0)
+
+#define SOC_RTC_INTERRUPT          0x8
+#define SOC_RTC_ALARM1                 BIT(0)
+#define SOC_RTC_ALARM2                 BIT(1)
+#define SOC_RTC_ALARM1_MASK            BIT(2)
+#define SOC_RTC_ALARM2_MASK            BIT(3)
+
+#define SAMPLE_NR 100
+
+struct value_to_freq {
+       u32 value;
+       u8 freq;
+};
 
 struct armada38x_rtc {
        struct rtc_device   *rtc_dev;
@@ -41,38 +73,153 @@ struct armada38x_rtc {
        void __iomem        *regs_soc;
        spinlock_t          lock;
        int                 irq;
+       struct value_to_freq *val_to_freq;
+       struct armada38x_rtc_data *data;
+};
+
+#define ALARM1 0
+#define ALARM2 1
+
+#define ALARM_REG(base, alarm)  ((base) + (alarm) * sizeof(u32))
+
+struct armada38x_rtc_data {
+       /* Initialize the RTC-MBUS bridge timing */
+       void (*update_mbus_timing)(struct armada38x_rtc *rtc);
+       u32 (*read_rtc_reg)(struct armada38x_rtc *rtc, u8 rtc_reg);
+       void (*clear_isr)(struct armada38x_rtc *rtc);
+       void (*unmask_interrupt)(struct armada38x_rtc *rtc);
+       u32 alarm;
 };
 
 /*
  * According to the datasheet, the OS should wait 5us after every
  * register write to the RTC hard macro so that the required update
  * can occur without holding off the system bus
+ * According to errata RES-3124064, Write to any RTC register
+ * may fail. As a workaround, before writing to RTC
+ * register, issue a dummy write of 0x0 twice to RTC Status
+ * register.
  */
+
 static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset)
 {
+       writel(0, rtc->regs + RTC_STATUS);
+       writel(0, rtc->regs + RTC_STATUS);
        writel(val, rtc->regs + offset);
        udelay(5);
 }
 
+/* Update RTC-MBUS bridge timing parameters */
+static void rtc_update_38x_mbus_timing_params(struct armada38x_rtc *rtc)
+{
+       u32 reg;
+
+       reg = readl(rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL);
+       reg &= ~RTC_38X_PERIOD_MASK;
+       reg |= 0x3FF << RTC_38X_PERIOD_OFFS; /* Maximum value */
+       reg &= ~RTC_38X_READ_DELAY_MASK;
+       reg |= 0x1F << RTC_38X_READ_DELAY_OFFS; /* Maximum value */
+       writel(reg, rtc->regs_soc + RTC_38X_BRIDGE_TIMING_CTL);
+}
+
+static void rtc_update_8k_mbus_timing_params(struct armada38x_rtc *rtc)
+{
+       u32 reg;
+
+       reg = readl(rtc->regs_soc + RTC_8K_BRIDGE_TIMING_CTL0);
+       reg &= ~RTC_8K_WRCLK_PERIOD_MASK;
+       reg |= 0x3FF << RTC_8K_WRCLK_PERIOD_OFFS;
+       reg &= ~RTC_8K_WRCLK_SETUP_MASK;
+       reg |= 0x29 << RTC_8K_WRCLK_SETUP_OFFS;
+       writel(reg, rtc->regs_soc + RTC_8K_BRIDGE_TIMING_CTL0);
+
+       reg = readl(rtc->regs_soc + RTC_8K_BRIDGE_TIMING_CTL1);
+       reg &= ~RTC_8K_READ_DELAY_MASK;
+       reg |= 0x3F << RTC_8K_READ_DELAY_OFFS;
+       writel(reg, rtc->regs_soc + RTC_8K_BRIDGE_TIMING_CTL1);
+}
+
+static u32 read_rtc_register(struct armada38x_rtc *rtc, u8 rtc_reg)
+{
+       return readl(rtc->regs + rtc_reg);
+}
+
+static u32 read_rtc_register_38x_wa(struct armada38x_rtc *rtc, u8 rtc_reg)
+{
+       int i, index_max = 0, max = 0;
+
+       for (i = 0; i < SAMPLE_NR; i++) {
+               rtc->val_to_freq[i].value = readl(rtc->regs + rtc_reg);
+               rtc->val_to_freq[i].freq = 0;
+       }
+
+       for (i = 0; i < SAMPLE_NR; i++) {
+               int j = 0;
+               u32 value = rtc->val_to_freq[i].value;
+
+               while (rtc->val_to_freq[j].freq) {
+                       if (rtc->val_to_freq[j].value == value) {
+                               rtc->val_to_freq[j].freq++;
+                               break;
+                       }
+                       j++;
+               }
+
+               if (!rtc->val_to_freq[j].freq) {
+                       rtc->val_to_freq[j].value = value;
+                       rtc->val_to_freq[j].freq = 1;
+               }
+
+               if (rtc->val_to_freq[j].freq > max) {
+                       index_max = j;
+                       max = rtc->val_to_freq[j].freq;
+               }
+
+               /*
+                * If a value already has half of the sample this is the most
+                * frequent one and we can stop the research right now
+                */
+               if (max > SAMPLE_NR / 2)
+                       break;
+       }
+
+       return rtc->val_to_freq[index_max].value;
+}
+
+static void armada38x_clear_isr(struct armada38x_rtc *rtc)
+{
+       u32 val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT);
+
+       writel(val & ~SOC_RTC_ALARM1, rtc->regs_soc + SOC_RTC_INTERRUPT);
+}
+
+static void armada38x_unmask_interrupt(struct armada38x_rtc *rtc)
+{
+       u32 val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT);
+
+       writel(val | SOC_RTC_ALARM1_MASK, rtc->regs_soc + SOC_RTC_INTERRUPT);
+}
+
+static void armada8k_clear_isr(struct armada38x_rtc *rtc)
+{
+       writel(RTC_8K_ALARM2, rtc->regs_soc + RTC_8K_ISR);
+}
+
+static void armada8k_unmask_interrupt(struct armada38x_rtc *rtc)
+{
+       writel(RTC_8K_ALARM2, rtc->regs_soc + RTC_8K_IMR);
+}
+
 static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        struct armada38x_rtc *rtc = dev_get_drvdata(dev);
-       unsigned long time, time_check, flags;
+       unsigned long time, flags;
 
        spin_lock_irqsave(&rtc->lock, flags);
-       time = readl(rtc->regs + RTC_TIME);
-       /*
-        * WA for failing time set attempts. As stated in HW ERRATA if
-        * more than one second between two time reads is detected
-        * then read once again.
-        */
-       time_check = readl(rtc->regs + RTC_TIME);
-       if ((time_check - time) > 1)
-               time_check = readl(rtc->regs + RTC_TIME);
-
+       time = rtc->data->read_rtc_reg(rtc, RTC_TIME);
        spin_unlock_irqrestore(&rtc->lock, flags);
 
-       rtc_time_to_tm(time_check, tm);
+       rtc_time_to_tm(time, tm);
 
        return 0;
 }
@@ -87,16 +234,9 @@ static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
 
        if (ret)
                goto out;
-       /*
-        * According to errata FE-3124064, Write to RTC TIME register
-        * may fail. As a workaround, after writing to RTC TIME
-        * register, issue a dummy write of 0x0 twice to RTC Status
-        * register.
-        */
+
        spin_lock_irqsave(&rtc->lock, flags);
        rtc_delayed_write(time, rtc, RTC_TIME);
-       rtc_delayed_write(0, rtc, RTC_STATUS);
-       rtc_delayed_write(0, rtc, RTC_STATUS);
        spin_unlock_irqrestore(&rtc->lock, flags);
 
 out:
@@ -107,12 +247,14 @@ static int armada38x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
        struct armada38x_rtc *rtc = dev_get_drvdata(dev);
        unsigned long time, flags;
+       u32 reg = ALARM_REG(RTC_ALARM1, rtc->data->alarm);
+       u32 reg_irq = ALARM_REG(RTC_IRQ1_CONF, rtc->data->alarm);
        u32 val;
 
        spin_lock_irqsave(&rtc->lock, flags);
 
-       time = readl(rtc->regs + RTC_ALARM1);
-       val = readl(rtc->regs + RTC_IRQ1_CONF) & RTC_IRQ1_AL_EN;
+       time = rtc->data->read_rtc_reg(rtc, reg);
+       val = rtc->data->read_rtc_reg(rtc, reg_irq) & RTC_IRQ_AL_EN;
 
        spin_unlock_irqrestore(&rtc->lock, flags);
 
@@ -125,9 +267,10 @@ static int armada38x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 static int armada38x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
        struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+       u32 reg = ALARM_REG(RTC_ALARM1, rtc->data->alarm);
+       u32 reg_irq = ALARM_REG(RTC_IRQ1_CONF, rtc->data->alarm);
        unsigned long time, flags;
        int ret = 0;
-       u32 val;
 
        ret = rtc_tm_to_time(&alrm->time, &time);
 
@@ -136,13 +279,11 @@ static int armada38x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 
        spin_lock_irqsave(&rtc->lock, flags);
 
-       rtc_delayed_write(time, rtc, RTC_ALARM1);
+       rtc_delayed_write(time, rtc, reg);
 
        if (alrm->enabled) {
-                       rtc_delayed_write(RTC_IRQ1_AL_EN, rtc, RTC_IRQ1_CONF);
-                       val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT);
-                       writel(val | SOC_RTC_ALARM1_MASK,
-                              rtc->regs_soc + SOC_RTC_INTERRUPT);
+               rtc_delayed_write(RTC_IRQ_AL_EN, rtc, reg_irq);
+               rtc->data->unmask_interrupt(rtc);
        }
 
        spin_unlock_irqrestore(&rtc->lock, flags);
@@ -155,14 +296,15 @@ static int armada38x_rtc_alarm_irq_enable(struct device *dev,
                                         unsigned int enabled)
 {
        struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+       u32 reg_irq = ALARM_REG(RTC_IRQ1_CONF, rtc->data->alarm);
        unsigned long flags;
 
        spin_lock_irqsave(&rtc->lock, flags);
 
        if (enabled)
-               rtc_delayed_write(RTC_IRQ1_AL_EN, rtc, RTC_IRQ1_CONF);
+               rtc_delayed_write(RTC_IRQ_AL_EN, rtc, reg_irq);
        else
-               rtc_delayed_write(0, rtc, RTC_IRQ1_CONF);
+               rtc_delayed_write(0, rtc, reg_irq);
 
        spin_unlock_irqrestore(&rtc->lock, flags);
 
@@ -174,24 +316,23 @@ static irqreturn_t armada38x_rtc_alarm_irq(int irq, void *data)
        struct armada38x_rtc *rtc = data;
        u32 val;
        int event = RTC_IRQF | RTC_AF;
+       u32 reg_irq = ALARM_REG(RTC_IRQ1_CONF, rtc->data->alarm);
 
        dev_dbg(&rtc->rtc_dev->dev, "%s:irq(%d)\n", __func__, irq);
 
        spin_lock(&rtc->lock);
 
-       val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT);
-
-       writel(val & ~SOC_RTC_ALARM1, rtc->regs_soc + SOC_RTC_INTERRUPT);
-       val = readl(rtc->regs + RTC_IRQ1_CONF);
-       /* disable all the interrupts for alarm 1 */
-       rtc_delayed_write(0, rtc, RTC_IRQ1_CONF);
+       rtc->data->clear_isr(rtc);
+       val = rtc->data->read_rtc_reg(rtc, reg_irq);
+       /* disable all the interrupts for alarm*/
+       rtc_delayed_write(0, rtc, reg_irq);
        /* Ack the event */
-       rtc_delayed_write(RTC_STATUS_ALARM1, rtc, RTC_STATUS);
+       rtc_delayed_write(1 << rtc->data->alarm, rtc, RTC_STATUS);
 
        spin_unlock(&rtc->lock);
 
-       if (val & RTC_IRQ1_FREQ_EN) {
-               if (val & RTC_IRQ1_FREQ_1HZ)
+       if (val & RTC_IRQ_FREQ_EN) {
+               if (val & RTC_IRQ_FREQ_1HZ)
                        event |= RTC_UF;
                else
                        event |= RTC_PF;
@@ -202,7 +343,7 @@ static irqreturn_t armada38x_rtc_alarm_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-static struct rtc_class_ops armada38x_rtc_ops = {
+static const struct rtc_class_ops armada38x_rtc_ops = {
        .read_time = armada38x_rtc_read_time,
        .set_time = armada38x_rtc_set_time,
        .read_alarm = armada38x_rtc_read_alarm,
@@ -210,17 +351,65 @@ static struct rtc_class_ops armada38x_rtc_ops = {
        .alarm_irq_enable = armada38x_rtc_alarm_irq_enable,
 };
 
+static const struct rtc_class_ops armada38x_rtc_ops_noirq = {
+       .read_time = armada38x_rtc_read_time,
+       .set_time = armada38x_rtc_set_time,
+       .read_alarm = armada38x_rtc_read_alarm,
+};
+
+static const struct armada38x_rtc_data armada38x_data = {
+       .update_mbus_timing = rtc_update_38x_mbus_timing_params,
+       .read_rtc_reg = read_rtc_register_38x_wa,
+       .clear_isr = armada38x_clear_isr,
+       .unmask_interrupt = armada38x_unmask_interrupt,
+       .alarm = ALARM1,
+};
+
+static const struct armada38x_rtc_data armada8k_data = {
+       .update_mbus_timing = rtc_update_8k_mbus_timing_params,
+       .read_rtc_reg = read_rtc_register,
+       .clear_isr = armada8k_clear_isr,
+       .unmask_interrupt = armada8k_unmask_interrupt,
+       .alarm = ALARM2,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id armada38x_rtc_of_match_table[] = {
+       {
+               .compatible = "marvell,armada-380-rtc",
+               .data = &armada38x_data,
+       },
+       {
+               .compatible = "marvell,armada-8k-rtc",
+               .data = &armada8k_data,
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table);
+#endif
+
 static __init int armada38x_rtc_probe(struct platform_device *pdev)
 {
+       const struct rtc_class_ops *ops;
        struct resource *res;
        struct armada38x_rtc *rtc;
+       const struct of_device_id *match;
        int ret;
 
+       match = of_match_device(armada38x_rtc_of_match_table, &pdev->dev);
+       if (!match)
+               return -ENODEV;
+
        rtc = devm_kzalloc(&pdev->dev, sizeof(struct armada38x_rtc),
                            GFP_KERNEL);
        if (!rtc)
                return -ENOMEM;
 
+       rtc->val_to_freq = devm_kcalloc(&pdev->dev, SAMPLE_NR,
+                               sizeof(struct value_to_freq), GFP_KERNEL);
+       if (!rtc->val_to_freq)
+               return -ENOMEM;
+
        spin_lock_init(&rtc->lock);
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc");
@@ -242,19 +431,27 @@ static __init int armada38x_rtc_probe(struct platform_device *pdev)
                                0, pdev->name, rtc) < 0) {
                dev_warn(&pdev->dev, "Interrupt not available.\n");
                rtc->irq = -1;
+       }
+       platform_set_drvdata(pdev, rtc);
+
+       if (rtc->irq != -1) {
+               device_init_wakeup(&pdev->dev, 1);
+               ops = &armada38x_rtc_ops;
+       } else {
                /*
                 * If there is no interrupt available then we can't
                 * use the alarm
                 */
-               armada38x_rtc_ops.set_alarm = NULL;
-               armada38x_rtc_ops.alarm_irq_enable = NULL;
+               ops = &armada38x_rtc_ops_noirq;
        }
-       platform_set_drvdata(pdev, rtc);
-       if (rtc->irq != -1)
-               device_init_wakeup(&pdev->dev, 1);
+       rtc->data = (struct armada38x_rtc_data *)match->data;
+
+
+       /* Update RTC-MBUS bridge timing parameters */
+       rtc->data->update_mbus_timing(rtc);
 
        rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
-                                       &armada38x_rtc_ops, THIS_MODULE);
+                                               ops, THIS_MODULE);
        if (IS_ERR(rtc->rtc_dev)) {
                ret = PTR_ERR(rtc->rtc_dev);
                dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
@@ -280,6 +477,9 @@ static int armada38x_rtc_resume(struct device *dev)
        if (device_may_wakeup(dev)) {
                struct armada38x_rtc *rtc = dev_get_drvdata(dev);
 
+               /* Update RTC-MBUS bridge timing parameters */
+               rtc->data->update_mbus_timing(rtc);
+
                return disable_irq_wake(rtc->irq);
        }
 
@@ -290,14 +490,6 @@ static int armada38x_rtc_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(armada38x_rtc_pm_ops,
                         armada38x_rtc_suspend, armada38x_rtc_resume);
 
-#ifdef CONFIG_OF
-static const struct of_device_id armada38x_rtc_of_match_table[] = {
-       { .compatible = "marvell,armada-380-rtc", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, armada38x_rtc_of_match_table);
-#endif
-
 static struct platform_driver armada38x_rtc_driver = {
        .driver         = {
                .name   = "armada38x-rtc",
index 84d6e026784daad1d793e6d10ff7da5c0fa239fe..2ba44ccb9c3a3fe00e3e9bf2c740845001011b79 100644 (file)
@@ -56,7 +56,7 @@ static int au1xtoy_rtc_set_time(struct device *dev, struct rtc_time *tm)
        return 0;
 }
 
-static struct rtc_class_ops au1xtoy_rtc_ops = {
+static const struct rtc_class_ops au1xtoy_rtc_ops = {
        .read_time      = au1xtoy_rtc_read_time,
        .set_time       = au1xtoy_rtc_set_time,
 };
index 535a5f9338d026ec8f433fb4960dc7227728ddf6..15344b7c07c599330366def14638236e093dbe6b 100644 (file)
@@ -333,7 +333,7 @@ static int bfin_rtc_proc(struct device *dev, struct seq_file *seq)
 #undef yesno
 }
 
-static struct rtc_class_ops bfin_rtc_ops = {
+static const struct rtc_class_ops bfin_rtc_ops = {
        .read_time     = bfin_rtc_read_time,
        .set_time      = bfin_rtc_set_time,
        .read_alarm    = bfin_rtc_read_alarm,
index 397742446007aa2479969969c60097ad3edb6889..2b223935001fb57e92abdbbd360b02db70ada47c 100644 (file)
@@ -34,6 +34,7 @@
 #define BQ32K_CALIBRATION      0x07    /* CAL_CFG1, calibration and control */
 #define BQ32K_TCH2             0x08    /* Trickle charge enable */
 #define BQ32K_CFG2             0x09    /* Trickle charger control */
+#define BQ32K_TCFE             BIT(6)  /* Trickle charge FET bypass */
 
 struct bq32k_regs {
        uint8_t         seconds;
@@ -188,6 +189,65 @@ static int trickle_charger_of_init(struct device *dev, struct device_node *node)
        return 0;
 }
 
+static ssize_t bq32k_sysfs_show_tricklecharge_bypass(struct device *dev,
+                                              struct device_attribute *attr,
+                                              char *buf)
+{
+       int reg, error;
+
+       error = bq32k_read(dev, &reg, BQ32K_CFG2, 1);
+       if (error)
+               return error;
+
+       return sprintf(buf, "%d\n", (reg & BQ32K_TCFE) ? 1 : 0);
+}
+
+static ssize_t bq32k_sysfs_store_tricklecharge_bypass(struct device *dev,
+                                               struct device_attribute *attr,
+                                               const char *buf, size_t count)
+{
+       int reg, enable, error;
+
+       if (kstrtoint(buf, 0, &enable))
+               return -EINVAL;
+
+       error = bq32k_read(dev, &reg, BQ32K_CFG2, 1);
+       if (error)
+               return error;
+
+       if (enable) {
+               reg |= BQ32K_TCFE;
+               error = bq32k_write(dev, &reg, BQ32K_CFG2, 1);
+               if (error)
+                       return error;
+
+               dev_info(dev, "Enabled trickle charge FET bypass.\n");
+       } else {
+               reg &= ~BQ32K_TCFE;
+               error = bq32k_write(dev, &reg, BQ32K_CFG2, 1);
+               if (error)
+                       return error;
+
+               dev_info(dev, "Disabled trickle charge FET bypass.\n");
+       }
+
+       return count;
+}
+
+static DEVICE_ATTR(trickle_charge_bypass, 0644,
+                  bq32k_sysfs_show_tricklecharge_bypass,
+                  bq32k_sysfs_store_tricklecharge_bypass);
+
+static int bq32k_sysfs_register(struct device *dev)
+{
+       return device_create_file(dev, &dev_attr_trickle_charge_bypass);
+}
+
+static void bq32k_sysfs_unregister(struct device *dev)
+{
+       device_remove_file(dev, &dev_attr_trickle_charge_bypass);
+}
+
 static int bq32k_probe(struct i2c_client *client,
                                const struct i2c_device_id *id)
 {
@@ -224,11 +284,26 @@ static int bq32k_probe(struct i2c_client *client,
        if (IS_ERR(rtc))
                return PTR_ERR(rtc);
 
+       error = bq32k_sysfs_register(&client->dev);
+       if (error) {
+               dev_err(&client->dev,
+                       "Unable to create sysfs entries for rtc bq32000\n");
+               return error;
+       }
+
+
        i2c_set_clientdata(client, rtc);
 
        return 0;
 }
 
+static int bq32k_remove(struct i2c_client *client)
+{
+       bq32k_sysfs_unregister(&client->dev);
+
+       return 0;
+}
+
 static const struct i2c_device_id bq32k_id[] = {
        { "bq32000", 0 },
        { }
@@ -240,6 +315,7 @@ static struct i2c_driver bq32k_driver = {
                .name   = "bq32k",
        },
        .probe          = bq32k_probe,
+       .remove         = bq32k_remove,
        .id_table       = bq32k_id,
 };
 
index 94067f8eeb103c1ff424ab17a69bf3833f02fd18..f225cd873ff6c29be6636b82a6506d77c6088b76 100644 (file)
@@ -116,7 +116,7 @@ static int dm355evm_rtc_set_time(struct device *dev, struct rtc_time *tm)
        return 0;
 }
 
-static struct rtc_class_ops dm355evm_rtc_ops = {
+static const struct rtc_class_ops dm355evm_rtc_ops = {
        .read_time      = dm355evm_rtc_read_time,
        .set_time       = dm355evm_rtc_set_time,
 };
index b1f20d8c358fd5c2a223563c46e302d221e575e9..9bb39a06b994ad5990b47870fe53fdaf7436dd7c 100644 (file)
 #include <linux/slab.h>
 #include <linux/regmap.h>
 
-#define DS3232_REG_SECONDS     0x00
-#define DS3232_REG_MINUTES     0x01
-#define DS3232_REG_HOURS       0x02
-#define DS3232_REG_AMPM                0x02
-#define DS3232_REG_DAY         0x03
-#define DS3232_REG_DATE                0x04
-#define DS3232_REG_MONTH       0x05
-#define DS3232_REG_CENTURY     0x05
-#define DS3232_REG_YEAR                0x06
-#define DS3232_REG_ALARM1         0x07 /* Alarm 1 BASE */
-#define DS3232_REG_ALARM2         0x0B /* Alarm 2 BASE */
-#define DS3232_REG_CR          0x0E    /* Control register */
-#      define DS3232_REG_CR_nEOSC        0x80
-#       define DS3232_REG_CR_INTCN        0x04
-#       define DS3232_REG_CR_A2IE        0x02
-#       define DS3232_REG_CR_A1IE        0x01
-
-#define DS3232_REG_SR  0x0F    /* control/status register */
-#      define DS3232_REG_SR_OSF   0x80
-#       define DS3232_REG_SR_BSY   0x04
-#       define DS3232_REG_SR_A2F   0x02
-#       define DS3232_REG_SR_A1F   0x01
+#define DS3232_REG_SECONDS      0x00
+#define DS3232_REG_MINUTES      0x01
+#define DS3232_REG_HOURS        0x02
+#define DS3232_REG_AMPM         0x02
+#define DS3232_REG_DAY          0x03
+#define DS3232_REG_DATE         0x04
+#define DS3232_REG_MONTH        0x05
+#define DS3232_REG_CENTURY      0x05
+#define DS3232_REG_YEAR         0x06
+#define DS3232_REG_ALARM1       0x07       /* Alarm 1 BASE */
+#define DS3232_REG_ALARM2       0x0B       /* Alarm 2 BASE */
+#define DS3232_REG_CR           0x0E       /* Control register */
+#       define DS3232_REG_CR_nEOSC   0x80
+#       define DS3232_REG_CR_INTCN   0x04
+#       define DS3232_REG_CR_A2IE    0x02
+#       define DS3232_REG_CR_A1IE    0x01
+
+#define DS3232_REG_SR           0x0F       /* control/status register */
+#       define DS3232_REG_SR_OSF     0x80
+#       define DS3232_REG_SR_BSY     0x04
+#       define DS3232_REG_SR_A2F     0x02
+#       define DS3232_REG_SR_A1F     0x01
 
 struct ds3232 {
        struct device *dev;
@@ -363,6 +363,9 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
        if (ret)
                return ret;
 
+       if (ds3232->irq > 0)
+               device_init_wakeup(dev, 1);
+
        ds3232->rtc = devm_rtc_device_register(dev, name, &ds3232_rtc_ops,
                                                THIS_MODULE);
        if (IS_ERR(ds3232->rtc))
@@ -374,10 +377,10 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
                                                IRQF_SHARED | IRQF_ONESHOT,
                                                name, dev);
                if (ret) {
+                       device_set_wakeup_capable(dev, 0);
                        ds3232->irq = 0;
                        dev_err(dev, "unable to request IRQ\n");
-               } else
-                       device_init_wakeup(dev, 1);
+               }
        }
 
        return 0;
@@ -420,6 +423,7 @@ static int ds3232_i2c_probe(struct i2c_client *client,
        static const struct regmap_config config = {
                .reg_bits = 8,
                .val_bits = 8,
+               .max_register = 0x13,
        };
 
        regmap = devm_regmap_init_i2c(client, &config);
@@ -479,6 +483,7 @@ static int ds3234_probe(struct spi_device *spi)
        static const struct regmap_config config = {
                .reg_bits = 8,
                .val_bits = 8,
+               .max_register = 0x13,
                .write_flag_mask = 0x80,
        };
        struct regmap *regmap;
index 688debc143483ff33aef70c08c85656a093b0fc9..ccf0dbadb62d16d7c512fffb9fc37efb7fcac7b8 100644 (file)
@@ -159,9 +159,16 @@ static int gemini_rtc_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id gemini_rtc_dt_match[] = {
+       { .compatible = "cortina,gemini-rtc" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, gemini_rtc_dt_match);
+
 static struct platform_driver gemini_rtc_driver = {
        .driver         = {
                .name   = DRV_NAME,
+               .of_match_table = gemini_rtc_dt_match,
        },
        .probe          = gemini_rtc_probe,
        .remove         = gemini_rtc_remove,
index 67b56b80dc7097049dbf20f0ea8d0e908a231b5f..6b54f6c24c5fb0e3e3cd1972dbaa41a3a5a2ca78 100644 (file)
  * @pdev: pionter to platform dev
  * @rtc: pointer to rtc struct
  * @ioaddr: IO registers pointer
- * @irq: dryice normal interrupt
  * @clk: input reference clock
  * @dsr: copy of the DSR register
  * @irq_lock: interrupt enable register (DIER) lock
@@ -120,7 +119,6 @@ struct imxdi_dev {
        struct platform_device *pdev;
        struct rtc_device *rtc;
        void __iomem *ioaddr;
-       int irq;
        struct clk *clk;
        u32 dsr;
        spinlock_t irq_lock;
@@ -668,7 +666,7 @@ static int dryice_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
        return 0;
 }
 
-static struct rtc_class_ops dryice_rtc_ops = {
+static const struct rtc_class_ops dryice_rtc_ops = {
        .read_time              = dryice_rtc_read_time,
        .set_mmss               = dryice_rtc_set_mmss,
        .alarm_irq_enable       = dryice_rtc_alarm_irq_enable,
@@ -677,9 +675,9 @@ static struct rtc_class_ops dryice_rtc_ops = {
 };
 
 /*
- * dryice "normal" interrupt handler
+ * interrupt handler for dryice "normal" and security violation interrupt
  */
-static irqreturn_t dryice_norm_irq(int irq, void *dev_id)
+static irqreturn_t dryice_irq(int irq, void *dev_id)
 {
        struct imxdi_dev *imxdi = dev_id;
        u32 dsr, dier;
@@ -765,6 +763,7 @@ static int __init dryice_rtc_probe(struct platform_device *pdev)
 {
        struct resource *res;
        struct imxdi_dev *imxdi;
+       int norm_irq, sec_irq;
        int rc;
 
        imxdi = devm_kzalloc(&pdev->dev, sizeof(*imxdi), GFP_KERNEL);
@@ -780,9 +779,16 @@ static int __init dryice_rtc_probe(struct platform_device *pdev)
 
        spin_lock_init(&imxdi->irq_lock);
 
-       imxdi->irq = platform_get_irq(pdev, 0);
-       if (imxdi->irq < 0)
-               return imxdi->irq;
+       norm_irq = platform_get_irq(pdev, 0);
+       if (norm_irq < 0)
+               return norm_irq;
+
+       /* the 2nd irq is the security violation irq
+        * make this optional, don't break the device tree ABI
+        */
+       sec_irq = platform_get_irq(pdev, 1);
+       if (sec_irq <= 0)
+               sec_irq = IRQ_NOTCONNECTED;
 
        init_waitqueue_head(&imxdi->write_wait);
 
@@ -808,13 +814,20 @@ static int __init dryice_rtc_probe(struct platform_device *pdev)
        if (rc != 0)
                goto err;
 
-       rc = devm_request_irq(&pdev->dev, imxdi->irq, dryice_norm_irq,
-                       IRQF_SHARED, pdev->name, imxdi);
+       rc = devm_request_irq(&pdev->dev, norm_irq, dryice_irq,
+                             IRQF_SHARED, pdev->name, imxdi);
        if (rc) {
                dev_warn(&pdev->dev, "interrupt not available.\n");
                goto err;
        }
 
+       rc = devm_request_irq(&pdev->dev, sec_irq, dryice_irq,
+                             IRQF_SHARED, pdev->name, imxdi);
+       if (rc) {
+               dev_warn(&pdev->dev, "security violation interrupt not available.\n");
+               /* this is not an error, see above */
+       }
+
        platform_set_drvdata(pdev, imxdi);
        imxdi->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
                                  &dryice_rtc_ops, THIS_MODULE);
index 22a9ec4f2b836c53585880ec6cd65b222ed522df..e04ca54f21e20791fbf393de0154f4168b3c6026 100644 (file)
@@ -138,7 +138,7 @@ err:
        return ret;
 }
 
-static struct rtc_class_ops  ls1x_rtc_ops = {
+static const struct rtc_class_ops  ls1x_rtc_ops = {
        .read_time      = ls1x_rtc_read_time,
        .set_time       = ls1x_rtc_set_time,
 };
index 0eeb5714c00fa610f7e438ac084ee16e09a89ae3..02af045305dd3ce156a7f60b14cc153e548ce60c 100644 (file)
 #include <linux/module.h>
 #include <linux/rtc.h>
 #include <linux/platform_device.h>
-#include <linux/platform_data/rtc-m48t86.h>
 #include <linux/bcd.h>
+#include <linux/io.h>
 
-#define M48T86_REG_SEC         0x00
-#define M48T86_REG_SECALRM     0x01
-#define M48T86_REG_MIN         0x02
-#define M48T86_REG_MINALRM     0x03
-#define M48T86_REG_HOUR                0x04
-#define M48T86_REG_HOURALRM    0x05
-#define M48T86_REG_DOW         0x06 /* 1 = sunday */
-#define M48T86_REG_DOM         0x07
-#define M48T86_REG_MONTH       0x08 /* 1 - 12 */
-#define M48T86_REG_YEAR                0x09 /* 0 - 99 */
-#define M48T86_REG_A           0x0A
-#define M48T86_REG_B           0x0B
-#define M48T86_REG_C           0x0C
-#define M48T86_REG_D           0x0D
-
-#define M48T86_REG_B_H24       (1 << 1)
-#define M48T86_REG_B_DM                (1 << 2)
-#define M48T86_REG_B_SET       (1 << 7)
-#define M48T86_REG_D_VRT       (1 << 7)
+#define M48T86_SEC             0x00
+#define M48T86_SECALRM         0x01
+#define M48T86_MIN             0x02
+#define M48T86_MINALRM         0x03
+#define M48T86_HOUR            0x04
+#define M48T86_HOURALRM                0x05
+#define M48T86_DOW             0x06 /* 1 = sunday */
+#define M48T86_DOM             0x07
+#define M48T86_MONTH           0x08 /* 1 - 12 */
+#define M48T86_YEAR            0x09 /* 0 - 99 */
+#define M48T86_A               0x0a
+#define M48T86_B               0x0b
+#define M48T86_B_SET           BIT(7)
+#define M48T86_B_DM            BIT(2)
+#define M48T86_B_H24           BIT(1)
+#define M48T86_C               0x0c
+#define M48T86_D               0x0d
+#define M48T86_D_VRT           BIT(7)
+#define M48T86_NVRAM(x)                (0x0e + (x))
+#define M48T86_NVRAM_LEN       114
+
+struct m48t86_rtc_info {
+       void __iomem *index_reg;
+       void __iomem *data_reg;
+       struct rtc_device *rtc;
+};
+
+static unsigned char m48t86_readb(struct device *dev, unsigned long addr)
+{
+       struct m48t86_rtc_info *info = dev_get_drvdata(dev);
+       unsigned char value;
+
+       writeb(addr, info->index_reg);
+       value = readb(info->data_reg);
+
+       return value;
+}
+
+static void m48t86_writeb(struct device *dev,
+                         unsigned char value, unsigned long addr)
+{
+       struct m48t86_rtc_info *info = dev_get_drvdata(dev);
+
+       writeb(addr, info->index_reg);
+       writeb(value, info->data_reg);
+}
 
 static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
        unsigned char reg;
-       struct platform_device *pdev = to_platform_device(dev);
-       struct m48t86_ops *ops = dev_get_platdata(&pdev->dev);
 
-       reg = ops->readbyte(M48T86_REG_B);
+       reg = m48t86_readb(dev, M48T86_B);
 
-       if (reg & M48T86_REG_B_DM) {
+       if (reg & M48T86_B_DM) {
                /* data (binary) mode */
-               tm->tm_sec      = ops->readbyte(M48T86_REG_SEC);
-               tm->tm_min      = ops->readbyte(M48T86_REG_MIN);
-               tm->tm_hour     = ops->readbyte(M48T86_REG_HOUR) & 0x3F;
-               tm->tm_mday     = ops->readbyte(M48T86_REG_DOM);
+               tm->tm_sec      = m48t86_readb(dev, M48T86_SEC);
+               tm->tm_min      = m48t86_readb(dev, M48T86_MIN);
+               tm->tm_hour     = m48t86_readb(dev, M48T86_HOUR) & 0x3f;
+               tm->tm_mday     = m48t86_readb(dev, M48T86_DOM);
                /* tm_mon is 0-11 */
-               tm->tm_mon      = ops->readbyte(M48T86_REG_MONTH) - 1;
-               tm->tm_year     = ops->readbyte(M48T86_REG_YEAR) + 100;
-               tm->tm_wday     = ops->readbyte(M48T86_REG_DOW);
+               tm->tm_mon      = m48t86_readb(dev, M48T86_MONTH) - 1;
+               tm->tm_year     = m48t86_readb(dev, M48T86_YEAR) + 100;
+               tm->tm_wday     = m48t86_readb(dev, M48T86_DOW);
        } else {
                /* bcd mode */
-               tm->tm_sec      = bcd2bin(ops->readbyte(M48T86_REG_SEC));
-               tm->tm_min      = bcd2bin(ops->readbyte(M48T86_REG_MIN));
-               tm->tm_hour     = bcd2bin(ops->readbyte(M48T86_REG_HOUR) & 0x3F);
-               tm->tm_mday     = bcd2bin(ops->readbyte(M48T86_REG_DOM));
+               tm->tm_sec      = bcd2bin(m48t86_readb(dev, M48T86_SEC));
+               tm->tm_min      = bcd2bin(m48t86_readb(dev, M48T86_MIN));
+               tm->tm_hour     = bcd2bin(m48t86_readb(dev, M48T86_HOUR) &
+                                         0x3f);
+               tm->tm_mday     = bcd2bin(m48t86_readb(dev, M48T86_DOM));
                /* tm_mon is 0-11 */
-               tm->tm_mon      = bcd2bin(ops->readbyte(M48T86_REG_MONTH)) - 1;
-               tm->tm_year     = bcd2bin(ops->readbyte(M48T86_REG_YEAR)) + 100;
-               tm->tm_wday     = bcd2bin(ops->readbyte(M48T86_REG_DOW));
+               tm->tm_mon      = bcd2bin(m48t86_readb(dev, M48T86_MONTH)) - 1;
+               tm->tm_year     = bcd2bin(m48t86_readb(dev, M48T86_YEAR)) + 100;
+               tm->tm_wday     = bcd2bin(m48t86_readb(dev, M48T86_DOW));
        }
 
        /* correct the hour if the clock is in 12h mode */
-       if (!(reg & M48T86_REG_B_H24))
-               if (ops->readbyte(M48T86_REG_HOUR) & 0x80)
+       if (!(reg & M48T86_B_H24))
+               if (m48t86_readb(dev, M48T86_HOUR) & 0x80)
                        tm->tm_hour += 12;
 
        return rtc_valid_tm(tm);
@@ -80,38 +106,36 @@ static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm)
 static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
        unsigned char reg;
-       struct platform_device *pdev = to_platform_device(dev);
-       struct m48t86_ops *ops = dev_get_platdata(&pdev->dev);
 
-       reg = ops->readbyte(M48T86_REG_B);
+       reg = m48t86_readb(dev, M48T86_B);
 
        /* update flag and 24h mode */
-       reg |= M48T86_REG_B_SET | M48T86_REG_B_H24;
-       ops->writebyte(reg, M48T86_REG_B);
+       reg |= M48T86_B_SET | M48T86_B_H24;
+       m48t86_writeb(dev, reg, M48T86_B);
 
-       if (reg & M48T86_REG_B_DM) {
+       if (reg & M48T86_B_DM) {
                /* data (binary) mode */
-               ops->writebyte(tm->tm_sec, M48T86_REG_SEC);
-               ops->writebyte(tm->tm_min, M48T86_REG_MIN);
-               ops->writebyte(tm->tm_hour, M48T86_REG_HOUR);
-               ops->writebyte(tm->tm_mday, M48T86_REG_DOM);
-               ops->writebyte(tm->tm_mon + 1, M48T86_REG_MONTH);
-               ops->writebyte(tm->tm_year % 100, M48T86_REG_YEAR);
-               ops->writebyte(tm->tm_wday, M48T86_REG_DOW);
+               m48t86_writeb(dev, tm->tm_sec, M48T86_SEC);
+               m48t86_writeb(dev, tm->tm_min, M48T86_MIN);
+               m48t86_writeb(dev, tm->tm_hour, M48T86_HOUR);
+               m48t86_writeb(dev, tm->tm_mday, M48T86_DOM);
+               m48t86_writeb(dev, tm->tm_mon + 1, M48T86_MONTH);
+               m48t86_writeb(dev, tm->tm_year % 100, M48T86_YEAR);
+               m48t86_writeb(dev, tm->tm_wday, M48T86_DOW);
        } else {
                /* bcd mode */
-               ops->writebyte(bin2bcd(tm->tm_sec), M48T86_REG_SEC);
-               ops->writebyte(bin2bcd(tm->tm_min), M48T86_REG_MIN);
-               ops->writebyte(bin2bcd(tm->tm_hour), M48T86_REG_HOUR);
-               ops->writebyte(bin2bcd(tm->tm_mday), M48T86_REG_DOM);
-               ops->writebyte(bin2bcd(tm->tm_mon + 1), M48T86_REG_MONTH);
-               ops->writebyte(bin2bcd(tm->tm_year % 100), M48T86_REG_YEAR);
-               ops->writebyte(bin2bcd(tm->tm_wday), M48T86_REG_DOW);
+               m48t86_writeb(dev, bin2bcd(tm->tm_sec), M48T86_SEC);
+               m48t86_writeb(dev, bin2bcd(tm->tm_min), M48T86_MIN);
+               m48t86_writeb(dev, bin2bcd(tm->tm_hour), M48T86_HOUR);
+               m48t86_writeb(dev, bin2bcd(tm->tm_mday), M48T86_DOM);
+               m48t86_writeb(dev, bin2bcd(tm->tm_mon + 1), M48T86_MONTH);
+               m48t86_writeb(dev, bin2bcd(tm->tm_year % 100), M48T86_YEAR);
+               m48t86_writeb(dev, bin2bcd(tm->tm_wday), M48T86_DOW);
        }
 
        /* update ended */
-       reg &= ~M48T86_REG_B_SET;
-       ops->writebyte(reg, M48T86_REG_B);
+       reg &= ~M48T86_B_SET;
+       m48t86_writeb(dev, reg, M48T86_B);
 
        return 0;
 }
@@ -119,18 +143,16 @@ static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm)
 static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq)
 {
        unsigned char reg;
-       struct platform_device *pdev = to_platform_device(dev);
-       struct m48t86_ops *ops = dev_get_platdata(&pdev->dev);
 
-       reg = ops->readbyte(M48T86_REG_B);
+       reg = m48t86_readb(dev, M48T86_B);
 
        seq_printf(seq, "mode\t\t: %s\n",
-                (reg & M48T86_REG_B_DM) ? "binary" : "bcd");
+                  (reg & M48T86_B_DM) ? "binary" : "bcd");
 
-       reg = ops->readbyte(M48T86_REG_D);
+       reg = m48t86_readb(dev, M48T86_D);
 
        seq_printf(seq, "battery\t\t: %s\n",
-                (reg & M48T86_REG_D_VRT) ? "ok" : "exhausted");
+                  (reg & M48T86_D_VRT) ? "ok" : "exhausted");
 
        return 0;
 }
@@ -141,25 +163,116 @@ static const struct rtc_class_ops m48t86_rtc_ops = {
        .proc           = m48t86_rtc_proc,
 };
 
-static int m48t86_rtc_probe(struct platform_device *dev)
+static ssize_t m48t86_nvram_read(struct file *filp, struct kobject *kobj,
+                                struct bin_attribute *attr,
+                                char *buf, loff_t off, size_t count)
+{
+       struct device *dev = kobj_to_dev(kobj);
+       unsigned int i;
+
+       for (i = 0; i < count; i++)
+               buf[i] = m48t86_readb(dev, M48T86_NVRAM(off + i));
+
+       return count;
+}
+
+static ssize_t m48t86_nvram_write(struct file *filp, struct kobject *kobj,
+                                 struct bin_attribute *attr,
+                                 char *buf, loff_t off, size_t count)
 {
+       struct device *dev = kobj_to_dev(kobj);
+       unsigned int i;
+
+       for (i = 0; i < count; i++)
+               m48t86_writeb(dev, buf[i], M48T86_NVRAM(off + i));
+
+       return count;
+}
+
+static BIN_ATTR(nvram, 0644, m48t86_nvram_read, m48t86_nvram_write,
+               M48T86_NVRAM_LEN);
+
+/*
+ * The RTC is an optional feature at purchase time on some Technologic Systems
+ * boards. Verify that it actually exists by checking if the last two bytes
+ * of the NVRAM can be changed.
+ *
+ * This is based on the method used in their rtc7800.c example.
+ */
+static bool m48t86_verify_chip(struct platform_device *pdev)
+{
+       unsigned int offset0 = M48T86_NVRAM(M48T86_NVRAM_LEN - 2);
+       unsigned int offset1 = M48T86_NVRAM(M48T86_NVRAM_LEN - 1);
+       unsigned char tmp0, tmp1;
+
+       tmp0 = m48t86_readb(&pdev->dev, offset0);
+       tmp1 = m48t86_readb(&pdev->dev, offset1);
+
+       m48t86_writeb(&pdev->dev, 0x00, offset0);
+       m48t86_writeb(&pdev->dev, 0x55, offset1);
+       if (m48t86_readb(&pdev->dev, offset1) == 0x55) {
+               m48t86_writeb(&pdev->dev, 0xaa, offset1);
+               if (m48t86_readb(&pdev->dev, offset1) == 0xaa &&
+                   m48t86_readb(&pdev->dev, offset0) == 0x00) {
+                       m48t86_writeb(&pdev->dev, tmp0, offset0);
+                       m48t86_writeb(&pdev->dev, tmp1, offset1);
+
+                       return true;
+               }
+       }
+       return false;
+}
+
+static int m48t86_rtc_probe(struct platform_device *pdev)
+{
+       struct m48t86_rtc_info *info;
+       struct resource *res;
        unsigned char reg;
-       struct m48t86_ops *ops = dev_get_platdata(&dev->dev);
-       struct rtc_device *rtc;
 
-       rtc = devm_rtc_device_register(&dev->dev, "m48t86",
-                               &m48t86_rtc_ops, THIS_MODULE);
+       info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+       info->index_reg = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(info->index_reg))
+               return PTR_ERR(info->index_reg);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+       if (!res)
+               return -ENODEV;
+       info->data_reg = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(info->data_reg))
+               return PTR_ERR(info->data_reg);
 
-       if (IS_ERR(rtc))
-               return PTR_ERR(rtc);
+       dev_set_drvdata(&pdev->dev, info);
+
+       if (!m48t86_verify_chip(pdev)) {
+               dev_info(&pdev->dev, "RTC not present\n");
+               return -ENODEV;
+       }
 
-       platform_set_drvdata(dev, rtc);
+       info->rtc = devm_rtc_device_register(&pdev->dev, "m48t86",
+                                            &m48t86_rtc_ops, THIS_MODULE);
+       if (IS_ERR(info->rtc))
+               return PTR_ERR(info->rtc);
 
        /* read battery status */
-       reg = ops->readbyte(M48T86_REG_D);
-       dev_info(&dev->dev, "battery %s\n",
-               (reg & M48T86_REG_D_VRT) ? "ok" : "exhausted");
+       reg = m48t86_readb(&pdev->dev, M48T86_D);
+       dev_info(&pdev->dev, "battery %s\n",
+                (reg & M48T86_D_VRT) ? "ok" : "exhausted");
 
+       if (device_create_bin_file(&pdev->dev, &bin_attr_nvram))
+               dev_err(&pdev->dev, "failed to create nvram sysfs entry\n");
+
+       return 0;
+}
+
+static int m48t86_rtc_remove(struct platform_device *pdev)
+{
+       device_remove_bin_file(&pdev->dev, &bin_attr_nvram);
        return 0;
 }
 
@@ -168,6 +281,7 @@ static struct platform_driver m48t86_rtc_platform_driver = {
                .name   = "rtc-m48t86",
        },
        .probe          = m48t86_rtc_probe,
+       .remove         = m48t86_rtc_remove,
 };
 
 module_platform_driver(m48t86_rtc_platform_driver);
index ce75e421ba001fce02c7f7afce57c310af012001..77f21331ae21c5f098cb7d3f307c294f1a62e889 100644 (file)
 #define MCP795_REG_DAY         0x04
 #define MCP795_REG_MONTH       0x06
 #define MCP795_REG_CONTROL     0x08
+#define MCP795_REG_ALM0_SECONDS        0x0C
+#define MCP795_REG_ALM0_DAY    0x0F
 
 #define MCP795_ST_BIT          BIT(7)
 #define MCP795_24_BIT          BIT(6)
 #define MCP795_LP_BIT          BIT(5)
 #define MCP795_EXTOSC_BIT      BIT(3)
 #define MCP795_OSCON_BIT       BIT(5)
+#define MCP795_ALM0_BIT                BIT(4)
+#define MCP795_ALM1_BIT                BIT(5)
+#define MCP795_ALM0IF_BIT      BIT(3)
+#define MCP795_ALM0C0_BIT      BIT(4)
+#define MCP795_ALM0C1_BIT      BIT(5)
+#define MCP795_ALM0C2_BIT      BIT(6)
+
+#define SEC_PER_DAY            (24 * 60 * 60)
 
 static int mcp795_rtcc_read(struct device *dev, u8 addr, u8 *buf, u8 count)
 {
@@ -150,6 +160,30 @@ static int mcp795_start_oscillator(struct device *dev, bool *extosc)
                        dev, MCP795_REG_SECONDS, MCP795_ST_BIT, MCP795_ST_BIT);
 }
 
+/* Enable or disable Alarm 0 in RTC */
+static int mcp795_update_alarm(struct device *dev, bool enable)
+{
+       int ret;
+
+       dev_dbg(dev, "%s alarm\n", enable ? "Enable" : "Disable");
+
+       if (enable) {
+               /* clear ALM0IF (Alarm 0 Interrupt Flag) bit */
+               ret = mcp795_rtcc_set_bits(dev, MCP795_REG_ALM0_DAY,
+                                       MCP795_ALM0IF_BIT, 0);
+               if (ret)
+                       return ret;
+               /* enable alarm 0 */
+               ret = mcp795_rtcc_set_bits(dev, MCP795_REG_CONTROL,
+                                       MCP795_ALM0_BIT, MCP795_ALM0_BIT);
+       } else {
+               /* disable alarm 0 and alarm 1 */
+               ret = mcp795_rtcc_set_bits(dev, MCP795_REG_CONTROL,
+                                       MCP795_ALM0_BIT | MCP795_ALM1_BIT, 0);
+       }
+       return ret;
+}
+
 static int mcp795_set_time(struct device *dev, struct rtc_time *tim)
 {
        int ret;
@@ -170,6 +204,7 @@ static int mcp795_set_time(struct device *dev, struct rtc_time *tim)
        data[0] = (data[0] & 0x80) | bin2bcd(tim->tm_sec);
        data[1] = (data[1] & 0x80) | bin2bcd(tim->tm_min);
        data[2] = bin2bcd(tim->tm_hour);
+       data[3] = (data[3] & 0xF8) | bin2bcd(tim->tm_wday + 1);
        data[4] = bin2bcd(tim->tm_mday);
        data[5] = (data[5] & MCP795_LP_BIT) | bin2bcd(tim->tm_mon + 1);
 
@@ -198,9 +233,9 @@ static int mcp795_set_time(struct device *dev, struct rtc_time *tim)
        if (ret)
                return ret;
 
-       dev_dbg(dev, "Set mcp795: %04d-%02d-%02d %02d:%02d:%02d\n",
+       dev_dbg(dev, "Set mcp795: %04d-%02d-%02d(%d) %02d:%02d:%02d\n",
                        tim->tm_year + 1900, tim->tm_mon, tim->tm_mday,
-                       tim->tm_hour, tim->tm_min, tim->tm_sec);
+                       tim->tm_wday, tim->tm_hour, tim->tm_min, tim->tm_sec);
 
        return 0;
 }
@@ -218,20 +253,139 @@ static int mcp795_read_time(struct device *dev, struct rtc_time *tim)
        tim->tm_sec     = bcd2bin(data[0] & 0x7F);
        tim->tm_min     = bcd2bin(data[1] & 0x7F);
        tim->tm_hour    = bcd2bin(data[2] & 0x3F);
+       tim->tm_wday    = bcd2bin(data[3] & 0x07) - 1;
        tim->tm_mday    = bcd2bin(data[4] & 0x3F);
        tim->tm_mon     = bcd2bin(data[5] & 0x1F) - 1;
        tim->tm_year    = bcd2bin(data[6]) + 100; /* Assume we are in 20xx */
 
-       dev_dbg(dev, "Read from mcp795: %04d-%02d-%02d %02d:%02d:%02d\n",
-                               tim->tm_year + 1900, tim->tm_mon, tim->tm_mday,
-                               tim->tm_hour, tim->tm_min, tim->tm_sec);
+       dev_dbg(dev, "Read from mcp795: %04d-%02d-%02d(%d) %02d:%02d:%02d\n",
+                       tim->tm_year + 1900, tim->tm_mon, tim->tm_mday,
+                       tim->tm_wday, tim->tm_hour, tim->tm_min, tim->tm_sec);
 
        return rtc_valid_tm(tim);
 }
 
+static int mcp795_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+       struct rtc_time now_tm;
+       time64_t now;
+       time64_t later;
+       u8 tmp[6];
+       int ret;
+
+       /* Read current time from RTC hardware */
+       ret = mcp795_read_time(dev, &now_tm);
+       if (ret)
+               return ret;
+       /* Get the number of seconds since 1970 */
+       now = rtc_tm_to_time64(&now_tm);
+       later = rtc_tm_to_time64(&alm->time);
+       if (later <= now)
+               return -EINVAL;
+       /* make sure alarm fires within the next one year */
+       if ((later - now) >=
+               (SEC_PER_DAY * (365 + is_leap_year(alm->time.tm_year))))
+               return -EDOM;
+       /* disable alarm */
+       ret = mcp795_update_alarm(dev, false);
+       if (ret)
+               return ret;
+       /* Read registers, so we can leave configuration bits untouched */
+       ret = mcp795_rtcc_read(dev, MCP795_REG_ALM0_SECONDS, tmp, sizeof(tmp));
+       if (ret)
+               return ret;
+
+       alm->time.tm_year       = -1;
+       alm->time.tm_isdst      = -1;
+       alm->time.tm_yday       = -1;
+
+       tmp[0] = (tmp[0] & 0x80) | bin2bcd(alm->time.tm_sec);
+       tmp[1] = (tmp[1] & 0x80) | bin2bcd(alm->time.tm_min);
+       tmp[2] = (tmp[2] & 0xE0) | bin2bcd(alm->time.tm_hour);
+       tmp[3] = (tmp[3] & 0x80) | bin2bcd(alm->time.tm_wday + 1);
+       /* set alarm match: seconds, minutes, hour, day, date and month */
+       tmp[3] |= (MCP795_ALM0C2_BIT | MCP795_ALM0C1_BIT | MCP795_ALM0C0_BIT);
+       tmp[4] = (tmp[4] & 0xC0) | bin2bcd(alm->time.tm_mday);
+       tmp[5] = (tmp[5] & 0xE0) | bin2bcd(alm->time.tm_mon + 1);
+
+       ret = mcp795_rtcc_write(dev, MCP795_REG_ALM0_SECONDS, tmp, sizeof(tmp));
+       if (ret)
+               return ret;
+
+       /* enable alarm if requested */
+       if (alm->enabled) {
+               ret = mcp795_update_alarm(dev, true);
+               if (ret)
+                       return ret;
+               dev_dbg(dev, "Alarm IRQ armed\n");
+       }
+       dev_dbg(dev, "Set alarm: %02d-%02d(%d) %02d:%02d:%02d\n",
+                       alm->time.tm_mon, alm->time.tm_mday, alm->time.tm_wday,
+                       alm->time.tm_hour, alm->time.tm_min, alm->time.tm_sec);
+       return 0;
+}
+
+static int mcp795_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+       u8 data[6];
+       int ret;
+
+       ret = mcp795_rtcc_read(
+                       dev, MCP795_REG_ALM0_SECONDS, data, sizeof(data));
+       if (ret)
+               return ret;
+
+       alm->time.tm_sec        = bcd2bin(data[0] & 0x7F);
+       alm->time.tm_min        = bcd2bin(data[1] & 0x7F);
+       alm->time.tm_hour       = bcd2bin(data[2] & 0x1F);
+       alm->time.tm_wday       = bcd2bin(data[3] & 0x07) - 1;
+       alm->time.tm_mday       = bcd2bin(data[4] & 0x3F);
+       alm->time.tm_mon        = bcd2bin(data[5] & 0x1F) - 1;
+       alm->time.tm_year       = -1;
+       alm->time.tm_isdst      = -1;
+       alm->time.tm_yday       = -1;
+
+       dev_dbg(dev, "Read alarm: %02d-%02d(%d) %02d:%02d:%02d\n",
+                       alm->time.tm_mon, alm->time.tm_mday, alm->time.tm_wday,
+                       alm->time.tm_hour, alm->time.tm_min, alm->time.tm_sec);
+       return 0;
+}
+
+static int mcp795_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       return mcp795_update_alarm(dev, !!enabled);
+}
+
+static irqreturn_t mcp795_irq(int irq, void *data)
+{
+       struct spi_device *spi = data;
+       struct rtc_device *rtc = spi_get_drvdata(spi);
+       struct mutex *lock = &rtc->ops_lock;
+       int ret;
+
+       mutex_lock(lock);
+
+       /* Disable alarm.
+        * There is no need to clear ALM0IF (Alarm 0 Interrupt Flag) bit,
+        * because it is done every time when alarm is enabled.
+        */
+       ret = mcp795_update_alarm(&spi->dev, false);
+       if (ret)
+               dev_err(&spi->dev,
+                       "Failed to disable alarm in IRQ (ret=%d)\n", ret);
+       rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF);
+
+       mutex_unlock(lock);
+
+       return IRQ_HANDLED;
+}
+
 static const struct rtc_class_ops mcp795_rtc_ops = {
                .read_time = mcp795_read_time,
-               .set_time = mcp795_set_time
+               .set_time = mcp795_set_time,
+               .read_alarm = mcp795_read_alarm,
+               .set_alarm = mcp795_set_alarm,
+               .alarm_irq_enable = mcp795_alarm_irq_enable
 };
 
 static int mcp795_probe(struct spi_device *spi)
@@ -259,6 +413,23 @@ static int mcp795_probe(struct spi_device *spi)
 
        spi_set_drvdata(spi, rtc);
 
+       if (spi->irq > 0) {
+               dev_dbg(&spi->dev, "Alarm support enabled\n");
+
+               /* Clear any pending alarm (ALM0IF bit) before requesting
+                * the interrupt.
+                */
+               mcp795_rtcc_set_bits(&spi->dev, MCP795_REG_ALM0_DAY,
+                                       MCP795_ALM0IF_BIT, 0);
+               ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
+                               mcp795_irq, IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+                               dev_name(&rtc->dev), spi);
+               if (ret)
+                       dev_err(&spi->dev, "Failed to request IRQ: %d: %d\n",
+                                               spi->irq, ret);
+               else
+                       device_init_wakeup(&spi->dev, true);
+       }
        return 0;
 }
 
index 359876a88ac860c06304bc9738f42f1ce406c044..77319122642ab51c491655ef5ffc94a9fc8c7745 100644 (file)
@@ -353,7 +353,7 @@ static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 }
 
 /* RTC layer */
-static struct rtc_class_ops mxc_rtc_ops = {
+static const struct rtc_class_ops mxc_rtc_ops = {
        .release                = mxc_rtc_release,
        .read_time              = mxc_rtc_read_time,
        .set_mmss64             = mxc_rtc_set_mmss,
index 2bfdf638b67390661f10e1405eea44d544eda6ad..f33447c5db85e395ac540f43c1bf7ec69f48efcf 100644 (file)
@@ -52,9 +52,20 @@ static int pcf2127_rtc_read_time(struct device *dev, struct rtc_time *tm)
        struct pcf2127 *pcf2127 = dev_get_drvdata(dev);
        unsigned char buf[10];
        int ret;
+       int i;
 
-       ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_CTRL1, buf,
-                               sizeof(buf));
+       for (i = 0; i <= PCF2127_REG_CTRL3; i++) {
+               ret = regmap_read(pcf2127->regmap, PCF2127_REG_CTRL1 + i,
+                                 (unsigned int *)(buf + i));
+               if (ret) {
+                       dev_err(dev, "%s: read error\n", __func__);
+                       return ret;
+               }
+       }
+
+       ret = regmap_bulk_read(pcf2127->regmap, PCF2127_REG_SC,
+                              (buf + PCF2127_REG_SC),
+                              ARRAY_SIZE(buf) - PCF2127_REG_SC);
        if (ret) {
                dev_err(dev, "%s: read error\n", __func__);
                return ret;
index 7163b91bb773bd3a8ef0a3be75d9936ffc116f9b..d08da371912cd868e496cbfd417d59067d04ce3a 100644 (file)
@@ -63,7 +63,6 @@ struct rx8010_data {
        struct i2c_client *client;
        struct rtc_device *rtc;
        u8 ctrlreg;
-       spinlock_t flags_lock;
 };
 
 static irqreturn_t rx8010_irq_1_handler(int irq, void *dev_id)
@@ -72,12 +71,12 @@ static irqreturn_t rx8010_irq_1_handler(int irq, void *dev_id)
        struct rx8010_data *rx8010 = i2c_get_clientdata(client);
        int flagreg;
 
-       spin_lock(&rx8010->flags_lock);
+       mutex_lock(&rx8010->rtc->ops_lock);
 
        flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG);
 
        if (flagreg <= 0) {
-               spin_unlock(&rx8010->flags_lock);
+               mutex_unlock(&rx8010->rtc->ops_lock);
                return IRQ_NONE;
        }
 
@@ -101,7 +100,7 @@ static irqreturn_t rx8010_irq_1_handler(int irq, void *dev_id)
 
        i2c_smbus_write_byte_data(client, RX8010_FLAG, flagreg);
 
-       spin_unlock(&rx8010->flags_lock);
+       mutex_unlock(&rx8010->rtc->ops_lock);
        return IRQ_HANDLED;
 }
 
@@ -143,7 +142,6 @@ static int rx8010_set_time(struct device *dev, struct rtc_time *dt)
        u8 date[7];
        int ctrl, flagreg;
        int ret;
-       unsigned long irqflags;
 
        if ((dt->tm_year < 100) || (dt->tm_year > 199))
                return -EINVAL;
@@ -181,11 +179,8 @@ static int rx8010_set_time(struct device *dev, struct rtc_time *dt)
        if (ret < 0)
                return ret;
 
-       spin_lock_irqsave(&rx8010->flags_lock, irqflags);
-
        flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG);
        if (flagreg < 0) {
-               spin_unlock_irqrestore(&rx8010->flags_lock, irqflags);
                return flagreg;
        }
 
@@ -193,8 +188,6 @@ static int rx8010_set_time(struct device *dev, struct rtc_time *dt)
                ret = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG,
                                                flagreg & ~RX8010_FLAG_VLF);
 
-       spin_unlock_irqrestore(&rx8010->flags_lock, irqflags);
-
        return 0;
 }
 
@@ -288,12 +281,9 @@ static int rx8010_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        u8 alarmvals[3];
        int extreg, flagreg;
        int err;
-       unsigned long irqflags;
 
-       spin_lock_irqsave(&rx8010->flags_lock, irqflags);
        flagreg = i2c_smbus_read_byte_data(client, RX8010_FLAG);
        if (flagreg < 0) {
-               spin_unlock_irqrestore(&rx8010->flags_lock, irqflags);
                return flagreg;
        }
 
@@ -302,14 +292,12 @@ static int rx8010_set_alarm(struct device *dev, struct rtc_wkalrm *t)
                err = i2c_smbus_write_byte_data(rx8010->client, RX8010_CTRL,
                                                rx8010->ctrlreg);
                if (err < 0) {
-                       spin_unlock_irqrestore(&rx8010->flags_lock, irqflags);
                        return err;
                }
        }
 
        flagreg &= ~RX8010_FLAG_AF;
        err = i2c_smbus_write_byte_data(rx8010->client, RX8010_FLAG, flagreg);
-       spin_unlock_irqrestore(&rx8010->flags_lock, irqflags);
        if (err < 0)
                return err;
 
@@ -404,7 +392,6 @@ static int rx8010_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
        struct rx8010_data *rx8010 = dev_get_drvdata(dev);
        int ret, tmp;
        int flagreg;
-       unsigned long irqflags;
 
        switch (cmd) {
        case RTC_VL_READ:
@@ -419,16 +406,13 @@ static int rx8010_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
                return 0;
 
        case RTC_VL_CLR:
-               spin_lock_irqsave(&rx8010->flags_lock, irqflags);
                flagreg = i2c_smbus_read_byte_data(rx8010->client, RX8010_FLAG);
                if (flagreg < 0) {
-                       spin_unlock_irqrestore(&rx8010->flags_lock, irqflags);
                        return flagreg;
                }
 
                flagreg &= ~RX8010_FLAG_VLF;
                ret = i2c_smbus_write_byte_data(client, RX8010_FLAG, flagreg);
-               spin_unlock_irqrestore(&rx8010->flags_lock, irqflags);
                if (ret < 0)
                        return ret;
 
@@ -466,8 +450,6 @@ static int rx8010_probe(struct i2c_client *client,
        rx8010->client = client;
        i2c_set_clientdata(client, rx8010);
 
-       spin_lock_init(&rx8010->flags_lock);
-
        err = rx8010_init_client(client);
        if (err)
                return err;
index 17b6235d67a588e9dff65f1c4689c923d939d8ff..c626e43a9cbb48f6c254517dc858dd1451c550d3 100644 (file)
@@ -535,7 +535,7 @@ static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
        return 0;
 }
 
-static struct rtc_class_ops sh_rtc_ops = {
+static const struct rtc_class_ops sh_rtc_ops = {
        .read_time      = sh_rtc_read_time,
        .set_time       = sh_rtc_set_time,
        .read_alarm     = sh_rtc_read_alarm,
index 0f11c2a228e35a02033e1b64dcddc6f5599927cd..d51b07d620f7bd6fadbbf66f666870d8e50516f0 100644 (file)
@@ -184,6 +184,7 @@ static int snvs_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
        rtc_tm_to_time(alrm_tm, &time);
 
        regmap_update_bits(data->regmap, data->offset + SNVS_LPCR, SNVS_LPCR_LPTA_EN, 0);
+       rtc_write_sync_lp(data);
        regmap_write(data->regmap, data->offset + SNVS_LPTAR, time);
 
        /* Clear alarm interrupt status bit */
diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c
new file mode 100644 (file)
index 0000000..bd57eb1
--- /dev/null
@@ -0,0 +1,725 @@
+/*
+ * Copyright (C) Amelie Delaunay 2016
+ * Author:  Amelie Delaunay <amelie.delaunay@st.com>
+ * License terms:  GNU General Public License (GPL), version 2
+ */
+
+#include <linux/bcd.h>
+#include <linux/clk.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+
+#define DRIVER_NAME "stm32_rtc"
+
+/* STM32 RTC registers */
+#define STM32_RTC_TR           0x00
+#define STM32_RTC_DR           0x04
+#define STM32_RTC_CR           0x08
+#define STM32_RTC_ISR          0x0C
+#define STM32_RTC_PRER         0x10
+#define STM32_RTC_ALRMAR       0x1C
+#define STM32_RTC_WPR          0x24
+
+/* STM32_RTC_TR bit fields  */
+#define STM32_RTC_TR_SEC_SHIFT         0
+#define STM32_RTC_TR_SEC               GENMASK(6, 0)
+#define STM32_RTC_TR_MIN_SHIFT         8
+#define STM32_RTC_TR_MIN               GENMASK(14, 8)
+#define STM32_RTC_TR_HOUR_SHIFT                16
+#define STM32_RTC_TR_HOUR              GENMASK(21, 16)
+
+/* STM32_RTC_DR bit fields */
+#define STM32_RTC_DR_DATE_SHIFT                0
+#define STM32_RTC_DR_DATE              GENMASK(5, 0)
+#define STM32_RTC_DR_MONTH_SHIFT       8
+#define STM32_RTC_DR_MONTH             GENMASK(12, 8)
+#define STM32_RTC_DR_WDAY_SHIFT                13
+#define STM32_RTC_DR_WDAY              GENMASK(15, 13)
+#define STM32_RTC_DR_YEAR_SHIFT                16
+#define STM32_RTC_DR_YEAR              GENMASK(23, 16)
+
+/* STM32_RTC_CR bit fields */
+#define STM32_RTC_CR_FMT               BIT(6)
+#define STM32_RTC_CR_ALRAE             BIT(8)
+#define STM32_RTC_CR_ALRAIE            BIT(12)
+
+/* STM32_RTC_ISR bit fields */
+#define STM32_RTC_ISR_ALRAWF           BIT(0)
+#define STM32_RTC_ISR_INITS            BIT(4)
+#define STM32_RTC_ISR_RSF              BIT(5)
+#define STM32_RTC_ISR_INITF            BIT(6)
+#define STM32_RTC_ISR_INIT             BIT(7)
+#define STM32_RTC_ISR_ALRAF            BIT(8)
+
+/* STM32_RTC_PRER bit fields */
+#define STM32_RTC_PRER_PRED_S_SHIFT    0
+#define STM32_RTC_PRER_PRED_S          GENMASK(14, 0)
+#define STM32_RTC_PRER_PRED_A_SHIFT    16
+#define STM32_RTC_PRER_PRED_A          GENMASK(22, 16)
+
+/* STM32_RTC_ALRMAR and STM32_RTC_ALRMBR bit fields */
+#define STM32_RTC_ALRMXR_SEC_SHIFT     0
+#define STM32_RTC_ALRMXR_SEC           GENMASK(6, 0)
+#define STM32_RTC_ALRMXR_SEC_MASK      BIT(7)
+#define STM32_RTC_ALRMXR_MIN_SHIFT     8
+#define STM32_RTC_ALRMXR_MIN           GENMASK(14, 8)
+#define STM32_RTC_ALRMXR_MIN_MASK      BIT(15)
+#define STM32_RTC_ALRMXR_HOUR_SHIFT    16
+#define STM32_RTC_ALRMXR_HOUR          GENMASK(21, 16)
+#define STM32_RTC_ALRMXR_PM            BIT(22)
+#define STM32_RTC_ALRMXR_HOUR_MASK     BIT(23)
+#define STM32_RTC_ALRMXR_DATE_SHIFT    24
+#define STM32_RTC_ALRMXR_DATE          GENMASK(29, 24)
+#define STM32_RTC_ALRMXR_WDSEL         BIT(30)
+#define STM32_RTC_ALRMXR_WDAY_SHIFT    24
+#define STM32_RTC_ALRMXR_WDAY          GENMASK(27, 24)
+#define STM32_RTC_ALRMXR_DATE_MASK     BIT(31)
+
+/* STM32_RTC_WPR key constants */
+#define RTC_WPR_1ST_KEY                        0xCA
+#define RTC_WPR_2ND_KEY                        0x53
+#define RTC_WPR_WRONG_KEY              0xFF
+
+/*
+ * RTC registers are protected against parasitic write access.
+ * PWR_CR_DBP bit must be set to enable write access to RTC registers.
+ */
+/* STM32_PWR_CR */
+#define PWR_CR                         0x00
+/* STM32_PWR_CR bit field */
+#define PWR_CR_DBP                     BIT(8)
+
+struct stm32_rtc {
+       struct rtc_device *rtc_dev;
+       void __iomem *base;
+       struct regmap *dbp;
+       struct clk *ck_rtc;
+       int irq_alarm;
+};
+
+static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)
+{
+       writel_relaxed(RTC_WPR_1ST_KEY, rtc->base + STM32_RTC_WPR);
+       writel_relaxed(RTC_WPR_2ND_KEY, rtc->base + STM32_RTC_WPR);
+}
+
+static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc)
+{
+       writel_relaxed(RTC_WPR_WRONG_KEY, rtc->base + STM32_RTC_WPR);
+}
+
+static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
+{
+       unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+
+       if (!(isr & STM32_RTC_ISR_INITF)) {
+               isr |= STM32_RTC_ISR_INIT;
+               writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
+
+               /*
+                * It takes around 2 ck_rtc clock cycles to enter in
+                * initialization phase mode (and have INITF flag set). As
+                * slowest ck_rtc frequency may be 32kHz and highest should be
+                * 1MHz, we poll every 10 us with a timeout of 100ms.
+                */
+               return readl_relaxed_poll_timeout_atomic(
+                                       rtc->base + STM32_RTC_ISR,
+                                       isr, (isr & STM32_RTC_ISR_INITF),
+                                       10, 100000);
+       }
+
+       return 0;
+}
+
+static void stm32_rtc_exit_init_mode(struct stm32_rtc *rtc)
+{
+       unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+
+       isr &= ~STM32_RTC_ISR_INIT;
+       writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
+}
+
+static int stm32_rtc_wait_sync(struct stm32_rtc *rtc)
+{
+       unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+
+       isr &= ~STM32_RTC_ISR_RSF;
+       writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
+
+       /*
+        * Wait for RSF to be set to ensure the calendar registers are
+        * synchronised, it takes around 2 ck_rtc clock cycles
+        */
+       return readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
+                                                isr,
+                                                (isr & STM32_RTC_ISR_RSF),
+                                                10, 100000);
+}
+
+static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
+{
+       struct stm32_rtc *rtc = (struct stm32_rtc *)dev_id;
+       unsigned int isr, cr;
+
+       mutex_lock(&rtc->rtc_dev->ops_lock);
+
+       isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+       cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+
+       if ((isr & STM32_RTC_ISR_ALRAF) &&
+           (cr & STM32_RTC_CR_ALRAIE)) {
+               /* Alarm A flag - Alarm interrupt */
+               dev_dbg(&rtc->rtc_dev->dev, "Alarm occurred\n");
+
+               /* Pass event to the kernel */
+               rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
+
+               /* Clear event flag, otherwise new events won't be received */
+               writel_relaxed(isr & ~STM32_RTC_ISR_ALRAF,
+                              rtc->base + STM32_RTC_ISR);
+       }
+
+       mutex_unlock(&rtc->rtc_dev->ops_lock);
+
+       return IRQ_HANDLED;
+}
+
+/* Convert rtc_time structure from bin to bcd format */
+static void tm2bcd(struct rtc_time *tm)
+{
+       tm->tm_sec = bin2bcd(tm->tm_sec);
+       tm->tm_min = bin2bcd(tm->tm_min);
+       tm->tm_hour = bin2bcd(tm->tm_hour);
+
+       tm->tm_mday = bin2bcd(tm->tm_mday);
+       tm->tm_mon = bin2bcd(tm->tm_mon + 1);
+       tm->tm_year = bin2bcd(tm->tm_year - 100);
+       /*
+        * Number of days since Sunday
+        * - on kernel side, 0=Sunday...6=Saturday
+        * - on rtc side, 0=invalid,1=Monday...7=Sunday
+        */
+       tm->tm_wday = (!tm->tm_wday) ? 7 : tm->tm_wday;
+}
+
+/* Convert rtc_time structure from bcd to bin format */
+static void bcd2tm(struct rtc_time *tm)
+{
+       tm->tm_sec = bcd2bin(tm->tm_sec);
+       tm->tm_min = bcd2bin(tm->tm_min);
+       tm->tm_hour = bcd2bin(tm->tm_hour);
+
+       tm->tm_mday = bcd2bin(tm->tm_mday);
+       tm->tm_mon = bcd2bin(tm->tm_mon) - 1;
+       tm->tm_year = bcd2bin(tm->tm_year) + 100;
+       /*
+        * Number of days since Sunday
+        * - on kernel side, 0=Sunday...6=Saturday
+        * - on rtc side, 0=invalid,1=Monday...7=Sunday
+        */
+       tm->tm_wday %= 7;
+}
+
+static int stm32_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct stm32_rtc *rtc = dev_get_drvdata(dev);
+       unsigned int tr, dr;
+
+       /* Time and Date in BCD format */
+       tr = readl_relaxed(rtc->base + STM32_RTC_TR);
+       dr = readl_relaxed(rtc->base + STM32_RTC_DR);
+
+       tm->tm_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT;
+       tm->tm_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT;
+       tm->tm_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT;
+
+       tm->tm_mday = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT;
+       tm->tm_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT;
+       tm->tm_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT;
+       tm->tm_wday = (dr & STM32_RTC_DR_WDAY) >> STM32_RTC_DR_WDAY_SHIFT;
+
+       /* We don't report tm_yday and tm_isdst */
+
+       bcd2tm(tm);
+
+       return 0;
+}
+
+static int stm32_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct stm32_rtc *rtc = dev_get_drvdata(dev);
+       unsigned int tr, dr;
+       int ret = 0;
+
+       tm2bcd(tm);
+
+       /* Time in BCD format */
+       tr = ((tm->tm_sec << STM32_RTC_TR_SEC_SHIFT) & STM32_RTC_TR_SEC) |
+            ((tm->tm_min << STM32_RTC_TR_MIN_SHIFT) & STM32_RTC_TR_MIN) |
+            ((tm->tm_hour << STM32_RTC_TR_HOUR_SHIFT) & STM32_RTC_TR_HOUR);
+
+       /* Date in BCD format */
+       dr = ((tm->tm_mday << STM32_RTC_DR_DATE_SHIFT) & STM32_RTC_DR_DATE) |
+            ((tm->tm_mon << STM32_RTC_DR_MONTH_SHIFT) & STM32_RTC_DR_MONTH) |
+            ((tm->tm_year << STM32_RTC_DR_YEAR_SHIFT) & STM32_RTC_DR_YEAR) |
+            ((tm->tm_wday << STM32_RTC_DR_WDAY_SHIFT) & STM32_RTC_DR_WDAY);
+
+       stm32_rtc_wpr_unlock(rtc);
+
+       ret = stm32_rtc_enter_init_mode(rtc);
+       if (ret) {
+               dev_err(dev, "Can't enter in init mode. Set time aborted.\n");
+               goto end;
+       }
+
+       writel_relaxed(tr, rtc->base + STM32_RTC_TR);
+       writel_relaxed(dr, rtc->base + STM32_RTC_DR);
+
+       stm32_rtc_exit_init_mode(rtc);
+
+       ret = stm32_rtc_wait_sync(rtc);
+end:
+       stm32_rtc_wpr_lock(rtc);
+
+       return ret;
+}
+
+static int stm32_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct stm32_rtc *rtc = dev_get_drvdata(dev);
+       struct rtc_time *tm = &alrm->time;
+       unsigned int alrmar, cr, isr;
+
+       alrmar = readl_relaxed(rtc->base + STM32_RTC_ALRMAR);
+       cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+       isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+
+       if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) {
+               /*
+                * Date/day doesn't matter in Alarm comparison so alarm
+                * triggers every day
+                */
+               tm->tm_mday = -1;
+               tm->tm_wday = -1;
+       } else {
+               if (alrmar & STM32_RTC_ALRMXR_WDSEL) {
+                       /* Alarm is set to a day of week */
+                       tm->tm_mday = -1;
+                       tm->tm_wday = (alrmar & STM32_RTC_ALRMXR_WDAY) >>
+                                     STM32_RTC_ALRMXR_WDAY_SHIFT;
+                       tm->tm_wday %= 7;
+               } else {
+                       /* Alarm is set to a day of month */
+                       tm->tm_wday = -1;
+                       tm->tm_mday = (alrmar & STM32_RTC_ALRMXR_DATE) >>
+                                      STM32_RTC_ALRMXR_DATE_SHIFT;
+               }
+       }
+
+       if (alrmar & STM32_RTC_ALRMXR_HOUR_MASK) {
+               /* Hours don't matter in Alarm comparison */
+               tm->tm_hour = -1;
+       } else {
+               tm->tm_hour = (alrmar & STM32_RTC_ALRMXR_HOUR) >>
+                              STM32_RTC_ALRMXR_HOUR_SHIFT;
+               if (alrmar & STM32_RTC_ALRMXR_PM)
+                       tm->tm_hour += 12;
+       }
+
+       if (alrmar & STM32_RTC_ALRMXR_MIN_MASK) {
+               /* Minutes don't matter in Alarm comparison */
+               tm->tm_min = -1;
+       } else {
+               tm->tm_min = (alrmar & STM32_RTC_ALRMXR_MIN) >>
+                             STM32_RTC_ALRMXR_MIN_SHIFT;
+       }
+
+       if (alrmar & STM32_RTC_ALRMXR_SEC_MASK) {
+               /* Seconds don't matter in Alarm comparison */
+               tm->tm_sec = -1;
+       } else {
+               tm->tm_sec = (alrmar & STM32_RTC_ALRMXR_SEC) >>
+                             STM32_RTC_ALRMXR_SEC_SHIFT;
+       }
+
+       bcd2tm(tm);
+
+       alrm->enabled = (cr & STM32_RTC_CR_ALRAE) ? 1 : 0;
+       alrm->pending = (isr & STM32_RTC_ISR_ALRAF) ? 1 : 0;
+
+       return 0;
+}
+
+static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct stm32_rtc *rtc = dev_get_drvdata(dev);
+       unsigned int isr, cr;
+
+       cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+
+       stm32_rtc_wpr_unlock(rtc);
+
+       /* We expose Alarm A to the kernel */
+       if (enabled)
+               cr |= (STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
+       else
+               cr &= ~(STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
+       writel_relaxed(cr, rtc->base + STM32_RTC_CR);
+
+       /* Clear event flag, otherwise new events won't be received */
+       isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
+       isr &= ~STM32_RTC_ISR_ALRAF;
+       writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
+
+       stm32_rtc_wpr_lock(rtc);
+
+       return 0;
+}
+
+static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm)
+{
+       int cur_day, cur_mon, cur_year, cur_hour, cur_min, cur_sec;
+       unsigned int dr = readl_relaxed(rtc->base + STM32_RTC_DR);
+       unsigned int tr = readl_relaxed(rtc->base + STM32_RTC_TR);
+
+       cur_day = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT;
+       cur_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT;
+       cur_year = (dr & STM32_RTC_DR_YEAR) >> STM32_RTC_DR_YEAR_SHIFT;
+       cur_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT;
+       cur_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT;
+       cur_hour = (tr & STM32_RTC_TR_HOUR) >> STM32_RTC_TR_HOUR_SHIFT;
+
+       /*
+        * Assuming current date is M-D-Y H:M:S.
+        * RTC alarm can't be set on a specific month and year.
+        * So the valid alarm range is:
+        *      M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S
+        * with a specific case for December...
+        */
+       if ((((tm->tm_year > cur_year) &&
+             (tm->tm_mon == 0x1) && (cur_mon == 0x12)) ||
+            ((tm->tm_year == cur_year) &&
+             (tm->tm_mon <= cur_mon + 1))) &&
+           ((tm->tm_mday > cur_day) ||
+            ((tm->tm_mday == cur_day) &&
+            ((tm->tm_hour > cur_hour) ||
+             ((tm->tm_hour == cur_hour) && (tm->tm_min > cur_min)) ||
+             ((tm->tm_hour == cur_hour) && (tm->tm_min == cur_min) &&
+              (tm->tm_sec >= cur_sec))))))
+               return 0;
+
+       return -EINVAL;
+}
+
+static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct stm32_rtc *rtc = dev_get_drvdata(dev);
+       struct rtc_time *tm = &alrm->time;
+       unsigned int cr, isr, alrmar;
+       int ret = 0;
+
+       tm2bcd(tm);
+
+       /*
+        * RTC alarm can't be set on a specific date, unless this date is
+        * up to the same day of month next month.
+        */
+       if (stm32_rtc_valid_alrm(rtc, tm) < 0) {
+               dev_err(dev, "Alarm can be set only on upcoming month.\n");
+               return -EINVAL;
+       }
+
+       alrmar = 0;
+       /* tm_year and tm_mon are not used because not supported by RTC */
+       alrmar |= (tm->tm_mday << STM32_RTC_ALRMXR_DATE_SHIFT) &
+                 STM32_RTC_ALRMXR_DATE;
+       /* 24-hour format */
+       alrmar &= ~STM32_RTC_ALRMXR_PM;
+       alrmar |= (tm->tm_hour << STM32_RTC_ALRMXR_HOUR_SHIFT) &
+                 STM32_RTC_ALRMXR_HOUR;
+       alrmar |= (tm->tm_min << STM32_RTC_ALRMXR_MIN_SHIFT) &
+                 STM32_RTC_ALRMXR_MIN;
+       alrmar |= (tm->tm_sec << STM32_RTC_ALRMXR_SEC_SHIFT) &
+                 STM32_RTC_ALRMXR_SEC;
+
+       stm32_rtc_wpr_unlock(rtc);
+
+       /* Disable Alarm */
+       cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+       cr &= ~STM32_RTC_CR_ALRAE;
+       writel_relaxed(cr, rtc->base + STM32_RTC_CR);
+
+       /*
+        * Poll Alarm write flag to be sure that Alarm update is allowed: it
+        * takes around 2 ck_rtc clock cycles
+        */
+       ret = readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
+                                               isr,
+                                               (isr & STM32_RTC_ISR_ALRAWF),
+                                               10, 100000);
+
+       if (ret) {
+               dev_err(dev, "Alarm update not allowed\n");
+               goto end;
+       }
+
+       /* Write to Alarm register */
+       writel_relaxed(alrmar, rtc->base + STM32_RTC_ALRMAR);
+
+       if (alrm->enabled)
+               stm32_rtc_alarm_irq_enable(dev, 1);
+       else
+               stm32_rtc_alarm_irq_enable(dev, 0);
+
+end:
+       stm32_rtc_wpr_lock(rtc);
+
+       return ret;
+}
+
+static const struct rtc_class_ops stm32_rtc_ops = {
+       .read_time      = stm32_rtc_read_time,
+       .set_time       = stm32_rtc_set_time,
+       .read_alarm     = stm32_rtc_read_alarm,
+       .set_alarm      = stm32_rtc_set_alarm,
+       .alarm_irq_enable = stm32_rtc_alarm_irq_enable,
+};
+
+static const struct of_device_id stm32_rtc_of_match[] = {
+       { .compatible = "st,stm32-rtc" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
+
+static int stm32_rtc_init(struct platform_device *pdev,
+                         struct stm32_rtc *rtc)
+{
+       unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr;
+       unsigned int rate;
+       int ret = 0;
+
+       rate = clk_get_rate(rtc->ck_rtc);
+
+       /* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */
+       pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
+       pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT;
+
+       for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) {
+               pred_s = (rate / (pred_a + 1)) - 1;
+
+               if (((pred_s + 1) * (pred_a + 1)) == rate)
+                       break;
+       }
+
+       /*
+        * Can't find a 1Hz, so give priority to RTC power consumption
+        * by choosing the higher possible value for prediv_a
+        */
+       if ((pred_s > pred_s_max) || (pred_a > pred_a_max)) {
+               pred_a = pred_a_max;
+               pred_s = (rate / (pred_a + 1)) - 1;
+
+               dev_warn(&pdev->dev, "ck_rtc is %s\n",
+                        (rate < ((pred_a + 1) * (pred_s + 1))) ?
+                        "fast" : "slow");
+       }
+
+       stm32_rtc_wpr_unlock(rtc);
+
+       ret = stm32_rtc_enter_init_mode(rtc);
+       if (ret) {
+               dev_err(&pdev->dev,
+                       "Can't enter in init mode. Prescaler config failed.\n");
+               goto end;
+       }
+
+       prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S;
+       writel_relaxed(prer, rtc->base + STM32_RTC_PRER);
+       prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A;
+       writel_relaxed(prer, rtc->base + STM32_RTC_PRER);
+
+       /* Force 24h time format */
+       cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+       cr &= ~STM32_RTC_CR_FMT;
+       writel_relaxed(cr, rtc->base + STM32_RTC_CR);
+
+       stm32_rtc_exit_init_mode(rtc);
+
+       ret = stm32_rtc_wait_sync(rtc);
+end:
+       stm32_rtc_wpr_lock(rtc);
+
+       return ret;
+}
+
+static int stm32_rtc_probe(struct platform_device *pdev)
+{
+       struct stm32_rtc *rtc;
+       struct resource *res;
+       int ret;
+
+       rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+       if (!rtc)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       rtc->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(rtc->base))
+               return PTR_ERR(rtc->base);
+
+       rtc->dbp = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+                                                  "st,syscfg");
+       if (IS_ERR(rtc->dbp)) {
+               dev_err(&pdev->dev, "no st,syscfg\n");
+               return PTR_ERR(rtc->dbp);
+       }
+
+       rtc->ck_rtc = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(rtc->ck_rtc)) {
+               dev_err(&pdev->dev, "no ck_rtc clock");
+               return PTR_ERR(rtc->ck_rtc);
+       }
+
+       ret = clk_prepare_enable(rtc->ck_rtc);
+       if (ret)
+               return ret;
+
+       regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
+
+       /*
+        * After a system reset, RTC_ISR.INITS flag can be read to check if
+        * the calendar has been initalized or not. INITS flag is reset by a
+        * power-on reset (no vbat, no power-supply). It is not reset if
+        * ck_rtc parent clock has changed (so RTC prescalers need to be
+        * changed). That's why we cannot rely on this flag to know if RTC
+        * init has to be done.
+        */
+       ret = stm32_rtc_init(pdev, rtc);
+       if (ret)
+               goto err;
+
+       rtc->irq_alarm = platform_get_irq(pdev, 0);
+       if (rtc->irq_alarm <= 0) {
+               dev_err(&pdev->dev, "no alarm irq\n");
+               ret = rtc->irq_alarm;
+               goto err;
+       }
+
+       platform_set_drvdata(pdev, rtc);
+
+       ret = device_init_wakeup(&pdev->dev, true);
+       if (ret)
+               dev_warn(&pdev->dev,
+                        "alarm won't be able to wake up the system");
+
+       rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
+                       &stm32_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc->rtc_dev)) {
+               ret = PTR_ERR(rtc->rtc_dev);
+               dev_err(&pdev->dev, "rtc device registration failed, err=%d\n",
+                       ret);
+               goto err;
+       }
+
+       /* Handle RTC alarm interrupts */
+       ret = devm_request_threaded_irq(&pdev->dev, rtc->irq_alarm, NULL,
+                                       stm32_rtc_alarm_irq,
+                                       IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+                                       pdev->name, rtc);
+       if (ret) {
+               dev_err(&pdev->dev, "IRQ%d (alarm interrupt) already claimed\n",
+                       rtc->irq_alarm);
+               goto err;
+       }
+
+       /*
+        * If INITS flag is reset (calendar year field set to 0x00), calendar
+        * must be initialized
+        */
+       if (!(readl_relaxed(rtc->base + STM32_RTC_ISR) & STM32_RTC_ISR_INITS))
+               dev_warn(&pdev->dev, "Date/Time must be initialized\n");
+
+       return 0;
+err:
+       clk_disable_unprepare(rtc->ck_rtc);
+
+       regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, 0);
+
+       device_init_wakeup(&pdev->dev, false);
+
+       return ret;
+}
+
+static int stm32_rtc_remove(struct platform_device *pdev)
+{
+       struct stm32_rtc *rtc = platform_get_drvdata(pdev);
+       unsigned int cr;
+
+       /* Disable interrupts */
+       stm32_rtc_wpr_unlock(rtc);
+       cr = readl_relaxed(rtc->base + STM32_RTC_CR);
+       cr &= ~STM32_RTC_CR_ALRAIE;
+       writel_relaxed(cr, rtc->base + STM32_RTC_CR);
+       stm32_rtc_wpr_lock(rtc);
+
+       clk_disable_unprepare(rtc->ck_rtc);
+
+       /* Enable backup domain write protection */
+       regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, 0);
+
+       device_init_wakeup(&pdev->dev, false);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int stm32_rtc_suspend(struct device *dev)
+{
+       struct stm32_rtc *rtc = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               return enable_irq_wake(rtc->irq_alarm);
+
+       return 0;
+}
+
+static int stm32_rtc_resume(struct device *dev)
+{
+       struct stm32_rtc *rtc = dev_get_drvdata(dev);
+       int ret = 0;
+
+       ret = stm32_rtc_wait_sync(rtc);
+       if (ret < 0)
+               return ret;
+
+       if (device_may_wakeup(dev))
+               return disable_irq_wake(rtc->irq_alarm);
+
+       return ret;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(stm32_rtc_pm_ops,
+                        stm32_rtc_suspend, stm32_rtc_resume);
+
+static struct platform_driver stm32_rtc_driver = {
+       .probe          = stm32_rtc_probe,
+       .remove         = stm32_rtc_remove,
+       .driver         = {
+               .name   = DRIVER_NAME,
+               .pm     = &stm32_rtc_pm_ops,
+               .of_match_table = stm32_rtc_of_match,
+       },
+};
+
+module_platform_driver(stm32_rtc_driver);
+
+MODULE_ALIAS("platform:" DRIVER_NAME);
+MODULE_AUTHOR("Amelie Delaunay <amelie.delaunay@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics STM32 Real Time Clock driver");
+MODULE_LICENSE("GPL v2");
index c169a2cd47273e11fd62cb85755cb0badbb31a94..39cbc1238b92bbb5766d558b53435ae9ffee0ddd 100644 (file)
@@ -20,6 +20,8 @@
  * more details.
  */
 
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/fs.h>
 #include <linux/of_device.h>
 #include <linux/platform_device.h>
 #include <linux/rtc.h>
+#include <linux/slab.h>
 #include <linux/types.h>
 
 /* Control register */
 #define SUN6I_LOSC_CTRL                                0x0000
+#define SUN6I_LOSC_CTRL_KEY                    (0x16aa << 16)
 #define SUN6I_LOSC_CTRL_ALM_DHMS_ACC           BIT(9)
 #define SUN6I_LOSC_CTRL_RTC_HMS_ACC            BIT(8)
 #define SUN6I_LOSC_CTRL_RTC_YMD_ACC            BIT(7)
+#define SUN6I_LOSC_CTRL_EXT_OSC                        BIT(0)
 #define SUN6I_LOSC_CTRL_ACC_MASK               GENMASK(9, 7)
 
+#define SUN6I_LOSC_CLK_PRESCAL                 0x0008
+
 /* RTC */
 #define SUN6I_RTC_YMD                          0x0010
 #define SUN6I_RTC_HMS                          0x0014
@@ -114,13 +121,142 @@ struct sun6i_rtc_dev {
        void __iomem *base;
        int irq;
        unsigned long alarm;
+
+       struct clk_hw hw;
+       struct clk_hw *int_osc;
+       struct clk *losc;
+
+       spinlock_t lock;
+};
+
+static struct sun6i_rtc_dev *sun6i_rtc;
+
+static unsigned long sun6i_rtc_osc_recalc_rate(struct clk_hw *hw,
+                                              unsigned long parent_rate)
+{
+       struct sun6i_rtc_dev *rtc = container_of(hw, struct sun6i_rtc_dev, hw);
+       u32 val;
+
+       val = readl(rtc->base + SUN6I_LOSC_CTRL);
+       if (val & SUN6I_LOSC_CTRL_EXT_OSC)
+               return parent_rate;
+
+       val = readl(rtc->base + SUN6I_LOSC_CLK_PRESCAL);
+       val &= GENMASK(4, 0);
+
+       return parent_rate / (val + 1);
+}
+
+static u8 sun6i_rtc_osc_get_parent(struct clk_hw *hw)
+{
+       struct sun6i_rtc_dev *rtc = container_of(hw, struct sun6i_rtc_dev, hw);
+
+       return readl(rtc->base + SUN6I_LOSC_CTRL) & SUN6I_LOSC_CTRL_EXT_OSC;
+}
+
+static int sun6i_rtc_osc_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct sun6i_rtc_dev *rtc = container_of(hw, struct sun6i_rtc_dev, hw);
+       unsigned long flags;
+       u32 val;
+
+       if (index > 1)
+               return -EINVAL;
+
+       spin_lock_irqsave(&rtc->lock, flags);
+       val = readl(rtc->base + SUN6I_LOSC_CTRL);
+       val &= ~SUN6I_LOSC_CTRL_EXT_OSC;
+       val |= SUN6I_LOSC_CTRL_KEY;
+       val |= index ? SUN6I_LOSC_CTRL_EXT_OSC : 0;
+       writel(val, rtc->base + SUN6I_LOSC_CTRL);
+       spin_unlock_irqrestore(&rtc->lock, flags);
+
+       return 0;
+}
+
+static const struct clk_ops sun6i_rtc_osc_ops = {
+       .recalc_rate    = sun6i_rtc_osc_recalc_rate,
+
+       .get_parent     = sun6i_rtc_osc_get_parent,
+       .set_parent     = sun6i_rtc_osc_set_parent,
 };
 
+static void __init sun6i_rtc_clk_init(struct device_node *node)
+{
+       struct clk_hw_onecell_data *clk_data;
+       struct sun6i_rtc_dev *rtc;
+       struct clk_init_data init = {
+               .ops            = &sun6i_rtc_osc_ops,
+       };
+       const char *parents[2];
+
+       rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+       if (!rtc)
+               return;
+       spin_lock_init(&rtc->lock);
+
+       clk_data = kzalloc(sizeof(*clk_data) + sizeof(*clk_data->hws),
+                          GFP_KERNEL);
+       if (!clk_data)
+               return;
+       spin_lock_init(&rtc->lock);
+
+       rtc->base = of_io_request_and_map(node, 0, of_node_full_name(node));
+       if (IS_ERR(rtc->base)) {
+               pr_crit("Can't map RTC registers");
+               return;
+       }
+
+       /* Switch to the external, more precise, oscillator */
+       writel(SUN6I_LOSC_CTRL_KEY | SUN6I_LOSC_CTRL_EXT_OSC,
+              rtc->base + SUN6I_LOSC_CTRL);
+
+       /* Yes, I know, this is ugly. */
+       sun6i_rtc = rtc;
+
+       /* Deal with old DTs */
+       if (!of_get_property(node, "clocks", NULL))
+               return;
+
+       rtc->int_osc = clk_hw_register_fixed_rate_with_accuracy(NULL,
+                                                               "rtc-int-osc",
+                                                               NULL, 0,
+                                                               667000,
+                                                               300000000);
+       if (IS_ERR(rtc->int_osc)) {
+               pr_crit("Couldn't register the internal oscillator\n");
+               return;
+       }
+
+       parents[0] = clk_hw_get_name(rtc->int_osc);
+       parents[1] = of_clk_get_parent_name(node, 0);
+
+       rtc->hw.init = &init;
+
+       init.parent_names = parents;
+       init.num_parents = of_clk_get_parent_count(node) + 1;
+       of_property_read_string(node, "clock-output-names", &init.name);
+
+       rtc->losc = clk_register(NULL, &rtc->hw);
+       if (IS_ERR(rtc->losc)) {
+               pr_crit("Couldn't register the LOSC clock\n");
+               return;
+       }
+
+       clk_data->num = 1;
+       clk_data->hws[0] = &rtc->hw;
+       of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
+}
+CLK_OF_DECLARE_DRIVER(sun6i_rtc_clk, "allwinner,sun6i-a31-rtc",
+                     sun6i_rtc_clk_init);
+
 static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id)
 {
        struct sun6i_rtc_dev *chip = (struct sun6i_rtc_dev *) id;
+       irqreturn_t ret = IRQ_NONE;
        u32 val;
 
+       spin_lock(&chip->lock);
        val = readl(chip->base + SUN6I_ALRM_IRQ_STA);
 
        if (val & SUN6I_ALRM_IRQ_STA_CNT_IRQ_PEND) {
@@ -129,10 +265,11 @@ static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id)
 
                rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF);
 
-               return IRQ_HANDLED;
+               ret = IRQ_HANDLED;
        }
+       spin_unlock(&chip->lock);
 
-       return IRQ_NONE;
+       return ret;
 }
 
 static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip)
@@ -140,6 +277,7 @@ static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip)
        u32 alrm_val = 0;
        u32 alrm_irq_val = 0;
        u32 alrm_wake_val = 0;
+       unsigned long flags;
 
        if (to) {
                alrm_val = SUN6I_ALRM_EN_CNT_EN;
@@ -150,9 +288,11 @@ static void sun6i_rtc_setaie(int to, struct sun6i_rtc_dev *chip)
                       chip->base + SUN6I_ALRM_IRQ_STA);
        }
 
+       spin_lock_irqsave(&chip->lock, flags);
        writel(alrm_val, chip->base + SUN6I_ALRM_EN);
        writel(alrm_irq_val, chip->base + SUN6I_ALRM_IRQ_EN);
        writel(alrm_wake_val, chip->base + SUN6I_ALARM_CONFIG);
+       spin_unlock_irqrestore(&chip->lock, flags);
 }
 
 static int sun6i_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
@@ -191,11 +331,15 @@ static int sun6i_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
 static int sun6i_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
 {
        struct sun6i_rtc_dev *chip = dev_get_drvdata(dev);
+       unsigned long flags;
        u32 alrm_st;
        u32 alrm_en;
 
+       spin_lock_irqsave(&chip->lock, flags);
        alrm_en = readl(chip->base + SUN6I_ALRM_IRQ_EN);
        alrm_st = readl(chip->base + SUN6I_ALRM_IRQ_STA);
+       spin_unlock_irqrestore(&chip->lock, flags);
+
        wkalrm->enabled = !!(alrm_en & SUN6I_ALRM_EN_CNT_EN);
        wkalrm->pending = !!(alrm_st & SUN6I_ALRM_EN_CNT_EN);
        rtc_time_to_tm(chip->alarm, &wkalrm->time);
@@ -349,22 +493,15 @@ static const struct rtc_class_ops sun6i_rtc_ops = {
 
 static int sun6i_rtc_probe(struct platform_device *pdev)
 {
-       struct sun6i_rtc_dev *chip;
-       struct resource *res;
+       struct sun6i_rtc_dev *chip = sun6i_rtc;
        int ret;
 
-       chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
        if (!chip)
-               return -ENOMEM;
+               return -ENODEV;
 
        platform_set_drvdata(pdev, chip);
        chip->dev = &pdev->dev;
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       chip->base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(chip->base))
-               return PTR_ERR(chip->base);
-
        chip->irq = platform_get_irq(pdev, 0);
        if (chip->irq < 0) {
                dev_err(&pdev->dev, "No IRQ resource\n");
@@ -404,8 +541,10 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
        /* disable alarm wakeup */
        writel(0, chip->base + SUN6I_ALARM_CONFIG);
 
-       chip->rtc = rtc_device_register("rtc-sun6i", &pdev->dev,
-                                       &sun6i_rtc_ops, THIS_MODULE);
+       clk_prepare_enable(chip->losc);
+
+       chip->rtc = devm_rtc_device_register(&pdev->dev, "rtc-sun6i",
+                                            &sun6i_rtc_ops, THIS_MODULE);
        if (IS_ERR(chip->rtc)) {
                dev_err(&pdev->dev, "unable to register device\n");
                return PTR_ERR(chip->rtc);
@@ -416,15 +555,6 @@ static int sun6i_rtc_probe(struct platform_device *pdev)
        return 0;
 }
 
-static int sun6i_rtc_remove(struct platform_device *pdev)
-{
-       struct sun6i_rtc_dev *chip = platform_get_drvdata(pdev);
-
-       rtc_device_unregister(chip->rtc);
-
-       return 0;
-}
-
 static const struct of_device_id sun6i_rtc_dt_ids[] = {
        { .compatible = "allwinner,sun6i-a31-rtc" },
        { /* sentinel */ },
@@ -433,15 +563,9 @@ MODULE_DEVICE_TABLE(of, sun6i_rtc_dt_ids);
 
 static struct platform_driver sun6i_rtc_driver = {
        .probe          = sun6i_rtc_probe,
-       .remove         = sun6i_rtc_remove,
        .driver         = {
                .name           = "sun6i-rtc",
                .of_match_table = sun6i_rtc_dt_ids,
        },
 };
-
-module_platform_driver(sun6i_rtc_driver);
-
-MODULE_DESCRIPTION("sun6i RTC driver");
-MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
-MODULE_LICENSE("GPL");
+builtin_platform_driver(sun6i_rtc_driver);
index 3853ba963bb5d801502b8d50d992c83aeb886eb0..d30d57b048d36ccb5c9ab3285e196d4e168207fc 100644 (file)
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-#include <linux/kernel.h>
+
+#include <linux/clk.h>
+#include <linux/delay.h>
 #include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/irq.h>
 #include <linux/io.h>
-#include <linux/delay.h>
-#include <linux/rtc.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/pm.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
 
 /* set to 1 = busy every eight 32kHz clocks during copy of sec+msec to AHB */
 #define TEGRA_RTC_REG_BUSY                     0x004
@@ -59,6 +61,7 @@ struct tegra_rtc_info {
        struct platform_device  *pdev;
        struct rtc_device       *rtc_dev;
        void __iomem            *rtc_base; /* NULL if not initialized. */
+       struct clk              *clk;
        int                     tegra_rtc_irq; /* alarm and periodic irq */
        spinlock_t              tegra_rtc_lock;
 };
@@ -326,6 +329,14 @@ static int __init tegra_rtc_probe(struct platform_device *pdev)
        if (info->tegra_rtc_irq <= 0)
                return -EBUSY;
 
+       info->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(info->clk))
+               return PTR_ERR(info->clk);
+
+       ret = clk_prepare_enable(info->clk);
+       if (ret < 0)
+               return ret;
+
        /* set context info. */
        info->pdev = pdev;
        spin_lock_init(&info->tegra_rtc_lock);
@@ -346,7 +357,7 @@ static int __init tegra_rtc_probe(struct platform_device *pdev)
                ret = PTR_ERR(info->rtc_dev);
                dev_err(&pdev->dev, "Unable to register device (err=%d).\n",
                        ret);
-               return ret;
+               goto disable_clk;
        }
 
        ret = devm_request_irq(&pdev->dev, info->tegra_rtc_irq,
@@ -356,11 +367,24 @@ static int __init tegra_rtc_probe(struct platform_device *pdev)
                dev_err(&pdev->dev,
                        "Unable to request interrupt for device (err=%d).\n",
                        ret);
-               return ret;
+               goto disable_clk;
        }
 
        dev_notice(&pdev->dev, "Tegra internal Real Time Clock\n");
 
+       return 0;
+
+disable_clk:
+       clk_disable_unprepare(info->clk);
+       return ret;
+}
+
+static int tegra_rtc_remove(struct platform_device *pdev)
+{
+       struct tegra_rtc_info *info = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(info->clk);
+
        return 0;
 }
 
@@ -413,6 +437,7 @@ static void tegra_rtc_shutdown(struct platform_device *pdev)
 
 MODULE_ALIAS("platform:tegra_rtc");
 static struct platform_driver tegra_rtc_driver = {
+       .remove         = tegra_rtc_remove,
        .shutdown       = tegra_rtc_shutdown,
        .driver         = {
                .name   = "tegra_rtc",
index 5a3d53caa485f733c3f38af872b18e8037b751ba..d0244d7979fcb8913bfaf6093334b6f3f5938bf4 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/types.h>
 #include <linux/rtc.h>
 #include <linux/bcd.h>
+#include <linux/math64.h>
 #include <linux/platform_device.h>
 #include <linux/interrupt.h>
 #include <linux/mfd/tps65910.h>
@@ -33,7 +34,21 @@ struct tps65910_rtc {
 /* Total number of RTC registers needed to set time*/
 #define NUM_TIME_REGS  (TPS65910_YEARS - TPS65910_SECONDS + 1)
 
-static int tps65910_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
+/* Total number of RTC registers needed to set compensation registers */
+#define NUM_COMP_REGS  (TPS65910_RTC_COMP_MSB - TPS65910_RTC_COMP_LSB + 1)
+
+/* Min and max values supported with 'offset' interface (swapped sign) */
+#define MIN_OFFSET     (-277761)
+#define MAX_OFFSET     (277778)
+
+/* Number of ticks per hour */
+#define TICKS_PER_HOUR (32768 * 3600)
+
+/* Multiplier for ppb conversions */
+#define PPB_MULT       (1000000000LL)
+
+static int tps65910_rtc_alarm_irq_enable(struct device *dev,
+                                        unsigned int enabled)
 {
        struct tps65910 *tps = dev_get_drvdata(dev->parent);
        u8 val = 0;
@@ -187,6 +202,133 @@ static int tps65910_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
        return ret;
 }
 
+static int tps65910_rtc_set_calibration(struct device *dev, int calibration)
+{
+       unsigned char comp_data[NUM_COMP_REGS];
+       struct tps65910 *tps = dev_get_drvdata(dev->parent);
+       s16 value;
+       int ret;
+
+       /*
+        * TPS65910 uses two's complement 16 bit value for compensation for RTC
+        * crystal inaccuracies. One time every hour when seconds counter
+        * increments from 0 to 1 compensation value will be added to internal
+        * RTC counter value.
+        *
+        * Compensation value 0x7FFF is prohibited value.
+        *
+        * Valid range for compensation value: [-32768 .. 32766]
+        */
+       if ((calibration < -32768) || (calibration > 32766)) {
+               dev_err(dev, "RTC calibration value out of range: %d\n",
+                       calibration);
+               return -EINVAL;
+       }
+
+       value = (s16)calibration;
+
+       comp_data[0] = (u16)value & 0xFF;
+       comp_data[1] = ((u16)value >> 8) & 0xFF;
+
+       /* Update all the compensation registers in one shot */
+       ret = regmap_bulk_write(tps->regmap, TPS65910_RTC_COMP_LSB,
+               comp_data, NUM_COMP_REGS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_set_calibration error: %d\n", ret);
+               return ret;
+       }
+
+       /* Enable automatic compensation */
+       ret = regmap_update_bits(tps->regmap, TPS65910_RTC_CTRL,
+               TPS65910_RTC_CTRL_AUTO_COMP, TPS65910_RTC_CTRL_AUTO_COMP);
+       if (ret < 0)
+               dev_err(dev, "auto_comp enable failed with error: %d\n", ret);
+
+       return ret;
+}
+
+static int tps65910_rtc_get_calibration(struct device *dev, int *calibration)
+{
+       unsigned char comp_data[NUM_COMP_REGS];
+       struct tps65910 *tps = dev_get_drvdata(dev->parent);
+       unsigned int ctrl;
+       u16 value;
+       int ret;
+
+       ret = regmap_read(tps->regmap, TPS65910_RTC_CTRL, &ctrl);
+       if (ret < 0)
+               return ret;
+
+       /* If automatic compensation is not enabled report back zero */
+       if (!(ctrl & TPS65910_RTC_CTRL_AUTO_COMP)) {
+               *calibration = 0;
+               return 0;
+       }
+
+       ret = regmap_bulk_read(tps->regmap, TPS65910_RTC_COMP_LSB, comp_data,
+               NUM_COMP_REGS);
+       if (ret < 0) {
+               dev_err(dev, "rtc_get_calibration error: %d\n", ret);
+               return ret;
+       }
+
+       value = (u16)comp_data[0] | ((u16)comp_data[1] << 8);
+
+       *calibration = (s16)value;
+
+       return 0;
+}
+
+static int tps65910_read_offset(struct device *dev, long *offset)
+{
+       int calibration;
+       s64 tmp;
+       int ret;
+
+       ret = tps65910_rtc_get_calibration(dev, &calibration);
+       if (ret < 0)
+               return ret;
+
+       /* Convert from RTC calibration register format to ppb format */
+       tmp = calibration * (s64)PPB_MULT;
+       if (tmp < 0)
+               tmp -= TICKS_PER_HOUR / 2LL;
+       else
+               tmp += TICKS_PER_HOUR / 2LL;
+       tmp = div_s64(tmp, TICKS_PER_HOUR);
+
+       /* Offset value operates in negative way, so swap sign */
+       *offset = (long)-tmp;
+
+       return 0;
+}
+
+static int tps65910_set_offset(struct device *dev, long offset)
+{
+       int calibration;
+       s64 tmp;
+       int ret;
+
+       /* Make sure offset value is within supported range */
+       if (offset < MIN_OFFSET || offset > MAX_OFFSET)
+               return -ERANGE;
+
+       /* Convert from ppb format to RTC calibration register format */
+       tmp = offset * (s64)TICKS_PER_HOUR;
+       if (tmp < 0)
+               tmp -= PPB_MULT / 2LL;
+       else
+               tmp += PPB_MULT / 2LL;
+       tmp = div_s64(tmp, PPB_MULT);
+
+       /* Offset value operates in negative way, so swap sign */
+       calibration = (int)-tmp;
+
+       ret = tps65910_rtc_set_calibration(dev, calibration);
+
+       return ret;
+}
+
 static irqreturn_t tps65910_rtc_interrupt(int irq, void *rtc)
 {
        struct device *dev = rtc;
@@ -219,6 +361,8 @@ static const struct rtc_class_ops tps65910_rtc_ops = {
        .read_alarm     = tps65910_rtc_read_alarm,
        .set_alarm      = tps65910_rtc_set_alarm,
        .alarm_irq_enable = tps65910_rtc_alarm_irq_enable,
+       .read_offset    = tps65910_read_offset,
+       .set_offset     = tps65910_set_offset,
 };
 
 static int tps65910_rtc_probe(struct platform_device *pdev)
index 6483a6fdce594a9036cad2cd859dff64c81e87cf..ffb21e79204d6a1e91acfe414c264261ab4a115c 100644 (file)
 
 /* RTC_CTRL_REG bitfields */
 #define TPS65910_RTC_CTRL_STOP_RTC                     0x01 /*0=stop, 1=run */
+#define TPS65910_RTC_CTRL_AUTO_COMP                    0x04
 #define TPS65910_RTC_CTRL_GET_TIME                     0x40
 
 /* RTC_STATUS_REG bitfields */
diff --git a/include/linux/platform_data/rtc-m48t86.h b/include/linux/platform_data/rtc-m48t86.h
deleted file mode 100644 (file)
index 915d6b4..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * ST M48T86 / Dallas DS12887 RTC driver
- * Copyright (c) 2006 Tower Technologies
- *
- * Author: Alessandro Zummo <a.zummo@towertech.it>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
-*/
-
-struct m48t86_ops
-{
-       void (*writebyte)(unsigned char value, unsigned long addr);
-       unsigned char (*readbyte)(unsigned long addr);
-};