]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/commitdiff
Merge tag 'rtc-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 13 Jul 2017 19:15:06 +0000 (12:15 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 13 Jul 2017 19:15:06 +0000 (12:15 -0700)
Pull RTC updates from Alexandre Belloni:
 "Here is the pull-request for the RTC subsystem for 4.13.

  Subsystem:

   - expose non volatile RAM using nvmem instead of open coding in many
     drivers. Unfortunately, this option has to be enabled by default to
     not break existing users.

   - rtctest can now test for cutoff dates, showing when an RTC will
     start failing to properly save time and date.

   - new RTC registration functions to remove race conditions in drivers

  Newly supported RTCs:

   - Broadcom STB wake-timer

   - Epson RX8130CE

   - Maxim IC DS1308

   - STMicroelectronics STM32H7

  Drivers:

   - ds1307: use regmap, use nvmem, more cleanups

   - ds3232: temperature reading support

   - gemini: renamed to ftrtc010

   - m41t80: use CCF to expose the clock

   - rv8803: use nvmem

   - s3c: many cleanups

   - st-lpc: fix y2106 bug"

* tag 'rtc-4.13' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (51 commits)
  rtc: Remove wrong deprecation comment
  nvmem: include linux/err.h from header
  rtc: st-lpc: make it robust against y2038/2106 bug
  rtc: rtctest: add check for problematic dates
  tools: timer: add rtctest_setdate
  rtc: ds1307: remove ds1307_remove
  rtc: ds1307: use generic nvmem
  rtc: ds1307: switch to rtc_register_device
  rtc: rv8803: remove rv8803_remove
  rtc: rv8803: use generic nvmem support
  rtc: rv8803: switch to rtc_register_device
  rtc: add generic nvmem support
  rtc: at91rm9200: remove race condition
  rtc: introduce new registration method
  rtc: class separate id allocation from registration
  rtc: class separate device allocation from registration
  rtc: stm32: add STM32H7 RTC support
  dt-bindings: rtc: stm32: add support for STM32H7
  rtc: ds1307: add ds1308 variant
  rtc: ds3232: add temperature support
  ...

34 files changed:
Documentation/devicetree/bindings/rtc/brcm,brcmstb-waketimer.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/cortina,gemini.txt [deleted file]
Documentation/devicetree/bindings/rtc/faraday,ftrtc010.txt [new file with mode: 0644]
Documentation/devicetree/bindings/rtc/st,stm32-rtc.txt
Documentation/rtc.txt
MAINTAINERS
drivers/rtc/Kconfig
drivers/rtc/Makefile
drivers/rtc/class.c
drivers/rtc/interface.c
drivers/rtc/nvmem.c [new file with mode: 0644]
drivers/rtc/rtc-at91rm9200.c
drivers/rtc/rtc-brcmstb-waketimer.c [new file with mode: 0644]
drivers/rtc/rtc-core.h
drivers/rtc/rtc-dev.c
drivers/rtc/rtc-ds1307.c
drivers/rtc/rtc-ds3232.c
drivers/rtc/rtc-ftrtc010.c [new file with mode: 0644]
drivers/rtc/rtc-gemini.c [deleted file]
drivers/rtc/rtc-m41t80.c
drivers/rtc/rtc-mxc.c
drivers/rtc/rtc-nuc900.c
drivers/rtc/rtc-opal.c
drivers/rtc/rtc-pcf8563.c
drivers/rtc/rtc-rv8803.c
drivers/rtc/rtc-s3c.c
drivers/rtc/rtc-st-lpc.c
drivers/rtc/rtc-stm32.c
drivers/rtc/rtc-sysfs.c
include/linux/nvmem-provider.h
include/linux/rtc.h
tools/testing/selftests/timers/Makefile
tools/testing/selftests/timers/rtctest.c
tools/testing/selftests/timers/rtctest_setdate.c [new file with mode: 0644]

diff --git a/Documentation/devicetree/bindings/rtc/brcm,brcmstb-waketimer.txt b/Documentation/devicetree/bindings/rtc/brcm,brcmstb-waketimer.txt
new file mode 100644 (file)
index 0000000..1d990bc
--- /dev/null
@@ -0,0 +1,22 @@
+Broadcom STB wake-up Timer
+
+The Broadcom STB wake-up timer provides a 27Mhz resolution timer, with the
+ability to wake up the system from low-power suspend/standby modes.
+
+Required properties:
+- compatible     : should contain "brcm,brcmstb-waketimer"
+- reg            : the register start and length for the WKTMR block
+- interrupts     : The TIMER interrupt
+- interrupt-parent: The phandle to the Always-On (AON) Power Management (PM) L2
+                    interrupt controller node
+- clocks        : The phandle to the UPG fixed clock (27Mhz domain)
+
+Example:
+
+waketimer@f0411580 {
+       compatible = "brcm,brcmstb-waketimer";
+       reg = <0xf0411580 0x14>;
+       interrupts = <0x3>;
+       interrupt-parent = <&aon_pm_l2_intc>;
+       clocks = <&upg_fixed>;
+};
diff --git a/Documentation/devicetree/bindings/rtc/cortina,gemini.txt b/Documentation/devicetree/bindings/rtc/cortina,gemini.txt
deleted file mode 100644 (file)
index 4ce4e79..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-* Cortina Systems Gemini RTC
-
-Gemini SoC real-time clock.
-
-Required properties:
-- compatible : Should be "cortina,gemini-rtc"
-
-Examples:
-
-rtc@45000000 {
-       compatible = "cortina,gemini-rtc";
-       reg = <0x45000000 0x100>;
-       interrupts = <17 IRQ_TYPE_LEVEL_HIGH>;
-};
diff --git a/Documentation/devicetree/bindings/rtc/faraday,ftrtc010.txt b/Documentation/devicetree/bindings/rtc/faraday,ftrtc010.txt
new file mode 100644 (file)
index 0000000..e3938f5
--- /dev/null
@@ -0,0 +1,28 @@
+* Faraday Technology FTRTC010 Real Time Clock
+
+This RTC appears in for example the Storlink Gemini family of
+SoCs.
+
+Required properties:
+- compatible : Should be one of:
+  "faraday,ftrtc010"
+  "cortina,gemini-rtc", "faraday,ftrtc010"
+
+Optional properties:
+- clocks: when present should contain clock references to the
+  PCLK and EXTCLK clocks. Faraday calls the later CLK1HZ and
+  says the clock should be 1 Hz, but implementers actually seem
+  to choose different clocks here, like Cortina who chose
+  32768 Hz (a typical low-power clock).
+- clock-names: should name the clocks "PCLK" and "EXTCLK"
+  respectively.
+
+Examples:
+
+rtc@45000000 {
+       compatible = "cortina,gemini-rtc";
+       reg = <0x45000000 0x100>;
+       interrupts = <17 IRQ_TYPE_LEVEL_HIGH>;
+       clocks = <&foo 0>, <&foo 1>;
+       clock-names = "PCLK", "EXTCLK";
+};
index e2837b951237b90300af6679975bed765bffdff3..0a4c371a9b7a8ac46eb7db378da1ad1b117723d1 100644 (file)
@@ -1,17 +1,25 @@
 STM32 Real Time Clock
 
 Required properties:
-- compatible: "st,stm32-rtc".
+- compatible: can be either "st,stm32-rtc" or "st,stm32h7-rtc", depending on
+  the device is compatible with stm32(f4/f7) or stm32h7.
 - reg: address range of rtc register set.
-- clocks: reference to the clock entry ck_rtc.
+- clocks: can use up to two clocks, depending on part used:
+  - "rtc_ck": RTC clock source.
+    It is required on stm32(f4/f7) and stm32h7.
+  - "pclk": RTC APB interface clock.
+    It is not present on stm32(f4/f7).
+    It is required on stm32h7.
+- clock-names: must be "rtc_ck" and "pclk".
+    It is required only on stm32h7.
 - interrupt-parent: phandle for the interrupt controller.
 - interrupts: rtc alarm interrupt.
 - st,syscfg: phandle for pwrcfg, mandatory to disable/enable backup domain
   (RTC registers) write protection.
 
-Optional properties (to override default ck_rtc parent clock):
-- assigned-clocks: reference to the ck_rtc clock entry.
-- assigned-clock-parents: phandle of the new parent clock of ck_rtc.
+Optional properties (to override default rtc_ck parent clock):
+- assigned-clocks: reference to the rtc_ck clock entry.
+- assigned-clock-parents: phandle of the new parent clock of rtc_ck.
 
 Example:
 
@@ -25,3 +33,17 @@ Example:
                interrupts = <17 1>;
                st,syscfg = <&pwrcfg>;
        };
+
+       rtc: rtc@58004000 {
+               compatible = "st,stm32h7-rtc";
+               reg = <0x58004000 0x400>;
+               clocks = <&rcc RTCAPB_CK>, <&rcc RTC_CK>;
+               clock-names = "pclk", "rtc_ck";
+               assigned-clocks = <&rcc RTC_CK>;
+               assigned-clock-parents = <&rcc LSE_CK>;
+               interrupt-parent = <&exti>;
+               interrupts = <17 1>;
+               interrupt-names = "alarm";
+               st,syscfg = <&pwrcfg>;
+               status = "disabled";
+       };
index ddc366026e00f60b8491fe50587e35836656835b..c0c977445fb9ca732e45acf1ddbf787f9398315d 100644 (file)
@@ -1,6 +1,6 @@
-
-       Real Time Clock (RTC) Drivers for Linux
-       =======================================
+=======================================
+Real Time Clock (RTC) Drivers for Linux
+=======================================
 
 When Linux developers talk about a "Real Time Clock", they usually mean
 something that tracks wall clock time and is battery backed so that it
@@ -32,8 +32,8 @@ only issue an alarm up to 24 hours in the future, other hardware may
 be able to schedule one any time in the upcoming century.
 
 
-       Old PC/AT-Compatible driver:  /dev/rtc
-       --------------------------------------
+Old PC/AT-Compatible driver:  /dev/rtc
+--------------------------------------
 
 All PCs (even Alpha machines) have a Real Time Clock built into them.
 Usually they are built into the chipset of the computer, but some may
@@ -105,8 +105,8 @@ that will be using this driver.  See the code at the end of this document.
 (The original /dev/rtc driver was written by Paul Gortmaker.)
 
 
-       New portable "RTC Class" drivers:  /dev/rtcN
-       --------------------------------------------
+New portable "RTC Class" drivers:  /dev/rtcN
+--------------------------------------------
 
 Because Linux supports many non-ACPI and non-PC platforms, some of which
 have more than one RTC style clock, it needed a more portable solution
@@ -136,35 +136,39 @@ a high functionality RTC is integrated into the SOC.  That system might read
 the system clock from the discrete RTC, but use the integrated one for all
 other tasks, because of its greater functionality.
 
-SYSFS INTERFACE
+SYSFS interface
 ---------------
 
 The sysfs interface under /sys/class/rtc/rtcN provides access to various
 rtc attributes without requiring the use of ioctls. All dates and times
 are in the RTC's timezone, rather than in system time.
 
-date:                   RTC-provided date
-hctosys:        1 if the RTC provided the system time at boot via the
+================ ==============================================================
+date            RTC-provided date
+hctosys         1 if the RTC provided the system time at boot via the
                 CONFIG_RTC_HCTOSYS kernel option, 0 otherwise
-max_user_freq:  The maximum interrupt rate an unprivileged user may request
+max_user_freq   The maximum interrupt rate an unprivileged user may request
                 from this RTC.
-name:           The name of the RTC corresponding to this sysfs directory
-since_epoch:    The number of seconds since the epoch according to the RTC
-time:           RTC-provided time
-wakealarm:      The time at which the clock will generate a system wakeup
+name            The name of the RTC corresponding to this sysfs directory
+since_epoch     The number of seconds since the epoch according to the RTC
+time            RTC-provided time
+wakealarm       The time at which the clock will generate a system wakeup
                 event. This is a one shot wakeup event, so must be reset
-                after wake if a daily wakeup is required. Format is seconds since
-                the epoch by default, or if there's a leading +, seconds in the
-                future, or if there is a leading +=, seconds ahead of the current
-                alarm.
-offset:                 The amount which the rtc clock has been adjusted in firmware.
+                after wake if a daily wakeup is required. Format is seconds
+                since the epoch by default, or if there's a leading +, seconds
+                in the future, or if there is a leading +=, seconds ahead of
+                the current alarm.
+offset          The amount which the rtc clock has been adjusted in firmware.
                 Visible only if the driver supports clock offset adjustment.
                 The unit is parts per billion, i.e. The number of clock ticks
                 which are added to or removed from the rtc's base clock per
                 billion ticks. A positive value makes a day pass more slowly,
                 longer, and a negative value makes a day pass more quickly.
+*/nvmem                 The non volatile storage exported as a raw file, as described
+                in Documentation/nvmem/nvmem.txt
+================ ==============================================================
 
-IOCTL INTERFACE
+IOCTL interface
 ---------------
 
 The ioctl() calls supported by /dev/rtc are also supported by the RTC class
index e1a22ed547b1b5751dbae50a70e7d611d9c7f17e..7d9bd4a041aff9254ce43f85ca173da777087c19 100644 (file)
@@ -1255,7 +1255,7 @@ L:        linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 T:     git git://github.com/ulli-kroll/linux.git
 S:     Maintained
 F:     arch/arm/mach-gemini/
-F:     drivers/rtc/rtc-gemini.c
+F:     drivers/rtc/rtc-ftrtc010.c
 
 ARM/CSR SIRFPRIMA2 MACHINE SUPPORT
 M:     Barry Song <baohua@kernel.org>
index 8d3b9572832666a5bbe5f5be8ea5a5f0b8efa29e..72419ac2c52a91345c69dcd4aaee6de1f585b35d 100644 (file)
@@ -77,6 +77,14 @@ config RTC_DEBUG
          Say yes here to enable debugging support in the RTC framework
          and individual RTC drivers.
 
+config RTC_NVMEM
+       bool "RTC non volatile storage support"
+       select NVMEM
+       default RTC_CLASS
+       help
+         Say yes here to add support for the non volatile (often battery
+         backed) storage present on RTCs.
+
 comment "RTC interfaces"
 
 config RTC_INTF_SYSFS
@@ -197,6 +205,17 @@ config RTC_DRV_AC100
          This driver can also be built as a module. If so, the module
          will be called rtc-ac100.
 
+config RTC_DRV_BRCMSTB
+       tristate "Broadcom STB wake-timer"
+       depends on ARCH_BRCMSTB || BMIPS_GENERIC || COMPILE_TEST
+       default ARCH_BRCMSTB || BMIPS_GENERIC
+       help
+         If you say yes here you get support for the wake-timer found on
+         Broadcom STB SoCs (BCM7xxx).
+
+         This driver can also be built as a module. If so, the module will
+         be called rtc-brcmstb-waketimer.
+
 config RTC_DRV_AS3722
        tristate "ams AS3722 RTC driver"
        depends on MFD_AS3722
@@ -791,6 +810,14 @@ config RTC_DRV_DS3232
          This driver can also be built as a module.  If so, the module
          will be called rtc-ds3232.
 
+config RTC_DRV_DS3232_HWMON
+       bool "HWMON support for Dallas/Maxim DS3232/DS3234"
+       depends on RTC_DRV_DS3232 && HWMON && !(RTC_DRV_DS3232=y && HWMON=m)
+       default y
+       help
+         Say Y here if you want to expose temperature sensor data on
+         rtc-ds3232
+
 config RTC_DRV_PCF2127
        tristate "NXP PCF2127"
        depends on RTC_I2C_AND_SPI
@@ -1484,16 +1511,16 @@ config RTC_DRV_ARMADA38X
          This driver can also be built as a module. If so, the module
          will be called armada38x-rtc.
 
-config RTC_DRV_GEMINI
-       tristate "Gemini SoC RTC"
-       depends on ARCH_GEMINI || COMPILE_TEST
+config RTC_DRV_FTRTC010
+       tristate "Faraday Technology FTRTC010 RTC"
        depends on HAS_IOMEM
+       default ARCH_GEMINI
        help
          If you say Y here you will get support for the
-         RTC found on Gemini SoC's.
+         Faraday Technolog FTRTC010 found on e.g. Gemini SoC's.
 
          This driver can also be built as a module. If so, the module
-         will be called rtc-gemini.
+         will be called rtc-ftrtc010.
 
 config RTC_DRV_PS3
        tristate "PS3 RTC"
index 13857d2fce09b24320db136c4e8deedc2f850259..acd366b41c854b390f773f8b6dd6f16e4c786fc9 100644 (file)
@@ -15,6 +15,7 @@ ifdef CONFIG_RTC_DRV_EFI
 rtc-core-y                     += rtc-efi-platform.o
 endif
 
+rtc-core-$(CONFIG_RTC_NVMEM)           += nvmem.o
 rtc-core-$(CONFIG_RTC_INTF_DEV)                += rtc-dev.o
 rtc-core-$(CONFIG_RTC_INTF_PROC)       += rtc-proc.o
 rtc-core-$(CONFIG_RTC_INTF_SYSFS)      += rtc-sysfs.o
@@ -36,6 +37,7 @@ obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
 obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
 obj-$(CONFIG_RTC_DRV_AU1XXX)   += rtc-au1xxx.o
 obj-$(CONFIG_RTC_DRV_BFIN)     += rtc-bfin.o
+obj-$(CONFIG_RTC_DRV_BRCMSTB)  += rtc-brcmstb-waketimer.o
 obj-$(CONFIG_RTC_DRV_BQ32K)    += rtc-bq32k.o
 obj-$(CONFIG_RTC_DRV_BQ4802)   += rtc-bq4802.o
 obj-$(CONFIG_RTC_DRV_CMOS)     += rtc-cmos.o
@@ -67,7 +69,7 @@ obj-$(CONFIG_RTC_DRV_EFI)     += rtc-efi.o
 obj-$(CONFIG_RTC_DRV_EM3027)   += rtc-em3027.o
 obj-$(CONFIG_RTC_DRV_EP93XX)   += rtc-ep93xx.o
 obj-$(CONFIG_RTC_DRV_FM3130)   += rtc-fm3130.o
-obj-$(CONFIG_RTC_DRV_GEMINI)   += rtc-gemini.o
+obj-$(CONFIG_RTC_DRV_FTRTC010) += rtc-ftrtc010.o
 obj-$(CONFIG_RTC_DRV_GENERIC)  += rtc-generic.o
 obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o
 obj-$(CONFIG_RTC_DRV_HYM8563)  += rtc-hym8563.o
index 5fb439897fe1acb707a8629ffdc788a59e80d544..2ed970d61da140c23a266e43a8b3b6b0eae8914d 100644 (file)
@@ -150,59 +150,19 @@ static SIMPLE_DEV_PM_OPS(rtc_class_dev_pm_ops, rtc_suspend, rtc_resume);
 #define RTC_CLASS_DEV_PM_OPS   NULL
 #endif
 
-
-/**
- * rtc_device_register - register w/ RTC class
- * @dev: the device to register
- *
- * rtc_device_unregister() must be called when the class device is no
- * longer needed.
- *
- * Returns the pointer to the new struct class device.
- */
-struct rtc_device *rtc_device_register(const char *name, struct device *dev,
-                                       const struct rtc_class_ops *ops,
-                                       struct module *owner)
+/* Ensure the caller will set the id before releasing the device */
+static struct rtc_device *rtc_allocate_device(void)
 {
        struct rtc_device *rtc;
-       struct rtc_wkalrm alrm;
-       int of_id = -1, id = -1, err;
-
-       if (dev->of_node)
-               of_id = of_alias_get_id(dev->of_node, "rtc");
-       else if (dev->parent && dev->parent->of_node)
-               of_id = of_alias_get_id(dev->parent->of_node, "rtc");
 
-       if (of_id >= 0) {
-               id = ida_simple_get(&rtc_ida, of_id, of_id + 1,
-                                   GFP_KERNEL);
-               if (id < 0)
-                       dev_warn(dev, "/aliases ID %d not available\n",
-                                   of_id);
-       }
-
-       if (id < 0) {
-               id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);
-               if (id < 0) {
-                       err = id;
-                       goto exit;
-               }
-       }
-
-       rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
-       if (rtc == NULL) {
-               err = -ENOMEM;
-               goto exit_ida;
-       }
+       rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+       if (!rtc)
+               return NULL;
 
        device_initialize(&rtc->dev);
 
-       rtc->id = id;
-       rtc->ops = ops;
-       rtc->owner = owner;
        rtc->irq_freq = 1;
        rtc->max_user_freq = 64;
-       rtc->dev.parent = dev;
        rtc->dev.class = rtc_class;
        rtc->dev.groups = rtc_get_dev_attribute_groups();
        rtc->dev.release = rtc_device_release;
@@ -224,7 +184,64 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
        rtc->pie_timer.function = rtc_pie_update_irq;
        rtc->pie_enabled = 0;
 
