brintos

brintos / linux-shallow public Read only

0
0
Text · 8.0 KiB · 5b96a6d Raw
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