Commit 3faae16b authored by Linus Torvalds's avatar Linus Torvalds

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

Pull RTC updates from Alexandre Belloni:
 "Subsytem:
   - rtc_class is now const

  Drivers:
   - ds1511: cleanup, set date and time range and alarm offset limit
   - max31335: fix interrupt handler
   - pcf8523: improve suspend support"

* tag 'rtc-6.9' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (28 commits)
  MAINTAINER: Include linux-arm-msm for Qualcomm RTC patches
  dt-bindings: rtc: zynqmp: Add support for Versal/Versal NET SoCs
  rtc: class: make rtc_class constant
  dt-bindings: rtc: abx80x: Improve checks on trickle charger constraints
  MAINTAINERS: adjust file entry in ARM/Mediatek RTC DRIVER
  rtc: nct3018y: fix possible NULL dereference
  rtc: max31335: fix interrupt status reg
  rtc: mt6397: select IRQ_DOMAIN instead of depending on it
  dt-bindings: rtc: abx80x: convert to yaml
  rtc: m41t80: Use the unified property API get the wakeup-source property
  dt-bindings: at91rm9260-rtt: add sam9x7 compatible
  dt-bindings: rtc: convert MT7622 RTC to the json-schema
  dt-bindings: rtc: convert MT2717 RTC to the json-schema
  rtc: pcf8523: add suspend handlers for alarm IRQ
  rtc: ds1511: set alarm offset limit
  rtc: ds1511: set range
  rtc: ds1511: drop inline/noinline hints
  rtc: ds1511: rename pdata
  rtc: ds1511: implement ds1511_rtc_read_alarm properly
  rtc: ds1511: remove partial alarm support
  ...