-       strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
+       return rtc;
+}
+
+static int rtc_device_get_id(struct device *dev)
+{
+       int of_id = -1, id = -1;
+
+       if (dev->of_node)
+               of_id = of_alias_get_id(dev->of_node, "rtc");
+       else if (dev->parent && dev->parent->of_node)
+               of_id = of_alias_get_id(dev->parent->of_node, "rtc");
+
+       if (of_id >= 0) {
+               id = ida_simple_get(&rtc_ida, of_id, of_id + 1, GFP_KERNEL);
+               if (id < 0)
+                       dev_warn(dev, "/aliases ID %d not available\n", of_id);
+       }
+
+       if (id < 0)
+               id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);
+
+       return id;
+}
+
+/**
+ * rtc_device_register - register w/ RTC class
+ * @dev: the device to register
+ *
+ * rtc_device_unregister() must be called when the class device is no
+ * longer needed.
+ *
+ * Returns the pointer to the new struct class device.
+ */
+struct rtc_device *rtc_device_register(const char *name, struct device *dev,
+                                       const struct rtc_class_ops *ops,
+                                       struct module *owner)
+{
+       struct rtc_device *rtc;
+       struct rtc_wkalrm alrm;
+       int id, err;
+
+       id = rtc_device_get_id(dev);
+       if (id < 0) {
+               err = id;
+               goto exit;
+       }
+
+       rtc = rtc_allocate_device();
+       if (!rtc) {
+               err = -ENOMEM;
+               goto exit_ida;
+       }
+
+       rtc->id = id;
+       rtc->ops = ops;
+       rtc->owner = owner;
+       rtc->dev.parent = dev;
+
        dev_set_name(&rtc->dev, "rtc%d", id);
 
        /* Check to see if there is an ALARM already set in hw */
@@ -238,20 +255,20 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
        err = cdev_device_add(&rtc->char_dev, &rtc->dev);
        if (err) {
                dev_warn(&rtc->dev, "%s: failed to add char device %d:%d\n",
-                        rtc->name, MAJOR(rtc->dev.devt), rtc->id);
+                        name, MAJOR(rtc->dev.devt), rtc->id);
 
                /* This will free both memory and the ID */
                put_device(&rtc->dev);
                goto exit;
        } else {
-               dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", rtc->name,
+               dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", name,
                        MAJOR(rtc->dev.devt), rtc->id);
        }
 
        rtc_proc_add_device(rtc);
 
        dev_info(dev, "rtc core: registered %s as %s\n",
-                       rtc->name, dev_name(&rtc->dev));
+                       name, dev_name(&rtc->dev));
 
        return rtc;
 
@@ -273,6 +290,8 @@ EXPORT_SYMBOL_GPL(rtc_device_register);
  */
 void rtc_device_unregister(struct rtc_device *rtc)
 {
+       rtc_nvmem_unregister(rtc);
+
        mutex_lock(&rtc->ops_lock);
        /*
         * Remove innards of this RTC, then disable it, before
@@ -356,6 +375,91 @@ void devm_rtc_device_unregister(struct device *dev, struct rtc_device *rtc)
 }
 EXPORT_SYMBOL_GPL(devm_rtc_device_unregister);
 
+static void devm_rtc_release_device(struct device *dev, void *res)
+{
+       struct rtc_device *rtc = *(struct rtc_device **)res;
+
+       if (rtc->registered)
+               rtc_device_unregister(rtc);
+       else
+               put_device(&rtc->dev);
+}
+
+struct rtc_device *devm_rtc_allocate_device(struct device *dev)
+{
+       struct rtc_device **ptr, *rtc;
+       int id, err;
+
+       id = rtc_device_get_id(dev);
+       if (id < 0)
+               return ERR_PTR(id);
+
+       ptr = devres_alloc(devm_rtc_release_device, sizeof(*ptr), GFP_KERNEL);
+       if (!ptr) {
+               err = -ENOMEM;
+               goto exit_ida;
+       }
+
+       rtc = rtc_allocate_device();
+       if (!rtc) {
+               err = -ENOMEM;
+               goto exit_devres;
+       }
+
+       *ptr = rtc;
+       devres_add(dev, ptr);
+
+       rtc->id = id;
+       rtc->dev.parent = dev;
+       dev_set_name(&rtc->dev, "rtc%d", id);
+
+       return rtc;
+
+exit_devres:
+       devres_free(ptr);
+exit_ida:
+       ida_simple_remove(&rtc_ida, id);
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(devm_rtc_allocate_device);
+
+int __rtc_register_device(struct module *owner, struct rtc_device *rtc)
+{
+       struct rtc_wkalrm alrm;
+       int err;
+
+       if (!rtc->ops)
+               return -EINVAL;
+
+       rtc->owner = owner;
+
+       /* Check to see if there is an ALARM already set in hw */
+       err = __rtc_read_alarm(rtc, &alrm);
+       if (!err && !rtc_valid_tm(&alrm.time))
+               rtc_initialize_alarm(rtc, &alrm);
+
+       rtc_dev_prepare(rtc);
+
+       err = cdev_device_add(&rtc->char_dev, &rtc->dev);
+       if (err)
+               dev_warn(rtc->dev.parent, "failed to add char device %d:%d\n",
+                        MAJOR(rtc->dev.devt), rtc->id);
+       else
+               dev_dbg(rtc->dev.parent, "char device (%d:%d)\n",
+                       MAJOR(rtc->dev.devt), rtc->id);
+
+       rtc_proc_add_device(rtc);
+
+       rtc_nvmem_register(rtc);
+
+       rtc->registered = true;
+       dev_info(rtc->dev.parent, "registered as %s\n",
+                dev_name(&rtc->dev));
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(__rtc_register_device);
+
 static int __init rtc_init(void)
 {
        rtc_class = class_create(THIS_MODULE, "rtc");
index fc0fa7577636dab1c02c3a34ea9e2c18b3255bfd..8cec9a02c0b8937fdcdca2fdd80d14dba4e79b7c 100644 (file)
@@ -227,6 +227,13 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
                        missing = year;
        }
 
+       /* Can't proceed if alarm is still invalid after replacing
+        * missing fields.
+        */
+       err = rtc_valid_tm(&alarm->time);
+       if (err)
+               goto done;
+
        /* with luck, no rollover is needed */
        t_now = rtc_tm_to_time64(&now);
        t_alm = rtc_tm_to_time64(&alarm->time);
@@ -278,9 +285,9 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
                dev_warn(&rtc->dev, "alarm rollover not handled\n");
        }
 
-done:
        err = rtc_valid_tm(&alarm->time);
 
