Merge tag 'rtc-4.15' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 23 Nov 2017 06:58:23 +0000 (20:58 -1000)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 23 Nov 2017 06:58:23 +0000 (20:58 -1000)
Pull RTC updates from Alexandre Belloni:
 "There is nothing scary this cycle, mostly driver fixes and updates.

  The core fix has been in for a while and has been tested on multiple
  kernel revisions by multiple teams.

  Core:
   - Fix setting the alarm to the next expiring timer

  New drivers:
   - Mediatek MT7622 RTC
   - NXP PCF85363
   - Spreadtrum SC27xx PMIC RTC

  Drivers updates:
   - Use generic nvmem to expose the Non volatile ram for ds1305,
     ds1511, m48t86 and omap
   - abx80x: solve possible race condition at probe
   - armada38x: support trimming the RTC oscillator
   - at91rm9200: fix reading the alarm value at boot
   - ds1511: allow waking platform
   - m41t80: rework square wave output
   - pcf8523: support trimming the RTC oscillator
   - pcf8563: fix clock output rate
   - pl031: make interrupt optional
   - xgene: fix suspend/resume"

* tag 'rtc-4.15' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (50 commits)
  dt-bindings: rtc: imxdi: Improve the bindings text
  rtc: sc27xx: Add Spreadtrum SC27xx PMIC RTC driver
  dt-bindings: rtc: Add Spreadtrum SC27xx RTC documentation
  rtc: at91rm9200: fix reading alarm value
  rtc: at91rm9200: stop calculating yday in at91_rtc_readalarm
  rtc: sysfs: Use time64_t variables to set time/alarm
  rtc: xgene: mark PM functions as __maybe_unused
  rtc: xgene: Fix suspend/resume
  rtc: pcf8563: don't alway enable the alarm
  rtc: pcf8563: fix output clock rate
  rtc: rx8010: Fix for incorrect return value
  rtc: rx8010: Specify correct address for RX8010_RESV31
  rtc: rx8010: Remove duplicate define
  rtc: m41t80: remove unneeded checks from m41t80_sqw_set_rate
  rtc: m41t80: avoid i2c read in m41t80_sqw_is_prepared
  rtc: m41t80: avoid i2c read in m41t80_sqw_recalc_rate
  rtc: m41t80: fix m41t80_sqw_round_rate return value
  rtc: m41t80: m41t80_sqw_set_rate should return 0 on success
  rtc: add support for NXP PCF85363 real-time clock
  rtc: omap: Support scratch registers
  ...

30 files changed:
Documentation/devicetree/bindings/rtc/imxdi-rtc.txt
Documentation/devicetree/bindings/rtc/pcf85363.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/rtc-mt7622.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/sprd,sc27xx-rtc.txt [new file with mode: 0644]
Documentation/devicetree/bindings/trivial-devices.txt
MAINTAINERS
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/interface.c
drivers/rtc/rtc-abx80x.c
drivers/rtc/rtc-armada38x.c
drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-ds1305.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds1390.c
drivers/rtc/rtc-ds1511.c
drivers/rtc/rtc-jz4740.c
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-m48t86.c
drivers/rtc/rtc-mt7622.c [new file with mode: 0644]
drivers/rtc/rtc-omap.c
drivers/rtc/rtc-pcf8523.c
drivers/rtc/rtc-pcf85363.c [new file with mode: 0644]
drivers/rtc/rtc-pcf8563.c
drivers/rtc/rtc-pl031.c
drivers/rtc/rtc-rv3029c2.c
drivers/rtc/rtc-rx8010.c
drivers/rtc/rtc-sc27xx.c [new file with mode: 0644]
drivers/rtc/rtc-sysfs.c
drivers/rtc/rtc-xgene.c

index 323cf26374cb14dff4284fb8cdbe4e27270b8107..c797bc9d77d2296a225c8d6da9922fb187243f9a 100644 (file)
@@ -1,20 +1,20 @@
 * i.MX25 Real Time Clock controller
 
-This binding supports the following chips: i.MX25, i.MX53
-
 Required properties:
 - compatible: should be: "fsl,imx25-rtc"
 - reg: physical base address of the controller and length of memory mapped
   region.
+- clocks: should contain the phandle for the rtc clock
 - interrupts: rtc alarm interrupt
 
 Optional properties:
-- interrupts: dryice security violation interrupt
+- interrupts: dryice security violation interrupt (second entry)
 
 Example:
 
-rtc@80056000 {
-       compatible = "fsl,imx53-rtc", "fsl,imx25-rtc";
-       reg = <0x80056000 2000>;
-       interrupts = <29 56>;
+rtc@53ffc000 {
+       compatible = "fsl,imx25-rtc";
+       reg = <0x53ffc000 0x4000>;
+       clocks = <&clks 81>;
+       interrupts = <25 56>;
 };
diff --git a/Documentation/devicetree/bindings/rtc/pcf85363.txt b/Documentation/devicetree/bindings/rtc/pcf85363.txt
new file mode 100644 (file)
index 0000000..76fdabc
--- /dev/null
@@ -0,0 +1,17 @@
+NXP PCF85363 Real Time Clock
+============================
+
+Required properties:
+- compatible: Should contain "nxp,pcf85363".
+- reg: I2C address for chip.
+
+Optional properties:
+- interrupts: IRQ line for the RTC (not implemented).
+
+Example:
+
+pcf85363: pcf85363@51 {
+       compatible = "nxp,pcf85363";
+       reg = <0x51>;
+};
+
diff --git a/Documentation/devicetree/bindings/rtc/rtc-mt7622.txt b/Documentation/devicetree/bindings/rtc/rtc-mt7622.txt
new file mode 100644 (file)
index 0000000..09fe8f5
--- /dev/null
@@ -0,0 +1,21 @@
+Device-Tree bindings for MediaTek SoC based RTC
+
+Required properties:
+- compatible       : Should be
+                       "mediatek,mt7622-rtc", "mediatek,soc-rtc" : for MT7622 SoC
+- reg              : Specifies base physical address and size of the registers;
+- interrupts       : Should contain the interrupt for RTC alarm;
+- clocks           : Specifies list of clock specifiers, corresponding to
+                     entries in clock-names property;
+- clock-names      : Should contain "rtc" entries
+
+Example:
+
+rtc: rtc@10212800 {
+       compatible = "mediatek,mt7622-rtc",
+                    "mediatek,soc-rtc";
+       reg = <0 0x10212800 0 0x200>;
+       interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_LOW>;
+       clocks = <&topckgen CLK_TOP_RTC>;
+       clock-names = "rtc";
+};
diff --git a/Documentation/devicetree/bindings/rtc/sprd,sc27xx-rtc.txt b/Documentation/devicetree/bindings/rtc/sprd,sc27xx-rtc.txt
new file mode 100644 (file)
index 0000000..7c170da
--- /dev/null
@@ -0,0 +1,27 @@
+Spreadtrum SC27xx Real Time Clock
+
+Required properties:
+- compatible: should be "sprd,sc2731-rtc".
+- reg: address offset of rtc register.
+- interrupt-parent: phandle for the interrupt controller.
+- interrupts: rtc alarm interrupt.
+
+Example:
+
+       sc2731_pmic: pmic@0 {
+               compatible = "sprd,sc2731";
+               reg = <0>;
+               spi-max-frequency = <26000000>;
+               interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+               interrupt-controller;
+               #interrupt-cells = <2>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               rtc@280 {
+                       compatible = "sprd,sc2731-rtc";
+                       reg = <0x280>;
+                       interrupt-parent = <&sc2731_pmic>;
+                       interrupts = <2 IRQ_TYPE_LEVEL_HIGH>;
+               };
+       };
index 678039d4d5e57f96eacd9c9b5a0e8ce72a1d4dd4..5f3143f970983ca92ce1024eaed87f03fa494877 100644 (file)
@@ -72,7 +72,6 @@ maxim,ds1050          5 Bit Programmable, Pulse-Width Modulator
 maxim,max1237          Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
 maxim,max6621          PECI-to-I2C translator for PECI-to-SMBus/I2C protocol conversion
 maxim,max6625          9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
-mc,rv3029c2            Real Time Clock Module with I2C-Bus
 mcube,mc3230           mCube 3-axis 8-bit digital accelerometer
 memsic,mxc6225         MEMSIC 2-axis 8-bit digital accelerometer
 microchip,mcp4531-502  Microchip 7-bit Single I2C Digital Potentiometer (5k)
@@ -141,6 +140,7 @@ microchip,mcp4662-503       Microchip 8-bit Dual I2C Digital Potentiometer with NV Mem
 microchip,mcp4662-104  Microchip 8-bit Dual I2C Digital Potentiometer with NV Memory (100k)
 microchip,tc654                PWM Fan Speed Controller With Fan Fault Detection
 microchip,tc655                PWM Fan Speed Controller With Fan Fault Detection
+microcrystal,rv3029    Real Time Clock Module with I2C-Bus
 miramems,da226         MiraMEMS DA226 2-axis 14-bit digital accelerometer
 miramems,da280         MiraMEMS DA280 3-axis 14-bit digital accelerometer
 miramems,da311         MiraMEMS DA311 3-axis 12-bit digital accelerometer
index 44512c346206708bfc9b90e14e8e733a8aa81018..aa71ab52fd76d1607b36f476dde8e0060f500070 100644 (file)
@@ -1590,10 +1590,13 @@ F:      drivers/rtc/rtc-armada38x.c
 
 ARM/Mediatek RTC DRIVER
 M:     Eddie Huang <eddie.huang@mediatek.com>
+M:     Sean Wang <sean.wang@mediatek.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-mediatek@lists.infradead.org (moderated for non-subscribers)
 S:     Maintained
+F:     Documentation/devicetree/bindings/rtc/rtc-mt7622.txt
 F:     drivers/rtc/rtc-mt6397.c
+F:     drivers/rtc/rtc-mt7622.c
 
 ARM/Mediatek SoC support
 M:     Matthias Brugger <matthias.bgg@gmail.com>
index e0e58f3b14209a7fe908adb0cf8ca544a93c65a2..b59a31b079a5347125a7ec55e56f92a75d06220f 100644 (file)
@@ -433,6 +433,19 @@ config RTC_DRV_PCF85063
          This driver can also be built as a module. If so, the module
          will be called rtc-pcf85063.
 
+config RTC_DRV_PCF85363
+       tristate "NXP PCF85363"
+       depends on I2C
+       select REGMAP_I2C
+       help
+         If you say yes here you get support for the PCF85363 RTC chip.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-pcf85363.
+
+         The nvmem interface will be named pcf85363-#, where # is the
+         zero-based instance number.
+
 config RTC_DRV_PCF8563
        tristate "Philips PCF8563/Epson RTC8564"
        help
@@ -1174,6 +1187,17 @@ config RTC_DRV_WM8350
          This driver can also be built as a module. If so, the module
          will be called "rtc-wm8350".
 
+config RTC_DRV_SC27XX
+       tristate "Spreadtrum SC27xx RTC"
+       depends on MFD_SC27XX_PMIC || COMPILE_TEST
+       help
+         If you say Y here you will get support for the RTC subsystem
+         of the Spreadtrum SC27xx series PMICs. The SC27xx series PMICs
+         includes the SC2720, SC2721, SC2723, SC2730 and SC2731 chips.
+
+         This driver can also be built as a module. If so, the module
+         will be called rtc-sc27xx.
+
 config RTC_DRV_SPEAR
        tristate "SPEAR ST RTC"
        depends on PLAT_SPEAR || COMPILE_TEST
@@ -1706,14 +1730,24 @@ config RTC_DRV_MOXART
           will be called rtc-moxart
 
 config RTC_DRV_MT6397
-       tristate "Mediatek Real Time Clock driver"
+       tristate "MediaTek PMIC based RTC"
        depends on MFD_MT6397 || (COMPILE_TEST && IRQ_DOMAIN)
        help
-         This selects the Mediatek(R) RTC driver. RTC is part of Mediatek
+         This selects the MediaTek(R) RTC driver. RTC is part of MediaTek
          MT6397 PMIC. You should enable MT6397 PMIC MFD before select
-         Mediatek(R) RTC driver.
+         MediaTek(R) RTC driver.
+
+         If you want to use MediaTek(R) RTC interface, select Y or M here.
 
-         If you want to use Mediatek(R) RTC interface, select Y or M here.
+config RTC_DRV_MT7622
+       tristate "MediaTek SoC based RTC"
+       depends on ARCH_MEDIATEK || COMPILE_TEST
+       help
+         This enables support for the real time clock built in the MediaTek
+         SoCs.
+
+         This drive can also be built as a module. If so, the module
+         will be called rtc-mt7622.
 
 config RTC_DRV_XGENE
        tristate "APM X-Gene RTC"
index 0bf1fc02b82c451348ba6110457bd8189b5e73e5..f2f50c11dc387d93d7cc0e16d1f779ae180b1596 100644 (file)
@@ -103,6 +103,7 @@ obj-$(CONFIG_RTC_DRV_MPC5121)       += rtc-mpc5121.o
 obj-$(CONFIG_RTC_DRV_VRTC)     += rtc-mrst.o
 obj-$(CONFIG_RTC_DRV_MSM6242)  += rtc-msm6242.o
 obj-$(CONFIG_RTC_DRV_MT6397)   += rtc-mt6397.o
+obj-$(CONFIG_RTC_DRV_MT7622)   += rtc-mt7622.o
 obj-$(CONFIG_RTC_DRV_MV)       += rtc-mv.o
 obj-$(CONFIG_RTC_DRV_MXC)      += rtc-mxc.o
 obj-$(CONFIG_RTC_DRV_NUC900)   += rtc-nuc900.o
@@ -114,6 +115,7 @@ obj-$(CONFIG_RTC_DRV_PCF2123)       += rtc-pcf2123.o
 obj-$(CONFIG_RTC_DRV_PCF2127)  += rtc-pcf2127.o
 obj-$(CONFIG_RTC_DRV_PCF50633) += rtc-pcf50633.o
 obj-$(CONFIG_RTC_DRV_PCF85063) += rtc-pcf85063.o
+obj-$(CONFIG_RTC_DRV_PCF85363) += rtc-pcf85363.o
 obj-$(CONFIG_RTC_DRV_PCF8523)  += rtc-pcf8523.o
 obj-$(CONFIG_RTC_DRV_PCF8563)  += rtc-pcf8563.o
 obj-$(CONFIG_RTC_DRV_PCF8583)  += rtc-pcf8583.o
