Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2018, Fuzhou Rockchip Electronics Co., Ltd
 * Author:  Jeffy Chen <jeffy.chen@rock-chips.com>
 *
 * Base on the Rockchip timer driver drivers/clocksource/rockchip_timer.c by
 * Daniel Lezcano <daniel.lezcano@linaro.org>
 */

#include <linux/clk.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/rtc.h>

#define DRV_NAME		"rk-timer-rtc"

#define TIMER_LOAD_COUNT0	0x00
#define TIMER_LOAD_COUNT1	0x04
#define TIMER_CURRENT_VALUE0	0x08
#define TIMER_CURRENT_VALUE1	0x0C
#define TIMER_CONTROL_REG3288	0x10
#define TIMER_INT_STATUS	0x18

#define TIMER_ENABLE			BIT(0)
#define TIMER_MODE_USER_DEFINED_COUNT	BIT(1)
#define TIMER_INT_UNMASK		BIT(2)

/* Forbid any alarms which would trigger inside the threshold */
#define TIMER_ALARM_THRESHOLD_MS	10

#if !defined(UINT64_MAX)
	#define UINT64_MAX ((u64)-1)
#endif

/**
 * struct rk_timer_rtc_data - Differences between SoC variants
 *
 * @ctrl_reg_offset: The offset of timer control register
 */
struct rk_timer_rtc_data {
	int ctrl_reg_offset;
};

/**
 * struct rk_timer_rtc - Driver data for Rockchip timer RTC
 *
 * @data: Pointer to rk_timer_rtc_data
 * @regmap: Register map of the timer
 * @rtc: Pointer to RTC device
 * @clk: The timer clock
 * @pclk: The peripheral clock
 * @freq: The freq of timer clock
 * @timebase: The base time of the timer RTC
 * @alarm_irq_enabled: Whether to report alarm irqs
 * @irq: The timer IRQ number
 */
struct rk_timer_rtc {
	const struct rk_timer_rtc_data *data;
	struct regmap *regmap;
	struct rtc_device *rtc;
	struct clk *clk;
	struct clk *pclk;
	u32 freq;
	u64 timebase;
	int alarm_irq_enabled;
	int irq;
};

static inline u64 tick_to_sec(struct rk_timer_rtc *rk_timer_rtc, u64 tick)
{
	do_div(tick, rk_timer_rtc->freq);
	return tick;
}

static inline u64 ms_to_tick(struct rk_timer_rtc *rk_timer_rtc, int ms)
{
	return ms * rk_timer_rtc->freq / 1000;
}

static inline u64 tick_to_time64(struct rk_timer_rtc *rk_timer_rtc, u64 tick)
{
	return tick_to_sec(rk_timer_rtc, tick) + rk_timer_rtc->timebase;
}

static inline u64 time64_to_tick(struct rk_timer_rtc *rk_timer_rtc, u64 time)
{
	return (time - rk_timer_rtc->timebase) * rk_timer_rtc->freq;
}

static inline int rk_timer_rtc_write64(struct rk_timer_rtc *rk_timer_rtc,
				       u32 reg, u64 val)
{
	return regmap_bulk_write(rk_timer_rtc->regmap, reg, &val, 2);
}

static inline int rk_timer_rtc_read64(struct rk_timer_rtc *rk_timer_rtc,
				      u32 reg, u64 *val)
{
	u32 val_lo, val_hi, tmp_hi;
	int ret;

	do {
		ret = regmap_read(rk_timer_rtc->regmap, reg + 4, &val_hi);
		if (ret)
			return ret;

		ret = regmap_read(rk_timer_rtc->regmap, reg, &val_lo);
		if (ret)
			return ret;

		ret = regmap_read(rk_timer_rtc->regmap, reg + 4, &tmp_hi);
		if (ret)
			return ret;
	} while (val_hi != tmp_hi);

	*val = ((u64) val_hi << 32) | val_lo;

	return 0;
}

static inline int rk_timer_rtc_irq_clear(struct rk_timer_rtc *rk_timer_rtc)
{
	return regmap_write(rk_timer_rtc->regmap, TIMER_INT_STATUS, 1);
}

static inline int rk_timer_rtc_irq_enable(struct rk_timer_rtc *rk_timer_rtc,
					  unsigned int enabled)
{
	/* Clear any pending irq before enable it */
	if (enabled)
		rk_timer_rtc_irq_clear(rk_timer_rtc);

	return regmap_update_bits(rk_timer_rtc->regmap,
				  rk_timer_rtc->data->ctrl_reg_offset,
				  TIMER_INT_UNMASK,
				  enabled ? TIMER_INT_UNMASK : 0);
}

