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-mc13xxx.c (8141B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Real Time Clock driver for Freescale MC13XXX PMIC
      4 *
      5 * (C) 2009 Sascha Hauer, Pengutronix
      6 * (C) 2009 Uwe Kleine-Koenig, Pengutronix
      7 */
      8
      9#include <linux/mfd/mc13xxx.h>
     10#include <linux/platform_device.h>
     11#include <linux/kernel.h>
     12#include <linux/module.h>
     13#include <linux/mod_devicetable.h>
     14#include <linux/slab.h>
     15#include <linux/rtc.h>
     16
     17#define DRIVER_NAME "mc13xxx-rtc"
     18
     19#define MC13XXX_RTCTOD	20
     20#define MC13XXX_RTCTODA	21
     21#define MC13XXX_RTCDAY	22
     22#define MC13XXX_RTCDAYA	23
     23
     24#define SEC_PER_DAY	(24 * 60 * 60)
     25
     26struct mc13xxx_rtc {
     27	struct rtc_device *rtc;
     28	struct mc13xxx *mc13xxx;
     29	int valid;
     30};
     31
     32static int mc13xxx_rtc_irq_enable_unlocked(struct device *dev,
     33		unsigned int enabled, int irq)
     34{
     35	struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
     36	int (*func)(struct mc13xxx *mc13xxx, int irq);
     37
     38	if (!priv->valid)
     39		return -ENODATA;
     40
     41	func = enabled ? mc13xxx_irq_unmask : mc13xxx_irq_mask;
     42	return func(priv->mc13xxx, irq);
     43}
     44
     45static int mc13xxx_rtc_alarm_irq_enable(struct device *dev,
     46					unsigned int enabled)
     47{
     48	struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
     49	int ret;
     50
     51	mc13xxx_lock(priv->mc13xxx);
     52
     53	ret = mc13xxx_rtc_irq_enable_unlocked(dev, enabled, MC13XXX_IRQ_TODA);
     54
     55	mc13xxx_unlock(priv->mc13xxx);
     56
     57	return ret;
     58}
     59
     60static int mc13xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)
     61{
     62	struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
     63	unsigned int seconds, days1, days2;
     64
     65	if (!priv->valid)
     66		return -ENODATA;
     67
     68	do {
     69		int ret;
     70
     71		ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days1);
     72		if (ret)
     73			return ret;
     74
     75		ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTOD, &seconds);
     76		if (ret)
     77			return ret;
     78
     79		ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days2);
     80		if (ret)
     81			return ret;
     82	} while (days1 != days2);
     83
     84	rtc_time64_to_tm((time64_t)days1 * SEC_PER_DAY + seconds, tm);
     85
     86	return 0;
     87}
     88
     89static int mc13xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)
     90{
     91	struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
     92	unsigned int seconds, days;
     93	unsigned int alarmseconds;
     94	int ret;
     95
     96	days = div_s64_rem(rtc_tm_to_time64(tm), SEC_PER_DAY, &seconds);
     97
     98	mc13xxx_lock(priv->mc13xxx);
     99
    100	/*
    101	 * temporarily invalidate alarm to prevent triggering it when the day is
    102	 * already updated while the time isn't yet.
    103	 */
    104	ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTODA, &alarmseconds);
    105	if (unlikely(ret))
    106		goto out;
    107
    108	if (alarmseconds < SEC_PER_DAY) {
    109		ret = mc13xxx_reg_write(priv->mc13xxx,
    110				MC13XXX_RTCTODA, 0x1ffff);
    111		if (unlikely(ret))
    112			goto out;
    113	}
    114
    115	/*
    116	 * write seconds=0 to prevent a day switch between writing days
    117	 * and seconds below
    118	 */
    119	ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTOD, 0);
    120	if (unlikely(ret))
    121		goto out;
    122
    123	ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCDAY, days);
    124	if (unlikely(ret))
    125		goto out;
    126
    127	ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTOD, seconds);
    128	if (unlikely(ret))
    129		goto out;
    130
    131	/* restore alarm */
    132	if (alarmseconds < SEC_PER_DAY) {
    133		ret = mc13xxx_reg_write(priv->mc13xxx,
    134				MC13XXX_RTCTODA, alarmseconds);
    135		if (unlikely(ret))
    136			goto out;
    137	}
    138
    139	if (!priv->valid) {
    140		ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_RTCRST);
    141		if (unlikely(ret))
    142			goto out;
    143
    144		ret = mc13xxx_irq_unmask(priv->mc13xxx, MC13XXX_IRQ_RTCRST);
    145	}
    146
    147out:
    148	priv->valid = !ret;
    149
    150	mc13xxx_unlock(priv->mc13xxx);
    151
    152	return ret;
    153}
    154
    155static int mc13xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
    156{
    157	struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
    158	unsigned int seconds, days;
    159	time64_t s1970;
    160	int enabled, pending;
    161	int ret;
    162
    163	mc13xxx_lock(priv->mc13xxx);
    164
    165	ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTODA, &seconds);
    166	if (unlikely(ret))
    167		goto out;
    168	if (seconds >= SEC_PER_DAY) {
    169		ret = -ENODATA;
    170		goto out;
    171	}
    172
    173	ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days);
    174	if (unlikely(ret))
    175		goto out;
    176
    177	ret = mc13xxx_irq_status(priv->mc13xxx, MC13XXX_IRQ_TODA,
    178			&enabled, &pending);
    179
    180out:
    181	mc13xxx_unlock(priv->mc13xxx);
    182
    183	if (ret)
    184		return ret;
    185
    186	alarm->enabled = enabled;
    187	alarm->pending = pending;
    188
    189	s1970 = (time64_t)days * SEC_PER_DAY + seconds;
    190
    191	rtc_time64_to_tm(s1970, &alarm->time);
    192	dev_dbg(dev, "%s: %lld\n", __func__, (long long)s1970);
    193
    194	return 0;
    195}
    196
    197static int mc13xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
    198{
    199	struct mc13xxx_rtc *priv = dev_get_drvdata(dev);
    200	time64_t s1970;
    201	u32 seconds, days;
    202	int ret;
    203
    204	mc13xxx_lock(priv->mc13xxx);
    205
    206	/* disable alarm to prevent false triggering */
    207	ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTODA, 0x1ffff);
    208	if (unlikely(ret))
    209		goto out;
    210
    211	ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_TODA);
    212	if (unlikely(ret))
    213		goto out;
    214
    215	s1970 = rtc_tm_to_time64(&alarm->time);
    216
    217	dev_dbg(dev, "%s: %s %lld\n", __func__, alarm->enabled ? "on" : "off",
    218			(long long)s1970);
    219
    220	ret = mc13xxx_rtc_irq_enable_unlocked(dev, alarm->enabled,
    221			MC13XXX_IRQ_TODA);
    222	if (unlikely(ret))
    223		goto out;
    224
    225	days = div_s64_rem(s1970, SEC_PER_DAY, &seconds);
    226
    227	ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCDAYA, days);
    228	if (unlikely(ret))
    229		goto out;
    230
    231	ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCTODA, seconds);
    232
    233out:
    234	mc13xxx_unlock(priv->mc13xxx);
    235
    236	return ret;
    237}
    238
    239static irqreturn_t mc13xxx_rtc_alarm_handler(int irq, void *dev)
    240{
    241	struct mc13xxx_rtc *priv = dev;
    242	struct mc13xxx *mc13xxx = priv->mc13xxx;
    243
    244	rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF);
    245
    246	mc13xxx_irq_ack(mc13xxx, irq);
    247
    248	return IRQ_HANDLED;
    249}
    250
    251static const struct rtc_class_ops mc13xxx_rtc_ops = {
    252	.read_time = mc13xxx_rtc_read_time,
    253	.set_time = mc13xxx_rtc_set_time,
    254	.read_alarm = mc13xxx_rtc_read_alarm,
    255	.set_alarm = mc13xxx_rtc_set_alarm,
    256	.alarm_irq_enable = mc13xxx_rtc_alarm_irq_enable,
    257};
    258
    259static irqreturn_t mc13xxx_rtc_reset_handler(int irq, void *dev)
    260{
    261	struct mc13xxx_rtc *priv = dev;
    262	struct mc13xxx *mc13xxx = priv->mc13xxx;
    263
    264	priv->valid = 0;
    265
    266	mc13xxx_irq_mask(mc13xxx, irq);
    267
    268	return IRQ_HANDLED;
    269}
    270
    271static int __init mc13xxx_rtc_probe(struct platform_device *pdev)
    272{
    273	int ret;
    274	struct mc13xxx_rtc *priv;
    275	struct mc13xxx *mc13xxx;
    276
    277	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
    278	if (!priv)
    279		return -ENOMEM;
    280
    281	mc13xxx = dev_get_drvdata(pdev->dev.parent);
    282	priv->mc13xxx = mc13xxx;
    283	priv->valid = 1;
    284
    285	priv->rtc = devm_rtc_allocate_device(&pdev->dev);
    286	if (IS_ERR(priv->rtc))
    287		return PTR_ERR(priv->rtc);
    288	platform_set_drvdata(pdev, priv);
    289
    290	priv->rtc->ops = &mc13xxx_rtc_ops;
    291	/* 15bit days + hours, minutes, seconds */
    292	priv->rtc->range_max = (timeu64_t)(1 << 15) * SEC_PER_DAY - 1;
    293
    294	mc13xxx_lock(mc13xxx);
    295
    296	mc13xxx_irq_ack(mc13xxx, MC13XXX_IRQ_RTCRST);
    297
    298	ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_RTCRST,
    299			mc13xxx_rtc_reset_handler, DRIVER_NAME, priv);
    300	if (ret)
    301		goto err_irq_request;
    302
    303	ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_TODA,
    304			mc13xxx_rtc_alarm_handler, DRIVER_NAME, priv);
    305	if (ret)
    306		goto err_irq_request;
    307
    308	mc13xxx_unlock(mc13xxx);
    309
    310	ret = devm_rtc_register_device(priv->rtc);
    311	if (ret) {
    312		mc13xxx_lock(mc13xxx);
    313		goto err_irq_request;
    314	}
    315
    316	return 0;
    317
    318err_irq_request:
    319	mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv);
    320	mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv);
    321
    322	mc13xxx_unlock(mc13xxx);
    323
    324	return ret;
    325}
    326
    327static int mc13xxx_rtc_remove(struct platform_device *pdev)
    328{
    329	struct mc13xxx_rtc *priv = platform_get_drvdata(pdev);
    330
    331	mc13xxx_lock(priv->mc13xxx);
    332
    333	mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_TODA, priv);
    334	mc13xxx_irq_free(priv->mc13xxx, MC13XXX_IRQ_RTCRST, priv);
    335
    336	mc13xxx_unlock(priv->mc13xxx);
    337
    338	return 0;
    339}
    340
    341static const struct platform_device_id mc13xxx_rtc_idtable[] = {
    342	{
    343		.name = "mc13783-rtc",
    344	}, {
    345		.name = "mc13892-rtc",
    346	}, {
    347		.name = "mc34708-rtc",
    348	},
    349	{ /* sentinel */ }
    350};
    351MODULE_DEVICE_TABLE(platform, mc13xxx_rtc_idtable);
    352
    353static struct platform_driver mc13xxx_rtc_driver = {
    354	.id_table = mc13xxx_rtc_idtable,
    355	.remove = mc13xxx_rtc_remove,
    356	.driver = {
    357		.name = DRIVER_NAME,
    358	},
    359};
    360
    361module_platform_driver_probe(mc13xxx_rtc_driver, &mc13xxx_rtc_probe);
    362
    363MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
    364MODULE_DESCRIPTION("RTC driver for Freescale MC13XXX PMIC");
    365MODULE_LICENSE("GPL v2");