@@ -144,6 +146,7 @@ obj-$(CONFIG_RTC_DRV_S35390A)       += rtc-s35390a.o
 obj-$(CONFIG_RTC_DRV_S3C)      += rtc-s3c.o
 obj-$(CONFIG_RTC_DRV_S5M)      += rtc-s5m.o
 obj-$(CONFIG_RTC_DRV_SA1100)   += rtc-sa1100.o
+obj-$(CONFIG_RTC_DRV_SC27XX)   += rtc-sc27xx.o
 obj-$(CONFIG_RTC_DRV_SH)       += rtc-sh.o
 obj-$(CONFIG_RTC_DRV_SIRFSOC)  += rtc-sirfsoc.o
 obj-$(CONFIG_RTC_DRV_SNVS)     += rtc-snvs.o
index 8cec9a02c0b8937fdcdca2fdd80d14dba4e79b7c..672b192f8153aa00665daaefc541ebaf601cfe74 100644 (file)
@@ -779,7 +779,7 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
        }
 
        timerqueue_add(&rtc->timerqueue, &timer->node);
-       if (!next) {
+       if (!next || ktime_before(timer->node.expires, next->expires)) {
                struct rtc_wkalrm alarm;
                int err;
                alarm.time = rtc_ktime_to_tm(timer->node.expires);
@@ -1004,6 +1004,10 @@ int rtc_read_offset(struct rtc_device *rtc, long *offset)
  * to compensate for differences in the actual clock rate due to temperature,
  * the crystal, capacitor, etc.
  *
+ * The adjustment applied is as follows:
+ *   t = t0 * (1 + offset * 1e-9)
+ * where t0 is the measured length of 1 RTC second with offset = 0
+ *
  * Kernel interface to adjust an rtc clock offset.
  * Return 0 on success, or a negative number on error.
  * If the rtc offset is not setable (or not implemented), return -EINVAL
index fea9a60b06cf6dd25b1a078bf6e812265aa0acc1..b033bc556f5d29b4d803ff6506685c3dc940aee1 100644 (file)
@@ -614,12 +614,12 @@ static int abx80x_probe(struct i2c_client *client,
        if (err)
                return err;
 
-       rtc = devm_rtc_device_register(&client->dev, "abx8xx",
-                                      &abx80x_rtc_ops, THIS_MODULE);
-
+       rtc = devm_rtc_allocate_device(&client->dev);
        if (IS_ERR(rtc))
                return PTR_ERR(rtc);
 
+       rtc->ops = &abx80x_rtc_ops;
+
        i2c_set_clientdata(client, rtc);
 
        if (client->irq > 0) {
@@ -646,10 +646,14 @@ static int abx80x_probe(struct i2c_client *client,
        err = devm_add_action_or_reset(&client->dev,
                                       rtc_calib_remove_sysfs_group,
                                       &client->dev);
-       if (err)
+       if (err) {
                dev_err(&client->dev,
                        "Failed to add sysfs cleanup action: %d\n",
                        err);
+               return err;
+       }
+
+       err = rtc_register_device(rtc);
 
        return err;
 }
index 21f355c37eab53cd4de0668e7250d1d578344e71..1e4978c96ffd273c617e9c8d89f49a9b2a0838ec 100644 (file)
@@ -28,6 +28,8 @@
 #define RTC_IRQ_AL_EN              BIT(0)
 #define RTC_IRQ_FREQ_EN                    BIT(1)
 #define RTC_IRQ_FREQ_1HZ           BIT(2)
+#define RTC_CCR                    0x18
+#define RTC_CCR_MODE               BIT(15)
 
 #define RTC_TIME           0xC
 #define RTC_ALARM1         0x10
@@ -343,18 +345,117 @@ static irqreturn_t armada38x_rtc_alarm_irq(int irq, void *data)
        return IRQ_HANDLED;
 }
 
+/*
+ * The information given in the Armada 388 functional spec is complex.
+ * They give two different formulas for calculating the offset value,
+ * but when considering "Offset" as an 8-bit signed integer, they both
+ * reduce down to (we shall rename "Offset" as "val" here):
+ *
+ *   val = (f_ideal / f_measured - 1) / resolution   where f_ideal = 32768
+ *
+ * Converting to time, f = 1/t:
+ *   val = (t_measured / t_ideal - 1) / resolution   where t_ideal = 1/32768
+ *
+ *   =>  t_measured / t_ideal = val * resolution + 1
+ *
+ * "offset" in the RTC interface is defined as:
+ *   t = t0 * (1 + offset * 1e-9)
+ * where t is the desired period, t0 is the measured period with a zero
+ * offset, which is t_measured above. With t0 = t_measured and t = t_ideal,
+ *   offset = (t_ideal / t_measured - 1) / 1e-9
+ *
+ *   => t_ideal / t_measured = offset * 1e-9 + 1
+ *
+ * so:
+ *
+ *   offset * 1e-9 + 1 = 1 / (val * resolution + 1)
+ *
+ * We want "resolution" to be an integer, so resolution = R * 1e-9, giving
+ *   offset = 1e18 / (val * R + 1e9) - 1e9
+ *   val = (1e18 / (offset + 1e9) - 1e9) / R
+ * with a common transformation:
+ *   f(x) = 1e18 / (x + 1e9) - 1e9
+ *   offset = f(val * R)
+ *   val = f(offset) / R
+ *
+ * Armada 38x supports two modes, fine mode (954ppb) and coarse mode (3815ppb).
+ */
+static long armada38x_ppb_convert(long ppb)
+{
+       long div = ppb + 1000000000L;
+
+       return div_s64(1000000000000000000LL + div / 2, div) - 1000000000L;
+}
+
+static int armada38x_rtc_read_offset(struct device *dev, long *offset)
+{
+       struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+       unsigned long ccr, flags;
+       long ppb_cor;
+
+       spin_lock_irqsave(&rtc->lock, flags);
+       ccr = rtc->data->read_rtc_reg(rtc, RTC_CCR);
+       spin_unlock_irqrestore(&rtc->lock, flags);
+
+       ppb_cor = (ccr & RTC_CCR_MODE ? 3815 : 954) * (s8)ccr;
+       /* ppb_cor + 1000000000L can never be zero */
+       *offset = armada38x_ppb_convert(ppb_cor);
+
+       return 0;
+}
+
+static int armada38x_rtc_set_offset(struct device *dev, long offset)
+{
+       struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+       unsigned long ccr = 0;
+       long ppb_cor, off;
+
+       /*
+        * The maximum ppb_cor is -128 * 3815 .. 127 * 3815, but we
+        * need to clamp the input.  This equates to -484270 .. 488558.
+        * Not only is this to stop out of range "off" but also to
+        * avoid the division by zero in armada38x_ppb_convert().
+        */
+       offset = clamp(offset, -484270L, 488558L);
+
+       ppb_cor = armada38x_ppb_convert(offset);
+
+       /*
+        * Use low update mode where possible, which gives a better
+        * resolution of correction.
+        */
+       off = DIV_ROUND_CLOSEST(ppb_cor, 954);
+       if (off > 127 || off < -128) {
+               ccr = RTC_CCR_MODE;
+               off = DIV_ROUND_CLOSEST(ppb_cor, 3815);
+       }
+
+       /*
+        * Armada 388 requires a bit pattern in bits 14..8 depending on
+        * the sign bit: { 0, ~S, S, S, S, S, S }
+        */
+       ccr |= (off & 0x3fff) ^ 0x2000;
+       rtc_delayed_write(ccr, rtc, RTC_CCR);
+
+       return 0;
+}
+
 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,
        .set_alarm = armada38x_rtc_set_alarm,
        .alarm_irq_enable = armada38x_rtc_alarm_irq_enable,
+       .read_offset = armada38x_rtc_read_offset,
+       .set_offset = armada38x_rtc_set_offset,
 };
 
 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,
+       .read_offset = armada38x_rtc_read_offset,
+       .set_offset = armada38x_rtc_set_offset,
 };
 
 static const struct armada38x_rtc_data armada38x_data = {
index e221b78b6f106ec3ccde7c3326b5934c48153f9c..de81ecedd571d8e0a1ff5ba1f5df59673d5efc60 100644 (file)
@@ -42,8 +42,6 @@
 #define at91_rtc_write(field, val) \
        writel_relaxed((val), at91_rtc_regs + field)
 
-#define AT91_RTC_EPOCH         1900UL  /* just like arch/arm/common/rtctime.c */
-
 struct at91_rtc_config {
        bool use_shadow_imr;
 };
@@ -51,7 +49,6 @@ struct at91_rtc_config {
 static const struct at91_rtc_config *at91_rtc_config;
 static DECLARE_COMPLETION(at91_rtc_updated);
 static DECLARE_COMPLETION(at91_rtc_upd_rdy);
-static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
 static void __iomem *at91_rtc_regs;
 static int irq;
 static DEFINE_SPINLOCK(at91_rtc_lock);
@@ -131,8 +128,7 @@ static void at91_rtc_decodetime(unsigned int timereg, unsigned int calreg,
 
        /*
         * The Calendar Alarm register does not have a field for
-        * the year - so these will return an invalid value.  When an
-        * alarm is set, at91_alarm_year will store the current year.
+        * the year - so these will return an invalid value.
         */
        tm->tm_year  = bcd2bin(date & AT91_RTC_CENT) * 100;     /* century */
        tm->tm_year += bcd2bin((date & AT91_RTC_YEAR) >> 8);    /* year */
@@ -208,15 +204,14 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
        struct rtc_time *tm = &alrm->time;
 
        at91_rtc_decodetime(AT91_RTC_TIMALR, AT91_RTC_CALALR, tm);
-       tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
-       tm->tm_year = at91_alarm_year - 1900;
+       tm->tm_year = -1;
 
        alrm->enabled = (at91_rtc_read_imr() & AT91_RTC_ALARM)
                        ? 1 : 0;
 
-       dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
-               1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
-               tm->tm_hour, tm->tm_min, tm->tm_sec);
+       dev_dbg(dev, "%s(): %02d-%02d %02d:%02d:%02d %sabled\n", __func__,
+               tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec,
+               alrm->enabled ? "en" : "dis");
 
        return 0;
 }
@@ -230,8 +225,6 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 
        at91_rtc_decodetime(AT91_RTC_TIMR, AT91_RTC_CALR, &tm);
 
-       at91_alarm_year = tm.tm_year;
-
        tm.tm_mon = alrm->time.tm_mon;
        tm.tm_mday = alrm->time.tm_mday;
        tm.tm_hour = alrm->time.tm_hour;
@@ -255,7 +248,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
        }
 
        dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
-               at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
+               tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
                tm.tm_min, tm.tm_sec);
 
        return 0;
index 72b22935eb62a0e9d71da4552ab64d0ace6ccd39..d8df2e9e14adb94e45a01655ee773cb76f10e28a 100644 (file)
@@ -514,56 +514,43 @@ static void msg_init(struct spi_message *m, struct spi_transfer *x,
        spi_message_add_tail(x, m);
 }
 
-static ssize_t
-ds1305_nvram_read(struct file *filp, struct kobject *kobj,
-               struct bin_attribute *attr,
-               char *buf, loff_t off, size_t count)
+static int ds1305_nvram_read(void *priv, unsigned int off, void *buf,
+                            size_t count)
 {
-       struct spi_device       *spi;
+       struct ds1305           *ds1305 = priv;
+       struct spi_device       *spi = ds1305->spi;
        u8                      addr;
        struct spi_message      m;
        struct spi_transfer     x[2];
-       int                     status;
-
-       spi = to_spi_device(kobj_to_dev(kobj));
 
        addr = DS1305_NVRAM + off;
        msg_init(&m, x, &addr, count, NULL, buf);
 
-       status = spi_sync(spi, &m);
-       if (status < 0)
-               dev_err(&spi->dev, "nvram %s error %d\n", "read", status);
-       return (status < 0) ? status : count;
+       return spi_sync(spi, &m);
 }
 
-static ssize_t
-ds1305_nvram_write(struct file *filp, struct kobject *kobj,
-               struct bin_attribute *attr,
-               char *buf, loff_t off, size_t count)
+static int ds1305_nvram_write(void *priv, unsigned int off, void *buf,
+                             size_t count)
 {
-       struct spi_device       *spi;
+       struct ds1305           *ds1305 = priv;
+       struct spi_device       *spi = ds1305->spi;
        u8                      addr;
        struct spi_message      m;
        struct spi_transfer     x[2];
-       int                     status;
-
-       spi = to_spi_device(kobj_to_dev(kobj));
 
        addr = (DS1305_WRITE | DS1305_NVRAM) + off;
        msg_init(&m, x, &addr, count, buf, NULL);
 
-       status = spi_sync(spi, &m);
-       if (status < 0)
-               dev_err(&spi->dev, "nvram %s error %d\n", "write", status);
-       return (status < 0) ? status : count;
+       return spi_sync(spi, &m);
 }
 
-static struct bin_attribute nvram = {
-       .attr.name      = "nvram",
-       .attr.mode      = S_IRUGO | S_IWUSR,
-       .read           = ds1305_nvram_read,
-       .write          = ds1305_nvram_write,
-       .size           = DS1305_NVRAM_LEN,
+static struct nvmem_config ds1305_nvmem_cfg = {
+       .name = "ds1305_nvram",
+       .word_size = 1,
+       .stride = 1,
+       .size = DS1305_NVRAM_LEN,
+       .reg_read = ds1305_nvram_read,
+       .reg_write = ds1305_nvram_write,
 };
 
 /*----------------------------------------------------------------------*/
@@ -708,10 +695,19 @@ static int ds1305_probe(struct spi_device *spi)
                dev_dbg(&spi->dev, "AM/PM\n");
 
        /* register RTC ... from here on, ds1305->ctrl needs locking */
-       ds1305->rtc = devm_rtc_device_register(&spi->dev, "ds1305",
-                       &ds1305_ops, THIS_MODULE);
+       ds1305->rtc = devm_rtc_allocate_device(&spi->dev);
        if (IS_ERR(ds1305->rtc)) {
-               status = PTR_ERR(ds1305->rtc);
+               return PTR_ERR(ds1305->rtc);
+       }
+
+       ds1305->rtc->ops = &ds1305_ops;
+
+       ds1305_nvmem_cfg.priv = ds1305;
+       ds1305->rtc->nvmem_config = &ds1305_nvmem_cfg;
+       ds1305->rtc->nvram_old_abi = true;
+
+       status = rtc_register_device(ds1305->rtc);
+       if (status) {
                dev_dbg(&spi->dev, "register rtc --> %d\n", status);
                return status;
        }
@@ -734,12 +730,6 @@ static int ds1305_probe(struct spi_device *spi)
                }
        }
 
-       /* export NVRAM */
-       status = sysfs_create_bin_file(&spi->dev.kobj, &nvram);
-       if (status < 0) {
-               dev_err(&spi->dev, "register nvram --> %d\n", status);
-       }
-
        return 0;
 }
 
