2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-11-15 06:05:13 +08:00

RTC for 6.8

Subsytem:
 
 New driver:
  - Analog Devices MAX31335
  - Nuvoton ma35d1
  - Texas Instrument TPS6594 PMIC RTC
 
 Drivers:
  - cmos: use ACPI alarm instead of HPET on recent AMD platforms
  - nuvoton: add NCT3015Y-R and NCT3018Y-R support
  - rv8803: proper suspend/resume and wakeup-source support
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEBqsFVZXh8s/0O5JiY6TcMGxwOjIFAmWpkqQACgkQY6TcMGxw
 OjJ2eQ//cDaUPgvOUQ2+qQiZOyOrjnck+QEyXZr2mcnNfRnMPiafJX09v3W4BMPh
 0oOVNF5BbGofTgJRnTC9BCRQnq8XZUwXaMr1B+mLQF4V9Xq3896pILkdRmd0q7EW
 3qwKCNP1vkYx2hGyWB9wVAMESAdUIFHCLxJWeQZ3ESGUacMoON0cdFa96TUx4fKa
 m29ybMTHRHKpnZsIYpegxG42lWp84IPvTbtySbT52dr2ucLToVos/dX23juQ40D0
 nyUa8Q+g6aLoTxjZPcFwK6dHJJIwWz56s40IbMRGr6dVfRis5QZfIQ/cB8ULj48L
 AkCtN6kptVsov/W2R9ZriTf5p53K7Fmwz+dhccW7SxA82cGyswWOD3BNzzOYnzPY
 pKSVeTnR7mD2IC28pGrekSpg3ExuNu/4+WHnz0EwpjgyXmtlxnfK6oV9nf8bIUsn
 JsY3tNOvenv8NQSQ1at3GugeQ4bGMbxay6pL9zm5EZjYGMDX0z7IcPFr9KeYC5tJ
 60dYWCGuB2JF0WocuAXSNrj2l9VFFqhn7OdDVuiB00rBROQcKKV/H30EnmAwRUI1
 8SZhVJ0TIeoG6XsajhbapvOH8EWUnKPn1mgJxSiyVR6Hz93oZldIPK3cUtfjcltx
 xl7LdVeseE1CXGh4g222CI0MCX6x1QPQ5L8jhgc67dyTUx/wQ4Q=
 =7u4i
 -----END PGP SIGNATURE-----

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

Pull RTC updates from Alexandre Belloni:
 "There are three new drivers this cycle. Also the cmos driver is
  getting fixes for longstanding wakeup issues on AMD.

  New drivers:
   - Analog Devices MAX31335
   - Nuvoton ma35d1
   - Texas Instrument TPS6594 PMIC RTC

  Drivers:
   - cmos: use ACPI alarm instead of HPET on recent AMD platforms
   - nuvoton: add NCT3015Y-R and NCT3018Y-R support
   - rv8803: proper suspend/resume and wakeup-source support"

* tag 'rtc-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (26 commits)
  rtc: nuvoton: Compatible with NCT3015Y-R and NCT3018Y-R
  rtc: da9063: Use dev_err_probe()
  rtc: da9063: Use device_get_match_data()
  rtc: da9063: Make IRQ as optional
  rtc: max31335: Fix comparison in max31335_volatile_reg()
  rtc: max31335: use regmap_update_bits_check
  rtc: max31335: remove unecessary locking
  rtc: max31335: add driver support
  dt-bindings: rtc: max31335: add max31335 bindings
  rtc: rv8803: add wakeup-source support
  rtc: ac100: remove misuses of kernel-doc
  rtc: class: Remove usage of the deprecated ida_simple_xx() API
  rtc: MAINTAINERS: drop Alessandro Zummo
  rtc: ma35d1: remove hardcoded UIE support
  dt-bindings: rtc: qcom-pm8xxx: fix inconsistent example
  rtc: rv8803: Add power management support
  rtc: ds3232: avoid unused-const-variable warning
  rtc: lpc24xx: add missing dependency
  rtc: tps6594: Add driver for TPS6594 RTC
  rtc: Add driver for Nuvoton ma35d1 rtc controller
  ...
This commit is contained in:
Linus Torvalds 2024-01-18 17:25:39 -08:00
commit 378de6df19
23 changed files with 1819 additions and 105 deletions

View File

@ -0,0 +1,70 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/adi,max31335.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Analog Devices MAX31335 RTC
maintainers:
- Antoniu Miclaus <antoniu.miclaus@analog.com>
description:
Analog Devices MAX31335 I2C RTC ±2ppm Automotive Real-Time Clock with
Integrated MEMS Resonator.
allOf:
- $ref: rtc.yaml#
properties:
compatible:
const: adi,max31335
reg:
maxItems: 1
interrupts:
maxItems: 1
"#clock-cells":
description:
RTC can be used as a clock source through its clock output pin.
const: 0
adi,tc-diode:
description:
Select the diode configuration for the trickle charger.
schottky - Schottky diode in series.
standard+schottky - standard diode + Schottky diode in series.
enum: [schottky, standard+schottky]
trickle-resistor-ohms:
description:
Selected resistor for trickle charger. Should be specified if trickle
charger should be enabled.
enum: [3000, 6000, 11000]
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
rtc@68 {
compatible = "adi,max31335";
reg = <0x68>;
pinctrl-0 = <&rtc_nint_pins>;
interrupts-extended = <&gpio1 16 IRQ_TYPE_LEVEL_HIGH>;
aux-voltage-chargeable = <1>;
trickle-resistor-ohms = <6000>;
adi,tc-diode = "schottky";
};
};
...

View File

@ -29,6 +29,8 @@ properties:
trickle-diode-disable: true
wakeup-source: true
required:
- compatible
- reg

View File

@ -0,0 +1,48 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/nuvoton,ma35d1-rtc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Nuvoton MA35D1 Real Time Clock
maintainers:
- Min-Jen Chen <mjchen@nuvoton.com>
allOf:
- $ref: rtc.yaml#
properties:
compatible:
enum:
- nuvoton,ma35d1-rtc
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
required:
- compatible
- reg
- interrupts
- clocks
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/nuvoton,ma35d1-clk.h>
rtc@40410000 {
compatible = "nuvoton,ma35d1-rtc";
reg = <0x40410000 0x200>;
interrupts = <GIC_SPI 5 IRQ_TYPE_EDGE_RISING>;
clocks = <&clk RTC_GATE>;
};
...

View File

