brintos

brintos / linux-shallow public Read only

0
0
Text · 7.9 KiB · 763a42f Raw
364 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Real Time Clock driver for Freescale MC13XXX PMIC4 *5 * (C) 2009 Sascha Hauer, Pengutronix6 * (C) 2009 Uwe Kleine-Koenig, Pengutronix7 */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	2020#define MC13XXX_RTCTODA	2121#define MC13XXX_RTCDAY	2222#define MC13XXX_RTCDAYA	2323 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 is102	 * 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 days117	 * and seconds below118	 */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 void 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 339static const struct platform_device_id mc13xxx_rtc_idtable[] = {340	{341		.name = "mc13783-rtc",342	}, {343		.name = "mc13892-rtc",344	}, {345		.name = "mc34708-rtc",346	},347	{ /* sentinel */ }348};349MODULE_DEVICE_TABLE(platform, mc13xxx_rtc_idtable);350 351static struct platform_driver mc13xxx_rtc_driver = {352	.id_table = mc13xxx_rtc_idtable,353	.remove_new = mc13xxx_rtc_remove,354	.driver = {355		.name = DRIVER_NAME,356	},357};358 359module_platform_driver_probe(mc13xxx_rtc_driver, &mc13xxx_rtc_probe);360 361MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");362MODULE_DESCRIPTION("RTC driver for Freescale MC13XXX PMIC");363MODULE_LICENSE("GPL v2");364