static int rk_timer_rtc_reset(struct rk_timer_rtc *rk_timer_rtc)
{
	int ret;

	ret = regmap_write(rk_timer_rtc->regmap,
			   rk_timer_rtc->data->ctrl_reg_offset, 0);
	if (ret)
		return ret;

	/* Init load count to UINT64_MAX to keep timer running */
	ret = rk_timer_rtc_write64(rk_timer_rtc, TIMER_LOAD_COUNT0, UINT64_MAX);
	if (ret)
		return ret;

	/* Clear any pending irq before enable it */
	rk_timer_rtc_irq_clear(rk_timer_rtc);

	/* Enable timer in user-defined count mode with irq unmasked */
	return regmap_write(rk_timer_rtc->regmap,
			    rk_timer_rtc->data->ctrl_reg_offset,
			    TIMER_ENABLE | TIMER_MODE_USER_DEFINED_COUNT |
				TIMER_INT_UNMASK);
}

static int rk_timer_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
	struct rk_timer_rtc *rk_timer_rtc = dev_get_drvdata(dev);
	int ret;
	u64 tick;

	ret = rk_timer_rtc_read64(rk_timer_rtc, TIMER_CURRENT_VALUE0, &tick);
	if (ret)
		return ret;

	rtc_time64_to_tm(tick_to_time64(rk_timer_rtc, tick), tm);

	dev_dbg(dev, "Read RTC: %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
		1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
		tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);

	return rtc_valid_tm(tm);
}

static int rk_timer_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
	struct rk_timer_rtc *rk_timer_rtc = dev_get_drvdata(dev);
	int ret;

	dev_dbg(dev, "Set RTC:%4d-%02d-%02d(%d) %02d:%02d:%02d\n",
		1900 + tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
		tm->tm_wday, tm->tm_hour, tm->tm_min, tm->tm_sec);

	ret = rtc_valid_tm(tm);
	if (ret)
		return ret;

	rk_timer_rtc->timebase = rtc_tm_to_time64(tm);

	dev_dbg(dev, "Setting new timebase:%lld\n", rk_timer_rtc->timebase);

	/* Restart timer for new timebase */
	ret = rk_timer_rtc_reset(rk_timer_rtc);
	if (ret) {
		dev_err(dev, "Failed to reset timer:%d\n", ret);
		return ret;
	}

	/* Tell framework to check alarms */
	rtc_update_irq(rk_timer_rtc->rtc, 1, RTC_IRQF | RTC_AF);

	return 0;
}

static int rk_timer_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
	struct rk_timer_rtc *rk_timer_rtc = dev_get_drvdata(dev);
	int ret;
	u64 tick;

	ret = rk_timer_rtc_read64(rk_timer_rtc, TIMER_LOAD_COUNT0, &tick);
	if (ret)
		return ret;

	rtc_time64_to_tm(tick_to_time64(rk_timer_rtc, tick), &alrm->time);

	dev_dbg(dev, "Read alarm: %4d-%02d-%02d(%d) %02d:%02d:%02d\n",
		1900 + alrm->time.tm_year, alrm->time.tm_mon + 1,
		alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour,
		alrm->time.tm_min, alrm->time.tm_sec);

	return rtc_valid_tm(&alrm->time);
}

static int rk_timer_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
	struct rk_timer_rtc *rk_timer_rtc = dev_get_drvdata(dev);
	int ret;
	u64 alarm_tick, alarm_threshold_tick, cur_tick;

	dev_dbg(dev, "Set alarm:%4d-%02d-%02d(%d) %02d:%02d:%02d\n",
		1900 + alrm->time.tm_year, alrm->time.tm_mon + 1,
		alrm->time.tm_mday, alrm->time.tm_wday, alrm->time.tm_hour,
		alrm->time.tm_min, alrm->time.tm_sec);

	ret = rtc_valid_tm(&alrm->time);
	if (ret)
		return ret;

	rk_timer_rtc->alarm_irq_enabled = false;

	alarm_tick = time64_to_tick(rk_timer_rtc,
				    rtc_tm_to_time64(&alrm->time));

	ret = rk_timer_rtc_read64(rk_timer_rtc, TIMER_CURRENT_VALUE0,
				  &cur_tick);
	if (ret)
		return ret;

	/* Don't set an alarm in the past or about to pass */
	alarm_threshold_tick = ms_to_tick(rk_timer_rtc,
					  TIMER_ALARM_THRESHOLD_MS);
	if (alarm_tick <= (cur_tick + alarm_threshold_tick))
		return -ETIME;

	/*
	 * When the current value counts up to the load count, the timer will
	 * stop and generate an irq.
	 */
	ret = rk_timer_rtc_write64(rk_timer_rtc, TIMER_LOAD_COUNT0, alarm_tick);
	if (ret)
		return ret;

	dev_dbg(dev, "New alarm enabled:%d\n", alrm->enabled);
	rk_timer_rtc->alarm_irq_enabled = alrm->enabled;

	return 0;
}

