RTC for 6.3

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
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEBqsFVZXh8s/0O5JiY6TcMGxwOjIFAmQBNu0ACgkQY6TcMGxw
 OjLXoA//S8YQQLqAOHPdmEmiVHEoYQv+VYwYrnK8of3QTDOJizboDRgRSSMgNNBj
 ViqDCLUUDnmPd/91BiTVgKdfmjY2gqR3coyu5XcEKDNRoLCeLjrKENtrmrjwOvKW
 gdbvs3oXsUtWC6JY0vuEABCn0DNxg7I7pvT57Ykaun2mhASo6LeTwGU5Jwo27GtY
 /MEY7Av+VMOvNWXsjRi9qaIms9DtX8LbXSDgkYoVy8QH97iW9iTVZu2tCgFAR9Fl
 HrLzVslnOg+ae8sBJ7rAY57xD+ZRT/P8ZnVlgUs/oQ9DxJ15rmjifzJA6SurcVea
 HmNrVzdyiNmTY4Vk9/M/pAADwwz0L5sxXMnbemLcl97MHIZulhAz/4zWMEwZixCi
 Of+ROqt1tahk69d3QRry4zlWp5dGfn07+DDD9aVFV2YqmAmBSlUkru65tse10gem
 QWVcrmURMQoBjrgXkWki3+6NjvqlBTrJa7qY8KAB3iGpDF/yAUwYm8rBVYxGAiUz
 NaoiFKgwbVxE67SSP6OFURTWi+lGyS+kmaTVbzfTfWDI8Tf++U4xbMkDzhyvL4A2
 HZD3HbTghdnbVfysTI9Fxtk1mFbO3EDuMRK5YpLcx7gZAn+S7vUNRU0oFPxAR/aX
 BhZAWSQvZJWewPuTBSfoSSPFCEEiCSqOVupHmMr5J4H1lgtZAXo=
 =aZkd
 -----END PGP SIGNATURE-----

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
  ...
This commit is contained in:
Linus Torvalds 2023-03-03 09:15:50 -08:00
commit 271d89394e
40 changed files with 1234 additions and 537 deletions

View File

@ -0,0 +1,44 @@
# 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>;
};

View File

@ -11,7 +11,8 @@ maintainers:
description:
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:
- $ref: "rtc.yaml#"
@ -24,8 +25,14 @@ properties:
maxItems: 1
interrupts:
description: the TIMER interrupt
maxItems: 1
minItems: 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:
description: clock reference in the 27MHz domain
@ -35,10 +42,10 @@ additionalProperties: false
examples:
- |
rtc@f0411580 {
rtc@f041a080 {
compatible = "brcm,brcmstb-waketimer";
reg = <0xf0411580 0x14>;
interrupts = <0x3>;
interrupt-parent = <&aon_pm_l2_intc>;
reg = <0xf041a080 0x14>;
interrupts-extended = <&aon_pm_l2_intc 0x04>,
<&upg_aux_aon_intr2_intc 0x08>;
clocks = <&upg_fixed>;
};

View File

@ -11,6 +11,17 @@ maintainers:
allOf:
- $ref: rtc.yaml#
- if:
not:
properties:
compatible:
contains:
enum:
- ingenic,jz4770-rtc
- ingenic,jz4780-rtc
then:
properties:
"#clock-cells": false
properties:
compatible:
@ -39,6 +50,9 @@ properties:
clock-names:
const: rtc
"#clock-cells":
const: 0
system-power-controller:
description: |
Indicates that the RTC is responsible for powering OFF
@ -83,3 +97,18 @@ examples:
clocks = <&cgu JZ4740_CLK_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>;
};

View File

@ -0,0 +1,54 @@
# 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>;
};
};
...

View File

@ -3,15 +3,15 @@ MOXA ART real-time clock
Required properties:
- compatible : Should be "moxa,moxart-rtc"
- gpio-rtc-sclk : RTC sclk gpio, with zero flags
- gpio-rtc-data : RTC data gpio, with zero flags
- gpio-rtc-reset : RTC reset gpio, with zero flags
- rtc-sclk-gpios : RTC sclk gpio, with zero flags
- rtc-data-gpios : RTC data gpio, with zero flags
- rtc-reset-gpios : RTC reset gpio, with zero flags
Example:
rtc: rtc {
compatible = "moxa,moxart-rtc";
gpio-rtc-sclk = <&gpio 5 0>;
gpio-rtc-data = <&gpio 6 0>;
gpio-rtc-reset = <&gpio 7 0>;
rtc-sclk-gpios = <&gpio 5 0>;
rtc-data-gpios = <&gpio 6 0>;
rtc-reset-gpios = <&gpio 7 0>;
};

View File

@ -14,7 +14,10 @@ maintainers:
properties:
compatible:
const: nxp,pcf2127
enum:
- nxp,pca2129
- nxp,pcf2127
- nxp,pcf2129
reg:
maxItems: 1

View File

@ -0,0 +1,60 @@
# 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>;
};
};

View File

@ -19,8 +19,6 @@ properties:
- microcrystal,rv8564
- nxp,pca8565
- nxp,pcf8563
- nxp,pcf85263
- nxp,pcf85363
reg:
maxItems: 1

View File

@ -40,6 +40,16 @@ properties:
description:
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
required:
@ -69,6 +79,8 @@ examples:
compatible = "qcom,pm8921-rtc";
reg = <0x11d>;
interrupts = <0x27 0>;
nvmem-cells = <&rtc_offset>;
nvmem-cell-names = "offset";
};
};
};

View File

@ -1,22 +0,0 @@
* 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>;
};

View File

@ -47,14 +47,12 @@ properties:
- isil,isl1218
# Intersil ISL12022 Real-time Clock
- isil,isl12022
# Real Time Clock Module with I2C-Bus
- microcrystal,rv3028
# Loongson-2K Socs/LS7A bridge Real-time Clock
- loongson,ls2x-rtc
# Real Time Clock Module with I2C-Bus
- microcrystal,rv3029
# Real Time Clock
- microcrystal,rv8523
- nxp,pca2129
- nxp,pcf2129
# Real-time Clock Module
- pericom,pt7c4338
# I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC

View File

@ -1677,7 +1677,7 @@ config RTC_DRV_MPC5121
config RTC_DRV_JZ4740
tristate "Ingenic JZ4740 SoC"
depends on MIPS || COMPILE_TEST
depends on OF
depends on OF && COMMON_CLK
help
If you say yes here you get support for the Ingenic JZ47xx SoCs RTC
controllers.
@ -1773,6 +1773,18 @@ config RTC_DRV_SNVS
This driver can also be built as a module, if so, the module
will be called "rtc-snvs".
config RTC_DRV_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
depends on IMX_SCU
depends on HAVE_ARM_SMCCC

View File

@ -33,6 +33,7 @@ obj-$(CONFIG_RTC_DRV_ASPEED) += rtc-aspeed.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
obj-$(CONFIG_RTC_DRV_AU1XXX) += rtc-au1xxx.o
obj-$(CONFIG_RTC_DRV_BBNSM) += rtc-nxp-bbnsm.o
obj-$(CONFIG_RTC_DRV_BD70528) += rtc-bd70528.o
obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o
obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o

View File

