Commit 75242f31 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull RTC updates from Alexandre Belloni:
 "Two new drivers this cycle and a significant rework of the CMOS driver
  make the bulk of the changes.

  I also carry powerpc changes with the agreement of Michael.

  New drivers:
   - Sunplus SP7021 RTC
   - Nintendo GameCube, Wii and Wii U RTC

  Driver updates:
   - cmos: refactor UIP handling and presence check, fix century
   - rs5c372: offset correction support, report low voltage
   - rv8803: Epson RX8804 support"

* tag 'rtc-5.17' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (33 commits)
  rtc: sunplus: fix return value in sp_rtc_probe()
  rtc: cmos: Evaluate century appropriate
  rtc: gamecube: Fix an IS_ERR() vs NULL check
  rtc: mc146818-lib: fix signedness bug in mc146818_get_time()
  dt-bindings: rtc: qcom-pm8xxx-rtc: update register numbers
  rtc: pxa: fix null pointer dereference
  rtc: ftrtc010: Use platform_get_irq() to get the interrupt
  rtc: Move variable into switch case statement
  rtc: pcf2127: Fix typo in comment
  dt-bindings: rtc: Add Sunplus RTC json-schema
  rtc: Add driver for RTC in Sunplus SP7021
  rtc: rs5c372: fix incorrect oscillation value on r2221tl
  rtc: rs5c372: add offset correction support
  rtc: cmos: avoid UIP when writing alarm time
  rtc: cmos: avoid UIP when reading alarm time
  rtc: mc146818-lib: refactor mc146818_does_rtc_work
  rtc: mc146818-lib: refactor mc146818_get_time
  rtc: mc146818-lib: extract mc146818_avoid_UIP
  rtc: mc146818-lib: fix RTC presence check
  rtc: Check return value from mc146818_get_time()
  ...
