whiterose

linux unikernel
Log | Files | Refs | README | LICENSE | git clone https://git.ne02ptzero.me/git/whiterose

commit 28e8c4bc8eb483c22d977e147a0b98fc63efadf7
parent c9bef4a651769927445900564781a9c99fdf6258
Author: Linus Torvalds <torvalds@linux-foundation.org>
Date:   Tue,  1 Jan 2019 13:24:31 -0800

Merge tag 'rtc-4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux

Pull RTC updates from Alexandre Belloni:
 "Subsystem:
   - new %ptR printk format
   - rename core files
   - allow registration of multiple nvmem devices

  New driver:
   - i.MX system controller RTC

  Driver updates:
   - abx80x: handle voltage ioctls, correct binding doc
   - m41t80: correct month in alarm reads
   - pcf85363: add pcf85263 support
   - pcf8523: properly handle battery low flag
   - s3c: limit alarm to one year in the future as ALMYEAR is broken
   - sun6i: rework clock output binding"

* tag 'rtc-4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (54 commits)
  rtc: rename core files
  rtc: nvmem: fix possible use after free
  rtc: add i.MX system controller RTC support
  dt-bindings: fsl: scu: add rtc binding
  rtc: pcf2123: Add Microcrystal rv2123
  rtc: class: reimplement devm_rtc_device_register
  rtc: enforce rtc_timer_init private_data type
  rtc: abx80x: Implement RTC_VL_READ,CLR ioctls
  rtc: pcf85363: Add support for NXP pcf85263 rtc
  dt-bindings: rtc: pcf85363: Document pcf85263 real-time clock
  rtc: pcf8523: don't return invalid date when battery is low
  dt-bindings: rtc: use a generic node name for ds1307
  PM: Switch to use %ptR
  m68k/mac: Switch to use %ptR
  Input: hp_sdc_rtc - Switch to use %ptR
  rtc: tegra: Switch to use %ptR
  rtc: s5m: Switch to use %ptR
  rtc: s3c: Switch to use %ptR
  rtc: rx8025: Switch to use %ptR
  rtc: rx6110: Switch to use %ptR
  ...

Diffstat:
MDocumentation/core-api/printk-formats.rst | 18++++++++++++++++++
MDocumentation/devicetree/bindings/arm/freescale/fsl,scu.txt | 10++++++++++
MDocumentation/devicetree/bindings/rtc/abracon,abx80x.txt | 2+-
MDocumentation/devicetree/bindings/rtc/nxp,rtc-2123.txt | 1+
MDocumentation/devicetree/bindings/rtc/pcf85363.txt | 4++--
MDocumentation/devicetree/bindings/rtc/rtc-ds1307.txt | 2+-
MDocumentation/devicetree/bindings/rtc/sun6i-rtc.txt | 33++++++++++++++++++++++++++-------
March/m68k/mac/misc.c | 8++------
Mdrivers/base/power/trace.c | 4+---
Mdrivers/char/rtc.c | 7+++----
Mdrivers/input/misc/hp_sdc_rtc.c | 8+++-----
Mdrivers/rtc/Kconfig | 7+++++++
Mdrivers/rtc/Makefile | 9+++++----
Mdrivers/rtc/class.c | 187++++++++++++++++---------------------------------------------------------------
Rdrivers/rtc/rtc-dev.c -> drivers/rtc/dev.c | 0
Mdrivers/rtc/hctosys.c | 8++------
Mdrivers/rtc/interface.c | 27+++++++++++----------------
Rdrivers/rtc/rtc-lib.c -> drivers/rtc/lib.c | 0
Mdrivers/rtc/nvmem.c | 38+++++++++++++++-----------------------
Adrivers/rtc/proc.c | 95+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/rtc/rtc-abx80x.c | 38++++++++++++++++++++++++++++++++++++++
Mdrivers/rtc/rtc-at91rm9200.c | 15++++-----------
Mdrivers/rtc/rtc-at91sam9.c | 16++++------------
Mdrivers/rtc/rtc-ep93xx.c | 2+-
Adrivers/rtc/rtc-imx-sc.c | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdrivers/rtc/rtc-isl1208.c | 37++++---------------------------------
Mdrivers/rtc/rtc-m41t80.c | 21++++++++++-----------
Mdrivers/rtc/rtc-m48t59.c | 8++------
Mdrivers/rtc/rtc-max6916.c | 2+-
Mdrivers/rtc/rtc-max77686.c | 2+-
Mdrivers/rtc/rtc-max8997.c | 2+-
Mdrivers/rtc/rtc-mcp795.c | 18++++++------------
Mdrivers/rtc/rtc-omap.c | 4+---
Mdrivers/rtc/rtc-pcf2123.c | 1+
Mdrivers/rtc/rtc-pcf50633.c | 8++------
Mdrivers/rtc/rtc-pcf8523.c | 32++++++++++++++++++++++++--------
Mdrivers/rtc/rtc-pcf85363.c | 94++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------
Mdrivers/rtc/rtc-pic32.c | 18++++--------------
Mdrivers/rtc/rtc-pm8xxx.c | 16+++++-----------
Ddrivers/rtc/rtc-proc.c | 121-------------------------------------------------------------------------------
Mdrivers/rtc/rtc-puv3.c | 18++++--------------
Mdrivers/rtc/rtc-rk808.c | 22+++++++---------------
Mdrivers/rtc/rtc-rx6110.c | 12+++---------
Mdrivers/rtc/rtc-rx8025.c | 19++++---------------
Mdrivers/rtc/rtc-s3c.c | 26++++----------------------
Mdrivers/rtc/rtc-s5m.c | 27++++++---------------------
Mdrivers/rtc/rtc-sh.c | 7++-----
Mdrivers/rtc/rtc-sun6i.c | 121+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
Ddrivers/rtc/rtc-sysfs.c | 362-------------------------------------------------------------------------------
Mdrivers/rtc/rtc-tegra.c | 30+++---------------------------
Adrivers/rtc/sysfs.c | 358+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Minclude/linux/rtc.h | 17++++++++---------
Mlib/test_printf.c | 61++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mlib/vsprintf.c | 100+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
54 files changed, 1186 insertions(+), 1008 deletions(-)