@@ -747,8 +737,6 @@ static int ds1305_remove(struct spi_device *spi)
 {
        struct ds1305 *ds1305 = spi_get_drvdata(spi);
 
-       sysfs_remove_bin_file(&spi->dev.kobj, &nvram);
-
        /* carefully shut down irq and workqueue, if present */
        if (spi->irq) {
                set_bit(FLAG_EXITING, &ds1305->flags);
index e7d9215c9201b14fe66aaefb8c7379aeb8ae6e00..923dde912f604094219c5860794080888308df1f 100644 (file)
@@ -325,6 +325,10 @@ static const struct of_device_id ds1307_of_match[] = {
                .compatible = "isil,isl12057",
                .data = (void *)ds_1337
        },
+       {
+               .compatible = "epson,rx8130",
+               .data = (void *)rx_8130
+       },
        { }
 };
 MODULE_DEVICE_TABLE(of, ds1307_of_match);
@@ -348,6 +352,7 @@ static const struct acpi_device_id ds1307_acpi_ids[] = {
        { .id = "PT7C4338", .driver_data = ds_1307 },
        { .id = "RX8025", .driver_data = rx_8025 },
        { .id = "ISL12057", .driver_data = ds_1337 },
+       { .id = "RX8130", .driver_data = rx_8130 },
        { }
 };
 MODULE_DEVICE_TABLE(acpi, ds1307_acpi_ids);
@@ -787,8 +792,6 @@ static int rx8130_alarm_irq_enable(struct device *dev, unsigned int enabled)
  * Alarm support for mcp794xx devices.
  */
 
-#define MCP794XX_REG_WEEKDAY           0x3
-#define MCP794XX_REG_WEEKDAY_WDAY_MASK 0x7
 #define MCP794XX_REG_CONTROL           0x07
 #      define MCP794XX_BIT_ALM0_EN     0x10
 #      define MCP794XX_BIT_ALM1_EN     0x20
@@ -877,15 +880,38 @@ static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t)
        return 0;
 }
 
+/*
+ * We may have a random RTC weekday, therefore calculate alarm weekday based
+ * on current weekday we read from the RTC timekeeping regs
+ */
+static int mcp794xx_alm_weekday(struct device *dev, struct rtc_time *tm_alarm)
+{
+       struct rtc_time tm_now;
+       int days_now, days_alarm, ret;
+
+       ret = ds1307_get_time(dev, &tm_now);
+       if (ret)
+               return ret;
+
+       days_now = div_s64(rtc_tm_to_time64(&tm_now), 24 * 60 * 60);
+       days_alarm = div_s64(rtc_tm_to_time64(tm_alarm), 24 * 60 * 60);
+
+       return (tm_now.tm_wday + days_alarm - days_now) % 7 + 1;
+}
+
 static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
        struct ds1307 *ds1307 = dev_get_drvdata(dev);
        unsigned char regs[10];
-       int ret;
+       int wday, ret;
 
        if (!test_bit(HAS_ALARM, &ds1307->flags))
                return -EINVAL;
 
+       wday = mcp794xx_alm_weekday(dev, &t->time);
+       if (wday < 0)
+               return wday;
+
        dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d "
                "enabled=%d pending=%d\n", __func__,
                t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
@@ -902,7 +928,7 @@ static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        regs[3] = bin2bcd(t->time.tm_sec);
        regs[4] = bin2bcd(t->time.tm_min);
        regs[5] = bin2bcd(t->time.tm_hour);
-       regs[6] = bin2bcd(t->time.tm_wday + 1);
+       regs[6] = wday;
        regs[7] = bin2bcd(t->time.tm_mday);
        regs[8] = bin2bcd(t->time.tm_mon + 1);
 
@@ -1354,14 +1380,12 @@ static int ds1307_probe(struct i2c_client *client,
 {
        struct ds1307           *ds1307;
        int                     err = -ENODEV;
-       int                     tmp, wday;
+       int                     tmp;
        const struct chip_desc  *chip;
        bool                    want_irq;
        bool                    ds1307_can_wakeup_device = false;
        unsigned char           regs[8];
        struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev);
-       struct rtc_time         tm;
-       unsigned long           timestamp;
        u8                      trickle_charger_setup = 0;
 
        ds1307 = devm_kzalloc(&client->dev, sizeof(struct ds1307), GFP_KERNEL);
@@ -1641,25 +1665,6 @@ read_rtc:
                             bin2bcd(tmp));
        }
 
-       /*
-        * Some IPs have weekday reset value = 0x1 which might not correct
-        * hence compute the wday using the current date/month/year values
-        */
-       ds1307_get_time(ds1307->dev, &tm);
-       wday = tm.tm_wday;
-       timestamp = rtc_tm_to_time64(&tm);
-       rtc_time64_to_tm(timestamp, &tm);
-
-       /*
-        * Check if reset wday is different from the computed wday
-        * If different then set the wday which we computed using
-        * timestamp
-        */
-       if (wday != tm.tm_wday)
-               regmap_update_bits(ds1307->regmap, MCP794XX_REG_WEEKDAY,
-                                  MCP794XX_REG_WEEKDAY_WDAY_MASK,
-                                  tm.tm_wday + 1);
-
        if (want_irq || ds1307_can_wakeup_device) {
                device_set_wakeup_capable(ds1307->dev, true);
                set_bit(HAS_ALARM, &ds1307->flags);
index aa0d2c6f1edc235d00d2da56be0d55b9d88ed44a..4d5b007d7fc68cfbe71cc6f4c577b5bc4cc357e3 100644 (file)
@@ -216,9 +216,16 @@ static int ds1390_probe(struct spi_device *spi)
        return res;
 }
 
+static const struct of_device_id ds1390_of_match[] = {
+       { .compatible = "dallas,ds1390" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, ds1390_of_match);
+
 static struct spi_driver ds1390_driver = {
        .driver = {
                .name   = "rtc-ds1390",
+               .of_match_table = of_match_ptr(ds1390_of_match),
        },
        .probe  = ds1390_probe,
 };
index 1b2dcb58c0abf84801a83e2974651f55860ac0d1..1e95312a6f2eecdce510a7cdd79a2b59fa37f037 100644 (file)
@@ -398,42 +398,37 @@ static const struct rtc_class_ops ds1511_rtc_ops = {
        .alarm_irq_enable       = ds1511_rtc_alarm_irq_enable,
 };
 
-static ssize_t
-ds1511_nvram_read(struct file *filp, struct kobject *kobj,
-                 struct bin_attribute *ba,
-                 char *buf, loff_t pos, size_t size)
+static int ds1511_nvram_read(void *priv, unsigned int pos, void *buf,
+                            size_t size)
 {
-       ssize_t count;
+       int i;
 
        rtc_write(pos, DS1511_RAMADDR_LSB);
-       for (count = 0; count < size; count++)
-               *buf++ = rtc_read(DS1511_RAMDATA);
+       for (i = 0; i < size; i++)
+               *(char *)buf++ = rtc_read(DS1511_RAMDATA);
 
-       return count;
+       return 0;
 }
 
-static ssize_t
-ds1511_nvram_write(struct file *filp, struct kobject *kobj,
-                  struct bin_attribute *bin_attr,
-                  char *buf, loff_t pos, size_t size)
+static int ds1511_nvram_write(void *priv, unsigned int pos, void *buf,
+                             size_t size)
 {
-       ssize_t count;
+       int i;
 
        rtc_write(pos, DS1511_RAMADDR_LSB);
-       for (count = 0; count < size; count++)
-               rtc_write(*buf++, DS1511_RAMDATA);
+       for (i = 0; i < size; i++)
+               rtc_write(*(char *)buf++, DS1511_RAMDATA);
 
-       return count;
+       return 0;
 }
 
-static struct bin_attribute ds1511_nvram_attr = {
-       .attr = {
-               .name = "nvram",
-               .mode = S_IRUGO | S_IWUSR,
-       },
+static struct nvmem_config ds1511_nvmem_cfg = {
+       .name = "ds1511_nvram",
+       .word_size = 1,
+       .stride = 1,
        .size = DS1511_RAM_MAX,
-       .read = ds1511_nvram_read,
-       .write = ds1511_nvram_write,
+       .reg_read = ds1511_nvram_read,
+       .reg_write = ds1511_nvram_write,
 };
 
 static int ds1511_rtc_probe(struct platform_device *pdev)
@@ -477,11 +472,20 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
        spin_lock_init(&pdata->lock);
        platform_set_drvdata(pdev, pdata);
 
-       pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
-                                             &ds1511_rtc_ops, THIS_MODULE);
+       pdata->rtc = devm_rtc_allocate_device(&pdev->dev);
        if (IS_ERR(pdata->rtc))
                return PTR_ERR(pdata->rtc);
 
+       pdata->rtc->ops = &ds1511_rtc_ops;
+
+       ds1511_nvmem_cfg.priv = &pdev->dev;
+       pdata->rtc->nvmem_config = &ds1511_nvmem_cfg;
+       pdata->rtc->nvram_old_abi = true;
+
+       ret = rtc_register_device(pdata->rtc);
+       if (ret)
+               return ret;
+
        /*
         * if the platform has an interrupt in mind for this device,
         * then by all means, set it
@@ -496,26 +500,6 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
                }
        }
 
-       ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
-       if (ret)
-               dev_err(&pdev->dev, "Unable to create sysfs entry: %s\n",
-                       ds1511_nvram_attr.attr.name);
-
-       return 0;
-}
-
-static int ds1511_rtc_remove(struct platform_device *pdev)
-{
-       struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
-
-       sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
-       if (pdata->irq > 0) {
-               /*
-                * disable the alarm interrupt
-                */
-               rtc_write(rtc_read(RTC_CMD) & ~RTC_TIE, RTC_CMD);
-               rtc_read(RTC_CMD1);
-       }
        return 0;
 }
 
@@ -524,7 +508,6 @@ MODULE_ALIAS("platform:ds1511");
 
 static struct platform_driver ds1511_rtc_driver = {
        .probe          = ds1511_rtc_probe,
-       .remove         = ds1511_rtc_remove,
        .driver         = {
                .name   = "ds1511",
        },
index 64989afffa3daada4b062321c527f18bca142bbb..ff65a7d2b9c9366c689d2efa09b5cc99ec3b5735 100644 (file)
@@ -82,7 +82,7 @@ static inline uint32_t jz4740_rtc_reg_read(struct jz4740_rtc *rtc, size_t reg)
 static int jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc)
 {
        uint32_t ctrl;
-       int timeout = 1000;
+       int timeout = 10000;
 
        do {
                ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL);
@@ -94,7 +94,7 @@ static int jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc)
 static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc)
 {
        uint32_t ctrl;
-       int ret, timeout = 1000;
+       int ret, timeout = 10000;
 
        ret = jz4740_rtc_wait_write_ready(rtc);
        if (ret != 0)
@@ -368,7 +368,7 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
                ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SCRATCHPAD, 0x12345678);
                ret = jz4740_rtc_reg_write(rtc, JZ_REG_RTC_SEC, 0);
                if (ret) {
-                       dev_err(&pdev->dev, "Could not write write to RTC registers\n");
+                       dev_err(&pdev->dev, "Could not write to RTC registers\n");
                        return ret;
                }
        }
index f4c070ea83849a9e67f700519f0f83b8b7541227..c90fba3ed861881c0c813361dfaece9efac60938 100644 (file)
@@ -154,6 +154,8 @@ struct m41t80_data {
        struct rtc_device *rtc;
 #ifdef CONFIG_COMMON_CLK
        struct clk_hw sqw;
+       unsigned long freq;
+       unsigned int sqwe;
 #endif
 };
 
@@ -443,43 +445,40 @@ static SIMPLE_DEV_PM_OPS(m41t80_pm, m41t80_suspend, m41t80_resume);
 #ifdef CONFIG_COMMON_CLK
 #define sqw_to_m41t80_data(_hw) container_of(_hw, struct m41t80_data, sqw)
 
-static unsigned long m41t80_sqw_recalc_rate(struct clk_hw *hw,
-                                           unsigned long parent_rate)
+static unsigned long m41t80_decode_freq(int setting)
+{
+       return (setting == 0) ? 0 : (setting == 1) ? M41T80_SQW_MAX_FREQ :
+               M41T80_SQW_MAX_FREQ >> setting;
+}
+
+static unsigned long m41t80_get_freq(struct m41t80_data *m41t80)
 {
-       struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw);
        struct i2c_client *client = m41t80->client;
        int reg_sqw = (m41t80->features & M41T80_FEATURE_SQ_ALT) ?
                M41T80_REG_WDAY : M41T80_REG_SQW;
        int ret = i2c_smbus_read_byte_data(client, reg_sqw);
-       unsigned long val = M41T80_SQW_MAX_FREQ;
 
        if (ret < 0)
                return 0;
+       return m41t80_decode_freq(ret >> 4);
+}
 
-       ret >>= 4;
-       if (ret == 0)
-               val = 0;
-       else if (ret > 1)
-               val = val / (1 << ret);
-
-       return val;
+static unsigned long m41t80_sqw_recalc_rate(struct clk_hw *hw,
+                                           unsigned long parent_rate)
+{
+       return sqw_to_m41t80_data(hw)->freq;
 }
 
 static long m41t80_sqw_round_rate(struct clk_hw *hw, unsigned long rate,
                                  unsigned long *prate)
 {
-       int i, freq = M41T80_SQW_MAX_FREQ;
-
-       if (freq <= rate)
-               return freq;
-
-       for (i = 2; i <= ilog2(M41T80_SQW_MAX_FREQ); i++) {
-               freq /= 1 << i;
-               if (freq <= rate)
-                       return freq;
-       }
-
-       return 0;
+       if (rate >= M41T80_SQW_MAX_FREQ)
+               return M41T80_SQW_MAX_FREQ;
+       if (rate >= M41T80_SQW_MAX_FREQ / 4)
+               return M41T80_SQW_MAX_FREQ / 4;
+       if (!rate)
+               return 0;
+       return 1 << ilog2(rate);
 }
 
 static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
@@ -491,17 +490,12 @@ static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
                M41T80_REG_WDAY : M41T80_REG_SQW;
        int reg, ret, val = 0;
 
-       if (rate) {
-               if (!is_power_of_2(rate))
-                       return -EINVAL;
-               val = ilog2(rate);
-               if (val == ilog2(M41T80_SQW_MAX_FREQ))
-                       val = 1;
-               else if (val < (ilog2(M41T80_SQW_MAX_FREQ) - 1))
-                       val = ilog2(M41T80_SQW_MAX_FREQ) - val;
-               else
-                       return -EINVAL;
-       }
+       if (rate >= M41T80_SQW_MAX_FREQ)
+               val = 1;
+       else if (rate >= M41T80_SQW_MAX_FREQ / 4)
+               val = 2;
+       else if (rate)
+               val = 15 - ilog2(rate);
 
        reg = i2c_smbus_read_byte_data(client, reg_sqw);
        if (reg < 0)
