mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 14:42:24 +00:00
RTC for 4.18
Subsystem: - rework of the rtc-test driver which allows to test the core more thoroughly - rtc_set_alarm() now fails early when alarms are not supported Drivers: - mktime is now replaced by mktime64 - RTC range added for 88pm80x, ab-b5ze-s3, at91rm9200, brcmstb-waketimer, ds1685, ftrtc010, ls1x, mxc_v2, rx8581, sprd, st-lpc, tps6586x, tps65910 and vr41xx - Fixed a possible race condition in probe functions - pxa: fix the probe function that is broken since v4.3 - stm32: now supports stm32mp1 -----BEGIN PGP SIGNATURE----- iQIyBAABCgAdFiEEXx9Viay1+e7J/aM4AyWl4gNJNJIFAlsdkVAACgkQAyWl4gNJ NJJMfA/3YzFFxsZZdcf84e3LWMwgA12c/YNM24nlQ3S+Fo23bAerGZyKEroBAaiq HVL7j6OwYkVrGJHbqvq7J0UhI0J9Fjbtp8suj7Cj5wBKOG3wUeTkpzBiHZN42WBB PpPC97z9HRTVjxAOmWC0wbbf622ZBOZyEti3kMVh5DwER+8iNoPJWUS6nmZdOVqR PjT/c79WCT3q7n2j9t+ZjQfVOqPlqTTty3WuCpYDu3ce3W7uUO/cISc3M4HA4A5d dw6gDcd9WQcf4qZESjlci84pn4Ktha317fX5QlkaKM2ul3x33652pbH8Yv6ynZsq ZlmIyE9vSWThBWUj7R4lo9/y2IsVL5FtMRIN5bvG6ms/tPuZGeX/qAZEBgMggN+r PgFY5U+k/1WkOeSMd4OpuE9g308wzR3xGIhtuiJOa006hvHNvyMunIeMURDWjceW fh1uu1eUQqf4yKt8ceB9s38pYcPrvtEOh9006VcHMp/JJpoOjIn93jdsaxCmlUZc poDAYgH+RudVaaMZ4VvZjzlrD/diSwjh51MpBf0ImdQut4ehfZdGna4WOzddenAT 1nsVKRp/qxR0b9kolQYCpSVsJKHME4pZPEKY0f5UyCZgEy/l3SkMPVOkjXlAzZAd ZX0l857UGeVbWP5sRDTc9J1sw2QAVO2oBsSOEeK0z9kvbuz/uQ== =I5F0 -----END PGP SIGNATURE----- Merge tag 'rtc-4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux Pull RTC updates from Alexandre Belloni: "Setting the supported range from drivers for RTCs failing soon has started. A few fixes are developed along the way. Some drivers have been switched to SPDX by their maintainers. Subsystem: - rework of the rtc-test driver which allows to test the core more thoroughly - rtc_set_alarm() now fails early when alarms are not supported Drivers: - mktime() is now replaced by mktime64() - RTC range added for 88pm80x, ab-b5ze-s3, at91rm9200, brcmstb-waketimer, ds1685, ftrtc010, ls1x, mxc_v2, rx8581, sprd, st-lpc, tps6586x, tps65910 and vr41xx - fixed a possible race condition in probe functions - pxa: fix the probe function that is broken since v4.3 - stm32: now supports stm32mp1" * tag 'rtc-4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (78 commits) rtc: pxa: fix probe function rtc: cros-ec: Switch to SPDX identifier. rtc: cros-ec: Make license text and module license match. rtc: ensure rtc_set_alarm fails when alarms are not supported rtc: test: remove alarm support from the first device rtc: test: convert to devm_rtc_allocate_device rtc: ftrtc010: let the core handle range rtc: ftrtc010: handle dates after 2106 rtc: ftrtc010: switch to devm_rtc_allocate_device rtc: mrst: switch to devm functions rtc: sunxi: fix possible race condition rtc: test: remove irq sysfs file rtc: test: emulate alarms using timers rtc: test: store time as an offset to system time rtc: test: allow registering many devices rtc: test: remove useless proc info rtc: ds1685: Add range rtc: ds1685: fix possible race condition rtc: sprd: Add new RTC power down check method rtc: sun6i: Fix bit_idx value for clk_register_gate ...
This commit is contained in:
commit
1aaccb5fa0
@ -9,7 +9,7 @@ Optional properties:
|
||||
|
||||
Example:
|
||||
|
||||
rtc: nxp,rtc-pcf2123@3 {
|
||||
pcf2123: rtc@3 {
|
||||
compatible = "nxp,rtc-pcf2123"
|
||||
reg = <3>
|
||||
spi-cs-high;
|
||||
|
@ -1,23 +1,29 @@
|
||||
STM32 Real Time Clock
|
||||
|
||||
Required properties:
|
||||
- compatible: can be either "st,stm32-rtc" or "st,stm32h7-rtc", depending on
|
||||
the device is compatible with stm32(f4/f7) or stm32h7.
|
||||
- compatible: can be one of the following:
|
||||
- "st,stm32-rtc" for devices compatible with stm32(f4/f7).
|
||||
- "st,stm32h7-rtc" for devices compatible with stm32h7.
|
||||
- "st,stm32mp1-rtc" for devices compatible with stm32mp1.
|
||||
- reg: address range of rtc register set.
|
||||
- clocks: can use up to two clocks, depending on part used:
|
||||
- "rtc_ck": RTC clock source.
|
||||
It is required on stm32(f4/f7) and stm32h7.
|
||||
- "pclk": RTC APB interface clock.
|
||||
It is not present on stm32(f4/f7).
|
||||
It is required on stm32h7.
|
||||
It is required on stm32(h7/mp1).
|
||||
- clock-names: must be "rtc_ck" and "pclk".
|
||||
It is required only on stm32h7.
|
||||
It is required on stm32(h7/mp1).
|
||||
- interrupt-parent: phandle for the interrupt controller.
|
||||
- interrupts: rtc alarm interrupt.
|
||||
- st,syscfg: phandle for pwrcfg, mandatory to disable/enable backup domain
|
||||
(RTC registers) write protection.
|
||||
It is required on stm32(f4/f7/h7).
|
||||
- interrupts: rtc alarm interrupt. On stm32mp1, a second interrupt is required
|
||||
for rtc alarm wakeup interrupt.
|
||||
- st,syscfg: phandle/offset/mask triplet. The phandle to pwrcfg used to
|
||||
access control register at offset, and change the dbp (Disable Backup
|
||||
Protection) bit represented by the mask, mandatory to disable/enable backup
|
||||
domain (RTC registers) write protection.
|
||||
It is required on stm32(f4/f7/h7).
|
||||
|
||||
Optional properties (to override default rtc_ck parent clock):
|
||||
Optional properties (to override default rtc_ck parent clock on stm32(f4/f7/h7):
|
||||
- assigned-clocks: reference to the rtc_ck clock entry.
|
||||
- assigned-clock-parents: phandle of the new parent clock of rtc_ck.
|
||||
|
||||
@ -31,7 +37,7 @@ Example:
|
||||
assigned-clock-parents = <&rcc 1 CLK_LSE>;
|
||||
interrupt-parent = <&exti>;
|
||||
interrupts = <17 1>;
|
||||
st,syscfg = <&pwrcfg>;
|
||||
st,syscfg = <&pwrcfg 0x00 0x100>;
|
||||
};
|
||||
|
||||
rtc: rtc@58004000 {
|
||||
@ -44,5 +50,14 @@ Example:
|
||||
interrupt-parent = <&exti>;
|
||||
interrupts = <17 1>;
|
||||
interrupt-names = "alarm";
|
||||
st,syscfg = <&pwrcfg>;
|
||||
st,syscfg = <&pwrcfg 0x00 0x100>;
|
||||
};
|
||||
|
||||
rtc: rtc@5c004000 {
|
||||
compatible = "st,stm32mp1-rtc";
|
||||
reg = <0x5c004000 0x400>;
|
||||
clocks = <&rcc RTCAPB>, <&rcc RTC>;
|
||||
clock-names = "pclk", "rtc_ck";
|
||||
interrupts-extended = <&intc GIC_SPI 3 IRQ_TYPE_NONE>,
|
||||
<&exti 19 1>;
|
||||
};
|
||||
|
@ -1613,7 +1613,7 @@ config RTC_DRV_JZ4740
|
||||
If you say yes here you get support for the Ingenic JZ47xx SoCs RTC
|
||||
controllers.
|
||||
|
||||
This driver can also be buillt as a module. If so, the module
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-jz4740.
|
||||
|
||||
config RTC_DRV_LPC24XX
|
||||
|
@ -441,6 +441,11 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!rtc->ops)
|
||||
return -ENODEV;
|
||||
else if (!rtc->ops->set_alarm)
|
||||
return -EINVAL;
|
||||
|
||||
err = rtc_valid_tm(&alarm->time);
|
||||
if (err != 0)
|
||||
return err;
|
||||
|
@ -94,7 +94,7 @@ int rtc_nvmem_register(struct rtc_device *rtc,
|
||||
nvmem_config->dev = rtc->dev.parent;
|
||||
nvmem_config->owner = rtc->owner;
|
||||
rtc->nvmem = nvmem_register(nvmem_config);
|
||||
if (IS_ERR_OR_NULL(rtc->nvmem))
|
||||
if (IS_ERR(rtc->nvmem))
|
||||
return PTR_ERR(rtc->nvmem);
|
||||
|
||||
/* Register the old ABI */
|
||||
|
@ -52,10 +52,8 @@ struct pm80x_rtc_info {
|
||||
struct regmap *map;
|
||||
struct rtc_device *rtc_dev;
|
||||
struct device *dev;
|
||||
struct delayed_work calib_work;
|
||||
|
||||
int irq;
|
||||
int vrtc;
|
||||
};
|
||||
|
||||
static irqreturn_t rtc_update_handler(int irq, void *data)
|
||||
@ -100,13 +98,13 @@ static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now,
|
||||
next->tm_min = alrm->tm_min;
|
||||
next->tm_sec = alrm->tm_sec;
|
||||
|
||||
rtc_tm_to_time(now, &now_time);
|
||||
rtc_tm_to_time(next, &next_time);
|
||||
now_time = rtc_tm_to_time64(now);
|
||||
next_time = rtc_tm_to_time64(next);
|
||||
|
||||
if (next_time < now_time) {
|
||||
/* Advance one day */
|
||||
next_time += 60 * 60 * 24;
|
||||
rtc_time_to_tm(next_time, next);
|
||||
rtc_time64_to_tm(next_time, next);
|
||||
}
|
||||
}
|
||||
|
||||
@ -125,7 +123,7 @@ static int pm80x_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
ticks = base + data;
|
||||
dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
|
||||
base, data, ticks);
|
||||
rtc_time_to_tm(ticks, tm);
|
||||
rtc_time64_to_tm(ticks, tm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -134,13 +132,8 @@ static int pm80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
struct pm80x_rtc_info *info = dev_get_drvdata(dev);
|
||||
unsigned char buf[4];
|
||||
unsigned long ticks, base, data;
|
||||
if (tm->tm_year > 206) {
|
||||
dev_dbg(info->dev,
|
||||
"Set time %d out of range. Please set time between 1970 to 2106.\n",
|
||||
1900 + tm->tm_year);
|
||||
return -EINVAL;
|
||||
}
|
||||
rtc_tm_to_time(tm, &ticks);
|
||||
|
||||
ticks = rtc_tm_to_time64(tm);
|
||||
|
||||
/* load 32-bit read-only counter */
|
||||
regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4);
|
||||
@ -174,7 +167,7 @@ static int pm80x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
|
||||
base, data, ticks);
|
||||
|
||||
rtc_time_to_tm(ticks, &alrm->time);
|
||||
rtc_time64_to_tm(ticks, &alrm->time);
|
||||
regmap_read(info->map, PM800_RTC_CONTROL, &ret);
|
||||
alrm->enabled = (ret & PM800_ALARM1_EN) ? 1 : 0;
|
||||
alrm->pending = (ret & (PM800_ALARM | PM800_ALARM_WAKEUP)) ? 1 : 0;
|
||||
@ -202,11 +195,11 @@ static int pm80x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
|
||||
base, data, ticks);
|
||||
|
||||
rtc_time_to_tm(ticks, &now_tm);
|
||||
rtc_time64_to_tm(ticks, &now_tm);
|
||||
dev_dbg(info->dev, "%s, now time : %lu\n", __func__, ticks);
|
||||
rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time);
|
||||
/* get new ticks for alarm in 24 hours */
|
||||
rtc_tm_to_time(&alarm_tm, &ticks);
|
||||
ticks = rtc_tm_to_time64(&alarm_tm);
|
||||
dev_dbg(info->dev, "%s, alarm time: %lu\n", __func__, ticks);
|
||||
data = ticks - base;
|
||||
|
||||
@ -254,8 +247,6 @@ static int pm80x_rtc_probe(struct platform_device *pdev)
|
||||
struct pm80x_rtc_pdata *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct pm80x_rtc_info *info;
|
||||
struct device_node *node = pdev->dev.of_node;
|
||||
struct rtc_time tm;
|
||||
unsigned long ticks = 0;
|
||||
int ret;
|
||||
|
||||
if (!pdata && !node) {
|
||||
@ -294,6 +285,10 @@ static int pm80x_rtc_probe(struct platform_device *pdev)
|
||||
info->dev = &pdev->dev;
|
||||
dev_set_drvdata(&pdev->dev, info);
|
||||
|
||||
info->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(info->rtc_dev))
|
||||
return PTR_ERR(info->rtc_dev);
|
||||
|
||||
ret = pm80x_request_irq(chip, info->irq, rtc_update_handler,
|
||||
IRQF_ONESHOT, "rtc", info);
|
||||
if (ret < 0) {
|
||||
@ -302,30 +297,11 @@ static int pm80x_rtc_probe(struct platform_device *pdev)
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = pm80x_rtc_read_time(&pdev->dev, &tm);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to read initial time.\n");
|
||||
goto out_rtc;
|
||||
}
|
||||
if ((tm.tm_year < 70) || (tm.tm_year > 138)) {
|
||||
tm.tm_year = 70;
|
||||
tm.tm_mon = 0;
|
||||
tm.tm_mday = 1;
|
||||
tm.tm_hour = 0;
|
||||
tm.tm_min = 0;
|
||||
tm.tm_sec = 0;
|
||||
ret = pm80x_rtc_set_time(&pdev->dev, &tm);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to set initial time.\n");
|
||||
goto out_rtc;
|
||||
}
|
||||
}
|
||||
rtc_tm_to_time(&tm, &ticks);
|
||||
info->rtc_dev->ops = &pm80x_rtc_ops;
|
||||
info->rtc_dev->range_max = U32_MAX;
|
||||
|
||||
info->rtc_dev = devm_rtc_device_register(&pdev->dev, "88pm80x-rtc",
|
||||
&pm80x_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(info->rtc_dev)) {
|
||||
ret = PTR_ERR(info->rtc_dev);
|
||||
ret = rtc_register_device(info->rtc_dev);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
|
||||
goto out_rtc;
|
||||
}
|
||||
|
@ -265,15 +265,6 @@ static int abb5zes3_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
u8 regs[ABB5ZES3_REG_RTC_SC + ABB5ZES3_RTC_SEC_LEN];
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Year register is 8-bit wide and bcd-coded, i.e records values
|
||||
* between 0 and 99. tm_year is an offset from 1900 and we are
|
||||
* interested in the 2000-2099 range, so any value less than 100
|
||||
* is invalid.
|
||||
*/
|
||||
if (tm->tm_year < 100)
|
||||
return -EINVAL;
|
||||
|
||||
regs[ABB5ZES3_REG_RTC_SC] = bin2bcd(tm->tm_sec); /* MSB=0 clears OSC */
|
||||
regs[ABB5ZES3_REG_RTC_MN] = bin2bcd(tm->tm_min);
|
||||
regs[ABB5ZES3_REG_RTC_HR] = bin2bcd(tm->tm_hour); /* 24-hour format */
|
||||
@ -925,6 +916,14 @@ static int abb5zes3_probe(struct i2c_client *client,
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (client->irq > 0) {
|
||||
ret = devm_request_threaded_irq(dev, client->irq, NULL,
|
||||
_abb5zes3_rtc_interrupt,
|
||||
@ -942,14 +941,9 @@ static int abb5zes3_probe(struct i2c_client *client,
|
||||
}
|
||||
}
|
||||
|
||||
data->rtc = devm_rtc_device_register(dev, DRV_NAME, &rtc_ops,
|
||||
THIS_MODULE);
|
||||
ret = PTR_ERR_OR_ZERO(data->rtc);
|
||||
if (ret) {
|
||||
dev_err(dev, "%s: unable to register RTC device (%d)\n",
|
||||
__func__, ret);
|
||||
goto err;
|
||||
}
|
||||
data->rtc->ops = &rtc_ops;
|
||||
data->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
data->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
||||
/* Enable battery low detection interrupt if battery not already low */
|
||||
if (!data->battery_low && data->irq) {
|
||||
@ -961,6 +955,8 @@ static int abb5zes3_probe(struct i2c_client *client,
|
||||
}
|
||||
}
|
||||
|
||||
ret = rtc_register_device(data->rtc);
|
||||
|
||||
err:
|
||||
if (ret && data && data->irq)
|
||||
device_init_wakeup(dev, false);
|
||||
|
@ -440,6 +440,8 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
rtc->ops = &at91_rtc_ops;
|
||||
rtc->range_min = RTC_TIMESTAMP_BEGIN_1900;
|
||||
rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
ret = rtc_register_device(rtc);
|
||||
if (ret)
|
||||
goto err_clk;
|
||||
|
@ -48,8 +48,7 @@ static void bq4802_write_mem(struct bq4802 *p, int off, u8 val)
|
||||
|
||||
static int bq4802_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct bq4802 *p = platform_get_drvdata(pdev);
|
||||
struct bq4802 *p = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
unsigned int century;
|
||||
u8 val;
|
||||
@ -91,8 +90,7 @@ static int bq4802_read_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
static int bq4802_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct bq4802 *p = platform_get_drvdata(pdev);
|
||||
struct bq4802 *p = dev_get_drvdata(dev);
|
||||
u8 sec, min, hrs, day, mon, yrs, century, val;
|
||||
unsigned long flags;
|
||||
unsigned int year;
|
||||
|
@ -145,9 +145,6 @@ static int brcmstb_waketmr_settime(struct device *dev,
|
||||
|
||||
sec = rtc_tm_to_time64(tm);
|
||||
|
||||
if (sec > U32_MAX || sec < 0)
|
||||
return -EINVAL;
|
||||
|
||||
writel_relaxed(sec, timer->base + BRCMSTB_WKTMR_COUNTER);
|
||||
|
||||
return 0;
|
||||
@ -184,9 +181,6 @@ static int brcmstb_waketmr_setalarm(struct device *dev,
|
||||
else
|
||||
sec = 0;
|
||||
|
||||
if (sec > U32_MAX || sec < 0)
|
||||
return -EINVAL;
|
||||
|
||||
brcmstb_waketmr_set_alarm(timer, sec);
|
||||
|
||||
return 0;
|
||||
@ -229,6 +223,10 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(timer->base))
|
||||
return PTR_ERR(timer->base);
|
||||
|
||||
timer->rtc = devm_rtc_allocate_device(dev);
|
||||
if (IS_ERR(timer->rtc))
|
||||
return PTR_ERR(timer->rtc);
|
||||
|
||||
/*
|
||||
* Set wakeup capability before requesting wakeup interrupt, so we can
|
||||
* process boot-time "wakeups" (e.g., from S5 soft-off)
|
||||
@ -261,11 +259,12 @@ static int brcmstb_waketmr_probe(struct platform_device *pdev)
|
||||
timer->reboot_notifier.notifier_call = brcmstb_waketmr_reboot;
|
||||
register_reboot_notifier(&timer->reboot_notifier);
|
||||
|
||||
timer->rtc = rtc_device_register("brcmstb-waketmr", dev,
|
||||
&brcmstb_waketmr_ops, THIS_MODULE);
|
||||
if (IS_ERR(timer->rtc)) {
|
||||
timer->rtc->ops = &brcmstb_waketmr_ops;
|
||||
timer->rtc->range_max = U32_MAX;
|
||||
|
||||
ret = rtc_register_device(timer->rtc);
|
||||
if (ret) {
|
||||
dev_err(dev, "unable to register device\n");
|
||||
ret = PTR_ERR(timer->rtc);
|
||||
goto err_notifier;
|
||||
}
|
||||
|
||||
@ -288,7 +287,6 @@ static int brcmstb_waketmr_remove(struct platform_device *pdev)
|
||||
struct brcmstb_waketmr *timer = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
unregister_reboot_notifier(&timer->reboot_notifier);
|
||||
rtc_device_unregister(timer->rtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -43,11 +43,24 @@
|
||||
#include <linux/of_platform.h>
|
||||
#ifdef CONFIG_X86
|
||||
#include <asm/i8259.h>
|
||||
#include <asm/processor.h>
|
||||
#include <linux/dmi.h>
|
||||
#endif
|
||||
|
||||
/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
/*
|
||||
* Use ACPI SCI to replace HPET interrupt for RTC Alarm event
|
||||
*
|
||||
* If cleared, ACPI SCI is only used to wake up the system from suspend
|
||||
*
|
||||
* If set, ACPI SCI is used to handle UIE/AIE and system wakeup
|
||||
*/
|
||||
|
||||
static bool use_acpi_alarm;
|
||||
module_param(use_acpi_alarm, bool, 0444);
|
||||
|
||||
struct cmos_rtc {
|
||||
struct rtc_device *rtc;
|
||||
struct device *dev;
|
||||
@ -153,6 +166,12 @@ static inline int hpet_unregister_irq_handler(irq_handler_t handler)
|
||||
|
||||
#endif
|
||||
|
||||
/* Don't use HPET for RTC Alarm event if ACPI Fixed event is used */
|
||||
static int use_hpet_alarm(void)
|
||||
{
|
||||
return is_hpet_enabled() && !use_acpi_alarm;
|
||||
}
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
#ifdef RTC_PORT
|
||||
@ -298,7 +317,7 @@ static void cmos_checkintr(struct cmos_rtc *cmos, unsigned char rtc_control)
|
||||
*/
|
||||
rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
|
||||
|
||||
if (is_hpet_enabled())
|
||||
if (use_hpet_alarm())
|
||||
return;
|
||||
|
||||
rtc_intr &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
|
||||
@ -318,7 +337,13 @@ static void cmos_irq_enable(struct cmos_rtc *cmos, unsigned char mask)
|
||||
|
||||
rtc_control |= mask;
|
||||
CMOS_WRITE(rtc_control, RTC_CONTROL);
|
||||
hpet_set_rtc_irq_bit(mask);
|
||||
if (use_hpet_alarm())
|
||||
hpet_set_rtc_irq_bit(mask);
|
||||
|
||||
if ((mask & RTC_AIE) && use_acpi_alarm) {
|
||||
if (cmos->wake_on)
|
||||
cmos->wake_on(cmos->dev);
|
||||
}
|
||||
|
||||
cmos_checkintr(cmos, rtc_control);
|
||||
}
|
||||
@ -330,7 +355,13 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask)
|
||||
rtc_control = CMOS_READ(RTC_CONTROL);
|
||||
rtc_control &= ~mask;
|
||||
CMOS_WRITE(rtc_control, RTC_CONTROL);
|
||||
hpet_mask_rtc_irq_bit(mask);
|
||||
if (use_hpet_alarm())
|
||||
hpet_mask_rtc_irq_bit(mask);
|
||||
|
||||
if ((mask & RTC_AIE) && use_acpi_alarm) {
|
||||
if (cmos->wake_off)
|
||||
cmos->wake_off(cmos->dev);
|
||||
}
|
||||
|
||||
cmos_checkintr(cmos, rtc_control);
|
||||
}
|
||||
@ -448,10 +479,14 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
CMOS_WRITE(mon, cmos->mon_alrm);
|
||||
}
|
||||
|
||||
/* FIXME the HPET alarm glue currently ignores day_alrm
|
||||
* and mon_alrm ...
|
||||
*/
|
||||
hpet_set_alarm_time(t->time.tm_hour, t->time.tm_min, t->time.tm_sec);
|
||||
if (use_hpet_alarm()) {
|
||||
/*
|
||||
* FIXME the HPET alarm glue currently ignores day_alrm
|
||||
* and mon_alrm ...
|
||||
*/
|
||||
hpet_set_alarm_time(t->time.tm_hour, t->time.tm_min,
|
||||
t->time.tm_sec);
|
||||
}
|
||||
|
||||
if (t->enabled)
|
||||
cmos_irq_enable(cmos, RTC_AIE);
|
||||
@ -508,7 +543,7 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq)
|
||||
"batt_status\t: %s\n",
|
||||
(rtc_control & RTC_PIE) ? "yes" : "no",
|
||||
(rtc_control & RTC_UIE) ? "yes" : "no",
|
||||
is_hpet_enabled() ? "yes" : "no",
|
||||
use_hpet_alarm() ? "yes" : "no",
|
||||
// (rtc_control & RTC_SQWE) ? "yes" : "no",
|
||||
(rtc_control & RTC_DM_BINARY) ? "no" : "yes",
|
||||
(rtc_control & RTC_DST_EN) ? "yes" : "no",
|
||||
@ -614,7 +649,7 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
|
||||
*/
|
||||
irqstat = CMOS_READ(RTC_INTR_FLAGS);
|
||||
rtc_control = CMOS_READ(RTC_CONTROL);
|
||||
if (is_hpet_enabled())
|
||||
if (use_hpet_alarm())
|
||||
irqstat = (unsigned long)irq & 0xF0;
|
||||
|
||||
/* If we were suspended, RTC_CONTROL may not be accurate since the
|
||||
@ -633,7 +668,8 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
|
||||
cmos_rtc.suspend_ctrl &= ~RTC_AIE;
|
||||
rtc_control &= ~RTC_AIE;
|
||||
CMOS_WRITE(rtc_control, RTC_CONTROL);
|
||||
hpet_mask_rtc_irq_bit(RTC_AIE);
|
||||
if (use_hpet_alarm())
|
||||
hpet_mask_rtc_irq_bit(RTC_AIE);
|
||||
CMOS_READ(RTC_INTR_FLAGS);
|
||||
}
|
||||
spin_unlock(&rtc_lock);
|
||||
@ -762,7 +798,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
|
||||
* need to do something about other clock frequencies.
|
||||
*/
|
||||
cmos_rtc.rtc->irq_freq = 1024;
|
||||
hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq);
|
||||
if (use_hpet_alarm())
|
||||
hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq);
|
||||
CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
|
||||
}
|
||||
|
||||
@ -780,12 +817,13 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
|
||||
goto cleanup1;
|
||||
}
|
||||
|
||||
hpet_rtc_timer_init();
|
||||
if (use_hpet_alarm())
|
||||
hpet_rtc_timer_init();
|
||||
|
||||
if (is_valid_irq(rtc_irq)) {
|
||||
irq_handler_t rtc_cmos_int_handler;
|
||||
|
||||
if (is_hpet_enabled()) {
|
||||
if (use_hpet_alarm()) {
|
||||
rtc_cmos_int_handler = hpet_rtc_interrupt;
|
||||
retval = hpet_register_irq_handler(cmos_interrupt);
|
||||
if (retval) {
|
||||
@ -824,7 +862,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
|
||||
"alarms up to one day",
|
||||
cmos_rtc.century ? ", y3k" : "",
|
||||
nvmem_cfg.size,
|
||||
is_hpet_enabled() ? ", hpet irqs" : "");
|
||||
use_hpet_alarm() ? ", hpet irqs" : "");
|
||||
|
||||
return 0;
|
||||
|
||||
@ -858,7 +896,8 @@ static void cmos_do_remove(struct device *dev)
|
||||
|
||||
if (is_valid_irq(cmos->irq)) {
|
||||
free_irq(cmos->irq, cmos->rtc);
|
||||
hpet_unregister_irq_handler(cmos_interrupt);
|
||||
if (use_hpet_alarm())
|
||||
hpet_unregister_irq_handler(cmos_interrupt);
|
||||
}
|
||||
|
||||
cmos->rtc = NULL;
|
||||
@ -935,13 +974,13 @@ static int cmos_suspend(struct device *dev)
|
||||
mask = RTC_IRQMASK;
|
||||
tmp &= ~mask;
|
||||
CMOS_WRITE(tmp, RTC_CONTROL);
|
||||
hpet_mask_rtc_irq_bit(mask);
|
||||
|
||||
if (use_hpet_alarm())
|
||||
hpet_mask_rtc_irq_bit(mask);
|
||||
cmos_checkintr(cmos, tmp);
|
||||
}
|
||||
spin_unlock_irq(&rtc_lock);
|
||||
|
||||
if (tmp & RTC_AIE) {
|
||||
if ((tmp & RTC_AIE) && !use_acpi_alarm) {
|
||||
cmos->enabled_wake = 1;
|
||||
if (cmos->wake_on)
|
||||
cmos->wake_on(dev);
|
||||
@ -976,8 +1015,26 @@ static void cmos_check_wkalrm(struct device *dev)
|
||||
{
|
||||
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
||||
struct rtc_wkalrm current_alarm;
|
||||
time64_t t_now;
|
||||
time64_t t_current_expires;
|
||||
time64_t t_saved_expires;
|
||||
struct rtc_time now;
|
||||
|
||||
/* Check if we have RTC Alarm armed */
|
||||
if (!(cmos->suspend_ctrl & RTC_AIE))
|
||||
return;
|
||||
|
||||
cmos_read_time(dev, &now);
|
||||
t_now = rtc_tm_to_time64(&now);
|
||||
|
||||
/*
|
||||
* ACPI RTC wake event is cleared after resume from STR,
|
||||
* ACK the rtc irq here
|
||||
*/
|
||||
if (t_now >= cmos->alarm_expires && use_acpi_alarm) {
|
||||
cmos_interrupt(0, (void *)cmos->rtc);
|
||||
return;
|
||||
}
|
||||
|
||||
cmos_read_alarm(dev, ¤t_alarm);
|
||||
t_current_expires = rtc_tm_to_time64(¤t_alarm.time);
|
||||
@ -996,7 +1053,7 @@ static int __maybe_unused cmos_resume(struct device *dev)
|
||||
struct cmos_rtc *cmos = dev_get_drvdata(dev);
|
||||
unsigned char tmp;
|
||||
|
||||
if (cmos->enabled_wake) {
|
||||
if (cmos->enabled_wake && !use_acpi_alarm) {
|
||||
if (cmos->wake_off)
|
||||
cmos->wake_off(dev);
|
||||
else
|
||||
@ -1014,16 +1071,17 @@ static int __maybe_unused cmos_resume(struct device *dev)
|
||||
if (tmp & RTC_IRQMASK) {
|
||||
unsigned char mask;
|
||||
|
||||
if (device_may_wakeup(dev))
|
||||
if (device_may_wakeup(dev) && use_hpet_alarm())
|
||||
hpet_rtc_timer_init();
|
||||
|
||||
do {
|
||||
CMOS_WRITE(tmp, RTC_CONTROL);
|
||||
hpet_set_rtc_irq_bit(tmp & RTC_IRQMASK);
|
||||
if (use_hpet_alarm())
|
||||
hpet_set_rtc_irq_bit(tmp & RTC_IRQMASK);
|
||||
|
||||
mask = CMOS_READ(RTC_INTR_FLAGS);
|
||||
mask &= (tmp & RTC_IRQMASK) | RTC_IRQF;
|
||||
if (!is_hpet_enabled() || !is_intr(mask))
|
||||
if (!use_hpet_alarm() || !is_intr(mask))
|
||||
break;
|
||||
|
||||
/* force one-shot behavior if HPET blocked
|
||||
@ -1068,16 +1126,27 @@ static u32 rtc_handler(void *context)
|
||||
unsigned char rtc_intr;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
if (cmos_rtc.suspend_ctrl)
|
||||
rtc_control = CMOS_READ(RTC_CONTROL);
|
||||
if (rtc_control & RTC_AIE) {
|
||||
cmos_rtc.suspend_ctrl &= ~RTC_AIE;
|
||||
CMOS_WRITE(rtc_control, RTC_CONTROL);
|
||||
rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
|
||||
rtc_update_irq(cmos->rtc, 1, rtc_intr);
|
||||
|
||||
/*
|
||||
* Always update rtc irq when ACPI is used as RTC Alarm.
|
||||
* Or else, ACPI SCI is enabled during suspend/resume only,
|
||||
* update rtc irq in that case.
|
||||
*/
|
||||
if (use_acpi_alarm)
|
||||
cmos_interrupt(0, (void *)cmos->rtc);
|
||||
else {
|
||||
/* Fix me: can we use cmos_interrupt() here as well? */
|
||||
spin_lock_irqsave(&rtc_lock, flags);
|
||||
if (cmos_rtc.suspend_ctrl)
|
||||
rtc_control = CMOS_READ(RTC_CONTROL);
|
||||
if (rtc_control & RTC_AIE) {
|
||||
cmos_rtc.suspend_ctrl &= ~RTC_AIE;
|
||||
CMOS_WRITE(rtc_control, RTC_CONTROL);
|
||||
rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
|
||||
rtc_update_irq(cmos->rtc, 1, rtc_intr);
|
||||
}
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
}
|
||||
spin_unlock_irqrestore(&rtc_lock, flags);
|
||||
|
||||
pm_wakeup_hard_event(dev);
|
||||
acpi_clear_event(ACPI_EVENT_RTC);
|
||||
@ -1107,6 +1176,28 @@ static void rtc_wake_off(struct device *dev)
|
||||
acpi_disable_event(ACPI_EVENT_RTC, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
/* Enable use_acpi_alarm mode for Intel platforms no earlier than 2015 */
|
||||
static void use_acpi_alarm_quirks(void)
|
||||
{
|
||||
int year;
|
||||
|
||||
if (boot_cpu_data.x86_vendor != X86_VENDOR_INTEL)
|
||||
return;
|
||||
|
||||
if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
|
||||
return;
|
||||
|
||||
if (!is_hpet_enabled())
|
||||
return;
|
||||
|
||||
if (dmi_get_date(DMI_BIOS_DATE, &year, NULL, NULL) && year >= 2015)
|
||||
use_acpi_alarm = true;
|
||||
}
|
||||
#else
|
||||
static inline void use_acpi_alarm_quirks(void) { }
|
||||
#endif
|
||||
|
||||
/* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find
|
||||
* its device node and pass extra config data. This helps its driver use
|
||||
* capabilities that the now-obsolete mc146818 didn't have, and informs it
|
||||
@ -1119,6 +1210,8 @@ static void cmos_wake_setup(struct device *dev)
|
||||
if (acpi_disabled)
|
||||
return;
|
||||
|
||||
use_acpi_alarm_quirks();
|
||||
|
||||
rtc_wake_setup(dev);
|
||||
acpi_rtc_info.wake_on = rtc_wake_on;
|
||||
acpi_rtc_info.wake_off = rtc_wake_off;
|
||||
|
@ -1,19 +1,8 @@
|
||||
/*
|
||||
* RTC driver for Chrome OS Embedded Controller
|
||||
*
|
||||
* Copyright (c) 2017, Google, Inc
|
||||
*
|
||||
* Author: Stephen Barber <smbarber@chromium.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope 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.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
// RTC driver for ChromeOS Embedded Controller.
|
||||
//
|
||||
// Copyright (C) 2017 Google, Inc.
|
||||
// Author: Stephen Barber <smbarber@chromium.org>
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mfd/cros_ec.h>
|
||||
@ -409,5 +398,5 @@ module_platform_driver(cros_ec_rtc_driver);
|
||||
|
||||
MODULE_DESCRIPTION("RTC driver for Chrome OS ECs");
|
||||
MODULE_AUTHOR("Stephen Barber <smbarber@chromium.org>");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_ALIAS("platform:" DRV_NAME);
|
||||
|
@ -76,8 +76,7 @@ static void ds1216_switch_ds_to_clock(u8 __iomem *ioaddr)
|
||||
|
||||
static int ds1216_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ds1216_priv *priv = platform_get_drvdata(pdev);
|
||||
struct ds1216_priv *priv = dev_get_drvdata(dev);
|
||||
struct ds1216_regs regs;
|
||||
|
||||
ds1216_switch_ds_to_clock(priv->ioaddr);
|
||||
@ -104,8 +103,7 @@ static int ds1216_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
static int ds1216_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ds1216_priv *priv = platform_get_drvdata(pdev);
|
||||
struct ds1216_priv *priv = dev_get_drvdata(dev);
|
||||
struct ds1216_regs regs;
|
||||
|
||||
ds1216_switch_ds_to_clock(priv->ioaddr);
|
||||
|
@ -201,6 +201,7 @@ static const struct chip_desc chips[last_ds_type] = {
|
||||
.century_reg = DS1307_REG_HOUR,
|
||||
.century_enable_bit = DS1340_BIT_CENTURY_EN,
|
||||
.century_bit = DS1340_BIT_CENTURY,
|
||||
.do_trickle_setup = &do_trickle_setup_ds1339,
|
||||
.trickle_charger_reg = 0x08,
|
||||
},
|
||||
[ds_1341] = {
|
||||
@ -1371,6 +1372,7 @@ static void ds1307_clks_register(struct ds1307 *ds1307)
|
||||
static const struct regmap_config regmap_config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0x9,
|
||||
};
|
||||
|
||||
static int ds1307_probe(struct i2c_client *client,
|
||||
|
@ -314,8 +314,7 @@ ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
|
||||
static int
|
||||
ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
|
||||
if (pdata->irq <= 0)
|
||||
return -EINVAL;
|
||||
@ -334,8 +333,7 @@ ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
static int
|
||||
ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
|
||||
if (pdata->irq <= 0)
|
||||
return -EINVAL;
|
||||
@ -373,8 +371,7 @@ ds1511_interrupt(int irq, void *dev_id)
|
||||
|
||||
static int ds1511_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
|
||||
if (pdata->irq <= 0)
|
||||
return -EINVAL;
|
||||
|
@ -73,8 +73,7 @@ struct rtc_plat_data {
|
||||
|
||||
static int ds1553_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
void __iomem *ioaddr = pdata->ioaddr;
|
||||
u8 century;
|
||||
|
||||
@ -98,8 +97,7 @@ static int ds1553_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
static int ds1553_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
void __iomem *ioaddr = pdata->ioaddr;
|
||||
unsigned int year, month, day, hour, minute, second, week;
|
||||
unsigned int century;
|
||||
@ -155,8 +153,7 @@ static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata)
|
||||
|
||||
static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
|
||||
if (pdata->irq <= 0)
|
||||
return -EINVAL;
|
||||
@ -172,8 +169,7 @@ static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
static int ds1553_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
|
||||
if (pdata->irq <= 0)
|
||||
return -EINVAL;
|
||||
@ -208,8 +204,7 @@ static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id)
|
||||
|
||||
static int ds1553_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
|
||||
if (pdata->irq <= 0)
|
||||
return -EINVAL;
|
||||
|
@ -267,8 +267,7 @@ ds1685_rtc_get_ssn(struct ds1685_priv *rtc, u8 *ssn)
|
||||
static int
|
||||
ds1685_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
|
||||
struct ds1685_priv *rtc = dev_get_drvdata(dev);
|
||||
u8 ctrlb, century;
|
||||
u8 seconds, minutes, hours, wday, mday, month, years;
|
||||
|
||||
@ -317,8 +316,7 @@ ds1685_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
static int
|
||||
ds1685_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
|
||||
struct ds1685_priv *rtc = dev_get_drvdata(dev);
|
||||
u8 ctrlb, seconds, minutes, hours, wday, mday, month, years, century;
|
||||
|
||||
/* Fetch the time info from rtc_time. */
|
||||
@ -394,8 +392,7 @@ ds1685_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
static int
|
||||
ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
|
||||
struct ds1685_priv *rtc = dev_get_drvdata(dev);
|
||||
u8 seconds, minutes, hours, mday, ctrlb, ctrlc;
|
||||
int ret;
|
||||
|
||||
@ -453,8 +450,7 @@ ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
static int
|
||||
ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
|
||||
struct ds1685_priv *rtc = dev_get_drvdata(dev);
|
||||
u8 ctrlb, seconds, minutes, hours, mday;
|
||||
int ret;
|
||||
|
||||
@ -1119,8 +1115,7 @@ static ssize_t
|
||||
ds1685_rtc_sysfs_battery_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
|
||||
struct ds1685_priv *rtc = dev_get_drvdata(dev);
|
||||
u8 ctrld;
|
||||
|
||||
ctrld = rtc->read(rtc, RTC_CTRL_D);
|
||||
@ -1140,8 +1135,7 @@ static ssize_t
|
||||
ds1685_rtc_sysfs_auxbatt_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
|
||||
struct ds1685_priv *rtc = dev_get_drvdata(dev);
|
||||
u8 ctrl4a;
|
||||
|
||||
ds1685_rtc_switch_to_bank1(rtc);
|
||||
@ -1163,8 +1157,7 @@ static ssize_t
|
||||
ds1685_rtc_sysfs_serial_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
|
||||
struct ds1685_priv *rtc = dev_get_drvdata(dev);
|
||||
u8 ssn[8];
|
||||
|
||||
ds1685_rtc_switch_to_bank1(rtc);
|
||||
@ -2044,6 +2037,26 @@ ds1685_rtc_probe(struct platform_device *pdev)
|
||||
rtc->write(rtc, RTC_EXT_CTRL_4B,
|
||||
(rtc->read(rtc, RTC_EXT_CTRL_4B) | RTC_CTRL_4B_KSE));
|
||||
|
||||
rtc_dev = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc_dev))
|
||||
return PTR_ERR(rtc_dev);
|
||||
|
||||
rtc_dev->ops = &ds1685_rtc_ops;
|
||||
|
||||
/* Century bit is useless because leap year fails in 1900 and 2100 */
|
||||
rtc_dev->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
rtc_dev->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
||||
/* Maximum periodic rate is 8192Hz (0.122070ms). */
|
||||
rtc_dev->max_user_freq = RTC_MAX_USER_FREQ;
|
||||
|
||||
/* See if the platform doesn't support UIE. */
|
||||
if (pdata->uie_unsupported)
|
||||
rtc_dev->uie_unsupported = 1;
|
||||
rtc->uie_unsupported = pdata->uie_unsupported;
|
||||
|
||||
rtc->dev = rtc_dev;
|
||||
|
||||
/*
|
||||
* Fetch the IRQ and setup the interrupt handler.
|
||||
*
|
||||
@ -2076,32 +2089,13 @@ ds1685_rtc_probe(struct platform_device *pdev)
|
||||
/* Setup complete. */
|
||||
ds1685_rtc_switch_to_bank0(rtc);
|
||||
|
||||
/* Register the device as an RTC. */
|
||||
rtc_dev = rtc_device_register(pdev->name, &pdev->dev,
|
||||
&ds1685_rtc_ops, THIS_MODULE);
|
||||
|
||||
/* Success? */
|
||||
if (IS_ERR(rtc_dev))
|
||||
return PTR_ERR(rtc_dev);
|
||||
|
||||
/* Maximum periodic rate is 8192Hz (0.122070ms). */
|
||||
rtc_dev->max_user_freq = RTC_MAX_USER_FREQ;
|
||||
|
||||
/* See if the platform doesn't support UIE. */
|
||||
if (pdata->uie_unsupported)
|
||||
rtc_dev->uie_unsupported = 1;
|
||||
rtc->uie_unsupported = pdata->uie_unsupported;
|
||||
|
||||
rtc->dev = rtc_dev;
|
||||
|
||||
#ifdef CONFIG_SYSFS
|
||||
ret = ds1685_rtc_sysfs_register(&pdev->dev);
|
||||
if (ret)
|
||||
rtc_device_unregister(rtc->dev);
|
||||
return ret;
|
||||
#endif
|
||||
|
||||
/* Done! */
|
||||
return ret;
|
||||
return rtc_register_device(rtc_dev);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2117,8 +2111,6 @@ ds1685_rtc_remove(struct platform_device *pdev)
|
||||
ds1685_rtc_sysfs_unregister(&pdev->dev);
|
||||
#endif
|
||||
|
||||
rtc_device_unregister(rtc->dev);
|
||||
|
||||
/* Read Ctrl B and clear PIE/AIE/UIE. */
|
||||
rtc->write(rtc, RTC_CTRL_B,
|
||||
(rtc->read(rtc, RTC_CTRL_B) &
|
||||
|
@ -58,8 +58,7 @@ struct rtc_plat_data {
|
||||
|
||||
static int ds1742_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
void __iomem *ioaddr = pdata->ioaddr_rtc;
|
||||
u8 century;
|
||||
|
||||
@ -83,8 +82,7 @@ static int ds1742_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
static int ds1742_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
void __iomem *ioaddr = pdata->ioaddr_rtc;
|
||||
unsigned int year, month, day, hour, minute, second, week;
|
||||
unsigned int century;
|
||||
@ -154,8 +152,6 @@ static int ds1742_rtc_probe(struct platform_device *pdev)
|
||||
int ret = 0;
|
||||
struct nvmem_config nvmem_cfg = {
|
||||
.name = "ds1742_nvram",
|
||||
.word_size = 1,
|
||||
.stride = 1,
|
||||
.reg_read = ds1742_nvram_read,
|
||||
.reg_write = ds1742_nvram_write,
|
||||
};
|
||||
|
@ -73,8 +73,8 @@ static int ftrtc010_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct ftrtc010_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
unsigned int days, hour, min, sec;
|
||||
unsigned long offset, time;
|
||||
u32 days, hour, min, sec, offset;
|
||||
timeu64_t time;
|
||||
|
||||
sec = readl(rtc->rtc_base + FTRTC010_RTC_SECOND);
|
||||
min = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE);
|
||||
@ -84,7 +84,7 @@ static int ftrtc010_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
time = offset + days * 86400 + hour * 3600 + min * 60 + sec;
|
||||
|
||||
rtc_time_to_tm(time, tm);
|
||||
rtc_time64_to_tm(time, tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -92,13 +92,10 @@ static int ftrtc010_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
static int ftrtc010_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct ftrtc010_rtc *rtc = dev_get_drvdata(dev);
|
||||
unsigned int sec, min, hour, day;
|
||||
unsigned long offset, time;
|
||||
u32 sec, min, hour, day, offset;
|
||||
timeu64_t time;
|
||||
|
||||
if (tm->tm_year >= 2148) /* EPOCH Year + 179 */
|
||||
return -EINVAL;
|
||||
|
||||
rtc_tm_to_time(tm, &time);
|
||||
time = rtc_tm_to_time64(tm);
|
||||
|
||||
sec = readl(rtc->rtc_base + FTRTC010_RTC_SECOND);
|
||||
min = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE);
|
||||
@ -120,6 +117,7 @@ static const struct rtc_class_ops ftrtc010_rtc_ops = {
|
||||
|
||||
static int ftrtc010_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
u32 days, hour, min, sec;
|
||||
struct ftrtc010_rtc *rtc;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct resource *res;
|
||||
@ -166,14 +164,27 @@ static int ftrtc010_rtc_probe(struct platform_device *pdev)
|
||||
if (!rtc->rtc_base)
|
||||
return -ENOMEM;
|
||||
|
||||
rtc->rtc_dev = devm_rtc_allocate_device(dev);
|
||||
if (IS_ERR(rtc->rtc_dev))
|
||||
return PTR_ERR(rtc->rtc_dev);
|
||||
|
||||
rtc->rtc_dev->ops = &ftrtc010_rtc_ops;
|
||||
|
||||
sec = readl(rtc->rtc_base + FTRTC010_RTC_SECOND);
|
||||
min = readl(rtc->rtc_base + FTRTC010_RTC_MINUTE);
|
||||
hour = readl(rtc->rtc_base + FTRTC010_RTC_HOUR);
|
||||
days = readl(rtc->rtc_base + FTRTC010_RTC_DAYS);
|
||||
|
||||
rtc->rtc_dev->range_min = (u64)days * 86400 + hour * 3600 +
|
||||
min * 60 + sec;
|
||||
rtc->rtc_dev->range_max = U32_MAX + rtc->rtc_dev->range_min;
|
||||
|
||||
ret = devm_request_irq(dev, rtc->rtc_irq, ftrtc010_rtc_interrupt,
|
||||
IRQF_SHARED, pdev->name, dev);
|
||||
if (unlikely(ret))
|
||||
return ret;
|
||||
|
||||
rtc->rtc_dev = rtc_device_register(pdev->name, dev,
|
||||
&ftrtc010_rtc_ops, THIS_MODULE);
|
||||
return PTR_ERR_OR_ZERO(rtc->rtc_dev);
|
||||
return rtc_register_device(rtc->rtc_dev);
|
||||
}
|
||||
|
||||
static int ftrtc010_rtc_remove(struct platform_device *pdev)
|
||||
@ -184,7 +195,6 @@ static int ftrtc010_rtc_remove(struct platform_device *pdev)
|
||||
clk_disable_unprepare(rtc->extclk);
|
||||
if (!IS_ERR(rtc->pclk))
|
||||
clk_disable_unprepare(rtc->pclk);
|
||||
rtc_device_unregister(rtc->rtc_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -294,11 +294,10 @@ static int lpc32xx_rtc_remove(struct platform_device *pdev)
|
||||
#ifdef CONFIG_PM
|
||||
static int lpc32xx_rtc_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
|
||||
struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (rtc->irq >= 0) {
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(rtc->irq);
|
||||
else
|
||||
disable_irq_wake(rtc->irq);
|
||||
@ -309,10 +308,9 @@ static int lpc32xx_rtc_suspend(struct device *dev)
|
||||
|
||||
static int lpc32xx_rtc_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
|
||||
struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (rtc->irq >= 0 && device_may_wakeup(&pdev->dev))
|
||||
if (rtc->irq >= 0 && device_may_wakeup(dev))
|
||||
disable_irq_wake(rtc->irq);
|
||||
|
||||
return 0;
|
||||
@ -321,8 +319,7 @@ static int lpc32xx_rtc_resume(struct device *dev)
|
||||
/* Unconditionally disable the alarm */
|
||||
static int lpc32xx_rtc_freeze(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
|
||||
struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
spin_lock_irq(&rtc->lock);
|
||||
|
||||
@ -337,8 +334,7 @@ static int lpc32xx_rtc_freeze(struct device *dev)
|
||||
|
||||
static int lpc32xx_rtc_thaw(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct lpc32xx_rtc *rtc = platform_get_drvdata(pdev);
|
||||
struct lpc32xx_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (rtc->alarm_enabled) {
|
||||
spin_lock_irq(&rtc->lock);
|
||||
|
@ -87,16 +87,17 @@
|
||||
|
||||
static int ls1x_rtc_read_time(struct device *dev, struct rtc_time *rtm)
|
||||
{
|
||||
unsigned long v, t;
|
||||
unsigned long v;
|
||||
time64_t t;
|
||||
|
||||
v = readl(SYS_TOYREAD0);
|
||||
t = readl(SYS_TOYREAD1);
|
||||
|
||||
memset(rtm, 0, sizeof(struct rtc_time));
|
||||
t = mktime((t & LS1X_YEAR_MASK), ls1x_get_month(v),
|
||||
t = mktime64((t & LS1X_YEAR_MASK), ls1x_get_month(v),
|
||||
ls1x_get_day(v), ls1x_get_hour(v),
|
||||
ls1x_get_min(v), ls1x_get_sec(v));
|
||||
rtc_time_to_tm(t, rtm);
|
||||
rtc_time64_to_tm(t, rtm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -147,15 +148,13 @@ static int ls1x_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct rtc_device *rtcdev;
|
||||
unsigned long v;
|
||||
int ret;
|
||||
|
||||
v = readl(SYS_COUNTER_CNTRL);
|
||||
if (!(v & RTC_CNTR_OK)) {
|
||||
dev_err(&pdev->dev, "rtc counters not working\n");
|
||||
ret = -ENODEV;
|
||||
goto err;
|
||||
return -ENODEV;
|
||||
}
|
||||
ret = -ETIMEDOUT;
|
||||
|
||||
/* set to 1 HZ if needed */
|
||||
if (readl(SYS_TOYTRIM) != 32767) {
|
||||
v = 0x100000;
|
||||
@ -164,7 +163,7 @@ static int ls1x_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
if (!v) {
|
||||
dev_err(&pdev->dev, "time out\n");
|
||||
goto err;
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
writel(32767, SYS_TOYTRIM);
|
||||
}
|
||||
@ -172,17 +171,16 @@ static int ls1x_rtc_probe(struct platform_device *pdev)
|
||||
while (readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_TTS)
|
||||
usleep_range(1000, 3000);
|
||||
|
||||
rtcdev = devm_rtc_device_register(&pdev->dev, "ls1x-rtc",
|
||||
&ls1x_rtc_ops , THIS_MODULE);
|
||||
if (IS_ERR(rtcdev)) {
|
||||
ret = PTR_ERR(rtcdev);
|
||||
goto err;
|
||||
}
|
||||
rtcdev = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtcdev))
|
||||
return PTR_ERR(rtcdev);
|
||||
|
||||
platform_set_drvdata(pdev, rtcdev);
|
||||
return 0;
|
||||
err:
|
||||
return ret;
|
||||
rtcdev->ops = &ls1x_rtc_ops;
|
||||
rtcdev->range_min = RTC_TIMESTAMP_BEGIN_1900;
|
||||
rtcdev->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
||||
return rtc_register_device(rtcdev);
|
||||
}
|
||||
|
||||
static struct platform_driver ls1x_rtc_driver = {
|
||||
|
@ -47,8 +47,7 @@ struct m48t59_private {
|
||||
static void
|
||||
m48t59_mem_writeb(struct device *dev, u32 ofs, u8 val)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
|
||||
struct m48t59_private *m48t59 = dev_get_drvdata(dev);
|
||||
|
||||
writeb(val, m48t59->ioaddr+ofs);
|
||||
}
|
||||
@ -56,8 +55,7 @@ m48t59_mem_writeb(struct device *dev, u32 ofs, u8 val)
|
||||
static u8
|
||||
m48t59_mem_readb(struct device *dev, u32 ofs)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
|
||||
struct m48t59_private *m48t59 = dev_get_drvdata(dev);
|
||||
|
||||
return readb(m48t59->ioaddr+ofs);
|
||||
}
|
||||
@ -67,9 +65,8 @@ m48t59_mem_readb(struct device *dev, u32 ofs)
|
||||
*/
|
||||
static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
|
||||
struct m48t59_plat_data *pdata = dev_get_platdata(dev);
|
||||
struct m48t59_private *m48t59 = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
u8 val;
|
||||
|
||||
@ -110,9 +107,8 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
|
||||
struct m48t59_plat_data *pdata = dev_get_platdata(dev);
|
||||
struct m48t59_private *m48t59 = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
u8 val = 0;
|
||||
int year = tm->tm_year;
|
||||
@ -157,9 +153,8 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
*/
|
||||
static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
|
||||
struct m48t59_plat_data *pdata = dev_get_platdata(dev);
|
||||
struct m48t59_private *m48t59 = dev_get_drvdata(dev);
|
||||
struct rtc_time *tm = &alrm->time;
|
||||
unsigned long flags;
|
||||
u8 val;
|
||||
@ -204,9 +199,8 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
*/
|
||||
static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
|
||||
struct m48t59_plat_data *pdata = dev_get_platdata(dev);
|
||||
struct m48t59_private *m48t59 = dev_get_drvdata(dev);
|
||||
struct rtc_time *tm = &alrm->time;
|
||||
u8 mday, hour, min, sec;
|
||||
unsigned long flags;
|
||||
@ -265,9 +259,8 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
*/
|
||||
static int m48t59_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
|
||||
struct m48t59_plat_data *pdata = dev_get_platdata(dev);
|
||||
struct m48t59_private *m48t59 = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&m48t59->lock, flags);
|
||||
@ -282,9 +275,8 @@ static int m48t59_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
|
||||
static int m48t59_rtc_proc(struct device *dev, struct seq_file *seq)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
|
||||
struct m48t59_plat_data *pdata = dev_get_platdata(dev);
|
||||
struct m48t59_private *m48t59 = dev_get_drvdata(dev);
|
||||
unsigned long flags;
|
||||
u8 val;
|
||||
|
||||
@ -303,9 +295,8 @@ static int m48t59_rtc_proc(struct device *dev, struct seq_file *seq)
|
||||
static irqreturn_t m48t59_rtc_interrupt(int irq, void *dev_id)
|
||||
{
|
||||
struct device *dev = (struct device *)dev_id;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);
|
||||
struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
|
||||
struct m48t59_plat_data *pdata = dev_get_platdata(dev);
|
||||
struct m48t59_private *m48t59 = dev_get_drvdata(dev);
|
||||
u8 event;
|
||||
|
||||
spin_lock(&m48t59->lock);
|
||||
|
@ -45,7 +45,6 @@ struct mrst_rtc {
|
||||
struct rtc_device *rtc;
|
||||
struct device *dev;
|
||||
int irq;
|
||||
struct resource *iomem;
|
||||
|
||||
u8 enabled_wake;
|
||||
u8 suspend_ctrl;
|
||||
@ -329,24 +328,22 @@ static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem,
|
||||
if (!iomem)
|
||||
return -ENODEV;
|
||||
|
||||
iomem = request_mem_region(iomem->start, resource_size(iomem),
|
||||
driver_name);
|
||||
iomem = devm_request_mem_region(dev, iomem->start, resource_size(iomem),
|
||||
driver_name);
|
||||
if (!iomem) {
|
||||
dev_dbg(dev, "i/o mem already in use.\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
mrst_rtc.irq = rtc_irq;
|
||||
mrst_rtc.iomem = iomem;
|
||||
mrst_rtc.dev = dev;
|
||||
dev_set_drvdata(dev, &mrst_rtc);
|
||||
|
||||
mrst_rtc.rtc = rtc_device_register(driver_name, dev,
|
||||
&mrst_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(mrst_rtc.rtc)) {
|
||||
retval = PTR_ERR(mrst_rtc.rtc);
|
||||
goto cleanup0;
|
||||
}
|
||||
mrst_rtc.rtc = devm_rtc_allocate_device(dev);
|
||||
if (IS_ERR(mrst_rtc.rtc))
|
||||
return PTR_ERR(mrst_rtc.rtc);
|
||||
|
||||
mrst_rtc.rtc->ops = &mrst_rtc_ops;
|
||||
|
||||
rename_region(iomem, dev_name(&mrst_rtc.rtc->dev));
|
||||
|
||||
@ -359,23 +356,27 @@ static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem,
|
||||
dev_dbg(dev, "TODO: support more than 24-hr BCD mode\n");
|
||||
|
||||
if (rtc_irq) {
|
||||
retval = request_irq(rtc_irq, mrst_rtc_irq,
|
||||
0, dev_name(&mrst_rtc.rtc->dev),
|
||||
mrst_rtc.rtc);
|
||||
retval = devm_request_irq(dev, rtc_irq, mrst_rtc_irq,
|
||||
0, dev_name(&mrst_rtc.rtc->dev),
|
||||
mrst_rtc.rtc);
|
||||
if (retval < 0) {
|
||||
dev_dbg(dev, "IRQ %d is already in use, err %d\n",
|
||||
rtc_irq, retval);
|
||||
goto cleanup1;
|
||||
goto cleanup0;
|
||||
}
|
||||
}
|
||||
|
||||
retval = rtc_register_device(mrst_rtc.rtc);
|
||||
if (retval) {
|
||||
retval = PTR_ERR(mrst_rtc.rtc);
|
||||
goto cleanup0;
|
||||
}
|
||||
|
||||
dev_dbg(dev, "initialised\n");
|
||||
return 0;
|
||||
|
||||
cleanup1:
|
||||
rtc_device_unregister(mrst_rtc.rtc);
|
||||
cleanup0:
|
||||
mrst_rtc.dev = NULL;
|
||||
release_mem_region(iomem->start, resource_size(iomem));
|
||||
dev_err(dev, "rtc-mrst: unable to initialise\n");
|
||||
return retval;
|
||||
}
|
||||
@ -390,20 +391,10 @@ static void rtc_mrst_do_shutdown(void)
|
||||
static void rtc_mrst_do_remove(struct device *dev)
|
||||
{
|
||||
struct mrst_rtc *mrst = dev_get_drvdata(dev);
|
||||
struct resource *iomem;
|
||||
|
||||
rtc_mrst_do_shutdown();
|
||||
|
||||
if (mrst->irq)
|
||||
free_irq(mrst->irq, mrst->rtc);
|
||||
|
||||
rtc_device_unregister(mrst->rtc);
|
||||
mrst->rtc = NULL;
|
||||
|
||||
iomem = mrst->iomem;
|
||||
release_mem_region(iomem->start, resource_size(iomem));
|
||||
mrst->iomem = NULL;
|
||||
|
||||
mrst->dev = NULL;
|
||||
}
|
||||
|
||||
|
@ -176,8 +176,7 @@ static int mv_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
|
||||
static int mv_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
void __iomem *ioaddr = pdata->ioaddr;
|
||||
|
||||
if (pdata->irq < 0)
|
||||
|
@ -1,13 +1,6 @@
|
||||
/*
|
||||
* Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// Copyright 2004-2008 Freescale Semiconductor, Inc. All Rights Reserved.
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <linux/rtc.h>
|
||||
@ -109,8 +102,7 @@ static inline int is_imx1_rtc(struct rtc_plat_data *data)
|
||||
*/
|
||||
static time64_t get_alarm_or_time(struct device *dev, int time_alarm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
void __iomem *ioaddr = pdata->ioaddr;
|
||||
u32 day = 0, hr = 0, min = 0, sec = 0, hr_min = 0;
|
||||
|
||||
@ -139,8 +131,7 @@ static time64_t get_alarm_or_time(struct device *dev, int time_alarm)
|
||||
static void set_alarm_or_time(struct device *dev, int time_alarm, time64_t time)
|
||||
{
|
||||
u32 tod, day, hr, min, sec, temp;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
void __iomem *ioaddr = pdata->ioaddr;
|
||||
|
||||
day = div_s64_rem(time, 86400, &tod);
|
||||
@ -176,8 +167,7 @@ static void set_alarm_or_time(struct device *dev, int time_alarm, time64_t time)
|
||||
static void rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
|
||||
{
|
||||
time64_t time;
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
void __iomem *ioaddr = pdata->ioaddr;
|
||||
|
||||
time = rtc_tm_to_time64(alrm);
|
||||
@ -190,8 +180,7 @@ static void rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
|
||||
static void mxc_rtc_irq_enable(struct device *dev, unsigned int bit,
|
||||
unsigned int enabled)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
void __iomem *ioaddr = pdata->ioaddr;
|
||||
u32 reg;
|
||||
|
||||
@ -266,8 +255,7 @@ static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
*/
|
||||
static int mxc_rtc_set_mmss(struct device *dev, time64_t time)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
|
||||
/*
|
||||
* TTC_DAYR register is 9-bit in MX1 SoC, save time and day of year only
|
||||
@ -295,8 +283,7 @@ static int mxc_rtc_set_mmss(struct device *dev, time64_t time)
|
||||
*/
|
||||
static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
void __iomem *ioaddr = pdata->ioaddr;
|
||||
|
||||
rtc_time64_to_tm(get_alarm_or_time(dev, MXC_RTC_ALARM), &alrm->time);
|
||||
@ -310,8 +297,7 @@ static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
*/
|
||||
static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
|
||||
rtc_update_alarm(dev, &alrm->time);
|
||||
|
||||
|
@ -165,11 +165,6 @@ static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
time64_t time = rtc_tm_to_time64(tm);
|
||||
int ret;
|
||||
|
||||
if (time > U32_MAX) {
|
||||
dev_err(dev, "RTC exceeded by %llus\n", time - U32_MAX);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = mxc_rtc_lock(pdata);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -198,7 +193,7 @@ static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
rtc_time_to_tm(readl(ioaddr + SRTC_LPSAR), &alrm->time);
|
||||
rtc_time64_to_tm(readl(ioaddr + SRTC_LPSAR), &alrm->time);
|
||||
alrm->pending = !!(readl(ioaddr + SRTC_LPSR) & SRTC_LPSR_ALP);
|
||||
return mxc_rtc_unlock(pdata);
|
||||
}
|
||||
@ -248,11 +243,6 @@ static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (time > U32_MAX) {
|
||||
dev_err(dev, "Hopefully I am out of service by then :-(\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
writel((u32)time, pdata->ioaddr + SRTC_LPSAR);
|
||||
|
||||
/* clear alarm interrupt status bit */
|
||||
@ -343,6 +333,13 @@ static int mxc_rtc_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pdata->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(pdata->rtc))
|
||||
return PTR_ERR(pdata->rtc);
|
||||
|
||||
pdata->rtc->ops = &mxc_rtc_ops;
|
||||
pdata->rtc->range_max = U32_MAX;
|
||||
|
||||
clk_disable(pdata->clk);
|
||||
platform_set_drvdata(pdev, pdata);
|
||||
ret =
|
||||
@ -354,15 +351,11 @@ static int mxc_rtc_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
pdata->rtc =
|
||||
devm_rtc_device_register(&pdev->dev, pdev->name, &mxc_rtc_ops,
|
||||
THIS_MODULE);
|
||||
if (IS_ERR(pdata->rtc)) {
|
||||
ret = rtc_register_device(pdata->rtc);
|
||||
if (ret < 0)
|
||||
clk_unprepare(pdata->clk);
|
||||
return PTR_ERR(pdata->rtc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mxc_rtc_remove(struct platform_device *pdev)
|
||||
|
@ -43,8 +43,7 @@ static irqreturn_t pcap_rtc_irq(int irq, void *_pcap_rtc)
|
||||
|
||||
static int pcap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pcap_rtc *pcap_rtc = platform_get_drvdata(pdev);
|
||||
struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev);
|
||||
struct rtc_time *tm = &alrm->time;
|
||||
unsigned long secs;
|
||||
u32 tod; /* time of day, seconds since midnight */
|
||||
@ -63,8 +62,7 @@ static int pcap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
static int pcap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pcap_rtc *pcap_rtc = platform_get_drvdata(pdev);
|
||||
struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev);
|
||||
struct rtc_time *tm = &alrm->time;
|
||||
unsigned long secs;
|
||||
u32 tod, days;
|
||||
@ -82,8 +80,7 @@ static int pcap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
static int pcap_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pcap_rtc *pcap_rtc = platform_get_drvdata(pdev);
|
||||
struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev);
|
||||
unsigned long secs;
|
||||
u32 tod, days;
|
||||
|
||||
@ -100,8 +97,7 @@ static int pcap_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
static int pcap_rtc_set_mmss(struct device *dev, unsigned long secs)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pcap_rtc *pcap_rtc = platform_get_drvdata(pdev);
|
||||
struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev);
|
||||
u32 tod, days;
|
||||
|
||||
tod = secs % SEC_PER_DAY;
|
||||
@ -115,8 +111,7 @@ static int pcap_rtc_set_mmss(struct device *dev, unsigned long secs)
|
||||
|
||||
static int pcap_rtc_irq_enable(struct device *dev, int pirq, unsigned int en)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct pcap_rtc *pcap_rtc = platform_get_drvdata(pdev);
|
||||
struct pcap_rtc *pcap_rtc = dev_get_drvdata(dev);
|
||||
|
||||
if (en)
|
||||
enable_irq(pcap_to_irq(pcap_rtc->pcap, pirq));
|
||||
|
@ -363,7 +363,7 @@ static int __init pxa_rtc_probe(struct platform_device *pdev)
|
||||
sa1100_rtc->rtar = pxa_rtc->base + 0x4;
|
||||
sa1100_rtc->rttr = pxa_rtc->base + 0xc;
|
||||
ret = sa1100_rtc_init(pdev, sa1100_rtc);
|
||||
if (!ret) {
|
||||
if (ret) {
|
||||
dev_err(dev, "Unable to init SA1100 RTC sub-device\n");
|
||||
return ret;
|
||||
}
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/log2.h>
|
||||
|
||||
@ -51,52 +52,20 @@
|
||||
#define RX8581_CTRL_RESET 0x01 /* RESET bit */
|
||||
|
||||
struct rx8581 {
|
||||
struct i2c_client *client;
|
||||
struct regmap *regmap;
|
||||
struct rtc_device *rtc;
|
||||
s32 (*read_block_data)(const struct i2c_client *client, u8 command,
|
||||
u8 length, u8 *values);
|
||||
s32 (*write_block_data)(const struct i2c_client *client, u8 command,
|
||||
u8 length, const u8 *values);
|
||||
};
|
||||
|
||||
static struct i2c_driver rx8581_driver;
|
||||
|
||||
static int rx8581_read_block_data(const struct i2c_client *client, u8 command,
|
||||
u8 length, u8 *values)
|
||||
{
|
||||
s32 i, data;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
data = i2c_smbus_read_byte_data(client, command + i);
|
||||
if (data < 0)
|
||||
return data;
|
||||
values[i] = data;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
static int rx8581_write_block_data(const struct i2c_client *client, u8 command,
|
||||
u8 length, const u8 *values)
|
||||
{
|
||||
s32 i, ret;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
ret = i2c_smbus_write_byte_data(client, command + i,
|
||||
values[i]);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
/*
|
||||
* In the routines that deal directly with the rx8581 hardware, we use
|
||||
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
|
||||
*/
|
||||
static int rx8581_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
static int rx8581_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
unsigned char date[7];
|
||||
int data, err;
|
||||
unsigned int data;
|
||||
int err;
|
||||
struct rx8581 *rx8581 = i2c_get_clientdata(client);
|
||||
|
||||
/* First we ensure that the "update flag" is not set, we read the
|
||||
@ -104,45 +73,38 @@ static int rx8581_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
* has been set, we know that the time has changed during the read so
|
||||
* we repeat the whole process again.
|
||||
*/
|
||||
data = i2c_smbus_read_byte_data(client, RX8581_REG_FLAG);
|
||||
if (data < 0) {
|
||||
dev_err(&client->dev, "Unable to read device flags\n");
|
||||
return -EIO;
|
||||
err = regmap_read(rx8581->regmap, RX8581_REG_FLAG, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (data & RX8581_FLAG_VLF) {
|
||||
dev_warn(dev,
|
||||
"low voltage detected, date/time is not reliable.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
do {
|
||||
/* If update flag set, clear it */
|
||||
if (data & RX8581_FLAG_UF) {
|
||||
err = i2c_smbus_write_byte_data(client,
|
||||
RX8581_REG_FLAG, (data & ~RX8581_FLAG_UF));
|
||||
if (err != 0) {
|
||||
dev_err(&client->dev, "Unable to write device flags\n");
|
||||
return -EIO;
|
||||
}
|
||||
err = regmap_write(rx8581->regmap, RX8581_REG_FLAG,
|
||||
data & ~RX8581_FLAG_UF);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Now read time and date */
|
||||
err = rx8581->read_block_data(client, RX8581_REG_SC,
|
||||
7, date);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "Unable to read date\n");
|
||||
return -EIO;
|
||||
}
|
||||
err = regmap_bulk_read(rx8581->regmap, RX8581_REG_SC, date,
|
||||
sizeof(date));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Check flag register */
|
||||
data = i2c_smbus_read_byte_data(client, RX8581_REG_FLAG);
|
||||
if (data < 0) {
|
||||
dev_err(&client->dev, "Unable to read device flags\n");
|
||||
return -EIO;
|
||||
}
|
||||
err = regmap_read(rx8581->regmap, RX8581_REG_FLAG, &data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
} while (data & RX8581_FLAG_UF);
|
||||
|
||||
if (data & RX8581_FLAG_VLF)
|
||||
dev_info(&client->dev,
|
||||
"low voltage detected, date/time is not reliable.\n");
|
||||
|
||||
dev_dbg(&client->dev,
|
||||
"%s: raw data is sec=%02x, min=%02x, hr=%02x, "
|
||||
dev_dbg(dev, "%s: raw data is sec=%02x, min=%02x, hr=%02x, "
|
||||
"wday=%02x, mday=%02x, mon=%02x, year=%02x\n",
|
||||
__func__,
|
||||
date[0], date[1], date[2], date[3], date[4], date[5], date[6]);
|
||||
@ -153,12 +115,9 @@ static int rx8581_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
tm->tm_wday = ilog2(date[RX8581_REG_DW] & 0x7F);
|
||||
tm->tm_mday = bcd2bin(date[RX8581_REG_DM] & 0x3F);
|
||||
tm->tm_mon = bcd2bin(date[RX8581_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
|
||||
tm->tm_year = bcd2bin(date[RX8581_REG_YR]);
|
||||
if (tm->tm_year < 70)
|
||||
tm->tm_year += 100; /* assume we are in 1970...2069 */
|
||||
tm->tm_year = bcd2bin(date[RX8581_REG_YR]) + 100;
|
||||
|
||||
|
||||
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
|
||||
dev_dbg(dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
|
||||
"mday=%d, mon=%d, year=%d, wday=%d\n",
|
||||
__func__,
|
||||
tm->tm_sec, tm->tm_min, tm->tm_hour,
|
||||
@ -167,13 +126,14 @@ static int rx8581_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rx8581_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
static int rx8581_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
int data, err;
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int err;
|
||||
unsigned char buf[7];
|
||||
struct rx8581 *rx8581 = i2c_get_clientdata(client);
|
||||
|
||||
dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
|
||||
dev_dbg(dev, "%s: secs=%d, mins=%d, hours=%d, "
|
||||
"mday=%d, mon=%d, year=%d, wday=%d\n",
|
||||
__func__,
|
||||
tm->tm_sec, tm->tm_min, tm->tm_hour,
|
||||
@ -190,69 +150,30 @@ static int rx8581_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
buf[RX8581_REG_MO] = bin2bcd(tm->tm_mon + 1);
|
||||
|
||||
/* year and century */
|
||||
buf[RX8581_REG_YR] = bin2bcd(tm->tm_year % 100);
|
||||
buf[RX8581_REG_YR] = bin2bcd(tm->tm_year - 100);
|
||||
buf[RX8581_REG_DW] = (0x1 << tm->tm_wday);
|
||||
|
||||
/* Stop the clock */
|
||||
data = i2c_smbus_read_byte_data(client, RX8581_REG_CTRL);
|
||||
if (data < 0) {
|
||||
dev_err(&client->dev, "Unable to read control register\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
err = i2c_smbus_write_byte_data(client, RX8581_REG_CTRL,
|
||||
(data | RX8581_CTRL_STOP));
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "Unable to write control register\n");
|
||||
return -EIO;
|
||||
}
|
||||
err = regmap_update_bits(rx8581->regmap, RX8581_REG_CTRL,
|
||||
RX8581_CTRL_STOP, RX8581_CTRL_STOP);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* write register's data */
|
||||
err = rx8581->write_block_data(client, RX8581_REG_SC, 7, buf);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "Unable to write to date registers\n");
|
||||
return -EIO;
|
||||
}
|
||||
err = regmap_bulk_write(rx8581->regmap, RX8581_REG_SC,
|
||||
buf, sizeof(buf));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* get VLF and clear it */
|
||||
data = i2c_smbus_read_byte_data(client, RX8581_REG_FLAG);
|
||||
if (data < 0) {
|
||||
dev_err(&client->dev, "Unable to read flag register\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
err = i2c_smbus_write_byte_data(client, RX8581_REG_FLAG,
|
||||
(data & ~(RX8581_FLAG_VLF)));
|
||||
if (err != 0) {
|
||||
dev_err(&client->dev, "Unable to write flag register\n");
|
||||
return -EIO;
|
||||
}
|
||||
err = regmap_update_bits(rx8581->regmap, RX8581_REG_FLAG,
|
||||
RX8581_FLAG_VLF, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* Restart the clock */
|
||||
data = i2c_smbus_read_byte_data(client, RX8581_REG_CTRL);
|
||||
if (data < 0) {
|
||||
dev_err(&client->dev, "Unable to read control register\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
err = i2c_smbus_write_byte_data(client, RX8581_REG_CTRL,
|
||||
(data & ~(RX8581_CTRL_STOP)));
|
||||
if (err != 0) {
|
||||
dev_err(&client->dev, "Unable to write control register\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rx8581_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
return rx8581_get_datetime(to_i2c_client(dev), tm);
|
||||
}
|
||||
|
||||
static int rx8581_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
return rx8581_set_datetime(to_i2c_client(dev), tm);
|
||||
return regmap_update_bits(rx8581->regmap, RX8581_REG_CTRL,
|
||||
RX8581_CTRL_STOP, 0);
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops rx8581_rtc_ops = {
|
||||
@ -264,38 +185,35 @@ static int rx8581_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct rx8581 *rx8581;
|
||||
static const struct regmap_config config = {
|
||||
.reg_bits = 8,
|
||||
.val_bits = 8,
|
||||
.max_register = 0xf,
|
||||
};
|
||||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)
|
||||
&& !i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
|
||||
return -EIO;
|
||||
|
||||
rx8581 = devm_kzalloc(&client->dev, sizeof(struct rx8581), GFP_KERNEL);
|
||||
if (!rx8581)
|
||||
return -ENOMEM;
|
||||
|
||||
i2c_set_clientdata(client, rx8581);
|
||||
rx8581->client = client;
|
||||
|
||||
if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
|
||||
rx8581->read_block_data = i2c_smbus_read_i2c_block_data;
|
||||
rx8581->write_block_data = i2c_smbus_write_i2c_block_data;
|
||||
} else {
|
||||
rx8581->read_block_data = rx8581_read_block_data;
|
||||
rx8581->write_block_data = rx8581_write_block_data;
|
||||
}
|
||||
rx8581->regmap = devm_regmap_init_i2c(client, &config);
|
||||
if (IS_ERR(rx8581->regmap))
|
||||
return PTR_ERR(rx8581->regmap);
|
||||
|
||||
rx8581->rtc = devm_rtc_device_register(&client->dev,
|
||||
rx8581_driver.driver.name, &rx8581_rtc_ops, THIS_MODULE);
|
||||
|
||||
if (IS_ERR(rx8581->rtc)) {
|
||||
dev_err(&client->dev,
|
||||
"unable to register the class device\n");
|
||||
rx8581->rtc = devm_rtc_allocate_device(&client->dev);
|
||||
if (IS_ERR(rx8581->rtc))
|
||||
return PTR_ERR(rx8581->rtc);
|
||||
}
|
||||
|
||||
return 0;
|
||||
rx8581->rtc->ops = &rx8581_rtc_ops;
|
||||
rx8581->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
rx8581->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
rx8581->rtc->start_secs = 0;
|
||||
rx8581->rtc->set_start_time = true;
|
||||
|
||||
return rtc_register_device(rx8581->rtc);
|
||||
}
|
||||
|
||||
static const struct i2c_device_id rx8581_id[] = {
|
||||
|
@ -35,6 +35,8 @@
|
||||
#define SPRD_RTC_DAY_ALM_VALUE 0x4c
|
||||
#define SPRD_RTC_SPG_VALUE 0x50
|
||||
#define SPRD_RTC_SPG_UPD 0x54
|
||||
#define SPRD_RTC_PWR_CTRL 0x58
|
||||
#define SPRD_RTC_PWR_STS 0x5c
|
||||
#define SPRD_RTC_SEC_AUXALM_UPD 0x60
|
||||
#define SPRD_RTC_MIN_AUXALM_UPD 0x64
|
||||
#define SPRD_RTC_HOUR_AUXALM_UPD 0x68
|
||||
@ -86,7 +88,13 @@
|
||||
|
||||
/* SPG values definition for SPRD_RTC_SPG_UPD register */
|
||||
#define SPRD_RTC_POWEROFF_ALM_FLAG BIT(8)
|
||||
#define SPRD_RTC_POWER_RESET_FLAG BIT(9)
|
||||
|
||||
/* power control/status definition */
|
||||
#define SPRD_RTC_POWER_RESET_VALUE 0x96
|
||||
#define SPRD_RTC_POWER_STS_CLEAR GENMASK(7, 0)
|
||||
#define SPRD_RTC_POWER_STS_SHIFT 8
|
||||
#define SPRD_RTC_POWER_STS_VALID \
|
||||
(~SPRD_RTC_POWER_RESET_VALUE << SPRD_RTC_POWER_STS_SHIFT)
|
||||
|
||||
/* timeout of synchronizing time and alarm registers (us) */
|
||||
#define SPRD_RTC_POLL_TIMEOUT 200000
|
||||
@ -383,7 +391,6 @@ static int sprd_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct sprd_rtc *rtc = dev_get_drvdata(dev);
|
||||
time64_t secs = rtc_tm_to_time64(tm);
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = sprd_rtc_set_secs(rtc, SPRD_RTC_TIME, secs);
|
||||
@ -391,27 +398,20 @@ static int sprd_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
return ret;
|
||||
|
||||
if (!rtc->valid) {
|
||||
/*
|
||||
* Set SPRD_RTC_POWER_RESET_FLAG to indicate now RTC has valid
|
||||
* time values.
|
||||
*/
|
||||
ret = regmap_update_bits(rtc->regmap,
|
||||
rtc->base + SPRD_RTC_SPG_UPD,
|
||||
SPRD_RTC_POWER_RESET_FLAG,
|
||||
SPRD_RTC_POWER_RESET_FLAG);
|
||||
/* Clear RTC power status firstly */
|
||||
ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_PWR_CTRL,
|
||||
SPRD_RTC_POWER_STS_CLEAR);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = regmap_read_poll_timeout(rtc->regmap,
|
||||
rtc->base + SPRD_RTC_INT_RAW_STS,
|
||||
val, (val & SPRD_RTC_SPG_UPD_EN),
|
||||
SPRD_RTC_POLL_DELAY_US,
|
||||
SPRD_RTC_POLL_TIMEOUT);
|
||||
if (ret) {
|
||||
dev_err(rtc->dev, "failed to update SPG value:%d\n",
|
||||
ret);
|
||||
/*
|
||||
* Set RTC power status to indicate now RTC has valid time
|
||||
* values.
|
||||
*/
|
||||
ret = regmap_write(rtc->regmap, rtc->base + SPRD_RTC_PWR_CTRL,
|
||||
SPRD_RTC_POWER_STS_VALID);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtc->valid = true;
|
||||
}
|
||||
@ -562,15 +562,16 @@ static int sprd_rtc_check_power_down(struct sprd_rtc *rtc)
|
||||
u32 val;
|
||||
int ret;
|
||||
|
||||
ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_SPG_VALUE, &val);
|
||||
ret = regmap_read(rtc->regmap, rtc->base + SPRD_RTC_PWR_STS, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* If the SPRD_RTC_POWER_RESET_FLAG was not set, which means the RTC has
|
||||
* been powered down, so the RTC time values are invalid.
|
||||
* If the RTC power status value is SPRD_RTC_POWER_RESET_VALUE, which
|
||||
* means the RTC has been powered down, so the RTC time values are
|
||||
* invalid.
|
||||
*/
|
||||
rtc->valid = (val & SPRD_RTC_POWER_RESET_FLAG) ? true : false;
|
||||
rtc->valid = val == SPRD_RTC_POWER_RESET_VALUE ? false : true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -600,6 +601,10 @@ static int sprd_rtc_probe(struct platform_device *pdev)
|
||||
return rtc->irq;
|
||||
}
|
||||
|
||||
rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc->rtc))
|
||||
return PTR_ERR(rtc->rtc);
|
||||
|
||||
rtc->dev = &pdev->dev;
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
@ -626,10 +631,14 @@ static int sprd_rtc_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
|
||||
&sprd_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc->rtc))
|
||||
return PTR_ERR(rtc->rtc);
|
||||
rtc->rtc->ops = &sprd_rtc_ops;
|
||||
rtc->rtc->range_min = 0;
|
||||
rtc->rtc->range_max = 5662310399LL;
|
||||
ret = rtc_register_device(rtc->rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to register rtc device\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
return 0;
|
||||
|
@ -359,8 +359,7 @@ static int sh_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
|
||||
static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct sh_rtc *rtc = platform_get_drvdata(pdev);
|
||||
struct sh_rtc *rtc = dev_get_drvdata(dev);
|
||||
unsigned int sec128, sec2, yr, yr100, cf_bit;
|
||||
|
||||
do {
|
||||
@ -419,8 +418,7 @@ static int sh_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
static int sh_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct sh_rtc *rtc = platform_get_drvdata(pdev);
|
||||
struct sh_rtc *rtc = dev_get_drvdata(dev);
|
||||
unsigned int tmp;
|
||||
int year;
|
||||
|
||||
@ -475,8 +473,7 @@ static inline int sh_rtc_read_alarm_value(struct sh_rtc *rtc, int reg_off)
|
||||
|
||||
static int sh_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct sh_rtc *rtc = platform_get_drvdata(pdev);
|
||||
struct sh_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct rtc_time *tm = &wkalrm->time;
|
||||
|
||||
spin_lock_irq(&rtc->lock);
|
||||
@ -509,8 +506,7 @@ static inline void sh_rtc_write_alarm_value(struct sh_rtc *rtc,
|
||||
|
||||
static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct sh_rtc *rtc = platform_get_drvdata(pdev);
|
||||
struct sh_rtc *rtc = dev_get_drvdata(dev);
|
||||
unsigned int rcr1;
|
||||
struct rtc_time *tm = &wkalrm->time;
|
||||
int mon;
|
||||
@ -723,8 +719,7 @@ static int __exit sh_rtc_remove(struct platform_device *pdev)
|
||||
|
||||
static void sh_rtc_set_irq_wake(struct device *dev, int enabled)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct sh_rtc *rtc = platform_get_drvdata(pdev);
|
||||
struct sh_rtc *rtc = dev_get_drvdata(dev);
|
||||
|
||||
irq_set_irq_wake(rtc->periodic_irq, enabled);
|
||||
|
||||
|
@ -1,13 +1,6 @@
|
||||
/*
|
||||
* Copyright (C) 2011-2012 Freescale Semiconductor, Inc.
|
||||
*
|
||||
* The code contained herein is licensed under the GNU General Public
|
||||
* License. You may obtain a copy of the GNU General Public License
|
||||
* Version 2 or later at the following locations:
|
||||
*
|
||||
* http://www.opensource.org/licenses/gpl-license.html
|
||||
* http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
//
|
||||
// Copyright (C) 2011-2012 Freescale Semiconductor, Inc.
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -212,6 +212,10 @@ static int st_rtc_probe(struct platform_device *pdev)
|
||||
if (!rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc->rtc_dev))
|
||||
return PTR_ERR(rtc->rtc_dev);
|
||||
|
||||
spin_lock_init(&rtc->lock);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
@ -253,26 +257,19 @@ static int st_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
rtc->rtc_dev = rtc_device_register("st-lpc-rtc", &pdev->dev,
|
||||
&st_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc->rtc_dev)) {
|
||||
rtc->rtc_dev->ops = &st_rtc_ops;
|
||||
rtc->rtc_dev->range_max = U64_MAX;
|
||||
do_div(rtc->rtc_dev->range_max, rtc->clkrate);
|
||||
|
||||
ret = rtc_register_device(rtc->rtc_dev);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(rtc->clk);
|
||||
return PTR_ERR(rtc->rtc_dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int st_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct st_rtc *rtc = platform_get_drvdata(pdev);
|
||||
|
||||
if (likely(rtc->rtc_dev))
|
||||
rtc_device_unregister(rtc->rtc_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int st_rtc_suspend(struct device *dev)
|
||||
{
|
||||
@ -325,7 +322,6 @@ static struct platform_driver st_rtc_platform_driver = {
|
||||
.of_match_table = st_rtc_match,
|
||||
},
|
||||
.probe = st_rtc_probe,
|
||||
.remove = st_rtc_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(st_rtc_platform_driver);
|
||||
|
@ -74,8 +74,7 @@ struct rtc_plat_data {
|
||||
|
||||
static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
void __iomem *ioaddr = pdata->ioaddr;
|
||||
u8 flags;
|
||||
|
||||
@ -97,8 +96,7 @@ static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
|
||||
static int stk17ta8_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
void __iomem *ioaddr = pdata->ioaddr;
|
||||
unsigned int year, month, day, hour, minute, second, week;
|
||||
unsigned int century;
|
||||
@ -163,8 +161,7 @@ static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata)
|
||||
|
||||
static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
|
||||
if (pdata->irq <= 0)
|
||||
return -EINVAL;
|
||||
@ -180,8 +177,7 @@ static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
static int stk17ta8_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
|
||||
if (pdata->irq <= 0)
|
||||
return -EINVAL;
|
||||
@ -217,8 +213,7 @@ static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)
|
||||
static int stk17ta8_rtc_alarm_irq_enable(struct device *dev,
|
||||
unsigned int enabled)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
|
||||
struct rtc_plat_data *pdata = dev_get_drvdata(dev);
|
||||
|
||||
if (pdata->irq <= 0)
|
||||
return -EINVAL;
|
||||
|
@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) STMicroelectronics SA 2017
|
||||
* Author: Amelie Delaunay <amelie.delaunay@st.com> for STMicroelectronics.
|
||||
* License terms: GNU General Public License (GPL), version 2
|
||||
* Copyright (C) STMicroelectronics 2017
|
||||
* Author: Amelie Delaunay <amelie.delaunay@st.com>
|
||||
*/
|
||||
|
||||
#include <linux/bcd.h>
|
||||
@ -11,20 +11,12 @@
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_wakeirq.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#define DRIVER_NAME "stm32_rtc"
|
||||
|
||||
/* STM32 RTC registers */
|
||||
#define STM32_RTC_TR 0x00
|
||||
#define STM32_RTC_DR 0x04
|
||||
#define STM32_RTC_CR 0x08
|
||||
#define STM32_RTC_ISR 0x0C
|
||||
#define STM32_RTC_PRER 0x10
|
||||
#define STM32_RTC_ALRMAR 0x1C
|
||||
#define STM32_RTC_WPR 0x24
|
||||
|
||||
/* STM32_RTC_TR bit fields */
|
||||
#define STM32_RTC_TR_SEC_SHIFT 0
|
||||
#define STM32_RTC_TR_SEC GENMASK(6, 0)
|
||||
@ -48,7 +40,7 @@
|
||||
#define STM32_RTC_CR_ALRAE BIT(8)
|
||||
#define STM32_RTC_CR_ALRAIE BIT(12)
|
||||
|
||||
/* STM32_RTC_ISR bit fields */
|
||||
/* STM32_RTC_ISR/STM32_RTC_ICSR bit fields */
|
||||
#define STM32_RTC_ISR_ALRAWF BIT(0)
|
||||
#define STM32_RTC_ISR_INITS BIT(4)
|
||||
#define STM32_RTC_ISR_RSF BIT(5)
|
||||
@ -80,52 +72,87 @@
|
||||
#define STM32_RTC_ALRMXR_WDAY GENMASK(27, 24)
|
||||
#define STM32_RTC_ALRMXR_DATE_MASK BIT(31)
|
||||
|
||||
/* STM32_RTC_SR/_SCR bit fields */
|
||||
#define STM32_RTC_SR_ALRA BIT(0)
|
||||
|
||||
/* STM32_RTC_VERR bit fields */
|
||||
#define STM32_RTC_VERR_MINREV_SHIFT 0
|
||||
#define STM32_RTC_VERR_MINREV GENMASK(3, 0)
|
||||
#define STM32_RTC_VERR_MAJREV_SHIFT 4
|
||||
#define STM32_RTC_VERR_MAJREV GENMASK(7, 4)
|
||||
|
||||
/* STM32_RTC_WPR key constants */
|
||||
#define RTC_WPR_1ST_KEY 0xCA
|
||||
#define RTC_WPR_2ND_KEY 0x53
|
||||
#define RTC_WPR_WRONG_KEY 0xFF
|
||||
|
||||
/*
|
||||
* RTC registers are protected against parasitic write access.
|
||||
* PWR_CR_DBP bit must be set to enable write access to RTC registers.
|
||||
*/
|
||||
/* STM32_PWR_CR */
|
||||
#define PWR_CR 0x00
|
||||
/* STM32_PWR_CR bit field */
|
||||
#define PWR_CR_DBP BIT(8)
|
||||
/* Max STM32 RTC register offset is 0x3FC */
|
||||
#define UNDEF_REG 0xFFFF
|
||||
|
||||
struct stm32_rtc;
|
||||
|
||||
struct stm32_rtc_registers {
|
||||
u16 tr;
|
||||
u16 dr;
|
||||
u16 cr;
|
||||
u16 isr;
|
||||
u16 prer;
|
||||
u16 alrmar;
|
||||
u16 wpr;
|
||||
u16 sr;
|
||||
u16 scr;
|
||||
u16 verr;
|
||||
};
|
||||
|
||||
struct stm32_rtc_events {
|
||||
u32 alra;
|
||||
};
|
||||
|
||||
struct stm32_rtc_data {
|
||||
const struct stm32_rtc_registers regs;
|
||||
const struct stm32_rtc_events events;
|
||||
void (*clear_events)(struct stm32_rtc *rtc, unsigned int flags);
|
||||
bool has_pclk;
|
||||
bool need_dbp;
|
||||
bool has_wakeirq;
|
||||
};
|
||||
|
||||
struct stm32_rtc {
|
||||
struct rtc_device *rtc_dev;
|
||||
void __iomem *base;
|
||||
struct regmap *dbp;
|
||||
struct stm32_rtc_data *data;
|
||||
unsigned int dbp_reg;
|
||||
unsigned int dbp_mask;
|
||||
struct clk *pclk;
|
||||
struct clk *rtc_ck;
|
||||
const struct stm32_rtc_data *data;
|
||||
int irq_alarm;
|
||||
int wakeirq_alarm;
|
||||
};
|
||||
|
||||
static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc)
|
||||
{
|
||||
writel_relaxed(RTC_WPR_1ST_KEY, rtc->base + STM32_RTC_WPR);
|
||||
writel_relaxed(RTC_WPR_2ND_KEY, rtc->base + STM32_RTC_WPR);
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
|
||||
writel_relaxed(RTC_WPR_1ST_KEY, rtc->base + regs->wpr);
|
||||
writel_relaxed(RTC_WPR_2ND_KEY, rtc->base + regs->wpr);
|
||||
}
|
||||
|
||||
static void stm32_rtc_wpr_lock(struct stm32_rtc *rtc)
|
||||
{
|
||||
writel_relaxed(RTC_WPR_WRONG_KEY, rtc->base + STM32_RTC_WPR);
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
|
||||
writel_relaxed(RTC_WPR_WRONG_KEY, rtc->base + regs->wpr);
|
||||
}
|
||||
|
||||
static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
|
||||
{
|
||||
unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
unsigned int isr = readl_relaxed(rtc->base + regs->isr);
|
||||
|
||||
if (!(isr & STM32_RTC_ISR_INITF)) {
|
||||
isr |= STM32_RTC_ISR_INIT;
|
||||
writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
|
||||
writel_relaxed(isr, rtc->base + regs->isr);
|
||||
|
||||
/*
|
||||
* It takes around 2 rtc_ck clock cycles to enter in
|
||||
@ -134,7 +161,7 @@ static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
|
||||
* 1MHz, we poll every 10 us with a timeout of 100ms.
|
||||
*/
|
||||
return readl_relaxed_poll_timeout_atomic(
|
||||
rtc->base + STM32_RTC_ISR,
|
||||
rtc->base + regs->isr,
|
||||
isr, (isr & STM32_RTC_ISR_INITF),
|
||||
10, 100000);
|
||||
}
|
||||
@ -144,40 +171,50 @@ static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc)
|
||||
|
||||
static void stm32_rtc_exit_init_mode(struct stm32_rtc *rtc)
|
||||
{
|
||||
unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
unsigned int isr = readl_relaxed(rtc->base + regs->isr);
|
||||
|
||||
isr &= ~STM32_RTC_ISR_INIT;
|
||||
writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
|
||||
writel_relaxed(isr, rtc->base + regs->isr);
|
||||
}
|
||||
|
||||
static int stm32_rtc_wait_sync(struct stm32_rtc *rtc)
|
||||
{
|
||||
unsigned int isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
unsigned int isr = readl_relaxed(rtc->base + regs->isr);
|
||||
|
||||
isr &= ~STM32_RTC_ISR_RSF;
|
||||
writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
|
||||
writel_relaxed(isr, rtc->base + regs->isr);
|
||||
|
||||
/*
|
||||
* Wait for RSF to be set to ensure the calendar registers are
|
||||
* synchronised, it takes around 2 rtc_ck clock cycles
|
||||
*/
|
||||
return readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
|
||||
return readl_relaxed_poll_timeout_atomic(rtc->base + regs->isr,
|
||||
isr,
|
||||
(isr & STM32_RTC_ISR_RSF),
|
||||
10, 100000);
|
||||
}
|
||||
|
||||
static void stm32_rtc_clear_event_flags(struct stm32_rtc *rtc,
|
||||
unsigned int flags)
|
||||
{
|
||||
rtc->data->clear_events(rtc, flags);
|
||||
}
|
||||
|
||||
static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct stm32_rtc *rtc = (struct stm32_rtc *)dev_id;
|
||||
unsigned int isr, cr;
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
const struct stm32_rtc_events *evts = &rtc->data->events;
|
||||
unsigned int status, cr;
|
||||
|
||||
mutex_lock(&rtc->rtc_dev->ops_lock);
|
||||
|
||||
isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
|
||||
cr = readl_relaxed(rtc->base + STM32_RTC_CR);
|
||||
status = readl_relaxed(rtc->base + regs->sr);
|
||||
cr = readl_relaxed(rtc->base + regs->cr);
|
||||
|
||||
if ((isr & STM32_RTC_ISR_ALRAF) &&
|
||||
if ((status & evts->alra) &&
|
||||
(cr & STM32_RTC_CR_ALRAIE)) {
|
||||
/* Alarm A flag - Alarm interrupt */
|
||||
dev_dbg(&rtc->rtc_dev->dev, "Alarm occurred\n");
|
||||
@ -185,9 +222,8 @@ static irqreturn_t stm32_rtc_alarm_irq(int irq, void *dev_id)
|
||||
/* Pass event to the kernel */
|
||||
rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
|
||||
|
||||
/* Clear event flag, otherwise new events won't be received */
|
||||
writel_relaxed(isr & ~STM32_RTC_ISR_ALRAF,
|
||||
rtc->base + STM32_RTC_ISR);
|
||||
/* Clear event flags, otherwise new events won't be received */
|
||||
stm32_rtc_clear_event_flags(rtc, evts->alra);
|
||||
}
|
||||
|
||||
mutex_unlock(&rtc->rtc_dev->ops_lock);
|
||||
@ -234,11 +270,12 @@ static void bcd2tm(struct rtc_time *tm)
|
||||
static int stm32_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct stm32_rtc *rtc = dev_get_drvdata(dev);
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
unsigned int tr, dr;
|
||||
|
||||
/* Time and Date in BCD format */
|
||||
tr = readl_relaxed(rtc->base + STM32_RTC_TR);
|
||||
dr = readl_relaxed(rtc->base + STM32_RTC_DR);
|
||||
tr = readl_relaxed(rtc->base + regs->tr);
|
||||
dr = readl_relaxed(rtc->base + regs->dr);
|
||||
|
||||
tm->tm_sec = (tr & STM32_RTC_TR_SEC) >> STM32_RTC_TR_SEC_SHIFT;
|
||||
tm->tm_min = (tr & STM32_RTC_TR_MIN) >> STM32_RTC_TR_MIN_SHIFT;
|
||||
@ -259,6 +296,7 @@ static int stm32_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
static int stm32_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct stm32_rtc *rtc = dev_get_drvdata(dev);
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
unsigned int tr, dr;
|
||||
int ret = 0;
|
||||
|
||||
@ -283,8 +321,8 @@ static int stm32_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
goto end;
|
||||
}
|
||||
|
||||
writel_relaxed(tr, rtc->base + STM32_RTC_TR);
|
||||
writel_relaxed(dr, rtc->base + STM32_RTC_DR);
|
||||
writel_relaxed(tr, rtc->base + regs->tr);
|
||||
writel_relaxed(dr, rtc->base + regs->dr);
|
||||
|
||||
stm32_rtc_exit_init_mode(rtc);
|
||||
|
||||
@ -298,12 +336,14 @@ end:
|
||||
static int stm32_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct stm32_rtc *rtc = dev_get_drvdata(dev);
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
const struct stm32_rtc_events *evts = &rtc->data->events;
|
||||
struct rtc_time *tm = &alrm->time;
|
||||
unsigned int alrmar, cr, isr;
|
||||
unsigned int alrmar, cr, status;
|
||||
|
||||
alrmar = readl_relaxed(rtc->base + STM32_RTC_ALRMAR);
|
||||
cr = readl_relaxed(rtc->base + STM32_RTC_CR);
|
||||
isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
|
||||
alrmar = readl_relaxed(rtc->base + regs->alrmar);
|
||||
cr = readl_relaxed(rtc->base + regs->cr);
|
||||
status = readl_relaxed(rtc->base + regs->sr);
|
||||
|
||||
if (alrmar & STM32_RTC_ALRMXR_DATE_MASK) {
|
||||
/*
|
||||
@ -356,7 +396,7 @@ static int stm32_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
bcd2tm(tm);
|
||||
|
||||
alrm->enabled = (cr & STM32_RTC_CR_ALRAE) ? 1 : 0;
|
||||
alrm->pending = (isr & STM32_RTC_ISR_ALRAF) ? 1 : 0;
|
||||
alrm->pending = (status & evts->alra) ? 1 : 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -364,9 +404,11 @@ static int stm32_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
{
|
||||
struct stm32_rtc *rtc = dev_get_drvdata(dev);
|
||||
unsigned int isr, cr;
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
const struct stm32_rtc_events *evts = &rtc->data->events;
|
||||
unsigned int cr;
|
||||
|
||||
cr = readl_relaxed(rtc->base + STM32_RTC_CR);
|
||||
cr = readl_relaxed(rtc->base + regs->cr);
|
||||
|
||||
stm32_rtc_wpr_unlock(rtc);
|
||||
|
||||
@ -375,12 +417,10 @@ static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
cr |= (STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
|
||||
else
|
||||
cr &= ~(STM32_RTC_CR_ALRAIE | STM32_RTC_CR_ALRAE);
|
||||
writel_relaxed(cr, rtc->base + STM32_RTC_CR);
|
||||
writel_relaxed(cr, rtc->base + regs->cr);
|
||||
|
||||
/* Clear event flag, otherwise new events won't be received */
|
||||
isr = readl_relaxed(rtc->base + STM32_RTC_ISR);
|
||||
isr &= ~STM32_RTC_ISR_ALRAF;
|
||||
writel_relaxed(isr, rtc->base + STM32_RTC_ISR);
|
||||
/* Clear event flags, otherwise new events won't be received */
|
||||
stm32_rtc_clear_event_flags(rtc, evts->alra);
|
||||
|
||||
stm32_rtc_wpr_lock(rtc);
|
||||
|
||||
@ -389,9 +429,10 @@ static int stm32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
|
||||
static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm)
|
||||
{
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
int cur_day, cur_mon, cur_year, cur_hour, cur_min, cur_sec;
|
||||
unsigned int dr = readl_relaxed(rtc->base + STM32_RTC_DR);
|
||||
unsigned int tr = readl_relaxed(rtc->base + STM32_RTC_TR);
|
||||
unsigned int dr = readl_relaxed(rtc->base + regs->dr);
|
||||
unsigned int tr = readl_relaxed(rtc->base + regs->tr);
|
||||
|
||||
cur_day = (dr & STM32_RTC_DR_DATE) >> STM32_RTC_DR_DATE_SHIFT;
|
||||
cur_mon = (dr & STM32_RTC_DR_MONTH) >> STM32_RTC_DR_MONTH_SHIFT;
|
||||
@ -425,6 +466,7 @@ static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm)
|
||||
static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct stm32_rtc *rtc = dev_get_drvdata(dev);
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
struct rtc_time *tm = &alrm->time;
|
||||
unsigned int cr, isr, alrmar;
|
||||
int ret = 0;
|
||||
@ -456,15 +498,15 @@ static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
stm32_rtc_wpr_unlock(rtc);
|
||||
|
||||
/* Disable Alarm */
|
||||
cr = readl_relaxed(rtc->base + STM32_RTC_CR);
|
||||
cr = readl_relaxed(rtc->base + regs->cr);
|
||||
cr &= ~STM32_RTC_CR_ALRAE;
|
||||
writel_relaxed(cr, rtc->base + STM32_RTC_CR);
|
||||
writel_relaxed(cr, rtc->base + regs->cr);
|
||||
|
||||
/*
|
||||
* Poll Alarm write flag to be sure that Alarm update is allowed: it
|
||||
* takes around 2 rtc_ck clock cycles
|
||||
*/
|
||||
ret = readl_relaxed_poll_timeout_atomic(rtc->base + STM32_RTC_ISR,
|
||||
ret = readl_relaxed_poll_timeout_atomic(rtc->base + regs->isr,
|
||||
isr,
|
||||
(isr & STM32_RTC_ISR_ALRAWF),
|
||||
10, 100000);
|
||||
@ -475,7 +517,7 @@ static int stm32_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
}
|
||||
|
||||
/* Write to Alarm register */
|
||||
writel_relaxed(alrmar, rtc->base + STM32_RTC_ALRMAR);
|
||||
writel_relaxed(alrmar, rtc->base + regs->alrmar);
|
||||
|
||||
if (alrm->enabled)
|
||||
stm32_rtc_alarm_irq_enable(dev, 1);
|
||||
@ -496,17 +538,95 @@ static const struct rtc_class_ops stm32_rtc_ops = {
|
||||
.alarm_irq_enable = stm32_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static void stm32_rtc_clear_events(struct stm32_rtc *rtc,
|
||||
unsigned int flags)
|
||||
{
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
|
||||
/* Flags are cleared by writing 0 in RTC_ISR */
|
||||
writel_relaxed(readl_relaxed(rtc->base + regs->isr) & ~flags,
|
||||
rtc->base + regs->isr);
|
||||
}
|
||||
|
||||
static const struct stm32_rtc_data stm32_rtc_data = {
|
||||
.has_pclk = false,
|
||||
.need_dbp = true,
|
||||
.has_wakeirq = false,
|
||||
.regs = {
|
||||
.tr = 0x00,
|
||||
.dr = 0x04,
|
||||
.cr = 0x08,
|
||||
.isr = 0x0C,
|
||||
.prer = 0x10,
|
||||
.alrmar = 0x1C,
|
||||
.wpr = 0x24,
|
||||
.sr = 0x0C, /* set to ISR offset to ease alarm management */
|
||||
.scr = UNDEF_REG,
|
||||
.verr = UNDEF_REG,
|
||||
},
|
||||
.events = {
|
||||
.alra = STM32_RTC_ISR_ALRAF,
|
||||
},
|
||||
.clear_events = stm32_rtc_clear_events,
|
||||
};
|
||||
|
||||
static const struct stm32_rtc_data stm32h7_rtc_data = {
|
||||
.has_pclk = true,
|
||||
.need_dbp = true,
|
||||
.has_wakeirq = false,
|
||||
.regs = {
|
||||
.tr = 0x00,
|
||||
.dr = 0x04,
|
||||
.cr = 0x08,
|
||||
.isr = 0x0C,
|
||||
.prer = 0x10,
|
||||
.alrmar = 0x1C,
|
||||
.wpr = 0x24,
|
||||
.sr = 0x0C, /* set to ISR offset to ease alarm management */
|
||||
.scr = UNDEF_REG,
|
||||
.verr = UNDEF_REG,
|
||||
},
|
||||
.events = {
|
||||
.alra = STM32_RTC_ISR_ALRAF,
|
||||
},
|
||||
.clear_events = stm32_rtc_clear_events,
|
||||
};
|
||||
|
||||
static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct stm32_rtc_registers regs = rtc->data->regs;
|
||||
|
||||
/* Flags are cleared by writing 1 in RTC_SCR */
|
||||
writel_relaxed(flags, rtc->base + regs.scr);
|
||||
}
|
||||
|
||||
static const struct stm32_rtc_data stm32mp1_data = {
|
||||
.has_pclk = true,
|
||||
.need_dbp = false,
|
||||
.has_wakeirq = true,
|
||||
.regs = {
|
||||
.tr = 0x00,
|
||||
.dr = 0x04,
|
||||
.cr = 0x18,
|
||||
.isr = 0x0C, /* named RTC_ICSR on stm32mp1 */
|
||||
.prer = 0x10,
|
||||
.alrmar = 0x40,
|
||||
.wpr = 0x24,
|
||||
.sr = 0x50,
|
||||
.scr = 0x5C,
|
||||
.verr = 0x3F4,
|
||||
},
|
||||
.events = {
|
||||
.alra = STM32_RTC_SR_ALRA,
|
||||
},
|
||||
.clear_events = stm32mp1_rtc_clear_events,
|
||||
};
|
||||
|
||||
static const struct of_device_id stm32_rtc_of_match[] = {
|
||||
{ .compatible = "st,stm32-rtc", .data = &stm32_rtc_data },
|
||||
{ .compatible = "st,stm32h7-rtc", .data = &stm32h7_rtc_data },
|
||||
{ .compatible = "st,stm32mp1-rtc", .data = &stm32mp1_data },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
|
||||
@ -514,6 +634,7 @@ MODULE_DEVICE_TABLE(of, stm32_rtc_of_match);
|
||||
static int stm32_rtc_init(struct platform_device *pdev,
|
||||
struct stm32_rtc *rtc)
|
||||
{
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
unsigned int prer, pred_a, pred_s, pred_a_max, pred_s_max, cr;
|
||||
unsigned int rate;
|
||||
int ret = 0;
|
||||
@ -554,14 +675,14 @@ static int stm32_rtc_init(struct platform_device *pdev,
|
||||
}
|
||||
|
||||
prer = (pred_s << STM32_RTC_PRER_PRED_S_SHIFT) & STM32_RTC_PRER_PRED_S;
|
||||
writel_relaxed(prer, rtc->base + STM32_RTC_PRER);
|
||||
writel_relaxed(prer, rtc->base + regs->prer);
|
||||
prer |= (pred_a << STM32_RTC_PRER_PRED_A_SHIFT) & STM32_RTC_PRER_PRED_A;
|
||||
writel_relaxed(prer, rtc->base + STM32_RTC_PRER);
|
||||
writel_relaxed(prer, rtc->base + regs->prer);
|
||||
|
||||
/* Force 24h time format */
|
||||
cr = readl_relaxed(rtc->base + STM32_RTC_CR);
|
||||
cr = readl_relaxed(rtc->base + regs->cr);
|
||||
cr &= ~STM32_RTC_CR_FMT;
|
||||
writel_relaxed(cr, rtc->base + STM32_RTC_CR);
|
||||
writel_relaxed(cr, rtc->base + regs->cr);
|
||||
|
||||
stm32_rtc_exit_init_mode(rtc);
|
||||
|
||||
@ -575,8 +696,8 @@ end:
|
||||
static int stm32_rtc_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct stm32_rtc *rtc;
|
||||
const struct stm32_rtc_registers *regs;
|
||||
struct resource *res;
|
||||
const struct of_device_id *match;
|
||||
int ret;
|
||||
|
||||
rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
|
||||
@ -588,15 +709,32 @@ static int stm32_rtc_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(rtc->base))
|
||||
return PTR_ERR(rtc->base);
|
||||
|
||||
rtc->dbp = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
|
||||
"st,syscfg");
|
||||
if (IS_ERR(rtc->dbp)) {
|
||||
dev_err(&pdev->dev, "no st,syscfg\n");
|
||||
return PTR_ERR(rtc->dbp);
|
||||
}
|
||||
rtc->data = (struct stm32_rtc_data *)
|
||||
of_device_get_match_data(&pdev->dev);
|
||||
regs = &rtc->data->regs;
|
||||
|
||||
match = of_match_device(stm32_rtc_of_match, &pdev->dev);
|
||||
rtc->data = (struct stm32_rtc_data *)match->data;
|
||||
if (rtc->data->need_dbp) {
|
||||
rtc->dbp = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
|
||||
"st,syscfg");
|
||||
if (IS_ERR(rtc->dbp)) {
|
||||
dev_err(&pdev->dev, "no st,syscfg\n");
|
||||
return PTR_ERR(rtc->dbp);
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_index(pdev->dev.of_node, "st,syscfg",
|
||||
1, &rtc->dbp_reg);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "can't read DBP register offset\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = of_property_read_u32_index(pdev->dev.of_node, "st,syscfg",
|
||||
2, &rtc->dbp_mask);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "can't read DBP register mask\n");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (!rtc->data->has_pclk) {
|
||||
rtc->pclk = NULL;
|
||||
@ -624,11 +762,13 @@ static int stm32_rtc_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, PWR_CR_DBP);
|
||||
if (rtc->data->need_dbp)
|
||||
regmap_update_bits(rtc->dbp, rtc->dbp_reg,
|
||||
rtc->dbp_mask, rtc->dbp_mask);
|
||||
|
||||
/*
|
||||
* After a system reset, RTC_ISR.INITS flag can be read to check if
|
||||
* the calendar has been initalized or not. INITS flag is reset by a
|
||||
* the calendar has been initialized or not. INITS flag is reset by a
|
||||
* power-on reset (no vbat, no power-supply). It is not reset if
|
||||
* rtc_ck parent clock has changed (so RTC prescalers need to be
|
||||
* changed). That's why we cannot rely on this flag to know if RTC
|
||||
@ -645,15 +785,22 @@ static int stm32_rtc_probe(struct platform_device *pdev)
|
||||
goto err;
|
||||
}
|
||||
|
||||
ret = device_init_wakeup(&pdev->dev, true);
|
||||
if (rtc->data->has_wakeirq) {
|
||||
rtc->wakeirq_alarm = platform_get_irq(pdev, 1);
|
||||
if (rtc->wakeirq_alarm <= 0)
|
||||
ret = rtc->wakeirq_alarm;
|
||||
else
|
||||
ret = dev_pm_set_dedicated_wake_irq(&pdev->dev,
|
||||
rtc->wakeirq_alarm);
|
||||
}
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev, "alarm can't wake up the system: %d", ret);
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
|
||||
ret = device_init_wakeup(&pdev->dev, true);
|
||||
if (ret)
|
||||
dev_warn(&pdev->dev,
|
||||
"alarm won't be able to wake up the system");
|
||||
|
||||
rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
|
||||
&stm32_rtc_ops, THIS_MODULE);
|
||||
&stm32_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc->rtc_dev)) {
|
||||
ret = PTR_ERR(rtc->rtc_dev);
|
||||
dev_err(&pdev->dev, "rtc device registration failed, err=%d\n",
|
||||
@ -663,8 +810,7 @@ static int stm32_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
/* Handle RTC alarm interrupts */
|
||||
ret = devm_request_threaded_irq(&pdev->dev, rtc->irq_alarm, NULL,
|
||||
stm32_rtc_alarm_irq,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
stm32_rtc_alarm_irq, IRQF_ONESHOT,
|
||||
pdev->name, rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "IRQ%d (alarm interrupt) already claimed\n",
|
||||
@ -676,17 +822,27 @@ static int stm32_rtc_probe(struct platform_device *pdev)
|
||||
* If INITS flag is reset (calendar year field set to 0x00), calendar
|
||||
* must be initialized
|
||||
*/
|
||||
if (!(readl_relaxed(rtc->base + STM32_RTC_ISR) & STM32_RTC_ISR_INITS))
|
||||
if (!(readl_relaxed(rtc->base + regs->isr) & STM32_RTC_ISR_INITS))
|
||||
dev_warn(&pdev->dev, "Date/Time must be initialized\n");
|
||||
|
||||
if (regs->verr != UNDEF_REG) {
|
||||
u32 ver = readl_relaxed(rtc->base + regs->verr);
|
||||
|
||||
dev_info(&pdev->dev, "registered rev:%d.%d\n",
|
||||
(ver >> STM32_RTC_VERR_MAJREV_SHIFT) & 0xF,
|
||||
(ver >> STM32_RTC_VERR_MINREV_SHIFT) & 0xF);
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
if (rtc->data->has_pclk)
|
||||
clk_disable_unprepare(rtc->pclk);
|
||||
clk_disable_unprepare(rtc->rtc_ck);
|
||||
|
||||
regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, 0);
|
||||
if (rtc->data->need_dbp)
|
||||
regmap_update_bits(rtc->dbp, rtc->dbp_reg, rtc->dbp_mask, 0);
|
||||
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
|
||||
return ret;
|
||||
@ -695,22 +851,25 @@ err:
|
||||
static int stm32_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct stm32_rtc *rtc = platform_get_drvdata(pdev);
|
||||
const struct stm32_rtc_registers *regs = &rtc->data->regs;
|
||||
unsigned int cr;
|
||||
|
||||
/* Disable interrupts */
|
||||
stm32_rtc_wpr_unlock(rtc);
|
||||
cr = readl_relaxed(rtc->base + STM32_RTC_CR);
|
||||
cr = readl_relaxed(rtc->base + regs->cr);
|
||||
cr &= ~STM32_RTC_CR_ALRAIE;
|
||||
writel_relaxed(cr, rtc->base + STM32_RTC_CR);
|
||||
writel_relaxed(cr, rtc->base + regs->cr);
|
||||
stm32_rtc_wpr_lock(rtc);
|
||||
|
||||
clk_disable_unprepare(rtc->rtc_ck);
|
||||
if (rtc->data->has_pclk)
|
||||
clk_disable_unprepare(rtc->pclk);
|
||||
|
||||
/* Enable backup domain write protection */
|
||||
regmap_update_bits(rtc->dbp, PWR_CR, PWR_CR_DBP, 0);
|
||||
/* Enable backup domain write protection if needed */
|
||||
if (rtc->data->need_dbp)
|
||||
regmap_update_bits(rtc->dbp, rtc->dbp_reg, rtc->dbp_mask, 0);
|
||||
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
|
||||
return 0;
|
||||
|
@ -74,7 +74,7 @@
|
||||
#define SUN6I_ALARM_CONFIG_WAKEUP BIT(0)
|
||||
|
||||
#define SUN6I_LOSC_OUT_GATING 0x0060
|
||||
#define SUN6I_LOSC_OUT_GATING_EN BIT(0)
|
||||
#define SUN6I_LOSC_OUT_GATING_EN_OFFSET 0
|
||||
|
||||
/*
|
||||
* Get date values
|
||||
@ -255,7 +255,7 @@ static void __init sun6i_rtc_clk_init(struct device_node *node)
|
||||
&clkout_name);
|
||||
rtc->ext_losc = clk_register_gate(NULL, clkout_name, rtc->hw.init->name,
|
||||
0, rtc->base + SUN6I_LOSC_OUT_GATING,
|
||||
SUN6I_LOSC_OUT_GATING_EN, 0,
|
||||
SUN6I_LOSC_OUT_GATING_EN_OFFSET, 0,
|
||||
&rtc->lock);
|
||||
if (IS_ERR(rtc->ext_losc)) {
|
||||
pr_crit("Couldn't register the LOSC external gate\n");
|
||||
|
@ -445,6 +445,10 @@ static int sunxi_rtc_probe(struct platform_device *pdev)
|
||||
platform_set_drvdata(pdev, chip);
|
||||
chip->dev = &pdev->dev;
|
||||
|
||||
chip->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(chip->rtc))
|
||||
return PTR_ERR(chip->rtc);
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
chip->base = devm_ioremap_resource(&pdev->dev, res);
|
||||
if (IS_ERR(chip->base))
|
||||
@ -481,11 +485,12 @@ static int sunxi_rtc_probe(struct platform_device *pdev)
|
||||
writel(SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND, chip->base +
|
||||
SUNXI_ALRM_IRQ_STA);
|
||||
|
||||
chip->rtc = rtc_device_register("rtc-sunxi", &pdev->dev,
|
||||
&sunxi_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(chip->rtc)) {
|
||||
chip->rtc->ops = &sunxi_rtc_ops;
|
||||
|
||||
ret = rtc_register_device(chip->rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "unable to register device\n");
|
||||
return PTR_ERR(chip->rtc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dev_info(&pdev->dev, "RTC enabled\n");
|
||||
@ -493,18 +498,8 @@ static int sunxi_rtc_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sunxi_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sunxi_rtc_dev *chip = platform_get_drvdata(pdev);
|
||||
|
||||
rtc_device_unregister(chip->rtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver sunxi_rtc_driver = {
|
||||
.probe = sunxi_rtc_probe,
|
||||
.remove = sunxi_rtc_remove,
|
||||
.driver = {
|
||||
.name = "sunxi-rtc",
|
||||
.of_match_table = sunxi_rtc_dt_ids,
|
||||
|
@ -13,135 +13,139 @@
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
static int test_mmss64;
|
||||
module_param(test_mmss64, int, 0644);
|
||||
MODULE_PARM_DESC(test_mmss64, "Test struct rtc_class_ops.set_mmss64().");
|
||||
#define MAX_RTC_TEST 3
|
||||
|
||||
static struct platform_device *test0 = NULL, *test1 = NULL;
|
||||
struct rtc_test_data {
|
||||
struct rtc_device *rtc;
|
||||
time64_t offset;
|
||||
struct timer_list alarm;
|
||||
bool alarm_en;
|
||||
};
|
||||
|
||||
static int test_rtc_read_alarm(struct device *dev,
|
||||
struct rtc_wkalrm *alrm)
|
||||
struct platform_device *pdev[MAX_RTC_TEST];
|
||||
|
||||
static int test_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct rtc_test_data *rtd = dev_get_drvdata(dev);
|
||||
time64_t alarm;
|
||||
|
||||
alarm = (rtd->alarm.expires - jiffies) / HZ;
|
||||
alarm += ktime_get_real_seconds() + rtd->offset;
|
||||
|
||||
rtc_time64_to_tm(alarm, &alrm->time);
|
||||
alrm->enabled = rtd->alarm_en;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_rtc_set_alarm(struct device *dev,
|
||||
struct rtc_wkalrm *alrm)
|
||||
static int test_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct rtc_test_data *rtd = dev_get_drvdata(dev);
|
||||
ktime_t timeout;
|
||||
u64 expires;
|
||||
|
||||
timeout = rtc_tm_to_time64(&alrm->time) - ktime_get_real_seconds();
|
||||
timeout -= rtd->offset;
|
||||
|
||||
del_timer(&rtd->alarm);
|
||||
|
||||
expires = jiffies + timeout * HZ;
|
||||
if (expires > U32_MAX)
|
||||
expires = U32_MAX;
|
||||
|
||||
pr_err("ABE: %s +%d %s\n", __FILE__, __LINE__, __func__);
|
||||
rtd->alarm.expires = expires;
|
||||
|
||||
if (alrm->enabled)
|
||||
add_timer(&rtd->alarm);
|
||||
|
||||
rtd->alarm_en = alrm->enabled;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_rtc_read_time(struct device *dev,
|
||||
struct rtc_time *tm)
|
||||
static int test_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
rtc_time64_to_tm(ktime_get_real_seconds(), tm);
|
||||
struct rtc_test_data *rtd = dev_get_drvdata(dev);
|
||||
|
||||
rtc_time64_to_tm(ktime_get_real_seconds() + rtd->offset, tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_rtc_set_mmss64(struct device *dev, time64_t secs)
|
||||
{
|
||||
dev_info(dev, "%s, secs = %lld\n", __func__, (long long)secs);
|
||||
return 0;
|
||||
}
|
||||
struct rtc_test_data *rtd = dev_get_drvdata(dev);
|
||||
|
||||
static int test_rtc_set_mmss(struct device *dev, unsigned long secs)
|
||||
{
|
||||
dev_info(dev, "%s, secs = %lu\n", __func__, secs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_rtc_proc(struct device *dev, struct seq_file *seq)
|
||||
{
|
||||
struct platform_device *plat_dev = to_platform_device(dev);
|
||||
|
||||
seq_printf(seq, "test\t\t: yes\n");
|
||||
seq_printf(seq, "id\t\t: %d\n", plat_dev->id);
|
||||
rtd->offset = secs - ktime_get_real_seconds();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)
|
||||
{
|
||||
struct rtc_test_data *rtd = dev_get_drvdata(dev);
|
||||
|
||||
rtd->alarm_en = enable;
|
||||
if (enable)
|
||||
add_timer(&rtd->alarm);
|
||||
else
|
||||
del_timer(&rtd->alarm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct rtc_class_ops test_rtc_ops = {
|
||||
.proc = test_rtc_proc,
|
||||
static const struct rtc_class_ops test_rtc_ops_noalm = {
|
||||
.read_time = test_rtc_read_time,
|
||||
.read_alarm = test_rtc_read_alarm,
|
||||
.set_alarm = test_rtc_set_alarm,
|
||||
.set_mmss = test_rtc_set_mmss,
|
||||
.set_mmss64 = test_rtc_set_mmss64,
|
||||
.alarm_irq_enable = test_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static ssize_t test_irq_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static const struct rtc_class_ops test_rtc_ops = {
|
||||
.read_time = test_rtc_read_time,
|
||||
.read_alarm = test_rtc_read_alarm,
|
||||
.set_alarm = test_rtc_set_alarm,
|
||||
.set_mmss64 = test_rtc_set_mmss64,
|
||||
.alarm_irq_enable = test_rtc_alarm_irq_enable,
|
||||
};
|
||||
|
||||
static void test_rtc_alarm_handler(struct timer_list *t)
|
||||
{
|
||||
return sprintf(buf, "%d\n", 42);
|
||||
struct rtc_test_data *rtd = from_timer(rtd, t, alarm);
|
||||
|
||||
rtc_update_irq(rtd->rtc, 1, RTC_AF | RTC_IRQF);
|
||||
}
|
||||
static ssize_t test_irq_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
int retval;
|
||||
struct platform_device *plat_dev = to_platform_device(dev);
|
||||
struct rtc_device *rtc = platform_get_drvdata(plat_dev);
|
||||
|
||||
retval = count;
|
||||
if (strncmp(buf, "tick", 4) == 0 && rtc->pie_enabled)
|
||||
rtc_update_irq(rtc, 1, RTC_PF | RTC_IRQF);
|
||||
else if (strncmp(buf, "alarm", 5) == 0) {
|
||||
struct rtc_wkalrm alrm;
|
||||
int err = rtc_read_alarm(rtc, &alrm);
|
||||
|
||||
if (!err && alrm.enabled)
|
||||
rtc_update_irq(rtc, 1, RTC_AF | RTC_IRQF);
|
||||
|
||||
} else if (strncmp(buf, "update", 6) == 0 && rtc->uie_rtctimer.enabled)
|
||||
rtc_update_irq(rtc, 1, RTC_UF | RTC_IRQF);
|
||||
else
|
||||
retval = -EINVAL;
|
||||
|
||||
return retval;
|
||||
}
|
||||
static DEVICE_ATTR(irq, S_IRUGO | S_IWUSR, test_irq_show, test_irq_store);
|
||||
|
||||
static int test_probe(struct platform_device *plat_dev)
|
||||
{
|
||||
int err;
|
||||
struct rtc_device *rtc;
|
||||
struct rtc_test_data *rtd;
|
||||
|
||||
if (test_mmss64) {
|
||||
test_rtc_ops.set_mmss64 = test_rtc_set_mmss64;
|
||||
test_rtc_ops.set_mmss = NULL;
|
||||
rtd = devm_kzalloc(&plat_dev->dev, sizeof(*rtd), GFP_KERNEL);
|
||||
if (!rtd)
|
||||
return -ENOMEM;
|
||||
|
||||
platform_set_drvdata(plat_dev, rtd);
|
||||
|
||||
rtd->rtc = devm_rtc_allocate_device(&plat_dev->dev);
|
||||
if (IS_ERR(rtd->rtc))
|
||||
return PTR_ERR(rtd->rtc);
|
||||
|
||||
switch (plat_dev->id) {
|
||||
case 0:
|
||||
rtd->rtc->ops = &test_rtc_ops_noalm;
|
||||
break;
|
||||
default:
|
||||
rtd->rtc->ops = &test_rtc_ops;
|
||||
}
|
||||
|
||||
rtc = devm_rtc_device_register(&plat_dev->dev, "test",
|
||||
&test_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc)) {
|
||||
return PTR_ERR(rtc);
|
||||
}
|
||||
timer_setup(&rtd->alarm, test_rtc_alarm_handler, 0);
|
||||
rtd->alarm.expires = 0;
|
||||
|
||||
err = device_create_file(&plat_dev->dev, &dev_attr_irq);
|
||||
if (err)
|
||||
dev_err(&plat_dev->dev, "Unable to create sysfs entry: %s\n",
|
||||
dev_attr_irq.attr.name);
|
||||
|
||||
platform_set_drvdata(plat_dev, rtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int test_remove(struct platform_device *plat_dev)
|
||||
{
|
||||
device_remove_file(&plat_dev->dev, &dev_attr_irq);
|
||||
|
||||
return 0;
|
||||
return rtc_register_device(rtd->rtc);
|
||||
}
|
||||
|
||||
static struct platform_driver test_driver = {
|
||||
.probe = test_probe,
|
||||
.remove = test_remove,
|
||||
.driver = {
|
||||
.name = "rtc-test",
|
||||
},
|
||||
@ -149,47 +153,45 @@ static struct platform_driver test_driver = {
|
||||
|
||||
static int __init test_init(void)
|
||||
{
|
||||
int err;
|
||||
int i, err;
|
||||
|
||||
if ((err = platform_driver_register(&test_driver)))
|
||||
return err;
|
||||
|
||||
if ((test0 = platform_device_alloc("rtc-test", 0)) == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto exit_driver_unregister;
|
||||
err = -ENOMEM;
|
||||
for (i = 0; i < MAX_RTC_TEST; i++) {
|
||||
pdev[i] = platform_device_alloc("rtc-test", i);
|
||||
if (!pdev[i])
|
||||
goto exit_free_mem;
|
||||
}
|
||||
|
||||
if ((test1 = platform_device_alloc("rtc-test", 1)) == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto exit_put_test0;
|
||||
for (i = 0; i < MAX_RTC_TEST; i++) {
|
||||
err = platform_device_add(pdev[i]);
|
||||
if (err)
|
||||
goto exit_device_del;
|
||||
}
|
||||
|
||||
if ((err = platform_device_add(test0)))
|
||||
goto exit_put_test1;
|
||||
|
||||
if ((err = platform_device_add(test1)))
|
||||
goto exit_del_test0;
|
||||
|
||||
return 0;
|
||||
|
||||
exit_del_test0:
|
||||
platform_device_del(test0);
|
||||
exit_device_del:
|
||||
for (; i > 0; i--)
|
||||
platform_device_del(pdev[i - 1]);
|
||||
|
||||
exit_put_test1:
|
||||
platform_device_put(test1);
|
||||
exit_free_mem:
|
||||
for (i = 0; i < MAX_RTC_TEST; i++)
|
||||
platform_device_put(pdev[i]);
|
||||
|
||||
exit_put_test0:
|
||||
platform_device_put(test0);
|
||||
|
||||
exit_driver_unregister:
|
||||
platform_driver_unregister(&test_driver);
|
||||
return err;
|
||||
}
|
||||
|
||||
static void __exit test_exit(void)
|
||||
{
|
||||
platform_device_unregister(test0);
|
||||
platform_device_unregister(test1);
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_RTC_TEST; i++)
|
||||
platform_device_unregister(pdev[i]);
|
||||
|
||||
platform_driver_unregister(&test_driver);
|
||||
}
|
||||
|
||||
|
@ -58,7 +58,6 @@ struct tps6586x_rtc {
|
||||
struct rtc_device *rtc;
|
||||
int irq;
|
||||
bool irq_en;
|
||||
unsigned long long epoch_start;
|
||||
};
|
||||
|
||||
static inline struct device *to_tps6586x_dev(struct device *dev)
|
||||
@ -68,10 +67,9 @@ static inline struct device *to_tps6586x_dev(struct device *dev)
|
||||
|
||||
static int tps6586x_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct device *tps_dev = to_tps6586x_dev(dev);
|
||||
unsigned long long ticks = 0;
|
||||
unsigned long seconds;
|
||||
time64_t seconds;
|
||||
u8 buff[6];
|
||||
int ret;
|
||||
int i;
|
||||
@ -88,26 +86,20 @@ static int tps6586x_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
}
|
||||
|
||||
seconds = ticks >> 10;
|
||||
seconds += rtc->epoch_start;
|
||||
rtc_time_to_tm(seconds, tm);
|
||||
rtc_time64_to_tm(seconds, tm);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tps6586x_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct device *tps_dev = to_tps6586x_dev(dev);
|
||||
unsigned long long ticks;
|
||||
unsigned long seconds;
|
||||
time64_t seconds;
|
||||
u8 buff[5];
|
||||
int ret;
|
||||
|
||||
rtc_tm_to_time(tm, &seconds);
|
||||
if (seconds < rtc->epoch_start) {
|
||||
dev_err(dev, "requested time unsupported\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
seconds -= rtc->epoch_start;
|
||||
seconds = rtc_tm_to_time64(tm);
|
||||
|
||||
ticks = (unsigned long long)seconds << 10;
|
||||
buff[0] = (ticks >> 32) & 0xff;
|
||||
@ -155,9 +147,8 @@ static int tps6586x_rtc_alarm_irq_enable(struct device *dev,
|
||||
|
||||
static int tps6586x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct device *tps_dev = to_tps6586x_dev(dev);
|
||||
unsigned long seconds;
|
||||
time64_t seconds;
|
||||
unsigned long ticks;
|
||||
unsigned long rtc_current_time;
|
||||
unsigned long long rticks = 0;
|
||||
@ -166,12 +157,7 @@ static int tps6586x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
rtc_tm_to_time(&alrm->time, &seconds);
|
||||
|
||||
if (alrm->enabled && (seconds < rtc->epoch_start)) {
|
||||
dev_err(dev, "can't set alarm to requested time\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
seconds = rtc_tm_to_time64(&alrm->time);
|
||||
|
||||
ret = tps6586x_rtc_alarm_irq_enable(dev, alrm->enabled);
|
||||
if (ret < 0) {
|
||||
@ -179,7 +165,6 @@ static int tps6586x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
return ret;
|
||||
}
|
||||
|
||||
seconds -= rtc->epoch_start;
|
||||
ret = tps6586x_reads(tps_dev, RTC_COUNT4_DUMMYREAD,
|
||||
sizeof(rbuff), rbuff);
|
||||
if (ret < 0) {
|
||||
@ -210,10 +195,9 @@ static int tps6586x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
static int tps6586x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
{
|
||||
struct tps6586x_rtc *rtc = dev_get_drvdata(dev);
|
||||
struct device *tps_dev = to_tps6586x_dev(dev);
|
||||
unsigned long ticks;
|
||||
unsigned long seconds;
|
||||
time64_t seconds;
|
||||
u8 buff[3];
|
||||
int ret;
|
||||
|
||||
@ -225,9 +209,8 @@ static int tps6586x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
ticks = (buff[0] << 16) | (buff[1] << 8) | buff[2];
|
||||
seconds = ticks >> 10;
|
||||
seconds += rtc->epoch_start;
|
||||
|
||||
rtc_time_to_tm(seconds, &alrm->time);
|
||||
rtc_time64_to_tm(seconds, &alrm->time);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -260,9 +243,6 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
|
||||
rtc->dev = &pdev->dev;
|
||||
rtc->irq = platform_get_irq(pdev, 0);
|
||||
|
||||
/* Set epoch start as 00:00:00:01:01:2009 */
|
||||
rtc->epoch_start = mktime(2009, 1, 1, 0, 0, 0);
|
||||
|
||||
/* 1 kHz tick mode, enable tick counting */
|
||||
ret = tps6586x_update(tps_dev, RTC_CTRL,
|
||||
RTC_ENABLE | OSC_SRC_SEL |
|
||||
@ -276,14 +256,18 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
|
||||
device_init_wakeup(&pdev->dev, 1);
|
||||
|
||||
platform_set_drvdata(pdev, rtc);
|
||||
rtc->rtc = devm_rtc_device_register(&pdev->dev, dev_name(&pdev->dev),
|
||||
&tps6586x_rtc_ops, THIS_MODULE);
|
||||
rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc->rtc)) {
|
||||
ret = PTR_ERR(rtc->rtc);
|
||||
dev_err(&pdev->dev, "RTC device register: ret %d\n", ret);
|
||||
dev_err(&pdev->dev, "RTC allocate device: ret %d\n", ret);
|
||||
goto fail_rtc_register;
|
||||
}
|
||||
|
||||
rtc->rtc->ops = &tps6586x_rtc_ops;
|
||||
rtc->rtc->range_max = (1ULL << 30) - 1; /* 30-bit seconds */
|
||||
rtc->rtc->start_secs = mktime64(2009, 1, 1, 0, 0, 0);
|
||||
rtc->rtc->set_start_time = true;
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, rtc->irq, NULL,
|
||||
tps6586x_rtc_irq,
|
||||
IRQF_ONESHOT,
|
||||
@ -294,6 +278,13 @@ static int tps6586x_rtc_probe(struct platform_device *pdev)
|
||||
goto fail_rtc_register;
|
||||
}
|
||||
disable_irq(rtc->irq);
|
||||
|
||||
ret = rtc_register_device(rtc->rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "RTC device register: ret %d\n", ret);
|
||||
goto fail_rtc_register;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail_rtc_register:
|
||||
|
@ -380,6 +380,10 @@ static int tps65910_rtc_probe(struct platform_device *pdev)
|
||||
if (!tps_rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
tps_rtc->rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(tps_rtc->rtc))
|
||||
return PTR_ERR(tps_rtc->rtc);
|
||||
|
||||
/* Clear pending interrupts */
|
||||
ret = regmap_read(tps65910->regmap, TPS65910_RTC_STATUS, &rtc_reg);
|
||||
if (ret < 0)
|
||||
@ -421,10 +425,12 @@ static int tps65910_rtc_probe(struct platform_device *pdev)
|
||||
tps_rtc->irq = irq;
|
||||
device_set_wakeup_capable(&pdev->dev, 1);
|
||||
|
||||
tps_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
|
||||
&tps65910_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(tps_rtc->rtc)) {
|
||||
ret = PTR_ERR(tps_rtc->rtc);
|
||||
tps_rtc->rtc->ops = &tps65910_rtc_ops;
|
||||
tps_rtc->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
|
||||
tps_rtc->rtc->range_max = RTC_TIMESTAMP_END_2099;
|
||||
|
||||
ret = rtc_register_device(tps_rtc->rtc);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "RTC device register: err %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
@ -432,17 +438,6 @@ static int tps65910_rtc_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Disable tps65910 RTC interrupts.
|
||||
* Sets status flag to free.
|
||||
*/
|
||||
static int tps65910_rtc_remove(struct platform_device *pdev)
|
||||
{
|
||||
tps65910_rtc_alarm_irq_enable(&pdev->dev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int tps65910_rtc_suspend(struct device *dev)
|
||||
{
|
||||
@ -468,7 +463,6 @@ static SIMPLE_DEV_PM_OPS(tps65910_rtc_pm_ops, tps65910_rtc_suspend,
|
||||
|
||||
static struct platform_driver tps65910_rtc_driver = {
|
||||
.probe = tps65910_rtc_probe,
|
||||
.remove = tps65910_rtc_remove,
|
||||
.driver = {
|
||||
.name = "tps65910-rtc",
|
||||
.pm = &tps65910_rtc_pm_ops,
|
||||
|
@ -88,7 +88,7 @@ static unsigned int alarm_enabled;
|
||||
static int aie_irq;
|
||||
static int pie_irq;
|
||||
|
||||
static inline unsigned long read_elapsed_second(void)
|
||||
static inline time64_t read_elapsed_second(void)
|
||||
{
|
||||
|
||||
unsigned long first_low, first_mid, first_high;
|
||||
@ -105,10 +105,10 @@ static inline unsigned long read_elapsed_second(void)
|
||||
} while (first_low != second_low || first_mid != second_mid ||
|
||||
first_high != second_high);
|
||||
|
||||
return (first_high << 17) | (first_mid << 1) | (first_low >> 15);
|
||||
return ((u64)first_high << 17) | (first_mid << 1) | (first_low >> 15);
|
||||
}
|
||||
|
||||
static inline void write_elapsed_second(unsigned long sec)
|
||||
static inline void write_elapsed_second(time64_t sec)
|
||||
{
|
||||
spin_lock_irq(&rtc_lock);
|
||||
|
||||
@ -121,22 +121,22 @@ static inline void write_elapsed_second(unsigned long sec)
|
||||
|
||||
static int vr41xx_rtc_read_time(struct device *dev, struct rtc_time *time)
|
||||
{
|
||||
unsigned long epoch_sec, elapsed_sec;
|
||||
time64_t epoch_sec, elapsed_sec;
|
||||
|
||||
epoch_sec = mktime(epoch, 1, 1, 0, 0, 0);
|
||||
epoch_sec = mktime64(epoch, 1, 1, 0, 0, 0);
|
||||
elapsed_sec = read_elapsed_second();
|
||||
|
||||
rtc_time_to_tm(epoch_sec + elapsed_sec, time);
|
||||
rtc_time64_to_tm(epoch_sec + elapsed_sec, time);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vr41xx_rtc_set_time(struct device *dev, struct rtc_time *time)
|
||||
{
|
||||
unsigned long epoch_sec, current_sec;
|
||||
time64_t epoch_sec, current_sec;
|
||||
|
||||
epoch_sec = mktime(epoch, 1, 1, 0, 0, 0);
|
||||
current_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
|
||||
epoch_sec = mktime64(epoch, 1, 1, 0, 0, 0);
|
||||
current_sec = mktime64(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
|
||||
time->tm_hour, time->tm_min, time->tm_sec);
|
||||
|
||||
write_elapsed_second(current_sec - epoch_sec);
|
||||
@ -165,11 +165,11 @@ static int vr41xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
||||
|
||||
static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
||||
{
|
||||
unsigned long alarm_sec;
|
||||
time64_t alarm_sec;
|
||||
struct rtc_time *time = &wkalrm->time;
|
||||
|
||||
alarm_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
|
||||
time->tm_hour, time->tm_min, time->tm_sec);
|
||||
alarm_sec = mktime64(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday,
|
||||
time->tm_hour, time->tm_min, time->tm_sec);
|
||||
|
||||
spin_lock_irq(&rtc_lock);
|
||||
|
||||
@ -292,13 +292,16 @@ static int rtc_probe(struct platform_device *pdev)
|
||||
goto err_rtc1_iounmap;
|
||||
}
|
||||
|
||||
rtc = devm_rtc_device_register(&pdev->dev, rtc_name, &vr41xx_rtc_ops,
|
||||
THIS_MODULE);
|
||||
rtc = devm_rtc_allocate_device(&pdev->dev);
|
||||
if (IS_ERR(rtc)) {
|
||||
retval = PTR_ERR(rtc);
|
||||
goto err_iounmap_all;
|
||||
}
|
||||
|
||||
rtc->ops = &vr41xx_rtc_ops;
|
||||
|
||||
/* 48-bit counter at 32.768 kHz */
|
||||
rtc->range_max = (1ULL << 33) - 1;
|
||||
rtc->max_user_freq = MAX_PERIODIC_RATE;
|
||||
|
||||
spin_lock_irq(&rtc_lock);
|
||||
@ -340,6 +343,10 @@ static int rtc_probe(struct platform_device *pdev)
|
||||
|
||||
dev_info(&pdev->dev, "Real Time Clock of NEC VR4100 series\n");
|
||||
|
||||
retval = rtc_register_device(rtc);
|
||||
if (retval)
|
||||
goto err_iounmap_all;
|
||||
|
||||
return 0;
|
||||
|
||||
err_iounmap_all:
|
||||
|
@ -278,10 +278,9 @@ static int xlnx_rtc_remove(struct platform_device *pdev)
|
||||
|
||||
static int __maybe_unused xlnx_rtc_suspend(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct xlnx_rtc_dev *xrtcdev = platform_get_drvdata(pdev);
|
||||
struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
if (device_may_wakeup(dev))
|
||||
enable_irq_wake(xrtcdev->alarm_irq);
|
||||
else
|
||||
xlnx_rtc_alarm_irq_enable(dev, 0);
|
||||
@ -291,10 +290,9 @@ static int __maybe_unused xlnx_rtc_suspend(struct device *dev)
|
||||
|
||||
static int __maybe_unused xlnx_rtc_resume(struct device *dev)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct xlnx_rtc_dev *xrtcdev = platform_get_drvdata(pdev);
|
||||
struct xlnx_rtc_dev *xrtcdev = dev_get_drvdata(dev);
|
||||
|
||||
if (device_may_wakeup(&pdev->dev))
|
||||
if (device_may_wakeup(dev))
|
||||
disable_irq_wake(xrtcdev->alarm_irq);
|
||||
else
|
||||
xlnx_rtc_alarm_irq_enable(dev, 1);
|
||||
|
@ -285,7 +285,7 @@ void rtc_nvmem_unregister(struct rtc_device *rtc);
|
||||
static inline int rtc_nvmem_register(struct rtc_device *rtc,
|
||||
struct nvmem_config *nvmem_config)
|
||||
{
|
||||
return -ENODEV;
|
||||
return 0;
|
||||
}
|
||||
static inline void rtc_nvmem_unregister(struct rtc_device *rtc) {}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user