diff options
Diffstat (limited to 'drivers/rtc')
83 files changed, 5540 insertions, 1015 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 9654aa3c05c..0754f5c7cb3 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -153,6 +153,16 @@ config RTC_DRV_88PM80X  	  This driver can also be built as a module. If so, the module  	  will be called rtc-88pm80x. +config RTC_DRV_AS3722 +	tristate "ams AS3722 RTC driver" +	depends on MFD_AS3722 +	help +	  If you say yes here you get support for the RTC of ams AS3722 PMIC +	  chips. + +	  This driver can also be built as a module. If so, the module +	  will be called rtc-as3722. +  config RTC_DRV_DS1307  	tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025"  	help @@ -202,6 +212,17 @@ config RTC_DRV_DS3232  	  This driver can also be built as a module.  If so, the module  	  will be called rtc-ds3232. +config RTC_DRV_HYM8563 +	tristate "Haoyu Microelectronics HYM8563" +	depends on I2C && OF +	help +	  Say Y to enable support for the HYM8563 I2C RTC chip. Apart +	  from the usual rtc functions it provides a clock output of +	  up to 32kHz. + +	  This driver can also be built as a module. If so, the module +	  will be called rtc-hym8563. +  config RTC_DRV_LP8788  	tristate "TI LP8788 RTC driver"  	depends on MFD_LP8788 @@ -294,6 +315,17 @@ config RTC_DRV_ISL12022  	  This driver can also be built as a module. If so, the module  	  will be called rtc-isl12022. +config RTC_DRV_ISL12057 +       depends on I2C +       select REGMAP_I2C +       tristate "Intersil ISL12057" +       help +	  If you say yes here you get support for the Intersil ISL12057 +	  I2C RTC chip. + +	  This driver can also be built as a module. If so, the module +	  will be called rtc-isl12057. +  config RTC_DRV_X1205  	tristate "Xicor/Intersil X1205"  	help @@ -354,12 +386,12 @@ config RTC_DRV_PCF8583  	  will be called rtc-pcf8583.  config RTC_DRV_M41T80 -	tristate "ST M41T62/65/M41T80/81/82/83/84/85/87" +	tristate "ST M41T62/65/M41T80/81/82/83/84/85/87 and compatible"  	help  	  If you say Y here you will get support for the ST M41T60  	  and M41T80 RTC chips series. Currently, the following chips are  	  supported: M41T62, M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84, -	  M41ST85, and M41ST87. +	  M41ST85, M41ST87, and MicroCrystal RV4162.  	  This driver can also be built as a module. If so, the module  	  will be called rtc-m41t80. @@ -497,6 +529,16 @@ config RTC_DRV_RV3029C2  	  This driver can also be built as a module. If so, the module  	  will be called rtc-rv3029c2. +config RTC_DRV_S5M +	tristate "Samsung S2M/S5M series" +	depends on MFD_SEC_CORE +	help +	  If you say yes here you will get support for the +	  RTC of Samsung S2MPS14 and S5M PMIC series. + +	  This driver can also be built as a module. If so, the module +	  will be called rtc-s5m. +  endif # I2C  comment "SPI RTC drivers" @@ -531,6 +573,29 @@ config RTC_DRV_DS1305  	  This driver can also be built as a module. If so, the module  	  will be called rtc-ds1305. +config RTC_DRV_DS1343 +	select REGMAP_SPI +	tristate "Dallas/Maxim DS1343/DS1344" +	help +	  If you say yes here you get support for the +	  Dallas/Maxim DS1343 and DS1344 real time clock chips. +	  Support for trickle charger, alarm is provided. + +	  This driver can also be built as a module. If so, the module +	  will be called rtc-ds1343. + +config RTC_DRV_DS1347 +	tristate "Dallas/Maxim DS1347" +	help +	  If you say yes here you get support for the +	  Dallas/Maxim DS1347 chips. + +	  This driver only supports the RTC feature, and not other chip +	  features such as alarms. + +	  This driver can also be built as a module. If so, the module +	  will be called rtc-ds1347. +  config RTC_DRV_DS1390  	tristate "Dallas/Maxim DS1390/93/94"  	help @@ -596,6 +661,14 @@ config RTC_DRV_RX4581  	  This driver can also be built as a module. If so the module  	  will be called rtc-rx4581. +config RTC_DRV_MCP795 +	tristate "Microchip MCP795" +	help +	  If you say yes here you will get support for the Microchip MCP795. + +	  This driver can also be built as a module. If so the module +	  will be called rtc-mcp795. +  endif # SPI_MASTER  comment "Platform RTC drivers" @@ -606,7 +679,7 @@ comment "Platform RTC drivers"  config RTC_DRV_CMOS  	tristate "PC-style 'CMOS'" -	depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS || SPARC64 +	depends on X86 || ARM || M32R || PPC || MIPS || SPARC64  	default y if X86  	help  	  Say "yes" here to get direct support for the real time clock @@ -623,6 +696,14 @@ config RTC_DRV_CMOS  	  This driver can also be built as a module. If so, the module  	  will be called rtc-cmos. +config RTC_DRV_ALPHA +	bool "Alpha PC-style CMOS" +	depends on ALPHA +	default y +	help +	  Direct support for the real-time clock found on every Alpha +	  system, specifically MC146818 compatibles.  If in doubt, say Y. +  config RTC_DRV_VRTC  	tristate "Virtual RTC for Intel MID platforms"  	depends on X86_INTEL_MID @@ -696,6 +777,16 @@ config RTC_DRV_DA9055  	  This driver can also be built as a module. If so, the module  	  will be called rtc-da9055 +config RTC_DRV_DA9063 +	tristate "Dialog Semiconductor DA9063 RTC" +	depends on MFD_DA9063 +	help +	  If you say yes here you will get support for the RTC subsystem +	  of the Dialog Semiconductor DA9063. + +	  This driver can also be built as a module. If so, the module +	  will be called "rtc-da9063". +  config RTC_DRV_EFI  	tristate "EFI RTC"  	depends on IA64 @@ -1076,6 +1167,13 @@ config RTC_DRV_SUN4V  	  If you say Y here you will get support for the Hypervisor  	  based RTC on SUN4V systems. +config RTC_DRV_SUNXI +	tristate "Allwinner sun4i/sun7i RTC" +	depends on ARCH_SUNXI +	help +	  If you say Y here you will get support for the RTC found on +	  Allwinner A10/A20. +  config RTC_DRV_STARFIRE  	bool "Starfire RTC"  	depends on SPARC64 @@ -1258,6 +1356,15 @@ config RTC_DRV_MOXART  	   This driver can also be built as a module. If so, the module  	   will be called rtc-moxart +config RTC_DRV_XGENE +	tristate "APM X-Gene RTC" +	help +	  If you say yes here you get support for the APM X-Gene SoC real time +	  clock. + +	  This driver can also be built as a module, if so, the module +	  will be called "rtc-xgene". +  comment "HID Sensor RTC drivers"  config RTC_DRV_HID_SENSOR_TIME diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 2dff3d2009b..70347d041d1 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -20,6 +20,7 @@ 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_AS3722)	+= rtc-as3722.o  obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o  obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o  obj-$(CONFIG_RTC_DRV_AT91SAM9)	+= rtc-at91sam9.o @@ -31,6 +32,7 @@ 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_DA9063)	+= rtc-da9063.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 @@ -39,6 +41,8 @@ obj-$(CONFIG_RTC_DRV_DS1286)	+= rtc-ds1286.o  obj-$(CONFIG_RTC_DRV_DS1302)	+= rtc-ds1302.o  obj-$(CONFIG_RTC_DRV_DS1305)	+= rtc-ds1305.o  obj-$(CONFIG_RTC_DRV_DS1307)	+= rtc-ds1307.o +obj-$(CONFIG_RTC_DRV_DS1343)	+= rtc-ds1343.o +obj-$(CONFIG_RTC_DRV_DS1347)	+= rtc-ds1347.o  obj-$(CONFIG_RTC_DRV_DS1374)	+= rtc-ds1374.o  obj-$(CONFIG_RTC_DRV_DS1390)	+= rtc-ds1390.o  obj-$(CONFIG_RTC_DRV_DS1511)	+= rtc-ds1511.o @@ -54,9 +58,11 @@ obj-$(CONFIG_RTC_DRV_EP93XX)	+= rtc-ep93xx.o  obj-$(CONFIG_RTC_DRV_FM3130)	+= rtc-fm3130.o  obj-$(CONFIG_RTC_DRV_GENERIC)	+= rtc-generic.o  obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o +obj-$(CONFIG_RTC_DRV_HYM8563)	+= rtc-hym8563.o  obj-$(CONFIG_RTC_DRV_IMXDI)	+= rtc-imxdi.o  obj-$(CONFIG_RTC_DRV_ISL1208)	+= rtc-isl1208.o  obj-$(CONFIG_RTC_DRV_ISL12022)	+= rtc-isl12022.o +obj-$(CONFIG_RTC_DRV_ISL12057)	+= rtc-isl12057.o  obj-$(CONFIG_RTC_DRV_JZ4740)	+= rtc-jz4740.o  obj-$(CONFIG_RTC_DRV_LP8788)	+= rtc-lp8788.o  obj-$(CONFIG_RTC_DRV_LPC32XX)	+= rtc-lpc32xx.o @@ -76,6 +82,7 @@ obj-$(CONFIG_RTC_DRV_MAX8997)	+= rtc-max8997.o  obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o  obj-$(CONFIG_RTC_DRV_MAX77686)	+= rtc-max77686.o  obj-$(CONFIG_RTC_DRV_MC13XXX)	+= rtc-mc13xxx.o +obj-$(CONFIG_RTC_DRV_MCP795)	+= rtc-mcp795.o  obj-$(CONFIG_RTC_DRV_MSM6242)	+= rtc-msm6242.o  obj-$(CONFIG_RTC_DRV_MPC5121)	+= rtc-mpc5121.o  obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o @@ -107,6 +114,7 @@ obj-$(CONFIG_RTC_DRV_RX8025)	+= rtc-rx8025.o  obj-$(CONFIG_RTC_DRV_RX8581)	+= rtc-rx8581.o  obj-$(CONFIG_RTC_DRV_S35390A)	+= rtc-s35390a.o  obj-$(CONFIG_RTC_DRV_S3C)	+= rtc-s3c.o +obj-$(CONFIG_RTC_DRV_S5M)	+= rtc-s5m.o  obj-$(CONFIG_RTC_DRV_SA1100)	+= rtc-sa1100.o  obj-$(CONFIG_RTC_DRV_SH)	+= rtc-sh.o  obj-$(CONFIG_RTC_DRV_SNVS)	+= rtc-snvs.o @@ -115,6 +123,7 @@ obj-$(CONFIG_RTC_DRV_STARFIRE)	+= rtc-starfire.o  obj-$(CONFIG_RTC_DRV_STK17TA8)	+= rtc-stk17ta8.o  obj-$(CONFIG_RTC_DRV_STMP)	+= rtc-stmp3xxx.o  obj-$(CONFIG_RTC_DRV_SUN4V)	+= rtc-sun4v.o +obj-$(CONFIG_RTC_DRV_SUNXI)	+= rtc-sunxi.o  obj-$(CONFIG_RTC_DRV_TEGRA)	+= rtc-tegra.o  obj-$(CONFIG_RTC_DRV_TEST)	+= rtc-test.o  obj-$(CONFIG_RTC_DRV_TILE)	+= rtc-tile.o @@ -129,5 +138,6 @@ obj-$(CONFIG_RTC_DRV_VT8500)	+= rtc-vt8500.o  obj-$(CONFIG_RTC_DRV_WM831X)	+= rtc-wm831x.o  obj-$(CONFIG_RTC_DRV_WM8350)	+= rtc-wm8350.o  obj-$(CONFIG_RTC_DRV_X1205)	+= rtc-x1205.o +obj-$(CONFIG_RTC_DRV_XGENE)	+= rtc-xgene.o  obj-$(CONFIG_RTC_DRV_SIRFSOC)	+= rtc-sirfsoc.o  obj-$(CONFIG_RTC_DRV_MOXART)	+= rtc-moxart.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 02426812beb..589351ef75d 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -14,6 +14,7 @@  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt  #include <linux/module.h> +#include <linux/of.h>  #include <linux/rtc.h>  #include <linux/kdev_t.h>  #include <linux/idr.h> @@ -157,12 +158,27 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,  {  	struct rtc_device *rtc;  	struct rtc_wkalrm alrm; -	int id, err; +	int of_id = -1, id = -1, err; + +	if (dev->of_node) +		of_id = of_alias_get_id(dev->of_node, "rtc"); +	else if (dev->parent && dev->parent->of_node) +		of_id = of_alias_get_id(dev->parent->of_node, "rtc"); + +	if (of_id >= 0) { +		id = ida_simple_get(&rtc_ida, of_id, of_id + 1, +				    GFP_KERNEL); +		if (id < 0) +			dev_warn(dev, "/aliases ID %d not available\n", +				    of_id); +	} -	id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);  	if (id < 0) { -		err = id; -		goto exit; +		id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL); +		if (id < 0) { +			err = id; +			goto exit; +		}  	}  	rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL); diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 72c5cdbe079..5813fa52c3d 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -72,6 +72,7 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)  	} else  		err = -EINVAL; +	pm_stay_awake(rtc->dev.parent);  	mutex_unlock(&rtc->ops_lock);  	/* A timer might have just expired */  	schedule_work(&rtc->irqwork); @@ -113,6 +114,7 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)  		err = -EINVAL;  	} +	pm_stay_awake(rtc->dev.parent);  	mutex_unlock(&rtc->ops_lock);  	/* A timer might have just expired */  	schedule_work(&rtc->irqwork); @@ -290,7 +292,8 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)  		dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year");  		do {  			alarm->time.tm_year++; -		} while (rtc_valid_tm(&alarm->time) != 0); +		} while (!is_leap_year(alarm->time.tm_year + 1900) +			&& rtc_valid_tm(&alarm->time) != 0);  		break;  	default: @@ -298,7 +301,16 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)  	}  done: -	return 0; +	err = rtc_valid_tm(&alarm->time); + +	if (err) { +		dev_warn(&rtc->dev, "invalid alarm value: %d-%d-%d %d:%d:%d\n", +			alarm->time.tm_year + 1900, alarm->time.tm_mon + 1, +			alarm->time.tm_mday, alarm->time.tm_hour, alarm->time.tm_min, +			alarm->time.tm_sec); +	} + +	return err;  }  int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm) @@ -582,6 +594,9 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)  void rtc_update_irq(struct rtc_device *rtc,  		unsigned long num, unsigned long events)  { +	if (unlikely(IS_ERR_OR_NULL(rtc))) +		return; +  	pm_stay_awake(rtc->dev.parent);  	schedule_work(&rtc->irqwork);  } @@ -771,9 +786,10 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)  		alarm.time = rtc_ktime_to_tm(timer->node.expires);  		alarm.enabled = 1;  		err = __rtc_set_alarm(rtc, &alarm); -		if (err == -ETIME) +		if (err == -ETIME) { +			pm_stay_awake(rtc->dev.parent);  			schedule_work(&rtc->irqwork); -		else if (err) { +		} else if (err) {  			timerqueue_del(&rtc->timerqueue, &timer->node);  			timer->enabled = 0;  			return err; @@ -818,8 +834,10 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)  		alarm.time = rtc_ktime_to_tm(next->expires);  		alarm.enabled = 1;  		err = __rtc_set_alarm(rtc, &alarm); -		if (err == -ETIME) +		if (err == -ETIME) { +			pm_stay_awake(rtc->dev.parent);  			schedule_work(&rtc->irqwork); +		}  	}  } @@ -845,7 +863,6 @@ void rtc_timer_do_work(struct work_struct *work)  	mutex_lock(&rtc->ops_lock);  again: -	pm_relax(rtc->dev.parent);  	__rtc_read_time(rtc, &tm);  	now = rtc_tm_to_ktime(tm);  	while ((next = timerqueue_getnext(&rtc->timerqueue))) { @@ -880,6 +897,7 @@ again:  	} else  		rtc_alarm_disable(rtc); +	pm_relax(rtc->dev.parent);  	mutex_unlock(&rtc->ops_lock);  } diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c index 354c937a586..0916089c7c3 100644 --- a/drivers/rtc/rtc-88pm80x.c +++ b/drivers/rtc/rtc-88pm80x.c @@ -251,14 +251,15 @@ static SIMPLE_DEV_PM_OPS(pm80x_rtc_pm_ops, pm80x_rtc_suspend, pm80x_rtc_resume);  static int 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_platform_data *pm80x_pdata = +				dev_get_platdata(pdev->dev.parent);  	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; +	pdata = dev_get_platdata(&pdev->dev);  	if (pdata == NULL)  		dev_warn(&pdev->dev, "No platform data!\n"); @@ -326,8 +327,7 @@ static int pm80x_rtc_probe(struct platform_device *pdev)  	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; +	if (pm80x_pdata) {  		pdata = pm80x_pdata->rtc;  		if (pdata)  			info->rtc_dev->dev.platform_data = &pdata->rtc_wakeup; diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c index 4e30c85728e..0c6add1a38d 100644 --- a/drivers/rtc/rtc-88pm860x.c +++ b/drivers/rtc/rtc-88pm860x.c @@ -293,7 +293,7 @@ static int pm860x_rtc_dt_init(struct platform_device *pdev,  	int ret;  	if (!np)  		return -ENODEV; -	np = of_find_node_by_name(np, "rtc"); +	np = of_get_child_by_name(np, "rtc");  	if (!np) {  		dev_err(&pdev->dev, "failed to find rtc node\n");  		return -ENODEV; @@ -301,6 +301,7 @@ static int pm860x_rtc_dt_init(struct platform_device *pdev,  	ret = of_property_read_u32(np, "marvell,88pm860x-vrtc", &info->vrtc);  	if (ret)  		info->vrtc = 0; +	of_node_put(np);  	return 0;  }  #else @@ -316,7 +317,7 @@ static int pm860x_rtc_probe(struct platform_device *pdev)  	unsigned long ticks = 0;  	int ret; -	pdata = pdev->dev.platform_data; +	pdata = dev_get_platdata(&pdev->dev);  	info = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_rtc_info),  			    GFP_KERNEL); diff --git a/drivers/rtc/rtc-as3722.c b/drivers/rtc/rtc-as3722.c new file mode 100644 index 00000000000..9f38eda6915 --- /dev/null +++ b/drivers/rtc/rtc-as3722.c @@ -0,0 +1,261 @@ +/* + * rtc-as3722.c - Real Time Clock driver for ams AS3722 PMICs + * + * Copyright (C) 2013 ams AG + * Copyright (c) 2013, NVIDIA Corporation. All rights reserved. + * + * Author: Florian Lobmaier <florian.lobmaier@ams.com> + * Author: Laxman Dewangan <ldewangan@nvidia.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. + * + * 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. + */ + +#include <linux/bcd.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/ioctl.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/mfd/as3722.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/time.h> + +#define AS3722_RTC_START_YEAR	  2000 +struct as3722_rtc { +	struct rtc_device	*rtc; +	struct device		*dev; +	struct as3722		*as3722; +	int			alarm_irq; +	bool			irq_enable; +}; + +static void as3722_time_to_reg(u8 *rbuff, struct rtc_time *tm) +{ +	rbuff[0] = bin2bcd(tm->tm_sec); +	rbuff[1] = bin2bcd(tm->tm_min); +	rbuff[2] = bin2bcd(tm->tm_hour); +	rbuff[3] = bin2bcd(tm->tm_mday); +	rbuff[4] = bin2bcd(tm->tm_mon); +	rbuff[5] = bin2bcd(tm->tm_year - (AS3722_RTC_START_YEAR - 1900)); +} + +static void as3722_reg_to_time(u8 *rbuff, struct rtc_time *tm) +{ +	tm->tm_sec = bcd2bin(rbuff[0] & 0x7F); +	tm->tm_min = bcd2bin(rbuff[1] & 0x7F); +	tm->tm_hour = bcd2bin(rbuff[2] & 0x3F); +	tm->tm_mday = bcd2bin(rbuff[3] & 0x3F); +	tm->tm_mon = bcd2bin(rbuff[4] & 0x1F); +	tm->tm_year = (AS3722_RTC_START_YEAR - 1900) + bcd2bin(rbuff[5] & 0x7F); +	return; +} + +static int as3722_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ +	struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); +	struct as3722 *as3722 = as3722_rtc->as3722; +	u8 as_time_array[6]; +	int ret; + +	ret = as3722_block_read(as3722, AS3722_RTC_SECOND_REG, +			6, as_time_array); +	if (ret < 0) { +		dev_err(dev, "RTC_SECOND reg block read failed %d\n", ret); +		return ret; +	} +	as3722_reg_to_time(as_time_array, tm); +	return 0; +} + +static int as3722_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ +	struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); +	struct as3722 *as3722 = as3722_rtc->as3722; +	u8 as_time_array[6]; +	int ret; + +	if (tm->tm_year < (AS3722_RTC_START_YEAR - 1900)) +		return -EINVAL; + +	as3722_time_to_reg(as_time_array, tm); +	ret = as3722_block_write(as3722, AS3722_RTC_SECOND_REG, 6, +			as_time_array); +	if (ret < 0) +		dev_err(dev, "RTC_SECOND reg block write failed %d\n", ret); +	return ret; +} + +static int as3722_rtc_alarm_irq_enable(struct device *dev, +		unsigned int enabled) +{ +	struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + +	if (enabled && !as3722_rtc->irq_enable) { +		enable_irq(as3722_rtc->alarm_irq); +		as3722_rtc->irq_enable = true; +	} else if (!enabled && as3722_rtc->irq_enable)  { +		disable_irq(as3722_rtc->alarm_irq); +		as3722_rtc->irq_enable = false; +	} +	return 0; +} + +static int as3722_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); +	struct as3722 *as3722 = as3722_rtc->as3722; +	u8 as_time_array[6]; +	int ret; + +	ret = as3722_block_read(as3722, AS3722_RTC_ALARM_SECOND_REG, 6, +			as_time_array); +	if (ret < 0) { +		dev_err(dev, "RTC_ALARM_SECOND block read failed %d\n", ret); +		return ret; +	} + +	as3722_reg_to_time(as_time_array, &alrm->time); +	return 0; +} + +static int as3722_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); +	struct as3722 *as3722 = as3722_rtc->as3722; +	u8 as_time_array[6]; +	int ret; + +	if (alrm->time.tm_year < (AS3722_RTC_START_YEAR - 1900)) +		return -EINVAL; + +	ret = as3722_rtc_alarm_irq_enable(dev, 0); +	if (ret < 0) { +		dev_err(dev, "Disable RTC alarm failed\n"); +		return ret; +	} + +	as3722_time_to_reg(as_time_array, &alrm->time); +	ret = as3722_block_write(as3722, AS3722_RTC_ALARM_SECOND_REG, 6, +			as_time_array); +	if (ret < 0) { +		dev_err(dev, "RTC_ALARM_SECOND block write failed %d\n", ret); +		return ret; +	} + +	if (alrm->enabled) +		ret = as3722_rtc_alarm_irq_enable(dev, alrm->enabled); +	return ret; +} + +static irqreturn_t as3722_alarm_irq(int irq, void *data) +{ +	struct as3722_rtc *as3722_rtc = data; + +	rtc_update_irq(as3722_rtc->rtc, 1, RTC_IRQF | RTC_AF); +	return IRQ_HANDLED; +} + +static const struct rtc_class_ops as3722_rtc_ops = { +	.read_time = as3722_rtc_read_time, +	.set_time = as3722_rtc_set_time, +	.read_alarm = as3722_rtc_read_alarm, +	.set_alarm = as3722_rtc_set_alarm, +	.alarm_irq_enable = as3722_rtc_alarm_irq_enable, +}; + +static int as3722_rtc_probe(struct platform_device *pdev) +{ +	struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent); +	struct as3722_rtc *as3722_rtc; +	int ret; + +	as3722_rtc = devm_kzalloc(&pdev->dev, sizeof(*as3722_rtc), GFP_KERNEL); +	if (!as3722_rtc) +		return -ENOMEM; + +	as3722_rtc->as3722 = as3722; +	as3722_rtc->dev = &pdev->dev; +	platform_set_drvdata(pdev, as3722_rtc); + +	/* Enable the RTC to make sure it is running. */ +	ret = as3722_update_bits(as3722, AS3722_RTC_CONTROL_REG, +			AS3722_RTC_ON | AS3722_RTC_ALARM_WAKEUP_EN, +			AS3722_RTC_ON | AS3722_RTC_ALARM_WAKEUP_EN); +	if (ret < 0) { +		dev_err(&pdev->dev, "RTC_CONTROL reg write failed: %d\n", ret); +		return ret; +	} + +	device_init_wakeup(&pdev->dev, 1); + +	as3722_rtc->rtc = devm_rtc_device_register(&pdev->dev, "as3722-rtc", +				&as3722_rtc_ops, THIS_MODULE); +	if (IS_ERR(as3722_rtc->rtc)) { +		ret = PTR_ERR(as3722_rtc->rtc); +		dev_err(&pdev->dev, "RTC register failed: %d\n", ret); +		return ret; +	} + +	as3722_rtc->alarm_irq = platform_get_irq(pdev, 0); +	dev_info(&pdev->dev, "RTC interrupt %d\n", as3722_rtc->alarm_irq); + +	ret = devm_request_threaded_irq(&pdev->dev, as3722_rtc->alarm_irq, NULL, +			as3722_alarm_irq, IRQF_ONESHOT | IRQF_EARLY_RESUME, +			"rtc-alarm", as3722_rtc); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n", +				as3722_rtc->alarm_irq, ret); +		return ret; +	} +	disable_irq(as3722_rtc->alarm_irq); +	return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int as3722_rtc_suspend(struct device *dev) +{ +	struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + +	if (device_may_wakeup(dev)) +		enable_irq_wake(as3722_rtc->alarm_irq); + +	return 0; +} + +static int as3722_rtc_resume(struct device *dev) +{ +	struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev); + +	if (device_may_wakeup(dev)) +		disable_irq_wake(as3722_rtc->alarm_irq); +	return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(as3722_rtc_pm_ops, as3722_rtc_suspend, +			 as3722_rtc_resume); + +static struct platform_driver as3722_rtc_driver = { +	.probe = as3722_rtc_probe, +	.driver = { +		.name = "as3722-rtc", +		.pm = &as3722_rtc_pm_ops, +	}, +}; +module_platform_driver(as3722_rtc_driver); + +MODULE_DESCRIPTION("RTC driver for AS3722 PMICs"); +MODULE_ALIAS("platform:as3722-rtc"); +MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@ams.com>"); +MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c index 3161ab5263e..aee3387fb09 100644 --- a/drivers/rtc/rtc-at32ap700x.c +++ b/drivers/rtc/rtc-at32ap700x.c @@ -204,10 +204,8 @@ static int __init at32_rtc_probe(struct platform_device *pdev)  	rtc = devm_kzalloc(&pdev->dev, sizeof(struct rtc_at32ap700x),  			   GFP_KERNEL); -	if (!rtc) { -		dev_dbg(&pdev->dev, "out of memory\n"); +	if (!rtc)  		return -ENOMEM; -	}  	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!regs) { diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c index 741892632ae..44fe83ee9be 100644 --- a/drivers/rtc/rtc-at91rm9200.c +++ b/drivers/rtc/rtc-at91rm9200.c @@ -48,6 +48,7 @@ struct at91_rtc_config {  static const struct at91_rtc_config *at91_rtc_config;  static DECLARE_COMPLETION(at91_rtc_updated); +static DECLARE_COMPLETION(at91_rtc_upd_rdy);  static unsigned int at91_alarm_year = AT91_RTC_EPOCH;  static void __iomem *at91_rtc_regs;  static int irq; @@ -161,6 +162,8 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)  		1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,  		tm->tm_hour, tm->tm_min, tm->tm_sec); +	wait_for_completion(&at91_rtc_upd_rdy); +  	/* Stop Time/Calendar from counting */  	cr = at91_rtc_read(AT91_RTC_CR);  	at91_rtc_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM); @@ -183,7 +186,9 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)  	/* Restart Time/Calendar */  	cr = at91_rtc_read(AT91_RTC_CR); +	at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_SECEV);  	at91_rtc_write(AT91_RTC_CR, cr & ~(AT91_RTC_UPDCAL | AT91_RTC_UPDTIM)); +	at91_rtc_write_ier(AT91_RTC_SECEV);  	return 0;  } @@ -220,6 +225,8 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)  	at91_alarm_year = tm.tm_year; +	tm.tm_mon = alrm->time.tm_mon; +	tm.tm_mday = alrm->time.tm_mday;  	tm.tm_hour = alrm->time.tm_hour;  	tm.tm_min = alrm->time.tm_min;  	tm.tm_sec = alrm->time.tm_sec; @@ -288,8 +295,10 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)  	if (rtsr) {		/* this interrupt is shared!  Is it ours? */  		if (rtsr & AT91_RTC_ALARM)  			events |= (RTC_AF | RTC_IRQF); -		if (rtsr & AT91_RTC_SECEV) -			events |= (RTC_UF | RTC_IRQF); +		if (rtsr & AT91_RTC_SECEV) { +			complete(&at91_rtc_upd_rdy); +			at91_rtc_write_idr(AT91_RTC_SECEV); +		}  		if (rtsr & AT91_RTC_ACKUPD)  			complete(&at91_rtc_updated); @@ -376,7 +385,8 @@ static int __init at91_rtc_probe(struct platform_device *pdev)  		return -ENXIO;  	} -	at91_rtc_regs = ioremap(regs->start, resource_size(regs)); +	at91_rtc_regs = devm_ioremap(&pdev->dev, regs->start, +				     resource_size(regs));  	if (!at91_rtc_regs) {  		dev_err(&pdev->dev, "failed to map registers, aborting.\n");  		return -ENOMEM; @@ -390,12 +400,12 @@ static int __init at91_rtc_probe(struct platform_device *pdev)  					AT91_RTC_SECEV | AT91_RTC_TIMEV |  					AT91_RTC_CALEV); -	ret = request_irq(irq, at91_rtc_interrupt, +	ret = devm_request_irq(&pdev->dev, irq, at91_rtc_interrupt,  				IRQF_SHARED,  				"at91_rtc", pdev);  	if (ret) {  		dev_err(&pdev->dev, "IRQ %d already in use.\n", irq); -		goto err_unmap; +		return ret;  	}  	/* cpu init code should really have flagged this device as @@ -404,23 +414,19 @@ static int __init at91_rtc_probe(struct platform_device *pdev)  	if (!device_can_wakeup(&pdev->dev))  		device_init_wakeup(&pdev->dev, 1); -	rtc = rtc_device_register(pdev->name, &pdev->dev, +	rtc = devm_rtc_device_register(&pdev->dev, pdev->name,  				&at91_rtc_ops, THIS_MODULE); -	if (IS_ERR(rtc)) { -		ret = PTR_ERR(rtc); -		goto err_free_irq; -	} +	if (IS_ERR(rtc)) +		return PTR_ERR(rtc);  	platform_set_drvdata(pdev, rtc); +	/* enable SECEV interrupt in order to initialize at91_rtc_upd_rdy +	 * completion. +	 */ +	at91_rtc_write_ier(AT91_RTC_SECEV); +  	dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n");  	return 0; - -err_free_irq: -	free_irq(irq, pdev); -err_unmap: -	iounmap(at91_rtc_regs); - -	return ret;  }  /* @@ -428,20 +434,22 @@ err_unmap:   */  static int __exit at91_rtc_remove(struct platform_device *pdev)  { -	struct rtc_device *rtc = platform_get_drvdata(pdev); -  	/* Disable all interrupts */  	at91_rtc_write_idr(AT91_RTC_ACKUPD | AT91_RTC_ALARM |  					AT91_RTC_SECEV | AT91_RTC_TIMEV |  					AT91_RTC_CALEV); -	free_irq(irq, pdev); - -	rtc_device_unregister(rtc); -	iounmap(at91_rtc_regs);  	return 0;  } +static void at91_rtc_shutdown(struct platform_device *pdev) +{ +	/* Disable all interrupts */ +	at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM | +					AT91_RTC_SECEV | AT91_RTC_TIMEV | +					AT91_RTC_CALEV); +} +  #ifdef CONFIG_PM_SLEEP  /* AT91RM9200 RTC Power management control */ @@ -480,6 +488,7 @@ static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume);  static struct platform_driver at91_rtc_driver = {  	.remove		= __exit_p(at91_rtc_remove), +	.shutdown	= at91_rtc_shutdown,  	.driver		= {  		.name	= "at91_rtc",  		.owner	= THIS_MODULE, diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c index 309b8b342d9..59637430453 100644 --- a/drivers/rtc/rtc-at91sam9.c +++ b/drivers/rtc/rtc-at91sam9.c @@ -24,7 +24,7 @@  #include <mach/at91_rtt.h>  #include <mach/cpu.h> - +#include <mach/hardware.h>  /*   * This driver uses two configurable hardware resources that live in the diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c index 0c53f452849..fe4bdb06a55 100644 --- a/drivers/rtc/rtc-bfin.c +++ b/drivers/rtc/rtc-bfin.c @@ -346,7 +346,7 @@ static int bfin_rtc_probe(struct platform_device *pdev)  {  	struct bfin_rtc *rtc;  	struct device *dev = &pdev->dev; -	int ret = 0; +	int ret;  	unsigned long timeout = jiffies + HZ;  	dev_dbg_stamp(dev); @@ -361,16 +361,17 @@ static int bfin_rtc_probe(struct platform_device *pdev)  	/* Register our RTC with the RTC framework */  	rtc->rtc_dev = devm_rtc_device_register(dev, pdev->name, &bfin_rtc_ops,  						THIS_MODULE); -	if (unlikely(IS_ERR(rtc->rtc_dev))) { -		ret = PTR_ERR(rtc->rtc_dev); -		goto err; -	} +	if (unlikely(IS_ERR(rtc->rtc_dev))) +		return PTR_ERR(rtc->rtc_dev);  	/* Grab the IRQ and init the hardware */  	ret = devm_request_irq(dev, IRQ_RTC, bfin_rtc_interrupt, 0,  				pdev->name, dev);  	if (unlikely(ret)) -		goto err; +		dev_err(&pdev->dev, +			"unable to request IRQ; alarm won't work, " +			"and writes will be delayed\n"); +  	/* sometimes the bootloader touched things, but the write complete was not  	 * enabled, so let's just do a quick timeout here since the IRQ will not fire ...  	 */ @@ -381,9 +382,6 @@ static int bfin_rtc_probe(struct platform_device *pdev)  	bfin_write_RTC_SWCNT(0);  	return 0; - -err: -	return ret;  }  static int bfin_rtc_remove(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index 24e733c98f8..b0e4a3eb33c 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -34,11 +34,11 @@  #include <linux/interrupt.h>  #include <linux/spinlock.h>  #include <linux/platform_device.h> -#include <linux/mod_devicetable.h>  #include <linux/log2.h>  #include <linux/pm.h>  #include <linux/of.h>  #include <linux/of_platform.h> +#include <linux/dmi.h>  /* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */  #include <asm-generic/rtc.h> @@ -377,6 +377,51 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)  	return 0;  } +/* + * Do not disable RTC alarm on shutdown - workaround for b0rked BIOSes. + */ +static bool alarm_disable_quirk; + +static int __init set_alarm_disable_quirk(const struct dmi_system_id *id) +{ +	alarm_disable_quirk = true; +	pr_info("rtc-cmos: BIOS has alarm-disable quirk. "); +	pr_info("RTC alarms disabled\n"); +	return 0; +} + +static const struct dmi_system_id rtc_quirks[] __initconst = { +	/* https://bugzilla.novell.com/show_bug.cgi?id=805740 */ +	{ +		.callback = set_alarm_disable_quirk, +		.ident    = "IBM Truman", +		.matches  = { +			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), +			DMI_MATCH(DMI_PRODUCT_NAME, "4852570"), +		}, +	}, +	/* https://bugzilla.novell.com/show_bug.cgi?id=812592 */ +	{ +		.callback = set_alarm_disable_quirk, +		.ident    = "Gigabyte GA-990XA-UD3", +		.matches  = { +			DMI_MATCH(DMI_SYS_VENDOR, +					"Gigabyte Technology Co., Ltd."), +			DMI_MATCH(DMI_PRODUCT_NAME, "GA-990XA-UD3"), +		}, +	}, +	/* http://permalink.gmane.org/gmane.linux.kernel/1604474 */ +	{ +		.callback = set_alarm_disable_quirk, +		.ident    = "Toshiba Satellite L300", +		.matches  = { +			DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"), +			DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L300"), +		}, +	}, +	{} +}; +  static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled)  {  	struct cmos_rtc	*cmos = dev_get_drvdata(dev); @@ -385,6 +430,9 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled)  	if (!is_valid_irq(cmos->irq))  		return -EINVAL; +	if (alarm_disable_quirk) +		return 0; +  	spin_lock_irqsave(&rtc_lock, flags);  	if (enabled) @@ -595,10 +643,11 @@ static irqreturn_t cmos_interrupt(int irq, void *p)  static int INITSECTION  cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)  { -	struct cmos_rtc_board_info	*info = dev->platform_data; +	struct cmos_rtc_board_info	*info = dev_get_platdata(dev);  	int				retval = 0;  	unsigned char			rtc_control;  	unsigned			address_space; +	u32				flags = 0;  	/* there can be only one ... */  	if (cmos_rtc.dev) @@ -612,9 +661,12 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)  	 * REVISIT non-x86 systems may instead use memory space resources  	 * (needing ioremap etc), not i/o space resources like this ...  	 */ -	ports = request_region(ports->start, -			resource_size(ports), -			driver_name); +	if (RTC_IOMAPPED) +		ports = request_region(ports->start, resource_size(ports), +				       driver_name); +	else +		ports = request_mem_region(ports->start, resource_size(ports), +					   driver_name);  	if (!ports) {  		dev_dbg(dev, "i/o registers already in use\n");  		return -EBUSY; @@ -651,6 +703,11 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)  	 * expect CMOS_READ and friends to handle.  	 */  	if (info) { +		if (info->flags) +			flags = info->flags; +		if (info->address_space) +			address_space = info->address_space; +  		if (info->rtc_day_alarm && info->rtc_day_alarm < 128)  			cmos_rtc.day_alrm = info->rtc_day_alarm;  		if (info->rtc_mon_alarm && info->rtc_mon_alarm < 128) @@ -678,18 +735,21 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)  	spin_lock_irq(&rtc_lock); -	/* force periodic irq to CMOS reset default of 1024Hz; -	 * -	 * REVISIT it's been reported that at least one x86_64 ALI mobo -	 * doesn't use 32KHz here ... for portability we might need to -	 * do something about other clock frequencies. -	 */ -	cmos_rtc.rtc->irq_freq = 1024; -	hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq); -	CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT); +	if (!(flags & CMOS_RTC_FLAGS_NOFREQ)) { +		/* force periodic irq to CMOS reset default of 1024Hz; +		 * +		 * REVISIT it's been reported that at least one x86_64 ALI +		 * mobo doesn't use 32KHz here ... for portability we might +		 * need to do something about other clock frequencies. +		 */ +		cmos_rtc.rtc->irq_freq = 1024; +		hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq); +		CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT); +	}  	/* disable irqs */ -	cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE); +	if (is_valid_irq(rtc_irq)) +		cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE);  	rtc_control = CMOS_READ(RTC_CONTROL); @@ -708,11 +768,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)  		irq_handler_t rtc_cmos_int_handler;  		if (is_hpet_enabled()) { -			int err; -  			rtc_cmos_int_handler = hpet_rtc_interrupt; -			err = hpet_register_irq_handler(cmos_interrupt); -			if (err != 0) { +			retval = hpet_register_irq_handler(cmos_interrupt); +			if (retval) {  				dev_warn(dev, "hpet_register_irq_handler "  						" failed in rtc_init().");  				goto cleanup1; @@ -756,14 +814,18 @@ cleanup1:  	cmos_rtc.dev = NULL;  	rtc_device_unregister(cmos_rtc.rtc);  cleanup0: -	release_region(ports->start, resource_size(ports)); +	if (RTC_IOMAPPED) +		release_region(ports->start, resource_size(ports)); +	else +		release_mem_region(ports->start, resource_size(ports));  	return retval;  } -static void cmos_do_shutdown(void) +static void cmos_do_shutdown(int rtc_irq)  {  	spin_lock_irq(&rtc_lock); -	cmos_irq_disable(&cmos_rtc, RTC_IRQMASK); +	if (is_valid_irq(rtc_irq)) +		cmos_irq_disable(&cmos_rtc, RTC_IRQMASK);  	spin_unlock_irq(&rtc_lock);  } @@ -772,7 +834,7 @@ static void __exit cmos_do_remove(struct device *dev)  	struct cmos_rtc	*cmos = dev_get_drvdata(dev);  	struct resource *ports; -	cmos_do_shutdown(); +	cmos_do_shutdown(cmos->irq);  	sysfs_remove_bin_file(&dev->kobj, &nvram); @@ -785,14 +847,16 @@ static void __exit cmos_do_remove(struct device *dev)  	cmos->rtc = NULL;  	ports = cmos->iomem; -	release_region(ports->start, resource_size(ports)); +	if (RTC_IOMAPPED) +		release_region(ports->start, resource_size(ports)); +	else +		release_mem_region(ports->start, resource_size(ports));  	cmos->iomem = NULL;  	cmos->dev = NULL; -	dev_set_drvdata(dev, NULL);  } -#ifdef	CONFIG_PM +#ifdef	CONFIG_PM_SLEEP  static int cmos_suspend(struct device *dev)  { @@ -890,8 +954,6 @@ static int cmos_resume(struct device *dev)  	return 0;  } -static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume); -  #else  static inline int cmos_poweroff(struct device *dev) @@ -901,6 +963,8 @@ static inline int cmos_poweroff(struct device *dev)  #endif +static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume); +  /*----------------------------------------------------------------*/  /* On non-x86 systems, a "CMOS" RTC lives most naturally on platform_bus. @@ -1020,10 +1084,13 @@ static void __exit cmos_pnp_remove(struct pnp_dev *pnp)  static void cmos_pnp_shutdown(struct pnp_dev *pnp)  { -	if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pnp->dev)) +	struct device *dev = &pnp->dev; +	struct cmos_rtc	*cmos = dev_get_drvdata(dev); + +	if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev))  		return; -	cmos_do_shutdown(); +	cmos_do_shutdown(cmos->irq);  }  static const struct pnp_device_id rtc_ids[] = { @@ -1043,11 +1110,9 @@ static struct pnp_driver cmos_pnp_driver = {  	/* flag ensures resume() gets called, and stops syslog spam */  	.flags		= PNP_DRIVER_RES_DO_NOT_CHANGE, -#ifdef CONFIG_PM_SLEEP  	.driver		= {  			.pm = &cmos_pm_ops,  	}, -#endif  };  #endif	/* CONFIG_PNP */ @@ -1100,11 +1165,21 @@ static inline void cmos_of_init(struct platform_device *pdev) {}  static int __init cmos_platform_probe(struct platform_device *pdev)  { +	struct resource *resource; +	int irq; +  	cmos_of_init(pdev);  	cmos_wake_setup(&pdev->dev); -	return cmos_do_probe(&pdev->dev, -			platform_get_resource(pdev, IORESOURCE_IO, 0), -			platform_get_irq(pdev, 0)); + +	if (RTC_IOMAPPED) +		resource = platform_get_resource(pdev, IORESOURCE_IO, 0); +	else +		resource = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	irq = platform_get_irq(pdev, 0); +	if (irq < 0) +		irq = -1; + +	return cmos_do_probe(&pdev->dev, resource, irq);  }  static int __exit cmos_platform_remove(struct platform_device *pdev) @@ -1115,10 +1190,13 @@ static int __exit cmos_platform_remove(struct platform_device *pdev)  static void cmos_platform_shutdown(struct platform_device *pdev)  { -	if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pdev->dev)) +	struct device *dev = &pdev->dev; +	struct cmos_rtc	*cmos = dev_get_drvdata(dev); + +	if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev))  		return; -	cmos_do_shutdown(); +	cmos_do_shutdown(cmos->irq);  }  /* work with hotplug and coldplug */ @@ -1128,7 +1206,7 @@ static struct platform_driver cmos_platform_driver = {  	.remove		= __exit_p(cmos_platform_remove),  	.shutdown	= cmos_platform_shutdown,  	.driver = { -		.name		= (char *) driver_name, +		.name		= driver_name,  #ifdef CONFIG_PM  		.pm		= &cmos_pm_ops,  #endif @@ -1158,6 +1236,8 @@ static int __init cmos_init(void)  			platform_driver_registered = true;  	} +	dmi_check_system(rtc_quirks); +  	if (retval == 0)  		return 0; diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index 73f157519df..869cae27379 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -43,8 +43,6 @@  struct coh901331_port {  	struct rtc_device *rtc;  	struct clk *clk; -	u32 phybase; -	u32 physize;  	void __iomem *virtbase;  	int irq;  #ifdef CONFIG_PM_SLEEP @@ -173,19 +171,9 @@ static int __init coh901331_probe(struct platform_device *pdev)  		return -ENOMEM;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) -		return -ENOENT; - -	rtap->phybase = res->start; -	rtap->physize = resource_size(res); - -	if (devm_request_mem_region(&pdev->dev, rtap->phybase, rtap->physize, -				    "rtc-coh901331") == NULL) -		return -EBUSY; - -	rtap->virtbase = devm_ioremap(&pdev->dev, rtap->phybase, rtap->physize); -	if (!rtap->virtbase) -		return -ENOMEM; +	rtap->virtbase  = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(rtap->virtbase)) +		return PTR_ERR(rtap->virtbase);  	rtap->irq = platform_get_irq(pdev, 0);  	if (devm_request_irq(&pdev->dev, rtap->irq, coh901331_interrupt, 0, diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c index 4385ca4503d..e5c9486cf45 100644 --- a/drivers/rtc/rtc-da9052.c +++ b/drivers/rtc/rtc-da9052.c @@ -20,29 +20,28 @@  #include <linux/mfd/da9052/da9052.h>  #include <linux/mfd/da9052/reg.h> -#define rtc_err(da9052, fmt, ...) \ -		dev_err(da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__) +#define rtc_err(rtc, fmt, ...) \ +		dev_err(rtc->da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__)  struct da9052_rtc {  	struct rtc_device *rtc;  	struct da9052 *da9052; -	int irq;  }; -static int da9052_rtc_enable_alarm(struct da9052 *da9052, bool enable) +static int da9052_rtc_enable_alarm(struct da9052_rtc *rtc, bool enable)  {  	int ret;  	if (enable) { -		ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG, -					DA9052_ALARM_Y_ALARM_ON, -					DA9052_ALARM_Y_ALARM_ON); +		ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG, +				DA9052_ALARM_Y_ALARM_ON|DA9052_ALARM_Y_TICK_ON, +				DA9052_ALARM_Y_ALARM_ON);  		if (ret != 0) -			rtc_err(da9052, "Failed to enable ALM: %d\n", ret); +			rtc_err(rtc, "Failed to enable ALM: %d\n", ret);  	} else { -		ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG, -					DA9052_ALARM_Y_ALARM_ON, 0); +		ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG, +			DA9052_ALARM_Y_ALARM_ON|DA9052_ALARM_Y_TICK_ON, 0);  		if (ret != 0) -			rtc_err(da9052, "Write error: %d\n", ret); +			rtc_err(rtc, "Write error: %d\n", ret);  	}  	return ret;  } @@ -50,31 +49,20 @@ static int da9052_rtc_enable_alarm(struct da9052 *da9052, bool enable)  static irqreturn_t da9052_rtc_irq(int irq, void *data)  {  	struct da9052_rtc *rtc = data; -	int ret; -	ret = da9052_reg_read(rtc->da9052, DA9052_ALARM_MI_REG); -	if (ret < 0) { -		rtc_err(rtc->da9052, "Read error: %d\n", ret); -		return IRQ_NONE; -	} - -	if (ret & DA9052_ALARMMI_ALARMTYPE) { -		da9052_rtc_enable_alarm(rtc->da9052, 0); -		rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF); -	} else -		rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_PF); +	rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);  	return IRQ_HANDLED;  } -static int da9052_read_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm) +static int da9052_read_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm)  {  	int ret;  	uint8_t v[5]; -	ret = da9052_group_read(da9052, DA9052_ALARM_MI_REG, 5, v); +	ret = da9052_group_read(rtc->da9052, DA9052_ALARM_MI_REG, 5, v);  	if (ret != 0) { -		rtc_err(da9052, "Failed to group read ALM: %d\n", ret); +		rtc_err(rtc, "Failed to group read ALM: %d\n", ret);  		return ret;  	} @@ -85,23 +73,33 @@ static int da9052_read_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm)  	rtc_tm->tm_min  = v[0] & DA9052_RTC_MIN;  	ret = rtc_valid_tm(rtc_tm); -	if (ret != 0) -		return ret;  	return ret;  } -static int da9052_set_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm) +static int da9052_set_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm)  { +	struct da9052 *da9052 = rtc->da9052; +	unsigned long alm_time;  	int ret;  	uint8_t v[3]; +	ret = rtc_tm_to_time(rtc_tm, &alm_time); +	if (ret != 0) +		return ret; + +	if (rtc_tm->tm_sec > 0) { +		alm_time += 60 - rtc_tm->tm_sec; +		rtc_time_to_tm(alm_time, rtc_tm); +	} +	BUG_ON(rtc_tm->tm_sec); /* it will cause repeated irqs if not zero */ +  	rtc_tm->tm_year -= 100;  	rtc_tm->tm_mon += 1;  	ret = da9052_reg_update(da9052, DA9052_ALARM_MI_REG,  				DA9052_RTC_MIN, rtc_tm->tm_min);  	if (ret != 0) { -		rtc_err(da9052, "Failed to write ALRM MIN: %d\n", ret); +		rtc_err(rtc, "Failed to write ALRM MIN: %d\n", ret);  		return ret;  	} @@ -116,22 +114,22 @@ static int da9052_set_alarm(struct da9052 *da9052, struct rtc_time *rtc_tm)  	ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG,  				DA9052_RTC_YEAR, rtc_tm->tm_year);  	if (ret != 0) -		rtc_err(da9052, "Failed to write ALRM YEAR: %d\n", ret); +		rtc_err(rtc, "Failed to write ALRM YEAR: %d\n", ret);  	return ret;  } -static int da9052_rtc_get_alarm_status(struct da9052 *da9052) +static int da9052_rtc_get_alarm_status(struct da9052_rtc *rtc)  {  	int ret; -	ret = da9052_reg_read(da9052, DA9052_ALARM_Y_REG); +	ret = da9052_reg_read(rtc->da9052, DA9052_ALARM_Y_REG);  	if (ret < 0) { -		rtc_err(da9052, "Failed to read ALM: %d\n", ret); +		rtc_err(rtc, "Failed to read ALM: %d\n", ret);  		return ret;  	} -	ret &= DA9052_ALARM_Y_ALARM_ON; -	return (ret > 0) ? 1 : 0; + +	return !!(ret&DA9052_ALARM_Y_ALARM_ON);  }  static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm) @@ -142,7 +140,7 @@ static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)  	ret = da9052_group_read(rtc->da9052, DA9052_COUNT_S_REG, 6, v);  	if (ret < 0) { -		rtc_err(rtc->da9052, "Failed to read RTC time : %d\n", ret); +		rtc_err(rtc, "Failed to read RTC time : %d\n", ret);  		return ret;  	} @@ -154,18 +152,14 @@ static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)  	rtc_tm->tm_sec  = v[0] & DA9052_RTC_SEC;  	ret = rtc_valid_tm(rtc_tm); -	if (ret != 0) { -		rtc_err(rtc->da9052, "rtc_valid_tm failed: %d\n", ret); -		return ret; -	} - -	return 0; +	return ret;  }  static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm)  {  	struct da9052_rtc *rtc;  	uint8_t v[6]; +	int ret;  	rtc = dev_get_drvdata(dev); @@ -176,7 +170,10 @@ static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm)  	v[4] = tm->tm_mon + 1;  	v[5] = tm->tm_year - 100; -	return da9052_group_write(rtc->da9052, DA9052_COUNT_S_REG, 6, v); +	ret = da9052_group_write(rtc->da9052, DA9052_COUNT_S_REG, 6, v); +	if (ret < 0) +		rtc_err(rtc, "failed to set RTC time: %d\n", ret); +	return ret;  }  static int da9052_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -185,13 +182,13 @@ static int da9052_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)  	struct rtc_time *tm = &alrm->time;  	struct da9052_rtc *rtc = dev_get_drvdata(dev); -	ret = da9052_read_alarm(rtc->da9052, tm); - -	if (ret) +	ret = da9052_read_alarm(rtc, tm); +	if (ret < 0) { +		rtc_err(rtc, "failed to read RTC alarm: %d\n", ret);  		return ret; +	} -	alrm->enabled = da9052_rtc_get_alarm_status(rtc->da9052); - +	alrm->enabled = da9052_rtc_get_alarm_status(rtc);  	return 0;  } @@ -201,16 +198,15 @@ static int da9052_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)  	struct rtc_time *tm = &alrm->time;  	struct da9052_rtc *rtc = dev_get_drvdata(dev); -	ret = da9052_rtc_enable_alarm(rtc->da9052, 0); +	ret = da9052_rtc_enable_alarm(rtc, 0);  	if (ret < 0)  		return ret; -	ret = da9052_set_alarm(rtc->da9052, tm); -	if (ret) +	ret = da9052_set_alarm(rtc, tm); +	if (ret < 0)  		return ret; -	ret = da9052_rtc_enable_alarm(rtc->da9052, 1); - +	ret = da9052_rtc_enable_alarm(rtc, 1);  	return ret;  } @@ -218,7 +214,7 @@ static int da9052_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)  {  	struct da9052_rtc *rtc = dev_get_drvdata(dev); -	return da9052_rtc_enable_alarm(rtc->da9052, enabled); +	return da9052_rtc_enable_alarm(rtc, enabled);  }  static const struct rtc_class_ops da9052_rtc_ops = { @@ -240,11 +236,23 @@ static int da9052_rtc_probe(struct platform_device *pdev)  	rtc->da9052 = dev_get_drvdata(pdev->dev.parent);  	platform_set_drvdata(pdev, rtc); -	rtc->irq =  DA9052_IRQ_ALARM; -	ret = da9052_request_irq(rtc->da9052, rtc->irq, "ALM", + +	ret = da9052_reg_write(rtc->da9052, DA9052_BBAT_CONT_REG, 0xFE); +	if (ret < 0) { +		rtc_err(rtc, +			"Failed to setup RTC battery charging: %d\n", ret); +		return ret; +	} + +	ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG, +				DA9052_ALARM_Y_TICK_ON, 0); +	if (ret != 0) +		rtc_err(rtc, "Failed to disable TICKS: %d\n", ret); + +	ret = da9052_request_irq(rtc->da9052, DA9052_IRQ_ALARM, "ALM",  				da9052_rtc_irq, rtc);  	if (ret != 0) { -		rtc_err(rtc->da9052, "irq registration failed: %d\n", ret); +		rtc_err(rtc, "irq registration failed: %d\n", ret);  		return ret;  	} @@ -263,7 +271,7 @@ static struct platform_driver da9052_rtc_driver = {  module_platform_driver(da9052_rtc_driver); -MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>"); +MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>");  MODULE_DESCRIPTION("RTC driver for Dialog DA9052 PMIC");  MODULE_LICENSE("GPL");  MODULE_ALIAS("platform:da9052-rtc"); diff --git a/drivers/rtc/rtc-da9055.c b/drivers/rtc/rtc-da9055.c index e00642b6107..a825491331c 100644 --- a/drivers/rtc/rtc-da9055.c +++ b/drivers/rtc/rtc-da9055.c @@ -278,7 +278,7 @@ static int da9055_rtc_probe(struct platform_device *pdev)  		return -ENOMEM;  	rtc->da9055 = dev_get_drvdata(pdev->dev.parent); -	pdata = rtc->da9055->dev->platform_data; +	pdata = dev_get_platdata(rtc->da9055->dev);  	platform_set_drvdata(pdev, rtc);  	ret = da9055_rtc_device_init(rtc->da9055, pdata); @@ -302,7 +302,9 @@ static int da9055_rtc_probe(struct platform_device *pdev)  	}  	alm_irq = platform_get_irq_byname(pdev, "ALM"); -	alm_irq = regmap_irq_get_virq(rtc->da9055->irq_data, alm_irq); +	if (alm_irq < 0) +		return alm_irq; +  	ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL,  					da9055_rtc_alm_irq,  					IRQF_TRIGGER_HIGH | IRQF_ONESHOT, diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c new file mode 100644 index 00000000000..595393098b0 --- /dev/null +++ b/drivers/rtc/rtc-da9063.c @@ -0,0 +1,333 @@ +/* rtc-da9063.c - Real time clock device driver for DA9063 + * Copyright (C) 2013-14  Dialog Semiconductor Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library 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 + * Library General Public License for more details. + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/interrupt.h> +#include <linux/rtc.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/regmap.h> +#include <linux/mfd/da9063/registers.h> +#include <linux/mfd/da9063/core.h> + +#define YEARS_TO_DA9063(year)		((year) - 100) +#define MONTHS_TO_DA9063(month)		((month) + 1) +#define YEARS_FROM_DA9063(year)		((year) + 100) +#define MONTHS_FROM_DA9063(month)	((month) - 1) + +#define RTC_DATA_LEN	(DA9063_REG_COUNT_Y - DA9063_REG_COUNT_S + 1) +#define RTC_SEC		0 +#define RTC_MIN		1 +#define RTC_HOUR	2 +#define RTC_DAY		3 +#define RTC_MONTH	4 +#define RTC_YEAR	5 + +struct da9063_rtc { +	struct rtc_device	*rtc_dev; +	struct da9063		*hw; +	struct rtc_time		alarm_time; +	bool			rtc_sync; +}; + +static void da9063_data_to_tm(u8 *data, struct rtc_time *tm) +{ +	tm->tm_sec  = data[RTC_SEC]  & DA9063_COUNT_SEC_MASK; +	tm->tm_min  = data[RTC_MIN]  & DA9063_COUNT_MIN_MASK; +	tm->tm_hour = data[RTC_HOUR] & DA9063_COUNT_HOUR_MASK; +	tm->tm_mday = data[RTC_DAY]  & DA9063_COUNT_DAY_MASK; +	tm->tm_mon  = MONTHS_FROM_DA9063(data[RTC_MONTH] & +					 DA9063_COUNT_MONTH_MASK); +	tm->tm_year = YEARS_FROM_DA9063(data[RTC_YEAR] & +					DA9063_COUNT_YEAR_MASK); +} + +static void da9063_tm_to_data(struct rtc_time *tm, u8 *data) +{ +	data[RTC_SEC] &= ~DA9063_COUNT_SEC_MASK; +	data[RTC_SEC] |= tm->tm_sec & DA9063_COUNT_SEC_MASK; + +	data[RTC_MIN] &= ~DA9063_COUNT_MIN_MASK; +	data[RTC_MIN] |= tm->tm_min & DA9063_COUNT_MIN_MASK; + +	data[RTC_HOUR] &= ~DA9063_COUNT_HOUR_MASK; +	data[RTC_HOUR] |= tm->tm_hour & DA9063_COUNT_HOUR_MASK; + +	data[RTC_DAY] &= ~DA9063_COUNT_DAY_MASK; +	data[RTC_DAY] |= tm->tm_mday & DA9063_COUNT_DAY_MASK; + +	data[RTC_MONTH] &= ~DA9063_COUNT_MONTH_MASK; +	data[RTC_MONTH] |= MONTHS_TO_DA9063(tm->tm_mon) & +				DA9063_COUNT_MONTH_MASK; + +	data[RTC_YEAR] &= ~DA9063_COUNT_YEAR_MASK; +	data[RTC_YEAR] |= YEARS_TO_DA9063(tm->tm_year) & +				DA9063_COUNT_YEAR_MASK; +} + +static int da9063_rtc_stop_alarm(struct device *dev) +{ +	struct da9063_rtc *rtc = dev_get_drvdata(dev); + +	return regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y, +				  DA9063_ALARM_ON, 0); +} + +static int da9063_rtc_start_alarm(struct device *dev) +{ +	struct da9063_rtc *rtc = dev_get_drvdata(dev); + +	return regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y, +				  DA9063_ALARM_ON, DA9063_ALARM_ON); +} + +static int da9063_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ +	struct da9063_rtc *rtc = dev_get_drvdata(dev); +	unsigned long tm_secs; +	unsigned long al_secs; +	u8 data[RTC_DATA_LEN]; +	int ret; + +	ret = regmap_bulk_read(rtc->hw->regmap, DA9063_REG_COUNT_S, +			       data, RTC_DATA_LEN); +	if (ret < 0) { +		dev_err(dev, "Failed to read RTC time data: %d\n", ret); +		return ret; +	} + +	if (!(data[RTC_SEC] & DA9063_RTC_READ)) { +		dev_dbg(dev, "RTC not yet ready to be read by the host\n"); +		return -EINVAL; +	} + +	da9063_data_to_tm(data, tm); + +	rtc_tm_to_time(tm, &tm_secs); +	rtc_tm_to_time(&rtc->alarm_time, &al_secs); + +	/* handle the rtc synchronisation delay */ +	if (rtc->rtc_sync == true && al_secs - tm_secs == 1) +		memcpy(tm, &rtc->alarm_time, sizeof(struct rtc_time)); +	else +		rtc->rtc_sync = false; + +	return rtc_valid_tm(tm); +} + +static int da9063_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ +	struct da9063_rtc *rtc = dev_get_drvdata(dev); +	u8 data[RTC_DATA_LEN]; +	int ret; + +	da9063_tm_to_data(tm, data); +	ret = regmap_bulk_write(rtc->hw->regmap, DA9063_REG_COUNT_S, +				data, RTC_DATA_LEN); +	if (ret < 0) +		dev_err(dev, "Failed to set RTC time data: %d\n", ret); + +	return ret; +} + +static int da9063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	struct da9063_rtc *rtc = dev_get_drvdata(dev); +	u8 data[RTC_DATA_LEN]; +	int ret; +	unsigned int val; + +	ret = regmap_bulk_read(rtc->hw->regmap, DA9063_REG_ALARM_S, +			       &data[RTC_SEC], RTC_DATA_LEN); +	if (ret < 0) +		return ret; + +	da9063_data_to_tm(data, &alrm->time); + +	alrm->enabled = !!(data[RTC_YEAR] & DA9063_ALARM_ON); + +	ret = regmap_read(rtc->hw->regmap, DA9063_REG_EVENT_A, &val); +	if (ret < 0) +		return ret; + +	if (val & (DA9063_E_ALARM)) +		alrm->pending = 1; +	else +		alrm->pending = 0; + +	return 0; +} + +static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	struct da9063_rtc *rtc = dev_get_drvdata(dev); +	u8 data[RTC_DATA_LEN]; +	int ret; + +	da9063_tm_to_data(&alrm->time, data); + +	ret = da9063_rtc_stop_alarm(dev); +	if (ret < 0) { +		dev_err(dev, "Failed to stop alarm: %d\n", ret); +		return ret; +	} + +	ret = regmap_bulk_write(rtc->hw->regmap, DA9063_REG_ALARM_S, +				data, RTC_DATA_LEN); +	if (ret < 0) { +		dev_err(dev, "Failed to write alarm: %d\n", ret); +		return ret; +	} + +	rtc->alarm_time = alrm->time; + +	if (alrm->enabled) { +		ret = da9063_rtc_start_alarm(dev); +		if (ret < 0) { +			dev_err(dev, "Failed to start alarm: %d\n", ret); +			return ret; +		} +	} + +	return ret; +} + +static int da9063_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ +	if (enabled) +		return da9063_rtc_start_alarm(dev); +	else +		return da9063_rtc_stop_alarm(dev); +} + +static irqreturn_t da9063_alarm_event(int irq, void *data) +{ +	struct da9063_rtc *rtc = data; + +	regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y, +			   DA9063_ALARM_ON, 0); + +	rtc->rtc_sync = true; +	rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF); + +	return IRQ_HANDLED; +} + +static const struct rtc_class_ops da9063_rtc_ops = { +	.read_time = da9063_rtc_read_time, +	.set_time = da9063_rtc_set_time, +	.read_alarm = da9063_rtc_read_alarm, +	.set_alarm = da9063_rtc_set_alarm, +	.alarm_irq_enable = da9063_rtc_alarm_irq_enable, +}; + +static int da9063_rtc_probe(struct platform_device *pdev) +{ +	struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent); +	struct da9063_rtc *rtc; +	int irq_alarm; +	u8 data[RTC_DATA_LEN]; +	int ret; + +	ret = regmap_update_bits(da9063->regmap, DA9063_REG_CONTROL_E, +				 DA9063_RTC_EN, DA9063_RTC_EN); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to enable RTC\n"); +		goto err; +	} + +	ret = regmap_update_bits(da9063->regmap, DA9063_REG_EN_32K, +				 DA9063_CRYSTAL, DA9063_CRYSTAL); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to run 32kHz oscillator\n"); +		goto err; +	} + +	ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_S, +			DA9063_ALARM_STATUS_TICK | DA9063_ALARM_STATUS_ALARM, +			0); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to access RTC alarm register\n"); +		goto err; +	} + +	ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_S, +				 DA9063_ALARM_STATUS_ALARM, +				 DA9063_ALARM_STATUS_ALARM); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to access RTC alarm register\n"); +		goto err; +	} + +	ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_Y, +				 DA9063_TICK_ON, 0); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to disable TICKs\n"); +		goto err; +	} + +	ret = regmap_bulk_read(da9063->regmap, DA9063_REG_ALARM_S, +			       data, RTC_DATA_LEN); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to read initial alarm data: %d\n", +			ret); +		goto err; +	} + +	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); +	if (!rtc) +		return -ENOMEM; + +	platform_set_drvdata(pdev, rtc); + +	irq_alarm = platform_get_irq_byname(pdev, "ALARM"); +	ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL, +					da9063_alarm_event, +					IRQF_TRIGGER_LOW | IRQF_ONESHOT, +					"ALARM", rtc); +	if (ret) { +		dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n", +			irq_alarm, ret); +		goto err; +	} + +	rtc->hw = da9063; +	rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC, +					   &da9063_rtc_ops, THIS_MODULE); +	if (IS_ERR(rtc->rtc_dev)) +		return PTR_ERR(rtc->rtc_dev); + +	da9063_data_to_tm(data, &rtc->alarm_time); +	rtc->rtc_sync = false; +err: +	return ret; +} + +static struct platform_driver da9063_rtc_driver = { +	.probe		= da9063_rtc_probe, +	.driver		= { +		.name	= DA9063_DRVNAME_RTC, +		.owner	= THIS_MODULE, +	}, +}; + +module_platform_driver(da9063_rtc_driver); + +MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>"); +MODULE_DESCRIPTION("Real time clock device driver for Dialog DA9063"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DA9063_DRVNAME_RTC); diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c index 24677ef8c39..c0a3b59f65a 100644 --- a/drivers/rtc/rtc-davinci.c +++ b/drivers/rtc/rtc-davinci.c @@ -119,8 +119,6 @@ static DEFINE_SPINLOCK(davinci_rtc_lock);  struct davinci_rtc {  	struct rtc_device		*rtc;  	void __iomem			*base; -	resource_size_t			pbase; -	size_t				base_size;  	int				irq;  }; @@ -482,14 +480,12 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)  {  	struct device *dev = &pdev->dev;  	struct davinci_rtc *davinci_rtc; -	struct resource *res, *mem; +	struct resource *res;  	int ret = 0;  	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"); +	if (!davinci_rtc)  		return -ENOMEM; -	}  	davinci_rtc->irq = platform_get_irq(pdev, 0);  	if (davinci_rtc->irq < 0) { @@ -498,28 +494,9 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)  	}  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!res) { -		dev_err(dev, "no mem resource\n"); -		return -EINVAL; -	} - -	davinci_rtc->pbase = res->start; -	davinci_rtc->base_size = resource_size(res); - -	mem = devm_request_mem_region(dev, davinci_rtc->pbase, -				davinci_rtc->base_size, pdev->name); -	if (!mem) { -		dev_err(dev, "RTC registers at %08x are not free\n", -			davinci_rtc->pbase); -		return -EBUSY; -	} - -	davinci_rtc->base = devm_ioremap(dev, davinci_rtc->pbase, -					davinci_rtc->base_size); -	if (!davinci_rtc->base) { -		dev_err(dev, "unable to ioremap MEM resource\n"); -		return -ENOMEM; -	} +	davinci_rtc->base = devm_ioremap_resource(dev, res); +	if (IS_ERR(davinci_rtc->base)) +		return PTR_ERR(davinci_rtc->base);  	platform_set_drvdata(pdev, davinci_rtc); diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index dd6170acde9..129add77065 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -606,7 +606,7 @@ static int ds1305_probe(struct spi_device *spi)  	struct ds1305			*ds1305;  	int				status;  	u8				addr, value; -	struct ds1305_platform_data	*pdata = spi->dev.platform_data; +	struct ds1305_platform_data	*pdata = dev_get_platdata(&spi->dev);  	bool				write_ctrl = false;  	/* Sanity check board setup data.  This may be hooked up @@ -756,19 +756,17 @@ static int ds1305_probe(struct spi_device *spi)  		status = devm_request_irq(&spi->dev, spi->irq, ds1305_irq,  				0, dev_name(&ds1305->rtc->dev), ds1305);  		if (status < 0) { -			dev_dbg(&spi->dev, "request_irq %d --> %d\n", +			dev_err(&spi->dev, "request_irq %d --> %d\n",  					spi->irq, status); -			return status; +		} else { +			device_set_wakeup_capable(&spi->dev, 1);  		} - -		device_set_wakeup_capable(&spi->dev, 1);  	}  	/* export NVRAM */  	status = sysfs_create_bin_file(&spi->dev.kobj, &nvram);  	if (status < 0) { -		dev_dbg(&spi->dev, "register nvram --> %d\n", status); -		return status; +		dev_err(&spi->dev, "register nvram --> %d\n", status);  	}  	return 0; @@ -787,7 +785,6 @@ static int ds1305_remove(struct spi_device *spi)  		cancel_work_sync(&ds1305->work);  	} -	spi_set_drvdata(spi, NULL);  	return 0;  } diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index ca18fd1433b..f03d5ba96db 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -154,6 +154,7 @@ static const struct chip_desc chips[last_ds_type] = {  		.alarm		= 1,  	},  	[mcp7941x] = { +		.alarm		= 1,  		/* this is battery backed SRAM */  		.nvram_offset	= 0x20,  		.nvram_size	= 0x40, @@ -606,6 +607,178 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {  /*----------------------------------------------------------------------*/ +/* + * Alarm support for mcp7941x devices. + */ + +#define MCP7941X_REG_CONTROL		0x07 +#	define MCP7941X_BIT_ALM0_EN	0x10 +#	define MCP7941X_BIT_ALM1_EN	0x20 +#define MCP7941X_REG_ALARM0_BASE	0x0a +#define MCP7941X_REG_ALARM0_CTRL	0x0d +#define MCP7941X_REG_ALARM1_BASE	0x11 +#define MCP7941X_REG_ALARM1_CTRL	0x14 +#	define MCP7941X_BIT_ALMX_IF	(1 << 3) +#	define MCP7941X_BIT_ALMX_C0	(1 << 4) +#	define MCP7941X_BIT_ALMX_C1	(1 << 5) +#	define MCP7941X_BIT_ALMX_C2	(1 << 6) +#	define MCP7941X_BIT_ALMX_POL	(1 << 7) +#	define MCP7941X_MSK_ALMX_MATCH	(MCP7941X_BIT_ALMX_C0 | \ +					 MCP7941X_BIT_ALMX_C1 | \ +					 MCP7941X_BIT_ALMX_C2) + +static void mcp7941x_work(struct work_struct *work) +{ +	struct ds1307 *ds1307 = container_of(work, struct ds1307, work); +	struct i2c_client *client = ds1307->client; +	int reg, ret; + +	mutex_lock(&ds1307->rtc->ops_lock); + +	/* Check and clear alarm 0 interrupt flag. */ +	reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_ALARM0_CTRL); +	if (reg < 0) +		goto out; +	if (!(reg & MCP7941X_BIT_ALMX_IF)) +		goto out; +	reg &= ~MCP7941X_BIT_ALMX_IF; +	ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_ALARM0_CTRL, reg); +	if (ret < 0) +		goto out; + +	/* Disable alarm 0. */ +	reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL); +	if (reg < 0) +		goto out; +	reg &= ~MCP7941X_BIT_ALM0_EN; +	ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg); +	if (ret < 0) +		goto out; + +	rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF); + +out: +	if (test_bit(HAS_ALARM, &ds1307->flags)) +		enable_irq(client->irq); +	mutex_unlock(&ds1307->rtc->ops_lock); +} + +static int mcp7941x_read_alarm(struct device *dev, struct rtc_wkalrm *t) +{ +	struct i2c_client *client = to_i2c_client(dev); +	struct ds1307 *ds1307 = i2c_get_clientdata(client); +	u8 *regs = ds1307->regs; +	int ret; + +	if (!test_bit(HAS_ALARM, &ds1307->flags)) +		return -EINVAL; + +	/* Read control and alarm 0 registers. */ +	ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs); +	if (ret < 0) +		return ret; + +	t->enabled = !!(regs[0] & MCP7941X_BIT_ALM0_EN); + +	/* Report alarm 0 time assuming 24-hour and day-of-month modes. */ +	t->time.tm_sec = bcd2bin(ds1307->regs[3] & 0x7f); +	t->time.tm_min = bcd2bin(ds1307->regs[4] & 0x7f); +	t->time.tm_hour = bcd2bin(ds1307->regs[5] & 0x3f); +	t->time.tm_wday = bcd2bin(ds1307->regs[6] & 0x7) - 1; +	t->time.tm_mday = bcd2bin(ds1307->regs[7] & 0x3f); +	t->time.tm_mon = bcd2bin(ds1307->regs[8] & 0x1f) - 1; +	t->time.tm_year = -1; +	t->time.tm_yday = -1; +	t->time.tm_isdst = -1; + +	dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d " +		"enabled=%d polarity=%d irq=%d match=%d\n", __func__, +		t->time.tm_sec, t->time.tm_min, t->time.tm_hour, +		t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled, +		!!(ds1307->regs[6] & MCP7941X_BIT_ALMX_POL), +		!!(ds1307->regs[6] & MCP7941X_BIT_ALMX_IF), +		(ds1307->regs[6] & MCP7941X_MSK_ALMX_MATCH) >> 4); + +	return 0; +} + +static int mcp7941x_set_alarm(struct device *dev, struct rtc_wkalrm *t) +{ +	struct i2c_client *client = to_i2c_client(dev); +	struct ds1307 *ds1307 = i2c_get_clientdata(client); +	unsigned char *regs = ds1307->regs; +	int ret; + +	if (!test_bit(HAS_ALARM, &ds1307->flags)) +		return -EINVAL; + +	dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d " +		"enabled=%d pending=%d\n", __func__, +		t->time.tm_sec, t->time.tm_min, t->time.tm_hour, +		t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, +		t->enabled, t->pending); + +	/* Read control and alarm 0 registers. */ +	ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs); +	if (ret < 0) +		return ret; + +	/* Set alarm 0, using 24-hour and day-of-month modes. */ +	regs[3] = bin2bcd(t->time.tm_sec); +	regs[4] = bin2bcd(t->time.tm_min); +	regs[5] = bin2bcd(t->time.tm_hour); +	regs[6] = bin2bcd(t->time.tm_wday) + 1; +	regs[7] = bin2bcd(t->time.tm_mday); +	regs[8] = bin2bcd(t->time.tm_mon) + 1; + +	/* Clear the alarm 0 interrupt flag. */ +	regs[6] &= ~MCP7941X_BIT_ALMX_IF; +	/* Set alarm match: second, minute, hour, day, date, month. */ +	regs[6] |= MCP7941X_MSK_ALMX_MATCH; + +	if (t->enabled) +		regs[0] |= MCP7941X_BIT_ALM0_EN; +	else +		regs[0] &= ~MCP7941X_BIT_ALM0_EN; + +	ret = ds1307->write_block_data(client, MCP7941X_REG_CONTROL, 10, regs); +	if (ret < 0) +		return ret; + +	return 0; +} + +static int mcp7941x_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ +	struct i2c_client *client = to_i2c_client(dev); +	struct ds1307 *ds1307 = i2c_get_clientdata(client); +	int reg; + +	if (!test_bit(HAS_ALARM, &ds1307->flags)) +		return -EINVAL; + +	reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL); +	if (reg < 0) +		return reg; + +	if (enabled) +		reg |= MCP7941X_BIT_ALM0_EN; +	else +		reg &= ~MCP7941X_BIT_ALM0_EN; + +	return i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg); +} + +static const struct rtc_class_ops mcp7941x_rtc_ops = { +	.read_time	= ds1307_get_time, +	.set_time	= ds1307_set_time, +	.read_alarm	= mcp7941x_read_alarm, +	.set_alarm	= mcp7941x_set_alarm, +	.alarm_irq_enable = mcp7941x_alarm_irq_enable, +}; + +/*----------------------------------------------------------------------*/ +  static ssize_t  ds1307_nvram_read(struct file *filp, struct kobject *kobj,  		struct bin_attribute *attr, @@ -670,14 +843,15 @@ static int ds1307_probe(struct i2c_client *client,  	int			tmp;  	const struct chip_desc	*chip = &chips[id->driver_data];  	struct i2c_adapter	*adapter = to_i2c_adapter(client->dev.parent); -	int			want_irq = false; +	bool			want_irq = false;  	unsigned char		*buf; -	struct ds1307_platform_data *pdata = client->dev.platform_data; +	struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev);  	static const int	bbsqi_bitpos[] = {  		[ds_1337] = 0,  		[ds_1339] = DS1339_BIT_BBSQI,  		[ds_3231] = DS3231_BIT_BBSQW,  	}; +	const struct rtc_class_ops *rtc_ops = &ds13xx_rtc_ops;  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)  	    && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) @@ -816,6 +990,13 @@ static int ds1307_probe(struct i2c_client *client,  	case ds_1388:  		ds1307->offset = 1; /* Seconds starts at 1 */  		break; +	case mcp7941x: +		rtc_ops = &mcp7941x_rtc_ops; +		if (ds1307->client->irq > 0 && chip->alarm) { +			INIT_WORK(&ds1307->work, mcp7941x_work); +			want_irq = true; +		} +		break;  	default:  		break;  	} @@ -927,49 +1108,57 @@ read_rtc:  				bin2bcd(tmp));  	} +	device_set_wakeup_capable(&client->dev, want_irq);  	ds1307->rtc = devm_rtc_device_register(&client->dev, client->name, -				&ds13xx_rtc_ops, THIS_MODULE); +				rtc_ops, THIS_MODULE);  	if (IS_ERR(ds1307->rtc)) { -		err = PTR_ERR(ds1307->rtc); -		dev_err(&client->dev, -			"unable to register the class device\n"); -		goto exit; +		return PTR_ERR(ds1307->rtc);  	}  	if (want_irq) {  		err = request_irq(client->irq, ds1307_irq, IRQF_SHARED,  			  ds1307->rtc->name, client);  		if (err) { -			dev_err(&client->dev, -				"unable to request IRQ!\n"); -			goto exit; -		} +			client->irq = 0; +			dev_err(&client->dev, "unable to request IRQ!\n"); +		} else { -		device_set_wakeup_capable(&client->dev, 1); -		set_bit(HAS_ALARM, &ds1307->flags); -		dev_dbg(&client->dev, "got IRQ %d\n", client->irq); +			set_bit(HAS_ALARM, &ds1307->flags); +			dev_dbg(&client->dev, "got IRQ %d\n", client->irq); +		}  	}  	if (chip->nvram_size) { +  		ds1307->nvram = devm_kzalloc(&client->dev,  					sizeof(struct bin_attribute),  					GFP_KERNEL);  		if (!ds1307->nvram) { -			err = -ENOMEM; -			goto exit; +			dev_err(&client->dev, "cannot allocate memory for nvram sysfs\n"); +		} else { + +			ds1307->nvram->attr.name = "nvram"; +			ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR; + +			sysfs_bin_attr_init(ds1307->nvram); + +			ds1307->nvram->read = ds1307_nvram_read; +			ds1307->nvram->write = ds1307_nvram_write; +			ds1307->nvram->size = chip->nvram_size; +			ds1307->nvram_offset = chip->nvram_offset; + +			err = sysfs_create_bin_file(&client->dev.kobj, +						    ds1307->nvram); +			if (err) { +				dev_err(&client->dev, +					"unable to create sysfs file: %s\n", +					ds1307->nvram->attr.name); +			} else { +				set_bit(HAS_NVRAM, &ds1307->flags); +				dev_info(&client->dev, "%zu bytes nvram\n", +					 ds1307->nvram->size); +			}  		} -		ds1307->nvram->attr.name = "nvram"; -		ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR; -		sysfs_bin_attr_init(ds1307->nvram); -		ds1307->nvram->read = ds1307_nvram_read; -		ds1307->nvram->write = ds1307_nvram_write; -		ds1307->nvram->size = chip->nvram_size; -		ds1307->nvram_offset = chip->nvram_offset; -		err = sysfs_create_bin_file(&client->dev.kobj, ds1307->nvram); -		if (err) -			goto exit; -		set_bit(HAS_NVRAM, &ds1307->flags); -		dev_info(&client->dev, "%zu bytes nvram\n", ds1307->nvram->size);  	}  	return 0; diff --git a/drivers/rtc/rtc-ds1343.c b/drivers/rtc/rtc-ds1343.c new file mode 100644 index 00000000000..c3719189dd9 --- /dev/null +++ b/drivers/rtc/rtc-ds1343.c @@ -0,0 +1,689 @@ +/* rtc-ds1343.c + * + * Driver for Dallas Semiconductor DS1343 Low Current, SPI Compatible + * Real Time Clock + * + * Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com> + * + * 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/init.h> +#include <linux/module.h> +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/spi/spi.h> +#include <linux/regmap.h> +#include <linux/rtc.h> +#include <linux/bcd.h> +#include <linux/pm.h> +#include <linux/slab.h> + +#define DS1343_DRV_VERSION	"01.00" +#define DALLAS_MAXIM_DS1343	0 +#define DALLAS_MAXIM_DS1344	1 + +/* RTC DS1343 Registers */ +#define DS1343_SECONDS_REG	0x00 +#define DS1343_MINUTES_REG	0x01 +#define DS1343_HOURS_REG	0x02 +#define DS1343_DAY_REG		0x03 +#define DS1343_DATE_REG		0x04 +#define DS1343_MONTH_REG	0x05 +#define DS1343_YEAR_REG		0x06 +#define DS1343_ALM0_SEC_REG	0x07 +#define DS1343_ALM0_MIN_REG	0x08 +#define DS1343_ALM0_HOUR_REG	0x09 +#define DS1343_ALM0_DAY_REG	0x0A +#define DS1343_ALM1_SEC_REG	0x0B +#define DS1343_ALM1_MIN_REG	0x0C +#define DS1343_ALM1_HOUR_REG	0x0D +#define DS1343_ALM1_DAY_REG	0x0E +#define DS1343_CONTROL_REG	0x0F +#define DS1343_STATUS_REG	0x10 +#define DS1343_TRICKLE_REG	0x11 + +/* DS1343 Control Registers bits */ +#define DS1343_EOSC		0x80 +#define DS1343_DOSF		0x20 +#define DS1343_EGFIL		0x10 +#define DS1343_SQW		0x08 +#define DS1343_INTCN		0x04 +#define DS1343_A1IE		0x02 +#define DS1343_A0IE		0x01 + +/* DS1343 Status Registers bits */ +#define DS1343_OSF		0x80 +#define DS1343_IRQF1		0x02 +#define DS1343_IRQF0		0x01 + +/* DS1343 Trickle Charger Registers bits */ +#define DS1343_TRICKLE_MAGIC	0xa0 +#define DS1343_TRICKLE_DS1	0x08 +#define DS1343_TRICKLE_1K	0x01 +#define DS1343_TRICKLE_2K	0x02 +#define DS1343_TRICKLE_4K	0x03 + +static const struct spi_device_id ds1343_id[] = { +	{ "ds1343", DALLAS_MAXIM_DS1343 }, +	{ "ds1344", DALLAS_MAXIM_DS1344 }, +	{ } +}; +MODULE_DEVICE_TABLE(spi, ds1343_id); + +struct ds1343_priv { +	struct spi_device *spi; +	struct rtc_device *rtc; +	struct regmap *map; +	struct mutex mutex; +	unsigned int irqen; +	int irq; +	int alarm_sec; +	int alarm_min; +	int alarm_hour; +	int alarm_mday; +}; + +static int ds1343_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ +	switch (cmd) { +#ifdef RTC_SET_CHARGE +	case RTC_SET_CHARGE: +	{ +		int val; + +		if (copy_from_user(&val, (int __user *)arg, sizeof(int))) +			return -EFAULT; + +		return regmap_write(priv->map, DS1343_TRICKLE_REG, val); +	} +	break; +#endif +	} + +	return -ENOIOCTLCMD; +} + +static ssize_t ds1343_show_glitchfilter(struct device *dev, +				struct device_attribute *attr, char *buf) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int glitch_filt_status, data; + +	regmap_read(priv->map, DS1343_CONTROL_REG, &data); + +	glitch_filt_status = !!(data & DS1343_EGFIL); + +	if (glitch_filt_status) +		return sprintf(buf, "enabled\n"); +	else +		return sprintf(buf, "disabled\n"); +} + +static ssize_t ds1343_store_glitchfilter(struct device *dev, +					struct device_attribute *attr, +					const char *buf, size_t count) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int data; + +	regmap_read(priv->map, DS1343_CONTROL_REG, &data); + +	if (strncmp(buf, "enabled", 7) == 0) +		data |= DS1343_EGFIL; + +	else if (strncmp(buf, "disabled", 8) == 0) +		data &= ~(DS1343_EGFIL); + +	else +		return -EINVAL; + +	regmap_write(priv->map, DS1343_CONTROL_REG, data); + +	return count; +} + +static DEVICE_ATTR(glitch_filter, S_IRUGO | S_IWUSR, ds1343_show_glitchfilter, +			ds1343_store_glitchfilter); + +static ssize_t ds1343_show_alarmstatus(struct device *dev, +				struct device_attribute *attr, char *buf) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int alarmstatus, data; + +	regmap_read(priv->map, DS1343_CONTROL_REG, &data); + +	alarmstatus = !!(data & DS1343_A0IE); + +	if (alarmstatus) +		return sprintf(buf, "enabled\n"); +	else +		return sprintf(buf, "disabled\n"); +} + +static DEVICE_ATTR(alarm_status, S_IRUGO, ds1343_show_alarmstatus, NULL); + +static ssize_t ds1343_show_alarmmode(struct device *dev, +				struct device_attribute *attr, char *buf) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int alarm_mode, data; +	char *alarm_str; + +	regmap_read(priv->map, DS1343_ALM0_SEC_REG, &data); +	alarm_mode = (data & 0x80) >> 4; + +	regmap_read(priv->map, DS1343_ALM0_MIN_REG, &data); +	alarm_mode |= (data & 0x80) >> 5; + +	regmap_read(priv->map, DS1343_ALM0_HOUR_REG, &data); +	alarm_mode |= (data & 0x80) >> 6; + +	regmap_read(priv->map, DS1343_ALM0_DAY_REG, &data); +	alarm_mode |= (data & 0x80) >> 7; + +	switch (alarm_mode) { +	case 15: +		alarm_str = "each second"; +		break; + +	case 7: +		alarm_str = "seconds match"; +		break; + +	case 3: +		alarm_str = "minutes and seconds match"; +		break; + +	case 1: +		alarm_str = "hours, minutes and seconds match"; +		break; + +	case 0: +		alarm_str = "day, hours, minutes and seconds match"; +		break; + +	default: +		alarm_str = "invalid"; +		break; +	} + +	return sprintf(buf, "%s\n", alarm_str); +} + +static DEVICE_ATTR(alarm_mode, S_IRUGO, ds1343_show_alarmmode, NULL); + +static ssize_t ds1343_show_tricklecharger(struct device *dev, +				struct device_attribute *attr, char *buf) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int data; +	char *diodes = "disabled", *resistors = " "; + +	regmap_read(priv->map, DS1343_TRICKLE_REG, &data); + +	if ((data & 0xf0) == DS1343_TRICKLE_MAGIC) { +		switch (data & 0x0c) { +		case DS1343_TRICKLE_DS1: +			diodes = "one diode,"; +			break; + +		default: +			diodes = "no diode,"; +			break; +		} + +		switch (data & 0x03) { +		case DS1343_TRICKLE_1K: +			resistors = "1k Ohm"; +			break; + +		case DS1343_TRICKLE_2K: +			resistors = "2k Ohm"; +			break; + +		case DS1343_TRICKLE_4K: +			resistors = "4k Ohm"; +			break; + +		default: +			diodes = "disabled"; +			break; +		} +	} + +	return sprintf(buf, "%s %s\n", diodes, resistors); +} + +static DEVICE_ATTR(trickle_charger, S_IRUGO, ds1343_show_tricklecharger, NULL); + +static int ds1343_sysfs_register(struct device *dev) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int err; + +	err = device_create_file(dev, &dev_attr_glitch_filter); +	if (err) +		return err; + +	err = device_create_file(dev, &dev_attr_trickle_charger); +	if (err) +		goto error1; + +	if (priv->irq <= 0) +		return err; + +	err = device_create_file(dev, &dev_attr_alarm_mode); +	if (err) +		goto error2; + +	err = device_create_file(dev, &dev_attr_alarm_status); +	if (!err) +		return err; + +	device_remove_file(dev, &dev_attr_alarm_mode); + +error2: +	device_remove_file(dev, &dev_attr_trickle_charger); + +error1: +	device_remove_file(dev, &dev_attr_glitch_filter); + +	return err; +} + +static void ds1343_sysfs_unregister(struct device *dev) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); + +	device_remove_file(dev, &dev_attr_glitch_filter); +	device_remove_file(dev, &dev_attr_trickle_charger); + +	if (priv->irq <= 0) +		return; + +	device_remove_file(dev, &dev_attr_alarm_status); +	device_remove_file(dev, &dev_attr_alarm_mode); +} + +static int ds1343_read_time(struct device *dev, struct rtc_time *dt) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	unsigned char buf[7]; +	int res; + +	res = regmap_bulk_read(priv->map, DS1343_SECONDS_REG, buf, 7); +	if (res) +		return res; + +	dt->tm_sec	= bcd2bin(buf[0]); +	dt->tm_min	= bcd2bin(buf[1]); +	dt->tm_hour	= bcd2bin(buf[2] & 0x3F); +	dt->tm_wday	= bcd2bin(buf[3]) - 1; +	dt->tm_mday	= bcd2bin(buf[4]); +	dt->tm_mon	= bcd2bin(buf[5] & 0x1F) - 1; +	dt->tm_year	= bcd2bin(buf[6]) + 100; /* year offset from 1900 */ + +	return rtc_valid_tm(dt); +} + +static int ds1343_set_time(struct device *dev, struct rtc_time *dt) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int res; + +	res = regmap_write(priv->map, DS1343_SECONDS_REG, +				bin2bcd(dt->tm_sec)); +	if (res) +		return res; + +	res = regmap_write(priv->map, DS1343_MINUTES_REG, +				bin2bcd(dt->tm_min)); +	if (res) +		return res; + +	res = regmap_write(priv->map, DS1343_HOURS_REG, +				bin2bcd(dt->tm_hour) & 0x3F); +	if (res) +		return res; + +	res = regmap_write(priv->map, DS1343_DAY_REG, +				bin2bcd(dt->tm_wday + 1)); +	if (res) +		return res; + +	res = regmap_write(priv->map, DS1343_DATE_REG, +				bin2bcd(dt->tm_mday)); +	if (res) +		return res; + +	res = regmap_write(priv->map, DS1343_MONTH_REG, +				bin2bcd(dt->tm_mon + 1)); +	if (res) +		return res; + +	dt->tm_year %= 100; + +	res = regmap_write(priv->map, DS1343_YEAR_REG, +				bin2bcd(dt->tm_year)); +	if (res) +		return res; + +	return 0; +} + +static int ds1343_update_alarm(struct device *dev) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	unsigned int control, stat; +	unsigned char buf[4]; +	int res = 0; + +	res = regmap_read(priv->map, DS1343_CONTROL_REG, &control); +	if (res) +		return res; + +	res = regmap_read(priv->map, DS1343_STATUS_REG, &stat); +	if (res) +		return res; + +	control &= ~(DS1343_A0IE); +	stat &= ~(DS1343_IRQF0); + +	res = regmap_write(priv->map, DS1343_CONTROL_REG, control); +	if (res) +		return res; + +	res = regmap_write(priv->map, DS1343_STATUS_REG, stat); +	if (res) +		return res; + +	buf[0] = priv->alarm_sec < 0 || (priv->irqen & RTC_UF) ? +		0x80 : bin2bcd(priv->alarm_sec) & 0x7F; +	buf[1] = priv->alarm_min < 0 || (priv->irqen & RTC_UF) ? +		0x80 : bin2bcd(priv->alarm_min) & 0x7F; +	buf[2] = priv->alarm_hour < 0 || (priv->irqen & RTC_UF) ? +		0x80 : bin2bcd(priv->alarm_hour) & 0x3F; +	buf[3] = priv->alarm_mday < 0 || (priv->irqen & RTC_UF) ? +		0x80 : bin2bcd(priv->alarm_mday) & 0x7F; + +	res = regmap_bulk_write(priv->map, DS1343_ALM0_SEC_REG, buf, 4); +	if (res) +		return res; + +	if (priv->irqen) { +		control |= DS1343_A0IE; +		res = regmap_write(priv->map, DS1343_CONTROL_REG, control); +	} + +	return res; +} + +static int ds1343_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int res = 0; +	unsigned int stat; + +	if (priv->irq <= 0) +		return -EINVAL; + +	mutex_lock(&priv->mutex); + +	res = regmap_read(priv->map, DS1343_STATUS_REG, &stat); +	if (res) +		goto out; + +	alarm->enabled = !!(priv->irqen & RTC_AF); +	alarm->pending = !!(stat & DS1343_IRQF0); + +	alarm->time.tm_sec = priv->alarm_sec < 0 ? 0 : priv->alarm_sec; +	alarm->time.tm_min = priv->alarm_min < 0 ? 0 : priv->alarm_min; +	alarm->time.tm_hour = priv->alarm_hour < 0 ? 0 : priv->alarm_hour; +	alarm->time.tm_mday = priv->alarm_mday < 0 ? 0 : priv->alarm_mday; + +	alarm->time.tm_mon = -1; +	alarm->time.tm_year = -1; +	alarm->time.tm_wday = -1; +	alarm->time.tm_yday = -1; +	alarm->time.tm_isdst = -1; + +out: +	mutex_unlock(&priv->mutex); +	return res; +} + +static int ds1343_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int res = 0; + +	if (priv->irq <= 0) +		return -EINVAL; + +	mutex_lock(&priv->mutex); + +	priv->alarm_sec = alarm->time.tm_sec; +	priv->alarm_min = alarm->time.tm_min; +	priv->alarm_hour = alarm->time.tm_hour; +	priv->alarm_mday = alarm->time.tm_mday; + +	if (alarm->enabled) +		priv->irqen |= RTC_AF; + +	res = ds1343_update_alarm(dev); + +	mutex_unlock(&priv->mutex); + +	return res; +} + +static int ds1343_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ +	struct ds1343_priv *priv = dev_get_drvdata(dev); +	int res = 0; + +	if (priv->irq <= 0) +		return -EINVAL; + +	mutex_lock(&priv->mutex); + +	if (enabled) +		priv->irqen |= RTC_AF; +	else +		priv->irqen &= ~RTC_AF; + +	res = ds1343_update_alarm(dev); + +	mutex_unlock(&priv->mutex); + +	return res; +} + +static irqreturn_t ds1343_thread(int irq, void *dev_id) +{ +	struct ds1343_priv *priv = dev_id; +	unsigned int stat, control; +	int res = 0; + +	mutex_lock(&priv->mutex); + +	res = regmap_read(priv->map, DS1343_STATUS_REG, &stat); +	if (res) +		goto out; + +	if (stat & DS1343_IRQF0) { +		stat &= ~DS1343_IRQF0; +		regmap_write(priv->map, DS1343_STATUS_REG, stat); + +		res = regmap_read(priv->map, DS1343_CONTROL_REG, &control); +		if (res) +			goto out; + +		control &= ~DS1343_A0IE; +		regmap_write(priv->map, DS1343_CONTROL_REG, control); + +		rtc_update_irq(priv->rtc, 1, RTC_AF | RTC_IRQF); +	} + +out: +	mutex_unlock(&priv->mutex); +	return IRQ_HANDLED; +} + +static const struct rtc_class_ops ds1343_rtc_ops = { +	.ioctl		= ds1343_ioctl, +	.read_time	= ds1343_read_time, +	.set_time	= ds1343_set_time, +	.read_alarm	= ds1343_read_alarm, +	.set_alarm	= ds1343_set_alarm, +	.alarm_irq_enable = ds1343_alarm_irq_enable, +}; + +static int ds1343_probe(struct spi_device *spi) +{ +	struct ds1343_priv *priv; +	struct regmap_config config; +	unsigned int data; +	int res; + +	memset(&config, 0, sizeof(config)); +	config.reg_bits = 8; +	config.val_bits = 8; +	config.write_flag_mask = 0x80; + +	priv = devm_kzalloc(&spi->dev, sizeof(struct ds1343_priv), GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	priv->spi = spi; +	mutex_init(&priv->mutex); + +	/* RTC DS1347 works in spi mode 3 and +	 * its chip select is active high +	 */ +	spi->mode = SPI_MODE_3 | SPI_CS_HIGH; +	spi->bits_per_word = 8; +	res = spi_setup(spi); +	if (res) +		return res; + +	spi_set_drvdata(spi, priv); + +	priv->map = devm_regmap_init_spi(spi, &config); + +	if (IS_ERR(priv->map)) { +		dev_err(&spi->dev, "spi regmap init failed for rtc ds1343\n"); +		return PTR_ERR(priv->map); +	} + +	res = regmap_read(priv->map, DS1343_SECONDS_REG, &data); +	if (res) +		return res; + +	regmap_read(priv->map, DS1343_CONTROL_REG, &data); +	data |= DS1343_INTCN; +	data &= ~(DS1343_EOSC | DS1343_A1IE | DS1343_A0IE); +	regmap_write(priv->map, DS1343_CONTROL_REG, data); + +	regmap_read(priv->map, DS1343_STATUS_REG, &data); +	data &= ~(DS1343_OSF | DS1343_IRQF1 | DS1343_IRQF0); +	regmap_write(priv->map, DS1343_STATUS_REG, data); + +	priv->rtc = devm_rtc_device_register(&spi->dev, "ds1343", +					&ds1343_rtc_ops, THIS_MODULE); +	if (IS_ERR(priv->rtc)) { +		dev_err(&spi->dev, "unable to register rtc ds1343\n"); +		return PTR_ERR(priv->rtc); +	} + +	priv->irq = spi->irq; + +	if (priv->irq >= 0) { +		res = devm_request_threaded_irq(&spi->dev, spi->irq, NULL, +						ds1343_thread, +						IRQF_NO_SUSPEND | IRQF_ONESHOT, +						"ds1343", priv); +		if (res) { +			priv->irq = -1; +			dev_err(&spi->dev, +				"unable to request irq for rtc ds1343\n"); +		} else { +			device_set_wakeup_capable(&spi->dev, 1); +		} +	} + +	res = ds1343_sysfs_register(&spi->dev); +	if (res) +		dev_err(&spi->dev, +			"unable to create sysfs entries for rtc ds1343\n"); + +	return 0; +} + +static int ds1343_remove(struct spi_device *spi) +{ +	struct ds1343_priv *priv = spi_get_drvdata(spi); + +	if (spi->irq) { +		mutex_lock(&priv->mutex); +		priv->irqen &= ~RTC_AF; +		mutex_unlock(&priv->mutex); + +		devm_free_irq(&spi->dev, spi->irq, priv); +	} + +	spi_set_drvdata(spi, NULL); + +	ds1343_sysfs_unregister(&spi->dev); + +	return 0; +} + +#ifdef CONFIG_PM_SLEEP + +static int ds1343_suspend(struct device *dev) +{ +	struct spi_device *spi = to_spi_device(dev); + +	if (spi->irq >= 0 && device_may_wakeup(dev)) +		enable_irq_wake(spi->irq); + +	return 0; +} + +static int ds1343_resume(struct device *dev) +{ +	struct spi_device *spi = to_spi_device(dev); + +	if (spi->irq >= 0 && device_may_wakeup(dev)) +		disable_irq_wake(spi->irq); + +	return 0; +} + +#endif + +static SIMPLE_DEV_PM_OPS(ds1343_pm, ds1343_suspend, ds1343_resume); + +static struct spi_driver ds1343_driver = { +	.driver = { +		.name = "ds1343", +		.owner = THIS_MODULE, +		.pm = &ds1343_pm, +	}, +	.probe = ds1343_probe, +	.remove = ds1343_remove, +	.id_table = ds1343_id, +}; + +module_spi_driver(ds1343_driver); + +MODULE_DESCRIPTION("DS1343 RTC SPI Driver"); +MODULE_AUTHOR("Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com>"); +MODULE_LICENSE("GPL v2"); +MODULE_VERSION(DS1343_DRV_VERSION); diff --git a/drivers/rtc/rtc-ds1347.c b/drivers/rtc/rtc-ds1347.c new file mode 100644 index 00000000000..c82b4c05032 --- /dev/null +++ b/drivers/rtc/rtc-ds1347.c @@ -0,0 +1,166 @@ +/* rtc-ds1347.c + * + * Driver for Dallas Semiconductor DS1347 Low Current, SPI Compatible + * Real Time Clock + * + * Author : Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com> + * + * 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/init.h> +#include <linux/module.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/spi/spi.h> +#include <linux/bcd.h> + +/* Registers in ds1347 rtc */ + +#define DS1347_SECONDS_REG	0x01 +#define DS1347_MINUTES_REG	0x03 +#define DS1347_HOURS_REG	0x05 +#define DS1347_DATE_REG		0x07 +#define DS1347_MONTH_REG	0x09 +#define DS1347_DAY_REG		0x0B +#define DS1347_YEAR_REG		0x0D +#define DS1347_CONTROL_REG	0x0F +#define DS1347_STATUS_REG	0x17 +#define DS1347_CLOCK_BURST	0x3F + +static int ds1347_read_reg(struct device *dev, unsigned char address, +				unsigned char *data) +{ +	struct spi_device *spi = to_spi_device(dev); + +	*data = address | 0x80; + +	return spi_write_then_read(spi, data, 1, data, 1); +} + +static int ds1347_write_reg(struct device *dev, unsigned char address, +				unsigned char data) +{ +	struct spi_device *spi = to_spi_device(dev); +	unsigned char buf[2]; + +	buf[0] = address & 0x7F; +	buf[1] = data; + +	return spi_write_then_read(spi, buf, 2, NULL, 0); +} + +static int ds1347_read_time(struct device *dev, struct rtc_time *dt) +{ +	struct spi_device *spi = to_spi_device(dev); +	int err; +	unsigned char buf[8]; + +	buf[0] = DS1347_CLOCK_BURST | 0x80; + +	err = spi_write_then_read(spi, buf, 1, buf, 8); +	if (err) +		return err; + +	dt->tm_sec = bcd2bin(buf[0]); +	dt->tm_min = bcd2bin(buf[1]); +	dt->tm_hour = bcd2bin(buf[2] & 0x3F); +	dt->tm_mday = bcd2bin(buf[3]); +	dt->tm_mon = bcd2bin(buf[4]) - 1; +	dt->tm_wday = bcd2bin(buf[5]) - 1; +	dt->tm_year = bcd2bin(buf[6]) + 100; + +	return rtc_valid_tm(dt); +} + +static int ds1347_set_time(struct device *dev, struct rtc_time *dt) +{ +	struct spi_device *spi = to_spi_device(dev); +	unsigned char buf[9]; + +	buf[0] = DS1347_CLOCK_BURST & 0x7F; +	buf[1] = bin2bcd(dt->tm_sec); +	buf[2] = bin2bcd(dt->tm_min); +	buf[3] = (bin2bcd(dt->tm_hour) & 0x3F); +	buf[4] = bin2bcd(dt->tm_mday); +	buf[5] = bin2bcd(dt->tm_mon + 1); +	buf[6] = bin2bcd(dt->tm_wday + 1); + +	/* year in linux is from 1900 i.e in range of 100 +	in rtc it is from 00 to 99 */ +	dt->tm_year = dt->tm_year % 100; + +	buf[7] = bin2bcd(dt->tm_year); +	buf[8] = bin2bcd(0x00); + +	/* write the rtc settings */ +	return spi_write_then_read(spi, buf, 9, NULL, 0); +} + +static const struct rtc_class_ops ds1347_rtc_ops = { +	.read_time = ds1347_read_time, +	.set_time = ds1347_set_time, +}; + +static int ds1347_probe(struct spi_device *spi) +{ +	struct rtc_device *rtc; +	unsigned char data; +	int res; + +	/* spi setup with ds1347 in mode 3 and bits per word as 8 */ +	spi->mode = SPI_MODE_3; +	spi->bits_per_word = 8; +	spi_setup(spi); + +	/* RTC Settings */ +	res = ds1347_read_reg(&spi->dev, DS1347_SECONDS_REG, &data); +	if (res) +		return res; + +	/* Disable the write protect of rtc */ +	ds1347_read_reg(&spi->dev, DS1347_CONTROL_REG, &data); +	data = data & ~(1<<7); +	ds1347_write_reg(&spi->dev, DS1347_CONTROL_REG, data); + +	/* Enable the oscillator , disable the oscillator stop flag, +	 and glitch filter to reduce current consumption */ +	ds1347_read_reg(&spi->dev, DS1347_STATUS_REG, &data); +	data = data & 0x1B; +	ds1347_write_reg(&spi->dev, DS1347_STATUS_REG, data); + +	/* display the settings */ +	ds1347_read_reg(&spi->dev, DS1347_CONTROL_REG, &data); +	dev_info(&spi->dev, "DS1347 RTC CTRL Reg = 0x%02x\n", data); + +	ds1347_read_reg(&spi->dev, DS1347_STATUS_REG, &data); +	dev_info(&spi->dev, "DS1347 RTC Status Reg = 0x%02x\n", data); + +	rtc = devm_rtc_device_register(&spi->dev, "ds1347", +				&ds1347_rtc_ops, THIS_MODULE); + +	if (IS_ERR(rtc)) +		return PTR_ERR(rtc); + +	spi_set_drvdata(spi, rtc); + +	return 0; +} + +static struct spi_driver ds1347_driver = { +	.driver = { +		.name = "ds1347", +		.owner = THIS_MODULE, +	}, +	.probe = ds1347_probe, +}; + +module_spi_driver(ds1347_driver); + +MODULE_DESCRIPTION("DS1347 SPI RTC DRIVER"); +MODULE_AUTHOR("Raghavendra C Ganiga <ravi23ganiga@gmail.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c index be9d8c0a7e3..e67bfcb3a1a 100644 --- a/drivers/rtc/rtc-ds1390.c +++ b/drivers/rtc/rtc-ds1390.c @@ -132,10 +132,9 @@ static int ds1390_probe(struct spi_device *spi)  	spi_setup(spi);  	chip = devm_kzalloc(&spi->dev, sizeof(*chip), GFP_KERNEL); -	if (!chip) { -		dev_err(&spi->dev, "unable to allocate device memory\n"); +	if (!chip)  		return -ENOMEM; -	} +  	spi_set_drvdata(spi, chip);  	res = ds1390_get_reg(&spi->dev, DS1390_REG_SECONDS, &tmp); diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index bc7b4fcf603..b13d1399b81 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -371,8 +371,7 @@ ds1511_interrupt(int irq, void *dev_id)  			events |= RTC_UF;  		else  			events |= RTC_AF; -		if (likely(pdata->rtc)) -			rtc_update_irq(pdata->rtc, 1, events); +		rtc_update_irq(pdata->rtc, 1, events);  	}  	spin_unlock(&pdata->lock);  	return events ? IRQ_HANDLED : IRQ_NONE; @@ -473,7 +472,6 @@ static struct bin_attribute ds1511_nvram_attr = {  static int ds1511_rtc_probe(struct platform_device *pdev)  { -	struct rtc_device *rtc;  	struct resource *res;  	struct rtc_plat_data *pdata;  	int ret = 0; @@ -512,6 +510,12 @@ static int ds1511_rtc_probe(struct platform_device *pdev)  	spin_lock_init(&pdata->lock);  	platform_set_drvdata(pdev, pdata); + +	pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, +					      &ds1511_rtc_ops, THIS_MODULE); +	if (IS_ERR(pdata->rtc)) +		return PTR_ERR(pdata->rtc); +  	/*  	 * if the platform has an interrupt in mind for this device,  	 * then by all means, set it @@ -526,15 +530,12 @@ static int ds1511_rtc_probe(struct platform_device *pdev)  		}  	} -	rtc = devm_rtc_device_register(&pdev->dev, pdev->name, &ds1511_rtc_ops, -					THIS_MODULE); -	if (IS_ERR(rtc)) -		return PTR_ERR(rtc); -	pdata->rtc = rtc; -  	ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); +	if (ret) +		dev_err(&pdev->dev, "Unable to create sysfs entry: %s\n", +			ds1511_nvram_attr.attr.name); -	return ret; +	return 0;  }  static int ds1511_rtc_remove(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index fd31571941f..ab56893aac7 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -206,8 +206,7 @@ static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id)  			events |= RTC_UF;  		else  			events |= RTC_AF; -		if (likely(pdata->rtc)) -			rtc_update_irq(pdata->rtc, 1, events); +		rtc_update_irq(pdata->rtc, 1, events);  	}  	spin_unlock(&pdata->lock);  	return events ? IRQ_HANDLED : IRQ_NONE; @@ -278,7 +277,6 @@ static struct bin_attribute ds1553_nvram_attr = {  static int ds1553_rtc_probe(struct platform_device *pdev)  { -	struct rtc_device *rtc;  	struct resource *res;  	unsigned int cen, sec;  	struct rtc_plat_data *pdata; @@ -311,6 +309,12 @@ static int ds1553_rtc_probe(struct platform_device *pdev)  	spin_lock_init(&pdata->lock);  	pdata->last_jiffies = jiffies;  	platform_set_drvdata(pdev, pdata); + +	pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, +				  &ds1553_rtc_ops, THIS_MODULE); +	if (IS_ERR(pdata->rtc)) +		return PTR_ERR(pdata->rtc); +  	if (pdata->irq > 0) {  		writeb(0, ioaddr + RTC_INTERRUPTS);  		if (devm_request_irq(&pdev->dev, pdata->irq, @@ -321,15 +325,12 @@ static int ds1553_rtc_probe(struct platform_device *pdev)  		}  	} -	rtc = devm_rtc_device_register(&pdev->dev, pdev->name, -				  &ds1553_rtc_ops, THIS_MODULE); -	if (IS_ERR(rtc)) -		return PTR_ERR(rtc); -	pdata->rtc = rtc; -  	ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr); +	if (ret) +		dev_err(&pdev->dev, "unable to create sysfs file: %s\n", +			ds1553_nvram_attr.attr.name); -	return ret; +	return 0;  }  static int ds1553_rtc_remove(struct platform_device *pdev) diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index 18e2d847147..a4888dbca2e 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -177,8 +177,9 @@ static int ds1672_probe(struct i2c_client *client,  	/* read control register */  	err = ds1672_get_control(client, &control); -	if (err) -		goto exit_devreg; +	if (err) { +		dev_warn(&client->dev, "Unable to read the control register\n"); +	}  	if (control & DS1672_REG_CONTROL_EOSC)  		dev_warn(&client->dev, "Oscillator not enabled. " @@ -187,12 +188,10 @@ static int ds1672_probe(struct i2c_client *client,  	/* Register sysfs hooks */  	err = device_create_file(&client->dev, &dev_attr_control);  	if (err) -		goto exit_devreg; +		dev_err(&client->dev, "Unable to create sysfs entry: %s\n", +			dev_attr_control.attr.name);  	return 0; - - exit_devreg: -	return err;  }  static struct i2c_device_id ds1672_id[] = { diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 17b73fdc3b6..c6b2191a412 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -13,12 +13,13 @@   */  #include <linux/bcd.h> -#include <linux/init.h>  #include <linux/kernel.h>  #include <linux/gfp.h>  #include <linux/delay.h>  #include <linux/jiffies.h>  #include <linux/rtc.h> +#include <linux/of.h> +#include <linux/of_device.h>  #include <linux/platform_device.h>  #include <linux/io.h>  #include <linux/module.h> @@ -203,8 +204,11 @@ static int ds1742_rtc_probe(struct platform_device *pdev)  		return PTR_ERR(rtc);  	ret = sysfs_create_bin_file(&pdev->dev.kobj, &pdata->nvram_attr); +	if (ret) +		dev_err(&pdev->dev, "Unable to create sysfs entry: %s\n", +			pdata->nvram_attr.attr.name); -	return ret; +	return 0;  }  static int ds1742_rtc_remove(struct platform_device *pdev) @@ -215,12 +219,19 @@ static int ds1742_rtc_remove(struct platform_device *pdev)  	return 0;  } +static const struct of_device_id __maybe_unused ds1742_rtc_of_match[] = { +	{ .compatible = "maxim,ds1742", }, +	{ } +}; +MODULE_DEVICE_TABLE(of, ds1742_rtc_of_match); +  static struct platform_driver ds1742_rtc_driver = {  	.probe		= ds1742_rtc_probe,  	.remove		= ds1742_rtc_remove,  	.driver		= {  		.name	= "rtc-ds1742",  		.owner	= THIS_MODULE, +		.of_match_table = ds1742_rtc_of_match,  	},  }; diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c index 2ca5a23aba8..fc209dc4e24 100644 --- a/drivers/rtc/rtc-ds2404.c +++ b/drivers/rtc/rtc-ds2404.c @@ -224,7 +224,7 @@ static const struct rtc_class_ops ds2404_rtc_ops = {  static int rtc_probe(struct platform_device *pdev)  { -	struct ds2404_platform_data *pdata = pdev->dev.platform_data; +	struct ds2404_platform_data *pdata = dev_get_platdata(&pdev->dev);  	struct ds2404 *chip;  	int retval = -EBUSY; diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c index b83bb5a527f..adaf06c4147 100644 --- a/drivers/rtc/rtc-ds3232.c +++ b/drivers/rtc/rtc-ds3232.c @@ -57,6 +57,7 @@ struct ds3232 {  	 * in the remove function.  	 */  	struct mutex mutex; +	bool suspended;  	int exiting;  }; @@ -345,7 +346,15 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id)  	struct ds3232 *ds3232 = i2c_get_clientdata(client);  	disable_irq_nosync(irq); -	schedule_work(&ds3232->work); + +	/* +	 * If rtc as a wakeup source, can't schedule the work +	 * at system resume flow, because at this time the i2c bus +	 * has not been resumed. +	 */ +	if (!ds3232->suspended) +		schedule_work(&ds3232->work); +  	return IRQ_HANDLED;  } @@ -363,22 +372,26 @@ static void ds3232_work(struct work_struct *work)  	if (stat & DS3232_REG_SR_A1F) {  		control = i2c_smbus_read_byte_data(client, DS3232_REG_CR); -		if (control < 0) -			goto out; -		/* disable alarm1 interrupt */ -		control &= ~(DS3232_REG_CR_A1IE); -		i2c_smbus_write_byte_data(client, DS3232_REG_CR, control); - -		/* clear the alarm pend flag */ -		stat &= ~DS3232_REG_SR_A1F; -		i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); - -		rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); +		if (control < 0) { +			pr_warn("Read DS3232 Control Register error." +				"Disable IRQ%d.\n", client->irq); +		} else { +			/* disable alarm1 interrupt */ +			control &= ~(DS3232_REG_CR_A1IE); +			i2c_smbus_write_byte_data(client, DS3232_REG_CR, +						control); + +			/* clear the alarm pend flag */ +			stat &= ~DS3232_REG_SR_A1F; +			i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat); + +			rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF); + +			if (!ds3232->exiting) +				enable_irq(client->irq); +		}  	} -out: -	if (!ds3232->exiting) -		enable_irq(client->irq);  unlock:  	mutex_unlock(&ds3232->mutex);  } @@ -411,23 +424,17 @@ static int ds3232_probe(struct i2c_client *client,  	if (ret)  		return ret; -	ds3232->rtc = devm_rtc_device_register(&client->dev, client->name, -					  &ds3232_rtc_ops, THIS_MODULE); -	if (IS_ERR(ds3232->rtc)) { -		dev_err(&client->dev, "unable to register the class device\n"); -		return PTR_ERR(ds3232->rtc); -	} - -	if (client->irq >= 0) { -		ret = devm_request_irq(&client->dev, client->irq, ds3232_irq, 0, -				 "ds3232", client); +	if (client->irq > 0) { +		ret = devm_request_irq(&client->dev, client->irq, ds3232_irq, +				       IRQF_SHARED, "ds3232", client);  		if (ret) {  			dev_err(&client->dev, "unable to request IRQ\n"); -			return ret;  		} +		device_init_wakeup(&client->dev, 1);  	} - -	return 0; +	ds3232->rtc = devm_rtc_device_register(&client->dev, client->name, +					  &ds3232_rtc_ops, THIS_MODULE); +	return PTR_ERR_OR_ZERO(ds3232->rtc);  }  static int ds3232_remove(struct i2c_client *client) @@ -446,6 +453,42 @@ static int ds3232_remove(struct i2c_client *client)  	return 0;  } +#ifdef CONFIG_PM_SLEEP +static int ds3232_suspend(struct device *dev) +{ +	struct ds3232 *ds3232 = dev_get_drvdata(dev); +	struct i2c_client *client = to_i2c_client(dev); + +	if (device_can_wakeup(dev)) { +		ds3232->suspended = true; +		irq_set_irq_wake(client->irq, 1); +	} + +	return 0; +} + +static int ds3232_resume(struct device *dev) +{ +	struct ds3232 *ds3232 = dev_get_drvdata(dev); +	struct i2c_client *client = to_i2c_client(dev); + +	if (ds3232->suspended) { +		ds3232->suspended = false; + +		/* Clear the hardware alarm pend flag */ +		schedule_work(&ds3232->work); + +		irq_set_irq_wake(client->irq, 0); +	} + +	return 0; +} +#endif + +static const struct dev_pm_ops ds3232_pm_ops = { +	SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume) +}; +  static const struct i2c_device_id ds3232_id[] = {  	{ "ds3232", 0 },  	{ } @@ -456,6 +499,7 @@ static struct i2c_driver ds3232_driver = {  	.driver = {  		.name = "rtc-ds3232",  		.owner = THIS_MODULE, +		.pm	= &ds3232_pm_ops,  	},  	.probe = ds3232_probe,  	.remove = ds3232_remove, diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c index 797aa0252ba..c4c38431012 100644 --- a/drivers/rtc/rtc-efi.c +++ b/drivers/rtc/rtc-efi.c @@ -35,7 +35,7 @@ static inline int  compute_yday(efi_time_t *eft)  {  	/* efi_time_t.month is in the [1-12] so, we need -1 */ -	return rtc_year_days(eft->day - 1, eft->month - 1, eft->year); +	return rtc_year_days(eft->day, eft->month - 1, eft->year);  }  /*   * returns day of the week [0-6] 0=Sunday diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 580e7b56bde..5e4f5dc40ba 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -42,7 +42,7 @@ struct ep93xx_rtc {  static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,  				unsigned short *delete)  { -	struct ep93xx_rtc *ep93xx_rtc = dev->platform_data; +	struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);  	unsigned long comp;  	comp = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_SWCOMP); @@ -60,7 +60,7 @@ static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,  static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)  { -	struct ep93xx_rtc *ep93xx_rtc = dev->platform_data; +	struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);  	unsigned long time;  	 time = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA); @@ -71,7 +71,7 @@ static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)  static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs)  { -	struct ep93xx_rtc *ep93xx_rtc = dev->platform_data; +	struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);  	__raw_writel(secs + 1, ep93xx_rtc->mmio_base + EP93XX_RTC_LOAD);  	return 0; diff --git a/drivers/rtc/rtc-hid-sensor-time.c b/drivers/rtc/rtc-hid-sensor-time.c index 4e2a81854f5..965a9da7086 100644 --- a/drivers/rtc/rtc-hid-sensor-time.c +++ b/drivers/rtc/rtc-hid-sensor-time.c @@ -209,7 +209,7 @@ static int hid_rtc_read_time(struct device *dev, struct rtc_time *tm)  		platform_get_drvdata(to_platform_device(dev));  	int ret; -	INIT_COMPLETION(time_state->comp_last_time); +	reinit_completion(&time_state->comp_last_time);  	/* get a report with all values through requesting one value */  	sensor_hub_input_attr_get_raw_value(time_state->common_attributes.hsdev,  			HID_USAGE_SENSOR_TIME, hid_time_addresses[0], @@ -236,7 +236,7 @@ static const struct rtc_class_ops hid_time_rtc_ops = {  static int hid_time_probe(struct platform_device *pdev)  {  	int ret = 0; -	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; +	struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev);  	struct hid_time_state *time_state = devm_kzalloc(&pdev->dev,  		sizeof(struct hid_time_state), GFP_KERNEL); @@ -275,24 +275,44 @@ static int hid_time_probe(struct platform_device *pdev)  		return ret;  	} +	ret = sensor_hub_device_open(hsdev); +	if (ret) { +		dev_err(&pdev->dev, "failed to open sensor hub device!\n"); +		goto err_open; +	} + +	/* +	 * Enable HID input processing early in order to be able to read the +	 * clock already in devm_rtc_device_register(). +	 */ +	hid_device_io_start(hsdev->hdev); +  	time_state->rtc = devm_rtc_device_register(&pdev->dev,  					"hid-sensor-time", &hid_time_rtc_ops,  					THIS_MODULE);  	if (IS_ERR_OR_NULL(time_state->rtc)) { +		hid_device_io_stop(hsdev->hdev);  		ret = time_state->rtc ? PTR_ERR(time_state->rtc) : -ENODEV;  		time_state->rtc = NULL; -		sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME);  		dev_err(&pdev->dev, "rtc device register failed!\n"); +		goto err_rtc;  	}  	return ret; + +err_rtc: +	sensor_hub_device_close(hsdev); +err_open: +	sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME); +	return ret;  }  static int hid_time_remove(struct platform_device *pdev)  { -	struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; +	struct hid_sensor_hub_device *hsdev = dev_get_platdata(&pdev->dev); +	sensor_hub_device_close(hsdev);  	sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_TIME);  	return 0; diff --git a/drivers/rtc/rtc-hym8563.c b/drivers/rtc/rtc-hym8563.c new file mode 100644 index 00000000000..b936bb4096b --- /dev/null +++ b/drivers/rtc/rtc-hym8563.c @@ -0,0 +1,612 @@ +/* + * Haoyu HYM8563 RTC driver + * + * Copyright (C) 2013 MundoReader S.L. + * Author: Heiko Stuebner <heiko@sntech.de> + * + * based on rtc-HYM8563 + * Copyright (C) 2010 ROCKCHIP, Inc. + * + * This software is licensed under the terms of the GNU General Public + * License version 2, as published by the Free Software Foundation, and + * may be copied, distributed, and modified under those terms. + * + * 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. + */ + +#include <linux/module.h> +#include <linux/clk-provider.h> +#include <linux/i2c.h> +#include <linux/bcd.h> +#include <linux/rtc.h> + +#define HYM8563_CTL1		0x00 +#define HYM8563_CTL1_TEST	BIT(7) +#define HYM8563_CTL1_STOP	BIT(5) +#define HYM8563_CTL1_TESTC	BIT(3) + +#define HYM8563_CTL2		0x01 +#define HYM8563_CTL2_TI_TP	BIT(4) +#define HYM8563_CTL2_AF		BIT(3) +#define HYM8563_CTL2_TF		BIT(2) +#define HYM8563_CTL2_AIE	BIT(1) +#define HYM8563_CTL2_TIE	BIT(0) + +#define HYM8563_SEC		0x02 +#define HYM8563_SEC_VL		BIT(7) +#define HYM8563_SEC_MASK	0x7f + +#define HYM8563_MIN		0x03 +#define HYM8563_MIN_MASK	0x7f + +#define HYM8563_HOUR		0x04 +#define HYM8563_HOUR_MASK	0x3f + +#define HYM8563_DAY		0x05 +#define HYM8563_DAY_MASK	0x3f + +#define HYM8563_WEEKDAY		0x06 +#define HYM8563_WEEKDAY_MASK	0x07 + +#define HYM8563_MONTH		0x07 +#define HYM8563_MONTH_CENTURY	BIT(7) +#define HYM8563_MONTH_MASK	0x1f + +#define HYM8563_YEAR		0x08 + +#define HYM8563_ALM_MIN		0x09 +#define HYM8563_ALM_HOUR	0x0a +#define HYM8563_ALM_DAY		0x0b +#define HYM8563_ALM_WEEK	0x0c + +/* Each alarm check can be disabled by setting this bit in the register */ +#define HYM8563_ALM_BIT_DISABLE	BIT(7) + +#define HYM8563_CLKOUT		0x0d +#define HYM8563_CLKOUT_DISABLE	BIT(7) +#define HYM8563_CLKOUT_32768	0 +#define HYM8563_CLKOUT_1024	1 +#define HYM8563_CLKOUT_32	2 +#define HYM8563_CLKOUT_1	3 +#define HYM8563_CLKOUT_MASK	3 + +#define HYM8563_TMR_CTL		0x0e +#define HYM8563_TMR_CTL_ENABLE	BIT(7) +#define HYM8563_TMR_CTL_4096	0 +#define HYM8563_TMR_CTL_64	1 +#define HYM8563_TMR_CTL_1	2 +#define HYM8563_TMR_CTL_1_60	3 +#define HYM8563_TMR_CTL_MASK	3 + +#define HYM8563_TMR_CNT		0x0f + +struct hym8563 { +	struct i2c_client	*client; +	struct rtc_device	*rtc; +	bool			valid; +#ifdef CONFIG_COMMON_CLK +	struct clk_hw		clkout_hw; +#endif +}; + +/* + * RTC handling + */ + +static int hym8563_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ +	struct i2c_client *client = to_i2c_client(dev); +	struct hym8563 *hym8563 = i2c_get_clientdata(client); +	u8 buf[7]; +	int ret; + +	if (!hym8563->valid) { +		dev_warn(&client->dev, "no valid clock/calendar values available\n"); +		return -EPERM; +	} + +	ret = i2c_smbus_read_i2c_block_data(client, HYM8563_SEC, 7, buf); + +	tm->tm_sec = bcd2bin(buf[0] & HYM8563_SEC_MASK); +	tm->tm_min = bcd2bin(buf[1] & HYM8563_MIN_MASK); +	tm->tm_hour = bcd2bin(buf[2] & HYM8563_HOUR_MASK); +	tm->tm_mday = bcd2bin(buf[3] & HYM8563_DAY_MASK); +	tm->tm_wday = bcd2bin(buf[4] & HYM8563_WEEKDAY_MASK); /* 0 = Sun */ +	tm->tm_mon = bcd2bin(buf[5] & HYM8563_MONTH_MASK) - 1; /* 0 = Jan */ +	tm->tm_year = bcd2bin(buf[6]) + 100; + +	return 0; +} + +static int hym8563_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ +	struct i2c_client *client = to_i2c_client(dev); +	struct hym8563 *hym8563 = i2c_get_clientdata(client); +	u8 buf[7]; +	int ret; + +	/* Years >= 2100 are to far in the future, 19XX is to early */ +	if (tm->tm_year < 100 || tm->tm_year >= 200) +		return -EINVAL; + +	buf[0] = bin2bcd(tm->tm_sec); +	buf[1] = bin2bcd(tm->tm_min); +	buf[2] = bin2bcd(tm->tm_hour); +	buf[3] = bin2bcd(tm->tm_mday); +	buf[4] = bin2bcd(tm->tm_wday); +	buf[5] = bin2bcd(tm->tm_mon + 1); + +	/* +	 * While the HYM8563 has a century flag in the month register, +	 * it does not seem to carry it over a subsequent write/read. +	 * So we'll limit ourself to 100 years, starting at 2000 for now. +	 */ +	buf[6] = tm->tm_year - 100; + +	/* +	 * CTL1 only contains TEST-mode bits apart from stop, +	 * so no need to read the value first +	 */ +	ret = i2c_smbus_write_byte_data(client, HYM8563_CTL1, +						HYM8563_CTL1_STOP); +	if (ret < 0) +		return ret; + +	ret = i2c_smbus_write_i2c_block_data(client, HYM8563_SEC, 7, buf); +	if (ret < 0) +		return ret; + +	ret = i2c_smbus_write_byte_data(client, HYM8563_CTL1, 0); +	if (ret < 0) +		return ret; + +	hym8563->valid = true; + +	return 0; +} + +static int hym8563_rtc_alarm_irq_enable(struct device *dev, +					unsigned int enabled) +{ +	struct i2c_client *client = to_i2c_client(dev); +	int data; + +	data = i2c_smbus_read_byte_data(client, HYM8563_CTL2); +	if (data < 0) +		return data; + +	if (enabled) +		data |= HYM8563_CTL2_AIE; +	else +		data &= ~HYM8563_CTL2_AIE; + +	return i2c_smbus_write_byte_data(client, HYM8563_CTL2, data); +}; + +static int hym8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ +	struct i2c_client *client = to_i2c_client(dev); +	struct rtc_time *alm_tm = &alm->time; +	u8 buf[4]; +	int ret; + +	ret = i2c_smbus_read_i2c_block_data(client, HYM8563_ALM_MIN, 4, buf); +	if (ret < 0) +		return ret; + +	/* The alarm only has a minute accuracy */ +	alm_tm->tm_sec = -1; + +	alm_tm->tm_min = (buf[0] & HYM8563_ALM_BIT_DISABLE) ? +					-1 : +					bcd2bin(buf[0] & HYM8563_MIN_MASK); +	alm_tm->tm_hour = (buf[1] & HYM8563_ALM_BIT_DISABLE) ? +					-1 : +					bcd2bin(buf[1] & HYM8563_HOUR_MASK); +	alm_tm->tm_mday = (buf[2] & HYM8563_ALM_BIT_DISABLE) ? +					-1 : +					bcd2bin(buf[2] & HYM8563_DAY_MASK); +	alm_tm->tm_wday = (buf[3] & HYM8563_ALM_BIT_DISABLE) ? +					-1 : +					bcd2bin(buf[3] & HYM8563_WEEKDAY_MASK); + +	alm_tm->tm_mon = -1; +	alm_tm->tm_year = -1; + +	ret = i2c_smbus_read_byte_data(client, HYM8563_CTL2); +	if (ret < 0) +		return ret; + +	if (ret & HYM8563_CTL2_AIE) +		alm->enabled = 1; + +	return 0; +} + +static int hym8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ +	struct i2c_client *client = to_i2c_client(dev); +	struct rtc_time *alm_tm = &alm->time; +	u8 buf[4]; +	int ret; + +	/* +	 * The alarm has no seconds so deal with it +	 */ +	if (alm_tm->tm_sec) { +		alm_tm->tm_sec = 0; +		alm_tm->tm_min++; +		if (alm_tm->tm_min >= 60) { +			alm_tm->tm_min = 0; +			alm_tm->tm_hour++; +			if (alm_tm->tm_hour >= 24) { +				alm_tm->tm_hour = 0; +				alm_tm->tm_mday++; +				if (alm_tm->tm_mday > 31) +					alm_tm->tm_mday = 0; +			} +		} +	} + +	ret = i2c_smbus_read_byte_data(client, HYM8563_CTL2); +	if (ret < 0) +		return ret; + +	ret &= ~HYM8563_CTL2_AIE; + +	ret = i2c_smbus_write_byte_data(client, HYM8563_CTL2, ret); +	if (ret < 0) +		return ret; + +	buf[0] = (alm_tm->tm_min < 60 && alm_tm->tm_min >= 0) ? +			bin2bcd(alm_tm->tm_min) : HYM8563_ALM_BIT_DISABLE; + +	buf[1] = (alm_tm->tm_hour < 24 && alm_tm->tm_hour >= 0) ? +			bin2bcd(alm_tm->tm_hour) : HYM8563_ALM_BIT_DISABLE; + +	buf[2] = (alm_tm->tm_mday <= 31 && alm_tm->tm_mday >= 1) ? +			bin2bcd(alm_tm->tm_mday) : HYM8563_ALM_BIT_DISABLE; + +	buf[3] = (alm_tm->tm_wday < 7 && alm_tm->tm_wday >= 0) ? +			bin2bcd(alm_tm->tm_wday) : HYM8563_ALM_BIT_DISABLE; + +	ret = i2c_smbus_write_i2c_block_data(client, HYM8563_ALM_MIN, 4, buf); +	if (ret < 0) +		return ret; + +	return hym8563_rtc_alarm_irq_enable(dev, alm->enabled); +} + +static const struct rtc_class_ops hym8563_rtc_ops = { +	.read_time		= hym8563_rtc_read_time, +	.set_time		= hym8563_rtc_set_time, +	.alarm_irq_enable	= hym8563_rtc_alarm_irq_enable, +	.read_alarm		= hym8563_rtc_read_alarm, +	.set_alarm		= hym8563_rtc_set_alarm, +}; + +/* + * Handling of the clkout + */ + +#ifdef CONFIG_COMMON_CLK +#define clkout_hw_to_hym8563(_hw) container_of(_hw, struct hym8563, clkout_hw) + +static int clkout_rates[] = { +	32768, +	1024, +	32, +	1, +}; + +static unsigned long hym8563_clkout_recalc_rate(struct clk_hw *hw, +						unsigned long parent_rate) +{ +	struct hym8563 *hym8563 = clkout_hw_to_hym8563(hw); +	struct i2c_client *client = hym8563->client; +	int ret = i2c_smbus_read_byte_data(client, HYM8563_CLKOUT); + +	if (ret < 0 || ret & HYM8563_CLKOUT_DISABLE) +		return 0; + +	ret &= HYM8563_CLKOUT_MASK; +	return clkout_rates[ret]; +} + +static long hym8563_clkout_round_rate(struct clk_hw *hw, unsigned long rate, +				      unsigned long *prate) +{ +	int i; + +	for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) +		if (clkout_rates[i] <= rate) +			return clkout_rates[i]; + +	return 0; +} + +static int hym8563_clkout_set_rate(struct clk_hw *hw, unsigned long rate, +				   unsigned long parent_rate) +{ +	struct hym8563 *hym8563 = clkout_hw_to_hym8563(hw); +	struct i2c_client *client = hym8563->client; +	int ret = i2c_smbus_read_byte_data(client, HYM8563_CLKOUT); +	int i; + +	if (ret < 0) +		return ret; + +	for (i = 0; i < ARRAY_SIZE(clkout_rates); i++) +		if (clkout_rates[i] == rate) { +			ret &= ~HYM8563_CLKOUT_MASK; +			ret |= i; +			return i2c_smbus_write_byte_data(client, +							 HYM8563_CLKOUT, ret); +		} + +	return -EINVAL; +} + +static int hym8563_clkout_control(struct clk_hw *hw, bool enable) +{ +	struct hym8563 *hym8563 = clkout_hw_to_hym8563(hw); +	struct i2c_client *client = hym8563->client; +	int ret = i2c_smbus_read_byte_data(client, HYM8563_CLKOUT); + +	if (ret < 0) +		return ret; + +	if (enable) +		ret &= ~HYM8563_CLKOUT_DISABLE; +	else +		ret |= HYM8563_CLKOUT_DISABLE; + +	return i2c_smbus_write_byte_data(client, HYM8563_CLKOUT, ret); +} + +static int hym8563_clkout_prepare(struct clk_hw *hw) +{ +	return hym8563_clkout_control(hw, 1); +} + +static void hym8563_clkout_unprepare(struct clk_hw *hw) +{ +	hym8563_clkout_control(hw, 0); +} + +static int hym8563_clkout_is_prepared(struct clk_hw *hw) +{ +	struct hym8563 *hym8563 = clkout_hw_to_hym8563(hw); +	struct i2c_client *client = hym8563->client; +	int ret = i2c_smbus_read_byte_data(client, HYM8563_CLKOUT); + +	if (ret < 0) +		return ret; + +	return !(ret & HYM8563_CLKOUT_DISABLE); +} + +static const struct clk_ops hym8563_clkout_ops = { +	.prepare = hym8563_clkout_prepare, +	.unprepare = hym8563_clkout_unprepare, +	.is_prepared = hym8563_clkout_is_prepared, +	.recalc_rate = hym8563_clkout_recalc_rate, +	.round_rate = hym8563_clkout_round_rate, +	.set_rate = hym8563_clkout_set_rate, +}; + +static struct clk *hym8563_clkout_register_clk(struct hym8563 *hym8563) +{ +	struct i2c_client *client = hym8563->client; +	struct device_node *node = client->dev.of_node; +	struct clk *clk; +	struct clk_init_data init; +	int ret; + +	ret = i2c_smbus_write_byte_data(client, HYM8563_CLKOUT, +						HYM8563_CLKOUT_DISABLE); +	if (ret < 0) +		return ERR_PTR(ret); + +	init.name = "hym8563-clkout"; +	init.ops = &hym8563_clkout_ops; +	init.flags = CLK_IS_ROOT; +	init.parent_names = NULL; +	init.num_parents = 0; +	hym8563->clkout_hw.init = &init; + +	/* optional override of the clockname */ +	of_property_read_string(node, "clock-output-names", &init.name); + +	/* register the clock */ +	clk = clk_register(&client->dev, &hym8563->clkout_hw); + +	if (!IS_ERR(clk)) +		of_clk_add_provider(node, of_clk_src_simple_get, clk); + +	return clk; +} +#endif + +/* + * The alarm interrupt is implemented as a level-low interrupt in the + * hym8563, while the timer interrupt uses a falling edge. + * We don't use the timer at all, so the interrupt is requested to + * use the level-low trigger. + */ +static irqreturn_t hym8563_irq(int irq, void *dev_id) +{ +	struct hym8563 *hym8563 = (struct hym8563 *)dev_id; +	struct i2c_client *client = hym8563->client; +	struct mutex *lock = &hym8563->rtc->ops_lock; +	int data, ret; + +	mutex_lock(lock); + +	/* Clear the alarm flag */ + +	data = i2c_smbus_read_byte_data(client, HYM8563_CTL2); +	if (data < 0) { +		dev_err(&client->dev, "%s: error reading i2c data %d\n", +			__func__, data); +		goto out; +	} + +	data &= ~HYM8563_CTL2_AF; + +	ret = i2c_smbus_write_byte_data(client, HYM8563_CTL2, data); +	if (ret < 0) { +		dev_err(&client->dev, "%s: error writing i2c data %d\n", +			__func__, ret); +	} + +out: +	mutex_unlock(lock); +	return IRQ_HANDLED; +} + +static int hym8563_init_device(struct i2c_client *client) +{ +	int ret; + +	/* Clear stop flag if present */ +	ret = i2c_smbus_write_byte_data(client, HYM8563_CTL1, 0); +	if (ret < 0) +		return ret; + +	ret = i2c_smbus_read_byte_data(client, HYM8563_CTL2); +	if (ret < 0) +		return ret; + +	/* Disable alarm and timer interrupts */ +	ret &= ~HYM8563_CTL2_AIE; +	ret &= ~HYM8563_CTL2_TIE; + +	/* Clear any pending alarm and timer flags */ +	if (ret & HYM8563_CTL2_AF) +		ret &= ~HYM8563_CTL2_AF; + +	if (ret & HYM8563_CTL2_TF) +		ret &= ~HYM8563_CTL2_TF; + +	ret &= ~HYM8563_CTL2_TI_TP; + +	return i2c_smbus_write_byte_data(client, HYM8563_CTL2, ret); +} + +#ifdef CONFIG_PM_SLEEP +static int hym8563_suspend(struct device *dev) +{ +	struct i2c_client *client = to_i2c_client(dev); +	int ret; + +	if (device_may_wakeup(dev)) { +		ret = enable_irq_wake(client->irq); +		if (ret) { +			dev_err(dev, "enable_irq_wake failed, %d\n", ret); +			return ret; +		} +	} + +	return 0; +} + +static int hym8563_resume(struct device *dev) +{ +	struct i2c_client *client = to_i2c_client(dev); + +	if (device_may_wakeup(dev)) +		disable_irq_wake(client->irq); + +	return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(hym8563_pm_ops, hym8563_suspend, hym8563_resume); + +static int hym8563_probe(struct i2c_client *client, +			 const struct i2c_device_id *id) +{ +	struct hym8563 *hym8563; +	int ret; + +	hym8563 = devm_kzalloc(&client->dev, sizeof(*hym8563), GFP_KERNEL); +	if (!hym8563) +		return -ENOMEM; + +	hym8563->client = client; +	i2c_set_clientdata(client, hym8563); + +	device_set_wakeup_capable(&client->dev, true); + +	ret = hym8563_init_device(client); +	if (ret) { +		dev_err(&client->dev, "could not init device, %d\n", ret); +		return ret; +	} + +	ret = devm_request_threaded_irq(&client->dev, client->irq, +					NULL, hym8563_irq, +					IRQF_TRIGGER_LOW | IRQF_ONESHOT, +					client->name, hym8563); +	if (ret < 0) { +		dev_err(&client->dev, "irq %d request failed, %d\n", +			client->irq, ret); +		return ret; +	} + +	/* check state of calendar information */ +	ret = i2c_smbus_read_byte_data(client, HYM8563_SEC); +	if (ret < 0) +		return ret; + +	hym8563->valid = !(ret & HYM8563_SEC_VL); +	dev_dbg(&client->dev, "rtc information is %s\n", +		hym8563->valid ? "valid" : "invalid"); + +	hym8563->rtc = devm_rtc_device_register(&client->dev, client->name, +						&hym8563_rtc_ops, THIS_MODULE); +	if (IS_ERR(hym8563->rtc)) +		return PTR_ERR(hym8563->rtc); + +	/* the hym8563 alarm only supports a minute accuracy */ +	hym8563->rtc->uie_unsupported = 1; + +#ifdef CONFIG_COMMON_CLK +	hym8563_clkout_register_clk(hym8563); +#endif + +	return 0; +} + +static const struct i2c_device_id hym8563_id[] = { +	{ "hym8563", 0 }, +	{}, +}; +MODULE_DEVICE_TABLE(i2c, hym8563_id); + +static const struct of_device_id hym8563_dt_idtable[] = { +	{ .compatible = "haoyu,hym8563" }, +	{}, +}; +MODULE_DEVICE_TABLE(of, hym8563_dt_idtable); + +static struct i2c_driver hym8563_driver = { +	.driver		= { +		.name	= "rtc-hym8563", +		.owner	= THIS_MODULE, +		.pm	= &hym8563_pm_ops, +		.of_match_table	= hym8563_dt_idtable, +	}, +	.probe		= hym8563_probe, +	.id_table	= hym8563_id, +}; + +module_i2c_driver(hym8563_driver); + +MODULE_AUTHOR("Heiko Stuebner <heiko@sntech.de>"); +MODULE_DESCRIPTION("HYM8563 RTC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c index abd7f9091f3..cd741c77e08 100644 --- a/drivers/rtc/rtc-imxdi.c +++ b/drivers/rtc/rtc-imxdi.c @@ -401,7 +401,9 @@ static int __init dryice_rtc_probe(struct platform_device *pdev)  	imxdi->clk = devm_clk_get(&pdev->dev, NULL);  	if (IS_ERR(imxdi->clk))  		return PTR_ERR(imxdi->clk); -	clk_prepare_enable(imxdi->clk); +	rc = clk_prepare_enable(imxdi->clk); +	if (rc) +		return rc;  	/*  	 * Initialize dryice hardware diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c new file mode 100644 index 00000000000..455b601d731 --- /dev/null +++ b/drivers/rtc/rtc-isl12057.c @@ -0,0 +1,306 @@ +/* + * rtc-isl12057 - Driver for Intersil ISL12057 I2C Real Time Clock + * + * Copyright (C) 2013, Arnaud EBALARD <arno@natisbad.org> + * + * This work is largely based on Intersil ISL1208 driver developed by + * Hebert Valerio Riedel <hvr@gnu.org>. + * + * Detailed datasheet on which this development is based is available here: + * + *  http://natisbad.org/NAS2/refs/ISL12057.pdf + * + * 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. + * + * 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. + */ + +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/rtc.h> +#include <linux/i2c.h> +#include <linux/bcd.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/regmap.h> + +#define DRV_NAME "rtc-isl12057" + +/* RTC section */ +#define ISL12057_REG_RTC_SC	0x00	/* Seconds */ +#define ISL12057_REG_RTC_MN	0x01	/* Minutes */ +#define ISL12057_REG_RTC_HR	0x02	/* Hours */ +#define ISL12057_REG_RTC_HR_PM	BIT(5)	/* AM/PM bit in 12h format */ +#define ISL12057_REG_RTC_HR_MIL BIT(6)	/* 24h/12h format */ +#define ISL12057_REG_RTC_DW	0x03	/* Day of the Week */ +#define ISL12057_REG_RTC_DT	0x04	/* Date */ +#define ISL12057_REG_RTC_MO	0x05	/* Month */ +#define ISL12057_REG_RTC_YR	0x06	/* Year */ +#define ISL12057_RTC_SEC_LEN	7 + +/* Alarm 1 section */ +#define ISL12057_REG_A1_SC	0x07	/* Alarm 1 Seconds */ +#define ISL12057_REG_A1_MN	0x08	/* Alarm 1 Minutes */ +#define ISL12057_REG_A1_HR	0x09	/* Alarm 1 Hours */ +#define ISL12057_REG_A1_HR_PM	BIT(5)	/* AM/PM bit in 12h format */ +#define ISL12057_REG_A1_HR_MIL	BIT(6)	/* 24h/12h format */ +#define ISL12057_REG_A1_DWDT	0x0A	/* Alarm 1 Date / Day of the week */ +#define ISL12057_REG_A1_DWDT_B	BIT(6)	/* DW / DT selection bit */ +#define ISL12057_A1_SEC_LEN	4 + +/* Alarm 2 section */ +#define ISL12057_REG_A2_MN	0x0B	/* Alarm 2 Minutes */ +#define ISL12057_REG_A2_HR	0x0C	/* Alarm 2 Hours */ +#define ISL12057_REG_A2_DWDT	0x0D	/* Alarm 2 Date / Day of the week */ +#define ISL12057_A2_SEC_LEN	3 + +/* Control/Status registers */ +#define ISL12057_REG_INT	0x0E +#define ISL12057_REG_INT_A1IE	BIT(0)	/* Alarm 1 interrupt enable bit */ +#define ISL12057_REG_INT_A2IE	BIT(1)	/* Alarm 2 interrupt enable bit */ +#define ISL12057_REG_INT_INTCN	BIT(2)	/* Interrupt control enable bit */ +#define ISL12057_REG_INT_RS1	BIT(3)	/* Freq out control bit 1 */ +#define ISL12057_REG_INT_RS2	BIT(4)	/* Freq out control bit 2 */ +#define ISL12057_REG_INT_EOSC	BIT(7)	/* Oscillator enable bit */ + +#define ISL12057_REG_SR		0x0F +#define ISL12057_REG_SR_A1F	BIT(0)	/* Alarm 1 interrupt bit */ +#define ISL12057_REG_SR_A2F	BIT(1)	/* Alarm 2 interrupt bit */ +#define ISL12057_REG_SR_OSF	BIT(7)	/* Oscillator failure bit */ + +/* Register memory map length */ +#define ISL12057_MEM_MAP_LEN	0x10 + +struct isl12057_rtc_data { +	struct regmap *regmap; +	struct mutex lock; +}; + +static void isl12057_rtc_regs_to_tm(struct rtc_time *tm, u8 *regs) +{ +	tm->tm_sec = bcd2bin(regs[ISL12057_REG_RTC_SC]); +	tm->tm_min = bcd2bin(regs[ISL12057_REG_RTC_MN]); + +	if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_MIL) { /* AM/PM */ +		tm->tm_hour = bcd2bin(regs[ISL12057_REG_RTC_HR] & 0x0f); +		if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_PM) +			tm->tm_hour += 12; +	} else {					    /* 24 hour mode */ +		tm->tm_hour = bcd2bin(regs[ISL12057_REG_RTC_HR] & 0x3f); +	} + +	tm->tm_mday = bcd2bin(regs[ISL12057_REG_RTC_DT]); +	tm->tm_wday = bcd2bin(regs[ISL12057_REG_RTC_DW]) - 1; /* starts at 1 */ +	tm->tm_mon  = bcd2bin(regs[ISL12057_REG_RTC_MO]) - 1; /* starts at 1 */ +	tm->tm_year = bcd2bin(regs[ISL12057_REG_RTC_YR]) + 100; +} + +static int isl12057_rtc_tm_to_regs(u8 *regs, struct rtc_time *tm) +{ +	/* +	 * The clock has an 8 bit wide bcd-coded register for the year. +	 * tm_year is an offset from 1900 and we are interested in the +	 * 2000-2099 range, so any value less than 100 is invalid. +	 */ +	if (tm->tm_year < 100) +		return -EINVAL; + +	regs[ISL12057_REG_RTC_SC] = bin2bcd(tm->tm_sec); +	regs[ISL12057_REG_RTC_MN] = bin2bcd(tm->tm_min); +	regs[ISL12057_REG_RTC_HR] = bin2bcd(tm->tm_hour); /* 24-hour format */ +	regs[ISL12057_REG_RTC_DT] = bin2bcd(tm->tm_mday); +	regs[ISL12057_REG_RTC_MO] = bin2bcd(tm->tm_mon + 1); +	regs[ISL12057_REG_RTC_YR] = bin2bcd(tm->tm_year - 100); +	regs[ISL12057_REG_RTC_DW] = bin2bcd(tm->tm_wday + 1); + +	return 0; +} + +/* + * Try and match register bits w/ fixed null values to see whether we + * are dealing with an ISL12057. Note: this function is called early + * during init and hence does need mutex protection. + */ +static int isl12057_i2c_validate_chip(struct regmap *regmap) +{ +	u8 regs[ISL12057_MEM_MAP_LEN]; +	static const u8 mask[ISL12057_MEM_MAP_LEN] = { 0x80, 0x80, 0x80, 0xf8, +						       0xc0, 0x60, 0x00, 0x00, +						       0x00, 0x00, 0x00, 0x00, +						       0x00, 0x00, 0x60, 0x7c }; +	int ret, i; + +	ret = regmap_bulk_read(regmap, 0, regs, ISL12057_MEM_MAP_LEN); +	if (ret) +		return ret; + +	for (i = 0; i < ISL12057_MEM_MAP_LEN; ++i) { +		if (regs[i] & mask[i])	/* check if bits are cleared */ +			return -ENODEV; +	} + +	return 0; +} + +static int isl12057_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ +	struct isl12057_rtc_data *data = dev_get_drvdata(dev); +	u8 regs[ISL12057_RTC_SEC_LEN]; +	int ret; + +	mutex_lock(&data->lock); +	ret = regmap_bulk_read(data->regmap, ISL12057_REG_RTC_SC, regs, +			       ISL12057_RTC_SEC_LEN); +	mutex_unlock(&data->lock); + +	if (ret) { +		dev_err(dev, "%s: RTC read failed\n", __func__); +		return ret; +	} + +	isl12057_rtc_regs_to_tm(tm, regs); + +	return rtc_valid_tm(tm); +} + +static int isl12057_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ +	struct isl12057_rtc_data *data = dev_get_drvdata(dev); +	u8 regs[ISL12057_RTC_SEC_LEN]; +	int ret; + +	ret = isl12057_rtc_tm_to_regs(regs, tm); +	if (ret) +		return ret; + +	mutex_lock(&data->lock); +	ret = regmap_bulk_write(data->regmap, ISL12057_REG_RTC_SC, regs, +				ISL12057_RTC_SEC_LEN); +	mutex_unlock(&data->lock); + +	if (ret) +		dev_err(dev, "%s: RTC write failed\n", __func__); + +	return ret; +} + +/* + * Check current RTC status and enable/disable what needs to be. Return 0 if + * everything went ok and a negative value upon error. Note: this function + * is called early during init and hence does need mutex protection. + */ +static int isl12057_check_rtc_status(struct device *dev, struct regmap *regmap) +{ +	int ret; + +	/* Enable oscillator if not already running */ +	ret = regmap_update_bits(regmap, ISL12057_REG_INT, +				 ISL12057_REG_INT_EOSC, 0); +	if (ret < 0) { +		dev_err(dev, "Unable to enable oscillator\n"); +		return ret; +	} + +	/* Clear oscillator failure bit if needed */ +	ret = regmap_update_bits(regmap, ISL12057_REG_SR, +				 ISL12057_REG_SR_OSF, 0); +	if (ret < 0) { +		dev_err(dev, "Unable to clear oscillator failure bit\n"); +		return ret; +	} + +	/* Clear alarm bit if needed */ +	ret = regmap_update_bits(regmap, ISL12057_REG_SR, +				 ISL12057_REG_SR_A1F, 0); +	if (ret < 0) { +		dev_err(dev, "Unable to clear alarm bit\n"); +		return ret; +	} + +	return 0; +} + +static const struct rtc_class_ops rtc_ops = { +	.read_time = isl12057_rtc_read_time, +	.set_time = isl12057_rtc_set_time, +}; + +static struct regmap_config isl12057_rtc_regmap_config = { +	.reg_bits = 8, +	.val_bits = 8, +}; + +static int isl12057_probe(struct i2c_client *client, +			  const struct i2c_device_id *id) +{ +	struct device *dev = &client->dev; +	struct isl12057_rtc_data *data; +	struct rtc_device *rtc; +	struct regmap *regmap; +	int ret; + +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C | +				     I2C_FUNC_SMBUS_BYTE_DATA | +				     I2C_FUNC_SMBUS_I2C_BLOCK)) +		return -ENODEV; + +	regmap = devm_regmap_init_i2c(client, &isl12057_rtc_regmap_config); +	if (IS_ERR(regmap)) { +		ret = PTR_ERR(regmap); +		dev_err(dev, "regmap allocation failed: %d\n", ret); +		return ret; +	} + +	ret = isl12057_i2c_validate_chip(regmap); +	if (ret) +		return ret; + +	ret = isl12057_check_rtc_status(dev, regmap); +	if (ret) +		return ret; + +	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); +	if (!data) +		return -ENOMEM; + +	mutex_init(&data->lock); +	data->regmap = regmap; +	dev_set_drvdata(dev, data); + +	rtc = devm_rtc_device_register(dev, DRV_NAME, &rtc_ops, THIS_MODULE); +	return PTR_ERR_OR_ZERO(rtc); +} + +#ifdef CONFIG_OF +static const struct of_device_id isl12057_dt_match[] = { +	{ .compatible = "isl,isl12057" }, +	{ }, +}; +#endif + +static const struct i2c_device_id isl12057_id[] = { +	{ "isl12057", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, isl12057_id); + +static struct i2c_driver isl12057_driver = { +	.driver = { +		.name = DRV_NAME, +		.owner = THIS_MODULE, +		.of_match_table = of_match_ptr(isl12057_dt_match), +	}, +	.probe	  = isl12057_probe, +	.id_table = isl12057_id, +}; +module_i2c_driver(isl12057_driver); + +MODULE_AUTHOR("Arnaud EBALARD <arno@natisbad.org>"); +MODULE_DESCRIPTION("Intersil ISL12057 RTC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-isl1208.c b/drivers/rtc/rtc-isl1208.c index c016ad81767..c3c549d511b 100644 --- a/drivers/rtc/rtc-isl1208.c +++ b/drivers/rtc/rtc-isl1208.c @@ -144,11 +144,7 @@ isl1208_i2c_validate_client(struct i2c_client *client)  static int  isl1208_i2c_get_sr(struct i2c_client *client)  { -	int sr = i2c_smbus_read_byte_data(client, ISL1208_REG_SR); -	if (sr < 0) -		return -EIO; - -	return sr; +	return i2c_smbus_read_byte_data(client, ISL1208_REG_SR);  }  static int @@ -647,10 +643,11 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)  		 "chip found, driver version " DRV_VERSION "\n");  	if (client->irq > 0) { -		rc = request_threaded_irq(client->irq, NULL, -					  isl1208_rtc_interrupt, -					  IRQF_SHARED, -					  isl1208_driver.driver.name, client); +		rc = devm_request_threaded_irq(&client->dev, client->irq, NULL, +					       isl1208_rtc_interrupt, +					       IRQF_SHARED, +					       isl1208_driver.driver.name, +					       client);  		if (!rc) {  			device_init_wakeup(&client->dev, 1);  			enable_irq_wake(client->irq); @@ -662,20 +659,18 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)  		}  	} -	rtc = rtc_device_register(isl1208_driver.driver.name, -				  &client->dev, &isl1208_rtc_ops, +	rtc = devm_rtc_device_register(&client->dev, isl1208_driver.driver.name, +				  &isl1208_rtc_ops,  				  THIS_MODULE); -	if (IS_ERR(rtc)) { -		rc = PTR_ERR(rtc); -		goto exit_free_irq; -	} +	if (IS_ERR(rtc)) +		return PTR_ERR(rtc);  	i2c_set_clientdata(client, rtc);  	rc = isl1208_i2c_get_sr(client);  	if (rc < 0) {  		dev_err(&client->dev, "reading status failed\n"); -		goto exit_unregister; +		return rc;  	}  	if (rc & ISL1208_REG_SR_RTCF) @@ -684,28 +679,15 @@ isl1208_probe(struct i2c_client *client, const struct i2c_device_id *id)  	rc = sysfs_create_group(&client->dev.kobj, &isl1208_rtc_sysfs_files);  	if (rc) -		goto exit_unregister; +		return rc;  	return 0; - -exit_unregister: -	rtc_device_unregister(rtc); -exit_free_irq: -	if (client->irq) -		free_irq(client->irq, client); - -	return rc;  }  static int  isl1208_remove(struct i2c_client *client)  { -	struct rtc_device *rtc = i2c_get_clientdata(client); -  	sysfs_remove_group(&client->dev.kobj, &isl1208_rtc_sysfs_files); -	rtc_device_unregister(rtc); -	if (client->irq) -		free_irq(client->irq, client);  	return 0;  } diff --git a/drivers/rtc/rtc-jz4740.c b/drivers/rtc/rtc-jz4740.c index 1b126d2513d..08f5160fb6d 100644 --- a/drivers/rtc/rtc-jz4740.c +++ b/drivers/rtc/rtc-jz4740.c @@ -38,7 +38,6 @@  #define JZ_RTC_CTRL_ENABLE	BIT(0)  struct jz4740_rtc { -	struct resource *mem;  	void __iomem *base;  	struct rtc_device *rtc; @@ -216,6 +215,7 @@ static int jz4740_rtc_probe(struct platform_device *pdev)  	int ret;  	struct jz4740_rtc *rtc;  	uint32_t scratchpad; +	struct resource *mem;  	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);  	if (!rtc) @@ -227,25 +227,10 @@ static int jz4740_rtc_probe(struct platform_device *pdev)  		return -ENOENT;  	} -	rtc->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (!rtc->mem) { -		dev_err(&pdev->dev, "Failed to get platform mmio memory\n"); -		return -ENOENT; -	} - -	rtc->mem = devm_request_mem_region(&pdev->dev, rtc->mem->start, -					resource_size(rtc->mem), pdev->name); -	if (!rtc->mem) { -		dev_err(&pdev->dev, "Failed to request mmio memory region\n"); -		return -EBUSY; -	} - -	rtc->base = devm_ioremap_nocache(&pdev->dev, rtc->mem->start, -					resource_size(rtc->mem)); -	if (!rtc->base) { -		dev_err(&pdev->dev, "Failed to ioremap mmio memory\n"); -		return -EBUSY; -	} +	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	rtc->base = devm_ioremap_resource(&pdev->dev, mem); +	if (IS_ERR(rtc->base)) +		return PTR_ERR(rtc->base);  	spin_lock_init(&rtc->lock); diff --git a/drivers/rtc/rtc-lpc32xx.c b/drivers/rtc/rtc-lpc32xx.c index bfdbcb82d06..f130c08c98f 100644 --- a/drivers/rtc/rtc-lpc32xx.c +++ b/drivers/rtc/rtc-lpc32xx.c @@ -211,10 +211,9 @@ static int lpc32xx_rtc_probe(struct platform_device *pdev)  	}  	rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL); -	if (unlikely(!rtc)) { -		dev_err(&pdev->dev, "Can't allocate memory\n"); +	if (unlikely(!rtc))  		return -ENOMEM; -	} +  	rtc->irq = rtcirq;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); diff --git a/drivers/rtc/rtc-m41t80.c b/drivers/rtc/rtc-m41t80.c index a5248aa1abf..7ff7427c2e6 100644 --- a/drivers/rtc/rtc-m41t80.c +++ b/drivers/rtc/rtc-m41t80.c @@ -66,8 +66,6 @@  #define M41T80_FEATURE_WD	(1 << 3)	/* Extra watchdog resolution */  #define M41T80_FEATURE_SQ_ALT	(1 << 4)	/* RSx bits are in reg 4 */ -#define DRV_VERSION "0.05" -  static DEFINE_MUTEX(m41t80_rtc_mutex);  static const struct i2c_device_id m41t80_id[] = {  	{ "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT }, @@ -80,6 +78,7 @@ static const struct i2c_device_id m41t80_id[] = {  	{ "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },  	{ "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },  	{ "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ }, +	{ "rv4162", M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT },  	{ }  };  MODULE_DEVICE_TABLE(i2c, m41t80_id); @@ -232,7 +231,7 @@ static ssize_t m41t80_sysfs_show_flags(struct device *dev,  	val = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);  	if (val < 0) -		return -EIO; +		return val;  	return sprintf(buf, "%#x\n", val);  }  static DEVICE_ATTR(flags, S_IRUGO, m41t80_sysfs_show_flags, NULL); @@ -252,7 +251,7 @@ static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev,  		reg_sqw = M41T80_REG_WDAY;  	val = i2c_smbus_read_byte_data(client, reg_sqw);  	if (val < 0) -		return -EIO; +		return val;  	val = (val >> 4) & 0xf;  	switch (val) {  	case 0: @@ -271,7 +270,7 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,  {  	struct i2c_client *client = to_i2c_client(dev);  	struct m41t80_data *clientdata = i2c_get_clientdata(client); -	int almon, sqw, reg_sqw; +	int almon, sqw, reg_sqw, rc;  	int val = simple_strtoul(buf, NULL, 0);  	if (!(clientdata->features & M41T80_FEATURE_SQ)) @@ -291,21 +290,30 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,  	/* disable SQW, set SQW frequency & re-enable */  	almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);  	if (almon < 0) -		return -EIO; +		return almon;  	reg_sqw = M41T80_REG_SQW;  	if (clientdata->features & M41T80_FEATURE_SQ_ALT)  		reg_sqw = M41T80_REG_WDAY;  	sqw = i2c_smbus_read_byte_data(client, reg_sqw);  	if (sqw < 0) -		return -EIO; +		return sqw;  	sqw = (sqw & 0x0f) | (val << 4); -	if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, -				      almon & ~M41T80_ALMON_SQWE) < 0 || -	    i2c_smbus_write_byte_data(client, reg_sqw, sqw) < 0) -		return -EIO; -	if (val && i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, -					     almon | M41T80_ALMON_SQWE) < 0) -		return -EIO; + +	rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, +				      almon & ~M41T80_ALMON_SQWE); +	if (rc < 0) +		return rc; + +	if (val) { +		rc = i2c_smbus_write_byte_data(client, reg_sqw, sqw); +		if (rc < 0) +			return rc; + +		rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, +					     almon | M41T80_ALMON_SQWE); +		if (rc <0) +			return rc; +	}  	return count;  }  static DEVICE_ATTR(sqwfreq, S_IRUGO | S_IWUSR, @@ -629,40 +637,28 @@ static int m41t80_probe(struct i2c_client *client,  	struct m41t80_data *clientdata = NULL;  	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C -				     | I2C_FUNC_SMBUS_BYTE_DATA)) { -		rc = -ENODEV; -		goto exit; -	} - -	dev_info(&client->dev, -		 "chip found, driver version " DRV_VERSION "\n"); +				     | I2C_FUNC_SMBUS_BYTE_DATA)) +		return -ENODEV;  	clientdata = devm_kzalloc(&client->dev, sizeof(*clientdata),  				GFP_KERNEL); -	if (!clientdata) { -		rc = -ENOMEM; -		goto exit; -	} +	if (!clientdata) +		return -ENOMEM;  	clientdata->features = id->driver_data;  	i2c_set_clientdata(client, clientdata);  	rtc = devm_rtc_device_register(&client->dev, client->name,  					&m41t80_rtc_ops, THIS_MODULE); -	if (IS_ERR(rtc)) { -		rc = PTR_ERR(rtc); -		rtc = NULL; -		goto exit; -	} +	if (IS_ERR(rtc)) +		return PTR_ERR(rtc);  	clientdata->rtc = rtc;  	/* Make sure HT (Halt Update) bit is cleared */  	rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR); -	if (rc < 0) -		goto ht_err; -	if (rc & M41T80_ALHOUR_HT) { +	if (rc >= 0 && rc & M41T80_ALHOUR_HT) {  		if (clientdata->features & M41T80_FEATURE_HT) {  			m41t80_get_datetime(client, &tm);  			dev_info(&client->dev, "HT bit was set!\n"); @@ -673,53 +669,44 @@ static int m41t80_probe(struct i2c_client *client,  				 tm.tm_mon + 1, tm.tm_mday, tm.tm_hour,  				 tm.tm_min, tm.tm_sec);  		} -		if (i2c_smbus_write_byte_data(client, -					      M41T80_REG_ALARM_HOUR, -					      rc & ~M41T80_ALHOUR_HT) < 0) -			goto ht_err; +		rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_HOUR, +					      rc & ~M41T80_ALHOUR_HT); +	} + +	if (rc < 0) { +		dev_err(&client->dev, "Can't clear HT bit\n"); +		return rc;  	}  	/* Make sure ST (stop) bit is cleared */  	rc = i2c_smbus_read_byte_data(client, M41T80_REG_SEC); -	if (rc < 0) -		goto st_err; -	if (rc & M41T80_SEC_ST) { -		if (i2c_smbus_write_byte_data(client, M41T80_REG_SEC, -					      rc & ~M41T80_SEC_ST) < 0) -			goto st_err; +	if (rc >= 0 && rc & M41T80_SEC_ST) +		rc = i2c_smbus_write_byte_data(client, M41T80_REG_SEC, +					      rc & ~M41T80_SEC_ST); +	if (rc < 0) { +		dev_err(&client->dev, "Can't clear ST bit\n"); +		return rc;  	}  	rc = m41t80_sysfs_register(&client->dev);  	if (rc) -		goto exit; +		return rc;  #ifdef CONFIG_RTC_DRV_M41T80_WDT  	if (clientdata->features & M41T80_FEATURE_HT) {  		save_client = client;  		rc = misc_register(&wdt_dev);  		if (rc) -			goto exit; +			return rc;  		rc = register_reboot_notifier(&wdt_notifier);  		if (rc) {  			misc_deregister(&wdt_dev); -			goto exit; +			return rc;  		}  	}  #endif  	return 0; - -st_err: -	rc = -EIO; -	dev_err(&client->dev, "Can't clear ST bit\n"); -	goto exit; -ht_err: -	rc = -EIO; -	dev_err(&client->dev, "Can't clear HT bit\n"); -	goto exit; - -exit: -	return rc;  }  static int m41t80_remove(struct i2c_client *client) @@ -750,4 +737,3 @@ module_i2c_driver(m41t80_driver);  MODULE_AUTHOR("Alexander Bigga <ab@mycable.de>");  MODULE_DESCRIPTION("ST Microelectronics M41T80 series RTC I2C Client Driver");  MODULE_LICENSE("GPL"); -MODULE_VERSION(DRV_VERSION); diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index fcb03291f14..11880c1e9da 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -68,7 +68,7 @@ m48t59_mem_readb(struct device *dev, u32 ofs)  static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)  {  	struct platform_device *pdev = to_platform_device(dev); -	struct m48t59_plat_data *pdata = pdev->dev.platform_data; +	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);  	unsigned long flags;  	u8 val; @@ -111,7 +111,7 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)  static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)  {  	struct platform_device *pdev = to_platform_device(dev); -	struct m48t59_plat_data *pdata = pdev->dev.platform_data; +	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);  	unsigned long flags;  	u8 val = 0; @@ -158,7 +158,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)  static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)  {  	struct platform_device *pdev = to_platform_device(dev); -	struct m48t59_plat_data *pdata = pdev->dev.platform_data; +	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);  	struct rtc_time *tm = &alrm->time;  	unsigned long flags; @@ -205,7 +205,7 @@ static int m48t59_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)  static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)  {  	struct platform_device *pdev = to_platform_device(dev); -	struct m48t59_plat_data *pdata = pdev->dev.platform_data; +	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);  	struct rtc_time *tm = &alrm->time;  	u8 mday, hour, min, sec; @@ -266,7 +266,7 @@ static int m48t59_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)  static int m48t59_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)  {  	struct platform_device *pdev = to_platform_device(dev); -	struct m48t59_plat_data *pdata = pdev->dev.platform_data; +	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);  	unsigned long flags; @@ -283,7 +283,7 @@ static int m48t59_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)  static int m48t59_rtc_proc(struct device *dev, struct seq_file *seq)  {  	struct platform_device *pdev = to_platform_device(dev); -	struct m48t59_plat_data *pdata = pdev->dev.platform_data; +	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);  	unsigned long flags;  	u8 val; @@ -304,7 +304,7 @@ static irqreturn_t m48t59_rtc_interrupt(int irq, void *dev_id)  {  	struct device *dev = (struct device *)dev_id;  	struct platform_device *pdev = to_platform_device(dev); -	struct m48t59_plat_data *pdata = pdev->dev.platform_data; +	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);  	u8 event; @@ -340,7 +340,7 @@ static ssize_t m48t59_nvram_read(struct file *filp, struct kobject *kobj,  {  	struct device *dev = container_of(kobj, struct device, kobj);  	struct platform_device *pdev = to_platform_device(dev); -	struct m48t59_plat_data *pdata = pdev->dev.platform_data; +	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);  	ssize_t cnt = 0;  	unsigned long flags; @@ -360,7 +360,7 @@ static ssize_t m48t59_nvram_write(struct file *filp, struct kobject *kobj,  {  	struct device *dev = container_of(kobj, struct device, kobj);  	struct platform_device *pdev = to_platform_device(dev); -	struct m48t59_plat_data *pdata = pdev->dev.platform_data; +	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);  	struct m48t59_private *m48t59 = platform_get_drvdata(pdev);  	ssize_t cnt = 0;  	unsigned long flags; @@ -385,7 +385,7 @@ static struct bin_attribute m48t59_nvram_attr = {  static int m48t59_rtc_probe(struct platform_device *pdev)  { -	struct m48t59_plat_data *pdata = pdev->dev.platform_data; +	struct m48t59_plat_data *pdata = dev_get_platdata(&pdev->dev);  	struct m48t59_private *m48t59 = NULL;  	struct resource *res;  	int ret = -ENOMEM; diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index 2d30314fa07..32f64c94262 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -46,7 +46,7 @@ static int m48t86_rtc_read_time(struct device *dev, struct rtc_time *tm)  {  	unsigned char reg;  	struct platform_device *pdev = to_platform_device(dev); -	struct m48t86_ops *ops = pdev->dev.platform_data; +	struct m48t86_ops *ops = dev_get_platdata(&pdev->dev);  	reg = ops->readbyte(M48T86_REG_B); @@ -84,7 +84,7 @@ static int m48t86_rtc_set_time(struct device *dev, struct rtc_time *tm)  {  	unsigned char reg;  	struct platform_device *pdev = to_platform_device(dev); -	struct m48t86_ops *ops = pdev->dev.platform_data; +	struct m48t86_ops *ops = dev_get_platdata(&pdev->dev);  	reg = ops->readbyte(M48T86_REG_B); @@ -123,7 +123,7 @@ static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq)  {  	unsigned char reg;  	struct platform_device *pdev = to_platform_device(dev); -	struct m48t86_ops *ops = pdev->dev.platform_data; +	struct m48t86_ops *ops = dev_get_platdata(&pdev->dev);  	reg = ops->readbyte(M48T86_REG_B); @@ -147,7 +147,7 @@ static const struct rtc_class_ops m48t86_rtc_ops = {  static int m48t86_rtc_probe(struct platform_device *dev)  {  	unsigned char reg; -	struct m48t86_ops *ops = dev->dev.platform_data; +	struct m48t86_ops *ops = dev_get_platdata(&dev->dev);  	struct rtc_device *rtc;  	rtc = devm_rtc_device_register(&dev->dev, "m48t86", diff --git a/drivers/rtc/rtc-max6900.c b/drivers/rtc/rtc-max6900.c index 55969b1b771..4804985b876 100644 --- a/drivers/rtc/rtc-max6900.c +++ b/drivers/rtc/rtc-max6900.c @@ -164,14 +164,7 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)  static int max6900_i2c_clear_write_protect(struct i2c_client *client)  { -	int rc; -	rc = i2c_smbus_write_byte_data(client, MAX6900_REG_CONTROL_WRITE, 0); -	if (rc < 0) { -		dev_err(&client->dev, "%s: control register write failed\n", -			__func__); -		return -EIO; -	} -	return 0; +	return i2c_smbus_write_byte_data(client, MAX6900_REG_CONTROL_WRITE, 0);  }  static int diff --git a/drivers/rtc/rtc-max8907.c b/drivers/rtc/rtc-max8907.c index 8e45b3c4aa2..3032178bd9e 100644 --- a/drivers/rtc/rtc-max8907.c +++ b/drivers/rtc/rtc-max8907.c @@ -51,7 +51,7 @@ static irqreturn_t max8907_irq_handler(int irq, void *data)  {  	struct max8907_rtc *rtc = data; -	regmap_update_bits(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0x7f, 0); +	regmap_write(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0);  	rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF); @@ -64,7 +64,7 @@ static void regs_to_tm(u8 *regs, struct rtc_time *tm)  		bcd2bin(regs[RTC_YEAR1]) - 1900;  	tm->tm_mon = bcd2bin(regs[RTC_MONTH] & 0x1f) - 1;  	tm->tm_mday = bcd2bin(regs[RTC_DATE] & 0x3f); -	tm->tm_wday = (regs[RTC_WEEKDAY] & 0x07) - 1; +	tm->tm_wday = (regs[RTC_WEEKDAY] & 0x07);  	if (regs[RTC_HOUR] & HOUR_12) {  		tm->tm_hour = bcd2bin(regs[RTC_HOUR] & 0x01f);  		if (tm->tm_hour == 12) @@ -88,7 +88,7 @@ static void tm_to_regs(struct rtc_time *tm, u8 *regs)  	regs[RTC_YEAR1] = bin2bcd(low);  	regs[RTC_MONTH] = bin2bcd(tm->tm_mon + 1);  	regs[RTC_DATE] = bin2bcd(tm->tm_mday); -	regs[RTC_WEEKDAY] = tm->tm_wday + 1; +	regs[RTC_WEEKDAY] = tm->tm_wday;  	regs[RTC_HOUR] = bin2bcd(tm->tm_hour);  	regs[RTC_MIN] = bin2bcd(tm->tm_min);  	regs[RTC_SEC] = bin2bcd(tm->tm_sec); @@ -153,7 +153,7 @@ static int max8907_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)  	tm_to_regs(&alrm->time, regs);  	/* Disable alarm while we update the target time */ -	ret = regmap_update_bits(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0x7f, 0); +	ret = regmap_write(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0);  	if (ret < 0)  		return ret; @@ -163,8 +163,7 @@ static int max8907_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)  		return ret;  	if (alrm->enabled) -		ret = regmap_update_bits(rtc->regmap, MAX8907_REG_ALARM0_CNTL, -					 0x7f, 0x7f); +		ret = regmap_write(rtc->regmap, MAX8907_REG_ALARM0_CNTL, 0x77);  	return ret;  } diff --git a/drivers/rtc/rtc-mc13xxx.c b/drivers/rtc/rtc-mc13xxx.c index 77ea9896b5b..0765606a2d1 100644 --- a/drivers/rtc/rtc-mc13xxx.c +++ b/drivers/rtc/rtc-mc13xxx.c @@ -23,6 +23,8 @@  #define MC13XXX_RTCDAY	22  #define MC13XXX_RTCDAYA	23 +#define SEC_PER_DAY	(24 * 60 * 60) +  struct mc13xxx_rtc {  	struct rtc_device *rtc;  	struct mc13xxx *mc13xxx; @@ -42,15 +44,15 @@ static int mc13xxx_rtc_irq_enable_unlocked(struct device *dev,  	return func(priv->mc13xxx, irq);  } -static int mc13xxx_rtc_irq_enable(struct device *dev, -		unsigned int enabled, int irq) +static int mc13xxx_rtc_alarm_irq_enable(struct device *dev, +					unsigned int enabled)  {  	struct mc13xxx_rtc *priv = dev_get_drvdata(dev);  	int ret;  	mc13xxx_lock(priv->mc13xxx); -	ret = mc13xxx_rtc_irq_enable_unlocked(dev, enabled, irq); +	ret = mc13xxx_rtc_irq_enable_unlocked(dev, enabled, MC13XXX_IRQ_TODA);  	mc13xxx_unlock(priv->mc13xxx); @@ -61,44 +63,27 @@ static int mc13xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)  {  	struct mc13xxx_rtc *priv = dev_get_drvdata(dev);  	unsigned int seconds, days1, days2; -	unsigned long s1970; -	int ret; - -	mc13xxx_lock(priv->mc13xxx); - -	if (!priv->valid) { -		ret = -ENODATA; -		goto out; -	} -	ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days1); -	if (unlikely(ret)) -		goto out; - -	ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTOD, &seconds); -	if (unlikely(ret)) -		goto out; - -	ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days2); -out: -	mc13xxx_unlock(priv->mc13xxx); +	if (!priv->valid) +		return -ENODATA; -	if (ret) -		return ret; +	do { +		int ret; -	if (days2 == days1 + 1) { -		if (seconds >= 86400 / 2) -			days2 = days1; -		else -			days1 = days2; -	} +		ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days1); +		if (ret) +			return ret; -	if (days1 != days2) -		return -EIO; +		ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTOD, &seconds); +		if (ret) +			return ret; -	s1970 = days1 * 86400 + seconds; +		ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCDAY, &days2); +		if (ret) +			return ret; +	} while (days1 != days2); -	rtc_time_to_tm(s1970, tm); +	rtc_time_to_tm(days1 * SEC_PER_DAY + seconds, tm);  	return rtc_valid_tm(tm);  } @@ -110,8 +95,8 @@ static int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs)  	unsigned int alarmseconds;  	int ret; -	seconds = secs % 86400; -	days = secs / 86400; +	seconds = secs % SEC_PER_DAY; +	days = secs / SEC_PER_DAY;  	mc13xxx_lock(priv->mc13xxx); @@ -123,7 +108,7 @@ static int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs)  	if (unlikely(ret))  		goto out; -	if (alarmseconds < 86400) { +	if (alarmseconds < SEC_PER_DAY) {  		ret = mc13xxx_reg_write(priv->mc13xxx,  				MC13XXX_RTCTODA, 0x1ffff);  		if (unlikely(ret)) @@ -147,18 +132,21 @@ static int mc13xxx_rtc_set_mmss(struct device *dev, unsigned long secs)  		goto out;  	/* restore alarm */ -	if (alarmseconds < 86400) { +	if (alarmseconds < SEC_PER_DAY) {  		ret = mc13xxx_reg_write(priv->mc13xxx,  				MC13XXX_RTCTODA, alarmseconds);  		if (unlikely(ret))  			goto out;  	} -	ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_RTCRST); -	if (unlikely(ret)) -		goto out; +	if (!priv->valid) { +		ret = mc13xxx_irq_ack(priv->mc13xxx, MC13XXX_IRQ_RTCRST); +		if (unlikely(ret)) +			goto out; + +		ret = mc13xxx_irq_unmask(priv->mc13xxx, MC13XXX_IRQ_RTCRST); +	} -	ret = mc13xxx_irq_unmask(priv->mc13xxx, MC13XXX_IRQ_RTCRST);  out:  	priv->valid = !ret; @@ -180,7 +168,7 @@ static int mc13xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)  	ret = mc13xxx_reg_read(priv->mc13xxx, MC13XXX_RTCTODA, &seconds);  	if (unlikely(ret))  		goto out; -	if (seconds >= 86400) { +	if (seconds >= SEC_PER_DAY) {  		ret = -ENODATA;  		goto out;  	} @@ -201,7 +189,7 @@ out:  	alarm->enabled = enabled;  	alarm->pending = pending; -	s1970 = days * 86400 + seconds; +	s1970 = days * SEC_PER_DAY + seconds;  	rtc_time_to_tm(s1970, &alarm->time);  	dev_dbg(dev, "%s: %lu\n", __func__, s1970); @@ -239,8 +227,8 @@ static int mc13xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)  	if (unlikely(ret))  		goto out; -	seconds = s1970 % 86400; -	days = s1970 / 86400; +	seconds = s1970 % SEC_PER_DAY; +	days = s1970 / SEC_PER_DAY;  	ret = mc13xxx_reg_write(priv->mc13xxx, MC13XXX_RTCDAYA, days);  	if (unlikely(ret)) @@ -259,8 +247,6 @@ static irqreturn_t mc13xxx_rtc_alarm_handler(int irq, void *dev)  	struct mc13xxx_rtc *priv = dev;  	struct mc13xxx *mc13xxx = priv->mc13xxx; -	dev_dbg(&priv->rtc->dev, "Alarm\n"); -  	rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_AF);  	mc13xxx_irq_ack(mc13xxx, irq); @@ -273,8 +259,6 @@ static irqreturn_t mc13xxx_rtc_update_handler(int irq, void *dev)  	struct mc13xxx_rtc *priv = dev;  	struct mc13xxx *mc13xxx = priv->mc13xxx; -	dev_dbg(&priv->rtc->dev, "1HZ\n"); -  	rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF);  	mc13xxx_irq_ack(mc13xxx, irq); @@ -282,12 +266,6 @@ static irqreturn_t mc13xxx_rtc_update_handler(int irq, void *dev)  	return IRQ_HANDLED;  } -static int mc13xxx_rtc_alarm_irq_enable(struct device *dev, -		unsigned int enabled) -{ -	return mc13xxx_rtc_irq_enable(dev, enabled, MC13XXX_IRQ_TODA); -} -  static const struct rtc_class_ops mc13xxx_rtc_ops = {  	.read_time = mc13xxx_rtc_read_time,  	.set_mmss = mc13xxx_rtc_set_mmss, @@ -301,7 +279,6 @@ static irqreturn_t mc13xxx_rtc_reset_handler(int irq, void *dev)  	struct mc13xxx_rtc *priv = dev;  	struct mc13xxx *mc13xxx = priv->mc13xxx; -	dev_dbg(&priv->rtc->dev, "RTCRST\n");  	priv->valid = 0;  	mc13xxx_irq_mask(mc13xxx, irq); @@ -314,7 +291,6 @@ static int __init mc13xxx_rtc_probe(struct platform_device *pdev)  	int ret;  	struct mc13xxx_rtc *priv;  	struct mc13xxx *mc13xxx; -	int rtcrst_pending;  	priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);  	if (!priv) @@ -322,60 +298,47 @@ static int __init mc13xxx_rtc_probe(struct platform_device *pdev)  	mc13xxx = dev_get_drvdata(pdev->dev.parent);  	priv->mc13xxx = mc13xxx; +	priv->valid = 1;  	platform_set_drvdata(pdev, priv);  	mc13xxx_lock(mc13xxx); +	mc13xxx_irq_ack(mc13xxx, MC13XXX_IRQ_RTCRST); +  	ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_RTCRST,  			mc13xxx_rtc_reset_handler, DRIVER_NAME, priv);  	if (ret) -		goto err_reset_irq_request; - -	ret = mc13xxx_irq_status(mc13xxx, MC13XXX_IRQ_RTCRST, -			NULL, &rtcrst_pending); -	if (ret) -		goto err_reset_irq_status; - -	priv->valid = !rtcrst_pending; +		goto err_irq_request; -	ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_1HZ, +	ret = mc13xxx_irq_request(mc13xxx, MC13XXX_IRQ_1HZ,  			mc13xxx_rtc_update_handler, DRIVER_NAME, priv);  	if (ret) -		goto err_update_irq_request; +		goto err_irq_request;  	ret = mc13xxx_irq_request_nounmask(mc13xxx, MC13XXX_IRQ_TODA,  			mc13xxx_rtc_alarm_handler, DRIVER_NAME, priv);  	if (ret) -		goto err_alarm_irq_request; +		goto err_irq_request;  	mc13xxx_unlock(mc13xxx);  	priv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, -					&mc13xxx_rtc_ops, THIS_MODULE); -	if (IS_ERR(priv->rtc)) { -		ret = PTR_ERR(priv->rtc); +					     &mc13xxx_rtc_ops, THIS_MODULE); -		mc13xxx_lock(mc13xxx); - -		mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv); -err_alarm_irq_request: - -		mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_1HZ, priv); -err_update_irq_request: - -err_reset_irq_status: +	return 0; -		mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv); -err_reset_irq_request: +err_irq_request: +	mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_TODA, priv); +	mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_1HZ, priv); +	mc13xxx_irq_free(mc13xxx, MC13XXX_IRQ_RTCRST, priv); -		mc13xxx_unlock(mc13xxx); -	} +	mc13xxx_unlock(mc13xxx);  	return ret;  } -static int __exit mc13xxx_rtc_remove(struct platform_device *pdev) +static int mc13xxx_rtc_remove(struct platform_device *pdev)  {  	struct mc13xxx_rtc *priv = platform_get_drvdata(pdev); @@ -404,7 +367,7 @@ MODULE_DEVICE_TABLE(platform, mc13xxx_rtc_idtable);  static struct platform_driver mc13xxx_rtc_driver = {  	.id_table = mc13xxx_rtc_idtable, -	.remove = __exit_p(mc13xxx_rtc_remove), +	.remove = mc13xxx_rtc_remove,  	.driver = {  		.name = DRIVER_NAME,  		.owner = THIS_MODULE, diff --git a/drivers/rtc/rtc-mcp795.c b/drivers/rtc/rtc-mcp795.c new file mode 100644 index 00000000000..34295bf0041 --- /dev/null +++ b/drivers/rtc/rtc-mcp795.c @@ -0,0 +1,199 @@ +/* + * SPI Driver for Microchip MCP795 RTC + * + * Copyright (C) Josef Gajdusek <atx@atx.name> + * + * based on other Linux RTC drivers + * + * Device datasheet: + * http://ww1.microchip.com/downloads/en/DeviceDoc/22280A.pdf + * + * 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/module.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include <linux/printk.h> +#include <linux/spi/spi.h> +#include <linux/rtc.h> + +/* MCP795 Instructions, see datasheet table 3-1 */ +#define MCP795_EEREAD	0x03 +#define MCP795_EEWRITE	0x02 +#define MCP795_EEWRDI	0x04 +#define MCP795_EEWREN	0x06 +#define MCP795_SRREAD	0x05 +#define MCP795_SRWRITE	0x01 +#define MCP795_READ		0x13 +#define MCP795_WRITE	0x12 +#define MCP795_UNLOCK	0x14 +#define MCP795_IDWRITE	0x32 +#define MCP795_IDREAD	0x33 +#define MCP795_CLRWDT	0x44 +#define MCP795_CLRRAM	0x54 + +#define MCP795_ST_BIT	0x80 +#define MCP795_24_BIT	0x40 + +static int mcp795_rtcc_read(struct device *dev, u8 addr, u8 *buf, u8 count) +{ +	struct spi_device *spi = to_spi_device(dev); +	int ret; +	u8 tx[2]; + +	tx[0] = MCP795_READ; +	tx[1] = addr; +	ret = spi_write_then_read(spi, tx, sizeof(tx), buf, count); + +	if (ret) +		dev_err(dev, "Failed reading %d bytes from address %x.\n", +					count, addr); + +	return ret; +} + +static int mcp795_rtcc_write(struct device *dev, u8 addr, u8 *data, u8 count) +{ +	struct spi_device *spi = to_spi_device(dev); +	int ret; +	u8 tx[2 + count]; + +	tx[0] = MCP795_WRITE; +	tx[1] = addr; +	memcpy(&tx[2], data, count); + +	ret = spi_write(spi, tx, 2 + count); + +	if (ret) +		dev_err(dev, "Failed to write %d bytes to address %x.\n", +					count, addr); + +	return ret; +} + +static int mcp795_rtcc_set_bits(struct device *dev, u8 addr, u8 mask, u8 state) +{ +	int ret; +	u8 tmp; + +	ret = mcp795_rtcc_read(dev, addr, &tmp, 1); +	if (ret) +		return ret; + +	if ((tmp & mask) != state) { +		tmp = (tmp & ~mask) | state; +		ret = mcp795_rtcc_write(dev, addr, &tmp, 1); +	} + +	return ret; +} + +static int mcp795_set_time(struct device *dev, struct rtc_time *tim) +{ +	int ret; +	u8 data[7]; + +	/* Read first, so we can leave config bits untouched */ +	ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data)); + +	if (ret) +		return ret; + +	data[0] = (data[0] & 0x80) | ((tim->tm_sec / 10) << 4) | (tim->tm_sec % 10); +	data[1] = (data[1] & 0x80) | ((tim->tm_min / 10) << 4) | (tim->tm_min % 10); +	data[2] = ((tim->tm_hour / 10) << 4) | (tim->tm_hour % 10); +	data[4] = ((tim->tm_mday / 10) << 4) | ((tim->tm_mday) % 10); +	data[5] = (data[5] & 0x10) | (tim->tm_mon / 10) | (tim->tm_mon % 10); + +	if (tim->tm_year > 100) +		tim->tm_year -= 100; + +	data[6] = ((tim->tm_year / 10) << 4) | (tim->tm_year % 10); + +	ret = mcp795_rtcc_write(dev, 0x01, data, sizeof(data)); + +	if (ret) +		return ret; + +	dev_dbg(dev, "Set mcp795: %04d-%02d-%02d %02d:%02d:%02d\n", +			tim->tm_year + 1900, tim->tm_mon, tim->tm_mday, +			tim->tm_hour, tim->tm_min, tim->tm_sec); + +	return 0; +} + +static int mcp795_read_time(struct device *dev, struct rtc_time *tim) +{ +	int ret; +	u8 data[7]; + +	ret = mcp795_rtcc_read(dev, 0x01, data, sizeof(data)); + +	if (ret) +		return ret; + +	tim->tm_sec		= ((data[0] & 0x70) >> 4) * 10 + (data[0] & 0x0f); +	tim->tm_min		= ((data[1] & 0x70) >> 4) * 10 + (data[1] & 0x0f); +	tim->tm_hour	= ((data[2] & 0x30) >> 4) * 10 + (data[2] & 0x0f); +	tim->tm_mday	= ((data[4] & 0x30) >> 4) * 10 + (data[4] & 0x0f); +	tim->tm_mon		= ((data[5] & 0x10) >> 4) * 10 + (data[5] & 0x0f); +	tim->tm_year	= ((data[6] & 0xf0) >> 4) * 10 + (data[6] & 0x0f) + 100; /* Assume we are in 20xx */ + +	dev_dbg(dev, "Read from mcp795: %04d-%02d-%02d %02d:%02d:%02d\n", +				tim->tm_year + 1900, tim->tm_mon, tim->tm_mday, +				tim->tm_hour, tim->tm_min, tim->tm_sec); + +	return rtc_valid_tm(tim); +} + +static struct rtc_class_ops mcp795_rtc_ops = { +		.read_time = mcp795_read_time, +		.set_time = mcp795_set_time +}; + +static int mcp795_probe(struct spi_device *spi) +{ +	struct rtc_device *rtc; +	int ret; + +	spi->mode = SPI_MODE_0; +	spi->bits_per_word = 8; +	ret = spi_setup(spi); +	if (ret) { +		dev_err(&spi->dev, "Unable to setup SPI\n"); +		return ret; +	} + +	/* Start the oscillator */ +	mcp795_rtcc_set_bits(&spi->dev, 0x01, MCP795_ST_BIT, MCP795_ST_BIT); +	/* Clear the 12 hour mode flag*/ +	mcp795_rtcc_set_bits(&spi->dev, 0x03, MCP795_24_BIT, 0); + +	rtc = devm_rtc_device_register(&spi->dev, "rtc-mcp795", +								&mcp795_rtc_ops, THIS_MODULE); +	if (IS_ERR(rtc)) +		return PTR_ERR(rtc); + +	spi_set_drvdata(spi, rtc); + +	return 0; +} + +static struct spi_driver mcp795_driver = { +		.driver = { +				.name = "rtc-mcp795", +				.owner = THIS_MODULE, +		}, +		.probe = mcp795_probe, +}; + +module_spi_driver(mcp795_driver); + +MODULE_DESCRIPTION("MCP795 RTC SPI Driver"); +MODULE_AUTHOR("Josef Gajdusek <atx@atx.name>"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("spi:mcp795"); diff --git a/drivers/rtc/rtc-moxart.c b/drivers/rtc/rtc-moxart.c index c29dee0946e..c3184623887 100644 --- a/drivers/rtc/rtc-moxart.c +++ b/drivers/rtc/rtc-moxart.c @@ -247,10 +247,8 @@ static int moxart_rtc_probe(struct platform_device *pdev)  	int ret = 0;  	moxart_rtc = devm_kzalloc(&pdev->dev, sizeof(*moxart_rtc), GFP_KERNEL); -	if (!moxart_rtc) { -		dev_err(&pdev->dev, "devm_kzalloc failed\n"); +	if (!moxart_rtc)  		return -ENOMEM; -	}  	moxart_rtc->gpio_data = of_get_named_gpio(pdev->dev.of_node,  						  "gpio-rtc-data", 0); diff --git a/drivers/rtc/rtc-mpc5121.c b/drivers/rtc/rtc-mpc5121.c index 9c8f6090379..dc4f14255cc 100644 --- a/drivers/rtc/rtc-mpc5121.c +++ b/drivers/rtc/rtc-mpc5121.c @@ -14,7 +14,9 @@  #include <linux/module.h>  #include <linux/rtc.h>  #include <linux/of.h> +#include <linux/of_address.h>  #include <linux/of_device.h> +#include <linux/of_irq.h>  #include <linux/of_platform.h>  #include <linux/io.h>  #include <linux/slab.h> diff --git a/drivers/rtc/rtc-mrst.c b/drivers/rtc/rtc-mrst.c index 578baf9d972..e2436d14017 100644 --- a/drivers/rtc/rtc-mrst.c +++ b/drivers/rtc/rtc-mrst.c @@ -38,8 +38,8 @@  #include <asm-generic/rtc.h>  #include <asm/intel_scu_ipc.h> -#include <asm/mrst.h> -#include <asm/mrst-vrtc.h> +#include <asm/intel-mid.h> +#include <asm/intel_mid_vrtc.h>  struct mrst_rtc {  	struct rtc_device	*rtc; @@ -380,7 +380,6 @@ static int vrtc_mrst_do_probe(struct device *dev, struct resource *iomem,  cleanup1:  	rtc_device_unregister(mrst_rtc.rtc);  cleanup0: -	dev_set_drvdata(dev, NULL);  	mrst_rtc.dev = NULL;  	release_mem_region(iomem->start, resource_size(iomem));  	dev_err(dev, "rtc-mrst: unable to initialise\n"); @@ -412,7 +411,6 @@ static void rtc_mrst_do_remove(struct device *dev)  	mrst->iomem = NULL;  	mrst->dev = NULL; -	dev_set_drvdata(dev, NULL);  }  #ifdef	CONFIG_PM diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index d536c5962c9..6aaec2fc7c0 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -222,6 +222,7 @@ static int __init mv_rtc_probe(struct platform_device *pdev)  	struct resource *res;  	struct rtc_plat_data *pdata;  	u32 rtc_time; +	u32 rtc_date;  	int ret = 0;  	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); @@ -257,6 +258,17 @@ static int __init mv_rtc_probe(struct platform_device *pdev)  		}  	} +	/* +	 * A date after January 19th, 2038 does not fit on 32 bits and +	 * will confuse the kernel and userspace. Reset to a sane date +	 * (January 1st, 2013) if we're after 2038. +	 */ +	rtc_date = readl(pdata->ioaddr + RTC_DATE_REG_OFFS); +	if (bcd2bin((rtc_date >> RTC_YEAR_OFFS) & 0xff) >= 38) { +		dev_info(&pdev->dev, "invalid RTC date, resetting to January 1st, 2013\n"); +		writel(0x130101, pdata->ioaddr + RTC_DATE_REG_OFFS); +	} +  	pdata->irq = platform_get_irq(pdev, 0);  	platform_set_drvdata(pdev, pdata); @@ -307,7 +319,7 @@ static int __exit mv_rtc_remove(struct platform_device *pdev)  }  #ifdef CONFIG_OF -static struct of_device_id rtc_mv_of_match_table[] = { +static const struct of_device_id rtc_mv_of_match_table[] = {  	{ .compatible = "marvell,orion-rtc", },  	{}  }; diff --git a/drivers/rtc/rtc-mxc.c b/drivers/rtc/rtc-mxc.c index 50c57264554..419874fefa4 100644 --- a/drivers/rtc/rtc-mxc.c +++ b/drivers/rtc/rtc-mxc.c @@ -391,11 +391,13 @@ static int mxc_rtc_probe(struct platform_device *pdev)  	pdata->clk = devm_clk_get(&pdev->dev, NULL);  	if (IS_ERR(pdata->clk)) {  		dev_err(&pdev->dev, "unable to get clock!\n"); -		ret = PTR_ERR(pdata->clk); -		goto exit_free_pdata; +		return PTR_ERR(pdata->clk);  	} -	clk_prepare_enable(pdata->clk); +	ret = clk_prepare_enable(pdata->clk); +	if (ret) +		return ret; +  	rate = clk_get_rate(pdata->clk);  	if (rate == 32768) @@ -447,8 +449,6 @@ static int mxc_rtc_probe(struct platform_device *pdev)  exit_put_clk:  	clk_disable_unprepare(pdata->clk); -exit_free_pdata: -  	return ret;  } diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c index 248653c74b8..a53da0958e9 100644 --- a/drivers/rtc/rtc-nuc900.c +++ b/drivers/rtc/rtc-nuc900.c @@ -229,10 +229,9 @@ static int __init nuc900_rtc_probe(struct platform_device *pdev)  	nuc900_rtc = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_rtc),  				GFP_KERNEL); -	if (!nuc900_rtc) { -		dev_err(&pdev->dev, "kzalloc nuc900_rtc failed\n"); +	if (!nuc900_rtc)  		return -ENOMEM; -	} +  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	nuc900_rtc->rtc_reg = devm_ioremap_resource(&pdev->dev, res);  	if (IS_ERR(nuc900_rtc->rtc_reg)) diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index c7d97ee5932..21142e6574a 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -73,43 +73,52 @@  #define OMAP_RTC_IRQWAKEEN		0x7c  /* OMAP_RTC_CTRL_REG bit fields: */ -#define OMAP_RTC_CTRL_SPLIT		(1<<7) -#define OMAP_RTC_CTRL_DISABLE		(1<<6) -#define OMAP_RTC_CTRL_SET_32_COUNTER	(1<<5) -#define OMAP_RTC_CTRL_TEST		(1<<4) -#define OMAP_RTC_CTRL_MODE_12_24	(1<<3) -#define OMAP_RTC_CTRL_AUTO_COMP		(1<<2) -#define OMAP_RTC_CTRL_ROUND_30S		(1<<1) -#define OMAP_RTC_CTRL_STOP		(1<<0) +#define OMAP_RTC_CTRL_SPLIT		BIT(7) +#define OMAP_RTC_CTRL_DISABLE		BIT(6) +#define OMAP_RTC_CTRL_SET_32_COUNTER	BIT(5) +#define OMAP_RTC_CTRL_TEST		BIT(4) +#define OMAP_RTC_CTRL_MODE_12_24	BIT(3) +#define OMAP_RTC_CTRL_AUTO_COMP		BIT(2) +#define OMAP_RTC_CTRL_ROUND_30S		BIT(1) +#define OMAP_RTC_CTRL_STOP		BIT(0)  /* OMAP_RTC_STATUS_REG bit fields: */ -#define OMAP_RTC_STATUS_POWER_UP        (1<<7) -#define OMAP_RTC_STATUS_ALARM           (1<<6) -#define OMAP_RTC_STATUS_1D_EVENT        (1<<5) -#define OMAP_RTC_STATUS_1H_EVENT        (1<<4) -#define OMAP_RTC_STATUS_1M_EVENT        (1<<3) -#define OMAP_RTC_STATUS_1S_EVENT        (1<<2) -#define OMAP_RTC_STATUS_RUN             (1<<1) -#define OMAP_RTC_STATUS_BUSY            (1<<0) +#define OMAP_RTC_STATUS_POWER_UP	BIT(7) +#define OMAP_RTC_STATUS_ALARM		BIT(6) +#define OMAP_RTC_STATUS_1D_EVENT	BIT(5) +#define OMAP_RTC_STATUS_1H_EVENT	BIT(4) +#define OMAP_RTC_STATUS_1M_EVENT	BIT(3) +#define OMAP_RTC_STATUS_1S_EVENT	BIT(2) +#define OMAP_RTC_STATUS_RUN		BIT(1) +#define OMAP_RTC_STATUS_BUSY		BIT(0)  /* OMAP_RTC_INTERRUPTS_REG bit fields: */ -#define OMAP_RTC_INTERRUPTS_IT_ALARM    (1<<3) -#define OMAP_RTC_INTERRUPTS_IT_TIMER    (1<<2) +#define OMAP_RTC_INTERRUPTS_IT_ALARM	BIT(3) +#define OMAP_RTC_INTERRUPTS_IT_TIMER	BIT(2) + +/* OMAP_RTC_OSC_REG bit fields: */ +#define OMAP_RTC_OSC_32KCLK_EN		BIT(6)  /* OMAP_RTC_IRQWAKEEN bit fields: */ -#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN    (1<<1) +#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN	BIT(1)  /* OMAP_RTC_KICKER values */  #define	KICK0_VALUE			0x83e70b13  #define	KICK1_VALUE			0x95a4f1e0 -#define	OMAP_RTC_HAS_KICKER		0x1 +#define	OMAP_RTC_HAS_KICKER		BIT(0)  /*   * Few RTC IP revisions has special WAKE-EN Register to enable Wakeup   * generation for event Alarm.   */ -#define	OMAP_RTC_HAS_IRQWAKEEN		0x2 +#define	OMAP_RTC_HAS_IRQWAKEEN		BIT(1) + +/* + * Some RTC IP revisions (like those in AM335x and DRA7x) need + * the 32KHz clock to be explicitly enabled. + */ +#define OMAP_RTC_HAS_32KCLK_EN		BIT(2)  static void __iomem	*rtc_base; @@ -162,17 +171,28 @@ static irqreturn_t rtc_irq(int irq, void *rtc)  static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)  { -	u8 reg; +	u8 reg, irqwake_reg = 0; +	struct platform_device *pdev = to_platform_device(dev); +	const struct platform_device_id *id_entry = +					platform_get_device_id(pdev);  	local_irq_disable();  	rtc_wait_not_busy();  	reg = rtc_read(OMAP_RTC_INTERRUPTS_REG); -	if (enabled) +	if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) +		irqwake_reg = rtc_read(OMAP_RTC_IRQWAKEEN); + +	if (enabled) {  		reg |= OMAP_RTC_INTERRUPTS_IT_ALARM; -	else +		irqwake_reg |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; +	} else {  		reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM; +		irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; +	}  	rtc_wait_not_busy();  	rtc_write(reg, OMAP_RTC_INTERRUPTS_REG); +	if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) +		rtc_write(irqwake_reg, OMAP_RTC_IRQWAKEEN);  	local_irq_enable();  	return 0; @@ -272,7 +292,10 @@ static int omap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)  static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)  { -	u8 reg; +	u8 reg, irqwake_reg = 0; +	struct platform_device *pdev = to_platform_device(dev); +	const struct platform_device_id *id_entry = +					platform_get_device_id(pdev);  	if (tm2bcd(&alm->time) < 0)  		return -EINVAL; @@ -288,11 +311,19 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)  	rtc_write(alm->time.tm_sec, OMAP_RTC_ALARM_SECONDS_REG);  	reg = rtc_read(OMAP_RTC_INTERRUPTS_REG); -	if (alm->enabled) +	if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) +		irqwake_reg = rtc_read(OMAP_RTC_IRQWAKEEN); + +	if (alm->enabled) {  		reg |= OMAP_RTC_INTERRUPTS_IT_ALARM; -	else +		irqwake_reg |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; +	} else {  		reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM; +		irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; +	}  	rtc_write(reg, OMAP_RTC_INTERRUPTS_REG); +	if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) +		rtc_write(irqwake_reg, OMAP_RTC_IRQWAKEEN);  	local_irq_enable(); @@ -319,7 +350,8 @@ static struct platform_device_id omap_rtc_devtype[] = {  	},  	[OMAP_RTC_DATA_AM3352_IDX] = {  		.name	= "am3352-rtc", -		.driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN, +		.driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN | +			       OMAP_RTC_HAS_32KCLK_EN,  	},  	[OMAP_RTC_DATA_DA830_IDX] = {  		.name	= "da830-rtc", @@ -352,6 +384,12 @@ static int __init omap_rtc_probe(struct platform_device *pdev)  	if (of_id)  		pdev->id_entry = of_id->data; +	id_entry = platform_get_device_id(pdev); +	if (!id_entry) { +		dev_err(&pdev->dev, "no matching device entry\n"); +		return -ENODEV; +	} +  	omap_rtc_timer = platform_get_irq(pdev, 0);  	if (omap_rtc_timer <= 0) {  		pr_debug("%s: no update irq?\n", pdev->name); @@ -373,8 +411,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev)  	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)) { +	if (id_entry->driver_data & OMAP_RTC_HAS_KICKER) {  		rtc_writel(KICK0_VALUE, OMAP_RTC_KICK0_REG);  		rtc_writel(KICK1_VALUE, OMAP_RTC_KICK1_REG);  	} @@ -393,6 +430,10 @@ static int __init omap_rtc_probe(struct platform_device *pdev)  	 */  	rtc_write(0, OMAP_RTC_INTERRUPTS_REG); +	/* enable RTC functional clock */ +	if (id_entry->driver_data & OMAP_RTC_HAS_32KCLK_EN) +		rtc_writel(OMAP_RTC_OSC_32KCLK_EN, OMAP_RTC_OSC_REG); +  	/* clear old status */  	reg = rtc_read(OMAP_RTC_STATUS_REG);  	if (reg & (u8) OMAP_RTC_STATUS_POWER_UP) { @@ -452,7 +493,7 @@ static int __init omap_rtc_probe(struct platform_device *pdev)  	return 0;  fail0: -	if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) +	if (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); @@ -469,7 +510,7 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)  	/* leave rtc running, but disable irqs */  	rtc_write(0, OMAP_RTC_INTERRUPTS_REG); -	if (id_entry && (id_entry->driver_data & OMAP_RTC_HAS_KICKER)) +	if (id_entry->driver_data & OMAP_RTC_HAS_KICKER)  		rtc_writel(0, OMAP_RTC_KICK0_REG);  	/* Disable the clock/module */ @@ -484,28 +525,16 @@ static u8 irqstat;  static int omap_rtc_suspend(struct device *dev)  { -	u8 irqwake_stat; -	struct platform_device *pdev = to_platform_device(dev); -	const struct platform_device_id *id_entry = -					platform_get_device_id(pdev); -  	irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG);  	/* FIXME the RTC alarm is not currently acting as a wakeup event  	 * source on some platforms, and in fact this enable() call is just  	 * saving a flag that's never used...  	 */ -	if (device_may_wakeup(dev)) { +	if (device_may_wakeup(dev))  		enable_irq_wake(omap_rtc_alarm); - -		if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) { -			irqwake_stat = rtc_read(OMAP_RTC_IRQWAKEEN); -			irqwake_stat |= OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; -			rtc_write(irqwake_stat, OMAP_RTC_IRQWAKEEN); -		} -	} else { +	else  		rtc_write(0, OMAP_RTC_INTERRUPTS_REG); -	}  	/* Disable the clock/module */  	pm_runtime_put_sync(dev); @@ -515,25 +544,14 @@ static int omap_rtc_suspend(struct device *dev)  static int omap_rtc_resume(struct device *dev)  { -	u8 irqwake_stat; -	struct platform_device *pdev = to_platform_device(dev); -	const struct platform_device_id *id_entry = -				platform_get_device_id(pdev); -  	/* Enable the clock/module so that we can access the registers */  	pm_runtime_get_sync(dev); -	if (device_may_wakeup(dev)) { +	if (device_may_wakeup(dev))  		disable_irq_wake(omap_rtc_alarm); - -		if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN) { -			irqwake_stat = rtc_read(OMAP_RTC_IRQWAKEEN); -			irqwake_stat &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN; -			rtc_write(irqwake_stat, OMAP_RTC_IRQWAKEEN); -		} -	} else { +	else  		rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG); -	} +  	return 0;  }  #endif @@ -553,7 +571,7 @@ static struct platform_driver omap_rtc_driver = {  		.name	= DRIVER_NAME,  		.owner	= THIS_MODULE,  		.pm	= &omap_rtc_pm_ops, -		.of_match_table = of_match_ptr(omap_rtc_of_match), +		.of_match_table = omap_rtc_of_match,  	},  	.id_table	= omap_rtc_devtype,  }; diff --git a/drivers/rtc/rtc-palmas.c b/drivers/rtc/rtc-palmas.c index fffb7d3449d..4dfe2d793fa 100644 --- a/drivers/rtc/rtc-palmas.c +++ b/drivers/rtc/rtc-palmas.c @@ -348,12 +348,11 @@ static int palmas_rtc_resume(struct device *dev)  }  #endif -static const struct dev_pm_ops palmas_rtc_pm_ops = { -	SET_SYSTEM_SLEEP_PM_OPS(palmas_rtc_suspend, palmas_rtc_resume) -}; +static SIMPLE_DEV_PM_OPS(palmas_rtc_pm_ops, palmas_rtc_suspend, +			 palmas_rtc_resume);  #ifdef CONFIG_OF -static struct of_device_id of_palmas_rtc_match[] = { +static const struct of_device_id of_palmas_rtc_match[] = {  	{ .compatible = "ti,palmas-rtc"},  	{ },  }; diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c index 1725b5090e3..d1953bb244c 100644 --- a/drivers/rtc/rtc-pcf2123.c +++ b/drivers/rtc/rtc-pcf2123.c @@ -327,7 +327,7 @@ kfree_exit:  static int pcf2123_remove(struct spi_device *spi)  { -	struct pcf2123_plat_data *pdata = spi->dev.platform_data; +	struct pcf2123_plat_data *pdata = dev_get_platdata(&spi->dev);  	int i;  	if (pdata) { diff --git a/drivers/rtc/rtc-pcf2127.c b/drivers/rtc/rtc-pcf2127.c index 1ee514a3972..9bd842e9774 100644 --- a/drivers/rtc/rtc-pcf2127.c +++ b/drivers/rtc/rtc-pcf2127.c @@ -197,10 +197,7 @@ static int pcf2127_probe(struct i2c_client *client,  				pcf2127_driver.driver.name,  				&pcf2127_rtc_ops, THIS_MODULE); -	if (IS_ERR(pcf2127->rtc)) -		return PTR_ERR(pcf2127->rtc); - -	return 0; +	return PTR_ERR_OR_ZERO(pcf2127->rtc);  }  static const struct i2c_device_id pcf2127_id[] = { diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c index 5c8f8226c84..4cdb64be061 100644 --- a/drivers/rtc/rtc-pcf8523.c +++ b/drivers/rtc/rtc-pcf8523.c @@ -206,7 +206,7 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm)  	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_mon = bcd2bin(regs[5] & 0x1f) - 1;  	tm->tm_year = bcd2bin(regs[6]) + 100;  	return rtc_valid_tm(tm); @@ -229,7 +229,7 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm)  	regs[3] = bin2bcd(tm->tm_hour);  	regs[4] = bin2bcd(tm->tm_mday);  	regs[5] = tm->tm_wday; -	regs[6] = bin2bcd(tm->tm_mon); +	regs[6] = bin2bcd(tm->tm_mon + 1);  	regs[7] = bin2bcd(tm->tm_year - 100);  	msg.addr = client->addr; diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c index 22bacdbf913..f85a1a93e66 100644 --- a/drivers/rtc/rtc-pl030.c +++ b/drivers/rtc/rtc-pl030.c @@ -106,7 +106,7 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id)  	if (ret)  		goto err_req; -	rtc = kmalloc(sizeof(*rtc), GFP_KERNEL); +	rtc = devm_kzalloc(&dev->dev, sizeof(*rtc), GFP_KERNEL);  	if (!rtc) {  		ret = -ENOMEM;  		goto err_rtc; @@ -115,7 +115,7 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id)  	rtc->base = ioremap(dev->res.start, resource_size(&dev->res));  	if (!rtc->base) {  		ret = -ENOMEM; -		goto err_map; +		goto err_rtc;  	}  	__raw_writel(0, rtc->base + RTC_CR); @@ -141,8 +141,6 @@ static int pl030_probe(struct amba_device *dev, const struct amba_id *id)  	free_irq(dev->irq[0], rtc);   err_irq:  	iounmap(rtc->base); - err_map: -	kfree(rtc);   err_rtc:  	amba_release_regions(dev);   err_req: @@ -153,14 +151,11 @@ static int pl030_remove(struct amba_device *dev)  {  	struct pl030_rtc *rtc = amba_get_drvdata(dev); -	amba_set_drvdata(dev, NULL); -  	writel(0, rtc->base + RTC_CR);  	free_irq(dev->irq[0], rtc);  	rtc_device_unregister(rtc->rtc);  	iounmap(rtc->base); -	kfree(rtc);  	amba_release_regions(dev);  	return 0; diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 0f0609b1aa2..99181fff88f 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -305,7 +305,6 @@ static int pl031_remove(struct amba_device *adev)  {  	struct pl031_local *ldata = dev_get_drvdata(&adev->dev); -	amba_set_drvdata(adev, NULL);  	free_irq(adev->irq[0], ldata);  	rtc_device_unregister(ldata->rtc);  	iounmap(ldata->base); @@ -371,6 +370,7 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)  		}  	} +	device_init_wakeup(&adev->dev, 1);  	ldata->rtc = rtc_device_register("pl031", &adev->dev, ops,  					THIS_MODULE);  	if (IS_ERR(ldata->rtc)) { @@ -384,15 +384,12 @@ static int pl031_probe(struct amba_device *adev, const struct amba_id *id)  		goto out_no_irq;  	} -	device_init_wakeup(&adev->dev, 1); -  	return 0;  out_no_irq:  	rtc_device_unregister(ldata->rtc);  out_no_rtc:  	iounmap(ldata->base); -	amba_set_drvdata(adev, NULL);  out_no_remap:  	kfree(ldata);  out: diff --git a/drivers/rtc/rtc-pm8xxx.c b/drivers/rtc/rtc-pm8xxx.c index 03f8f75d5af..197699f358c 100644 --- a/drivers/rtc/rtc-pm8xxx.c +++ b/drivers/rtc/rtc-pm8xxx.c @@ -9,18 +9,16 @@   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * GNU General Public License for more details.   */ - +#include <linux/of.h>  #include <linux/module.h>  #include <linux/init.h>  #include <linux/rtc.h> +#include <linux/platform_device.h>  #include <linux/pm.h> +#include <linux/regmap.h>  #include <linux/slab.h>  #include <linux/spinlock.h> -#include <linux/mfd/pm8xxx/core.h> -#include <linux/mfd/pm8xxx/rtc.h> - -  /* RTC Register offsets from RTC CTRL REG */  #define PM8XXX_ALARM_CTRL_OFFSET	0x01  #define PM8XXX_RTC_WRITE_OFFSET		0x02 @@ -37,6 +35,8 @@  /**   * struct pm8xxx_rtc -  rtc driver internal structure   * @rtc:		rtc device for this driver. + * @regmap:		regmap used to access RTC registers + * @allow_set_time:	indicates whether writing to the RTC is allowed   * @rtc_alarm_irq:	rtc alarm irq number.   * @rtc_base:		address of rtc control register.   * @rtc_read_base:	base address of read registers. @@ -48,55 +48,19 @@   */  struct pm8xxx_rtc {  	struct rtc_device *rtc; +	struct regmap *regmap; +	bool allow_set_time;  	int rtc_alarm_irq;  	int rtc_base;  	int rtc_read_base;  	int rtc_write_base;  	int alarm_rw_base; -	u8  ctrl_reg; +	u8 ctrl_reg;  	struct device *rtc_dev;  	spinlock_t ctrl_reg_lock;  };  /* - * The RTC registers need to be read/written one byte at a time. This is a - * hardware limitation. - */ -static int pm8xxx_read_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val, -		int base, int count) -{ -	int i, rc; -	struct device *parent = rtc_dd->rtc_dev->parent; - -	for (i = 0; i < count; i++) { -		rc = pm8xxx_readb(parent, base + i, &rtc_val[i]); -		if (rc < 0) { -			dev_err(rtc_dd->rtc_dev, "PMIC read failed\n"); -			return rc; -		} -	} - -	return 0; -} - -static int pm8xxx_write_wrapper(struct pm8xxx_rtc *rtc_dd, u8 *rtc_val, -		int base, int count) -{ -	int i, rc; -	struct device *parent = rtc_dd->rtc_dev->parent; - -	for (i = 0; i < count; i++) { -		rc = pm8xxx_writeb(parent, base + i, rtc_val[i]); -		if (rc < 0) { -			dev_err(rtc_dd->rtc_dev, "PMIC write failed\n"); -			return rc; -		} -	} - -	return 0; -} - -/*   * Steps to write the RTC registers.   * 1. Disable alarm if enabled.   * 2. Write 0x00 to LSB. @@ -107,9 +71,12 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)  {  	int rc, i;  	unsigned long secs, irq_flags; -	u8 value[NUM_8_BIT_RTC_REGS], reg = 0, alarm_enabled = 0, ctrl_reg; +	u8 value[NUM_8_BIT_RTC_REGS], alarm_enabled = 0, ctrl_reg;  	struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); +	if (!rtc_dd->allow_set_time) +		return -EACCES; +  	rtc_tm_to_time(tm, &secs);  	for (i = 0; i < NUM_8_BIT_RTC_REGS; i++) { @@ -125,47 +92,43 @@ static int pm8xxx_rtc_set_time(struct device *dev, struct rtc_time *tm)  	if (ctrl_reg & PM8xxx_RTC_ALARM_ENABLE) {  		alarm_enabled = 1;  		ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE; -		rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, -				1); -		if (rc < 0) { -			dev_err(dev, "Write to RTC control register " -								"failed\n"); +		rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg); +		if (rc) { +			dev_err(dev, "Write to RTC control register failed\n");  			goto rtc_rw_fail;  		}  		rtc_dd->ctrl_reg = ctrl_reg; -	} else +	} else {  		spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); +	}  	/* Write 0 to Byte[0] */ -	reg = 0; -	rc = pm8xxx_write_wrapper(rtc_dd, ®, rtc_dd->rtc_write_base, 1); -	if (rc < 0) { +	rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_write_base, 0); +	if (rc) {  		dev_err(dev, "Write to RTC write data register failed\n");  		goto rtc_rw_fail;  	}  	/* Write Byte[1], Byte[2], Byte[3] */ -	rc = pm8xxx_write_wrapper(rtc_dd, value + 1, -					rtc_dd->rtc_write_base + 1, 3); -	if (rc < 0) { +	rc = regmap_bulk_write(rtc_dd->regmap, rtc_dd->rtc_write_base + 1, +			       &value[1], sizeof(value) - 1); +	if (rc) {  		dev_err(dev, "Write to RTC write data register failed\n");  		goto rtc_rw_fail;  	}  	/* Write Byte[0] */ -	rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->rtc_write_base, 1); -	if (rc < 0) { +	rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_write_base, value[0]); +	if (rc) {  		dev_err(dev, "Write to RTC write data register failed\n");  		goto rtc_rw_fail;  	}  	if (alarm_enabled) {  		ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE; -		rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, -									1); -		if (rc < 0) { -			dev_err(dev, "Write to RTC control register " -								"failed\n"); +		rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg); +		if (rc) { +			dev_err(dev, "Write to RTC control register failed\n");  			goto rtc_rw_fail;  		}  		rtc_dd->ctrl_reg = ctrl_reg; @@ -181,13 +144,14 @@ rtc_rw_fail:  static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)  {  	int rc; -	u8 value[NUM_8_BIT_RTC_REGS], reg; +	u8 value[NUM_8_BIT_RTC_REGS];  	unsigned long secs; +	unsigned int reg;  	struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); -	rc = pm8xxx_read_wrapper(rtc_dd, value, rtc_dd->rtc_read_base, -							NUM_8_BIT_RTC_REGS); -	if (rc < 0) { +	rc = regmap_bulk_read(rtc_dd->regmap, rtc_dd->rtc_read_base, +			      value, sizeof(value)); +	if (rc) {  		dev_err(dev, "RTC read data register failed\n");  		return rc;  	} @@ -196,16 +160,16 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)  	 * Read the LSB again and check if there has been a carry over.  	 * If there is, redo the read operation.  	 */ -	rc = pm8xxx_read_wrapper(rtc_dd, ®, rtc_dd->rtc_read_base, 1); +	rc = regmap_read(rtc_dd->regmap, rtc_dd->rtc_read_base, ®);  	if (rc < 0) {  		dev_err(dev, "RTC read data register failed\n");  		return rc;  	}  	if (unlikely(reg < value[0])) { -		rc = pm8xxx_read_wrapper(rtc_dd, value, -				rtc_dd->rtc_read_base, NUM_8_BIT_RTC_REGS); -		if (rc < 0) { +		rc = regmap_bulk_read(rtc_dd->regmap, rtc_dd->rtc_read_base, +				      value, sizeof(value)); +		if (rc) {  			dev_err(dev, "RTC read data register failed\n");  			return rc;  		} @@ -222,8 +186,8 @@ static int pm8xxx_rtc_read_time(struct device *dev, struct rtc_time *tm)  	}  	dev_dbg(dev, "secs = %lu, h:m:s == %d:%d:%d, d/m/y = %d/%d/%d\n", -				secs, tm->tm_hour, tm->tm_min, tm->tm_sec, -				tm->tm_mday, tm->tm_mon, tm->tm_year); +		secs, tm->tm_hour, tm->tm_min, tm->tm_sec, +		tm->tm_mday, tm->tm_mon, tm->tm_year);  	return 0;  } @@ -244,19 +208,22 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)  	spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); -	rc = pm8xxx_write_wrapper(rtc_dd, value, rtc_dd->alarm_rw_base, -							NUM_8_BIT_RTC_REGS); -	if (rc < 0) { +	rc = regmap_bulk_write(rtc_dd->regmap, rtc_dd->alarm_rw_base, value, +			       sizeof(value)); +	if (rc) {  		dev_err(dev, "Write to RTC ALARM register failed\n");  		goto rtc_rw_fail;  	}  	ctrl_reg = rtc_dd->ctrl_reg; -	ctrl_reg = alarm->enabled ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) : -					(ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE); -	rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1); -	if (rc < 0) { +	if (alarm->enabled) +		ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE; +	else +		ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE; + +	rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg); +	if (rc) {  		dev_err(dev, "Write to RTC control register failed\n");  		goto rtc_rw_fail;  	} @@ -264,9 +231,9 @@ static int pm8xxx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)  	rtc_dd->ctrl_reg = ctrl_reg;  	dev_dbg(dev, "Alarm Set for h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n", -				alarm->time.tm_hour, alarm->time.tm_min, -				alarm->time.tm_sec, alarm->time.tm_mday, -				alarm->time.tm_mon, alarm->time.tm_year); +		alarm->time.tm_hour, alarm->time.tm_min, +		alarm->time.tm_sec, alarm->time.tm_mday, +		alarm->time.tm_mon, alarm->time.tm_year);  rtc_rw_fail:  	spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);  	return rc; @@ -279,9 +246,9 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)  	unsigned long secs;  	struct pm8xxx_rtc *rtc_dd = dev_get_drvdata(dev); -	rc = pm8xxx_read_wrapper(rtc_dd, value, rtc_dd->alarm_rw_base, -			NUM_8_BIT_RTC_REGS); -	if (rc < 0) { +	rc = regmap_bulk_read(rtc_dd->regmap, rtc_dd->alarm_rw_base, value, +			      sizeof(value)); +	if (rc) {  		dev_err(dev, "RTC alarm time read failed\n");  		return rc;  	} @@ -297,9 +264,9 @@ static int pm8xxx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)  	}  	dev_dbg(dev, "Alarm set for - h:r:s=%d:%d:%d, d/m/y=%d/%d/%d\n", -				alarm->time.tm_hour, alarm->time.tm_min, -				alarm->time.tm_sec, alarm->time.tm_mday, -				alarm->time.tm_mon, alarm->time.tm_year); +		alarm->time.tm_hour, alarm->time.tm_min, +		alarm->time.tm_sec, alarm->time.tm_mday, +		alarm->time.tm_mon, alarm->time.tm_year);  	return 0;  } @@ -312,12 +279,16 @@ static int pm8xxx_rtc_alarm_irq_enable(struct device *dev, unsigned int enable)  	u8 ctrl_reg;  	spin_lock_irqsave(&rtc_dd->ctrl_reg_lock, irq_flags); +  	ctrl_reg = rtc_dd->ctrl_reg; -	ctrl_reg = (enable) ? (ctrl_reg | PM8xxx_RTC_ALARM_ENABLE) : -				(ctrl_reg & ~PM8xxx_RTC_ALARM_ENABLE); -	rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1); -	if (rc < 0) { +	if (enable) +		ctrl_reg |= PM8xxx_RTC_ALARM_ENABLE; +	else +		ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE; + +	rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg); +	if (rc) {  		dev_err(dev, "Write to RTC control register failed\n");  		goto rtc_rw_fail;  	} @@ -329,8 +300,9 @@ rtc_rw_fail:  	return rc;  } -static struct rtc_class_ops pm8xxx_rtc_ops = { +static const struct rtc_class_ops pm8xxx_rtc_ops = {  	.read_time	= pm8xxx_rtc_read_time, +	.set_time	= pm8xxx_rtc_set_time,  	.set_alarm	= pm8xxx_rtc_set_alarm,  	.read_alarm	= pm8xxx_rtc_read_alarm,  	.alarm_irq_enable = pm8xxx_rtc_alarm_irq_enable, @@ -339,7 +311,7 @@ static struct rtc_class_ops pm8xxx_rtc_ops = {  static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id)  {  	struct pm8xxx_rtc *rtc_dd = dev_id; -	u8 ctrl_reg; +	unsigned int ctrl_reg;  	int rc;  	unsigned long irq_flags; @@ -351,11 +323,11 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id)  	ctrl_reg = rtc_dd->ctrl_reg;  	ctrl_reg &= ~PM8xxx_RTC_ALARM_ENABLE; -	rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1); -	if (rc < 0) { +	rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg); +	if (rc) {  		spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags); -		dev_err(rtc_dd->rtc_dev, "Write to RTC control register " -								"failed\n"); +		dev_err(rtc_dd->rtc_dev, +			"Write to RTC control register failed\n");  		goto rtc_alarm_handled;  	} @@ -363,61 +335,71 @@ static irqreturn_t pm8xxx_alarm_trigger(int irq, void *dev_id)  	spin_unlock_irqrestore(&rtc_dd->ctrl_reg_lock, irq_flags);  	/* Clear RTC alarm register */ -	rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base + -						PM8XXX_ALARM_CTRL_OFFSET, 1); -	if (rc < 0) { -		dev_err(rtc_dd->rtc_dev, "RTC Alarm control register read " -								"failed\n"); +	rc = regmap_read(rtc_dd->regmap, +			 rtc_dd->rtc_base + PM8XXX_ALARM_CTRL_OFFSET, +			 &ctrl_reg); +	if (rc) { +		dev_err(rtc_dd->rtc_dev, +			"RTC Alarm control register read failed\n");  		goto rtc_alarm_handled;  	}  	ctrl_reg &= ~PM8xxx_RTC_ALARM_CLEAR; -	rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base + -						PM8XXX_ALARM_CTRL_OFFSET, 1); -	if (rc < 0) -		dev_err(rtc_dd->rtc_dev, "Write to RTC Alarm control register" -								" failed\n"); +	rc = regmap_write(rtc_dd->regmap, +			  rtc_dd->rtc_base + PM8XXX_ALARM_CTRL_OFFSET, +			  ctrl_reg); +	if (rc) +		dev_err(rtc_dd->rtc_dev, +			"Write to RTC Alarm control register failed\n");  rtc_alarm_handled:  	return IRQ_HANDLED;  } +/* + * Hardcoded RTC bases until IORESOURCE_REG mapping is figured out + */ +static const struct of_device_id pm8xxx_id_table[] = { +	{ .compatible = "qcom,pm8921-rtc", .data = (void *) 0x11D }, +	{ .compatible = "qcom,pm8058-rtc", .data = (void *) 0x1E8 }, +	{ }, +}; +MODULE_DEVICE_TABLE(of, pm8xxx_id_table); +  static int pm8xxx_rtc_probe(struct platform_device *pdev)  {  	int rc; -	u8 ctrl_reg; -	bool rtc_write_enable = false; +	unsigned int ctrl_reg;  	struct pm8xxx_rtc *rtc_dd; -	struct resource *rtc_resource; -	const struct pm8xxx_rtc_platform_data *pdata = -						dev_get_platdata(&pdev->dev); +	const struct of_device_id *match; -	if (pdata != NULL) -		rtc_write_enable = pdata->rtc_write_enable; +	match = of_match_node(pm8xxx_id_table, pdev->dev.of_node); +	if (!match) +		return -ENXIO;  	rtc_dd = devm_kzalloc(&pdev->dev, sizeof(*rtc_dd), GFP_KERNEL); -	if (rtc_dd == NULL) { -		dev_err(&pdev->dev, "Unable to allocate memory!\n"); +	if (rtc_dd == NULL)  		return -ENOMEM; -	}  	/* Initialise spinlock to protect RTC control register */  	spin_lock_init(&rtc_dd->ctrl_reg_lock); +	rtc_dd->regmap = dev_get_regmap(pdev->dev.parent, NULL); +	if (!rtc_dd->regmap) { +		dev_err(&pdev->dev, "Parent regmap unavailable.\n"); +		return -ENXIO; +	} +  	rtc_dd->rtc_alarm_irq = platform_get_irq(pdev, 0);  	if (rtc_dd->rtc_alarm_irq < 0) {  		dev_err(&pdev->dev, "Alarm IRQ resource absent!\n");  		return -ENXIO;  	} -	rtc_resource = platform_get_resource_byname(pdev, IORESOURCE_IO, -							"pmic_rtc_base"); -	if (!(rtc_resource && rtc_resource->start)) { -		dev_err(&pdev->dev, "RTC IO resource absent!\n"); -		return -ENXIO; -	} +	rtc_dd->allow_set_time = of_property_read_bool(pdev->dev.of_node, +						      "allow-set-time"); -	rtc_dd->rtc_base = rtc_resource->start; +	rtc_dd->rtc_base = (long) match->data;  	/* Setup RTC register addresses */  	rtc_dd->rtc_write_base = rtc_dd->rtc_base + PM8XXX_RTC_WRITE_OFFSET; @@ -427,64 +409,52 @@ static int pm8xxx_rtc_probe(struct platform_device *pdev)  	rtc_dd->rtc_dev = &pdev->dev;  	/* Check if the RTC is on, else turn it on */ -	rc = pm8xxx_read_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, 1); -	if (rc < 0) { +	rc = regmap_read(rtc_dd->regmap, rtc_dd->rtc_base, &ctrl_reg); +	if (rc) {  		dev_err(&pdev->dev, "RTC control register read failed!\n");  		return rc;  	}  	if (!(ctrl_reg & PM8xxx_RTC_ENABLE)) {  		ctrl_reg |= PM8xxx_RTC_ENABLE; -		rc = pm8xxx_write_wrapper(rtc_dd, &ctrl_reg, rtc_dd->rtc_base, -									1); -		if (rc < 0) { -			dev_err(&pdev->dev, "Write to RTC control register " -								"failed\n"); +		rc = regmap_write(rtc_dd->regmap, rtc_dd->rtc_base, ctrl_reg); +		if (rc) { +			dev_err(&pdev->dev, +				"Write to RTC control register failed\n");  			return rc;  		}  	}  	rtc_dd->ctrl_reg = ctrl_reg; -	if (rtc_write_enable == true) -		pm8xxx_rtc_ops.set_time = pm8xxx_rtc_set_time;  	platform_set_drvdata(pdev, rtc_dd); +	device_init_wakeup(&pdev->dev, 1); +  	/* Register the RTC device */  	rtc_dd->rtc = devm_rtc_device_register(&pdev->dev, "pm8xxx_rtc", -				&pm8xxx_rtc_ops, THIS_MODULE); +					       &pm8xxx_rtc_ops, THIS_MODULE);  	if (IS_ERR(rtc_dd->rtc)) {  		dev_err(&pdev->dev, "%s: RTC registration failed (%ld)\n", -					__func__, PTR_ERR(rtc_dd->rtc)); +			__func__, PTR_ERR(rtc_dd->rtc));  		return PTR_ERR(rtc_dd->rtc);  	}  	/* Request the alarm IRQ */ -	rc = request_any_context_irq(rtc_dd->rtc_alarm_irq, -				 pm8xxx_alarm_trigger, IRQF_TRIGGER_RISING, -				 "pm8xxx_rtc_alarm", rtc_dd); +	rc = devm_request_any_context_irq(&pdev->dev, rtc_dd->rtc_alarm_irq, +					  pm8xxx_alarm_trigger, +					  IRQF_TRIGGER_RISING, +					  "pm8xxx_rtc_alarm", rtc_dd);  	if (rc < 0) {  		dev_err(&pdev->dev, "Request IRQ failed (%d)\n", rc);  		return rc;  	} -	device_init_wakeup(&pdev->dev, 1); -  	dev_dbg(&pdev->dev, "Probe success !!\n");  	return 0;  } -static int pm8xxx_rtc_remove(struct platform_device *pdev) -{ -	struct pm8xxx_rtc *rtc_dd = platform_get_drvdata(pdev); - -	device_init_wakeup(&pdev->dev, 0); -	free_irq(rtc_dd->rtc_alarm_irq, rtc_dd); - -	return 0; -} -  #ifdef CONFIG_PM_SLEEP  static int pm8xxx_rtc_resume(struct device *dev)  { @@ -507,15 +477,17 @@ static int pm8xxx_rtc_suspend(struct device *dev)  }  #endif -static SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, pm8xxx_rtc_suspend, pm8xxx_rtc_resume); +static SIMPLE_DEV_PM_OPS(pm8xxx_rtc_pm_ops, +			 pm8xxx_rtc_suspend, +			 pm8xxx_rtc_resume);  static struct platform_driver pm8xxx_rtc_driver = {  	.probe		= pm8xxx_rtc_probe, -	.remove		= pm8xxx_rtc_remove,  	.driver	= { -		.name	= PM8XXX_RTC_DEV_NAME, -		.owner	= THIS_MODULE, -		.pm	= &pm8xxx_rtc_pm_ops, +		.name		= "rtc-pm8xxx", +		.owner		= THIS_MODULE, +		.pm		= &pm8xxx_rtc_pm_ops, +		.of_match_table	= pm8xxx_id_table,  	},  }; diff --git a/drivers/rtc/rtc-puv3.c b/drivers/rtc/rtc-puv3.c index 402732cfb32..1cff2a21db6 100644 --- a/drivers/rtc/rtc-puv3.c +++ b/drivers/rtc/rtc-puv3.c @@ -53,11 +53,11 @@ static irqreturn_t puv3_rtc_tickirq(int irq, void *id)  }  /* Update control registers */ -static void puv3_rtc_setaie(int to) +static void puv3_rtc_setaie(struct device *dev, int to)  {  	unsigned int tmp; -	pr_debug("%s: aie=%d\n", __func__, to); +	dev_dbg(dev, "%s: aie=%d\n", __func__, to);  	tmp = readl(RTC_RTSR) & ~RTC_RTSR_ALE; @@ -71,7 +71,7 @@ static int puv3_rtc_setpie(struct device *dev, int enabled)  {  	unsigned int tmp; -	pr_debug("%s: pie=%d\n", __func__, enabled); +	dev_dbg(dev, "%s: pie=%d\n", __func__, enabled);  	spin_lock_irq(&puv3_rtc_pie_lock);  	tmp = readl(RTC_RTSR) & ~RTC_RTSR_HZE; @@ -90,7 +90,7 @@ static int puv3_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm)  {  	rtc_time_to_tm(readl(RTC_RCNR), rtc_tm); -	pr_debug("read time %02x.%02x.%02x %02x/%02x/%02x\n", +	dev_dbg(dev, "read time %02x.%02x.%02x %02x/%02x/%02x\n",  		 rtc_tm->tm_year, rtc_tm->tm_mon, rtc_tm->tm_mday,  		 rtc_tm->tm_hour, rtc_tm->tm_min, rtc_tm->tm_sec); @@ -101,7 +101,7 @@ static int puv3_rtc_settime(struct device *dev, struct rtc_time *tm)  {  	unsigned long rtc_count = 0; -	pr_debug("set time %02d.%02d.%02d %02d/%02d/%02d\n", +	dev_dbg(dev, "set time %02d.%02d.%02d %02d/%02d/%02d\n",  		 tm->tm_year, tm->tm_mon, tm->tm_mday,  		 tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -119,7 +119,7 @@ static int puv3_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)  	alrm->enabled = readl(RTC_RTSR) & RTC_RTSR_ALE; -	pr_debug("read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n", +	dev_dbg(dev, "read alarm %02x %02x.%02x.%02x %02x/%02x/%02x\n",  		 alrm->enabled,  		 alm_tm->tm_year, alm_tm->tm_mon, alm_tm->tm_mday,  		 alm_tm->tm_hour, alm_tm->tm_min, alm_tm->tm_sec); @@ -132,7 +132,7 @@ static int puv3_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)  	struct rtc_time *tm = &alrm->time;  	unsigned long rtcalarm_count = 0; -	pr_debug("puv3_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n", +	dev_dbg(dev, "puv3_rtc_setalarm: %d, %02x/%02x/%02x %02x.%02x.%02x\n",  		 alrm->enabled,  		 tm->tm_mday & 0xff, tm->tm_mon & 0xff, tm->tm_year & 0xff,  		 tm->tm_hour & 0xff, tm->tm_min & 0xff, tm->tm_sec); @@ -140,7 +140,7 @@ static int puv3_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)  	rtc_tm_to_time(tm, &rtcalarm_count);  	writel(rtcalarm_count, RTC_RTAR); -	puv3_rtc_setaie(alrm->enabled); +	puv3_rtc_setaie(dev, alrm->enabled);  	if (alrm->enabled)  		enable_irq_wake(puv3_rtc_alarmno); @@ -227,7 +227,7 @@ static int puv3_rtc_remove(struct platform_device *dev)  	rtc_device_unregister(rtc);  	puv3_rtc_setpie(&dev->dev, 0); -	puv3_rtc_setaie(0); +	puv3_rtc_setaie(&dev->dev, 0);  	release_resource(puv3_rtc_mem);  	kfree(puv3_rtc_mem); @@ -241,7 +241,7 @@ static int puv3_rtc_probe(struct platform_device *pdev)  	struct resource *res;  	int ret; -	pr_debug("%s: probe=%p\n", __func__, pdev); +	dev_dbg(&pdev->dev, "%s: probe=%p\n", __func__, pdev);  	/* find the IRQs */  	puv3_rtc_tickno = platform_get_irq(pdev, 1); @@ -256,7 +256,7 @@ static int puv3_rtc_probe(struct platform_device *pdev)  		return -ENOENT;  	} -	pr_debug("PKUnity_rtc: tick irq %d, alarm irq %d\n", +	dev_dbg(&pdev->dev, "PKUnity_rtc: tick irq %d, alarm irq %d\n",  		 puv3_rtc_tickno, puv3_rtc_alarmno);  	/* get the memory region */ diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index a355f2b82bb..4561f375327 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -32,7 +32,6 @@  #include <mach/hardware.h> -#define TIMER_FREQ		CLOCK_TICK_RATE  #define RTC_DEF_DIVIDER		(32768 - 1)  #define RTC_DEF_TRIM		0  #define MAXFREQ_PERIODIC	1000 @@ -390,7 +389,7 @@ static int __exit pxa_rtc_remove(struct platform_device *pdev)  }  #ifdef CONFIG_OF -static struct of_device_id pxa_rtc_dt_ids[] = { +static const struct of_device_id pxa_rtc_dt_ids[] = {  	{ .compatible = "marvell,pxa-rtc" },  	{}  }; diff --git a/drivers/rtc/rtc-rs5c348.c b/drivers/rtc/rtc-rs5c348.c index f7a90a116a3..090a101c1c8 100644 --- a/drivers/rtc/rtc-rs5c348.c +++ b/drivers/rtc/rtc-rs5c348.c @@ -64,7 +64,7 @@ static int  rs5c348_rtc_set_time(struct device *dev, struct rtc_time *tm)  {  	struct spi_device *spi = to_spi_device(dev); -	struct rs5c348_plat_data *pdata = spi->dev.platform_data; +	struct rs5c348_plat_data *pdata = dev_get_platdata(&spi->dev);  	u8 txbuf[5+7], *txp;  	int ret; @@ -100,7 +100,7 @@ static int  rs5c348_rtc_read_time(struct device *dev, struct rtc_time *tm)  {  	struct spi_device *spi = to_spi_device(dev); -	struct rs5c348_plat_data *pdata = spi->dev.platform_data; +	struct rs5c348_plat_data *pdata = dev_get_platdata(&spi->dev);  	u8 txbuf[5], rxbuf[7];  	int ret; diff --git a/drivers/rtc/rtc-rv3029c2.c b/drivers/rtc/rtc-rv3029c2.c index 1a779a67ff6..e9ac5a43be1 100644 --- a/drivers/rtc/rtc-rv3029c2.c +++ b/drivers/rtc/rtc-rv3029c2.c @@ -395,6 +395,12 @@ static int rv3029c2_probe(struct i2c_client *client,  	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_EMUL))  		return -ENODEV; +	rc = rv3029c2_i2c_get_sr(client, buf); +	if (rc < 0) { +		dev_err(&client->dev, "reading status failed\n"); +		return rc; +	} +  	rtc = devm_rtc_device_register(&client->dev, client->name,  					&rv3029c2_rtc_ops, THIS_MODULE); @@ -403,12 +409,6 @@ static int rv3029c2_probe(struct i2c_client *client,  	i2c_set_clientdata(client, rtc); -	rc = rv3029c2_i2c_get_sr(client, buf); -	if (rc < 0) { -		dev_err(&client->dev, "reading status failed\n"); -		return rc; -	} -  	return 0;  } diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c index 8fa23eabcb6..e6298e02b40 100644 --- a/drivers/rtc/rtc-rx8025.c +++ b/drivers/rtc/rtc-rx8025.c @@ -551,7 +551,6 @@ static int rx8025_probe(struct i2c_client *client,  	rx8025 = devm_kzalloc(&client->dev, sizeof(*rx8025), GFP_KERNEL);  	if (!rx8025) { -		dev_err(&adapter->dev, "failed to alloc memory\n");  		err = -ENOMEM;  		goto errout;  	} diff --git a/drivers/rtc/rtc-rx8581.c b/drivers/rtc/rtc-rx8581.c index 00b0eb7fe16..de8d9c42778 100644 --- a/drivers/rtc/rtc-rx8581.c +++ b/drivers/rtc/rtc-rx8581.c @@ -52,8 +52,45 @@  #define RX8581_CTRL_STOP	0x02 /* STOP bit */  #define RX8581_CTRL_RESET	0x01 /* RESET bit */ +struct rx8581 { +	struct i2c_client	*client; +	struct rtc_device	*rtc; +	s32 (*read_block_data)(const struct i2c_client *client, u8 command, +				u8 length, u8 *values); +	s32 (*write_block_data)(const struct i2c_client *client, u8 command, +				u8 length, const u8 *values); +}; +  static struct i2c_driver rx8581_driver; +static int rx8581_read_block_data(const struct i2c_client *client, u8 command, +					u8 length, u8 *values) +{ +	s32 i, data; + +	for (i = 0; i < length; i++) { +		data = i2c_smbus_read_byte_data(client, command + i); +		if (data < 0) +			return data; +		values[i] = data; +	} +	return i; +} + +static int rx8581_write_block_data(const struct i2c_client *client, u8 command, +					u8 length, const u8 *values) +{ +	s32 i, ret; + +	for (i = 0; i < length; i++) { +		ret = i2c_smbus_write_byte_data(client, command + i, +						values[i]); +		if (ret < 0) +			return ret; +	} +	return length; +} +  /*   * In the routines that deal directly with the rx8581 hardware, we use   * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch. @@ -62,6 +99,7 @@ static int rx8581_get_datetime(struct i2c_client *client, struct rtc_time *tm)  {  	unsigned char date[7];  	int data, err; +	struct rx8581 *rx8581 = i2c_get_clientdata(client);  	/* First we ensure that the "update flag" is not set, we read the  	 * time and date then re-read the "update flag". If the update flag @@ -80,14 +118,13 @@ static int rx8581_get_datetime(struct i2c_client *client, struct rtc_time *tm)  			err = i2c_smbus_write_byte_data(client,  				RX8581_REG_FLAG, (data & ~RX8581_FLAG_UF));  			if (err != 0) { -				dev_err(&client->dev, "Unable to write device " -					"flags\n"); +				dev_err(&client->dev, "Unable to write device flags\n");  				return -EIO;  			}  		}  		/* Now read time and date */ -		err = i2c_smbus_read_i2c_block_data(client, RX8581_REG_SC, +		err = rx8581->read_block_data(client, RX8581_REG_SC,  			7, date);  		if (err < 0) {  			dev_err(&client->dev, "Unable to read date\n"); @@ -140,6 +177,7 @@ static int rx8581_set_datetime(struct i2c_client *client, struct rtc_time *tm)  {  	int data, err;  	unsigned char buf[7]; +	struct rx8581 *rx8581 = i2c_get_clientdata(client);  	dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "  		"mday=%d, mon=%d, year=%d, wday=%d\n", @@ -176,7 +214,7 @@ static int rx8581_set_datetime(struct i2c_client *client, struct rtc_time *tm)  	}  	/* write register's data */ -	err = i2c_smbus_write_i2c_block_data(client, RX8581_REG_SC, 7, buf); +	err = rx8581->write_block_data(client, RX8581_REG_SC, 7, buf);  	if (err < 0) {  		dev_err(&client->dev, "Unable to write to date registers\n");  		return -EIO; @@ -231,22 +269,39 @@ static const struct rtc_class_ops rx8581_rtc_ops = {  static int rx8581_probe(struct i2c_client *client,  			const struct i2c_device_id *id)  { -	struct rtc_device *rtc; +	struct rx8581	  *rx8581;  	dev_dbg(&client->dev, "%s\n", __func__); -	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) -		return -ENODEV; +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA) +		&& !i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) +		return -EIO; -	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); +	rx8581 = devm_kzalloc(&client->dev, sizeof(struct rx8581), GFP_KERNEL); +	if (!rx8581) +		return -ENOMEM; -	rtc = devm_rtc_device_register(&client->dev, rx8581_driver.driver.name, -					&rx8581_rtc_ops, THIS_MODULE); +	i2c_set_clientdata(client, rx8581); +	rx8581->client = client; -	if (IS_ERR(rtc)) -		return PTR_ERR(rtc); +	if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) { +		rx8581->read_block_data = i2c_smbus_read_i2c_block_data; +		rx8581->write_block_data = i2c_smbus_write_i2c_block_data; +	} else { +		rx8581->read_block_data = rx8581_read_block_data; +		rx8581->write_block_data = rx8581_write_block_data; +	} -	i2c_set_clientdata(client, rtc); +	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); + +	rx8581->rtc = devm_rtc_device_register(&client->dev, +		rx8581_driver.driver.name, &rx8581_rtc_ops, THIS_MODULE); + +	if (IS_ERR(rx8581->rtc)) { +		dev_err(&client->dev, +			"unable to register the class device\n"); +		return PTR_ERR(rx8581->rtc); +	}  	return 0;  } diff --git a/drivers/rtc/rtc-s3c.c b/drivers/rtc/rtc-s3c.c index 7afd373b959..4958a363b2c 100644 --- a/drivers/rtc/rtc-s3c.c +++ b/drivers/rtc/rtc-s3c.c @@ -48,8 +48,8 @@ struct s3c_rtc_drv_data {  static struct clk *rtc_clk;  static void __iomem *s3c_rtc_base; -static int s3c_rtc_alarmno = NO_IRQ; -static int s3c_rtc_tickno  = NO_IRQ; +static int s3c_rtc_alarmno; +static int s3c_rtc_tickno;  static enum s3c_cpu_type s3c_rtc_cpu_type;  static DEFINE_SPINLOCK(s3c_rtc_pie_lock); @@ -580,10 +580,12 @@ static int s3c_rtc_suspend(struct device *dev)  	clk_enable(rtc_clk);  	/* save TICNT for anyone using periodic interrupts */ -	ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);  	if (s3c_rtc_cpu_type == TYPE_S3C64XX) {  		ticnt_en_save = readw(s3c_rtc_base + S3C2410_RTCCON);  		ticnt_en_save &= S3C64XX_RTCCON_TICEN; +		ticnt_save = readl(s3c_rtc_base + S3C2410_TICNT); +	} else { +		ticnt_save = readb(s3c_rtc_base + S3C2410_TICNT);  	}  	s3c_rtc_enable(pdev, 0); @@ -605,10 +607,15 @@ static int s3c_rtc_resume(struct device *dev)  	clk_enable(rtc_clk);  	s3c_rtc_enable(pdev, 1); -	writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT); -	if (s3c_rtc_cpu_type == TYPE_S3C64XX && ticnt_en_save) { -		tmp = readw(s3c_rtc_base + S3C2410_RTCCON); -		writew(tmp | ticnt_en_save, s3c_rtc_base + S3C2410_RTCCON); +	if (s3c_rtc_cpu_type == TYPE_S3C64XX) { +		writel(ticnt_save, s3c_rtc_base + S3C2410_TICNT); +		if (ticnt_en_save) { +			tmp = readw(s3c_rtc_base + S3C2410_RTCCON); +			writew(tmp | ticnt_en_save, +					s3c_rtc_base + S3C2410_RTCCON); +		} +	} else { +		writeb(ticnt_save, s3c_rtc_base + S3C2410_TICNT);  	}  	if (device_may_wakeup(dev) && wake_en) { diff --git a/drivers/rtc/rtc-s5m.c b/drivers/rtc/rtc-s5m.c new file mode 100644 index 00000000000..8f06250a038 --- /dev/null +++ b/drivers/rtc/rtc-s5m.c @@ -0,0 +1,848 @@ +/* + * Copyright (c) 2013-2014 Samsung Electronics Co., Ltd + *	http://www.samsung.com + * + *  Copyright (C) 2013 Google, Inc + * + *  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. + * + *  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. + */ + +#include <linux/module.h> +#include <linux/i2c.h> +#include <linux/bcd.h> +#include <linux/regmap.h> +#include <linux/rtc.h> +#include <linux/platform_device.h> +#include <linux/mfd/samsung/core.h> +#include <linux/mfd/samsung/irq.h> +#include <linux/mfd/samsung/rtc.h> +#include <linux/mfd/samsung/s2mps14.h> + +/* + * Maximum number of retries for checking changes in UDR field + * of S5M_RTC_UDR_CON register (to limit possible endless loop). + * + * After writing to RTC registers (setting time or alarm) read the UDR field + * in S5M_RTC_UDR_CON register. UDR is auto-cleared when data have + * been transferred. + */ +#define UDR_READ_RETRY_CNT	5 + +/* Registers used by the driver which are different between chipsets. */ +struct s5m_rtc_reg_config { +	/* Number of registers used for setting time/alarm0/alarm1 */ +	unsigned int regs_count; +	/* First register for time, seconds */ +	unsigned int time; +	/* RTC control register */ +	unsigned int ctrl; +	/* First register for alarm 0, seconds */ +	unsigned int alarm0; +	/* First register for alarm 1, seconds */ +	unsigned int alarm1; +	/* SMPL/WTSR register */ +	unsigned int smpl_wtsr; +	/* +	 * Register for update flag (UDR). Typically setting UDR field to 1 +	 * will enable update of time or alarm register. Then it will be +	 * auto-cleared after successful update. +	 */ +	unsigned int rtc_udr_update; +	/* Mask for UDR field in 'rtc_udr_update' register */ +	unsigned int rtc_udr_mask; +}; + +/* Register map for S5M8763 and S5M8767 */ +static const struct s5m_rtc_reg_config s5m_rtc_regs = { +	.regs_count		= 8, +	.time			= S5M_RTC_SEC, +	.ctrl			= S5M_ALARM1_CONF, +	.alarm0			= S5M_ALARM0_SEC, +	.alarm1			= S5M_ALARM1_SEC, +	.smpl_wtsr		= S5M_WTSR_SMPL_CNTL, +	.rtc_udr_update		= S5M_RTC_UDR_CON, +	.rtc_udr_mask		= S5M_RTC_UDR_MASK, +}; + +/* + * Register map for S2MPS14. + * It may be also suitable for S2MPS11 but this was not tested. + */ +static const struct s5m_rtc_reg_config s2mps_rtc_regs = { +	.regs_count		= 7, +	.time			= S2MPS_RTC_SEC, +	.ctrl			= S2MPS_RTC_CTRL, +	.alarm0			= S2MPS_ALARM0_SEC, +	.alarm1			= S2MPS_ALARM1_SEC, +	.smpl_wtsr		= S2MPS_WTSR_SMPL_CNTL, +	.rtc_udr_update		= S2MPS_RTC_UDR_CON, +	.rtc_udr_mask		= S2MPS_RTC_WUDR_MASK, +}; + +struct s5m_rtc_info { +	struct device *dev; +	struct i2c_client *i2c; +	struct sec_pmic_dev *s5m87xx; +	struct regmap *regmap; +	struct rtc_device *rtc_dev; +	int irq; +	int device_type; +	int rtc_24hr_mode; +	bool wtsr_smpl; +	const struct s5m_rtc_reg_config	*regs; +}; + +static const struct regmap_config s5m_rtc_regmap_config = { +	.reg_bits = 8, +	.val_bits = 8, + +	.max_register = S5M_RTC_REG_MAX, +}; + +static const struct regmap_config s2mps14_rtc_regmap_config = { +	.reg_bits = 8, +	.val_bits = 8, + +	.max_register = S2MPS_RTC_REG_MAX, +}; + +static void s5m8767_data_to_tm(u8 *data, struct rtc_time *tm, +			       int rtc_24hr_mode) +{ +	tm->tm_sec = data[RTC_SEC] & 0x7f; +	tm->tm_min = data[RTC_MIN] & 0x7f; +	if (rtc_24hr_mode) { +		tm->tm_hour = data[RTC_HOUR] & 0x1f; +	} else { +		tm->tm_hour = data[RTC_HOUR] & 0x0f; +		if (data[RTC_HOUR] & HOUR_PM_MASK) +			tm->tm_hour += 12; +	} + +	tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0x7f); +	tm->tm_mday = data[RTC_DATE] & 0x1f; +	tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1; +	tm->tm_year = (data[RTC_YEAR1] & 0x7f) + 100; +	tm->tm_yday = 0; +	tm->tm_isdst = 0; +} + +static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data) +{ +	data[RTC_SEC] = tm->tm_sec; +	data[RTC_MIN] = tm->tm_min; + +	if (tm->tm_hour >= 12) +		data[RTC_HOUR] = tm->tm_hour | HOUR_PM_MASK; +	else +		data[RTC_HOUR] = tm->tm_hour & ~HOUR_PM_MASK; + +	data[RTC_WEEKDAY] = 1 << tm->tm_wday; +	data[RTC_DATE] = tm->tm_mday; +	data[RTC_MONTH] = tm->tm_mon + 1; +	data[RTC_YEAR1] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0; + +	if (tm->tm_year < 100) { +		pr_err("s5m8767 RTC cannot handle the year %d.\n", +		       1900 + tm->tm_year); +		return -EINVAL; +	} else { +		return 0; +	} +} + +/* + * Read RTC_UDR_CON register and wait till UDR field is cleared. + * This indicates that time/alarm update ended. + */ +static inline int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info) +{ +	int ret, retry = UDR_READ_RETRY_CNT; +	unsigned int data; + +	do { +		ret = regmap_read(info->regmap, info->regs->rtc_udr_update, +				&data); +	} while (--retry && (data & info->regs->rtc_udr_mask) && !ret); + +	if (!retry) +		dev_err(info->dev, "waiting for UDR update, reached max number of retries\n"); + +	return ret; +} + +static inline int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info, +		struct rtc_wkalrm *alarm) +{ +	int ret; +	unsigned int val; + +	switch (info->device_type) { +	case S5M8767X: +	case S5M8763X: +		ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val); +		val &= S5M_ALARM0_STATUS; +		break; +	case S2MPS14X: +		ret = regmap_read(info->s5m87xx->regmap_pmic, S2MPS14_REG_ST2, +				&val); +		val &= S2MPS_ALARM0_STATUS; +		break; +	default: +		return -EINVAL; +	} +	if (ret < 0) +		return ret; + +	if (val) +		alarm->pending = 1; +	else +		alarm->pending = 0; + +	return 0; +} + +static inline int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info) +{ +	int ret; +	unsigned int data; + +	ret = regmap_read(info->regmap, info->regs->rtc_udr_update, &data); +	if (ret < 0) { +		dev_err(info->dev, "failed to read update reg(%d)\n", ret); +		return ret; +	} + +	data |= info->regs->rtc_udr_mask; +	if (info->device_type == S5M8763X || info->device_type == S5M8767X) +		data |= S5M_RTC_TIME_EN_MASK; + +	ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data); +	if (ret < 0) { +		dev_err(info->dev, "failed to write update reg(%d)\n", ret); +		return ret; +	} + +	ret = s5m8767_wait_for_udr_update(info); + +	return ret; +} + +static inline int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info) +{ +	int ret; +	unsigned int data; + +	ret = regmap_read(info->regmap, info->regs->rtc_udr_update, &data); +	if (ret < 0) { +		dev_err(info->dev, "%s: fail to read update reg(%d)\n", +			__func__, ret); +		return ret; +	} + +	data |= info->regs->rtc_udr_mask; +	switch (info->device_type) { +	case S5M8763X: +	case S5M8767X: +		data &= ~S5M_RTC_TIME_EN_MASK; +		break; +	case S2MPS14X: +		data |= S2MPS_RTC_RUDR_MASK; +		break; +	default: +		return -EINVAL; +	} + +	ret = regmap_write(info->regmap, info->regs->rtc_udr_update, data); +	if (ret < 0) { +		dev_err(info->dev, "%s: fail to write update reg(%d)\n", +			__func__, ret); +		return ret; +	} + +	ret = s5m8767_wait_for_udr_update(info); + +	return ret; +} + +static void s5m8763_data_to_tm(u8 *data, struct rtc_time *tm) +{ +	tm->tm_sec = bcd2bin(data[RTC_SEC]); +	tm->tm_min = bcd2bin(data[RTC_MIN]); + +	if (data[RTC_HOUR] & HOUR_12) { +		tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x1f); +		if (data[RTC_HOUR] & HOUR_PM) +			tm->tm_hour += 12; +	} else { +		tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f); +	} + +	tm->tm_wday = data[RTC_WEEKDAY] & 0x07; +	tm->tm_mday = bcd2bin(data[RTC_DATE]); +	tm->tm_mon = bcd2bin(data[RTC_MONTH]); +	tm->tm_year = bcd2bin(data[RTC_YEAR1]) + bcd2bin(data[RTC_YEAR2]) * 100; +	tm->tm_year -= 1900; +} + +static void s5m8763_tm_to_data(struct rtc_time *tm, u8 *data) +{ +	data[RTC_SEC] = bin2bcd(tm->tm_sec); +	data[RTC_MIN] = bin2bcd(tm->tm_min); +	data[RTC_HOUR] = bin2bcd(tm->tm_hour); +	data[RTC_WEEKDAY] = tm->tm_wday; +	data[RTC_DATE] = bin2bcd(tm->tm_mday); +	data[RTC_MONTH] = bin2bcd(tm->tm_mon); +	data[RTC_YEAR1] = bin2bcd(tm->tm_year % 100); +	data[RTC_YEAR2] = bin2bcd((tm->tm_year + 1900) / 100); +} + +static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ +	struct s5m_rtc_info *info = dev_get_drvdata(dev); +	u8 data[info->regs->regs_count]; +	int ret; + +	if (info->device_type == S2MPS14X) { +		ret = regmap_update_bits(info->regmap, +				info->regs->rtc_udr_update, +				S2MPS_RTC_RUDR_MASK, S2MPS_RTC_RUDR_MASK); +		if (ret) { +			dev_err(dev, +				"Failed to prepare registers for time reading: %d\n", +				ret); +			return ret; +		} +	} +	ret = regmap_bulk_read(info->regmap, info->regs->time, data, +			info->regs->regs_count); +	if (ret < 0) +		return ret; + +	switch (info->device_type) { +	case S5M8763X: +		s5m8763_data_to_tm(data, tm); +		break; + +	case S5M8767X: +	case S2MPS14X: +		s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode); +		break; + +	default: +		return -EINVAL; +	} + +	dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, +		1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, +		tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); + +	return rtc_valid_tm(tm); +} + +static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ +	struct s5m_rtc_info *info = dev_get_drvdata(dev); +	u8 data[info->regs->regs_count]; +	int ret = 0; + +	switch (info->device_type) { +	case S5M8763X: +		s5m8763_tm_to_data(tm, data); +		break; +	case S5M8767X: +	case S2MPS14X: +		ret = s5m8767_tm_to_data(tm, data); +		break; +	default: +		return -EINVAL; +	} + +	if (ret < 0) +		return ret; + +	dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, +		1900 + tm->tm_year, 1 + tm->tm_mon, tm->tm_mday, +		tm->tm_hour, tm->tm_min, tm->tm_sec, tm->tm_wday); + +	ret = regmap_raw_write(info->regmap, info->regs->time, data, +			info->regs->regs_count); +	if (ret < 0) +		return ret; + +	ret = s5m8767_rtc_set_time_reg(info); + +	return ret; +} + +static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	struct s5m_rtc_info *info = dev_get_drvdata(dev); +	u8 data[info->regs->regs_count]; +	unsigned int val; +	int ret, i; + +	ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, +			info->regs->regs_count); +	if (ret < 0) +		return ret; + +	switch (info->device_type) { +	case S5M8763X: +		s5m8763_data_to_tm(data, &alrm->time); +		ret = regmap_read(info->regmap, S5M_ALARM0_CONF, &val); +		if (ret < 0) +			return ret; + +		alrm->enabled = !!val; +		break; + +	case S5M8767X: +	case S2MPS14X: +		s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode); +		alrm->enabled = 0; +		for (i = 0; i < info->regs->regs_count; i++) { +			if (data[i] & ALARM_ENABLE_MASK) { +				alrm->enabled = 1; +				break; +			} +		} +		break; + +	default: +		return -EINVAL; +	} + +	dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, +		1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon, +		alrm->time.tm_mday, alrm->time.tm_hour, +		alrm->time.tm_min, alrm->time.tm_sec, +		alrm->time.tm_wday); + +	ret = s5m_check_peding_alarm_interrupt(info, alrm); + +	return 0; +} + +static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info) +{ +	u8 data[info->regs->regs_count]; +	int ret, i; +	struct rtc_time tm; + +	ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, +			info->regs->regs_count); +	if (ret < 0) +		return ret; + +	s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode); +	dev_dbg(info->dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, +		1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, +		tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday); + +	switch (info->device_type) { +	case S5M8763X: +		ret = regmap_write(info->regmap, S5M_ALARM0_CONF, 0); +		break; + +	case S5M8767X: +	case S2MPS14X: +		for (i = 0; i < info->regs->regs_count; i++) +			data[i] &= ~ALARM_ENABLE_MASK; + +		ret = regmap_raw_write(info->regmap, info->regs->alarm0, data, +				info->regs->regs_count); +		if (ret < 0) +			return ret; + +		ret = s5m8767_rtc_set_alarm_reg(info); + +		break; + +	default: +		return -EINVAL; +	} + +	return ret; +} + +static int s5m_rtc_start_alarm(struct s5m_rtc_info *info) +{ +	int ret; +	u8 data[info->regs->regs_count]; +	u8 alarm0_conf; +	struct rtc_time tm; + +	ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data, +			info->regs->regs_count); +	if (ret < 0) +		return ret; + +	s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode); +	dev_dbg(info->dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, +		1900 + tm.tm_year, 1 + tm.tm_mon, tm.tm_mday, +		tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday); + +	switch (info->device_type) { +	case S5M8763X: +		alarm0_conf = 0x77; +		ret = regmap_write(info->regmap, S5M_ALARM0_CONF, alarm0_conf); +		break; + +	case S5M8767X: +	case S2MPS14X: +		data[RTC_SEC] |= ALARM_ENABLE_MASK; +		data[RTC_MIN] |= ALARM_ENABLE_MASK; +		data[RTC_HOUR] |= ALARM_ENABLE_MASK; +		data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK; +		if (data[RTC_DATE] & 0x1f) +			data[RTC_DATE] |= ALARM_ENABLE_MASK; +		if (data[RTC_MONTH] & 0xf) +			data[RTC_MONTH] |= ALARM_ENABLE_MASK; +		if (data[RTC_YEAR1] & 0x7f) +			data[RTC_YEAR1] |= ALARM_ENABLE_MASK; + +		ret = regmap_raw_write(info->regmap, info->regs->alarm0, data, +				info->regs->regs_count); +		if (ret < 0) +			return ret; +		ret = s5m8767_rtc_set_alarm_reg(info); + +		break; + +	default: +		return -EINVAL; +	} + +	return ret; +} + +static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	struct s5m_rtc_info *info = dev_get_drvdata(dev); +	u8 data[info->regs->regs_count]; +	int ret; + +	switch (info->device_type) { +	case S5M8763X: +		s5m8763_tm_to_data(&alrm->time, data); +		break; + +	case S5M8767X: +	case S2MPS14X: +		s5m8767_tm_to_data(&alrm->time, data); +		break; + +	default: +		return -EINVAL; +	} + +	dev_dbg(dev, "%s: %d/%d/%d %d:%d:%d(%d)\n", __func__, +		1900 + alrm->time.tm_year, 1 + alrm->time.tm_mon, +		alrm->time.tm_mday, alrm->time.tm_hour, alrm->time.tm_min, +		alrm->time.tm_sec, alrm->time.tm_wday); + +	ret = s5m_rtc_stop_alarm(info); +	if (ret < 0) +		return ret; + +	ret = regmap_raw_write(info->regmap, info->regs->alarm0, data, +			info->regs->regs_count); +	if (ret < 0) +		return ret; + +	ret = s5m8767_rtc_set_alarm_reg(info); +	if (ret < 0) +		return ret; + +	if (alrm->enabled) +		ret = s5m_rtc_start_alarm(info); + +	return ret; +} + +static int s5m_rtc_alarm_irq_enable(struct device *dev, +				    unsigned int enabled) +{ +	struct s5m_rtc_info *info = dev_get_drvdata(dev); + +	if (enabled) +		return s5m_rtc_start_alarm(info); +	else +		return s5m_rtc_stop_alarm(info); +} + +static irqreturn_t s5m_rtc_alarm_irq(int irq, void *data) +{ +	struct s5m_rtc_info *info = data; + +	rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF); + +	return IRQ_HANDLED; +} + +static const struct rtc_class_ops s5m_rtc_ops = { +	.read_time = s5m_rtc_read_time, +	.set_time = s5m_rtc_set_time, +	.read_alarm = s5m_rtc_read_alarm, +	.set_alarm = s5m_rtc_set_alarm, +	.alarm_irq_enable = s5m_rtc_alarm_irq_enable, +}; + +static void s5m_rtc_enable_wtsr(struct s5m_rtc_info *info, bool enable) +{ +	int ret; +	ret = regmap_update_bits(info->regmap, info->regs->smpl_wtsr, +				 WTSR_ENABLE_MASK, +				 enable ? WTSR_ENABLE_MASK : 0); +	if (ret < 0) +		dev_err(info->dev, "%s: fail to update WTSR reg(%d)\n", +			__func__, ret); +} + +static void s5m_rtc_enable_smpl(struct s5m_rtc_info *info, bool enable) +{ +	int ret; +	ret = regmap_update_bits(info->regmap, info->regs->smpl_wtsr, +				 SMPL_ENABLE_MASK, +				 enable ? SMPL_ENABLE_MASK : 0); +	if (ret < 0) +		dev_err(info->dev, "%s: fail to update SMPL reg(%d)\n", +			__func__, ret); +} + +static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info) +{ +	u8 data[2]; +	int ret; + +	switch (info->device_type) { +	case S5M8763X: +	case S5M8767X: +		/* UDR update time. Default of 7.32 ms is too long. */ +		ret = regmap_update_bits(info->regmap, S5M_RTC_UDR_CON, +				S5M_RTC_UDR_T_MASK, S5M_RTC_UDR_T_450_US); +		if (ret < 0) +			dev_err(info->dev, "%s: fail to change UDR time: %d\n", +					__func__, ret); + +		/* Set RTC control register : Binary mode, 24hour mode */ +		data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); +		data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); + +		ret = regmap_raw_write(info->regmap, S5M_ALARM0_CONF, data, 2); +		break; + +	case S2MPS14X: +		data[0] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT); +		ret = regmap_write(info->regmap, info->regs->ctrl, data[0]); +		break; + +	default: +		return -EINVAL; +	} + +	info->rtc_24hr_mode = 1; +	if (ret < 0) { +		dev_err(info->dev, "%s: fail to write controlm reg(%d)\n", +			__func__, ret); +		return ret; +	} + +	return ret; +} + +static int s5m_rtc_probe(struct platform_device *pdev) +{ +	struct sec_pmic_dev *s5m87xx = dev_get_drvdata(pdev->dev.parent); +	struct sec_platform_data *pdata = s5m87xx->pdata; +	struct s5m_rtc_info *info; +	const struct regmap_config *regmap_cfg; +	int ret, alarm_irq; + +	if (!pdata) { +		dev_err(pdev->dev.parent, "Platform data not supplied\n"); +		return -ENODEV; +	} + +	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL); +	if (!info) +		return -ENOMEM; + +	switch (pdata->device_type) { +	case S2MPS14X: +		regmap_cfg = &s2mps14_rtc_regmap_config; +		info->regs = &s2mps_rtc_regs; +		alarm_irq = S2MPS14_IRQ_RTCA0; +		break; +	case S5M8763X: +		regmap_cfg = &s5m_rtc_regmap_config; +		info->regs = &s5m_rtc_regs; +		alarm_irq = S5M8763_IRQ_ALARM0; +		break; +	case S5M8767X: +		regmap_cfg = &s5m_rtc_regmap_config; +		info->regs = &s5m_rtc_regs; +		alarm_irq = S5M8767_IRQ_RTCA1; +		break; +	default: +		dev_err(&pdev->dev, "Device type is not supported by RTC driver\n"); +		return -ENODEV; +	} + +	info->i2c = i2c_new_dummy(s5m87xx->i2c->adapter, RTC_I2C_ADDR); +	if (!info->i2c) { +		dev_err(&pdev->dev, "Failed to allocate I2C for RTC\n"); +		return -ENODEV; +	} + +	info->regmap = devm_regmap_init_i2c(info->i2c, regmap_cfg); +	if (IS_ERR(info->regmap)) { +		ret = PTR_ERR(info->regmap); +		dev_err(&pdev->dev, "Failed to allocate RTC register map: %d\n", +				ret); +		goto err; +	} + +	info->dev = &pdev->dev; +	info->s5m87xx = s5m87xx; +	info->device_type = s5m87xx->device_type; +	info->wtsr_smpl = s5m87xx->wtsr_smpl; + +	info->irq = regmap_irq_get_virq(s5m87xx->irq_data, alarm_irq); +	if (info->irq <= 0) { +		ret = -EINVAL; +		dev_err(&pdev->dev, "Failed to get virtual IRQ %d\n", +				alarm_irq); +		goto err; +	} + +	platform_set_drvdata(pdev, info); + +	ret = s5m8767_rtc_init_reg(info); + +	if (info->wtsr_smpl) { +		s5m_rtc_enable_wtsr(info, true); +		s5m_rtc_enable_smpl(info, true); +	} + +	device_init_wakeup(&pdev->dev, 1); + +	info->rtc_dev = devm_rtc_device_register(&pdev->dev, "s5m-rtc", +						 &s5m_rtc_ops, THIS_MODULE); + +	if (IS_ERR(info->rtc_dev)) { +		ret = PTR_ERR(info->rtc_dev); +		goto err; +	} + +	ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL, +					s5m_rtc_alarm_irq, 0, "rtc-alarm0", +					info); +	if (ret < 0) { +		dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d\n", +			info->irq, ret); +		goto err; +	} + +	return 0; + +err: +	i2c_unregister_device(info->i2c); + +	return ret; +} + +static void s5m_rtc_shutdown(struct platform_device *pdev) +{ +	struct s5m_rtc_info *info = platform_get_drvdata(pdev); +	int i; +	unsigned int val = 0; +	if (info->wtsr_smpl) { +		for (i = 0; i < 3; i++) { +			s5m_rtc_enable_wtsr(info, false); +			regmap_read(info->regmap, info->regs->smpl_wtsr, &val); +			pr_debug("%s: WTSR_SMPL reg(0x%02x)\n", __func__, val); +			if (val & WTSR_ENABLE_MASK) +				pr_emerg("%s: fail to disable WTSR\n", +					 __func__); +			else { +				pr_info("%s: success to disable WTSR\n", +					__func__); +				break; +			} +		} +	} +	/* Disable SMPL when power off */ +	s5m_rtc_enable_smpl(info, false); +} + +static int s5m_rtc_remove(struct platform_device *pdev) +{ +	struct s5m_rtc_info *info = platform_get_drvdata(pdev); + +	/* Perform also all shutdown steps when removing */ +	s5m_rtc_shutdown(pdev); +	i2c_unregister_device(info->i2c); + +	return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int s5m_rtc_resume(struct device *dev) +{ +	struct s5m_rtc_info *info = dev_get_drvdata(dev); +	int ret = 0; + +	if (device_may_wakeup(dev)) +		ret = disable_irq_wake(info->irq); + +	return ret; +} + +static int s5m_rtc_suspend(struct device *dev) +{ +	struct s5m_rtc_info *info = dev_get_drvdata(dev); +	int ret = 0; + +	if (device_may_wakeup(dev)) +		ret = enable_irq_wake(info->irq); + +	return ret; +} +#endif /* CONFIG_PM_SLEEP */ + +static SIMPLE_DEV_PM_OPS(s5m_rtc_pm_ops, s5m_rtc_suspend, s5m_rtc_resume); + +static const struct platform_device_id s5m_rtc_id[] = { +	{ "s5m-rtc",		S5M8767X }, +	{ "s2mps14-rtc",	S2MPS14X }, +}; + +static struct platform_driver s5m_rtc_driver = { +	.driver		= { +		.name	= "s5m-rtc", +		.owner	= THIS_MODULE, +		.pm	= &s5m_rtc_pm_ops, +	}, +	.probe		= s5m_rtc_probe, +	.remove		= s5m_rtc_remove, +	.shutdown	= s5m_rtc_shutdown, +	.id_table	= s5m_rtc_id, +}; + +module_platform_driver(s5m_rtc_driver); + +/* Module information */ +MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>"); +MODULE_DESCRIPTION("Samsung S5M/S2MPS14 RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:s5m-rtc"); diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 0f7adeb1944..b6e1ca08c2c 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -338,7 +338,7 @@ static SIMPLE_DEV_PM_OPS(sa1100_rtc_pm_ops, sa1100_rtc_suspend,  			sa1100_rtc_resume);  #ifdef CONFIG_OF -static struct of_device_id sa1100_rtc_dt_ids[] = { +static const struct of_device_id sa1100_rtc_dt_ids[] = {  	{ .compatible = "mrvl,sa1100-rtc", },  	{ .compatible = "mrvl,mmp-rtc", },  	{} diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index 6d87e26355a..d0d2b047658 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -649,8 +649,9 @@ static int __init sh_rtc_probe(struct platform_device *pdev)  	clk_enable(rtc->clk);  	rtc->capabilities = RTC_DEF_CAPABILITIES; -	if (pdev->dev.platform_data) { -		struct sh_rtc_platform_info *pinfo = pdev->dev.platform_data; +	if (dev_get_platdata(&pdev->dev)) { +		struct sh_rtc_platform_info *pinfo = +			dev_get_platdata(&pdev->dev);  		/*  		 * Some CPUs have special capabilities in addition to the diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c index 63460cf80f1..76e38007ba9 100644 --- a/drivers/rtc/rtc-sirfsoc.c +++ b/drivers/rtc/rtc-sirfsoc.c @@ -59,7 +59,7 @@ static int sirfsoc_rtc_read_alarm(struct device *dev,  	unsigned long rtc_alarm, rtc_count;  	struct sirfsoc_rtc_drv *rtcdrv; -	rtcdrv = (struct sirfsoc_rtc_drv *)dev_get_drvdata(dev); +	rtcdrv = dev_get_drvdata(dev);  	local_irq_disable(); @@ -94,7 +94,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev,  {  	unsigned long rtc_status_reg, rtc_alarm;  	struct sirfsoc_rtc_drv *rtcdrv; -	rtcdrv = (struct sirfsoc_rtc_drv *)dev_get_drvdata(dev); +	rtcdrv = dev_get_drvdata(dev);  	if (alrm->enabled) {  		rtc_tm_to_time(&(alrm->time), &rtc_alarm); @@ -157,7 +157,7 @@ static int sirfsoc_rtc_read_time(struct device *dev,  {  	unsigned long tmp_rtc = 0;  	struct sirfsoc_rtc_drv *rtcdrv; -	rtcdrv = (struct sirfsoc_rtc_drv *)dev_get_drvdata(dev); +	rtcdrv = dev_get_drvdata(dev);  	/*  	 * This patch is taken from WinCE - Need to validate this for  	 * correctness. To work around sirfsoc RTC counter double sync logic @@ -178,7 +178,7 @@ static int sirfsoc_rtc_set_time(struct device *dev,  {  	unsigned long rtc_time;  	struct sirfsoc_rtc_drv *rtcdrv; -	rtcdrv = (struct sirfsoc_rtc_drv *)dev_get_drvdata(dev); +	rtcdrv = dev_get_drvdata(dev);  	rtc_tm_to_time(tm, &rtc_time); @@ -264,17 +264,13 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev)  	rtcdrv = devm_kzalloc(&pdev->dev,  		sizeof(struct sirfsoc_rtc_drv), GFP_KERNEL); -	if (rtcdrv == NULL) { -		dev_err(&pdev->dev, -			"%s: can't alloc mem for drv struct\n", -			pdev->name); +	if (rtcdrv == NULL)  		return -ENOMEM; -	}  	err = of_property_read_u32(np, "reg", &rtcdrv->rtc_base);  	if (err) {  		dev_err(&pdev->dev, "unable to find base address of rtc node in dtb\n"); -		goto error; +		return err;  	}  	platform_set_drvdata(pdev, rtcdrv); @@ -290,7 +286,7 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev)  	rtc_div = ((32768 / RTC_HZ) / 2) - 1;  	sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV); -	rtcdrv->rtc = rtc_device_register(pdev->name, &(pdev->dev), +	rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,  			&sirfsoc_rtc_ops, THIS_MODULE);  	if (IS_ERR(rtcdrv->rtc)) {  		err = PTR_ERR(rtcdrv->rtc); @@ -322,61 +318,42 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev)  			rtcdrv);  	if (err) {  		dev_err(&pdev->dev, "Unable to register for the SiRF SOC RTC IRQ\n"); -		goto error; +		return err;  	}  	return 0; - -error: -	if (rtcdrv->rtc) -		rtc_device_unregister(rtcdrv->rtc); - -	return err;  }  static int sirfsoc_rtc_remove(struct platform_device *pdev)  { -	struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev); -  	device_init_wakeup(&pdev->dev, 0); -	rtc_device_unregister(rtcdrv->rtc);  	return 0;  } -#ifdef CONFIG_PM - +#ifdef CONFIG_PM_SLEEP  static int sirfsoc_rtc_suspend(struct device *dev)  { -	struct platform_device *pdev = to_platform_device(dev); -	struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev); +	struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev);  	rtcdrv->overflow_rtc =  		sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE);  	rtcdrv->saved_counter =  		sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);  	rtcdrv->saved_overflow_rtc = rtcdrv->overflow_rtc; -	if (device_may_wakeup(&pdev->dev) && !enable_irq_wake(rtcdrv->irq)) +	if (device_may_wakeup(dev) && !enable_irq_wake(rtcdrv->irq))  		rtcdrv->irq_wake = 1;  	return 0;  } -static int sirfsoc_rtc_freeze(struct device *dev) -{ -	sirfsoc_rtc_suspend(dev); - -	return 0; -} - -static int sirfsoc_rtc_thaw(struct device *dev) +static int sirfsoc_rtc_resume(struct device *dev)  {  	u32 tmp; -	struct sirfsoc_rtc_drv *rtcdrv; -	rtcdrv = (struct sirfsoc_rtc_drv *)dev_get_drvdata(dev); +	struct sirfsoc_rtc_drv *rtcdrv = dev_get_drvdata(dev);  	/* -	 * if resume from snapshot and the rtc power is losed, +	 * if resume from snapshot and the rtc power is lost,  	 * restroe the rtc settings  	 */  	if (SIRFSOC_RTC_CLK != sirfsoc_rtc_iobrg_readl( @@ -416,58 +393,24 @@ static int sirfsoc_rtc_thaw(struct device *dev)  	sirfsoc_rtc_iobrg_writel(rtcdrv->overflow_rtc,  			rtcdrv->rtc_base + RTC_SW_VALUE); -	return 0; -} - -static int sirfsoc_rtc_resume(struct device *dev) -{ -	struct platform_device *pdev = to_platform_device(dev); -	struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev); -	sirfsoc_rtc_thaw(dev); -	if (device_may_wakeup(&pdev->dev) && rtcdrv->irq_wake) { +	if (device_may_wakeup(dev) && rtcdrv->irq_wake) {  		disable_irq_wake(rtcdrv->irq);  		rtcdrv->irq_wake = 0;  	}  	return 0;  } - -static int sirfsoc_rtc_restore(struct device *dev) -{ -	struct platform_device *pdev = to_platform_device(dev); -	struct sirfsoc_rtc_drv *rtcdrv = platform_get_drvdata(pdev); - -	if (device_may_wakeup(&pdev->dev) && rtcdrv->irq_wake) { -		disable_irq_wake(rtcdrv->irq); -		rtcdrv->irq_wake = 0; -	} -	return 0; -} - -#else -#define sirfsoc_rtc_suspend	NULL -#define sirfsoc_rtc_resume	NULL -#define sirfsoc_rtc_freeze	NULL -#define sirfsoc_rtc_thaw	NULL -#define sirfsoc_rtc_restore	NULL  #endif -static const struct dev_pm_ops sirfsoc_rtc_pm_ops = { -	.suspend = sirfsoc_rtc_suspend, -	.resume = sirfsoc_rtc_resume, -	.freeze = sirfsoc_rtc_freeze, -	.thaw = sirfsoc_rtc_thaw, -	.restore = sirfsoc_rtc_restore, -}; +static SIMPLE_DEV_PM_OPS(sirfsoc_rtc_pm_ops, +		sirfsoc_rtc_suspend, sirfsoc_rtc_resume);  static struct platform_driver sirfsoc_rtc_driver = {  	.driver = {  		.name = "sirfsoc-rtc",  		.owner = THIS_MODULE, -#ifdef CONFIG_PM  		.pm = &sirfsoc_rtc_pm_ops, -#endif -		.of_match_table = of_match_ptr(sirfsoc_rtc_of_match), +		.of_match_table = sirfsoc_rtc_of_match,  	},  	.probe = sirfsoc_rtc_probe,  	.remove = sirfsoc_rtc_remove, diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c index 316a342115b..fa384fe2898 100644 --- a/drivers/rtc/rtc-snvs.c +++ b/drivers/rtc/rtc-snvs.c @@ -329,7 +329,7 @@ static struct platform_driver snvs_rtc_driver = {  		.name	= "snvs_rtc",  		.owner	= THIS_MODULE,  		.pm	= &snvs_rtc_pm_ops, -		.of_match_table = of_match_ptr(snvs_dt_ids), +		.of_match_table = snvs_dt_ids,  	},  	.probe		= snvs_rtc_probe,  }; diff --git a/drivers/rtc/rtc-spear.c b/drivers/rtc/rtc-spear.c index c492cf0ab8c..d2cdb9823a1 100644 --- a/drivers/rtc/rtc-spear.c +++ b/drivers/rtc/rtc-spear.c @@ -365,10 +365,8 @@ static int spear_rtc_probe(struct platform_device *pdev)  	}  	config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL); -	if (!config) { -		dev_err(&pdev->dev, "out of memory\n"); +	if (!config)  		return -ENOMEM; -	}  	/* alarm irqs */  	irq = platform_get_irq(pdev, 0); diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c index a176ba61468..35ed49ea1f8 100644 --- a/drivers/rtc/rtc-stk17ta8.c +++ b/drivers/rtc/rtc-stk17ta8.c @@ -214,8 +214,7 @@ static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)  			events |= RTC_UF;  		else  			events |= RTC_AF; -		if (likely(pdata->rtc)) -			rtc_update_irq(pdata->rtc, 1, events); +		rtc_update_irq(pdata->rtc, 1, events);  	}  	spin_unlock(&pdata->lock);  	return events ? IRQ_HANDLED : IRQ_NONE; diff --git a/drivers/rtc/rtc-stmp3xxx.c b/drivers/rtc/rtc-stmp3xxx.c index 26019531db1..ea96492357b 100644 --- a/drivers/rtc/rtc-stmp3xxx.c +++ b/drivers/rtc/rtc-stmp3xxx.c @@ -343,7 +343,7 @@ static struct platform_driver stmp3xxx_rtcdrv = {  		.name	= "stmp3xxx-rtc",  		.owner	= THIS_MODULE,  		.pm	= &stmp3xxx_rtc_pm_ops, -		.of_match_table = of_match_ptr(rtc_dt_ids), +		.of_match_table = rtc_dt_ids,  	},  }; diff --git a/drivers/rtc/rtc-sunxi.c b/drivers/rtc/rtc-sunxi.c new file mode 100644 index 00000000000..b6f21f73d50 --- /dev/null +++ b/drivers/rtc/rtc-sunxi.c @@ -0,0 +1,523 @@ +/* + * An RTC driver for Allwinner A10/A20 + * + * Copyright (c) 2013, Carlo Caione <carlo.caione@gmail.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. + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. + */ + +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_device.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/types.h> + +#define SUNXI_LOSC_CTRL				0x0000 +#define SUNXI_LOSC_CTRL_RTC_HMS_ACC		BIT(8) +#define SUNXI_LOSC_CTRL_RTC_YMD_ACC		BIT(7) + +#define SUNXI_RTC_YMD				0x0004 + +#define SUNXI_RTC_HMS				0x0008 + +#define SUNXI_ALRM_DHMS				0x000c + +#define SUNXI_ALRM_EN				0x0014 +#define SUNXI_ALRM_EN_CNT_EN			BIT(8) + +#define SUNXI_ALRM_IRQ_EN			0x0018 +#define SUNXI_ALRM_IRQ_EN_CNT_IRQ_EN		BIT(0) + +#define SUNXI_ALRM_IRQ_STA			0x001c +#define SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND		BIT(0) + +#define SUNXI_MASK_DH				0x0000001f +#define SUNXI_MASK_SM				0x0000003f +#define SUNXI_MASK_M				0x0000000f +#define SUNXI_MASK_LY				0x00000001 +#define SUNXI_MASK_D				0x00000ffe +#define SUNXI_MASK_M				0x0000000f + +#define SUNXI_GET(x, mask, shift)		(((x) & ((mask) << (shift))) \ +							>> (shift)) + +#define SUNXI_SET(x, mask, shift)		(((x) & (mask)) << (shift)) + +/* + * Get date values + */ +#define SUNXI_DATE_GET_DAY_VALUE(x)		SUNXI_GET(x, SUNXI_MASK_DH, 0) +#define SUNXI_DATE_GET_MON_VALUE(x)		SUNXI_GET(x, SUNXI_MASK_M, 8) +#define SUNXI_DATE_GET_YEAR_VALUE(x, mask)	SUNXI_GET(x, mask, 16) + +/* + * Get time values + */ +#define SUNXI_TIME_GET_SEC_VALUE(x)		SUNXI_GET(x, SUNXI_MASK_SM, 0) +#define SUNXI_TIME_GET_MIN_VALUE(x)		SUNXI_GET(x, SUNXI_MASK_SM, 8) +#define SUNXI_TIME_GET_HOUR_VALUE(x)		SUNXI_GET(x, SUNXI_MASK_DH, 16) + +/* + * Get alarm values + */ +#define SUNXI_ALRM_GET_SEC_VALUE(x)		SUNXI_GET(x, SUNXI_MASK_SM, 0) +#define SUNXI_ALRM_GET_MIN_VALUE(x)		SUNXI_GET(x, SUNXI_MASK_SM, 8) +#define SUNXI_ALRM_GET_HOUR_VALUE(x)		SUNXI_GET(x, SUNXI_MASK_DH, 16) + +/* + * Set date values + */ +#define SUNXI_DATE_SET_DAY_VALUE(x)		SUNXI_DATE_GET_DAY_VALUE(x) +#define SUNXI_DATE_SET_MON_VALUE(x)		SUNXI_SET(x, SUNXI_MASK_M, 8) +#define SUNXI_DATE_SET_YEAR_VALUE(x, mask)	SUNXI_SET(x, mask, 16) +#define SUNXI_LEAP_SET_VALUE(x, shift)		SUNXI_SET(x, SUNXI_MASK_LY, shift) + +/* + * Set time values + */ +#define SUNXI_TIME_SET_SEC_VALUE(x)		SUNXI_TIME_GET_SEC_VALUE(x) +#define SUNXI_TIME_SET_MIN_VALUE(x)		SUNXI_SET(x, SUNXI_MASK_SM, 8) +#define SUNXI_TIME_SET_HOUR_VALUE(x)		SUNXI_SET(x, SUNXI_MASK_DH, 16) + +/* + * Set alarm values + */ +#define SUNXI_ALRM_SET_SEC_VALUE(x)		SUNXI_ALRM_GET_SEC_VALUE(x) +#define SUNXI_ALRM_SET_MIN_VALUE(x)		SUNXI_SET(x, SUNXI_MASK_SM, 8) +#define SUNXI_ALRM_SET_HOUR_VALUE(x)		SUNXI_SET(x, SUNXI_MASK_DH, 16) +#define SUNXI_ALRM_SET_DAY_VALUE(x)		SUNXI_SET(x, SUNXI_MASK_D, 21) + +/* + * Time unit conversions + */ +#define SEC_IN_MIN				60 +#define SEC_IN_HOUR				(60 * SEC_IN_MIN) +#define SEC_IN_DAY				(24 * SEC_IN_HOUR) + +/* + * The year parameter passed to the driver is usually an offset relative to + * the year 1900. This macro is used to convert this offset to another one + * relative to the minimum year allowed by the hardware. + */ +#define SUNXI_YEAR_OFF(x)			((x)->min - 1900) + +/* + * min and max year are arbitrary set considering the limited range of the + * hardware register field + */ +struct sunxi_rtc_data_year { +	unsigned int min;		/* min year allowed */ +	unsigned int max;		/* max year allowed */ +	unsigned int mask;		/* mask for the year field */ +	unsigned char leap_shift;	/* bit shift to get the leap year */ +}; + +static struct sunxi_rtc_data_year data_year_param[] = { +	[0] = { +		.min		= 2010, +		.max		= 2073, +		.mask		= 0x3f, +		.leap_shift	= 22, +	}, +	[1] = { +		.min		= 1970, +		.max		= 2225, +		.mask		= 0xff, +		.leap_shift	= 24, +	}, +}; + +struct sunxi_rtc_dev { +	struct rtc_device *rtc; +	struct device *dev; +	struct sunxi_rtc_data_year *data_year; +	void __iomem *base; +	int irq; +}; + +static irqreturn_t sunxi_rtc_alarmirq(int irq, void *id) +{ +	struct sunxi_rtc_dev *chip = (struct sunxi_rtc_dev *) id; +	u32 val; + +	val = readl(chip->base + SUNXI_ALRM_IRQ_STA); + +	if (val & SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND) { +		val |= SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND; +		writel(val, chip->base + SUNXI_ALRM_IRQ_STA); + +		rtc_update_irq(chip->rtc, 1, RTC_AF | RTC_IRQF); + +		return IRQ_HANDLED; +	} + +	return IRQ_NONE; +} + +static void sunxi_rtc_setaie(int to, struct sunxi_rtc_dev *chip) +{ +	u32 alrm_val = 0; +	u32 alrm_irq_val = 0; + +	if (to) { +		alrm_val = readl(chip->base + SUNXI_ALRM_EN); +		alrm_val |= SUNXI_ALRM_EN_CNT_EN; + +		alrm_irq_val = readl(chip->base + SUNXI_ALRM_IRQ_EN); +		alrm_irq_val |= SUNXI_ALRM_IRQ_EN_CNT_IRQ_EN; +	} else { +		writel(SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND, +				chip->base + SUNXI_ALRM_IRQ_STA); +	} + +	writel(alrm_val, chip->base + SUNXI_ALRM_EN); +	writel(alrm_irq_val, chip->base + SUNXI_ALRM_IRQ_EN); +} + +static int sunxi_rtc_getalarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ +	struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); +	struct rtc_time *alrm_tm = &wkalrm->time; +	u32 alrm; +	u32 alrm_en; +	u32 date; + +	alrm = readl(chip->base + SUNXI_ALRM_DHMS); +	date = readl(chip->base + SUNXI_RTC_YMD); + +	alrm_tm->tm_sec = SUNXI_ALRM_GET_SEC_VALUE(alrm); +	alrm_tm->tm_min = SUNXI_ALRM_GET_MIN_VALUE(alrm); +	alrm_tm->tm_hour = SUNXI_ALRM_GET_HOUR_VALUE(alrm); + +	alrm_tm->tm_mday = SUNXI_DATE_GET_DAY_VALUE(date); +	alrm_tm->tm_mon = SUNXI_DATE_GET_MON_VALUE(date); +	alrm_tm->tm_year = SUNXI_DATE_GET_YEAR_VALUE(date, +			chip->data_year->mask); + +	alrm_tm->tm_mon -= 1; + +	/* +	 * switch from (data_year->min)-relative offset to +	 * a (1900)-relative one +	 */ +	alrm_tm->tm_year += SUNXI_YEAR_OFF(chip->data_year); + +	alrm_en = readl(chip->base + SUNXI_ALRM_IRQ_EN); +	if (alrm_en & SUNXI_ALRM_EN_CNT_EN) +		wkalrm->enabled = 1; + +	return 0; +} + +static int sunxi_rtc_gettime(struct device *dev, struct rtc_time *rtc_tm) +{ +	struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); +	u32 date, time; + +	/* +	 * read again in case it changes +	 */ +	do { +		date = readl(chip->base + SUNXI_RTC_YMD); +		time = readl(chip->base + SUNXI_RTC_HMS); +	} while ((date != readl(chip->base + SUNXI_RTC_YMD)) || +		 (time != readl(chip->base + SUNXI_RTC_HMS))); + +	rtc_tm->tm_sec  = SUNXI_TIME_GET_SEC_VALUE(time); +	rtc_tm->tm_min  = SUNXI_TIME_GET_MIN_VALUE(time); +	rtc_tm->tm_hour = SUNXI_TIME_GET_HOUR_VALUE(time); + +	rtc_tm->tm_mday = SUNXI_DATE_GET_DAY_VALUE(date); +	rtc_tm->tm_mon  = SUNXI_DATE_GET_MON_VALUE(date); +	rtc_tm->tm_year = SUNXI_DATE_GET_YEAR_VALUE(date, +					chip->data_year->mask); + +	rtc_tm->tm_mon  -= 1; + +	/* +	 * switch from (data_year->min)-relative offset to +	 * a (1900)-relative one +	 */ +	rtc_tm->tm_year += SUNXI_YEAR_OFF(chip->data_year); + +	return rtc_valid_tm(rtc_tm); +} + +static int sunxi_rtc_setalarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ +	struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); +	struct rtc_time *alrm_tm = &wkalrm->time; +	struct rtc_time tm_now; +	u32 alrm = 0; +	unsigned long time_now = 0; +	unsigned long time_set = 0; +	unsigned long time_gap = 0; +	unsigned long time_gap_day = 0; +	unsigned long time_gap_hour = 0; +	unsigned long time_gap_min = 0; +	int ret = 0; + +	ret = sunxi_rtc_gettime(dev, &tm_now); +	if (ret < 0) { +		dev_err(dev, "Error in getting time\n"); +		return -EINVAL; +	} + +	rtc_tm_to_time(alrm_tm, &time_set); +	rtc_tm_to_time(&tm_now, &time_now); +	if (time_set <= time_now) { +		dev_err(dev, "Date to set in the past\n"); +		return -EINVAL; +	} + +	time_gap = time_set - time_now; +	time_gap_day = time_gap / SEC_IN_DAY; +	time_gap -= time_gap_day * SEC_IN_DAY; +	time_gap_hour = time_gap / SEC_IN_HOUR; +	time_gap -= time_gap_hour * SEC_IN_HOUR; +	time_gap_min = time_gap / SEC_IN_MIN; +	time_gap -= time_gap_min * SEC_IN_MIN; + +	if (time_gap_day > 255) { +		dev_err(dev, "Day must be in the range 0 - 255\n"); +		return -EINVAL; +	} + +	sunxi_rtc_setaie(0, chip); +	writel(0, chip->base + SUNXI_ALRM_DHMS); +	usleep_range(100, 300); + +	alrm = SUNXI_ALRM_SET_SEC_VALUE(time_gap) | +		SUNXI_ALRM_SET_MIN_VALUE(time_gap_min) | +		SUNXI_ALRM_SET_HOUR_VALUE(time_gap_hour) | +		SUNXI_ALRM_SET_DAY_VALUE(time_gap_day); +	writel(alrm, chip->base + SUNXI_ALRM_DHMS); + +	writel(0, chip->base + SUNXI_ALRM_IRQ_EN); +	writel(SUNXI_ALRM_IRQ_EN_CNT_IRQ_EN, chip->base + SUNXI_ALRM_IRQ_EN); + +	sunxi_rtc_setaie(wkalrm->enabled, chip); + +	return 0; +} + +static int sunxi_rtc_wait(struct sunxi_rtc_dev *chip, int offset, +			  unsigned int mask, unsigned int ms_timeout) +{ +	const unsigned long timeout = jiffies + msecs_to_jiffies(ms_timeout); +	u32 reg; + +	do { +		reg = readl(chip->base + offset); +		reg &= mask; + +		if (reg == mask) +			return 0; + +	} while (time_before(jiffies, timeout)); + +	return -ETIMEDOUT; +} + +static int sunxi_rtc_settime(struct device *dev, struct rtc_time *rtc_tm) +{ +	struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); +	u32 date = 0; +	u32 time = 0; +	int year; + +	/* +	 * the input rtc_tm->tm_year is the offset relative to 1900. We use +	 * the SUNXI_YEAR_OFF macro to rebase it with respect to the min year +	 * allowed by the hardware +	 */ + +	year = rtc_tm->tm_year + 1900; +	if (year < chip->data_year->min || year > chip->data_year->max) { +		dev_err(dev, "rtc only supports year in range %d - %d\n", +				chip->data_year->min, chip->data_year->max); +		return -EINVAL; +	} + +	rtc_tm->tm_year -= SUNXI_YEAR_OFF(chip->data_year); +	rtc_tm->tm_mon += 1; + +	date = SUNXI_DATE_SET_DAY_VALUE(rtc_tm->tm_mday) | +		SUNXI_DATE_SET_MON_VALUE(rtc_tm->tm_mon)  | +		SUNXI_DATE_SET_YEAR_VALUE(rtc_tm->tm_year, +				chip->data_year->mask); + +	if (is_leap_year(year)) +		date |= SUNXI_LEAP_SET_VALUE(1, chip->data_year->leap_shift); + +	time = SUNXI_TIME_SET_SEC_VALUE(rtc_tm->tm_sec)  | +		SUNXI_TIME_SET_MIN_VALUE(rtc_tm->tm_min)  | +		SUNXI_TIME_SET_HOUR_VALUE(rtc_tm->tm_hour); + +	writel(0, chip->base + SUNXI_RTC_HMS); +	writel(0, chip->base + SUNXI_RTC_YMD); + +	writel(time, chip->base + SUNXI_RTC_HMS); + +	/* +	 * After writing the RTC HH-MM-SS register, the +	 * SUNXI_LOSC_CTRL_RTC_HMS_ACC bit is set and it will not +	 * be cleared until the real writing operation is finished +	 */ + +	if (sunxi_rtc_wait(chip, SUNXI_LOSC_CTRL, +				SUNXI_LOSC_CTRL_RTC_HMS_ACC, 50)) { +		dev_err(dev, "Failed to set rtc time.\n"); +		return -1; +	} + +	writel(date, chip->base + SUNXI_RTC_YMD); + +	/* +	 * After writing the RTC YY-MM-DD register, the +	 * SUNXI_LOSC_CTRL_RTC_YMD_ACC bit is set and it will not +	 * be cleared until the real writing operation is finished +	 */ + +	if (sunxi_rtc_wait(chip, SUNXI_LOSC_CTRL, +				SUNXI_LOSC_CTRL_RTC_YMD_ACC, 50)) { +		dev_err(dev, "Failed to set rtc time.\n"); +		return -1; +	} + +	return 0; +} + +static int sunxi_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ +	struct sunxi_rtc_dev *chip = dev_get_drvdata(dev); + +	if (!enabled) +		sunxi_rtc_setaie(enabled, chip); + +	return 0; +} + +static const struct rtc_class_ops sunxi_rtc_ops = { +	.read_time		= sunxi_rtc_gettime, +	.set_time		= sunxi_rtc_settime, +	.read_alarm		= sunxi_rtc_getalarm, +	.set_alarm		= sunxi_rtc_setalarm, +	.alarm_irq_enable	= sunxi_rtc_alarm_irq_enable +}; + +static const struct of_device_id sunxi_rtc_dt_ids[] = { +	{ .compatible = "allwinner,sun4i-a10-rtc", .data = &data_year_param[0] }, +	{ .compatible = "allwinner,sun7i-a20-rtc", .data = &data_year_param[1] }, +	{ /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, sunxi_rtc_dt_ids); + +static int sunxi_rtc_probe(struct platform_device *pdev) +{ +	struct sunxi_rtc_dev *chip; +	struct resource *res; +	const struct of_device_id *of_id; +	int ret; + +	chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); +	if (!chip) +		return -ENOMEM; + +	platform_set_drvdata(pdev, chip); +	chip->dev = &pdev->dev; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	chip->base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(chip->base)) +		return PTR_ERR(chip->base); + +	chip->irq = platform_get_irq(pdev, 0); +	if (chip->irq < 0) { +		dev_err(&pdev->dev, "No IRQ resource\n"); +		return chip->irq; +	} +	ret = devm_request_irq(&pdev->dev, chip->irq, sunxi_rtc_alarmirq, +			0, dev_name(&pdev->dev), chip); +	if (ret) { +		dev_err(&pdev->dev, "Could not request IRQ\n"); +		return ret; +	} + +	of_id = of_match_device(sunxi_rtc_dt_ids, &pdev->dev); +	if (!of_id) { +		dev_err(&pdev->dev, "Unable to setup RTC data\n"); +		return -ENODEV; +	} +	chip->data_year = (struct sunxi_rtc_data_year *) of_id->data; + +	/* clear the alarm count value */ +	writel(0, chip->base + SUNXI_ALRM_DHMS); + +	/* disable alarm, not generate irq pending */ +	writel(0, chip->base + SUNXI_ALRM_EN); + +	/* disable alarm week/cnt irq, unset to cpu */ +	writel(0, chip->base + SUNXI_ALRM_IRQ_EN); + +	/* clear alarm week/cnt irq pending */ +	writel(SUNXI_ALRM_IRQ_STA_CNT_IRQ_PEND, chip->base + +			SUNXI_ALRM_IRQ_STA); + +	chip->rtc = rtc_device_register("rtc-sunxi", &pdev->dev, +			&sunxi_rtc_ops, THIS_MODULE); +	if (IS_ERR(chip->rtc)) { +		dev_err(&pdev->dev, "unable to register device\n"); +		return PTR_ERR(chip->rtc); +	} + +	dev_info(&pdev->dev, "RTC enabled\n"); + +	return 0; +} + +static int sunxi_rtc_remove(struct platform_device *pdev) +{ +	struct sunxi_rtc_dev *chip = platform_get_drvdata(pdev); + +	rtc_device_unregister(chip->rtc); + +	return 0; +} + +static struct platform_driver sunxi_rtc_driver = { +	.probe		= sunxi_rtc_probe, +	.remove		= sunxi_rtc_remove, +	.driver		= { +		.name		= "sunxi-rtc", +		.owner		= THIS_MODULE, +		.of_match_table = sunxi_rtc_dt_ids, +	}, +}; + +module_platform_driver(sunxi_rtc_driver); + +MODULE_DESCRIPTION("sunxi RTC driver"); +MODULE_AUTHOR("Carlo Caione <carlo.caione@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index 7746e65b93f..6599c20bc45 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -104,20 +104,17 @@ static int test_probe(struct platform_device *plat_dev)  	rtc = devm_rtc_device_register(&plat_dev->dev, "test",  				&test_rtc_ops, THIS_MODULE);  	if (IS_ERR(rtc)) { -		err = PTR_ERR(rtc); -		return err; +		return PTR_ERR(rtc);  	}  	err = device_create_file(&plat_dev->dev, &dev_attr_irq);  	if (err) -		goto err; +		dev_err(&plat_dev->dev, "Unable to create sysfs entry: %s\n", +			dev_attr_irq.attr.name);  	platform_set_drvdata(plat_dev, rtc);  	return 0; - -err: -	return err;  }  static int test_remove(struct platform_device *plat_dev) diff --git a/drivers/rtc/rtc-tps65910.c b/drivers/rtc/rtc-tps65910.c index a9caf043b0c..7af00208d63 100644 --- a/drivers/rtc/rtc-tps65910.c +++ b/drivers/rtc/rtc-tps65910.c @@ -22,7 +22,6 @@  #include <linux/rtc.h>  #include <linux/bcd.h>  #include <linux/platform_device.h> -#include <linux/pm_runtime.h>  #include <linux/interrupt.h>  #include <linux/mfd/tps65910.h> diff --git a/drivers/rtc/rtc-twl.c b/drivers/rtc/rtc-twl.c index c2e80d7ca5e..1915464e4cd 100644 --- a/drivers/rtc/rtc-twl.c +++ b/drivers/rtc/rtc-twl.c @@ -479,7 +479,7 @@ static int twl_rtc_probe(struct platform_device *pdev)  	u8 rd_reg;  	if (irq <= 0) -		goto out1; +		return ret;  	/* Initialize the register map */  	if (twl_class_is_4030()) @@ -489,7 +489,7 @@ static int twl_rtc_probe(struct platform_device *pdev)  	ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);  	if (ret < 0) -		goto out1; +		return ret;  	if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M)  		dev_warn(&pdev->dev, "Power up reset detected.\n"); @@ -500,7 +500,7 @@ static int twl_rtc_probe(struct platform_device *pdev)  	/* Clear RTC Power up reset and pending alarm interrupts */  	ret = twl_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG);  	if (ret < 0) -		goto out1; +		return ret;  	if (twl_class_is_6030()) {  		twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, @@ -512,7 +512,7 @@ static int twl_rtc_probe(struct platform_device *pdev)  	dev_info(&pdev->dev, "Enabling TWL-RTC\n");  	ret = twl_rtc_write_u8(BIT_RTC_CTRL_REG_STOP_RTC_M, REG_RTC_CTRL_REG);  	if (ret < 0) -		goto out1; +		return ret;  	/* ensure interrupts are disabled, bootloaders can be strange */  	ret = twl_rtc_write_u8(0, REG_RTC_INTERRUPTS_REG); @@ -522,34 +522,29 @@ static int twl_rtc_probe(struct platform_device *pdev)  	/* init cached IRQ enable bits */  	ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);  	if (ret < 0) -		goto out1; +		return ret;  	device_init_wakeup(&pdev->dev, 1); -	rtc = rtc_device_register(pdev->name, -				  &pdev->dev, &twl_rtc_ops, THIS_MODULE); +	rtc = devm_rtc_device_register(&pdev->dev, pdev->name, +					&twl_rtc_ops, THIS_MODULE);  	if (IS_ERR(rtc)) { -		ret = PTR_ERR(rtc);  		dev_err(&pdev->dev, "can't register RTC device, err %ld\n",  			PTR_ERR(rtc)); -		goto out1; +		return PTR_ERR(rtc);  	} -	ret = request_threaded_irq(irq, NULL, twl_rtc_interrupt, -				   IRQF_TRIGGER_RISING | IRQF_ONESHOT, -				   dev_name(&rtc->dev), rtc); +	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL, +					twl_rtc_interrupt, +					IRQF_TRIGGER_RISING | IRQF_ONESHOT, +					dev_name(&rtc->dev), rtc);  	if (ret < 0) {  		dev_err(&pdev->dev, "IRQ is not free.\n"); -		goto out2; +		return ret;  	}  	platform_set_drvdata(pdev, rtc);  	return 0; - -out2: -	rtc_device_unregister(rtc); -out1: -	return ret;  }  /* @@ -559,9 +554,6 @@ out1:  static int twl_rtc_remove(struct platform_device *pdev)  {  	/* leave rtc running, but disable irqs */ -	struct rtc_device *rtc = platform_get_drvdata(pdev); -	int irq = platform_get_irq(pdev, 0); -  	mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);  	mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);  	if (twl_class_is_6030()) { @@ -571,10 +563,6 @@ static int twl_rtc_remove(struct platform_device *pdev)  			REG_INT_MSK_STS_A);  	} - -	free_irq(irq, rtc); - -	rtc_device_unregister(rtc);  	return 0;  } diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c index 4f87234e0de..2e678c681b1 100644 --- a/drivers/rtc/rtc-tx4939.c +++ b/drivers/rtc/rtc-tx4939.c @@ -176,8 +176,8 @@ static irqreturn_t tx4939_rtc_interrupt(int irq, void *dev_id)  		tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_NOP);  	}  	spin_unlock(&pdata->lock); -	if (likely(pdata->rtc)) -		rtc_update_irq(pdata->rtc, 1, events); +	rtc_update_irq(pdata->rtc, 1, events); +  	return IRQ_HANDLED;  } diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index d07d8982302..25222cdccdc 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -303,7 +303,7 @@ static const struct rtc_class_ops v3020_rtc_ops = {  static int rtc_probe(struct platform_device *pdev)  { -	struct v3020_platform_data *pdata = pdev->dev.platform_data; +	struct v3020_platform_data *pdata = dev_get_platdata(&pdev->dev);  	struct v3020 *chip;  	int retval = -EBUSY;  	int i; diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index 54e104e197e..88c9c92e89f 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -20,6 +20,7 @@  #include <linux/err.h>  #include <linux/fs.h>  #include <linux/init.h> +#include <linux/io.h>  #include <linux/ioport.h>  #include <linux/interrupt.h>  #include <linux/module.h> @@ -27,11 +28,10 @@  #include <linux/rtc.h>  #include <linux/spinlock.h>  #include <linux/types.h> +#include <linux/uaccess.h>  #include <linux/log2.h>  #include <asm/div64.h> -#include <asm/io.h> -#include <asm/uaccess.h>  MODULE_AUTHOR("Yoichi Yuasa <yuasa@linux-mips.org>");  MODULE_DESCRIPTION("NEC VR4100 series RTC driver"); @@ -293,7 +293,7 @@ static int rtc_probe(struct platform_device *pdev)  	if (!res)  		return -EBUSY; -	rtc1_base = ioremap(res->start, resource_size(res)); +	rtc1_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));  	if (!rtc1_base)  		return -EBUSY; @@ -303,13 +303,14 @@ static int rtc_probe(struct platform_device *pdev)  		goto err_rtc1_iounmap;  	} -	rtc2_base = ioremap(res->start, resource_size(res)); +	rtc2_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));  	if (!rtc2_base) {  		retval = -EBUSY;  		goto err_rtc1_iounmap;  	} -	rtc = rtc_device_register(rtc_name, &pdev->dev, &vr41xx_rtc_ops, THIS_MODULE); +	rtc = devm_rtc_device_register(&pdev->dev, rtc_name, &vr41xx_rtc_ops, +					THIS_MODULE);  	if (IS_ERR(rtc)) {  		retval = PTR_ERR(rtc);  		goto err_iounmap_all; @@ -330,24 +331,24 @@ static int rtc_probe(struct platform_device *pdev)  	aie_irq = platform_get_irq(pdev, 0);  	if (aie_irq <= 0) {  		retval = -EBUSY; -		goto err_device_unregister; +		goto err_iounmap_all;  	} -	retval = request_irq(aie_irq, elapsedtime_interrupt, 0, -			     "elapsed_time", pdev); +	retval = devm_request_irq(&pdev->dev, aie_irq, elapsedtime_interrupt, 0, +				"elapsed_time", pdev);  	if (retval < 0) -		goto err_device_unregister; +		goto err_iounmap_all;  	pie_irq = platform_get_irq(pdev, 1);  	if (pie_irq <= 0) {  		retval = -EBUSY; -		goto err_free_irq; +		goto err_iounmap_all;  	} -	retval = request_irq(pie_irq, rtclong1_interrupt, 0, -			     "rtclong1", pdev); +	retval = devm_request_irq(&pdev->dev, pie_irq, rtclong1_interrupt, 0, +				"rtclong1", pdev);  	if (retval < 0) -		goto err_free_irq; +		goto err_iounmap_all;  	platform_set_drvdata(pdev, rtc); @@ -358,47 +359,20 @@ static int rtc_probe(struct platform_device *pdev)  	return 0; -err_free_irq: -	free_irq(aie_irq, pdev); - -err_device_unregister: -	rtc_device_unregister(rtc); -  err_iounmap_all: -	iounmap(rtc2_base);  	rtc2_base = NULL;  err_rtc1_iounmap: -	iounmap(rtc1_base);  	rtc1_base = NULL;  	return retval;  } -static int rtc_remove(struct platform_device *pdev) -{ -	struct rtc_device *rtc; - -	rtc = platform_get_drvdata(pdev); -	if (rtc) -		rtc_device_unregister(rtc); - -	free_irq(aie_irq, pdev); -	free_irq(pie_irq, pdev); -	if (rtc1_base) -		iounmap(rtc1_base); -	if (rtc2_base) -		iounmap(rtc2_base); - -	return 0; -} -  /* work with hotplug and coldplug */  MODULE_ALIAS("platform:RTC");  static struct platform_driver rtc_platform_driver = {  	.probe		= rtc_probe, -	.remove		= rtc_remove,  	.driver		= {  		.name	= rtc_name,  		.owner	= THIS_MODULE, diff --git a/drivers/rtc/rtc-vt8500.c b/drivers/rtc/rtc-vt8500.c index c2d6331fc71..051da968da6 100644 --- a/drivers/rtc/rtc-vt8500.c +++ b/drivers/rtc/rtc-vt8500.c @@ -79,7 +79,6 @@  struct vt8500_rtc {  	void __iomem		*regbase; -	struct resource		*res;  	int			irq_alarm;  	struct rtc_device	*rtc;  	spinlock_t		lock;		/* Protects this structure */ @@ -209,6 +208,7 @@ static const struct rtc_class_ops vt8500_rtc_ops = {  static int vt8500_rtc_probe(struct platform_device *pdev)  {  	struct vt8500_rtc *vt8500_rtc; +	struct resource	*res;  	int ret;  	vt8500_rtc = devm_kzalloc(&pdev->dev, @@ -219,34 +219,16 @@ static int vt8500_rtc_probe(struct platform_device *pdev)  	spin_lock_init(&vt8500_rtc->lock);  	platform_set_drvdata(pdev, vt8500_rtc); -	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"); -		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"); -		return -ENXIO; -	} - -	vt8500_rtc->res = devm_request_mem_region(&pdev->dev, -					vt8500_rtc->res->start, -					resource_size(vt8500_rtc->res), -					"vt8500-rtc"); -	if (vt8500_rtc->res == NULL) { -		dev_err(&pdev->dev, "failed to request I/O memory\n"); -		return -EBUSY; +		return vt8500_rtc->irq_alarm;  	} -	vt8500_rtc->regbase = devm_ioremap(&pdev->dev, vt8500_rtc->res->start, -				      resource_size(vt8500_rtc->res)); -	if (!vt8500_rtc->regbase) { -		dev_err(&pdev->dev, "Unable to map RTC I/O memory\n"); -		ret = -EBUSY; -		goto err_return; -	} +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	vt8500_rtc->regbase = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(vt8500_rtc->regbase)) +		return PTR_ERR(vt8500_rtc->regbase);  	/* Enable RTC and set it to 24-hour mode */  	writel(VT8500_RTC_CR_ENABLE, @@ -296,7 +278,7 @@ static struct platform_driver vt8500_rtc_driver = {  	.driver		= {  		.name	= "vt8500-rtc",  		.owner	= THIS_MODULE, -		.of_match_table = of_match_ptr(wmt_dt_ids), +		.of_match_table = wmt_dt_ids,  	},  }; diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index 365dc650514..b1de58e0b3d 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -660,7 +660,7 @@ static int x1205_probe(struct i2c_client *client,  	err = x1205_sysfs_register(&client->dev);  	if (err) -		return err; +		dev_err(&client->dev, "Unable to create sysfs entries\n");  	return 0;  } diff --git a/drivers/rtc/rtc-xgene.c b/drivers/rtc/rtc-xgene.c new file mode 100644 index 00000000000..14129cc85bd --- /dev/null +++ b/drivers/rtc/rtc-xgene.c @@ -0,0 +1,278 @@ +/* + * APM X-Gene SoC Real Time Clock Driver + * + * Copyright (c) 2014, Applied Micro Circuits Corporation + * Author: Rameshwar Prasad Sahu <rsahu@apm.com> + *         Loc Ho <lho@apm.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. + * + * 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, see <http://www.gnu.org/licenses/>. + * + */ + +#include <linux/init.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/platform_device.h> +#include <linux/io.h> +#include <linux/slab.h> +#include <linux/clk.h> +#include <linux/delay.h> +#include <linux/rtc.h> + +/* RTC CSR Registers */ +#define RTC_CCVR		0x00 +#define RTC_CMR			0x04 +#define RTC_CLR			0x08 +#define RTC_CCR			0x0C +#define  RTC_CCR_IE		BIT(0) +#define  RTC_CCR_MASK		BIT(1) +#define  RTC_CCR_EN		BIT(2) +#define  RTC_CCR_WEN		BIT(3) +#define RTC_STAT		0x10 +#define  RTC_STAT_BIT		BIT(0) +#define RTC_RSTAT		0x14 +#define RTC_EOI			0x18 +#define RTC_VER			0x1C + +struct xgene_rtc_dev { +	struct rtc_device *rtc; +	struct device *dev; +	unsigned long alarm_time; +	void __iomem *csr_base; +	struct clk *clk; +	unsigned int irq_wake; +}; + +static int xgene_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ +	struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); + +	rtc_time_to_tm(readl(pdata->csr_base + RTC_CCVR), tm); +	return rtc_valid_tm(tm); +} + +static int xgene_rtc_set_mmss(struct device *dev, unsigned long secs) +{ +	struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); + +	/* +	 * NOTE: After the following write, the RTC_CCVR is only reflected +	 *       after the update cycle of 1 seconds. +	 */ +	writel((u32) secs, pdata->csr_base + RTC_CLR); +	readl(pdata->csr_base + RTC_CLR); /* Force a barrier */ + +	return 0; +} + +static int xgene_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); + +	rtc_time_to_tm(pdata->alarm_time, &alrm->time); +	alrm->enabled = readl(pdata->csr_base + RTC_CCR) & RTC_CCR_IE; + +	return 0; +} + +static int xgene_rtc_alarm_irq_enable(struct device *dev, u32 enabled) +{ +	struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); +	u32 ccr; + +	ccr = readl(pdata->csr_base + RTC_CCR); +	if (enabled) { +		ccr &= ~RTC_CCR_MASK; +		ccr |= RTC_CCR_IE; +	} else { +		ccr &= ~RTC_CCR_IE; +		ccr |= RTC_CCR_MASK; +	} +	writel(ccr, pdata->csr_base + RTC_CCR); + +	return 0; +} + +static int xgene_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	struct xgene_rtc_dev *pdata = dev_get_drvdata(dev); +	unsigned long rtc_time; +	unsigned long alarm_time; + +	rtc_time = readl(pdata->csr_base + RTC_CCVR); +	rtc_tm_to_time(&alrm->time, &alarm_time); + +	pdata->alarm_time = alarm_time; +	writel((u32) pdata->alarm_time, pdata->csr_base + RTC_CMR); + +	xgene_rtc_alarm_irq_enable(dev, alrm->enabled); + +	return 0; +} + +static const struct rtc_class_ops xgene_rtc_ops = { +	.read_time	= xgene_rtc_read_time, +	.set_mmss	= xgene_rtc_set_mmss, +	.read_alarm	= xgene_rtc_read_alarm, +	.set_alarm	= xgene_rtc_set_alarm, +	.alarm_irq_enable = xgene_rtc_alarm_irq_enable, +}; + +static irqreturn_t xgene_rtc_interrupt(int irq, void *id) +{ +	struct xgene_rtc_dev *pdata = (struct xgene_rtc_dev *) id; + +	/* Check if interrupt asserted */ +	if (!(readl(pdata->csr_base + RTC_STAT) & RTC_STAT_BIT)) +		return IRQ_NONE; + +	/* Clear interrupt */ +	readl(pdata->csr_base + RTC_EOI); + +	rtc_update_irq(pdata->rtc, 1, RTC_IRQF | RTC_AF); + +	return IRQ_HANDLED; +} + +static int xgene_rtc_probe(struct platform_device *pdev) +{ +	struct xgene_rtc_dev *pdata; +	struct resource *res; +	int ret; +	int irq; + +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); +	if (!pdata) +		return -ENOMEM; +	platform_set_drvdata(pdev, pdata); +	pdata->dev = &pdev->dev; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	pdata->csr_base = devm_ioremap_resource(&pdev->dev, res); +	if (IS_ERR(pdata->csr_base)) +		return PTR_ERR(pdata->csr_base); + +	irq = platform_get_irq(pdev, 0); +	if (irq < 0) { +		dev_err(&pdev->dev, "No IRQ resource\n"); +		return irq; +	} +	ret = devm_request_irq(&pdev->dev, irq, xgene_rtc_interrupt, 0, +			       dev_name(&pdev->dev), pdata); +	if (ret) { +		dev_err(&pdev->dev, "Could not request IRQ\n"); +		return ret; +	} + +	pdata->clk = devm_clk_get(&pdev->dev, NULL); +	if (IS_ERR(pdata->clk)) { +		dev_err(&pdev->dev, "Couldn't get the clock for RTC\n"); +		return -ENODEV; +	} +	clk_prepare_enable(pdata->clk); + +	/* Turn on the clock and the crystal */ +	writel(RTC_CCR_EN, pdata->csr_base + RTC_CCR); + +	device_init_wakeup(&pdev->dev, 1); + +	pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name, +					 &xgene_rtc_ops, THIS_MODULE); +	if (IS_ERR(pdata->rtc)) { +		clk_disable_unprepare(pdata->clk); +		return PTR_ERR(pdata->rtc); +	} + +	/* HW does not support update faster than 1 seconds */ +	pdata->rtc->uie_unsupported = 1; + +	return 0; +} + +static int xgene_rtc_remove(struct platform_device *pdev) +{ +	struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev); + +	xgene_rtc_alarm_irq_enable(&pdev->dev, 0); +	device_init_wakeup(&pdev->dev, 0); +	clk_disable_unprepare(pdata->clk); +	return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int xgene_rtc_suspend(struct device *dev) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev); +	int irq; + +	irq = platform_get_irq(pdev, 0); +	if (device_may_wakeup(&pdev->dev)) { +		if (!enable_irq_wake(irq)) +			pdata->irq_wake = 1; +	} else { +		xgene_rtc_alarm_irq_enable(dev, 0); +		clk_disable(pdata->clk); +	} + +	return 0; +} + +static int xgene_rtc_resume(struct device *dev) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct xgene_rtc_dev *pdata = platform_get_drvdata(pdev); +	int irq; + +	irq = platform_get_irq(pdev, 0); +	if (device_may_wakeup(&pdev->dev)) { +		if (pdata->irq_wake) { +			disable_irq_wake(irq); +			pdata->irq_wake = 0; +		} +	} else { +		clk_enable(pdata->clk); +		xgene_rtc_alarm_irq_enable(dev, 1); +	} + +	return 0; +} +#endif + +static SIMPLE_DEV_PM_OPS(xgene_rtc_pm_ops, xgene_rtc_suspend, xgene_rtc_resume); + +#ifdef CONFIG_OF +static const struct of_device_id xgene_rtc_of_match[] = { +	{.compatible = "apm,xgene-rtc" }, +	{ } +}; +MODULE_DEVICE_TABLE(of, xgene_rtc_of_match); +#endif + +static struct platform_driver xgene_rtc_driver = { +	.probe		= xgene_rtc_probe, +	.remove		= xgene_rtc_remove, +	.driver		= { +		.owner	= THIS_MODULE, +		.name	= "xgene-rtc", +		.pm = &xgene_rtc_pm_ops, +		.of_match_table	= of_match_ptr(xgene_rtc_of_match), +	}, +}; + +module_platform_driver(xgene_rtc_driver); + +MODULE_DESCRIPTION("APM X-Gene SoC RTC driver"); +MODULE_AUTHOR("Rameshwar Sahu <rsahu@apm.com>"); +MODULE_LICENSE("GPL");  | 