@@ -510,10 +504,9 @@ static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
        reg = (reg & 0x0f) | (val << 4);
 
        ret = i2c_smbus_write_byte_data(client, reg_sqw, reg);
-       if (ret < 0)
-               return ret;
-
-       return -EINVAL;
+       if (!ret)
+               m41t80->freq = m41t80_decode_freq(val);
+       return ret;
 }
 
 static int m41t80_sqw_control(struct clk_hw *hw, bool enable)
@@ -530,7 +523,10 @@ static int m41t80_sqw_control(struct clk_hw *hw, bool enable)
        else
                ret &= ~M41T80_ALMON_SQWE;
 
-       return i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, ret);
+       ret = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, ret);
+       if (!ret)
+               m41t80->sqwe = enable;
+       return ret;
 }
 
 static int m41t80_sqw_prepare(struct clk_hw *hw)
@@ -545,14 +541,7 @@ static void m41t80_sqw_unprepare(struct clk_hw *hw)
 
 static int m41t80_sqw_is_prepared(struct clk_hw *hw)
 {
-       struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw);
-       struct i2c_client *client = m41t80->client;
-       int ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
-
-       if (ret < 0)
-               return ret;
-
-       return !!(ret & M41T80_ALMON_SQWE);
+       return sqw_to_m41t80_data(hw)->sqwe;
 }
 
 static const struct clk_ops m41t80_sqw_ops = {
@@ -587,6 +576,7 @@ static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80)
        init.parent_names = NULL;
        init.num_parents = 0;
        m41t80->sqw.init = &init;
+       m41t80->freq = m41t80_get_freq(m41t80);
 
        /* optional override of the clockname */
        of_property_read_string(node, "clock-output-names", &init.name);
index 02af045305dd3ce156a7f60b14cc153e548ce60c..d9aea9b6d9cd9189767e8ff074d1c78ffabf9ade 100644 (file)
@@ -163,35 +163,30 @@ static const struct rtc_class_ops m48t86_rtc_ops = {
        .proc           = m48t86_rtc_proc,
 };
 
-static ssize_t m48t86_nvram_read(struct file *filp, struct kobject *kobj,
-                                struct bin_attribute *attr,
-                                char *buf, loff_t off, size_t count)
+static int m48t86_nvram_read(void *priv, unsigned int off, void *buf,
+                            size_t count)
 {
-       struct device *dev = kobj_to_dev(kobj);
+       struct device *dev = priv;
        unsigned int i;
 
        for (i = 0; i < count; i++)
-               buf[i] = m48t86_readb(dev, M48T86_NVRAM(off + i));
+               ((u8 *)buf)[i] = m48t86_readb(dev, M48T86_NVRAM(off + i));
 
-       return count;
+       return 0;
 }
 
-static ssize_t m48t86_nvram_write(struct file *filp, struct kobject *kobj,
-                                 struct bin_attribute *attr,
-                                 char *buf, loff_t off, size_t count)
+static int m48t86_nvram_write(void *priv, unsigned int off, void *buf,
+                             size_t count)
 {
-       struct device *dev = kobj_to_dev(kobj);
+       struct device *dev = priv;
        unsigned int i;
 
        for (i = 0; i < count; i++)
-               m48t86_writeb(dev, buf[i], M48T86_NVRAM(off + i));
+               m48t86_writeb(dev, ((u8 *)buf)[i], M48T86_NVRAM(off + i));
 
-       return count;
+       return 0;
 }
 
-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
@@ -223,11 +218,21 @@ static bool m48t86_verify_chip(struct platform_device *pdev)
        return false;
 }
 
+static struct nvmem_config m48t86_nvmem_cfg = {
+       .name = "m48t86_nvram",
+       .word_size = 1,
+       .stride = 1,
+       .size = M48T86_NVRAM_LEN,
+       .reg_read = m48t86_nvram_read,
+       .reg_write = m48t86_nvram_write,
+};
+
 static int m48t86_rtc_probe(struct platform_device *pdev)
 {
        struct m48t86_rtc_info *info;
        struct resource *res;
        unsigned char reg;
+       int err;
 
        info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
        if (!info)
@@ -254,25 +259,25 @@ static int m48t86_rtc_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       info->rtc = devm_rtc_device_register(&pdev->dev, "m48t86",
-                                            &m48t86_rtc_ops, THIS_MODULE);
+       info->rtc = devm_rtc_allocate_device(&pdev->dev);
        if (IS_ERR(info->rtc))
                return PTR_ERR(info->rtc);
 
+       info->rtc->ops = &m48t86_rtc_ops;
+
+       m48t86_nvmem_cfg.priv = &pdev->dev;
+       info->rtc->nvmem_config = &m48t86_nvmem_cfg;
+       info->rtc->nvram_old_abi = true;
+
+       err = rtc_register_device(info->rtc);
+       if (err)
+               return err;
+
        /* read battery status */
        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;
 }
 