+done:
        if (err) {
                dev_warn(&rtc->dev, "invalid alarm value: %d-%d-%d %d:%d:%d\n",
                        alarm->time.tm_year + 1900, alarm->time.tm_mon + 1,
diff --git a/drivers/rtc/nvmem.c b/drivers/rtc/nvmem.c
new file mode 100644 (file)
index 0000000..8567b4e
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * RTC subsystem, nvmem interface
+ *
+ * Copyright (C) 2017 Alexandre Belloni
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/types.h>
+#include <linux/nvmem-consumer.h>
+#include <linux/rtc.h>
+#include <linux/sysfs.h>
+
+#include "rtc-core.h"
+
+/*
+ * Deprecated ABI compatibility, this should be removed at some point
+ */
+
+static const char nvram_warning[] = "Deprecated ABI, please use nvmem";
+
+static ssize_t
+rtc_nvram_read(struct file *filp, struct kobject *kobj,
+              struct bin_attribute *attr,
+              char *buf, loff_t off, size_t count)
+{
+       struct rtc_device *rtc = attr->private;
+
+       dev_warn_once(kobj_to_dev(kobj), nvram_warning);
+
+       return nvmem_device_read(rtc->nvmem, off, count, buf);
+}
+
+static ssize_t
+rtc_nvram_write(struct file *filp, struct kobject *kobj,
+               struct bin_attribute *attr,
+               char *buf, loff_t off, size_t count)
+{
+       struct rtc_device *rtc = attr->private;
+
+       dev_warn_once(kobj_to_dev(kobj), nvram_warning);
+
+       return nvmem_device_write(rtc->nvmem, off, count, buf);
+}
+
+static int rtc_nvram_register(struct rtc_device *rtc)
+{
+       int err;
+
+       rtc->nvram = devm_kzalloc(rtc->dev.parent,
+                               sizeof(struct bin_attribute),
+                               GFP_KERNEL);
+       if (!rtc->nvram)
+               return -ENOMEM;
+
+       rtc->nvram->attr.name = "nvram";
+       rtc->nvram->attr.mode = 0644;
+       rtc->nvram->private = rtc;
+
+       sysfs_bin_attr_init(rtc->nvram);
+
+       rtc->nvram->read = rtc_nvram_read;
+       rtc->nvram->write = rtc_nvram_write;
+       rtc->nvram->size = rtc->nvmem_config->size;
+
+       err = sysfs_create_bin_file(&rtc->dev.parent->kobj,
+                                   rtc->nvram);
+       if (err) {
+               devm_kfree(rtc->dev.parent, rtc->nvram);
+               rtc->nvram = NULL;
+       }
+
+       return err;
+}
+
+static void rtc_nvram_unregister(struct rtc_device *rtc)
+{
+       sysfs_remove_bin_file(&rtc->dev.parent->kobj, rtc->nvram);
+}
+
+/*
+ * New ABI, uses nvmem
+ */
+void rtc_nvmem_register(struct rtc_device *rtc)
+{
+       if (!rtc->nvmem_config)
+               return;
+
+       rtc->nvmem_config->dev = &rtc->dev;
+       rtc->nvmem_config->owner = rtc->owner;
+       rtc->nvmem = nvmem_register(rtc->nvmem_config);
+       if (IS_ERR_OR_NULL(rtc->nvmem))
+               return;
+
+       /* Register the old ABI */
+       if (rtc->nvram_old_abi)
+               rtc_nvram_register(rtc);
+}
+
+void rtc_nvmem_unregister(struct rtc_device *rtc)
+{
+       if (IS_ERR_OR_NULL(rtc->nvmem))
+               return;
+
+       /* unregister the old ABI */
+       if (rtc->nvram)
+               rtc_nvram_unregister(rtc);
+
+       nvmem_unregister(rtc->nvmem);
+}
index b60fd477778f7fed1e8c1a510d80646f47d8373f..e221b78b6f106ec3ccde7c3326b5934c48153f9c 100644 (file)
@@ -409,6 +409,11 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       rtc = devm_rtc_allocate_device(&pdev->dev);
+       if (IS_ERR(rtc))
+               return PTR_ERR(rtc);
+       platform_set_drvdata(pdev, rtc);
+
        sclk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(sclk))
                return PTR_ERR(sclk);
@@ -441,13 +446,10 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
        if (!device_can_wakeup(&pdev->dev))
                device_init_wakeup(&pdev->dev, 1);
 
-       rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
-                               &at91_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rtc)) {
-               ret = PTR_ERR(rtc);
+       rtc->ops = &at91_rtc_ops;
+       ret = rtc_register_device(rtc);
+       if (ret)
                goto err_clk;
-       }
-       platform_set_drvdata(pdev, rtc);
 
        /* enable SECEV interrupt in order to initialize at91_rtc_upd_rdy
         * completion.
diff --git a/drivers/rtc/rtc-brcmstb-waketimer.c b/drivers/rtc/rtc-brcmstb-waketimer.c
new file mode 100644 (file)
index 0000000..796ac79
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * Copyright Â© 2014-2017 Broadcom
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt)    KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irqreturn.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
+#include <linux/pm_wakeup.h>
+#include <linux/reboot.h>
+#include <linux/rtc.h>
+#include <linux/stat.h>
+#include <linux/suspend.h>
+
+struct brcmstb_waketmr {
+       struct rtc_device *rtc;
+       struct device *dev;
+       void __iomem *base;
+       int irq;
+       struct notifier_block reboot_notifier;
+       struct clk *clk;
+       u32 rate;
+};
+
+#define BRCMSTB_WKTMR_EVENT            0x00
+#define BRCMSTB_WKTMR_COUNTER          0x04
+#define BRCMSTB_WKTMR_ALARM            0x08
+#define BRCMSTB_WKTMR_PRESCALER                0x0C
+#define BRCMSTB_WKTMR_PRESCALER_VAL    0x10
+
+#define BRCMSTB_WKTMR_DEFAULT_FREQ     27000000
+
+static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer)
+{
+       writel_relaxed(1, timer->base + BRCMSTB_WKTMR_EVENT);
+       (void)readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
+}
+
+static void brcmstb_waketmr_set_alarm(struct brcmstb_waketmr *timer,
+                                     unsigned int secs)
+{
+       brcmstb_waketmr_clear_alarm(timer);
+
+       writel_relaxed(secs + 1, timer->base + BRCMSTB_WKTMR_ALARM);
+}
+
+static irqreturn_t brcmstb_waketmr_irq(int irq, void *data)
+{
+       struct brcmstb_waketmr *timer = data;
+
+       pm_wakeup_event(timer->dev, 0);
+
+       return IRQ_HANDLED;
+}
+
+struct wktmr_time {
+       u32 sec;
+       u32 pre;
+};
+
+static void wktmr_read(struct brcmstb_waketmr *timer,
+                      struct wktmr_time *t)
+{
+       u32 tmp;
+
+       do {
+               t->sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER);
+               tmp = readl_relaxed(timer->base + BRCMSTB_WKTMR_PRESCALER_VAL);
+       } while (tmp >= timer->rate);
+
+       t->pre = timer->rate - tmp;
+}
+
+static int brcmstb_waketmr_prepare_suspend(struct brcmstb_waketmr *timer)
+{
+       struct device *dev = timer->dev;
+       int ret = 0;
+
+       if (device_may_wakeup(dev)) {
+               ret = enable_irq_wake(timer->irq);
+               if (ret) {
+                       dev_err(dev, "failed to enable wake-up interrupt\n");
+                       return ret;
+               }
+       }
+
+       return ret;
+}
+
+/* If enabled as a wakeup-source, arm the timer when powering off */
+static int brcmstb_waketmr_reboot(struct notifier_block *nb,
+               unsigned long action, void *data)
+{
+       struct brcmstb_waketmr *timer;
+
+       timer = container_of(nb, struct brcmstb_waketmr, reboot_notifier);
+
+       /* Set timer for cold boot */
+       if (action == SYS_POWER_OFF)
+               brcmstb_waketmr_prepare_suspend(timer);
+
+       return NOTIFY_DONE;
+}
+
+static int brcmstb_waketmr_gettime(struct device *dev,
+                                  struct rtc_time *tm)
+{
+       struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
+       struct wktmr_time now;
+
+       wktmr_read(timer, &now);
+
+       rtc_time_to_tm(now.sec, tm);
+
+       return 0;
+}
+
+static int brcmstb_waketmr_settime(struct device *dev,
+                                  struct rtc_time *tm)
+{
+       struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
+       time64_t sec;
+
+       sec = rtc_tm_to_time64(tm);
+
+       if (sec > U32_MAX || sec < 0)
+               return -EINVAL;
+
+       writel_relaxed(sec, timer->base + BRCMSTB_WKTMR_COUNTER);
+
+       return 0;
+}
+
+static int brcmstb_waketmr_getalarm(struct device *dev,
+                                   struct rtc_wkalrm *alarm)
+{
+       struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
+       time64_t sec;
+       u32 reg;
+
+       sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM);
+       if (sec != 0) {
+               /* Alarm is enabled */
+               alarm->enabled = 1;
+               rtc_time64_to_tm(sec, &alarm->time);
+       }
+
+       reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
+       alarm->pending = !!(reg & 1);
+
+       return 0;
+}
+
+static int brcmstb_waketmr_setalarm(struct device *dev,
+                                    struct rtc_wkalrm *alarm)
+{
+       struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
+       time64_t sec;
+
+       if (alarm->enabled)
+               sec = rtc_tm_to_time64(&alarm->time);
+       else
+               sec = 0;
+
+       if (sec > U32_MAX || sec < 0)
+               return -EINVAL;
+
+       brcmstb_waketmr_set_alarm(timer, sec);
+
+       return 0;
+}
+
+/*
+ * Does not do much but keep the RTC class happy. We always support
+ * alarms.
+ */
+static int brcmstb_waketmr_alarm_enable(struct device *dev,
+                                       unsigned int enabled)
+{
+       return 0;
+}
+
+static const struct rtc_class_ops brcmstb_waketmr_ops = {
+       .read_time      = brcmstb_waketmr_gettime,
+       .set_time       = brcmstb_waketmr_settime,
+       .read_alarm     = brcmstb_waketmr_getalarm,
+       .set_alarm      = brcmstb_waketmr_setalarm,
+       .alarm_irq_enable = brcmstb_waketmr_alarm_enable,
+};
+
+static int brcmstb_waketmr_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct brcmstb_waketmr *timer;
+       struct resource *res;
+       int ret;
+
+       timer = devm_kzalloc(dev, sizeof(*timer), GFP_KERNEL);
+       if (!timer)
+               return -ENOMEM;
+
+       platform_set_drvdata(pdev, timer);
+       timer->dev = dev;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       timer->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(timer->base))
+               return PTR_ERR(timer->base);
+
+       /*
+        * Set wakeup capability before requesting wakeup interrupt, so we can
+        * process boot-time "wakeups" (e.g., from S5 soft-off)
+        */
+       device_set_wakeup_capable(dev, true);
+       device_wakeup_enable(dev);
+
+       timer->irq = platform_get_irq(pdev, 0);
+       if (timer->irq < 0)
+               return -ENODEV;
+
+       timer->clk = devm_clk_get(dev, NULL);
+       if (!IS_ERR(timer->clk)) {
+               ret = clk_prepare_enable(timer->clk);
+               if (ret)
+                       return ret;
+               timer->rate = clk_get_rate(timer->clk);
+               if (!timer->rate)
+                       timer->rate = BRCMSTB_WKTMR_DEFAULT_FREQ;
+       } else {
+               timer->rate = BRCMSTB_WKTMR_DEFAULT_FREQ;
+               timer->clk = NULL;
+       }
+
+       ret = devm_request_irq(dev, timer->irq, brcmstb_waketmr_irq, 0,
+                              "brcmstb-waketimer", timer);
+       if (ret < 0)
+               return ret;
+
+       timer->reboot_notifier.notifier_call = brcmstb_waketmr_reboot;
+       register_reboot_notifier(&timer->reboot_notifier);
+
+       timer->rtc = rtc_device_register("brcmstb-waketmr", dev,
+                                        &brcmstb_waketmr_ops, THIS_MODULE);
+       if (IS_ERR(timer->rtc)) {
+               dev_err(dev, "unable to register device\n");
+               unregister_reboot_notifier(&timer->reboot_notifier);
+               return PTR_ERR(timer->rtc);
+       }
+
+       dev_info(dev, "registered, with irq %d\n", timer->irq);
+
+       return ret;
+}
+
+static int brcmstb_waketmr_remove(struct platform_device *pdev)
+{
+       struct brcmstb_waketmr *timer = dev_get_drvdata(&pdev->dev);
+
+       unregister_reboot_notifier(&timer->reboot_notifier);
+       rtc_device_unregister(timer->rtc);
+
+       return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int brcmstb_waketmr_suspend(struct device *dev)
+{
+       struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
+
+       return brcmstb_waketmr_prepare_suspend(timer);
+}
+
+static int brcmstb_waketmr_resume(struct device *dev)
+{
+       struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
+       int ret;
+
+       if (!device_may_wakeup(dev))
+               return 0;
+
+       ret = disable_irq_wake(timer->irq);
+
+       brcmstb_waketmr_clear_alarm(timer);
+
+       return ret;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static SIMPLE_DEV_PM_OPS(brcmstb_waketmr_pm_ops,
+                        brcmstb_waketmr_suspend, brcmstb_waketmr_resume);
+
+static const struct of_device_id brcmstb_waketmr_of_match[] = {
+       { .compatible = "brcm,brcmstb-waketimer" },
+       { /* sentinel */ },
+};
+
+static struct platform_driver brcmstb_waketmr_driver = {
+       .probe                  = brcmstb_waketmr_probe,
+       .remove                 = brcmstb_waketmr_remove,
+       .driver = {
+               .name           = "brcmstb-waketimer",
+               .pm             = &brcmstb_waketmr_pm_ops,
+               .of_match_table = of_match_ptr(brcmstb_waketmr_of_match),
+       }
+};
+module_platform_driver(brcmstb_waketmr_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Brian Norris");
+MODULE_AUTHOR("Markus Mayer");
+MODULE_DESCRIPTION("Wake-up timer driver for STB chips");
index 7a4ed2f7c7d7dfcd531654d355d8ef4c23b082c5..ecab76a3207c08e2fd9ad58772bbde3104018154 100644 (file)
@@ -45,3 +45,11 @@ static inline const struct attribute_group **rtc_get_dev_attribute_groups(void)
        return NULL;
 }
 #endif
+
+#ifdef CONFIG_RTC_NVMEM
+void rtc_nvmem_register(struct rtc_device *rtc);
+void rtc_nvmem_unregister(struct rtc_device *rtc);
+#else
+static inline void rtc_nvmem_register(struct rtc_device *rtc) {}
+static inline void rtc_nvmem_unregister(struct rtc_device *rtc) {}
+#endif
index e81a8711fea741b2c347f9655b2fd158db093f7d..794bc4fa4937126314bc745aae218e7e2aabc903 100644 (file)
@@ -464,7 +464,7 @@ void rtc_dev_prepare(struct rtc_device *rtc)
                return;
 
        if (rtc->id >= RTC_DEV_MAX) {
-               dev_dbg(&rtc->dev, "%s: too many RTC devices\n", rtc->name);
+               dev_dbg(&rtc->dev, "too many RTC devices\n");
                return;
        }
 
index 77339b3d50a1e8a9f921afa54340a30373e3d00b..4fac49e55d473e80c87eb932698a33383ffca04b 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/hwmon.h>
 #include <linux/hwmon-sysfs.h>
 #include <linux/clk-provider.h>
+#include <linux/regmap.h>
 
 /*
  * We can't determine type by probing, but if we expect pre-Linux code
@@ -33,6 +34,7 @@
  */
 enum ds_type {
        ds_1307,
+       ds_1308,
        ds_1337,
        ds_1338,
        ds_1339,
@@ -43,6 +45,7 @@ enum ds_type {
        m41t00,
        mcp794xx,
        rx_8025,
+       rx_8130,
        last_ds_type /* always last */
        /* rs5c372 too?  different address... */
 };
@@ -115,17 +118,16 @@ struct ds1307 {
        u8                      offset; /* register's offset */
        u8                      regs[11];
        u16                     nvram_offset;
-       struct bin_attribute    *nvram;
+       struct nvmem_config     nvmem_cfg;
        enum ds_type            type;
        unsigned long           flags;
 #define HAS_NVRAM      0               /* bit 0 == sysfs file active */
 #define HAS_ALARM      1               /* bit 1 == irq claimed */
-       struct i2c_client       *client;
+       struct device           *dev;
+       struct regmap           *regmap;
+       const char              *name;
+       int                     irq;
        struct rtc_device       *rtc;
-       s32 (*read_block_data)(const struct i2c_client *client, u8 command,
-                              u8 length, u8 *values);
-       s32 (*write_block_data)(const struct i2c_client *client, u8 command,
-                               u8 length, const u8 *values);
 #ifdef CONFIG_COMMON_CLK
        struct clk_hw           clks[2];
 #endif
@@ -135,21 +137,30 @@ struct chip_desc {
        unsigned                alarm:1;
        u16                     nvram_offset;
        u16                     nvram_size;
+       u8                      century_reg;
+       u8                      century_enable_bit;
+       u8                      century_bit;
        u16                     trickle_charger_reg;
        u8                      trickle_charger_setup;
-       u8                      (*do_trickle_setup)(struct i2c_client *, uint32_t, bool);
+       u8                      (*do_trickle_setup)(struct ds1307 *, uint32_t,
+                                                   bool);
 };
 
-static u8 do_trickle_setup_ds1339(struct i2c_client *,
-                                 uint32_t ohms, bool diode);
+static u8 do_trickle_setup_ds1339(struct ds1307 *, uint32_t ohms, bool diode);
 
 static struct chip_desc chips[last_ds_type] = {
        [ds_1307] = {
                .nvram_offset   = 8,
                .nvram_size     = 56,
        },
+       [ds_1308] = {
+               .nvram_offset   = 8,
+               .nvram_size     = 56,
+       },
        [ds_1337] = {
                .alarm          = 1,
+               .century_reg    = DS1307_REG_MONTH,
+               .century_bit    = DS1337_BIT_CENTURY,
        },
        [ds_1338] = {
                .nvram_offset   = 8,
@@ -157,10 +168,15 @@ static struct chip_desc chips[last_ds_type] = {
        },
        [ds_1339] = {
                .alarm          = 1,
+               .century_reg    = DS1307_REG_MONTH,
+               .century_bit    = DS1337_BIT_CENTURY,
                .trickle_charger_reg = 0x10,
                .do_trickle_setup = &do_trickle_setup_ds1339,
        },
        [ds_1340] = {
+               .century_reg    = DS1307_REG_HOUR,
+               .century_enable_bit = DS1340_BIT_CENTURY_EN,
+               .century_bit    = DS1340_BIT_CENTURY,
                .trickle_charger_reg = 0x08,
        },
        [ds_1388] = {
@@ -168,6 +184,14 @@ static struct chip_desc chips[last_ds_type] = {
        },
        [ds_3231] = {
                .alarm          = 1,
+               .century_reg    = DS1307_REG_MONTH,
+               .century_bit    = DS1337_BIT_CENTURY,
+       },
+       [rx_8130] = {
+               .alarm          = 1,
+               /* this is battery backed SRAM */
+               .nvram_offset   = 0x20,
+               .nvram_size     = 4,    /* 32bit (4 word x 8 bit) */
        },
        [mcp794xx] = {
                .alarm          = 1,
@@ -179,6 +203,7 @@ static struct chip_desc chips[last_ds_type] = {
 
 static const struct i2c_device_id ds1307_id[] = {
        { "ds1307", ds_1307 },
+       { "ds1308", ds_1308 },
        { "ds1337", ds_1337 },
        { "ds1338", ds_1338 },
        { "ds1339", ds_1339 },
@@ -192,6 +217,7 @@ static const struct i2c_device_id ds1307_id[] = {
        { "pt7c4338", ds_1307 },
        { "rx8025", rx_8025 },
        { "isl12057", ds_1337 },
+       { "rx8130", rx_8130 },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, ds1307_id);
@@ -202,6 +228,10 @@ static const struct of_device_id ds1307_of_match[] = {
                .compatible = "dallas,ds1307",
                .data = (void *)ds_1307
        },
+       {
+               .compatible = "dallas,ds1308",
+               .data = (void *)ds_1308
+       },
        {
                .compatible = "dallas,ds1337",
                .data = (void *)ds_1337
@@ -262,6 +292,7 @@ MODULE_DEVICE_TABLE(of, ds1307_of_match);
 #ifdef CONFIG_ACPI
 static const struct acpi_device_id ds1307_acpi_ids[] = {
        { .id = "DS1307", .driver_data = ds_1307 },
+       { .id = "DS1308", .driver_data = ds_1308 },
        { .id = "DS1337", .driver_data = ds_1337 },
        { .id = "DS1338", .driver_data = ds_1338 },
        { .id = "DS1339", .driver_data = ds_1339 },
@@ -280,136 +311,6 @@ static const struct acpi_device_id ds1307_acpi_ids[] = {
 MODULE_DEVICE_TABLE(acpi, ds1307_acpi_ids);
 #endif
 
-/*----------------------------------------------------------------------*/
-
-#define BLOCK_DATA_MAX_TRIES 10
-
-static s32 ds1307_read_block_data_once(const struct i2c_client *client,
-                                      u8 command, u8 length, u8 *values)
-{
-       s32 i, data;
-
-       for (i = 0; i < length; i++) {
-               data = i2c_smbus_read_byte_data(client, command + i);
-               if (data < 0)
-                       return data;
-               values[i] = data;
-       }
-       return i;
-}
-
-static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command,
-                                 u8 length, u8 *values)
-{
-       u8 oldvalues[255];
-       s32 ret;
-       int tries = 0;
-
-       dev_dbg(&client->dev, "ds1307_read_block_data (length=%d)\n", length);
-       ret = ds1307_read_block_data_once(client, command, length, values);
-       if (ret < 0)
-               return ret;
-       do {
-               if (++tries > BLOCK_DATA_MAX_TRIES) {
-                       dev_err(&client->dev,
-                               "ds1307_read_block_data failed\n");
-                       return -EIO;
-               }
-               memcpy(oldvalues, values, length);
-               ret = ds1307_read_block_data_once(client, command, length,
-                                                 values);
-               if (ret < 0)
-                       return ret;
-       } while (memcmp(oldvalues, values, length));
-       return length;
-}
-
-static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command,
-                                  u8 length, const u8 *values)
-{
-       u8 currvalues[255];
-       int tries = 0;
-
-       dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length);
-       do {
-               s32 i, ret;
-
-               if (++tries > BLOCK_DATA_MAX_TRIES) {
-                       dev_err(&client->dev,
-                               "ds1307_write_block_data failed\n");
-                       return -EIO;
-               }
-               for (i = 0; i < length; i++) {
-                       ret = i2c_smbus_write_byte_data(client, command + i,
-                                                       values[i]);
-                       if (ret < 0)
-                               return ret;
-               }
-               ret = ds1307_read_block_data_once(client, command, length,
-                                                 currvalues);
-               if (ret < 0)
-                       return ret;
-       } while (memcmp(currvalues, values, length));
-       return length;
-}
-
-/*----------------------------------------------------------------------*/
-
-/* These RTC devices are not designed to be connected to a SMbus adapter.
-   SMbus limits block operations length to 32 bytes, whereas it's not
-   limited on I2C buses. As a result, accesses may exceed 32 bytes;
-   in that case, split them into smaller blocks */
-
-static s32 ds1307_native_smbus_write_block_data(const struct i2c_client *client,
-                               u8 command, u8 length, const u8 *values)
-{
-       u8 suboffset = 0;
-
-       if (length <= I2C_SMBUS_BLOCK_MAX) {
-               s32 retval = i2c_smbus_write_i2c_block_data(client,
-                                       command, length, values);
-               if (retval < 0)
-                       return retval;
-               return length;
-       }
-
-       while (suboffset < length) {
-               s32 retval = i2c_smbus_write_i2c_block_data(client,
-                               command + suboffset,
-                               min(I2C_SMBUS_BLOCK_MAX, length - suboffset),
-                               values + suboffset);
-               if (retval < 0)
-                       return retval;
-
-               suboffset += I2C_SMBUS_BLOCK_MAX;
-       }
-       return length;
-}
-
-static s32 ds1307_native_smbus_read_block_data(const struct i2c_client *client,
-                               u8 command, u8 length, u8 *values)
-{
-       u8 suboffset = 0;
-
-       if (length <= I2C_SMBUS_BLOCK_MAX)
-               return i2c_smbus_read_i2c_block_data(client,
-                                       command, length, values);
-
-       while (suboffset < length) {
-               s32 retval = i2c_smbus_read_i2c_block_data(client,
-                               command + suboffset,
-                               min(I2C_SMBUS_BLOCK_MAX, length - suboffset),
-                               values + suboffset);
-               if (retval < 0)
-                       return retval;
-
-               suboffset += I2C_SMBUS_BLOCK_MAX;
-       }
-       return length;
-}
-
-/*----------------------------------------------------------------------*/
-
 /*
  * The ds1337 and ds1339 both have two alarms, but we only use the first
  * one (with a "seconds" field).  For ds1337 we expect nINTA is our alarm
@@ -417,27 +318,24 @@ static s32 ds1307_native_smbus_read_block_data(const struct i2c_client *client,
  */
 static irqreturn_t ds1307_irq(int irq, void *dev_id)
 {
-       struct i2c_client       *client = dev_id;
-       struct ds1307           *ds1307 = i2c_get_clientdata(client);
+       struct ds1307           *ds1307 = dev_id;
        struct mutex            *lock = &ds1307->rtc->ops_lock;
-       int                     stat, control;
+       int                     stat, ret;
 
        mutex_lock(lock);
-       stat = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
-       if (stat < 0)
+       ret = regmap_read(ds1307->regmap, DS1337_REG_STATUS, &stat);
+       if (ret)
                goto out;
 
        if (stat & DS1337_BIT_A1I) {
                stat &= ~DS1337_BIT_A1I;
-               i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, stat);
+               regmap_write(ds1307->regmap, DS1337_REG_STATUS, stat);
 
-               control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
-               if (control < 0)
+               ret = regmap_update_bits(ds1307->regmap, DS1337_REG_CONTROL,
+                                        DS1337_BIT_A1IE, 0);
+               if (ret)
                        goto out;
 
-               control &= ~DS1337_BIT_A1IE;
-               i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, control);
-
                rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
        }
 
@@ -452,14 +350,14 @@ out:
 static int ds1307_get_time(struct device *dev, struct rtc_time *t)
 {
        struct ds1307   *ds1307 = dev_get_drvdata(dev);
-       int             tmp;
+       int             tmp, ret;
+       const struct chip_desc *chip = &chips[ds1307->type];
 
        /* read the RTC date and time registers all at once */
-       tmp = ds1307->read_block_data(ds1307->client,
-               ds1307->offset, 7, ds1307->regs);
-       if (tmp != 7) {
-               dev_err(dev, "%s error %d\n", "read", tmp);
-               return -EIO;
+       ret = regmap_bulk_read(ds1307->regmap, ds1307->offset, ds1307->regs, 7);
+       if (ret) {
+               dev_err(dev, "%s error %d\n", "read", ret);
+               return ret;
        }
 
        dev_dbg(dev, "%s: %7ph\n", "read", ds1307->regs);
@@ -481,22 +379,9 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
        t->tm_mon = bcd2bin(tmp) - 1;
        t->tm_year = bcd2bin(ds1307->regs[DS1307_REG_YEAR]) + 100;
 
-#ifdef CONFIG_RTC_DRV_DS1307_CENTURY
-       switch (ds1307->type) {
-       case ds_1337:
-       case ds_1339:
-       case ds_3231:
-               if (ds1307->regs[DS1307_REG_MONTH] & DS1337_BIT_CENTURY)
-                       t->tm_year += 100;
-               break;
-       case ds_1340:
-               if (ds1307->regs[DS1307_REG_HOUR] & DS1340_BIT_CENTURY)
-                       t->tm_year += 100;
-               break;
-       default:
-               break;
-       }
-#endif
+       if (ds1307->regs[chip->century_reg] & chip->century_bit &&
+           IS_ENABLED(CONFIG_RTC_DRV_DS1307_CENTURY))
+               t->tm_year += 100;
 
        dev_dbg(dev, "%s secs=%d, mins=%d, "
                "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
@@ -511,6 +396,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
 static int ds1307_set_time(struct device *dev, struct rtc_time *t)
 {
        struct ds1307   *ds1307 = dev_get_drvdata(dev);
+       const struct chip_desc *chip = &chips[ds1307->type];
        int             result;
        int             tmp;
        u8              *buf = ds1307->regs;
@@ -521,24 +407,14 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
                t->tm_hour, t->tm_mday,
                t->tm_mon, t->tm_year, t->tm_wday);
 
-#ifdef CONFIG_RTC_DRV_DS1307_CENTURY
        if (t->tm_year < 100)
                return -EINVAL;
 
-       switch (ds1307->type) {
-       case ds_1337:
-       case ds_1339:
-       case ds_3231:
-       case ds_1340:
-               if (t->tm_year > 299)
-                       return -EINVAL;
-       default:
-               if (t->tm_year > 199)
-                       return -EINVAL;
-               break;
-       }
+#ifdef CONFIG_RTC_DRV_DS1307_CENTURY
+       if (t->tm_year > (chip->century_bit ? 299 : 199))
+               return -EINVAL;
 #else
-       if (t->tm_year < 100 || t->tm_year > 199)
+       if (t->tm_year > 199)
                return -EINVAL;
 #endif
 
@@ -553,19 +429,12 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
        tmp = t->tm_year - 100;
        buf[DS1307_REG_YEAR] = bin2bcd(tmp);
 
-       switch (ds1307->type) {
-       case ds_1337:
-       case ds_1339:
-       case ds_3231:
-               if (t->tm_year > 199)
-                       buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY;
-               break;
-       case ds_1340:
-               buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN;
-               if (t->tm_year > 199)
-                       buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY;
-               break;
-       case mcp794xx:
+       if (chip->century_enable_bit)
+               buf[chip->century_reg] |= chip->century_enable_bit;
+       if (t->tm_year > 199 && chip->century_bit)
+               buf[chip->century_reg] |= chip->century_bit;
+
+       if (ds1307->type == mcp794xx) {
                /*
                 * these bits were cleared when preparing the date/time
                 * values and need to be set again before writing the
@@ -573,16 +442,12 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
                 */
                buf[DS1307_REG_SECS] |= MCP794XX_BIT_ST;
                buf[DS1307_REG_WDAY] |= MCP794XX_BIT_VBATEN;
-               break;
-       default:
-               break;
        }
 
        dev_dbg(dev, "%s: %7ph\n", "write", buf);
 
-       result = ds1307->write_block_data(ds1307->client,
-               ds1307->offset, 7, buf);
-       if (result < 0) {
+       result = regmap_bulk_write(ds1307->regmap, ds1307->offset, buf, 7);
+       if (result) {
                dev_err(dev, "%s error %d\n", "write", result);
                return result;
        }
@@ -591,19 +456,18 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
 
 static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
-       struct i2c_client       *client = to_i2c_client(dev);
-       struct ds1307           *ds1307 = i2c_get_clientdata(client);
+       struct ds1307           *ds1307 = dev_get_drvdata(dev);
        int                     ret;
 
        if (!test_bit(HAS_ALARM, &ds1307->flags))
                return -EINVAL;
 
        /* read all ALARM1, ALARM2, and status registers at once */
-       ret = ds1307->read_block_data(client,
-                       DS1339_REG_ALARM1_SECS, 9, ds1307->regs);
-       if (ret != 9) {
+       ret = regmap_bulk_read(ds1307->regmap, DS1339_REG_ALARM1_SECS,
+                              ds1307->regs, 9);
+       if (ret) {
                dev_err(dev, "%s error %d\n", "alarm read", ret);
-               return -EIO;
+               return ret;
        }
 
        dev_dbg(dev, "%s: %4ph, %3ph, %2ph\n", "alarm read",
@@ -633,8 +497,7 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
 
 static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
-       struct i2c_client       *client = to_i2c_client(dev);
-       struct ds1307           *ds1307 = i2c_get_clientdata(client);
+       struct ds1307           *ds1307 = dev_get_drvdata(dev);
        unsigned char           *buf = ds1307->regs;
        u8                      control, status;
        int                     ret;
@@ -649,11 +512,10 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
                t->enabled, t->pending);
 
        /* read current status of both alarms and the chip */
-       ret = ds1307->read_block_data(client,
-                       DS1339_REG_ALARM1_SECS, 9, buf);
-       if (ret != 9) {
+       ret = regmap_bulk_read(ds1307->regmap, DS1339_REG_ALARM1_SECS, buf, 9);
+       if (ret) {
                dev_err(dev, "%s error %d\n", "alarm write", ret);
-               return -EIO;
+               return ret;
        }
        control = ds1307->regs[7];
        status = ds1307->regs[8];
@@ -676,9 +538,8 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        buf[7] = control & ~(DS1337_BIT_A1IE | DS1337_BIT_A2IE);
        buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I);
 
-       ret = ds1307->write_block_data(client,
-                       DS1339_REG_ALARM1_SECS, 9, buf);
-       if (ret < 0) {
+       ret = regmap_bulk_write(ds1307->regmap, DS1339_REG_ALARM1_SECS, buf, 9);
+       if (ret) {
                dev_err(dev, "can't set alarm time\n");
                return ret;
        }
@@ -687,7 +548,7 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        if (t->enabled) {
                dev_dbg(dev, "alarm IRQ armed\n");
                buf[7] |= DS1337_BIT_A1IE;      /* only ALARM1 is used */
-               i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, buf[7]);
+               regmap_write(ds1307->regmap, DS1337_REG_CONTROL, buf[7]);
        }
 
        return 0;
@@ -695,35 +556,181 @@ static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 
 static int ds1307_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
-       struct i2c_client       *client = to_i2c_client(dev);
-       struct ds1307           *ds1307 = i2c_get_clientdata(client);
-       int                     ret;
+       struct ds1307           *ds1307 = dev_get_drvdata(dev);
 
        if (!test_bit(HAS_ALARM, &ds1307->flags))
                return -ENOTTY;
 
-       ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
+       return regmap_update_bits(ds1307->regmap, DS1337_REG_CONTROL,
+                                 DS1337_BIT_A1IE,
+                                 enabled ? DS1337_BIT_A1IE : 0);
+}
+
+static const struct rtc_class_ops ds13xx_rtc_ops = {
+       .read_time      = ds1307_get_time,
+       .set_time       = ds1307_set_time,
+       .read_alarm     = ds1337_read_alarm,
+       .set_alarm      = ds1337_set_alarm,
+       .alarm_irq_enable = ds1307_alarm_irq_enable,
+};
+
+/*----------------------------------------------------------------------*/
+
+/*
+ * Alarm support for rx8130 devices.
+ */
+
+#define RX8130_REG_ALARM_MIN           0x07
+#define RX8130_REG_ALARM_HOUR          0x08
+#define RX8130_REG_ALARM_WEEK_OR_DAY   0x09
+#define RX8130_REG_EXTENSION           0x0c
+#define RX8130_REG_EXTENSION_WADA      (1 << 3)
+#define RX8130_REG_FLAG                        0x0d
+#define RX8130_REG_FLAG_AF             (1 << 3)
+#define RX8130_REG_CONTROL0            0x0e
+#define RX8130_REG_CONTROL0_AIE                (1 << 3)
+
+static irqreturn_t rx8130_irq(int irq, void *dev_id)
+{
+       struct ds1307           *ds1307 = dev_id;
+       struct mutex            *lock = &ds1307->rtc->ops_lock;
+       u8 ctl[3];
+       int ret;
+
+       mutex_lock(lock);
+
+       /* Read control registers. */
+       ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3);
        if (ret < 0)
-               return ret;
+               goto out;
+       if (!(ctl[1] & RX8130_REG_FLAG_AF))
+               goto out;
+       ctl[1] &= ~RX8130_REG_FLAG_AF;
+       ctl[2] &= ~RX8130_REG_CONTROL0_AIE;
 
-       if (enabled)
-               ret |= DS1337_BIT_A1IE;
-       else
-               ret &= ~DS1337_BIT_A1IE;
+       ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3);
+       if (ret < 0)
+               goto out;
+
+       rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
+
+out:
+       mutex_unlock(lock);
+
+       return IRQ_HANDLED;
+}
 
-       ret = i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, ret);
+static int rx8130_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+       struct ds1307 *ds1307 = dev_get_drvdata(dev);
+       u8 ald[3], ctl[3];
+       int ret;
+
+       if (!test_bit(HAS_ALARM, &ds1307->flags))
+               return -EINVAL;
+
+       /* Read alarm registers. */
+       ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_ALARM_MIN, ald, 3);
        if (ret < 0)
                return ret;
 
+       /* Read control registers. */
+       ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3);
+       if (ret < 0)
+               return ret;
+
+       t->enabled = !!(ctl[2] & RX8130_REG_CONTROL0_AIE);
+       t->pending = !!(ctl[1] & RX8130_REG_FLAG_AF);
+
+       /* Report alarm 0 time assuming 24-hour and day-of-month modes. */
+       t->time.tm_sec = -1;
+       t->time.tm_min = bcd2bin(ald[0] & 0x7f);
+       t->time.tm_hour = bcd2bin(ald[1] & 0x7f);
+       t->time.tm_wday = -1;
+       t->time.tm_mday = bcd2bin(ald[2] & 0x7f);
+       t->time.tm_mon = -1;
+       t->time.tm_year = -1;
+       t->time.tm_yday = -1;
+       t->time.tm_isdst = -1;
+
+       dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d enabled=%d\n",
+               __func__, t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
+               t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled);
+
        return 0;
 }
 
-static const struct rtc_class_ops ds13xx_rtc_ops = {
+static int rx8130_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+       struct ds1307 *ds1307 = dev_get_drvdata(dev);
+       u8 ald[3], ctl[3];
+       int ret;
+
+       if (!test_bit(HAS_ALARM, &ds1307->flags))
+               return -EINVAL;
+
+       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,
+               t->time.tm_wday, t->time.tm_mday, t->time.tm_mon,
+               t->enabled, t->pending);
+
+       /* Read control registers. */
+       ret = regmap_bulk_read(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3);
+       if (ret < 0)
+               return ret;
+
+       ctl[0] &= ~RX8130_REG_EXTENSION_WADA;
+       ctl[1] |= RX8130_REG_FLAG_AF;
+       ctl[2] &= ~RX8130_REG_CONTROL0_AIE;
+
+       ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3);
+       if (ret < 0)
+               return ret;
+
+       /* Hardware alarm precision is 1 minute! */
+       ald[0] = bin2bcd(t->time.tm_min);
+       ald[1] = bin2bcd(t->time.tm_hour);
+       ald[2] = bin2bcd(t->time.tm_mday);
+
+       ret = regmap_bulk_write(ds1307->regmap, RX8130_REG_ALARM_MIN, ald, 3);
+       if (ret < 0)
+               return ret;
+
+       if (!t->enabled)
+               return 0;
+
+       ctl[2] |= RX8130_REG_CONTROL0_AIE;
+
+       return regmap_bulk_write(ds1307->regmap, RX8130_REG_EXTENSION, ctl, 3);
+}
+
+static int rx8130_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct ds1307 *ds1307 = dev_get_drvdata(dev);
+       int ret, reg;
+
+       if (!test_bit(HAS_ALARM, &ds1307->flags))
+               return -EINVAL;
+
+       ret = regmap_read(ds1307->regmap, RX8130_REG_CONTROL0, &reg);
+       if (ret < 0)
+               return ret;
+
+       if (enabled)
+               reg |= RX8130_REG_CONTROL0_AIE;
+       else
+               reg &= ~RX8130_REG_CONTROL0_AIE;
+
+       return regmap_write(ds1307->regmap, RX8130_REG_CONTROL0, reg);
+}
+
+static const struct rtc_class_ops rx8130_rtc_ops = {
        .read_time      = ds1307_get_time,
        .set_time       = ds1307_set_time,
-       .read_alarm     = ds1337_read_alarm,
-       .set_alarm      = ds1337_set_alarm,
-       .alarm_irq_enable = ds1307_alarm_irq_enable,
+       .read_alarm     = rx8130_read_alarm,
+       .set_alarm      = rx8130_set_alarm,
+       .alarm_irq_enable = rx8130_alarm_irq_enable,
 };
 
 /*----------------------------------------------------------------------*/
@@ -752,31 +759,27 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
 
 static irqreturn_t mcp794xx_irq(int irq, void *dev_id)
 {
-       struct i2c_client       *client = dev_id;
-       struct ds1307           *ds1307 = i2c_get_clientdata(client);
+       struct ds1307           *ds1307 = dev_id;
        struct mutex            *lock = &ds1307->rtc->ops_lock;
        int reg, ret;
 
        mutex_lock(lock);
 
        /* Check and clear alarm 0 interrupt flag. */
-       reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_ALARM0_CTRL);
-       if (reg < 0)
+       ret = regmap_read(ds1307->regmap, MCP794XX_REG_ALARM0_CTRL, &reg);
+       if (ret)
                goto out;
        if (!(reg & MCP794XX_BIT_ALMX_IF))
                goto out;
        reg &= ~MCP794XX_BIT_ALMX_IF;
-       ret = i2c_smbus_write_byte_data(client, MCP794XX_REG_ALARM0_CTRL, reg);
-       if (ret < 0)
+       ret = regmap_write(ds1307->regmap, MCP794XX_REG_ALARM0_CTRL, reg);
+       if (ret)
                goto out;
 
        /* Disable alarm 0. */
-       reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_CONTROL);
-       if (reg < 0)
-               goto out;
-       reg &= ~MCP794XX_BIT_ALM0_EN;
-       ret = i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, reg);
-       if (ret < 0)
+       ret = regmap_update_bits(ds1307->regmap, MCP794XX_REG_CONTROL,
+                                MCP794XX_BIT_ALM0_EN, 0);
+       if (ret)
                goto out;
 
        rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
@@ -789,8 +792,7 @@ out:
 
 static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct ds1307 *ds1307 = i2c_get_clientdata(client);
+       struct ds1307 *ds1307 = dev_get_drvdata(dev);
        u8 *regs = ds1307->regs;
        int ret;
 
@@ -798,8 +800,8 @@ static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t)
                return -EINVAL;
 
        /* Read control and alarm 0 registers. */
-       ret = ds1307->read_block_data(client, MCP794XX_REG_CONTROL, 10, regs);
-       if (ret < 0)
+       ret = regmap_bulk_read(ds1307->regmap, MCP794XX_REG_CONTROL, regs, 10);
+       if (ret)
                return ret;
 
        t->enabled = !!(regs[0] & MCP794XX_BIT_ALM0_EN);
@@ -828,8 +830,7 @@ static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t)
 
 static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct ds1307 *ds1307 = i2c_get_clientdata(client);