static int rk_timer_rtc_alarm_irq_enable(struct device *dev,
					 unsigned int enabled)
{
	struct rk_timer_rtc *rk_timer_rtc = dev_get_drvdata(dev);

	dev_dbg(dev, "Set alarm irq enabled:%d\n", enabled);
	rk_timer_rtc->alarm_irq_enabled = enabled;

	return 0;
}

static irqreturn_t rk_timer_rtc_alarm_irq(int irq, void *data)
{
	struct device *dev = data;
	struct rk_timer_rtc *rk_timer_rtc = dev_get_drvdata(dev);
	int ret;

	dev_dbg(dev, "Received timer irq, alarm_irq_enabled:%d\n",
		rk_timer_rtc->alarm_irq_enabled);

	/* The timer is stopped now, reset the load count to start it again */
	ret = rk_timer_rtc_write64(rk_timer_rtc, TIMER_LOAD_COUNT0, UINT64_MAX);
	if (ret)
		dev_err(dev, "Failed to set load count:%d\n", ret);

	ret = regmap_write(rk_timer_rtc->regmap, TIMER_INT_STATUS, 1);
	if (ret)
		dev_err(dev, "Failed to clear irq:%d\n", ret);

	/* Only report rtc irq when alarm irq is enabled */
	if (rk_timer_rtc->alarm_irq_enabled)
		rtc_update_irq(rk_timer_rtc->rtc, 1, RTC_IRQF | RTC_AF);

	return IRQ_HANDLED;
}

static const struct rtc_class_ops rk_timer_rtc_ops = {
	.read_time = rk_timer_rtc_read_time,
	.set_time = rk_timer_rtc_set_time,
	.read_alarm = rk_timer_rtc_read_alarm,
	.set_alarm = rk_timer_rtc_set_alarm,
	.alarm_irq_enable = rk_timer_rtc_alarm_irq_enable,
};

static struct regmap_config rk_timer_regmap_config = {
	.name		= DRV_NAME,
	.reg_bits	= 32,
	.val_bits	= 32,
	.reg_stride	= 4,
};

static const struct of_device_id rk_timer_rtc_dt_match[];