@@ -281,7 +286,6 @@ 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);
diff --git a/drivers/rtc/rtc-mt7622.c b/drivers/rtc/rtc-mt7622.c
new file mode 100644 (file)
index 0000000..d79b9ae
--- /dev/null
@@ -0,0 +1,422 @@
+/*
+ * Driver for MediaTek SoC based RTC
+ *
+ * Copyright (C) 2017 Sean Wang <sean.wang@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#define MTK_RTC_DEV KBUILD_MODNAME
+
+#define MTK_RTC_PWRCHK1                0x4
+#define        RTC_PWRCHK1_MAGIC       0xc6
+
+#define MTK_RTC_PWRCHK2                0x8
+#define        RTC_PWRCHK2_MAGIC       0x9a
+
+#define MTK_RTC_KEY            0xc
+#define        RTC_KEY_MAGIC           0x59
+
+#define MTK_RTC_PROT1          0x10
+#define        RTC_PROT1_MAGIC         0xa3
+
+#define MTK_RTC_PROT2          0x14
+#define        RTC_PROT2_MAGIC         0x57
+
+#define MTK_RTC_PROT3          0x18
+#define        RTC_PROT3_MAGIC         0x67
+
+#define MTK_RTC_PROT4          0x1c
+#define        RTC_PROT4_MAGIC         0xd2
+
+#define MTK_RTC_CTL            0x20
+#define        RTC_RC_STOP             BIT(0)
+
+#define MTK_RTC_DEBNCE         0x2c
+#define        RTC_DEBNCE_MASK         GENMASK(2, 0)
+
+#define MTK_RTC_INT            0x30
+#define RTC_INT_AL_STA         BIT(4)
+
+/*
+ * Ranges from 0x40 to 0x78 provide RTC time setup for year, month,
+ * day of month, day of week, hour, minute and second.
+ */
+#define MTK_RTC_TREG(_t, _f)   (0x40 + (0x4 * (_f)) + ((_t) * 0x20))
+
+#define MTK_RTC_AL_CTL         0x7c
+#define        RTC_AL_EN               BIT(0)
+#define        RTC_AL_ALL              GENMASK(7, 0)
+
+/*
+ * The offset is used in the translation for the year between in struct
+ * rtc_time and in hardware register MTK_RTC_TREG(x,MTK_YEA)
+ */
+#define MTK_RTC_TM_YR_OFFSET   100
+
+/*
+ * The lowest value for the valid tm_year. RTC hardware would take incorrectly
+ * tm_year 100 as not a leap year and thus it is also required being excluded
+ * from the valid options.
+ */
+#define MTK_RTC_TM_YR_L                (MTK_RTC_TM_YR_OFFSET + 1)
+
+/*
+ * The most year the RTC can hold is 99 and the next to 99 in year register
+ * would be wraparound to 0, for MT7622.
+ */
+#define MTK_RTC_HW_YR_LIMIT    99
+
+/* The highest value for the valid tm_year */
+#define MTK_RTC_TM_YR_H                (MTK_RTC_TM_YR_OFFSET + MTK_RTC_HW_YR_LIMIT)
+
+/* Simple macro helps to check whether the hardware supports the tm_year */
+#define MTK_RTC_TM_YR_VALID(_y)        ((_y) >= MTK_RTC_TM_YR_L && \
+                                (_y) <= MTK_RTC_TM_YR_H)
+
+/* Types of the function the RTC provides are time counter and alarm. */
+enum {
+       MTK_TC,
+       MTK_AL,
+};
+
+/* Indexes are used for the pointer to relevant registers in MTK_RTC_TREG */
+enum {
+       MTK_YEA,
+       MTK_MON,
+       MTK_DOM,
+       MTK_DOW,
+       MTK_HOU,
+       MTK_MIN,
+       MTK_SEC
+};
+
+struct mtk_rtc {
+       struct rtc_device *rtc;
+       void __iomem *base;
+       int irq;
+       struct clk *clk;
+};
+
+static void mtk_w32(struct mtk_rtc *rtc, u32 reg, u32 val)
+{
+       writel_relaxed(val, rtc->base + reg);
+}
+
+static u32 mtk_r32(struct mtk_rtc *rtc, u32 reg)
+{
+       return readl_relaxed(rtc->base + reg);
+}
+
+static void mtk_rmw(struct mtk_rtc *rtc, u32 reg, u32 mask, u32 set)
+{
+       u32 val;
+
+       val = mtk_r32(rtc, reg);
+       val &= ~mask;
+       val |= set;
+       mtk_w32(rtc, reg, val);
+}
+
+static void mtk_set(struct mtk_rtc *rtc, u32 reg, u32 val)
+{
+       mtk_rmw(rtc, reg, 0, val);
+}
+
+static void mtk_clr(struct mtk_rtc *rtc, u32 reg, u32 val)
+{
+       mtk_rmw(rtc, reg, val, 0);
+}
+
+static void mtk_rtc_hw_init(struct mtk_rtc *hw)
+{
+       /* The setup of the init sequence is for allowing RTC got to work */
+       mtk_w32(hw, MTK_RTC_PWRCHK1, RTC_PWRCHK1_MAGIC);
+       mtk_w32(hw, MTK_RTC_PWRCHK2, RTC_PWRCHK2_MAGIC);
+       mtk_w32(hw, MTK_RTC_KEY, RTC_KEY_MAGIC);
+       mtk_w32(hw, MTK_RTC_PROT1, RTC_PROT1_MAGIC);
+       mtk_w32(hw, MTK_RTC_PROT2, RTC_PROT2_MAGIC);
+       mtk_w32(hw, MTK_RTC_PROT3, RTC_PROT3_MAGIC);
+       mtk_w32(hw, MTK_RTC_PROT4, RTC_PROT4_MAGIC);
+       mtk_rmw(hw, MTK_RTC_DEBNCE, RTC_DEBNCE_MASK, 0);
+       mtk_clr(hw, MTK_RTC_CTL, RTC_RC_STOP);
+}
+
+static void mtk_rtc_get_alarm_or_time(struct mtk_rtc *hw, struct rtc_time *tm,
+                                     int time_alarm)
+{
+       u32 year, mon, mday, wday, hour, min, sec;
+
+       /*
+        * Read again until the field of the second is not changed which
+        * ensures all fields in the consistent state. Note that MTK_SEC must
+        * be read first. In this way, it guarantees the others remain not
+        * changed when the results for two MTK_SEC consecutive reads are same.
+        */
+       do {
+               sec = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_SEC));
+               min = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_MIN));
+               hour = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_HOU));
+               wday = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_DOW));
+               mday = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_DOM));
+               mon = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_MON));
+               year = mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_YEA));
+       } while (sec != mtk_r32(hw, MTK_RTC_TREG(time_alarm, MTK_SEC)));
+
+       tm->tm_sec  = sec;
+       tm->tm_min  = min;
+       tm->tm_hour = hour;
+       tm->tm_wday = wday;
+       tm->tm_mday = mday;
+       tm->tm_mon  = mon - 1;
+
+       /* Rebase to the absolute year which userspace queries */
+       tm->tm_year = year + MTK_RTC_TM_YR_OFFSET;
+}
+
+static void mtk_rtc_set_alarm_or_time(struct mtk_rtc *hw, struct rtc_time *tm,
+                                     int time_alarm)
+{
+       u32 year;
+
+       /* Rebase to the relative year which RTC hardware requires */
+       year = tm->tm_year - MTK_RTC_TM_YR_OFFSET;
+
+       mtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_YEA), year);
+       mtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_MON), tm->tm_mon + 1);
+       mtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_DOW), tm->tm_wday);
+       mtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_DOM), tm->tm_mday);
+       mtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_HOU), tm->tm_hour);
+       mtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_MIN), tm->tm_min);
+       mtk_w32(hw, MTK_RTC_TREG(time_alarm, MTK_SEC), tm->tm_sec);
+}
+
+static irqreturn_t mtk_rtc_alarmirq(int irq, void *id)
+{
+       struct mtk_rtc *hw = (struct mtk_rtc *)id;
+       u32 irq_sta;
+
+       irq_sta = mtk_r32(hw, MTK_RTC_INT);
+       if (irq_sta & RTC_INT_AL_STA) {
+               /* Stop alarm also implicitly disables the alarm interrupt */
+               mtk_w32(hw, MTK_RTC_AL_CTL, 0);
+               rtc_update_irq(hw->rtc, 1, RTC_IRQF | RTC_AF);
+
+               /* Ack alarm interrupt status */
+               mtk_w32(hw, MTK_RTC_INT, RTC_INT_AL_STA);
+               return IRQ_HANDLED;
+       }
+
+       return IRQ_NONE;
+}
+
+static int mtk_rtc_gettime(struct device *dev, struct rtc_time *tm)
+{
+       struct mtk_rtc *hw = dev_get_drvdata(dev);
+
+       mtk_rtc_get_alarm_or_time(hw, tm, MTK_TC);
+
+       return rtc_valid_tm(tm);
+}
+
+static int mtk_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+       struct mtk_rtc *hw = dev_get_drvdata(dev);
+
+       if (!MTK_RTC_TM_YR_VALID(tm->tm_year))
+               return -EINVAL;
+
+       /* Stop time counter before setting a new one*/
+       mtk_set(hw, MTK_RTC_CTL, RTC_RC_STOP);
+
+       mtk_rtc_set_alarm_or_time(hw, tm, MTK_TC);
+
+       /* Restart the time counter */
+       mtk_clr(hw, MTK_RTC_CTL, RTC_RC_STOP);
+
+       return 0;
+}
+
+static int mtk_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+       struct mtk_rtc *hw = dev_get_drvdata(dev);
+       struct rtc_time *alrm_tm = &wkalrm->time;
+
+       mtk_rtc_get_alarm_or_time(hw, alrm_tm, MTK_AL);
+
+       wkalrm->enabled = !!(mtk_r32(hw, MTK_RTC_AL_CTL) & RTC_AL_EN);
+       wkalrm->pending = !!(mtk_r32(hw, MTK_RTC_INT) & RTC_INT_AL_STA);
+
+       return 0;
+}
+
+static int mtk_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm)
+{
+       struct mtk_rtc *hw = dev_get_drvdata(dev);
+       struct rtc_time *alrm_tm = &wkalrm->time;
+
+       if (!MTK_RTC_TM_YR_VALID(alrm_tm->tm_year))
+               return -EINVAL;
+
+       /*
+        * Stop the alarm also implicitly including disables interrupt before
+        * setting a new one.
+        */
+       mtk_clr(hw, MTK_RTC_AL_CTL, RTC_AL_EN);
+
+       /*
+        * Avoid contention between mtk_rtc_setalarm and IRQ handler so that
+        * disabling the interrupt and awaiting for pending IRQ handler to
+        * complete.
+        */
+       synchronize_irq(hw->irq);
+
+       mtk_rtc_set_alarm_or_time(hw, alrm_tm, MTK_AL);
+
+       /* Restart the alarm with the new setup */
+       mtk_w32(hw, MTK_RTC_AL_CTL, RTC_AL_ALL);
+
+       return 0;
+}
+
+static const struct rtc_class_ops mtk_rtc_ops = {
+       .read_time              = mtk_rtc_gettime,
+       .set_time               = mtk_rtc_settime,
+       .read_alarm             = mtk_rtc_getalarm,
+       .set_alarm              = mtk_rtc_setalarm,
+};
+
+static const struct of_device_id mtk_rtc_match[] = {
+       { .compatible = "mediatek,mt7622-rtc" },
+       { .compatible = "mediatek,soc-rtc" },
+       {},
+};
+
+static int mtk_rtc_probe(struct platform_device *pdev)
+{
+       struct mtk_rtc *hw;
+       struct resource *res;
+       int ret;
+
+       hw = devm_kzalloc(&pdev->dev, sizeof(*hw), GFP_KERNEL);
+       if (!hw)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, hw);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       hw->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(hw->base))
+               return PTR_ERR(hw->base);
+
+       hw->clk = devm_clk_get(&pdev->dev, "rtc");
+       if (IS_ERR(hw->clk)) {
+               dev_err(&pdev->dev, "No clock\n");
+               return PTR_ERR(hw->clk);
+       }
+
+       ret = clk_prepare_enable(hw->clk);
+       if (ret)
+               return ret;
+
+       hw->irq = platform_get_irq(pdev, 0);
+       if (hw->irq < 0) {
+               dev_err(&pdev->dev, "No IRQ resource\n");
+               ret = hw->irq;
+               goto err;
+       }
+
+       ret = devm_request_irq(&pdev->dev, hw->irq, mtk_rtc_alarmirq,
+                              0, dev_name(&pdev->dev), hw);
+       if (ret) {
+               dev_err(&pdev->dev, "Can't request IRQ\n");
+               goto err;
+       }
+
+       mtk_rtc_hw_init(hw);
+
+       device_init_wakeup(&pdev->dev, true);
+
+       hw->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+                                          &mtk_rtc_ops, THIS_MODULE);
+       if (IS_ERR(hw->rtc)) {
+               ret = PTR_ERR(hw->rtc);
+               dev_err(&pdev->dev, "Unable to register device\n");
+               goto err;
+       }
+
+       return 0;
+err:
+       clk_disable_unprepare(hw->clk);
+
+       return ret;
+}
+
+static int mtk_rtc_remove(struct platform_device *pdev)
+{
+       struct mtk_rtc *hw = platform_get_drvdata(pdev);
+
+       clk_disable_unprepare(hw->clk);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_rtc_suspend(struct device *dev)
+{
+       struct mtk_rtc *hw = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               enable_irq_wake(hw->irq);
+
+       return 0;
+}
+
+static int mtk_rtc_resume(struct device *dev)
+{
+       struct mtk_rtc *hw = dev_get_drvdata(dev);
+
+       if (device_may_wakeup(dev))
+               disable_irq_wake(hw->irq);
+
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(mtk_rtc_pm_ops, mtk_rtc_suspend, mtk_rtc_resume);
+
+#define MTK_RTC_PM_OPS (&mtk_rtc_pm_ops)
+#else  /* CONFIG_PM */
+#define MTK_RTC_PM_OPS NULL
+#endif /* CONFIG_PM */
+
+static struct platform_driver mtk_rtc_driver = {
+       .probe  = mtk_rtc_probe,
+       .remove = mtk_rtc_remove,
+       .driver = {
+               .name = MTK_RTC_DEV,
+               .of_match_table = mtk_rtc_match,
+               .pm = MTK_RTC_PM_OPS,
+       },
+};
+
+module_platform_driver(mtk_rtc_driver);
+
+MODULE_DESCRIPTION("MediaTek SoC based RTC Driver");
+MODULE_AUTHOR("Sean Wang <sean.wang@mediatek.com>");
+MODULE_LICENSE("GPL");
index 13f7cd11c07eb52948121225242b57f8ab2c8e2c..1d666ac9ef706e083124516f18663a347e9db564 100644 (file)
 #define OMAP_RTC_COMP_MSB_REG          0x50
 #define OMAP_RTC_OSC_REG               0x54
 
+#define OMAP_RTC_SCRATCH0_REG          0x60
+#define OMAP_RTC_SCRATCH1_REG          0x64
+#define OMAP_RTC_SCRATCH2_REG          0x68
+
 #define OMAP_RTC_KICK0_REG             0x6c
 #define OMAP_RTC_KICK1_REG             0x70
 
@@ -667,6 +671,45 @@ static struct pinctrl_desc rtc_pinctrl_desc = {
        .owner = THIS_MODULE,
 };
 
+static int omap_rtc_scratch_read(void *priv, unsigned int offset, void *_val,
+                                size_t bytes)
+{
+       struct omap_rtc *rtc = priv;
+       u32 *val = _val;
+       int i;
+
+       for (i = 0; i < bytes / 4; i++)
+               val[i] = rtc_readl(rtc,
+                                  OMAP_RTC_SCRATCH0_REG + offset + (i * 4));
+
+       return 0;
+}
+
+static int omap_rtc_scratch_write(void *priv, unsigned int offset, void *_val,
+                                 size_t bytes)
+{
+       struct omap_rtc *rtc = priv;
+       u32 *val = _val;
+       int i;
+
+       rtc->type->unlock(rtc);
+       for (i = 0; i < bytes / 4; i++)
+               rtc_writel(rtc,
+                          OMAP_RTC_SCRATCH0_REG + offset + (i * 4), val[i]);
+       rtc->type->lock(rtc);
+
+       return 0;
+}
+
+static struct nvmem_config omap_rtc_nvmem_config = {
+       .name = "omap_rtc_scratch",
+       .word_size = 4,
+       .stride = 4,
+       .size = OMAP_RTC_KICK0_REG - OMAP_RTC_SCRATCH0_REG,
+       .reg_read = omap_rtc_scratch_read,
+       .reg_write = omap_rtc_scratch_write,
+};
+
 static int omap_rtc_probe(struct platform_device *pdev)
 {
        struct omap_rtc *rtc;
@@ -797,13 +840,16 @@ static int omap_rtc_probe(struct platform_device *pdev)
 
        device_init_wakeup(&pdev->dev, true);
 
-       rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
-                       &omap_rtc_ops, THIS_MODULE);
+       rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
        if (IS_ERR(rtc->rtc)) {
                ret = PTR_ERR(rtc->rtc);
                goto err;
        }
 
+       rtc->rtc->ops = &omap_rtc_ops;
+       omap_rtc_nvmem_config.priv = rtc;
+       rtc->rtc->nvmem_config = &omap_rtc_nvmem_config;
+
        /* handle periodic and alarm irqs */
        ret = devm_request_irq(&pdev->dev, rtc->irq_timer, rtc_irq, 0,
                        dev_name(&rtc->rtc->dev), rtc);
@@ -830,9 +876,14 @@ static int omap_rtc_probe(struct platform_device *pdev)
        rtc->pctldev = pinctrl_register(&rtc_pinctrl_desc, &pdev->dev, rtc);
        if (IS_ERR(rtc->pctldev)) {
                dev_err(&pdev->dev, "Couldn't register pinctrl driver\n");
-               return PTR_ERR(rtc->pctldev);
+               ret = PTR_ERR(rtc->pctldev);
+               goto err;
        }
 
+       ret = rtc_register_device(rtc->rtc);
+       if (ret)
+               goto err;
+
        return 0;
 
 err:
index 28c48b3c1946dc8856b7c00a090ba132755dddc7..c312af0db72957af5ed4980663fce838ab7cec1c 100644 (file)
@@ -35,6 +35,9 @@
 #define REG_MONTHS   0x08
 #define REG_YEARS    0x09
 
+#define REG_OFFSET   0x0e
+#define REG_OFFSET_MODE BIT(7)
+
 struct pcf8523 {
        struct rtc_device *rtc;
 };
@@ -272,10 +275,47 @@ static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd,
 #define pcf8523_rtc_ioctl NULL
 #endif
 
+static int pcf8523_rtc_read_offset(struct device *dev, long *offset)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       int err;
+       u8 value;
+       s8 val;
+
+       err = pcf8523_read(client, REG_OFFSET, &value);
+       if (err < 0)
+               return err;
+
+       /* sign extend the 7-bit offset value */
+       val = value << 1;
+       *offset = (value & REG_OFFSET_MODE ? 4069 : 4340) * (val >> 1);
+
+       return 0;
+}
+
+static int pcf8523_rtc_set_offset(struct device *dev, long offset)
+{
+       struct i2c_client *client = to_i2c_client(dev);
+       long reg_m0, reg_m1;
+       u8 value;
+
+       reg_m0 = clamp(DIV_ROUND_CLOSEST(offset, 4340), -64L, 63L);
+       reg_m1 = clamp(DIV_ROUND_CLOSEST(offset, 4069), -64L, 63L);
+
+       if (abs(reg_m0 * 4340 - offset) < abs(reg_m1 * 4069 - offset))
+               value = reg_m0 & 0x7f;
+       else
+               value = (reg_m1 & 0x7f) | REG_OFFSET_MODE;
+
+       return pcf8523_write(client, REG_OFFSET, value);
+}
+
 static const struct rtc_class_ops pcf8523_rtc_ops = {
        .read_time = pcf8523_rtc_read_time,
        .set_time = pcf8523_rtc_set_time,
        .ioctl = pcf8523_rtc_ioctl,
+       .read_offset = pcf8523_rtc_read_offset,
+       .set_offset = pcf8523_rtc_set_offset,
 };
 
 static int pcf8523_probe(struct i2c_client *client,
diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c
new file mode 100644 (file)
index 0000000..ea04e9f
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+ * drivers/rtc/rtc-pcf85363.c
+ *
+ * Driver for NXP PCF85363 real-time clock.
+ *
+ * Copyright (C) 2017 Eric Nelson
+ *
+ * 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.
+ *
+ * Based loosely on rtc-8583 by Russell King, Wolfram Sang and Juergen Beisert
+ */
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/bcd.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+
+/*
+ * Date/Time registers
+ */
+#define DT_100THS      0x00
+#define DT_SECS                0x01
+#define DT_MINUTES     0x02
+#define DT_HOURS       0x03
+#define DT_DAYS                0x04
+#define DT_WEEKDAYS    0x05
+#define DT_MONTHS      0x06
+#define DT_YEARS       0x07
+
+/*
+ * Alarm registers
+ */
+#define DT_SECOND_ALM1 0x08
+#define DT_MINUTE_ALM1 0x09
+#define DT_HOUR_ALM1   0x0a
+#define DT_DAY_ALM1    0x0b
+#define DT_MONTH_ALM1  0x0c
+#define DT_MINUTE_ALM2 0x0d
+#define DT_HOUR_ALM2   0x0e
+#define DT_WEEKDAY_ALM2        0x0f
+#define DT_ALARM_EN    0x10
+
+/*
+ * Time stamp registers
+ */
+#define DT_TIMESTAMP1  0x11
+#define DT_TIMESTAMP2  0x17
+#define DT_TIMESTAMP3  0x1d
+#define DT_TS_MODE     0x23
+
+/*
+ * control registers
+ */
+#define CTRL_OFFSET    0x24
+#define CTRL_OSCILLATOR        0x25
+#define CTRL_BATTERY   0x26
+#define CTRL_PIN_IO    0x27
+#define CTRL_FUNCTION  0x28
+#define CTRL_INTA_EN   0x29
+#define CTRL_INTB_EN   0x2a
+#define CTRL_FLAGS     0x2b
+#define CTRL_RAMBYTE   0x2c
+#define CTRL_WDOG      0x2d
+#define CTRL_STOP_EN   0x2e
+#define CTRL_RESETS    0x2f
+#define CTRL_RAM       0x40
+
+#define NVRAM_SIZE     0x40
+
+static struct i2c_driver pcf85363_driver;
+
+struct pcf85363 {
+       struct device           *dev;
+       struct rtc_device       *rtc;
+       struct nvmem_config     nvmem_cfg;
+       struct regmap           *regmap;
+};
+
+static int pcf85363_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct pcf85363 *pcf85363 = dev_get_drvdata(dev);
+       unsigned char buf[DT_YEARS + 1];
+       int ret, len = sizeof(buf);
+
+       /* read the RTC date and time registers all at once */
+       ret = regmap_bulk_read(pcf85363->regmap, DT_100THS, buf, len);
+       if (ret) {
+               dev_err(dev, "%s: error %d\n", __func__, ret);
+               return ret;
+       }
+
+       tm->tm_year = bcd2bin(buf[DT_YEARS]);
+       /* adjust for 1900 base of rtc_time */
+       tm->tm_year += 100;
+
+       tm->tm_wday = buf[DT_WEEKDAYS] & 7;
+       buf[DT_SECS] &= 0x7F;
+       tm->tm_sec = bcd2bin(buf[DT_SECS]);
+       buf[DT_MINUTES] &= 0x7F;
+       tm->tm_min = bcd2bin(buf[DT_MINUTES]);
+       tm->tm_hour = bcd2bin(buf[DT_HOURS]);
+       tm->tm_mday = bcd2bin(buf[DT_DAYS]);
+       tm->tm_mon = bcd2bin(buf[DT_MONTHS]) - 1;
+
+       return 0;
+}
+
+static int pcf85363_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct pcf85363 *pcf85363 = dev_get_drvdata(dev);
+       unsigned char buf[DT_YEARS + 1];
+       int len = sizeof(buf);
+
+       buf[DT_100THS] = 0;
+       buf[DT_SECS] = bin2bcd(tm->tm_sec);
+       buf[DT_MINUTES] = bin2bcd(tm->tm_min);
+       buf[DT_HOURS] = bin2bcd(tm->tm_hour);
+       buf[DT_DAYS] = bin2bcd(tm->tm_mday);
+       buf[DT_WEEKDAYS] = tm->tm_wday;
+       buf[DT_MONTHS] = bin2bcd(tm->tm_mon + 1);
+       buf[DT_YEARS] = bin2bcd(tm->tm_year % 100);
+
+       return regmap_bulk_write(pcf85363->regmap, DT_100THS,
+                                buf, len);
+}
+
+static const struct rtc_class_ops rtc_ops = {
+       .read_time      = pcf85363_rtc_read_time,
+       .set_time       = pcf85363_rtc_set_time,
+};
+
+static int pcf85363_nvram_read(void *priv, unsigned int offset, void *val,
+                              size_t bytes)
+{
+       struct pcf85363 *pcf85363 = priv;
+
+       return regmap_bulk_read(pcf85363->regmap, CTRL_RAM + offset,
+                               val, bytes);
+}
+
+static int pcf85363_nvram_write(void *priv, unsigned int offset, void *val,
+                               size_t bytes)
+{
+       struct pcf85363 *pcf85363 = priv;
+
+       return regmap_bulk_write(pcf85363->regmap, CTRL_RAM + offset,
+                                val, bytes);
+}
+
+static const struct regmap_config regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+};
+
+static int pcf85363_probe(struct i2c_client *client,
+                         const struct i2c_device_id *id)
+{
+       struct pcf85363 *pcf85363;
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+               return -ENODEV;
+
+       pcf85363 = devm_kzalloc(&client->dev, sizeof(struct pcf85363),
+                               GFP_KERNEL);
+       if (!pcf85363)
+               return -ENOMEM;
+
+       pcf85363->regmap = devm_regmap_init_i2c(client, &regmap_config);
+       if (IS_ERR(pcf85363->regmap)) {
+               dev_err(&client->dev, "regmap allocation failed\n");
+               return PTR_ERR(pcf85363->regmap);
+       }
+
+       pcf85363->dev = &client->dev;
+       i2c_set_clientdata(client, pcf85363);
+
+       pcf85363->rtc = devm_rtc_allocate_device(pcf85363->dev);
+       if (IS_ERR(pcf85363->rtc))
+               return PTR_ERR(pcf85363->rtc);
+
+       pcf85363->nvmem_cfg.name = "pcf85363-";
+       pcf85363->nvmem_cfg.word_size = 1;
+       pcf85363->nvmem_cfg.stride = 1;
+       pcf85363->nvmem_cfg.size = NVRAM_SIZE;
+       pcf85363->nvmem_cfg.reg_read = pcf85363_nvram_read;
+       pcf85363->nvmem_cfg.reg_write = pcf85363_nvram_write;
+       pcf85363->nvmem_cfg.priv = pcf85363;
+       pcf85363->rtc->nvmem_config = &pcf85363->nvmem_cfg;
+       pcf85363->rtc->ops = &rtc_ops;
+
+       return rtc_register_device(pcf85363->rtc);
+}
+
+static const struct of_device_id dev_ids[] = {
+       { .compatible = "nxp,pcf85363" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, dev_ids);
+
+static struct i2c_driver pcf85363_driver = {
+       .driver = {
+               .name   = "pcf85363",
+               .of_match_table = of_match_ptr(dev_ids),
+       },
+       .probe  = pcf85363_probe,
+};
+
+module_i2c_driver(pcf85363_driver);
+
+MODULE_AUTHOR("Eric Nelson");
+MODULE_DESCRIPTION("pcf85363 I2C RTC driver");
+MODULE_LICENSE("GPL");
index cea6ea4df970ff44925008b643e894300d3adeaa..3efc86c25d27a5754031f95136522766e67cd563 100644 (file)
@@ -387,7 +387,7 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
        if (err)
                return err;
 
-       return pcf8563_set_alarm_mode(client, 1);
+       return pcf8563_set_alarm_mode(client, !!tm->enabled);
 }
 
 static int pcf8563_irq_enable(struct device *dev, unsigned int enabled)