+       struct ds1307 *ds1307 = dev_get_drvdata(dev);
        unsigned char *regs = ds1307->regs;
        int ret;
 
@@ -843,8 +844,8 @@ static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t)
                t->enabled, t->pending);
 
        /* Read control and alarm 0 registers. */
-       ret = ds1307->read_block_data(client, MCP794XX_REG_CONTROL, 10, regs);
-       if (ret < 0)
+       ret = regmap_bulk_read(ds1307->regmap, MCP794XX_REG_CONTROL, regs, 10);
+       if (ret)
                return ret;
 
        /* Set alarm 0, using 24-hour and day-of-month modes. */
@@ -862,35 +863,26 @@ static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t)
        /* Disable interrupt. We will not enable until completely programmed */
        regs[0] &= ~MCP794XX_BIT_ALM0_EN;
 
-       ret = ds1307->write_block_data(client, MCP794XX_REG_CONTROL, 10, regs);
-       if (ret < 0)
+       ret = regmap_bulk_write(ds1307->regmap, MCP794XX_REG_CONTROL, regs, 10);
+       if (ret)
                return ret;
 
        if (!t->enabled)
                return 0;
        regs[0] |= MCP794XX_BIT_ALM0_EN;
-       return i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, regs[0]);
+       return regmap_write(ds1307->regmap, MCP794XX_REG_CONTROL, regs[0]);
 }
 
 static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct ds1307 *ds1307 = i2c_get_clientdata(client);
-       int reg;
+       struct ds1307 *ds1307 = dev_get_drvdata(dev);
 
        if (!test_bit(HAS_ALARM, &ds1307->flags))
                return -EINVAL;
 