@ -392,7 +392,7 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
return err;
if (!rtc->ops) {
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;
} else {
memset(alarm, 0, sizeof(struct rtc_wkalrm));

View File

@ -536,9 +536,14 @@ static int abeoz9_probe(struct i2c_client *client)
clear_bit(RTC_FEATURE_ALARM, data->rtc->features);
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,
abeoz9_rtc_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
irqflags | IRQF_ONESHOT,
dev_name(dev), dev);
if (ret) {
dev_err(dev, "failed to request alarm irq\n");

View File

@ -11,6 +11,7 @@
*/
#include <linux/bcd.h>
#include <linux/bitfield.h>
#include <linux/i2c.h>
#include <linux/kstrtox.h>
#include <linux/module.h>
@ -88,6 +89,16 @@
#define ABX8XX_TRICKLE_STANDARD_DIODE 0x8
#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};
enum abx80x_chip {AB0801, AB0803, AB0804, AB0805,
@ -674,6 +685,68 @@ static int abx80x_setup_watchdog(struct abx80x_priv *priv)
}
#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[] = {
{ "abx80x", ABX80X },
{ "ab0801", AB0801 },
@ -840,6 +913,10 @@ static int abx80x_probe(struct i2c_client *client)
return err;
}
err = abx80x_setup_nvmem(priv);
if (err)
return err;
if (client->irq > 0) {
dev_info(&client->dev, "IRQ %d supplied\n", client->irq);
err = devm_request_threaded_irq(&client->dev, client->irq, NULL,

View File

@ -27,13 +27,17 @@ struct brcmstb_waketmr {
struct rtc_device *rtc;
struct device *dev;
void __iomem *base;
int irq;
unsigned int wake_irq;
unsigned int alarm_irq;
struct notifier_block reboot_notifier;
struct clk *clk;
u32 rate;
unsigned long rtc_alarm;
bool alarm_en;
};
#define BRCMSTB_WKTMR_EVENT 0x00
#define WKTMR_ALARM_EVENT BIT(0)
#define BRCMSTB_WKTMR_COUNTER 0x04
#define BRCMSTB_WKTMR_ALARM 0x08
#define BRCMSTB_WKTMR_PRESCALER 0x0C
@ -41,28 +45,71 @@ struct brcmstb_waketmr {
#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)
{
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);
}
static void brcmstb_waketmr_set_alarm(struct brcmstb_waketmr *timer,
unsigned int secs)
{
unsigned int now;
brcmstb_waketmr_clear_alarm(timer);
/* Make sure we are actually counting in seconds */
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)
{
struct brcmstb_waketmr *timer = data;
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;
}
@ -88,17 +135,25 @@ static void wktmr_read(struct brcmstb_waketmr *timer,
static int brcmstb_waketmr_prepare_suspend(struct brcmstb_waketmr *timer)
{
struct device *dev = timer->dev;
int ret = 0;
int ret;
if (device_may_wakeup(dev)) {
ret = enable_irq_wake(timer->irq);
ret = enable_irq_wake(timer->wake_irq);
if (ret) {
dev_err(dev, "failed to enable wake-up interrupt\n");
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 */
@ -146,18 +201,33 @@ static int brcmstb_waketmr_getalarm(struct device *dev,
struct rtc_wkalrm *alarm)
{
struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
time64_t sec;
u32 reg;
sec = readl_relaxed(timer->base + BRCMSTB_WKTMR_ALARM);
if (sec != 0) {
/* Alarm is enabled */
alarm->enabled = 1;
rtc_time64_to_tm(sec, &alarm->time);
alarm->enabled = timer->alarm_en;
rtc_time64_to_tm(timer->rtc_alarm, &alarm->time);
alarm->pending = brcmstb_waketmr_is_pending(timer);
return 0;
}
reg = readl_relaxed(timer->base + BRCMSTB_WKTMR_EVENT);
alarm->pending = !!(reg & 1);
static int brcmstb_waketmr_alarm_enable(struct device *dev,
unsigned int enabled)
{
struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
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;
}
@ -166,26 +236,12 @@ static int brcmstb_waketmr_setalarm(struct device *dev,
struct rtc_wkalrm *alarm)
{
struct brcmstb_waketmr *timer = dev_get_drvdata(dev);
time64_t sec;
if (alarm->enabled)
sec = rtc_tm_to_time64(&alarm->time);
else
sec = 0;
timer->rtc_alarm = rtc_tm_to_time64(&alarm->time);
brcmstb_waketmr_set_alarm(timer, sec);
brcmstb_waketmr_set_alarm(timer, timer->rtc_alarm);
return 0;
}
/*
* Does not do much but keep the RTC class happy. We always support
* alarms.
*/
static int brcmstb_waketmr_alarm_enable(struct device *dev,
unsigned int enabled)
{
return 0;
return brcmstb_waketmr_alarm_enable(dev, alarm->enabled);
}
static const struct rtc_class_ops brcmstb_waketmr_ops = {
@ -221,12 +277,12 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
* Set wakeup capability before requesting wakeup interrupt, so we can
* process boot-time "wakeups" (e.g., from S5 soft-off)
*/
device_set_wakeup_capable(dev, true);
device_wakeup_enable(dev);
device_init_wakeup(dev, true);
timer->irq = platform_get_irq(pdev, 0);
if (timer->irq < 0)
ret = platform_get_irq(pdev, 0);
if (ret < 0)
return -ENODEV;
timer->wake_irq = (unsigned int)ret;
timer->clk = devm_clk_get(dev, NULL);
if (!IS_ERR(timer->clk)) {
@ -241,11 +297,24 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
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);
if (ret < 0)
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;
register_reboot_notifier(&timer->reboot_notifier);
@ -256,8 +325,6 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
if (ret)
goto err_notifier;
dev_info(dev, "registered, with irq %d\n", timer->irq);
return 0;
err_notifier:
@ -295,7 +362,9 @@ static int brcmstb_waketmr_resume(struct device *dev)
if (!device_may_wakeup(dev))
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);
@ -325,4 +394,5 @@ module_platform_driver(brcmstb_waketmr_driver);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Brian Norris");
MODULE_AUTHOR("Markus Mayer");
MODULE_AUTHOR("Doug Berger");
MODULE_DESCRIPTION("Wake-up timer driver for STB chips");

View File

@ -1712,9 +1712,9 @@ static const struct regmap_config regmap_config = {
.val_bits = 8,
};
static int ds1307_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int ds1307_probe(struct i2c_client *client)
{
const struct i2c_device_id *id = i2c_client_get_device_id(client);
struct ds1307 *ds1307;
const void *match;
int err = -ENODEV;
@ -2011,7 +2011,7 @@ static struct i2c_driver ds1307_driver = {
.name = "rtc-ds1307",
.of_match_table = ds1307_of_match,
},
.probe = ds1307_probe,
.probe_new = ds1307_probe,
.id_table = ds1307_id,
};

View File

@ -164,7 +164,7 @@ static int efi_read_time(struct device *dev, struct rtc_time *tm)
if (status != EFI_SUCCESS) {
/* should never happen */
dev_err(dev, "can't read time\n");
dev_err_once(dev, "can't read time\n");
return -EINVAL;
}

View File

@ -518,9 +518,14 @@ static int hym8563_probe(struct i2c_client *client)
}
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,
NULL, hym8563_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
irqflags | IRQF_ONESHOT,
client->name, hym8563);
if (ret < 0) {
dev_err(&client->dev, "irq %d request failed, %d\n",

View File

@ -8,16 +8,16 @@
* by Alessandro Zummo <a.zummo@towertech.it>.
*/
#include <linux/i2c.h>
#include <linux/bcd.h>
#include <linux/err.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 <linux/module.h>
#include <linux/err.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/regmap.h>
#include <linux/hwmon.h>
#include <asm/byteorder.h>
/* ISL register offsets */
#define ISL12022_REG_SC 0x00
@ -44,13 +44,6 @@
#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,
enum hwmon_sensor_types type,
u32 attr, int channel)
@ -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)
{
struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
u8 temp_buf[2];
struct regmap *regmap = dev_get_drvdata(dev);
int temp, ret;
__le16 buf;
ret = regmap_bulk_read(regmap, ISL12022_REG_TEMP_L,
temp_buf, sizeof(temp_buf));
ret = regmap_bulk_read(regmap, ISL12022_REG_TEMP_L, &buf, sizeof(buf));
if (ret)
return ret;
/*
* 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 -= 273000;
@ -115,23 +106,21 @@ static const struct hwmon_chip_info isl12022_hwmon_chip_info = {
static void isl12022_hwmon_register(struct device *dev)
{
struct isl12022 *isl12022;
struct regmap *regmap = dev_get_drvdata(dev);
struct device *hwmon;
int ret;
if (!IS_REACHABLE(CONFIG_HWMON))
return;
isl12022 = dev_get_drvdata(dev);
ret = regmap_update_bits(isl12022->regmap, ISL12022_REG_BETA,
ret = regmap_update_bits(regmap, ISL12022_REG_BETA,
ISL12022_BETA_TSE, ISL12022_BETA_TSE);
if (ret) {
dev_warn(dev, "unable to enable temperature sensor\n");
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,
NULL);
if (IS_ERR(hwmon))
@ -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)
{
struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
struct regmap *regmap = dev_get_drvdata(dev);
uint8_t buf[ISL12022_REG_INT + 1];
int ret;
@ -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)) {
dev_warn(dev,
"voltage dropped below %u%%, "
"date and time is not reliable.\n",
"voltage dropped below %u%%, date and time is not reliable.\n",
buf[ISL12022_REG_SR] & ISL12022_SR_LBAT85 ? 85 : 75);
}
dev_dbg(dev,
"%s: raw data is sec=%02x, min=%02x, hr=%02x, "
"mday=%02x, mon=%02x, year=%02x, wday=%02x, "
"sr=%02x, int=%02x",
__func__,
"raw data is sec=%02x, min=%02x, hr=%02x, mday=%02x, mon=%02x, year=%02x, wday=%02x, sr=%02x, int=%02x",
buf[ISL12022_REG_SC],
buf[ISL12022_REG_MN],
buf[ISL12022_REG_HR],
@ -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)
{
struct isl12022 *isl12022 = dev_get_drvdata(dev);
struct regmap *regmap = isl12022->regmap;
struct regmap *regmap = dev_get_drvdata(dev);
int ret;
uint8_t buf[ISL12022_REG_DW + 1];
@ -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;
return regmap_bulk_write(isl12022->regmap, ISL12022_REG_SC,
buf, sizeof(buf));
return regmap_bulk_write(regmap, ISL12022_REG_SC, buf, sizeof(buf));
}
static const struct rtc_class_ops isl12022_rtc_ops = {
@ -235,44 +217,39 @@ static const struct regmap_config regmap_config = {
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))
return -ENODEV;
isl12022 = devm_kzalloc(&client->dev, sizeof(struct isl12022),
GFP_KERNEL);
if (!isl12022)
return -ENOMEM;
dev_set_drvdata(&client->dev, isl12022);
isl12022->regmap = devm_regmap_init_i2c(client, &regmap_config);
if (IS_ERR(isl12022->regmap)) {
regmap = devm_regmap_init_i2c(client, &regmap_config);
if (IS_ERR(regmap)) {
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->rtc = devm_rtc_allocate_device(&client->dev);
if (IS_ERR(isl12022->rtc))
return PTR_ERR(isl12022->rtc);
rtc = devm_rtc_allocate_device(&client->dev);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
isl12022->rtc->ops = &isl12022_rtc_ops;
isl12022->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
isl12022->rtc->range_max = RTC_TIMESTAMP_END_2099;
rtc->ops = &isl12022_rtc_ops;
rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
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[] = {
{ .compatible = "isl,isl12022" }, /* for backward compat., don't use */
{ .compatible = "isil,isl12022" },
{ },
};
MODULE_DEVICE_TABLE(of, isl12022_dt_match);
#endif
static const struct i2c_device_id isl12022_id[] = {
{ "isl12022", 0 },
@ -283,9 +260,7 @@ MODULE_DEVICE_TABLE(i2c, isl12022_id);
static struct i2c_driver isl12022_driver = {
.driver = {
.name = "rtc-isl12022",
#ifdef CONFIG_OF
.of_match_table = of_match_ptr(isl12022_dt_match),
#endif
.of_match_table = isl12022_dt_match,
},
.probe_new = isl12022_probe,
.id_table = isl12022_id,

View File

@ -6,12 +6,15 @@
*/
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/io.h>
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_wakeirq.h>
#include <linux/property.h>
#include <linux/reboot.h>
#include <linux/rtc.h>
#include <linux/slab.h>
@ -25,6 +28,7 @@
#define JZ_REG_RTC_WAKEUP_FILTER 0x24
#define JZ_REG_RTC_RESET_COUNTER 0x28
#define JZ_REG_RTC_SCRATCHPAD 0x34
#define JZ_REG_RTC_CKPCR 0x40
/* The following are present on the jz4780 */
#define JZ_REG_RTC_WENR 0x3C
@ -44,6 +48,9 @@
#define JZ_RTC_WAKEUP_FILTER_MASK 0x0000FFE0
#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 {
ID_JZ4740,
ID_JZ4760,
@ -56,6 +63,8 @@ struct jz4740_rtc {
struct rtc_device *rtc;
struct clk_hw clk32k;
spinlock_t lock;
};
@ -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)
{
uint32_t ctrl;
int timeout = 10000;
do {
ctrl = jz4740_rtc_reg_read(rtc, JZ_REG_RTC_CTRL);
} while (!(ctrl & JZ_RTC_CTRL_WRDY) && --timeout);
return timeout ? 0 : -EIO;
return readl_poll_timeout(rtc->base + JZ_REG_RTC_CTRL, ctrl,
ctrl & JZ_RTC_CTRL_WRDY, 0, 1000);
}
static inline int jz4780_rtc_enable_write(struct jz4740_rtc *rtc)
{
uint32_t ctrl;
int ret, timeout = 10000;
int ret;
ret = jz4740_rtc_wait_write_ready(rtc);
if (ret != 0)
@ -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);
do {
ctrl = readl(rtc->base + JZ_REG_RTC_WENR);
} while (!(ctrl & JZ_RTC_WENR_WEN) && --timeout);
return timeout ? 0 : -EIO;
return readl_poll_timeout(rtc->base + JZ_REG_RTC_WENR, ctrl,
ctrl & JZ_RTC_WENR_WEN, 0, 1000);
}
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)
static const struct of_device_id jz4740_rtc_of_match[] = {
{ .compatible = "ingenic,jz4740-rtc", .data = (void *)ID_JZ4740 },
{ .compatible = "ingenic,jz4760-rtc", .data = (void *)ID_JZ4760 },
{ .compatible = "ingenic,jz4770-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,
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)
{
struct device *dev = &pdev->dev;
@ -335,17 +370,13 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
device_init_wakeup(dev, 1);
ret = dev_pm_set_wake_irq(dev, irq);
if (ret) {
dev_err(dev, "Failed to set wake irq: %d\n", ret);
return ret;
}
if (ret)
return dev_err_probe(dev, ret, "Failed to set wake irq\n");
rtc->rtc = devm_rtc_allocate_device(dev);
if (IS_ERR(rtc->rtc)) {
ret = PTR_ERR(rtc->rtc);
dev_err(dev, "Failed to allocate rtc device: %d\n", ret);
return ret;
}
if (IS_ERR(rtc->rtc))
return dev_err_probe(dev, PTR_ERR(rtc->rtc),
"Failed to allocate rtc device\n");
rtc->rtc->ops = &jz4740_rtc_ops;
rtc->rtc->range_max = U32_MAX;
@ -362,10 +393,8 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
ret = devm_request_irq(dev, irq, jz4740_rtc_irq, 0,
pdev->name, rtc);
if (ret) {
dev_err(dev, "Failed to request rtc irq: %d\n", ret);
return ret;
}
if (ret)
return dev_err_probe(dev, ret, "Failed to request rtc irq\n");
if (of_device_is_system_power_controller(np)) {
dev_for_power_off = dev;
@ -376,6 +405,21 @@ static int jz4740_rtc_probe(struct platform_device *pdev)
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;
}

View File

@ -914,9 +914,14 @@ static int m41t80_probe(struct i2c_client *client)
"wakeup-source");
#endif
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,
NULL, m41t80_handle_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
irqflags | IRQF_ONESHOT,
"m41t80", client);
if (rc) {
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");

View File

@ -9,7 +9,6 @@
*/
#include <linux/bcd.h>
#include <linux/i2c.h>
#include <linux/mfd/max8907.h>
#include <linux/module.h>
#include <linux/platform_device.h>

View File

@ -10,14 +10,15 @@
* Moxa Technology Co., Ltd. <www.moxa.com>
*/
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/mod_devicetable.h>
#include <linux/gpio/consumer.h>
#define GPIO_RTC_RESERVED 0x0C
#define GPIO_RTC_DATA_SET 0x10
@ -55,7 +56,9 @@
struct moxart_rtc {
struct rtc_device *rtc;
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,
@ -67,10 +70,10 @@ static void moxart_rtc_write_byte(struct device *dev, u8 data)
int i;
for (i = 0; i < 8; i++, data >>= 1) {
gpio_set_value(moxart_rtc->gpio_sclk, 0);
gpio_set_value(moxart_rtc->gpio_data, ((data & 1) == 1));
gpiod_set_value(moxart_rtc->gpio_sclk, 0);
gpiod_set_value(moxart_rtc->gpio_data, ((data & 1) == 1));
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);
}
}
@ -82,11 +85,11 @@ static u8 moxart_rtc_read_byte(struct device *dev)
u8 data = 0;
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);
gpio_set_value(moxart_rtc->gpio_sclk, 1);
gpiod_set_value(moxart_rtc->gpio_sclk, 1);
udelay(GPIO_RTC_DELAY_TIME);
if (gpio_get_value(moxart_rtc->gpio_data))
if (gpiod_get_value(moxart_rtc->gpio_data))
data |= (1 << i);
udelay(GPIO_RTC_DELAY_TIME);
}
@ -101,15 +104,15 @@ static u8 moxart_rtc_read_register(struct device *dev, u8 cmd)
local_irq_save(flags);
gpio_direction_output(moxart_rtc->gpio_data, 0);
gpio_set_value(moxart_rtc->gpio_reset, 1);
gpiod_direction_output(moxart_rtc->gpio_data, 0);
gpiod_set_value(moxart_rtc->gpio_reset, 1);
udelay(GPIO_RTC_DELAY_TIME);
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);
data = moxart_rtc_read_byte(dev);
gpio_set_value(moxart_rtc->gpio_sclk, 0);
gpio_set_value(moxart_rtc->gpio_reset, 0);
gpiod_set_value(moxart_rtc->gpio_sclk, 0);
gpiod_set_value(moxart_rtc->gpio_reset, 0);
udelay(GPIO_RTC_DELAY_TIME);
local_irq_restore(flags);
@ -124,13 +127,13 @@ static void moxart_rtc_write_register(struct device *dev, u8 cmd, u8 data)
local_irq_save(flags);
gpio_direction_output(moxart_rtc->gpio_data, 0);
gpio_set_value(moxart_rtc->gpio_reset, 1);
gpiod_direction_output(moxart_rtc->gpio_data, 0);
gpiod_set_value(moxart_rtc->gpio_reset, 1);
udelay(GPIO_RTC_DELAY_TIME);
moxart_rtc_write_byte(dev, cmd);
moxart_rtc_write_byte(dev, data);
gpio_set_value(moxart_rtc->gpio_sclk, 0);
gpio_set_value(moxart_rtc->gpio_reset, 0);
gpiod_set_value(moxart_rtc->gpio_sclk, 0);
gpiod_set_value(moxart_rtc->gpio_reset, 0);
udelay(GPIO_RTC_DELAY_TIME);
local_irq_restore(flags);
@ -247,53 +250,33 @@ static int moxart_rtc_probe(struct platform_device *pdev)
if (!moxart_rtc)
return -ENOMEM;
moxart_rtc->gpio_data = of_get_named_gpio(pdev->dev.of_node,
"gpio-rtc-data", 0);
if (!gpio_is_valid(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_data = devm_gpiod_get(&pdev->dev, "rtc-data",
GPIOD_IN);
ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_data);
if (ret) {
dev_err(&pdev->dev, "can't get rtc data gpio: %d\n", ret);
return ret;
}
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_sclk = devm_gpiod_get(&pdev->dev, "rtc-sclk",
GPIOD_ASIS);
ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_sclk);
if (ret) {
dev_err(&pdev->dev, "can't get rtc sclk gpio: %d\n", ret);
return ret;
}
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;
moxart_rtc->gpio_reset = devm_gpiod_get(&pdev->dev, "rtc-reset",
GPIOD_ASIS);
ret = PTR_ERR_OR_ZERO(moxart_rtc->gpio_reset);
if (ret) {
dev_err(&pdev->dev, "can't get rtc reset gpio: %d\n", ret);
return ret;
}
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) {
dev_err(&pdev->dev, "can't get rtc_data gpio\n");
return ret;
}
ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_sclk,
GPIOF_DIR_OUT, "rtc_sclk");
if (ret) {
dev_err(&pdev->dev, "can't get rtc_sclk gpio\n");
return ret;
}
ret = devm_gpio_request_one(&pdev->dev, moxart_rtc->gpio_reset,
GPIOF_DIR_OUT, "rtc_reset");
if (ret) {
dev_err(&pdev->dev, "can't get rtc_reset gpio\n");
return ret;
}
moxart_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&moxart_rtc_ops,
THIS_MODULE);

