mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'rtc-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
Pull RTC updates from Alexandre Belloni:
"A huge series from me this cycle. I went through many drivers to set
the date and time range supported by the RTC which helps solving HW
limitation when the time comes (as early as next year for some). This
time, I focused on drivers using .set_mms and .set_mmss64, allowing me
to remove those callbacks. About a third of the patches got reviews, I
actually own the RTCs and I tested another third and the remaining one
are unlikely to cause any issues.
Other than that, a single new driver and the usual fixes here and there.
Summary:
Subsystem:
- set_mmss and set_mmss64 rtc_ops removal
- Fix timestamp value for RTC_TIMESTAMP_BEGIN_1900
- Use SPDX identifier for the core
- validate upper bound of tm->tm_year
New driver:
- Aspeed BMC SoC RTC
Drivers:
- abx80x: use rtc_add_group
- ds3232: nvram support
- pcf85063: add alarm, nvram, offset correction and microcrystal
rv8263 support
- x1205: add of_match_table
- Use set_time instead of set_mms/set_mmss64 for: ab3100, coh901331,
digicolor, ds1672, ds2404, ep93xx, imxdi, jz4740, lpc32xx, mc13xxx,
mxc, pcap, stmp3xxx, test, wm831x, xgene.
- Set RTC range for: ab3100, at91sam9, coh901331, da9063, digicolor,
dm355evm, ds1672, ds2404, ep39xx, goldfish, imxdi, jz4740, lpc32xx,
mc13xxx, mv, mxc, omap, pcap, pcf85063, pcf85363, ps3, sh,
stmp3xxx, sun4v, tegra, wm831x, xgene.
- Switch to rtc_time64_to_tm/rtc_tm_to_time64 for the driver that
properly set the RTC range.
- Use dev_get_drvdata instead of multiple indirections"
* tag 'rtc-5.2' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (177 commits)
rtc: snvs: Use __maybe_unused instead of #if CONFIG_PM_SLEEP
rtc: imxdi: remove unused variable
rtc: drop set_mms and set_mmss64
rtc: pcap: convert to SPDX identifier
rtc: pcap: use .set_time
rtc: pcap: switch to rtc_time64_to_tm/rtc_tm_to_time64
rtc: pcap: set range
rtc: digicolor: convert to SPDX identifier
rtc: digicolor: use .set_time
rtc: digicolor: set range
rtc: digicolor: fix possible race condition
rtc: jz4740: convert to SPDX identifier
rtc: jz4740: rework invalid time detection
rtc: jz4740: use dev_pm_set_wake_irq() to simplify code
rtc: jz4740: use .set_time
rtc: jz4740: remove useless check
rtc: jz4740: switch to rtc_time64_to_tm/rtc_tm_to_time64
rtc: jz4740: set range
rtc: 88pm860x: prevent use-after-free on device remove
rtc: Use dev_get_drvdata()
...
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
* NXP PCF85063 Real Time Clock
|
||||
|
||||
Required properties:
|
||||
- compatible: Should contain "nxp,pcf85063".
|
||||
- compatible: Should one of contain:
|
||||
"nxp,pcf85063",
|
||||
"nxp,pcf85063a",
|
||||
"nxp,pcf85063tp",
|
||||
"microcrystal,rv8263"
|
||||
- reg: I2C address for chip.
|
||||
|
||||
Optional property:
|
||||
|
||||
22
Documentation/devicetree/bindings/rtc/rtc-aspeed.txt
Normal file
22
Documentation/devicetree/bindings/rtc/rtc-aspeed.txt
Normal file
@@ -0,0 +1,22 @@
|
||||
ASPEED BMC RTC
|
||||
==============
|
||||
|
||||
Required properties:
|
||||
- compatible: should be one of the following
|
||||
* aspeed,ast2400-rtc for the ast2400
|
||||
* aspeed,ast2500-rtc for the ast2500
|
||||
* aspeed,ast2600-rtc for the ast2600
|
||||
|
||||
- reg: physical base address of the controller and length of memory mapped
|
||||
region
|
||||
|
||||
- interrupts: The interrupt number
|
||||
|
||||
Example:
|
||||
|
||||
rtc@1e781000 {
|
||||
compatible = "aspeed,ast2400-rtc";
|
||||
reg = <0x1e781000 0x18>;
|
||||
interrupts = <22>;
|
||||
status = "disabled";
|
||||
};
|
||||
@@ -69,3 +69,4 @@ ricoh,rv5c386 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
ricoh,rv5c387a I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
sii,s35390a 2-wire CMOS real-time clock
|
||||
whwave,sd3078 I2C bus SERIAL INTERFACE REAL-TIME CLOCK IC
|
||||
xircom,x1205 Xircom X1205 I2C RTC
|
||||
|
||||
@@ -439,6 +439,7 @@ config RTC_DRV_PCF8523
|
||||
|
||||
config RTC_DRV_PCF85063
|
||||
tristate "NXP PCF85063"
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for the PCF85063 RTC chip
|
||||
|
||||
@@ -447,7 +448,6 @@ config RTC_DRV_PCF85063
|
||||
|
||||
config RTC_DRV_PCF85363
|
||||
tristate "NXP PCF85363"
|
||||
depends on I2C
|
||||
select REGMAP_I2C
|
||||
help
|
||||
If you say yes here you get support for the PCF85363 RTC chip.
|
||||
@@ -602,7 +602,6 @@ config RTC_DRV_FM3130
|
||||
|
||||
config RTC_DRV_RX8010
|
||||
tristate "Epson RX8010SJ"
|
||||
depends on I2C
|
||||
help
|
||||
If you say yes here you get support for the Epson RX8010SJ RTC
|
||||
chip.
|
||||
@@ -1432,7 +1431,7 @@ config RTC_DRV_AT91RM9200
|
||||
config RTC_DRV_AT91SAM9
|
||||
tristate "AT91SAM9 RTT as RTC"
|
||||
depends on ARCH_AT91 || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
depends on OF && HAS_IOMEM
|
||||
select MFD_SYSCON
|
||||
help
|
||||
Some AT91SAM9 SoCs provide an RTT (Real Time Timer) block which
|
||||
@@ -1841,6 +1840,17 @@ config RTC_DRV_RTD119X
|
||||
If you say yes here, you get support for the RTD1295 SoC
|
||||
Real Time Clock.
|
||||
|
||||
config RTC_DRV_ASPEED
|
||||
tristate "ASPEED RTC"
|
||||
depends on OF
|
||||
depends on ARCH_ASPEED || COMPILE_TEST
|
||||
help
|
||||
If you say yes here you get support for the ASPEED BMC SoC real time
|
||||
clocks.
|
||||
|
||||
This driver can also be built as a module, if so, the module
|
||||
will be called "rtc-aspeed".
|
||||
|
||||
comment "HID Sensor RTC drivers"
|
||||
|
||||
config RTC_DRV_HID_SENSOR_TIME
|
||||
@@ -1857,7 +1867,8 @@ config RTC_DRV_HID_SENSOR_TIME
|
||||
|
||||
config RTC_DRV_GOLDFISH
|
||||
tristate "Goldfish Real Time Clock"
|
||||
depends on MIPS && (GOLDFISH || COMPILE_TEST)
|
||||
depends on OF && HAS_IOMEM
|
||||
depends on GOLDFISH || COMPILE_TEST
|
||||
help
|
||||
Say yes to enable RTC driver for the Goldfish based virtual platform.
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ obj-$(CONFIG_RTC_DRV_AC100) += rtc-ac100.o
|
||||
obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o
|
||||
obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o
|
||||
obj-$(CONFIG_RTC_DRV_ASM9260) += rtc-asm9260.o
|
||||
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
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* RTC subsystem, base class
|
||||
*
|
||||
@@ -5,11 +6,7 @@
|
||||
* Author: Alessandro Zummo <a.zummo@towertech.it>
|
||||
*
|
||||
* class skeleton from drivers/hwmon/hwmon.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
@@ -23,13 +20,13 @@
|
||||
|
||||
#include "rtc-core.h"
|
||||
|
||||
|
||||
static DEFINE_IDA(rtc_ida);
|
||||
struct class *rtc_class;
|
||||
|
||||
static void rtc_device_release(struct device *dev)
|
||||
{
|
||||
struct rtc_device *rtc = to_rtc_device(dev);
|
||||
|
||||
ida_simple_remove(&rtc_ida, rtc->id);
|
||||
kfree(rtc);
|
||||
}
|
||||
@@ -47,7 +44,6 @@ int rtc_hctosys_ret = -ENODEV;
|
||||
|
||||
static struct timespec64 old_rtc, old_system, old_delta;
|
||||
|
||||
|
||||
static int rtc_suspend(struct device *dev)
|
||||
{
|
||||
struct rtc_device *rtc = to_rtc_device(dev);
|
||||
@@ -71,7 +67,6 @@ static int rtc_suspend(struct device *dev)
|
||||
ktime_get_real_ts64(&old_system);
|
||||
old_rtc.tv_sec = rtc_tm_to_time64(&tm);
|
||||
|
||||
|
||||
/*
|
||||
* To avoid drift caused by repeated suspend/resumes,
|
||||
* which each can add ~1 second drift error,
|
||||
@@ -83,7 +78,7 @@ static int rtc_suspend(struct device *dev)
|
||||
if (delta_delta.tv_sec < -2 || delta_delta.tv_sec >= 2) {
|
||||
/*
|
||||
* if delta_delta is too large, assume time correction
|
||||
* has occured and set old_delta to the current delta.
|
||||
* has occurred and set old_delta to the current delta.
|
||||
*/
|
||||
old_delta = delta;
|
||||
} else {
|
||||
@@ -136,7 +131,7 @@ static int rtc_resume(struct device *dev)
|
||||
* to keep things accurate.
|
||||
*/
|
||||
sleep_time = timespec64_sub(sleep_time,
|
||||
timespec64_sub(new_system, old_system));
|
||||
timespec64_sub(new_system, old_system));
|
||||
|
||||
if (sleep_time.tv_sec >= 0)
|
||||
timekeeping_inject_sleeptime64(&sleep_time);
|
||||
@@ -397,9 +392,9 @@ EXPORT_SYMBOL_GPL(__rtc_register_device);
|
||||
* rtc_register_device instead
|
||||
*/
|
||||
struct rtc_device *devm_rtc_device_register(struct device *dev,
|
||||
const char *name,
|
||||
const struct rtc_class_ops *ops,
|
||||
struct module *owner)
|
||||
const char *name,
|
||||
const struct rtc_class_ops *ops,
|
||||
struct module *owner)
|
||||
{
|
||||
struct rtc_device *rtc;
|
||||
int err;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* RTC subsystem, dev interface
|
||||
*
|
||||
@@ -5,11 +6,7 @@
|
||||
* Author: Alessandro Zummo <a.zummo@towertech.it>
|
||||
*
|
||||
* based on arch/arm/common/rtctime.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
@@ -60,7 +57,7 @@ static void rtc_uie_task(struct work_struct *work)
|
||||
} else if (rtc->oldsecs != tm.tm_sec) {
|
||||
num = (tm.tm_sec + 60 - rtc->oldsecs) % 60;
|
||||
rtc->oldsecs = tm.tm_sec;
|
||||
rtc->uie_timer.expires = jiffies + HZ - (HZ/10);
|
||||
rtc->uie_timer.expires = jiffies + HZ - (HZ / 10);
|
||||
rtc->uie_timer_active = 1;
|
||||
rtc->uie_task_active = 0;
|
||||
add_timer(&rtc->uie_timer);
|
||||
@@ -71,6 +68,7 @@ static void rtc_uie_task(struct work_struct *work)
|
||||
if (num)
|
||||
rtc_handle_legacy_irq(rtc, num, RTC_UF);
|
||||
}
|
||||
|
||||
static void rtc_uie_timer(struct timer_list *t)
|
||||
{
|
||||
struct rtc_device *rtc = from_timer(rtc, t, uie_timer);
|
||||
@@ -202,14 +200,14 @@ static __poll_t rtc_dev_poll(struct file *file, poll_table *wait)
|
||||
}
|
||||
|
||||
static long rtc_dev_ioctl(struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int err = 0;
|
||||
struct rtc_device *rtc = file->private_data;
|
||||
const struct rtc_class_ops *ops = rtc->ops;
|
||||
struct rtc_time tm;
|
||||
struct rtc_wkalrm alarm;
|
||||
void __user *uarg = (void __user *) arg;
|
||||
void __user *uarg = (void __user *)arg;
|
||||
|
||||
err = mutex_lock_interruptible(&rtc->ops_lock);
|
||||
if (err)
|
||||
@@ -233,7 +231,7 @@ static long rtc_dev_ioctl(struct file *file,
|
||||
|
||||
case RTC_PIE_ON:
|
||||
if (rtc->irq_freq > rtc->max_user_freq &&
|
||||
!capable(CAP_SYS_RESOURCE))
|
||||
!capable(CAP_SYS_RESOURCE))
|
||||
err = -EACCES;
|
||||
break;
|
||||
}
|
||||
@@ -390,8 +388,9 @@ static long rtc_dev_ioctl(struct file *file,
|
||||
err = ops->ioctl(rtc->dev.parent, cmd, arg);
|
||||
if (err == -ENOIOCTLCMD)
|
||||
err = -ENOTTY;
|
||||
} else
|
||||
} else {
|
||||
err = -ENOTTY;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -403,6 +402,7 @@ done:
|
||||
static int rtc_dev_fasync(int fd, struct file *file, int on)
|
||||
{
|
||||
struct rtc_device *rtc = file->private_data;
|
||||
|
||||
return fasync_helper(fd, file, on, &rtc->async_queue);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* RTC subsystem, initialize system time on startup
|
||||
*
|
||||
* Copyright (C) 2005 Tower Technologies
|
||||
* Author: Alessandro Zummo <a.zummo@towertech.it>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
@@ -33,7 +30,7 @@ static int __init rtc_hctosys(void)
|
||||
};
|
||||
struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
|
||||
|
||||
if (rtc == NULL) {
|
||||
if (!rtc) {
|
||||
pr_info("unable to open rtc device (%s)\n",
|
||||
CONFIG_RTC_HCTOSYS_DEVICE);
|
||||
goto err_open;
|
||||
@@ -44,7 +41,6 @@ static int __init rtc_hctosys(void)
|
||||
dev_err(rtc->dev.parent,
|
||||
"hctosys: unable to read the hardware clock\n");
|
||||
goto err_read;
|
||||
|
||||
}
|
||||
|
||||
tv64.tv_sec = rtc_tm_to_time64(&tm);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* RTC subsystem, interface functions
|
||||
*
|
||||
@@ -5,11 +6,7 @@
|
||||
* Author: Alessandro Zummo <a.zummo@towertech.it>
|
||||
*
|
||||
* based on arch/arm/common/rtctime.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
*/
|
||||
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/sched.h>
|
||||
@@ -87,11 +84,12 @@ static int rtc_valid_range(struct rtc_device *rtc, struct rtc_time *tm)
|
||||
static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
|
||||
{
|
||||
int err;
|
||||
if (!rtc->ops)
|
||||
|
||||
if (!rtc->ops) {
|
||||
err = -ENODEV;
|
||||
else if (!rtc->ops->read_time)
|
||||
} else if (!rtc->ops->read_time) {
|
||||
err = -EINVAL;
|
||||
else {
|
||||
} else {
|
||||
memset(tm, 0, sizeof(struct rtc_time));
|
||||
err = rtc->ops->read_time(rtc->dev.parent, tm);
|
||||
if (err < 0) {
|
||||
@@ -147,14 +145,7 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
|
||||
err = -ENODEV;
|
||||
else if (rtc->ops->set_time)
|
||||
err = rtc->ops->set_time(rtc->dev.parent, tm);
|
||||
else if (rtc->ops->set_mmss64) {
|
||||
time64_t secs64 = rtc_tm_to_time64(tm);
|
||||
|
||||
err = rtc->ops->set_mmss64(rtc->dev.parent, secs64);
|
||||
} else if (rtc->ops->set_mmss) {
|
||||
time64_t secs64 = rtc_tm_to_time64(tm);
|
||||
err = rtc->ops->set_mmss(rtc->dev.parent, secs64);
|
||||
} else
|
||||
else
|
||||
err = -EINVAL;
|
||||
|
||||
pm_stay_awake(rtc->dev.parent);
|
||||
@@ -167,7 +158,8 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_set_time);
|
||||
|
||||
static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
static int rtc_read_alarm_internal(struct rtc_device *rtc,
|
||||
struct rtc_wkalrm *alarm)
|
||||
{
|
||||
int err;
|
||||
|
||||
@@ -175,11 +167,11 @@ static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *al
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (rtc->ops == NULL)
|
||||
if (!rtc->ops) {
|
||||
err = -ENODEV;
|
||||
else if (!rtc->ops->read_alarm)
|
||||
} else if (!rtc->ops->read_alarm) {
|
||||
err = -EINVAL;
|
||||
else {
|
||||
} else {
|
||||
alarm->enabled = 0;
|
||||
alarm->pending = 0;
|
||||
alarm->time.tm_sec = -1;
|
||||
@@ -207,7 +199,7 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
int first_time = 1;
|
||||
time64_t t_now, t_alm;
|
||||
enum { none, day, month, year } missing = none;
|
||||
unsigned days;
|
||||
unsigned int days;
|
||||
|
||||
/* The lower level RTC driver may return -1 in some fields,
|
||||
* creating invalid alarm->time values, for reasons like:
|
||||
@@ -276,10 +268,10 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
return err;
|
||||
|
||||
/* note that tm_sec is a "don't care" value here: */
|
||||
} while ( before.tm_min != now.tm_min
|
||||
|| before.tm_hour != now.tm_hour
|
||||
|| before.tm_mon != now.tm_mon
|
||||
|| before.tm_year != now.tm_year);
|
||||
} while (before.tm_min != now.tm_min ||
|
||||
before.tm_hour != now.tm_hour ||
|
||||
before.tm_mon != now.tm_mon ||
|
||||
before.tm_year != now.tm_year);
|
||||
|
||||
/* Fill in the missing alarm fields using the timestamp; we
|
||||
* know there's at least one since alarm->time is invalid.
|
||||
@@ -296,7 +288,7 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
alarm->time.tm_mday = now.tm_mday;
|
||||
missing = day;
|
||||
}
|
||||
if ((unsigned)alarm->time.tm_mon >= 12) {
|
||||
if ((unsigned int)alarm->time.tm_mon >= 12) {
|
||||
alarm->time.tm_mon = now.tm_mon;
|
||||
if (missing == none)
|
||||
missing = month;
|
||||
@@ -321,7 +313,6 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
goto done;
|
||||
|
||||
switch (missing) {
|
||||
|
||||
/* 24 hour rollover ... if it's now 10am Monday, an alarm that
|
||||
* that will trigger at 5am will do so at 5am Tuesday, which
|
||||
* could also be in the next month or year. This is a common
|
||||
@@ -341,14 +332,14 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
case month:
|
||||
dev_dbg(&rtc->dev, "alarm rollover: %s\n", "month");
|
||||
do {
|
||||
if (alarm->time.tm_mon < 11)
|
||||
if (alarm->time.tm_mon < 11) {
|
||||
alarm->time.tm_mon++;
|
||||
else {
|
||||
} else {
|
||||
alarm->time.tm_mon = 0;
|
||||
alarm->time.tm_year++;
|
||||
}
|
||||
days = rtc_month_days(alarm->time.tm_mon,
|
||||
alarm->time.tm_year);
|
||||
alarm->time.tm_year);
|
||||
} while (days < alarm->time.tm_mday);
|
||||
break;
|
||||
|
||||
@@ -357,8 +348,8 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year");
|
||||
do {
|
||||
alarm->time.tm_year++;
|
||||
} while (!is_leap_year(alarm->time.tm_year + 1900)
|
||||
&& rtc_valid_tm(&alarm->time) != 0);
|
||||
} while (!is_leap_year(alarm->time.tm_year + 1900) &&
|
||||
rtc_valid_tm(&alarm->time) != 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -369,7 +360,8 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
|
||||
done:
|
||||
if (err)
|
||||
dev_warn(&rtc->dev, "invalid alarm value: %ptR\n", &alarm->time);
|
||||
dev_warn(&rtc->dev, "invalid alarm value: %ptR\n",
|
||||
&alarm->time);
|
||||
|
||||
return err;
|
||||
}
|
||||
@@ -381,11 +373,11 @@ int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
err = mutex_lock_interruptible(&rtc->ops_lock);
|
||||
if (err)
|
||||
return err;
|
||||
if (rtc->ops == NULL)
|
||||
if (!rtc->ops) {
|
||||
err = -ENODEV;
|
||||
else if (!rtc->ops->read_alarm)
|
||||
} else if (!rtc->ops->read_alarm) {
|
||||
err = -EINVAL;
|
||||
else {
|
||||
} else {
|
||||
memset(alarm, 0, sizeof(struct rtc_wkalrm));
|
||||
alarm->enabled = rtc->aie_timer.enabled;
|
||||
alarm->time = rtc_ktime_to_tm(rtc->aie_timer.node.expires);
|
||||
@@ -494,7 +486,6 @@ int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
/* Alarm has to be enabled & in the future for us to enqueue it */
|
||||
if (alarm->enabled && (rtc_tm_to_ktime(now) <
|
||||
rtc->aie_timer.node.expires)) {
|
||||
|
||||
rtc->aie_timer.enabled = 1;
|
||||
timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node);
|
||||
trace_rtc_timer_enqueue(&rtc->aie_timer);
|
||||
@@ -506,7 +497,9 @@ EXPORT_SYMBOL_GPL(rtc_initialize_alarm);
|
||||
|
||||
int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
|
||||
{
|
||||
int err = mutex_lock_interruptible(&rtc->ops_lock);
|
||||
int err;
|
||||
|
||||
err = mutex_lock_interruptible(&rtc->ops_lock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -535,7 +528,9 @@ EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable);
|
||||
|
||||
int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
|
||||
{
|
||||
int err = mutex_lock_interruptible(&rtc->ops_lock);
|
||||
int err;
|
||||
|
||||
err = mutex_lock_interruptible(&rtc->ops_lock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -564,27 +559,25 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
|
||||
rtc->uie_rtctimer.node.expires = ktime_add(now, onesec);
|
||||
rtc->uie_rtctimer.period = ktime_set(1, 0);
|
||||
err = rtc_timer_enqueue(rtc, &rtc->uie_rtctimer);
|
||||
} else
|
||||
} else {
|
||||
rtc_timer_remove(rtc, &rtc->uie_rtctimer);
|
||||
}
|
||||
|
||||
out:
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
|
||||
/*
|
||||
* Enable emulation if the driver did not provide
|
||||
* the update_irq_enable function pointer or if returned
|
||||
* -EINVAL to signal that it has been configured without
|
||||
* interrupts or that are not available at the moment.
|
||||
* Enable emulation if the driver returned -EINVAL to signal that it has
|
||||
* been configured without interrupts or they are not available at the
|
||||
* moment.
|
||||
*/
|
||||
if (err == -EINVAL)
|
||||
err = rtc_dev_update_irq_enable_emul(rtc, enabled);
|
||||
#endif
|
||||
return err;
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
|
||||
|
||||
|
||||
/**
|
||||
* rtc_handle_legacy_irq - AIE, UIE and PIE event hook
|
||||
* @rtc: pointer to the rtc device
|
||||
@@ -599,14 +592,13 @@ void rtc_handle_legacy_irq(struct rtc_device *rtc, int num, int mode)
|
||||
|
||||
/* mark one irq of the appropriate mode */
|
||||
spin_lock_irqsave(&rtc->irq_lock, flags);
|
||||
rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF|mode);
|
||||
rtc->irq_data = (rtc->irq_data + (num << 8)) | (RTC_IRQF | mode);
|
||||
spin_unlock_irqrestore(&rtc->irq_lock, flags);
|
||||
|
||||
wake_up_interruptible(&rtc->irq_queue);
|
||||
kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* rtc_aie_update_irq - AIE mode rtctimer hook
|
||||
* @rtc: pointer to the rtc_device
|
||||
@@ -618,7 +610,6 @@ void rtc_aie_update_irq(struct rtc_device *rtc)
|
||||
rtc_handle_legacy_irq(rtc, 1, RTC_AF);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* rtc_uie_update_irq - UIE mode rtctimer hook
|
||||
* @rtc: pointer to the rtc_device
|
||||
@@ -630,7 +621,6 @@ void rtc_uie_update_irq(struct rtc_device *rtc)
|
||||
rtc_handle_legacy_irq(rtc, 1, RTC_UF);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* rtc_pie_update_irq - PIE mode hrtimer hook
|
||||
* @timer: pointer to the pie mode hrtimer
|
||||
@@ -644,6 +634,7 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)
|
||||
struct rtc_device *rtc;
|
||||
ktime_t period;
|
||||
int count;
|
||||
|
||||
rtc = container_of(timer, struct rtc_device, pie_timer);
|
||||
|
||||
period = NSEC_PER_SEC / rtc->irq_freq;
|
||||
@@ -662,7 +653,7 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)
|
||||
* Context: any
|
||||
*/
|
||||
void rtc_update_irq(struct rtc_device *rtc,
|
||||
unsigned long num, unsigned long events)
|
||||
unsigned long num, unsigned long events)
|
||||
{
|
||||
if (IS_ERR_OR_NULL(rtc))
|
||||
return;
|
||||
@@ -811,6 +802,7 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
|
||||
if (!next || ktime_before(timer->node.expires, next->expires)) {
|
||||
struct rtc_wkalrm alarm;
|
||||
int err;
|
||||
|
||||
alarm.time = rtc_ktime_to_tm(timer->node.expires);
|
||||
alarm.enabled = 1;
|
||||
err = __rtc_set_alarm(rtc, &alarm);
|
||||
@@ -851,12 +843,14 @@ static void rtc_alarm_disable(struct rtc_device *rtc)
|
||||
static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
|
||||
{
|
||||
struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
|
||||
|
||||
timerqueue_del(&rtc->timerqueue, &timer->node);
|
||||
trace_rtc_timer_dequeue(timer);
|
||||
timer->enabled = 0;
|
||||
if (next == &timer->node) {
|
||||
struct rtc_wkalrm alarm;
|
||||
int err;
|
||||
|
||||
next = timerqueue_getnext(&rtc->timerqueue);
|
||||
if (!next) {
|
||||
rtc_alarm_disable(rtc);
|
||||
@@ -929,9 +923,9 @@ again:
|
||||
alarm.enabled = 1;
|
||||
reprogram:
|
||||
err = __rtc_set_alarm(rtc, &alarm);
|
||||
if (err == -ETIME)
|
||||
if (err == -ETIME) {
|
||||
goto again;
|
||||
else if (err) {
|
||||
} else if (err) {
|
||||
if (retry-- > 0)
|
||||
goto reprogram;
|
||||
|
||||
@@ -942,14 +936,14 @@ reprogram:
|
||||
dev_err(&rtc->dev, "__rtc_set_alarm: err=%d\n", err);
|
||||
goto again;
|
||||
}
|
||||
} else
|
||||
} else {
|
||||
rtc_alarm_disable(rtc);
|
||||
}
|
||||
|
||||
pm_relax(rtc->dev.parent);
|
||||
mutex_unlock(&rtc->ops_lock);
|
||||
}
|
||||
|
||||
|
||||
/* rtc_timer_init - Initializes an rtc_timer
|
||||
* @timer: timer to be intiialized
|
||||
* @f: function pointer to be called when timer fires
|
||||
@@ -975,9 +969,10 @@ void rtc_timer_init(struct rtc_timer *timer, void (*f)(struct rtc_device *r),
|
||||
* Kernel interface to set an rtc_timer
|
||||
*/
|
||||
int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer,
|
||||
ktime_t expires, ktime_t period)
|
||||
ktime_t expires, ktime_t period)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&rtc->ops_lock);
|
||||
if (timer->enabled)
|
||||
rtc_timer_remove(rtc, timer);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* rtc and date/time utility functions
|
||||
*
|
||||
@@ -5,11 +6,7 @@
|
||||
* Author: Alessandro Zummo <a.zummo@towertech.it>
|
||||
*
|
||||
* based on arch/arm/common/rtctime.c and other bits
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
*/
|
||||
|
||||
#include <linux/export.h>
|
||||
#include <linux/rtc.h>
|
||||
@@ -25,7 +22,7 @@ static const unsigned short rtc_ydays[2][13] = {
|
||||
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
|
||||
};
|
||||
|
||||
#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
|
||||
#define LEAPS_THRU_END_OF(y) ((y) / 4 - (y) / 100 + (y) / 400)
|
||||
|
||||
/*
|
||||
* The number of days in the month.
|
||||
@@ -41,11 +38,10 @@ EXPORT_SYMBOL(rtc_month_days);
|
||||
*/
|
||||
int rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
|
||||
{
|
||||
return rtc_ydays[is_leap_year(year)][month] + day-1;
|
||||
return rtc_ydays[is_leap_year(year)][month] + day - 1;
|
||||
}
|
||||
EXPORT_SYMBOL(rtc_year_days);
|
||||
|
||||
|
||||
/*
|
||||
* rtc_time64_to_tm - Converts time64_t to rtc_time.
|
||||
* Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
|
||||
@@ -97,13 +93,15 @@ EXPORT_SYMBOL(rtc_time64_to_tm);
|
||||
*/
|
||||
int rtc_valid_tm(struct rtc_time *tm)
|
||||
{
|
||||
if (tm->tm_year < 70
|
||||
|| ((unsigned)tm->tm_mon) >= 12
|
||||
|| tm->tm_mday < 1
|
||||
|| tm->tm_mday > rtc_month_days(tm->tm_mon, ((unsigned)tm->tm_year + 1900))
|
||||
|| ((unsigned)tm->tm_hour) >= 24
|
||||
|| ((unsigned)tm->tm_min) >= 60
|
||||
|| ((unsigned)tm->tm_sec) >= 60)
|
||||
if (tm->tm_year < 70 ||
|
||||
tm->tm_year > (INT_MAX - 1900) ||
|
||||
((unsigned int)tm->tm_mon) >= 12 ||
|
||||
tm->tm_mday < 1 ||
|
||||
tm->tm_mday > rtc_month_days(tm->tm_mon,
|
||||
((unsigned int)tm->tm_year + 1900)) ||
|
||||
((unsigned int)tm->tm_hour) >= 24 ||
|
||||
((unsigned int)tm->tm_min) >= 60 ||
|
||||
((unsigned int)tm->tm_sec) >= 60)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
@@ -116,7 +114,7 @@ EXPORT_SYMBOL(rtc_valid_tm);
|
||||
*/
|
||||
time64_t rtc_tm_to_time64(struct rtc_time *tm)
|
||||
{
|
||||
return mktime64(((unsigned)tm->tm_year + 1900), tm->tm_mon + 1,
|
||||
return mktime64(((unsigned int)tm->tm_year + 1900), tm->tm_mon + 1,
|
||||
tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec);
|
||||
}
|
||||
EXPORT_SYMBOL(rtc_tm_to_time64);
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* RTC subsystem, nvmem interface
|
||||
*
|
||||
* Copyright (C) 2017 Alexandre Belloni
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
@@ -46,7 +43,7 @@ static int rtc_nvram_register(struct rtc_device *rtc,
|
||||
{
|
||||
int err;
|
||||
|
||||
rtc->nvram = kzalloc(sizeof(struct bin_attribute), GFP_KERNEL);
|
||||
rtc->nvram = kzalloc(sizeof(*rtc->nvram), GFP_KERNEL);
|
||||
if (!rtc->nvram)
|
||||
return -ENOMEM;
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* RTC subsystem, proc interface
|
||||
*
|
||||
@@ -5,11 +6,7 @@
|
||||
* Author: Alessandro Zummo <a.zummo@towertech.it>
|
||||
*
|
||||
* based on arch/arm/common/rtctime.c
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/rtc.h>
|
||||
@@ -60,17 +57,17 @@ static int rtc_proc_show(struct seq_file *seq, void *offset)
|
||||
seq_printf(seq, "alrm_time\t: %ptRt\n", &alrm.time);
|
||||
seq_printf(seq, "alrm_date\t: %ptRd\n", &alrm.time);
|
||||
seq_printf(seq, "alarm_IRQ\t: %s\n",
|
||||
alrm.enabled ? "yes" : "no");
|
||||
alrm.enabled ? "yes" : "no");
|
||||
seq_printf(seq, "alrm_pending\t: %s\n",
|
||||
alrm.pending ? "yes" : "no");
|
||||
alrm.pending ? "yes" : "no");
|
||||
seq_printf(seq, "update IRQ enabled\t: %s\n",
|
||||
(rtc->uie_rtctimer.enabled) ? "yes" : "no");
|
||||
(rtc->uie_rtctimer.enabled) ? "yes" : "no");
|
||||
seq_printf(seq, "periodic IRQ enabled\t: %s\n",
|
||||
(rtc->pie_enabled) ? "yes" : "no");
|
||||
(rtc->pie_enabled) ? "yes" : "no");
|
||||
seq_printf(seq, "periodic IRQ frequency\t: %d\n",
|
||||
rtc->irq_freq);
|
||||
rtc->irq_freq);
|
||||
seq_printf(seq, "max user IRQ frequency\t: %d\n",
|
||||
rtc->max_user_freq);
|
||||
rtc->max_user_freq);
|
||||
}
|
||||
|
||||
seq_printf(seq, "24hr\t\t: yes\n");
|
||||
@@ -85,7 +82,7 @@ void rtc_proc_add_device(struct rtc_device *rtc)
|
||||
{
|
||||
if (is_rtc_hctosys(rtc))
|
||||
proc_create_single_data("driver/rtc", 0, NULL, rtc_proc_show,
|
||||
rtc);
|
||||
rtc);
|
||||
}
|
||||
|
||||
void rtc_proc_del_device(struct rtc_device *rtc)
|
||||
|
||||
@@ -1,22 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Real Time Clock driver for Marvell 88PM80x PMIC
|
||||
*
|
||||
* Copyright (c) 2012 Marvell International Ltd.
|
||||
* Wenzeng Chen<wzch@marvell.com>
|
||||
* Qiao Zhou <zhouqiao@marvell.com>
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General
|
||||
* Public License. See the file "COPYING" in the main directory of this
|
||||
* archive for more details.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
@@ -421,7 +421,7 @@ static int pm860x_rtc_remove(struct platform_device *pdev)
|
||||
struct pm860x_rtc_info *info = platform_get_drvdata(pdev);
|
||||
|
||||
#ifdef VRTC_CALIBRATION
|
||||
flush_scheduled_work();
|
||||
cancel_delayed_work_sync(&info->calib_work);
|
||||
/* disable measurement */
|
||||
pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0);
|
||||
#endif /* VRTC_CALIBRATION */
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* rtc-ab-b5ze-s3 - Driver for Abracon AB-RTCMC-32.768Khz-B5ZE-S3
|
||||
* I2C RTC / Alarm chip
|
||||
@@ -10,19 +11,9 @@
|
||||
*
|
||||
* This work is based on ISL12057 driver (drivers/rtc/rtc-isl12057.c).
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/bcd.h>
|
||||
@@ -128,7 +119,6 @@
|
||||
struct abb5zes3_rtc_data {
|
||||
struct rtc_device *rtc;
|
||||
struct regmap *regmap;
|
||||
struct mutex lock;
|
||||
|
||||
int irq;
|
||||
|
||||
@@ -138,8 +128,7 @@ struct abb5zes3_rtc_data {
|
||||
|
||||
/*
|
||||
* Try and match register bits w/ fixed null values to see whether we
|
||||
* are dealing with an ABB5ZES3. Note: this function is called early
|
||||
* during init and hence does need mutex protection.
|
||||
* are dealing with an ABB5ZES3.
|
||||
*/
|
||||
static int abb5zes3_i2c_validate_chip(struct regmap *regmap)
|
||||
{
|
||||
@@ -230,14 +219,12 @@ static int _abb5zes3_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: reading RTC time failed (%d)\n",
|
||||
__func__, ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* If clock integrity is not guaranteed, do not return a time value */
|
||||
if (regs[ABB5ZES3_REG_RTC_SC] & ABB5ZES3_REG_RTC_SC_OSC) {
|
||||
ret = -ENODATA;
|
||||
goto err;
|
||||
}
|
||||
if (regs[ABB5ZES3_REG_RTC_SC] & ABB5ZES3_REG_RTC_SC_OSC)
|
||||
return -ENODATA;
|
||||
|
||||
tm->tm_sec = bcd2bin(regs[ABB5ZES3_REG_RTC_SC] & 0x7F);
|
||||
tm->tm_min = bcd2bin(regs[ABB5ZES3_REG_RTC_MN]);
|
||||
@@ -255,7 +242,6 @@ static int _abb5zes3_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
tm->tm_mon = bcd2bin(regs[ABB5ZES3_REG_RTC_MO]) - 1; /* starts at 1 */
|
||||
tm->tm_year = bcd2bin(regs[ABB5ZES3_REG_RTC_YR]) + 100;
|
||||
|
||||
err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -273,12 +259,9 @@ static int abb5zes3_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
regs[ABB5ZES3_REG_RTC_MO] = bin2bcd(tm->tm_mon + 1);
|
||||
regs[ABB5ZES3_REG_RTC_YR] = bin2bcd(tm->tm_year - 100);
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = regmap_bulk_write(data->regmap, ABB5ZES3_REG_RTC_SC,
|
||||
regs + ABB5ZES3_REG_RTC_SC,
|
||||
ABB5ZES3_RTC_SEC_LEN);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -332,38 +315,35 @@ static int _abb5zes3_rtc_read_timer(struct device *dev,
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: reading Timer A section failed (%d)\n",
|
||||
__func__, ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* get current time ... */
|
||||
ret = _abb5zes3_rtc_read_time(dev, &rtc_tm);
|
||||
if (ret)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
/* ... convert to seconds ... */
|
||||
ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
|
||||
if (ret)
|
||||
goto err;
|
||||
rtc_secs = rtc_tm_to_time64(&rtc_tm);
|
||||
|
||||
/* ... add remaining timer A time ... */
|
||||
ret = sec_from_timer_a(&timer_secs, regs[1], regs[2]);
|
||||
if (ret)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
/* ... and convert back. */
|
||||
rtc_time_to_tm(rtc_secs + timer_secs, alarm_tm);
|
||||
rtc_time64_to_tm(rtc_secs + timer_secs, alarm_tm);
|
||||
|
||||
ret = regmap_read(data->regmap, ABB5ZES3_REG_CTRL2, ®);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: reading ctrl reg failed (%d)\n",
|
||||
__func__, ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
alarm->enabled = !!(reg & ABB5ZES3_REG_CTRL2_WTAIE);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read alarm currently configured via a RTC alarm registers. */
|
||||
@@ -382,7 +362,7 @@ static int _abb5zes3_rtc_read_alarm(struct device *dev,
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: reading alarm section failed (%d)\n",
|
||||
__func__, ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
alarm_tm->tm_sec = 0;
|
||||
@@ -398,18 +378,13 @@ static int _abb5zes3_rtc_read_alarm(struct device *dev,
|
||||
*/
|
||||
ret = _abb5zes3_rtc_read_time(dev, &rtc_tm);
|
||||
if (ret)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
alarm_tm->tm_year = rtc_tm.tm_year;
|
||||
alarm_tm->tm_mon = rtc_tm.tm_mon;
|
||||
|
||||
ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = rtc_tm_to_time(alarm_tm, &alarm_secs);
|
||||
if (ret)
|
||||
goto err;
|
||||
rtc_secs = rtc_tm_to_time64(&rtc_tm);
|
||||
alarm_secs = rtc_tm_to_time64(alarm_tm);
|
||||
|
||||
if (alarm_secs < rtc_secs) {
|
||||
if (alarm_tm->tm_mon == 11) {
|
||||
@@ -424,13 +399,12 @@ static int _abb5zes3_rtc_read_alarm(struct device *dev,
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: reading ctrl reg failed (%d)\n",
|
||||
__func__, ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
alarm->enabled = !!(reg & ABB5ZES3_REG_CTRL1_AIE);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -447,12 +421,10 @@ static int abb5zes3_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
if (data->timer_alarm)
|
||||
ret = _abb5zes3_rtc_read_timer(dev, alarm);
|
||||
else
|
||||
ret = _abb5zes3_rtc_read_alarm(dev, alarm);
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -466,33 +438,25 @@ static int _abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
|
||||
struct rtc_time *alarm_tm = &alarm->time;
|
||||
unsigned long rtc_secs, alarm_secs;
|
||||
u8 regs[ABB5ZES3_ALRM_SEC_LEN];
|
||||
struct rtc_time rtc_tm;
|
||||
int ret, enable = 1;
|
||||
|
||||
ret = _abb5zes3_rtc_read_time(dev, &rtc_tm);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = rtc_tm_to_time(alarm_tm, &alarm_secs);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
/* If alarm time is before current time, disable the alarm */
|
||||
if (!alarm->enabled || alarm_secs <= rtc_secs) {
|
||||
if (!alarm->enabled) {
|
||||
enable = 0;
|
||||
} else {
|
||||
unsigned long rtc_secs, alarm_secs;
|
||||
|
||||
/*
|
||||
* Chip only support alarms up to one month in the future. Let's
|
||||
* return an error if we get something after that limit.
|
||||
* Comparison is done by incrementing rtc_tm month field by one
|
||||
* and checking alarm value is still below.
|
||||
*/
|
||||
ret = _abb5zes3_rtc_read_time(dev, &rtc_tm);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (rtc_tm.tm_mon == 11) { /* handle year wrapping */
|
||||
rtc_tm.tm_mon = 0;
|
||||
rtc_tm.tm_year += 1;
|
||||
@@ -500,15 +464,13 @@ static int _abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
rtc_tm.tm_mon += 1;
|
||||
}
|
||||
|
||||
ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
|
||||
if (ret)
|
||||
goto err;
|
||||
rtc_secs = rtc_tm_to_time64(&rtc_tm);
|
||||
alarm_secs = rtc_tm_to_time64(alarm_tm);
|
||||
|
||||
if (alarm_secs > rtc_secs) {
|
||||
dev_err(dev, "%s: alarm maximum is one month in the "
|
||||
"future (%d)\n", __func__, ret);
|
||||
ret = -EINVAL;
|
||||
goto err;
|
||||
dev_err(dev, "%s: alarm maximum is one month in the future (%d)\n",
|
||||
__func__, ret);
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -526,17 +488,14 @@ static int _abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: writing ALARM section failed (%d)\n",
|
||||
__func__, ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Record currently configured alarm is not a timer */
|
||||
data->timer_alarm = 0;
|
||||
|
||||
/* Enable or disable alarm interrupt generation */
|
||||
ret = _abb5zes3_rtc_update_alarm(dev, enable);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
return _abb5zes3_rtc_update_alarm(dev, enable);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -557,7 +516,7 @@ static int _abb5zes3_rtc_set_timer(struct device *dev, struct rtc_wkalrm *alarm,
|
||||
ABB5ZES3_TIMA_SEC_LEN);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: writing timer section failed\n", __func__);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Configure Timer A as a watchdog timer */
|
||||
@@ -570,10 +529,7 @@ static int _abb5zes3_rtc_set_timer(struct device *dev, struct rtc_wkalrm *alarm,
|
||||
data->timer_alarm = 1;
|
||||
|
||||
/* Enable or disable timer interrupt generation */
|
||||
ret = _abb5zes3_rtc_update_timer(dev, alarm->enabled);
|
||||
|
||||
err:
|
||||
return ret;
|
||||
return _abb5zes3_rtc_update_timer(dev, alarm->enabled);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -590,31 +546,25 @@ static int abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
struct rtc_time rtc_tm;
|
||||
int ret;
|
||||
|
||||
mutex_lock(&data->lock);
|
||||
ret = _abb5zes3_rtc_read_time(dev, &rtc_tm);
|
||||
if (ret)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
ret = rtc_tm_to_time(alarm_tm, &alarm_secs);
|
||||
if (ret)
|
||||
goto err;
|
||||
rtc_secs = rtc_tm_to_time64(&rtc_tm);
|
||||
alarm_secs = rtc_tm_to_time64(alarm_tm);
|
||||
|
||||
/* Let's first disable both the alarm and the timer interrupts */
|
||||
ret = _abb5zes3_rtc_update_alarm(dev, false);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: unable to disable alarm (%d)\n", __func__,
|
||||
ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
ret = _abb5zes3_rtc_update_timer(dev, false);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: unable to disable timer (%d)\n", __func__,
|
||||
ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
data->timer_alarm = 0;
|
||||
@@ -629,9 +579,6 @@ static int abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
else
|
||||
ret = _abb5zes3_rtc_set_alarm(dev, alarm);
|
||||
|
||||
err:
|
||||
mutex_unlock(&data->lock);
|
||||
|
||||
if (ret)
|
||||
dev_err(dev, "%s: unable to configure alarm (%d)\n", __func__,
|
||||
ret);
|
||||
@@ -650,8 +597,7 @@ static inline int _abb5zes3_rtc_battery_low_irq_enable(struct regmap *regmap,
|
||||
|
||||
/*
|
||||
* Check current RTC status and enable/disable what needs to be. Return 0 if
|
||||
* everything went ok and a negative value upon error. Note: this function
|
||||
* is called early during init and hence does need mutex protection.
|
||||
* everything went ok and a negative value upon error.
|
||||
*/
|
||||
static int abb5zes3_rtc_check_setup(struct device *dev)
|
||||
{
|
||||
@@ -675,8 +621,9 @@ static int abb5zes3_rtc_check_setup(struct device *dev)
|
||||
ABB5ZES3_REG_TIM_CLK_COF1 | ABB5ZES3_REG_TIM_CLK_COF2 |
|
||||
ABB5ZES3_REG_TIM_CLK_TBM | ABB5ZES3_REG_TIM_CLK_TAM);
|
||||
ret = regmap_update_bits(regmap, ABB5ZES3_REG_TIM_CLK, mask,
|
||||
ABB5ZES3_REG_TIM_CLK_COF0 | ABB5ZES3_REG_TIM_CLK_COF1 |
|
||||
ABB5ZES3_REG_TIM_CLK_COF2);
|
||||
ABB5ZES3_REG_TIM_CLK_COF0 |
|
||||
ABB5ZES3_REG_TIM_CLK_COF1 |
|
||||
ABB5ZES3_REG_TIM_CLK_COF2);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: unable to initialize clkout register (%d)\n",
|
||||
__func__, ret);
|
||||
@@ -729,9 +676,9 @@ static int abb5zes3_rtc_check_setup(struct device *dev)
|
||||
* switchover flag but not battery low flag. The latter is checked
|
||||
* later below.
|
||||
*/
|
||||
mask = (ABB5ZES3_REG_CTRL3_PM0 | ABB5ZES3_REG_CTRL3_PM1 |
|
||||
ABB5ZES3_REG_CTRL3_PM2 | ABB5ZES3_REG_CTRL3_BLIE |
|
||||
ABB5ZES3_REG_CTRL3_BSIE| ABB5ZES3_REG_CTRL3_BSF);
|
||||
mask = (ABB5ZES3_REG_CTRL3_PM0 | ABB5ZES3_REG_CTRL3_PM1 |
|
||||
ABB5ZES3_REG_CTRL3_PM2 | ABB5ZES3_REG_CTRL3_BLIE |
|
||||
ABB5ZES3_REG_CTRL3_BSIE | ABB5ZES3_REG_CTRL3_BSF);
|
||||
ret = regmap_update_bits(regmap, ABB5ZES3_REG_CTRL3, mask, 0);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "%s: unable to initialize CTRL3 register (%d)\n",
|
||||
@@ -748,10 +695,8 @@ static int abb5zes3_rtc_check_setup(struct device *dev)
|
||||
}
|
||||
|
||||
if (reg & ABB5ZES3_REG_RTC_SC_OSC) {
|
||||
dev_err(dev, "clock integrity not guaranteed. Osc. has stopped "
|
||||
"or has been interrupted.\n");
|
||||
dev_err(dev, "change battery (if not already done) and "
|
||||
"then set time to reset osc. failure flag.\n");
|
||||
dev_err(dev, "clock integrity not guaranteed. Osc. has stopped or has been interrupted.\n");
|
||||
dev_err(dev, "change battery (if not already done) and then set time to reset osc. failure flag.\n");
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -769,13 +714,12 @@ static int abb5zes3_rtc_check_setup(struct device *dev)
|
||||
|
||||
data->battery_low = reg & ABB5ZES3_REG_CTRL3_BLF;
|
||||
if (data->battery_low) {
|
||||
dev_err(dev, "RTC battery is low; please, consider "
|
||||
"changing it!\n");
|
||||
dev_err(dev, "RTC battery is low; please, consider changing it!\n");
|
||||
|
||||
ret = _abb5zes3_rtc_battery_low_irq_enable(regmap, false);
|
||||
if (ret)
|
||||
dev_err(dev, "%s: disabling battery low interrupt "
|
||||
"generation failed (%d)\n", __func__, ret);
|
||||
dev_err(dev, "%s: disabling battery low interrupt generation failed (%d)\n",
|
||||
__func__, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -788,12 +732,10 @@ static int abb5zes3_rtc_alarm_irq_enable(struct device *dev,
|
||||
int ret = 0;
|
||||
|
||||
if (rtc_data->irq) {
|
||||
mutex_lock(&rtc_data->lock);
|
||||
if (rtc_data->timer_alarm)
|
||||
ret = _abb5zes3_rtc_update_timer(dev, enable);
|
||||
else
|
||||
ret = _abb5zes3_rtc_update_alarm(dev, enable);
|
||||
mutex_unlock(&rtc_data->lock);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -885,49 +827,44 @@ static int abb5zes3_probe(struct i2c_client *client,
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
|
||||
I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK)) {
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
}
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK))
|
||||
return -ENODEV;
|
||||
|
||||
regmap = devm_regmap_init_i2c(client, &abb5zes3_rtc_regmap_config);
|
||||
if (IS_ERR(regmap)) {
|
||||
ret = PTR_ERR(regmap);
|
||||
dev_err(dev, "%s: regmap allocation failed: %d\n",
|
||||
__func__, ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = abb5zes3_i2c_validate_chip(regmap);
|
||||
if (ret)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&data->lock);
|
||||
data->regmap = regmap;
|
||||
dev_set_drvdata(dev, data);
|
||||
|
||||
ret = abb5zes3_rtc_check_setup(dev);
|
||||
if (ret)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
data->rtc = devm_rtc_allocate_device(dev);
|
||||
ret = PTR_ERR_OR_ZERO(data->rtc);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: unable to allocate RTC device (%d)\n",
|
||||
__func__, ret);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (client->irq > 0) {
|
||||
ret = devm_request_threaded_irq(dev, client->irq, NULL,
|
||||
_abb5zes3_rtc_interrupt,
|
||||
IRQF_SHARED|IRQF_ONESHOT,
|
||||
IRQF_SHARED | IRQF_ONESHOT,
|
||||
DRV_NAME, client);
|
||||
if (!ret) {
|
||||
device_init_wakeup(dev, true);
|
||||
@@ -949,8 +886,8 @@ static int abb5zes3_probe(struct i2c_client *client,
|
||||
if (!data->battery_low && data->irq) {
|
||||
ret = _abb5zes3_rtc_battery_low_irq_enable(regmap, true);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: enabling battery low interrupt "
|
||||
"generation failed (%d)\n", __func__, ret);
|
||||
dev_err(dev, "%s: enabling battery low interrupt generation failed (%d)\n",
|
||||
__func__, ret);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
@@ -958,7 +895,7 @@ static int abb5zes3_probe(struct i2c_client *client,
|
||||
ret = rtc_register_device(data->rtc);
|
||||
|
||||
err:
|
||||
if (ret && data && data->irq)
|
||||
if (ret && data->irq)
|
||||
device_init_wakeup(dev, false);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2007-2009 ST-Ericsson AB
|
||||
* License terms: GNU General Public License (GPL) version 2
|
||||
* RTC clock driver for the AB3100 Analog Baseband Chip
|
||||
* Author: Linus Walleij <linus.walleij@stericsson.com>
|
||||
*/
|
||||
@@ -43,12 +43,12 @@
|
||||
/*
|
||||
* RTC clock functions and device struct declaration
|
||||
*/
|
||||
static int ab3100_rtc_set_mmss(struct device *dev, time64_t secs)
|
||||
static int ab3100_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
u8 regs[] = {AB3100_TI0, AB3100_TI1, AB3100_TI2,
|
||||
AB3100_TI3, AB3100_TI4, AB3100_TI5};
|
||||
unsigned char buf[6];
|
||||
u64 hw_counter = secs * AB3100_RTC_CLOCK_RATE * 2;
|
||||
u64 hw_counter = rtc_tm_to_time64(tm) * AB3100_RTC_CLOCK_RATE * 2;
|
||||
int err = 0;
|
||||
int i;
|
||||
|
||||
@@ -192,7 +192,7 @@ static int ab3100_rtc_irq_enable(struct device *dev, unsigned int enabled)
|
||||
|
||||
static const struct rtc_class_ops ab3100_rtc_ops = {
|
||||
.read_time = ab3100_rtc_read_time,
|
||||
.set_mmss64 = ab3100_rtc_set_mmss,
|
||||
.set_time = ab3100_rtc_set_time,
|
||||
.read_alarm = ab3100_rtc_read_alarm,
|
||||
.set_alarm = ab3100_rtc_set_alarm,
|
||||
.alarm_irq_enable = ab3100_rtc_irq_enable,
|
||||
@@ -228,15 +228,17 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev)
|
||||
/* Ignore any error on this write */
|
||||
}
|
||||
|
||||
rtc = devm_rtc_device_register(&pdev->dev, "ab3100-rtc",
|
||||
&ab3100_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc)) {
|
||||
err = PTR_ERR(rtc);
|
||||
return err;
|
||||
}
|
||||
rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
rtc->ops = &ab3100_rtc_ops;
|
||||
/* 48bit counter at (AB3100_RTC_CLOCK_RATE * 2) */
|
||||
rtc->range_max = U32_MAX;
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
return 0;
|
||||
return rtc_register_device(rtc);
|
||||
}
|
||||
|
||||
static struct platform_driver ab3100_rtc_driver = {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* A driver for the I2C members of the Abracon AB x8xx RTC family,
|
||||
* and compatible: AB 1805 and AB 0805
|
||||
@@ -7,10 +8,6 @@
|
||||
* Author: Philippe De Muyter <phdm@macqel.be>
|
||||
* Author: Alexandre Belloni <alexandre.belloni@bootlin.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/bcd.h>
|
||||
@@ -404,7 +401,7 @@ static ssize_t autocalibration_store(struct device *dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
retval = abx80x_rtc_set_autocalibration(dev, autocalibration);
|
||||
retval = abx80x_rtc_set_autocalibration(dev->parent, autocalibration);
|
||||
|
||||
return retval ? retval : count;
|
||||
}
|
||||
@@ -414,7 +411,7 @@ static ssize_t autocalibration_show(struct device *dev,
|
||||
{
|
||||
int autocalibration = 0;
|
||||
|
||||
autocalibration = abx80x_rtc_get_autocalibration(dev);
|
||||
autocalibration = abx80x_rtc_get_autocalibration(dev->parent);
|
||||
if (autocalibration < 0) {
|
||||
dev_err(dev, "Failed to read RTC autocalibration\n");
|
||||
sprintf(buf, "0\n");
|
||||
@@ -430,7 +427,7 @@ static ssize_t oscillator_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_client *client = to_i2c_client(dev->parent);
|
||||
int retval, flags, rc_mode = 0;
|
||||
|
||||
if (strncmp(buf, "rc", 2) == 0) {
|
||||
@@ -472,7 +469,7 @@ static ssize_t oscillator_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
int rc_mode = 0;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct i2c_client *client = to_i2c_client(dev->parent);
|
||||
|
||||
rc_mode = abx80x_is_rc_mode(client);
|
||||
|
||||
@@ -592,13 +589,6 @@ static int abx80x_dt_trickle_cfg(struct device_node *np)
|
||||
return (trickle_cfg | i);
|
||||
}
|
||||
|
||||
static void rtc_calib_remove_sysfs_group(void *_dev)
|
||||
{
|
||||
struct device *dev = _dev;
|
||||
|
||||
sysfs_remove_group(&dev->kobj, &rtc_calib_attr_group);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WATCHDOG
|
||||
|
||||
static inline u8 timeout_bits(unsigned int timeout)
|
||||
@@ -851,32 +841,14 @@ static int abx80x_probe(struct i2c_client *client,
|
||||
}
|
||||
}
|
||||
|
||||
/* Export sysfs entries */
|
||||
err = sysfs_create_group(&(&client->dev)->kobj, &rtc_calib_attr_group);
|
||||
err = rtc_add_group(priv->rtc, &rtc_calib_attr_group);
|
||||
if (err) {
|
||||
dev_err(&client->dev, "Failed to create sysfs group: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = devm_add_action_or_reset(&client->dev,
|
||||
rtc_calib_remove_sysfs_group,
|
||||
&client->dev);
|
||||
if (err) {
|
||||
dev_err(&client->dev,
|
||||
"Failed to add sysfs cleanup action: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = rtc_register_device(priv->rtc);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int abx80x_remove(struct i2c_client *client)
|
||||
{
|
||||
return 0;
|
||||
return rtc_register_device(priv->rtc);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id abx80x_id[] = {
|
||||
@@ -899,7 +871,6 @@ static struct i2c_driver abx80x_driver = {
|
||||
.name = "rtc-abx80x",
|
||||
},
|
||||
.probe = abx80x_probe,
|
||||
.remove = abx80x_remove,
|
||||
.id_table = abx80x_id,
|
||||
};
|
||||
|
||||
|
||||
136
drivers/rtc/rtc-aspeed.c
Normal file
136
drivers/rtc/rtc-aspeed.c
Normal file
@@ -0,0 +1,136 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
// Copyright 2015 IBM Corp.
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
struct aspeed_rtc {
|
||||
struct rtc_device *rtc_dev;
|
||||
void __iomem *base;
|
||||
};
|
||||
|
||||
#define RTC_TIME 0x00
|
||||
#define RTC_YEAR 0x04
|
||||
#define RTC_CTRL 0x10
|
||||
|
||||
#define RTC_UNLOCK BIT(1)
|
||||
#define RTC_ENABLE BIT(0)
|
||||
|
||||
static int aspeed_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct aspeed_rtc *rtc = dev_get_drvdata(dev);
|
||||
unsigned int cent, year;
|
||||
u32 reg1, reg2;
|
||||
|
||||
if (!(readl(rtc->base + RTC_CTRL) & RTC_ENABLE)) {
|
||||
dev_dbg(dev, "%s failing as rtc disabled\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
do {
|
||||
reg2 = readl(rtc->base + RTC_YEAR);
|
||||
reg1 = readl(rtc->base + RTC_TIME);
|
||||
} while (reg2 != readl(rtc->base + RTC_YEAR));
|
||||
|
||||
tm->tm_mday = (reg1 >> 24) & 0x1f;
|
||||
tm->tm_hour = (reg1 >> 16) & 0x1f;
|
||||
tm->tm_min = (reg1 >> 8) & 0x3f;
|
||||
tm->tm_sec = (reg1 >> 0) & 0x3f;
|
||||
|
||||
cent = (reg2 >> 16) & 0x1f;
|
||||
year = (reg2 >> 8) & 0x7f;
|
||||
tm->tm_mon = ((reg2 >> 0) & 0x0f) - 1;
|
||||
tm->tm_year = year + (cent * 100) - 1900;
|
||||
|
||||
dev_dbg(dev, "%s %ptR", __func__, tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aspeed_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct aspeed_rtc *rtc = dev_get_drvdata(dev);
|
||||
u32 reg1, reg2, ctrl;
|
||||
int year, cent;
|
||||
|
||||
cent = (tm->tm_year + 1900) / 100;
|
||||
year = tm->tm_year % 100;
|
||||
|
||||
reg1 = (tm->tm_mday << 24) | (tm->tm_hour << 16) | (tm->tm_min << 8) |
|
||||
tm->tm_sec;
|
||||
|
||||
reg2 = ((cent & 0x1f) << 16) | ((year & 0x7f) << 8) |
|
||||
((tm->tm_mon + 1) & 0xf);
|
||||
|
||||
ctrl = readl(rtc->base + RTC_CTRL);
|
||||
writel(ctrl | RTC_UNLOCK, rtc->base + RTC_CTRL);
|
||||
|
||||
writel(reg1, rtc->base + RTC_TIME);
|
||||
writel(reg2, rtc->base + RTC_YEAR);
|
||||
|
||||
/* Re-lock and ensure enable is set now that a time is programmed */
|
||||
writel(ctrl | RTC_ENABLE, rtc->base + RTC_CTRL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops aspeed_rtc_ops = {
|
||||
.read_time = aspeed_rtc_read_time,
|
||||
.set_time = aspeed_rtc_set_time,
|
||||
};
|
||||
|
||||
static int aspeed_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct aspeed_rtc *rtc;
|
||||
struct resource *res;
|
||||
int ret;
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
if (!rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
rtc->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(rtc->base))
|
||||
return PTR_ERR(rtc->base);
|
||||
|
||||
rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc->rtc_dev))
|
||||
return PTR_ERR(rtc->rtc_dev);
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
rtc->rtc_dev->ops = &aspeed_rtc_ops;
|
||||
rtc->rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_1900;
|
||||
rtc->rtc_dev->range_max = 38814989399LL; /* 3199-12-31 23:59:59 */
|
||||
|
||||
ret = rtc_register_device(rtc->rtc_dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id aspeed_rtc_match[] = {
|
||||
{ .compatible = "aspeed,ast2400-rtc", },
|
||||
{ .compatible = "aspeed,ast2500-rtc", },
|
||||
{ .compatible = "aspeed,ast2600-rtc", },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, aspeed_rtc_match);
|
||||
|
||||
static struct platform_driver aspeed_rtc_driver = {
|
||||
.driver = {
|
||||
.name = "aspeed-rtc",
|
||||
.of_match_table = of_match_ptr(aspeed_rtc_match),
|
||||
},
|
||||
};
|
||||
|
||||
module_platform_driver_probe(aspeed_rtc_driver, aspeed_rtc_probe);
|
||||
|
||||
MODULE_DESCRIPTION("ASPEED RTC driver");
|
||||
MODULE_AUTHOR("Joel Stanley <joel@jms.id.au>");
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -1,14 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* "RTT as Real Time Clock" driver for AT91SAM9 SoC family
|
||||
*
|
||||
* (C) 2007 Michel Benoit
|
||||
*
|
||||
* Based on rtc-at91rm9200.c by Rick Bronson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/clk.h>
|
||||
@@ -47,21 +43,21 @@
|
||||
* registers available, likewise usable for more than "RTC" support.
|
||||
*/
|
||||
|
||||
#define AT91_RTT_MR 0x00 /* Real-time Mode Register */
|
||||
#define AT91_RTT_RTPRES (0xffff << 0) /* Real-time Timer Prescaler Value */
|
||||
#define AT91_RTT_ALMIEN (1 << 16) /* Alarm Interrupt Enable */
|
||||
#define AT91_RTT_RTTINCIEN (1 << 17) /* Real Time Timer Increment Interrupt Enable */
|
||||
#define AT91_RTT_RTTRST (1 << 18) /* Real Time Timer Restart */
|
||||
#define AT91_RTT_MR 0x00 /* Real-time Mode Register */
|
||||
#define AT91_RTT_RTPRES (0xffff << 0) /* Timer Prescaler Value */
|
||||
#define AT91_RTT_ALMIEN BIT(16) /* Alarm Interrupt Enable */
|
||||
#define AT91_RTT_RTTINCIEN BIT(17) /* Increment Interrupt Enable */
|
||||
#define AT91_RTT_RTTRST BIT(18) /* Timer Restart */
|
||||
|
||||
#define AT91_RTT_AR 0x04 /* Real-time Alarm Register */
|
||||
#define AT91_RTT_ALMV (0xffffffff) /* Alarm Value */
|
||||
#define AT91_RTT_AR 0x04 /* Real-time Alarm Register */
|
||||
#define AT91_RTT_ALMV (0xffffffff) /* Alarm Value */
|
||||
|
||||
#define AT91_RTT_VR 0x08 /* Real-time Value Register */
|
||||
#define AT91_RTT_CRTV (0xffffffff) /* Current Real-time Value */
|
||||
#define AT91_RTT_VR 0x08 /* Real-time Value Register */
|
||||
#define AT91_RTT_CRTV (0xffffffff) /* Current Real-time Value */
|
||||
|
||||
#define AT91_RTT_SR 0x0c /* Real-time Status Register */
|
||||
#define AT91_RTT_ALMS (1 << 0) /* Real-time Alarm Status */
|
||||
#define AT91_RTT_RTTINC (1 << 1) /* Real-time Timer Increment */
|
||||
#define AT91_RTT_SR 0x0c /* Real-time Status Register */
|
||||
#define AT91_RTT_ALMS BIT(0) /* Alarm Status */
|
||||
#define AT91_RTT_RTTINC BIT(1) /* Timer Increment */
|
||||
|
||||
/*
|
||||
* We store ALARM_DISABLED in ALMV to record that no alarm is set.
|
||||
@@ -69,14 +65,13 @@
|
||||
*/
|
||||
#define ALARM_DISABLED ((u32)~0)
|
||||
|
||||
|
||||
struct sam9_rtc {
|
||||
void __iomem *rtt;
|
||||
struct rtc_device *rtcdev;
|
||||
u32 imr;
|
||||
struct regmap *gpbr;
|
||||
unsigned int gpbr_offset;
|
||||
int irq;
|
||||
int irq;
|
||||
struct clk *sclk;
|
||||
bool suspended;
|
||||
unsigned long events;
|
||||
@@ -122,7 +117,7 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
|
||||
if (secs != secs2)
|
||||
secs = rtt_readl(rtc, VR);
|
||||
|
||||
rtc_time_to_tm(offset + secs, tm);
|
||||
rtc_time64_to_tm(offset + secs, tm);
|
||||
|
||||
dev_dbg(dev, "%s: %ptR\n", __func__, tm);
|
||||
|
||||
@@ -135,15 +130,12 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
|
||||
static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct sam9_rtc *rtc = dev_get_drvdata(dev);
|
||||
int err;
|
||||
u32 offset, alarm, mr;
|
||||
unsigned long secs;
|
||||
|
||||
dev_dbg(dev, "%s: %ptR\n", __func__, tm);
|
||||
|
||||
err = rtc_tm_to_time(tm, &secs);
|
||||
if (err != 0)
|
||||
return err;
|
||||
secs = rtc_tm_to_time64(tm);
|
||||
|
||||
mr = rtt_readl(rtc, MR);
|
||||
|
||||
@@ -193,7 +185,7 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
memset(alrm, 0, sizeof(*alrm));
|
||||
if (alarm != ALARM_DISABLED && offset != 0) {
|
||||
rtc_time_to_tm(offset + alarm, tm);
|
||||
rtc_time64_to_tm(offset + alarm, tm);
|
||||
|
||||
dev_dbg(dev, "%s: %ptR\n", __func__, tm);
|
||||
|
||||
@@ -211,11 +203,8 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
unsigned long secs;
|
||||
u32 offset;
|
||||
u32 mr;
|
||||
int err;
|
||||
|
||||
err = rtc_tm_to_time(tm, &secs);
|
||||
if (err != 0)
|
||||
return err;
|
||||
secs = rtc_tm_to_time64(tm);
|
||||
|
||||
offset = gpbr_readl(rtc);
|
||||
if (offset == 0) {
|
||||
@@ -263,7 +252,7 @@ static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
|
||||
u32 mr = rtt_readl(rtc, MR);
|
||||
|
||||
seq_printf(seq, "update_IRQ\t: %s\n",
|
||||
(mr & AT91_RTT_RTTINCIEN) ? "yes" : "no");
|
||||
(mr & AT91_RTT_RTTINCIEN) ? "yes" : "no");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -299,7 +288,7 @@ static void at91_rtc_flush_events(struct sam9_rtc *rtc)
|
||||
rtc->events = 0;
|
||||
|
||||
pr_debug("%s: num=%ld, events=0x%02lx\n", __func__,
|
||||
rtc->events >> 8, rtc->events & 0x000000FF);
|
||||
rtc->events >> 8, rtc->events & 0x000000FF);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -340,13 +329,6 @@ static const struct rtc_class_ops at91_rtc_ops = {
|
||||
.alarm_irq_enable = at91_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static const struct regmap_config gpbr_regmap_config = {
|
||||
.name = "gpbr",
|
||||
.reg_bits = 32,
|
||||
.val_bits = 32,
|
||||
.reg_stride = 4,
|
||||
};
|
||||
|
||||
/*
|
||||
* Initialize and install RTC driver
|
||||
*/
|
||||
@@ -357,6 +339,7 @@ static int at91_rtc_probe(struct platform_device *pdev)
|
||||
int ret, irq;
|
||||
u32 mr;
|
||||
unsigned int sclk_rate;
|
||||
struct of_phandle_args args;
|
||||
|
||||
irq = platform_get_irq(pdev, 0);
|
||||
if (irq < 0) {
|
||||
@@ -382,34 +365,14 @@ static int at91_rtc_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(rtc->rtt))
|
||||
return PTR_ERR(rtc->rtt);
|
||||
|
||||
if (!pdev->dev.of_node) {
|
||||
/*
|
||||
* TODO: Remove this code chunk when removing non DT board
|
||||
* support. Remember to remove the gpbr_regmap_config
|
||||
* variable too.
|
||||
*/
|
||||
void __iomem *gpbr;
|
||||
|
||||
r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
|
||||
gpbr = devm_ioremap_resource(&pdev->dev, r);
|
||||
if (IS_ERR(gpbr))
|
||||
return PTR_ERR(gpbr);
|
||||
|
||||
rtc->gpbr = regmap_init_mmio(NULL, gpbr,
|
||||
&gpbr_regmap_config);
|
||||
} else {
|
||||
struct of_phandle_args args;
|
||||
|
||||
ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
|
||||
"atmel,rtt-rtc-time-reg", 1, 0,
|
||||
&args);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rtc->gpbr = syscon_node_to_regmap(args.np);
|
||||
rtc->gpbr_offset = args.args[0];
|
||||
}
|
||||
ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
|
||||
"atmel,rtt-rtc-time-reg", 1, 0,
|
||||
&args);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rtc->gpbr = syscon_node_to_regmap(args.np);
|
||||
rtc->gpbr_offset = args.args[0];
|
||||
if (IS_ERR(rtc->gpbr)) {
|
||||
dev_err(&pdev->dev, "failed to retrieve gpbr regmap, aborting.\n");
|
||||
return -ENOMEM;
|
||||
@@ -444,13 +407,15 @@ static int at91_rtc_probe(struct platform_device *pdev)
|
||||
mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
|
||||
rtt_writel(rtc, MR, mr);
|
||||
|
||||
rtc->rtcdev = devm_rtc_device_register(&pdev->dev, pdev->name,
|
||||
&at91_rtc_ops, THIS_MODULE);
|
||||
rtc->rtcdev = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc->rtcdev)) {
|
||||
ret = PTR_ERR(rtc->rtcdev);
|
||||
goto err_clk;
|
||||
}
|
||||
|
||||
rtc->rtcdev->ops = &at91_rtc_ops;
|
||||
rtc->rtcdev->range_max = U32_MAX;
|
||||
|
||||
/* register irq handler after we know what name we'll use */
|
||||
ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt,
|
||||
IRQF_SHARED | IRQF_COND_SUSPEND,
|
||||
@@ -468,9 +433,9 @@ static int at91_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
if (gpbr_readl(rtc) == 0)
|
||||
dev_warn(&pdev->dev, "%s: SET TIME!\n",
|
||||
dev_name(&rtc->rtcdev->dev));
|
||||
dev_name(&rtc->rtcdev->dev));
|
||||
|
||||
return 0;
|
||||
return rtc_register_device(rtc->rtcdev);
|
||||
|
||||
err_clk:
|
||||
clk_disable_unprepare(rtc->sclk);
|
||||
@@ -528,8 +493,9 @@ static int at91_rtc_suspend(struct device *dev)
|
||||
/* don't let RTTINC cause wakeups */
|
||||
if (mr & AT91_RTT_RTTINCIEN)
|
||||
rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
|
||||
} else
|
||||
} else {
|
||||
rtt_writel(rtc, MR, mr & ~rtc->imr);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -561,13 +527,11 @@ static int at91_rtc_resume(struct device *dev)
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume);
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id at91_rtc_dt_ids[] = {
|
||||
{ .compatible = "atmel,at91sam9260-rtt" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids);
|
||||
#endif
|
||||
|
||||
static struct platform_driver at91_rtc_driver = {
|
||||
.probe = at91_rtc_probe,
|
||||
|
||||
@@ -132,7 +132,7 @@ static int brcmstb_waketmr_gettime(struct device *dev,
|
||||
|
||||
wktmr_read(timer, &now);
|
||||
|
||||
rtc_time_to_tm(now.sec, tm);
|
||||
rtc_time64_to_tm(now.sec, tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user