-       reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_CONTROL);
-       if (reg < 0)
-               return reg;
-
-       if (enabled)
-               reg |= MCP794XX_BIT_ALM0_EN;
-       else
-               reg &= ~MCP794XX_BIT_ALM0_EN;
-
-       return i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, reg);
+       return regmap_update_bits(ds1307->regmap, MCP794XX_REG_CONTROL,
+                                 MCP794XX_BIT_ALM0_EN,
+                                 enabled ? MCP794XX_BIT_ALM0_EN : 0);
 }
 
 static const struct rtc_class_ops mcp794xx_rtc_ops = {
@@ -903,50 +895,27 @@ static const struct rtc_class_ops mcp794xx_rtc_ops = {
 
 /*----------------------------------------------------------------------*/
 
-static ssize_t
-ds1307_nvram_read(struct file *filp, struct kobject *kobj,
-               struct bin_attribute *attr,
-               char *buf, loff_t off, size_t count)
+static int ds1307_nvram_read(void *priv, unsigned int offset, void *val,
+                            size_t bytes)
 {
-       struct i2c_client       *client;
-       struct ds1307           *ds1307;
-       int                     result;
+       struct ds1307 *ds1307 = priv;
 
-       client = kobj_to_i2c_client(kobj);
-       ds1307 = i2c_get_clientdata(client);
-
-       result = ds1307->read_block_data(client, ds1307->nvram_offset + off,
-                                                               count, buf);
-       if (result < 0)
-               dev_err(&client->dev, "%s error %d\n", "nvram read", result);
-       return result;
+       return regmap_bulk_read(ds1307->regmap, ds1307->nvram_offset + offset,
+                               val, bytes);
 }
 
-static ssize_t
-ds1307_nvram_write(struct file *filp, struct kobject *kobj,
-               struct bin_attribute *attr,
-               char *buf, loff_t off, size_t count)
+static int ds1307_nvram_write(void *priv, unsigned int offset, void *val,
+                             size_t bytes)
 {
-       struct i2c_client       *client;
-       struct ds1307           *ds1307;
-       int                     result;
+       struct ds1307 *ds1307 = priv;
 
-       client = kobj_to_i2c_client(kobj);
-       ds1307 = i2c_get_clientdata(client);
-
-       result = ds1307->write_block_data(client, ds1307->nvram_offset + off,
-                                                               count, buf);
-       if (result < 0) {
-               dev_err(&client->dev, "%s error %d\n", "nvram write", result);
-               return result;
-       }
-       return count;
+       return regmap_bulk_write(ds1307->regmap, ds1307->nvram_offset + offset,
+                                val, bytes);
 }
 
-
 /*----------------------------------------------------------------------*/
 
-static u8 do_trickle_setup_ds1339(struct i2c_client *client,
+static u8 do_trickle_setup_ds1339(struct ds1307 *ds1307,
                                  uint32_t ohms, bool diode)
 {
        u8 setup = (diode) ? DS1307_TRICKLE_CHARGER_DIODE :
@@ -963,14 +932,14 @@ static u8 do_trickle_setup_ds1339(struct i2c_client *client,
                setup |= DS1307_TRICKLE_CHARGER_4K_OHM;
                break;
        default:
-               dev_warn(&client->dev,
+               dev_warn(ds1307->dev,
                         "Unsupported ohm value %u in dt\n", ohms);
                return 0;
        }
        return setup;
 }
 
-static void ds1307_trickle_init(struct i2c_client *client,
+static void ds1307_trickle_init(struct ds1307 *ds1307,
                                struct chip_desc *chip)
 {
        uint32_t ohms = 0;
@@ -978,11 +947,12 @@ static void ds1307_trickle_init(struct i2c_client *client,
 
        if (!chip->do_trickle_setup)
                goto out;
-       if (device_property_read_u32(&client->dev, "trickle-resistor-ohms", &ohms))
+       if (device_property_read_u32(ds1307->dev, "trickle-resistor-ohms",
+                                    &ohms))
                goto out;
-       if (device_property_read_bool(&client->dev, "trickle-diode-disable"))
+       if (device_property_read_bool(ds1307->dev, "trickle-diode-disable"))
                diode = false;
-       chip->trickle_charger_setup = chip->do_trickle_setup(client,
+       chip->trickle_charger_setup = chip->do_trickle_setup(ds1307,
                                                             ohms, diode);
 out:
        return;
@@ -1009,13 +979,10 @@ static int ds3231_hwmon_read_temp(struct device *dev, s32 *mC)
        s16 temp;
        int ret;
 
-       ret = ds1307->read_block_data(ds1307->client, DS3231_REG_TEMPERATURE,
-                                       sizeof(temp_buf), temp_buf);
-       if (ret < 0)
+       ret = regmap_bulk_read(ds1307->regmap, DS3231_REG_TEMPERATURE,
+                              temp_buf, sizeof(temp_buf));
+       if (ret)
                return ret;
-       if (ret != sizeof(temp_buf))
-               return -EIO;
-
        /*
         * Temperature is represented as a 10-bit code with a resolution of
         * 0.25 degree celsius and encoded in two's complement format.
@@ -1055,12 +1022,11 @@ static void ds1307_hwmon_register(struct ds1307 *ds1307)
        if (ds1307->type != ds_3231)
                return;
 
-       dev = devm_hwmon_device_register_with_groups(&ds1307->client->dev,
-                                               ds1307->client->name,
+       dev = devm_hwmon_device_register_with_groups(ds1307->dev, ds1307->name,
                                                ds1307, ds3231_hwmon_groups);
        if (IS_ERR(dev)) {
-               dev_warn(&ds1307->client->dev,
-                       "unable to register hwmon device %ld\n", PTR_ERR(dev));
+               dev_warn(ds1307->dev, "unable to register hwmon device %ld\n",
+                        PTR_ERR(dev));
        }
 }
 
@@ -1099,24 +1065,12 @@ static int ds3231_clk_sqw_rates[] = {
 
 static int ds1337_write_control(struct ds1307 *ds1307, u8 mask, u8 value)
 {
-       struct i2c_client *client = ds1307->client;
        struct mutex *lock = &ds1307->rtc->ops_lock;
-       int control;
        int ret;
 
        mutex_lock(lock);
-
-       control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
-       if (control < 0) {
-               ret = control;
-               goto out;
-       }
-
-       control &= ~mask;
-       control |= value;
-
-       ret = i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, control);
-out:
+       ret = regmap_update_bits(ds1307->regmap, DS1337_REG_CONTROL,
+                                mask, value);
        mutex_unlock(lock);
 
        return ret;
@@ -1126,12 +1080,12 @@ static unsigned long ds3231_clk_sqw_recalc_rate(struct clk_hw *hw,
                                                unsigned long parent_rate)
 {
        struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
-       int control;
+       int control, ret;
        int rate_sel = 0;
 
-       control = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_CONTROL);
-       if (control < 0)
-               return control;
+       ret = regmap_read(ds1307->regmap, DS1337_REG_CONTROL, &control);
+       if (ret)
+               return ret;
        if (control & DS1337_BIT_RS1)
                rate_sel += 1;
        if (control & DS1337_BIT_RS2)
@@ -1195,11 +1149,11 @@ static void ds3231_clk_sqw_unprepare(struct clk_hw *hw)
 static int ds3231_clk_sqw_is_prepared(struct clk_hw *hw)
 {
        struct ds1307 *ds1307 = clk_sqw_to_ds1307(hw);
-       int control;
+       int control, ret;
 
-       control = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_CONTROL);
-       if (control < 0)
-               return control;
+       ret = regmap_read(ds1307->regmap, DS1337_REG_CONTROL, &control);
+       if (ret)
+               return ret;
 
        return !(control & DS1337_BIT_INTCN);
 }
@@ -1221,26 +1175,13 @@ static unsigned long ds3231_clk_32khz_recalc_rate(struct clk_hw *hw,
 
 static int ds3231_clk_32khz_control(struct ds1307 *ds1307, bool enable)
 {
-       struct i2c_client *client = ds1307->client;
        struct mutex *lock = &ds1307->rtc->ops_lock;
-       int status;
        int ret;
 
        mutex_lock(lock);
-
-       status = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
-       if (status < 0) {
-               ret = status;
-               goto out;
-       }
-
-       if (enable)
-               status |= DS3231_BIT_EN32KHZ;
-       else
-               status &= ~DS3231_BIT_EN32KHZ;
-
-       ret = i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, status);
-out:
+       ret = regmap_update_bits(ds1307->regmap, DS1337_REG_STATUS,
+                                DS3231_BIT_EN32KHZ,
+                                enable ? DS3231_BIT_EN32KHZ : 0);
        mutex_unlock(lock);
 
        return ret;
@@ -1263,11 +1204,11 @@ static void ds3231_clk_32khz_unprepare(struct clk_hw *hw)
 static int ds3231_clk_32khz_is_prepared(struct clk_hw *hw)
 {
        struct ds1307 *ds1307 = clk_32khz_to_ds1307(hw);
-       int status;
+       int status, ret;
 
-       status = i2c_smbus_read_byte_data(ds1307->client, DS1337_REG_STATUS);
-       if (status < 0)
-               return status;
+       ret = regmap_read(ds1307->regmap, DS1337_REG_STATUS, &status);
+       if (ret)
+               return ret;
 
        return !!(status & DS3231_BIT_EN32KHZ);
 }
@@ -1292,18 +1233,17 @@ static struct clk_init_data ds3231_clks_init[] = {
 
 static int ds3231_clks_register(struct ds1307 *ds1307)
 {
-       struct i2c_client *client = ds1307->client;
-       struct device_node *node = client->dev.of_node;
+       struct device_node *node = ds1307->dev->of_node;
        struct clk_onecell_data *onecell;
        int i;
 
-       onecell = devm_kzalloc(&client->dev, sizeof(*onecell), GFP_KERNEL);
+       onecell = devm_kzalloc(ds1307->dev, sizeof(*onecell), GFP_KERNEL);
        if (!onecell)
                return -ENOMEM;
 
        onecell->clk_num = ARRAY_SIZE(ds3231_clks_init);
-       onecell->clks = devm_kcalloc(&client->dev, onecell->clk_num,
-                                       sizeof(onecell->clks[0]), GFP_KERNEL);
+       onecell->clks = devm_kcalloc(ds1307->dev, onecell->clk_num,
+                                    sizeof(onecell->clks[0]), GFP_KERNEL);
        if (!onecell->clks)
                return -ENOMEM;
 
@@ -1322,8 +1262,8 @@ static int ds3231_clks_register(struct ds1307 *ds1307)
                                                &init.name);
                ds1307->clks[i].init = &init;
 
-               onecell->clks[i] = devm_clk_register(&client->dev,
-                                                       &ds1307->clks[i]);
+               onecell->clks[i] = devm_clk_register(ds1307->dev,
+                                                    &ds1307->clks[i]);
                if (IS_ERR(onecell->clks[i]))
                        return PTR_ERR(onecell->clks[i]);
        }
@@ -1345,8 +1285,8 @@ static void ds1307_clks_register(struct ds1307 *ds1307)
 
        ret = ds3231_clks_register(ds1307);
        if (ret) {
-               dev_warn(&ds1307->client->dev,
-                       "unable to register clock device %d\n", ret);
+               dev_warn(ds1307->dev, "unable to register clock device %d\n",
+                        ret);
        }
 }
 
@@ -1358,6 +1298,12 @@ static void ds1307_clks_register(struct ds1307 *ds1307)
 
 #endif /* CONFIG_COMMON_CLK */
 
+static const struct regmap_config regmap_config = {
+       .reg_bits = 8,
+       .val_bits = 8,
+       .max_register = 0x12,
+};
+
 static int ds1307_probe(struct i2c_client *client,
                        const struct i2c_device_id *id)
 {
@@ -1365,7 +1311,6 @@ static int ds1307_probe(struct i2c_client *client,
        int                     err = -ENODEV;
        int                     tmp, wday;
        struct chip_desc        *chip;
-       struct i2c_adapter      *adapter = to_i2c_adapter(client->dev.parent);
        bool                    want_irq = false;
        bool                    ds1307_can_wakeup_device = false;
        unsigned char           *buf;
@@ -1382,17 +1327,22 @@ static int ds1307_probe(struct i2c_client *client,
        };
        const struct rtc_class_ops *rtc_ops = &ds13xx_rtc_ops;
 
-       if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)
-           && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
-               return -EIO;
-
        ds1307 = devm_kzalloc(&client->dev, sizeof(struct ds1307), GFP_KERNEL);
        if (!ds1307)
                return -ENOMEM;
 
-       i2c_set_clientdata(client, ds1307);
+       dev_set_drvdata(&client->dev, ds1307);
+       ds1307->dev = &client->dev;
+       ds1307->name = client->name;
+       ds1307->irq = client->irq;
 
-       ds1307->client  = client;
+       ds1307->regmap = devm_regmap_init_i2c(client, &regmap_config);
+       if (IS_ERR(ds1307->regmap)) {
+               dev_err(ds1307->dev, "regmap allocation failed\n");
+               return PTR_ERR(ds1307->regmap);
+       }
+
+       i2c_set_clientdata(client, ds1307);
 
        if (client->dev.of_node) {
                ds1307->type = (enum ds_type)
@@ -1405,7 +1355,7 @@ static int ds1307_probe(struct i2c_client *client,
                const struct acpi_device_id *acpi_id;
 
                acpi_id = acpi_match_device(ACPI_PTR(ds1307_acpi_ids),
-                                           &client->dev);
+                                           ds1307->dev);
                if (!acpi_id)
                        return -ENODEV;
                chip = &chips[acpi_id->driver_data];
@@ -1413,27 +1363,21 @@ static int ds1307_probe(struct i2c_client *client,
        }
 
        if (!pdata)
-               ds1307_trickle_init(client, chip);
+               ds1307_trickle_init(ds1307, chip);
        else if (pdata->trickle_charger_setup)
                chip->trickle_charger_setup = pdata->trickle_charger_setup;
 
        if (chip->trickle_charger_setup && chip->trickle_charger_reg) {
-               dev_dbg(&client->dev, "writing trickle charger info 0x%x to 0x%x\n",
+               dev_dbg(ds1307->dev,
+                       "writing trickle charger info 0x%x to 0x%x\n",
                    DS13XX_TRICKLE_CHARGER_MAGIC | chip->trickle_charger_setup,
                    chip->trickle_charger_reg);
-               i2c_smbus_write_byte_data(client, chip->trickle_charger_reg,
+               regmap_write(ds1307->regmap, chip->trickle_charger_reg,
                    DS13XX_TRICKLE_CHARGER_MAGIC |
                    chip->trickle_charger_setup);
        }
 
        buf = ds1307->regs;
-       if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
-               ds1307->read_block_data = ds1307_native_smbus_read_block_data;
-               ds1307->write_block_data = ds1307_native_smbus_write_block_data;
-       } else {
-               ds1307->read_block_data = ds1307_read_block_data;
-               ds1307->write_block_data = ds1307_write_block_data;
-       }
 
 #ifdef CONFIG_OF
 /*
@@ -1459,11 +1403,10 @@ static int ds1307_probe(struct i2c_client *client,
        case ds_1339:
        case ds_3231:
                /* get registers that the "rtc" read below won't read... */
-               tmp = ds1307->read_block_data(ds1307->client,
-                               DS1337_REG_CONTROL, 2, buf);
-               if (tmp != 2) {
-                       dev_dbg(&client->dev, "read error %d\n", tmp);
-                       err = -EIO;
+               err = regmap_bulk_read(ds1307->regmap, DS1337_REG_CONTROL,
+                                      buf, 2);
+               if (err) {
+                       dev_dbg(ds1307->dev, "read error %d\n", err);
                        goto exit;
                }
 
@@ -1477,8 +1420,8 @@ static int ds1307_probe(struct i2c_client *client,
                 * For some variants, be sure alarms can trigger when we're
                 * running on Vbackup (BBSQI/BBSQW)
                 */
-               if (chip->alarm && (ds1307->client->irq > 0 ||
-                                               ds1307_can_wakeup_device)) {
+               if (chip->alarm && (ds1307->irq > 0 ||
+                                   ds1307_can_wakeup_device)) {
                        ds1307->regs[0] |= DS1337_BIT_INTCN
                                        | bbsqi_bitpos[ds1307->type];
                        ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
@@ -1486,50 +1429,49 @@ static int ds1307_probe(struct i2c_client *client,
                        want_irq = true;
                }
 
-               i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL,
-                                                       ds1307->regs[0]);
+               regmap_write(ds1307->regmap, DS1337_REG_CONTROL,
+                            ds1307->regs[0]);
 
                /* oscillator fault?  clear flag, and warn */
                if (ds1307->regs[1] & DS1337_BIT_OSF) {
-                       i2c_smbus_write_byte_data(client, DS1337_REG_STATUS,
-                               ds1307->regs[1] & ~DS1337_BIT_OSF);
-                       dev_warn(&client->dev, "SET TIME!\n");
+                       regmap_write(ds1307->regmap, DS1337_REG_STATUS,
+                                    ds1307->regs[1] & ~DS1337_BIT_OSF);
+                       dev_warn(ds1307->dev, "SET TIME!\n");
                }
                break;
 
        case rx_8025:
-               tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
-                               RX8025_REG_CTRL1 << 4 | 0x08, 2, buf);
-               if (tmp != 2) {
-                       dev_dbg(&client->dev, "read error %d\n", tmp);
-                       err = -EIO;
+               err = regmap_bulk_read(ds1307->regmap,
+                                      RX8025_REG_CTRL1 << 4 | 0x08, buf, 2);
+               if (err) {
+                       dev_dbg(ds1307->dev, "read error %d\n", err);
                        goto exit;
                }
 
                /* oscillator off?  turn it on, so clock can tick. */
                if (!(ds1307->regs[1] & RX8025_BIT_XST)) {
                        ds1307->regs[1] |= RX8025_BIT_XST;
-                       i2c_smbus_write_byte_data(client,
-                                                 RX8025_REG_CTRL2 << 4 | 0x08,
-                                                 ds1307->regs[1]);
-                       dev_warn(&client->dev,
+                       regmap_write(ds1307->regmap,
+                                    RX8025_REG_CTRL2 << 4 | 0x08,
+                                    ds1307->regs[1]);
+                       dev_warn(ds1307->dev,
                                 "oscillator stop detected - SET TIME!\n");
                }
 
                if (ds1307->regs[1] & RX8025_BIT_PON) {
                        ds1307->regs[1] &= ~RX8025_BIT_PON;
-                       i2c_smbus_write_byte_data(client,
-                                                 RX8025_REG_CTRL2 << 4 | 0x08,
-                                                 ds1307->regs[1]);
-                       dev_warn(&client->dev, "power-on detected\n");
+                       regmap_write(ds1307->regmap,
+                                    RX8025_REG_CTRL2 << 4 | 0x08,
+                                    ds1307->regs[1]);
+                       dev_warn(ds1307->dev, "power-on detected\n");
                }
 
                if (ds1307->regs[1] & RX8025_BIT_VDET) {
                        ds1307->regs[1] &= ~RX8025_BIT_VDET;
-                       i2c_smbus_write_byte_data(client,
-                                                 RX8025_REG_CTRL2 << 4 | 0x08,
-                                                 ds1307->regs[1]);
-                       dev_warn(&client->dev, "voltage drop detected\n");
+                       regmap_write(ds1307->regmap,
+                                    RX8025_REG_CTRL2 << 4 | 0x08,
+                                    ds1307->regs[1]);
+                       dev_warn(ds1307->dev, "voltage drop detected\n");
                }
 
                /* make sure we are running in 24hour mode */
@@ -1537,16 +1479,15 @@ static int ds1307_probe(struct i2c_client *client,
                        u8 hour;
 
                        /* switch to 24 hour mode */
-                       i2c_smbus_write_byte_data(client,
-                                                 RX8025_REG_CTRL1 << 4 | 0x08,
-                                                 ds1307->regs[0] |
-                                                 RX8025_BIT_2412);
-
-                       tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
-                                       RX8025_REG_CTRL1 << 4 | 0x08, 2, buf);
-                       if (tmp != 2) {
-                               dev_dbg(&client->dev, "read error %d\n", tmp);
-                               err = -EIO;
+                       regmap_write(ds1307->regmap,
+                                    RX8025_REG_CTRL1 << 4 | 0x08,
+                                    ds1307->regs[0] | RX8025_BIT_2412);
+
+                       err = regmap_bulk_read(ds1307->regmap,
+                                              RX8025_REG_CTRL1 << 4 | 0x08,
+                                              buf, 2);
+                       if (err) {
+                               dev_dbg(ds1307->dev, "read error %d\n", err);
                                goto exit;
                        }
 
@@ -1557,9 +1498,16 @@ static int ds1307_probe(struct i2c_client *client,
                        if (ds1307->regs[DS1307_REG_HOUR] & DS1307_BIT_PM)
                                hour += 12;
 
-                       i2c_smbus_write_byte_data(client,
-                                                 DS1307_REG_HOUR << 4 | 0x08,
-                                                 hour);
+                       regmap_write(ds1307->regmap,
+                                    DS1307_REG_HOUR << 4 | 0x08, hour);
+               }
+               break;
+       case rx_8130:
+               ds1307->offset = 0x10; /* Seconds starts at 0x10 */
+               rtc_ops = &rx8130_rtc_ops;
+               if (chip->alarm && ds1307->irq > 0) {
+                       irq_handler = rx8130_irq;
+                       want_irq = true;
                }
                break;
        case ds_1388:
@@ -1567,7 +1515,8 @@ static int ds1307_probe(struct i2c_client *client,
                break;
        case mcp794xx:
                rtc_ops = &mcp794xx_rtc_ops;
-               if (ds1307->client->irq > 0 && chip->alarm) {
+               if (chip->alarm && (ds1307->irq > 0 ||
+                                   ds1307_can_wakeup_device)) {
                        irq_handler = mcp794xx_irq;
                        want_irq = true;
                }
@@ -1578,10 +1527,9 @@ static int ds1307_probe(struct i2c_client *client,
 
 read_rtc:
        /* read RTC registers */
-       tmp = ds1307->read_block_data(ds1307->client, ds1307->offset, 8, buf);
-       if (tmp != 8) {
-               dev_dbg(&client->dev, "read error %d\n", tmp);
-               err = -EIO;
+       err = regmap_bulk_read(ds1307->regmap, ds1307->offset, buf, 8);
+       if (err) {
+               dev_dbg(ds1307->dev, "read error %d\n", err);
                goto exit;
        }
 
@@ -1597,56 +1545,56 @@ read_rtc:
        case m41t00:
                /* clock halted?  turn it on, so clock can tick. */
                if (tmp & DS1307_BIT_CH) {
-                       i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0);
-                       dev_warn(&client->dev, "SET TIME!\n");
+                       regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
+                       dev_warn(ds1307->dev, "SET TIME!\n");
                        goto read_rtc;
                }
                break;
+       case ds_1308:
        case ds_1338:
                /* clock halted?  turn it on, so clock can tick. */
                if (tmp & DS1307_BIT_CH)
-                       i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0);
+                       regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
 
                /* oscillator fault?  clear flag, and warn */
                if (ds1307->regs[DS1307_REG_CONTROL] & DS1338_BIT_OSF) {
-                       i2c_smbus_write_byte_data(client, DS1307_REG_CONTROL,
-                                       ds1307->regs[DS1307_REG_CONTROL]
-                                       ~DS1338_BIT_OSF);
-                       dev_warn(&client->dev, "SET TIME!\n");
+                       regmap_write(ds1307->regmap, DS1307_REG_CONTROL,
+                                       ds1307->regs[DS1307_REG_CONTROL] &
+                                       ~DS1338_BIT_OSF);
+                       dev_warn(ds1307->dev, "SET TIME!\n");
                        goto read_rtc;
                }
                break;
        case ds_1340:
                /* clock halted?  turn it on, so clock can tick. */
                if (tmp & DS1340_BIT_nEOSC)
-                       i2c_smbus_write_byte_data(client, DS1307_REG_SECS, 0);
+                       regmap_write(ds1307->regmap, DS1307_REG_SECS, 0);
 
-               tmp = i2c_smbus_read_byte_data(client, DS1340_REG_FLAG);
-               if (tmp < 0) {
-                       dev_dbg(&client->dev, "read error %d\n", tmp);
-                       err = -EIO;
+               err = regmap_read(ds1307->regmap, DS1340_REG_FLAG, &tmp);
+               if (err) {
+                       dev_dbg(ds1307->dev, "read error %d\n", err);
                        goto exit;
                }
 
                /* oscillator fault?  clear flag, and warn */
                if (tmp & DS1340_BIT_OSF) {
-                       i2c_smbus_write_byte_data(client, DS1340_REG_FLAG, 0);
-                       dev_warn(&client->dev, "SET TIME!\n");
+                       regmap_write(ds1307->regmap, DS1340_REG_FLAG, 0);
+                       dev_warn(ds1307->dev, "SET TIME!\n");
                }
                break;
        case mcp794xx:
                /* make sure that the backup battery is enabled */
                if (!(ds1307->regs[DS1307_REG_WDAY] & MCP794XX_BIT_VBATEN)) {
-                       i2c_smbus_write_byte_data(client, DS1307_REG_WDAY,
-                                       ds1307->regs[DS1307_REG_WDAY]
-                                       | MCP794XX_BIT_VBATEN);
+                       regmap_write(ds1307->regmap, DS1307_REG_WDAY,
+                                    ds1307->regs[DS1307_REG_WDAY] |
+                                    MCP794XX_BIT_VBATEN);
                }
 
                /* clock halted?  turn it on, so clock can tick. */
                if (!(tmp & MCP794XX_BIT_ST)) {
-                       i2c_smbus_write_byte_data(client, DS1307_REG_SECS,
-                                       MCP794XX_BIT_ST);
-                       dev_warn(&client->dev, "SET TIME!\n");
+                       regmap_write(ds1307->regmap, DS1307_REG_SECS,
+                                    MCP794XX_BIT_ST);
+                       dev_warn(ds1307->dev, "SET TIME!\n");
                        goto read_rtc;
                }
 
@@ -1680,16 +1628,15 @@ read_rtc:
                        tmp = 0;
                if (ds1307->regs[DS1307_REG_HOUR] & DS1307_BIT_PM)
                        tmp += 12;
-               i2c_smbus_write_byte_data(client,
-                               ds1307->offset + DS1307_REG_HOUR,
-                               bin2bcd(tmp));
+               regmap_write(ds1307->regmap, ds1307->offset + DS1307_REG_HOUR,
+                            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(&client->dev, &tm);
+       ds1307_get_time(ds1307->dev, &tm);
        wday = tm.tm_wday;
        timestamp = rtc_tm_to_time64(&tm);
        rtc_time64_to_tm(timestamp, &tm);
@@ -1699,78 +1646,63 @@ read_rtc:
         * If different then set the wday which we computed using
         * timestamp
         */
-       if (wday != tm.tm_wday) {
-               wday = i2c_smbus_read_byte_data(client, MCP794XX_REG_WEEKDAY);
-               wday = wday & ~MCP794XX_REG_WEEKDAY_WDAY_MASK;
-               wday = wday | (tm.tm_wday + 1);
-               i2c_smbus_write_byte_data(client, MCP794XX_REG_WEEKDAY, wday);
-       }
+       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) {
-               device_set_wakeup_capable(&client->dev, true);
+               device_set_wakeup_capable(ds1307->dev, true);
                set_bit(HAS_ALARM, &ds1307->flags);
        }
-       ds1307->rtc = devm_rtc_device_register(&client->dev, client->name,
-                               rtc_ops, THIS_MODULE);
+
+       ds1307->rtc = devm_rtc_allocate_device(ds1307->dev);
        if (IS_ERR(ds1307->rtc)) {
                return PTR_ERR(ds1307->rtc);
        }
 
-       if (ds1307_can_wakeup_device && ds1307->client->irq <= 0) {
+       if (ds1307_can_wakeup_device && ds1307->irq <= 0) {
                /* Disable request for an IRQ */
                want_irq = false;
-               dev_info(&client->dev, "'wakeup-source' is set, request for an IRQ is disabled!\n");
+               dev_info(ds1307->dev,
+                        "'wakeup-source' is set, request for an IRQ is disabled!\n");
                /* We cannot support UIE mode if we do not have an IRQ line */
                ds1307->rtc->uie_unsupported = 1;
        }
 
        if (want_irq) {
-               err = devm_request_threaded_irq(&client->dev,
-                                               client->irq, NULL, irq_handler,
+               err = devm_request_threaded_irq(ds1307->dev,
+                                               ds1307->irq, NULL, irq_handler,
                                                IRQF_SHARED | IRQF_ONESHOT,
-                                               ds1307->rtc->name, client);
+                                               ds1307->name, ds1307);
                if (err) {
                        client->irq = 0;
-                       device_set_wakeup_capable(&client->dev, false);
+                       device_set_wakeup_capable(ds1307->dev, false);
                        clear_bit(HAS_ALARM, &ds1307->flags);
-                       dev_err(&client->dev, "unable to request IRQ!\n");
+                       dev_err(ds1307->dev, "unable to request IRQ!\n");
                } else
-                       dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
+                       dev_dbg(ds1307->dev, "got IRQ %d\n", client->irq);
        }
 
        if (chip->nvram_size) {
-
-               ds1307->nvram = devm_kzalloc(&client->dev,
-                                       sizeof(struct bin_attribute),
-                                       GFP_KERNEL);
-               if (!ds1307->nvram) {
-                       dev_err(&client->dev, "cannot allocate memory for nvram sysfs\n");
-               } else {
-
-                       ds1307->nvram->attr.name = "nvram";
-                       ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR;
-
-                       sysfs_bin_attr_init(ds1307->nvram);
-
-                       ds1307->nvram->read = ds1307_nvram_read;
-                       ds1307->nvram->write = ds1307_nvram_write;
-                       ds1307->nvram->size = chip->nvram_size;
-                       ds1307->nvram_offset = chip->nvram_offset;
-
-                       err = sysfs_create_bin_file(&client->dev.kobj,
-                                                   ds1307->nvram);
-                       if (err) {
-                               dev_err(&client->dev,
-                                       "unable to create sysfs file: %s\n",
-                                       ds1307->nvram->attr.name);
-                       } else {
-                               set_bit(HAS_NVRAM, &ds1307->flags);
-                               dev_info(&client->dev, "%zu bytes nvram\n",
-                                        ds1307->nvram->size);
-                       }
-               }
+               ds1307->nvmem_cfg.name = "ds1307_nvram";
+               ds1307->nvmem_cfg.word_size = 1;
+               ds1307->nvmem_cfg.stride = 1;
+               ds1307->nvmem_cfg.size = chip->nvram_size;
+               ds1307->nvmem_cfg.reg_read = ds1307_nvram_read;
+               ds1307->nvmem_cfg.reg_write = ds1307_nvram_write;
+               ds1307->nvmem_cfg.priv = ds1307;
+               ds1307->nvram_offset = chip->nvram_offset;
+
+               ds1307->rtc->nvmem_config = &ds1307->nvmem_cfg;
+               ds1307->rtc->nvram_old_abi = true;
        }
 
+       ds1307->rtc->ops = rtc_ops;
+       err = rtc_register_device(ds1307->rtc);
+       if (err)
+               return err;
+
        ds1307_hwmon_register(ds1307);
        ds1307_clks_register(ds1307);
 
@@ -1780,16 +1712,6 @@ exit:
        return err;
 }
 
-static int ds1307_remove(struct i2c_client *client)
-{
-       struct ds1307 *ds1307 = i2c_get_clientdata(client);
-
-       if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags))
-               sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram);
-
-       return 0;
-}
-
 static struct i2c_driver ds1307_driver = {
        .driver = {
                .name   = "rtc-ds1307",
@@ -1797,7 +1719,6 @@ static struct i2c_driver ds1307_driver = {
                .acpi_match_table = ACPI_PTR(ds1307_acpi_ids),
        },
        .probe          = ds1307_probe,
-       .remove         = ds1307_remove,
        .id_table       = ds1307_id,
 };
 
index deff431a37c446359fb925605494b7e19c717911..0550f7ba464f414d068985d1c58b2d0029754d26 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/bcd.h>
 #include <linux/slab.h>
 #include <linux/regmap.h>
+#include <linux/hwmon.h>
 
 #define DS3232_REG_SECONDS      0x00
 #define DS3232_REG_MINUTES      0x01
@@ -46,6 +47,8 @@
 #       define DS3232_REG_SR_A2F     0x02
 #       define DS3232_REG_SR_A1F     0x01
 
+#define DS3232_REG_TEMPERATURE 0x11
+
 struct ds3232 {
        struct device *dev;
        struct regmap *regmap;
@@ -275,6 +278,120 @@ static int ds3232_update_alarm(struct device *dev, unsigned int enabled)
        return ret;
 }
 
+/*
+ * Temperature sensor support for ds3232/ds3234 devices.
+ * A user-initiated temperature conversion is not started by this function,
+ * so the temperature is updated once every 64 seconds.
+ */
+static int ds3232_hwmon_read_temp(struct device *dev, long int *mC)
+{
+       struct ds3232 *ds3232 = dev_get_drvdata(dev);
+       u8 temp_buf[2];
+       s16 temp;
+       int ret;
+
+       ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_TEMPERATURE, temp_buf,
+                              sizeof(temp_buf));
+       if (ret < 0)
+               return ret;
+
+       /*
+        * Temperature is represented as a 10-bit code with a resolution of
+        * 0.25 degree celsius and encoded in two's complement format.
+        */
+       temp = (temp_buf[0] << 8) | temp_buf[1];
+       temp >>= 6;
+       *mC = temp * 250;
+
+       return 0;
+}
+
+static umode_t ds3232_hwmon_is_visible(const void *data,
+                                      enum hwmon_sensor_types type,
+                                      u32 attr, int channel)
+{
+       if (type != hwmon_temp)
+               return 0;
+
+       switch (attr) {
+       case hwmon_temp_input:
+               return 0444;
+       default:
+               return 0;
+       }
+}
+
+static int ds3232_hwmon_read(struct device *dev,
+                            enum hwmon_sensor_types type,
+                            u32 attr, int channel, long *temp)
+{
+       int err;
+
+       switch (attr) {
+       case hwmon_temp_input:
+               err = ds3232_hwmon_read_temp(dev, temp);
+               break;
+       default:
+               err = -EOPNOTSUPP;
+               break;
+       }
+
+       return err;
+}
+
+static u32 ds3232_hwmon_chip_config[] = {
+       HWMON_C_REGISTER_TZ,
+       0
+};
+
+static const struct hwmon_channel_info ds3232_hwmon_chip = {
+       .type = hwmon_chip,
+       .config = ds3232_hwmon_chip_config,
+};
+
+static u32 ds3232_hwmon_temp_config[] = {
+       HWMON_T_INPUT,
+       0
+};
+
+static const struct hwmon_channel_info ds3232_hwmon_temp = {
+       .type = hwmon_temp,
+       .config = ds3232_hwmon_temp_config,
+};
+
+static const struct hwmon_channel_info *ds3232_hwmon_info[] = {
+       &ds3232_hwmon_chip,
+       &ds3232_hwmon_temp,
+       NULL
+};
+
+static const struct hwmon_ops ds3232_hwmon_hwmon_ops = {
+       .is_visible = ds3232_hwmon_is_visible,
+       .read = ds3232_hwmon_read,
+};
+
+static const struct hwmon_chip_info ds3232_hwmon_chip_info = {
+       .ops = &ds3232_hwmon_hwmon_ops,
+       .info = ds3232_hwmon_info,
+};
+
+static void ds3232_hwmon_register(struct device *dev, const char *name)
+{
+       struct ds3232 *ds3232 = dev_get_drvdata(dev);
+       struct device *hwmon_dev;
+
+       if (!IS_ENABLED(CONFIG_RTC_DRV_DS3232_HWMON))
+               return;
+
+       hwmon_dev = devm_hwmon_device_register_with_info(dev, name, ds3232,
+                                                       &ds3232_hwmon_chip_info,
+                                                       NULL);
+       if (IS_ERR(hwmon_dev)) {
+               dev_err(dev, "unable to register hwmon device %ld\n",
+                       PTR_ERR(hwmon_dev));
+       }
+}
+
 static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled)
 {
        struct ds3232 *ds3232 = dev_get_drvdata(dev);
@@ -366,6 +483,8 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
        if (ds3232->irq > 0)
                device_init_wakeup(dev, 1);
 
+       ds3232_hwmon_register(dev, name);
+
        ds3232->rtc = devm_rtc_device_register(dev, name, &ds3232_rtc_ops,
                                                THIS_MODULE);
        if (IS_ERR(ds3232->rtc))
diff --git a/drivers/rtc/rtc-ftrtc010.c b/drivers/rtc/rtc-ftrtc010.c
new file mode 100644 (file)
index 0000000..af8d6be
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ *  Faraday Technology FTRTC010 driver
+ *
+ *  Copyright (C) 2009 Janos Laube <janos.dev@gmail.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.
+ *
+ * Original code for older kernel 2.6.15 are from Stormlinksemi
+ * first update from Janos Laube for > 2.6.29 kernels
+ *
+ * checkpatch fixes and usage of rtc-lib code
+ * Hans Ulli Kroll <ulli.kroll@googlemail.com>
+ */
+
+#include <linux/rtc.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+
+#define DRV_NAME        "rtc-ftrtc010"
+
+MODULE_AUTHOR("Hans Ulli Kroll <ulli.kroll@googlemail.com>");
+MODULE_DESCRIPTION("RTC driver for Gemini SoC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+
+struct ftrtc010_rtc {
+       struct rtc_device       *rtc_dev;
+       void __iomem            *rtc_base;
+       int                     rtc_irq;
+       struct clk              *pclk;
+       struct clk              *extclk;
+};
+
+enum ftrtc010_rtc_offsets {
+       FTRTC010_RTC_SECOND             = 0x00,
+       FTRTC010_RTC_MINUTE             = 0x04,
+       FTRTC010_RTC_HOUR               = 0x08,
+       FTRTC010_RTC_DAYS               = 0x0C,
+       FTRTC010_RTC_ALARM_SECOND       = 0x10,
+       FTRTC010_RTC_ALARM_MINUTE       = 0x14,
+       FTRTC010_RTC_ALARM_HOUR         = 0x18,
+       FTRTC010_RTC_RECORD             = 0x1C,
+       FTRTC010_RTC_CR                 = 0x20,
+};
+
+static irqreturn_t ftrtc010_rtc_interrupt(int irq, void *dev)
+{
+       return IRQ_HANDLED;
+}
+
+/*
+ * Looks like the RTC in the Gemini SoC is (totaly) broken
+ * We can't read/write directly the time from RTC registers.
+ * We must do some "offset" calculation to get the real time
+ *
+ * This FIX works pretty fine and Stormlinksemi aka Cortina-Networks does
+ * the same thing, without the rtc-lib.c calls.
+ */
+
+static int ftrtc010_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+       struct ftrtc010_rtc *rtc = dev_get_drvdata(dev);
+
+       unsigned int  days, hour, min, sec;
+       unsigned long offset, time;
+
+       sec  = readl(rtc->rtc_base + FTRTC010_RTC_SECOND);
+       min  = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE);
+       hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR);
+       days = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);
+       offset = readl(rtc->rtc_base + FTRTC010_RTC_RECORD);
+
+       time = offset + days * 86400 + hour * 3600 + min * 60 + sec;
+
+       rtc_time_to_tm(time, tm);
+
+       return 0;
+}
+
+static int ftrtc010_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+       struct ftrtc010_rtc *rtc = dev_get_drvdata(dev);
+       unsigned int sec, min, hour, day;
+       unsigned long offset, time;
+
+       if (tm->tm_year >= 2148)        /* EPOCH Year + 179 */
+               return -EINVAL;
+
+       rtc_tm_to_time(tm, &time);
+
+       sec = readl(rtc->rtc_base + FTRTC010_RTC_SECOND);
+       min = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE);
+       hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR);
+       day = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);
+
+       offset = time - (day * 86400 + hour * 3600 + min * 60 + sec);
+
+       writel(offset, rtc->rtc_base + FTRTC010_RTC_RECORD);
+       writel(0x01, rtc->rtc_base + FTRTC010_RTC_CR);
+
+       return 0;
+}
+
+static const struct rtc_class_ops ftrtc010_rtc_ops = {
+       .read_time     = ftrtc010_rtc_read_time,
+       .set_time      = ftrtc010_rtc_set_time,
+};
+
+static int ftrtc010_rtc_probe(struct platform_device *pdev)
+{
+       struct ftrtc010_rtc *rtc;
+       struct device *dev = &pdev->dev;
+       struct resource *res;
+       int ret;
+
+       rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+       if (unlikely(!rtc))
+               return -ENOMEM;
+       platform_set_drvdata(pdev, rtc);
+
+       rtc->pclk = devm_clk_get(dev, "PCLK");
+       if (IS_ERR(rtc->pclk)) {
+               dev_err(dev, "could not get PCLK\n");
+       } else {
+               ret = clk_prepare_enable(rtc->pclk);
+               if (ret) {
+                       dev_err(dev, "failed to enable PCLK\n");
+                       return ret;
+               }
+       }
+       rtc->extclk = devm_clk_get(dev, "EXTCLK");
+       if (IS_ERR(rtc->extclk)) {
+               dev_err(dev, "could not get EXTCLK\n");
+       } else {
+               ret = clk_prepare_enable(rtc->extclk);
+               if (ret) {
+                       dev_err(dev, "failed to enable EXTCLK\n");
+                       return ret;
+               }
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (!res)
+               return -ENODEV;
+
+       rtc->rtc_irq = res->start;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res)
+               return -ENODEV;
+
+       rtc->rtc_base = devm_ioremap(dev, res->start,
+                                    resource_size(res));
+       if (!rtc->rtc_base)
+               return -ENOMEM;
+
+       ret = devm_request_irq(dev, rtc->rtc_irq, ftrtc010_rtc_interrupt,
+                              IRQF_SHARED, pdev->name, dev);
+       if (unlikely(ret))
+               return ret;
+
+       rtc->rtc_dev = rtc_device_register(pdev->name, dev,
+                                          &ftrtc010_rtc_ops, THIS_MODULE);
+       return PTR_ERR_OR_ZERO(rtc->rtc_dev);
+}
+
+static int ftrtc010_rtc_remove(struct platform_device *pdev)
+{
+       struct ftrtc010_rtc *rtc = platform_get_drvdata(pdev);
+
+       if (!IS_ERR(rtc->extclk))
+               clk_disable_unprepare(rtc->extclk);
+       if (!IS_ERR(rtc->pclk))
+               clk_disable_unprepare(rtc->pclk);
+       rtc_device_unregister(rtc->rtc_dev);
+
+       return 0;
+}
+
+static const struct of_device_id ftrtc010_rtc_dt_match[] = {
+       { .compatible = "cortina,gemini-rtc" },
+       { .compatible = "faraday,ftrtc010" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, ftrtc010_rtc_dt_match);
+
+static struct platform_driver ftrtc010_rtc_driver = {
+       .driver         = {
+               .name   = DRV_NAME,
+               .of_match_table = ftrtc010_rtc_dt_match,
+       },
+       .probe          = ftrtc010_rtc_probe,
+       .remove         = ftrtc010_rtc_remove,
+};
+
+module_platform_driver_probe(ftrtc010_rtc_driver, ftrtc010_rtc_probe);
diff --git a/drivers/rtc/rtc-gemini.c b/drivers/rtc/rtc-gemini.c
deleted file mode 100644 (file)
index 5279390..0000000
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- *  Gemini OnChip RTC
- *
- *  Copyright (C) 2009 Janos Laube <janos.dev@gmail.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.
- *
- * Original code for older kernel 2.6.15 are from Stormlinksemi
- * first update from Janos Laube for > 2.6.29 kernels
- *
- * checkpatch fixes and usage of rtc-lib code
- * Hans Ulli Kroll <ulli.kroll@googlemail.com>
- */
-
-#include <linux/rtc.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-
-#define DRV_NAME        "rtc-gemini"
-
-MODULE_AUTHOR("Hans Ulli Kroll <ulli.kroll@googlemail.com>");
-MODULE_DESCRIPTION("RTC driver for Gemini SoC");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
-
-struct gemini_rtc {
-       struct rtc_device       *rtc_dev;
-       void __iomem            *rtc_base;
-       int                     rtc_irq;
-};
-
-enum gemini_rtc_offsets {
-       GEMINI_RTC_SECOND       = 0x00,
-       GEMINI_RTC_MINUTE       = 0x04,
-       GEMINI_RTC_HOUR         = 0x08,
-       GEMINI_RTC_DAYS         = 0x0C,
-       GEMINI_RTC_ALARM_SECOND = 0x10,
-       GEMINI_RTC_ALARM_MINUTE = 0x14,
-       GEMINI_RTC_ALARM_HOUR   = 0x18,
-       GEMINI_RTC_RECORD       = 0x1C,
-       GEMINI_RTC_CR           = 0x20
-};
-
-static irqreturn_t gemini_rtc_interrupt(int irq, void *dev)
-{
-       return IRQ_HANDLED;
-}
-
-/*
- * Looks like the RTC in the Gemini SoC is (totaly) broken
- * We can't read/write directly the time from RTC registers.
- * We must do some "offset" calculation to get the real time
- *
- * This FIX works pretty fine and Stormlinksemi aka Cortina-Networks does
- * the same thing, without the rtc-lib.c calls.
- */
-
-static int gemini_rtc_read_time(struct device *dev, struct rtc_time *tm)
-{
-       struct gemini_rtc *rtc = dev_get_drvdata(dev);
-
-       unsigned int  days, hour, min, sec;
-       unsigned long offset, time;
-
-       sec  = readl(rtc->rtc_base + GEMINI_RTC_SECOND);
-       min  = readl(rtc->rtc_base + GEMINI_RTC_MINUTE);
-       hour = readl(rtc->rtc_base + GEMINI_RTC_HOUR);
-       days = readl(rtc->rtc_base + GEMINI_RTC_DAYS);
-       offset = readl(rtc->rtc_base + GEMINI_RTC_RECORD);
-
-       time = offset + days * 86400 + hour * 3600 + min * 60 + sec;
-
-       rtc_time_to_tm(time, tm);
-
-       return 0;
-}
-
-static int gemini_rtc_set_time(struct device *dev, struct rtc_time *tm)
-{
-       struct gemini_rtc *rtc = dev_get_drvdata(dev);
-       unsigned int sec, min, hour, day;
-       unsigned long offset, time;
-
-       if (tm->tm_year >= 2148)        /* EPOCH Year + 179 */
-               return -EINVAL;
-
-       rtc_tm_to_time(tm, &time);
-
-       sec = readl(rtc->rtc_base + GEMINI_RTC_SECOND);
-       min = readl(rtc->rtc_base + GEMINI_RTC_MINUTE);
-       hour = readl(rtc->rtc_base + GEMINI_RTC_HOUR);
-       day = readl(rtc->rtc_base + GEMINI_RTC_DAYS);
-
-       offset = time - (day * 86400 + hour * 3600 + min * 60 + sec);
-
-       writel(offset, rtc->rtc_base + GEMINI_RTC_RECORD);
-       writel(0x01, rtc->rtc_base + GEMINI_RTC_CR);
-
-       return 0;
-}
-
-static const struct rtc_class_ops gemini_rtc_ops = {
-       .read_time     = gemini_rtc_read_time,
-       .set_time      = gemini_rtc_set_time,
-};
-
-static int gemini_rtc_probe(struct platform_device *pdev)
-{
-       struct gemini_rtc *rtc;
-       struct device *dev = &pdev->dev;
-       struct resource *res;
-       int ret;
-
-       rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
-       if (unlikely(!rtc))
-               return -ENOMEM;
-       platform_set_drvdata(pdev, rtc);
-
-       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
-       if (!res)
-               return -ENODEV;
-
-       rtc->rtc_irq = res->start;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENODEV;
-
-       rtc->rtc_base = devm_ioremap(dev, res->start,
-                                    resource_size(res));
-       if (!rtc->rtc_base)
-               return -ENOMEM;
-
-       ret = devm_request_irq(dev, rtc->rtc_irq, gemini_rtc_interrupt,
-                              IRQF_SHARED, pdev->name, dev);
-       if (unlikely(ret))
-               return ret;
-
-       rtc->rtc_dev = rtc_device_register(pdev->name, dev,
-                                          &gemini_rtc_ops, THIS_MODULE);
-       return PTR_ERR_OR_ZERO(rtc->rtc_dev);
-}
-
-static int gemini_rtc_remove(struct platform_device *pdev)
-{
-       struct gemini_rtc *rtc = platform_get_drvdata(pdev);
-
-       rtc_device_unregister(rtc->rtc_dev);
-
-       return 0;
-}
-
-static const struct of_device_id gemini_rtc_dt_match[] = {
-       { .compatible = "cortina,gemini-rtc" },
-       { }
-};
-MODULE_DEVICE_TABLE(of, gemini_rtc_dt_match);
-
-static struct platform_driver gemini_rtc_driver = {
-       .driver         = {
-               .name   = DRV_NAME,
-               .of_match_table = gemini_rtc_dt_match,
-       },
-       .probe          = gemini_rtc_probe,
-       .remove         = gemini_rtc_remove,
-};
-
-module_platform_driver_probe(gemini_rtc_driver, gemini_rtc_probe);
index 5ec4653022fff574ae8d4df2a31531d6963b5ca2..8940e9e43ea0fca378345df45e899b27d2e98f48 100644 (file)
@@ -16,6 +16,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/bcd.h>
+#include <linux/clk-provider.h>
 #include <linux/i2c.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
@@ -53,6 +54,8 @@
 #define M41T80_ALARM_REG_SIZE  \
        (M41T80_REG_ALARM_SEC + 1 - M41T80_REG_ALARM_MON)
 
+#define M41T80_SQW_MAX_FREQ    32768
+
 #define M41T80_SEC_ST          BIT(7)  /* ST: Stop Bit */
 #define M41T80_ALMON_AFE       BIT(7)  /* AFE: AF Enable Bit */
 #define M41T80_ALMON_SQWE      BIT(6)  /* SQWE: SQW Enable Bit */
@@ -147,7 +150,11 @@ MODULE_DEVICE_TABLE(of, m41t80_of_match);
 
 struct m41t80_data {
        unsigned long features;
+       struct i2c_client *client;
        struct rtc_device *rtc;
+#ifdef CONFIG_COMMON_CLK
+       struct clk_hw sqw;
+#endif
 };
 
 static irqreturn_t m41t80_handle_irq(int irq, void *dev_id)
@@ -227,6 +234,7 @@ static int m41t80_get_datetime(struct i2c_client *client,
 /* Sets the given date and time to the real time clock. */
 static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm)
 {
+       struct m41t80_data *clientdata = i2c_get_clientdata(client);
        unsigned char buf[8];
        int err, flags;
 
@@ -242,6 +250,17 @@ static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm)
        buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year - 100);
        buf[M41T80_REG_WDAY] = tm->tm_wday;
 
+       /* If the square wave output is controlled in the weekday register */
+       if (clientdata->features & M41T80_FEATURE_SQ_ALT) {
+               int val;
+
+               val = i2c_smbus_read_byte_data(client, M41T80_REG_WDAY);
+               if (val < 0)
+                       return val;
+
+               buf[M41T80_REG_WDAY] |= (val & 0xf0);
+       }
+
        err = i2c_smbus_write_i2c_block_data(client, M41T80_REG_SSEC,
                                             sizeof(buf), buf);
        if (err < 0) {
@@ -332,6 +351,9 @@ static int m41t80_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
                return err;
        }
 
+       /* Keep SQWE bit value */
+       alarmvals[0] |= (ret & M41T80_ALMON_SQWE);
+
        ret = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
        if (ret < 0)
                return ret;
@@ -431,103 +453,175 @@ static ssize_t flags_show(struct device *dev,
 }
 static DEVICE_ATTR_RO(flags);
 
-static ssize_t sqwfreq_show(struct device *dev,
-                           struct device_attribute *attr, char *buf)
+static struct attribute *attrs[] = {
+       &dev_attr_flags.attr,
+       NULL,
+};
+
+static struct attribute_group attr_group = {
+       .attrs = attrs,
+};
+
+#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)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct m41t80_data *clientdata = i2c_get_clientdata(client);
-       int val, reg_sqw;
+       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 (!(clientdata->features & M41T80_FEATURE_SQ))
-               return -EINVAL;
+       if (ret < 0)
+               return 0;
 
-       reg_sqw = M41T80_REG_SQW;
-       if (clientdata->features & M41T80_FEATURE_SQ_ALT)
-               reg_sqw = M41T80_REG_WDAY;
-       val = i2c_smbus_read_byte_data(client, reg_sqw);
-       if (val < 0)
-               return val;
-       val = (val >> 4) & 0xf;
-       switch (val) {
-       case 0:
-               break;
-       case 1:
-               val = 32768;
-               break;
-       default:
-               val = 32768 >> val;
-       }
-       return sprintf(buf, "%d\n", val);
+       ret >>= 4;
+       if (ret == 0)
+               val = 0;
+       else if (ret > 1)
+               val = val / (1 << ret);
+
+       return val;
 }
 
-static ssize_t sqwfreq_store(struct device *dev,
-                            struct device_attribute *attr,
-                            const char *buf, size_t count)
+static long m41t80_sqw_round_rate(struct clk_hw *hw, unsigned long rate,
+                                 unsigned long *prate)
 {
-       struct i2c_client *client = to_i2c_client(dev);
-       struct m41t80_data *clientdata = i2c_get_clientdata(client);
-       int almon, sqw, reg_sqw, rc;
-       unsigned long val;
+       int i, freq = M41T80_SQW_MAX_FREQ;
 
-       rc = kstrtoul(buf, 0, &val);
-       if (rc < 0)
-               return rc;
+       if (freq <= rate)
+               return freq;
 
-       if (!(clientdata->features & M41T80_FEATURE_SQ))
-               return -EINVAL;
+       for (i = 2; i <= ilog2(M41T80_SQW_MAX_FREQ); i++) {
+               freq /= 1 << i;
+               if (freq <= rate)
+                       return freq;
+       }
 
-       if (val) {
-               if (!is_power_of_2(val))
+       return 0;
+}
+
+static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
+                              unsigned long parent_rate)
+{
+       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 reg, ret, val = 0;
+
+       if (rate) {
+               if (!is_power_of_2(rate))
                        return -EINVAL;
-               val = ilog2(val);
-               if (val == 15)
+               val = ilog2(rate);
+               if (val == ilog2(M41T80_SQW_MAX_FREQ))
                        val = 1;
-               else if (val < 14)
-                       val = 15 - val;
+               else if (val < (ilog2(M41T80_SQW_MAX_FREQ) - 1))
+                       val = ilog2(M41T80_SQW_MAX_FREQ) - val;
                else
                        return -EINVAL;
        }
-       /* disable SQW, set SQW frequency & re-enable */
-       almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
-       if (almon < 0)
-               return almon;
-       reg_sqw = M41T80_REG_SQW;
-       if (clientdata->features & M41T80_FEATURE_SQ_ALT)
-               reg_sqw = M41T80_REG_WDAY;
-       sqw = i2c_smbus_read_byte_data(client, reg_sqw);
-       if (sqw < 0)
-               return sqw;
-       sqw = (sqw & 0x0f) | (val << 4);
-
-       rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
-                                      almon & ~M41T80_ALMON_SQWE);
-       if (rc < 0)
-               return rc;
 
-       if (val) {
-               rc = i2c_smbus_write_byte_data(client, reg_sqw, sqw);
-               if (rc < 0)
-                       return rc;
+       reg = i2c_smbus_read_byte_data(client, reg_sqw);
+       if (reg < 0)
+               return reg;
 
-               rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
-                                              almon | M41T80_ALMON_SQWE);
-               if (rc < 0)
-                       return rc;
-       }
-       return count;
+       reg = (reg & 0x0f) | (val << 4);
+
+       ret = i2c_smbus_write_byte_data(client, reg_sqw, reg);
+       if (ret < 0)
+               return ret;
+
+       return -EINVAL;
 }
-static DEVICE_ATTR_RW(sqwfreq);
 
-static struct attribute *attrs[] = {
-       &dev_attr_flags.attr,
-       &dev_attr_sqwfreq.attr,
-       NULL,
-};
+static int m41t80_sqw_control(struct clk_hw *hw, bool enable)
+{
+       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);
 
-static struct attribute_group attr_group = {
-       .attrs = attrs,
+       if (ret < 0)
+               return ret;
+
+       if (enable)
+               ret |= M41T80_ALMON_SQWE;
+       else
+               ret &= ~M41T80_ALMON_SQWE;
+
+       return i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, ret);
+}
+
+static int m41t80_sqw_prepare(struct clk_hw *hw)
+{
+       return m41t80_sqw_control(hw, 1);
+}
+
+static void m41t80_sqw_unprepare(struct clk_hw *hw)
+{
+       m41t80_sqw_control(hw, 0);
+}
+
+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);
+}
+
+static const struct clk_ops m41t80_sqw_ops = {
+       .prepare = m41t80_sqw_prepare,
+       .unprepare = m41t80_sqw_unprepare,
+       .is_prepared = m41t80_sqw_is_prepared,
+       .recalc_rate = m41t80_sqw_recalc_rate,
+       .round_rate = m41t80_sqw_round_rate,
+       .set_rate = m41t80_sqw_set_rate,
 };
 
+static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80)
+{
+       struct i2c_client *client = m41t80->client;
+       struct device_node *node = client->dev.of_node;
+       struct clk *clk;
+       struct clk_init_data init;
+       int ret;
+
+       /* First disable the clock */
+       ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
+       if (ret < 0)
+               return ERR_PTR(ret);
+       ret = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
+                                       ret & ~(M41T80_ALMON_SQWE));
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       init.name = "m41t80-sqw";
+       init.ops = &m41t80_sqw_ops;
+       init.flags = 0;
+       init.parent_names = NULL;
+       init.num_parents = 0;
+       m41t80->sqw.init = &init;
+
+       /* optional override of the clockname */
+       of_property_read_string(node, "clock-output-names", &init.name);
+
+       /* register the clock */
+       clk = clk_register(&client->dev, &m41t80->sqw);
+       if (!IS_ERR(clk))
+               of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+       return clk;
+}
+#endif
+
 #ifdef CONFIG_RTC_DRV_M41T80_WDT
 /*
  *****************************************************************************
@@ -845,6 +939,7 @@ static int m41t80_probe(struct i2c_client *client,
        if (!m41t80_data)
                return -ENOMEM;
 
+       m41t80_data->client = client;
        if (client->dev.of_node)
                m41t80_data->features = (unsigned long)
                        of_device_get_match_data(&client->dev);
@@ -936,6 +1031,10 @@ static int m41t80_probe(struct i2c_client *client,
                        return rc;
                }
        }
+#endif
+#ifdef CONFIG_COMMON_CLK
+       if (m41t80_data->features & M41T80_FEATURE_SQ)
+               m41t80_sqw_register_clk(m41t80_data);
 #endif
        return 0;
 }
index 77319122642ab51c491655ef5ffc94a9fc8c7745..401f46d8f21b600e707b877f25b17280d9d31cc5 100644 (file)
 
 #define MAX_PIE_NUM     9
 #define MAX_PIE_FREQ    512
-static const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = {
-       { 2,            RTC_2HZ_BIT },
-       { 4,            RTC_SAM0_BIT },
-       { 8,            RTC_SAM1_BIT },
-       { 16,           RTC_SAM2_BIT },
-       { 32,           RTC_SAM3_BIT },
-       { 64,           RTC_SAM4_BIT },
-       { 128,          RTC_SAM5_BIT },
-       { 256,          RTC_SAM6_BIT },
-       { MAX_PIE_FREQ, RTC_SAM7_BIT },
-};
 
 #define MXC_RTC_TIME   0
 #define MXC_RTC_ALARM  1
index b1b6b3041bfbc94eac0a478daabd7549bc891163..4ed81117cf5f346d663d11f0a799df4bd3801926 100644 (file)
@@ -93,7 +93,7 @@ static int *check_rtc_access_enable(struct nuc900_rtc *nuc900_rtc)
        __raw_writel(AERPOWERON, nuc900_rtc->rtc_reg + REG_RTC_AER);
 
        while (!(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB)
-                                                               && timeout--)
+                                                               && --timeout)
                mdelay(1);
 
        if (!timeout)
index ea20f627dabea3617b52e9ad1476245f42a5fc94..e2a946c0e667e150e1029728134c6d20baf4d076 100644 (file)
@@ -142,6 +142,16 @@ static int opal_get_tpo_time(struct device *dev, struct rtc_wkalrm *alarm)
 
        y_m_d = be32_to_cpu(__y_m_d);
        h_m_s_ms = ((u64)be32_to_cpu(__h_m) << 32);
+
+       /* check if no alarm is set */
+       if (y_m_d == 0 && h_m_s_ms == 0) {
+               pr_debug("No alarm is set\n");
+               rc = -ENOENT;
+               goto exit;
+       } else {
+               pr_debug("Alarm set to %x %llx\n", y_m_d, h_m_s_ms);
+       }
+
        opal_to_tm(y_m_d, h_m_s_ms, &alarm->time);
 
 exit:
@@ -157,7 +167,14 @@ static int opal_set_tpo_time(struct device *dev, struct rtc_wkalrm *alarm)
        u32 y_m_d = 0;
        int token, rc;
 
-       tm_to_opal(&alarm->time, &y_m_d, &h_m_s_ms);
+       /* if alarm is enabled */
+       if (alarm->enabled) {
+               tm_to_opal(&alarm->time, &y_m_d, &h_m_s_ms);
+               pr_debug("Alarm set to %x %llx\n", y_m_d, h_m_s_ms);
+
+       } else {
+               pr_debug("Alarm getting disabled\n");
+       }
 
        token = opal_async_get_token_interruptible();
        if (token < 0) {
@@ -190,6 +207,18 @@ exit:
        return rc;
 }
 
+int opal_tpo_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+       struct rtc_wkalrm alarm = { .enabled = 0 };
+
+       /*
+        * TPO is automatically enabled when opal_set_tpo_time() is called with
+        * non-zero rtc-time. We only handle disable case which needs to be
+        * explicitly told to opal.
+        */
+       return enabled ? 0 : opal_set_tpo_time(dev, &alarm);
+}
+
 static struct rtc_class_ops opal_rtc_ops = {
        .read_time      = opal_get_rtc_time,
        .set_time       = opal_set_rtc_time,
@@ -205,6 +234,7 @@ static int opal_rtc_probe(struct platform_device *pdev)
                device_set_wakeup_capable(&pdev->dev, true);
                opal_rtc_ops.read_alarm = opal_get_tpo_time;
                opal_rtc_ops.set_alarm = opal_set_tpo_time;
+               opal_rtc_ops.alarm_irq_enable = opal_tpo_alarm_irq_enable;
        }
 
        rtc = devm_rtc_device_register(&pdev->dev, DRVNAME, &opal_rtc_ops,
index 1227ceab61eecc408526c6eb542477058a46417a..cea6ea4df970ff44925008b643e894300d3adeaa 100644 (file)
@@ -606,7 +606,7 @@ static int pcf8563_probe(struct i2c_client *client,
                err = devm_request_threaded_irq(&client->dev, client->irq,
                                NULL, pcf8563_irq,
                                IRQF_SHARED|IRQF_ONESHOT|IRQF_TRIGGER_FALLING,
-                               pcf8563->rtc->name, client);
+                               pcf8563_driver.driver.name, client);
                if (err) {
                        dev_err(&client->dev, "unable to request IRQ %d\n",
                                                                client->irq);
index 9ad97ab298664c9bda5bc221aa94f9cef97173b1..aae2576741a61585a9624217fa2a6cd1d26510e1 100644 (file)
@@ -68,6 +68,7 @@ struct rv8803_data {
        struct mutex flags_lock;
        u8 ctrl;
        enum rv8803_type type;
+       struct nvmem_config nvmem_cfg;
 };
 
 static int rv8803_read_reg(const struct i2c_client *client, u8 reg)
@@ -460,48 +461,32 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
        }
 }
 
