diff options
Diffstat (limited to 'drivers/rtc')
| -rw-r--r-- | drivers/rtc/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/rtc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/rtc/rtc-88pm80x.c | 369 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ab8500.c | 38 | ||||
| -rw-r--r-- | drivers/rtc/rtc-coh901331.c | 61 | ||||
| -rw-r--r-- | drivers/rtc/rtc-da9052.c | 5 | ||||
| -rw-r--r-- | drivers/rtc/rtc-max8925.c | 13 | ||||
| -rw-r--r-- | drivers/rtc/rtc-mc13xxx.c | 6 | ||||
| -rw-r--r-- | drivers/rtc/rtc-pcf8563.c | 11 | ||||
| -rw-r--r-- | drivers/rtc/rtc-pl031.c | 95 | ||||
| -rw-r--r-- | drivers/rtc/rtc-r9701.c | 6 | ||||
| -rw-r--r-- | drivers/rtc/rtc-s3c.c | 4 | ||||
| -rw-r--r-- | drivers/rtc/rtc-wm831x.c | 24 | 
13 files changed, 541 insertions, 103 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 08cbdb900a1..fabc99a75c6 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -135,6 +135,16 @@ config RTC_DRV_88PM860X  	  This driver can also be built as a module. If so, the module  	  will be called rtc-88pm860x. +config RTC_DRV_88PM80X +	tristate "Marvell 88PM80x" +	depends on RTC_CLASS && I2C && MFD_88PM800 +	help +	  If you say yes here you get support for RTC function in Marvell +	  88PM80x chips. + +	  This driver can also be built as a module. If so, the module +	  will be called rtc-88pm80x. +  config RTC_DRV_DS1307  	tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025"  	help @@ -694,6 +704,7 @@ config RTC_DRV_AB3100  config RTC_DRV_AB8500  	tristate "ST-Ericsson AB8500 RTC"  	depends on AB8500_CORE +	select RTC_INTF_DEV_UIE_EMUL  	help  	  Select this to enable the ST-Ericsson AB8500 power management IC RTC  	  support. This chip contains a battery- and capacitor-backed RTC. diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 2973921c30d..0d5b2b66f90 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -16,6 +16,7 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o  # Keep the list ordered.  obj-$(CONFIG_RTC_DRV_88PM860X)  += rtc-88pm860x.o +obj-$(CONFIG_RTC_DRV_88PM80X)	+= rtc-88pm80x.o  obj-$(CONFIG_RTC_DRV_AB3100)	+= rtc-ab3100.o  obj-$(CONFIG_RTC_DRV_AB8500)	+= rtc-ab8500.o  obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c new file mode 100644 index 00000000000..6367984e056 --- /dev/null +++ b/drivers/rtc/rtc-88pm80x.c @@ -0,0 +1,369 @@ +/* + * Real Time Clock driver for Marvell 88PM80x PMIC + * + * Copyright (c) 2012 Marvell International Ltd. + *  Wenzeng Chen<wzch@marvell.com> + *  Qiao Zhou <zhouqiao@marvell.com> + * + * This file is subject to the terms and conditions of the GNU General + * Public License. See the file "COPYING" in the main directory of this + * archive for more details. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/regmap.h> +#include <linux/mfd/core.h> +#include <linux/mfd/88pm80x.h> +#include <linux/rtc.h> + +#define PM800_RTC_COUNTER1		(0xD1) +#define PM800_RTC_COUNTER2		(0xD2) +#define PM800_RTC_COUNTER3		(0xD3) +#define PM800_RTC_COUNTER4		(0xD4) +#define PM800_RTC_EXPIRE1_1		(0xD5) +#define PM800_RTC_EXPIRE1_2		(0xD6) +#define PM800_RTC_EXPIRE1_3		(0xD7) +#define PM800_RTC_EXPIRE1_4		(0xD8) +#define PM800_RTC_TRIM1			(0xD9) +#define PM800_RTC_TRIM2			(0xDA) +#define PM800_RTC_TRIM3			(0xDB) +#define PM800_RTC_TRIM4			(0xDC) +#define PM800_RTC_EXPIRE2_1		(0xDD) +#define PM800_RTC_EXPIRE2_2		(0xDE) +#define PM800_RTC_EXPIRE2_3		(0xDF) +#define PM800_RTC_EXPIRE2_4		(0xE0) + +#define PM800_POWER_DOWN_LOG1	(0xE5) +#define PM800_POWER_DOWN_LOG2	(0xE6) + +struct pm80x_rtc_info { +	struct pm80x_chip *chip; +	struct regmap *map; +	struct rtc_device *rtc_dev; +	struct device *dev; +	struct delayed_work calib_work; + +	int irq; +	int vrtc; +}; + +static irqreturn_t rtc_update_handler(int irq, void *data) +{ +	struct pm80x_rtc_info *info = (struct pm80x_rtc_info *)data; +	int mask; + +	mask = PM800_ALARM | PM800_ALARM_WAKEUP; +	regmap_update_bits(info->map, PM800_RTC_CONTROL, mask | PM800_ALARM1_EN, +			   mask); +	rtc_update_irq(info->rtc_dev, 1, RTC_AF); +	return IRQ_HANDLED; +} + +static int pm80x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ +	struct pm80x_rtc_info *info = dev_get_drvdata(dev); + +	if (enabled) +		regmap_update_bits(info->map, PM800_RTC_CONTROL, +				   PM800_ALARM1_EN, PM800_ALARM1_EN); +	else +		regmap_update_bits(info->map, PM800_RTC_CONTROL, +				   PM800_ALARM1_EN, 0); +	return 0; +} + +/* + * Calculate the next alarm time given the requested alarm time mask + * and the current time. + */ +static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now, +				struct rtc_time *alrm) +{ +	unsigned long next_time; +	unsigned long now_time; + +	next->tm_year = now->tm_year; +	next->tm_mon = now->tm_mon; +	next->tm_mday = now->tm_mday; +	next->tm_hour = alrm->tm_hour; +	next->tm_min = alrm->tm_min; +	next->tm_sec = alrm->tm_sec; + +	rtc_tm_to_time(now, &now_time); +	rtc_tm_to_time(next, &next_time); + +	if (next_time < now_time) { +		/* Advance one day */ +		next_time += 60 * 60 * 24; +		rtc_time_to_tm(next_time, next); +	} +} + +static int pm80x_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ +	struct pm80x_rtc_info *info = dev_get_drvdata(dev); +	unsigned char buf[4]; +	unsigned long ticks, base, data; +	regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4); +	base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; +	dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]); + +	/* load 32-bit read-only counter */ +	regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4); +	data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; +	ticks = base + data; +	dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", +		base, data, ticks); +	rtc_time_to_tm(ticks, tm); +	return 0; +} + +static int pm80x_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ +	struct pm80x_rtc_info *info = dev_get_drvdata(dev); +	unsigned char buf[4]; +	unsigned long ticks, base, data; +	if ((tm->tm_year < 70) || (tm->tm_year > 138)) { +		dev_dbg(info->dev, +			"Set time %d out of range. Please set time between 1970 to 2038.\n", +			1900 + tm->tm_year); +		return -EINVAL; +	} +	rtc_tm_to_time(tm, &ticks); + +	/* load 32-bit read-only counter */ +	regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4); +	data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; +	base = ticks - data; +	dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", +		base, data, ticks); +	buf[0] = base & 0xFF; +	buf[1] = (base >> 8) & 0xFF; +	buf[2] = (base >> 16) & 0xFF; +	buf[3] = (base >> 24) & 0xFF; +	regmap_raw_write(info->map, PM800_RTC_EXPIRE2_1, buf, 4); + +	return 0; +} + +static int pm80x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	struct pm80x_rtc_info *info = dev_get_drvdata(dev); +	unsigned char buf[4]; +	unsigned long ticks, base, data; +	int ret; + +	regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4); +	base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; +	dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]); + +	regmap_raw_read(info->map, PM800_RTC_EXPIRE1_1, buf, 4); +	data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; +	ticks = base + data; +	dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", +		base, data, ticks); + +	rtc_time_to_tm(ticks, &alrm->time); +	regmap_read(info->map, PM800_RTC_CONTROL, &ret); +	alrm->enabled = (ret & PM800_ALARM1_EN) ? 1 : 0; +	alrm->pending = (ret & (PM800_ALARM | PM800_ALARM_WAKEUP)) ? 1 : 0; +	return 0; +} + +static int pm80x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	struct pm80x_rtc_info *info = dev_get_drvdata(dev); +	struct rtc_time now_tm, alarm_tm; +	unsigned long ticks, base, data; +	unsigned char buf[4]; +	int mask; + +	regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_ALARM1_EN, 0); + +	regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4); +	base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; +	dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]); + +	/* load 32-bit read-only counter */ +	regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4); +	data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; +	ticks = base + data; +	dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n", +		base, data, ticks); + +	rtc_time_to_tm(ticks, &now_tm); +	dev_dbg(info->dev, "%s, now time : %lu\n", __func__, ticks); +	rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time); +	/* get new ticks for alarm in 24 hours */ +	rtc_tm_to_time(&alarm_tm, &ticks); +	dev_dbg(info->dev, "%s, alarm time: %lu\n", __func__, ticks); +	data = ticks - base; + +	buf[0] = data & 0xff; +	buf[1] = (data >> 8) & 0xff; +	buf[2] = (data >> 16) & 0xff; +	buf[3] = (data >> 24) & 0xff; +	regmap_raw_write(info->map, PM800_RTC_EXPIRE1_1, buf, 4); +	if (alrm->enabled) { +		mask = PM800_ALARM | PM800_ALARM_WAKEUP | PM800_ALARM1_EN; +		regmap_update_bits(info->map, PM800_RTC_CONTROL, mask, mask); +	} else { +		mask = PM800_ALARM | PM800_ALARM_WAKEUP | PM800_ALARM1_EN; +		regmap_update_bits(info->map, PM800_RTC_CONTROL, mask, +				   PM800_ALARM | PM800_ALARM_WAKEUP); +	} +	return 0; +} + +static const struct rtc_class_ops pm80x_rtc_ops = { +	.read_time = pm80x_rtc_read_time, +	.set_time = pm80x_rtc_set_time, +	.read_alarm = pm80x_rtc_read_alarm, +	.set_alarm = pm80x_rtc_set_alarm, +	.alarm_irq_enable = pm80x_rtc_alarm_irq_enable, +}; + +#ifdef CONFIG_PM +static int pm80x_rtc_suspend(struct device *dev) +{ +	return pm80x_dev_suspend(dev); +} + +static int pm80x_rtc_resume(struct device *dev) +{ +	return pm80x_dev_resume(dev); +} +#endif + +static SIMPLE_DEV_PM_OPS(pm80x_rtc_pm_ops, pm80x_rtc_suspend, pm80x_rtc_resume); + +static int __devinit pm80x_rtc_probe(struct platform_device *pdev) +{ +	struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent); +	struct pm80x_platform_data *pm80x_pdata; +	struct pm80x_rtc_pdata *pdata = NULL; +	struct pm80x_rtc_info *info; +	struct rtc_time tm; +	unsigned long ticks = 0; +	int ret; + +	pdata = pdev->dev.platform_data; +	if (pdata == NULL) +		dev_warn(&pdev->dev, "No platform data!\n"); + +	info = +	    devm_kzalloc(&pdev->dev, sizeof(struct pm80x_rtc_info), GFP_KERNEL); +	if (!info) +		return -ENOMEM; +	info->irq = platform_get_irq(pdev, 0); +	if (info->irq < 0) { +		dev_err(&pdev->dev, "No IRQ resource!\n"); +		ret = -EINVAL; +		goto out; +	} + +	info->chip = chip; +	info->map = chip->regmap; +	if (!info->map) { +		dev_err(&pdev->dev, "no regmap!\n"); +		ret = -EINVAL; +		goto out; +	} + +	info->dev = &pdev->dev; +	dev_set_drvdata(&pdev->dev, info); + +	ret = pm80x_request_irq(chip, info->irq, rtc_update_handler, +				IRQF_ONESHOT, "rtc", info); +	if (ret < 0) { +		dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", +			info->irq, ret); +		goto out; +	} + +	ret = pm80x_rtc_read_time(&pdev->dev, &tm); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to read initial time.\n"); +		goto out_rtc; +	} +	if ((tm.tm_year < 70) || (tm.tm_year > 138)) { +		tm.tm_year = 70; +		tm.tm_mon = 0; +		tm.tm_mday = 1; +		tm.tm_hour = 0; +		tm.tm_min = 0; +		tm.tm_sec = 0; +		ret = pm80x_rtc_set_time(&pdev->dev, &tm); +		if (ret < 0) { +			dev_err(&pdev->dev, "Failed to set initial time.\n"); +			goto out_rtc; +		} +	} +	rtc_tm_to_time(&tm, &ticks); + +	info->rtc_dev = rtc_device_register("88pm80x-rtc", &pdev->dev, +					    &pm80x_rtc_ops, THIS_MODULE); +	if (IS_ERR(info->rtc_dev)) { +		ret = PTR_ERR(info->rtc_dev); +		dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret); +		goto out_rtc; +	} +	/* +	 * enable internal XO instead of internal 3.25MHz clock since it can +	 * free running in PMIC power-down state. +	 */ +	regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_RTC1_USE_XO, +			   PM800_RTC1_USE_XO); + +	if (pdev->dev.parent->platform_data) { +		pm80x_pdata = pdev->dev.parent->platform_data; +		pdata = pm80x_pdata->rtc; +		if (pdata) +			info->rtc_dev->dev.platform_data = &pdata->rtc_wakeup; +	} + +	device_init_wakeup(&pdev->dev, 1); + +	return 0; +out_rtc: +	pm80x_free_irq(chip, info->irq, info); +out: +	return ret; +} + +static int __devexit pm80x_rtc_remove(struct platform_device *pdev) +{ +	struct pm80x_rtc_info *info = platform_get_drvdata(pdev); +	platform_set_drvdata(pdev, NULL); +	rtc_device_unregister(info->rtc_dev); +	pm80x_free_irq(info->chip, info->irq, info); +	return 0; +} + +static struct platform_driver pm80x_rtc_driver = { +	.driver = { +		   .name = "88pm80x-rtc", +		   .owner = THIS_MODULE, +		   .pm = &pm80x_rtc_pm_ops, +		   }, +	.probe = pm80x_rtc_probe, +	.remove = __devexit_p(pm80x_rtc_remove), +}; + +module_platform_driver(pm80x_rtc_driver); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Marvell 88PM80x RTC driver"); +MODULE_AUTHOR("Qiao Zhou <zhouqiao@marvell.com>"); +MODULE_ALIAS("platform:88pm80x-rtc"); diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c index 370889d0489..bf3c2f669c3 100644 --- a/drivers/rtc/rtc-ab8500.c +++ b/drivers/rtc/rtc-ab8500.c @@ -89,22 +89,17 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)  	if (retval < 0)  		return retval; -	/* Early AB8500 chips will not clear the rtc read request bit */ -	if (abx500_get_chip_id(dev) == 0) { -		usleep_range(1000, 1000); -	} else { -		/* Wait for some cycles after enabling the rtc read in ab8500 */ -		while (time_before(jiffies, timeout)) { -			retval = abx500_get_register_interruptible(dev, -				AB8500_RTC, AB8500_RTC_READ_REQ_REG, &value); -			if (retval < 0) -				return retval; +	/* Wait for some cycles after enabling the rtc read in ab8500 */ +	while (time_before(jiffies, timeout)) { +		retval = abx500_get_register_interruptible(dev, +			AB8500_RTC, AB8500_RTC_READ_REQ_REG, &value); +		if (retval < 0) +			return retval; -			if (!(value & RTC_READ_REQUEST)) -				break; +		if (!(value & RTC_READ_REQUEST)) +			break; -			usleep_range(1000, 5000); -		} +		usleep_range(1000, 5000);  	}  	/* Read the Watchtime registers */ @@ -225,7 +220,8 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)  {  	int retval, i;  	unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)]; -	unsigned long mins, secs = 0; +	unsigned long mins, secs = 0, cursec = 0; +	struct rtc_time curtm;  	if (alarm->time.tm_year < (AB8500_RTC_EPOCH - 1900)) {  		dev_dbg(dev, "year should be equal to or greater than %d\n", @@ -237,6 +233,18 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)  	rtc_tm_to_time(&alarm->time, &secs);  	/* +	 * Check whether alarm is set less than 1min. +	 * Since our RTC doesn't support alarm resolution less than 1min, +	 * return -EINVAL, so UIE EMUL can take it up, incase of UIE_ON +	 */ +	ab8500_rtc_read_time(dev, &curtm); /* Read current time */ +	rtc_tm_to_time(&curtm, &cursec); +	if ((secs - cursec) < 59) { +		dev_dbg(dev, "Alarm less than 1 minute not supported\r\n"); +		return -EINVAL; +	} + +	/*  	 * Convert it to the number of seconds since 01-01-2000 00:00:00, since  	 * we only have a small counter in the RTC.  	 */ diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index a5b8a0c4ea8..76b2156d3c6 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -155,13 +155,10 @@ static int __exit coh901331_remove(struct platform_device *pdev)  	struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);  	if (rtap) { -		free_irq(rtap->irq, rtap);  		rtc_device_unregister(rtap->rtc); +		clk_unprepare(rtap->clk);  		clk_put(rtap->clk); -		iounmap(rtap->virtbase); -		release_mem_region(rtap->phybase, rtap->physize);  		platform_set_drvdata(pdev, NULL); -		kfree(rtap);  	}  	return 0; @@ -174,49 +171,43 @@ static int __init coh901331_probe(struct platform_device *pdev)  	struct coh901331_port *rtap;  	struct resource *res; -	rtap = kzalloc(sizeof(struct coh901331_port), GFP_KERNEL); +	rtap = devm_kzalloc(&pdev->dev, +			    sizeof(struct coh901331_port), GFP_KERNEL);  	if (!rtap)  		return -ENOMEM;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) { -		ret = -ENOENT; -		goto out_no_resource; -	} +	if (!res) +		return -ENOENT; +  	rtap->phybase = res->start;  	rtap->physize = resource_size(res); -	if (request_mem_region(rtap->phybase, rtap->physize, -			       "rtc-coh901331") == NULL) { -		ret = -EBUSY; -		goto out_no_memregion; -	} +	if (devm_request_mem_region(&pdev->dev, rtap->phybase, rtap->physize, +				    "rtc-coh901331") == NULL) +		return -EBUSY; -	rtap->virtbase = ioremap(rtap->phybase, rtap->physize); -	if (!rtap->virtbase) { -		ret = -ENOMEM; -		goto out_no_remap; -	} +	rtap->virtbase = devm_ioremap(&pdev->dev, rtap->phybase, rtap->physize); +	if (!rtap->virtbase) +		return -ENOMEM;  	rtap->irq = platform_get_irq(pdev, 0); -	if (request_irq(rtap->irq, coh901331_interrupt, 0, -			"RTC COH 901 331 Alarm", rtap)) { -		ret = -EIO; -		goto out_no_irq; -	} +	if (devm_request_irq(&pdev->dev, rtap->irq, coh901331_interrupt, 0, +			     "RTC COH 901 331 Alarm", rtap)) +		return -EIO;  	rtap->clk = clk_get(&pdev->dev, NULL);  	if (IS_ERR(rtap->clk)) {  		ret = PTR_ERR(rtap->clk);  		dev_err(&pdev->dev, "could not get clock\n"); -		goto out_no_clk; +		return ret;  	}  	/* We enable/disable the clock only to assure it works */ -	ret = clk_enable(rtap->clk); +	ret = clk_prepare_enable(rtap->clk);  	if (ret) {  		dev_err(&pdev->dev, "could not enable clock\n"); -		goto out_no_clk_enable; +		goto out_no_clk_prepenable;  	}  	clk_disable(rtap->clk); @@ -232,18 +223,9 @@ static int __init coh901331_probe(struct platform_device *pdev)   out_no_rtc:  	platform_set_drvdata(pdev, NULL); - out_no_clk_enable: +	clk_unprepare(rtap->clk); + out_no_clk_prepenable:  	clk_put(rtap->clk); - out_no_clk: -	free_irq(rtap->irq, rtap); - out_no_irq: -	iounmap(rtap->virtbase); - out_no_remap: -	platform_set_drvdata(pdev, NULL); - out_no_memregion: -	release_mem_region(rtap->phybase, SZ_4K); - out_no_resource: -	kfree(rtap);  	return ret;  } @@ -265,6 +247,7 @@ static int coh901331_suspend(struct platform_device *pdev, pm_message_t state)  		writel(0, rtap->virtbase + COH901331_IRQ_MASK);  		clk_disable(rtap->clk);  	} +	clk_unprepare(rtap->clk);  	return 0;  } @@ -272,6 +255,7 @@ static int coh901331_resume(struct platform_device *pdev)  {  	struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev); +	clk_prepare(rtap->clk);  	if (device_may_wakeup(&pdev->dev)) {  		disable_irq_wake(rtap->irq);  	} else { @@ -293,6 +277,7 @@ static void coh901331_shutdown(struct platform_device *pdev)  	clk_enable(rtap->clk);  	writel(0, rtap->virtbase + COH901331_IRQ_MASK);  	clk_disable(rtap->clk); +	clk_unprepare(rtap->clk);  }  static struct platform_driver coh901331_driver = { diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c index da6ab5291a4..78070255bd3 100644 --- a/drivers/rtc/rtc-da9052.c +++ b/drivers/rtc/rtc-da9052.c @@ -245,7 +245,7 @@ static int __devinit da9052_rtc_probe(struct platform_device *pdev)  				   "ALM", rtc);  	if (ret != 0) {  		rtc_err(rtc->da9052, "irq registration failed: %d\n", ret); -		goto err_mem; +		return ret;  	}  	rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, @@ -259,8 +259,6 @@ static int __devinit da9052_rtc_probe(struct platform_device *pdev)  err_free_irq:  	free_irq(rtc->irq, rtc); -err_mem: -	devm_kfree(&pdev->dev, rtc);  	return ret;  } @@ -271,7 +269,6 @@ static int __devexit da9052_rtc_remove(struct platform_device *pdev)  	rtc_device_unregister(rtc->rtc);  	free_irq(rtc->irq, rtc);  	platform_set_drvdata(pdev, NULL); -	devm_kfree(&pdev->dev, rtc);  	return 0;  } diff --git a/drivers/rtc/rtc-max8925.c b/drivers/rtc/rtc-max8925.c index 1459055a83a..34e4349611d 100644 --- a/drivers/rtc/rtc-max8925.c +++ b/drivers/rtc/rtc-max8925.c @@ -69,6 +69,7 @@ struct max8925_rtc_info {  	struct max8925_chip	*chip;  	struct i2c_client	*rtc;  	struct device		*dev; +	int			irq;  };  static irqreturn_t rtc_update_handler(int irq, void *data) @@ -250,7 +251,7 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev)  {  	struct max8925_chip *chip = dev_get_drvdata(pdev->dev.parent);  	struct max8925_rtc_info *info; -	int irq, ret; +	int ret;  	info = kzalloc(sizeof(struct max8925_rtc_info), GFP_KERNEL);  	if (!info) @@ -258,13 +259,13 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev)  	info->chip = chip;  	info->rtc = chip->rtc;  	info->dev = &pdev->dev; -	irq = chip->irq_base + MAX8925_IRQ_RTC_ALARM0; +	info->irq = platform_get_irq(pdev, 0); -	ret = request_threaded_irq(irq, NULL, rtc_update_handler, +	ret = request_threaded_irq(info->irq, NULL, rtc_update_handler,  				   IRQF_ONESHOT, "rtc-alarm0", info);  	if (ret < 0) {  		dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n", -			irq, ret); +			info->irq, ret);  		goto out_irq;  	} @@ -285,7 +286,7 @@ static int __devinit max8925_rtc_probe(struct platform_device *pdev)  	return 0;  out_rtc:  	platform_set_drvdata(pdev, NULL); -	free_irq(chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info); +	free_irq(info->irq, info);  out_irq:  	kfree(info);  	return ret; @@ -296,7 +297,7 @@ static int __devexit max8925_rtc_remove(struct platform_device *pdev)  	struct max8925_rtc_info *info = platform_get_drvdata(pdev);  	if (info) { -		free_irq(info->chip->irq_base + MAX8925_IRQ_RTC_ALARM0, info); +		free_irq(info->irq, info);  		rtc_device_unregister(info->rtc_dev);  		kfree(info);  	} diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c index 546f6850bff..2643d887492 100644 --- a/drivers/rtc/rtc-mc13xxx.c +++ b/drivers/rtc/rtc-mc13xxx.c @@ -404,9 +404,12 @@ static const struct platform_device_id mc13xxx_rtc_idtable[] = {  		.name = "mc13783-rtc",  	}, {  		.name = "mc13892-rtc", +	}, { +		.name = "mc34708-rtc",  	}, -	{ } +	{ /* sentinel */ }  }; +MODULE_DEVICE_TABLE(platform, mc13xxx_rtc_idtable);  static struct platform_driver mc13xxx_rtc_driver = {  	.id_table = mc13xxx_rtc_idtable, @@ -432,4 +435,3 @@ module_exit(mc13xxx_rtc_exit);  MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");  MODULE_DESCRIPTION("RTC driver for Freescale MC13XXX PMIC");  MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index 97a3284bb7c..c2fe426a6ef 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -19,6 +19,7 @@  #include <linux/rtc.h>  #include <linux/slab.h>  #include <linux/module.h> +#include <linux/of.h>  #define DRV_VERSION "0.4.3" @@ -285,9 +286,19 @@ static const struct i2c_device_id pcf8563_id[] = {  };  MODULE_DEVICE_TABLE(i2c, pcf8563_id); +#ifdef CONFIG_OF +static const struct of_device_id pcf8563_of_match[] __devinitconst = { +	{ .compatible = "nxp,pcf8563" }, +	{} +}; +MODULE_DEVICE_TABLE(of, pcf8563_of_match); +#endif +  static struct i2c_driver pcf8563_driver = {  	.driver		= {  		.name	= "rtc-pcf8563", +		.owner	= THIS_MODULE, +		.of_match_table = of_match_ptr(pcf8563_of_match),  	},  	.probe		= pcf8563_probe,  	.remove		= pcf8563_remove, diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index cc0533994f6..08378e3cc21 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -68,11 +68,26 @@  #define RTC_TIMER_FREQ 32768 +/** + * struct pl031_vendor_data - per-vendor variations + * @ops: the vendor-specific operations used on this silicon version + * @clockwatch: if this is an ST Microelectronics silicon version with a + *	clockwatch function + * @st_weekday: if this is an ST Microelectronics silicon version that need + *	the weekday fix + * @irqflags: special IRQ flags per variant + */ +struct pl031_vendor_data { +	struct rtc_class_ops ops; +	bool clockwatch; +	bool st_weekday; +	unsigned long irqflags; +}; +  struct pl031_local { +	struct pl031_vendor_data *vendor;  	struct rtc_device *rtc;  	void __iomem *base; -	u8 hw_designer; -	u8 hw_revision:4;  };  static int pl031_alarm_irq_enable(struct device *dev, @@ -303,7 +318,8 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)  {  	int ret;  	struct pl031_local *ldata; -	struct rtc_class_ops *ops = id->data; +	struct pl031_vendor_data *vendor = id->data; +	struct rtc_class_ops *ops = &vendor->ops;  	unsigned long time;  	ret = amba_request_regions(adev, NULL); @@ -315,6 +331,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)  		ret = -ENOMEM;  		goto out;  	} +	ldata->vendor = vendor;  	ldata->base = ioremap(adev->res.start, resource_size(&adev->res)); @@ -325,14 +342,11 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)  	amba_set_drvdata(adev, ldata); -	ldata->hw_designer = amba_manf(adev); -	ldata->hw_revision = amba_rev(adev); - -	dev_dbg(&adev->dev, "designer ID = 0x%02x\n", ldata->hw_designer); -	dev_dbg(&adev->dev, "revision = 0x%01x\n", ldata->hw_revision); +	dev_dbg(&adev->dev, "designer ID = 0x%02x\n", amba_manf(adev)); +	dev_dbg(&adev->dev, "revision = 0x%01x\n", amba_rev(adev));  	/* Enable the clockwatch on ST Variants */ -	if (ldata->hw_designer == AMBA_VENDOR_ST) +	if (vendor->clockwatch)  		writel(readl(ldata->base + RTC_CR) | RTC_CR_CWEN,  		       ldata->base + RTC_CR); @@ -340,7 +354,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)  	 * On ST PL031 variants, the RTC reset value does not provide correct  	 * weekday for 2000-01-01. Correct the erroneous sunday to saturday.  	 */ -	if (ldata->hw_designer == AMBA_VENDOR_ST) { +	if (vendor->st_weekday) {  		if (readl(ldata->base + RTC_YDR) == 0x2000) {  			time = readl(ldata->base + RTC_DR);  			if ((time & @@ -361,7 +375,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)  	}  	if (request_irq(adev->irq[0], pl031_interrupt, -			0, "rtc-pl031", ldata)) { +			vendor->irqflags, "rtc-pl031", ldata)) {  		ret = -EIO;  		goto out_no_irq;  	} @@ -383,48 +397,65 @@ err_req:  }  /* Operations for the original ARM version */ -static struct rtc_class_ops arm_pl031_ops = { -	.read_time = pl031_read_time, -	.set_time = pl031_set_time, -	.read_alarm = pl031_read_alarm, -	.set_alarm = pl031_set_alarm, -	.alarm_irq_enable = pl031_alarm_irq_enable, +static struct pl031_vendor_data arm_pl031 = { +	.ops = { +		.read_time = pl031_read_time, +		.set_time = pl031_set_time, +		.read_alarm = pl031_read_alarm, +		.set_alarm = pl031_set_alarm, +		.alarm_irq_enable = pl031_alarm_irq_enable, +	}, +	.irqflags = IRQF_NO_SUSPEND,  };  /* The First ST derivative */ -static struct rtc_class_ops stv1_pl031_ops = { -	.read_time = pl031_read_time, -	.set_time = pl031_set_time, -	.read_alarm = pl031_read_alarm, -	.set_alarm = pl031_set_alarm, -	.alarm_irq_enable = pl031_alarm_irq_enable, +static struct pl031_vendor_data stv1_pl031 = { +	.ops = { +		.read_time = pl031_read_time, +		.set_time = pl031_set_time, +		.read_alarm = pl031_read_alarm, +		.set_alarm = pl031_set_alarm, +		.alarm_irq_enable = pl031_alarm_irq_enable, +	}, +	.clockwatch = true, +	.st_weekday = true, +	.irqflags = IRQF_NO_SUSPEND,  };  /* And the second ST derivative */ -static struct rtc_class_ops stv2_pl031_ops = { -	.read_time = pl031_stv2_read_time, -	.set_time = pl031_stv2_set_time, -	.read_alarm = pl031_stv2_read_alarm, -	.set_alarm = pl031_stv2_set_alarm, -	.alarm_irq_enable = pl031_alarm_irq_enable, +static struct pl031_vendor_data stv2_pl031 = { +	.ops = { +		.read_time = pl031_stv2_read_time, +		.set_time = pl031_stv2_set_time, +		.read_alarm = pl031_stv2_read_alarm, +		.set_alarm = pl031_stv2_set_alarm, +		.alarm_irq_enable = pl031_alarm_irq_enable, +	}, +	.clockwatch = true, +	.st_weekday = true, +	/* +	 * This variant shares the IRQ with another block and must not +	 * suspend that IRQ line. +	 */ +	.irqflags = IRQF_SHARED | IRQF_NO_SUSPEND,  };  static struct amba_id pl031_ids[] = {  	{  		.id = 0x00041031,  		.mask = 0x000fffff, -		.data = &arm_pl031_ops, +		.data = &arm_pl031,  	},  	/* ST Micro variants */  	{  		.id = 0x00180031,  		.mask = 0x00ffffff, -		.data = &stv1_pl031_ops, +		.data = &stv1_pl031,  	},  	{  		.id = 0x00280031,  		.mask = 0x00ffffff, -		.data = &stv2_pl031_ops, +		.data = &stv2_pl031,  	},  	{0, 0},  }; diff --git a/drivers/rtc/rtc-r9701.c b/drivers/rtc/rtc-r9701.c index 33b6ba0afa0..2c183ebff71 100644 --- a/drivers/rtc/rtc-r9701.c +++ b/drivers/rtc/rtc-r9701.c @@ -138,8 +138,7 @@ static int __devinit r9701_probe(struct spi_device *spi)  	 * contain invalid values. If so, try to write a default date:  	 * 2000/1/1 00:00:00  	 */ -	r9701_get_datetime(&spi->dev, &dt); -	if (rtc_valid_tm(&dt)) { +	if (r9701_get_datetime(&spi->dev, &dt)) {  		dev_info(&spi->dev, "trying to repair invalid date/time\n");  		dt.tm_sec  = 0;  		dt.tm_min  = 0; @@ -148,7 +147,8 @@ static int __devinit r9701_probe(struct spi_device *spi)  		dt.tm_mon  = 0;  		dt.tm_year = 100; -		if (r9701_set_datetime(&spi->dev, &dt)) { +		if (r9701_set_datetime(&spi->dev, &dt) || +				r9701_get_datetime(&spi->dev, &dt)) {  			dev_err(&spi->dev, "cannot repair RTC register\n");  			return -ENODEV;  		} diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 7e6af0b22f1..bfbd92c8d1c 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -26,10 +26,10 @@  #include <linux/log2.h>  #include <linux/slab.h>  #include <linux/of.h> +#include <linux/uaccess.h> +#include <linux/io.h>  #include <mach/hardware.h> -#include <asm/uaccess.h> -#include <asm/io.h>  #include <asm/irq.h>  #include <plat/regs-rtc.h> diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c index 59c6245e042..ea5c6f857ca 100644 --- a/drivers/rtc/rtc-wm831x.c +++ b/drivers/rtc/rtc-wm831x.c @@ -24,7 +24,7 @@  #include <linux/mfd/wm831x/core.h>  #include <linux/delay.h>  #include <linux/platform_device.h> - +#include <linux/random.h>  /*   * R16416 (0x4020) - RTC Write Counter @@ -96,6 +96,26 @@ struct wm831x_rtc {  	unsigned int alarm_enabled:1;  }; +static void wm831x_rtc_add_randomness(struct wm831x *wm831x) +{ +	int ret; +	u16 reg; + +	/* +	 * The write counter contains a pseudo-random number which is +	 * regenerated every time we set the RTC so it should be a +	 * useful per-system source of entropy. +	 */ +	ret = wm831x_reg_read(wm831x, WM831X_RTC_WRITE_COUNTER); +	if (ret >= 0) { +		reg = ret; +		add_device_randomness(®, sizeof(reg)); +	} else { +		dev_warn(wm831x->dev, "Failed to read RTC write counter: %d\n", +			 ret); +	} +} +  /*   * Read current time and date in RTC   */ @@ -431,6 +451,8 @@ static int wm831x_rtc_probe(struct platform_device *pdev)  			alm_irq, ret);  	} +	wm831x_rtc_add_randomness(wm831x); +  	return 0;  err:  |