parents c2c94b3b 5ceee540
...@@ -15,6 +15,7 @@ allOf: ...@@ -15,6 +15,7 @@ allOf:
properties: properties:
compatible: compatible:
enum: enum:
- epson,rx8804
- epson,rx8900 - epson,rx8900
- microcrystal,rv8803 - microcrystal,rv8803
......
...@@ -19,7 +19,14 @@ properties: ...@@ -19,7 +19,14 @@ properties:
- qcom,pmk8350-rtc - qcom,pmk8350-rtc
reg: reg:
maxItems: 1 minItems: 1
maxItems: 2
reg-names:
minItems: 1
items:
- const: rtc
- const: alarm
interrupts: interrupts:
maxItems: 1 maxItems: 1
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
# Copyright (C) Sunplus Co., Ltd. 2021
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/sunplus,sp7021-rtc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Sunplus SP7021 Real Time Clock controller
maintainers:
- Vincent Shih <vincent.sunplus@gmail.com>
properties:
compatible:
const: sunplus,sp7021-rtc
reg:
maxItems: 1
reg-names:
items:
- const: rtc
clocks:
maxItems: 1
resets:
maxItems: 1
interrupts:
maxItems: 1
required:
- compatible
- reg
- reg-names
- clocks
- resets
- interrupts
additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
rtc: serial@9c003a00 {
compatible = "sunplus,sp7021-rtc";
reg = <0x9c003a00 0x80>;
reg-names = "rtc";
clocks = <&clkc 0x12>;
resets = <&rstc 0x02>;
interrupt-parent = <&intc>;
interrupts = <163 IRQ_TYPE_EDGE_RISING>;
};
...
...@@ -18491,6 +18491,13 @@ L: netdev@vger.kernel.org ...@@ -18491,6 +18491,13 @@ L: netdev@vger.kernel.org
S: Maintained S: Maintained
F: drivers/net/ethernet/dlink/sundance.c F: drivers/net/ethernet/dlink/sundance.c
SUNPLUS RTC DRIVER
M: Vincent Shih <vincent.sunplus@gmail.com>
L: linux-rtc@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/rtc/sunplus,sp7021-rtc.yaml
F: drivers/rtc/rtc-sunplus.c
SUPERH SUPERH
M: Yoshinori Sato <ysato@users.sourceforge.jp> M: Yoshinori Sato <ysato@users.sourceforge.jp>
M: Rich Felker <dalias@libc.org> M: Rich Felker <dalias@libc.org>
......
...@@ -80,7 +80,12 @@ init_rtc_epoch(void) ...@@ -80,7 +80,12 @@ init_rtc_epoch(void)
static int static int
alpha_rtc_read_time(struct device *dev, struct rtc_time *tm) alpha_rtc_read_time(struct device *dev, struct rtc_time *tm)
{ {
mc146818_get_time(tm); int ret = mc146818_get_time(tm);
if (ret < 0) {
dev_err_ratelimited(dev, "unable to read current time\n");
return ret;
}
/* Adjust for non-default epochs. It's easier to depend on the /* Adjust for non-default epochs. It's easier to depend on the
generic __get_rtc_time and adjust the epoch here than create generic __get_rtc_time and adjust the epoch here than create
......
...@@ -168,6 +168,11 @@ PIC1: pic1@d800030 { ...@@ -168,6 +168,11 @@ PIC1: pic1@d800030 {
interrupts = <14>; interrupts = <14>;
}; };
srnprot@d800060 {
compatible = "nintendo,hollywood-srnprot";
reg = <0x0d800060 0x4>;
};
GPIO: gpio@d8000c0 { GPIO: gpio@d8000c0 {
#gpio-cells = <2>; #gpio-cells = <2>;
compatible = "nintendo,hollywood-gpio"; compatible = "nintendo,hollywood-gpio";
......
...@@ -68,7 +68,7 @@ CONFIG_SND_SEQUENCER=y ...@@ -68,7 +68,7 @@ CONFIG_SND_SEQUENCER=y
CONFIG_SND_SEQUENCER_OSS=y CONFIG_SND_SEQUENCER_OSS=y
# CONFIG_USB_SUPPORT is not set # CONFIG_USB_SUPPORT is not set
CONFIG_RTC_CLASS=y CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_GENERIC=y CONFIG_RTC_DRV_GAMECUBE=y
CONFIG_EXT2_FS=y CONFIG_EXT2_FS=y
CONFIG_EXT4_FS=y CONFIG_EXT4_FS=y
CONFIG_ISO9660_FS=y CONFIG_ISO9660_FS=y
......
...@@ -98,7 +98,7 @@ CONFIG_LEDS_TRIGGERS=y ...@@ -98,7 +98,7 @@ CONFIG_LEDS_TRIGGERS=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_PANIC=y CONFIG_LEDS_TRIGGER_PANIC=y
CONFIG_RTC_CLASS=y CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_GENERIC=y CONFIG_RTC_DRV_GAMECUBE=y
CONFIG_NVMEM_NINTENDO_OTP=y CONFIG_NVMEM_NINTENDO_OTP=y
CONFIG_EXT2_FS=y CONFIG_EXT2_FS=y
CONFIG_EXT4_FS=y CONFIG_EXT4_FS=y
......
...@@ -1435,8 +1435,12 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id) ...@@ -1435,8 +1435,12 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
hpet_rtc_timer_reinit(); hpet_rtc_timer_reinit();
memset(&curr_time, 0, sizeof(struct rtc_time)); memset(&curr_time, 0, sizeof(struct rtc_time));
if (hpet_rtc_flags & (RTC_UIE | RTC_AIE)) if (hpet_rtc_flags & (RTC_UIE | RTC_AIE)) {
mc146818_get_time(&curr_time); if (unlikely(mc146818_get_time(&curr_time) < 0)) {
pr_err_ratelimited("unable to read current time from RTC\n");
return IRQ_HANDLED;
}
}
if (hpet_rtc_flags & RTC_UIE && if (hpet_rtc_flags & RTC_UIE &&
curr_time.tm_sec != hpet_prev_update_sec) { curr_time.tm_sec != hpet_prev_update_sec) {
......
...@@ -120,7 +120,11 @@ static unsigned int read_magic_time(void) ...@@ -120,7 +120,11 @@ static unsigned int read_magic_time(void)
struct rtc_time time; struct rtc_time time;
unsigned int val; unsigned int val;
mc146818_get_time(&time); if (mc146818_get_time(&time) < 0) {
pr_err("Unable to read current time from RTC\n");
return 0;
}
pr_info("RTC time: %ptRt, date: %ptRd\n", &time, &time); pr_info("RTC time: %ptRt, date: %ptRd\n", &time, &time);
val = time.tm_year; /* 100 years */ val = time.tm_year; /* 100 years */
if (val > 100) if (val > 100)
......
...@@ -1216,6 +1216,17 @@ config RTC_DRV_V3020 ...@@ -1216,6 +1216,17 @@ config RTC_DRV_V3020
This driver can also be built as a module. If so, the module This driver can also be built as a module. If so, the module
will be called rtc-v3020. will be called rtc-v3020.
config RTC_DRV_GAMECUBE
tristate "Nintendo GameCube, Wii and Wii U RTC"
depends on GAMECUBE || WII || COMPILE_TEST
select REGMAP
help
If you say yes here you will get support for the RTC subsystem
of the Nintendo GameCube, Wii and Wii U.
This driver can also be built as a module. If so, the module
will be called "rtc-gamecube".
config RTC_DRV_WM831X config RTC_DRV_WM831X
tristate "Wolfson Microelectronics WM831x RTC" tristate "Wolfson Microelectronics WM831x RTC"
depends on MFD_WM831X depends on MFD_WM831X
...@@ -1444,6 +1455,19 @@ config RTC_DRV_SH ...@@ -1444,6 +1455,19 @@ config RTC_DRV_SH
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called rtc-sh. module will be called rtc-sh.
config RTC_DRV_SUNPLUS
tristate "Sunplus SP7021 RTC"
depends on SOC_SP7021
help
Say 'yes' to get support for the real-time clock present in
Sunplus SP7021 - a SoC for industrial applications. It provides
RTC status check, timer/alarm functionalities, user data
reservation with the battery over 2.5V, RTC power status check
and battery charge.
This driver can also be built as a module. If so, the module
will be called rtc-sunplus.
config RTC_DRV_VR41XX config RTC_DRV_VR41XX
tristate "NEC VR41XX" tristate "NEC VR41XX"
depends on CPU_VR41XX || COMPILE_TEST depends on CPU_VR41XX || COMPILE_TEST
......
...@@ -111,6 +111,7 @@ obj-$(CONFIG_RTC_DRV_MT7622) += rtc-mt7622.o ...@@ -111,6 +111,7 @@ obj-$(CONFIG_RTC_DRV_MT7622) += rtc-mt7622.o
obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc.o obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc.o
obj-$(CONFIG_RTC_DRV_MXC_V2) += rtc-mxc_v2.o obj-$(CONFIG_RTC_DRV_MXC_V2) += rtc-mxc_v2.o
obj-$(CONFIG_RTC_DRV_GAMECUBE) += rtc-gamecube.o
obj-$(CONFIG_RTC_DRV_NTXEC) += rtc-ntxec.o obj-$(CONFIG_RTC_DRV_NTXEC) += rtc-ntxec.o
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o obj-$(CONFIG_RTC_DRV_OPAL) += rtc-opal.o
...@@ -165,6 +166,7 @@ obj-$(CONFIG_RTC_DRV_STM32) += rtc-stm32.o ...@@ -165,6 +166,7 @@ obj-$(CONFIG_RTC_DRV_STM32) += rtc-stm32.o
obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o
obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o obj-$(CONFIG_RTC_DRV_SUN6I) += rtc-sun6i.o
obj-$(CONFIG_RTC_DRV_SUNPLUS) += rtc-sunplus.o
obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o
obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
......
...@@ -391,14 +391,14 @@ static long rtc_dev_ioctl(struct file *file, ...@@ -391,14 +391,14 @@ static long rtc_dev_ioctl(struct file *file,
} }
switch(param.param) { switch(param.param) {
long offset;
case RTC_PARAM_FEATURES: case RTC_PARAM_FEATURES:
if (param.index != 0) if (param.index != 0)
err = -EINVAL; err = -EINVAL;
param.uvalue = rtc->features[0]; param.uvalue = rtc->features[0];
break; break;
case RTC_PARAM_CORRECTION: case RTC_PARAM_CORRECTION: {
long offset;
mutex_unlock(&rtc->ops_lock); mutex_unlock(&rtc->ops_lock);
if (param.index != 0) if (param.index != 0)
return -EINVAL; return -EINVAL;
...@@ -407,7 +407,7 @@ static long rtc_dev_ioctl(struct file *file, ...@@ -407,7 +407,7 @@ static long rtc_dev_ioctl(struct file *file,
if (err == 0) if (err == 0)
param.svalue = offset; param.svalue = offset;
break; break;
}
default: default:
if (rtc->ops->param_get) if (rtc->ops->param_get)
err = rtc->ops->param_get(rtc->dev.parent, &param); err = rtc->ops->param_get(rtc->dev.parent, &param);
......
...@@ -222,6 +222,8 @@ static inline void cmos_write_bank2(unsigned char val, unsigned char addr) ...@@ -222,6 +222,8 @@ static inline void cmos_write_bank2(unsigned char val, unsigned char addr)
static int cmos_read_time(struct device *dev, struct rtc_time *t) static int cmos_read_time(struct device *dev, struct rtc_time *t)
{ {
int ret;
/* /*
* If pm_trace abused the RTC for storage, set the timespec to 0, * If pm_trace abused the RTC for storage, set the timespec to 0,
* which tells the caller that this RTC value is unusable. * which tells the caller that this RTC value is unusable.
...@@ -229,7 +231,12 @@ static int cmos_read_time(struct device *dev, struct rtc_time *t) ...@@ -229,7 +231,12 @@ static int cmos_read_time(struct device *dev, struct rtc_time *t)
if (!pm_trace_rtc_valid()) if (!pm_trace_rtc_valid())
return -EIO; return -EIO;
mc146818_get_time(t); ret = mc146818_get_time(t);
if (ret < 0) {
dev_err_ratelimited(dev, "unable to read current time\n");
return ret;
}
return 0; return 0;
} }
...@@ -242,10 +249,46 @@ static int cmos_set_time(struct device *dev, struct rtc_time *t) ...@@ -242,10 +249,46 @@ static int cmos_set_time(struct device *dev, struct rtc_time *t)
return mc146818_set_time(t); return mc146818_set_time(t);
} }
struct cmos_read_alarm_callback_param {
struct cmos_rtc *cmos;
struct rtc_time *time;
unsigned char rtc_control;
};
static void cmos_read_alarm_callback(unsigned char __always_unused seconds,
void *param_in)
{
struct cmos_read_alarm_callback_param *p =
(struct cmos_read_alarm_callback_param *)param_in;
struct rtc_time *time = p->time;
time->tm_sec = CMOS_READ(RTC_SECONDS_ALARM);
time->tm_min = CMOS_READ(RTC_MINUTES_ALARM);
time->tm_hour = CMOS_READ(RTC_HOURS_ALARM);
if (p->cmos->day_alrm) {
/* ignore upper bits on readback per ACPI spec */
time->tm_mday = CMOS_READ(p->cmos->day_alrm) & 0x3f;
if (!time->tm_mday)
time->tm_mday = -1;
if (p->cmos->mon_alrm) {
time->tm_mon = CMOS_READ(p->cmos->mon_alrm);
if (!time->tm_mon)
time->tm_mon = -1;
}
}
p->rtc_control = CMOS_READ(RTC_CONTROL);
}
static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t) static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
{ {
struct cmos_rtc *cmos = dev_get_drvdata(dev); struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char rtc_control; struct cmos_read_alarm_callback_param p = {
.cmos = cmos,
.time = &t->time,
};
/* This not only a rtc_op, but also called directly */ /* This not only a rtc_op, but also called directly */
if (!is_valid_irq(cmos->irq)) if (!is_valid_irq(cmos->irq))
...@@ -256,28 +299,18 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t) ...@@ -256,28 +299,18 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
* the future. * the future.
*/ */
spin_lock_irq(&rtc_lock); /* Some Intel chipsets disconnect the alarm registers when the clock
t->time.tm_sec = CMOS_READ(RTC_SECONDS_ALARM); * update is in progress - during this time reads return bogus values
t->time.tm_min = CMOS_READ(RTC_MINUTES_ALARM); * and writes may fail silently. See for example "7th Generation Intel®
t->time.tm_hour = CMOS_READ(RTC_HOURS_ALARM); * Processor Family I/O for U/Y Platforms [...] Datasheet", section
* 27.7.1
if (cmos->day_alrm) { *
/* ignore upper bits on readback per ACPI spec */ * Use the mc146818_avoid_UIP() function to avoid this.
t->time.tm_mday = CMOS_READ(cmos->day_alrm) & 0x3f; */
if (!t->time.tm_mday) if (!mc146818_avoid_UIP(cmos_read_alarm_callback, &p))
t->time.tm_mday = -1; return -EIO;
if (cmos->mon_alrm) {
t->time.tm_mon = CMOS_READ(cmos->mon_alrm);
if (!t->time.tm_mon)
t->time.tm_mon = -1;
}
}
rtc_control = CMOS_READ(RTC_CONTROL);
spin_unlock_irq(&rtc_lock);
if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { if (!(p.rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
if (((unsigned)t->time.tm_sec) < 0x60) if (((unsigned)t->time.tm_sec) < 0x60)
t->time.tm_sec = bcd2bin(t->time.tm_sec); t->time.tm_sec = bcd2bin(t->time.tm_sec);
else else
...@@ -306,7 +339,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t) ...@@ -306,7 +339,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
} }
} }
t->enabled = !!(rtc_control & RTC_AIE); t->enabled = !!(p.rtc_control & RTC_AIE);
t->pending = 0; t->pending = 0;
return 0; return 0;
...@@ -437,10 +470,57 @@ static int cmos_validate_alarm(struct device *dev, struct rtc_wkalrm *t) ...@@ -437,10 +470,57 @@ static int cmos_validate_alarm(struct device *dev, struct rtc_wkalrm *t)
return 0; return 0;
} }
struct cmos_set_alarm_callback_param {
struct cmos_rtc *cmos;
unsigned char mon, mday, hrs, min, sec;
struct rtc_wkalrm *t;
};
/* Note: this function may be executed by mc146818_avoid_UIP() more then
* once
*/
static void cmos_set_alarm_callback(unsigned char __always_unused seconds,
void *param_in)
{
struct cmos_set_alarm_callback_param *p =
(struct cmos_set_alarm_callback_param *)param_in;
/* next rtc irq must not be from previous alarm setting */
cmos_irq_disable(p->cmos, RTC_AIE);
/* update alarm */
CMOS_WRITE(p->hrs, RTC_HOURS_ALARM);
CMOS_WRITE(p->min, RTC_MINUTES_ALARM);
CMOS_WRITE(p->sec, RTC_SECONDS_ALARM);
/* the system may support an "enhanced" alarm */
if (p->cmos->day_alrm) {
CMOS_WRITE(p->mday, p->cmos->day_alrm);
if (p->cmos->mon_alrm)
CMOS_WRITE(p->mon, p->cmos->mon_alrm);
}
if (use_hpet_alarm()) {
/*
* FIXME the HPET alarm glue currently ignores day_alrm
* and mon_alrm ...
*/
hpet_set_alarm_time(p->t->time.tm_hour, p->t->time.tm_min,
p->t->time.tm_sec);
}
if (p->t->enabled)
cmos_irq_enable(p->cmos, RTC_AIE);
}
static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{ {
struct cmos_rtc *cmos = dev_get_drvdata(dev); struct cmos_rtc *cmos = dev_get_drvdata(dev);
unsigned char mon, mday, hrs, min, sec, rtc_control; struct cmos_set_alarm_callback_param p = {
.cmos = cmos,
.t = t
};
unsigned char rtc_control;
int ret; int ret;
/* This not only a rtc_op, but also called directly */ /* This not only a rtc_op, but also called directly */
...@@ -451,52 +531,33 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t) ...@@ -451,52 +531,33 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
if (ret < 0) if (ret < 0)
return ret; return ret;
mon = t->time.tm_mon + 1; p.mon = t->time.tm_mon + 1;
mday = t->time.tm_mday; p.mday = t->time.tm_mday;
hrs = t->time.tm_hour; p.hrs = t->time.tm_hour;
min = t->time.tm_min; p.min = t->time.tm_min;
sec = t->time.tm_sec; p.sec = t->time.tm_sec;
spin_lock_irq(&rtc_lock);
rtc_control = CMOS_READ(RTC_CONTROL); rtc_control = CMOS_READ(RTC_CONTROL);
spin_unlock_irq(&rtc_lock);
if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) { if (!(rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
/* Writing 0xff means "don't care" or "match all". */ /* Writing 0xff means "don't care" or "match all". */
mon = (mon <= 12) ? bin2bcd(mon) : 0xff; p.mon = (p.mon <= 12) ? bin2bcd(p.mon) : 0xff;
mday = (mday >= 1 && mday <= 31) ? bin2bcd(mday) : 0xff; p.mday = (p.mday >= 1 && p.mday <= 31) ? bin2bcd(p.mday) : 0xff;
hrs = (hrs < 24) ? bin2bcd(hrs) : 0xff; p.hrs = (p.hrs < 24) ? bin2bcd(p.hrs) : 0xff;
min = (min < 60) ? bin2bcd(min) : 0xff; p.min = (p.min < 60) ? bin2bcd(p.min) : 0xff;
sec = (sec < 60) ? bin2bcd(sec) : 0xff; p.sec = (p.sec < 60) ? bin2bcd(p.sec) : 0xff;
}
spin_lock_irq(&rtc_lock);
/* next rtc irq must not be from previous alarm setting */
cmos_irq_disable(cmos, RTC_AIE);
/* update alarm */
CMOS_WRITE(hrs, RTC_HOURS_ALARM);
CMOS_WRITE(min, RTC_MINUTES_ALARM);
CMOS_WRITE(sec, RTC_SECONDS_ALARM);
/* the system may support an "enhanced" alarm */
if (cmos->day_alrm) {
CMOS_WRITE(mday, cmos->day_alrm);
if (cmos->mon_alrm)
CMOS_WRITE(mon, cmos->mon_alrm);
} }
if (use_hpet_alarm()) { /*
/* * Some Intel chipsets disconnect the alarm registers when the clock
* FIXME the HPET alarm glue currently ignores day_alrm * update is in progress - during this time writes fail silently.
* and mon_alrm ... *
*/ * Use mc146818_avoid_UIP() to avoid this.
hpet_set_alarm_time(t->time.tm_hour, t->time.tm_min, */
t->time.tm_sec); if (!mc146818_avoid_UIP(cmos_set_alarm_callback, &p))
} return -EIO;
if (t->enabled)
cmos_irq_enable(cmos, RTC_AIE);
spin_unlock_irq(&rtc_lock);
cmos->alarm_expires = rtc_tm_to_time64(&t->time); cmos->alarm_expires = rtc_tm_to_time64(&t->time);
...@@ -790,16 +851,14 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq) ...@@ -790,16 +851,14 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
rename_region(ports, dev_name(&cmos_rtc.rtc->dev)); rename_region(ports, dev_name(&cmos_rtc.rtc->dev));
spin_lock_irq(&rtc_lock); if (!mc146818_does_rtc_work()) {
dev_warn(dev, "broken or not accessible\n");
/* Ensure that the RTC is accessible. Bit 6 must be 0! */
if ((CMOS_READ(RTC_VALID) & 0x40) != 0) {
spin_unlock_irq(&rtc_lock);
dev_warn(dev, "not accessible\n");
retval = -ENXIO; retval = -ENXIO;
goto cleanup1; goto cleanup1;
} }
spin_lock_irq(&rtc_lock);
if (!(flags & CMOS_RTC_FLAGS_NOFREQ)) { if (!(flags & CMOS_RTC_FLAGS_NOFREQ)) {
/* force periodic irq to CMOS reset default of 1024Hz; /* force periodic irq to CMOS reset default of 1024Hz;
* *
......
...@@ -475,12 +475,14 @@ static int da9063_rtc_probe(struct platform_device *pdev) ...@@ -475,12 +475,14 @@ static int da9063_rtc_probe(struct platform_device *pdev)
da9063_data_to_tm(data, &rtc->alarm_time, rtc); da9063_data_to_tm(data, &rtc->alarm_time, rtc);
rtc->rtc_sync = false; rtc->rtc_sync = false;
/* if (config->rtc_data_start != RTC_SEC) {
* TODO: some models have alarms on a minute boundary but still support set_bit(RTC_FEATURE_ALARM_RES_MINUTE, rtc->rtc_dev->features);
* real hardware interrupts. Add this once the core supports it. /*
*/ * TODO: some models have alarms on a minute boundary but still
if (config->rtc_data_start != RTC_SEC) * support real hardware interrupts.
rtc->rtc_dev->uie_unsupported = 1; */
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtc_dev->features);
}
irq_alarm = platform_get_irq_byname(pdev, "ALARM"); irq_alarm = platform_get_irq_byname(pdev, "ALARM");
if (irq_alarm < 0) if (irq_alarm < 0)
...@@ -494,6 +496,8 @@ static int da9063_rtc_probe(struct platform_device *pdev) ...@@ -494,6 +496,8 @@ static int da9063_rtc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n", dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n",
irq_alarm, ret); irq_alarm, ret);
device_init_wakeup(&pdev->dev, true);
return devm_rtc_register_device(rtc->rtc_dev); return devm_rtc_register_device(rtc->rtc_dev);
} }
......
...@@ -141,11 +141,9 @@ static int ftrtc010_rtc_probe(struct platform_device *pdev) ...@@ -141,11 +141,9 @@ static int ftrtc010_rtc_probe(struct platform_device *pdev)
} }
} }
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); rtc->rtc_irq = platform_get_irq(pdev, 0);
if (!res) if (rtc->rtc_irq < 0)
return -ENODEV; return rtc->rtc_irq;
rtc->rtc_irq = res->start;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0); res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) if (!res)
......
This diff is collapsed.
...@@ -8,48 +8,100 @@ ...@@ -8,48 +8,100 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#endif #endif
unsigned int mc146818_get_time(struct rtc_time *time) /*
* Execute a function while the UIP (Update-in-progress) bit of the RTC is
* unset.
*
* Warning: callback may be executed more then once.
*/
bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
void *param)
{ {
unsigned char ctrl; int i;
unsigned long flags; unsigned long flags;
unsigned char century = 0; unsigned char seconds;
bool retry;
#ifdef CONFIG_MACH_DECSTATION for (i = 0; i < 10; i++) {
unsigned int real_year; spin_lock_irqsave(&rtc_lock, flags);
#endif
again: /*
spin_lock_irqsave(&rtc_lock, flags); * Check whether there is an update in progress during which the
/* Ensure that the RTC is accessible. Bit 6 must be 0! */ * readout is unspecified. The maximum update time is ~2ms. Poll
if (WARN_ON_ONCE((CMOS_READ(RTC_VALID) & 0x40) != 0)) { * every msec for completion.
spin_unlock_irqrestore(&rtc_lock, flags); *
memset(time, 0xff, sizeof(*time)); * Store the second value before checking UIP so a long lasting
return 0; * NMI which happens to hit after the UIP check cannot make
} * an update cycle invisible.
*/
seconds = CMOS_READ(RTC_SECONDS);
/* if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
* Check whether there is an update in progress during which the spin_unlock_irqrestore(&rtc_lock, flags);
* readout is unspecified. The maximum update time is ~2ms. Poll mdelay(1);
* every msec for completion. continue;
* }
* Store the second value before checking UIP so a long lasting NMI
* which happens to hit after the UIP check cannot make an update
* cycle invisible.
*/
time->tm_sec = CMOS_READ(RTC_SECONDS);
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) { /* Revalidate the above readout */
spin_unlock_irqrestore(&rtc_lock, flags); if (seconds != CMOS_READ(RTC_SECONDS)) {
mdelay(1); spin_unlock_irqrestore(&rtc_lock, flags);
goto again; continue;
} }
/* Revalidate the above readout */ if (callback)
if (time->tm_sec != CMOS_READ(RTC_SECONDS)) { callback(seconds, param);
/*
* Check for the UIP bit again. If it is set now then
* the above values may contain garbage.
*/
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
spin_unlock_irqrestore(&rtc_lock, flags);
mdelay(1);
continue;
}
/*
* A NMI might have interrupted the above sequence so check
* whether the seconds value has changed which indicates that
* the NMI took longer than the UIP bit was set. Unlikely, but
* possible and there is also virt...
*/
if (seconds != CMOS_READ(RTC_SECONDS)) {
spin_unlock_irqrestore(&rtc_lock, flags);
continue;
}
spin_unlock_irqrestore(&rtc_lock, flags); spin_unlock_irqrestore(&rtc_lock, flags);
goto again;
return true;
} }
return false;
}
EXPORT_SYMBOL_GPL(mc146818_avoid_UIP);
/*
* If the UIP (Update-in-progress) bit of the RTC is set for more then
* 10ms, the RTC is apparently broken or not present.
*/
bool mc146818_does_rtc_work(void)
{
return mc146818_avoid_UIP(NULL, NULL);
}
EXPORT_SYMBOL_GPL(mc146818_does_rtc_work);
struct mc146818_get_time_callback_param {
struct rtc_time *time;
unsigned char ctrl;
#ifdef CONFIG_ACPI
unsigned char century;
#endif
#ifdef CONFIG_MACH_DECSTATION
unsigned int real_year;
#endif
};
static void mc146818_get_time_callback(unsigned char seconds, void *param_in)
{
struct mc146818_get_time_callback_param *p = param_in;
/* /*
* Only the values that we read from the RTC are set. We leave * Only the values that we read from the RTC are set. We leave
...@@ -57,39 +109,39 @@ unsigned int mc146818_get_time(struct rtc_time *time) ...@@ -57,39 +109,39 @@ unsigned int mc146818_get_time(struct rtc_time *time)
* RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated * RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
* by the RTC when initially set to a non-zero value. * by the RTC when initially set to a non-zero value.
*/ */
time->tm_min = CMOS_READ(RTC_MINUTES); p->time->tm_sec = seconds;
time->tm_hour = CMOS_READ(RTC_HOURS); p->time->tm_min = CMOS_READ(RTC_MINUTES);
time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH); p->time->tm_hour = CMOS_READ(RTC_HOURS);
time->tm_mon = CMOS_READ(RTC_MONTH); p->time->tm_mday = CMOS_READ(RTC_DAY_OF_MONTH);
time->tm_year = CMOS_READ(RTC_YEAR); p->time->tm_mon = CMOS_READ(RTC_MONTH);
p->time->tm_year = CMOS_READ(RTC_YEAR);
#ifdef CONFIG_MACH_DECSTATION #ifdef CONFIG_MACH_DECSTATION
real_year = CMOS_READ(RTC_DEC_YEAR); p->real_year = CMOS_READ(RTC_DEC_YEAR);
#endif #endif
#ifdef CONFIG_ACPI #ifdef CONFIG_ACPI
if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
acpi_gbl_FADT.century) acpi_gbl_FADT.century) {
century = CMOS_READ(acpi_gbl_FADT.century); p->century = CMOS_READ(acpi_gbl_FADT.century);
} else {
p->century = 0;
}
#endif #endif
ctrl = CMOS_READ(RTC_CONTROL);
/*
* Check for the UIP bit again. If it is set now then
* the above values may contain garbage.
*/
retry = CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP;
/*
* A NMI might have interrupted the above sequence so check whether
* the seconds value has changed which indicates that the NMI took
* longer than the UIP bit was set. Unlikely, but possible and
* there is also virt...
*/
retry |= time->tm_sec != CMOS_READ(RTC_SECONDS);
spin_unlock_irqrestore(&rtc_lock, flags); p->ctrl = CMOS_READ(RTC_CONTROL);
}
if (retry) int mc146818_get_time(struct rtc_time *time)
goto again; {
struct mc146818_get_time_callback_param p = {
.time = time
};
if (!mc146818_avoid_UIP(mc146818_get_time_callback, &p)) {
memset(time, 0, sizeof(*time));
return -EIO;
}
if (!(ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD) if (!(p.ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
{ {
time->tm_sec = bcd2bin(time->tm_sec); time->tm_sec = bcd2bin(time->tm_sec);
time->tm_min = bcd2bin(time->tm_min); time->tm_min = bcd2bin(time->tm_min);
...@@ -97,15 +149,19 @@ unsigned int mc146818_get_time(struct rtc_time *time) ...@@ -97,15 +149,19 @@ unsigned int mc146818_get_time(struct rtc_time *time)
time->tm_mday = bcd2bin(time->tm_mday); time->tm_mday = bcd2bin(time->tm_mday);
time->tm_mon = bcd2bin(time->tm_mon); time->tm_mon = bcd2bin(time->tm_mon);
time->tm_year = bcd2bin(time->tm_year); time->tm_year = bcd2bin(time->tm_year);
century = bcd2bin(century); #ifdef CONFIG_ACPI
p.century = bcd2bin(p.century);
#endif
} }
#ifdef CONFIG_MACH_DECSTATION #ifdef CONFIG_MACH_DECSTATION
time->tm_year += real_year - 72; time->tm_year += p.real_year - 72;
#endif #endif
if (century > 20) #ifdef CONFIG_ACPI
time->tm_year += (century - 19) * 100; if (p.century > 19)
time->tm_year += (p.century - 19) * 100;
#endif
/* /*
* Account for differences between how the RTC uses the values * Account for differences between how the RTC uses the values
...@@ -116,7 +172,7 @@ unsigned int mc146818_get_time(struct rtc_time *time) ...@@ -116,7 +172,7 @@ unsigned int mc146818_get_time(struct rtc_time *time)
time->tm_mon--; time->tm_mon--;
return RTC_24H; return 0;
} }
EXPORT_SYMBOL_GPL(mc146818_get_time); EXPORT_SYMBOL_GPL(mc146818_get_time);
......
...@@ -748,7 +748,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap, ...@@ -748,7 +748,7 @@ static int pcf2127_probe(struct device *dev, struct regmap *regmap,
/* /*
* Enable timestamp function and store timestamp of first trigger * Enable timestamp function and store timestamp of first trigger
* event until TSF1 and TFS2 interrupt flags are cleared. * event until TSF1 and TSF2 interrupt flags are cleared.
*/ */
ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_TS_CTRL, ret = regmap_update_bits(pcf2127->regmap, PCF2127_REG_TS_CTRL,
PCF2127_BIT_TS_CTRL_TSOFF | PCF2127_BIT_TS_CTRL_TSOFF |
......
...@@ -514,21 +514,56 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063) ...@@ -514,21 +514,56 @@ static struct clk *pcf85063_clkout_register_clk(struct pcf85063 *pcf85063)
} }
#endif #endif
static const struct pcf85063_config pcf85063tp_config = { enum pcf85063_type {
.regmap = { PCF85063,
.reg_bits = 8, PCF85063TP,
.val_bits = 8, PCF85063A,
.max_register = 0x0a, RV8263,
PCF85063_LAST_ID
};
static struct pcf85063_config pcf85063_cfg[] = {
[PCF85063] = {
.regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x0a,
},
},
[PCF85063TP] = {
.regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x0a,
},
},
[PCF85063A] = {
.regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x11,
},
.has_alarms = 1,
},
[RV8263] = {
.regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x11,
},
.has_alarms = 1,
.force_cap_7000 = 1,
}, },
}; };
static const struct i2c_device_id pcf85063_ids[];
static int pcf85063_probe(struct i2c_client *client) static int pcf85063_probe(struct i2c_client *client)
{ {
struct pcf85063 *pcf85063; struct pcf85063 *pcf85063;
unsigned int tmp; unsigned int tmp;
int err; int err;
const struct pcf85063_config *config = &pcf85063tp_config; const struct pcf85063_config *config;
const void *data = of_device_get_match_data(&client->dev);
struct nvmem_config nvmem_cfg = { struct nvmem_config nvmem_cfg = {
.name = "pcf85063_nvram", .name = "pcf85063_nvram",
.reg_read = pcf85063_nvmem_read, .reg_read = pcf85063_nvmem_read,
...@@ -544,8 +579,17 @@ static int pcf85063_probe(struct i2c_client *client) ...@@ -544,8 +579,17 @@ static int pcf85063_probe(struct i2c_client *client)
if (!pcf85063) if (!pcf85063)
return -ENOMEM; return -ENOMEM;
if (data) if (client->dev.of_node) {
config = data; config = of_device_get_match_data(&client->dev);
if (!config)
return -ENODEV;
} else {
enum pcf85063_type type =
i2c_match_id(pcf85063_ids, client)->driver_data;
if (type >= PCF85063_LAST_ID)
return -ENODEV;
config = &pcf85063_cfg[type];
}
pcf85063->regmap = devm_regmap_init_i2c(client, &config->regmap); pcf85063->regmap = devm_regmap_init_i2c(client, &config->regmap);
if (IS_ERR(pcf85063->regmap)) if (IS_ERR(pcf85063->regmap))
...@@ -604,31 +648,21 @@ static int pcf85063_probe(struct i2c_client *client) ...@@ -604,31 +648,21 @@ static int pcf85063_probe(struct i2c_client *client)
return devm_rtc_register_device(pcf85063->rtc); return devm_rtc_register_device(pcf85063->rtc);
} }
#ifdef CONFIG_OF static const struct i2c_device_id pcf85063_ids[] = {
static const struct pcf85063_config pcf85063a_config = { { "pcf85063", PCF85063 },
.regmap = { { "pcf85063tp", PCF85063TP },
.reg_bits = 8, { "pcf85063a", PCF85063A },
.val_bits = 8, { "rv8263", RV8263 },
.max_register = 0x11, {}
},
.has_alarms = 1,
};
static const struct pcf85063_config rv8263_config = {
.regmap = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x11,
},
.has_alarms = 1,
.force_cap_7000 = 1,
}; };
MODULE_DEVICE_TABLE(i2c, pcf85063_ids);
#ifdef CONFIG_OF
static const struct of_device_id pcf85063_of_match[] = { static const struct of_device_id pcf85063_of_match[] = {
{ .compatible = "nxp,pcf85063", .data = &pcf85063tp_config }, { .compatible = "nxp,pcf85063", .data = &pcf85063_cfg[PCF85063] },
{ .compatible = "nxp,pcf85063tp", .data = &pcf85063tp_config }, { .compatible = "nxp,pcf85063tp", .data = &pcf85063_cfg[PCF85063TP] },
{ .compatible = "nxp,pcf85063a", .data = &pcf85063a_config }, { .compatible = "nxp,pcf85063a", .data = &pcf85063_cfg[PCF85063A] },
{ .compatible = "microcrystal,rv8263", .data = &rv8263_config }, { .compatible = "microcrystal,rv8263", .data = &pcf85063_cfg[RV8263] },
{} {}
}; };
MODULE_DEVICE_TABLE(of, pcf85063_of_match); MODULE_DEVICE_TABLE(of, pcf85063_of_match);
...@@ -640,6 +674,7 @@ static struct i2c_driver pcf85063_driver = { ...@@ -640,6 +674,7 @@ static struct i2c_driver pcf85063_driver = {
.of_match_table = of_match_ptr(pcf85063_of_match), .of_match_table = of_match_ptr(pcf85063_of_match),
}, },
.probe_new = pcf85063_probe, .probe_new = pcf85063_probe,
.id_table = pcf85063_ids,
}; };
module_i2c_driver(pcf85063_driver); module_i2c_driver(pcf85063_driver);
......
...@@ -330,6 +330,10 @@ static int __init pxa_rtc_probe(struct platform_device *pdev) ...@@ -330,6 +330,10 @@ static int __init pxa_rtc_probe(struct platform_device *pdev)
if (sa1100_rtc->irq_alarm < 0) if (sa1100_rtc->irq_alarm < 0)
return -ENXIO; return -ENXIO;
sa1100_rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(sa1100_rtc->rtc))
return PTR_ERR(sa1100_rtc->rtc);
pxa_rtc->base = devm_ioremap(dev, pxa_rtc->ress->start, pxa_rtc->base = devm_ioremap(dev, pxa_rtc->ress->start,
resource_size(pxa_rtc->ress)); resource_size(pxa_rtc->ress));
if (!pxa_rtc->base) { if (!pxa_rtc->base) {
......
...@@ -28,8 +28,10 @@ ...@@ -28,8 +28,10 @@
#define RS5C372_REG_MONTH 5 #define RS5C372_REG_MONTH 5
#define RS5C372_REG_YEAR 6 #define RS5C372_REG_YEAR 6
#define RS5C372_REG_TRIM 7 #define RS5C372_REG_TRIM 7
# define RS5C372_TRIM_XSL 0x80 # define RS5C372_TRIM_XSL 0x80 /* only if RS5C372[a|b] */
# define RS5C372_TRIM_MASK 0x7F # define RS5C372_TRIM_MASK 0x7F
# define R2221TL_TRIM_DEV (1 << 7) /* only if R2221TL */
# define RS5C372_TRIM_DECR (1 << 6)
#define RS5C_REG_ALARM_A_MIN 8 /* or ALARM_W */ #define RS5C_REG_ALARM_A_MIN 8 /* or ALARM_W */
#define RS5C_REG_ALARM_A_HOURS 9 #define RS5C_REG_ALARM_A_HOURS 9
...@@ -324,8 +326,12 @@ static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim) ...@@ -324,8 +326,12 @@ static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim)
struct rs5c372 *rs5c372 = i2c_get_clientdata(client); struct rs5c372 *rs5c372 = i2c_get_clientdata(client);
u8 tmp = rs5c372->regs[RS5C372_REG_TRIM]; u8 tmp = rs5c372->regs[RS5C372_REG_TRIM];
if (osc) if (osc) {
*osc = (tmp & RS5C372_TRIM_XSL) ? 32000 : 32768; if (rs5c372->type == rtc_rs5c372a || rs5c372->type == rtc_rs5c372b)
*osc = (tmp & RS5C372_TRIM_XSL) ? 32000 : 32768;
else
*osc = 32768;
}
if (trim) { if (trim) {
dev_dbg(&client->dev, "%s: raw trim=%x\n", __func__, tmp); dev_dbg(&client->dev, "%s: raw trim=%x\n", __func__, tmp);
...@@ -485,6 +491,176 @@ static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq) ...@@ -485,6 +491,176 @@ static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq)
#define rs5c372_rtc_proc NULL #define rs5c372_rtc_proc NULL
#endif #endif
#ifdef CONFIG_RTC_INTF_DEV
static int rs5c372_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
struct rs5c372 *rs5c = i2c_get_clientdata(to_i2c_client(dev));
unsigned char ctrl2;
int addr;
unsigned int flags;
dev_dbg(dev, "%s: cmd=%x\n", __func__, cmd);
addr = RS5C_ADDR(RS5C_REG_CTRL2);
ctrl2 = i2c_smbus_read_byte_data(rs5c->client, addr);
switch (cmd) {
case RTC_VL_READ:
flags = 0;
switch (rs5c->type) {
case rtc_r2025sd:
case rtc_r2221tl:
if ((rs5c->type == rtc_r2025sd && !(ctrl2 & R2x2x_CTRL2_XSTP)) ||
(rs5c->type == rtc_r2221tl && (ctrl2 & R2x2x_CTRL2_XSTP))) {
flags |= RTC_VL_DATA_INVALID;
}
if (ctrl2 & R2x2x_CTRL2_VDET)
flags |= RTC_VL_BACKUP_LOW;
break;
default:
if (ctrl2 & RS5C_CTRL2_XSTP)
flags |= RTC_VL_DATA_INVALID;
break;
}
return put_user(flags, (unsigned int __user *)arg);
case RTC_VL_CLR:
/* clear VDET bit */
if (rs5c->type == rtc_r2025sd || rs5c->type == rtc_r2221tl) {
ctrl2 &= ~R2x2x_CTRL2_VDET;
if (i2c_smbus_write_byte_data(rs5c->client, addr, ctrl2) < 0) {
dev_dbg(&rs5c->client->dev, "%s: write error in line %i\n",
__func__, __LINE__);
return -EIO;
}
}
return 0;
default:
return -ENOIOCTLCMD;
}
return 0;
}
#else
#define rs5c372_ioctl NULL
#endif
static int rs5c372_read_offset(struct device *dev, long *offset)
{
struct rs5c372 *rs5c = i2c_get_clientdata(to_i2c_client(dev));
u8 val = rs5c->regs[RS5C372_REG_TRIM];
long ppb_per_step = 0;
bool decr = val & RS5C372_TRIM_DECR;
switch (rs5c->type) {
case rtc_r2221tl:
ppb_per_step = val & R2221TL_TRIM_DEV ? 1017 : 3051;
break;
case rtc_rs5c372a:
case rtc_rs5c372b:
ppb_per_step = val & RS5C372_TRIM_XSL ? 3125 : 3051;
break;
default:
ppb_per_step = 3051;
break;
}
/* Only bits[0:5] repsents the time counts */
val &= 0x3F;
/* If bits[1:5] are all 0, it means no increment or decrement */
if (!(val & 0x3E)) {
*offset = 0;
} else {
if (decr)
*offset = -(((~val) & 0x3F) + 1) * ppb_per_step;
else
*offset = (val - 1) * ppb_per_step;
}
return 0;
}
static int rs5c372_set_offset(struct device *dev, long offset)
{
struct rs5c372 *rs5c = i2c_get_clientdata(to_i2c_client(dev));
int addr = RS5C_ADDR(RS5C372_REG_TRIM);
u8 val = 0;
u8 tmp = 0;
long ppb_per_step = 3051;
long steps = LONG_MIN;
switch (rs5c->type) {
case rtc_rs5c372a:
case rtc_rs5c372b:
tmp = rs5c->regs[RS5C372_REG_TRIM];
if (tmp & RS5C372_TRIM_XSL) {
ppb_per_step = 3125;
val |= RS5C372_TRIM_XSL;
}
break;
case rtc_r2221tl:
/*
* Check if it is possible to use high resolution mode (DEV=1).
* In this mode, the minimum resolution is 2 / (32768 * 20 * 3),
* which is about 1017 ppb.
*/
steps = DIV_ROUND_CLOSEST(offset, 1017);
if (steps >= -0x3E && steps <= 0x3E) {
ppb_per_step = 1017;
val |= R2221TL_TRIM_DEV;
} else {
/*
* offset is out of the range of high resolution mode.
* Try to use low resolution mode (DEV=0). In this mode,
* the minimum resolution is 2 / (32768 * 20), which is
* about 3051 ppb.
*/
steps = LONG_MIN;
}
break;
default:
break;
}
if (steps == LONG_MIN) {
steps = DIV_ROUND_CLOSEST(offset, ppb_per_step);
if (steps > 0x3E || steps < -0x3E)
return -ERANGE;
}
if (steps > 0) {
val |= steps + 1;
} else {
val |= RS5C372_TRIM_DECR;
val |= (~(-steps - 1)) & 0x3F;
}
if (!steps || !(val & 0x3E)) {
/*
* if offset is too small, set oscillation adjustment register
* or time trimming register with its default value whic means
* no increment or decrement. But for rs5c372[a|b], the XSL bit
* should be kept unchanged.
*/
if (rs5c->type == rtc_rs5c372a || rs5c->type == rtc_rs5c372b)
val &= RS5C372_TRIM_XSL;
else
val = 0;
}
dev_dbg(&rs5c->client->dev, "write 0x%x for offset %ld\n", val, offset);
if (i2c_smbus_write_byte_data(rs5c->client, addr, val) < 0) {
dev_err(&rs5c->client->dev, "failed to write 0x%x to reg %d\n", val, addr);
return -EIO;
}
rs5c->regs[RS5C372_REG_TRIM] = val;
return 0;
}
static const struct rtc_class_ops rs5c372_rtc_ops = { static const struct rtc_class_ops rs5c372_rtc_ops = {
.proc = rs5c372_rtc_proc, .proc = rs5c372_rtc_proc,
.read_time = rs5c372_rtc_read_time, .read_time = rs5c372_rtc_read_time,
...@@ -492,6 +668,9 @@ static const struct rtc_class_ops rs5c372_rtc_ops = { ...@@ -492,6 +668,9 @@ static const struct rtc_class_ops rs5c372_rtc_ops = {
.read_alarm = rs5c_read_alarm, .read_alarm = rs5c_read_alarm,
.set_alarm = rs5c_set_alarm, .set_alarm = rs5c_set_alarm,
.alarm_irq_enable = rs5c_rtc_alarm_irq_enable, .alarm_irq_enable = rs5c_rtc_alarm_irq_enable,
.ioctl = rs5c372_ioctl,
.read_offset = rs5c372_read_offset,
.set_offset = rs5c372_set_offset,
}; };
#if IS_ENABLED(CONFIG_RTC_INTF_SYSFS) #if IS_ENABLED(CONFIG_RTC_INTF_SYSFS)
......
...@@ -55,6 +55,7 @@ ...@@ -55,6 +55,7 @@
enum rv8803_type { enum rv8803_type {
rv_8803, rv_8803,
rx_8804,
rx_8900 rx_8900
}; };
...@@ -601,6 +602,7 @@ static int rv8803_probe(struct i2c_client *client, ...@@ -601,6 +602,7 @@ static int rv8803_probe(struct i2c_client *client,
static const struct i2c_device_id rv8803_id[] = { static const struct i2c_device_id rv8803_id[] = {
{ "rv8803", rv_8803 }, { "rv8803", rv_8803 },
{ "rv8804", rx_8804 },
{ "rx8803", rv_8803 }, { "rx8803", rv_8803 },
{ "rx8900", rx_8900 }, { "rx8900", rx_8900 },
{ } { }
...@@ -616,6 +618,10 @@ static const __maybe_unused struct of_device_id rv8803_of_match[] = { ...@@ -616,6 +618,10 @@ static const __maybe_unused struct of_device_id rv8803_of_match[] = {
.compatible = "epson,rx8803", .compatible = "epson,rx8803",
.data = (void *)rv_8803 .data = (void *)rv_8803
}, },
{
.compatible = "epson,rx8804",
.data = (void *)rx_8804
},
{ {
.compatible = "epson,rx8900", .compatible = "epson,rx8900",
.data = (void *)rx_8900 .data = (void *)rx_8900
......
This diff is collapsed.
...@@ -123,7 +123,11 @@ struct cmos_rtc_board_info { ...@@ -123,7 +123,11 @@ struct cmos_rtc_board_info {
#define RTC_IO_EXTENT_USED RTC_IO_EXTENT #define RTC_IO_EXTENT_USED RTC_IO_EXTENT
#endif /* ARCH_RTC_LOCATION */ #endif /* ARCH_RTC_LOCATION */
unsigned int mc146818_get_time(struct rtc_time *time); bool mc146818_does_rtc_work(void);
int mc146818_get_time(struct rtc_time *time);
int mc146818_set_time(struct rtc_time *time); int mc146818_set_time(struct rtc_time *time);
bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
void *param);
#endif /* _MC146818RTC_H */ #endif /* _MC146818RTC_H */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment