diff options
Diffstat (limited to 'drivers/rtc')
| -rw-r--r-- | drivers/rtc/Kconfig | 31 | ||||
| -rw-r--r-- | drivers/rtc/Makefile | 2 | ||||
| -rw-r--r-- | drivers/rtc/rtc-da9055.c | 413 | ||||
| -rw-r--r-- | drivers/rtc/rtc-davinci.c | 21 | ||||
| -rw-r--r-- | drivers/rtc/rtc-dev.c | 19 | ||||
| -rw-r--r-- | drivers/rtc/rtc-imxdi.c | 11 | ||||
| -rw-r--r-- | drivers/rtc/rtc-omap.c | 80 | ||||
| -rw-r--r-- | drivers/rtc/rtc-pcf8523.c | 326 | ||||
| -rw-r--r-- | drivers/rtc/rtc-s3c.c | 52 | ||||
| -rw-r--r-- | drivers/rtc/rtc-spear.c | 91 | ||||
| -rw-r--r-- | drivers/rtc/rtc-test.c | 14 | ||||
| -rw-r--r-- | drivers/rtc/rtc-tps65910.c | 9 | ||||
| -rw-r--r-- | drivers/rtc/rtc-twl.c | 32 | ||||
| -rw-r--r-- | drivers/rtc/rtc-vt8500.c | 15 | 
14 files changed, 938 insertions, 178 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 19c03ab2bdc..d0cea02b5df 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -269,6 +269,15 @@ config RTC_DRV_X1205  	  This driver can also be built as a module. If so, the module  	  will be called rtc-x1205. +config RTC_DRV_PCF8523 +	tristate "NXP PCF8523" +	help +	  If you say yes here you get support for the NXP PCF8523 RTC +	  chips. + +	  This driver can also be built as a module. If so, the module +	  will be called rtc-pcf8523. +  config RTC_DRV_PCF8563  	tristate "Philips PCF8563/Epson RTC8564"  	help @@ -600,6 +609,16 @@ config RTC_DRV_DA9052  	  Say y here to support the RTC driver for Dialog Semiconductor  	  DA9052-BC and DA9053-AA/Bx PMICs. +config RTC_DRV_DA9055 +	tristate "Dialog Semiconductor DA9055 RTC" +	depends on MFD_DA9055 +	help +	  If you say yes here you will get support for the +	  RTC of the Dialog DA9055 PMIC. + +	  This driver can also be built as a module. If so, the module +	  will be called rtc-da9055 +  config RTC_DRV_EFI  	tristate "EFI RTC"  	depends on IA64 @@ -768,7 +787,7 @@ config RTC_DRV_DAVINCI  config RTC_DRV_IMXDI  	tristate "Freescale IMX DryIce Real Time Clock" -	depends on SOC_IMX25 +	depends on ARCH_MXC  	help  	   Support for Freescale IMX DryIce RTC @@ -777,11 +796,13 @@ config RTC_DRV_IMXDI  config RTC_DRV_OMAP  	tristate "TI OMAP1" -	depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_DAVINCI_DA8XX +	depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_DAVINCI_DA8XX || SOC_AM33XX  	help -	  Say "yes" here to support the real time clock on TI OMAP1 and -	  DA8xx/OMAP-L13x chips.  This driver can also be built as a -	  module called rtc-omap. +	  Say "yes" here to support the on chip real time clock +	  present on TI OMAP1, AM33xx and DA8xx/OMAP-L13x. + +	  This driver can also be built as a module, if so, module +	  will be called rtc-omap.  config HAVE_S3C_RTC  	bool diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 56297f0fd38..c3f62c80dc0 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_RTC_DRV_BQ4802)	+= rtc-bq4802.o  obj-$(CONFIG_RTC_DRV_CMOS)	+= rtc-cmos.o  obj-$(CONFIG_RTC_DRV_COH901331)	+= rtc-coh901331.o  obj-$(CONFIG_RTC_DRV_DA9052)	+= rtc-da9052.o +obj-$(CONFIG_RTC_DRV_DA9055)	+= rtc-da9055.o  obj-$(CONFIG_RTC_DRV_DAVINCI)	+= rtc-davinci.o  obj-$(CONFIG_RTC_DRV_DM355EVM)	+= rtc-dm355evm.o  obj-$(CONFIG_RTC_DRV_VRTC)	+= rtc-mrst.o @@ -76,6 +77,7 @@ obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o  obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o  obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o  obj-$(CONFIG_RTC_DRV_PCAP)	+= rtc-pcap.o +obj-$(CONFIG_RTC_DRV_PCF8523)	+= rtc-pcf8523.o  obj-$(CONFIG_RTC_DRV_PCF8563)	+= rtc-pcf8563.o  obj-$(CONFIG_RTC_DRV_PCF8583)	+= rtc-pcf8583.o  obj-$(CONFIG_RTC_DRV_PCF2123)	+= rtc-pcf2123.o diff --git a/drivers/rtc/rtc-da9055.c b/drivers/rtc/rtc-da9055.c new file mode 100644 index 00000000000..96bafc5c3bf --- /dev/null +++ b/drivers/rtc/rtc-da9055.c @@ -0,0 +1,413 @@ +/* + * Real time clock driver for DA9055 + * + * Copyright(c) 2012 Dialog Semiconductor Ltd. + * + * Author: Dajun Dajun Chen <dajun.chen@diasemi.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + */ + +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> + +#include <linux/mfd/da9055/core.h> +#include <linux/mfd/da9055/reg.h> +#include <linux/mfd/da9055/pdata.h> + +struct da9055_rtc { +	struct rtc_device *rtc; +	struct da9055 *da9055; +	int alarm_enable; +}; + +static int da9055_rtc_enable_alarm(struct da9055_rtc *rtc, bool enable) +{ +	int ret; +	if (enable) { +		ret = da9055_reg_update(rtc->da9055, DA9055_REG_ALARM_Y, +					DA9055_RTC_ALM_EN, +					DA9055_RTC_ALM_EN); +		if (ret != 0) +			dev_err(rtc->da9055->dev, "Failed to enable ALM: %d\n", +				ret); +		rtc->alarm_enable = 1; +	} else { +		ret = da9055_reg_update(rtc->da9055, DA9055_REG_ALARM_Y, +					DA9055_RTC_ALM_EN, 0); +		if (ret != 0) +			dev_err(rtc->da9055->dev, +				"Failed to disable ALM: %d\n", ret); +		rtc->alarm_enable = 0; +	} +	return ret; +} + +static irqreturn_t da9055_rtc_alm_irq(int irq, void *data) +{ +	struct da9055_rtc *rtc = data; + +	da9055_rtc_enable_alarm(rtc, 0); +	rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); + +	return IRQ_HANDLED; +} + +static int da9055_read_alarm(struct da9055 *da9055, struct rtc_time *rtc_tm) +{ +	int ret; +	uint8_t v[5]; + +	ret = da9055_group_read(da9055, DA9055_REG_ALARM_MI, 5, v); +	if (ret != 0) { +		dev_err(da9055->dev, "Failed to group read ALM: %d\n", ret); +		return ret; +	} + +	rtc_tm->tm_year = (v[4] & DA9055_RTC_ALM_YEAR) + 100; +	rtc_tm->tm_mon  = (v[3] & DA9055_RTC_ALM_MONTH) - 1; +	rtc_tm->tm_mday = v[2] & DA9055_RTC_ALM_DAY; +	rtc_tm->tm_hour = v[1] & DA9055_RTC_ALM_HOUR; +	rtc_tm->tm_min  = v[0] & DA9055_RTC_ALM_MIN; + +	return rtc_valid_tm(rtc_tm); +} + +static int da9055_set_alarm(struct da9055 *da9055, struct rtc_time *rtc_tm) +{ +	int ret; +	uint8_t v[2]; + +	rtc_tm->tm_year -= 100; +	rtc_tm->tm_mon += 1; + +	ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MI, +				DA9055_RTC_ALM_MIN, rtc_tm->tm_min); +	if (ret != 0) { +		dev_err(da9055->dev, "Failed to write ALRM MIN: %d\n", ret); +		return ret; +	} + +	v[0] = rtc_tm->tm_hour; +	v[1] = rtc_tm->tm_mday; + +	ret = da9055_group_write(da9055, DA9055_REG_ALARM_H, 2, v); +	if (ret < 0) +		return ret; + +	ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MO, +				DA9055_RTC_ALM_MONTH, rtc_tm->tm_mon); +	if (ret < 0) +		dev_err(da9055->dev, "Failed to write ALM Month:%d\n", ret); + +	ret = da9055_reg_update(da9055, DA9055_REG_ALARM_Y, +				DA9055_RTC_ALM_YEAR, rtc_tm->tm_year); +	if (ret < 0) +		dev_err(da9055->dev, "Failed to write ALM Year:%d\n", ret); + +	return ret; +} + +static int da9055_rtc_get_alarm_status(struct da9055 *da9055) +{ +	int ret; + +	ret = da9055_reg_read(da9055, DA9055_REG_ALARM_Y); +	if (ret < 0) { +		dev_err(da9055->dev, "Failed to read ALM: %d\n", ret); +		return ret; +	} +	ret &= DA9055_RTC_ALM_EN; +	return (ret > 0) ? 1 : 0; +} + +static int da9055_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) +{ +	struct da9055_rtc *rtc = dev_get_drvdata(dev); +	uint8_t v[6]; +	int ret; + +	ret = da9055_reg_read(rtc->da9055, DA9055_REG_COUNT_S); +	if (ret < 0) +		return ret; + +	/* +	 * Registers are only valid when RTC_READ +	 * status bit is asserted +	 */ +	if (!(ret & DA9055_RTC_READ)) +		return -EBUSY; + +	ret = da9055_group_read(rtc->da9055, DA9055_REG_COUNT_S, 6, v); +	if (ret < 0) { +		dev_err(rtc->da9055->dev, "Failed to read RTC time : %d\n", +			ret); +		return ret; +	} + +	rtc_tm->tm_year = (v[5] & DA9055_RTC_YEAR) + 100; +	rtc_tm->tm_mon  = (v[4] & DA9055_RTC_MONTH) - 1; +	rtc_tm->tm_mday = v[3] & DA9055_RTC_DAY; +	rtc_tm->tm_hour = v[2] & DA9055_RTC_HOUR; +	rtc_tm->tm_min  = v[1] & DA9055_RTC_MIN; +	rtc_tm->tm_sec  = v[0] & DA9055_RTC_SEC; + +	return rtc_valid_tm(rtc_tm); +} + +static int da9055_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ +	struct da9055_rtc *rtc; +	uint8_t v[6]; + +	rtc = dev_get_drvdata(dev); + +	v[0] = tm->tm_sec; +	v[1] = tm->tm_min; +	v[2] = tm->tm_hour; +	v[3] = tm->tm_mday; +	v[4] = tm->tm_mon + 1; +	v[5] = tm->tm_year - 100; + +	return da9055_group_write(rtc->da9055, DA9055_REG_COUNT_S, 6, v); +} + +static int da9055_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	int ret; +	struct rtc_time *tm = &alrm->time; +	struct da9055_rtc *rtc = dev_get_drvdata(dev); + +	ret = da9055_read_alarm(rtc->da9055, tm); + +	if (ret) +		return ret; + +	alrm->enabled = da9055_rtc_get_alarm_status(rtc->da9055); + +	return 0; +} + +static int da9055_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	int ret; +	struct rtc_time *tm = &alrm->time; +	struct da9055_rtc *rtc = dev_get_drvdata(dev); + +	ret = da9055_rtc_enable_alarm(rtc, 0); +	if (ret < 0) +		return ret; + +	ret = da9055_set_alarm(rtc->da9055, tm); +	if (ret) +		return ret; + +	ret = da9055_rtc_enable_alarm(rtc, 1); + +	return ret; +} + +static int da9055_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ +	struct da9055_rtc *rtc = dev_get_drvdata(dev); + +	return da9055_rtc_enable_alarm(rtc, enabled); +} + +static const struct rtc_class_ops da9055_rtc_ops = { +	.read_time	= da9055_rtc_read_time, +	.set_time	= da9055_rtc_set_time, +	.read_alarm	= da9055_rtc_read_alarm, +	.set_alarm	= da9055_rtc_set_alarm, +	.alarm_irq_enable = da9055_rtc_alarm_irq_enable, +}; + +static int __init da9055_rtc_device_init(struct da9055 *da9055, +					struct da9055_pdata *pdata) +{ +	int ret; + +	/* Enable RTC and the internal Crystal */ +	ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B, +				DA9055_RTC_EN, DA9055_RTC_EN); +	if (ret < 0) +		return ret; +	ret = da9055_reg_update(da9055, DA9055_REG_EN_32K, +				DA9055_CRYSTAL_EN, DA9055_CRYSTAL_EN); +	if (ret < 0) +		return ret; + +	/* Enable RTC in Power Down mode */ +	ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B, +				DA9055_RTC_MODE_PD, DA9055_RTC_MODE_PD); +	if (ret < 0) +		return ret; + +	/* Enable RTC in Reset mode */ +	if (pdata && pdata->reset_enable) { +		ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B, +					DA9055_RTC_MODE_SD, +					DA9055_RTC_MODE_SD << +					DA9055_RTC_MODE_SD_SHIFT); +		if (ret < 0) +			return ret; +	} + +	/* Disable the RTC TICK ALM */ +	ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MO, +				DA9055_RTC_TICK_WAKE_MASK, 0); +	if (ret < 0) +		return ret; + +	return 0; +} + +static int da9055_rtc_probe(struct platform_device *pdev) +{ +	struct da9055_rtc *rtc; +	struct da9055_pdata *pdata = NULL; +	int ret, alm_irq; + +	rtc = devm_kzalloc(&pdev->dev, sizeof(struct da9055_rtc), GFP_KERNEL); +	if (!rtc) +		return -ENOMEM; + +	rtc->da9055 = dev_get_drvdata(pdev->dev.parent); +	pdata = rtc->da9055->dev->platform_data; +	platform_set_drvdata(pdev, rtc); + +	ret = da9055_rtc_device_init(rtc->da9055, pdata); +	if (ret < 0) +		goto err_rtc; + +	ret = da9055_reg_read(rtc->da9055, DA9055_REG_ALARM_Y); +	if (ret < 0) +		goto err_rtc; + +	if (ret & DA9055_RTC_ALM_EN) +		rtc->alarm_enable = 1; + +	device_init_wakeup(&pdev->dev, 1); + +	rtc->rtc = rtc_device_register(pdev->name, &pdev->dev, +					&da9055_rtc_ops, THIS_MODULE); +	if (IS_ERR(rtc->rtc)) { +		ret = PTR_ERR(rtc->rtc); +		goto err_rtc; +	} + +	alm_irq = platform_get_irq_byname(pdev, "ALM"); +	alm_irq = regmap_irq_get_virq(rtc->da9055->irq_data, alm_irq); +	ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL, +					da9055_rtc_alm_irq, +					IRQF_TRIGGER_HIGH | IRQF_ONESHOT, +					"ALM", rtc); +	if (ret != 0) +		dev_err(rtc->da9055->dev, "irq registration failed: %d\n", ret); + +err_rtc: +	return ret; + +} + +static int da9055_rtc_remove(struct platform_device *pdev) +{ +	struct da9055_rtc *rtc = pdev->dev.platform_data; + +	rtc_device_unregister(rtc->rtc); +	platform_set_drvdata(pdev, NULL); + +	return 0; +} + +#ifdef CONFIG_PM +/* Turn off the alarm if it should not be a wake source. */ +static int da9055_rtc_suspend(struct device *dev) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev); +	int ret; + +	if (!device_may_wakeup(&pdev->dev)) { +		/* Disable the ALM IRQ */ +		ret = da9055_rtc_enable_alarm(rtc, 0); +		if (ret < 0) +			dev_err(&pdev->dev, "Failed to disable RTC ALM\n"); +	} + +	return 0; +} + +/* Enable the alarm if it should be enabled (in case it was disabled to + * prevent use as a wake source). + */ +static int da9055_rtc_resume(struct device *dev) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev); +	int ret; + +	if (!device_may_wakeup(&pdev->dev)) { +		if (rtc->alarm_enable) { +			ret = da9055_rtc_enable_alarm(rtc, 1); +			if (ret < 0) +				dev_err(&pdev->dev, +					"Failed to restart RTC ALM\n"); +		} +	} + +	return 0; +} + +/* Unconditionally disable the alarm */ +static int da9055_rtc_freeze(struct device *dev) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev); +	int ret; + +	ret = da9055_rtc_enable_alarm(rtc, 0); +	if (ret < 0) +		dev_err(&pdev->dev, "Failed to freeze RTC ALMs\n"); + +	return 0; + +} +#else +#define da9055_rtc_suspend NULL +#define da9055_rtc_resume NULL +#define da9055_rtc_freeze NULL +#endif + +static const struct dev_pm_ops da9055_rtc_pm_ops = { +	.suspend = da9055_rtc_suspend, +	.resume = da9055_rtc_resume, + +	.freeze = da9055_rtc_freeze, +	.thaw = da9055_rtc_resume, +	.restore = da9055_rtc_resume, + +	.poweroff = da9055_rtc_suspend, +}; + +static struct platform_driver da9055_rtc_driver = { +	.probe  = da9055_rtc_probe, +	.remove = da9055_rtc_remove, +	.driver = { +		.name   = "da9055-rtc", +		.owner  = THIS_MODULE, +		.pm = &da9055_rtc_pm_ops, +	}, +}; + +module_platform_driver(da9055_rtc_driver); + +MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); +MODULE_DESCRIPTION("RTC driver for Dialog DA9055 PMIC"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:da9055-rtc"); diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index 14c2109dbaa..07cd03eae60 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -485,7 +485,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)  	struct resource *res, *mem;  	int ret = 0; -	davinci_rtc = kzalloc(sizeof(struct davinci_rtc), GFP_KERNEL); +	davinci_rtc = devm_kzalloc(&pdev->dev, sizeof(struct davinci_rtc), GFP_KERNEL);  	if (!davinci_rtc) {  		dev_dbg(dev, "could not allocate memory for private data\n");  		return -ENOMEM; @@ -494,15 +494,13 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)  	davinci_rtc->irq = platform_get_irq(pdev, 0);  	if (davinci_rtc->irq < 0) {  		dev_err(dev, "no RTC irq\n"); -		ret = davinci_rtc->irq; -		goto fail1; +		return davinci_rtc->irq;  	}  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!res) {  		dev_err(dev, "no mem resource\n"); -		ret = -EINVAL; -		goto fail1; +		return -EINVAL;  	}  	davinci_rtc->pbase = res->start; @@ -513,8 +511,7 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)  	if (!mem) {  		dev_err(dev, "RTC registers at %08x are not free\n",  			davinci_rtc->pbase); -		ret = -EBUSY; -		goto fail1; +		return -EBUSY;  	}  	davinci_rtc->base = ioremap(davinci_rtc->pbase, davinci_rtc->base_size); @@ -529,8 +526,9 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)  	davinci_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,  				    &davinci_rtc_ops, THIS_MODULE);  	if (IS_ERR(davinci_rtc->rtc)) { -		dev_err(dev, "unable to register RTC device, err %ld\n", -				PTR_ERR(davinci_rtc->rtc)); +		ret = PTR_ERR(davinci_rtc->rtc); +		dev_err(dev, "unable to register RTC device, err %d\n", +				ret);  		goto fail3;  	} @@ -566,9 +564,6 @@ fail3:  	iounmap(davinci_rtc->base);  fail2:  	release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size); -fail1: -	kfree(davinci_rtc); -  	return ret;  } @@ -589,8 +584,6 @@ static int __devexit davinci_rtc_remove(struct platform_device *pdev)  	platform_set_drvdata(pdev, NULL); -	kfree(davinci_rtc); -  	return 0;  } diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index cace6d3aed9..9a86b4bd869 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -379,25 +379,6 @@ static long rtc_dev_ioctl(struct file *file,  		err = put_user(rtc->irq_freq, (unsigned long __user *)uarg);  		break; -#if 0 -	case RTC_EPOCH_SET: -#ifndef rtc_epoch -		/* -		 * There were no RTC clocks before 1900. -		 */ -		if (arg < 1900) { -			err = -EINVAL; -			break; -		} -		rtc_epoch = arg; -		err = 0; -#endif -		break; - -	case RTC_EPOCH_READ: -		err = put_user(rtc_epoch, (unsigned long __user *)uarg); -		break; -#endif  	case RTC_WKALM_SET:  		mutex_unlock(&rtc->ops_lock);  		if (copy_from_user(&alarm, uarg, sizeof(alarm))) diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c index 4eed51044c5..18a4f0dd78a 100644 --- a/drivers/rtc/rtc-imxdi.c +++ b/drivers/rtc/rtc-imxdi.c @@ -37,6 +37,7 @@  #include <linux/rtc.h>  #include <linux/sched.h>  #include <linux/workqueue.h> +#include <linux/of.h>  /* DryIce Register Definitions */ @@ -495,10 +496,20 @@ static int __devexit dryice_rtc_remove(struct platform_device *pdev)  	return 0;  } +#ifdef CONFIG_OF +static const struct of_device_id dryice_dt_ids[] = { +	{ .compatible = "fsl,imx25-rtc" }, +	{ /* sentinel */ } +}; + +MODULE_DEVICE_TABLE(of, dryice_dt_ids); +#endif +  static struct platform_driver dryice_rtc_driver = {  	.driver = {  		   .name = "imxdi_rtc",  		   .owner = THIS_MODULE, +		   .of_match_table = of_match_ptr(dryice_dt_ids),  		   },  	.remove = __devexit_p(dryice_rtc_remove),  }; diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 0b614e32653..600971407aa 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -20,6 +20,9 @@  #include <linux/rtc.h>  #include <linux/bcd.h>  #include <linux/platform_device.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/pm_runtime.h>  #include <asm/io.h> @@ -38,6 +41,8 @@   * the SoC). See the BOARD-SPECIFIC CUSTOMIZATION comment.   */ +#define	DRIVER_NAME			"omap_rtc" +  #define OMAP_RTC_BASE			0xfffb4800  /* RTC registers */ @@ -64,6 +69,9 @@  #define OMAP_RTC_COMP_MSB_REG		0x50  #define OMAP_RTC_OSC_REG		0x54 +#define OMAP_RTC_KICK0_REG		0x6c +#define OMAP_RTC_KICK1_REG		0x70 +  /* OMAP_RTC_CTRL_REG bit fields: */  #define OMAP_RTC_CTRL_SPLIT		(1<<7)  #define OMAP_RTC_CTRL_DISABLE		(1<<6) @@ -88,10 +96,18 @@  #define OMAP_RTC_INTERRUPTS_IT_ALARM    (1<<3)  #define OMAP_RTC_INTERRUPTS_IT_TIMER    (1<<2) +/* OMAP_RTC_KICKER values */ +#define	KICK0_VALUE			0x83e70b13 +#define	KICK1_VALUE			0x95a4f1e0 + +#define	OMAP_RTC_HAS_KICKER		0x1 +  static void __iomem	*rtc_base; -#define rtc_read(addr)		__raw_readb(rtc_base + (addr)) -#define rtc_write(val, addr)	__raw_writeb(val, rtc_base + (addr)) +#define rtc_read(addr)		readb(rtc_base + (addr)) +#define rtc_write(val, addr)	writeb(val, rtc_base + (addr)) + +#define rtc_writel(val, addr)	writel(val, rtc_base + (addr))  /* we rely on the rtc framework to handle locking (rtc->ops_lock), @@ -285,11 +301,38 @@ static struct rtc_class_ops omap_rtc_ops = {  static int omap_rtc_alarm;  static int omap_rtc_timer; +#define	OMAP_RTC_DATA_DA830_IDX	1 + +static struct platform_device_id omap_rtc_devtype[] = { +	{ +		.name	= DRIVER_NAME, +	}, { +		.name	= "da830-rtc", +		.driver_data = OMAP_RTC_HAS_KICKER, +	}, +	{}, +}; +MODULE_DEVICE_TABLE(platform, omap_rtc_devtype); + +static const struct of_device_id omap_rtc_of_match[] = { +	{	.compatible	= "ti,da830-rtc", +		.data		= &omap_rtc_devtype[OMAP_RTC_DATA_DA830_IDX], +	}, +	{}, +}; +MODULE_DEVICE_TABLE(of, omap_rtc_of_match); +  static int __init omap_rtc_probe(struct platform_device *pdev)  {  	struct resource		*res, *mem;  	struct rtc_device	*rtc;  	u8			reg, new_ctrl; +	const struct platform_device_id *id_entry; +	const struct of_device_id *of_id; + +	of_id = of_match_device(omap_rtc_of_match, &pdev->dev); +	if (of_id) +		pdev->id_entry = of_id->data;  	omap_rtc_timer = platform_get_irq(pdev, 0);  	if (omap_rtc_timer <= 0) { @@ -322,6 +365,16 @@ static int __init omap_rtc_probe(struct platform_device *pdev)  		goto fail;  	} +	/* Enable the clock/module so that we can access the registers */ +	pm_runtime_enable(&pdev->dev); +	pm_runtime_get_sync(&pdev->dev); + +	id_entry = platform_get_device_id(pdev); +	if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) { +		rtc_writel(KICK0_VALUE, OMAP_RTC_KICK0_REG); +		rtc_writel(KICK1_VALUE, OMAP_RTC_KICK1_REG); +	} +  	rtc = rtc_device_register(pdev->name, &pdev->dev,  			&omap_rtc_ops, THIS_MODULE);  	if (IS_ERR(rtc)) { @@ -398,6 +451,10 @@ fail2:  fail1:  	rtc_device_unregister(rtc);  fail0: +	if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) +		rtc_writel(0, OMAP_RTC_KICK0_REG); +	pm_runtime_put_sync(&pdev->dev); +	pm_runtime_disable(&pdev->dev);  	iounmap(rtc_base);  fail:  	release_mem_region(mem->start, resource_size(mem)); @@ -408,6 +465,8 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)  {  	struct rtc_device	*rtc = platform_get_drvdata(pdev);  	struct resource		*mem = dev_get_drvdata(&rtc->dev); +	const struct platform_device_id *id_entry = +				platform_get_device_id(pdev);  	device_init_wakeup(&pdev->dev, 0); @@ -420,6 +479,13 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)  		free_irq(omap_rtc_alarm, rtc);  	rtc_device_unregister(rtc); +	if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) +		rtc_writel(0, OMAP_RTC_KICK0_REG); + +	/* Disable the clock/module */ +	pm_runtime_put_sync(&pdev->dev); +	pm_runtime_disable(&pdev->dev); +  	iounmap(rtc_base);  	release_mem_region(mem->start, resource_size(mem));  	return 0; @@ -442,11 +508,17 @@ static int omap_rtc_suspend(struct platform_device *pdev, pm_message_t state)  	else  		rtc_write(0, OMAP_RTC_INTERRUPTS_REG); +	/* Disable the clock/module */ +	pm_runtime_put_sync(&pdev->dev); +  	return 0;  }  static int omap_rtc_resume(struct platform_device *pdev)  { +	/* Enable the clock/module so that we can access the registers */ +	pm_runtime_get_sync(&pdev->dev); +  	if (device_may_wakeup(&pdev->dev))  		disable_irq_wake(omap_rtc_alarm);  	else @@ -471,9 +543,11 @@ static struct platform_driver omap_rtc_driver = {  	.resume		= omap_rtc_resume,  	.shutdown	= omap_rtc_shutdown,  	.driver		= { -		.name	= "omap_rtc", +		.name	= DRIVER_NAME,  		.owner	= THIS_MODULE, +		.of_match_table = of_match_ptr(omap_rtc_of_match),  	}, +	.id_table	= omap_rtc_devtype,  };  static int __init rtc_init(void) diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c new file mode 100644 index 00000000000..be05a645f99 --- /dev/null +++ b/drivers/rtc/rtc-pcf8523.c @@ -0,0 +1,326 @@ +/* + * Copyright (C) 2012 Avionic Design GmbH + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/bcd.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/rtc.h> +#include <linux/of.h> + +#define DRIVER_NAME "rtc-pcf8523" + +#define REG_CONTROL1 0x00 +#define REG_CONTROL1_CAP_SEL (1 << 7) +#define REG_CONTROL1_STOP    (1 << 5) + +#define REG_CONTROL3 0x02 +#define REG_CONTROL3_PM_BLD (1 << 7) /* battery low detection disabled */ +#define REG_CONTROL3_PM_VDD (1 << 6) /* switch-over disabled */ +#define REG_CONTROL3_PM_DSM (1 << 5) /* direct switching mode */ +#define REG_CONTROL3_PM_MASK 0xe0 + +#define REG_SECONDS  0x03 +#define REG_SECONDS_OS (1 << 7) + +#define REG_MINUTES  0x04 +#define REG_HOURS    0x05 +#define REG_DAYS     0x06 +#define REG_WEEKDAYS 0x07 +#define REG_MONTHS   0x08 +#define REG_YEARS    0x09 + +struct pcf8523 { +	struct rtc_device *rtc; +}; + +static int pcf8523_read(struct i2c_client *client, u8 reg, u8 *valuep) +{ +	struct i2c_msg msgs[2]; +	u8 value = 0; +	int err; + +	msgs[0].addr = client->addr; +	msgs[0].flags = 0; +	msgs[0].len = sizeof(reg); +	msgs[0].buf = ® + +	msgs[1].addr = client->addr; +	msgs[1].flags = I2C_M_RD; +	msgs[1].len = sizeof(value); +	msgs[1].buf = &value; + +	err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); +	if (err < 0) +		return err; + +	*valuep = value; + +	return 0; +} + +static int pcf8523_write(struct i2c_client *client, u8 reg, u8 value) +{ +	u8 buffer[2] = { reg, value }; +	struct i2c_msg msg; +	int err; + +	msg.addr = client->addr; +	msg.flags = 0; +	msg.len = sizeof(buffer); +	msg.buf = buffer; + +	err = i2c_transfer(client->adapter, &msg, 1); +	if (err < 0) +		return err; + +	return 0; +} + +static int pcf8523_select_capacitance(struct i2c_client *client, bool high) +{ +	u8 value; +	int err; + +	err = pcf8523_read(client, REG_CONTROL1, &value); +	if (err < 0) +		return err; + +	if (!high) +		value &= ~REG_CONTROL1_CAP_SEL; +	else +		value |= REG_CONTROL1_CAP_SEL; + +	err = pcf8523_write(client, REG_CONTROL1, value); +	if (err < 0) +		return err; + +	return err; +} + +static int pcf8523_set_pm(struct i2c_client *client, u8 pm) +{ +	u8 value; +	int err; + +	err = pcf8523_read(client, REG_CONTROL3, &value); +	if (err < 0) +		return err; + +	value = (value & ~REG_CONTROL3_PM_MASK) | pm; + +	err = pcf8523_write(client, REG_CONTROL3, value); +	if (err < 0) +		return err; + +	return 0; +} + +static int pcf8523_stop_rtc(struct i2c_client *client) +{ +	u8 value; +	int err; + +	err = pcf8523_read(client, REG_CONTROL1, &value); +	if (err < 0) +		return err; + +	value |= REG_CONTROL1_STOP; + +	err = pcf8523_write(client, REG_CONTROL1, value); +	if (err < 0) +		return err; + +	return 0; +} + +static int pcf8523_start_rtc(struct i2c_client *client) +{ +	u8 value; +	int err; + +	err = pcf8523_read(client, REG_CONTROL1, &value); +	if (err < 0) +		return err; + +	value &= ~REG_CONTROL1_STOP; + +	err = pcf8523_write(client, REG_CONTROL1, value); +	if (err < 0) +		return err; + +	return 0; +} + +static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ +	struct i2c_client *client = to_i2c_client(dev); +	u8 start = REG_SECONDS, regs[7]; +	struct i2c_msg msgs[2]; +	int err; + +	msgs[0].addr = client->addr; +	msgs[0].flags = 0; +	msgs[0].len = 1; +	msgs[0].buf = &start; + +	msgs[1].addr = client->addr; +	msgs[1].flags = I2C_M_RD; +	msgs[1].len = sizeof(regs); +	msgs[1].buf = regs; + +	err = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); +	if (err < 0) +		return err; + +	if (regs[0] & REG_SECONDS_OS) { +		/* +		 * If the oscillator was stopped, try to clear the flag. Upon +		 * power-up the flag is always set, but if we cannot clear it +		 * the oscillator isn't running properly for some reason. The +		 * sensible thing therefore is to return an error, signalling +		 * that the clock cannot be assumed to be correct. +		 */ + +		regs[0] &= ~REG_SECONDS_OS; + +		err = pcf8523_write(client, REG_SECONDS, regs[0]); +		if (err < 0) +			return err; + +		err = pcf8523_read(client, REG_SECONDS, ®s[0]); +		if (err < 0) +			return err; + +		if (regs[0] & REG_SECONDS_OS) +			return -EAGAIN; +	} + +	tm->tm_sec = bcd2bin(regs[0] & 0x7f); +	tm->tm_min = bcd2bin(regs[1] & 0x7f); +	tm->tm_hour = bcd2bin(regs[2] & 0x3f); +	tm->tm_mday = bcd2bin(regs[3] & 0x3f); +	tm->tm_wday = regs[4] & 0x7; +	tm->tm_mon = bcd2bin(regs[5] & 0x1f); +	tm->tm_year = bcd2bin(regs[6]) + 100; + +	return rtc_valid_tm(tm); +} + +static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ +	struct i2c_client *client = to_i2c_client(dev); +	struct i2c_msg msg; +	u8 regs[8]; +	int err; + +	err = pcf8523_stop_rtc(client); +	if (err < 0) +		return err; + +	regs[0] = REG_SECONDS; +	regs[1] = bin2bcd(tm->tm_sec); +	regs[2] = bin2bcd(tm->tm_min); +	regs[3] = bin2bcd(tm->tm_hour); +	regs[4] = bin2bcd(tm->tm_mday); +	regs[5] = tm->tm_wday; +	regs[6] = bin2bcd(tm->tm_mon); +	regs[7] = bin2bcd(tm->tm_year - 100); + +	msg.addr = client->addr; +	msg.flags = 0; +	msg.len = sizeof(regs); +	msg.buf = regs; + +	err = i2c_transfer(client->adapter, &msg, 1); +	if (err < 0) { +		/* +		 * If the time cannot be set, restart the RTC anyway. Note +		 * that errors are ignored if the RTC cannot be started so +		 * that we have a chance to propagate the original error. +		 */ +		pcf8523_start_rtc(client); +		return err; +	} + +	return pcf8523_start_rtc(client); +} + +static const struct rtc_class_ops pcf8523_rtc_ops = { +	.read_time = pcf8523_rtc_read_time, +	.set_time = pcf8523_rtc_set_time, +}; + +static int pcf8523_probe(struct i2c_client *client, +			 const struct i2c_device_id *id) +{ +	struct pcf8523 *pcf; +	int err; + +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) +		return -ENODEV; + +	pcf = devm_kzalloc(&client->dev, sizeof(*pcf), GFP_KERNEL); +	if (!pcf) +		return -ENOMEM; + +	err = pcf8523_select_capacitance(client, true); +	if (err < 0) +		return err; + +	err = pcf8523_set_pm(client, 0); +	if (err < 0) +		return err; + +	pcf->rtc = rtc_device_register(DRIVER_NAME, &client->dev, +				       &pcf8523_rtc_ops, THIS_MODULE); +	if (IS_ERR(pcf->rtc)) +		return PTR_ERR(pcf->rtc); + +	i2c_set_clientdata(client, pcf); + +	return 0; +} + +static int pcf8523_remove(struct i2c_client *client) +{ +	struct pcf8523 *pcf = i2c_get_clientdata(client); + +	rtc_device_unregister(pcf->rtc); + +	return 0; +} + +static const struct i2c_device_id pcf8523_id[] = { +	{ "pcf8523", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, pcf8523_id); + +#ifdef CONFIG_OF +static const struct of_device_id pcf8523_of_match[] = { +	{ .compatible = "nxp,pcf8523" }, +	{ } +}; +MODULE_DEVICE_TABLE(of, pcf8523_of_match); +#endif + +static struct i2c_driver pcf8523_driver = { +	.driver = { +		.name = DRIVER_NAME, +		.owner = THIS_MODULE, +		.of_match_table = of_match_ptr(pcf8523_of_match), +	}, +	.probe = pcf8523_probe, +	.remove = pcf8523_remove, +	.id_table = pcf8523_id, +}; +module_i2c_driver(pcf8523_driver); + +MODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>"); +MODULE_DESCRIPTION("NXP PCF8523 RTC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index a7a2a998fa9..4bd9414aee6 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -47,8 +47,6 @@ struct s3c_rtc_drv_data {  /* I have yet to find an S3C implementation with more than one   * of these rtc blocks in */ -static struct resource *s3c_rtc_mem; -  static struct clk *rtc_clk;  static void __iomem *s3c_rtc_base;  static int s3c_rtc_alarmno = NO_IRQ; @@ -427,21 +425,13 @@ static int __devexit s3c_rtc_remove(struct platform_device *dev)  {  	struct rtc_device *rtc = platform_get_drvdata(dev); -	free_irq(s3c_rtc_alarmno, rtc); -	free_irq(s3c_rtc_tickno, rtc); -  	platform_set_drvdata(dev, NULL);  	rtc_device_unregister(rtc);  	s3c_rtc_setaie(&dev->dev, 0); -	clk_put(rtc_clk);  	rtc_clk = NULL; -	iounmap(s3c_rtc_base); -	release_resource(s3c_rtc_mem); -	kfree(s3c_rtc_mem); -  	return 0;  } @@ -496,28 +486,18 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)  		return -ENOENT;  	} -	s3c_rtc_mem = request_mem_region(res->start, resource_size(res), -					 pdev->name); - -	if (s3c_rtc_mem == NULL) { -		dev_err(&pdev->dev, "failed to reserve memory region\n"); -		ret = -ENOENT; -		goto err_nores; -	} - -	s3c_rtc_base = ioremap(res->start, resource_size(res)); +	s3c_rtc_base = devm_request_and_ioremap(&pdev->dev, res);  	if (s3c_rtc_base == NULL) { -		dev_err(&pdev->dev, "failed ioremap()\n"); -		ret = -EINVAL; -		goto err_nomap; +		dev_err(&pdev->dev, "failed to ioremap memory region\n"); +		return -EINVAL;  	} -	rtc_clk = clk_get(&pdev->dev, "rtc"); +	rtc_clk = devm_clk_get(&pdev->dev, "rtc");  	if (IS_ERR(rtc_clk)) {  		dev_err(&pdev->dev, "failed to find rtc clock source\n");  		ret = PTR_ERR(rtc_clk);  		rtc_clk = NULL; -		goto err_clk; +		return ret;  	}  	clk_enable(rtc_clk); @@ -576,28 +556,24 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)  	s3c_rtc_setfreq(&pdev->dev, 1); -	ret = request_irq(s3c_rtc_alarmno, s3c_rtc_alarmirq, +	ret = devm_request_irq(&pdev->dev, s3c_rtc_alarmno, s3c_rtc_alarmirq,  			  0,  "s3c2410-rtc alarm", rtc);  	if (ret) {  		dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_alarmno, ret);  		goto err_alarm_irq;  	} -	ret = request_irq(s3c_rtc_tickno, s3c_rtc_tickirq, +	ret = devm_request_irq(&pdev->dev, s3c_rtc_tickno, s3c_rtc_tickirq,  			  0,  "s3c2410-rtc tick", rtc);  	if (ret) {  		dev_err(&pdev->dev, "IRQ%d error %d\n", s3c_rtc_tickno, ret); -		free_irq(s3c_rtc_alarmno, rtc); -		goto err_tick_irq; +		goto err_alarm_irq;  	}  	clk_disable(rtc_clk);  	return 0; - err_tick_irq: -	free_irq(s3c_rtc_alarmno, rtc); -   err_alarm_irq:  	platform_set_drvdata(pdev, NULL);  	rtc_device_unregister(rtc); @@ -605,15 +581,7 @@ static int __devinit s3c_rtc_probe(struct platform_device *pdev)   err_nortc:  	s3c_rtc_enable(pdev, 0);  	clk_disable(rtc_clk); -	clk_put(rtc_clk); - err_clk: -	iounmap(s3c_rtc_base); - - err_nomap: -	release_resource(s3c_rtc_mem); - - err_nores:  	return ret;  } @@ -695,8 +663,6 @@ static const struct of_device_id s3c_rtc_dt_match[] = {  	{},  };  MODULE_DEVICE_TABLE(of, s3c_rtc_dt_match); -#else -#define s3c_rtc_dt_match NULL  #endif  static struct platform_device_id s3c_rtc_driver_ids[] = { @@ -727,7 +693,7 @@ static struct platform_driver s3c_rtc_driver = {  	.driver		= {  		.name	= "s3c-rtc",  		.owner	= THIS_MODULE, -		.of_match_table	= s3c_rtc_dt_match, +		.of_match_table	= of_match_ptr(s3c_rtc_dt_match),  	},  }; diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c index bb507d23f6c..141fc945295 100644 --- a/drivers/rtc/rtc-spear.c +++ b/drivers/rtc/rtc-spear.c @@ -363,35 +363,42 @@ static int __devinit spear_rtc_probe(struct platform_device *pdev)  		dev_err(&pdev->dev, "no resource defined\n");  		return -EBUSY;  	} -	if (!request_mem_region(res->start, resource_size(res), pdev->name)) { -		dev_err(&pdev->dev, "rtc region already claimed\n"); -		return -EBUSY; -	} -	config = kzalloc(sizeof(*config), GFP_KERNEL); +	config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);  	if (!config) {  		dev_err(&pdev->dev, "out of memory\n"); -		status = -ENOMEM; -		goto err_release_region; +		return -ENOMEM;  	} -	config->clk = clk_get(&pdev->dev, NULL); -	if (IS_ERR(config->clk)) { -		status = PTR_ERR(config->clk); -		goto err_kfree; +	/* alarm irqs */ +	irq = platform_get_irq(pdev, 0); +	if (irq < 0) { +		dev_err(&pdev->dev, "no update irq?\n"); +		return irq;  	} -	status = clk_enable(config->clk); -	if (status < 0) -		goto err_clk_put; +	status = devm_request_irq(&pdev->dev, irq, spear_rtc_irq, 0, pdev->name, +			config); +	if (status) { +		dev_err(&pdev->dev, "Alarm interrupt IRQ%d already claimed\n", +				irq); +		return status; +	} -	config->ioaddr = ioremap(res->start, resource_size(res)); +	config->ioaddr = devm_request_and_ioremap(&pdev->dev, res);  	if (!config->ioaddr) { -		dev_err(&pdev->dev, "ioremap fail\n"); -		status = -ENOMEM; -		goto err_disable_clock; +		dev_err(&pdev->dev, "request-ioremap fail\n"); +		return -ENOMEM;  	} +	config->clk = devm_clk_get(&pdev->dev, NULL); +	if (IS_ERR(config->clk)) +		return PTR_ERR(config->clk); + +	status = clk_prepare_enable(config->clk); +	if (status < 0) +		return status; +  	spin_lock_init(&config->lock);  	platform_set_drvdata(pdev, config); @@ -401,42 +408,19 @@ static int __devinit spear_rtc_probe(struct platform_device *pdev)  		dev_err(&pdev->dev, "can't register RTC device, err %ld\n",  				PTR_ERR(config->rtc));  		status = PTR_ERR(config->rtc); -		goto err_iounmap; -	} - -	/* alarm irqs */ -	irq = platform_get_irq(pdev, 0); -	if (irq < 0) { -		dev_err(&pdev->dev, "no update irq?\n"); -		status = irq; -		goto err_clear_platdata; +		goto err_disable_clock;  	} -	status = request_irq(irq, spear_rtc_irq, 0, pdev->name, config); -	if (status) { -		dev_err(&pdev->dev, "Alarm interrupt IRQ%d already \ -				claimed\n", irq); -		goto err_clear_platdata; -	} +	config->rtc->uie_unsupported = 1;  	if (!device_can_wakeup(&pdev->dev))  		device_init_wakeup(&pdev->dev, 1);  	return 0; -err_clear_platdata: -	platform_set_drvdata(pdev, NULL); -	rtc_device_unregister(config->rtc); -err_iounmap: -	iounmap(config->ioaddr);  err_disable_clock: -	clk_disable(config->clk); -err_clk_put: -	clk_put(config->clk); -err_kfree: -	kfree(config); -err_release_region: -	release_mem_region(res->start, resource_size(res)); +	platform_set_drvdata(pdev, NULL); +	clk_disable_unprepare(config->clk);  	return status;  } @@ -444,24 +428,11 @@ err_release_region:  static int __devexit spear_rtc_remove(struct platform_device *pdev)  {  	struct spear_rtc_config *config = platform_get_drvdata(pdev); -	int irq; -	struct resource *res; -	/* leave rtc running, but disable irqs */ +	rtc_device_unregister(config->rtc);  	spear_rtc_disable_interrupt(config); +	clk_disable_unprepare(config->clk);  	device_init_wakeup(&pdev->dev, 0); -	irq = platform_get_irq(pdev, 0); -	if (irq) -		free_irq(irq, pdev); -	clk_disable(config->clk); -	clk_put(config->clk); -	iounmap(config->ioaddr); -	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (res) -		release_mem_region(res->start, resource_size(res)); -	platform_set_drvdata(pdev, NULL); -	rtc_device_unregister(config->rtc); -	kfree(config);  	return 0;  } diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index 7e96254bd36..974b9ae252a 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -152,24 +152,24 @@ static int __init test_init(void)  	if ((test1 = platform_device_alloc("rtc-test", 1)) == NULL) {  		err = -ENOMEM; -		goto exit_free_test0; +		goto exit_put_test0;  	}  	if ((err = platform_device_add(test0))) -		goto exit_free_test1; +		goto exit_put_test1;  	if ((err = platform_device_add(test1))) -		goto exit_device_unregister; +		goto exit_del_test0;  	return 0; -exit_device_unregister: -	platform_device_unregister(test0); +exit_del_test0: +	platform_device_del(test0); -exit_free_test1: +exit_put_test1:  	platform_device_put(test1); -exit_free_test0: +exit_put_test0:  	platform_device_put(test0);  exit_driver_unregister: diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index 073108dcf9e..22eb4ebfa1a 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -247,6 +247,13 @@ static int __devinit tps65910_rtc_probe(struct platform_device *pdev)  		return ret;  	dev_dbg(&pdev->dev, "Enabling rtc-tps65910.\n"); + +	/* Enable RTC digital power domain */ +	ret = regmap_update_bits(tps65910->regmap, TPS65910_DEVCTRL, +		DEVCTRL_RTC_PWDN_MASK, 0 << DEVCTRL_RTC_PWDN_SHIFT); +	if (ret < 0) +		return ret; +  	rtc_reg = TPS65910_RTC_CTRL_STOP_RTC;  	ret = regmap_write(tps65910->regmap, TPS65910_RTC_CTRL, rtc_reg);  	if (ret < 0) @@ -261,7 +268,7 @@ static int __devinit tps65910_rtc_probe(struct platform_device *pdev)  	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,  		tps65910_rtc_interrupt, IRQF_TRIGGER_LOW, -		"rtc-tps65910", &pdev->dev); +		dev_name(&pdev->dev), &pdev->dev);  	if (ret < 0) {  		dev_err(&pdev->dev, "IRQ is not free.\n");  		return ret; diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index 9277d945bf4..8b7464c8b5c 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -233,7 +233,7 @@ static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)   */  static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)  { -	unsigned char rtc_data[ALL_TIME_REGS + 1]; +	unsigned char rtc_data[ALL_TIME_REGS];  	int ret;  	u8 save_control;  	u8 rtc_control; @@ -300,15 +300,15 @@ static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)  static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)  {  	unsigned char save_control; -	unsigned char rtc_data[ALL_TIME_REGS + 1]; +	unsigned char rtc_data[ALL_TIME_REGS];  	int ret; -	rtc_data[1] = bin2bcd(tm->tm_sec); -	rtc_data[2] = bin2bcd(tm->tm_min); -	rtc_data[3] = bin2bcd(tm->tm_hour); -	rtc_data[4] = bin2bcd(tm->tm_mday); -	rtc_data[5] = bin2bcd(tm->tm_mon + 1); -	rtc_data[6] = bin2bcd(tm->tm_year - 100); +	rtc_data[0] = bin2bcd(tm->tm_sec); +	rtc_data[1] = bin2bcd(tm->tm_min); +	rtc_data[2] = bin2bcd(tm->tm_hour); +	rtc_data[3] = bin2bcd(tm->tm_mday); +	rtc_data[4] = bin2bcd(tm->tm_mon + 1); +	rtc_data[5] = bin2bcd(tm->tm_year - 100);  	/* Stop RTC while updating the TC registers */  	ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); @@ -341,7 +341,7 @@ out:   */  static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)  { -	unsigned char rtc_data[ALL_TIME_REGS + 1]; +	unsigned char rtc_data[ALL_TIME_REGS];  	int ret;  	ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, @@ -368,19 +368,19 @@ static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)  static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)  { -	unsigned char alarm_data[ALL_TIME_REGS + 1]; +	unsigned char alarm_data[ALL_TIME_REGS];  	int ret;  	ret = twl_rtc_alarm_irq_enable(dev, 0);  	if (ret)  		goto out; -	alarm_data[1] = bin2bcd(alm->time.tm_sec); -	alarm_data[2] = bin2bcd(alm->time.tm_min); -	alarm_data[3] = bin2bcd(alm->time.tm_hour); -	alarm_data[4] = bin2bcd(alm->time.tm_mday); -	alarm_data[5] = bin2bcd(alm->time.tm_mon + 1); -	alarm_data[6] = bin2bcd(alm->time.tm_year - 100); +	alarm_data[0] = bin2bcd(alm->time.tm_sec); +	alarm_data[1] = bin2bcd(alm->time.tm_min); +	alarm_data[2] = bin2bcd(alm->time.tm_hour); +	alarm_data[3] = bin2bcd(alm->time.tm_mday); +	alarm_data[4] = bin2bcd(alm->time.tm_mon + 1); +	alarm_data[5] = bin2bcd(alm->time.tm_year - 100);  	/* update all the alarm registers in one shot */  	ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data, diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index 07bf19364a7..14e2d8cfcc8 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -210,7 +210,8 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev)  	struct vt8500_rtc *vt8500_rtc;  	int ret; -	vt8500_rtc = kzalloc(sizeof(struct vt8500_rtc), GFP_KERNEL); +	vt8500_rtc = devm_kzalloc(&pdev->dev, +			   sizeof(struct vt8500_rtc), GFP_KERNEL);  	if (!vt8500_rtc)  		return -ENOMEM; @@ -220,15 +221,13 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev)  	vt8500_rtc->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!vt8500_rtc->res) {  		dev_err(&pdev->dev, "No I/O memory resource defined\n"); -		ret = -ENXIO; -		goto err_free; +		return -ENXIO;  	}  	vt8500_rtc->irq_alarm = platform_get_irq(pdev, 0);  	if (vt8500_rtc->irq_alarm < 0) {  		dev_err(&pdev->dev, "No alarm IRQ resource defined\n"); -		ret = -ENXIO; -		goto err_free; +		return -ENXIO;  	}  	vt8500_rtc->res = request_mem_region(vt8500_rtc->res->start, @@ -236,8 +235,7 @@ static int __devinit vt8500_rtc_probe(struct platform_device *pdev)  					     "vt8500-rtc");  	if (vt8500_rtc->res == NULL) {  		dev_err(&pdev->dev, "failed to request I/O memory\n"); -		ret = -EBUSY; -		goto err_free; +		return -EBUSY;  	}  	vt8500_rtc->regbase = ioremap(vt8500_rtc->res->start, @@ -278,8 +276,6 @@ err_unmap:  err_release:  	release_mem_region(vt8500_rtc->res->start,  			   resource_size(vt8500_rtc->res)); -err_free: -	kfree(vt8500_rtc);  	return ret;  } @@ -297,7 +293,6 @@ static int __devexit vt8500_rtc_remove(struct platform_device *pdev)  	release_mem_region(vt8500_rtc->res->start,  			   resource_size(vt8500_rtc->res)); -	kfree(vt8500_rtc);  	platform_set_drvdata(pdev, NULL);  	return 0;  |