-static ssize_t rv8803_nvram_write(struct file *filp, struct kobject *kobj,
-                                 struct bin_attribute *attr,
-                                 char *buf, loff_t off, size_t count)
+static int rv8803_nvram_write(void *priv, unsigned int offset, void *val,
+                             size_t bytes)
 {
-       struct device *dev = kobj_to_dev(kobj);
-       struct i2c_client *client = to_i2c_client(dev);
        int ret;
 
-       ret = rv8803_write_reg(client, RV8803_RAM, buf[0]);
+       ret = rv8803_write_reg(priv, RV8803_RAM, *(u8 *)val);
        if (ret)
                return ret;
 
-       return 1;
+       return 0;
 }
 
-static ssize_t rv8803_nvram_read(struct file *filp, struct kobject *kobj,
-                                struct bin_attribute *attr,
-                                char *buf, loff_t off, size_t count)
+static int rv8803_nvram_read(void *priv, unsigned int offset,
+                            void *val, size_t bytes)
 {
-       struct device *dev = kobj_to_dev(kobj);
-       struct i2c_client *client = to_i2c_client(dev);
        int ret;
 
-       ret = rv8803_read_reg(client, RV8803_RAM);
+       ret = rv8803_read_reg(priv, RV8803_RAM);
        if (ret < 0)
                return ret;
 
-       buf[0] = ret;
+       *(u8 *)val = ret;
 
-       return 1;
+       return 0;
 }
 