@@ -422,7 +422,7 @@ static unsigned long pcf8563_clkout_recalc_rate(struct clk_hw *hw,
                return 0;
 
        buf &= PCF8563_REG_CLKO_F_MASK;
-       return clkout_rates[ret];
+       return clkout_rates[buf];
 }
 
 static long pcf8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
index e1687e19c59f4ad57e6dd78d5f7e8702fa411d27..82eb7da2c47835b3e5515e48bc081ada07e892de 100644 (file)
@@ -308,10 +308,9 @@ static int pl031_remove(struct amba_device *adev)
 
        dev_pm_clear_wake_irq(&adev->dev);
        device_init_wakeup(&adev->dev, false);
-       free_irq(adev->irq[0], ldata);
+       if (adev->irq[0])
+               free_irq(adev->irq[0], ldata);
        rtc_device_unregister(ldata->rtc);
-       iounmap(ldata->base);
-       kfree(ldata);
        amba_release_regions(adev);
 
        return 0;
@@ -322,25 +321,28 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
        int ret;
        struct pl031_local *ldata;
        struct pl031_vendor_data *vendor = id->data;
-       struct rtc_class_ops *ops = &vendor->ops;
+       struct rtc_class_ops *ops;
        unsigned long time, data;
 
        ret = amba_request_regions(adev, NULL);
        if (ret)
                goto err_req;
 
-       ldata = kzalloc(sizeof(struct pl031_local), GFP_KERNEL);
-       if (!ldata) {
+       ldata = devm_kzalloc(&adev->dev, sizeof(struct pl031_local),
+                            GFP_KERNEL);
+       ops = devm_kmemdup(&adev->dev, &vendor->ops, sizeof(vendor->ops),
+                          GFP_KERNEL);
+       if (!ldata || !ops) {
                ret = -ENOMEM;
                goto out;
        }
-       ldata->vendor = vendor;
-
-       ldata->base = ioremap(adev->res.start, resource_size(&adev->res));
 
+       ldata->vendor = vendor;
+       ldata->base = devm_ioremap(&adev->dev, adev->res.start,
+                                  resource_size(&adev->res));
        if (!ldata->base) {
                ret = -ENOMEM;
-               goto out_no_remap;
+               goto out;
        }
 
        amba_set_drvdata(adev, ldata);
@@ -373,28 +375,32 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)
                }
        }
 
+       if (!adev->irq[0]) {
+               /* When there's no interrupt, no point in exposing the alarm */
+               ops->read_alarm = NULL;
+               ops->set_alarm = NULL;
+               ops->alarm_irq_enable = NULL;
+       }
+
        device_init_wakeup(&adev->dev, true);
        ldata->rtc = rtc_device_register("pl031", &adev->dev, ops,
                                        THIS_MODULE);
        if (IS_ERR(ldata->rtc)) {
                ret = PTR_ERR(ldata->rtc);
-               goto out_no_rtc;
+               goto out;
        }
 
