Skip to content

Commit 3ca0495

Browse files
jhovoldalexandrebelloni
authored andcommitted
rtc: pm8xxx: add support for nvmem offset
On many Qualcomm platforms the PMIC RTC control and time registers are read-only so that the RTC time can not be updated. Instead an offset needs be stored in some machine-specific non-volatile memory, which the driver can take into account. Add support for storing a 32-bit offset from the Epoch in an nvmem cell so that the RTC time can be set on such platforms. Signed-off-by: Johan Hovold <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexandre Belloni <[email protected]>
1 parent 430aa33 commit 3ca0495

File tree

1 file changed

+129
-12
lines changed

1 file changed

+129
-12
lines changed

drivers/rtc/rtc-pm8xxx.c

Lines changed: 129 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
// SPDX-License-Identifier: GPL-2.0-only
2-
/* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
2+
/*
3+
* pm8xxx RTC driver
4+
*
5+
* Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
6+
* Copyright (c) 2023, Linaro Limited
37
*/
48
#include <linux/of.h>
59
#include <linux/module.h>
10+
#include <linux/nvmem-consumer.h>
611
#include <linux/init.h>
712
#include <linux/rtc.h>
813
#include <linux/platform_device.h>
@@ -49,6 +54,8 @@ struct pm8xxx_rtc_regs {
4954
* @alarm_irq: alarm irq number
5055
* @regs: register description
5156
* @dev: device structure
57+
* @nvmem_cell: nvmem cell for offset
58+
* @offset: offset from epoch in seconds
5259
*/
5360
struct pm8xxx_rtc {
5461
struct rtc_device *rtc;
@@ -57,8 +64,60 @@ struct pm8xxx_rtc {
5764
int alarm_irq;
5865
const struct pm8xxx_rtc_regs *regs;
5966
struct device *dev;
67+
struct nvmem_cell *nvmem_cell;
68+
u32 offset;
6069
};
6170

71+
static int pm8xxx_rtc_read_nvmem_offset(struct pm8xxx_rtc *rtc_dd)
72+
{
73+
size_t len;
74+
void *buf;
75+
int rc;
76+
77+
buf = nvmem_cell_read(rtc_dd->nvmem_cell, &len);
78+
if (IS_ERR(buf)) {
79+
rc = PTR_ERR(buf);
80+
dev_dbg(rtc_dd->dev, "failed to read nvmem offset: %d\n", rc);
81+
return rc;
82+
}
83+
84+
if (len != sizeof(u32)) {
85+
dev_dbg(rtc_dd->dev, "unexpected nvmem cell size %zu\n", len);
86+
kfree(buf);
87+
return -EINVAL;
88+
}
89+
90+
rtc_dd->offset = get_unaligned_le32(buf);
91+
92+
kfree(buf);
93+
94+
return 0;
95+
}
96+
97+
static int pm8xxx_rtc_write_nvmem_offset(struct pm8xxx_rtc *rtc_dd, u32 offset)
98+
{
99+
u8 buf[sizeof(u32)];
100+
int rc;
101+
102+
put_unaligned_le32(offset, buf);
103+
104+
rc = nvmem_cell_write(rtc_dd->nvmem_cell, buf, sizeof(buf));
105+
if (rc < 0) {
106+
dev_dbg(rtc_dd->dev, "failed to write nvmem offset: %d\n", rc);
107+
return rc;
108+
}
109+
110+
return 0;
111+
}
112+
113+
static int pm8xxx_rtc_read_offset(struct pm8xxx_rtc *rtc_dd)
114+
{
115+
if (!rtc_dd->nvmem_cell)
116+
return 0;
117+
118+
return pm8xxx_rtc_read_nvmem_offset(rtc_dd);
119+
}
120+
62121
static int pm8xxx_rtc_read_raw(struct pm8xxx_rtc *rtc_dd, u32 *secs)
63122
{
64123
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
@@ -90,6 +149,33 @@ static int pm8xxx_rtc_read_raw(struct pm8xxx_rtc *rtc_dd, u32 *secs)
90149
return 0;
91150
}
92151

152+
static int pm8xxx_rtc_update_offset(struct pm8xxx_rtc *rtc_dd, u32 secs)
153+
{
154+
u32 raw_secs;
155+
u32 offset;
156+
int rc;
157+
158+
if (!rtc_dd->nvmem_cell)
159+
return -ENODEV;
160+
161+
rc = pm8xxx_rtc_read_raw(rtc_dd, &raw_secs);
162+
if (rc)
163+
return rc;
164+
165+
offset = secs - raw_secs;
166+
167+
if (offset == rtc_dd->offset)
168+
return 0;
169+
170+
rc = pm8xxx_rtc_write_nvmem_offset(rtc_dd, offset);
171+
if (rc)
172+
return rc;
173+
174+
rtc_dd->offset = offset;
175+
176+
return 0;
177+
}
178+
93179
/*
94180
* Steps to write the RTC registers.
95181
* 1. Disable alarm if enabled.
@@ -99,23 +185,15 @@ static int pm8xxx_rtc_read_raw(struct pm8xxx_rtc *rtc_dd, u32 *secs)
99185
* 5. Enable rtc if disabled in step 2.
100186
* 6. Enable alarm if disabled in step 1.
101187
*/
102-
static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
188+
static int __pm8xxx_rtc_set_time(struct pm8xxx_rtc *rtc_dd, u32 secs)
103189
{
104-
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
105190
const struct pm8xxx_rtc_regs *regs = rtc_dd->regs;
106191
u8 value[NUM_8_BIT_RTC_REGS];
107192
bool alarm_enabled;
108-
u32 secs;
109193
int rc;
110194

111-
if (!rtc_dd->allow_set_time)
112-
return -ENODEV;
113-
114-
secs = rtc_tm_to_time64(tm);
115195
put_unaligned_le32(secs, value);
116196

117-
dev_dbg(dev, "set time: %ptRd %ptRt (%u)\n", tm, tm, secs);
118-
119197
rc = regmap_update_bits_check(rtc_dd->regmap, regs->alarm_ctrl,
120198
regs->alarm_en, 0, &alarm_enabled);
121199
if (rc)
@@ -158,6 +236,27 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
158236
return 0;
159237
}
160238

239+
static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
240+
{
241+
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
242+
u32 secs;
243+
int rc;
244+
245+
secs = rtc_tm_to_time64(tm);
246+
247+
if (rtc_dd->allow_set_time)
248+
rc = __pm8xxx_rtc_set_time(rtc_dd, secs);
249+
else
250+
rc = pm8xxx_rtc_update_offset(rtc_dd, secs);
251+
252+
if (rc)
253+
return rc;
254+
255+
dev_dbg(dev, "set time: %ptRd %ptRt (%u + %u)\n", tm, tm,
256+
secs - rtc_dd->offset, rtc_dd->offset);
257+
return 0;
258+
}
259+
161260
static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
162261
{
163262
struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev);
@@ -168,10 +267,11 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
168267
if (rc)
169268
return rc;
170269

270+
secs += rtc_dd->offset;
171271
rtc_time64_to_tm(secs, tm);
172272

173-
dev_dbg(dev, "read time: %ptRd %ptRt (%u)\n", tm, tm, secs);
174-
273+
dev_dbg(dev, "read time: %ptRd %ptRt (%u + %u)\n", tm, tm,
274+
secs - rtc_dd->offset, rtc_dd->offset);
175275
return 0;
176276
}
177277

@@ -184,6 +284,7 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
184284
int rc;
185285

186286
secs = rtc_tm_to_time64(&alarm->time);
287+
secs -= rtc_dd->offset;
187288
put_unaligned_le32(secs, value);
188289

189290
rc = regmap_update_bits(rtc_dd->regmap, regs->alarm_ctrl,
@@ -223,6 +324,7 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
223324
return rc;
224325

225326
secs = get_unaligned_le32(value);
327+
secs += rtc_dd->offset;
226328
rtc_time64_to_tm(secs, &alarm->time);
227329

228330
rc = regmap_read(rtc_dd->regmap, regs->alarm_ctrl, &ctrl_reg);
@@ -378,9 +480,23 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)
378480
rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node,
379481
"allow-set-time");
380482

483+
rtc_dd->nvmem_cell = devm_nvmem_cell_get(&pdev->dev, "offset");
484+
if (IS_ERR(rtc_dd->nvmem_cell)) {
485+
rc = PTR_ERR(rtc_dd->nvmem_cell);
486+
if (rc != -ENOENT)
487+
return rc;
488+
rtc_dd->nvmem_cell = NULL;
489+
}
490+
381491
rtc_dd->regs = match->data;
382492
rtc_dd->dev = &pdev->dev;
383493

494+
if (!rtc_dd->allow_set_time) {
495+
rc = pm8xxx_rtc_read_offset(rtc_dd);
496+
if (rc)
497+
return rc;
498+
}
499+
384500
rc = pm8xxx_rtc_enable(rtc_dd);
385501
if (rc)
386502
return rc;
@@ -435,3 +551,4 @@ MODULE_ALIAS("platform:rtc-pm8xxx");
435551
MODULE_DESCRIPTION("PMIC8xxx RTC driver");
436552
MODULE_LICENSE("GPL v2");
437553
MODULE_AUTHOR("Anirudh Ghayal <[email protected]>");
554+
MODULE_AUTHOR("Johan Hovold <[email protected]>");

0 commit comments

Comments
 (0)