226
drivers/rtc/rtc-nxp-bbnsm.c Normal file
View File

@ -0,0 +1,226 @@
// 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");

View File

@ -413,9 +413,14 @@ static int pcf2123_probe(struct spi_device *spi)
/* Register alarm irq */
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,
pcf2123_rtc_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
irqflags | IRQF_ONESHOT,
pcf2123_driver.driver.name, &spi->dev);
if (!ret)
device_init_wakeup(&spi->dev, true);

View File

@ -621,9 +621,14 @@ static int pcf85063_probe(struct i2c_client *client)
clear_bit(RTC_FEATURE_ALARM, pcf85063->rtc->features);
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,
NULL, pcf85063_rtc_handle_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
irqflags | IRQF_ONESHOT,
"pcf85063", pcf85063);
if (err) {
dev_warn(&pcf85063->rtc->dev,

View File

@ -445,13 +445,18 @@ static int pcf8523_probe(struct i2c_client *client)
clear_bit(RTC_FEATURE_UPDATE_INTERRUPT, rtc->features);
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);
if (err < 0)
return err;
err = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf8523_irq,
IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW,
IRQF_SHARED | IRQF_ONESHOT | irqflags,
dev_name(&rtc->dev), pcf8523);
if (err)
return err;

View File

@ -101,6 +101,10 @@
#define PIN_IO_INTA_OUT 2
#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 RESET_CPR 0xa4
@ -117,6 +121,32 @@ struct pcf85x63_config {
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)
{
struct pcf85363 *pcf85363 = dev_get_drvdata(dev);
@ -372,7 +402,7 @@ static int pcf85363_probe(struct i2c_client *client)
.reg_write = pcf85363_nvram_write,
},
};
int ret, i;
int ret, i, err;
if (data)
config = data;
@ -394,18 +424,28 @@ static int pcf85363_probe(struct i2c_client *client)
if (IS_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->range_min = RTC_TIMESTAMP_BEGIN_2000;
pcf85363->rtc->range_max = RTC_TIMESTAMP_END_2099;
clear_bit(RTC_FEATURE_ALARM, pcf85363->rtc->features);
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_update_bits(pcf85363->regmap, CTRL_PIN_IO,
PIN_IO_INTA_OUT, PIN_IO_INTAPM);
ret = devm_request_threaded_irq(&client->dev, client->irq,
NULL, pcf85363_rtc_handle_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
irqflags | IRQF_ONESHOT,
"pcf85363", client);
if (ret)
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");

View File

@ -558,9 +558,14 @@ static int pcf8563_probe(struct i2c_client *client)
pcf8563->rtc->set_start_time = true;
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,
NULL, pcf8563_irq,
IRQF_SHARED | IRQF_ONESHOT | IRQF_TRIGGER_LOW,
IRQF_SHARED | IRQF_ONESHOT | irqflags,
pcf8563_driver.driver.name, client);
if (err) {
dev_err(&client->dev, "unable to request IRQ %d\n",

View File

@ -1,8 +1,13 @@
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
/*
* pm8xxx RTC driver
*
* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
* Copyright (c) 2023, Linaro Limited
*/
#include <linux/of.h>
#include <linux/module.h>
#include <linux/nvmem-consumer.h>
#include <linux/init.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
@ -12,11 +17,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
/* RTC Register offsets from RTC CTRL REG */
#define PM8XXX_ALARM_CTRL_OFFSET 0x01
#define PM8XXX_RTC_WRITE_OFFSET 0x02
#define PM8XXX_RTC_READ_OFFSET 0x06
#define PM8XXX_ALARM_RW_OFFSET 0x0A
#include <asm/unaligned.h>
/* RTC_CTRL register bit fields */
#define PM8xxx_RTC_ENABLE BIT(7)
@ -27,12 +28,12 @@
/**
* struct pm8xxx_rtc_regs - describe RTC registers per PMIC versions
* @ctrl: base address of control register
* @write: base address of write register
* @read: base address of read register
* @alarm_ctrl: base address of alarm control register
* @alarm_ctrl2: base address of alarm control2 register
* @alarm_rw: base address of alarm read-write register
* @ctrl: address of control register
* @write: base address of write registers
* @read: base address of read registers
* @alarm_ctrl: address of alarm control register
* @alarm_ctrl2: address of alarm control2 register
* @alarm_rw: base address of alarm read-write registers
* @alarm_en: alarm enable mask
*/
struct pm8xxx_rtc_regs {
@ -46,25 +47,135 @@ struct pm8xxx_rtc_regs {
};
/**
* struct pm8xxx_rtc - rtc driver internal structure
* @rtc: rtc device for this driver.
* @regmap: regmap used to access RTC registers
* @allow_set_time: indicates whether writing to the RTC is allowed
* @rtc_alarm_irq: rtc alarm irq number.
* @regs: rtc registers description.
* @rtc_dev: device structure.
* @ctrl_reg_lock: spinlock protecting access to ctrl_reg.
* struct pm8xxx_rtc - RTC driver internal structure
* @rtc: RTC device
* @regmap: regmap used to access registers
* @allow_set_time: whether the time can be set
* @alarm_irq: alarm irq number
* @regs: register description
* @dev: device structure
* @nvmem_cell: nvmem cell for offset
* @offset: offset from epoch in seconds
*/
struct pm8xxx_rtc {
struct rtc_device *rtc;
struct regmap *regmap;
bool allow_set_time;
int rtc_alarm_irq;
int alarm_irq;
const struct pm8xxx_rtc_regs *regs;
struct device *rtc_dev;
spinlock_t ctrl_reg_lock;
struct device *dev;
struct nvmem_cell *nvmem_cell;
u32 offset;
};
static int pm8xxx_rtc_read_nvmem_offset(struct pm8xxx_rtc *rtc_dd)
{
size_t len;
void *buf;
int rc;
buf = nvmem_cell_read(rtc_dd->nvmem_cell, &len);
if (IS_ERR(buf)) {
rc = PTR_ERR(buf);
dev_dbg(rtc_dd->dev, "failed to read nvmem offset: %d\n", rc);
return rc;
}
if (len != sizeof(u32)) {
dev_dbg(rtc_dd->dev, "unexpected nvmem cell size %zu\n", len);
kfree(buf);
return -EINVAL;
}
rtc_dd->offset = get_unaligned_le32(buf);
kfree(buf);
return 0;
}
static int pm8xxx_rtc_write_nvmem_offset(struct pm8xxx_rtc *rtc_dd, u32 offset)
{
u8 buf[sizeof(u32)];
int rc;
put_unaligned_le32(offset, buf);
rc = nvmem_cell_write(rtc_dd->nvmem_cell, buf, sizeof(buf));
if (rc < 0) {
dev_dbg(rtc_dd->dev, "failed to write nvmem offset: %d\n", rc);
return rc;
}
return 0;
}
static int pm8xxx_rtc_read_offset(struct pm8xxx_rtc *rtc_dd)
{
if (!rtc_dd->nvmem_cell)
return 0;
return pm8xxx_rtc_read_nvmem_offset(rtc_dd);
}
static int pm8xxx_rtc_read_raw(struct pm8xxx_rtc *rtc_dd, u32 *secs)
{
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
u8 value[NUM_8_BIT_RTC_REGS];
unsigned int reg;
int rc;
rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value, sizeof(value));
if (rc)
return rc;
/*
* Read the LSB again and check if there has been a carry over.
* If there has, redo the read operation.
*/
rc = regmap_read(rtc_dd->regmap, regs->read, &reg);
if (rc < 0)
return rc;
if (reg < value[0]) {
rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value,
sizeof(value));
if (rc)
return rc;
}
*secs = get_unaligned_le32(value);
return 0;
}
static int pm8xxx_rtc_update_offset(struct pm8xxx_rtc *rtc_dd, u32 secs)
{
u32 raw_secs;
u32 offset;
int rc;
if (!rtc_dd->nvmem_cell)
return -ENODEV;
rc = pm8xxx_rtc_read_raw(rtc_dd, &raw_secs);
if (rc)
return rc;
offset = secs - raw_secs;
if (offset == rtc_dd->offset)
return 0;
rc = pm8xxx_rtc_write_nvmem_offset(rtc_dd, offset);
if (rc)
return rc;
rtc_dd->offset = offset;
return 0;
}
/*
* Steps to write the RTC registers.
* 1. Disable alarm if enabled.
@ -74,269 +185,186 @@ struct pm8xxx_rtc {
* 5. Enable rtc if disabled in step 2.
* 6. Enable alarm if disabled in step 1.
*/
static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
static int __pm8xxx_rtc_set_time(struct pm8xxx_rtc *rtc_dd, u32 secs)
{
int rc, i;
unsigned long secs, irq_flags;
u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0, rtc_disabled = 0;
unsigned int ctrl_reg, rtc_ctrl_reg;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
u8 value[NUM_8_BIT_RTC_REGS];
bool alarm_enabled;
int rc;
if (!rtc_dd->allow_set_time)
return -ENODEV;
put_unaligned_le32(secs, value);
secs = rtc_tm_to_time64(tm);
dev_dbg(dev, "Seconds value to be written to RTC = %lu\n", secs);
for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
value[i] = secs & 0xFF;
secs >>= 8;
}
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
rc = regmap_update_bits_check(rtc_dd->regmap, regs->alarm_ctrl,
regs->alarm_en, 0, &alarm_enabled);
if (rc)
goto rtc_rw_fail;
return rc;
if (ctrl_reg & regs->alarm_en) {
alarm_enabled = 1;
ctrl_reg &= ~regs->alarm_en;
rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
if (rc) {
dev_err(dev, "Write to RTC Alarm control register failed\n");
goto rtc_rw_fail;
}
}
/* Disable RTC H/w before writing on RTC register */
rc = regmap_read(rtc_dd->regmap, regs->ctrl, &rtc_ctrl_reg);
/* Disable RTC */
rc = regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE, 0);
if (rc)
goto rtc_rw_fail;
if (rtc_ctrl_reg & PM8xxx_RTC_ENABLE) {
rtc_disabled = 1;
rtc_ctrl_reg &= ~PM8xxx_RTC_ENABLE;
rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg);
if (rc) {
dev_err(dev, "Write to RTC control register failed\n");
goto rtc_rw_fail;
}
}
return rc;
/* Write 0 to Byte[0] */
rc = regmap_write(rtc_dd->regmap, regs->write, 0);
if (rc) {
dev_err(dev, "Write to RTC write data register failed\n");
goto rtc_rw_fail;
}
if (rc)
return rc;
/* Write Byte[1], Byte[2], Byte[3] */
rc = regmap_bulk_write(rtc_dd->regmap, regs->write + 1,
&value[1], sizeof(value) - 1);
if (rc) {
dev_err(dev, "Write to RTC write data register failed\n");
goto rtc_rw_fail;
}
if (rc)
return rc;
/* Write Byte[0] */
rc = regmap_write(rtc_dd->regmap, regs->write, value[0]);
if (rc) {
dev_err(dev, "Write to RTC write data register failed\n");
goto rtc_rw_fail;
}
if (rc)
return rc;
/* Enable RTC H/w after writing on RTC register */
if (rtc_disabled) {
rtc_ctrl_reg |= PM8xxx_RTC_ENABLE;
rc = regmap_write(rtc_dd->regmap, regs->ctrl, rtc_ctrl_reg);
if (rc) {
dev_err(dev, "Write to RTC control register failed\n");
goto rtc_rw_fail;
}
}
/* Enable RTC */
rc = regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE,
PM8xxx_RTC_ENABLE);
if (rc)
return rc;
if (alarm_enabled) {
ctrl_reg |= regs->alarm_en;
rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
if (rc) {
dev_err(dev, "Write to RTC Alarm control register failed\n");
goto rtc_rw_fail;
}
}
rtc_rw_fail:
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl,
regs->alarm_en, regs->alarm_en);
if (rc)
return rc;
}
return 0;
}
static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
u32 secs;
int rc;
secs = rtc_tm_to_time64(tm);
if (rtc_dd->allow_set_time)
rc = __pm8xxx_rtc_set_time(rtc_dd, secs);
else
rc = pm8xxx_rtc_update_offset(rtc_dd, secs);
if (rc)
return rc;
dev_dbg(dev, "set time: %ptRd %ptRt (%u + %u)\n", tm, tm,
secs - rtc_dd->offset, rtc_dd->offset);
return 0;
}
static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
int rc;
u8 value[NUM_8_BIT_RTC_REGS];
unsigned long secs;
unsigned int reg;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
u32 secs;
int rc;
rc = regmap_bulk_read(rtc_dd->regmap, regs->read, value, sizeof(value));
if (rc) {
dev_err(dev, "RTC read data register failed\n");
rc = pm8xxx_rtc_read_raw(rtc_dd, &secs);
if (rc)
return rc;
}
/*
* Read the LSB again and check if there has been a carry over.
* If there is, redo the read operation.
*/
rc = regmap_read(rtc_dd->regmap, regs->read, &reg);
if (rc < 0) {
dev_err(dev, "RTC read data register failed\n");
return rc;
}
if (unlikely(reg < value[0])) {
rc = regmap_bulk_read(rtc_dd->regmap, regs->read,
value, sizeof(value));
if (rc) {
dev_err(dev, "RTC read data register failed\n");
return rc;
}
}
secs = value[0] | (value[1] << 8) | (value[2] << 16) |
((unsigned long)value[3] << 24);
secs += rtc_dd->offset;
rtc_time64_to_tm(secs, tm);
dev_dbg(dev, "secs = %lu, h:m:s == %ptRt, y-m-d = %ptRdr\n", secs, tm, tm);
dev_dbg(dev, "read time: %ptRd %ptRt (%u + %u)\n", tm, tm,
secs - rtc_dd->offset, rtc_dd->offset);
return 0;
}
static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
int rc, i;
u8 value[NUM_8_BIT_RTC_REGS];
unsigned int ctrl_reg;
unsigned long secs, irq_flags;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
u8 value[NUM_8_BIT_RTC_REGS];
u32 secs;
int rc;
secs = rtc_tm_to_time64(&alarm->time);
secs -= rtc_dd->offset;
put_unaligned_le32(secs, value);
for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) {
value[i] = secs & 0xFF;
secs >>= 8;
}
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl,
regs->alarm_en, 0);
if (rc)
return rc;
rc = regmap_bulk_write(rtc_dd->regmap, regs->alarm_rw, value,
sizeof(value));
if (rc) {
dev_err(dev, "Write to RTC ALARM register failed\n");
goto rtc_rw_fail;
}
rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
if (rc)
goto rtc_rw_fail;
return rc;
if (alarm->enabled)
ctrl_reg |= regs->alarm_en;
else
ctrl_reg &= ~regs->alarm_en;
rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
if (rc) {
dev_err(dev, "Write to RTC alarm control register failed\n");
goto rtc_rw_fail;
if (alarm->enabled) {
rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl,
regs->alarm_en, regs->alarm_en);
if (rc)
return rc;
}
dev_dbg(dev, "Alarm Set for h:m:s=%ptRt, y-m-d=%ptRdr\n",
&alarm->time, &alarm->time);
rtc_rw_fail:
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
return rc;
dev_dbg(dev, "set alarm: %ptRd %ptRt\n", &alarm->time, &alarm->time);
return 0;
}
static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
int rc;
unsigned int ctrl_reg;
u8 value[NUM_8_BIT_RTC_REGS];
unsigned long secs;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
u8 value[NUM_8_BIT_RTC_REGS];
unsigned int ctrl_reg;
u32 secs;
int rc;
rc = regmap_bulk_read(rtc_dd->regmap, regs->alarm_rw, value,
sizeof(value));
if (rc) {
dev_err(dev, "RTC alarm time read failed\n");
if (rc)
return rc;
}
secs = value[0] | (value[1] << 8) | (value[2] << 16) |
((unsigned long)value[3] << 24);
secs = get_unaligned_le32(value);
secs += rtc_dd->offset;
rtc_time64_to_tm(secs, &alarm->time);
rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
if (rc) {
dev_err(dev, "Read from RTC alarm control register failed\n");
if (rc)
return rc;
}
alarm->enabled = !!(ctrl_reg & PM8xxx_RTC_ALARM_ENABLE);
dev_dbg(dev, "Alarm set for - h:m:s=%ptRt, y-m-d=%ptRdr\n",
&alarm->time, &alarm->time);
dev_dbg(dev, "read alarm: %ptRd %ptRt\n", &alarm->time, &alarm->time);
return 0;
}
static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
{
int rc;
unsigned long irq_flags;
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
unsigned int ctrl_reg;
u8 value[NUM_8_BIT_RTC_REGS] = {0};
spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags);
rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
if (rc)
goto rtc_rw_fail;
unsigned int val;
int rc;
if (enable)
ctrl_reg |= regs->alarm_en;
val = regs->alarm_en;
else
ctrl_reg &= ~regs->alarm_en;
val = 0;
rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
if (rc) {
dev_err(dev, "Write to RTC control register failed\n");
goto rtc_rw_fail;
}
rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl,
regs->alarm_en, val);
if (rc)
return rc;
/* Clear Alarm register */
/* Clear alarm register */
if (!enable) {
rc = regmap_bulk_write(rtc_dd->regmap, regs->alarm_rw, value,
sizeof(value));
if (rc) {
dev_err(dev, "Clear RTC ALARM register failed\n");
goto rtc_rw_fail;
}
if (rc)
return rc;
}
rtc_rw_fail:
spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);
return rc;
return 0;
}
static const struct rtc_class_ops pm8xxx_rtc_ops = {
@ -351,69 +379,31 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id)
{
struct pm8xxx_rtc *rtc_dd = dev_id;
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
unsigned int ctrl_reg;
int rc;
rtc_update_irq(rtc_dd->rtc, 1, RTC_IRQF | RTC_AF);
spin_lock(&rtc_dd->ctrl_reg_lock);
/* Clear the alarm enable bit */
rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
if (rc) {
spin_unlock(&rtc_dd->ctrl_reg_lock);
goto rtc_alarm_handled;
}
ctrl_reg &= ~regs->alarm_en;
rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl, ctrl_reg);
if (rc) {
spin_unlock(&rtc_dd->ctrl_reg_lock);
dev_err(rtc_dd->rtc_dev,
"Write to alarm control register failed\n");
goto rtc_alarm_handled;
}
spin_unlock(&rtc_dd->ctrl_reg_lock);
/* Clear RTC alarm register */
rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl2, &ctrl_reg);
if (rc) {
dev_err(rtc_dd->rtc_dev,
"RTC Alarm control2 register read failed\n");
goto rtc_alarm_handled;
}
ctrl_reg |= PM8xxx_RTC_ALARM_CLEAR;
rc = regmap_write(rtc_dd->regmap, regs->alarm_ctrl2, ctrl_reg);
/* Disable alarm */
rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl,
regs->alarm_en, 0);
if (rc)
dev_err(rtc_dd->rtc_dev,
"Write to RTC Alarm control2 register failed\n");
return IRQ_NONE;
/* Clear alarm status */
rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl2,
PM8xxx_RTC_ALARM_CLEAR, 0);
if (rc)
return IRQ_NONE;
rtc_alarm_handled:
return IRQ_HANDLED;
}
static int pm8xxx_rtc_enable(struct pm8xxx_rtc *rtc_dd)
{
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
unsigned int ctrl_reg;
int rc;
/* Check if the RTC is on, else turn it on */
rc = regmap_read(rtc_dd->regmap, regs->ctrl, &ctrl_reg);
if (rc)
return rc;
if (!(ctrl_reg & PM8xxx_RTC_ENABLE)) {
ctrl_reg |= PM8xxx_RTC_ENABLE;
rc = regmap_write(rtc_dd->regmap, regs->ctrl, ctrl_reg);
if (rc)
return rc;
}
return 0;
return regmap_update_bits(rtc_dd->regmap, regs->ctrl, PM8xxx_RTC_ENABLE,
PM8xxx_RTC_ENABLE);
}
static const struct pm8xxx_rtc_regs pm8921_regs = {
@ -456,9 +446,6 @@ static const struct pm8xxx_rtc_regs pmk8350_regs = {
.alarm_en = BIT(7),
};
/*
* Hardcoded RTC bases until IORESOURCE_REG mapping is figured out
*/
static const struct of_device_id pm8xxx_id_table[] = {
{ .compatible = "qcom,pm8921-rtc", .data = &pm8921_regs },
{ .compatible = "qcom,pm8058-rtc", .data = &pm8058_regs },
@ -470,9 +457,9 @@ MODULE_DEVICE_TABLE(of, pm8xxx_id_table);
static int pm8xxx_rtc_probe(struct platform_device *pdev)
{
int rc;
struct pm8xxx_rtc *rtc_dd;
const struct of_device_id *match;
struct pm8xxx_rtc *rtc_dd;
int rc;
match = of_match_node(pm8xxx_id_table, pdev->dev.of_node);
if (!match)
@ -482,24 +469,33 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
if (rtc_dd == NULL)
return -ENOMEM;
/* Initialise spinlock to protect RTC control register */
spin_lock_init(&rtc_dd->ctrl_reg_lock);
rtc_dd->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!rtc_dd->regmap) {
dev_err(&pdev->dev, "Parent regmap unavailable.\n");
if (!rtc_dd->regmap)
return -ENXIO;
}
rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 0);
if (rtc_dd->rtc_alarm_irq < 0)
rtc_dd->alarm_irq = platform_get_irq(pdev, 0);
if (rtc_dd->alarm_irq < 0)
return -ENXIO;
rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node,
"allow-set-time");
rtc_dd->nvmem_cell = devm_nvmem_cell_get(&pdev->dev, "offset");
if (IS_ERR(rtc_dd->nvmem_cell)) {
rc = PTR_ERR(rtc_dd->nvmem_cell);
if (rc != -ENOENT)
return rc;
rtc_dd->nvmem_cell = NULL;
}
rtc_dd->regs = match->data;
rtc_dd->rtc_dev = &pdev->dev;
rtc_dd->dev = &pdev->dev;
if (!rtc_dd->allow_set_time) {
rc = pm8xxx_rtc_read_offset(rtc_dd);
if (rc)
return rc;
}
rc = pm8xxx_rtc_enable(rtc_dd);
if (rc)
@ -509,7 +505,6 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
/* Register the RTC device */
rtc_dd->rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(rtc_dd->rtc))
return PTR_ERR(rtc_dd->rtc);
@ -517,21 +512,18 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
rtc_dd->rtc->ops = &pm8xxx_rtc_ops;
rtc_dd->rtc->range_max = U32_MAX;
/* Request the alarm IRQ */
rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->rtc_alarm_irq,
rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->alarm_irq,
pm8xxx_alarm_trigger,
IRQF_TRIGGER_RISING,
"pm8xxx_rtc_alarm", rtc_dd);
if (rc < 0) {
dev_err(&pdev->dev, "Request IRQ failed (%d)\n", rc);
if (rc < 0)
return rc;
}
rc = devm_rtc_register_device(rtc_dd->rtc);
if (rc)
return rc;
rc = dev_pm_set_wake_irq(&pdev->dev, rtc_dd->rtc_alarm_irq);
rc = dev_pm_set_wake_irq(&pdev->dev, rtc_dd->alarm_irq);
if (rc)
return rc;
@ -559,3 +551,4 @@ MODULE_ALIAS("platform:rtc-pm8xxx");
MODULE_DESCRIPTION("PMIC8xxx RTC driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Anirudh Ghayal <aghayal@codeaurora.org>");
MODULE_AUTHOR("Johan Hovold <johan@kernel.org>");