-       if (request_irq(adev->irq[0], pl031_interrupt,
-                       vendor->irqflags, "rtc-pl031", ldata)) {
-               ret = -EIO;
-               goto out_no_irq;
+       if (adev->irq[0]) {
+               ret = request_irq(adev->irq[0], pl031_interrupt,
+                                 vendor->irqflags, "rtc-pl031", ldata);
+               if (ret)
+                       goto out_no_irq;
+               dev_pm_set_wake_irq(&adev->dev, adev->irq[0]);
        }
-       dev_pm_set_wake_irq(&adev->dev, adev->irq[0]);
        return 0;
 
 out_no_irq:
        rtc_device_unregister(ldata->rtc);
-out_no_rtc:
-       iounmap(ldata->base);
-out_no_remap:
-       kfree(ldata);
 out:
        amba_release_regions(adev);
 err_req:
@@ -446,7 +452,7 @@ static struct pl031_vendor_data stv2_pl031 = {
        .irqflags = IRQF_SHARED | IRQF_COND_SUSPEND,
 };
 
-static struct amba_id pl031_ids[] = {
+static const struct amba_id pl031_ids[] = {
        {
                .id = 0x00041031,
                .mask = 0x000fffff,
index aa09771de04f764cff457180ef090bb2f052d632..3d6174eb32f6a3b09920c7a9eb370fcd1fc95c89 100644 (file)
@@ -282,13 +282,13 @@ static int rv3029_eeprom_read(struct device *dev, u8 reg,
 static int rv3029_eeprom_write(struct device *dev, u8 reg,
                               u8 const buf[], size_t len)
 {
-       int ret, err;
+       int ret;
        size_t i;
        u8 tmp;
 
-       err = rv3029_eeprom_enter(dev);
-       if (err < 0)
-               return err;
+       ret = rv3029_eeprom_enter(dev);
+       if (ret < 0)
+               return ret;
 
        for (i = 0; i < len; i++, reg++) {
                ret = rv3029_read_regs(dev, reg, &tmp, 1);
@@ -304,11 +304,11 @@ static int rv3029_eeprom_write(struct device *dev, u8 reg,
                        break;
        }
 
-       err = rv3029_eeprom_exit(dev);
-       if (err < 0)
-               return err;
+       ret = rv3029_eeprom_exit(dev);
+       if (ret < 0)
+               return ret;
 
-       return ret;
+       return 0;
 }
 
 static int rv3029_eeprom_update_bits(struct device *dev,
@@ -876,6 +876,8 @@ static const struct i2c_device_id rv3029_id[] = {
 MODULE_DEVICE_TABLE(i2c, rv3029_id);
 
 static const struct of_device_id rv3029_of_match[] = {
+       { .compatible = "microcrystal,rv3029" },
+       /* Backward compatibility only, do not use compatibles below: */
        { .compatible = "rv3029" },
        { .compatible = "rv3029c2" },
        { .compatible = "mc,rv3029c2" },
index 1ed3403ff8ac23ae1c9c2923b76f3f8aff1c9c11..5c5938ab3d86bcb0bef62e9425553cce800b9d2b 100644 (file)
@@ -24,7 +24,6 @@
 #define RX8010_MDAY    0x14
 #define RX8010_MONTH   0x15
 #define RX8010_YEAR    0x16
-#define RX8010_YEAR    0x16
 #define RX8010_RESV17  0x17
 #define RX8010_ALMIN   0x18
 #define RX8010_ALHOUR  0x19
@@ -36,7 +35,7 @@
 #define RX8010_CTRL    0x1F
 /* 0x20 to 0x2F are user registers */
 #define RX8010_RESV30  0x30
-#define RX8010_RESV31  0x32
+#define RX8010_RESV31  0x31
 #define RX8010_IRQ     0x32
 
 #define RX8010_EXT_WADA  BIT(3)
@@ -248,7 +247,7 @@ static int rx8010_init_client(struct i2c_client *client)
 
        rx8010->ctrlreg = (ctrl[1] & ~RX8010_CTRL_TEST);
 
-       return err;
+       return 0;
 }
 
 static int rx8010_read_alarm(struct device *dev, struct rtc_wkalrm *t)
@@ -277,7 +276,7 @@ static int rx8010_read_alarm(struct device *dev, struct rtc_wkalrm *t)
        t->enabled = !!(rx8010->ctrlreg & RX8010_CTRL_AIE);
        t->pending = (flagreg & RX8010_FLAG_AF) && t->enabled;
 
-       return err;
+       return 0;
 }
 
 static int rx8010_set_alarm(struct device *dev, struct rtc_wkalrm *t)
diff --git a/drivers/rtc/rtc-sc27xx.c b/drivers/rtc/rtc-sc27xx.c
new file mode 100644 (file)
index 0000000..d544d52
--- /dev/null
@@ -0,0 +1,662 @@
+/*
+ * Copyright (C) 2017 Spreadtrum Communications Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+
+#define SPRD_RTC_SEC_CNT_VALUE         0x0
+#define SPRD_RTC_MIN_CNT_VALUE         0x4
+#define SPRD_RTC_HOUR_CNT_VALUE                0x8
+#define SPRD_RTC_DAY_CNT_VALUE         0xc
+#define SPRD_RTC_SEC_CNT_UPD           0x10
+#define SPRD_RTC_MIN_CNT_UPD           0x14
+#define SPRD_RTC_HOUR_CNT_UPD          0x18
+#define SPRD_RTC_DAY_CNT_UPD           0x1c
+#define SPRD_RTC_SEC_ALM_UPD           0x20
+#define SPRD_RTC_MIN_ALM_UPD           0x24
+#define SPRD_RTC_HOUR_ALM_UPD          0x28
+#define SPRD_RTC_DAY_ALM_UPD           0x2c
+#define SPRD_RTC_INT_EN                        0x30
+#define SPRD_RTC_INT_RAW_STS           0x34
+#define SPRD_RTC_INT_CLR               0x38
+#define SPRD_RTC_INT_MASK_STS          0x3C
+#define SPRD_RTC_SEC_ALM_VALUE         0x40
+#define SPRD_RTC_MIN_ALM_VALUE         0x44
+#define SPRD_RTC_HOUR_ALM_VALUE                0x48
+#define SPRD_RTC_DAY_ALM_VALUE         0x4c
+#define SPRD_RTC_SPG_VALUE             0x50
+#define SPRD_RTC_SPG_UPD               0x54
+#define SPRD_RTC_SEC_AUXALM_UPD                0x60
+#define SPRD_RTC_MIN_AUXALM_UPD                0x64
+#define SPRD_RTC_HOUR_AUXALM_UPD       0x68
+#define SPRD_RTC_DAY_AUXALM_UPD                0x6c
+
+/* BIT & MASK definition for SPRD_RTC_INT_* registers */
+#define SPRD_RTC_SEC_EN                        BIT(0)
+#define SPRD_RTC_MIN_EN                        BIT(1)
+#define SPRD_RTC_HOUR_EN               BIT(2)
+#define SPRD_RTC_DAY_EN                        BIT(3)
+#define SPRD_RTC_ALARM_EN              BIT(4)
+#define SPRD_RTC_HRS_FORMAT_EN         BIT(5)
+#define SPRD_RTC_AUXALM_EN             BIT(6)
+#define SPRD_RTC_SPG_UPD_EN            BIT(7)
+#define SPRD_RTC_SEC_UPD_EN            BIT(8)
+#define SPRD_RTC_MIN_UPD_EN            BIT(9)
+#define SPRD_RTC_HOUR_UPD_EN           BIT(10)
+#define SPRD_RTC_DAY_UPD_EN            BIT(11)
+#define SPRD_RTC_ALMSEC_UPD_EN         BIT(12)
+#define SPRD_RTC_ALMMIN_UPD_EN         BIT(13)
+#define SPRD_RTC_ALMHOUR_UPD_EN                BIT(14)
+#define SPRD_RTC_ALMDAY_UPD_EN         BIT(15)
+#define SPRD_RTC_INT_MASK              GENMASK(15, 0)
+
+#define SPRD_RTC_TIME_INT_MASK                         \
+       (SPRD_RTC_SEC_UPD_EN | SPRD_RTC_MIN_UPD_EN |    \
+        SPRD_RTC_HOUR_UPD_EN | SPRD_RTC_DAY_UPD_EN)
+
+#define SPRD_RTC_ALMTIME_INT_MASK                              \
+       (SPRD_RTC_ALMSEC_UPD_EN | SPRD_RTC_ALMMIN_UPD_EN |      \
+        SPRD_RTC_ALMHOUR_UPD_EN | SPRD_RTC_ALMDAY_UPD_EN)
+
+#define SPRD_RTC_ALM_INT_MASK                  \
+       (SPRD_RTC_SEC_EN | SPRD_RTC_MIN_EN |    \
+        SPRD_RTC_HOUR_EN | SPRD_RTC_DAY_EN |   \
+        SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN)
+
+/* second/minute/hour/day values mask definition */
+#define SPRD_RTC_SEC_MASK              GENMASK(5, 0)
+#define SPRD_RTC_MIN_MASK              GENMASK(5, 0)
+#define SPRD_RTC_HOUR_MASK             GENMASK(4, 0)
+#define SPRD_RTC_DAY_MASK              GENMASK(15, 0)
+
+/* alarm lock definition for SPRD_RTC_SPG_UPD register */
+#define SPRD_RTC_ALMLOCK_MASK          GENMASK(7, 0)
+#define SPRD_RTC_ALM_UNLOCK            0xa5
+#define SPRD_RTC_ALM_LOCK              (~SPRD_RTC_ALM_UNLOCK & \
+                                        SPRD_RTC_ALMLOCK_MASK)
+
+/* SPG values definition for SPRD_RTC_SPG_UPD register */
+#define SPRD_RTC_POWEROFF_ALM_FLAG     BIT(8)
+#define SPRD_RTC_POWER_RESET_FLAG      BIT(9)
+
+/* timeout of synchronizing time and alarm registers (us) */
+#define SPRD_RTC_POLL_TIMEOUT          200000
+#define SPRD_RTC_POLL_DELAY_US         20000
+
+struct sprd_rtc {
+       struct rtc_device       *rtc;
+       struct regmap           *regmap;
+       struct device           *dev;
+       u32                     base;
+       int                     irq;
+       bool                    valid;
+};
+
+/*
+ * The Spreadtrum RTC controller has 3 groups registers, including time, normal
+ * alarm and auxiliary alarm. The time group registers are used to set RTC time,
+ * the normal alarm registers are used to set normal alarm, and the auxiliary
+ * alarm registers are used to set auxiliary alarm. Both alarm event and
+ * auxiliary alarm event can wake up system from deep sleep, but only alarm
+ * event can power up system from power down status.
+ */
+enum sprd_rtc_reg_types {
+       SPRD_RTC_TIME,
+       SPRD_RTC_ALARM,
+       SPRD_RTC_AUX_ALARM,
+};
+
+static int sprd_rtc_clear_alarm_ints(struct sprd_rtc *rtc)
+{
+       return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
+                           SPRD_RTC_ALM_INT_MASK);
+}
+
+static int sprd_rtc_disable_ints(struct sprd_rtc *rtc)
+{
+       int ret;
+
+       ret = regmap_update_bits(rtc->regmap, rtc->base + SPRD_RTC_INT_EN,
+                                SPRD_RTC_INT_MASK, 0);
+       if (ret)
+               return ret;
+
+       return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
+                           SPRD_RTC_INT_MASK);
+}
+
+static int sprd_rtc_lock_alarm(struct sprd_rtc *rtc, bool lock)
+{
+       int ret;
+       u32 val;
+
+       ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_SPG_VALUE, &val);
+       if (ret)
+               return ret;
+
+       val &= ~(SPRD_RTC_ALMLOCK_MASK | SPRD_RTC_POWEROFF_ALM_FLAG);
+       if (lock)
+               val |= SPRD_RTC_ALM_LOCK;
+       else
+               val |= SPRD_RTC_ALM_UNLOCK | SPRD_RTC_POWEROFF_ALM_FLAG;
+
+       ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_SPG_UPD, val);
+       if (ret)
+               return ret;
+
+       /* wait until the SPG value is updated successfully */
+       ret = regmap_read_poll_timeout(rtc->regmap,
+                                      rtc->base + SPRD_RTC_INT_RAW_STS, val,
+                                      (val & SPRD_RTC_SPG_UPD_EN),
+                                      SPRD_RTC_POLL_DELAY_US,
+                                      SPRD_RTC_POLL_TIMEOUT);
+       if (ret) {
+               dev_err(rtc->dev, "failed to update SPG value:%d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+static int sprd_rtc_get_secs(struct sprd_rtc *rtc, enum sprd_rtc_reg_types type,
+                            time64_t *secs)
+{
+       u32 sec_reg, min_reg, hour_reg, day_reg;
+       u32 val, sec, min, hour, day;
+       int ret;
+
+       switch (type) {
+       case SPRD_RTC_TIME:
+               sec_reg = SPRD_RTC_SEC_CNT_VALUE;
+               min_reg = SPRD_RTC_MIN_CNT_VALUE;
+               hour_reg = SPRD_RTC_HOUR_CNT_VALUE;
+               day_reg = SPRD_RTC_DAY_CNT_VALUE;
+               break;
+       case SPRD_RTC_ALARM:
+               sec_reg = SPRD_RTC_SEC_ALM_VALUE;
+               min_reg = SPRD_RTC_MIN_ALM_VALUE;
+               hour_reg = SPRD_RTC_HOUR_ALM_VALUE;
+               day_reg = SPRD_RTC_DAY_ALM_VALUE;
+               break;
+       case SPRD_RTC_AUX_ALARM:
+               sec_reg = SPRD_RTC_SEC_AUXALM_UPD;
+               min_reg = SPRD_RTC_MIN_AUXALM_UPD;
+               hour_reg = SPRD_RTC_HOUR_AUXALM_UPD;
+               day_reg = SPRD_RTC_DAY_AUXALM_UPD;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = regmap_read(rtc->regmap, rtc->base + sec_reg, &val);
+       if (ret)
+               return ret;
+
+       sec = val & SPRD_RTC_SEC_MASK;
+
+       ret = regmap_read(rtc->regmap, rtc->base + min_reg, &val);
+       if (ret)
+               return ret;
+
+       min = val & SPRD_RTC_MIN_MASK;
+
+       ret = regmap_read(rtc->regmap, rtc->base + hour_reg, &val);
+       if (ret)
+               return ret;
+
+       hour = val & SPRD_RTC_HOUR_MASK;
+
+       ret = regmap_read(rtc->regmap, rtc->base + day_reg, &val);
+       if (ret)
+               return ret;
+
+       day = val & SPRD_RTC_DAY_MASK;
+       *secs = (((time64_t)(day * 24) + hour) * 60 + min) * 60 + sec;
+       return 0;
+}
+
+static int sprd_rtc_set_secs(struct sprd_rtc *rtc, enum sprd_rtc_reg_types type,
+                            time64_t secs)
+{
+       u32 sec_reg, min_reg, hour_reg, day_reg, sts_mask;
+       u32 sec, min, hour, day, val;
+       int ret, rem;
+
+       /* convert seconds to RTC time format */
+       day = div_s64_rem(secs, 86400, &rem);
+       hour = rem / 3600;
+       rem -= hour * 3600;
+       min = rem / 60;
+       sec = rem - min * 60;
+
+       switch (type) {
+       case SPRD_RTC_TIME:
+               sec_reg = SPRD_RTC_SEC_CNT_UPD;
+               min_reg = SPRD_RTC_MIN_CNT_UPD;
+               hour_reg = SPRD_RTC_HOUR_CNT_UPD;
+               day_reg = SPRD_RTC_DAY_CNT_UPD;
+               sts_mask = SPRD_RTC_TIME_INT_MASK;
+               break;
+       case SPRD_RTC_ALARM:
+               sec_reg = SPRD_RTC_SEC_ALM_UPD;
+               min_reg = SPRD_RTC_MIN_ALM_UPD;
+               hour_reg = SPRD_RTC_HOUR_ALM_UPD;
+               day_reg = SPRD_RTC_DAY_ALM_UPD;
+               sts_mask = SPRD_RTC_ALMTIME_INT_MASK;
+               break;
+       case SPRD_RTC_AUX_ALARM:
+               sec_reg = SPRD_RTC_SEC_AUXALM_UPD;
+               min_reg = SPRD_RTC_MIN_AUXALM_UPD;
+               hour_reg = SPRD_RTC_HOUR_AUXALM_UPD;
+               day_reg = SPRD_RTC_DAY_AUXALM_UPD;
+               sts_mask = 0;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       ret = regmap_write(rtc->regmap, rtc->base + sec_reg, sec);
+       if (ret)
+               return ret;
+
+       ret = regmap_write(rtc->regmap, rtc->base + min_reg, min);
+       if (ret)
+               return ret;
+
+       ret = regmap_write(rtc->regmap, rtc->base + hour_reg, hour);
+       if (ret)
+               return ret;
+
+       ret = regmap_write(rtc->regmap, rtc->base + day_reg, day);
+       if (ret)
+               return ret;
+
+       if (type == SPRD_RTC_AUX_ALARM)
+               return 0;
+
+       /*
+        * Since the time and normal alarm registers are put in always-power-on
+        * region supplied by VDDRTC, then these registers changing time will
+        * be very long, about 125ms. Thus here we should wait until all
+        * values are updated successfully.
+        */
+       ret = regmap_read_poll_timeout(rtc->regmap,
+                                      rtc->base + SPRD_RTC_INT_RAW_STS, val,
+                                      ((val & sts_mask) == sts_mask),
+                                      SPRD_RTC_POLL_DELAY_US,
+                                      SPRD_RTC_POLL_TIMEOUT);
+       if (ret < 0) {
+               dev_err(rtc->dev, "set time/alarm values timeout\n");
+               return ret;
+       }
+
+       return regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
+                           sts_mask);
+}
+
+static int sprd_rtc_read_aux_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct sprd_rtc *rtc = dev_get_drvdata(dev);
+       time64_t secs;
+       u32 val;
+       int ret;
+
+       ret = sprd_rtc_get_secs(rtc, SPRD_RTC_AUX_ALARM, &secs);
+       if (ret)
+               return ret;
+
+       rtc_time64_to_tm(secs, &alrm->time);
+
+       ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_EN, &val);
+       if (ret)
+               return ret;
+
+       alrm->enabled = !!(val & SPRD_RTC_AUXALM_EN);
+
+       ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_RAW_STS, &val);
+       if (ret)
+               return ret;
+
+       alrm->pending = !!(val & SPRD_RTC_AUXALM_EN);
+       return 0;
+}
+
+static int sprd_rtc_set_aux_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct sprd_rtc *rtc = dev_get_drvdata(dev);
+       time64_t secs = rtc_tm_to_time64(&alrm->time);
+       int ret;
+
+       /* clear the auxiliary alarm interrupt status */
+       ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
+                          SPRD_RTC_AUXALM_EN);
+       if (ret)
+               return ret;
+
+       ret = sprd_rtc_set_secs(rtc, SPRD_RTC_AUX_ALARM, secs);
+       if (ret)
+               return ret;
+
+       if (alrm->enabled) {
+               ret = regmap_update_bits(rtc->regmap,
+                                        rtc->base + SPRD_RTC_INT_EN,
+                                        SPRD_RTC_AUXALM_EN,
+                                        SPRD_RTC_AUXALM_EN);
+       } else {
+               ret = regmap_update_bits(rtc->regmap,
+                                        rtc->base + SPRD_RTC_INT_EN,
+                                        SPRD_RTC_AUXALM_EN, 0);
+       }
+
+       return ret;
+}
+
+static int sprd_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct sprd_rtc *rtc = dev_get_drvdata(dev);
+       time64_t secs;
+       int ret;
+
+       if (!rtc->valid) {
+               dev_warn(dev, "RTC values are invalid\n");
+               return -EINVAL;
+       }
+
+       ret = sprd_rtc_get_secs(rtc, SPRD_RTC_TIME, &secs);
+       if (ret)
+               return ret;
+
+       rtc_time64_to_tm(secs, tm);
+       return rtc_valid_tm(tm);
+}
+
+static int sprd_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct sprd_rtc *rtc = dev_get_drvdata(dev);
+       time64_t secs = rtc_tm_to_time64(tm);
+       u32 val;
+       int ret;
+
+       ret = sprd_rtc_set_secs(rtc, SPRD_RTC_TIME, secs);
+       if (ret)
+               return ret;
+
+       if (!rtc->valid) {
+               /*
+                * Set SPRD_RTC_POWER_RESET_FLAG to indicate now RTC has valid
+                * time values.
+                */
+               ret = regmap_update_bits(rtc->regmap,
+                                        rtc->base + SPRD_RTC_SPG_UPD,
+                                        SPRD_RTC_POWER_RESET_FLAG,
+                                        SPRD_RTC_POWER_RESET_FLAG);
+               if (ret)
+                       return ret;
+
+               ret = regmap_read_poll_timeout(rtc->regmap,
+                                              rtc->base + SPRD_RTC_INT_RAW_STS,
+                                              val, (val & SPRD_RTC_SPG_UPD_EN),
+                                              SPRD_RTC_POLL_DELAY_US,
+                                              SPRD_RTC_POLL_TIMEOUT);
+               if (ret) {
+                       dev_err(rtc->dev, "failed to update SPG value:%d\n",
+                               ret);
+                       return ret;
+               }
+
+               rtc->valid = true;
+       }
+
+       return 0;
+}
+
+static int sprd_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct sprd_rtc *rtc = dev_get_drvdata(dev);
+       time64_t secs;
+       int ret;
+       u32 val;
+
+       /*
+        * If aie_timer is enabled, we should get the normal alarm time.
+        * Otherwise we should get auxiliary alarm time.
+        */
+       if (rtc->rtc && rtc->rtc->aie_timer.enabled == 0)
+               return sprd_rtc_read_aux_alarm(dev, alrm);
+
+       ret = sprd_rtc_get_secs(rtc, SPRD_RTC_ALARM, &secs);
+       if (ret)
+               return ret;
+
+       rtc_time64_to_tm(secs, &alrm->time);
+
+       ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_EN, &val);
+       if (ret)
+               return ret;
+
+       alrm->enabled = !!(val & SPRD_RTC_ALARM_EN);
+
+       ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_INT_RAW_STS, &val);
+       if (ret)
+               return ret;
+
+       alrm->pending = !!(val & SPRD_RTC_ALARM_EN);
+       return 0;
+}
+
+static int sprd_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+       struct sprd_rtc *rtc = dev_get_drvdata(dev);
+       time64_t secs = rtc_tm_to_time64(&alrm->time);
+       struct rtc_time aie_time =
+               rtc_ktime_to_tm(rtc->rtc->aie_timer.node.expires);
+       int ret;
+
+       /*
+        * We have 2 groups alarms: normal alarm and auxiliary alarm. Since
+        * both normal alarm event and auxiliary alarm event can wake up system
+        * from deep sleep, but only alarm event can power up system from power
+        * down status. Moreover we do not need to poll about 125ms when
+        * updating auxiliary alarm registers. Thus we usually set auxiliary
+        * alarm when wake up system from deep sleep, and for other scenarios,
+        * we should set normal alarm with polling status.
+        *
+        * So here we check if the alarm time is set by aie_timer, if yes, we
+        * should set normal alarm, if not, we should set auxiliary alarm which
+        * means it is just a wake event.
+        */
+       if (!rtc->rtc->aie_timer.enabled || rtc_tm_sub(&aie_time, &alrm->time))
+               return sprd_rtc_set_aux_alarm(dev, alrm);
+
+       /* clear the alarm interrupt status firstly */
+       ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_INT_CLR,
+                          SPRD_RTC_ALARM_EN);
+       if (ret)
+               return ret;
+
+       ret = sprd_rtc_set_secs(rtc, SPRD_RTC_ALARM, secs);
+       if (ret)
+               return ret;
+
+       if (alrm->enabled) {
+               ret = regmap_update_bits(rtc->regmap,
+                                        rtc->base + SPRD_RTC_INT_EN,
+                                        SPRD_RTC_ALARM_EN,
+                                        SPRD_RTC_ALARM_EN);
+               if (ret)
+                       return ret;
+
+               /* unlock the alarm to enable the alarm function. */
+               ret = sprd_rtc_lock_alarm(rtc, false);
+       } else {
+               regmap_update_bits(rtc->regmap,
+                                  rtc->base + SPRD_RTC_INT_EN,
+                                  SPRD_RTC_ALARM_EN, 0);
+
+               /*
+                * Lock the alarm function in case fake alarm event will power
+                * up systems.
+                */
+               ret = sprd_rtc_lock_alarm(rtc, true);
+       }
+
+       return ret;
+}
+
+static int sprd_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct sprd_rtc *rtc = dev_get_drvdata(dev);
+       int ret;
+
+       if (enabled) {
+               ret = regmap_update_bits(rtc->regmap,
+                                        rtc->base + SPRD_RTC_INT_EN,
+                                        SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN,
+                                        SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN);
+               if (ret)
+                       return ret;
+
+               ret = sprd_rtc_lock_alarm(rtc, false);
+       } else {
+               regmap_update_bits(rtc->regmap, rtc->base + SPRD_RTC_INT_EN,
+                                  SPRD_RTC_ALARM_EN | SPRD_RTC_AUXALM_EN, 0);
+
+               ret = sprd_rtc_lock_alarm(rtc, true);
+       }
+
+       return ret;
+}
+
+static const struct rtc_class_ops sprd_rtc_ops = {
+       .read_time = sprd_rtc_read_time,
+       .set_time = sprd_rtc_set_time,
+       .read_alarm = sprd_rtc_read_alarm,
+       .set_alarm = sprd_rtc_set_alarm,
+       .alarm_irq_enable = sprd_rtc_alarm_irq_enable,
+};
+
+static irqreturn_t sprd_rtc_handler(int irq, void *dev_id)
+{
+       struct sprd_rtc *rtc = dev_id;
+       int ret;
+
+       ret = sprd_rtc_clear_alarm_ints(rtc);
+       if (ret)
+               return IRQ_RETVAL(ret);
+
+       rtc_update_irq(rtc->rtc, 1, RTC_AF | RTC_IRQF);
+       return IRQ_HANDLED;
+}
+
+static int sprd_rtc_check_power_down(struct sprd_rtc *rtc)
+{
+       u32 val;
+       int ret;
+
+       ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_SPG_VALUE, &val);
+       if (ret)
+               return ret;
+
+       /*
+        * If the SPRD_RTC_POWER_RESET_FLAG was not set, which means the RTC has
+        * been powered down, so the RTC time values are invalid.
+        */
+       rtc->valid = (val & SPRD_RTC_POWER_RESET_FLAG) ? true : false;
+       return 0;
+}
+
+static int sprd_rtc_probe(struct platform_device *pdev)
+{
+       struct device_node *node = pdev->dev.of_node;
+       struct sprd_rtc *rtc;
+       int ret;
+
+       rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+       if (!rtc)
+               return -ENOMEM;
+
+       rtc->regmap = dev_get_regmap(pdev->dev.parent, NULL);
+       if (!rtc->regmap)
+               return -ENODEV;
+
+       ret = of_property_read_u32(node, "reg", &rtc->base);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to get RTC base address\n");
+               return ret;
+       }
+
+       rtc->irq = platform_get_irq(pdev, 0);
+       if (rtc->irq < 0) {
+               dev_err(&pdev->dev, "failed to get RTC irq number\n");
+               return rtc->irq;
+       }
+
+       rtc->dev = &pdev->dev;
+       platform_set_drvdata(pdev, rtc);
+
+       /* clear all RTC interrupts and disable all RTC interrupts */
+       ret = sprd_rtc_disable_ints(rtc);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to disable RTC interrupts\n");
+               return ret;
+       }
+
+       /* check if RTC time values are valid */
+       ret = sprd_rtc_check_power_down(rtc);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to check RTC time values\n");
+               return ret;
+       }
+
+       ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
+                                       sprd_rtc_handler,
+                                       IRQF_ONESHOT | IRQF_EARLY_RESUME,
+                                       pdev->name, rtc);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to request RTC irq\n");
+               return ret;
+       }
+
+       rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+                                           &sprd_rtc_ops, THIS_MODULE);
+       if (IS_ERR(rtc->rtc))
+               return PTR_ERR(rtc->rtc);
+
+       device_init_wakeup(&pdev->dev, 1);
+       return 0;
+}
+
+static int sprd_rtc_remove(struct platform_device *pdev)
+{
+       device_init_wakeup(&pdev->dev, 0);
+       return 0;
+}
+
+static const struct of_device_id sprd_rtc_of_match[] = {
+       { .compatible = "sprd,sc2731-rtc", },
+       { },
+};
+MODULE_DEVICE_TABLE(of, sprd_rtc_of_match);
+
+static struct platform_driver sprd_rtc_driver = {
+       .driver = {
+               .name = "sprd-rtc",
+               .of_match_table = sprd_rtc_of_match,
+       },
+       .probe  = sprd_rtc_probe,
+       .remove = sprd_rtc_remove,
+};
+module_platform_driver(sprd_rtc_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Spreadtrum RTC Device Driver");
+MODULE_AUTHOR("Baolin Wang <baolin.wang@spreadtrum.com>");
index e364550eb9a7fad8ef4efed7ca2f200116832e9c..92ff2edb86a653afecda26f6ec9422715fb78e79 100644 (file)
@@ -72,9 +72,10 @@ since_epoch_show(struct device *dev, struct device_attribute *attr, char *buf)
 
        retval = rtc_read_time(to_rtc_device(dev), &tm);
        if (retval == 0) {
-               unsigned long time;
-               rtc_tm_to_time(&tm, &time);
-               retval = sprintf(buf, "%lu\n", time);
+               time64_t time;
+
+               time = rtc_tm_to_time64(&tm);
+               retval = sprintf(buf, "%lld\n", time);
        }
 
        return retval;
@@ -132,7 +133,7 @@ static ssize_t
 wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
        ssize_t retval;
-       unsigned long alarm;
+       time64_t alarm;
        struct rtc_wkalrm alm;
 
        /* Don't show disabled alarms.  For uniformity, RTC alarms are
@@ -145,8 +146,8 @@ wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf)
         */
        retval = rtc_read_alarm(to_rtc_device(dev), &alm);
        if (retval == 0 && alm.enabled) {
-               rtc_tm_to_time(&alm.time, &alarm);
-               retval = sprintf(buf, "%lu\n", alarm);
+               alarm = rtc_tm_to_time64(&alm.time);
+               retval = sprintf(buf, "%lld\n", alarm);
        }
 
        return retval;
@@ -157,8 +158,8 @@ wakealarm_store(struct device *dev, struct device_attribute *attr,
                const char *buf, size_t n)
 {
        ssize_t retval;
-       unsigned long now, alarm;
-       unsigned long push = 0;
+       time64_t now, alarm;
+       time64_t push = 0;
        struct rtc_wkalrm alm;
        struct rtc_device *rtc = to_rtc_device(dev);
        const char *buf_ptr;
@@ -170,7 +171,7 @@ wakealarm_store(struct device *dev, struct device_attribute *attr,
        retval = rtc_read_time(rtc, &alm.time);
        if (retval < 0)
                return retval;
-       rtc_tm_to_time(&alm.time, &now);
+       now = rtc_tm_to_time64(&alm.time);
 
        buf_ptr = buf;
        if (*buf_ptr == '+') {
@@ -181,7 +182,7 @@ wakealarm_store(struct device *dev, struct device_attribute *attr,
                } else
                        adjust = 1;
        }
-       retval = kstrtoul(buf_ptr, 0, &alarm);
+       retval = kstrtos64(buf_ptr, 0, &alarm);
        if (retval)
                return retval;
        if (adjust) {
@@ -197,7 +198,7 @@ wakealarm_store(struct device *dev, struct device_attribute *attr,
                        return retval;
                if (alm.enabled) {
                        if (push) {
-                               rtc_tm_to_time(&alm.time, &push);
+                               push = rtc_tm_to_time64(&alm.time);
                                alarm += push;
                        } else
                                return -EBUSY;
@@ -212,7 +213,7 @@ wakealarm_store(struct device *dev, struct device_attribute *attr,
                 */
                alarm = now + 300;
        }
-       rtc_time_to_tm(alarm, &alm.time);
+       rtc_time64_to_tm(alarm, &alm.time);
 
        retval = rtc_set_alarm(rtc, &alm);
        return (retval < 0) ? retval : n;
index 65b432a096fe22ffc489f876c355f05654315bb4..0c34d3b81279e535bbe027e77bce04443bd5b05a 100644 (file)
@@ -52,6 +52,7 @@ struct xgene_rtc_dev {
        void __iomem *csr_base;
        struct clk *clk;
        unsigned int irq_wake;
+       unsigned int irq_enabled;
 };
 
 static int xgene_rtc_read_time(struct device *dev, struct rtc_time *tm)
@@ -104,15 +105,19 @@ static int xgene_rtc_alarm_irq_enable(struct device *dev, u32 enabled)
        return 0;
 }
 
+static int xgene_rtc_alarm_irq_enabled(struct device *dev)
+{
+       struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
+
+       return readl(pdata->csr_base + RTC_CCR) & RTC_CCR_IE ? 1 : 0;
+}
+
 static int xgene_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
        struct xgene_rtc_dev *pdata = dev_get_drvdata(dev);
-       unsigned long rtc_time;
        unsigned long alarm_time;
 
-       rtc_time = readl(pdata->csr_base + RTC_CCVR);
        rtc_tm_to_time(&alrm->time, &alarm_time);
-
        pdata->alarm_time = alarm_time;
        writel((u32) pdata->alarm_time, pdata->csr_base + RTC_CMR);
 
@@ -180,12 +185,18 @@ static int xgene_rtc_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "Couldn't get the clock for RTC\n");
                return -ENODEV;
        }
-       clk_prepare_enable(pdata->clk);
+       ret = clk_prepare_enable(pdata->clk);
+       if (ret)
+               return ret;
 
        /* Turn on the clock and the crystal */
        writel(RTC_CCR_EN, pdata->csr_base + RTC_CCR);
 
-       device_init_wakeup(&pdev->dev, 1);
+       ret = device_init_wakeup(&pdev->dev, 1);
+       if (ret) {
+               clk_disable_unprepare(pdata->clk);
+               return ret;
+       }
 
        pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
                                         &xgene_rtc_ops, THIS_MODULE);
@@ -210,45 +221,55 @@ static int xgene_rtc_remove(struct platform_device *pdev)
        return 0;
 }
 
-#ifdef CONFIG_PM_SLEEP
-static int xgene_rtc_suspend(struct device *dev)
+static int __maybe_unused xgene_rtc_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev);
        int irq;
 
        irq = platform_get_irq(pdev, 0);
