brintos

brintos / linux-shallow public Read only

0
0
Text · 12.4 KiB · 1df5c7e Raw
493 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * drivers/rtc/rtc-spear.c4 *5 * Copyright (C) 2010 ST Microelectronics6 * Rajeev Kumar<rajeev-dlh.kumar@st.com>7 */8 9#include <linux/bcd.h>10#include <linux/clk.h>11#include <linux/delay.h>12#include <linux/init.h>13#include <linux/io.h>14#include <linux/irq.h>15#include <linux/module.h>16#include <linux/of.h>17#include <linux/platform_device.h>18#include <linux/rtc.h>19#include <linux/slab.h>20#include <linux/spinlock.h>21 22/* RTC registers */23#define TIME_REG		0x0024#define DATE_REG		0x0425#define ALARM_TIME_REG		0x0826#define ALARM_DATE_REG		0x0C27#define CTRL_REG		0x1028#define STATUS_REG		0x1429 30/* TIME_REG & ALARM_TIME_REG */31#define SECONDS_UNITS		(0xf<<0)	/* seconds units position */32#define SECONDS_TENS		(0x7<<4)	/* seconds tens position */33#define MINUTES_UNITS		(0xf<<8)	/* minutes units position */34#define MINUTES_TENS		(0x7<<12)	/* minutes tens position */35#define HOURS_UNITS		(0xf<<16)	/* hours units position */36#define HOURS_TENS		(0x3<<20)	/* hours tens position */37 38/* DATE_REG & ALARM_DATE_REG */39#define DAYS_UNITS		(0xf<<0)	/* days units position */40#define DAYS_TENS		(0x3<<4)	/* days tens position */41#define MONTHS_UNITS		(0xf<<8)	/* months units position */42#define MONTHS_TENS		(0x1<<12)	/* months tens position */43#define YEARS_UNITS		(0xf<<16)	/* years units position */44#define YEARS_TENS		(0xf<<20)	/* years tens position */45#define YEARS_HUNDREDS		(0xf<<24)	/* years hundereds position */46#define YEARS_MILLENIUMS	(0xf<<28)	/* years millenium position */47 48/* MASK SHIFT TIME_REG & ALARM_TIME_REG*/49#define SECOND_SHIFT		0x00		/* seconds units */50#define MINUTE_SHIFT		0x08		/* minutes units position */51#define HOUR_SHIFT		0x10		/* hours units position */52#define MDAY_SHIFT		0x00		/* Month day shift */53#define MONTH_SHIFT		0x08		/* Month shift */54#define YEAR_SHIFT		0x10		/* Year shift */55 56#define SECOND_MASK		0x7F57#define MIN_MASK		0x7F58#define HOUR_MASK		0x3F59#define DAY_MASK		0x3F60#define MONTH_MASK		0x7F61#define YEAR_MASK		0xFFFF62 63/* date reg equal to time reg, for debug only */64#define TIME_BYP		(1<<9)65#define INT_ENABLE		(1<<31)		/* interrupt enable */66 67/* STATUS_REG */68#define CLK_UNCONNECTED		(1<<0)69#define PEND_WR_TIME		(1<<2)70#define PEND_WR_DATE		(1<<3)71#define LOST_WR_TIME		(1<<4)72#define LOST_WR_DATE		(1<<5)73#define RTC_INT_MASK		(1<<31)74#define STATUS_BUSY		(PEND_WR_TIME | PEND_WR_DATE)75#define STATUS_FAIL		(LOST_WR_TIME | LOST_WR_DATE)76 77struct spear_rtc_config {78	struct rtc_device *rtc;79	struct clk *clk;80	spinlock_t lock;81	void __iomem *ioaddr;82	unsigned int irq_wake;83};84 85static inline void spear_rtc_clear_interrupt(struct spear_rtc_config *config)86{87	unsigned int val;88	unsigned long flags;89 90	spin_lock_irqsave(&config->lock, flags);91	val = readl(config->ioaddr + STATUS_REG);92	val |= RTC_INT_MASK;93	writel(val, config->ioaddr + STATUS_REG);94	spin_unlock_irqrestore(&config->lock, flags);95}96 97static inline void spear_rtc_enable_interrupt(struct spear_rtc_config *config)98{99	unsigned int val;100 101	val = readl(config->ioaddr + CTRL_REG);102	if (!(val & INT_ENABLE)) {103		spear_rtc_clear_interrupt(config);104		val |= INT_ENABLE;105		writel(val, config->ioaddr + CTRL_REG);106	}107}108 109static inline void spear_rtc_disable_interrupt(struct spear_rtc_config *config)110{111	unsigned int val;112 113	val = readl(config->ioaddr + CTRL_REG);114	if (val & INT_ENABLE) {115		val &= ~INT_ENABLE;116		writel(val, config->ioaddr + CTRL_REG);117	}118}119 120static inline int is_write_complete(struct spear_rtc_config *config)121{122	int ret = 0;123	unsigned long flags;124 125	spin_lock_irqsave(&config->lock, flags);126	if ((readl(config->ioaddr + STATUS_REG)) & STATUS_FAIL)127		ret = -EIO;128	spin_unlock_irqrestore(&config->lock, flags);129 130	return ret;131}132 133static void rtc_wait_not_busy(struct spear_rtc_config *config)134{135	int status, count = 0;136	unsigned long flags;137 138	/* Assuming BUSY may stay active for 80 msec) */139	for (count = 0; count < 80; count++) {140		spin_lock_irqsave(&config->lock, flags);141		status = readl(config->ioaddr + STATUS_REG);142		spin_unlock_irqrestore(&config->lock, flags);143		if ((status & STATUS_BUSY) == 0)144			break;145		/* check status busy, after each msec */146		msleep(1);147	}148}149 150static irqreturn_t spear_rtc_irq(int irq, void *dev_id)151{152	struct spear_rtc_config *config = dev_id;153	unsigned long events = 0;154	unsigned int irq_data;155 156	spin_lock(&config->lock);157	irq_data = readl(config->ioaddr + STATUS_REG);158	spin_unlock(&config->lock);159 160	if ((irq_data & RTC_INT_MASK)) {161		spear_rtc_clear_interrupt(config);162		events = RTC_IRQF | RTC_AF;163		rtc_update_irq(config->rtc, 1, events);164		return IRQ_HANDLED;165	} else166		return IRQ_NONE;167 168}169 170static void tm2bcd(struct rtc_time *tm)171{172	tm->tm_sec = bin2bcd(tm->tm_sec);173	tm->tm_min = bin2bcd(tm->tm_min);174	tm->tm_hour = bin2bcd(tm->tm_hour);175	tm->tm_mday = bin2bcd(tm->tm_mday);176	tm->tm_mon = bin2bcd(tm->tm_mon + 1);177	tm->tm_year = bin2bcd(tm->tm_year);178}179 180static void bcd2tm(struct rtc_time *tm)181{182	tm->tm_sec = bcd2bin(tm->tm_sec);183	tm->tm_min = bcd2bin(tm->tm_min);184	tm->tm_hour = bcd2bin(tm->tm_hour);185	tm->tm_mday = bcd2bin(tm->tm_mday);186	tm->tm_mon = bcd2bin(tm->tm_mon) - 1;187	/* epoch == 1900 */188	tm->tm_year = bcd2bin(tm->tm_year);189}190 191/*192 * spear_rtc_read_time - set the time193 * @dev: rtc device in use194 * @tm: holds date and time195 *196 * This function read time and date. On success it will return 0197 * otherwise -ve error is returned.198 */199static int spear_rtc_read_time(struct device *dev, struct rtc_time *tm)200{201	struct spear_rtc_config *config = dev_get_drvdata(dev);202	unsigned int time, date;203 204	/* we don't report wday/yday/isdst ... */205	rtc_wait_not_busy(config);206 207	do {208		time = readl(config->ioaddr + TIME_REG);209		date = readl(config->ioaddr + DATE_REG);210	} while (time == readl(config->ioaddr + TIME_REG));211	tm->tm_sec = (time >> SECOND_SHIFT) & SECOND_MASK;212	tm->tm_min = (time >> MINUTE_SHIFT) & MIN_MASK;213	tm->tm_hour = (time >> HOUR_SHIFT) & HOUR_MASK;214	tm->tm_mday = (date >> MDAY_SHIFT) & DAY_MASK;215	tm->tm_mon = (date >> MONTH_SHIFT) & MONTH_MASK;216	tm->tm_year = (date >> YEAR_SHIFT) & YEAR_MASK;217 218	bcd2tm(tm);219	return 0;220}221 222/*223 * spear_rtc_set_time - set the time224 * @dev: rtc device in use225 * @tm: holds date and time226 *227 * This function set time and date. On success it will return 0228 * otherwise -ve error is returned.229 */230static int spear_rtc_set_time(struct device *dev, struct rtc_time *tm)231{232	struct spear_rtc_config *config = dev_get_drvdata(dev);233	unsigned int time, date;234 235	tm2bcd(tm);236 237	rtc_wait_not_busy(config);238	time = (tm->tm_sec << SECOND_SHIFT) | (tm->tm_min << MINUTE_SHIFT) |239		(tm->tm_hour << HOUR_SHIFT);240	date = (tm->tm_mday << MDAY_SHIFT) | (tm->tm_mon << MONTH_SHIFT) |241		(tm->tm_year << YEAR_SHIFT);242	writel(time, config->ioaddr + TIME_REG);243	writel(date, config->ioaddr + DATE_REG);244 245	return is_write_complete(config);246}247 248/*249 * spear_rtc_read_alarm - read the alarm time250 * @dev: rtc device in use251 * @alm: holds alarm date and time252 *253 * This function read alarm time and date. On success it will return 0254 * otherwise -ve error is returned.255 */256static int spear_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)257{258	struct spear_rtc_config *config = dev_get_drvdata(dev);259	unsigned int time, date;260 261	rtc_wait_not_busy(config);262 263	time = readl(config->ioaddr + ALARM_TIME_REG);264	date = readl(config->ioaddr + ALARM_DATE_REG);265	alm->time.tm_sec = (time >> SECOND_SHIFT) & SECOND_MASK;266	alm->time.tm_min = (time >> MINUTE_SHIFT) & MIN_MASK;267	alm->time.tm_hour = (time >> HOUR_SHIFT) & HOUR_MASK;268	alm->time.tm_mday = (date >> MDAY_SHIFT) & DAY_MASK;269	alm->time.tm_mon = (date >> MONTH_SHIFT) & MONTH_MASK;270	alm->time.tm_year = (date >> YEAR_SHIFT) & YEAR_MASK;271 272	bcd2tm(&alm->time);273	alm->enabled = readl(config->ioaddr + CTRL_REG) & INT_ENABLE;274 275	return 0;276}277 278/*279 * spear_rtc_set_alarm - set the alarm time280 * @dev: rtc device in use281 * @alm: holds alarm date and time282 *283 * This function set alarm time and date. On success it will return 0284 * otherwise -ve error is returned.285 */286static int spear_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)287{288	struct spear_rtc_config *config = dev_get_drvdata(dev);289	unsigned int time, date;290	int err;291 292	tm2bcd(&alm->time);293 294	rtc_wait_not_busy(config);295 296	time = (alm->time.tm_sec << SECOND_SHIFT) | (alm->time.tm_min <<297			MINUTE_SHIFT) |	(alm->time.tm_hour << HOUR_SHIFT);298	date = (alm->time.tm_mday << MDAY_SHIFT) | (alm->time.tm_mon <<299			MONTH_SHIFT) | (alm->time.tm_year << YEAR_SHIFT);300 301	writel(time, config->ioaddr + ALARM_TIME_REG);302	writel(date, config->ioaddr + ALARM_DATE_REG);303	err = is_write_complete(config);304	if (err < 0)305		return err;306 307	if (alm->enabled)308		spear_rtc_enable_interrupt(config);309	else310		spear_rtc_disable_interrupt(config);311 312	return 0;313}314 315static int spear_alarm_irq_enable(struct device *dev, unsigned int enabled)316{317	struct spear_rtc_config *config = dev_get_drvdata(dev);318	int ret = 0;319 320	spear_rtc_clear_interrupt(config);321 322	switch (enabled) {323	case 0:324		/* alarm off */325		spear_rtc_disable_interrupt(config);326		break;327	case 1:328		/* alarm on */329		spear_rtc_enable_interrupt(config);330		break;331	default:332		ret = -EINVAL;333		break;334	}335 336	return ret;337}338 339static const struct rtc_class_ops spear_rtc_ops = {340	.read_time = spear_rtc_read_time,341	.set_time = spear_rtc_set_time,342	.read_alarm = spear_rtc_read_alarm,343	.set_alarm = spear_rtc_set_alarm,344	.alarm_irq_enable = spear_alarm_irq_enable,345};346 347static int spear_rtc_probe(struct platform_device *pdev)348{349	struct spear_rtc_config *config;350	int status = 0;351	int irq;352 353	config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);354	if (!config)355		return -ENOMEM;356 357	config->rtc = devm_rtc_allocate_device(&pdev->dev);358	if (IS_ERR(config->rtc))359		return PTR_ERR(config->rtc);360 361	/* alarm irqs */362	irq = platform_get_irq(pdev, 0);363	if (irq < 0)364		return irq;365 366	status = devm_request_irq(&pdev->dev, irq, spear_rtc_irq, 0, pdev->name,367			config);368	if (status) {369		dev_err(&pdev->dev, "Alarm interrupt IRQ%d already claimed\n",370				irq);371		return status;372	}373 374	config->ioaddr = devm_platform_ioremap_resource(pdev, 0);375	if (IS_ERR(config->ioaddr))376		return PTR_ERR(config->ioaddr);377 378	config->clk = devm_clk_get(&pdev->dev, NULL);379	if (IS_ERR(config->clk))380		return PTR_ERR(config->clk);381 382	status = clk_prepare_enable(config->clk);383	if (status < 0)384		return status;385 386	spin_lock_init(&config->lock);387	platform_set_drvdata(pdev, config);388 389	config->rtc->ops = &spear_rtc_ops;390	config->rtc->range_min = RTC_TIMESTAMP_BEGIN_0000;391	config->rtc->range_max = RTC_TIMESTAMP_END_9999;392 393	status = devm_rtc_register_device(config->rtc);394	if (status)395		goto err_disable_clock;396 397	if (!device_can_wakeup(&pdev->dev))398		device_init_wakeup(&pdev->dev, 1);399 400	return 0;401 402err_disable_clock:403	clk_disable_unprepare(config->clk);404 405	return status;406}407 408static void spear_rtc_remove(struct platform_device *pdev)409{410	struct spear_rtc_config *config = platform_get_drvdata(pdev);411 412	spear_rtc_disable_interrupt(config);413	clk_disable_unprepare(config->clk);414	device_init_wakeup(&pdev->dev, 0);415}416 417#ifdef CONFIG_PM_SLEEP418static int spear_rtc_suspend(struct device *dev)419{420	struct platform_device *pdev = to_platform_device(dev);421	struct spear_rtc_config *config = platform_get_drvdata(pdev);422	int irq;423 424	irq = platform_get_irq(pdev, 0);425	if (device_may_wakeup(&pdev->dev)) {426		if (!enable_irq_wake(irq))427			config->irq_wake = 1;428	} else {429		spear_rtc_disable_interrupt(config);430		clk_disable(config->clk);431	}432 433	return 0;434}435 436static int spear_rtc_resume(struct device *dev)437{438	struct platform_device *pdev = to_platform_device(dev);439	struct spear_rtc_config *config = platform_get_drvdata(pdev);440	int irq;441 442	irq = platform_get_irq(pdev, 0);443 444	if (device_may_wakeup(&pdev->dev)) {445		if (config->irq_wake) {446			disable_irq_wake(irq);447			config->irq_wake = 0;448		}449	} else {450		clk_enable(config->clk);451		spear_rtc_enable_interrupt(config);452	}453 454	return 0;455}456#endif457 458static SIMPLE_DEV_PM_OPS(spear_rtc_pm_ops, spear_rtc_suspend, spear_rtc_resume);459 460static void spear_rtc_shutdown(struct platform_device *pdev)461{462	struct spear_rtc_config *config = platform_get_drvdata(pdev);463 464	spear_rtc_disable_interrupt(config);465	clk_disable(config->clk);466}467 468#ifdef CONFIG_OF469static const struct of_device_id spear_rtc_id_table[] = {470	{ .compatible = "st,spear600-rtc" },471	{}472};473MODULE_DEVICE_TABLE(of, spear_rtc_id_table);474#endif475 476static struct platform_driver spear_rtc_driver = {477	.probe = spear_rtc_probe,478	.remove_new = spear_rtc_remove,479	.shutdown = spear_rtc_shutdown,480	.driver = {481		.name = "rtc-spear",482		.pm = &spear_rtc_pm_ops,483		.of_match_table = of_match_ptr(spear_rtc_id_table),484	},485};486 487module_platform_driver(spear_rtc_driver);488 489MODULE_ALIAS("platform:rtc-spear");490MODULE_AUTHOR("Rajeev Kumar <rajeev-dlh.kumar@st.com>");491MODULE_DESCRIPTION("ST SPEAr Realtime Clock Driver (RTC)");492MODULE_LICENSE("GPL");493