1 // SPDX-License-Identifier: GPL-2.0-only
2 #include <linux/limits.h>
3 #include <linux/mod_devicetable.h>
4 #include <linux/platform_device.h>
7 #include <linux/mfd/88pm886.h>
10 * Time is calculated as the sum of a 32-bit read-only advancing counter and a
11 * writeable constant offset stored in the chip's spare registers.
14 static int pm886_rtc_read_time(struct device
*dev
, struct rtc_time
*tm
)
16 struct regmap
*regmap
= dev_get_drvdata(dev
);
21 ret
= regmap_bulk_read(regmap
, PM886_REG_RTC_SPARE1
, &buf
, 4);
26 ret
= regmap_bulk_read(regmap
, PM886_REG_RTC_CNT1
, &buf
, 4);
31 rtc_time64_to_tm(time
, tm
);
36 static int pm886_rtc_set_time(struct device
*dev
, struct rtc_time
*tm
)
38 struct regmap
*regmap
= dev_get_drvdata(dev
);
42 ret
= regmap_bulk_read(regmap
, PM886_REG_RTC_CNT1
, &buf
, 4);
46 buf
= rtc_tm_to_time64(tm
) - buf
;
48 return regmap_bulk_write(regmap
, PM886_REG_RTC_SPARE1
, &buf
, 4);
51 static const struct rtc_class_ops pm886_rtc_ops
= {
52 .read_time
= pm886_rtc_read_time
,
53 .set_time
= pm886_rtc_set_time
,
56 static int pm886_rtc_probe(struct platform_device
*pdev
)
58 struct pm886_chip
*chip
= dev_get_drvdata(pdev
->dev
.parent
);
59 struct device
*dev
= &pdev
->dev
;
60 struct rtc_device
*rtc
;
63 platform_set_drvdata(pdev
, chip
->regmap
);
65 rtc
= devm_rtc_allocate_device(dev
);
67 return dev_err_probe(dev
, PTR_ERR(rtc
),
68 "Failed to allocate RTC device\n");
70 rtc
->ops
= &pm886_rtc_ops
;
71 rtc
->range_max
= U32_MAX
;
73 ret
= devm_rtc_register_device(rtc
);
75 return dev_err_probe(dev
, ret
, "Failed to register RTC device\n");
80 static const struct platform_device_id pm886_rtc_id_table
[] = {
84 MODULE_DEVICE_TABLE(platform
, pm886_rtc_id_table
);
86 static struct platform_driver pm886_rtc_driver
= {
88 .name
= "88pm886-rtc",
90 .probe
= pm886_rtc_probe
,
91 .id_table
= pm886_rtc_id_table
,
93 module_platform_driver(pm886_rtc_driver
);
95 MODULE_DESCRIPTION("Marvell 88PM886 RTC driver");
96 MODULE_AUTHOR("Karel Balej <balejk@matfyz.cz>");
97 MODULE_LICENSE("GPL");