+
+       /*
+        * If this RTC alarm will be used for waking the system up,
+        * don't disable it of course. Else we just disable the alarm
+        * and await suspension.
+        */
        if (device_may_wakeup(&pdev->dev)) {
                if (!enable_irq_wake(irq))
                        pdata->irq_wake = 1;
        } else {
+               pdata->irq_enabled = xgene_rtc_alarm_irq_enabled(dev);
                xgene_rtc_alarm_irq_enable(dev, 0);
-               clk_disable(pdata->clk);
+               clk_disable_unprepare(pdata->clk);
        }
-
        return 0;
 }
 
-static int xgene_rtc_resume(struct device *dev)
+static int __maybe_unused xgene_rtc_resume(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
        struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev);
        int irq;
+       int rc;
 
        irq = platform_get_irq(pdev, 0);
+
        if (device_may_wakeup(&pdev->dev)) {
                if (pdata->irq_wake) {
                        disable_irq_wake(irq);
                        pdata->irq_wake = 0;
                }
        } else {
-               clk_enable(pdata->clk);
-               xgene_rtc_alarm_irq_enable(dev, 1);
+               rc = clk_prepare_enable(pdata->clk);
+               if (rc) {
+                       dev_err(dev, "Unable to enable clock error %d\n", rc);
+                       return rc;
+               }
+               xgene_rtc_alarm_irq_enable(dev, pdata->irq_enabled);
        }
 
        return 0;
 }
-#endif
 
 static SIMPLE_DEV_PM_OPS(xgene_rtc_pm_ops, xgene_rtc_suspend, xgene_rtc_resume);