Commit 271d8939 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull RTC updates from Alexandre Belloni:
 "A few drivers got some nice cleanups and a new driver are making the
  bulk of the changes.

  Subsystem:
   - allow rtc_read_alarm without read_alarm callback

  New driver:
   - NXP BBNSM module RTC

  Drivers:
   - use IRQ flags from fwnode when available
   - abx80x: nvmem support
   - brcmstb-waketimer: add non-wake alarm support
   - ingenic: provide CLK32K clock
   - isl12022: cleanups
   - moxart: switch to using gpiod API
   - pcf85363: allow setting quartz load
   - pm8xxx: cleanups and support for setting time
   - rv3028, rv3032: add ACPI support"

* tag 'rtc-6.3' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (64 commits)
  rtc: pm8xxx: add support for nvmem offset
  dt-bindings: rtc: qcom-pm8xxx: add nvmem-cell offset
  rtc: abx80x: Add nvmem support
  rtc: rx6110: Remove unused of_gpio,h
  rtc: efi: Avoid spamming the log on RTC read failure
  rtc: isl12022: sort header inclusion alphabetically
  rtc: isl12022: Join string literals back
  rtc: isl12022: Drop unneeded OF guards and of_match_ptr()
  rtc: isl12022: Explicitly use __le16 type for ISL12022_REG_TEMP_L
  rtc: isl12022: Get rid of unneeded private struct isl12022
  rtc: pcf85363: add support for the quartz-load-femtofarads property
  dt-bindings: rtc: nxp,pcf8563: move pcf85263/pcf85363 to a dedicated binding
  rtc: allow rtc_read_alarm without read_alarm callback
  rtc: rv3032: add ACPI support
  rtc: rv3028: add ACPI support
  rtc: bbnsm: Add the bbnsm rtc support
  rtc: jz4740: Register clock provider for the CLK32K pin
  rtc: jz4740: Use dev_err_probe()
  rtc: jz4740: Use readl_poll_timeout
  dt-bindings: rtc: Add #clock-cells property
  ...