@ -61,27 +61,27 @@ additionalProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/spmi/spmi.h>
spmi_bus: spmi@c440000 {
reg = <0x0c440000 0x1100>;
#address-cells = <2>;
#size-cells = <0>;
pmicintc: pmic@0 {
reg = <0x0 SPMI_USID>;
compatible = "qcom,pm8921";
interrupts = <104 8>;
#interrupt-cells = <2>;
interrupt-controller;
#address-cells = <1>;
spmi {
#address-cells = <2>;
#size-cells = <0>;
pm8921_rtc: rtc@11d {
compatible = "qcom,pm8921-rtc";
reg = <0x11d>;
interrupts = <0x27 0>;
nvmem-cells = <&rtc_offset>;
nvmem-cell-names = "offset";
pmic@0 {
compatible = "qcom,pm8941", "qcom,spmi-pmic";
reg = <0x0 SPMI_USID>;
#address-cells = <1>;
#size-cells = <0>;
rtc@6000 {
compatible = "qcom,pm8941-rtc";
reg = <0x6000>, <0x6100>;
reg-names = "rtc", "alarm";
interrupts = <0x0 0x61 0x1 IRQ_TYPE_EDGE_RISING>;
nvmem-cells = <&rtc_offset>;
nvmem-cell-names = "offset";
};
};
};
};
...

View File

@ -13126,6 +13126,14 @@ F: Documentation/devicetree/bindings/hwmon/adi,max31827.yaml
F: Documentation/hwmon/max31827.rst
F: drivers/hwmon/max31827.c
MAX31335 RTC DRIVER
M: Antoniu Miclaus <antoniu.miclaus@analog.com>
L: linux-rtc@vger.kernel.org
S: Supported
W: https://ez.analog.com/linux-software-drivers
F: Documentation/devicetree/bindings/rtc/adi,max31335.yaml
F: drivers/rtc/rtc-max31335.c
MAX6650 HARDWARE MONITOR AND FAN CONTROLLER DRIVER
L: linux-hwmon@vger.kernel.org
S: Orphan
@ -18451,7 +18459,6 @@ X: include/linux/srcu*.h
X: kernel/rcu/srcu*.c
REAL TIME CLOCK (RTC) SUBSYSTEM
M: Alessandro Zummo <a.zummo@towertech.it>
M: Alexandre Belloni <alexandre.belloni@bootlin.com>
L: linux-rtc@vger.kernel.org
S: Maintained

View File

@ -80,7 +80,7 @@ init_rtc_epoch(void)
static int
alpha_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
int ret = mc146818_get_time(tm);
int ret = mc146818_get_time(tm, 10);
if (ret < 0) {
dev_err_ratelimited(dev, "unable to read current time\n");

View File

@ -1438,7 +1438,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
memset(&curr_time, 0, sizeof(struct rtc_time));
if (hpet_rtc_flags & (RTC_UIE | RTC_AIE)) {
if (unlikely(mc146818_get_time(&curr_time) < 0)) {
if (unlikely(mc146818_get_time(&curr_time, 10) < 0)) {
pr_err_ratelimited("unable to read current time from RTC\n");
return IRQ_HANDLED;
}

View File

@ -67,7 +67,7 @@ void mach_get_cmos_time(struct timespec64 *now)
return;
}
if (mc146818_get_time(&tm)) {
if (mc146818_get_time(&tm, 1000)) {
pr_err("Unable to read current time from RTC\n");
now->tv_sec = now->tv_nsec = 0;
return;

View File

@ -120,7 +120,7 @@ static unsigned int read_magic_time(void)
struct rtc_time time;
unsigned int val;
if (mc146818_get_time(&time) < 0) {
if (mc146818_get_time(&time, 1000) < 0) {
pr_err("Unable to read current time from RTC\n");
return 0;
}

View File

@ -373,6 +373,19 @@ config RTC_DRV_MAX8997
This driver can also be built as a module. If so, the module
will be called rtc-max8997.
config RTC_DRV_MAX31335
tristate "Analog Devices MAX31335"
depends on I2C
depends on COMMON_CLK
depends on HWMON || HWMON=n
select REGMAP_I2C
help
If you say yes here you get support for the Analog Devices
MAX31335.
This driver can also be built as a module. If so, the module
will be called rtc-max31335.
config RTC_DRV_MAX77686
tristate "Maxim MAX77686"
depends on MFD_MAX77686 || MFD_MAX77620 || MFD_MAX77714 || COMPILE_TEST
@ -578,6 +591,18 @@ config RTC_DRV_TPS6586X
along with alarm. This driver supports the RTC driver for
the TPS6586X RTC module.
config RTC_DRV_TPS6594
tristate "TI TPS6594 RTC driver"
depends on MFD_TPS6594
default MFD_TPS6594
help
TI Power Management IC TPS6594 supports RTC functionality
along with alarm. This driver supports the RTC driver for
the TPS6594 RTC module.
This driver can also be built as a module. If so, the module
will be called rtc-tps6594.
config RTC_DRV_TPS65910
tristate "TI TPS65910 RTC driver"
depends on MFD_TPS65910
@ -1705,6 +1730,7 @@ config RTC_DRV_LPC24XX
tristate "NXP RTC for LPC178x/18xx/408x/43xx"
depends on ARCH_LPC18XX || COMPILE_TEST
depends on OF && HAS_IOMEM
depends on COMMON_CLK
help
This enables support for the NXP RTC found which can be found on
NXP LPC178x/18xx/408x/43xx devices.
@ -1930,6 +1956,17 @@ config RTC_DRV_TI_K3
This driver can also be built as a module, if so, the module
will be called "rtc-ti-k3".
config RTC_DRV_MA35D1
tristate "Nuvoton MA35D1 RTC"
depends on ARCH_MA35 || COMPILE_TEST
select REGMAP_MMIO
help
If you say yes here you get support for the Nuvoton MA35D1
On-Chip Real Time Clock.
This driver can also be built as a module, if so, the module
will be called "rtc-ma35d1".
comment "HID Sensor RTC drivers"
config RTC_DRV_HID_SENSOR_TIME

View File

@ -88,6 +88,8 @@ obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o
obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o
obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
obj-$(CONFIG_RTC_DRV_MA35D1) += rtc-ma35d1.o
obj-$(CONFIG_RTC_DRV_MAX31335) += rtc-max31335.o
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
obj-$(CONFIG_RTC_DRV_MAX6916) += rtc-max6916.o
@ -176,6 +178,7 @@ obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
obj-$(CONFIG_RTC_DRV_TI_K3) += rtc-ti-k3.o
obj-$(CONFIG_RTC_DRV_TPS6586X) += rtc-tps6586x.o
obj-$(CONFIG_RTC_DRV_TPS6594) += rtc-tps6594.o
obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o
obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o
obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o

View File

@ -256,7 +256,7 @@ static int rtc_device_get_id(struct device *dev)
of_id = of_alias_get_id(dev->parent->of_node, "rtc");
if (of_id >= 0) {
id = ida_simple_get(&rtc_ida, of_id, of_id + 1, GFP_KERNEL);
id = ida_alloc_range(&rtc_ida, of_id, of_id, GFP_KERNEL);
if (id < 0)
dev_warn(dev, "/aliases ID %d not available\n", of_id);
}

View File

@ -99,7 +99,7 @@ struct ac100_rtc_dev {
struct clk_hw_onecell_data *clk_data;
};
/**
/*
* Clock controls for 3 clock output pins
*/
@ -378,7 +378,7 @@ static void ac100_rtc_unregister_clks(struct ac100_rtc_dev *chip)
clk_unregister_fixed_rate(chip->rtc_32k_clk->clk);
}
/**
/*
* RTC related bits
*/
static int ac100_rtc_get_time(struct device *dev, struct rtc_time *rtc_tm)

View File

@ -231,7 +231,7 @@ static int cmos_read_time(struct device *dev, struct rtc_time *t)
if (!pm_trace_rtc_valid())
return -EIO;
ret = mc146818_get_time(t);
ret = mc146818_get_time(t, 1000);
if (ret < 0) {
dev_err_ratelimited(dev, "unable to read current time\n");
return ret;
@ -292,7 +292,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
/* This not only a rtc_op, but also called directly */
if (!is_valid_irq(cmos->irq))
return -EIO;
return -ETIMEDOUT;
/* Basic alarms only support hour, minute, and seconds fields.
* Some also support day and month, for alarms up to a year in
@ -307,7 +307,7 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
*
* Use the mc146818_avoid_UIP() function to avoid this.
*/
if (!mc146818_avoid_UIP(cmos_read_alarm_callback, &p))
if (!mc146818_avoid_UIP(cmos_read_alarm_callback, 10, &p))
return -EIO;
if (!(p.rtc_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
@ -556,8 +556,8 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
*
* Use mc146818_avoid_UIP() to avoid this.
*/
if (!mc146818_avoid_UIP(cmos_set_alarm_callback, &p))
return -EIO;
if (!mc146818_avoid_UIP(cmos_set_alarm_callback, 10, &p))
return -ETIMEDOUT;
cmos->alarm_expires = rtc_tm_to_time64(&t->time);
@ -818,18 +818,24 @@ static void rtc_wake_off(struct device *dev)
}
#ifdef CONFIG_X86
/* Enable use_acpi_alarm mode for Intel platforms no earlier than 2015 */
static void use_acpi_alarm_quirks(void)
{
if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
switch (boot_cpu_data.x86_vendor) {
case X86_VENDOR_INTEL:
if (dmi_get_bios_year() < 2015)
return;
break;
case X86_VENDOR_AMD:
case X86_VENDOR_HYGON:
if (dmi_get_bios_year() < 2021)
return;
break;
default:
return;
}
if (!is_hpet_enabled())
return;
if (dmi_get_bios_year() < 2015)
return;
use_acpi_alarm = true;
}
#else

View File

@ -377,7 +377,6 @@ static int da9063_rtc_probe(struct platform_device *pdev)
{
struct da9063_compatible_rtc *rtc;
const struct da9063_compatible_rtc_regmap *config;
const struct of_device_id *match;
int irq_alarm;
u8 data[RTC_DATA_LEN];
int ret;
@ -385,14 +384,11 @@ static int da9063_rtc_probe(struct platform_device *pdev)
if (!pdev->dev.of_node)
return -ENXIO;
match = of_match_node(da9063_compatible_reg_id_table,
pdev->dev.of_node);
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
rtc->config = match->data;
rtc->config = device_get_match_data(&pdev->dev);
if (of_device_is_compatible(pdev->dev.of_node, "dlg,da9063-rtc")) {
struct da9063 *chip = dev_get_drvdata(pdev->dev.parent);
@ -411,57 +407,49 @@ static int da9063_rtc_probe(struct platform_device *pdev)
config->rtc_enable_reg,
config->rtc_enable_mask,
config->rtc_enable_mask);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to enable RTC\n");
return ret;
}
if (ret < 0)
return dev_err_probe(&pdev->dev, ret, "Failed to enable RTC\n");
ret = regmap_update_bits(rtc->regmap,
config->rtc_enable_32k_crystal_reg,
config->rtc_crystal_mask,
config->rtc_crystal_mask);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to run 32kHz oscillator\n");
return ret;
}
if (ret < 0)
return dev_err_probe(&pdev->dev, ret,
"Failed to run 32kHz oscillator\n");
ret = regmap_update_bits(rtc->regmap,
config->rtc_alarm_secs_reg,
config->rtc_alarm_status_mask,
0);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to access RTC alarm register\n");
return ret;
}
if (ret < 0)
return dev_err_probe(&pdev->dev, ret,
"Failed to access RTC alarm register\n");
ret = regmap_update_bits(rtc->regmap,
config->rtc_alarm_secs_reg,
DA9063_ALARM_STATUS_ALARM,
DA9063_ALARM_STATUS_ALARM);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to access RTC alarm register\n");
return ret;
}
if (ret < 0)
return dev_err_probe(&pdev->dev, ret,
"Failed to access RTC alarm register\n");
ret = regmap_update_bits(rtc->regmap,
config->rtc_alarm_year_reg,
config->rtc_tick_on_mask,
0);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to disable TICKs\n");
return ret;
}
if (ret < 0)
return dev_err_probe(&pdev->dev, ret,
"Failed to disable TICKs\n");
data[RTC_SEC] = 0;
ret = regmap_bulk_read(rtc->regmap,
config->rtc_alarm_secs_reg,
&data[config->rtc_data_start],
config->rtc_alarm_len);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to read initial alarm data: %d\n",
ret);
return ret;
}
if (ret < 0)
return dev_err_probe(&pdev->dev, ret,
"Failed to read initial alarm data\n");
platform_set_drvdata(pdev, rtc);
@ -485,25 +473,29 @@ static int da9063_rtc_probe(struct platform_device *pdev)
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->rtc_dev->features);
}
irq_alarm = platform_get_irq_byname(pdev, "ALARM");
if (irq_alarm < 0)
irq_alarm = platform_get_irq_byname_optional(pdev, "ALARM");
if (irq_alarm >= 0) {
ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL,
da9063_alarm_event,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"ALARM", rtc);
if (ret)
dev_err(&pdev->dev,
"Failed to request ALARM IRQ %d: %d\n",
irq_alarm, ret);
ret = dev_pm_set_wake_irq(&pdev->dev, irq_alarm);
if (ret)
dev_warn(&pdev->dev,
"Failed to set IRQ %d as a wake IRQ: %d\n",
irq_alarm, ret);
device_init_wakeup(&pdev->dev, true);
} else if (irq_alarm != -ENXIO) {
return irq_alarm;
ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL,
da9063_alarm_event,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
"ALARM", rtc);
if (ret)
dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n",
irq_alarm, ret);
ret = dev_pm_set_wake_irq(&pdev->dev, irq_alarm);
if (ret)
dev_warn(&pdev->dev,
"Failed to set IRQ %d as a wake IRQ: %d\n",
irq_alarm, ret);
device_init_wakeup(&pdev->dev, true);
} else {
clear_bit(RTC_FEATURE_ALARM, rtc->rtc_dev->features);
}
return devm_rtc_register_device(rtc->rtc_dev);
}