-static struct bin_attribute rv8803_nvram_attr = {
-       .attr = {
-               .name = "nvram",
-               .mode = S_IRUGO | S_IWUSR,
-       },
-       .size = 1,
-       .read = rv8803_nvram_read,
-       .write = rv8803_nvram_write,
-};
-
 static struct rtc_class_ops rv8803_rtc_ops = {
        .read_time = rv8803_get_time,
        .set_time = rv8803_set_time,
@@ -577,6 +562,11 @@ static int rv8803_probe(struct i2c_client *client,
        if (flags & RV8803_FLAG_AF)
                dev_warn(&client->dev, "An alarm maybe have been missed.\n");
 
+       rv8803->rtc = devm_rtc_allocate_device(&client->dev);
+       if (IS_ERR(rv8803->rtc)) {
+               return PTR_ERR(rv8803->rtc);
+       }
+
        if (client->irq > 0) {
                err = devm_request_threaded_irq(&client->dev, client->irq,
                                                NULL, rv8803_handle_irq,
@@ -592,12 +582,20 @@ static int rv8803_probe(struct i2c_client *client,
                }
        }
 
-       rv8803->rtc = devm_rtc_device_register(&client->dev, client->name,
-                                              &rv8803_rtc_ops, THIS_MODULE);
-       if (IS_ERR(rv8803->rtc)) {
-               dev_err(&client->dev, "unable to register the class device\n");
-               return PTR_ERR(rv8803->rtc);
-       }
+       rv8803->nvmem_cfg.name = "rv8803_nvram",
+       rv8803->nvmem_cfg.word_size = 1,
+       rv8803->nvmem_cfg.stride = 1,
+       rv8803->nvmem_cfg.size = 1,
+       rv8803->nvmem_cfg.reg_read = rv8803_nvram_read,
+       rv8803->nvmem_cfg.reg_write = rv8803_nvram_write,
+       rv8803->nvmem_cfg.priv = client;
+
+       rv8803->rtc->ops = &rv8803_rtc_ops;
+       rv8803->rtc->nvmem_config = &rv8803->nvmem_cfg;
+       rv8803->rtc->nvram_old_abi = true;
+       err = rtc_register_device(rv8803->rtc);
+       if (err)
+               return err;
 
        err = rv8803_write_reg(rv8803->client, RV8803_EXT, RV8803_EXT_WADA);
        if (err)
@@ -609,22 +607,11 @@ static int rv8803_probe(struct i2c_client *client,
                return err;
        }
 
-       err = device_create_bin_file(&client->dev, &rv8803_nvram_attr);
-       if (err)
-               return err;
-
        rv8803->rtc->max_user_freq = 1;
 
        return 0;
 }
 
-static int rv8803_remove(struct i2c_client *client)
-{
-       device_remove_bin_file(&client->dev, &rv8803_nvram_attr);
-
-       return 0;
-}
-
 static const struct i2c_device_id rv8803_id[] = {
        { "rv8803", rv_8803 },
        { "rx8900", rx_8900 },
@@ -651,7 +638,6 @@ static struct i2c_driver rv8803_driver = {
                .of_match_table = of_match_ptr(rv8803_of_match),
        },
        .probe          = rv8803_probe,
-       .remove         = rv8803_remove,
        .id_table       = rv8803_id,
 };
 module_i2c_driver(rv8803_driver);
index d44fb34df8fe894b41f1a8c107e699f752ac5a00..a8992c227f611807c998bbe81c434d9388cfd33f 100644 (file)
@@ -41,7 +41,7 @@ struct s3c_rtc {
        struct clk *rtc_src_clk;
        bool clk_disabled;
 
-       struct s3c_rtc_data *data;
+       const struct s3c_rtc_data *data;
 
        int irq_alarm;
        int irq_tick;
@@ -49,7 +49,8 @@ struct s3c_rtc {
        spinlock_t pie_lock;
        spinlock_t alarm_clk_lock;
 
-       int ticnt_save, ticnt_en_save;
+       int ticnt_save;
+       int ticnt_en_save;
        bool wake_en;
 };
 
@@ -67,18 +68,32 @@ struct s3c_rtc_data {
        void (*disable) (struct s3c_rtc *info);
 };
 
-static void s3c_rtc_enable_clk(struct s3c_rtc *info)
+static int s3c_rtc_enable_clk(struct s3c_rtc *info)
 {
        unsigned long irq_flags;
+       int ret = 0;
 
        spin_lock_irqsave(&info->alarm_clk_lock, irq_flags);
+
        if (info->clk_disabled) {
-               clk_enable(info->rtc_clk);
-               if (info->data->needs_src_clk)
-                       clk_enable(info->rtc_src_clk);
+               ret = clk_enable(info->rtc_clk);
+               if (ret)
+                       goto out;
+
+               if (info->data->needs_src_clk) {
+                       ret = clk_enable(info->rtc_src_clk);
+                       if (ret) {
+                               clk_disable(info->rtc_clk);
+                               goto out;
+                       }
+               }
                info->clk_disabled = false;
        }
+
+out:
        spin_unlock_irqrestore(&info->alarm_clk_lock, irq_flags);
+
+       return ret;
 }
 
 static void s3c_rtc_disable_clk(struct s3c_rtc *info)
@@ -121,10 +136,13 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
 {
        struct s3c_rtc *info = dev_get_drvdata(dev);
        unsigned int tmp;
+       int ret;
 
        dev_dbg(info->dev, "%s: aie=%d\n", __func__, enabled);
 
-       s3c_rtc_enable_clk(info);
+       ret = s3c_rtc_enable_clk(info);
+       if (ret)
+               return ret;
 
        tmp = readb(info->base + S3C2410_RTCALM) & ~S3C2410_RTCALM_ALMEN;
 
@@ -135,10 +153,13 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
 
        s3c_rtc_disable_clk(info);
 
-       if (enabled)
-               s3c_rtc_enable_clk(info);
-       else
+       if (enabled) {
+               ret = s3c_rtc_enable_clk(info);
+               if (ret)
+                       return ret;
+       } else {
                s3c_rtc_disable_clk(info);
+       }
 
        return 0;
 }
@@ -146,10 +167,14 @@ static int s3c_rtc_setaie(struct device *dev, unsigned int enabled)
 /* Set RTC frequency */
 static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq)
 {
+       int ret;
+
        if (!is_power_of_2(freq))
                return -EINVAL;
 
-       s3c_rtc_enable_clk(info);
+       ret = s3c_rtc_enable_clk(info);
+       if (ret)
+               return ret;
        spin_lock_irq(&info->pie_lock);
 
        if (info->data->set_freq)
@@ -166,10 +191,13 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
 {
        struct s3c_rtc *info = dev_get_drvdata(dev);
        unsigned int have_retried = 0;
+       int ret;
 
-       s3c_rtc_enable_clk(info);
+       ret = s3c_rtc_enable_clk(info);
+       if (ret)
+               return ret;
 
- retry_get_time:
+retry_get_time:
        rtc_tm->tm_min  = readb(info->base + S3C2410_RTCMIN);
        rtc_tm->tm_hour = readb(info->base + S3C2410_RTCHOUR);
        rtc_tm->tm_mday = readb(info->base + S3C2410_RTCDATE);
@@ -199,8 +227,8 @@ static int s3c_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)
        rtc_tm->tm_year += 100;
 
        dev_dbg(dev, "read time %04d.%02d.%02d %02d:%02d:%02d\n",
-                1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
-                rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
+               1900 + rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,
+               rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec);
 
        rtc_tm->tm_mon -= 1;
 
@@ -211,10 +239,11 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
 {
        struct s3c_rtc *info = dev_get_drvdata(dev);
        int year = tm->tm_year - 100;
+       int ret;
 
        dev_dbg(dev, "set time %04d.%02d.%02d %02d:%02d:%02d\n",
-                1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
-                tm->tm_hour, tm->tm_min, tm->tm_sec);
+               1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
 
        /* we get around y2k by simply not supporting it */
 
@@ -223,7 +252,9 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm)
                return -EINVAL;
        }
 
-       s3c_rtc_enable_clk(info);
+       ret = s3c_rtc_enable_clk(info);
+       if (ret)
+               return ret;
 
        writeb(bin2bcd(tm->tm_sec),  info->base + S3C2410_RTCSEC);
        writeb(bin2bcd(tm->tm_min),  info->base + S3C2410_RTCMIN);
@@ -242,8 +273,11 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
        struct s3c_rtc *info = dev_get_drvdata(dev);
        struct rtc_time *alm_tm = &alrm->time;
        unsigned int alm_en;
+       int ret;
 
-       s3c_rtc_enable_clk(info);
+       ret = s3c_rtc_enable_clk(info);
+       if (ret)
+               return ret;
 
        alm_tm->tm_sec  = readb(info->base + S3C2410_ALMSEC);
        alm_tm->tm_min  = readb(info->base + S3C2410_ALMMIN);
@@ -259,9 +293,9 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
        alrm->enabled = (alm_en & S3C2410_RTCALM_ALMEN) ? 1 : 0;
 
        dev_dbg(dev, "read alarm %d, %04d.%02d.%02d %02d:%02d:%02d\n",
-                alm_en,
-                1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
-                alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
+               alm_en,
+               1900 + alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,
+               alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec);
 
        /* decode the alarm enable field */
        if (alm_en & S3C2410_RTCALM_SECEN)
@@ -292,14 +326,17 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
        struct s3c_rtc *info = dev_get_drvdata(dev);
        struct rtc_time *tm = &alrm->time;
        unsigned int alrm_en;
+       int ret;
        int year = tm->tm_year - 100;
 
        dev_dbg(dev, "s3c_rtc_setalarm: %d, %04d.%02d.%02d %02d:%02d:%02d\n",
-                alrm->enabled,
-                1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
-                tm->tm_hour, tm->tm_min, tm->tm_sec);
+               alrm->enabled,
+               1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
 
-       s3c_rtc_enable_clk(info);
+       ret = s3c_rtc_enable_clk(info);
+       if (ret)
+               return ret;
 
        alrm_en = readb(info->base + S3C2410_RTCALM) & S3C2410_RTCALM_ALMEN;
        writeb(0x00, info->base + S3C2410_RTCALM);
@@ -348,8 +385,11 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
 static int s3c_rtc_proc(struct device *dev, struct seq_file *seq)
 {
        struct s3c_rtc *info = dev_get_drvdata(dev);
+       int ret;
 
-       s3c_rtc_enable_clk(info);
+       ret = s3c_rtc_enable_clk(info);
+       if (ret)
+               return ret;
 
        if (info->data->enable_tick)
                info->data->enable_tick(info, seq);
@@ -378,8 +418,7 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info)
                dev_info(info->dev, "rtc disabled, re-enabling\n");
 
                tmp = readw(info->base + S3C2410_RTCCON);
-               writew(tmp | S3C2410_RTCCON_RTCEN,
-                       info->base + S3C2410_RTCCON);
+               writew(tmp | S3C2410_RTCCON_RTCEN, info->base + S3C2410_RTCCON);
        }
 
        if (con & S3C2410_RTCCON_CNTSEL) {
@@ -387,7 +426,7 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info)
 
                tmp = readw(info->base + S3C2410_RTCCON);
                writew(tmp & ~S3C2410_RTCCON_CNTSEL,
-                       info->base + S3C2410_RTCCON);
+                      info->base + S3C2410_RTCCON);
        }
 
        if (con & S3C2410_RTCCON_CLKRST) {
@@ -395,7 +434,7 @@ static void s3c24xx_rtc_enable(struct s3c_rtc *info)
 
                tmp = readw(info->base + S3C2410_RTCCON);
                writew(tmp & ~S3C2410_RTCCON_CLKRST,
-                       info->base + S3C2410_RTCCON);
+                      info->base + S3C2410_RTCCON);
        }
 }
 
@@ -437,12 +476,12 @@ static int s3c_rtc_remove(struct platform_device *pdev)
 
 static const struct of_device_id s3c_rtc_dt_match[];
 
-static struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev)
+static const struct s3c_rtc_data *s3c_rtc_get_data(struct platform_device *pdev)
 {
        const struct of_device_id *match;
 
        match = of_match_node(s3c_rtc_dt_match, pdev->dev.of_node);
-       return (struct s3c_rtc_data *)match->data;
+       return match->data;
 }
 
 static int s3c_rtc_probe(struct platform_device *pdev)
@@ -481,7 +520,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
        }
 
        dev_dbg(&pdev->dev, "s3c2410_rtc: tick irq %d, alarm irq %d\n",
-                info->irq_tick, info->irq_alarm);
+               info->irq_tick, info->irq_alarm);
 
        /* get the memory region */
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -498,7 +537,9 @@ static int s3c_rtc_probe(struct platform_device *pdev)
                        dev_dbg(&pdev->dev, "probe deferred due to missing rtc clk\n");
                return ret;
        }
-       clk_prepare_enable(info->rtc_clk);
+       ret = clk_prepare_enable(info->rtc_clk);
+       if (ret)
+               return ret;
 
        if (info->data->needs_src_clk) {
                info->rtc_src_clk = devm_clk_get(&pdev->dev, "rtc_src");
@@ -510,10 +551,11 @@ static int s3c_rtc_probe(struct platform_device *pdev)
                        else
                                dev_dbg(&pdev->dev,
                                        "probe deferred due to missing rtc src clk\n");
-                       clk_disable_unprepare(info->rtc_clk);
-                       return ret;
+                       goto err_src_clk;
                }
-               clk_prepare_enable(info->rtc_src_clk);
+               ret = clk_prepare_enable(info->rtc_src_clk);
+               if (ret)
+                       goto err_src_clk;
        }
 
        /* check to see if everything is setup correctly */
@@ -521,7 +563,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
                info->data->enable(info);
 
        dev_dbg(&pdev->dev, "s3c2410_rtc: RTCCON=%02x\n",
-                readw(info->base + S3C2410_RTCCON));
+               readw(info->base + S3C2410_RTCCON));
 
        device_init_wakeup(&pdev->dev, 1);
 