parents 2eb29d59 3ca04951
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/amlogic,meson-vrtc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Amlogic Virtual RTC (VRTC)
maintainers:
- Neil Armstrong <neil.armstrong@linaro.org>
description: |
This is a Linux interface to an RTC managed by firmware, hence it's
virtual from a Linux perspective. The interface is 1 register where
an alarm time (in seconds) is to be written.
The alarm register is a simple scratch register shared between the
application processors (AP) and the secure co-processor (SCP.) When
the AP suspends, the SCP will use the value of this register to
program an always-on timer before going sleep. When the timer expires,
the SCP will wake up and will then wake the AP.
allOf:
- $ref: rtc.yaml#
properties:
compatible:
enum:
- amlogic,meson-vrtc
reg:
maxItems: 1
required:
- compatible
- reg
additionalProperties: false
examples:
- |
rtc@a8 {
compatible = "amlogic,meson-vrtc";
reg = <0x000a8 0x4>;
};
...@@ -11,7 +11,8 @@ maintainers: ...@@ -11,7 +11,8 @@ maintainers:
description: description:
The Broadcom STB wake-up timer provides a 27Mhz resolution timer, with the The Broadcom STB wake-up timer provides a 27Mhz resolution timer, with the
ability to wake up the system from low-power suspend/standby modes. ability to wake up the system from low-power suspend/standby modes and
optionally generate RTC alarm interrupts.
allOf: allOf:
- $ref: "rtc.yaml#" - $ref: "rtc.yaml#"
...@@ -24,8 +25,14 @@ properties: ...@@ -24,8 +25,14 @@ properties:
maxItems: 1 maxItems: 1
interrupts: interrupts:
description: the TIMER interrupt minItems: 1
maxItems: 1 items:
- description: the TIMER interrupt
- description: the ALARM interrupt
description:
The TIMER interrupt wakes the system from low-power suspend/standby modes.
An ALARM interrupt may be specified to interrupt the CPU when an RTC alarm
is enabled.
clocks: clocks:
description: clock reference in the 27MHz domain description: clock reference in the 27MHz domain
...@@ -35,10 +42,10 @@ additionalProperties: false ...@@ -35,10 +42,10 @@ additionalProperties: false
examples: examples:
- | - |
rtc@f0411580 { rtc@f041a080 {
compatible = "brcm,brcmstb-waketimer"; compatible = "brcm,brcmstb-waketimer";
reg = <0xf0411580 0x14>; reg = <0xf041a080 0x14>;
interrupts = <0x3>; interrupts-extended = <&aon_pm_l2_intc 0x04>,
interrupt-parent = <&aon_pm_l2_intc>; <&upg_aux_aon_intr2_intc 0x08>;
clocks = <&upg_fixed>; clocks = <&upg_fixed>;
}; };
...@@ -11,6 +11,17 @@ maintainers: ...@@ -11,6 +11,17 @@ maintainers:
allOf: allOf:
- $ref: rtc.yaml# - $ref: rtc.yaml#
- if:
not:
properties:
compatible:
contains:
enum:
- ingenic,jz4770-rtc
- ingenic,jz4780-rtc
then:
properties:
"#clock-cells": false
properties: properties:
compatible: compatible:
...@@ -39,6 +50,9 @@ properties: ...@@ -39,6 +50,9 @@ properties:
clock-names: clock-names:
const: rtc const: rtc
"#clock-cells":
const: 0
system-power-controller: system-power-controller:
description: | description: |
Indicates that the RTC is responsible for powering OFF Indicates that the RTC is responsible for powering OFF
...@@ -83,3 +97,18 @@ examples: ...@@ -83,3 +97,18 @@ examples:
clocks = <&cgu JZ4740_CLK_RTC>; clocks = <&cgu JZ4740_CLK_RTC>;
clock-names = "rtc"; clock-names = "rtc";
}; };
- |
#include <dt-bindings/clock/ingenic,jz4780-cgu.h>
rtc: rtc@10003000 {
compatible = "ingenic,jz4780-rtc", "ingenic,jz4760-rtc";
reg = <0x10003000 0x4c>;
interrupt-parent = <&intc>;
interrupts = <32>;
clocks = <&cgu JZ4780_CLK_RTCLK>;
clock-names = "rtc";
#clock-cells = <0>;
};
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/microcrystal,rv3028.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Microchip RV-3028 RTC
allOf:
- $ref: rtc.yaml#
maintainers:
- Alexandre Belloni <alexandre.belloni@bootlin.com>
properties:
compatible:
const: microcrystal,rv3028
reg:
maxItems: 1
interrupts:
maxItems: 1
trickle-resistor-ohms:
enum:
- 3000
- 5000
- 9000
- 15000
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
rtc@51 {
compatible = "microcrystal,rv3028";
reg = <0x51>;
pinctrl-0 = <&rtc_nint_pins>;
interrupts-extended = <&gpio1 16 IRQ_TYPE_LEVEL_HIGH>;
trickle-resistor-ohms = <3000>;
};
};
...
...@@ -3,15 +3,15 @@ MOXA ART real-time clock ...@@ -3,15 +3,15 @@ MOXA ART real-time clock
Required properties: Required properties:
- compatible : Should be "moxa,moxart-rtc" - compatible : Should be "moxa,moxart-rtc"
- gpio-rtc-sclk : RTC sclk gpio, with zero flags - rtc-sclk-gpios : RTC sclk gpio, with zero flags
- gpio-rtc-data : RTC data gpio, with zero flags - rtc-data-gpios : RTC data gpio, with zero flags
- gpio-rtc-reset : RTC reset gpio, with zero flags - rtc-reset-gpios : RTC reset gpio, with zero flags
Example: Example:
rtc: rtc { rtc: rtc {
compatible = "moxa,moxart-rtc"; compatible = "moxa,moxart-rtc";
gpio-rtc-sclk = <&gpio 5 0>; rtc-sclk-gpios = <&gpio 5 0>;
gpio-rtc-data = <&gpio 6 0>; rtc-data-gpios = <&gpio 6 0>;
gpio-rtc-reset = <&gpio 7 0>; rtc-reset-gpios = <&gpio 7 0>;
}; };
...@@ -14,7 +14,10 @@ maintainers: ...@@ -14,7 +14,10 @@ maintainers:
properties: properties:
compatible: compatible:
const: nxp,pcf2127 enum:
- nxp,pca2129
- nxp,pcf2127
- nxp,pcf2129
reg: reg:
maxItems: 1 maxItems: 1
......
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/nxp,pcf85363.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Philips PCF85263/PCF85363 Real Time Clock
maintainers:
- Alexandre Belloni <alexandre.belloni@bootlin.com>
allOf:
- $ref: rtc.yaml#
properties:
compatible:
enum:
- nxp,pcf85263
- nxp,pcf85363
reg:
maxItems: 1
"#clock-cells":
const: 0
clock-output-names:
maxItems: 1
interrupts:
maxItems: 1
quartz-load-femtofarads:
description:
The capacitive load of the quartz(x-tal).
enum: [6000, 7000, 12500]
default: 7000
start-year: true
wakeup-source: true
required:
- compatible
- reg
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
rtc@51 {
compatible = "nxp,pcf85363";
reg = <0x51>;
#clock-cells = <0>;
quartz-load-femtofarads = <12500>;
};
};
...@@ -19,8 +19,6 @@ properties: ...@@ -19,8 +19,6 @@ properties:
- microcrystal,rv8564 - microcrystal,rv8564
- nxp,pca8565 - nxp,pca8565
- nxp,pcf8563 - nxp,pcf8563
- nxp,pcf85263
- nxp,pcf85363
reg: reg:
maxItems: 1 maxItems: 1
......
...@@ -40,6 +40,16 @@ properties: ...@@ -40,6 +40,16 @@ properties:
description: description:
Indicates that the setting of RTC time is allowed by the host CPU. Indicates that the setting of RTC time is allowed by the host CPU.
nvmem-cells:
items:
- description:
four-byte nvmem cell holding a little-endian offset from the Unix
epoch representing the time when the RTC timer was last reset
nvmem-cell-names:
items:
- const: offset
wakeup-source: true wakeup-source: true
required: required:
...@@ -69,6 +79,8 @@ examples: ...@@ -69,6 +79,8 @@ examples:
compatible = "qcom,pm8921-rtc"; compatible = "qcom,pm8921-rtc";
reg = <0x11d>; reg = <0x11d>;
interrupts = <0x27 0>; interrupts = <0x27 0>;
nvmem-cells = <&rtc_offset>;
nvmem-cell-names = "offset";
}; };
}; };
}; };
......
* Amlogic Virtual RTC (VRTC)
This is a Linux interface to an RTC managed by firmware, hence it's
virtual from a Linux perspective. The interface is 1 register where
an alarm time (in seconds) is to be written.
Required properties:
- compatible: should be "amlogic,meson-vrtc"
- reg: physical address for the alarm register
The alarm register is a simple scratch register shared between the
application processors (AP) and the secure co-processor (SCP.) When
the AP suspends, the SCP will use the value of this register to
program an always-on timer before going sleep. When the timer expires,
the SCP will wake up and will then wake the AP.
Example:
vrtc: rtc@0a8 {
compatible = "amlogic,meson-vrtc";
reg = <0x0 0x000a8 0x0 0x4>;
};
...@@ -47,14 +47,12 @@ properties: ...@@ -47,14 +47,12 @@ properties:
- isil,isl1218 - isil,isl1218
# Intersil ISL12022 Real-time Clock # Intersil ISL12022 Real-time Clock
- isil,isl12022 - isil,isl12022
# Real Time Clock Module with I2C-Bus # Loongson-2K Socs/LS7A bridge Real-time Clock
- microcrystal,rv3028 - loongson,ls2x-rtc
# Real Time Clock Module with I2C-Bus # Real Time Clock Module with I2C-Bus
- microcrystal,rv3029 - microcrystal,rv3029
# Real Time Clock # Real Time Clock
- microcrystal,rv8523 - microcrystal,rv8523
- nxp,pca2129
- nxp,pcf2129
# Real-time Clock Module # Real-time Clock Module
- pericom,pt7c4338 - pericom,pt7c4338
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC # I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
......
...@@ -1677,7 +1677,7 @@ config RTC_DRV_MPC5121 ...@@ -1677,7 +1677,7 @@ config RTC_DRV_MPC5121
config RTC_DRV_JZ4740 config RTC_DRV_JZ4740
tristate "Ingenic JZ4740 SoC" tristate "Ingenic JZ4740 SoC"
depends on MIPS || COMPILE_TEST depends on MIPS || COMPILE_TEST
depends on OF depends on OF && COMMON_CLK
help help
If you say yes here you get support for the Ingenic JZ47xx SoCs RTC If you say yes here you get support for the Ingenic JZ47xx SoCs RTC
controllers. controllers.
...@@ -1773,6 +1773,18 @@ config RTC_DRV_SNVS ...@@ -1773,6 +1773,18 @@ config RTC_DRV_SNVS
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-snvs". will be called "rtc-snvs".
config RTC_DRV_BBNSM
tristate "NXP BBNSM RTC support"
select REGMAP_MMIO
depends on ARCH_MXC || COMPILE_TEST
depends on HAS_IOMEM
depends on OF
help
If you say yes here you get support for the NXP BBNSM RTC module.
This driver can also be built as a module, if so, the module
will be called "rtc-bbnsm".
config RTC_DRV_IMX_SC config RTC_DRV_IMX_SC
depends on IMX_SCU depends on IMX_SCU
depends on HAVE_ARM_SMCCC depends on HAVE_ARM_SMCCC
......
...@@ -33,6 +33,7 @@ obj-$(CONFIG_RTC_DRV_ASPEED) += rtc-aspeed.o ...@@ -33,6 +33,7 @@ obj-$(CONFIG_RTC_DRV_ASPEED) += rtc-aspeed.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o
obj-$(CONFIG_RTC_DRV_BBNSM) += rtc-nxp-bbnsm.o
obj-$(CONFIG_RTC_DRV_BD70528) += rtc-bd70528.o obj-$(CONFIG_RTC_DRV_BD70528) += rtc-bd70528.o
obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o
obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
......
...@@ -392,7 +392,7 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) ...@@ -392,7 +392,7 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
return err; return err;
if (!rtc->ops) { if (!rtc->ops) {
err = -ENODEV; err = -ENODEV;
} else if (!test_bit(RTC_FEATURE_ALARM, rtc->features) || !rtc->ops->read_alarm) { } else if (!test_bit(RTC_FEATURE_ALARM, rtc->features)) {
err = -EINVAL; err = -EINVAL;
} else { } else {
memset(alarm, 0, sizeof(struct rtc_wkalrm)); memset(alarm, 0, sizeof(struct rtc_wkalrm));
......
...@@ -536,9 +536,14 @@ static int abeoz9_probe(struct i2c_client *client) ...@@ -536,9 +536,14 @@ static int abeoz9_probe(struct i2c_client *client)
clear_bit(RTC_FEATURE_ALARM, data->rtc->features); clear_bit(RTC_FEATURE_ALARM, data->rtc->features);
if (client->irq > 0) { if (client->irq > 0) {
unsigned long irqflags = IRQF_TRIGGER_LOW;
if (dev_fwnode(&client->dev))
irqflags = 0;
ret = devm_request_threaded_irq(dev, client->irq, NULL, ret = devm_request_threaded_irq(dev, client->irq, NULL,
abeoz9_rtc_irq, abeoz9_rtc_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, irqflags | IRQF_ONESHOT,
dev_name(dev), dev); dev_name(dev), dev);
if (ret) { if (ret) {
dev_err(dev, "failed to request alarm irq\n"); dev_err(dev, "failed to request alarm irq\n");
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
*/ */
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/bitfield.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/kstrtox.h> #include <linux/kstrtox.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -88,6 +89,16 @@ ...@@ -88,6 +89,16 @@
#define ABX8XX_TRICKLE_STANDARD_DIODE 0x8 #define ABX8XX_TRICKLE_STANDARD_DIODE 0x8
#define ABX8XX_TRICKLE_SCHOTTKY_DIODE 0x4 #define ABX8XX_TRICKLE_SCHOTTKY_DIODE 0x4
#define ABX8XX_REG_EXTRAM 0x3f
#define ABX8XX_EXTRAM_XADS GENMASK(1, 0)
#define ABX8XX_SRAM_BASE 0x40
#define ABX8XX_SRAM_WIN_SIZE 0x40
#define ABX8XX_RAM_SIZE 256
#define NVMEM_ADDR_LOWER GENMASK(5, 0)
#define NVMEM_ADDR_UPPER GENMASK(7, 6)
static u8 trickle_resistors[] = {0, 3, 6, 11}; static u8 trickle_resistors[] = {0, 3, 6, 11};
enum abx80x_chip {AB0801, AB0803, AB0804, AB0805, enum abx80x_chip {AB0801, AB0803, AB0804, AB0805,
...@@ -674,6 +685,68 @@ static int abx80x_setup_watchdog(struct abx80x_priv *priv) ...@@ -674,6 +685,68 @@ static int abx80x_setup_watchdog(struct abx80x_priv *priv)
} }
#endif #endif
static int abx80x_nvmem_xfer(struct abx80x_priv *priv, unsigned int offset,
void *val, size_t bytes, bool write)
{
int ret;
while (bytes) {
u8 extram, reg, len, lower, upper;
lower = FIELD_GET(NVMEM_ADDR_LOWER, offset);
upper = FIELD_GET(NVMEM_ADDR_UPPER, offset);
extram = FIELD_PREP(ABX8XX_EXTRAM_XADS, upper);
reg = ABX8XX_SRAM_BASE + lower;
len = min(lower + bytes, (size_t)ABX8XX_SRAM_WIN_SIZE) - lower;
len = min_t(u8, len, I2C_SMBUS_BLOCK_MAX);
ret = i2c_smbus_write_byte_data(priv->client, ABX8XX_REG_EXTRAM,
extram);
if (ret)
return ret;
if (write)
ret = i2c_smbus_write_i2c_block_data(priv->client, reg,
len, val);
else
ret = i2c_smbus_read_i2c_block_data(priv->client, reg,
len, val);
if (ret)
return ret;
offset += len;
val += len;
bytes -= len;
}
return 0;
}
static int abx80x_nvmem_read(void *priv, unsigned int offset, void *val,
size_t bytes)
{
return abx80x_nvmem_xfer(priv, offset, val, bytes, false);
}
static int abx80x_nvmem_write(void *priv, unsigned int offset, void *val,
size_t bytes)
{
return abx80x_nvmem_xfer(priv, offset, val, bytes, true);
}
static int abx80x_setup_nvmem(struct abx80x_priv *priv)
{
struct nvmem_config config = {
.type = NVMEM_TYPE_BATTERY_BACKED,
.reg_read = abx80x_nvmem_read,
.reg_write = abx80x_nvmem_write,
.size = ABX8XX_RAM_SIZE,
.priv = priv,
};
return devm_rtc_nvmem_register(priv->rtc, &config);
}
static const struct i2c_device_id abx80x_id[] = { static const struct i2c_device_id abx80x_id[] = {
{ "abx80x", ABX80X }, { "abx80x", ABX80X },
{ "ab0801", AB0801 }, { "ab0801", AB0801 },
...@@ -840,6 +913,10 @@ static int abx80x_probe(struct i2c_client *client) ...@@ -840,6 +913,10 @@ static int abx80x_probe(struct i2c_client *client)
return err; return err;
} }
err = abx80x_setup_nvmem(priv);
if (err)
return err;
if (client->irq > 0) { if (client->irq > 0) {
dev_info(&client->dev, "IRQ %d supplied\n", client->irq); dev_info(&client->dev, "IRQ %d supplied\n", client->irq);
err = devm_request_threaded_irq(&client->dev, client->irq, NULL, err = devm_request_threaded_irq(&client->dev, client->irq, NULL,
......
...@@ -27,13 +27,17 @@ struct brcmstb_waketmr { ...@@ -27,13 +27,17 @@ struct brcmstb_waketmr {
struct rtc_device *rtc; struct rtc_device *rtc;
struct device *dev; struct device *dev;
void __iomem *base; void __iomem *base;
int irq; unsigned int wake_irq;
unsigned int alarm_irq;
struct notifier_block reboot_notifier; struct notifier_block reboot_notifier;
struct clk *clk; struct clk *clk;
u32 rate; u32 rate;
unsigned long rtc_alarm;
bool alarm_en;
}; };
#define BRCMSTB_WKTMR_EVENT 0x00 #define BRCMSTB_WKTMR_EVENT 0x00
#define WKTMR_ALARM_EVENT BIT(0)
#define BRCMSTB_WKTMR_COUNTER 0x04 #define BRCMSTB_WKTMR_COUNTER 0x04
#define BRCMSTB_WKTMR_ALARM 0x08 #define BRCMSTB_WKTMR_ALARM 0x08
#define BRCMSTB_WKTMR_PRESCALER 0x0C #define BRCMSTB_WKTMR_PRESCALER 0x0C
...@@ -41,28 +45,71 @@ struct brcmstb_waketmr { ...@@ -41,28 +45,71 @@ struct brcmstb_waketmr {
#define BRCMSTB_WKTMR_DEFAULT_FREQ 27000000 #define BRCMSTB_WKTMR_DEFAULT_FREQ 27000000
static inline bool brcmstb_waketmr_is_pending(struct brcmstb_waketmr *timer)
{
u32 reg;
reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
return !!(reg & WKTMR_ALARM_EVENT);
}
static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer) static inline void brcmstb_waketmr_clear_alarm(struct brcmstb_waketmr *timer)
{ {
writel_relaxed(1, timer->base + BRCMSTB_WKTMR_EVENT); u32 reg;
if (timer->alarm_en && timer->alarm_irq)
disable_irq(timer->alarm_irq);
timer->alarm_en = false;
reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER);
writel_relaxed(reg - 1, timer->base + BRCMSTB_WKTMR_ALARM);
writel_relaxed(WKTMR_ALARM_EVENT, timer->base + BRCMSTB_WKTMR_EVENT);
(void)readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT); (void)readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
} }
static void brcmstb_waketmr_set_alarm(struct brcmstb_waketmr *timer, static void brcmstb_waketmr_set_alarm(struct brcmstb_waketmr *timer,
unsigned int secs) unsigned int secs)
{ {
unsigned int now;
brcmstb_waketmr_clear_alarm(timer); brcmstb_waketmr_clear_alarm(timer);
/* Make sure we are actually counting in seconds */ /* Make sure we are actually counting in seconds */
writel_relaxed(timer->rate, timer->base + BRCMSTB_WKTMR_PRESCALER); writel_relaxed(timer->rate, timer->base + BRCMSTB_WKTMR_PRESCALER);
writel_relaxed(secs + 1, timer->base + BRCMSTB_WKTMR_ALARM); writel_relaxed(secs, timer->base + BRCMSTB_WKTMR_ALARM);
now = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER);
while ((int)(secs - now) <= 0 &&
!brcmstb_waketmr_is_pending(timer)) {
secs = now + 1;
writel_relaxed(secs, timer->base + BRCMSTB_WKTMR_ALARM);
now = readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER);
}
} }
static irqreturn_t brcmstb_waketmr_irq(int irq, void *data) static irqreturn_t brcmstb_waketmr_irq(int irq, void *data)
{ {
struct brcmstb_waketmr *timer = data; struct brcmstb_waketmr *timer = data;
pm_wakeup_event(timer->dev, 0); if (!timer->alarm_irq)
pm_wakeup_event(timer->dev, 0);
return IRQ_HANDLED;
}
static irqreturn_t brcmstb_alarm_irq(int irq, void *data)
{
struct brcmstb_waketmr *timer = data;
/* Ignore spurious interrupts */
if (!brcmstb_waketmr_is_pending(timer))
return IRQ_HANDLED;
if (timer->alarm_en) {
if (!device_may_wakeup(timer->dev))
writel_relaxed(WKTMR_ALARM_EVENT,
timer->base + BRCMSTB_WKTMR_EVENT);
rtc_update_irq(timer->rtc, 1, RTC_IRQF | RTC_AF);
}
return IRQ_HANDLED; return IRQ_HANDLED;
} }
...@@ -88,17 +135,25 @@ static void wktmr_read(struct brcmstb_waketmr *timer, ...@@ -88,17 +135,25 @@ static void wktmr_read(struct brcmstb_waketmr *timer,
static int brcmstb_waketmr_prepare_suspend(struct brcmstb_waketmr *timer) static int brcmstb_waketmr_prepare_suspend(struct brcmstb_waketmr *timer)
{ {
struct device *dev = timer->dev; struct device *dev = timer->dev;
int ret = 0; int ret;
if (device_may_wakeup(dev)) { if (device_may_wakeup(dev)) {
ret = enable_irq_wake(timer->irq); ret = enable_irq_wake(timer->wake_irq);
if (ret) { if (ret) {
dev_err(dev, "failed to enable wake-up interrupt\n"); dev_err(dev, "failed to enable wake-up interrupt\n");
return ret; return ret;
} }
if (timer->alarm_en && timer->alarm_irq) {
ret = enable_irq_wake(timer->alarm_irq);
if (ret) {
dev_err(dev, "failed to enable rtc interrupt\n");
disable_irq_wake(timer->wake_irq);
return ret;
}
}
} }
return ret; return 0;
} }
/* If enabled as a wakeup-source, arm the timer when powering off */ /* If enabled as a wakeup-source, arm the timer when powering off */
...@@ -146,46 +201,47 @@ static int brcmstb_waketmr_getalarm(struct device *dev, ...@@ -146,46 +201,47 @@ static int brcmstb_waketmr_getalarm(struct device *dev,
struct rtc_wkalrm *alarm) struct rtc_wkalrm *alarm)
{ {
struct brcmstb_waketmr *timer = dev_get_drvdata(dev); struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
time64_t sec;
u32 reg;
sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM); alarm->enabled = timer->alarm_en;
if (sec != 0) { rtc_time64_to_tm(timer->rtc_alarm, &alarm->time);
/* Alarm is enabled */
alarm->enabled = 1;
rtc_time64_to_tm(sec, &alarm->time);
}
reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT); alarm->pending = brcmstb_waketmr_is_pending(timer);
alarm->pending = !!(reg & 1);
return 0; return 0;
} }
static int brcmstb_waketmr_setalarm(struct device *dev, static int brcmstb_waketmr_alarm_enable(struct device *dev,
struct rtc_wkalrm *alarm) unsigned int enabled)
{ {
struct brcmstb_waketmr *timer = dev_get_drvdata(dev); struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
time64_t sec;
if (alarm->enabled)
sec = rtc_tm_to_time64(&alarm->time);
else
sec = 0;
brcmstb_waketmr_set_alarm(timer, sec); if (enabled && !timer->alarm_en) {
if ((int)(readl_relaxed(timer->base + BRCMSTB_WKTMR_COUNTER) -
readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM)) >= 0 &&
!brcmstb_waketmr_is_pending(timer))
return -EINVAL;
timer->alarm_en = true;
if (timer->alarm_irq)
enable_irq(timer->alarm_irq);
} else if (!enabled && timer->alarm_en) {
if (timer->alarm_irq)
disable_irq(timer->alarm_irq);
timer->alarm_en = false;
}
return 0; return 0;
} }
/* static int brcmstb_waketmr_setalarm(struct device *dev,
* Does not do much but keep the RTC class happy. We always support struct rtc_wkalrm *alarm)
* alarms.
*/
static int brcmstb_waketmr_alarm_enable(struct device *dev,
unsigned int enabled)
{ {
return 0; struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
timer->rtc_alarm = rtc_tm_to_time64(&alarm->time);
brcmstb_waketmr_set_alarm(timer, timer->rtc_alarm);
return brcmstb_waketmr_alarm_enable(dev, alarm->enabled);
} }
static const struct rtc_class_ops brcmstb_waketmr_ops = { static const struct rtc_class_ops brcmstb_waketmr_ops = {
...@@ -221,12 +277,12 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev) ...@@ -221,12 +277,12 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
* Set wakeup capability before requesting wakeup interrupt, so we can * Set wakeup capability before requesting wakeup interrupt, so we can
* process boot-time "wakeups" (e.g., from S5 soft-off) * process boot-time "wakeups" (e.g., from S5 soft-off)
*/ */
device_set_wakeup_capable(dev, true); device_init_wakeup(dev, true);
device_wakeup_enable(dev);
timer->irq = platform_get_irq(pdev, 0); ret = platform_get_irq(pdev, 0);
if (timer->irq < 0) if (ret < 0)
return -ENODEV; return -ENODEV;
timer->wake_irq = (unsigned int)ret;
timer->clk = devm_clk_get(dev, NULL); timer->clk = devm_clk_get(dev, NULL);
if (!IS_ERR(timer->clk)) { if (!IS_ERR(timer->clk)) {
...@@ -241,11 +297,24 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev) ...@@ -241,11 +297,24 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
timer->clk = NULL; timer->clk = NULL;
} }
ret = devm_request_irq(dev, timer->irq, brcmstb_waketmr_irq, 0, ret = devm_request_irq(dev, timer->wake_irq, brcmstb_waketmr_irq, 0,
"brcmstb-waketimer", timer); "brcmstb-waketimer", timer);
if (ret < 0) if (ret < 0)
goto err_clk; goto err_clk;
brcmstb_waketmr_clear_alarm(timer);
/* Attempt to initialize non-wake irq */
ret = platform_get_irq(pdev, 1);
if (ret > 0) {
timer->alarm_irq = (unsigned int)ret;
ret = devm_request_irq(dev, timer->alarm_irq, brcmstb_alarm_irq,
IRQF_NO_AUTOEN, "brcmstb-waketimer-rtc",
timer);
if (ret < 0)
timer->alarm_irq = 0;
}
timer->reboot_notifier.notifier_call = brcmstb_waketmr_reboot; timer->reboot_notifier.notifier_call = brcmstb_waketmr_reboot;
register_reboot_notifier(&timer->reboot_notifier); register_reboot_notifier(&timer->reboot_notifier);
...@@ -256,8 +325,6 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev) ...@@ -256,8 +325,6 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
if (ret) if (ret)
goto err_notifier; goto err_notifier;
dev_info(dev, "registered, with irq %d\n", timer->irq);
return 0; return 0;
err_notifier: err_notifier:
...@@ -295,7 +362,9 @@ static int brcmstb_waketmr_resume(struct device *dev) ...@@ -295,7 +362,9 @@ static int brcmstb_waketmr_resume(struct device *dev)
if (!device_may_wakeup(dev)) if (!device_may_wakeup(dev))
return 0; return 0;
ret = disable_irq_wake(timer->irq); ret = disable_irq_wake(timer->wake_irq);
if (timer->alarm_en && timer->alarm_irq)
disable_irq_wake(timer->alarm_irq);
brcmstb_waketmr_clear_alarm(timer); brcmstb_waketmr_clear_alarm(timer);
...@@ -325,4 +394,5 @@ module_platform_driver(brcmstb_waketmr_driver); ...@@ -325,4 +394,5 @@ module_platform_driver(brcmstb_waketmr_driver);
MODULE_LICENSE("GPL v2"); MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Brian Norris"); MODULE_AUTHOR("Brian Norris");
MODULE_AUTHOR("Markus Mayer"); MODULE_AUTHOR("Markus Mayer");
MODULE_AUTHOR("Doug Berger");
MODULE_DESCRIPTION("Wake-up timer driver for STB chips"); MODULE_DESCRIPTION("Wake-up timer driver for STB chips");
...@@ -1712,9 +1712,9 @@ static const struct regmap_config regmap_config = { ...@@ -1712,9 +1712,9 @@ static const struct regmap_config regmap_config = {
.val_bits = 8, .val_bits = 8,
}; };
static int ds1307_probe(struct i2c_client *client, static int ds1307_probe(struct i2c_client *client)
const struct i2c_device_id *id)
{ {
const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct ds1307 *ds1307; struct ds1307 *ds1307;
const void *match; const void *match;
int err = -ENODEV; int err = -ENODEV;
...@@ -2011,7 +2011,7 @@ static struct i2c_driver ds1307_driver = { ...@@ -2011,7 +2011,7 @@ static struct i2c_driver ds1307_driver = {
.name = "rtc-ds1307", .name = "rtc-ds1307",
.of_match_table = ds1307_of_match, .of_match_table = ds1307_of_match,
}, },
.probe = ds1307_probe, .probe_new = ds1307_probe,
.id_table = ds1307_id, .id_table = ds1307_id,
}; };
......
...@@ -164,7 +164,7 @@ static int efi_read_time(struct device *dev, struct rtc_time *tm) ...@@ -164,7 +164,7 @@ static int efi_read_time(struct device *dev, struct rtc_time *tm)
if (status != EFI_SUCCESS) { if (status != EFI_SUCCESS) {
/* should never happen */ /* should never happen */
dev_err(dev, "can't read time\n"); dev_err_once(dev, "can't read time\n");
return -EINVAL; return -EINVAL;
} }
......
...@@ -518,9 +518,14 @@ static int hym8563_probe(struct i2c_client *client) ...@@ -518,9 +518,14 @@ static int hym8563_probe(struct i2c_client *client)
} }
if (client->irq > 0) { if (client->irq > 0) {
unsigned long irqflags = IRQF_TRIGGER_LOW;
if (dev_fwnode(&client->dev))
irqflags = 0;
ret = devm_request_threaded_irq(&client->dev, client->irq, ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, hym8563_irq, NULL, hym8563_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, irqflags | IRQF_ONESHOT,
client->name, hym8563); client->name, hym8563);
if (ret < 0) { if (ret < 0) {
dev_err(&client->dev, "irq %d request failed, %d\n", dev_err(&client->dev, "irq %d request failed, %d\n",
......
...@@ -8,16 +8,16 @@ ...@@ -8,16 +8,16 @@
* by Alessandro Zummo <a.zummo@towertech.it>. * by Alessandro Zummo <a.zummo@towertech.it>.
*/ */
#include <linux/i2c.h>
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/rtc.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/err.h> #include <linux/err.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/hwmon.h> #include <linux/hwmon.h>
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#include <linux/slab.h>
#include <asm/byteorder.h>
/* ISL register offsets */ /* ISL register offsets */
#define ISL12022_REG_SC 0x00 #define ISL12022_REG_SC 0x00
...@@ -44,13 +44,6 @@ ...@@ -44,13 +44,6 @@
#define ISL12022_BETA_TSE (1 << 7) #define ISL12022_BETA_TSE (1 << 7)
static struct i2c_driver isl12022_driver;
struct isl12022 {
struct rtc_device *rtc;
struct regmap *regmap;
};
static umode_t isl12022_hwmon_is_visible(const void *data, static umode_t isl12022_hwmon_is_visible(const void *data,
enum hwmon_sensor_types type, enum hwmon_sensor_types type,
u32 attr, int channel) u32 attr, int channel)
...@@ -67,19 +60,17 @@ static umode_t isl12022_hwmon_is_visible(const void *data, ...@@ -67,19 +60,17 @@ static umode_t isl12022_hwmon_is_visible(const void *data,
*/ */
static int isl12022_hwmon_read_temp(struct device *dev, long *mC) static int isl12022_hwmon_read_temp(struct device *dev, long *mC)
{ {
struct isl12022 *isl12022 = dev_get_drvdata(dev); struct regmap *regmap = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
u8 temp_buf[2];
int temp, ret; int temp, ret;
__le16 buf;
ret = regmap_bulk_read(regmap, ISL12022_REG_TEMP_L, ret = regmap_bulk_read(regmap, ISL12022_REG_TEMP_L, &buf, sizeof(buf));
temp_buf, sizeof(temp_buf));
if (ret) if (ret)
return ret; return ret;
/* /*
* Temperature is represented as a 10-bit number, unit half-Kelvins. * Temperature is represented as a 10-bit number, unit half-Kelvins.
*/ */
temp = (temp_buf[1] << 8) | temp_buf[0]; temp = le16_to_cpu(buf);
temp *= 500; temp *= 500;
temp -= 273000; temp -= 273000;
...@@ -115,23 +106,21 @@ static const struct hwmon_chip_info isl12022_hwmon_chip_info = { ...@@ -115,23 +106,21 @@ static const struct hwmon_chip_info isl12022_hwmon_chip_info = {
static void isl12022_hwmon_register(struct device *dev) static void isl12022_hwmon_register(struct device *dev)
{ {
struct isl12022 *isl12022; struct regmap *regmap = dev_get_drvdata(dev);
struct device *hwmon; struct device *hwmon;
int ret; int ret;
if (!IS_REACHABLE(CONFIG_HWMON)) if (!IS_REACHABLE(CONFIG_HWMON))
return; return;
isl12022 = dev_get_drvdata(dev); ret = regmap_update_bits(regmap, ISL12022_REG_BETA,
ret = regmap_update_bits(isl12022->regmap, ISL12022_REG_BETA,
ISL12022_BETA_TSE, ISL12022_BETA_TSE); ISL12022_BETA_TSE, ISL12022_BETA_TSE);
if (ret) { if (ret) {
dev_warn(dev, "unable to enable temperature sensor\n"); dev_warn(dev, "unable to enable temperature sensor\n");
return; return;
} }
hwmon = devm_hwmon_device_register_with_info(dev, "isl12022", isl12022, hwmon = devm_hwmon_device_register_with_info(dev, "isl12022", regmap,
&isl12022_hwmon_chip_info, &isl12022_hwmon_chip_info,
NULL); NULL);
if (IS_ERR(hwmon)) if (IS_ERR(hwmon))
...@@ -144,8 +133,7 @@ static void isl12022_hwmon_register(struct device *dev) ...@@ -144,8 +133,7 @@ static void isl12022_hwmon_register(struct device *dev)
*/ */
static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm) static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
{ {
struct isl12022 *isl12022 = dev_get_drvdata(dev); struct regmap *regmap = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
uint8_t buf[ISL12022_REG_INT + 1]; uint8_t buf[ISL12022_REG_INT + 1];
int ret; int ret;
...@@ -155,16 +143,12 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -155,16 +143,12 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
if (buf[ISL12022_REG_SR] & (ISL12022_SR_LBAT85 | ISL12022_SR_LBAT75)) { if (buf[ISL12022_REG_SR] & (ISL12022_SR_LBAT85 | ISL12022_SR_LBAT75)) {
dev_warn(dev, dev_warn(dev,
"voltage dropped below %u%%, " "voltage dropped below %u%%, date and time is not reliable.\n",
"date and time is not reliable.\n",
buf[ISL12022_REG_SR] & ISL12022_SR_LBAT85 ? 85 : 75); buf[ISL12022_REG_SR] & ISL12022_SR_LBAT85 ? 85 : 75);
} }
dev_dbg(dev, dev_dbg(dev,
"%s: raw data is sec=%02x, min=%02x, hr=%02x, " "raw data is sec=%02x, min=%02x, hr=%02x, mday=%02x, mon=%02x, year=%02x, wday=%02x, sr=%02x, int=%02x",
"mday=%02x, mon=%02x, year=%02x, wday=%02x, "
"sr=%02x, int=%02x",
__func__,
buf[ISL12022_REG_SC], buf[ISL12022_REG_SC],
buf[ISL12022_REG_MN], buf[ISL12022_REG_MN],
buf[ISL12022_REG_HR], buf[ISL12022_REG_HR],
...@@ -190,8 +174,7 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm) ...@@ -190,8 +174,7 @@ static int isl12022_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm) static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm)
{ {
struct isl12022 *isl12022 = dev_get_drvdata(dev); struct regmap *regmap = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
int ret; int ret;
uint8_t buf[ISL12022_REG_DW + 1]; uint8_t buf[ISL12022_REG_DW + 1];
...@@ -218,8 +201,7 @@ static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm) ...@@ -218,8 +201,7 @@ static int isl12022_rtc_set_time(struct device *dev, struct rtc_time *tm)
buf[ISL12022_REG_DW] = tm->tm_wday & 0x07; buf[ISL12022_REG_DW] = tm->tm_wday & 0x07;
return regmap_bulk_write(isl12022->regmap, ISL12022_REG_SC, return regmap_bulk_write(regmap, ISL12022_REG_SC, buf, sizeof(buf));
buf, sizeof(buf));
} }
static const struct rtc_class_ops isl12022_rtc_ops = { static const struct rtc_class_ops isl12022_rtc_ops = {
...@@ -235,44 +217,39 @@ static const struct regmap_config regmap_config = { ...@@ -235,44 +217,39 @@ static const struct regmap_config regmap_config = {
static int isl12022_probe(struct i2c_client *client) static int isl12022_probe(struct i2c_client *client)
{ {
struct isl12022 *isl12022; struct rtc_device *rtc;
struct regmap *regmap;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV; return -ENODEV;
isl12022 = devm_kzalloc(&client->dev, sizeof(struct isl12022), regmap = devm_regmap_init_i2c(client, &regmap_config);
GFP_KERNEL); if (IS_ERR(regmap)) {
if (!isl12022)
return -ENOMEM;
dev_set_drvdata(&client->dev, isl12022);
isl12022->regmap = devm_regmap_init_i2c(client, &regmap_config);
if (IS_ERR(isl12022->regmap)) {
dev_err(&client->dev, "regmap allocation failed\n"); dev_err(&client->dev, "regmap allocation failed\n");
return PTR_ERR(isl12022->regmap); return PTR_ERR(regmap);
} }
dev_set_drvdata(&client->dev, regmap);
isl12022_hwmon_register(&client->dev); isl12022_hwmon_register(&client->dev);
isl12022->rtc = devm_rtc_allocate_device(&client->dev); rtc = devm_rtc_allocate_device(&client->dev);
if (IS_ERR(isl12022->rtc)) if (IS_ERR(rtc))
return PTR_ERR(isl12022->rtc); return PTR_ERR(rtc);
isl12022->rtc->ops = &isl12022_rtc_ops; rtc->ops = &isl12022_rtc_ops;
isl12022->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
isl12022->rtc->range_max = RTC_TIMESTAMP_END_2099; rtc->range_max = RTC_TIMESTAMP_END_2099;
return devm_rtc_register_device(isl12022->rtc); return devm_rtc_register_device(rtc);
} }
#ifdef CONFIG_OF
static const struct of_device_id isl12022_dt_match[] = { static const struct of_device_id isl12022_dt_match[] = {
{ .compatible = "isl,isl12022" }, /* for backward compat., don't use */ { .compatible = "isl,isl12022" }, /* for backward compat., don't use */
{ .compatible = "isil,isl12022" }, { .compatible = "isil,isl12022" },
{ }, { },
}; };
MODULE_DEVICE_TABLE(of, isl12022_dt_match); MODULE_DEVICE_TABLE(of, isl12022_dt_match);
#endif
static const struct i2c_device_id isl12022_id[] = { static const struct i2c_device_id isl12022_id[] = {
{ "isl12022", 0 }, { "isl12022", 0 },
...@@ -283,9 +260,7 @@ MODULE_DEVICE_TABLE(i2c, isl12022_id); ...@@ -283,9 +260,7 @@ MODULE_DEVICE_TABLE(i2c, isl12022_id);
static struct i2c_driver isl12022_driver = { static struct i2c_driver isl12022_driver = {
.driver = { .driver = {
.name = "rtc-isl12022", .name = "rtc-isl12022",
#ifdef CONFIG_OF .of_match_table = isl12022_dt_match,
.of_match_table = of_match_ptr(isl12022_dt_match),
#endif
}, },
.probe_new = isl12022_probe, .probe_new = isl12022_probe,
.id_table = isl12022_id, .id_table = isl12022_id,
......
...@@ -6,12 +6,15 @@ ...@@ -6,12 +6,15 @@
*/ */
#include <linux/clk.h> #include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_device.h> #include <linux/of_device.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_wakeirq.h> #include <linux/pm_wakeirq.h>
#include <linux/property.h>
#include <linux/reboot.h> #include <linux/reboot.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/slab.h> #include <linux/slab.h>
...@@ -25,6 +28,7 @@ ...@@ -25,6 +28,7 @@
#define JZ_REG_RTC_WAKEUP_FILTER 0x24 #define JZ_REG_RTC_WAKEUP_FILTER 0x24
#define JZ_REG_RTC_RESET_COUNTER 0x28 #define JZ_REG_RTC_RESET_COUNTER 0x28
#define JZ_REG_RTC_SCRATCHPAD 0x34 #define JZ_REG_RTC_SCRATCHPAD 0x34
#define JZ_REG_RTC_CKPCR 0x40
/* The following are present on the jz4780 */ /* The following are present on the jz4780 */
#define JZ_REG_RTC_WENR 0x3C #define JZ_REG_RTC_WENR 0x3C
...@@ -44,6 +48,9 @@ ...@@ -44,6 +48,9 @@
#define JZ_RTC_WAKEUP_FILTER_MASK 0x0000FFE0 #define JZ_RTC_WAKEUP_FILTER_MASK 0x0000FFE0
#define JZ_RTC_RESET_COUNTER_MASK 0x00000FE0 #define JZ_RTC_RESET_COUNTER_MASK 0x00000FE0
#define JZ_RTC_CKPCR_CK32PULL_DIS BIT(4)
#define JZ_RTC_CKPCR_CK32CTL_EN (BIT(2) | BIT(1))
enum jz4740_rtc_type { enum jz4740_rtc_type {
ID_JZ4740, ID_JZ4740,
ID_JZ4760, ID_JZ4760,
...@@ -56,6 +63,8 @@ struct jz4740_rtc { ...@@ -56,6 +63,8 @@ struct jz4740_rtc {
struct rtc_device *rtc; struct rtc_device *rtc;
struct clk_hw clk32k;
spinlock_t lock; spinlock_t lock;
}; };
...@@ -69,19 +78,15 @@ static inline uint32_t jz4740_rtc_reg_read(struct jz4740_rtc *rtc, size_t reg) ...@@ -69,19 +78,15 @@ static inline uint32_t jz4740_rtc_reg_read(struct jz4740_rtc *rtc, size_t reg)
static int jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc) static int jz4740_rtc_wait_write_ready(struct jz4740_rtc *rtc)
{ {
uint32_t ctrl; uint32_t ctrl;
int timeout = 10000;
do { return readl_poll_timeout(rtc->base + JZ_REG_RTC_CTRL, ctrl,
ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL); ctrl & JZ_RTC_CTRL_WRDY, 0, 1000);
} while (!(ctrl & JZ_RTC_CTRL_WRDY) && --timeout);
return timeout ? 0 : -EIO;
} }
static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc) static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc)
{ {
uint32_t ctrl; uint32_t ctrl;
int ret, timeout = 10000; int ret;
ret = jz4740_rtc_wait_write_ready(rtc); ret = jz4740_rtc_wait_write_ready(rtc);
if (ret != 0) if (ret != 0)
...@@ -89,11 +94,8 @@ static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc) ...@@ -89,11 +94,8 @@ static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc)
writel(JZ_RTC_WENR_MAGIC, rtc->base + JZ_REG_RTC_WENR); writel(JZ_RTC_WENR_MAGIC, rtc->base + JZ_REG_RTC_WENR);
do { return readl_poll_timeout(rtc->base + JZ_REG_RTC_WENR, ctrl,
ctrl = readl(rtc->base + JZ_REG_RTC_WENR); ctrl & JZ_RTC_WENR_WEN, 0, 1000);
} while (!(ctrl & JZ_RTC_WENR_WEN) && --timeout);
return timeout ? 0 : -EIO;
} }
static inline int jz4740_rtc_reg_write(struct jz4740_rtc *rtc, size_t reg, static inline int jz4740_rtc_reg_write(struct jz4740_rtc *rtc, size_t reg,
...@@ -260,6 +262,7 @@ static void jz4740_rtc_power_off(void) ...@@ -260,6 +262,7 @@ static void jz4740_rtc_power_off(void)
static const struct of_device_id jz4740_rtc_of_match[] = { static const struct of_device_id jz4740_rtc_of_match[] = {
{ .compatible = "ingenic,jz4740-rtc", .data = (void *)ID_JZ4740 }, { .compatible = "ingenic,jz4740-rtc", .data = (void *)ID_JZ4740 },
{ .compatible = "ingenic,jz4760-rtc", .data = (void *)ID_JZ4760 }, { .compatible = "ingenic,jz4760-rtc", .data = (void *)ID_JZ4760 },
{ .compatible = "ingenic,jz4770-rtc", .data = (void *)ID_JZ4780 },
{ .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 }, { .compatible = "ingenic,jz4780-rtc", .data = (void *)ID_JZ4780 },
{}, {},
}; };
...@@ -301,6 +304,38 @@ static void jz4740_rtc_set_wakeup_params(struct jz4740_rtc *rtc, ...@@ -301,6 +304,38 @@ static void jz4740_rtc_set_wakeup_params(struct jz4740_rtc *rtc,
jz4740_rtc_reg_write(rtc, JZ_REG_RTC_RESET_COUNTER, reset_ticks); jz4740_rtc_reg_write(rtc, JZ_REG_RTC_RESET_COUNTER, reset_ticks);
} }
static int jz4740_rtc_clk32k_enable(struct clk_hw *hw)
{
struct jz4740_rtc *rtc = container_of(hw, struct jz4740_rtc, clk32k);
return jz4740_rtc_reg_write(rtc, JZ_REG_RTC_CKPCR,
JZ_RTC_CKPCR_CK32PULL_DIS |
JZ_RTC_CKPCR_CK32CTL_EN);
}
static void jz4740_rtc_clk32k_disable(struct clk_hw *hw)
{
struct jz4740_rtc *rtc = container_of(hw, struct jz4740_rtc, clk32k);
jz4740_rtc_reg_write(rtc, JZ_REG_RTC_CKPCR, 0);
}
static int jz4740_rtc_clk32k_is_enabled(struct clk_hw *hw)
{
struct jz4740_rtc *rtc = container_of(hw, struct jz4740_rtc, clk32k);
u32 ckpcr;
ckpcr = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CKPCR);
return !!(ckpcr & JZ_RTC_CKPCR_CK32CTL_EN);
}
static const struct clk_ops jz4740_rtc_clk32k_ops = {
.enable = jz4740_rtc_clk32k_enable,
.disable = jz4740_rtc_clk32k_disable,
.is_enabled = jz4740_rtc_clk32k_is_enabled,
};
static int jz4740_rtc_probe(struct platform_device *pdev) static int jz4740_rtc_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
...@@ -335,17 +370,13 @@ static int jz4740_rtc_probe(struct platform_device *pdev) ...@@ -335,17 +370,13 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
device_init_wakeup(dev, 1); device_init_wakeup(dev, 1);
ret = dev_pm_set_wake_irq(dev, irq); ret = dev_pm_set_wake_irq(dev, irq);
if (ret) { if (ret)
dev_err(dev, "Failed to set wake irq: %d\n", ret); return dev_err_probe(dev, ret, "Failed to set wake irq\n");
return ret;
}
rtc->rtc = devm_rtc_allocate_device(dev); rtc->rtc = devm_rtc_allocate_device(dev);
if (IS_ERR(rtc->rtc)) { if (IS_ERR(rtc->rtc))
ret = PTR_ERR(rtc->rtc); return dev_err_probe(dev, PTR_ERR(rtc->rtc),
dev_err(dev, "Failed to allocate rtc device: %d\n", ret); "Failed to allocate rtc device\n");
return ret;
}
rtc->rtc->ops = &jz4740_rtc_ops; rtc->rtc->ops = &jz4740_rtc_ops;
rtc->rtc->range_max = U32_MAX; rtc->rtc->range_max = U32_MAX;
...@@ -362,10 +393,8 @@ static int jz4740_rtc_probe(struct platform_device *pdev) ...@@ -362,10 +393,8 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, irq, jz4740_rtc_irq, 0, ret = devm_request_irq(dev, irq, jz4740_rtc_irq, 0,
pdev->name, rtc); pdev->name, rtc);
if (ret) { if (ret)
dev_err(dev, "Failed to request rtc irq: %d\n", ret); return dev_err_probe(dev, ret, "Failed to request rtc irq\n");
return ret;
}
if (of_device_is_system_power_controller(np)) { if (of_device_is_system_power_controller(np)) {
dev_for_power_off = dev; dev_for_power_off = dev;
...@@ -376,6 +405,21 @@ static int jz4740_rtc_probe(struct platform_device *pdev) ...@@ -376,6 +405,21 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
dev_warn(dev, "Poweroff handler already present!\n"); dev_warn(dev, "Poweroff handler already present!\n");
} }
if (device_property_present(dev, "#clock-cells")) {
rtc->clk32k.init = CLK_HW_INIT_HW("clk32k", __clk_get_hw(clk),
&jz4740_rtc_clk32k_ops, 0);
ret = devm_clk_hw_register(dev, &rtc->clk32k);
if (ret)
return dev_err_probe(dev, ret,
"Unable to register clk32k clock\n");
ret = of_clk_add_hw_provider(np, of_clk_hw_simple_get, &rtc->clk32k);
if (ret)
return dev_err_probe(dev, ret,
"Unable to register clk32k clock provider\n");
}
return 0; return 0;
} }
......
...@@ -914,9 +914,14 @@ static int m41t80_probe(struct i2c_client *client) ...@@ -914,9 +914,14 @@ static int m41t80_probe(struct i2c_client *client)
"wakeup-source"); "wakeup-source");
#endif #endif
if (client->irq > 0) { if (client->irq > 0) {
unsigned long irqflags = IRQF_TRIGGER_LOW;
if (dev_fwnode(&client->dev))
irqflags = 0;
rc = devm_request_threaded_irq(&client->dev, client->irq, rc = devm_request_threaded_irq(&client->dev, client->irq,
NULL, m41t80_handle_irq, NULL, m41t80_handle_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, irqflags | IRQF_ONESHOT,
"m41t80", client); "m41t80", client);
if (rc) { if (rc) {
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n"); dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
......
...@@ -9,7 +9,6 @@ ...@@ -9,7 +9,6 @@
*/ */
#include <linux/bcd.h> #include <linux/bcd.h>
#include <linux/i2c.h>
#include <linux/mfd/max8907.h> #include <linux/mfd/max8907.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
......
...@@ -10,14 +10,15 @@ ...@@ -10,14 +10,15 @@
* Moxa Technology Co., Ltd. <www.moxa.com> * Moxa Technology Co., Ltd. <www.moxa.com>
*/ */
#include <linux/err.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/gpio.h> #include <linux/mod_devicetable.h>
#include <linux/of_gpio.h> #include <linux/gpio/consumer.h>
#define GPIO_RTC_RESERVED 0x0C #define GPIO_RTC_RESERVED 0x0C
#define GPIO_RTC_DATA_SET 0x10 #define GPIO_RTC_DATA_SET 0x10
...@@ -55,7 +56,9 @@ ...@@ -55,7 +56,9 @@
struct moxart_rtc { struct moxart_rtc {
struct rtc_device *rtc; struct rtc_device *rtc;
spinlock_t rtc_lock; spinlock_t rtc_lock;
int gpio_data, gpio_sclk, gpio_reset; struct gpio_desc *gpio_data;
struct gpio_desc *gpio_sclk;
struct gpio_desc *gpio_reset;
}; };
static int day_of_year[12] = { 0, 31, 59, 90, 120, 151, 181, static int day_of_year[12] = { 0, 31, 59, 90, 120, 151, 181,
...@@ -67,10 +70,10 @@ static void moxart_rtc_write_byte(struct device *dev, u8 data) ...@@ -67,10 +70,10 @@ static void moxart_rtc_write_byte(struct device *dev, u8 data)
int i; int i;
for (i = 0; i < 8; i++, data >>= 1) { for (i = 0; i < 8; i++, data >>= 1) {
gpio_set_value(moxart_rtc->gpio_sclk, 0); gpiod_set_value(moxart_rtc->gpio_sclk, 0);
gpio_set_value(moxart_rtc->gpio_data, ((data & 1) == 1)); gpiod_set_value(moxart_rtc->gpio_data, ((data & 1) == 1));
udelay(GPIO_RTC_DELAY_TIME); udelay(GPIO_RTC_DELAY_TIME);
gpio_set_value(moxart_rtc->gpio_sclk, 1); gpiod_set_value(moxart_rtc->gpio_sclk, 1);
udelay(GPIO_RTC_DELAY_TIME); udelay(GPIO_RTC_DELAY_TIME);
} }
} }
...@@ -82,11 +85,11 @@ static u8 moxart_rtc_read_byte(struct device *dev) ...@@ -82,11 +85,11 @@ static u8 moxart_rtc_read_byte(struct device *dev)
u8 data = 0; u8 data = 0;
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
gpio_set_value(moxart_rtc->gpio_sclk, 0); gpiod_set_value(moxart_rtc->gpio_sclk, 0);
udelay(GPIO_RTC_DELAY_TIME); udelay(GPIO_RTC_DELAY_TIME);
gpio_set_value(moxart_rtc->gpio_sclk, 1); gpiod_set_value(moxart_rtc->gpio_sclk, 1);
udelay(GPIO_RTC_DELAY_TIME); udelay(GPIO_RTC_DELAY_TIME);
if (gpio_get_value(moxart_rtc->gpio_data)) if (gpiod_get_value(moxart_rtc->gpio_data))
data |= (1 << i); data |= (1 << i);
udelay(GPIO_RTC_DELAY_TIME); udelay(GPIO_RTC_DELAY_TIME);
} }
...@@ -101,15 +104,15 @@ static u8 moxart_rtc_read_register(struct device *dev, u8 cmd) ...@@ -101,15 +104,15 @@ static u8 moxart_rtc_read_register(struct device *dev, u8 cmd)
local_irq_save(flags); local_irq_save(flags);
gpio_direction_output(moxart_rtc->gpio_data, 0); gpiod_direction_output(moxart_rtc->gpio_data, 0);
gpio_set_value(moxart_rtc->gpio_reset, 1); gpiod_set_value(moxart_rtc->gpio_reset, 1);
udelay(GPIO_RTC_DELAY_TIME); udelay(GPIO_RTC_DELAY_TIME);
moxart_rtc_write_byte(dev, cmd); moxart_rtc_write_byte(dev, cmd);
gpio_direction_input(moxart_rtc->gpio_data); gpiod_direction_input(moxart_rtc->gpio_data);
udelay(GPIO_RTC_DELAY_TIME); udelay(GPIO_RTC_DELAY_TIME);
data = moxart_rtc_read_byte(dev); data = moxart_rtc_read_byte(dev);
gpio_set_value(moxart_rtc->gpio_sclk, 0); gpiod_set_value(moxart_rtc->gpio_sclk, 0);
gpio_set_value(moxart_rtc->gpio_reset, 0); gpiod_set_value(moxart_rtc->gpio_reset, 0);
udelay(GPIO_RTC_DELAY_TIME); udelay(GPIO_RTC_DELAY_TIME);
local_irq_restore(flags); local_irq_restore(flags);
...@@ -124,13 +127,13 @@ static void moxart_rtc_write_register(struct device *dev, u8 cmd, u8 data) ...@@ -124,13 +127,13 @@ static void moxart_rtc_write_register(struct device *dev, u8 cmd, u8 data)
local_irq_save(flags); local_irq_save(flags);
gpio_direction_output(moxart_rtc->gpio_data, 0); gpiod_direction_output(moxart_rtc->gpio_data, 0);
gpio_set_value(moxart_rtc->gpio_reset, 1); gpiod_set_value(moxart_rtc->gpio_reset, 1);
udelay(GPIO_RTC_DELAY_TIME); udelay(GPIO_RTC_DELAY_TIME);
moxart_rtc_write_byte(dev, cmd); moxart_rtc_write_byte(dev, cmd);
moxart_rtc_write_byte(dev, data); moxart_rtc_write_byte(dev, data);
gpio_set_value(moxart_rtc->gpio_sclk, 0); gpiod_set_value(moxart_rtc->gpio_sclk, 0);
gpio_set_value(moxart_rtc->gpio_reset, 0); gpiod_set_value(moxart_rtc->gpio_reset, 0);
udelay(GPIO_RTC_DELAY_TIME); udelay(GPIO_RTC_DELAY_TIME);
local_irq_restore(flags); local_irq_restore(flags);
...@@ -247,53 +250,33 @@ static int moxart_rtc_probe(struct platform_device *pdev) ...@@ -247,53 +250,33 @@ static int moxart_rtc_probe(struct platform_device *pdev)
if (!moxart_rtc) if (!moxart_rtc)
return -ENOMEM; return -ENOMEM;
moxart_rtc->gpio_data = of_get_named_gpio(pdev->dev.of_node, moxart_rtc->gpio_data = devm_gpiod_get(&pdev->dev, "rtc-data",
"gpio-rtc-data", 0); GPIOD_IN);
if (!gpio_is_valid(moxart_rtc->gpio_data)) { ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_data);
dev_err(&pdev->dev, "invalid gpio (data): %d\n",
moxart_rtc->gpio_data);
return moxart_rtc->gpio_data;
}
moxart_rtc->gpio_sclk = of_get_named_gpio(pdev->dev.of_node,
"gpio-rtc-sclk", 0);
if (!gpio_is_valid(moxart_rtc->gpio_sclk)) {
dev_err(&pdev->dev, "invalid gpio (sclk): %d\n",
moxart_rtc->gpio_sclk);
return moxart_rtc->gpio_sclk;
}
moxart_rtc->gpio_reset = of_get_named_gpio(pdev->dev.of_node,
"gpio-rtc-reset", 0);
if (!gpio_is_valid(moxart_rtc->gpio_reset)) {
dev_err(&pdev->dev, "invalid gpio (reset): %d\n",
moxart_rtc->gpio_reset);
return moxart_rtc->gpio_reset;
}
spin_lock_init(&moxart_rtc->rtc_lock);
platform_set_drvdata(pdev, moxart_rtc);
ret = devm_gpio_request(&pdev->dev, moxart_rtc->gpio_data, "rtc_data");
if (ret) { if (ret) {
dev_err(&pdev->dev, "can't get rtc_data gpio\n"); dev_err(&pdev->dev, "can't get rtc data gpio: %d\n", ret);
return ret; return ret;
} }
ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_sclk, moxart_rtc->gpio_sclk = devm_gpiod_get(&pdev->dev, "rtc-sclk",
GPIOF_DIR_OUT, "rtc_sclk"); GPIOD_ASIS);
ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_sclk);
if (ret) { if (ret) {
dev_err(&pdev->dev, "can't get rtc_sclk gpio\n"); dev_err(&pdev->dev, "can't get rtc sclk gpio: %d\n", ret);
return ret; return ret;
} }
ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_reset, moxart_rtc->gpio_reset = devm_gpiod_get(&pdev->dev, "rtc-reset",
GPIOF_DIR_OUT, "rtc_reset"); GPIOD_ASIS);
ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_reset);
if (ret) { if (ret) {
dev_err(&pdev->dev, "can't get rtc_reset gpio\n"); dev_err(&pdev->dev, "can't get rtc reset gpio: %d\n", ret);
return ret; return ret;
} }
spin_lock_init(&moxart_rtc->rtc_lock);
platform_set_drvdata(pdev, moxart_rtc);
moxart_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, moxart_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&moxart_rtc_ops, &moxart_rtc_ops,
THIS_MODULE); THIS_MODULE);
......
// SPDX-License-Identifier: GPL-2.0+
//
// Copyright 2022 NXP.
#include <linux/init.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_wakeirq.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#define BBNSM_CTRL 0x8
#define BBNSM_INT_EN 0x10
#define BBNSM_EVENTS 0x14
#define BBNSM_RTC_LS 0x40
#define BBNSM_RTC_MS 0x44
#define BBNSM_TA 0x50
#define RTC_EN 0x2
#define RTC_EN_MSK 0x3
#define TA_EN (0x2 << 2)
#define TA_DIS (0x1 << 2)
#define TA_EN_MSK (0x3 << 2)
#define RTC_INT_EN 0x2
#define TA_INT_EN (0x2 << 2)
#define BBNSM_EVENT_TA (0x2 << 2)
#define CNTR_TO_SECS_SH 15
struct bbnsm_rtc {
struct rtc_device *rtc;
struct regmap *regmap;
int irq;
struct clk *clk;
};
static u32 bbnsm_read_counter(struct bbnsm_rtc *bbnsm)
{
u32 rtc_msb, rtc_lsb;
unsigned int timeout = 100;
u32 time;
u32 tmp = 0;
do {
time = tmp;
/* read the msb */
regmap_read(bbnsm->regmap, BBNSM_RTC_MS, &rtc_msb);
/* read the lsb */
regmap_read(bbnsm->regmap, BBNSM_RTC_LS, &rtc_lsb);
/* convert to seconds */
tmp = (rtc_msb << 17) | (rtc_lsb >> 15);
} while (tmp != time && --timeout);
return time;
}
static int bbnsm_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
unsigned long time;
u32 val;
regmap_read(bbnsm->regmap, BBNSM_CTRL, &val);
if ((val & RTC_EN_MSK) != RTC_EN)
return -EINVAL;
time = bbnsm_read_counter(bbnsm);
rtc_time64_to_tm(time, tm);
return 0;
}
static int bbnsm_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
unsigned long time = rtc_tm_to_time64(tm);
/* disable the RTC first */
regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, RTC_EN_MSK, 0);
/* write the 32bit sec time to 47 bit timer counter, leaving 15 LSBs blank */
regmap_write(bbnsm->regmap, BBNSM_RTC_LS, time << CNTR_TO_SECS_SH);
regmap_write(bbnsm->regmap, BBNSM_RTC_MS, time >> (32 - CNTR_TO_SECS_SH));
/* Enable the RTC again */
regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, RTC_EN_MSK, RTC_EN);
return 0;
}
static int bbnsm_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
u32 bbnsm_events, bbnsm_ta;
regmap_read(bbnsm->regmap, BBNSM_TA, &bbnsm_ta);
rtc_time64_to_tm(bbnsm_ta, &alrm->time);
regmap_read(bbnsm->regmap, BBNSM_EVENTS, &bbnsm_events);
alrm->pending = (bbnsm_events & BBNSM_EVENT_TA) ? 1 : 0;
return 0;
}
static int bbnsm_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
{
struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
/* enable the alarm event */
regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, TA_EN_MSK, enable ? TA_EN : TA_DIS);
/* enable the alarm interrupt */
regmap_update_bits(bbnsm->regmap, BBNSM_INT_EN, TA_EN_MSK, enable ? TA_EN : TA_DIS);
return 0;
}
static int bbnsm_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
unsigned long time = rtc_tm_to_time64(&alrm->time);
/* disable the alarm */
regmap_update_bits(bbnsm->regmap, BBNSM_CTRL, TA_EN, TA_EN);
/* write the seconds to TA */
regmap_write(bbnsm->regmap, BBNSM_TA, time);
return bbnsm_rtc_alarm_irq_enable(dev, alrm->enabled);
}
static const struct rtc_class_ops bbnsm_rtc_ops = {
.read_time = bbnsm_rtc_read_time,
.set_time = bbnsm_rtc_set_time,
.read_alarm = bbnsm_rtc_read_alarm,
.set_alarm = bbnsm_rtc_set_alarm,
.alarm_irq_enable = bbnsm_rtc_alarm_irq_enable,
};
static irqreturn_t bbnsm_rtc_irq_handler(int irq, void *dev_id)
{
struct device *dev = dev_id;
struct bbnsm_rtc *bbnsm = dev_get_drvdata(dev);
u32 val;
regmap_read(bbnsm->regmap, BBNSM_EVENTS, &val);
if (val & BBNSM_EVENT_TA) {
bbnsm_rtc_alarm_irq_enable(dev, false);
/* clear the alarm event */
regmap_write_bits(bbnsm->regmap, BBNSM_EVENTS, TA_EN_MSK, BBNSM_EVENT_TA);
rtc_update_irq(bbnsm->rtc, 1, RTC_AF | RTC_IRQF);
return IRQ_HANDLED;
}
return IRQ_NONE;
}
static int bbnsm_rtc_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct bbnsm_rtc *bbnsm;
int ret;
bbnsm = devm_kzalloc(&pdev->dev, sizeof(*bbnsm), GFP_KERNEL);
if (!bbnsm)
return -ENOMEM;
bbnsm->rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(bbnsm->rtc))
return PTR_ERR(bbnsm->rtc);
bbnsm->regmap = syscon_node_to_regmap(np->parent);
if (IS_ERR(bbnsm->regmap)) {
dev_dbg(&pdev->dev, "bbnsm get regmap failed\n");
return PTR_ERR(bbnsm->regmap);
}
bbnsm->irq = platform_get_irq(pdev, 0);
if (bbnsm->irq < 0)
return bbnsm->irq;
platform_set_drvdata(pdev, bbnsm);
/* clear all the pending events */
regmap_write(bbnsm->regmap, BBNSM_EVENTS, 0x7A);
device_init_wakeup(&pdev->dev, true);
dev_pm_set_wake_irq(&pdev->dev, bbnsm->irq);
ret = devm_request_irq(&pdev->dev, bbnsm->irq, bbnsm_rtc_irq_handler,
IRQF_SHARED, "rtc alarm", &pdev->dev);
if (ret) {
dev_err(&pdev->dev, "failed to request irq %d: %d\n",
bbnsm->irq, ret);
return ret;
}
bbnsm->rtc->ops = &bbnsm_rtc_ops;
bbnsm->rtc->range_max = U32_MAX;
return devm_rtc_register_device(bbnsm->rtc);
}
static const struct of_device_id bbnsm_dt_ids[] = {
{ .compatible = "nxp,imx93-bbnsm-rtc" },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, bbnsm_dt_ids);
static struct platform_driver bbnsm_rtc_driver = {
.driver = {
.name = "bbnsm_rtc",
.of_match_table = bbnsm_dt_ids,
},
.probe = bbnsm_rtc_probe,
};
module_platform_driver(bbnsm_rtc_driver);
MODULE_AUTHOR("Jacky Bai <ping.bai@nxp.com>");
MODULE_DESCRIPTION("NXP BBNSM RTC Driver");
MODULE_LICENSE("GPL");
...@@ -413,9 +413,14 @@ static int pcf2123_probe(struct spi_device *spi) ...@@ -413,9 +413,14 @@ static int pcf2123_probe(struct spi_device *spi)
/* Register alarm irq */ /* Register alarm irq */
if (spi->irq > 0) { if (spi->irq > 0) {
unsigned long irqflags = IRQF_TRIGGER_LOW;
if (dev_fwnode(&spi->dev))
irqflags = 0;
ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, ret = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
pcf2123_rtc_irq, pcf2123_rtc_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, irqflags | IRQF_ONESHOT,
pcf2123_driver.driver.name, &spi->dev); pcf2123_driver.driver.name, &spi->dev);
if (!ret) if (!ret)
device_init_wakeup(&spi->dev, true); device_init_wakeup(&spi->dev, true);
......
...@@ -621,9 +621,14 @@ static int pcf85063_probe(struct i2c_client *client) ...@@ -621,9 +621,14 @@ static int pcf85063_probe(struct i2c_client *client)
clear_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features); clear_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features);
if (config->has_alarms && client->irq > 0) { if (config->has_alarms && client->irq > 0) {
unsigned long irqflags = IRQF_TRIGGER_LOW;
if (dev_fwnode(&client->dev))
irqflags = 0;
err = devm_request_threaded_irq(&client->dev, client->irq, err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf85063_rtc_handle_irq, NULL, pcf85063_rtc_handle_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, irqflags | IRQF_ONESHOT,
"pcf85063", pcf85063); "pcf85063", pcf85063);
if (err) { if (err) {
dev_warn(&pcf85063->rtc->dev, dev_warn(&pcf85063->rtc->dev,
......
...@@ -445,13 +445,18 @@ static int pcf8523_probe(struct i2c_client *client) ...@@ -445,13 +445,18 @@ static int pcf8523_probe(struct i2c_client *client)
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features); clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
if (client->irq > 0) { if (client->irq > 0) {
unsigned long irqflags = IRQF_TRIGGER_LOW;
if (dev_fwnode(&client->dev))
irqflags = 0;
err = regmap_write(pcf8523->regmap, PCF8523_TMR_CLKOUT_CTRL, 0x38); err = regmap_write(pcf8523->regmap, PCF8523_TMR_CLKOUT_CTRL, 0x38);
if (err < 0) if (err < 0)
return err; return err;
err = devm_request_threaded_irq(&client->dev, client->irq, err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf8523_irq, NULL, pcf8523_irq,
IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW, IRQF_SHARED | IRQF_ONESHOT | irqflags,
dev_name(&rtc->dev), pcf8523); dev_name(&rtc->dev), pcf8523);
if (err) if (err)
return err; return err;
......
...@@ -101,6 +101,10 @@ ...@@ -101,6 +101,10 @@
#define PIN_IO_INTA_OUT 2 #define PIN_IO_INTA_OUT 2
#define PIN_IO_INTA_HIZ 3 #define PIN_IO_INTA_HIZ 3
#define OSC_CAP_SEL GENMASK(1, 0)
#define OSC_CAP_6000 0x01
#define OSC_CAP_12500 0x02
#define STOP_EN_STOP BIT(0) #define STOP_EN_STOP BIT(0)
#define RESET_CPR 0xa4 #define RESET_CPR 0xa4
...@@ -117,6 +121,32 @@ struct pcf85x63_config { ...@@ -117,6 +121,32 @@ struct pcf85x63_config {
unsigned int num_nvram; unsigned int num_nvram;
}; };
static int pcf85363_load_capacitance(struct pcf85363 *pcf85363, struct device_node *node)
{
u32 load = 7000;
u8 value = 0;
of_property_read_u32(node, "quartz-load-femtofarads", &load);
switch (load) {
default:
dev_warn(&pcf85363->rtc->dev, "Unknown quartz-load-femtofarads value: %d. Assuming 7000",
load);
fallthrough;
case 7000:
break;
case 6000:
value = OSC_CAP_6000;
break;
case 12500:
value = OSC_CAP_12500;
break;
}
return regmap_update_bits(pcf85363->regmap, CTRL_OSCILLATOR,
OSC_CAP_SEL, value);
}
static int pcf85363_rtc_read_time(struct device *dev, struct rtc_time *tm) static int pcf85363_rtc_read_time(struct device *dev, struct rtc_time *tm)
{ {
struct pcf85363 *pcf85363 = dev_get_drvdata(dev); struct pcf85363 *pcf85363 = dev_get_drvdata(dev);
...@@ -372,7 +402,7 @@ static int pcf85363_probe(struct i2c_client *client) ...@@ -372,7 +402,7 @@ static int pcf85363_probe(struct i2c_client *client)
.reg_write = pcf85363_nvram_write, .reg_write = pcf85363_nvram_write,
}, },
}; };
int ret, i; int ret, i, err;
if (data) if (data)
config = data; config = data;
...@@ -394,18 +424,28 @@ static int pcf85363_probe(struct i2c_client *client) ...@@ -394,18 +424,28 @@ static int pcf85363_probe(struct i2c_client *client)
if (IS_ERR(pcf85363->rtc)) if (IS_ERR(pcf85363->rtc))
return PTR_ERR(pcf85363->rtc); return PTR_ERR(pcf85363->rtc);
err = pcf85363_load_capacitance(pcf85363, client->dev.of_node);
if (err < 0)
dev_warn(&client->dev, "failed to set xtal load capacitance: %d",
err);
pcf85363->rtc->ops = &rtc_ops; pcf85363->rtc->ops = &rtc_ops;
pcf85363->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; pcf85363->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
pcf85363->rtc->range_max = RTC_TIMESTAMP_END_2099; pcf85363->rtc->range_max = RTC_TIMESTAMP_END_2099;
clear_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features); clear_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features);
if (client->irq > 0) { if (client->irq > 0) {
unsigned long irqflags = IRQF_TRIGGER_LOW;
if (dev_fwnode(&client->dev))
irqflags = 0;
regmap_write(pcf85363->regmap, CTRL_FLAGS, 0); regmap_write(pcf85363->regmap, CTRL_FLAGS, 0);
regmap_update_bits(pcf85363->regmap, CTRL_PIN_IO, regmap_update_bits(pcf85363->regmap, CTRL_PIN_IO,
PIN_IO_INTA_OUT, PIN_IO_INTAPM); PIN_IO_INTA_OUT, PIN_IO_INTAPM);
ret = devm_request_threaded_irq(&client->dev, client->irq, ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf85363_rtc_handle_irq, NULL, pcf85363_rtc_handle_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, irqflags | IRQF_ONESHOT,
"pcf85363", client); "pcf85363", client);
if (ret) if (ret)
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n"); dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
......
...@@ -558,9 +558,14 @@ static int pcf8563_probe(struct i2c_client *client) ...@@ -558,9 +558,14 @@ static int pcf8563_probe(struct i2c_client *client)
pcf8563->rtc->set_start_time = true; pcf8563->rtc->set_start_time = true;
if (client->irq > 0) { if (client->irq > 0) {
unsigned long irqflags = IRQF_TRIGGER_LOW;
if (dev_fwnode(&client->dev))
irqflags = 0;
err = devm_request_threaded_irq(&client->dev, client->irq, err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf8563_irq, NULL, pcf8563_irq,
IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW, IRQF_SHARED | IRQF_ONESHOT | irqflags,
pcf8563_driver.driver.name, client); pcf8563_driver.driver.name, client);
if (err) { if (err) {
dev_err(&client->dev, "unable to request IRQ %d\n", dev_err(&client->dev, "unable to request IRQ %d\n",
......
This diff is collapsed.
...@@ -982,6 +982,12 @@ static int rv3028_probe(struct i2c_client *client) ...@@ -982,6 +982,12 @@ static int rv3028_probe(struct i2c_client *client)
return 0; return 0;
} }
static const struct acpi_device_id rv3028_i2c_acpi_match[] = {
{ "MCRY3028" },
{ }
};
MODULE_DEVICE_TABLE(acpi, rv3028_i2c_acpi_match);
static const __maybe_unused struct of_device_id rv3028_of_match[] = { static const __maybe_unused struct of_device_id rv3028_of_match[] = {
{ .compatible = "microcrystal,rv3028", }, { .compatible = "microcrystal,rv3028", },
{ } { }
...@@ -991,6 +997,7 @@ MODULE_DEVICE_TABLE(of, rv3028_of_match); ...@@ -991,6 +997,7 @@ MODULE_DEVICE_TABLE(of, rv3028_of_match);
static struct i2c_driver rv3028_driver = { static struct i2c_driver rv3028_driver = {
.driver = { .driver = {
.name = "rtc-rv3028", .name = "rtc-rv3028",
.acpi_match_table = rv3028_i2c_acpi_match,
.of_match_table = of_match_ptr(rv3028_of_match), .of_match_table = of_match_ptr(rv3028_of_match),
}, },
.probe_new = rv3028_probe, .probe_new = rv3028_probe,
......
...@@ -735,9 +735,14 @@ static int rv3029_probe(struct device *dev, struct regmap *regmap, int irq, ...@@ -735,9 +735,14 @@ static int rv3029_probe(struct device *dev, struct regmap *regmap, int irq,
return PTR_ERR(rv3029->rtc); return PTR_ERR(rv3029->rtc);
if (rv3029->irq > 0) { if (rv3029->irq > 0) {
unsigned long irqflags = IRQF_TRIGGER_LOW;
if (dev_fwnode(dev))
irqflags = 0;
rc = devm_request_threaded_irq(dev, rv3029->irq, rc = devm_request_threaded_irq(dev, rv3029->irq,
NULL, rv3029_handle_irq, NULL, rv3029_handle_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, irqflags | IRQF_ONESHOT,
"rv3029", dev); "rv3029", dev);
if (rc) { if (rc) {
dev_warn(dev, "unable to request IRQ, alarms disabled\n"); dev_warn(dev, "unable to request IRQ, alarms disabled\n");
......
...@@ -930,9 +930,14 @@ static int rv3032_probe(struct i2c_client *client) ...@@ -930,9 +930,14 @@ static int rv3032_probe(struct i2c_client *client)
return PTR_ERR(rv3032->rtc); return PTR_ERR(rv3032->rtc);
if (client->irq > 0) { if (client->irq > 0) {
unsigned long irqflags = IRQF_TRIGGER_LOW;
if (dev_fwnode(&client->dev))
irqflags = 0;
ret = devm_request_threaded_irq(&client->dev, client->irq, ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, rv3032_handle_irq, NULL, rv3032_handle_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, irqflags | IRQF_ONESHOT,
"rv3032", rv3032); "rv3032", rv3032);
if (ret) { if (ret) {
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n"); dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
...@@ -975,6 +980,12 @@ static int rv3032_probe(struct i2c_client *client) ...@@ -975,6 +980,12 @@ static int rv3032_probe(struct i2c_client *client)
return 0; return 0;
} }
static const struct acpi_device_id rv3032_i2c_acpi_match[] = {
{ "MCRY3032" },
{ }
};
MODULE_DEVICE_TABLE(acpi, rv3032_i2c_acpi_match);
static const __maybe_unused struct of_device_id rv3032_of_match[] = { static const __maybe_unused struct of_device_id rv3032_of_match[] = {
{ .compatible = "microcrystal,rv3032", }, { .compatible = "microcrystal,rv3032", },
{ } { }
...@@ -984,6 +995,7 @@ MODULE_DEVICE_TABLE(of, rv3032_of_match); ...@@ -984,6 +995,7 @@ MODULE_DEVICE_TABLE(of, rv3032_of_match);
static struct i2c_driver rv3032_driver = { static struct i2c_driver rv3032_driver = {
.driver = { .driver = {
.name = "rtc-rv3032", .name = "rtc-rv3032",
.acpi_match_table = rv3032_i2c_acpi_match,
.of_match_table = of_match_ptr(rv3032_of_match), .of_match_table = of_match_ptr(rv3032_of_match),
}, },
.probe_new = rv3032_probe, .probe_new = rv3032_probe,
......
...@@ -70,6 +70,7 @@ struct rv8803_data { ...@@ -70,6 +70,7 @@ struct rv8803_data {
struct mutex flags_lock; struct mutex flags_lock;
u8 ctrl; u8 ctrl;
u8 backup; u8 backup;
u8 alarm_invalid:1;
enum rv8803_type type; enum rv8803_type type;
}; };
...@@ -165,13 +166,13 @@ static int rv8803_regs_init(struct rv8803_data *rv8803) ...@@ -165,13 +166,13 @@ static int rv8803_regs_init(struct rv8803_data *rv8803)
static int rv8803_regs_configure(struct rv8803_data *rv8803); static int rv8803_regs_configure(struct rv8803_data *rv8803);
static int rv8803_regs_reset(struct rv8803_data *rv8803) static int rv8803_regs_reset(struct rv8803_data *rv8803, bool full)
{ {
/* /*
* The RV-8803 resets all registers to POR defaults after voltage-loss, * The RV-8803 resets all registers to POR defaults after voltage-loss,
* the Epson RTCs don't, so we manually reset the remainder here. * the Epson RTCs don't, so we manually reset the remainder here.
*/ */
if (rv8803->type == rx_8803 || rv8803->type == rx_8900) { if (full || rv8803->type == rx_8803 || rv8803->type == rx_8900) {
int ret = rv8803_regs_init(rv8803); int ret = rv8803_regs_init(rv8803);
if (ret) if (ret)
return ret; return ret;
...@@ -238,6 +239,11 @@ static int rv8803_get_time(struct device *dev, struct rtc_time *tm) ...@@ -238,6 +239,11 @@ static int rv8803_get_time(struct device *dev, struct rtc_time *tm)
u8 *date = date1; u8 *date = date1;
int ret, flags; int ret, flags;
if (rv8803->alarm_invalid) {
dev_warn(dev, "Corruption detected, data may be invalid.\n");
return -EINVAL;
}
flags = rv8803_read_reg(rv8803->client, RV8803_FLAG); flags = rv8803_read_reg(rv8803->client, RV8803_FLAG);
if (flags < 0) if (flags < 0)
return flags; return flags;
...@@ -313,12 +319,19 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm) ...@@ -313,12 +319,19 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
return flags; return flags;
} }
if (flags & RV8803_FLAG_V2F) { if ((flags & RV8803_FLAG_V2F) || rv8803->alarm_invalid) {
ret = rv8803_regs_reset(rv8803); /*
* If we sense corruption in the alarm registers, but see no
* voltage loss flag, we can't rely on other registers having
* sensible values. Reset them fully.
*/
ret = rv8803_regs_reset(rv8803, rv8803->alarm_invalid);
if (ret) { if (ret) {
mutex_unlock(&rv8803->flags_lock); mutex_unlock(&rv8803->flags_lock);
return ret; return ret;
} }
rv8803->alarm_invalid = false;
} }
ret = rv8803_write_reg(rv8803->client, RV8803_FLAG, ret = rv8803_write_reg(rv8803->client, RV8803_FLAG,
...@@ -344,15 +357,33 @@ static int rv8803_get_alarm(struct device *dev, struct rtc_wkalrm *alrm) ...@@ -344,15 +357,33 @@ static int rv8803_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
if (flags < 0) if (flags < 0)
return flags; return flags;
alarmvals[0] &= 0x7f;
alarmvals[1] &= 0x3f;
alarmvals[2] &= 0x3f;
if (!bcd_is_valid(alarmvals[0]) ||
!bcd_is_valid(alarmvals[1]) ||
!bcd_is_valid(alarmvals[2]))
goto err_invalid;
alrm->time.tm_sec = 0; alrm->time.tm_sec = 0;
alrm->time.tm_min = bcd2bin(alarmvals[0] & 0x7f); alrm->time.tm_min = bcd2bin(alarmvals[0]);
alrm->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f); alrm->time.tm_hour = bcd2bin(alarmvals[1]);
alrm->time.tm_mday = bcd2bin(alarmvals[2] & 0x3f); alrm->time.tm_mday = bcd2bin(alarmvals[2]);
alrm->enabled = !!(rv8803->ctrl & RV8803_CTRL_AIE); alrm->enabled = !!(rv8803->ctrl & RV8803_CTRL_AIE);
alrm->pending = (flags & RV8803_FLAG_AF) && alrm->enabled; alrm->pending = (flags & RV8803_FLAG_AF) && alrm->enabled;
if ((unsigned int)alrm->time.tm_mday > 31 ||
(unsigned int)alrm->time.tm_hour >= 24 ||
(unsigned int)alrm->time.tm_min >= 60)
goto err_invalid;
return 0; return 0;
err_invalid:
rv8803->alarm_invalid = true;
return -EINVAL;
} }
static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
...@@ -641,9 +672,14 @@ static int rv8803_probe(struct i2c_client *client) ...@@ -641,9 +672,14 @@ static int rv8803_probe(struct i2c_client *client)
return PTR_ERR(rv8803->rtc); return PTR_ERR(rv8803->rtc);
if (client->irq > 0) { if (client->irq > 0) {
unsigned long irqflags = IRQF_TRIGGER_LOW;
if (dev_fwnode(&client->dev))
irqflags = 0;
err = devm_request_threaded_irq(&client->dev, client->irq, err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, rv8803_handle_irq, NULL, rv8803_handle_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, irqflags | IRQF_ONESHOT,
"rv8803", client); "rv8803", client);
if (err) { if (err) {
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n"); dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <linux/rtc.h> #include <linux/rtc.h>
#include <linux/of.h> #include <linux/of.h>
......
...@@ -394,10 +394,14 @@ static int rx8010_probe(struct i2c_client *client) ...@@ -394,10 +394,14 @@ static int rx8010_probe(struct i2c_client *client)
return PTR_ERR(rx8010->rtc); return PTR_ERR(rx8010->rtc);
if (client->irq > 0) { if (client->irq > 0) {
dev_info(dev, "IRQ %d supplied\n", client->irq); unsigned long irqflags = IRQF_TRIGGER_LOW;
if (dev_fwnode(&client->dev))
irqflags = 0;
err = devm_request_threaded_irq(dev, client->irq, NULL, err = devm_request_threaded_irq(dev, client->irq, NULL,
rx8010_irq_1_handler, rx8010_irq_1_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT, irqflags | IRQF_ONESHOT,
"rx8010", client); "rx8010", client);
if (err) { if (err) {
dev_err(dev, "unable to request IRQ\n"); dev_err(dev, "unable to request IRQ\n");
......
...@@ -136,7 +136,6 @@ struct sun6i_rtc_clk_data { ...@@ -136,7 +136,6 @@ struct sun6i_rtc_clk_data {
unsigned int fixed_prescaler : 16; unsigned int fixed_prescaler : 16;
unsigned int has_prescaler : 1; unsigned int has_prescaler : 1;
unsigned int has_out_clk : 1; unsigned int has_out_clk : 1;
unsigned int export_iosc : 1;
unsigned int has_losc_en : 1; unsigned int has_losc_en : 1;
unsigned int has_auto_swt : 1; unsigned int has_auto_swt : 1;
}; };
...@@ -271,10 +270,8 @@ static void __init sun6i_rtc_clk_init(struct device_node *node, ...@@ -271,10 +270,8 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
/* Yes, I know, this is ugly. */ /* Yes, I know, this is ugly. */
sun6i_rtc = rtc; sun6i_rtc = rtc;
/* Only read IOSC name from device tree if it is exported */ of_property_read_string_index(node, "clock-output-names", 2,
if (rtc->data->export_iosc) &iosc_name);
of_property_read_string_index(node, "clock-output-names", 2,
&iosc_name);
rtc->int_osc = clk_hw_register_fixed_rate_with_accuracy(NULL, rtc->int_osc = clk_hw_register_fixed_rate_with_accuracy(NULL,
iosc_name, iosc_name,
...@@ -315,13 +312,10 @@ static void __init sun6i_rtc_clk_init(struct device_node *node, ...@@ -315,13 +312,10 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
goto err_register; goto err_register;
} }
clk_data->num = 2; clk_data->num = 3;
clk_data->hws[0] = &rtc->hw; clk_data->hws[0] = &rtc->hw;
clk_data->hws[1] = __clk_get_hw(rtc->ext_losc); clk_data->hws[1] = __clk_get_hw(rtc->ext_losc);
if (rtc->data->export_iosc) { clk_data->hws[2] = rtc->int_osc;
clk_data->hws[2] = rtc->int_osc;
clk_data->num = 3;
}
of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data); of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
return; return;
...@@ -361,7 +355,6 @@ static const struct sun6i_rtc_clk_data sun8i_h3_rtc_data = { ...@@ -361,7 +355,6 @@ static const struct sun6i_rtc_clk_data sun8i_h3_rtc_data = {
.fixed_prescaler = 32, .fixed_prescaler = 32,
.has_prescaler = 1, .has_prescaler = 1,
.has_out_clk = 1, .has_out_clk = 1,
.export_iosc = 1,
}; };
static void __init sun8i_h3_rtc_clk_init(struct device_node *node) static void __init sun8i_h3_rtc_clk_init(struct device_node *node)
...@@ -379,7 +372,6 @@ static const struct sun6i_rtc_clk_data sun50i_h6_rtc_data = { ...@@ -379,7 +372,6 @@ static const struct sun6i_rtc_clk_data sun50i_h6_rtc_data = {
.fixed_prescaler = 32, .fixed_prescaler = 32,
.has_prescaler = 1, .has_prescaler = 1,
.has_out_clk = 1, .has_out_clk = 1,
.export_iosc = 1,
.has_losc_en = 1, .has_losc_en = 1,
.has_auto_swt = 1, .has_auto_swt = 1,
}; };
......
...@@ -14,8 +14,12 @@ ...@@ -14,8 +14,12 @@
const_bin2bcd(x) : \ const_bin2bcd(x) : \
_bin2bcd(x)) _bin2bcd(x))
#define bcd_is_valid(x) \
const_bcd_is_valid(x)
#define const_bcd2bin(x) (((x) & 0x0f) + ((x) >> 4) * 10) #define const_bcd2bin(x) (((x) & 0x0f) + ((x) >> 4) * 10)
#define const_bin2bcd(x) ((((x) / 10) << 4) + (x) % 10) #define const_bin2bcd(x) ((((x) / 10) << 4) + (x) % 10)
#define const_bcd_is_valid(x) (((x) & 0x0f) < 10 && ((x) >> 4) < 10)
unsigned _bcd2bin(unsigned char val) __attribute_const__; unsigned _bcd2bin(unsigned char val) __attribute_const__;
unsigned char _bin2bcd(unsigned val) __attribute_const__; unsigned char _bin2bcd(unsigned val) __attribute_const__;
......
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