cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

rtc-digicolor.c (5281B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Real Time Clock driver for Conexant Digicolor
      4 *
      5 * Copyright (C) 2015 Paradox Innovation Ltd.
      6 *
      7 * Author: Baruch Siach <baruch@tkos.co.il>
      8 */
      9
     10#include <linux/io.h>
     11#include <linux/iopoll.h>
     12#include <linux/delay.h>
     13#include <linux/module.h>
     14#include <linux/platform_device.h>
     15#include <linux/rtc.h>
     16#include <linux/of.h>
     17
     18#define DC_RTC_CONTROL		0x0
     19#define DC_RTC_TIME		0x8
     20#define DC_RTC_REFERENCE	0xc
     21#define DC_RTC_ALARM		0x10
     22#define DC_RTC_INTFLAG_CLEAR	0x14
     23#define DC_RTC_INTENABLE	0x16
     24
     25#define DC_RTC_CMD_MASK		0xf
     26#define DC_RTC_GO_BUSY		BIT(7)
     27
     28#define CMD_NOP			0
     29#define CMD_RESET		1
     30#define CMD_WRITE		3
     31#define CMD_READ		4
     32
     33#define CMD_DELAY_US		(10*1000)
     34#define CMD_TIMEOUT_US		(500*CMD_DELAY_US)
     35
     36struct dc_rtc {
     37	struct rtc_device	*rtc_dev;
     38	void __iomem		*regs;
     39};
     40
     41static int dc_rtc_cmds(struct dc_rtc *rtc, const u8 *cmds, int len)
     42{
     43	u8 val;
     44	int i, ret;
     45
     46	for (i = 0; i < len; i++) {
     47		writeb_relaxed((cmds[i] & DC_RTC_CMD_MASK) | DC_RTC_GO_BUSY,
     48			       rtc->regs + DC_RTC_CONTROL);
     49		ret = readb_relaxed_poll_timeout(
     50			rtc->regs + DC_RTC_CONTROL, val,
     51			!(val & DC_RTC_GO_BUSY), CMD_DELAY_US, CMD_TIMEOUT_US);
     52		if (ret < 0)
     53			return ret;
     54	}
     55
     56	return 0;
     57}
     58
     59static int dc_rtc_read(struct dc_rtc *rtc, unsigned long *val)
     60{
     61	static const u8 read_cmds[] = {CMD_READ, CMD_NOP};
     62	u32 reference, time1, time2;
     63	int ret;
     64
     65	ret = dc_rtc_cmds(rtc, read_cmds, ARRAY_SIZE(read_cmds));
     66	if (ret < 0)
     67		return ret;
     68
     69	reference = readl_relaxed(rtc->regs + DC_RTC_REFERENCE);
     70	time1 = readl_relaxed(rtc->regs + DC_RTC_TIME);
     71	/* Read twice to ensure consistency */
     72	while (1) {
     73		time2 = readl_relaxed(rtc->regs + DC_RTC_TIME);
     74		if (time1 == time2)
     75			break;
     76		time1 = time2;
     77	}
     78
     79	*val = reference + time1;
     80	return 0;
     81}
     82
     83static int dc_rtc_write(struct dc_rtc *rtc, u32 val)
     84{
     85	static const u8 write_cmds[] = {CMD_WRITE, CMD_NOP, CMD_RESET, CMD_NOP};
     86
     87	writel_relaxed(val, rtc->regs + DC_RTC_REFERENCE);
     88	return dc_rtc_cmds(rtc, write_cmds, ARRAY_SIZE(write_cmds));
     89}
     90
     91static int dc_rtc_read_time(struct device *dev, struct rtc_time *tm)
     92{
     93	struct dc_rtc *rtc = dev_get_drvdata(dev);
     94	unsigned long now;
     95	int ret;
     96
     97	ret = dc_rtc_read(rtc, &now);
     98	if (ret < 0)
     99		return ret;
    100	rtc_time64_to_tm(now, tm);
    101
    102	return 0;
    103}
    104
    105static int dc_rtc_set_time(struct device *dev, struct rtc_time *tm)
    106{
    107	struct dc_rtc *rtc = dev_get_drvdata(dev);
    108
    109	return dc_rtc_write(rtc, rtc_tm_to_time64(tm));
    110}
    111
    112static int dc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
    113{
    114	struct dc_rtc *rtc = dev_get_drvdata(dev);
    115	u32 alarm_reg, reference;
    116	unsigned long now;
    117	int ret;
    118
    119	alarm_reg = readl_relaxed(rtc->regs + DC_RTC_ALARM);
    120	reference = readl_relaxed(rtc->regs + DC_RTC_REFERENCE);
    121	rtc_time64_to_tm(reference + alarm_reg, &alarm->time);
    122
    123	ret = dc_rtc_read(rtc, &now);
    124	if (ret < 0)
    125		return ret;
    126
    127	alarm->pending = alarm_reg + reference > now;
    128	alarm->enabled = readl_relaxed(rtc->regs + DC_RTC_INTENABLE);
    129
    130	return 0;
    131}
    132
    133static int dc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
    134{
    135	struct dc_rtc *rtc = dev_get_drvdata(dev);
    136	time64_t alarm_time;
    137	u32 reference;
    138
    139	alarm_time = rtc_tm_to_time64(&alarm->time);
    140
    141	reference = readl_relaxed(rtc->regs + DC_RTC_REFERENCE);
    142	writel_relaxed(alarm_time - reference, rtc->regs + DC_RTC_ALARM);
    143
    144	writeb_relaxed(!!alarm->enabled, rtc->regs + DC_RTC_INTENABLE);
    145
    146	return 0;
    147}
    148
    149static int dc_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
    150{
    151	struct dc_rtc *rtc = dev_get_drvdata(dev);
    152
    153	writeb_relaxed(!!enabled, rtc->regs + DC_RTC_INTENABLE);
    154
    155	return 0;
    156}
    157
    158static const struct rtc_class_ops dc_rtc_ops = {
    159	.read_time		= dc_rtc_read_time,
    160	.set_time		= dc_rtc_set_time,
    161	.read_alarm		= dc_rtc_read_alarm,
    162	.set_alarm		= dc_rtc_set_alarm,
    163	.alarm_irq_enable	= dc_rtc_alarm_irq_enable,
    164};
    165
    166static irqreturn_t dc_rtc_irq(int irq, void *dev_id)
    167{
    168	struct dc_rtc *rtc = dev_id;
    169
    170	writeb_relaxed(1, rtc->regs + DC_RTC_INTFLAG_CLEAR);
    171	rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF);
    172
    173	return IRQ_HANDLED;
    174}
    175
    176static int __init dc_rtc_probe(struct platform_device *pdev)
    177{
    178	struct dc_rtc *rtc;
    179	int irq, ret;
    180
    181	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
    182	if (!rtc)
    183		return -ENOMEM;
    184
    185	rtc->regs = devm_platform_ioremap_resource(pdev, 0);
    186	if (IS_ERR(rtc->regs))
    187		return PTR_ERR(rtc->regs);
    188
    189	rtc->rtc_dev = devm_rtc_allocate_device(&pdev->dev);
    190	if (IS_ERR(rtc->rtc_dev))
    191		return PTR_ERR(rtc->rtc_dev);
    192
    193	irq = platform_get_irq(pdev, 0);
    194	if (irq < 0)
    195		return irq;
    196	ret = devm_request_irq(&pdev->dev, irq, dc_rtc_irq, 0, pdev->name, rtc);
    197	if (ret < 0)
    198		return ret;
    199
    200	platform_set_drvdata(pdev, rtc);
    201
    202	rtc->rtc_dev->ops = &dc_rtc_ops;
    203	rtc->rtc_dev->range_max = U32_MAX;
    204
    205	return devm_rtc_register_device(rtc->rtc_dev);
    206}
    207
    208static const __maybe_unused struct of_device_id dc_dt_ids[] = {
    209	{ .compatible = "cnxt,cx92755-rtc" },
    210	{ /* sentinel */ }
    211};
    212MODULE_DEVICE_TABLE(of, dc_dt_ids);
    213
    214static struct platform_driver dc_rtc_driver = {
    215	.driver = {
    216		.name = "digicolor_rtc",
    217		.of_match_table = of_match_ptr(dc_dt_ids),
    218	},
    219};
    220module_platform_driver_probe(dc_rtc_driver, dc_rtc_probe);
    221
    222MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
    223MODULE_DESCRIPTION("Conexant Digicolor Realtime Clock Driver (RTC)");
    224MODULE_LICENSE("GPL");