@@ -541,7 +583,7 @@ static int s3c_rtc_probe(struct platform_device *pdev)
 
        /* register RTC and exit */
        info->rtc = devm_rtc_device_register(&pdev->dev, "s3c", &s3c_rtcops,
-                                 THIS_MODULE);
+                                            THIS_MODULE);
        if (IS_ERR(info->rtc)) {
                dev_err(&pdev->dev, "cannot attach rtc\n");
                ret = PTR_ERR(info->rtc);
@@ -549,14 +591,14 @@ static int s3c_rtc_probe(struct platform_device *pdev)
        }
 
        ret = devm_request_irq(&pdev->dev, info->irq_alarm, s3c_rtc_alarmirq,
-                         0,  "s3c2410-rtc alarm", info);
+                              0, "s3c2410-rtc alarm", info);
        if (ret) {
                dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_alarm, ret);
                goto err_nortc;
        }
 
        ret = devm_request_irq(&pdev->dev, info->irq_tick, s3c_rtc_tickirq,
-                         0,  "s3c2410-rtc tick", info);
+                              0, "s3c2410-rtc tick", info);
        if (ret) {
                dev_err(&pdev->dev, "IRQ%d error %d\n", info->irq_tick, ret);
                goto err_nortc;
@@ -569,12 +611,13 @@ static int s3c_rtc_probe(struct platform_device *pdev)
 
        return 0;
 
- err_nortc:
+err_nortc:
        if (info->data->disable)
                info->data->disable(info);
 
        if (info->data->needs_src_clk)
                clk_disable_unprepare(info->rtc_src_clk);
+err_src_clk:
        clk_disable_unprepare(info->rtc_clk);
 
        return ret;
@@ -585,8 +628,11 @@ static int s3c_rtc_probe(struct platform_device *pdev)
 static int s3c_rtc_suspend(struct device *dev)
 {
        struct s3c_rtc *info = dev_get_drvdata(dev);
+       int ret;
 
-       s3c_rtc_enable_clk(info);
+       ret = s3c_rtc_enable_clk(info);
+       if (ret)
+               return ret;
 
        /* save TICNT for anyone using periodic interrupts */
        if (info->data->save_tick_cnt)
@@ -747,8 +793,7 @@ static void s3c6410_rtc_restore_tick_cnt(struct s3c_rtc *info)
        writel(info->ticnt_save, info->base + S3C2410_TICNT);
        if (info->ticnt_en_save) {
                con = readw(info->base + S3C2410_RTCCON);
-               writew(con | info->ticnt_en_save,
-                               info->base + S3C2410_RTCCON);
+               writew(con | info->ticnt_en_save, info->base + S3C2410_RTCCON);
        }
 }
 
@@ -802,19 +847,19 @@ static struct s3c_rtc_data const s3c6410_rtc_data = {
 static const struct of_device_id s3c_rtc_dt_match[] = {
        {
                .compatible = "samsung,s3c2410-rtc",
-               .data = (void *)&s3c2410_rtc_data,
+               .data = &s3c2410_rtc_data,
        }, {
                .compatible = "samsung,s3c2416-rtc",
-               .data = (void *)&s3c2416_rtc_data,
+               .data = &s3c2416_rtc_data,
        }, {
                .compatible = "samsung,s3c2443-rtc",
-               .data = (void *)&s3c2443_rtc_data,
+               .data = &s3c2443_rtc_data,
        }, {
                .compatible = "samsung,s3c6410-rtc",
-               .data = (void *)&s3c6410_rtc_data,
+               .data = &s3c6410_rtc_data,
        }, {
                .compatible = "samsung,exynos3250-rtc",
-               .data = (void *)&s3c6410_rtc_data,
+               .data = &s3c6410_rtc_data,
        },
        { /* sentinel */ },
 };
index 74c0a336ceea0650965701f93399814299275bd1..82b0af159a28221cff367964b27206e8b402385d 100644 (file)
@@ -99,7 +99,7 @@ static int st_rtc_read_time(struct device *dev, struct rtc_time *tm)
 
        lpt = ((unsigned long long)lpt_msb << 32) | lpt_lsb;
        do_div(lpt, rtc->clkrate);
-       rtc_time_to_tm(lpt, tm);
+       rtc_time64_to_tm(lpt, tm);
 
        return 0;
 }
@@ -107,13 +107,10 @@ static int st_rtc_read_time(struct device *dev, struct rtc_time *tm)
 static int st_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
        struct st_rtc *rtc = dev_get_drvdata(dev);
-       unsigned long long lpt;
-       unsigned long secs, flags;
-       int ret;
+       unsigned long long lpt, secs;
+       unsigned long flags;
 
-       ret = rtc_tm_to_time(tm, &secs);
-       if (ret)
-               return ret;
+       secs = rtc_tm_to_time64(tm);
 
        lpt = (unsigned long long)secs * rtc->clkrate;
 
@@ -161,13 +158,13 @@ static int st_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t)
 {
        struct st_rtc *rtc = dev_get_drvdata(dev);
        struct rtc_time now;
-       unsigned long now_secs;
-       unsigned long alarm_secs;
+       unsigned long long now_secs;
+       unsigned long long alarm_secs;
        unsigned long long lpa;
 
        st_rtc_read_time(dev, &now);
-       rtc_tm_to_time(&now, &now_secs);
-       rtc_tm_to_time(&t->time, &alarm_secs);
+       now_secs = rtc_tm_to_time64(&now);
+       alarm_secs = rtc_tm_to_time64(&t->time);
 
        /* Invalid alarm time */
        if (now_secs > alarm_secs)
index bd57eb1029e116f5c91694addfaf993ab6688066..3a5c3d7d0c77a4f1bc8729cf01832da003bfc4f6 100644 (file)
 /* STM32_PWR_CR bit field */
 #define PWR_CR_DBP                     BIT(8)
 
+struct stm32_rtc_data {
+       bool has_pclk;
+};
+
 struct stm32_rtc {
        struct rtc_device *rtc_dev;
        void __iomem *base;
        struct regmap *dbp;
-       struct clk *ck_rtc;
+       struct stm32_rtc_data *data;
+       struct clk *pclk;
+       struct clk *rtc_ck;
        int irq_alarm;
 };
 
@@ -122,9 +128,9 @@ static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
                writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
 
                /*
-                * It takes around 2 ck_rtc clock cycles to enter in
+                * It takes around 2 rtc_ck clock cycles to enter in
                 * initialization phase mode (and have INITF flag set). As
-                * slowest ck_rtc frequency may be 32kHz and highest should be
+                * slowest rtc_ck frequency may be 32kHz and highest should be
                 * 1MHz, we poll every 10 us with a timeout of 100ms.
                 */
                return readl_relaxed_poll_timeout_atomic(
@@ -153,7 +159,7 @@ static int stm32_rtc_wait_sync(struct stm32_rtc *rtc)
 
        /*
         * Wait for RSF to be set to ensure the calendar registers are
-        * synchronised, it takes around 2 ck_rtc clock cycles
+        * synchronised, it takes around 2 rtc_ck clock cycles
         */
        return readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
                                                 isr,
@@ -456,7 +462,7 @@ static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 
        /*
         * Poll Alarm write flag to be sure that Alarm update is allowed: it
-        * takes around 2 ck_rtc clock cycles
+        * takes around 2 rtc_ck clock cycles
         */
        ret = readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
                                                isr,
@@ -490,8 +496,17 @@ static const struct rtc_class_ops stm32_rtc_ops = {
        .alarm_irq_enable = stm32_rtc_alarm_irq_enable,
 };
 
+static const struct stm32_rtc_data stm32_rtc_data = {
+       .has_pclk = false,
+};
+
+static const struct stm32_rtc_data stm32h7_rtc_data = {
+       .has_pclk = true,
+};
+
 static const struct of_device_id stm32_rtc_of_match[] = {
-       { .compatible = "st,stm32-rtc" },
+       { .compatible = "st,stm32-rtc", .data = &stm32_rtc_data },
+       { .compatible = "st,stm32h7-rtc", .data = &stm32h7_rtc_data },
        {}
 };
 MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
@@ -503,7 +518,7 @@ static int stm32_rtc_init(struct platform_device *pdev,
        unsigned int rate;
        int ret = 0;
 
-       rate = clk_get_rate(rtc->ck_rtc);
+       rate = clk_get_rate(rtc->rtc_ck);
 
        /* Find prediv_a and prediv_s to obtain the 1Hz calendar clock */
        pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT;
@@ -524,7 +539,7 @@ static int stm32_rtc_init(struct platform_device *pdev,
                pred_a = pred_a_max;
                pred_s = (rate / (pred_a + 1)) - 1;
 
-               dev_warn(&pdev->dev, "ck_rtc is %s\n",
+               dev_warn(&pdev->dev, "rtc_ck is %s\n",
                         (rate < ((pred_a + 1) * (pred_s + 1))) ?
                         "fast" : "slow");
        }
@@ -561,6 +576,7 @@ static int stm32_rtc_probe(struct platform_device *pdev)
 {
        struct stm32_rtc *rtc;
        struct resource *res;
+       const struct of_device_id *match;
        int ret;
 
        rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
@@ -579,15 +595,34 @@ static int stm32_rtc_probe(struct platform_device *pdev)
                return PTR_ERR(rtc->dbp);
        }
 
-       rtc->ck_rtc = devm_clk_get(&pdev->dev, NULL);
-       if (IS_ERR(rtc->ck_rtc)) {
-               dev_err(&pdev->dev, "no ck_rtc clock");
-               return PTR_ERR(rtc->ck_rtc);
+       match = of_match_device(stm32_rtc_of_match, &pdev->dev);
+       rtc->data = (struct stm32_rtc_data *)match->data;
+
+       if (!rtc->data->has_pclk) {
+               rtc->pclk = NULL;
+               rtc->rtc_ck = devm_clk_get(&pdev->dev, NULL);
+       } else {
+               rtc->pclk = devm_clk_get(&pdev->dev, "pclk");
+               if (IS_ERR(rtc->pclk)) {
+                       dev_err(&pdev->dev, "no pclk clock");
+                       return PTR_ERR(rtc->pclk);
+               }
+               rtc->rtc_ck = devm_clk_get(&pdev->dev, "rtc_ck");
+       }
+       if (IS_ERR(rtc->rtc_ck)) {
+               dev_err(&pdev->dev, "no rtc_ck clock");
+               return PTR_ERR(rtc->rtc_ck);
+       }
+
+       if (rtc->data->has_pclk) {
+               ret = clk_prepare_enable(rtc->pclk);
+               if (ret)
+                       return ret;
        }
 
-       ret = clk_prepare_enable(rtc->ck_rtc);
+       ret = clk_prepare_enable(rtc->rtc_ck);
        if (ret)
-               return ret;
+               goto err;
 
        regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
 
@@ -595,7 +630,7 @@ static int stm32_rtc_probe(struct platform_device *pdev)
         * After a system reset, RTC_ISR.INITS flag can be read to check if
         * the calendar has been initalized or not. INITS flag is reset by a
         * power-on reset (no vbat, no power-supply). It is not reset if
-        * ck_rtc parent clock has changed (so RTC prescalers need to be
+        * rtc_ck parent clock has changed (so RTC prescalers need to be
         * changed). That's why we cannot rely on this flag to know if RTC
         * init has to be done.
         */
@@ -646,7 +681,9 @@ static int stm32_rtc_probe(struct platform_device *pdev)
 
        return 0;
 err:
-       clk_disable_unprepare(rtc->ck_rtc);
+       if (rtc->data->has_pclk)
+               clk_disable_unprepare(rtc->pclk);
+       clk_disable_unprepare(rtc->rtc_ck);
 
        regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, 0);
 
@@ -667,7 +704,9 @@ static int stm32_rtc_remove(struct platform_device *pdev)
        writel_relaxed(cr, rtc->base + STM32_RTC_CR);
        stm32_rtc_wpr_lock(rtc);
 
-       clk_disable_unprepare(rtc->ck_rtc);
+       clk_disable_unprepare(rtc->rtc_ck);
+       if (rtc->data->has_pclk)
+               clk_disable_unprepare(rtc->pclk);
 
        /* Enable backup domain write protection */
        regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, 0);
@@ -682,6 +721,9 @@ static int stm32_rtc_suspend(struct device *dev)
 {
        struct stm32_rtc *rtc = dev_get_drvdata(dev);
 
+       if (rtc->data->has_pclk)
+               clk_disable_unprepare(rtc->pclk);
+
        if (device_may_wakeup(dev))
                return enable_irq_wake(rtc->irq_alarm);
 
@@ -693,6 +735,12 @@ static int stm32_rtc_resume(struct device *dev)
        struct stm32_rtc *rtc = dev_get_drvdata(dev);
        int ret = 0;
 
+       if (rtc->data->has_pclk) {
+               ret = clk_prepare_enable(rtc->pclk);
+               if (ret)
+                       return ret;
+       }
+
        ret = stm32_rtc_wait_sync(rtc);
        if (ret < 0)
                return ret;
index 1218d5d4224ddae32c28be3b4977a597120027f0..e364550eb9a7fad8ef4efed7ca2f200116832e9c 100644 (file)
@@ -27,7 +27,8 @@
 static ssize_t
 name_show(struct device *dev, struct device_attribute *attr, char *buf)
 {
-       return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
+       return sprintf(buf, "%s %s\n", dev_driver_string(dev->parent),
+                      dev_name(dev->parent));
 }
 static DEVICE_ATTR_RO(name);
 
index cd93416d762ed0a63a3b262dec01d657bbadaa80..497706f5adcacc5db666a3099931bb45d0fbfc28 100644 (file)
@@ -12,6 +12,9 @@
 #ifndef _LINUX_NVMEM_PROVIDER_H
 #define _LINUX_NVMEM_PROVIDER_H
 
+#include <linux/err.h>
+#include <linux/errno.h>
+
 struct nvmem_device;
 struct nvmem_cell_info;
 typedef int (*nvmem_reg_read_t)(void *priv, unsigned int offset,
index b693adac853b24e02046d3ce040ad03ea04e8208..0a0f0d14a5fba5582ab8c86ba1dc3a726b9881a0 100644 (file)
@@ -14,6 +14,7 @@
 
 #include <linux/types.h>
 #include <linux/interrupt.h>
+#include <linux/nvmem-provider.h>
 #include <uapi/linux/rtc.h>
 
 extern int rtc_month_days(unsigned int month, unsigned int year);
@@ -32,17 +33,11 @@ static inline time64_t rtc_tm_sub(struct rtc_time *lhs, struct rtc_time *rhs)
        return rtc_tm_to_time64(lhs) - rtc_tm_to_time64(rhs);
 }
 
-/**
- * Deprecated. Use rtc_time64_to_tm().
- */
 static inline void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
 {
        rtc_time64_to_tm(time, tm);
 }
 
-/**
- * Deprecated. Use rtc_tm_to_time64().
- */
 static inline int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
 {
        *time = rtc_tm_to_time64(tm);
@@ -116,7 +111,6 @@ struct rtc_device {
        struct module *owner;
 
        int id;
-       char name[RTC_DEVICE_NAME_SIZE];
 
        const struct rtc_class_ops *ops;
        struct mutex ops_lock;
@@ -143,6 +137,14 @@ struct rtc_device {
        /* Some hardware can't support UIE mode */
        int uie_unsupported;
 
+       bool registered;
+
+       struct nvmem_config *nvmem_config;
+       struct nvmem_device *nvmem;
+       /* Old ABI support */
+       bool nvram_old_abi;
+       struct bin_attribute *nvram;
+
 #ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
        struct work_struct uie_task;
        struct timer_list uie_timer;
@@ -164,6 +166,8 @@ extern struct rtc_device *devm_rtc_device_register(struct device *dev,
                                        const char *name,
                                        const struct rtc_class_ops *ops,
                                        struct module *owner);
+struct rtc_device *devm_rtc_allocate_device(struct device *dev);
+int __rtc_register_device(struct module *owner, struct rtc_device *rtc);
 extern void rtc_device_unregister(struct rtc_device *rtc);
 extern void devm_rtc_device_unregister(struct device *dev,
                                        struct rtc_device *rtc);
@@ -219,6 +223,9 @@ static inline bool is_leap_year(unsigned int year)
        return (!(year % 4) && (year % 100)) || !(year % 400);
 }
 
+#define rtc_register_device(device) \
+       __rtc_register_device(THIS_MODULE, device)
+
 #ifdef CONFIG_RTC_HCTOSYS_DEVICE
 extern int rtc_hctosys_ret;
 #else
index 5801bbefbe891509d2a33b54433ee9f5c6226e19..a9b86133b9b3986ff3617e4e9e0a6c45f1ee16bb 100644 (file)
@@ -9,7 +9,7 @@ TEST_GEN_PROGS = posix_timers nanosleep nsleep-lat set-timer-lat mqueue-lat \
 
 TEST_GEN_PROGS_EXTENDED = alarmtimer-suspend valid-adjtimex adjtick change_skew \
                      skew_consistency clocksource-switch freq-step leap-a-day \
-                     leapcrash set-tai set-2038 set-tz
+                     leapcrash set-tai set-2038 set-tz rtctest_setdate
 
 
 include ../lib.mk
index 4230d3052e5d5948939926866d649ad636726051..f61170f7b024a65cd3587f5a933a9a7088e0dcb4 100644 (file)
@@ -21,6 +21,9 @@
 #include <stdlib.h>
 #include <errno.h>
 
+#ifndef ARRAY_SIZE
+# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
+#endif
 
 /*
  * This expects the new RTC class driver framework, working with
  */
 static const char default_rtc[] = "/dev/rtc0";
 
+static struct rtc_time cutoff_dates[] = {
+       {
+               .tm_year = 70, /* 1970 -1900 */
+               .tm_mday = 1,
+       },
+       /* signed time_t 19/01/2038 3:14:08 */
+       {
+               .tm_year = 138,
+               .tm_mday = 19,
+       },
+       {
+               .tm_year = 138,
+               .tm_mday = 20,
+       },
+       {
+               .tm_year = 199, /* 2099 -1900 */
+               .tm_mday = 1,
+       },
+       {
+               .tm_year = 200, /* 2100 -1900 */
+               .tm_mday = 1,
+       },
+       /* unsigned time_t 07/02/2106 7:28:15*/
+       {
+               .tm_year = 205,
+               .tm_mon = 1,
+               .tm_mday = 7,
+       },
+       {
+               .tm_year = 206,
+               .tm_mon = 1,
+               .tm_mday = 8,
+       },
+       /* signed time on 64bit in nanoseconds 12/04/2262 01:47:16*/
+       {
+               .tm_year = 362,
+               .tm_mon = 3,
+               .tm_mday = 12,
+       },
+       {
+               .tm_year = 362, /* 2262 -1900 */
+               .tm_mon = 3,
+               .tm_mday = 13,
+       },
+};
+
+static int compare_dates(struct rtc_time *a, struct rtc_time *b)
+{
+       if (a->tm_year != b->tm_year ||
+           a->tm_mon != b->tm_mon ||
+           a->tm_mday != b->tm_mday ||
+           a->tm_hour != b->tm_hour ||
+           a->tm_min != b->tm_min ||
+           ((b->tm_sec - a->tm_sec) > 1))
+               return 1;
+
+       return 0;
+}
 
 int main(int argc, char **argv)
 {
-       int i, fd, retval, irqcount = 0;
+       int i, fd, retval, irqcount = 0, dangerous = 0;
        unsigned long tmp, data;
        struct rtc_time rtc_tm;
        const char *rtc = default_rtc;
        struct timeval start, end, diff;
 
        switch (argc) {
+       case 3:
+               if (*argv[2] == 'd')
+                       dangerous = 1;
        case 2:
                rtc = argv[1];
                /* FALLTHROUGH */
        case 1:
                break;
        default:
-               fprintf(stderr, "usage:  rtctest [rtcdev]\n");
+               fprintf(stderr, "usage:  rtctest [rtcdev] [d]\n");
                return 1;
        }
 
@@ -202,7 +266,7 @@ test_PIE:
                /* not all RTCs support periodic IRQs */
                if (errno == EINVAL) {
                        fprintf(stderr, "\nNo periodic IRQ support\n");
-                       goto done;
+                       goto test_DATE;
                }
                perror("RTC_IRQP_READ ioctl");
                exit(errno);
@@ -221,7 +285,7 @@ test_PIE:
                        if (errno == EINVAL) {
                                fprintf(stderr,
                                        "\n...Periodic IRQ rate is fixed\n");
-                               goto done;
+                               goto test_DATE;
                        }
                        perror("RTC_IRQP_SET ioctl");
                        exit(errno);
@@ -269,6 +333,62 @@ test_PIE:
                }
        }
 
+test_DATE:
+       if (!dangerous)
+               goto done;
+
+       fprintf(stderr, "\nTesting problematic dates\n");
+
+       for (i = 0; i < ARRAY_SIZE(cutoff_dates); i++) {
+               struct rtc_time current;
+
+               /* Write the new date in RTC */
+               retval = ioctl(fd, RTC_SET_TIME, &cutoff_dates[i]);
+               if (retval == -1) {
+                       perror("RTC_SET_TIME ioctl");
+                       close(fd);
+                       exit(errno);
+               }
+
+               /* Read back */
+               retval = ioctl(fd, RTC_RD_TIME, &current);
+               if (retval == -1) {
+                       perror("RTC_RD_TIME ioctl");
+                       exit(errno);
+               }
+
+               if(compare_dates(&cutoff_dates[i], &current)) {
+                       fprintf(stderr,"Setting date %d failed\n",
+                               cutoff_dates[i].tm_year + 1900);
+                       goto done;
+               }
+
+               cutoff_dates[i].tm_sec += 5;
+
+               /* Write the new alarm in RTC */
+               retval = ioctl(fd, RTC_ALM_SET, &cutoff_dates[i]);
+               if (retval == -1) {
+                       perror("RTC_ALM_SET ioctl");
+                       close(fd);
+                       exit(errno);
+               }
+
+               /* Read back */
+               retval = ioctl(fd, RTC_ALM_READ, &current);
+               if (retval == -1) {
+                       perror("RTC_ALM_READ ioctl");
+                       exit(errno);
+               }
+
+               if(compare_dates(&cutoff_dates[i], &current)) {
+                       fprintf(stderr,"Setting alarm %d failed\n",
+                               cutoff_dates[i].tm_year + 1900);
+                       goto done;
+               }
+
+               fprintf(stderr, "Setting year %d is OK \n",
+                       cutoff_dates[i].tm_year + 1900);
+       }
 done:
        fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n");
 
diff --git a/tools/testing/selftests/timers/rtctest_setdate.c b/tools/testing/selftests/timers/rtctest_setdate.c
new file mode 100644 (file)
index 0000000..2cb7848
--- /dev/null
@@ -0,0 +1,86 @@
+/* Real Time Clock Driver Test
+ *     by: Benjamin Gaignard (benjamin.gaignard@linaro.org)
+ *
+ * To build
+ *     gcc rtctest_setdate.c -o rtctest_setdate
+ *
+ *   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 <stdio.h>
+#include <linux/rtc.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+
+static const char default_time[] = "00:00:00";
+
+int main(int argc, char **argv)
+{
+       int fd, retval;
+       struct rtc_time new, current;
+       const char *rtc, *date;
+       const char *time = default_time;
+
+       switch (argc) {
+       case 4:
+               time = argv[3];
+               /* FALLTHROUGH */
+       case 3:
+               date = argv[2];
+               rtc = argv[1];
+               break;
+       default:
+               fprintf(stderr, "usage: rtctest_setdate <rtcdev> <DD-MM-YYYY> [HH:MM:SS]\n");
+               return 1;
+       }
+
+       fd = open(rtc, O_RDONLY);
+       if (fd == -1) {
+               perror(rtc);
+               exit(errno);
+       }
+
+       sscanf(date, "%d-%d-%d", &new.tm_mday, &new.tm_mon, &new.tm_year);
+       new.tm_mon -= 1;
+       new.tm_year -= 1900;
+       sscanf(time, "%d:%d:%d", &new.tm_hour, &new.tm_min, &new.tm_sec);
+
+       fprintf(stderr, "Test will set RTC date/time to %d-%d-%d, %02d:%02d:%02d.\n",
+               new.tm_mday, new.tm_mon + 1, new.tm_year + 1900,
+               new.tm_hour, new.tm_min, new.tm_sec);
+
+       /* Write the new date in RTC */
+       retval = ioctl(fd, RTC_SET_TIME, &new);
+       if (retval == -1) {
+               perror("RTC_SET_TIME ioctl");
+               close(fd);
+               exit(errno);
+       }
+
+       /* Read back */
+       retval = ioctl(fd, RTC_RD_TIME, &current);
+       if (retval == -1) {
+               perror("RTC_RD_TIME ioctl");
+               exit(errno);
+       }
+
+       fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n",
+               current.tm_mday, current.tm_mon + 1, current.tm_year + 1900,
+               current.tm_hour, current.tm_min, current.tm_sec);
+
+       close(fd);
+       return 0;
+}