View File

@ -982,6 +982,12 @@ static int rv3028_probe(struct i2c_client *client)
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[] = {
{ .compatible = "microcrystal,rv3028", },
{ }
@ -991,6 +997,7 @@ MODULE_DEVICE_TABLE(of, rv3028_of_match);
static struct i2c_driver rv3028_driver = {
.driver = {
.name = "rtc-rv3028",
.acpi_match_table = rv3028_i2c_acpi_match,
.of_match_table = of_match_ptr(rv3028_of_match),
},
.probe_new = rv3028_probe,

View File

@ -735,9 +735,14 @@ static int rv3029_probe(struct device *dev, struct regmap *regmap, int irq,
return PTR_ERR(rv3029->rtc);
if (rv3029->irq > 0) {
unsigned long irqflags = IRQF_TRIGGER_LOW;
if (dev_fwnode(dev))
irqflags = 0;
rc = devm_request_threaded_irq(dev, rv3029->irq,
NULL, rv3029_handle_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
irqflags | IRQF_ONESHOT,
"rv3029", dev);
if (rc) {
dev_warn(dev, "unable to request IRQ, alarms disabled\n");

View File

@ -930,9 +930,14 @@ static int rv3032_probe(struct i2c_client *client)
return PTR_ERR(rv3032->rtc);
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,
NULL, rv3032_handle_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
irqflags | IRQF_ONESHOT,
"rv3032", rv3032);
if (ret) {
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");
@ -975,6 +980,12 @@ static int rv3032_probe(struct i2c_client *client)
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[] = {
{ .compatible = "microcrystal,rv3032", },
{ }
@ -984,6 +995,7 @@ MODULE_DEVICE_TABLE(of, rv3032_of_match);
static struct i2c_driver rv3032_driver = {
.driver = {
.name = "rtc-rv3032",
.acpi_match_table = rv3032_i2c_acpi_match,
.of_match_table = of_match_ptr(rv3032_of_match),
},
.probe_new = rv3032_probe,

View File

@ -70,6 +70,7 @@ struct rv8803_data {
struct mutex flags_lock;
u8 ctrl;
u8 backup;
u8 alarm_invalid:1;
enum rv8803_type type;
};
@ -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_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 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);
if (ret)
return ret;
@ -238,6 +239,11 @@ static int rv8803_get_time(struct device *dev, struct rtc_time *tm)
u8 *date = date1;
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);
if (flags < 0)
return flags;
@ -313,12 +319,19 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
return flags;
}
if (flags & RV8803_FLAG_V2F) {
ret = rv8803_regs_reset(rv8803);
if ((flags & RV8803_FLAG_V2F) || rv8803->alarm_invalid) {
/*
* 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) {
mutex_unlock(&rv8803->flags_lock);
return ret;
}
rv8803->alarm_invalid = false;
}
ret = rv8803_write_reg(rv8803->client, RV8803_FLAG,
@ -344,15 +357,33 @@ static int rv8803_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
if (flags < 0)
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_min = bcd2bin(alarmvals[0] & 0x7f);
alrm->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f);
alrm->time.tm_mday = bcd2bin(alarmvals[2] & 0x3f);
alrm->time.tm_min = bcd2bin(alarmvals[0]);
alrm->time.tm_hour = bcd2bin(alarmvals[1]);
alrm->time.tm_mday = bcd2bin(alarmvals[2]);
alrm->enabled = !!(rv8803->ctrl & RV8803_CTRL_AIE);
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;
err_invalid:
rv8803->alarm_invalid = true;
return -EINVAL;
}
static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
@ -641,9 +672,14 @@ static int rv8803_probe(struct i2c_client *client)
return PTR_ERR(rv8803->rtc);
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,
NULL, rv8803_handle_irq,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
irqflags | IRQF_ONESHOT,
"rv8803", client);
if (err) {
dev_warn(&client->dev, "unable to request IRQ, alarms disabled\n");

View File

@ -10,7 +10,6 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/regmap.h>
#include <linux/rtc.h>
#include <linux/of.h>

View File

@ -394,10 +394,14 @@ static int rx8010_probe(struct i2c_client *client)
return PTR_ERR(rx8010->rtc);
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,
rx8010_irq_1_handler,
IRQF_TRIGGER_LOW | IRQF_ONESHOT,
irqflags | IRQF_ONESHOT,
"rx8010", client);
if (err) {
dev_err(dev, "unable to request IRQ\n");

View File

@ -136,7 +136,6 @@ struct sun6i_rtc_clk_data {
unsigned int fixed_prescaler : 16;
unsigned int has_prescaler : 1;
unsigned int has_out_clk : 1;
unsigned int export_iosc : 1;
unsigned int has_losc_en : 1;
unsigned int has_auto_swt : 1;
};
@ -271,8 +270,6 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
/* Yes, I know, this is ugly. */
sun6i_rtc = rtc;
/* Only read IOSC name from device tree if it is exported */
if (rtc->data->export_iosc)
of_property_read_string_index(node, "clock-output-names", 2,
&iosc_name);
@ -315,13 +312,10 @@ static void __init sun6i_rtc_clk_init(struct device_node *node,
goto err_register;
}
clk_data->num = 2;
clk_data->num = 3;
clk_data->hws[0] = &rtc->hw;
clk_data->hws[1] = __clk_get_hw(rtc->ext_losc);
if (rtc->data->export_iosc) {
clk_data->hws[2] = rtc->int_osc;
clk_data->num = 3;
}
of_clk_add_hw_provider(node, of_clk_hw_onecell_get, clk_data);
return;
@ -361,7 +355,6 @@ static const struct sun6i_rtc_clk_data sun8i_h3_rtc_data = {
.fixed_prescaler = 32,
.has_prescaler = 1,
.has_out_clk = 1,
.export_iosc = 1,
};
static void __init sun8i_h3_rtc_clk_init(struct device_node *node)
@ -379,7 +372,6 @@ static const struct sun6i_rtc_clk_data sun50i_h6_rtc_data = {
.fixed_prescaler = 32,
.has_prescaler = 1,
.has_out_clk = 1,
.export_iosc = 1,
.has_losc_en = 1,
.has_auto_swt = 1,
};

View File

@ -14,8 +14,12 @@
const_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_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 char _bin2bcd(unsigned val) __attribute_const__;