parents 00453419 f7cee094
Abracon ABX80X I2C ultra low power RTC/Alarm chip
The Abracon ABX80X family consist of the ab0801, ab0803, ab0804, ab0805, ab1801,
ab1803, ab1804 and ab1805. The ab0805 is the superset of ab080x and the ab1805
is the superset of ab180x.
Required properties:
- "compatible": should one of:
"abracon,abx80x"
"abracon,ab0801"
"abracon,ab0803"
"abracon,ab0804"
"abracon,ab0805"
"abracon,ab1801"
"abracon,ab1803"
"abracon,ab1804"
"abracon,ab1805"
"microcrystal,rv1805"
Using "abracon,abx80x" will enable chip autodetection.
- "reg": I2C bus address of the device
Optional properties:
The abx804 and abx805 have a trickle charger that is able to charge the
connected battery or supercap. Both the following properties have to be defined
and valid to enable charging:
- "abracon,tc-diode": should be "standard" (0.6V) or "schottky" (0.3V)
- "abracon,tc-resistor": should be <0>, <3>, <6> or <11>. 0 disables the output
resistor, the other values are in kOhm.
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/abracon,abx80x.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Abracon ABX80X I2C ultra low power RTC/Alarm chip
maintainers:
- linux-rtc@vger.kernel.org
properties:
compatible:
description:
The wildcard 'abracon,abx80x' may be used to support a mix
of different abracon rtc`s. In this case the driver
must perform auto-detection from ID register.
enum:
- abracon,abx80x
- abracon,ab0801
- abracon,ab0803
- abracon,ab0804
- abracon,ab0805
- abracon,ab1801
- abracon,ab1803
- abracon,ab1804
- abracon,ab1805
- microcrystal,rv1805
reg:
maxItems: 1
interrupts:
maxItems: 1
abracon,tc-diode:
description:
Trickle-charge diode type.
Required to enable charging backup battery.
Supported are 'standard' diodes with a 0.6V drop
and 'schottky' diodes with a 0.3V drop.
$ref: /schemas/types.yaml#/definitions/string
enum:
- standard
- schottky
abracon,tc-resistor:
description:
Trickle-charge resistor value in kOhm.
Required to enable charging backup battery.
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 3, 6, 11]
dependentRequired:
abracon,tc-diode: ["abracon,tc-resistor"]
abracon,tc-resistor: ["abracon,tc-diode"]
required:
- compatible
- reg
allOf:
- $ref: rtc.yaml#
- if:
properties:
compatible:
not:
contains:
enum:
- abracon,abx80x
- abracon,ab0804
- abracon,ab1804
- abracon,ab0805
- abracon,ab1805
then:
properties:
abracon,tc-diode: false
abracon,tc-resistor: false
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
rtc@69 {
compatible = "abracon,abx80x";
reg = <0x69>;
abracon,tc-diode = "schottky";
abracon,tc-resistor = <3>;
interrupts = <44 IRQ_TYPE_EDGE_FALLING>;
};
};
......@@ -19,7 +19,9 @@ properties:
- items:
- const: atmel,at91sam9260-rtt
- items:
- const: microchip,sam9x60-rtt
- enum:
- microchip,sam9x60-rtt
- microchip,sam9x7-rtt
- const: atmel,at91sam9260-rtt
- items:
- const: microchip,sama7g5-rtt
......
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/mediatek,mt2712-rtc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek MT2712 on-SoC RTC
allOf:
- $ref: rtc.yaml#
maintainers:
- Ran Bi <ran.bi@mediatek.com>
properties:
compatible:
const: mediatek,mt2712-rtc
reg:
maxItems: 1
interrupts:
maxItems: 1
required:
- reg
- interrupts
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/arm-gic.h>
rtc@10011000 {
compatible = "mediatek,mt2712-rtc";
reg = <0x10011000 0x1000>;
interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_LOW>;
};
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/rtc/mediatek,mt7622-rtc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek MT7622 on-SoC RTC
allOf:
- $ref: rtc.yaml#
maintainers:
- Sean Wang <sean.wang@mediatek.com>
properties:
compatible:
items:
- const: mediatek,mt7622-rtc
- const: mediatek,soc-rtc
reg:
maxItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
clock-names:
const: rtc
required:
- reg
- interrupts
- clocks
- clock-names
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/clock/mt7622-clk.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
rtc@10212800 {
compatible = "mediatek,mt7622-rtc", "mediatek,soc-rtc";
reg = <0x10212800 0x200>;
interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_LOW>;
clocks = <&topckgen CLK_TOP_RTC>;
clock-names = "rtc";
};
Device-Tree bindings for MediaTek SoC based RTC
Required properties:
- compatible : Should be "mediatek,mt2712-rtc" : for MT2712 SoC
- reg : Specifies base physical address and size of the registers;
- interrupts : Should contain the interrupt for RTC alarm;
Example:
rtc: rtc@10011000 {
compatible = "mediatek,mt2712-rtc";
reg = <0 0x10011000 0 0x1000>;
interrupts = <GIC_SPI 239 IRQ_TYPE_LEVEL_LOW>;
};
Device-Tree bindings for MediaTek SoC based RTC
Required properties:
- compatible : Should be
"mediatek,mt7622-rtc", "mediatek,soc-rtc" : for MT7622 SoC
- reg : Specifies base physical address and size of the registers;
- interrupts : Should contain the interrupt for RTC alarm;
- clocks : Specifies list of clock specifiers, corresponding to
entries in clock-names property;
- clock-names : Should contain "rtc" entries
Example:
rtc: rtc@10212800 {
compatible = "mediatek,mt7622-rtc",
"mediatek,soc-rtc";
reg = <0 0x10212800 0 0x200>;
interrupts = <GIC_SPI 129 IRQ_TYPE_LEVEL_LOW>;
clocks = <&topckgen CLK_TOP_RTC>;
clock-names = "rtc";
};
......@@ -18,7 +18,13 @@ allOf:
properties:
compatible:
const: xlnx,zynqmp-rtc
oneOf:
- const: xlnx,zynqmp-rtc
- items:
- enum:
- xlnx,versal-rtc
- xlnx,versal-net-rtc
- const: xlnx,zynqmp-rtc
reg:
maxItems: 1
......@@ -48,6 +54,9 @@ properties:
default: 0x198233
deprecated: true
power-domains:
maxItems: 1
required:
- compatible
- reg
......
......@@ -2377,8 +2377,8 @@ M: Sean Wang <sean.wang@mediatek.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
L: linux-mediatek@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/rtc/rtc-mt2712.txt
F: Documentation/devicetree/bindings/rtc/rtc-mt7622.txt
F: Documentation/devicetree/bindings/rtc/mediatek,mt2712-rtc.yaml
F: Documentation/devicetree/bindings/rtc/mediatek,mt7622-rtc.yaml
F: drivers/rtc/rtc-mt2712.c
F: drivers/rtc/rtc-mt6397.c
F: drivers/rtc/rtc-mt7622.c
......@@ -2617,6 +2617,7 @@ F: drivers/pci/controller/dwc/pcie-qcom.c
F: drivers/phy/qualcomm/
F: drivers/power/*/msm*
F: drivers/reset/reset-qcom-*
F: drivers/rtc/rtc-pm8xxx.c
F: drivers/spi/spi-geni-qcom.c
F: drivers/spi/spi-qcom-qspi.c
F: drivers/spi/spi-qup.c
......
......@@ -1858,7 +1858,8 @@ config RTC_DRV_MT2712
config RTC_DRV_MT6397
tristate "MediaTek PMIC based RTC"
depends on MFD_MT6397 || (COMPILE_TEST && IRQ_DOMAIN)
depends on MFD_MT6397 || COMPILE_TEST
select IRQ_DOMAIN
help
This selects the MediaTek(R) RTC driver. RTC is part of MediaTek
MT6397 PMIC. You should enable MT6397 PMIC MFD before select
......
......@@ -21,7 +21,6 @@
#include "rtc-core.h"
static DEFINE_IDA(rtc_ida);
struct class *rtc_class;
static void rtc_device_release(struct device *dev)
{
......@@ -199,6 +198,11 @@ static SIMPLE_DEV_PM_OPS(rtc_class_dev_pm_ops, rtc_suspend, rtc_resume);
#define RTC_CLASS_DEV_PM_OPS NULL
#endif
const struct class rtc_class = {
.name = "rtc",
.pm = RTC_CLASS_DEV_PM_OPS,
};
/* Ensure the caller will set the id before releasing the device */
static struct rtc_device *rtc_allocate_device(void)
{
......@@ -220,7 +224,7 @@ static struct rtc_device *rtc_allocate_device(void)
rtc->irq_freq = 1;
rtc->max_user_freq = 64;
rtc->dev.class = rtc_class;
rtc->dev.class = &rtc_class;
rtc->dev.groups = rtc_get_dev_attribute_groups();
rtc->dev.release = rtc_device_release;
......@@ -475,13 +479,14 @@ EXPORT_SYMBOL_GPL(devm_rtc_device_register);
static int __init rtc_init(void)
{
rtc_class = class_create("rtc");
if (IS_ERR(rtc_class)) {
pr_err("couldn't create class\n");
return PTR_ERR(rtc_class);
}
rtc_class->pm = RTC_CLASS_DEV_PM_OPS;
int err;
err = class_register(&rtc_class);
if (err)
return err;
rtc_dev_init();
return 0;
}
subsys_initcall(rtc_init);
......@@ -696,7 +696,7 @@ struct rtc_device *rtc_class_open(const char *name)
struct device *dev;
struct rtc_device *rtc = NULL;
dev = class_find_device_by_name(rtc_class, name);
dev = class_find_device_by_name(&rtc_class, name);
if (dev)
rtc = to_rtc_device(dev);
......
......@@ -22,26 +22,24 @@
#include <linux/io.h>
#include <linux/module.h>
enum ds1511reg {
DS1511_SEC = 0x0,
DS1511_MIN = 0x1,
DS1511_HOUR = 0x2,
DS1511_DOW = 0x3,
DS1511_DOM = 0x4,
DS1511_MONTH = 0x5,
DS1511_YEAR = 0x6,
DS1511_CENTURY = 0x7,
DS1511_AM1_SEC = 0x8,
DS1511_AM2_MIN = 0x9,
DS1511_AM3_HOUR = 0xa,
DS1511_AM4_DATE = 0xb,
DS1511_WD_MSEC = 0xc,
DS1511_WD_SEC = 0xd,
DS1511_CONTROL_A = 0xe,
DS1511_CONTROL_B = 0xf,
DS1511_RAMADDR_LSB = 0x10,
DS1511_RAMDATA = 0x13
};
#define DS1511_SEC 0x0
#define DS1511_MIN 0x1
#define DS1511_HOUR 0x2
#define DS1511_DOW 0x3
#define DS1511_DOM 0x4
#define DS1511_MONTH 0x5
#define DS1511_YEAR 0x6
#define DS1511_CENTURY 0x7
#define DS1511_AM1_SEC 0x8
#define DS1511_AM2_MIN 0x9
#define DS1511_AM3_HOUR 0xa
#define DS1511_AM4_DATE 0xb
#define DS1511_WD_MSEC 0xc
#define DS1511_WD_SEC 0xd
#define DS1511_CONTROL_A 0xe
#define DS1511_CONTROL_B 0xf
#define DS1511_RAMADDR_LSB 0x10
#define DS1511_RAMDATA 0x13
#define DS1511_BLF1 0x80
#define DS1511_BLF2 0x40
......@@ -61,35 +59,10 @@ enum ds1511reg {
#define DS1511_WDS 0x01
#define DS1511_RAM_MAX 0x100
#define RTC_CMD DS1511_CONTROL_B
#define RTC_CMD1 DS1511_CONTROL_A
#define RTC_ALARM_SEC DS1511_AM1_SEC
#define RTC_ALARM_MIN DS1511_AM2_MIN
#define RTC_ALARM_HOUR DS1511_AM3_HOUR
#define RTC_ALARM_DATE DS1511_AM4_DATE
#define RTC_SEC DS1511_SEC
#define RTC_MIN DS1511_MIN
#define RTC_HOUR DS1511_HOUR
#define RTC_DOW DS1511_DOW
#define RTC_DOM DS1511_DOM
#define RTC_MON DS1511_MONTH
#define RTC_YEAR DS1511_YEAR
#define RTC_CENTURY DS1511_CENTURY
#define RTC_TIE DS1511_TIE
#define RTC_TE DS1511_TE
struct rtc_plat_data {
struct ds1511_data {
struct rtc_device *rtc;
void __iomem *ioaddr; /* virtual base address */
int irq;
unsigned int irqen;
int alrm_sec;
int alrm_min;
int alrm_hour;
int alrm_mday;
spinlock_t lock;
};
......@@ -98,95 +71,33 @@ static DEFINE_SPINLOCK(ds1511_lock);
static __iomem char *ds1511_base;
static u32 reg_spacing = 1;
static noinline void
rtc_write(uint8_t val, uint32_t reg)
static void rtc_write(uint8_t val, uint32_t reg)
{
writeb(val, ds1511_base + (reg * reg_spacing));
}
static noinline uint8_t
rtc_read(enum ds1511reg reg)
static uint8_t rtc_read(uint32_t reg)
{
return readb(ds1511_base + (reg * reg_spacing));
}
static inline void
rtc_disable_update(void)
static void rtc_disable_update(void)
{
rtc_write((rtc_read(RTC_CMD) & ~RTC_TE), RTC_CMD);
rtc_write((rtc_read(DS1511_CONTROL_B) & ~DS1511_TE), DS1511_CONTROL_B);
}
static void
rtc_enable_update(void)
static void rtc_enable_update(void)
{
rtc_write((rtc_read(RTC_CMD) | RTC_TE), RTC_CMD);
}
/*
* #define DS1511_WDOG_RESET_SUPPORT
*
* Uncomment this if you want to use these routines in
* some platform code.
*/
#ifdef DS1511_WDOG_RESET_SUPPORT
/*
* just enough code to set the watchdog timer so that it
* will reboot the system
*/
void
ds1511_wdog_set(unsigned long deciseconds)
{
/*
* the wdog timer can take 99.99 seconds
*/
deciseconds %= 10000;
/*
* set the wdog values in the wdog registers
*/
rtc_write(bin2bcd(deciseconds % 100), DS1511_WD_MSEC);
rtc_write(bin2bcd(deciseconds / 100), DS1511_WD_SEC);
/*
* set wdog enable and wdog 'steering' bit to issue a reset
*/
rtc_write(rtc_read(RTC_CMD) | DS1511_WDE | DS1511_WDS, RTC_CMD);
}
void
ds1511_wdog_disable(void)
{
/*
* clear wdog enable and wdog 'steering' bits
*/
rtc_write(rtc_read(RTC_CMD) & ~(DS1511_WDE | DS1511_WDS), RTC_CMD);
/*
* clear the wdog counter
*/
rtc_write(0, DS1511_WD_MSEC);
rtc_write(0, DS1511_WD_SEC);
rtc_write((rtc_read(DS1511_CONTROL_B) | DS1511_TE), DS1511_CONTROL_B);
}
#endif
/*
* set the rtc chip's idea of the time.
* stupidly, some callers call with year unmolested;
* and some call with year = year - 1900. thanks.
*/
static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
{
u8 mon, day, dow, hrs, min, sec, yrs, cen;
unsigned long flags;
/*
* won't have to change this for a while
*/
if (rtc_tm->tm_year < 1900)
rtc_tm->tm_year += 1900;
if (rtc_tm->tm_year < 1970)
return -EINVAL;
yrs = rtc_tm->tm_year % 100;
cen = rtc_tm->tm_year / 100;
cen = 19 + rtc_tm->tm_year / 100;
mon = rtc_tm->tm_mon + 1; /* tm_mon starts at zero */
day = rtc_tm->tm_mday;
dow = rtc_tm->tm_wday & 0x7; /* automatic BCD */
......@@ -194,15 +105,6 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
min = rtc_tm->tm_min;
sec = rtc_tm->tm_sec;
if ((mon > 12) || (day == 0))
return -EINVAL;
if (day > rtc_month_days(rtc_tm->tm_mon, rtc_tm->tm_year))
return -EINVAL;
if ((hrs >= 24) || (min >= 60) || (sec >= 60))
return -EINVAL;
/*
* each register is a different number of valid bits
*/
......@@ -216,14 +118,14 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
spin_lock_irqsave(&ds1511_lock, flags);
rtc_disable_update();
rtc_write(cen, RTC_CENTURY);
rtc_write(yrs, RTC_YEAR);
rtc_write((rtc_read(RTC_MON) & 0xe0) | mon, RTC_MON);
rtc_write(day, RTC_DOM);
rtc_write(hrs, RTC_HOUR);
rtc_write(min, RTC_MIN);
rtc_write(sec, RTC_SEC);
rtc_write(dow, RTC_DOW);
rtc_write(cen, DS1511_CENTURY);
rtc_write(yrs, DS1511_YEAR);
rtc_write((rtc_read(DS1511_MONTH) & 0xe0) | mon, DS1511_MONTH);
rtc_write(day, DS1511_DOM);
rtc_write(hrs, DS1511_HOUR);
rtc_write(min, DS1511_MIN);
rtc_write(sec, DS1511_SEC);
rtc_write(dow, DS1511_DOW);
rtc_enable_update();
spin_unlock_irqrestore(&ds1511_lock, flags);
......@@ -238,14 +140,14 @@ static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
spin_lock_irqsave(&ds1511_lock, flags);
rtc_disable_update();
rtc_tm->tm_sec = rtc_read(RTC_SEC) & 0x7f;
rtc_tm->tm_min = rtc_read(RTC_MIN) & 0x7f;
rtc_tm->tm_hour = rtc_read(RTC_HOUR) & 0x3f;
rtc_tm->tm_mday = rtc_read(RTC_DOM) & 0x3f;
rtc_tm->tm_wday = rtc_read(RTC_DOW) & 0x7;
rtc_tm->tm_mon = rtc_read(RTC_MON) & 0x1f;
rtc_tm->tm_year = rtc_read(RTC_YEAR) & 0x7f;
century = rtc_read(RTC_CENTURY);
rtc_tm->tm_sec = rtc_read(DS1511_SEC) & 0x7f;
rtc_tm->tm_min = rtc_read(DS1511_MIN) & 0x7f;
rtc_tm->tm_hour = rtc_read(DS1511_HOUR) & 0x3f;
rtc_tm->tm_mday = rtc_read(DS1511_DOM) & 0x3f;
rtc_tm->tm_wday = rtc_read(DS1511_DOW) & 0x7;
rtc_tm->tm_mon = rtc_read(DS1511_MONTH) & 0x1f;
rtc_tm->tm_year = rtc_read(DS1511_YEAR) & 0x7f;
century = rtc_read(DS1511_CENTURY);
rtc_enable_update();
spin_unlock_irqrestore(&ds1511_lock, flags);
......@@ -271,106 +173,67 @@ static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
return 0;
}
/*
* write the alarm register settings
*
* we only have the use to interrupt every second, otherwise
* known as the update interrupt, or the interrupt if the whole
* date/hours/mins/secs matches. the ds1511 has many more
* permutations, but the kernel doesn't.
*/
static void
ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
static void ds1511_rtc_alarm_enable(unsigned int enabled)
{
unsigned long flags;
spin_lock_irqsave(&pdata->lock, flags);
rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?
0x80 : bin2bcd(pdata->alrm_mday) & 0x3f,
RTC_ALARM_DATE);
rtc_write(pdata->alrm_hour < 0 || (pdata->irqen & RTC_UF) ?
0x80 : bin2bcd(pdata->alrm_hour) & 0x3f,
RTC_ALARM_HOUR);
rtc_write(pdata->alrm_min < 0 || (pdata->irqen & RTC_UF) ?
0x80 : bin2bcd(pdata->alrm_min) & 0x7f,
RTC_ALARM_MIN);
rtc_write(pdata->alrm_sec < 0 || (pdata->irqen & RTC_UF) ?
0x80 : bin2bcd(pdata->alrm_sec) & 0x7f,
RTC_ALARM_SEC);
rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD);
rtc_read(RTC_CMD1); /* clear interrupts */
spin_unlock_irqrestore(&pdata->lock, flags);
rtc_write(rtc_read(DS1511_CONTROL_B) | (enabled ? DS1511_TIE : 0), DS1511_CONTROL_B);
}
static int
ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
static int ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
struct ds1511_data *ds1511 = dev_get_drvdata(dev);
unsigned long flags;
if (pdata->irq <= 0)
return -EINVAL;
spin_lock_irqsave(&ds1511->lock, flags);
rtc_write(bin2bcd(alrm->time.tm_mday) & 0x3f, DS1511_AM4_DATE);
rtc_write(bin2bcd(alrm->time.tm_hour) & 0x3f, DS1511_AM3_HOUR);
rtc_write(bin2bcd(alrm->time.tm_min) & 0x7f, DS1511_AM2_MIN);
rtc_write(bin2bcd(alrm->time.tm_sec) & 0x7f, DS1511_AM1_SEC);
ds1511_rtc_alarm_enable(alrm->enabled);
pdata->alrm_mday = alrm->time.tm_mday;
pdata->alrm_hour = alrm->time.tm_hour;
pdata->alrm_min = alrm->time.tm_min;
pdata->alrm_sec = alrm->time.tm_sec;
if (alrm->enabled)
pdata->irqen |= RTC_AF;
rtc_read(DS1511_CONTROL_A); /* clear interrupts */
spin_unlock_irqrestore(&ds1511->lock, flags);
ds1511_rtc_update_alarm(pdata);
return 0;
}
static int
ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
static int ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
if (pdata->irq <= 0)
return -EINVAL;
alrm->time.tm_mday = bcd2bin(rtc_read(DS1511_AM4_DATE) & 0x3f);
alrm->time.tm_hour = bcd2bin(rtc_read(DS1511_AM3_HOUR) & 0x3f);
alrm->time.tm_min = bcd2bin(rtc_read(DS1511_AM2_MIN) & 0x7f);
alrm->time.tm_sec = bcd2bin(rtc_read(DS1511_AM1_SEC) & 0x7f);
alrm->enabled = !!(rtc_read(DS1511_CONTROL_B) & DS1511_TIE);
alrm->time.tm_mday = pdata->alrm_mday < 0 ? 0 : pdata->alrm_mday;
alrm->time.tm_hour = pdata->alrm_hour < 0 ? 0 : pdata->alrm_hour;
alrm->time.tm_min = pdata->alrm_min < 0 ? 0 : pdata->alrm_min;
alrm->time.tm_sec = pdata->alrm_sec < 0 ? 0 : pdata->alrm_sec;
alrm->enabled = (pdata->irqen & RTC_AF) ? 1 : 0;
return 0;
}
static irqreturn_t
ds1511_interrupt(int irq, void *dev_id)
static irqreturn_t ds1511_interrupt(int irq, void *dev_id)
{
struct platform_device *pdev = dev_id;
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
struct ds1511_data *ds1511 = platform_get_drvdata(pdev);
unsigned long events = 0;
spin_lock(&pdata->lock);
spin_lock(&ds1511->lock);
/*
* read and clear interrupt
*/
if (rtc_read(RTC_CMD1) & DS1511_IRQF) {
events = RTC_IRQF;
if (rtc_read(RTC_ALARM_SEC) & 0x80)
events |= RTC_UF;
else
events |= RTC_AF;
rtc_update_irq(pdata->rtc, 1, events);
if (rtc_read(DS1511_CONTROL_A) & DS1511_IRQF) {
events = RTC_IRQF | RTC_AF;
rtc_update_irq(ds1511->rtc, 1, events);
}
spin_unlock(&pdata->lock);
spin_unlock(&ds1511->lock);
return events ? IRQ_HANDLED : IRQ_NONE;
}
static int ds1511_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
if (pdata->irq <= 0)
return -EINVAL;
if (enabled)
pdata->irqen |= RTC_AF;
else
pdata->irqen &= ~RTC_AF;
ds1511_rtc_update_alarm(pdata);
struct ds1511_data *ds1511 = dev_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&ds1511->lock, flags);
ds1511_rtc_alarm_enable(enabled);
spin_unlock_irqrestore(&ds1511->lock, flags);
return 0;
}
......@@ -408,7 +271,7 @@ static int ds1511_nvram_write(void *priv, unsigned int pos, void *buf,
static int ds1511_rtc_probe(struct platform_device *pdev)
{
struct rtc_plat_data *pdata;
struct ds1511_data *ds1511;
int ret = 0;
struct nvmem_config ds1511_nvmem_cfg = {
.name = "ds1511_nvram",
......@@ -420,21 +283,21 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
.priv = &pdev->dev,
};
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
ds1511 = devm_kzalloc(&pdev->dev, sizeof(*ds1511), GFP_KERNEL);
if (!ds1511)
return -ENOMEM;
ds1511_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ds1511_base))
return PTR_ERR(ds1511_base);
pdata->ioaddr = ds1511_base;
pdata->irq = platform_get_irq(pdev, 0);
ds1511->ioaddr = ds1511_base;
ds1511->irq = platform_get_irq(pdev, 0);
/*
* turn on the clock and the crystal, etc.
*/
rtc_write(DS1511_BME, RTC_CMD);
rtc_write(0, RTC_CMD1);
rtc_write(DS1511_BME, DS1511_CONTROL_B);
rtc_write(0, DS1511_CONTROL_A);
/*
* clear the wdog counter
*/
......@@ -448,38 +311,43 @@ static int ds1511_rtc_probe(struct platform_device *pdev)
/*
* check for a dying bat-tree
*/
if (rtc_read(RTC_CMD1) & DS1511_BLF1)
if (rtc_read(DS1511_CONTROL_A) & DS1511_BLF1)
dev_warn(&pdev->dev, "voltage-low detected.\n");
spin_lock_init(&pdata->lock);
platform_set_drvdata(pdev, pdata);
pdata->rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(pdata->rtc))
return PTR_ERR(pdata->rtc);
pdata->rtc->ops = &ds1511_rtc_ops;
spin_lock_init(&ds1511->lock);
platform_set_drvdata(pdev, ds1511);
ret = devm_rtc_register_device(pdata->rtc);
if (ret)
return ret;
ds1511->rtc = devm_rtc_allocate_device(&pdev->dev);
if (IS_ERR(ds1511->rtc))
return PTR_ERR(ds1511->rtc);
devm_rtc_nvmem_register(pdata->rtc, &ds1511_nvmem_cfg);
ds1511->rtc->ops = &ds1511_rtc_ops;
ds1511->rtc->range_max = RTC_TIMESTAMP_END_2099;
ds1511->rtc->alarm_offset_max = 28 * 24 * 60 * 60 - 1;
/*
* if the platform has an interrupt in mind for this device,
* then by all means, set it
*/
if (pdata->irq > 0) {
rtc_read(RTC_CMD1);
if (devm_request_irq(&pdev->dev, pdata->irq, ds1511_interrupt,
if (ds1511->irq > 0) {
rtc_read(DS1511_CONTROL_A);
if (devm_request_irq(&pdev->dev, ds1511->irq, ds1511_interrupt,
IRQF_SHARED, pdev->name, pdev) < 0) {
dev_warn(&pdev->dev, "interrupt not available.\n");
pdata->irq = 0;
ds1511->irq = 0;
}
}
if (ds1511->irq == 0)
clear_bit(RTC_FEATURE_ALARM, ds1511->rtc->features);
ret = devm_rtc_register_device(ds1511->rtc);
if (ret)
return ret;
devm_rtc_nvmem_register(ds1511->rtc, &ds1511_nvmem_cfg);
return 0;
}
......
......@@ -909,10 +909,7 @@ static int m41t80_probe(struct i2c_client *client)
if (IS_ERR(m41t80_data->rtc))
return PTR_ERR(m41t80_data->rtc);
#ifdef CONFIG_OF
wakeup_source = of_property_read_bool(client->dev.of_node,
"wakeup-source");
#endif
wakeup_source = device_property_read_bool(&client->dev, "wakeup-source");
if (client->irq > 0) {
unsigned long irqflags = IRQF_TRIGGER_LOW;
......
......@@ -204,7 +204,7 @@ static bool max31335_volatile_reg(struct device *dev, unsigned int reg)
return true;
/* interrupt status register */
if (reg == MAX31335_INT_EN1_A1IE)
if (reg == MAX31335_STATUS1)
return true;
/* temperature registers */
......
......@@ -102,6 +102,8 @@ static int nct3018y_get_alarm_mode(struct i2c_client *client, unsigned char *ala
if (flags < 0)
return flags;
*alarm_enable = flags & NCT3018Y_BIT_AIE;
dev_dbg(&client->dev, "%s:alarm_enable:%x\n", __func__, *alarm_enable);
}
if (alarm_flag) {
......@@ -110,11 +112,9 @@ static int nct3018y_get_alarm_mode(struct i2c_client *client, unsigned char *ala
if (flags < 0)
return flags;
*alarm_flag = flags & NCT3018Y_BIT_AF;
dev_dbg(&client->dev, "%s:alarm_flag:%x\n", __func__, *alarm_flag);
}
dev_dbg(&client->dev, "%s:alarm_enable:%x alarm_flag:%x\n",
__func__, *alarm_enable, *alarm_flag);
return 0;
}
......
......@@ -370,6 +370,30 @@ static int pcf8523_rtc_set_offset(struct device *dev, long offset)
return regmap_write(pcf8523->regmap, PCF8523_REG_OFFSET, value);
}
#ifdef CONFIG_PM_SLEEP
static int pcf8523_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
if (client->irq > 0 && device_may_wakeup(dev))
enable_irq_wake(client->irq);
return 0;
}
static int pcf8523_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
if (client->irq > 0 && device_may_wakeup(dev))
disable_irq_wake(client->irq);
return 0;
}
#endif
static SIMPLE_DEV_PM_OPS(pcf8523_pm, pcf8523_suspend, pcf8523_resume);
static const struct rtc_class_ops pcf8523_rtc_ops = {
.read_time = pcf8523_rtc_read_time,
.set_time = pcf8523_rtc_set_time,
......@@ -487,6 +511,7 @@ static struct i2c_driver pcf8523_driver = {
.driver = {
.name = "rtc-pcf8523",
.of_match_table = pcf8523_of_match,
.pm = &pcf8523_pm,
},
.probe = pcf8523_probe,
.id_table = pcf8523_id,
......
......@@ -42,7 +42,7 @@ static inline time64_t rtc_tm_sub(struct rtc_time *lhs, struct rtc_time *rhs)
#include <linux/timerqueue.h>
#include <linux/workqueue.h>
extern struct class *rtc_class;
extern const struct class rtc_class;
/*
* For these RTC methods the device parameter is the physical device
......
......@@ -201,7 +201,7 @@ static int __init test_suspend(void)
}
/* RTCs have initialized by now too ... can we use one? */
dev = class_find_device(rtc_class, NULL, NULL, has_wakealarm);
dev = class_find_device(&rtc_class, NULL, NULL, has_wakealarm);
if (dev) {
rtc = rtc_class_open(dev_name(dev));
put_device(dev);
......
......@@ -134,7 +134,7 @@ static struct class_interface alarmtimer_rtc_interface = {
static int alarmtimer_rtc_interface_setup(void)
{
alarmtimer_rtc_interface.class = rtc_class;
alarmtimer_rtc_interface.class = &rtc_class;
return class_interface_register(&alarmtimer_rtc_interface);
}
static void alarmtimer_rtc_interface_remove(void)
......
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