304 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Microchip MPFS RTC driver4 *5 * Copyright (c) 2021-2022 Microchip Corporation. All rights reserved.6 *7 * Author: Daire McNamara <daire.mcnamara@microchip.com>8 * & Conor Dooley <conor.dooley@microchip.com>9 */10#include "linux/bits.h"11#include "linux/iopoll.h"12#include <linux/clk.h>13#include <linux/io.h>14#include <linux/module.h>15#include <linux/kernel.h>16#include <linux/of.h>17#include <linux/platform_device.h>18#include <linux/pm_wakeirq.h>19#include <linux/slab.h>20#include <linux/rtc.h>21 22#define CONTROL_REG 0x0023#define MODE_REG 0x0424#define PRESCALER_REG 0x0825#define ALARM_LOWER_REG 0x0c26#define ALARM_UPPER_REG 0x1027#define COMPARE_LOWER_REG 0x1428#define COMPARE_UPPER_REG 0x1829#define DATETIME_LOWER_REG 0x2030#define DATETIME_UPPER_REG 0x2431 32#define CONTROL_RUNNING_BIT BIT(0)33#define CONTROL_START_BIT BIT(0)34#define CONTROL_STOP_BIT BIT(1)35#define CONTROL_ALARM_ON_BIT BIT(2)36#define CONTROL_ALARM_OFF_BIT BIT(3)37#define CONTROL_RESET_BIT BIT(4)38#define CONTROL_UPLOAD_BIT BIT(5)39#define CONTROL_DOWNLOAD_BIT BIT(6)40#define CONTROL_MATCH_BIT BIT(7)41#define CONTROL_WAKEUP_CLR_BIT BIT(8)42#define CONTROL_WAKEUP_SET_BIT BIT(9)43#define CONTROL_UPDATED_BIT BIT(10)44 45#define MODE_CLOCK_CALENDAR BIT(0)46#define MODE_WAKE_EN BIT(1)47#define MODE_WAKE_RESET BIT(2)48#define MODE_WAKE_CONTINUE BIT(3)49 50#define MAX_PRESCALER_COUNT GENMASK(25, 0)51#define DATETIME_UPPER_MASK GENMASK(29, 0)52#define ALARM_UPPER_MASK GENMASK(10, 0)53 54#define UPLOAD_TIMEOUT_US 5055 56struct mpfs_rtc_dev {57 struct rtc_device *rtc;58 void __iomem *base;59};60 61static void mpfs_rtc_start(struct mpfs_rtc_dev *rtcdev)62{63 u32 ctrl;64 65 ctrl = readl(rtcdev->base + CONTROL_REG);66 ctrl &= ~CONTROL_STOP_BIT;67 ctrl |= CONTROL_START_BIT;68 writel(ctrl, rtcdev->base + CONTROL_REG);69}70 71static void mpfs_rtc_clear_irq(struct mpfs_rtc_dev *rtcdev)72{73 u32 val = readl(rtcdev->base + CONTROL_REG);74 75 val &= ~(CONTROL_ALARM_ON_BIT | CONTROL_STOP_BIT);76 val |= CONTROL_ALARM_OFF_BIT;77 writel(val, rtcdev->base + CONTROL_REG);78 /*79 * Ensure that the posted write to the CONTROL_REG register completed before80 * returning from this function. Not doing this may result in the interrupt81 * only being cleared some time after this function returns.82 */83 (void)readl(rtcdev->base + CONTROL_REG);84}85 86static int mpfs_rtc_readtime(struct device *dev, struct rtc_time *tm)87{88 struct mpfs_rtc_dev *rtcdev = dev_get_drvdata(dev);89 u64 time;90 91 time = readl(rtcdev->base + DATETIME_LOWER_REG);92 time |= ((u64)readl(rtcdev->base + DATETIME_UPPER_REG) & DATETIME_UPPER_MASK) << 32;93 rtc_time64_to_tm(time, tm);94 95 return 0;96}97 98static int mpfs_rtc_settime(struct device *dev, struct rtc_time *tm)99{100 struct mpfs_rtc_dev *rtcdev = dev_get_drvdata(dev);101 u32 ctrl, prog;102 u64 time;103 int ret;104 105 time = rtc_tm_to_time64(tm);106 107 writel((u32)time, rtcdev->base + DATETIME_LOWER_REG);108 writel((u32)(time >> 32) & DATETIME_UPPER_MASK, rtcdev->base + DATETIME_UPPER_REG);109 110 ctrl = readl(rtcdev->base + CONTROL_REG);111 ctrl &= ~CONTROL_STOP_BIT;112 ctrl |= CONTROL_UPLOAD_BIT;113 writel(ctrl, rtcdev->base + CONTROL_REG);114 115 ret = read_poll_timeout(readl, prog, prog & CONTROL_UPLOAD_BIT, 0, UPLOAD_TIMEOUT_US,116 false, rtcdev->base + CONTROL_REG);117 if (ret) {118 dev_err(dev, "timed out uploading time to rtc");119 return ret;120 }121 mpfs_rtc_start(rtcdev);122 123 return 0;124}125 126static int mpfs_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)127{128 struct mpfs_rtc_dev *rtcdev = dev_get_drvdata(dev);129 u32 mode = readl(rtcdev->base + MODE_REG);130 u64 time;131 132 alrm->enabled = mode & MODE_WAKE_EN;133 134 time = (u64)readl(rtcdev->base + ALARM_LOWER_REG) << 32;135 time |= (readl(rtcdev->base + ALARM_UPPER_REG) & ALARM_UPPER_MASK);136 rtc_time64_to_tm(time, &alrm->time);137 138 return 0;139}140 141static int mpfs_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)142{143 struct mpfs_rtc_dev *rtcdev = dev_get_drvdata(dev);144 u32 mode, ctrl;145 u64 time;146 147 /* Disable the alarm before updating */148 ctrl = readl(rtcdev->base + CONTROL_REG);149 ctrl |= CONTROL_ALARM_OFF_BIT;150 writel(ctrl, rtcdev->base + CONTROL_REG);151 152 time = rtc_tm_to_time64(&alrm->time);153 154 writel((u32)time, rtcdev->base + ALARM_LOWER_REG);155 writel((u32)(time >> 32) & ALARM_UPPER_MASK, rtcdev->base + ALARM_UPPER_REG);156 157 /* Bypass compare register in alarm mode */158 writel(GENMASK(31, 0), rtcdev->base + COMPARE_LOWER_REG);159 writel(GENMASK(29, 0), rtcdev->base + COMPARE_UPPER_REG);160 161 /* Configure the RTC to enable the alarm. */162 ctrl = readl(rtcdev->base + CONTROL_REG);163 mode = readl(rtcdev->base + MODE_REG);164 if (alrm->enabled) {165 mode = MODE_WAKE_EN | MODE_WAKE_CONTINUE;166 /* Enable the alarm */167 ctrl &= ~CONTROL_ALARM_OFF_BIT;168 ctrl |= CONTROL_ALARM_ON_BIT;169 }170 ctrl &= ~CONTROL_STOP_BIT;171 ctrl |= CONTROL_START_BIT;172 writel(ctrl, rtcdev->base + CONTROL_REG);173 writel(mode, rtcdev->base + MODE_REG);174 175 return 0;176}177 178static int mpfs_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)179{180 struct mpfs_rtc_dev *rtcdev = dev_get_drvdata(dev);181 u32 ctrl;182 183 ctrl = readl(rtcdev->base + CONTROL_REG);184 ctrl &= ~(CONTROL_ALARM_ON_BIT | CONTROL_ALARM_OFF_BIT | CONTROL_STOP_BIT);185 186 if (enabled)187 ctrl |= CONTROL_ALARM_ON_BIT;188 else189 ctrl |= CONTROL_ALARM_OFF_BIT;190 191 writel(ctrl, rtcdev->base + CONTROL_REG);192 193 return 0;194}195 196static irqreturn_t mpfs_rtc_wakeup_irq_handler(int irq, void *dev)197{198 struct mpfs_rtc_dev *rtcdev = dev;199 200 mpfs_rtc_clear_irq(rtcdev);201 202 rtc_update_irq(rtcdev->rtc, 1, RTC_IRQF | RTC_AF);203 204 return IRQ_HANDLED;205}206 207static const struct rtc_class_ops mpfs_rtc_ops = {208 .read_time = mpfs_rtc_readtime,209 .set_time = mpfs_rtc_settime,210 .read_alarm = mpfs_rtc_readalarm,211 .set_alarm = mpfs_rtc_setalarm,212 .alarm_irq_enable = mpfs_rtc_alarm_irq_enable,213};214 215static int mpfs_rtc_probe(struct platform_device *pdev)216{217 struct mpfs_rtc_dev *rtcdev;218 struct clk *clk;219 unsigned long prescaler;220 int wakeup_irq, ret;221 222 rtcdev = devm_kzalloc(&pdev->dev, sizeof(struct mpfs_rtc_dev), GFP_KERNEL);223 if (!rtcdev)224 return -ENOMEM;225 226 platform_set_drvdata(pdev, rtcdev);227 228 rtcdev->rtc = devm_rtc_allocate_device(&pdev->dev);229 if (IS_ERR(rtcdev->rtc))230 return PTR_ERR(rtcdev->rtc);231 232 rtcdev->rtc->ops = &mpfs_rtc_ops;233 234 /* range is capped by alarm max, lower reg is 31:0 & upper is 10:0 */235 rtcdev->rtc->range_max = GENMASK_ULL(42, 0);236 237 clk = devm_clk_get_enabled(&pdev->dev, "rtc");238 if (IS_ERR(clk))239 return PTR_ERR(clk);240 241 rtcdev->base = devm_platform_ioremap_resource(pdev, 0);242 if (IS_ERR(rtcdev->base)) {243 dev_dbg(&pdev->dev, "invalid ioremap resources\n");244 return PTR_ERR(rtcdev->base);245 }246 247 wakeup_irq = platform_get_irq(pdev, 0);248 if (wakeup_irq <= 0) {249 dev_dbg(&pdev->dev, "could not get wakeup irq\n");250 return wakeup_irq;251 }252 ret = devm_request_irq(&pdev->dev, wakeup_irq, mpfs_rtc_wakeup_irq_handler, 0,253 dev_name(&pdev->dev), rtcdev);254 if (ret) {255 dev_dbg(&pdev->dev, "could not request wakeup irq\n");256 return ret;257 }258 259 /* prescaler hardware adds 1 to reg value */260 prescaler = clk_get_rate(devm_clk_get(&pdev->dev, "rtcref")) - 1;261 if (prescaler > MAX_PRESCALER_COUNT) {262 dev_dbg(&pdev->dev, "invalid prescaler %lu\n", prescaler);263 return -EINVAL;264 }265 266 writel(prescaler, rtcdev->base + PRESCALER_REG);267 dev_info(&pdev->dev, "prescaler set to: %lu\n", prescaler);268 269 device_init_wakeup(&pdev->dev, true);270 ret = dev_pm_set_wake_irq(&pdev->dev, wakeup_irq);271 if (ret)272 dev_err(&pdev->dev, "failed to enable irq wake\n");273 274 return devm_rtc_register_device(rtcdev->rtc);275}276 277static void mpfs_rtc_remove(struct platform_device *pdev)278{279 dev_pm_clear_wake_irq(&pdev->dev);280}281 282static const struct of_device_id mpfs_rtc_of_match[] = {283 { .compatible = "microchip,mpfs-rtc" },284 { }285};286 287MODULE_DEVICE_TABLE(of, mpfs_rtc_of_match);288 289static struct platform_driver mpfs_rtc_driver = {290 .probe = mpfs_rtc_probe,291 .remove_new = mpfs_rtc_remove,292 .driver = {293 .name = "mpfs_rtc",294 .of_match_table = mpfs_rtc_of_match,295 },296};297 298module_platform_driver(mpfs_rtc_driver);299 300MODULE_DESCRIPTION("Real time clock for Microchip Polarfire SoC");301MODULE_AUTHOR("Daire McNamara <daire.mcnamara@microchip.com>");302MODULE_AUTHOR("Conor Dooley <conor.dooley@microchip.com>");303MODULE_LICENSE("GPL");304