static int rk_timer_rtc_probe(struct platform_device *pdev)
{
	const struct of_device_id *match;
	struct device *dev = &pdev->dev;
	struct rk_timer_rtc *rk_timer_rtc;
	void __iomem *base;
	resource_size_t size;
	int ret;

	rk_timer_rtc = devm_kzalloc(dev, sizeof(*rk_timer_rtc), GFP_KERNEL);
	if (!rk_timer_rtc)
		return -ENOMEM;

	match = of_match_node(rk_timer_rtc_dt_match, dev->of_node);
	rk_timer_rtc->data = match->data;

	platform_set_drvdata(pdev, rk_timer_rtc);

	base = devm_of_iomap(dev, dev->of_node, 0, &size);
	if (!base) {
		dev_err(dev, "Failed to iomap\n");
		return -EINVAL;
	}

	rk_timer_regmap_config.max_register = size - 4;
	rk_timer_rtc->regmap = devm_regmap_init_mmio(dev, base,
						     &rk_timer_regmap_config);
	if (IS_ERR(rk_timer_rtc->regmap)) {
		ret = PTR_ERR(rk_timer_rtc->regmap);
		dev_err(dev, "Failed to init regmap:%d\n", ret);
		return ret;
	}

	rk_timer_rtc->irq = platform_get_irq(pdev, 0);
	if (rk_timer_rtc->irq < 0) {
		ret = rk_timer_rtc->irq;
		dev_err(dev, "Failed to get irq:%d\n", ret);
		return ret;
	}

	ret = devm_request_irq(dev, rk_timer_rtc->irq, rk_timer_rtc_alarm_irq,
			       0, dev_name(dev), dev);
	if (ret) {
		dev_err(dev, "Failed to request irq:%d\n", ret);
		return ret;
	}

	rk_timer_rtc->pclk = devm_clk_get(dev, "pclk");
	if (IS_ERR(rk_timer_rtc->pclk)) {
		ret = PTR_ERR(rk_timer_rtc->pclk);
		pr_err("Failed to get timer pclk:%d\n", ret);
		return ret;
	}

	ret = clk_prepare_enable(rk_timer_rtc->pclk);
	if (ret) {
		dev_err(dev, "Failed to enable pclk:%d\n", ret);
		return ret;
	}

	rk_timer_rtc->clk = devm_clk_get(dev, "timer");
	if (IS_ERR(rk_timer_rtc->clk)) {
		ret = PTR_ERR(rk_timer_rtc->clk);
		pr_err("Failed to get timer clk:%d\n", ret);
		goto err_disable_pclk;
	}

	ret = clk_prepare_enable(rk_timer_rtc->clk);
	if (ret) {
		dev_err(dev, "Failed to enable timer clk:%d\n", ret);
		goto err_disable_pclk;
	}

	rk_timer_rtc->freq = clk_get_rate(rk_timer_rtc->clk);
	dev_dbg(dev, "RTC timer freq:%d\n", rk_timer_rtc->freq);

	ret = rk_timer_rtc_reset(rk_timer_rtc);
	if (ret) {
		dev_err(dev, "Failed to reset timer:%d\n", ret);
		goto err_disable_clk;
	}

	ret = device_init_wakeup(dev, true);
	if (ret) {
		dev_err(dev, "Failed to init wakeup:%d\n", ret);
		goto err_disable_irq;
	}

	rk_timer_rtc->rtc = devm_rtc_device_register(dev, DRV_NAME,
						     &rk_timer_rtc_ops,
						     THIS_MODULE);
	if (IS_ERR(rk_timer_rtc->rtc)) {
		ret = PTR_ERR(rk_timer_rtc->rtc);
		dev_err(dev, "Failed to register rtc:%d\n", ret);
		goto err_uninit_wakeup;
	}

	return 0;
err_uninit_wakeup:
	device_init_wakeup(&pdev->dev, false);
err_disable_irq:
	rk_timer_rtc_irq_enable(rk_timer_rtc, false);
err_disable_clk:
	clk_disable_unprepare(rk_timer_rtc->clk);
err_disable_pclk:
	clk_disable_unprepare(rk_timer_rtc->pclk);
	return ret;
}

static int rk_timer_rtc_remove(struct platform_device *pdev)
{
	struct rk_timer_rtc *rk_timer_rtc = dev_get_drvdata(&pdev->dev);

	device_init_wakeup(&pdev->dev, false);
	rk_timer_rtc_irq_enable(rk_timer_rtc, false);
	clk_disable_unprepare(rk_timer_rtc->clk);
	clk_disable_unprepare(rk_timer_rtc->pclk);

	return 0;
}

#ifdef CONFIG_PM_SLEEP
static int rk_timer_rtc_suspend(struct device *dev)
{
	struct rk_timer_rtc *rk_timer_rtc = dev_get_drvdata(dev);

	if (device_may_wakeup(dev))
		enable_irq_wake(rk_timer_rtc->irq);

	return 0;
}

static int rk_timer_rtc_resume(struct device *dev)
{
	struct rk_timer_rtc *rk_timer_rtc = dev_get_drvdata(dev);

	if (device_may_wakeup(dev))
		disable_irq_wake(rk_timer_rtc->irq);

	return 0;
}
#endif

static SIMPLE_DEV_PM_OPS(rk_timer_rtc_pm_ops, rk_timer_rtc_suspend,
			 rk_timer_rtc_resume);

static const struct rk_timer_rtc_data rk3288_timer_rtc_data = {
	.ctrl_reg_offset = TIMER_CONTROL_REG3288,
};

static const struct of_device_id rk_timer_rtc_dt_match[] = {
	{
		.compatible = "rockchip,rk3308-timer-rtc",
		.data = &rk3288_timer_rtc_data,
	},
	{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, rk_timer_rtc_dt_match);

static struct platform_driver rk_timer_rtc_driver = {
	.probe = rk_timer_rtc_probe,
	.remove = rk_timer_rtc_remove,
	.driver = {
		.name = DRV_NAME,
		.pm = &rk_timer_rtc_pm_ops,
		.of_match_table = of_match_ptr(rk_timer_rtc_dt_match),
	},
};

module_platform_driver(rk_timer_rtc_driver);

MODULE_DESCRIPTION("RTC driver for the rockchip timer");
MODULE_AUTHOR("Jeffy Chen <jeffy.chen@rock-chips.com>");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("platform:" DRV_NAME);