View File

@ -536,6 +536,8 @@ static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
return 0;
}
#if IS_ENABLED(CONFIG_I2C)
#ifdef CONFIG_PM_SLEEP
static int ds3232_suspend(struct device *dev)
{
@ -564,8 +566,6 @@ static const struct dev_pm_ops ds3232_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume)
};
#if IS_ENABLED(CONFIG_I2C)
static int ds3232_i2c_probe(struct i2c_client *client)
{
struct regmap *regmap;

304
drivers/rtc/rtc-ma35d1.c Normal file
View File

@ -0,0 +1,304 @@
// SPDX-License-Identifier: GPL-2.0
/*
* RTC driver for Nuvoton MA35D1
*
* Copyright (C) 2023 Nuvoton Technology Corp.
*/
#include <linux/bcd.h>
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
/* MA35D1 RTC Control Registers */
#define MA35_REG_RTC_INIT 0x00
#define MA35_REG_RTC_SINFASTS 0x04
#define MA35_REG_RTC_FREQADJ 0x08
#define MA35_REG_RTC_TIME 0x0c
#define MA35_REG_RTC_CAL 0x10
#define MA35_REG_RTC_CLKFMT 0x14
#define MA35_REG_RTC_WEEKDAY 0x18
#define MA35_REG_RTC_TALM 0x1c
#define MA35_REG_RTC_CALM 0x20
#define MA35_REG_RTC_LEAPYEAR 0x24
#define MA35_REG_RTC_INTEN 0x28
#define MA35_REG_RTC_INTSTS 0x2c
/* register MA35_REG_RTC_INIT */
#define RTC_INIT_ACTIVE BIT(0)
#define RTC_INIT_MAGIC_CODE 0xa5eb1357
/* register MA35_REG_RTC_CLKFMT */
#define RTC_CLKFMT_24HEN BIT(0)
#define RTC_CLKFMT_DCOMPEN BIT(16)
/* register MA35_REG_RTC_INTEN */
#define RTC_INTEN_ALMIEN BIT(0)
#define RTC_INTEN_UIEN BIT(1)
#define RTC_INTEN_CLKFIEN BIT(24)
#define RTC_INTEN_CLKSTIEN BIT(25)
/* register MA35_REG_RTC_INTSTS */
#define RTC_INTSTS_ALMIF BIT(0)
#define RTC_INTSTS_UIF BIT(1)
#define RTC_INTSTS_CLKFIF BIT(24)
#define RTC_INTSTS_CLKSTIF BIT(25)
#define RTC_INIT_TIMEOUT 250
struct ma35_rtc {
int irq_num;
void __iomem *rtc_reg;
struct rtc_device *rtcdev;
};
static u32 rtc_reg_read(struct ma35_rtc *p, u32 offset)
{
return __raw_readl(p->rtc_reg + offset);
}
static inline void rtc_reg_write(struct ma35_rtc *p, u32 offset, u32 value)
{
__raw_writel(value, p->rtc_reg + offset);
}
static irqreturn_t ma35d1_rtc_interrupt(int irq, void *data)
{
struct ma35_rtc *rtc = (struct ma35_rtc *)data;
unsigned long events = 0, rtc_irq;
rtc_irq = rtc_reg_read(rtc, MA35_REG_RTC_INTSTS);
if (rtc_irq & RTC_INTSTS_ALMIF) {
rtc_reg_write(rtc, MA35_REG_RTC_INTSTS, RTC_INTSTS_ALMIF);
events |= RTC_AF | RTC_IRQF;
}
rtc_update_irq(rtc->rtcdev, 1, events);
return IRQ_HANDLED;
}
static int ma35d1_rtc_init(struct ma35_rtc *rtc, u32 ms_timeout)
{
const unsigned long timeout = jiffies + msecs_to_jiffies(ms_timeout);
do {
if (rtc_reg_read(rtc, MA35_REG_RTC_INIT) & RTC_INIT_ACTIVE)
return 0;
rtc_reg_write(rtc, MA35_REG_RTC_INIT, RTC_INIT_MAGIC_CODE);
mdelay(1);
} while (time_before(jiffies, timeout));
return -ETIMEDOUT;
}
static int ma35d1_alarm_irq_enable(struct device *dev, u32 enabled)
{
struct ma35_rtc *rtc = dev_get_drvdata(dev);
u32 reg_ien;
reg_ien = rtc_reg_read(rtc, MA35_REG_RTC_INTEN);
if (enabled)
rtc_reg_write(rtc, MA35_REG_RTC_INTEN, reg_ien | RTC_INTEN_ALMIEN);
else
rtc_reg_write(rtc, MA35_REG_RTC_INTEN, reg_ien & ~RTC_INTEN_ALMIEN);
return 0;
}
static int ma35d1_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct ma35_rtc *rtc = dev_get_drvdata(dev);
u32 time, cal, wday;
do {
time = rtc_reg_read(rtc, MA35_REG_RTC_TIME);
cal = rtc_reg_read(rtc, MA35_REG_RTC_CAL);
wday = rtc_reg_read(rtc, MA35_REG_RTC_WEEKDAY);
} while (time != rtc_reg_read(rtc, MA35_REG_RTC_TIME) ||
cal != rtc_reg_read(rtc, MA35_REG_RTC_CAL));
tm->tm_mday = bcd2bin(cal >> 0);
tm->tm_wday = wday;
tm->tm_mon = bcd2bin(cal >> 8);
tm->tm_mon = tm->tm_mon - 1;
tm->tm_year = bcd2bin(cal >> 16) + 100;
tm->tm_sec = bcd2bin(time >> 0);
tm->tm_min = bcd2bin(time >> 8);
tm->tm_hour = bcd2bin(time >> 16);
return rtc_valid_tm(tm);
}
static int ma35d1_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct ma35_rtc *rtc = dev_get_drvdata(dev);
u32 val;
val = bin2bcd(tm->tm_mday) << 0 | bin2bcd(tm->tm_mon + 1) << 8 |
bin2bcd(tm->tm_year - 100) << 16;
rtc_reg_write(rtc, MA35_REG_RTC_CAL, val);
val = bin2bcd(tm->tm_sec) << 0 | bin2bcd(tm->tm_min) << 8 |
bin2bcd(tm->tm_hour) << 16;
rtc_reg_write(rtc, MA35_REG_RTC_TIME, val);
val = tm->tm_wday;
rtc_reg_write(rtc, MA35_REG_RTC_WEEKDAY, val);
return 0;
}
static int ma35d1_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct ma35_rtc *rtc = dev_get_drvdata(dev);
u32 talm, calm;
talm = rtc_reg_read(rtc, MA35_REG_RTC_TALM);
calm = rtc_reg_read(rtc, MA35_REG_RTC_CALM);
alrm->time.tm_mday = bcd2bin(calm >> 0);
alrm->time.tm_mon = bcd2bin(calm >> 8);
alrm->time.tm_mon = alrm->time.tm_mon - 1;
alrm->time.tm_year = bcd2bin(calm >> 16) + 100;
alrm->time.tm_sec = bcd2bin(talm >> 0);
alrm->time.tm_min = bcd2bin(talm >> 8);
alrm->time.tm_hour = bcd2bin(talm >> 16);
return rtc_valid_tm(&alrm->time);
}
static int ma35d1_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct ma35_rtc *rtc = dev_get_drvdata(dev);
unsigned long val;
val = bin2bcd(alrm->time.tm_mday) << 0 | bin2bcd(alrm->time.tm_mon + 1) << 8 |
bin2bcd(alrm->time.tm_year - 100) << 16;
rtc_reg_write(rtc, MA35_REG_RTC_CALM, val);
val = bin2bcd(alrm->time.tm_sec) << 0 | bin2bcd(alrm->time.tm_min) << 8 |
bin2bcd(alrm->time.tm_hour) << 16;
rtc_reg_write(rtc, MA35_REG_RTC_TALM, val);
ma35d1_alarm_irq_enable(dev, alrm->enabled);
return 0;
}
static const struct rtc_class_ops ma35d1_rtc_ops = {
.read_time = ma35d1_rtc_read_time,
.set_time = ma35d1_rtc_set_time,
.read_alarm = ma35d1_rtc_read_alarm,
.set_alarm = ma35d1_rtc_set_alarm,
.alarm_irq_enable = ma35d1_alarm_irq_enable,
};
static int ma35d1_rtc_probe(struct platform_device *pdev)
{
struct ma35_rtc *rtc;
struct clk *clk;
int ret;
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
rtc->rtc_reg = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(rtc->rtc_reg))
return PTR_ERR(rtc->rtc_reg);
clk = of_clk_get(pdev->dev.of_node, 0);
if (IS_ERR(clk))
return dev_err_probe(&pdev->dev, PTR_ERR(clk), "failed to find rtc clock\n");
ret = clk_prepare_enable(clk);
if (ret)
return ret;
if (!(rtc_reg_read(rtc, MA35_REG_RTC_INIT) & RTC_INIT_ACTIVE)) {
ret = ma35d1_rtc_init(rtc, RTC_INIT_TIMEOUT);
if (ret)
return dev_err_probe(&pdev->dev, ret, "rtc init failed\n");
}
rtc->irq_num = platform_get_irq(pdev, 0);
ret = devm_request_irq(&pdev->dev, rtc->irq_num, ma35d1_rtc_interrupt,
IRQF_NO_SUSPEND, "ma35d1rtc", rtc);
if (ret)
return dev_err_probe(&pdev->dev, ret, "Failed to request rtc irq\n");
platform_set_drvdata(pdev, rtc);
device_init_wakeup(&pdev->dev, true);
rtc->rtcdev = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(rtc->rtcdev))
return PTR_ERR(rtc->rtcdev);
rtc->rtcdev->ops = &ma35d1_rtc_ops;
rtc->rtcdev->range_min = RTC_TIMESTAMP_BEGIN_2000;
rtc->rtcdev->range_max = RTC_TIMESTAMP_END_2099;
ret = devm_rtc_register_device(rtc->rtcdev);
if (ret)
return dev_err_probe(&pdev->dev, ret, "Failed to register rtc device\n");
return 0;
}
static int ma35d1_rtc_suspend(struct platform_device *pdev, pm_message_t state)
{
struct ma35_rtc *rtc = platform_get_drvdata(pdev);
if (device_may_wakeup(&pdev->dev))
enable_irq_wake(rtc->irq_num);
return 0;
}
static int ma35d1_rtc_resume(struct platform_device *pdev)
{
struct ma35_rtc *rtc = platform_get_drvdata(pdev);
if (device_may_wakeup(&pdev->dev))
disable_irq_wake(rtc->irq_num);
return 0;
}
static const struct of_device_id ma35d1_rtc_of_match[] = {
{ .compatible = "nuvoton,ma35d1-rtc", },
{},
};
MODULE_DEVICE_TABLE(of, ma35d1_rtc_of_match);
static struct platform_driver ma35d1_rtc_driver = {
.suspend = ma35d1_rtc_suspend,
.resume = ma35d1_rtc_resume,
.probe = ma35d1_rtc_probe,
.driver = {
.name = "rtc-ma35d1",
.of_match_table = ma35d1_rtc_of_match,
},
};
module_platform_driver(ma35d1_rtc_driver);
MODULE_AUTHOR("Ming-Jen Chen <mjchen@nuvoton.com>");
MODULE_DESCRIPTION("MA35D1 RTC driver");
MODULE_LICENSE("GPL");