diff --git a/Documentation/core-api/printk-formats.rst b/Documentation/core-api/printk-formats.rst @@ -412,6 +412,24 @@ Examples:: Passed by reference. +Time and date (struct rtc_time) +------------------------------- + +:: + + %ptR YYYY-mm-ddTHH:MM:SS + %ptRd YYYY-mm-dd + %ptRt HH:MM:SS + %ptR[dt][r] + +For printing date and time as represented by struct rtc_time structure in +human readable format. + +By default year will be incremented by 1900 and month by 1. Use %ptRr (raw) +to suppress this behaviour. + +Passed by reference. + struct clk ---------- diff --git a/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt b/Documentation/devicetree/bindings/arm/freescale/fsl,scu.txt @@ -109,6 +109,12 @@ Required properties for Pinctrl sub nodes: [2] Documentation/devicetree/bindings/power/power_domain.txt [3] Documentation/devicetree/bindings/pinctrl/fsl,imx-pinctrl.txt +RTC bindings based on SCU Message Protocol +------------------------------------------------------------ + +Required properties: +- compatible: should be "fsl,imx8qxp-sc-rtc"; + Example (imx8qxp): ------------- lsio_mu1: mailbox@5d1c0000 { @@ -151,6 +157,10 @@ firmware { compatible = "fsl,imx8qxp-scu-pd"; #power-domain-cells = <1>; }; + + rtc: rtc { + compatible = "fsl,imx8qxp-sc-rtc"; + }; }; }; diff --git a/Documentation/devicetree/bindings/rtc/abracon,abx80x.txt b/Documentation/devicetree/bindings/rtc/abracon,abx80x.txt @@ -27,4 +27,4 @@ and valid to enable charging: - "abracon,tc-diode": should be "standard" (0.6V) or "schottky" (0.3V) - "abracon,tc-resistor": should be <0>, <3>, <6> or <11>. 0 disables the output - resistor, the other values are in ohm. + resistor, the other values are in kOhm. diff --git a/Documentation/devicetree/bindings/rtc/nxp,rtc-2123.txt b/Documentation/devicetree/bindings/rtc/nxp,rtc-2123.txt @@ -2,6 +2,7 @@ NXP PCF2123 SPI Real Time Clock Required properties: - compatible: should be: "nxp,rtc-pcf2123" + or "microcrystal,rv2123" - reg: should be the SPI slave chipselect address Optional properties: diff --git a/Documentation/devicetree/bindings/rtc/pcf85363.txt b/Documentation/devicetree/bindings/rtc/pcf85363.txt @@ -1,8 +1,8 @@ -NXP PCF85363 Real Time Clock +NXP PCF85263/PCF85363 Real Time Clock ============================ Required properties: -- compatible: Should contain "nxp,pcf85363". +- compatible: Should contain "nxp,pcf85263" or "nxp,pcf85363". - reg: I2C address for chip. Optional properties: diff --git a/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt b/Documentation/devicetree/bindings/rtc/rtc-ds1307.txt @@ -35,7 +35,7 @@ Optional properties: Should be given if internal trickle charger diode should be disabled Example: - rtc1: ds1339@68 { + ds1339: rtc@68 { compatible = "dallas,ds1339"; reg = <0x68>; interrupt-parent = <&gpio4>; diff --git a/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt b/Documentation/devicetree/bindings/rtc/sun6i-rtc.txt @@ -3,25 +3,44 @@ RTC controller for the Allwinner A31 Required properties: -- compatible : Should be "allwinner,sun6i-a31-rtc" +- compatible : Should be one of the following combinations: + - "allwinner,sun6i-a31-rtc" + - "allwinner,sun8i-a23-rtc" + - "allwinner,sun8i-h3-rtc" + - "allwinner,sun8i-r40-rtc", "allwinner,sun8i-h3-rtc" + - "allwinner,sun8i-v3-rtc" + - "allwinner,sun50i-a64-rtc", "allwinner,sun8i-h3-rtc" + - "allwinner,sun50i-h5-rtc" + + Where there are two or more compatible strings, this + denotes the hardware covered by the most specific one + is backward-compatible with the latter ones, and the + implementation for the latter ones can be used, albeit + with reduced functionality. + - reg : physical base address of the controller and length of memory mapped region. - interrupts : IRQ lines for the RTC alarm 0 and alarm 1, in that order. Required properties for new device trees - clocks : phandle to the 32kHz external oscillator -- clock-output-names : names of the LOSC and its external output clocks created -- #clock-cells : must be equals to 1. The RTC provides two clocks: the - LOSC and its external output, with index 0 and 1 - respectively. +- clock-output-names : names of up to three clock outputs. See below. +- #clock-cells : must be equal to 1. + +The RTC provides the following clocks at the given indices: +- 0: LOSC +- 1: LOSC external output, known as X32KFOUT in the datasheet. + This clock is not available on the A31 and is deprecated for old + device trees still using the "allwinner,sun6i-a31-rtc" compatible. +- 2: InternalOSC, or internal RC oscillator (A64/H3/H5 only) Example: rtc: rtc@1f00000 { compatible = "allwinner,sun6i-a31-rtc"; - reg = <0x01f00000 0x54>; + reg = <0x01f00000 0x400>; interrupts = <0 40 4>, <0 41 4>; - clock-output-names = "osc32k", "osc32k-out"; + clock-output-names = "osc32k"; clocks = <&ext_osc32k>; #clock-cells = <1>; }; diff --git a/arch/m68k/mac/misc.c b/arch/m68k/mac/misc.c @@ -605,13 +605,9 @@ int mac_hwclk(int op, struct rtc_time *t) unmktime(now, 0, &t->tm_year, &t->tm_mon, &t->tm_mday, &t->tm_hour, &t->tm_min, &t->tm_sec); - pr_debug("%s: read %04d-%02d-%-2d %02d:%02d:%02d\n", - __func__, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, - t->tm_hour, t->tm_min, t->tm_sec); + pr_debug("%s: read %ptR\n", __func__, t); } else { /* write */ - pr_debug("%s: tried to write %04d-%02d-%-2d %02d:%02d:%02d\n", - __func__, t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, - t->tm_hour, t->tm_min, t->tm_sec); + pr_debug("%s: tried to write %ptR\n", __func__, t); switch (macintosh_config->adb_type) { case MAC_ADB_IOP: diff --git a/drivers/base/power/trace.c b/drivers/base/power/trace.c @@ -118,9 +118,7 @@ static unsigned int read_magic_time(void) unsigned int val; mc146818_get_time(&time); - pr_info("RTC time: %2d:%02d:%02d, date: %02d/%02d/%02d\n", - time.tm_hour, time.tm_min, time.tm_sec, - time.tm_mon + 1, time.tm_mday, time.tm_year % 100); + pr_info("RTC time: %ptRt, date: %ptRd\n", &time, &time); val = time.tm_year; /* 100 years */ if (val > 100) val -= 100; diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c @@ -1125,11 +1125,10 @@ static int rtc_proc_show(struct seq_file *seq, void *v) * time or for Universal Standard Time (GMT). Probably local though. */ seq_printf(seq, - "rtc_time\t: %02d:%02d:%02d\n" - "rtc_date\t: %04d-%02d-%02d\n" + "rtc_time\t: %ptRt\n" + "rtc_date\t: %ptRd\n" "rtc_epoch\t: %04lu\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); + &tm, &tm, epoch); get_rtc_alm_time(&tm); diff --git a/drivers/input/misc/hp_sdc_rtc.c b/drivers/input/misc/hp_sdc_rtc.c @@ -441,12 +441,10 @@ static int hp_sdc_rtc_proc_show(struct seq_file *m, void *v) seq_puts(m, "BBRTC\t\t: READ FAILED!\n"); } else { seq_printf(m, - "rtc_time\t: %02d:%02d:%02d\n" - "rtc_date\t: %04d-%02d-%02d\n" + "rtc_time\t: %ptRt\n" + "rtc_date\t: %ptRd\n" "rtc_epoch\t: %04lu\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, - tm.tm_year + 1900, tm.tm_mon + 1, - tm.tm_mday, epoch); + &tm, &tm, epoch); } if (hp_sdc_rtc_read_rt(&tv)) { diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig @@ -1677,6 +1677,13 @@ config RTC_DRV_SNVS This driver can also be built as a module, if so, the module will be called "rtc-snvs". +config RTC_DRV_IMX_SC + depends on IMX_SCU + tristate "NXP i.MX System Controller RTC support" + help + If you say yes here you get support for the NXP i.MX System + Controller RTC module. + config RTC_DRV_SIRFSOC tristate "SiRFSOC RTC" depends on ARCH_SIRF diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile @@ -5,7 +5,7 @@ ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG -obj-$(CONFIG_RTC_LIB) += rtc-lib.o +obj-$(CONFIG_RTC_LIB) += lib.o obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o obj-$(CONFIG_RTC_SYSTOHC) += systohc.o obj-$(CONFIG_RTC_CLASS) += rtc-core.o @@ -17,9 +17,9 @@ 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 +rtc-core-$(CONFIG_RTC_INTF_DEV) += dev.o +rtc-core-$(CONFIG_RTC_INTF_PROC) += proc.o +rtc-core-$(CONFIG_RTC_INTF_SYSFS) += sysfs.o # Keep the list ordered. @@ -75,6 +75,7 @@ obj-$(CONFIG_RTC_DRV_GOLDFISH) += rtc-goldfish.o obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o obj-$(CONFIG_RTC_DRV_HYM8563) += rtc-hym8563.o obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o +obj-$(CONFIG_RTC_DRV_IMX_SC) += rtc-imx-sc.o obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o obj-$(CONFIG_RTC_DRV_ISL12026) += rtc-isl12026.o obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c @@ -178,9 +178,9 @@ static struct rtc_device *rtc_allocate_device(void) timerqueue_init_head(&rtc->timerqueue); INIT_WORK(&rtc->irqwork, rtc_timer_do_work); /* Init aie timer */ - rtc_timer_init(&rtc->aie_timer, rtc_aie_update_irq, (void *)rtc); + rtc_timer_init(&rtc->aie_timer, rtc_aie_update_irq, rtc); /* Init uie timer */ - rtc_timer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, (void *)rtc); + rtc_timer_init(&rtc->uie_rtctimer, rtc_uie_update_irq, rtc); /* Init pie timer */ hrtimer_init(&rtc->pie_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); rtc->pie_timer.function = rtc_pie_update_irq; @@ -278,82 +278,6 @@ static void rtc_device_get_offset(struct rtc_device *rtc) } /** - * 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. - */ -static 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); - - rtc_device_get_offset(rtc); - - /* 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, "%s: failed to add char device %d:%d\n", - 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", name, - MAJOR(rtc->dev.devt), rtc->id); - } - - rtc_proc_add_device(rtc); - - dev_info(dev, "rtc core: registered %s as %s\n", - name, dev_name(&rtc->dev)); - - return rtc; - -exit_ida: - ida_simple_remove(&rtc_ida, id); - -exit: - dev_err(dev, "rtc core: unable to register %s, err = %d\n", - name, err); - return ERR_PTR(err); -} - -/** * rtc_device_unregister - removes the previously registered RTC class device * * @rtc: the RTC class device to destroy @@ -372,77 +296,6 @@ static void rtc_device_unregister(struct rtc_device *rtc) put_device(&rtc->dev); } -static void devm_rtc_device_release(struct device *dev, void *res) -{ - struct rtc_device *rtc = *(struct rtc_device **)res; - - rtc_nvmem_unregister(rtc); - rtc_device_unregister(rtc); -} - -static int devm_rtc_device_match(struct device *dev, void *res, void *data) -{ - struct rtc **r = res; - - return *r == data; -} - -/** - * devm_rtc_device_register - resource managed rtc_device_register() - * @dev: the device to register - * @name: the name of the device - * @ops: the rtc operations structure - * @owner: the module owner - * - * @return a struct rtc on success, or an ERR_PTR on error - * - * Managed rtc_device_register(). The rtc_device returned from this function - * are automatically freed on driver detach. See rtc_device_register() - * for more information. - */ - -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 **ptr, *rtc; - - ptr = devres_alloc(devm_rtc_device_release, sizeof(*ptr), GFP_KERNEL); - if (!ptr) - return ERR_PTR(-ENOMEM); - - rtc = rtc_device_register(name, dev, ops, owner); - if (!IS_ERR(rtc)) { - *ptr = rtc; - devres_add(dev, ptr); - } else { - devres_free(ptr); - } - - return rtc; -} -EXPORT_SYMBOL_GPL(devm_rtc_device_register); - -/** - * devm_rtc_device_unregister - resource managed devm_rtc_device_unregister() - * @dev: the device to unregister - * @rtc: the RTC class device to unregister - * - * Deallocated a rtc allocated with devm_rtc_device_register(). Normally this - * function will not need to be called and the resource management code will - * ensure that the resource is freed. - */ -void devm_rtc_device_unregister(struct device *dev, struct rtc_device *rtc) -{ - int rc; - - rc = devres_release(dev, devm_rtc_device_release, - devm_rtc_device_match, rtc); - WARN_ON(rc); -} -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; @@ -529,6 +382,42 @@ int __rtc_register_device(struct module *owner, struct rtc_device *rtc) } EXPORT_SYMBOL_GPL(__rtc_register_device); +/** + * devm_rtc_device_register - resource managed rtc_device_register() + * @dev: the device to register + * @name: the name of the device (unused) + * @ops: the rtc operations structure + * @owner: the module owner + * + * @return a struct rtc on success, or an ERR_PTR on error + * + * Managed rtc_device_register(). The rtc_device returned from this function + * are automatically freed on driver detach. + * This function is deprecated, use devm_rtc_allocate_device and + * rtc_register_device instead + */ +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 *rtc; + int err; + + rtc = devm_rtc_allocate_device(dev); + if (IS_ERR(rtc)) + return rtc; + + rtc->ops = ops; + + err = __rtc_register_device(owner, rtc); + if (err) + return ERR_PTR(err); + + return rtc; +} +EXPORT_SYMBOL_GPL(devm_rtc_device_register); + static int __init rtc_init(void) { rtc_class = class_create(THIS_MODULE, "rtc"); diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/dev.c diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c @@ -58,12 +58,8 @@ static int __init rtc_hctosys(void) err = do_settimeofday64(&tv64); - dev_info(rtc->dev.parent, - "setting system clock to " - "%d-%02d-%02d %02d:%02d:%02d UTC (%lld)\n", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, - (long long) tv64.tv_sec); + dev_info(rtc->dev.parent, "setting system clock to %ptR UTC (%lld)\n", + &tm, (long long)tv64.tv_sec); err_read: rtc_class_close(rtc); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c @@ -368,12 +368,8 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) 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, - alarm->time.tm_mday, alarm->time.tm_hour, alarm->time.tm_min, - alarm->time.tm_sec); - } + if (err) + dev_warn(&rtc->dev, "invalid alarm value: %ptR\n", &alarm->time); return err; } @@ -613,26 +609,24 @@ void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode) /** * rtc_aie_update_irq - AIE mode rtctimer hook - * @private: pointer to the rtc_device + * @rtc: pointer to the rtc_device * * This functions is called when the aie_timer expires. */ -void rtc_aie_update_irq(void *private) +void rtc_aie_update_irq(struct rtc_device *rtc) { - struct rtc_device *rtc = (struct rtc_device *)private; rtc_handle_legacy_irq(rtc, 1, RTC_AF); } /** * rtc_uie_update_irq - UIE mode rtctimer hook - * @private: pointer to the rtc_device + * @rtc: pointer to the rtc_device * * This functions is called when the uie_timer expires. */ -void rtc_uie_update_irq(void *private) +void rtc_uie_update_irq(struct rtc_device *rtc) { - struct rtc_device *rtc = (struct rtc_device *)private; rtc_handle_legacy_irq(rtc, 1, RTC_UF); } @@ -912,7 +906,7 @@ again: trace_rtc_timer_dequeue(timer); timer->enabled = 0; if (timer->func) - timer->func(timer->private_data); + timer->func(timer->rtc); trace_rtc_timer_fired(timer); /* Re-add/fwd periodic timers */ @@ -959,16 +953,17 @@ reprogram: /* rtc_timer_init - Initializes an rtc_timer * @timer: timer to be intiialized * @f: function pointer to be called when timer fires - * @data: private data passed to function pointer + * @rtc: pointer to the rtc_device * * Kernel interface to initializing an rtc_timer. */ -void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data) +void rtc_timer_init(struct rtc_timer *timer, void (*f)(struct rtc_device *r), + struct rtc_device *rtc) { timerqueue_init(&timer->node); timer->enabled = 0; timer->func = f; - timer->private_data = data; + timer->rtc = rtc; } /* rtc_timer_start - Sets an rtc_timer to fire in the future diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/lib.c diff --git a/drivers/rtc/nvmem.c b/drivers/rtc/nvmem.c @@ -12,6 +12,7 @@ #include <linux/types.h> #include <linux/nvmem-consumer.h> #include <linux/rtc.h> +#include <linux/slab.h> #include <linux/sysfs.h> /* @@ -25,11 +26,9 @@ 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); + return nvmem_device_read(attr->private, off, count, buf); } static ssize_t @@ -37,26 +36,23 @@ 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); + return nvmem_device_write(attr->private, off, count, buf); } -static int rtc_nvram_register(struct rtc_device *rtc, size_t size) +static int rtc_nvram_register(struct rtc_device *rtc, + struct nvmem_device *nvmem, size_t size) { int err; - rtc->nvram = devm_kzalloc(rtc->dev.parent, - sizeof(struct bin_attribute), - GFP_KERNEL); + rtc->nvram = kzalloc(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; + rtc->nvram->private = nvmem; sysfs_bin_attr_init(rtc->nvram); @@ -67,7 +63,7 @@ static int rtc_nvram_register(struct rtc_device *rtc, size_t size) err = sysfs_create_bin_file(&rtc->dev.parent->kobj, rtc->nvram); if (err) { - devm_kfree(rtc->dev.parent, rtc->nvram); + kfree(rtc->nvram); rtc->nvram = NULL; } @@ -77,6 +73,8 @@ static int rtc_nvram_register(struct rtc_device *rtc, size_t size) static void rtc_nvram_unregister(struct rtc_device *rtc) { sysfs_remove_bin_file(&rtc->dev.parent->kobj, rtc->nvram); + kfree(rtc->nvram); + rtc->nvram = NULL; } /* @@ -85,21 +83,20 @@ static void rtc_nvram_unregister(struct rtc_device *rtc) int rtc_nvmem_register(struct rtc_device *rtc, struct nvmem_config *nvmem_config) { - if (!IS_ERR_OR_NULL(rtc->nvmem)) - return -EBUSY; + struct nvmem_device *nvmem; if (!nvmem_config) return -ENODEV; nvmem_config->dev = rtc->dev.parent; nvmem_config->owner = rtc->owner; - rtc->nvmem = nvmem_register(nvmem_config); - if (IS_ERR(rtc->nvmem)) - return PTR_ERR(rtc->nvmem); + nvmem = devm_nvmem_register(rtc->dev.parent, nvmem_config); + if (IS_ERR(nvmem)) + return PTR_ERR(nvmem); /* Register the old ABI */ if (rtc->nvram_old_abi) - rtc_nvram_register(rtc, nvmem_config->size); + rtc_nvram_register(rtc, nvmem, nvmem_config->size); return 0; } @@ -107,12 +104,7 @@ EXPORT_SYMBOL_GPL(rtc_nvmem_register); 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); } diff --git a/drivers/rtc/proc.c b/drivers/rtc/proc.c @@ -0,0 +1,95 @@ +/* + * RTC subsystem, proc interface + * + * Copyright (C) 2005-06 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * based on arch/arm/common/rtctime.c + * + * 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/module.h> +#include <linux/rtc.h> +#include <linux/proc_fs.h> +#include <linux/seq_file.h> + +#include "rtc-core.h" + +#define NAME_SIZE 10 + +#if defined(CONFIG_RTC_HCTOSYS_DEVICE) +static bool is_rtc_hctosys(struct rtc_device *rtc) +{ + int size; + char name[NAME_SIZE]; + + size = scnprintf(name, NAME_SIZE, "rtc%d", rtc->id); + if (size > NAME_SIZE) + return false; + + return !strncmp(name, CONFIG_RTC_HCTOSYS_DEVICE, NAME_SIZE); +} +#else +static bool is_rtc_hctosys(struct rtc_device *rtc) +{ + return (rtc->id == 0); +} +#endif + +static int rtc_proc_show(struct seq_file *seq, void *offset) +{ + int err; + struct rtc_device *rtc = seq->private; + const struct rtc_class_ops *ops = rtc->ops; + struct rtc_wkalrm alrm; + struct rtc_time tm; + + err = rtc_read_time(rtc, &tm); + if (err == 0) { + seq_printf(seq, + "rtc_time\t: %ptRt\n" + "rtc_date\t: %ptRd\n", + &tm, &tm); + } + + err = rtc_read_alarm(rtc, &alrm); + if (err == 0) { + seq_printf(seq, "alrm_time\t: %ptRt\n", &alrm.time); + seq_printf(seq, "alrm_date\t: %ptRd\n", &alrm.time); + seq_printf(seq, "alarm_IRQ\t: %s\n", + alrm.enabled ? "yes" : "no"); + seq_printf(seq, "alrm_pending\t: %s\n", + alrm.pending ? "yes" : "no"); + seq_printf(seq, "update IRQ enabled\t: %s\n", + (rtc->uie_rtctimer.enabled) ? "yes" : "no"); + seq_printf(seq, "periodic IRQ enabled\t: %s\n", + (rtc->pie_enabled) ? "yes" : "no"); + seq_printf(seq, "periodic IRQ frequency\t: %d\n", + rtc->irq_freq); + seq_printf(seq, "max user IRQ frequency\t: %d\n", + rtc->max_user_freq); + } + + seq_printf(seq, "24hr\t\t: yes\n"); + + if (ops->proc) + ops->proc(rtc->dev.parent, seq); + + return 0; +} + +void rtc_proc_add_device(struct rtc_device *rtc) +{ + if (is_rtc_hctosys(rtc)) + proc_create_single_data("driver/rtc", 0, NULL, rtc_proc_show, + rtc); +} + +void rtc_proc_del_device(struct rtc_device *rtc) +{ + if (is_rtc_hctosys(rtc)) + remove_proc_entry("driver/rtc", NULL); +} diff --git a/drivers/rtc/rtc-abx80x.c b/drivers/rtc/rtc-abx80x.c @@ -38,6 +38,7 @@ #define ABX8XX_REG_STATUS 0x0f #define ABX8XX_STATUS_AF BIT(2) +#define ABX8XX_STATUS_BLF BIT(4) #define ABX8XX_STATUS_WDT BIT(6) #define ABX8XX_REG_CTRL1 0x10 @@ -507,12 +508,49 @@ static int abx80x_alarm_irq_enable(struct device *dev, unsigned int enabled) return err; } +static int abx80x_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + struct i2c_client *client = to_i2c_client(dev); + int status, tmp; + + switch (cmd) { + case RTC_VL_READ: + status = i2c_smbus_read_byte_data(client, ABX8XX_REG_STATUS); + if (status < 0) + return status; + + tmp = !!(status & ABX8XX_STATUS_BLF); + + if (copy_to_user((void __user *)arg, &tmp, sizeof(int))) + return -EFAULT; + + return 0; + + case RTC_VL_CLR: + status = i2c_smbus_read_byte_data(client, ABX8XX_REG_STATUS); + if (status < 0) + return status; + + status &= ~ABX8XX_STATUS_BLF; + + tmp = i2c_smbus_write_byte_data(client, ABX8XX_REG_STATUS, 0); + if (tmp < 0) + return tmp; + + return 0; + + default: + return -ENOIOCTLCMD; + } +} + static const struct rtc_class_ops abx80x_rtc_ops = { .read_time = abx80x_rtc_read_time, .set_time = abx80x_rtc_set_time, .read_alarm = abx80x_read_alarm, .set_alarm = abx80x_set_alarm, .alarm_irq_enable = abx80x_alarm_irq_enable, + .ioctl = abx80x_ioctl, }; static int abx80x_dt_trickle_cfg(struct device_node *np) diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c @@ -147,9 +147,7 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm) tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year); tm->tm_year = tm->tm_year - 1900; - dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "%s(): %ptR\n", __func__, tm); return 0; } @@ -161,9 +159,7 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) { unsigned long cr; - dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "%s(): %ptR\n", __func__, tm); wait_for_completion(&at91_rtc_upd_rdy); @@ -209,8 +205,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = (at91_rtc_read_imr() & AT91_RTC_ALARM) ? 1 : 0; - dev_dbg(dev, "%s(): %02d-%02d %02d:%02d:%02d %sabled\n", __func__, - tm->tm_mon, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, + dev_dbg(dev, "%s(): %ptR %sabled\n", __func__, tm, alrm->enabled ? "en" : "dis"); return 0; @@ -247,9 +242,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) at91_rtc_write_ier(AT91_RTC_ALARM); } - dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__, - tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, - tm.tm_min, tm.tm_sec); + dev_dbg(dev, "%s(): %ptR\n", __func__, &tm); return 0; } diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c @@ -124,9 +124,7 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm) rtc_time_to_tm(offset + secs, tm); - dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readtime", - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "%s: %ptR\n", __func__, tm); return 0; } @@ -141,9 +139,7 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm) u32 offset, alarm, mr; unsigned long secs; - dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "settime", - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "%s: %ptR\n", __func__, tm); err = rtc_tm_to_time(tm, &secs); if (err != 0) @@ -199,9 +195,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) if (alarm != ALARM_DISABLED && offset != 0) { rtc_time_to_tm(offset + alarm, tm); - dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "readalarm", - 1900 + tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "%s: %ptR\n", __func__, tm); if (rtt_readl(rtc, MR) & AT91_RTT_ALMIEN) alrm->enabled = 1; @@ -242,9 +236,7 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) if (alrm->enabled) rtt_writel(rtc, MR, mr | AT91_RTT_ALMIEN); - dev_dbg(dev, "%s: %4d-%02d-%02d %02d:%02d:%02d\n", "setalarm", - tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour, - tm->tm_min, tm->tm_sec); + dev_dbg(dev, "%s: %ptR\n", __func__, tm); return 0; } diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c @@ -61,7 +61,7 @@ static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm) struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev); unsigned long time; - time = readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA); + time = readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA); rtc_time_to_tm(time, tm); return 0; diff --git a/drivers/rtc/rtc-imx-sc.c b/drivers/rtc/rtc-imx-sc.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright 2018 NXP. + */ + +#include <linux/firmware/imx/sci.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> + +#define IMX_SC_TIMER_FUNC_GET_RTC_SEC1970 9 +#define IMX_SC_TIMER_FUNC_SET_RTC_TIME 6 + +static struct imx_sc_ipc *rtc_ipc_handle; +static struct rtc_device *imx_sc_rtc; + +struct imx_sc_msg_timer_get_rtc_time { + struct imx_sc_rpc_msg hdr; + u32 time; +} __packed; + +static int imx_sc_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ + struct imx_sc_msg_timer_get_rtc_time msg; + struct imx_sc_rpc_msg *hdr = &msg.hdr; + int ret; + + hdr->ver = IMX_SC_RPC_VERSION; + hdr->svc = IMX_SC_RPC_SVC_TIMER; + hdr->func = IMX_SC_TIMER_FUNC_GET_RTC_SEC1970; + hdr->size = 1; + + ret = imx_scu_call_rpc(rtc_ipc_handle, &msg, true); + if (ret) { + dev_err(dev, "read rtc time failed, ret %d\n", ret); + return ret; + } + + rtc_time_to_tm(msg.time, tm); + + return 0; +} + +static const struct rtc_class_ops imx_sc_rtc_ops = { + .read_time = imx_sc_rtc_read_time, +}; + +static int imx_sc_rtc_probe(struct platform_device *pdev) +{ + int ret; + + ret = imx_scu_get_handle(&rtc_ipc_handle); + if (ret) + return ret; + + imx_sc_rtc = devm_rtc_allocate_device(&pdev->dev); + if (IS_ERR(imx_sc_rtc)) + return PTR_ERR(imx_sc_rtc); + + imx_sc_rtc->ops = &imx_sc_rtc_ops; + imx_sc_rtc->range_min = 0; + imx_sc_rtc->range_max = U32_MAX; + + ret = rtc_register_device(imx_sc_rtc); + if (ret) { + dev_err(&pdev->dev, "failed to register rtc: %d\n", ret); + return ret; + } + + return 0; +} + +static const struct of_device_id imx_sc_dt_ids[] = { + { .compatible = "fsl,imx8qxp-sc-rtc", }, + {} +}; +MODULE_DEVICE_TABLE(of, imx_sc_dt_ids); + +static struct platform_driver imx_sc_rtc_driver = { + .driver = { + .name = "imx-sc-rtc", + .of_match_table = imx_sc_dt_ids, + }, + .probe = imx_sc_rtc_probe, +}; +module_platform_driver(imx_sc_rtc_driver); + +MODULE_AUTHOR("Anson Huang <Anson.Huang@nxp.com>"); +MODULE_DESCRIPTION("NXP i.MX System Controller RTC Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c @@ -84,29 +84,13 @@ static int isl1208_i2c_read_regs(struct i2c_client *client, u8 reg, u8 buf[], unsigned len) { - u8 reg_addr[1] = { reg }; - struct i2c_msg msgs[2] = { - { - .addr = client->addr, - .len = sizeof(reg_addr), - .buf = reg_addr - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = len, - .buf = buf - } - }; int ret; WARN_ON(reg > ISL1219_REG_YRT); WARN_ON(reg + len > ISL1219_REG_YRT + 1); - ret = i2c_transfer(client->adapter, msgs, 2); - if (ret > 0) - ret = 0; - return ret; + ret = i2c_smbus_read_i2c_block_data(client, reg, len, buf); + return (ret < 0) ? ret : 0; } /* block write */ @@ -114,26 +98,13 @@ static int isl1208_i2c_set_regs(struct i2c_client *client, u8 reg, u8 const buf[], unsigned len) { - u8 i2c_buf[ISL1208_REG_USR2 + 2]; - struct i2c_msg msgs[1] = { - { - .addr = client->addr, - .len = len + 1, - .buf = i2c_buf - } - }; int ret; WARN_ON(reg > ISL1219_REG_YRT); WARN_ON(reg + len > ISL1219_REG_YRT + 1); - i2c_buf[0] = reg; - memcpy(&i2c_buf[1], &buf[0], len); - - ret = i2c_transfer(client->adapter, msgs, 1); - if (ret > 0) - ret = 0; - return ret; + ret = i2c_smbus_write_i2c_block_data(client, reg, len, buf); + return (ret < 0) ? ret : 0; } /* simple check to see whether we have a isl1208 */ diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c @@ -217,7 +217,7 @@ static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm) sizeof(buf), buf); if (err < 0) { dev_err(&client->dev, "Unable to read date\n"); - return -EIO; + return err; } tm->tm_sec = bcd2bin(buf[M41T80_REG_SEC] & 0x7f); @@ -274,10 +274,11 @@ static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm) if (flags < 0) return flags; - if (i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS, - flags & ~M41T80_FLAGS_OF)) { + err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS, + flags & ~M41T80_FLAGS_OF); + if (err < 0) { dev_err(&client->dev, "Unable to write flags register\n"); - return -EIO; + return err; } return err; @@ -287,10 +288,12 @@ static int m41t80_rtc_proc(struct device *dev, struct seq_file *seq) { struct i2c_client *client = to_i2c_client(dev); struct m41t80_data *clientdata = i2c_get_clientdata(client); - u8 reg; + int reg; if (clientdata->features & M41T80_FEATURE_BL) { reg = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS); + if (reg < 0) + return reg; seq_printf(seq, "battery\t\t: %s\n", (reg & M41T80_FLAGS_BATT_LOW) ? "exhausted" : "ok"); } @@ -393,7 +396,7 @@ static int m41t80_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->time.tm_min = bcd2bin(alarmvals[3] & 0x7f); alrm->time.tm_hour = bcd2bin(alarmvals[2] & 0x3f); alrm->time.tm_mday = bcd2bin(alarmvals[1] & 0x3f); - alrm->time.tm_mon = bcd2bin(alarmvals[0] & 0x3f); + alrm->time.tm_mon = bcd2bin(alarmvals[0] & 0x3f) - 1; alrm->enabled = !!(alarmvals[0] & M41T80_ALMON_AFE); alrm->pending = (flags & M41T80_FLAGS_AF) && alrm->enabled; @@ -939,11 +942,7 @@ static int m41t80_probe(struct i2c_client *client, if (m41t80_data->features & M41T80_FEATURE_HT) { m41t80_rtc_read_time(&client->dev, &tm); dev_info(&client->dev, "HT bit was set!\n"); - dev_info(&client->dev, - "Power Down at %04i-%02i-%02i %02i:%02i:%02i\n", - tm.tm_year + 1900, - tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, - tm.tm_min, tm.tm_sec); + dev_info(&client->dev, "Power Down at %ptR\n", &tm); } rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_HOUR, rc & ~M41T80_ALHOUR_HT); diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c @@ -99,9 +99,7 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm) M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL); spin_unlock_irqrestore(&m48t59->lock, flags); - dev_dbg(dev, "RTC read time %04d-%02d-%02d %02d/%02d/%02d\n", - tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "RTC read time %ptR\n", tm); return 0; } @@ -188,9 +186,7 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) M48T59_CLEAR_BITS(M48T59_CNTL_READ, M48T59_CNTL); spin_unlock_irqrestore(&m48t59->lock, flags); - dev_dbg(dev, "RTC read alarm time %04d-%02d-%02d %02d/%02d/%02d\n", - tm->tm_year + 1900, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "RTC read alarm time %ptR\n", tm); return rtc_valid_tm(tm); } diff --git a/drivers/rtc/rtc-max6916.c b/drivers/rtc/rtc-max6916.c @@ -86,7 +86,7 @@ static int max6916_set_time(struct device *dev, struct rtc_time *dt) if (dt->tm_year < 100 || dt->tm_year > 199) { dev_err(&spi->dev, "Year must be between 2000 and 2099. It's %d.\n", dt->tm_year + 1900); - return -EINVAL; + return -EINVAL; } buf[0] = MAX6916_CLOCK_BURST & 0x7F; diff --git a/drivers/rtc/rtc-max77686.c b/drivers/rtc/rtc-max77686.c @@ -360,7 +360,7 @@ static int max77686_rtc_read_time(struct device *dev, struct rtc_time *tm) out: mutex_unlock(&info->lock); - return 0; + return ret; } static int max77686_rtc_set_time(struct device *dev, struct rtc_time *tm) diff --git a/drivers/rtc/rtc-max8997.c b/drivers/rtc/rtc-max8997.c @@ -215,7 +215,7 @@ static int max8997_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) out: mutex_unlock(&info->lock); - return 0; + return ret; } static int max8997_rtc_stop_alarm(struct max8997_rtc_info *info) diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c @@ -233,9 +233,7 @@ static int mcp795_set_time(struct device *dev, struct rtc_time *tim) if (ret) return ret; - dev_dbg(dev, "Set mcp795: %04d-%02d-%02d(%d) %02d:%02d:%02d\n", - tim->tm_year + 1900, tim->tm_mon, tim->tm_mday, - tim->tm_wday, tim->tm_hour, tim->tm_min, tim->tm_sec); + dev_dbg(dev, "Set mcp795: %ptR\n", tim); return 0; } @@ -258,9 +256,7 @@ static int mcp795_read_time(struct device *dev, struct rtc_time *tim) tim->tm_mon = bcd2bin(data[5] & 0x1F) - 1; tim->tm_year = bcd2bin(data[6]) + 100; /* Assume we are in 20xx */ - dev_dbg(dev, "Read from mcp795: %04d-%02d-%02d(%d) %02d:%02d:%02d\n", - tim->tm_year + 1900, tim->tm_mon, tim->tm_mday, - tim->tm_wday, tim->tm_hour, tim->tm_min, tim->tm_sec); + dev_dbg(dev, "Read from mcp795: %ptR\n", tim); return 0; } @@ -319,9 +315,8 @@ static int mcp795_set_alarm(struct device *dev, struct rtc_wkalrm *alm) return ret; dev_dbg(dev, "Alarm IRQ armed\n"); } - dev_dbg(dev, "Set alarm: %02d-%02d(%d) %02d:%02d:%02d\n", - alm->time.tm_mon, alm->time.tm_mday, alm->time.tm_wday, - alm->time.tm_hour, alm->time.tm_min, alm->time.tm_sec); + dev_dbg(dev, "Set alarm: %ptRdr(%d) %ptRt\n", + &alm->time, alm->time.tm_wday, &alm->time); return 0; } @@ -345,9 +340,8 @@ static int mcp795_read_alarm(struct device *dev, struct rtc_wkalrm *alm) alm->time.tm_isdst = -1; alm->time.tm_yday = -1; - dev_dbg(dev, "Read alarm: %02d-%02d(%d) %02d:%02d:%02d\n", - alm->time.tm_mon, alm->time.tm_mday, alm->time.tm_wday, - alm->time.tm_hour, alm->time.tm_min, alm->time.tm_sec); + dev_dbg(dev, "Read alarm: %ptRdr(%d) %ptRt\n", + &alm->time, alm->time.tm_wday, &alm->time); return 0; } diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c @@ -566,9 +566,7 @@ static const struct pinctrl_ops rtc_pinctrl_ops = { .dt_free_map = pinconf_generic_dt_free_map, }; -enum rtc_pin_config_param { - PIN_CONFIG_ACTIVE_HIGH = PIN_CONFIG_END + 1, -}; +#define PIN_CONFIG_ACTIVE_HIGH (PIN_CONFIG_END + 1) static const struct pinconf_generic_params rtc_params[] = { {"ti,active-high", PIN_CONFIG_ACTIVE_HIGH, 0}, diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c @@ -453,6 +453,7 @@ static int pcf2123_remove(struct spi_device *spi) #ifdef CONFIG_OF static const struct of_device_id pcf2123_dt_ids[] = { { .compatible = "nxp,rtc-pcf2123", }, + { .compatible = "microcrystal,rv2123", }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, pcf2123_dt_ids); diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c @@ -131,9 +131,7 @@ static int pcf50633_rtc_read_time(struct device *dev, struct rtc_time *tm) pcf2rtc_time(tm, &pcf_tm); - dev_dbg(dev, "RTC_TIME: %u.%u.%u %u:%u:%u\n", - tm->tm_mday, tm->tm_mon, tm->tm_year, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "RTC_TIME: %ptRr\n", tm); return 0; } @@ -146,9 +144,7 @@ static int pcf50633_rtc_set_time(struct device *dev, struct rtc_time *tm) rtc = dev_get_drvdata(dev); - dev_dbg(dev, "RTC_TIME: %u.%u.%u %u:%u:%u\n", - tm->tm_mday, tm->tm_mon, tm->tm_year, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "RTC_TIME: %ptRr\n", tm); rtc2pcf_time(&pcf_tm, tm); diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c @@ -85,6 +85,18 @@ static int pcf8523_write(struct i2c_client *client, u8 reg, u8 value) return 0; } +static int pcf8523_voltage_low(struct i2c_client *client) +{ + u8 value; + int err; + + err = pcf8523_read(client, REG_CONTROL3, &value); + if (err < 0) + return err; + + return !!(value & REG_CONTROL3_BLF); +} + static int pcf8523_select_capacitance(struct i2c_client *client, bool high) { u8 value; @@ -167,6 +179,14 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) struct i2c_msg msgs[2]; int err; + err = pcf8523_voltage_low(client); + if (err < 0) { + return err; + } else if (err > 0) { + dev_err(dev, "low voltage detected, time is unreliable\n"); + return -EINVAL; + } + msgs[0].addr = client->addr; msgs[0].flags = 0; msgs[0].len = 1; @@ -251,17 +271,13 @@ static int pcf8523_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) { struct i2c_client *client = to_i2c_client(dev); - u8 value; - int ret = 0, err; + int ret; switch (cmd) { case RTC_VL_READ: - err = pcf8523_read(client, REG_CONTROL3, &value); - if (err < 0) - return err; - - if (value & REG_CONTROL3_BLF) - ret = 1; + ret = pcf8523_voltage_low(client); + if (ret < 0) + return ret; if (copy_to_user((void __user *)arg, &ret, sizeof(int))) return -EFAULT; diff --git a/drivers/rtc/rtc-pcf85363.c b/drivers/rtc/rtc-pcf85363.c @@ -120,6 +120,11 @@ struct pcf85363 { struct regmap *regmap; }; +struct pcf85x63_config { + struct regmap_config regmap; + unsigned int num_nvram; +}; + static int pcf85363_rtc_read_time(struct device *dev, struct rtc_time *tm) { struct pcf85363 *pcf85363 = dev_get_drvdata(dev); @@ -311,25 +316,75 @@ static int pcf85363_nvram_write(void *priv, unsigned int offset, void *val, val, bytes); } -static const struct regmap_config regmap_config = { - .reg_bits = 8, - .val_bits = 8, - .max_register = 0x7f, +static int pcf85x63_nvram_read(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct pcf85363 *pcf85363 = priv; + unsigned int tmp_val; + int ret; + + ret = regmap_read(pcf85363->regmap, CTRL_RAMBYTE, &tmp_val); + (*(unsigned char *) val) = (unsigned char) tmp_val; + + return ret; +} + +static int pcf85x63_nvram_write(void *priv, unsigned int offset, void *val, + size_t bytes) +{ + struct pcf85363 *pcf85363 = priv; + unsigned char tmp_val; + + tmp_val = *((unsigned char *)val); + return regmap_write(pcf85363->regmap, CTRL_RAMBYTE, + (unsigned int)tmp_val); +} + +static const struct pcf85x63_config pcf_85263_config = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x2f, + }, + .num_nvram = 1 +}; + +static const struct pcf85x63_config pcf_85363_config = { + .regmap = { + .reg_bits = 8, + .val_bits = 8, + .max_register = 0x7f, + }, + .num_nvram = 2 }; static int pcf85363_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct pcf85363 *pcf85363; - struct nvmem_config nvmem_cfg = { - .name = "pcf85363-", - .word_size = 1, - .stride = 1, - .size = NVRAM_SIZE, - .reg_read = pcf85363_nvram_read, - .reg_write = pcf85363_nvram_write, + const struct pcf85x63_config *config = &pcf_85363_config; + const void *data = of_device_get_match_data(&client->dev); + static struct nvmem_config nvmem_cfg[] = { + { + .name = "pcf85x63-", + .word_size = 1, + .stride = 1, + .size = 1, + .reg_read = pcf85x63_nvram_read, + .reg_write = pcf85x63_nvram_write, + }, { + .name = "pcf85363-", + .word_size = 1, + .stride = 1, + .size = NVRAM_SIZE, + .reg_read = pcf85363_nvram_read, + .reg_write = pcf85363_nvram_write, + }, }; - int ret; + int ret, i; + + if (data) + config = data; if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) return -ENODEV; @@ -339,7 +394,7 @@ static int pcf85363_probe(struct i2c_client *client, if (!pcf85363) return -ENOMEM; - pcf85363->regmap = devm_regmap_init_i2c(client, &regmap_config); + pcf85363->regmap = devm_regmap_init_i2c(client, &config->regmap); if (IS_ERR(pcf85363->regmap)) { dev_err(&client->dev, "regmap allocation failed\n"); return PTR_ERR(pcf85363->regmap); @@ -370,15 +425,18 @@ static int pcf85363_probe(struct i2c_client *client, ret = rtc_register_device(pcf85363->rtc); - nvmem_cfg.priv = pcf85363; - rtc_nvmem_register(pcf85363->rtc, &nvmem_cfg); + for (i = 0; i < config->num_nvram; i++) { + nvmem_cfg[i].priv = pcf85363; + rtc_nvmem_register(pcf85363->rtc, &nvmem_cfg[i]); + } return ret; } static const struct of_device_id dev_ids[] = { - { .compatible = "nxp,pcf85363" }, - {} + { .compatible = "nxp,pcf85263", .data = &pcf_85263_config }, + { .compatible = "nxp,pcf85363", .data = &pcf_85363_config }, + { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, dev_ids); @@ -393,5 +451,5 @@ static struct i2c_driver pcf85363_driver = { module_i2c_driver(pcf85363_driver); MODULE_AUTHOR("Eric Nelson"); -MODULE_DESCRIPTION("pcf85363 I2C RTC driver"); +MODULE_DESCRIPTION("pcf85263/pcf85363 I2C RTC driver"); MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-pic32.c b/drivers/rtc/rtc-pic32.c @@ -170,9 +170,7 @@ static int pic32_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); + dev_dbg(dev, "read time %ptR\n", rtc_tm); clk_disable(pdata->clk); return 0; @@ -184,9 +182,7 @@ static int pic32_rtc_settime(struct device *dev, struct rtc_time *tm) void __iomem *base = pdata->reg_base; int year = tm->tm_year - 100; - 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); + dev_dbg(dev, "set time %ptR\n", tm); if (year < 0 || year >= 100) { dev_err(dev, "rtc only supports 100 years\n"); @@ -224,10 +220,7 @@ static int pic32_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = (alm_en & PIC32_RTCALRM_ALRMEN) ? 1 : 0; - dev_dbg(dev, "getalarm: %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); + dev_dbg(dev, "getalarm: %d, %ptR\n", alm_en, alm_tm); alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec); alm_tm->tm_min = bcd2bin(alm_tm->tm_min); @@ -247,10 +240,7 @@ static int pic32_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) void __iomem *base = pdata->reg_base; clk_enable(pdata->clk); - dev_dbg(dev, "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); + dev_dbg(dev, "setalarm: %d, %ptR\n", alrm->enabled, tm); writel(0x00, base + PIC32_ALRMTIME); writel(0x00, base + PIC32_ALRMDATE); diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c @@ -217,9 +217,7 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm) rtc_time_to_tm(secs, tm); - dev_dbg(dev, "secs = %lu, h:m:s == %d:%d:%d, d/m/y = %d/%d/%d\n", - secs, tm->tm_hour, tm->tm_min, tm->tm_sec, - tm->tm_mday, tm->tm_mon, tm->tm_year); + dev_dbg(dev, "secs = %lu, h:m:s == %ptRt, y-m-d = %ptRdr\n", secs, tm, tm); return 0; } @@ -264,10 +262,8 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) goto rtc_rw_fail; } - dev_dbg(dev, "Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n", - alarm->time.tm_hour, alarm->time.tm_min, - alarm->time.tm_sec, alarm->time.tm_mday, - alarm->time.tm_mon, alarm->time.tm_year); + dev_dbg(dev, "Alarm Set for h:m:s=%ptRt, y-m-d=%ptRdr\n", + &alarm->time, &alarm->time); rtc_rw_fail: spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); return rc; @@ -298,10 +294,8 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) return rc; } - dev_dbg(dev, "Alarm set for - h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n", - alarm->time.tm_hour, alarm->time.tm_min, - alarm->time.tm_sec, alarm->time.tm_mday, - alarm->time.tm_mon, alarm->time.tm_year); + dev_dbg(dev, "Alarm set for - h:m:s=%ptRt, y-m-d=%ptRdr\n", + &alarm->time, &alarm->time); return 0; } diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c @@ -1,121 +0,0 @@ -/* - * RTC subsystem, proc interface - * - * Copyright (C) 2005-06 Tower Technologies - * Author: Alessandro Zummo <a.zummo@towertech.it> - * - * based on arch/arm/common/rtctime.c - * - * 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/module.h> -#include <linux/rtc.h> -#include <linux/proc_fs.h> -#include <linux/seq_file.h> - -#include "rtc-core.h" - -#define NAME_SIZE 10 - -#if defined(CONFIG_RTC_HCTOSYS_DEVICE) -static bool is_rtc_hctosys(struct rtc_device *rtc) -{ - int size; - char name[NAME_SIZE]; - - size = scnprintf(name, NAME_SIZE, "rtc%d", rtc->id); - if (size > NAME_SIZE) - return false; - - return !strncmp(name, CONFIG_RTC_HCTOSYS_DEVICE, NAME_SIZE); -} -#else -static bool is_rtc_hctosys(struct rtc_device *rtc) -{ - return (rtc->id == 0); -} -#endif - -static int rtc_proc_show(struct seq_file *seq, void *offset) -{ - int err; - struct rtc_device *rtc = seq->private; - const struct rtc_class_ops *ops = rtc->ops; - struct rtc_wkalrm alrm; - struct rtc_time tm; - - err = rtc_read_time(rtc, &tm); - if (err == 0) { - seq_printf(seq, - "rtc_time\t: %02d:%02d:%02d\n" - "rtc_date\t: %04d-%02d-%02d\n", - tm.tm_hour, tm.tm_min, tm.tm_sec, - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); - } - - err = rtc_read_alarm(rtc, &alrm); - if (err == 0) { - seq_printf(seq, "alrm_time\t: "); - if ((unsigned int)alrm.time.tm_hour <= 24) - seq_printf(seq, "%02d:", alrm.time.tm_hour); - else - seq_printf(seq, "**:"); - if ((unsigned int)alrm.time.tm_min <= 59) - seq_printf(seq, "%02d:", alrm.time.tm_min); - else - seq_printf(seq, "**:"); - if ((unsigned int)alrm.time.tm_sec <= 59) - seq_printf(seq, "%02d\n", alrm.time.tm_sec); - else - seq_printf(seq, "**\n"); - - seq_printf(seq, "alrm_date\t: "); - if ((unsigned int)alrm.time.tm_year <= 200) - seq_printf(seq, "%04d-", alrm.time.tm_year + 1900); - else - seq_printf(seq, "****-"); - if ((unsigned int)alrm.time.tm_mon <= 11) - seq_printf(seq, "%02d-", alrm.time.tm_mon + 1); - else - seq_printf(seq, "**-"); - if (alrm.time.tm_mday && (unsigned int)alrm.time.tm_mday <= 31) - seq_printf(seq, "%02d\n", alrm.time.tm_mday); - else - seq_printf(seq, "**\n"); - seq_printf(seq, "alarm_IRQ\t: %s\n", - alrm.enabled ? "yes" : "no"); - seq_printf(seq, "alrm_pending\t: %s\n", - alrm.pending ? "yes" : "no"); - seq_printf(seq, "update IRQ enabled\t: %s\n", - (rtc->uie_rtctimer.enabled) ? "yes" : "no"); - seq_printf(seq, "periodic IRQ enabled\t: %s\n", - (rtc->pie_enabled) ? "yes" : "no"); - seq_printf(seq, "periodic IRQ frequency\t: %d\n", - rtc->irq_freq); - seq_printf(seq, "max user IRQ frequency\t: %d\n", - rtc->max_user_freq); - } - - seq_printf(seq, "24hr\t\t: yes\n"); - - if (ops->proc) - ops->proc(rtc->dev.parent, seq); - - return 0; -} - -void rtc_proc_add_device(struct rtc_device *rtc) -{ - if (is_rtc_hctosys(rtc)) - proc_create_single_data("driver/rtc", 0, NULL, rtc_proc_show, - rtc); -} - -void rtc_proc_del_device(struct rtc_device *rtc) -{ - if (is_rtc_hctosys(rtc)) - remove_proc_entry("driver/rtc", NULL); -} diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c @@ -90,9 +90,7 @@ static int puv3_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) { rtc_time_to_tm(readl(RTC_RCNR), rtc_tm); - dev_dbg(dev, "read time %02x.%02x.%02x %02x/%02x/%02x\n", - rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday, - rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); + dev_dbg(dev, "read time %ptRr\n", rtc_tm); return 0; } @@ -101,9 +99,7 @@ static int puv3_rtc_settime(struct device *dev, struct rtc_time *tm) { unsigned long rtc_count = 0; - dev_dbg(dev, "set time %02d.%02d.%02d %02d/%02d/%02d\n", - tm->tm_year, tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "set time %ptRr\n", tm); rtc_tm_to_time(tm, &rtc_count); writel(rtc_count, RTC_RCNR); @@ -119,10 +115,7 @@ static int puv3_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm) alrm->enabled = readl(RTC_RTSR) & RTC_RTSR_ALE; - dev_dbg(dev, "read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", - alrm->enabled, - alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday, - alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); + dev_dbg(dev, "read alarm: %d, %ptRr\n", alrm->enabled, alm_tm); return 0; } @@ -132,10 +125,7 @@ static int puv3_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) struct rtc_time *tm = &alrm->time; unsigned long rtcalarm_count = 0; - dev_dbg(dev, "puv3_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", - alrm->enabled, - tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff, - tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); + dev_dbg(dev, "set alarm: %d, %ptRr\n", alrm->enabled, tm); rtc_tm_to_time(tm, &rtcalarm_count); writel(rtcalarm_count, RTC_RTAR); diff --git a/drivers/rtc/rtc-rk808.c b/drivers/rtc/rtc-rk808.c @@ -138,9 +138,7 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm) tm->tm_year = (bcd2bin(rtc_data[5] & YEARS_REG_MSK)) + 100; tm->tm_wday = bcd2bin(rtc_data[6] & WEEKS_REG_MSK); rockchip_to_gregorian(tm); - dev_dbg(dev, "RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", - 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, - tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "RTC date/time %ptRd(%d) %ptRt\n", tm, tm->tm_wday, tm); return ret; } @@ -153,9 +151,7 @@ static int rk808_rtc_set_time(struct device *dev, struct rtc_time *tm) u8 rtc_data[NUM_TIME_REGS]; int ret; - dev_dbg(dev, "set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", - 1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday, - tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec); + dev_dbg(dev, "set RTC date/time %ptRd(%d) %ptRt\n", tm, tm->tm_wday, tm); gregorian_to_rockchip(tm); rtc_data[0] = bin2bcd(tm->tm_sec); rtc_data[1] = bin2bcd(tm->tm_min); @@ -216,10 +212,8 @@ static int rk808_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm) return ret; } - dev_dbg(dev, "alrm read RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", - 1900 + alrm->time.tm_year, alrm->time.tm_mon + 1, - alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour, - alrm->time.tm_min, alrm->time.tm_sec); + dev_dbg(dev, "alrm read RTC date/time %ptRd(%d) %ptRt\n", + &alrm->time, alrm->time.tm_wday, &alrm->time); alrm->enabled = (int_reg & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M) ? 1 : 0; @@ -261,10 +255,8 @@ static int rk808_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) dev_err(dev, "Failed to stop alarm: %d\n", ret); return ret; } - dev_dbg(dev, "alrm set RTC date/time %4d-%02d-%02d(%d) %02d:%02d:%02d\n", - 1900 + alrm->time.tm_year, alrm->time.tm_mon + 1, - alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour, - alrm->time.tm_min, alrm->time.tm_sec); + dev_dbg(dev, "alrm set RTC date/time %ptRd(%d) %ptRt\n", + &alrm->time, alrm->time.tm_wday, &alrm->time); gregorian_to_rockchip(&alrm->time); alrm_data[0] = bin2bcd(alrm->time.tm_sec); @@ -400,7 +392,7 @@ static int rk808_rtc_probe(struct platform_device *pdev) if (ret) { dev_err(&pdev->dev, "Failed to write RTC status: %d\n", ret); - return ret; + return ret; } device_init_wakeup(&pdev->dev, 1); diff --git a/drivers/rtc/rtc-rx6110.c b/drivers/rtc/rtc-rx6110.c @@ -114,9 +114,7 @@ struct rx6110_data { */ static int rx6110_rtc_tm_to_data(struct rtc_time *tm, u8 *data) { - pr_debug("%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, - tm->tm_sec, tm->tm_min, tm->tm_hour, - tm->tm_mday, tm->tm_mon, tm->tm_year); + pr_debug("%s: date %ptRr\n", __func__, tm); /* * The year in the RTC is a value between 0 and 99. @@ -154,9 +152,7 @@ static int rx6110_data_to_rtc_tm(u8 *data, struct rtc_time *tm) tm->tm_mon = bcd2bin(data[RTC_MONTH] & 0x1f) - 1; tm->tm_year = bcd2bin(data[RTC_YEAR]) + 100; - pr_debug("%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, - tm->tm_sec, tm->tm_min, tm->tm_hour, - tm->tm_mday, tm->tm_mon, tm->tm_year); + pr_debug("%s: date %ptRr\n", __func__, tm); /* * The year in the RTC is a value between 0 and 99. @@ -248,9 +244,7 @@ static int rx6110_get_time(struct device *dev, struct rtc_time *tm) if (ret) return ret; - dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, - tm->tm_sec, tm->tm_min, tm->tm_hour, - tm->tm_mday, tm->tm_mon, tm->tm_year); + dev_dbg(dev, "%s: date %ptRr\n", __func__, tm); return 0; } diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c @@ -193,10 +193,7 @@ static int rx8025_get_time(struct device *dev, struct rtc_time *dt) if (err) return err; - dev_dbg(dev, "%s: read 0x%02x 0x%02x " - "0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", __func__, - date[0], date[1], date[2], date[3], date[4], - date[5], date[6]); + dev_dbg(dev, "%s: read %7ph\n", __func__, date); dt->tm_sec = bcd2bin(date[RX8025_REG_SEC] & 0x7f); dt->tm_min = bcd2bin(date[RX8025_REG_MIN] & 0x7f); @@ -210,9 +207,7 @@ static int rx8025_get_time(struct device *dev, struct rtc_time *dt) dt->tm_mon = bcd2bin(date[RX8025_REG_MONTH] & 0x1f) - 1; dt->tm_year = bcd2bin(date[RX8025_REG_YEAR]) + 100; - dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, - dt->tm_sec, dt->tm_min, dt->tm_hour, - dt->tm_mday, dt->tm_mon, dt->tm_year); + dev_dbg(dev, "%s: date %ptRr\n", __func__, dt); return 0; } @@ -243,10 +238,7 @@ static int rx8025_set_time(struct device *dev, struct rtc_time *dt) date[RX8025_REG_MONTH] = bin2bcd(dt->tm_mon + 1); date[RX8025_REG_YEAR] = bin2bcd(dt->tm_year - 100); - dev_dbg(dev, - "%s: write 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", - __func__, - date[0], date[1], date[2], date[3], date[4], date[5], date[6]); + dev_dbg(dev, "%s: write %7ph\n", __func__, date); ret = rx8025_write_regs(rx8025->client, RX8025_REG_SEC, 7, date); if (ret < 0) @@ -319,10 +311,7 @@ static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t) t->time.tm_hour = bcd2bin(ald[1] & 0x1f) % 12 + (ald[1] & 0x20 ? 12 : 0); - dev_dbg(dev, "%s: date: %ds %dm %dh %dmd %dm %dy\n", - __func__, - t->time.tm_sec, t->time.tm_min, t->time.tm_hour, - t->time.tm_mday, t->time.tm_mon, t->time.tm_year); + dev_dbg(dev, "%s: date: %ptRr\n", __func__, t); t->enabled = !!(rx8025->ctrl1 & RX8025_BIT_CTRL1_DALE); t->pending = (ctrl2 & RX8025_BIT_CTRL2_DAFG) && t->enabled; diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c @@ -225,13 +225,9 @@ retry_get_time: s3c_rtc_disable_clk(info); 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); - rtc_tm->tm_mon -= 1; + dev_dbg(dev, "read time %ptR\n", rtc_tm); return 0; } @@ -241,9 +237,7 @@ static int s3c_rtc_settime(struct device *dev, struct rtc_time *tm) 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); + dev_dbg(dev, "set time %ptR\n", tm); /* we get around y2k by simply not supporting it */ @@ -292,10 +286,7 @@ 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); + dev_dbg(dev, "read alarm %d, %ptR\n", alm_en, alm_tm); /* decode the alarm enable field */ if (alm_en & S3C2410_RTCALM_SECEN) @@ -327,12 +318,8 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) 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); + dev_dbg(dev, "s3c_rtc_setalarm: %d, %ptR\n", alrm->enabled, tm); ret = s3c_rtc_enable_clk(info); if (ret) @@ -356,11 +343,6 @@ static int s3c_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm) writeb(bin2bcd(tm->tm_hour), info->base + S3C2410_ALMHOUR); } - if (year < 100 && year >= 0) { - alrm_en |= S3C2410_RTCALM_YEAREN; - writeb(bin2bcd(year), info->base + S3C2410_ALMYEAR); - } - if (tm->tm_mon < 12 && tm->tm_mon >= 0) { alrm_en |= S3C2410_RTCALM_MONEN; writeb(bin2bcd(tm->tm_mon + 1), info->base + S3C2410_ALMMON); diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c @@ -406,9 +406,7 @@ static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) return -EINVAL; } - dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, - 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); + dev_dbg(dev, "%s: %ptR(%d)\n", __func__, tm, tm->tm_wday); return 0; } @@ -436,9 +434,7 @@ static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) if (ret < 0) return ret; - dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, - 1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); + dev_dbg(dev, "%s: %ptR(%d)\n", __func__, tm, tm->tm_wday); ret = regmap_raw_write(info->regmap, info->regs->time, data, info->regs->regs_count); @@ -490,11 +486,7 @@ static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) return -EINVAL; } - dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, - 1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon, - alrm->time.tm_mday, alrm->time.tm_hour, - alrm->time.tm_min, alrm->time.tm_sec, - alrm->time.tm_wday); + dev_dbg(dev, "%s: %ptR(%d)\n", __func__, &alrm->time, alrm->time.tm_wday); ret = s5m_check_peding_alarm_interrupt(info, alrm); @@ -513,9 +505,7 @@ static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) return ret; s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode); - dev_dbg(info->dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, - 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday); + dev_dbg(info->dev, "%s: %ptR(%d)\n", __func__, &tm, tm.tm_wday); switch (info->device_type) { case S5M8763X: @@ -558,9 +548,7 @@ static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) return ret; s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode); - dev_dbg(info->dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, - 1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, - tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday); + dev_dbg(info->dev, "%s: %ptR(%d)\n", __func__, &tm, tm.tm_wday); switch (info->device_type) { case S5M8763X: @@ -620,10 +608,7 @@ static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) return -EINVAL; } - dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, - 1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon, - alrm->time.tm_mday, alrm->time.tm_hour, alrm->time.tm_min, - alrm->time.tm_sec, alrm->time.tm_wday); + dev_dbg(dev, "%s: %ptR(%d)\n", __func__, &alrm->time, alrm->time.tm_wday); ret = s5m_rtc_stop_alarm(info); if (ret < 0) diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * SuperH On-Chip RTC Support * @@ -9,10 +10,6 @@ * * Copyright (C) 2000 Philipp Rumpf <prumpf@tux.org> * Copyright (C) 1999 Tetsuya Okada & Niibe Yutaka - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. */ #include <linux/module.h> #include <linux/mod_devicetable.h> @@ -681,5 +678,5 @@ MODULE_DESCRIPTION("SuperH on-chip RTC driver"); MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, " "Jamie Lenehan <lenehan@twibble.org>, " "Angelo Castello <angelo.castello@st.com>"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:" DRV_NAME); diff --git a/drivers/rtc/rtc-sun6i.c b/drivers/rtc/rtc-sun6i.c @@ -118,9 +118,31 @@ #define SUN6I_YEAR_MAX 2033 #define SUN6I_YEAR_OFF (SUN6I_YEAR_MIN - 1900) +/* + * There are other differences between models, including: + * + * - number of GPIO pins that can be configured to hold a certain level + * - crypto-key related registers (H5, H6) + * - boot process related (super standby, secondary processor entry address) + * registers (R40, H6) + * - SYS power domain controls (R40) + * - DCXO controls (H6) + * - RC oscillator calibration (H6) + * + * These functions are not covered by this driver. + */ +struct sun6i_rtc_clk_data { + unsigned long rc_osc_rate; + unsigned int fixed_prescaler : 16; + unsigned int has_prescaler : 1; + unsigned int has_out_clk : 1; + unsigned int export_iosc : 1; +}; + struct sun6i_rtc_dev { struct rtc_device *rtc; struct device *dev; + const struct sun6i_rtc_clk_data *data; void __iomem *base; int irq; unsigned long alarm; @@ -139,14 +161,19 @@ static unsigned long sun6i_rtc_osc_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) { struct sun6i_rtc_dev *rtc = container_of(hw, struct sun6i_rtc_dev, hw); - u32 val; + u32 val = 0; val = readl(rtc->base + SUN6I_LOSC_CTRL); if (val & SUN6I_LOSC_CTRL_EXT_OSC) return parent_rate; - val = readl(rtc->base + SUN6I_LOSC_CLK_PRESCAL); - val &= GENMASK(4, 0); + if (rtc->data->fixed_prescaler) + parent_rate /= rtc->data->fixed_prescaler; + + if (rtc->data->has_prescaler) { + val = readl(rtc->base + SUN6I_LOSC_CLK_PRESCAL); + val &= GENMASK(4, 0); + } return parent_rate / (val + 1); } @@ -185,13 +212,16 @@ static const struct clk_ops sun6i_rtc_osc_ops = { .set_parent = sun6i_rtc_osc_set_parent, }; -static void __init sun6i_rtc_clk_init(struct device_node *node) +static void __init sun6i_rtc_clk_init(struct device_node *node, + const struct sun6i_rtc_clk_data *data) { struct clk_hw_onecell_data *clk_data; struct sun6i_rtc_dev *rtc; struct clk_init_data init = { .ops = &sun6i_rtc_osc_ops, + .name = "losc", }; + const char *iosc_name = "rtc-int-osc"; const char *clkout_name = "osc32k-out"; const char *parents[2]; @@ -199,7 +229,8 @@ static void __init sun6i_rtc_clk_init(struct device_node *node) if (!rtc) return; - clk_data = kzalloc(struct_size(clk_data, hws, 2), GFP_KERNEL); + rtc->data = data; + clk_data = kzalloc(struct_size(clk_data, hws, 3), GFP_KERNEL); if (!clk_data) { kfree(rtc); return; @@ -224,10 +255,15 @@ static void __init sun6i_rtc_clk_init(struct device_node *node) if (!of_get_property(node, "clocks", NULL)) goto err; + /* Only read IOSC name from device tree if it is exported */ + if (rtc->data->export_iosc) + of_property_read_string_index(node, "clock-output-names", 2, + &iosc_name); + rtc->int_osc = clk_hw_register_fixed_rate_with_accuracy(NULL, - "rtc-int-osc", + iosc_name, NULL, 0, - 667000, + rtc->data->rc_osc_rate, 300000000); if (IS_ERR(rtc->int_osc)) { pr_crit("Couldn't register the internal oscillator\n"); @@ -264,14 +300,71 @@ static void __init sun6i_rtc_clk_init(struct device_node *node) clk_data->num = 2; clk_data->hws[0] = &rtc->hw; clk_data->hws[1] = __clk_get_hw(rtc->ext_losc); + if (rtc->data->export_iosc) { + clk_data->hws[2] = rtc->int_osc; + clk_data->num = 3; + } of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); return; err: kfree(clk_data); } -CLK_OF_DECLARE_DRIVER(sun6i_rtc_clk, "allwinner,sun6i-a31-rtc", - sun6i_rtc_clk_init); + +static const struct sun6i_rtc_clk_data sun6i_a31_rtc_data = { + .rc_osc_rate = 667000, /* datasheet says 600 ~ 700 KHz */ + .has_prescaler = 1, +}; + +static void __init sun6i_a31_rtc_clk_init(struct device_node *node) +{ + sun6i_rtc_clk_init(node, &sun6i_a31_rtc_data); +} +CLK_OF_DECLARE_DRIVER(sun6i_a31_rtc_clk, "allwinner,sun6i-a31-rtc", + sun6i_a31_rtc_clk_init); + +static const struct sun6i_rtc_clk_data sun8i_a23_rtc_data = { + .rc_osc_rate = 667000, /* datasheet says 600 ~ 700 KHz */ + .has_prescaler = 1, + .has_out_clk = 1, +}; + +static void __init sun8i_a23_rtc_clk_init(struct device_node *node) +{ + sun6i_rtc_clk_init(node, &sun8i_a23_rtc_data); +} +CLK_OF_DECLARE_DRIVER(sun8i_a23_rtc_clk, "allwinner,sun8i-a23-rtc", + sun8i_a23_rtc_clk_init); + +static const struct sun6i_rtc_clk_data sun8i_h3_rtc_data = { + .rc_osc_rate = 16000000, + .fixed_prescaler = 32, + .has_prescaler = 1, + .has_out_clk = 1, + .export_iosc = 1, +}; + +static void __init sun8i_h3_rtc_clk_init(struct device_node *node) +{ + sun6i_rtc_clk_init(node, &sun8i_h3_rtc_data); +} +CLK_OF_DECLARE_DRIVER(sun8i_h3_rtc_clk, "allwinner,sun8i-h3-rtc", + sun8i_h3_rtc_clk_init); +/* As far as we are concerned, clocks for H5 are the same as H3 */ +CLK_OF_DECLARE_DRIVER(sun50i_h5_rtc_clk, "allwinner,sun50i-h5-rtc", + sun8i_h3_rtc_clk_init); + +static const struct sun6i_rtc_clk_data sun8i_v3_rtc_data = { + .rc_osc_rate = 32000, + .has_out_clk = 1, +}; + +static void __init sun8i_v3_rtc_clk_init(struct device_node *node) +{ + sun6i_rtc_clk_init(node, &sun8i_v3_rtc_data); +} +CLK_OF_DECLARE_DRIVER(sun8i_v3_rtc_clk, "allwinner,sun8i-v3-rtc", + sun8i_v3_rtc_clk_init); static irqreturn_t sun6i_rtc_alarmirq(int irq, void *id) { @@ -578,8 +671,18 @@ static int sun6i_rtc_probe(struct platform_device *pdev) return 0; } +/* + * As far as RTC functionality goes, all models are the same. The + * datasheets claim that different models have different number of + * registers available for non-volatile storage, but experiments show + * that all SoCs have 16 registers available for this purpose. + */ static const struct of_device_id sun6i_rtc_dt_ids[] = { { .compatible = "allwinner,sun6i-a31-rtc" }, + { .compatible = "allwinner,sun8i-a23-rtc" }, + { .compatible = "allwinner,sun8i-h3-rtc" }, + { .compatible = "allwinner,sun8i-v3-rtc" }, + { .compatible = "allwinner,sun50i-h5-rtc" }, { /* sentinel */ }, }; MODULE_DEVICE_TABLE(of, sun6i_rtc_dt_ids); diff --git a/drivers/rtc/rtc-sysfs.c b/drivers/rtc/rtc-sysfs.c @@ -1,362 +0,0 @@ -/* - * RTC subsystem, sysfs interface - * - * Copyright (C) 2005 Tower Technologies - * Author: Alessandro Zummo <a.zummo@towertech.it> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. -*/ - -#include <linux/module.h> -#include <linux/rtc.h> - -#include "rtc-core.h" - - -/* device attributes */ - -/* - * NOTE: RTC times displayed in sysfs use the RTC's timezone. That's - * ideally UTC. However, PCs that also boot to MS-Windows normally use - * the local time and change to match daylight savings time. That affects - * attributes including date, time, since_epoch, and wakealarm. - */ - -static ssize_t -name_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%s %s\n", dev_driver_string(dev->parent), - dev_name(dev->parent)); -} -static DEVICE_ATTR_RO(name); - -static ssize_t -date_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - ssize_t retval; - struct rtc_time tm; - - retval = rtc_read_time(to_rtc_device(dev), &tm); - if (retval == 0) { - retval = sprintf(buf, "%04d-%02d-%02d\n", - tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); - } - - return retval; -} -static DEVICE_ATTR_RO(date); - -static ssize_t -time_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - ssize_t retval; - struct rtc_time tm; - - retval = rtc_read_time(to_rtc_device(dev), &tm); - if (retval == 0) { - retval = sprintf(buf, "%02d:%02d:%02d\n", - tm.tm_hour, tm.tm_min, tm.tm_sec); - } - - return retval; -} -static DEVICE_ATTR_RO(time); - -static ssize_t -since_epoch_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - ssize_t retval; - struct rtc_time tm; - - retval = rtc_read_time(to_rtc_device(dev), &tm); - if (retval == 0) { - time64_t time; - - time = rtc_tm_to_time64(&tm); - retval = sprintf(buf, "%lld\n", time); - } - - return retval; -} -static DEVICE_ATTR_RO(since_epoch); - -static ssize_t -max_user_freq_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq); -} - -static ssize_t -max_user_freq_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) -{ - struct rtc_device *rtc = to_rtc_device(dev); - unsigned long val; - int err; - - err = kstrtoul(buf, 0, &val); - if (err) - return err; - - if (val >= 4096 || val == 0) - return -EINVAL; - - rtc->max_user_freq = (int)val; - - return n; -} -static DEVICE_ATTR_RW(max_user_freq); - -/** - * rtc_sysfs_show_hctosys - indicate if the given RTC set the system time - * - * Returns 1 if the system clock was set by this RTC at the last - * boot or resume event. - */ -static ssize_t -hctosys_show(struct device *dev, struct device_attribute *attr, char *buf) -{ -#ifdef CONFIG_RTC_HCTOSYS_DEVICE - if (rtc_hctosys_ret == 0 && - strcmp(dev_name(&to_rtc_device(dev)->dev), - CONFIG_RTC_HCTOSYS_DEVICE) == 0) - return sprintf(buf, "1\n"); - else -#endif - return sprintf(buf, "0\n"); -} -static DEVICE_ATTR_RO(hctosys); - -static ssize_t -wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - ssize_t retval; - time64_t alarm; - struct rtc_wkalrm alm; - - /* Don't show disabled alarms. For uniformity, RTC alarms are - * conceptually one-shot, even though some common RTCs (on PCs) - * don't actually work that way. - * - * NOTE: RTC implementations where the alarm doesn't match an - * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC - * alarms after they trigger, to ensure one-shot semantics. - */ - retval = rtc_read_alarm(to_rtc_device(dev), &alm); - if (retval == 0 && alm.enabled) { - alarm = rtc_tm_to_time64(&alm.time); - retval = sprintf(buf, "%lld\n", alarm); - } - - return retval; -} - -static ssize_t -wakealarm_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) -{ - ssize_t retval; - time64_t now, alarm; - time64_t push = 0; - struct rtc_wkalrm alm; - struct rtc_device *rtc = to_rtc_device(dev); - const char *buf_ptr; - int adjust = 0; - - /* Only request alarms that trigger in the future. Disable them - * by writing another time, e.g. 0 meaning Jan 1 1970 UTC. - */ - retval = rtc_read_time(rtc, &alm.time); - if (retval < 0) - return retval; - now = rtc_tm_to_time64(&alm.time); - - buf_ptr = buf; - if (*buf_ptr == '+') { - buf_ptr++; - if (*buf_ptr == '=') { - buf_ptr++; - push = 1; - } else - adjust = 1; - } - retval = kstrtos64(buf_ptr, 0, &alarm); - if (retval) - return retval; - if (adjust) { - alarm += now; - } - if (alarm > now || push) { - /* Avoid accidentally clobbering active alarms; we can't - * entirely prevent that here, without even the minimal - * locking from the /dev/rtcN api. - */ - retval = rtc_read_alarm(rtc, &alm); - if (retval < 0) - return retval; - if (alm.enabled) { - if (push) { - push = rtc_tm_to_time64(&alm.time); - alarm += push; - } else - return -EBUSY; - } else if (push) - return -EINVAL; - alm.enabled = 1; - } else { - alm.enabled = 0; - - /* Provide a valid future alarm time. Linux isn't EFI, - * this time won't be ignored when disabling the alarm. - */ - alarm = now + 300; - } - rtc_time64_to_tm(alarm, &alm.time); - - retval = rtc_set_alarm(rtc, &alm); - return (retval < 0) ? retval : n; -} -static DEVICE_ATTR_RW(wakealarm); - -static ssize_t -offset_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - ssize_t retval; - long offset; - - retval = rtc_read_offset(to_rtc_device(dev), &offset); - if (retval == 0) - retval = sprintf(buf, "%ld\n", offset); - - return retval; -} - -static ssize_t -offset_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t n) -{ - ssize_t retval; - long offset; - - retval = kstrtol(buf, 10, &offset); - if (retval == 0) - retval = rtc_set_offset(to_rtc_device(dev), offset); - - return (retval < 0) ? retval : n; -} -static DEVICE_ATTR_RW(offset); - -static ssize_t -range_show(struct device *dev, struct device_attribute *attr, char *buf) -{ - return sprintf(buf, "[%lld,%llu]\n", to_rtc_device(dev)->range_min, - to_rtc_device(dev)->range_max); -} -static DEVICE_ATTR_RO(range); - -static struct attribute *rtc_attrs[] = { - &dev_attr_name.attr, - &dev_attr_date.attr, - &dev_attr_time.attr, - &dev_attr_since_epoch.attr, - &dev_attr_max_user_freq.attr, - &dev_attr_hctosys.attr, - &dev_attr_wakealarm.attr, - &dev_attr_offset.attr, - &dev_attr_range.attr, - NULL, -}; - -/* The reason to trigger an alarm with no process watching it (via sysfs) - * is its side effect: waking from a system state like suspend-to-RAM or - * suspend-to-disk. So: no attribute unless that side effect is possible. - * (Userspace may disable that mechanism later.) - */ -static bool rtc_does_wakealarm(struct rtc_device *rtc) -{ - if (!device_can_wakeup(rtc->dev.parent)) - return false; - - return rtc->ops->set_alarm != NULL; -} - -static umode_t rtc_attr_is_visible(struct kobject *kobj, - struct attribute *attr, int n) -{ - struct device *dev = container_of(kobj, struct device, kobj); - struct rtc_device *rtc = to_rtc_device(dev); - umode_t mode = attr->mode; - - if (attr == &dev_attr_wakealarm.attr) { - if (!rtc_does_wakealarm(rtc)) - mode = 0; - } else if (attr == &dev_attr_offset.attr) { - if (!rtc->ops->set_offset) - mode = 0; - } else if (attr == &dev_attr_range.attr) { - if (!(rtc->range_max - rtc->range_min)) - mode = 0; - } - - return mode; -} - -static struct attribute_group rtc_attr_group = { - .is_visible = rtc_attr_is_visible, - .attrs = rtc_attrs, -}; - -static const struct attribute_group *rtc_attr_groups[] = { - &rtc_attr_group, - NULL -}; - -const struct attribute_group **rtc_get_dev_attribute_groups(void) -{ - return rtc_attr_groups; -} - -int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps) -{ - size_t old_cnt = 0, add_cnt = 0, new_cnt; - const struct attribute_group **groups, **old; - - if (rtc->registered) - return -EINVAL; - if (!grps) - return -EINVAL; - - groups = rtc->dev.groups; - if (groups) - for (; *groups; groups++) - old_cnt++; - - for (groups = grps; *groups; groups++) - add_cnt++; - - new_cnt = old_cnt + add_cnt + 1; - groups = devm_kcalloc(&rtc->dev, new_cnt, sizeof(*groups), GFP_KERNEL); - if (!groups) - return -ENOMEM; - memcpy(groups, rtc->dev.groups, old_cnt * sizeof(*groups)); - memcpy(groups + old_cnt, grps, add_cnt * sizeof(*groups)); - groups[old_cnt + add_cnt] = NULL; - - old = rtc->dev.groups; - rtc->dev.groups = groups; - if (old && old != rtc_attr_groups) - devm_kfree(&rtc->dev, old); - - return 0; -} -EXPORT_SYMBOL(rtc_add_groups); - -int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp) -{ - const struct attribute_group *groups[] = { grp, NULL }; - - return rtc_add_groups(rtc, groups); -} -EXPORT_SYMBOL(rtc_add_group); diff --git a/drivers/rtc/rtc-tegra.c b/drivers/rtc/rtc-tegra.c @@ -125,15 +125,7 @@ static int tegra_rtc_read_time(struct device *dev, struct rtc_time *tm) rtc_time_to_tm(sec, tm); - dev_vdbg(dev, "time read as %lu. %d/%d/%d %d:%02u:%02u\n", - sec, - tm->tm_mon + 1, - tm->tm_mday, - tm->tm_year + 1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec - ); + dev_vdbg(dev, "time read as %lu. %ptR\n", sec, tm); return 0; } @@ -147,15 +139,7 @@ static int tegra_rtc_set_time(struct device *dev, struct rtc_time *tm) /* convert tm to seconds. */ rtc_tm_to_time(tm, &sec); - dev_vdbg(dev, "time set to %lu. %d/%d/%d %d:%02u:%02u\n", - sec, - tm->tm_mon+1, - tm->tm_mday, - tm->tm_year+1900, - tm->tm_hour, - tm->tm_min, - tm->tm_sec - ); + dev_vdbg(dev, "time set to %lu. %ptR\n", sec, tm); /* seconds only written if wait succeeded. */ ret = tegra_rtc_wait_while_busy(dev); @@ -232,15 +216,7 @@ static int tegra_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) /* if successfully written and alarm is enabled ... */ if (sec) { tegra_rtc_alarm_irq_enable(dev, 1); - - dev_vdbg(dev, "alarm set as %lu. %d/%d/%d %d:%02u:%02u\n", - sec, - alarm->time.tm_mon+1, - alarm->time.tm_mday, - alarm->time.tm_year+1900, - alarm->time.tm_hour, - alarm->time.tm_min, - alarm->time.tm_sec); + dev_vdbg(dev, "alarm set as %lu. %ptR\n", sec, &alarm->time); } else { /* disable alarm if 0 or write error. */ dev_vdbg(dev, "alarm disabled\n"); diff --git a/drivers/rtc/sysfs.c b/drivers/rtc/sysfs.c @@ -0,0 +1,358 @@ +/* + * RTC subsystem, sysfs interface + * + * Copyright (C) 2005 Tower Technologies + * Author: Alessandro Zummo <a.zummo@towertech.it> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include <linux/module.h> +#include <linux/rtc.h> + +#include "rtc-core.h" + + +/* device attributes */ + +/* + * NOTE: RTC times displayed in sysfs use the RTC's timezone. That's + * ideally UTC. However, PCs that also boot to MS-Windows normally use + * the local time and change to match daylight savings time. That affects + * attributes including date, time, since_epoch, and wakealarm. + */ + +static ssize_t +name_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%s %s\n", dev_driver_string(dev->parent), + dev_name(dev->parent)); +} +static DEVICE_ATTR_RO(name); + +static ssize_t +date_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t retval; + struct rtc_time tm; + + retval = rtc_read_time(to_rtc_device(dev), &tm); + if (retval) + return retval; + + return sprintf(buf, "%ptRd\n", &tm); +} +static DEVICE_ATTR_RO(date); + +static ssize_t +time_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t retval; + struct rtc_time tm; + + retval = rtc_read_time(to_rtc_device(dev), &tm); + if (retval) + return retval; + + return sprintf(buf, "%ptRt\n", &tm); +} +static DEVICE_ATTR_RO(time); + +static ssize_t +since_epoch_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t retval; + struct rtc_time tm; + + retval = rtc_read_time(to_rtc_device(dev), &tm); + if (retval == 0) { + time64_t time; + + time = rtc_tm_to_time64(&tm); + retval = sprintf(buf, "%lld\n", time); + } + + return retval; +} +static DEVICE_ATTR_RO(since_epoch); + +static ssize_t +max_user_freq_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", to_rtc_device(dev)->max_user_freq); +} + +static ssize_t +max_user_freq_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + struct rtc_device *rtc = to_rtc_device(dev); + unsigned long val; + int err; + + err = kstrtoul(buf, 0, &val); + if (err) + return err; + + if (val >= 4096 || val == 0) + return -EINVAL; + + rtc->max_user_freq = (int)val; + + return n; +} +static DEVICE_ATTR_RW(max_user_freq); + +/** + * rtc_sysfs_show_hctosys - indicate if the given RTC set the system time + * + * Returns 1 if the system clock was set by this RTC at the last + * boot or resume event. + */ +static ssize_t +hctosys_show(struct device *dev, struct device_attribute *attr, char *buf) +{ +#ifdef CONFIG_RTC_HCTOSYS_DEVICE + if (rtc_hctosys_ret == 0 && + strcmp(dev_name(&to_rtc_device(dev)->dev), + CONFIG_RTC_HCTOSYS_DEVICE) == 0) + return sprintf(buf, "1\n"); + else +#endif + return sprintf(buf, "0\n"); +} +static DEVICE_ATTR_RO(hctosys); + +static ssize_t +wakealarm_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t retval; + time64_t alarm; + struct rtc_wkalrm alm; + + /* Don't show disabled alarms. For uniformity, RTC alarms are + * conceptually one-shot, even though some common RTCs (on PCs) + * don't actually work that way. + * + * NOTE: RTC implementations where the alarm doesn't match an + * exact YYYY-MM-DD HH:MM[:SS] date *must* disable their RTC + * alarms after they trigger, to ensure one-shot semantics. + */ + retval = rtc_read_alarm(to_rtc_device(dev), &alm); + if (retval == 0 && alm.enabled) { + alarm = rtc_tm_to_time64(&alm.time); + retval = sprintf(buf, "%lld\n", alarm); + } + + return retval; +} + +static ssize_t +wakealarm_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + ssize_t retval; + time64_t now, alarm; + time64_t push = 0; + struct rtc_wkalrm alm; + struct rtc_device *rtc = to_rtc_device(dev); + const char *buf_ptr; + int adjust = 0; + + /* Only request alarms that trigger in the future. Disable them + * by writing another time, e.g. 0 meaning Jan 1 1970 UTC. + */ + retval = rtc_read_time(rtc, &alm.time); + if (retval < 0) + return retval; + now = rtc_tm_to_time64(&alm.time); + + buf_ptr = buf; + if (*buf_ptr == '+') { + buf_ptr++; + if (*buf_ptr == '=') { + buf_ptr++; + push = 1; + } else + adjust = 1; + } + retval = kstrtos64(buf_ptr, 0, &alarm); + if (retval) + return retval; + if (adjust) { + alarm += now; + } + if (alarm > now || push) { + /* Avoid accidentally clobbering active alarms; we can't + * entirely prevent that here, without even the minimal + * locking from the /dev/rtcN api. + */ + retval = rtc_read_alarm(rtc, &alm); + if (retval < 0) + return retval; + if (alm.enabled) { + if (push) { + push = rtc_tm_to_time64(&alm.time); + alarm += push; + } else + return -EBUSY; + } else if (push) + return -EINVAL; + alm.enabled = 1; + } else { + alm.enabled = 0; + + /* Provide a valid future alarm time. Linux isn't EFI, + * this time won't be ignored when disabling the alarm. + */ + alarm = now + 300; + } + rtc_time64_to_tm(alarm, &alm.time); + + retval = rtc_set_alarm(rtc, &alm); + return (retval < 0) ? retval : n; +} +static DEVICE_ATTR_RW(wakealarm); + +static ssize_t +offset_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + ssize_t retval; + long offset; + + retval = rtc_read_offset(to_rtc_device(dev), &offset); + if (retval == 0) + retval = sprintf(buf, "%ld\n", offset); + + return retval; +} + +static ssize_t +offset_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t n) +{ + ssize_t retval; + long offset; + + retval = kstrtol(buf, 10, &offset); + if (retval == 0) + retval = rtc_set_offset(to_rtc_device(dev), offset); + + return (retval < 0) ? retval : n; +} +static DEVICE_ATTR_RW(offset); + +static ssize_t +range_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "[%lld,%llu]\n", to_rtc_device(dev)->range_min, + to_rtc_device(dev)->range_max); +} +static DEVICE_ATTR_RO(range); + +static struct attribute *rtc_attrs[] = { + &dev_attr_name.attr, + &dev_attr_date.attr, + &dev_attr_time.attr, + &dev_attr_since_epoch.attr, + &dev_attr_max_user_freq.attr, + &dev_attr_hctosys.attr, + &dev_attr_wakealarm.attr, + &dev_attr_offset.attr, + &dev_attr_range.attr, + NULL, +}; + +/* The reason to trigger an alarm with no process watching it (via sysfs) + * is its side effect: waking from a system state like suspend-to-RAM or + * suspend-to-disk. So: no attribute unless that side effect is possible. + * (Userspace may disable that mechanism later.) + */ +static bool rtc_does_wakealarm(struct rtc_device *rtc) +{ + if (!device_can_wakeup(rtc->dev.parent)) + return false; + + return rtc->ops->set_alarm != NULL; +} + +static umode_t rtc_attr_is_visible(struct kobject *kobj, + struct attribute *attr, int n) +{ + struct device *dev = container_of(kobj, struct device, kobj); + struct rtc_device *rtc = to_rtc_device(dev); + umode_t mode = attr->mode; + + if (attr == &dev_attr_wakealarm.attr) { + if (!rtc_does_wakealarm(rtc)) + mode = 0; + } else if (attr == &dev_attr_offset.attr) { + if (!rtc->ops->set_offset) + mode = 0; + } else if (attr == &dev_attr_range.attr) { + if (!(rtc->range_max - rtc->range_min)) + mode = 0; + } + + return mode; +} + +static struct attribute_group rtc_attr_group = { + .is_visible = rtc_attr_is_visible, + .attrs = rtc_attrs, +}; + +static const struct attribute_group *rtc_attr_groups[] = { + &rtc_attr_group, + NULL +}; + +const struct attribute_group **rtc_get_dev_attribute_groups(void) +{ + return rtc_attr_groups; +} + +int rtc_add_groups(struct rtc_device *rtc, const struct attribute_group **grps) +{ + size_t old_cnt = 0, add_cnt = 0, new_cnt; + const struct attribute_group **groups, **old; + + if (rtc->registered) + return -EINVAL; + if (!grps) + return -EINVAL; + + groups = rtc->dev.groups; + if (groups) + for (; *groups; groups++) + old_cnt++; + + for (groups = grps; *groups; groups++) + add_cnt++; + + new_cnt = old_cnt + add_cnt + 1; + groups = devm_kcalloc(&rtc->dev, new_cnt, sizeof(*groups), GFP_KERNEL); + if (!groups) + return -ENOMEM; + memcpy(groups, rtc->dev.groups, old_cnt * sizeof(*groups)); + memcpy(groups + old_cnt, grps, add_cnt * sizeof(*groups)); + groups[old_cnt + add_cnt] = NULL; + + old = rtc->dev.groups; + rtc->dev.groups = groups; + if (old && old != rtc_attr_groups) + devm_kfree(&rtc->dev, old); + + return 0; +} +EXPORT_SYMBOL(rtc_add_groups); + +int rtc_add_group(struct rtc_device *rtc, const struct attribute_group *grp) +{ + const struct attribute_group *groups[] = { grp, NULL }; + + return rtc_add_groups(rtc, groups); +} +EXPORT_SYMBOL(rtc_add_group); diff --git a/include/linux/rtc.h b/include/linux/rtc.h @@ -87,15 +87,16 @@ struct rtc_class_ops { int (*set_offset)(struct device *, long offset); }; +struct rtc_device; + struct rtc_timer { struct timerqueue_node node; ktime_t period; - void (*func)(void *private_data); - void *private_data; + void (*func)(struct rtc_device *rtc); + struct rtc_device *rtc; int enabled; }; - /* flags */ #define RTC_DEV_BUSY 0 @@ -138,7 +139,6 @@ struct rtc_device { bool registered; - struct nvmem_device *nvmem; /* Old ABI support */ bool nvram_old_abi; struct bin_attribute *nvram; @@ -173,8 +173,6 @@ extern struct rtc_device *devm_rtc_device_register(struct device *dev, 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 devm_rtc_device_unregister(struct device *dev, - struct rtc_device *rtc); extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm); extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm); @@ -200,11 +198,12 @@ extern int rtc_dev_update_irq_enable_emul(struct rtc_device *rtc, unsigned int enabled); void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode); -void rtc_aie_update_irq(void *private); -void rtc_uie_update_irq(void *private); +void rtc_aie_update_irq(struct rtc_device *rtc); +void rtc_uie_update_irq(struct rtc_device *rtc); enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer); -void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data); +void rtc_timer_init(struct rtc_timer *timer, void (*f)(struct rtc_device *r), + struct rtc_device *rtc); int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer, ktime_t expires, ktime_t period); void rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer); diff --git a/lib/test_printf.c b/lib/test_printf.c @@ -9,6 +9,7 @@ #include <linux/module.h> #include <linux/printk.h> #include <linux/random.h> +#include <linux/rtc.h> #include <linux/slab.h> #include <linux/string.h> @@ -249,12 +250,11 @@ plain_format(void) #endif /* BITS_PER_LONG == 64 */ static int __init -plain_hash(void) +plain_hash_to_buffer(const void *p, char *buf, size_t len) { - char buf[PLAIN_BUF_SIZE]; int nchars; - nchars = snprintf(buf, PLAIN_BUF_SIZE, "%p", PTR); + nchars = snprintf(buf, len, "%p", p); if (nchars != PTR_WIDTH) return -1; @@ -265,6 +265,20 @@ plain_hash(void) return 0; } + return 0; +} + + +static int __init +plain_hash(void) +{ + char buf[PLAIN_BUF_SIZE]; + int ret; + + ret = plain_hash_to_buffer(PTR, buf, PLAIN_BUF_SIZE); + if (ret) + return ret; + if (strncmp(buf, PTR_STR, PTR_WIDTH) == 0) return -1; @@ -295,6 +309,23 @@ plain(void) } static void __init +test_hashed(const char *fmt, const void *p) +{ + char buf[PLAIN_BUF_SIZE]; + int ret; + + /* + * No need to increase failed test counter since this is assumed + * to be called after plain(). + */ + ret = plain_hash_to_buffer(p, buf, PLAIN_BUF_SIZE); + if (ret) + return; + + test(buf, fmt, p); +} + +static void __init symbol_ptr(void) { } @@ -419,6 +450,29 @@ struct_va_format(void) } static void __init +struct_rtc_time(void) +{ + /* 1543210543 */ + const struct rtc_time tm = { + .tm_sec = 43, + .tm_min = 35, + .tm_hour = 5, + .tm_mday = 26, + .tm_mon = 10, + .tm_year = 118, + }; + + test_hashed("%pt", &tm); + + test("2018-11-26T05:35:43", "%ptR", &tm); + test("0118-10-26T05:35:43", "%ptRr", &tm); + test("05:35:43|2018-11-26", "%ptRt|%ptRd", &tm, &tm); + test("05:35:43|0118-10-26", "%ptRtr|%ptRdr", &tm, &tm); + test("05:35:43|2018-11-26", "%ptRttr|%ptRdtr", &tm, &tm); + test("05:35:43 tr|2018-11-26 tr", "%ptRt tr|%ptRd tr", &tm, &tm); +} + +static void __init struct_clk(void) { } @@ -529,6 +583,7 @@ test_pointer(void) uuid(); dentry(); struct_va_format(); + struct_rtc_time(); struct_clk(); bitmap(); netdev_features(); diff --git a/lib/vsprintf.c b/lib/vsprintf.c @@ -30,6 +30,7 @@ #include <linux/ioport.h> #include <linux/dcache.h> #include <linux/cred.h> +#include <linux/rtc.h> #include <linux/uuid.h> #include <linux/of.h> #include <net/addrconf.h> @@ -822,6 +823,20 @@ static const struct printf_spec default_dec_spec = { .precision = -1, }; +static const struct printf_spec default_dec02_spec = { + .base = 10, + .field_width = 2, + .precision = -1, + .flags = ZEROPAD, +}; + +static const struct printf_spec default_dec04_spec = { + .base = 10, + .field_width = 4, + .precision = -1, + .flags = ZEROPAD, +}; + static noinline_for_stack char *resource_string(char *buf, char *end, struct resource *res, struct printf_spec spec, const char *fmt) @@ -1550,6 +1565,87 @@ char *address_val(char *buf, char *end, const void *addr, const char *fmt) } static noinline_for_stack +char *date_str(char *buf, char *end, const struct rtc_time *tm, bool r) +{ + int year = tm->tm_year + (r ? 0 : 1900); + int mon = tm->tm_mon + (r ? 0 : 1); + + buf = number(buf, end, year, default_dec04_spec); + if (buf < end) + *buf = '-'; + buf++; + + buf = number(buf, end, mon, default_dec02_spec); + if (buf < end) + *buf = '-'; + buf++; + + return number(buf, end, tm->tm_mday, default_dec02_spec); +} + +static noinline_for_stack +char *time_str(char *buf, char *end, const struct rtc_time *tm, bool r) +{ + buf = number(buf, end, tm->tm_hour, default_dec02_spec); + if (buf < end) + *buf = ':'; + buf++; + + buf = number(buf, end, tm->tm_min, default_dec02_spec); + if (buf < end) + *buf = ':'; + buf++; + + return number(buf, end, tm->tm_sec, default_dec02_spec); +} + +static noinline_for_stack +char *rtc_str(char *buf, char *end, const struct rtc_time *tm, const char *fmt) +{ + bool have_t = true, have_d = true; + bool raw = false; + int count = 2; + + switch (fmt[count]) { + case 'd': + have_t = false; + count++; + break; + case 't': + have_d = false; + count++; + break; + } + + raw = fmt[count] == 'r'; + + if (have_d) + buf = date_str(buf, end, tm, raw); + if (have_d && have_t) { + /* Respect ISO 8601 */ + if (buf < end) + *buf = 'T'; + buf++; + } + if (have_t) + buf = time_str(buf, end, tm, raw); + + return buf; +} + +static noinline_for_stack +char *time_and_date(char *buf, char *end, void *ptr, struct printf_spec spec, + const char *fmt) +{ + switch (fmt[1]) { + case 'R': + return rtc_str(buf, end, (const struct rtc_time *)ptr, fmt); + default: + return ptr_to_id(buf, end, ptr, spec); + } +} + +static noinline_for_stack char *clock(char *buf, char *end, struct clk *clk, struct printf_spec spec, const char *fmt) { @@ -1828,6 +1924,8 @@ char *device_node_string(char *buf, char *end, struct device_node *dn, * - 'd[234]' For a dentry name (optionally 2-4 last components) * - 'D[234]' Same as 'd' but for a struct file * - 'g' For block_device name (gendisk + partition number) + * - 't[R][dt][r]' For time and date as represented: + * R struct rtc_time * - 'C' For a clock, it prints the name (Common Clock Framework) or address * (legacy clock framework) of the clock * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address @@ -1952,6 +2050,8 @@ char *pointer(const char *fmt, char *buf, char *end, void *ptr, return address_val(buf, end, ptr, fmt); case 'd': return dentry_name(buf, end, ptr, spec, fmt); + case 't': + return time_and_date(buf, end, ptr, spec, fmt); case 'C': return clock(buf, end, ptr, spec, fmt); case 'D':