1 // SPDX-License-Identifier: GPL-2.0-only 2 #include <linux/limits.h> 3 #include <linux/platform_device.h> 4 #include <linux/rtc.h> 5 6 #include <linux/mfd/88pm886.h> 7 8 /* 9 * Time is calculated as the sum of a 32-bit read-only advancing counter and a 10 * writeable constant offset stored in the chip's spare registers. 11 */ 12 13 static int pm886_rtc_read_time(struct device *dev, struct rtc_time *tm) 14 { 15 struct regmap *regmap = dev_get_drvdata(dev); 16 u32 time; 17 u32 buf; 18 int ret; 19 20 ret = regmap_bulk_read(regmap, PM886_REG_RTC_SPARE1, &buf, 4); 21 if (ret) 22 return ret; 23 time = buf; 24 25 ret = regmap_bulk_read(regmap, PM886_REG_RTC_CNT1, &buf, 4); 26 if (ret) 27 return ret; 28 time += buf; 29 30 rtc_time64_to_tm(time, tm); 31 32 return 0; 33 } 34 35 static int pm886_rtc_set_time(struct device *dev, struct rtc_time *tm) 36 { 37 struct regmap *regmap = dev_get_drvdata(dev); 38 u32 buf; 39 int ret; 40 41 ret = regmap_bulk_read(regmap, PM886_REG_RTC_CNT1, &buf, 4); 42 if (ret) 43 return ret; 44 45 buf = rtc_tm_to_time64(tm) - buf; 46 47 return regmap_bulk_write(regmap, PM886_REG_RTC_SPARE1, &buf, 4); 48 } 49 50 static const struct rtc_class_ops pm886_rtc_ops = { 51 .read_time = pm886_rtc_read_time, 52 .set_time = pm886_rtc_set_time, 53 }; 54 55 static int pm886_rtc_probe(struct platform_device *pdev) 56 { 57 struct pm886_chip *chip = dev_get_drvdata(pdev->dev.parent); 58 struct device *dev = &pdev->dev; 59 struct rtc_device *rtc; 60 int ret; 61 62 platform_set_drvdata(pdev, chip->regmap); 63 64 rtc = devm_rtc_allocate_device(dev); 65 if (IS_ERR(rtc)) 66 return dev_err_probe(dev, PTR_ERR(rtc), 67 "Failed to allocate RTC device\n"); 68 69 rtc->ops = &pm886_rtc_ops; 70 rtc->range_max = U32_MAX; 71 72 ret = devm_rtc_register_device(rtc); 73 if (ret) 74 return dev_err_probe(dev, ret, "Failed to register RTC device\n"); 75 76 return 0; 77 } 78 79 static const struct platform_device_id pm886_rtc_id_table[] = { 80 { .name = "88pm886-rtc" }, 81 { } 82 }; 83 MODULE_DEVICE_TABLE(platform, pm886_rtc_id_table); 84 85 static struct platform_driver pm886_rtc_driver = { 86 .driver = { 87 .name = "88pm886-rtc", 88 }, 89 .probe = pm886_rtc_probe, 90 .id_table = pm886_rtc_id_table, 91 }; 92 module_platform_driver(pm886_rtc_driver); 93 94 MODULE_DESCRIPTION("Marvell 88PM886 RTC driver"); 95 MODULE_AUTHOR("Karel Balej <balejk@matfyz.cz>"); 96 MODULE_LICENSE("GPL"); 97