697
drivers/rtc/rtc-max31335.c Normal file
View File

@ -0,0 +1,697 @@
// SPDX-License-Identifier: GPL-2.0
/*
* RTC driver for the MAX31335
*
* Copyright (C) 2023 Analog Devices
*
* Antoniu Miclaus <antoniu.miclaus@analog.com>
*
*/
#include <asm-generic/unaligned.h>
#include <linux/bcd.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#include <linux/util_macros.h>
/* MAX31335 Register Map */
#define MAX31335_STATUS1 0x00
#define MAX31335_INT_EN1 0x01
#define MAX31335_STATUS2 0x02
#define MAX31335_INT_EN2 0x03
#define MAX31335_RTC_RESET 0x04
#define MAX31335_RTC_CONFIG 0x05
#define MAX31335_RTC_CONFIG2 0x06
#define MAX31335_TIMESTAMP_CONFIG 0x07
#define MAX31335_TIMER_CONFIG 0x08
#define MAX31335_SECONDS_1_128 0x09
#define MAX31335_SECONDS 0x0A
#define MAX31335_MINUTES 0x0B
#define MAX31335_HOURS 0x0C
#define MAX31335_DAY 0x0D
#define MAX31335_DATE 0x0E
#define MAX31335_MONTH 0x0F
#define MAX31335_YEAR 0x0F
#define MAX31335_ALM1_SEC 0x11
#define MAX31335_ALM1_MIN 0x12
#define MAX31335_ALM1_HRS 0x13
#define MAX31335_ALM1_DAY_DATE 0x14
#define MAX31335_ALM1_MON 0x15
#define MAX31335_ALM1_YEAR 0x16
#define MAX31335_ALM2_MIN 0x17
#define MAX31335_ALM2_HRS 0x18
#define MAX31335_ALM2_DAY_DATE 0x19
#define MAX31335_TIMER_COUNT 0x1A
#define MAX31335_TIMER_INIT 0x1B
#define MAX31335_PWR_MGMT 0x1C
#define MAX31335_TRICKLE_REG 0x1D
#define MAX31335_AGING_OFFSET 0x1E
#define MAX31335_TS_CONFIG 0x30
#define MAX31335_TEMP_ALARM_HIGH_MSB 0x31
#define MAX31335_TEMP_ALARM_HIGH_LSB 0x32
#define MAX31335_TEMP_ALARM_LOW_MSB 0x33
#define MAX31335_TEMP_ALARM_LOW_LSB 0x34
#define MAX31335_TEMP_DATA_MSB 0x35
#define MAX31335_TEMP_DATA_LSB 0x36
#define MAX31335_TS0_SEC_1_128 0x40
#define MAX31335_TS0_SEC 0x41
#define MAX31335_TS0_MIN 0x42
#define MAX31335_TS0_HOUR 0x43
#define MAX31335_TS0_DATE 0x44
#define MAX31335_TS0_MONTH 0x45
#define MAX31335_TS0_YEAR 0x46
#define MAX31335_TS0_FLAGS 0x47
#define MAX31335_TS1_SEC_1_128 0x48
#define MAX31335_TS1_SEC 0x49
#define MAX31335_TS1_MIN 0x4A
#define MAX31335_TS1_HOUR 0x4B
#define MAX31335_TS1_DATE 0x4C
#define MAX31335_TS1_MONTH 0x4D
#define MAX31335_TS1_YEAR 0x4E
#define MAX31335_TS1_FLAGS 0x4F
#define MAX31335_TS2_SEC_1_128 0x50
#define MAX31335_TS2_SEC 0x51
#define MAX31335_TS2_MIN 0x52
#define MAX31335_TS2_HOUR 0x53
#define MAX31335_TS2_DATE 0x54
#define MAX31335_TS2_MONTH 0x55
#define MAX31335_TS2_YEAR 0x56
#define MAX31335_TS2_FLAGS 0x57
#define MAX31335_TS3_SEC_1_128 0x58
#define MAX31335_TS3_SEC 0x59
#define MAX31335_TS3_MIN 0x5A
#define MAX31335_TS3_HOUR 0x5B
#define MAX31335_TS3_DATE 0x5C
#define MAX31335_TS3_MONTH 0x5D
#define MAX31335_TS3_YEAR 0x5E
#define MAX31335_TS3_FLAGS 0x5F
/* MAX31335_STATUS1 Bit Definitions */
#define MAX31335_STATUS1_PSDECT BIT(7)
#define MAX31335_STATUS1_OSF BIT(6)
#define MAX31335_STATUS1_PFAIL BIT(5)
#define MAX31335_STATUS1_VBATLOW BIT(4)
#define MAX31335_STATUS1_DIF BIT(3)
#define MAX31335_STATUS1_TIF BIT(2)
#define MAX31335_STATUS1_A2F BIT(1)
#define MAX31335_STATUS1_A1F BIT(0)
/* MAX31335_INT_EN1 Bit Definitions */
#define MAX31335_INT_EN1_DOSF BIT(6)
#define MAX31335_INT_EN1_PFAILE BIT(5)
#define MAX31335_INT_EN1_VBATLOWE BIT(4)
#define MAX31335_INT_EN1_DIE BIT(3)
#define MAX31335_INT_EN1_TIE BIT(2)
#define MAX31335_INT_EN1_A2IE BIT(1)
#define MAX31335_INT_EN1_A1IE BIT(0)
/* MAX31335_STATUS2 Bit Definitions */
#define MAX31335_STATUS2_TEMP_RDY BIT(2)
#define MAX31335_STATUS2_OTF BIT(1)
#define MAX31335_STATUS2_UTF BIT(0)
/* MAX31335_INT_EN2 Bit Definitions */
#define MAX31335_INT_EN2_TEMP_RDY_EN BIT(2)
#define MAX31335_INT_EN2_OTIE BIT(1)
#define MAX31335_INT_EN2_UTIE BIT(0)
/* MAX31335_RTC_RESET Bit Definitions */
#define MAX31335_RTC_RESET_SWRST BIT(0)
/* MAX31335_RTC_CONFIG1 Bit Definitions */
#define MAX31335_RTC_CONFIG1_EN_IO BIT(6)
#define MAX31335_RTC_CONFIG1_A1AC GENMASK(5, 4)
#define MAX31335_RTC_CONFIG1_DIP BIT(3)
#define MAX31335_RTC_CONFIG1_I2C_TIMEOUT BIT(1)
#define MAX31335_RTC_CONFIG1_EN_OSC BIT(0)
/* MAX31335_RTC_CONFIG2 Bit Definitions */
#define MAX31335_RTC_CONFIG2_ENCLKO BIT(2)
#define MAX31335_RTC_CONFIG2_CLKO_HZ GENMASK(1, 0)
/* MAX31335_TIMESTAMP_CONFIG Bit Definitions */
#define MAX31335_TIMESTAMP_CONFIG_TSVLOW BIT(5)
#define MAX31335_TIMESTAMP_CONFIG_TSPWM BIT(4)
#define MAX31335_TIMESTAMP_CONFIG_TSDIN BIT(3)
#define MAX31335_TIMESTAMP_CONFIG_TSOW BIT(2)
#define MAX31335_TIMESTAMP_CONFIG_TSR BIT(1)
#define MAX31335_TIMESTAMP_CONFIG_TSE BIT(0)
/* MAX31335_TIMER_CONFIG Bit Definitions */
#define MAX31335_TIMER_CONFIG_TE BIT(4)
#define MAX31335_TIMER_CONFIG_TPAUSE BIT(3)
#define MAX31335_TIMER_CONFIG_TRPT BIT(2)
#define MAX31335_TIMER_CONFIG_TFS GENMASK(1, 0)
/* MAX31335_HOURS Bit Definitions */
#define MAX31335_HOURS_F_24_12 BIT(6)
#define MAX31335_HOURS_HR_20_AM_PM BIT(5)
/* MAX31335_MONTH Bit Definitions */
#define MAX31335_MONTH_CENTURY BIT(7)
/* MAX31335_PWR_MGMT Bit Definitions */
#define MAX31335_PWR_MGMT_PFVT BIT(0)
/* MAX31335_TRICKLE_REG Bit Definitions */
#define MAX31335_TRICKLE_REG_TRICKLE GENMASK(3, 1)
#define MAX31335_TRICKLE_REG_EN_TRICKLE BIT(0)
/* MAX31335_TS_CONFIG Bit Definitions */
#define MAX31335_TS_CONFIG_AUTO BIT(4)
#define MAX31335_TS_CONFIG_CONVERT_T BIT(3)
#define MAX31335_TS_CONFIG_TSINT GENMASK(2, 0)
/* MAX31335_TS_FLAGS Bit Definitions */
#define MAX31335_TS_FLAGS_VLOWF BIT(3)
#define MAX31335_TS_FLAGS_VBATF BIT(2)
#define MAX31335_TS_FLAGS_VCCF BIT(1)
#define MAX31335_TS_FLAGS_DINF BIT(0)
/* MAX31335 Miscellaneous Definitions */
#define MAX31335_TRICKLE_SCHOTTKY_DIODE 1
#define MAX31335_TRICKLE_STANDARD_DIODE 4
#define MAX31335_RAM_SIZE 32
#define MAX31335_TIME_SIZE 0x07
#define clk_hw_to_max31335(_hw) container_of(_hw, struct max31335_data, clkout)
struct max31335_data {
struct regmap *regmap;
struct rtc_device *rtc;
struct clk_hw clkout;
};
static const int max31335_clkout_freq[] = { 1, 64, 1024, 32768 };
static const u16 max31335_trickle_resistors[] = {3000, 6000, 11000};
static bool max31335_volatile_reg(struct device *dev, unsigned int reg)
{
/* time keeping registers */
if (reg >= MAX31335_SECONDS &&
reg < MAX31335_SECONDS + MAX31335_TIME_SIZE)
return true;
/* interrupt status register */
if (reg == MAX31335_INT_EN1_A1IE)
return true;
/* temperature registers */
if (reg == MAX31335_TEMP_DATA_MSB || reg == MAX31335_TEMP_DATA_LSB)
return true;
return false;
}
static const struct regmap_config regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = 0x5F,
.volatile_reg = max31335_volatile_reg,
};
static int max31335_read_time(struct device *dev, struct rtc_time *tm)
{
struct max31335_data *max31335 = dev_get_drvdata(dev);
u8 date[7];
int ret;
ret = regmap_bulk_read(max31335->regmap, MAX31335_SECONDS, date,
sizeof(date));
if (ret)
return ret;
tm->tm_sec = bcd2bin(date[0] & 0x7f);
tm->tm_min = bcd2bin(date[1] & 0x7f);
tm->tm_hour = bcd2bin(date[2] & 0x3f);
tm->tm_wday = bcd2bin(date[3] & 0x7) - 1;
tm->tm_mday = bcd2bin(date[4] & 0x3f);
tm->tm_mon = bcd2bin(date[5] & 0x1f) - 1;
tm->tm_year = bcd2bin(date[6]) + 100;
if (FIELD_GET(MAX31335_MONTH_CENTURY, date[5]))
tm->tm_year += 100;
return 0;
}
static int max31335_set_time(struct device *dev, struct rtc_time *tm)
{
struct max31335_data *max31335 = dev_get_drvdata(dev);
u8 date[7];
date[0] = bin2bcd(tm->tm_sec);
date[1] = bin2bcd(tm->tm_min);
date[2] = bin2bcd(tm->tm_hour);
date[3] = bin2bcd(tm->tm_wday + 1);
date[4] = bin2bcd(tm->tm_mday);
date[5] = bin2bcd(tm->tm_mon + 1);
date[6] = bin2bcd(tm->tm_year % 100);
if (tm->tm_year >= 200)
date[5] |= FIELD_PREP(MAX31335_MONTH_CENTURY, 1);
return regmap_bulk_write(max31335->regmap, MAX31335_SECONDS, date,
sizeof(date));
}
static int max31335_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct max31335_data *max31335 = dev_get_drvdata(dev);
int ret, ctrl, status;
struct rtc_time time;
u8 regs[6];
ret = regmap_bulk_read(max31335->regmap, MAX31335_ALM1_SEC, regs,
sizeof(regs));
if (ret)
return ret;
alrm->time.tm_sec = bcd2bin(regs[0] & 0x7f);
alrm->time.tm_min = bcd2bin(regs[1] & 0x7f);
alrm->time.tm_hour = bcd2bin(regs[2] & 0x3f);
alrm->time.tm_mday = bcd2bin(regs[3] & 0x3f);
alrm->time.tm_mon = bcd2bin(regs[4] & 0x1f) - 1;
alrm->time.tm_year = bcd2bin(regs[5]) + 100;
ret = max31335_read_time(dev, &time);
if (ret)
return ret;
if (time.tm_year >= 200)
alrm->time.tm_year += 100;
ret = regmap_read(max31335->regmap, MAX31335_INT_EN1, &ctrl);
if (ret)
return ret;
ret = regmap_read(max31335->regmap, MAX31335_STATUS1, &status);
if (ret)
return ret;
alrm->enabled = FIELD_GET(MAX31335_INT_EN1_A1IE, ctrl);
alrm->pending = FIELD_GET(MAX31335_STATUS1_A1F, status);
return 0;
}
static int max31335_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct max31335_data *max31335 = dev_get_drvdata(dev);
unsigned int reg;
u8 regs[6];
int ret;
regs[0] = bin2bcd(alrm->time.tm_sec);
regs[1] = bin2bcd(alrm->time.tm_min);
regs[2] = bin2bcd(alrm->time.tm_hour);
regs[3] = bin2bcd(alrm->time.tm_mday);
regs[4] = bin2bcd(alrm->time.tm_mon + 1);
regs[5] = bin2bcd(alrm->time.tm_year % 100);
ret = regmap_bulk_write(max31335->regmap, MAX31335_ALM1_SEC,
regs, sizeof(regs));
if (ret)
return ret;
reg = FIELD_PREP(MAX31335_INT_EN1_A1IE, alrm->enabled);
ret = regmap_update_bits(max31335->regmap, MAX31335_INT_EN1,
MAX31335_INT_EN1_A1IE, reg);
if (ret)
return ret;
ret = regmap_update_bits(max31335->regmap, MAX31335_STATUS1,
MAX31335_STATUS1_A1F, 0);
return 0;
}
static int max31335_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct max31335_data *max31335 = dev_get_drvdata(dev);
return regmap_update_bits(max31335->regmap, MAX31335_INT_EN1,
MAX31335_INT_EN1_A1IE, enabled);
}
static irqreturn_t max31335_handle_irq(int irq, void *dev_id)
{
struct max31335_data *max31335 = dev_id;
bool status;
int ret;
ret = regmap_update_bits_check(max31335->regmap, MAX31335_STATUS1,
MAX31335_STATUS1_A1F, 0, &status);
if (ret)
return IRQ_HANDLED;
if (status)
rtc_update_irq(max31335->rtc, 1, RTC_AF | RTC_IRQF);
return IRQ_HANDLED;
}
static const struct rtc_class_ops max31335_rtc_ops = {
.read_time = max31335_read_time,
.set_time = max31335_set_time,
.read_alarm = max31335_read_alarm,
.set_alarm = max31335_set_alarm,
.alarm_irq_enable = max31335_alarm_irq_enable,
};
static int max31335_trickle_charger_setup(struct device *dev,
struct max31335_data *max31335)
{
u32 ohms, chargeable;
int i, trickle_cfg;
const char *diode;
if (device_property_read_u32(dev, "aux-voltage-chargeable",
&chargeable))
return 0;
if (device_property_read_u32(dev, "trickle-resistor-ohms", &ohms))
return 0;
if (device_property_read_string(dev, "adi,tc-diode", &diode))
return 0;
if (!strcmp(diode, "schottky"))
trickle_cfg = MAX31335_TRICKLE_SCHOTTKY_DIODE;
else if (!strcmp(diode, "standard+schottky"))
trickle_cfg = MAX31335_TRICKLE_STANDARD_DIODE;
else
return dev_err_probe(dev, -EINVAL,
"Invalid tc-diode value: %s\n", diode);
for (i = 0; i < ARRAY_SIZE(max31335_trickle_resistors); i++)
if (ohms == max31335_trickle_resistors[i])
break;
if (i >= ARRAY_SIZE(max31335_trickle_resistors))
return 0;
i = i + trickle_cfg;
return regmap_write(max31335->regmap, MAX31335_TRICKLE_REG,
FIELD_PREP(MAX31335_TRICKLE_REG_TRICKLE, i) |
FIELD_PREP(MAX31335_TRICKLE_REG_EN_TRICKLE,
chargeable));
}
static unsigned long max31335_clkout_recalc_rate(struct clk_hw *hw,
unsigned long parent_rate)
{
struct max31335_data *max31335 = clk_hw_to_max31335(hw);
unsigned int freq_mask;
unsigned int reg;
int ret;
ret = regmap_read(max31335->regmap, MAX31335_RTC_CONFIG2, &reg);
if (ret)
return 0;
freq_mask = __roundup_pow_of_two(ARRAY_SIZE(max31335_clkout_freq)) - 1;
return max31335_clkout_freq[reg & freq_mask];
}
static long max31335_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
unsigned long *prate)
{
int index;
index = find_closest(rate, max31335_clkout_freq,
ARRAY_SIZE(max31335_clkout_freq));
return max31335_clkout_freq[index];
}
static int max31335_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct max31335_data *max31335 = clk_hw_to_max31335(hw);
unsigned int freq_mask;
int index;
index = find_closest(rate, max31335_clkout_freq,
ARRAY_SIZE(max31335_clkout_freq));
freq_mask = __roundup_pow_of_two(ARRAY_SIZE(max31335_clkout_freq)) - 1;
return regmap_update_bits(max31335->regmap, MAX31335_RTC_CONFIG2,
freq_mask, index);
}
static int max31335_clkout_enable(struct clk_hw *hw)
{
struct max31335_data *max31335 = clk_hw_to_max31335(hw);
return regmap_set_bits(max31335->regmap, MAX31335_RTC_CONFIG2,
MAX31335_RTC_CONFIG2_ENCLKO);
}
static void max31335_clkout_disable(struct clk_hw *hw)
{
struct max31335_data *max31335 = clk_hw_to_max31335(hw);
regmap_clear_bits(max31335->regmap, MAX31335_RTC_CONFIG2,
MAX31335_RTC_CONFIG2_ENCLKO);
}
static int max31335_clkout_is_enabled(struct clk_hw *hw)
{
struct max31335_data *max31335 = clk_hw_to_max31335(hw);
unsigned int reg;
int ret;
ret = regmap_read(max31335->regmap, MAX31335_RTC_CONFIG2, &reg);
if (ret)
return ret;
return !!(reg & MAX31335_RTC_CONFIG2_ENCLKO);
}
static const struct clk_ops max31335_clkout_ops = {
.recalc_rate = max31335_clkout_recalc_rate,
.round_rate = max31335_clkout_round_rate,
.set_rate = max31335_clkout_set_rate,
.enable = max31335_clkout_enable,
.disable = max31335_clkout_disable,
.is_enabled = max31335_clkout_is_enabled,
};
static struct clk_init_data max31335_clk_init = {
.name = "max31335-clkout",
.ops = &max31335_clkout_ops,
};
static int max31335_nvmem_reg_read(void *priv, unsigned int offset,
void *val, size_t bytes)
{
struct max31335_data *max31335 = priv;
unsigned int reg = MAX31335_TS0_SEC_1_128 + offset;
return regmap_bulk_read(max31335->regmap, reg, val, bytes);
}
static int max31335_nvmem_reg_write(void *priv, unsigned int offset,
void *val, size_t bytes)
{
struct max31335_data *max31335 = priv;
unsigned int reg = MAX31335_TS0_SEC_1_128 + offset;
return regmap_bulk_write(max31335->regmap, reg, val, bytes);
}
static struct nvmem_config max31335_nvmem_cfg = {
.reg_read = max31335_nvmem_reg_read,
.reg_write = max31335_nvmem_reg_write,
.word_size = 8,
.size = MAX31335_RAM_SIZE,
};
#if IS_REACHABLE(HWMON)
static int max31335_read_temp(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
struct max31335_data *max31335 = dev_get_drvdata(dev);
u8 reg[2];
s16 temp;
int ret;
if (type != hwmon_temp || attr != hwmon_temp_input)
return -EOPNOTSUPP;
ret = regmap_bulk_read(max31335->regmap, MAX31335_TEMP_DATA_MSB,
reg, 2);
if (ret)
return ret;
temp = get_unaligned_be16(reg);
*val = (temp / 64) * 250;
return 0;
}
static umode_t max31335_is_visible(const void *data,
enum hwmon_sensor_types type,
u32 attr, int channel)
{
if (type == hwmon_temp && attr == hwmon_temp_input)
return 0444;
return 0;
}
static const struct hwmon_channel_info *max31335_info[] = {
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
NULL
};
static const struct hwmon_ops max31335_hwmon_ops = {
.is_visible = max31335_is_visible,
.read = max31335_read_temp,
};
static const struct hwmon_chip_info max31335_chip_info = {
.ops = &max31335_hwmon_ops,
.info = max31335_info,
};
#endif
static int max31335_clkout_register(struct device *dev)
{
struct max31335_data *max31335 = dev_get_drvdata(dev);
int ret;
if (!device_property_present(dev, "#clock-cells"))
return regmap_clear_bits(max31335->regmap, MAX31335_RTC_CONFIG2,
MAX31335_RTC_CONFIG2_ENCLKO);
max31335->clkout.init = &max31335_clk_init;
ret = devm_clk_hw_register(dev, &max31335->clkout);
if (ret)
return dev_err_probe(dev, ret, "cannot register clock\n");
ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
&max31335->clkout);
if (ret)
return dev_err_probe(dev, ret, "cannot add hw provider\n");
max31335->clkout.clk = devm_clk_get_enabled(dev, NULL);
if (IS_ERR(max31335->clkout.clk))
return dev_err_probe(dev, PTR_ERR(max31335->clkout.clk),
"cannot enable clkout\n");
return 0;
}
static int max31335_probe(struct i2c_client *client)
{
struct max31335_data *max31335;
#if IS_REACHABLE(HWMON)
struct device *hwmon;
#endif
int ret;
max31335 = devm_kzalloc(&client->dev, sizeof(*max31335), GFP_KERNEL);
if (!max31335)
return -ENOMEM;
max31335->regmap = devm_regmap_init_i2c(client, &regmap_config);
if (IS_ERR(max31335->regmap))
return PTR_ERR(max31335->regmap);
i2c_set_clientdata(client, max31335);
max31335->rtc = devm_rtc_allocate_device(&client->dev);
if (IS_ERR(max31335->rtc))
return PTR_ERR(max31335->rtc);
max31335->rtc->ops = &max31335_rtc_ops;
max31335->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
max31335->rtc->range_max = RTC_TIMESTAMP_END_2199;
max31335->rtc->alarm_offset_max = 24 * 60 * 60;
ret = max31335_clkout_register(&client->dev);
if (ret)
return ret;
if (client->irq > 0) {
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, max31335_handle_irq,
IRQF_ONESHOT,
"max31335", max31335);
if (ret) {
dev_warn(&client->dev,
"unable to request IRQ, alarm max31335 disabled\n");
client->irq = 0;
}
}
if (!client->irq)
clear_bit(RTC_FEATURE_ALARM, max31335->rtc->features);
max31335_nvmem_cfg.priv = max31335;
ret = devm_rtc_nvmem_register(max31335->rtc, &max31335_nvmem_cfg);
if (ret)
return dev_err_probe(&client->dev, ret,
"cannot register rtc nvmem\n");
#if IS_REACHABLE(HWMON)
hwmon = devm_hwmon_device_register_with_info(&client->dev, client->name,
max31335,
&max31335_chip_info,
NULL);
if (IS_ERR(hwmon))
return dev_err_probe(&client->dev, PTR_ERR(hwmon),
"cannot register hwmon device\n");
#endif
ret = max31335_trickle_charger_setup(&client->dev, max31335);
if (ret)
return ret;
return devm_rtc_register_device(max31335->rtc);
}
static const struct i2c_device_id max31335_id[] = {
{ "max31335", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, max31335_id);
static const struct of_device_id max31335_of_match[] = {
{ .compatible = "adi,max31335" },
{ }
};
MODULE_DEVICE_TABLE(of, max31335_of_match);
static struct i2c_driver max31335_driver = {
.driver = {
.name = "rtc-max31335",
.of_match_table = max31335_of_match,
},
.probe = max31335_probe,
.id_table = max31335_id,
};
module_i2c_driver(max31335_driver);
MODULE_AUTHOR("Antoniu Miclaus <antoniu.miclaus@analog.com>");
MODULE_DESCRIPTION("MAX31335 RTC driver");
MODULE_LICENSE("GPL");

View File

@ -8,26 +8,31 @@
#include <linux/acpi.h>
#endif
#define UIP_RECHECK_DELAY 100 /* usec */
#define UIP_RECHECK_DELAY_MS (USEC_PER_MSEC / UIP_RECHECK_DELAY)
#define UIP_RECHECK_LOOPS_MS(x) (x / UIP_RECHECK_DELAY_MS)
/*
* Execute a function while the UIP (Update-in-progress) bit of the RTC is
* unset.
* unset. The timeout is configurable by the caller in ms.
*
* Warning: callback may be executed more then once.
*/
bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
int timeout,
void *param)
{
int i;
unsigned long flags;
unsigned char seconds;
for (i = 0; i < 100; i++) {
for (i = 0; UIP_RECHECK_LOOPS_MS(i) < timeout; i++) {
spin_lock_irqsave(&rtc_lock, flags);
/*
* Check whether there is an update in progress during which the
* readout is unspecified. The maximum update time is ~2ms. Poll
* every 100 usec for completion.
* for completion.
*
* Store the second value before checking UIP so a long lasting
* NMI which happens to hit after the UIP check cannot make
@ -37,7 +42,7 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
spin_unlock_irqrestore(&rtc_lock, flags);
udelay(100);
udelay(UIP_RECHECK_DELAY);
continue;
}
@ -56,7 +61,7 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
*/
if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) {
spin_unlock_irqrestore(&rtc_lock, flags);
udelay(100);
udelay(UIP_RECHECK_DELAY);
continue;
}
@ -72,6 +77,10 @@ bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
}
spin_unlock_irqrestore(&rtc_lock, flags);
if (UIP_RECHECK_LOOPS_MS(i) >= 100)
pr_warn("Reading current time from RTC took around %li ms\n",
UIP_RECHECK_LOOPS_MS(i));
return true;
}
return false;
@ -84,7 +93,7 @@ EXPORT_SYMBOL_GPL(mc146818_avoid_UIP);
*/
bool mc146818_does_rtc_work(void)
{
return mc146818_avoid_UIP(NULL, NULL);
return mc146818_avoid_UIP(NULL, 1000, NULL);
}
EXPORT_SYMBOL_GPL(mc146818_does_rtc_work);
@ -130,15 +139,27 @@ static void mc146818_get_time_callback(unsigned char seconds, void *param_in)
p->ctrl = CMOS_READ(RTC_CONTROL);
}
int mc146818_get_time(struct rtc_time *time)
/**
* mc146818_get_time - Get the current time from the RTC
* @time: pointer to struct rtc_time to store the current time
* @timeout: timeout value in ms
*
* This function reads the current time from the RTC and stores it in the
* provided struct rtc_time. The timeout parameter specifies the maximum
* time to wait for the RTC to become ready.
*
* Return: 0 on success, -ETIMEDOUT if the RTC did not become ready within
* the specified timeout, or another error code if an error occurred.
*/
int mc146818_get_time(struct rtc_time *time, int timeout)
{
struct mc146818_get_time_callback_param p = {
.time = time
};
if (!mc146818_avoid_UIP(mc146818_get_time_callback, &p)) {
if (!mc146818_avoid_UIP(mc146818_get_time_callback, timeout, &p)) {
memset(time, 0, sizeof(*time));
return -EIO;
return -ETIMEDOUT;
}
if (!(p.ctrl & RTC_DM_BINARY) || RTC_ALWAYS_BCD)

View File

@ -23,6 +23,7 @@
#define NCT3018Y_REG_CTRL 0x0A /* timer control */
#define NCT3018Y_REG_ST 0x0B /* status */
#define NCT3018Y_REG_CLKO 0x0C /* clock out */
#define NCT3018Y_REG_PART 0x21 /* part info */
#define NCT3018Y_BIT_AF BIT(7)
#define NCT3018Y_BIT_ST BIT(7)
@ -37,10 +38,12 @@
#define NCT3018Y_REG_BAT_MASK 0x07
#define NCT3018Y_REG_CLKO_F_MASK 0x03 /* frequenc mask */
#define NCT3018Y_REG_CLKO_CKE 0x80 /* clock out enabled */
#define NCT3018Y_REG_PART_NCT3018Y 0x02
struct nct3018y {
struct rtc_device *rtc;
struct i2c_client *client;
int part_num;
#ifdef CONFIG_COMMON_CLK
struct clk_hw clkout_hw;
#endif
@ -177,8 +180,27 @@ static int nct3018y_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int nct3018y_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct i2c_client *client = to_i2c_client(dev);
struct nct3018y *nct3018y = dev_get_drvdata(dev);
unsigned char buf[4] = {0};
int err;
int err, flags;
int restore_flags = 0;
flags = i2c_smbus_read_byte_data(client, NCT3018Y_REG_CTRL);
if (flags < 0) {
dev_dbg(&client->dev, "Failed to read NCT3018Y_REG_CTRL.\n");
return flags;
}
/* Check and set TWO bit */
if (nct3018y->part_num == NCT3018Y_REG_PART_NCT3018Y && !(flags & NCT3018Y_BIT_TWO)) {
restore_flags = 1;
flags |= NCT3018Y_BIT_TWO;
err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_CTRL, flags);
if (err < 0) {
dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_CTRL.\n");
return err;
}
}
buf[0] = bin2bcd(tm->tm_sec);
err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_SC, buf[0]);
@ -212,6 +234,18 @@ static int nct3018y_rtc_set_time(struct device *dev, struct rtc_time *tm)
return -EIO;
}
/* Restore TWO bit */
if (restore_flags) {
if (nct3018y->part_num == NCT3018Y_REG_PART_NCT3018Y)
flags &= ~NCT3018Y_BIT_TWO;
err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_CTRL, flags);
if (err < 0) {
dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_CTRL.\n");
return err;
}
}
return err;
}
@ -479,11 +513,17 @@ static int nct3018y_probe(struct i2c_client *client)
dev_dbg(&client->dev, "%s: NCT3018Y_BIT_TWO is set\n", __func__);
}
flags = NCT3018Y_BIT_TWO;
err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_CTRL, flags);
if (err < 0) {
dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_CTRL\n");
return err;
nct3018y->part_num = i2c_smbus_read_byte_data(client, NCT3018Y_REG_PART);
if (nct3018y->part_num < 0) {
dev_dbg(&client->dev, "Failed to read NCT3018Y_REG_PART.\n");
return nct3018y->part_num;
} else if (nct3018y->part_num == NCT3018Y_REG_PART_NCT3018Y) {
flags = NCT3018Y_BIT_HF;
err = i2c_smbus_write_byte_data(client, NCT3018Y_REG_CTRL, flags);
if (err < 0) {
dev_dbg(&client->dev, "Unable to write NCT3018Y_REG_CTRL.\n");
return err;
}
}
flags = 0;

View File

@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/of.h>
#include <linux/rtc.h>
#include <linux/pm_wakeirq.h>
#define RV8803_I2C_TRY_COUNT 4
@ -607,6 +608,28 @@ static int rv8803_regs_configure(struct rv8803_data *rv8803)
return 0;
}
static int rv8803_resume(struct device *dev)
{
struct rv8803_data *rv8803 = dev_get_drvdata(dev);
if (rv8803->client->irq > 0 && device_may_wakeup(dev))
disable_irq_wake(rv8803->client->irq);
return 0;
}
static int rv8803_suspend(struct device *dev)
{
struct rv8803_data *rv8803 = dev_get_drvdata(dev);
if (rv8803->client->irq > 0 && device_may_wakeup(dev))
enable_irq_wake(rv8803->client->irq);
return 0;
}
static DEFINE_SIMPLE_DEV_PM_OPS(rv8803_pm_ops, rv8803_suspend, rv8803_resume);
static const struct i2c_device_id rv8803_id[] = {
{ "rv8803", rv_8803 },
{ "rv8804", rx_8804 },
@ -683,10 +706,18 @@ static int rv8803_probe(struct i2c_client *client)
if (err) {
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
client->irq = 0;
} else {
device_init_wakeup(&client->dev, true);
err = dev_pm_set_wake_irq(&client->dev, client->irq);
if (err)
dev_err(&client->dev, "failed to set wake IRQ\n");
}
} else {
if (device_property_read_bool(&client->dev, "wakeup-source"))
device_init_wakeup(&client->dev, true);
else
clear_bit(RTC_FEATURE_ALARM, rv8803->rtc->features);
}
if (!client->irq)
clear_bit(RTC_FEATURE_ALARM, rv8803->rtc->features);
if (of_property_read_bool(client->dev.of_node, "epson,vdet-disable"))
rv8803->backup |= RX8900_FLAG_VDETOFF;
@ -737,6 +768,7 @@ static struct i2c_driver rv8803_driver = {
.driver = {
.name = "rtc-rv8803",
.of_match_table = of_match_ptr(rv8803_of_match),
.pm = &rv8803_pm_ops,
},
.probe = rv8803_probe,
.id_table = rv8803_id,

454
drivers/rtc/rtc-tps6594.c Normal file
View File

@ -0,0 +1,454 @@
// SPDX-License-Identifier: GPL-2.0
/*
* RTC driver for tps6594 PMIC
*
* Copyright (C) 2023 BayLibre Incorporated - https://www.baylibre.com/
*/
#include <linux/bcd.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/limits.h>
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/rtc.h>
#include <linux/types.h>
#include <linux/units.h>
#include <linux/mfd/tps6594.h>
// Total number of RTC registers needed to set time
#define NUM_TIME_REGS (TPS6594_REG_RTC_WEEKS - TPS6594_REG_RTC_SECONDS + 1)
// Total number of RTC alarm registers
#define NUM_TIME_ALARM_REGS (NUM_TIME_REGS - 1)
/*
* Min and max values supported by 'offset' interface (swapped sign).
* After conversion, the values do not exceed the range [-32767, 33767]
* which COMP_REG must conform to.
*/
#define MIN_OFFSET (-277774)
#define MAX_OFFSET (277774)
// Number of ticks per hour
#define TICKS_PER_HOUR (32768 * 3600)
// Multiplier for ppb conversions
#define PPB_MULT NANO
static int tps6594_rtc_alarm_irq_enable(struct device *dev,
unsigned int enabled)
{
struct tps6594 *tps = dev_get_drvdata(dev->parent);
u8 val;
val = enabled ? TPS6594_BIT_IT_ALARM : 0;
return regmap_update_bits(tps->regmap, TPS6594_REG_RTC_INTERRUPTS,
TPS6594_BIT_IT_ALARM, val);
}
/* Pulse GET_TIME field of RTC_CTRL_1 to store a timestamp in shadow registers. */
static int tps6594_rtc_shadow_timestamp(struct device *dev, struct tps6594 *tps)
{
int ret;
/*
* Set GET_TIME to 0. Next time we set GET_TIME to 1 we will be sure to store
* an up-to-date timestamp.
*/
ret = regmap_clear_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1,
TPS6594_BIT_GET_TIME);
if (ret < 0)
return ret;
/*
* Copy content of RTC registers to shadow registers or latches to read
* a coherent timestamp.
*/
return regmap_set_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1,
TPS6594_BIT_GET_TIME);
}
static int tps6594_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
unsigned char rtc_data[NUM_TIME_REGS];
struct tps6594 *tps = dev_get_drvdata(dev->parent);
int ret;
// Check if RTC is running.
ret = regmap_test_bits(tps->regmap, TPS6594_REG_RTC_STATUS,
TPS6594_BIT_RUN);
if (ret < 0)
return ret;
if (ret == 0)
return -EINVAL;
ret = tps6594_rtc_shadow_timestamp(dev, tps);
if (ret < 0)
return ret;
// Read shadowed RTC registers.
ret = regmap_bulk_read(tps->regmap, TPS6594_REG_RTC_SECONDS, rtc_data,
NUM_TIME_REGS);
if (ret < 0)
return ret;
tm->tm_sec = bcd2bin(rtc_data[0]);
tm->tm_min = bcd2bin(rtc_data[1]);
tm->tm_hour = bcd2bin(rtc_data[2]);
tm->tm_mday = bcd2bin(rtc_data[3]);
tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
tm->tm_year = bcd2bin(rtc_data[5]) + 100;
tm->tm_wday = bcd2bin(rtc_data[6]);
return 0;
}
static int tps6594_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
unsigned char rtc_data[NUM_TIME_REGS];
struct tps6594 *tps = dev_get_drvdata(dev->parent);
int ret;
rtc_data[0] = bin2bcd(tm->tm_sec);
rtc_data[1] = bin2bcd(tm->tm_min);
rtc_data[2] = bin2bcd(tm->tm_hour);
rtc_data[3] = bin2bcd(tm->tm_mday);
rtc_data[4] = bin2bcd(tm->tm_mon + 1);
rtc_data[5] = bin2bcd(tm->tm_year - 100);
rtc_data[6] = bin2bcd(tm->tm_wday);
// Stop RTC while updating the RTC time registers.
ret = regmap_clear_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1,
TPS6594_BIT_STOP_RTC);
if (ret < 0)
return ret;
// Update all the time registers in one shot.
ret = regmap_bulk_write(tps->regmap, TPS6594_REG_RTC_SECONDS, rtc_data,
NUM_TIME_REGS);
if (ret < 0)
return ret;
// Start back RTC.
return regmap_set_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1,
TPS6594_BIT_STOP_RTC);
}
static int tps6594_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
unsigned char alarm_data[NUM_TIME_ALARM_REGS];
u32 int_val;
struct tps6594 *tps = dev_get_drvdata(dev->parent);
int ret;
ret = regmap_bulk_read(tps->regmap, TPS6594_REG_ALARM_SECONDS,
alarm_data, NUM_TIME_ALARM_REGS);
if (ret < 0)
return ret;
alm->time.tm_sec = bcd2bin(alarm_data[0]);
alm->time.tm_min = bcd2bin(alarm_data[1]);
alm->time.tm_hour = bcd2bin(alarm_data[2]);
alm->time.tm_mday = bcd2bin(alarm_data[3]);
alm->time.tm_mon = bcd2bin(alarm_data[4]) - 1;
alm->time.tm_year = bcd2bin(alarm_data[5]) + 100;
ret = regmap_read(tps->regmap, TPS6594_REG_RTC_INTERRUPTS, &int_val);
if (ret < 0)
return ret;
alm->enabled = int_val & TPS6594_BIT_IT_ALARM;
return 0;
}
static int tps6594_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
unsigned char alarm_data[NUM_TIME_ALARM_REGS];
struct tps6594 *tps = dev_get_drvdata(dev->parent);
int ret;
// Disable alarm irq before changing the alarm timestamp.
ret = tps6594_rtc_alarm_irq_enable(dev, 0);
if (ret)
return ret;
alarm_data[0] = bin2bcd(alm->time.tm_sec);
alarm_data[1] = bin2bcd(alm->time.tm_min);
alarm_data[2] = bin2bcd(alm->time.tm_hour);
alarm_data[3] = bin2bcd(alm->time.tm_mday);
alarm_data[4] = bin2bcd(alm->time.tm_mon + 1);
alarm_data[5] = bin2bcd(alm->time.tm_year - 100);
// Update all the alarm registers in one shot.
ret = regmap_bulk_write(tps->regmap, TPS6594_REG_ALARM_SECONDS,
alarm_data, NUM_TIME_ALARM_REGS);
if (ret < 0)
return ret;
if (alm->enabled)
ret = tps6594_rtc_alarm_irq_enable(dev, 1);
return ret;
}
static int tps6594_rtc_set_calibration(struct device *dev, int calibration)
{
struct tps6594 *tps = dev_get_drvdata(dev->parent);
__le16 value;
int ret;
/*
* TPS6594 uses two's complement 16 bit value for compensation of RTC
* crystal inaccuracies. One time every hour when seconds counter
* increments from 0 to 1 compensation value will be added to internal
* RTC counter value.
*
* Valid range for compensation value: [-32767 .. 32767].
*/
if (calibration < S16_MIN + 1 || calibration > S16_MAX)
return -ERANGE;
value = cpu_to_le16(calibration);
// Update all the compensation registers in one shot.
ret = regmap_bulk_write(tps->regmap, TPS6594_REG_RTC_COMP_LSB, &value,
sizeof(value));
if (ret < 0)
return ret;
// Enable automatic compensation.
return regmap_set_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1,
TPS6594_BIT_AUTO_COMP);
}
static int tps6594_rtc_get_calibration(struct device *dev, int *calibration)
{
struct tps6594 *tps = dev_get_drvdata(dev->parent);
unsigned int ctrl;
__le16 value;
int ret;
ret = regmap_read(tps->regmap, TPS6594_REG_RTC_CTRL_1, &ctrl);
if (ret < 0)
return ret;
// If automatic compensation is not enabled report back zero.
if (!(ctrl & TPS6594_BIT_AUTO_COMP)) {
*calibration = 0;
return 0;
}
ret = regmap_bulk_read(tps->regmap, TPS6594_REG_RTC_COMP_LSB, &value,
sizeof(value));
if (ret < 0)
return ret;
*calibration = le16_to_cpu(value);
return 0;
}
static int tps6594_rtc_read_offset(struct device *dev, long *offset)
{
int calibration;
s64 tmp;
int ret;
ret = tps6594_rtc_get_calibration(dev, &calibration);
if (ret < 0)
return ret;
// Convert from RTC calibration register format to ppb format.
tmp = calibration * PPB_MULT;
if (tmp < 0)
tmp -= TICKS_PER_HOUR / 2LL;
else
tmp += TICKS_PER_HOUR / 2LL;
tmp = div_s64(tmp, TICKS_PER_HOUR);
/*
* SAFETY:
* Computatiion is the reverse operation of the one done in
* `tps6594_rtc_set_offset`. The safety remarks applie here too.
*/
/*
* Offset value operates in negative way, so swap sign.
* See 8.3.10.5, (32768 - COMP_REG).
*/
*offset = (long)-tmp;
return 0;
}
static int tps6594_rtc_set_offset(struct device *dev, long offset)
{
int calibration;
s64 tmp;
// Make sure offset value is within supported range.
if (offset < MIN_OFFSET || offset > MAX_OFFSET)
return -ERANGE;
// Convert from ppb format to RTC calibration register format.
tmp = offset * TICKS_PER_HOUR;
if (tmp < 0)
tmp -= PPB_MULT / 2LL;
else
tmp += PPB_MULT / 2LL;
tmp = div_s64(tmp, PPB_MULT);
/*
* SAFETY:
* - tmp = offset * TICK_PER_HOUR :
* `offset` can't be more than 277774, so `tmp` can't exceed 277774000000000
* which is lower than the maximum value in an `s64` (2^63-1). No overflow here.
*
* - tmp += TICK_PER_HOUR / 2LL :
* tmp will have a maximum value of 277774117964800 which is still inferior to 2^63-1.
*/
// Offset value operates in negative way, so swap sign.
calibration = (int)-tmp;
return tps6594_rtc_set_calibration(dev, calibration);
}
static irqreturn_t tps6594_rtc_interrupt(int irq, void *rtc)
{
struct device *dev = rtc;
struct tps6594 *tps = dev_get_drvdata(dev->parent);
struct rtc_device *rtc_dev = dev_get_drvdata(dev);
int ret;
u32 rtc_reg;
ret = regmap_read(tps->regmap, TPS6594_REG_RTC_STATUS, &rtc_reg);
if (ret)
return IRQ_NONE;
rtc_update_irq(rtc_dev, 1, RTC_IRQF | RTC_AF);
return IRQ_HANDLED;
}
static const struct rtc_class_ops tps6594_rtc_ops = {
.read_time = tps6594_rtc_read_time,
.set_time = tps6594_rtc_set_time,
.read_alarm = tps6594_rtc_read_alarm,
.set_alarm = tps6594_rtc_set_alarm,
.alarm_irq_enable = tps6594_rtc_alarm_irq_enable,
.read_offset = tps6594_rtc_read_offset,
.set_offset = tps6594_rtc_set_offset,
};
static int tps6594_rtc_probe(struct platform_device *pdev)
{
struct tps6594 *tps = dev_get_drvdata(pdev->dev.parent);
struct device *dev = &pdev->dev;
struct rtc_device *rtc;
int irq;
int ret;
rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
rtc = devm_rtc_allocate_device(dev);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
// Enable crystal oscillator.
ret = regmap_set_bits(tps->regmap, TPS6594_REG_RTC_CTRL_2,
TPS6594_BIT_XTAL_EN);
if (ret < 0)
return ret;
ret = regmap_test_bits(tps->regmap, TPS6594_REG_RTC_STATUS,
TPS6594_BIT_RUN);
if (ret < 0)
return ret;
// RTC not running.
if (ret == 0) {
ret = regmap_set_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1,
TPS6594_BIT_STOP_RTC);
if (ret < 0)
return ret;
/*
* On some boards, a 40 ms delay is needed before BIT_RUN is set.
* 80 ms should provide sufficient margin.
*/
mdelay(80);
/*
* RTC should be running now. Check if this is the case.
* If not it might be a missing oscillator.
*/
ret = regmap_test_bits(tps->regmap, TPS6594_REG_RTC_STATUS,
TPS6594_BIT_RUN);
if (ret < 0)
return ret;
if (ret == 0)
return -ENODEV;
// Stop RTC until first call to `tps6594_rtc_set_time`.
ret = regmap_clear_bits(tps->regmap, TPS6594_REG_RTC_CTRL_1,
TPS6594_BIT_STOP_RTC);
if (ret < 0)
return ret;
}
platform_set_drvdata(pdev, rtc);
irq = platform_get_irq_byname(pdev, TPS6594_IRQ_NAME_ALARM);
if (irq < 0)
return dev_err_probe(dev, irq, "Failed to get irq\n");
ret = devm_request_threaded_irq(dev, irq, NULL, tps6594_rtc_interrupt,
IRQF_ONESHOT, TPS6594_IRQ_NAME_ALARM,
dev);
if (ret < 0)
return dev_err_probe(dev, ret,
"Failed to request_threaded_irq\n");
ret = device_init_wakeup(dev, true);
if (ret < 0)
return dev_err_probe(dev, ret,
"Failed to init rtc as wakeup source\n");
rtc->ops = &tps6594_rtc_ops;
rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
rtc->range_max = RTC_TIMESTAMP_END_2099;
return devm_rtc_register_device(rtc);
}
static const struct platform_device_id tps6594_rtc_id_table[] = {
{ "tps6594-rtc", },
{}
};
MODULE_DEVICE_TABLE(platform, tps6594_rtc_id_table);
static struct platform_driver tps6594_rtc_driver = {
.probe = tps6594_rtc_probe,
.driver = {
.name = "tps6594-rtc",
},
.id_table = tps6594_rtc_id_table,
};
module_platform_driver(tps6594_rtc_driver);
MODULE_AUTHOR("Esteban Blanc <eblanc@baylibre.com>");
MODULE_DESCRIPTION("TPS6594 RTC driver");
MODULE_LICENSE("GPL");

View File

@ -126,10 +126,11 @@ struct cmos_rtc_board_info {
#endif /* ARCH_RTC_LOCATION */
bool mc146818_does_rtc_work(void);
int mc146818_get_time(struct rtc_time *time);
int mc146818_get_time(struct rtc_time *time, int timeout);
int mc146818_set_time(struct rtc_time *time);
bool mc146818_avoid_UIP(void (*callback)(unsigned char seconds, void *param),
int timeout,
void *param);
#endif /* _MC146818RTC_H */