diff options
Diffstat (limited to 'drivers/rtc')
38 files changed, 2125 insertions, 628 deletions
| diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 3c20dae43ce..8167e9e6827 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -242,6 +242,15 @@ config RTC_DRV_M41T80_WDT  	  If you say Y here you will get support for the  	  watchdog timer in the ST M41T60 and M41T80 RTC chips series. +config RTC_DRV_BQ32K +	tristate "TI BQ32000" +	help +	  If you say Y here you will get support for the TI +	  BQ32000 I2C RTC chip. + +	  This driver can also be built as a module. If so, the module +	  will be called rtc-bq32k. +  config RTC_DRV_DM355EVM  	tristate "TI DaVinci DM355 EVM RTC"  	depends on MFD_DM355EVM_MSP @@ -258,14 +267,14 @@ config RTC_DRV_TWL92330  	  the Menelaus driver; it's not separate module.  config RTC_DRV_TWL4030 -	tristate "TI TWL4030/TWL5030/TPS659x0" +	tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0"  	depends on RTC_CLASS && TWL4030_CORE  	help  	  If you say yes here you get support for the RTC on the -	  TWL4030 family chips, used mostly with OMAP3 platforms. +	  TWL4030/TWL5030/TWL6030 family chips, used mostly with OMAP3 platforms.  	  This driver can also be built as a module. If so, the module -	  will be called rtc-twl4030. +	  will be called rtc-twl.  config RTC_DRV_S35390A  	tristate "Seiko Instruments S-35390A" @@ -509,6 +518,15 @@ config RTC_DRV_M48T59  	  This driver can also be built as a module, if so, the module  	  will be called "rtc-m48t59". +config RTC_DRV_MSM6242 +	tristate "Oki MSM6242" +	help +	  If you say yes here you get support for the Oki MSM6242 +	  timekeeping chip. It is used in some Amiga models (e.g. A2000). + +	  This driver can also be built as a module. If so, the module +	  will be called rtc-msm6242. +  config RTC_MXC  	tristate "Freescale MXC Real Time Clock"  	depends on ARCH_MXC @@ -529,6 +547,16 @@ config RTC_DRV_BQ4802  	  This driver can also be built as a module. If so, the module  	  will be called rtc-bq4802. +config RTC_DRV_RP5C01 +	tristate "Ricoh RP5C01" +	help +	  If you say yes here you get support for the Ricoh RP5C01 +	  timekeeping chip. It is used in some Amiga models (e.g. A3000 +	  and A4000). + +	  This driver can also be built as a module. If so, the module +	  will be called rtc-rp5c01. +  config RTC_DRV_V3020  	tristate "EM Microelectronic V3020"  	help @@ -573,15 +601,22 @@ config RTC_DRV_AB3100  	  Select this to enable the ST-Ericsson AB3100 Mixed Signal IC RTC  	  support. This chip contains a battery- and capacitor-backed RTC. +config RTC_DRV_NUC900 +	tristate "NUC910/NUC920 RTC driver" +	depends on RTC_CLASS && ARCH_W90X900 +	help +	  If you say yes here you get support for the RTC subsystem of the +	  NUC910/NUC920 used in embedded systems.  comment "on-CPU RTC drivers"  config RTC_DRV_OMAP  	tristate "TI OMAP1" -	depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 +	depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_DAVINCI_DA8XX  	help -	  Say "yes" here to support the real time clock on TI OMAP1 chips. -	  This driver can also be built as a module called rtc-omap. +	  Say "yes" here to support the real time clock on TI OMAP1 and +	  DA8xx/OMAP-L13x chips.  This driver can also be built as a +	  module called rtc-omap.  config RTC_DRV_S3C  	tristate "Samsung S3C series SoC RTC" @@ -780,7 +815,7 @@ config RTC_DRV_TX4939  config RTC_DRV_MV  	tristate "Marvell SoC RTC" -	depends on ARCH_KIRKWOOD +	depends on ARCH_KIRKWOOD || ARCH_DOVE  	help  	  If you say yes here you will get support for the in-chip RTC  	  that can be found in some of Marvell's SoC devices, such as @@ -827,4 +862,10 @@ config RTC_DRV_PCAP  	  If you say Y here you will get support for the RTC found on  	  the PCAP2 ASIC used on some Motorola phones. +config RTC_DRV_MC13783 +	depends on MFD_MC13783 +	tristate "Freescale MC13783 RTC" +	help +	  This enables support for the Freescale MC13783 PMIC RTC +  endif # RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index aa3fbd5517a..e5160fddc44 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -23,6 +23,7 @@ obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o  obj-$(CONFIG_RTC_DRV_AT91SAM9)	+= rtc-at91sam9.o  obj-$(CONFIG_RTC_DRV_AU1XXX)	+= rtc-au1xxx.o  obj-$(CONFIG_RTC_DRV_BFIN)	+= rtc-bfin.o +obj-$(CONFIG_RTC_DRV_BQ32K)	+= rtc-bq32k.o  obj-$(CONFIG_RTC_DRV_BQ4802)	+= rtc-bq4802.o  obj-$(CONFIG_RTC_DRV_CMOS)	+= rtc-cmos.o  obj-$(CONFIG_RTC_DRV_COH901331)	+= rtc-coh901331.o @@ -52,7 +53,10 @@ obj-$(CONFIG_RTC_DRV_M48T86)	+= rtc-m48t86.o  obj-$(CONFIG_RTC_MXC)		+= rtc-mxc.o  obj-$(CONFIG_RTC_DRV_MAX6900)	+= rtc-max6900.o  obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o +obj-$(CONFIG_RTC_DRV_MC13783)	+= rtc-mc13783.o +obj-$(CONFIG_RTC_DRV_MSM6242)	+= rtc-msm6242.o  obj-$(CONFIG_RTC_DRV_MV)	+= rtc-mv.o +obj-$(CONFIG_RTC_DRV_NUC900)	+= rtc-nuc900.o  obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o  obj-$(CONFIG_RTC_DRV_PCAP)	+= rtc-pcap.o  obj-$(CONFIG_RTC_DRV_PCF8563)	+= rtc-pcf8563.o @@ -64,6 +68,7 @@ obj-$(CONFIG_RTC_DRV_PL031)	+= rtc-pl031.o  obj-$(CONFIG_RTC_DRV_PS3)	+= rtc-ps3.o  obj-$(CONFIG_RTC_DRV_PXA)	+= rtc-pxa.o  obj-$(CONFIG_RTC_DRV_R9701)	+= rtc-r9701.o +obj-$(CONFIG_RTC_DRV_RP5C01)	+= rtc-rp5c01.o  obj-$(CONFIG_RTC_DRV_RS5C313)	+= rtc-rs5c313.o  obj-$(CONFIG_RTC_DRV_RS5C348)	+= rtc-rs5c348.o  obj-$(CONFIG_RTC_DRV_RS5C372)	+= rtc-rs5c372.o @@ -78,7 +83,7 @@ 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_TEST)	+= rtc-test.o -obj-$(CONFIG_RTC_DRV_TWL4030)	+= rtc-twl4030.o +obj-$(CONFIG_RTC_DRV_TWL4030)	+= rtc-twl.o  obj-$(CONFIG_RTC_DRV_TX4939)	+= rtc-tx4939.o  obj-$(CONFIG_RTC_DRV_V3020)	+= rtc-v3020.o  obj-$(CONFIG_RTC_DRV_VR41XX)	+= rtc-vr41xx.o diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 4cdb31a362c..a0c816238aa 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -12,6 +12,7 @@  */  #include <linux/rtc.h> +#include <linux/sched.h>  #include <linux/log2.h>  int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c index e1ec33e40e3..8825695777d 100644 --- a/drivers/rtc/rtc-at32ap700x.c +++ b/drivers/rtc/rtc-at32ap700x.c @@ -256,6 +256,8 @@ static int __init at32_rtc_probe(struct platform_device *pdev)  		goto out_iounmap;  	} +	platform_set_drvdata(pdev, rtc); +  	rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,  				&at32_rtc_ops, THIS_MODULE);  	if (IS_ERR(rtc->rtc)) { @@ -264,7 +266,6 @@ static int __init at32_rtc_probe(struct platform_device *pdev)  		goto out_free_irq;  	} -	platform_set_drvdata(pdev, rtc);  	device_init_wakeup(&pdev->dev, 1);  	dev_info(&pdev->dev, "Atmel RTC for AT32AP700x at %08lx irq %ld\n", @@ -273,6 +274,7 @@ static int __init at32_rtc_probe(struct platform_device *pdev)  	return 0;  out_free_irq: +	platform_set_drvdata(pdev, NULL);  	free_irq(irq, rtc);  out_iounmap:  	iounmap(rtc->regs); diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c new file mode 100644 index 00000000000..408cc8f735b --- /dev/null +++ b/drivers/rtc/rtc-bq32k.c @@ -0,0 +1,204 @@ +/* + * Driver for TI BQ32000 RTC. + * + * Copyright (C) 2009 Semihalf. + * + * 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/i2c.h> +#include <linux/rtc.h> +#include <linux/init.h> +#include <linux/errno.h> +#include <linux/bcd.h> + +#define BQ32K_SECONDS		0x00	/* Seconds register address */ +#define BQ32K_SECONDS_MASK	0x7F	/* Mask over seconds value */ +#define BQ32K_STOP		0x80	/* Oscillator Stop flat */ + +#define BQ32K_MINUTES		0x01	/* Minutes register address */ +#define BQ32K_MINUTES_MASK	0x7F	/* Mask over minutes value */ +#define BQ32K_OF		0x80	/* Oscillator Failure flag */ + +#define BQ32K_HOURS_MASK	0x3F	/* Mask over hours value */ +#define BQ32K_CENT		0x40	/* Century flag */ +#define BQ32K_CENT_EN		0x80	/* Century flag enable bit */ + +struct bq32k_regs { +	uint8_t		seconds; +	uint8_t		minutes; +	uint8_t		cent_hours; +	uint8_t		day; +	uint8_t		date; +	uint8_t		month; +	uint8_t		years; +}; + +static struct i2c_driver bq32k_driver; + +static int bq32k_read(struct device *dev, void *data, uint8_t off, uint8_t len) +{ +	struct i2c_client *client = to_i2c_client(dev); +	struct i2c_msg msgs[] = { +		{ +			.addr = client->addr, +			.flags = 0, +			.len = 1, +			.buf = &off, +		}, { +			.addr = client->addr, +			.flags = I2C_M_RD, +			.len = len, +			.buf = data, +		} +	}; + +	if (i2c_transfer(client->adapter, msgs, 2) == 2) +		return 0; + +	return -EIO; +} + +static int bq32k_write(struct device *dev, void *data, uint8_t off, uint8_t len) +{ +	struct i2c_client *client = to_i2c_client(dev); +	uint8_t buffer[len + 1]; + +	buffer[0] = off; +	memcpy(&buffer[1], data, len); + +	if (i2c_master_send(client, buffer, len + 1) == len + 1) +		return 0; + +	return -EIO; +} + +static int bq32k_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ +	struct bq32k_regs regs; +	int error; + +	error = bq32k_read(dev, ®s, 0, sizeof(regs)); +	if (error) +		return error; + +	tm->tm_sec = bcd2bin(regs.seconds & BQ32K_SECONDS_MASK); +	tm->tm_min = bcd2bin(regs.minutes & BQ32K_SECONDS_MASK); +	tm->tm_hour = bcd2bin(regs.cent_hours & BQ32K_HOURS_MASK); +	tm->tm_mday = bcd2bin(regs.date); +	tm->tm_wday = bcd2bin(regs.day) - 1; +	tm->tm_mon = bcd2bin(regs.month) - 1; +	tm->tm_year = bcd2bin(regs.years) + +				((regs.cent_hours & BQ32K_CENT) ? 100 : 0); + +	return rtc_valid_tm(tm); +} + +static int bq32k_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ +	struct bq32k_regs regs; + +	regs.seconds = bin2bcd(tm->tm_sec); +	regs.minutes = bin2bcd(tm->tm_min); +	regs.cent_hours = bin2bcd(tm->tm_hour) | BQ32K_CENT_EN; +	regs.day = bin2bcd(tm->tm_wday + 1); +	regs.date = bin2bcd(tm->tm_mday); +	regs.month = bin2bcd(tm->tm_mon + 1); + +	if (tm->tm_year >= 100) { +		regs.cent_hours |= BQ32K_CENT; +		regs.years = bin2bcd(tm->tm_year - 100); +	} else +		regs.years = bin2bcd(tm->tm_year); + +	return bq32k_write(dev, ®s, 0, sizeof(regs)); +} + +static const struct rtc_class_ops bq32k_rtc_ops = { +	.read_time	= bq32k_rtc_read_time, +	.set_time	= bq32k_rtc_set_time, +}; + +static int bq32k_probe(struct i2c_client *client, +				const struct i2c_device_id *id) +{ +	struct device *dev = &client->dev; +	struct rtc_device *rtc; +	uint8_t reg; +	int error; + +	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) +		return -ENODEV; + +	/* Check Oscillator Stop flag */ +	error = bq32k_read(dev, ®, BQ32K_SECONDS, 1); +	if (!error && (reg & BQ32K_STOP)) { +		dev_warn(dev, "Oscillator was halted. Restarting...\n"); +		reg &= ~BQ32K_STOP; +		error = bq32k_write(dev, ®, BQ32K_SECONDS, 1); +	} +	if (error) +		return error; + +	/* Check Oscillator Failure flag */ +	error = bq32k_read(dev, ®, BQ32K_MINUTES, 1); +	if (!error && (reg & BQ32K_OF)) { +		dev_warn(dev, "Oscillator Failure. Check RTC battery.\n"); +		reg &= ~BQ32K_OF; +		error = bq32k_write(dev, ®, BQ32K_MINUTES, 1); +	} +	if (error) +		return error; + +	rtc = rtc_device_register(bq32k_driver.driver.name, &client->dev, +						&bq32k_rtc_ops, THIS_MODULE); +	if (IS_ERR(rtc)) +		return PTR_ERR(rtc); + +	i2c_set_clientdata(client, rtc); + +	return 0; +} + +static int __devexit bq32k_remove(struct i2c_client *client) +{ +	struct rtc_device *rtc = i2c_get_clientdata(client); + +	rtc_device_unregister(rtc); +	return 0; +} + +static const struct i2c_device_id bq32k_id[] = { +	{ "bq32000", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, bq32k_id); + +static struct i2c_driver bq32k_driver = { +	.driver = { +		.name	= "bq32k", +		.owner	= THIS_MODULE, +	}, +	.probe		= bq32k_probe, +	.remove		= __devexit_p(bq32k_remove), +	.id_table	= bq32k_id, +}; + +static __init int bq32k_init(void) +{ +	return i2c_add_driver(&bq32k_driver); +} +module_init(bq32k_init); + +static __exit void bq32k_exit(void) +{ +	i2c_del_driver(&bq32k_driver); +} +module_exit(bq32k_exit); + +MODULE_AUTHOR("Semihalf, Piotr Ziecik <kosmo@semihalf.com>"); +MODULE_DESCRIPTION("TI BQ32000 I2C RTC driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c index d00a274df8f..280fe48ada0 100644 --- a/drivers/rtc/rtc-bq4802.c +++ b/drivers/rtc/rtc-bq4802.c @@ -169,6 +169,8 @@ static int __devinit bq4802_probe(struct platform_device *pdev)  		goto out_free;  	} +	platform_set_drvdata(pdev, p); +  	p->rtc = rtc_device_register("bq4802", &pdev->dev,  				     &bq4802_ops, THIS_MODULE);  	if (IS_ERR(p->rtc)) { @@ -176,7 +178,6 @@ static int __devinit bq4802_probe(struct platform_device *pdev)  		goto out_iounmap;  	} -	platform_set_drvdata(pdev, p);  	err = 0;  out:  	return err; diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c index f7a4701bf86..eb154dc5716 100644 --- a/drivers/rtc/rtc-cmos.c +++ b/drivers/rtc/rtc-cmos.c @@ -420,49 +420,43 @@ static int cmos_irq_set_state(struct device *dev, int enabled)  	return 0;  } -#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) - -static int -cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled)  {  	struct cmos_rtc	*cmos = dev_get_drvdata(dev);  	unsigned long	flags; -	switch (cmd) { -	case RTC_AIE_OFF: -	case RTC_AIE_ON: -	case RTC_UIE_OFF: -	case RTC_UIE_ON: -		if (!is_valid_irq(cmos->irq)) -			return -EINVAL; -		break; -	/* PIE ON/OFF is handled by cmos_irq_set_state() */ -	default: -		return -ENOIOCTLCMD; -	} +	if (!is_valid_irq(cmos->irq)) +		return -EINVAL;  	spin_lock_irqsave(&rtc_lock, flags); -	switch (cmd) { -	case RTC_AIE_OFF:	/* alarm off */ -		cmos_irq_disable(cmos, RTC_AIE); -		break; -	case RTC_AIE_ON:	/* alarm on */ + +	if (enabled)  		cmos_irq_enable(cmos, RTC_AIE); -		break; -	case RTC_UIE_OFF:	/* update off */ -		cmos_irq_disable(cmos, RTC_UIE); -		break; -	case RTC_UIE_ON:	/* update on */ -		cmos_irq_enable(cmos, RTC_UIE); -		break; -	} +	else +		cmos_irq_disable(cmos, RTC_AIE); +  	spin_unlock_irqrestore(&rtc_lock, flags);  	return 0;  } -#else -#define	cmos_rtc_ioctl	NULL -#endif +static int cmos_update_irq_enable(struct device *dev, unsigned int enabled) +{ +	struct cmos_rtc	*cmos = dev_get_drvdata(dev); +	unsigned long	flags; + +	if (!is_valid_irq(cmos->irq)) +		return -EINVAL; + +	spin_lock_irqsave(&rtc_lock, flags); + +	if (enabled) +		cmos_irq_enable(cmos, RTC_UIE); +	else +		cmos_irq_disable(cmos, RTC_UIE); + +	spin_unlock_irqrestore(&rtc_lock, flags); +	return 0; +}  #if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE) @@ -503,14 +497,15 @@ static int cmos_procfs(struct device *dev, struct seq_file *seq)  #endif  static const struct rtc_class_ops cmos_rtc_ops = { -	.ioctl		= cmos_rtc_ioctl, -	.read_time	= cmos_read_time, -	.set_time	= cmos_set_time, -	.read_alarm	= cmos_read_alarm, -	.set_alarm	= cmos_set_alarm, -	.proc		= cmos_procfs, -	.irq_set_freq	= cmos_irq_set_freq, -	.irq_set_state	= cmos_irq_set_state, +	.read_time		= cmos_read_time, +	.set_time		= cmos_set_time, +	.read_alarm		= cmos_read_alarm, +	.set_alarm		= cmos_set_alarm, +	.proc			= cmos_procfs, +	.irq_set_freq		= cmos_irq_set_freq, +	.irq_set_state		= cmos_irq_set_state, +	.alarm_irq_enable	= cmos_alarm_irq_enable, +	.update_irq_enable	= cmos_update_irq_enable,  };  /*----------------------------------------------------------------*/ @@ -871,8 +866,9 @@ static int cmos_suspend(struct device *dev, pm_message_t mesg)  			mask = RTC_IRQMASK;  		tmp &= ~mask;  		CMOS_WRITE(tmp, RTC_CONTROL); -		hpet_mask_rtc_irq_bit(mask); +		/* shut down hpet emulation - we don't need it for alarm */ +		hpet_mask_rtc_irq_bit(RTC_PIE|RTC_AIE|RTC_UIE);  		cmos_checkintr(cmos, tmp);  	}  	spin_unlock_irq(&rtc_lock); diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c index 7fe1fa26c52..03ea530981d 100644 --- a/drivers/rtc/rtc-coh901331.c +++ b/drivers/rtc/rtc-coh901331.c @@ -58,7 +58,16 @@ static irqreturn_t coh901331_interrupt(int irq, void *data)  	clk_enable(rtap->clk);  	/* Ack IRQ */  	writel(1, rtap->virtbase + COH901331_IRQ_EVENT); +	/* +	 * Disable the interrupt. This is necessary because +	 * the RTC lives on a lower-clocked line and will +	 * not release the IRQ line until after a few (slower) +	 * clock cycles. The interrupt will be re-enabled when +	 * a new alarm is set anyway. +	 */ +	writel(0, rtap->virtbase + COH901331_IRQ_MASK);  	clk_disable(rtap->clk); +  	/* Set alarm flag */  	rtc_update_irq(rtap->rtc, 1, RTC_AF); @@ -128,6 +137,8 @@ static int coh901331_alarm_irq_enable(struct device *dev, unsigned int enabled)  	else  		writel(0, rtap->virtbase + COH901331_IRQ_MASK);  	clk_disable(rtap->clk); + +	return 0;  }  static struct rtc_class_ops coh901331_ops = { diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 8a11de9552c..62227cd5241 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -13,6 +13,7 @@  #include <linux/module.h>  #include <linux/rtc.h> +#include <linux/sched.h>  #include "rtc-core.h"  static dev_t rtc_devt; diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c index d490628b64d..532acf9b05d 100644 --- a/drivers/rtc/rtc-ds1302.c +++ b/drivers/rtc/rtc-ds1302.c @@ -143,7 +143,6 @@ static int ds1302_rtc_ioctl(struct device *dev, unsigned int cmd,  #ifdef RTC_SET_CHARGE  	case RTC_SET_CHARGE:  	{ -		struct ds1302_rtc *rtc = dev_get_drvdata(dev);  		int tcs_val;  		if (copy_from_user(&tcs_val, (int __user *)arg, sizeof(int))) @@ -201,7 +200,7 @@ static struct platform_driver ds1302_platform_driver = {  		.name	= DRV_NAME,  		.owner	= THIS_MODULE,  	}, -	.remove		= __exit_p(ds1302_rtc_remove), +	.remove		= __devexit_p(ds1302_rtc_remove),  };  static int __init ds1302_rtc_init(void) diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index 2736b11a1b1..259db7f3535 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -617,7 +617,6 @@ static struct bin_attribute nvram = {  static int __devinit ds1305_probe(struct spi_device *spi)  {  	struct ds1305			*ds1305; -	struct rtc_device		*rtc;  	int				status;  	u8				addr, value;  	struct ds1305_platform_data	*pdata = spi->dev.platform_data; @@ -756,14 +755,13 @@ static int __devinit ds1305_probe(struct spi_device *spi)  		dev_dbg(&spi->dev, "AM/PM\n");  	/* register RTC ... from here on, ds1305->ctrl needs locking */ -	rtc = rtc_device_register("ds1305", &spi->dev, +	ds1305->rtc = rtc_device_register("ds1305", &spi->dev,  			&ds1305_ops, THIS_MODULE); -	if (IS_ERR(rtc)) { -		status = PTR_ERR(rtc); +	if (IS_ERR(ds1305->rtc)) { +		status = PTR_ERR(ds1305->rtc);  		dev_dbg(&spi->dev, "register rtc --> %d\n", status);  		goto fail0;  	} -	ds1305->rtc = rtc;  	/* Maybe set up alarm IRQ; be ready to handle it triggering right  	 * away.  NOTE that we don't share this.  The signal is active low, @@ -774,7 +772,7 @@ static int __devinit ds1305_probe(struct spi_device *spi)  	if (spi->irq) {  		INIT_WORK(&ds1305->work, ds1305_work);  		status = request_irq(spi->irq, ds1305_irq, -				0, dev_name(&rtc->dev), ds1305); +				0, dev_name(&ds1305->rtc->dev), ds1305);  		if (status < 0) {  			dev_dbg(&spi->dev, "request_irq %d --> %d\n",  					spi->irq, status); @@ -794,7 +792,7 @@ static int __devinit ds1305_probe(struct spi_device *spi)  fail2:  	free_irq(spi->irq, ds1305);  fail1: -	rtc_device_unregister(rtc); +	rtc_device_unregister(ds1305->rtc);  fail0:  	kfree(ds1305);  	return status; @@ -802,7 +800,7 @@ fail0:  static int __devexit ds1305_remove(struct spi_device *spi)  { -	struct ds1305	*ds1305 = spi_get_drvdata(spi); +	struct ds1305 *ds1305 = spi_get_drvdata(spi);  	sysfs_remove_bin_file(&spi->dev.kobj, &nvram); diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index eb99ee4fa0f..8a99da6f2f2 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -874,7 +874,7 @@ read_rtc:  	}  	if (want_irq) { -		err = request_irq(client->irq, ds1307_irq, 0, +		err = request_irq(client->irq, ds1307_irq, IRQF_SHARED,  			  ds1307->rtc->name, client);  		if (err) {  			dev_err(&client->dev, diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c index 0b6b7730c71..4166b84cb51 100644 --- a/drivers/rtc/rtc-ds1511.c +++ b/drivers/rtc/rtc-ds1511.c @@ -2,7 +2,7 @@   * An rtc driver for the Dallas DS1511   *   * Copyright (C) 2006 Atsushi Nemoto <anemo@mba.ocn.ne.jp> - * Copyright (C) 2007 Andrew Sharp <andy.sharp@onstor.com> + * Copyright (C) 2007 Andrew Sharp <andy.sharp@lsi.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 @@ -87,7 +87,6 @@ enum ds1511reg {  struct rtc_plat_data {  	struct rtc_device *rtc;  	void __iomem *ioaddr;		/* virtual base address */ -	unsigned long baseaddr;		/* physical base address */  	int size;				/* amount of memory mapped */  	int irq;  	unsigned int irqen; @@ -95,6 +94,7 @@ struct rtc_plat_data {  	int alrm_min;  	int alrm_hour;  	int alrm_mday; +	spinlock_t lock;  };  static DEFINE_SPINLOCK(ds1511_lock); @@ -302,7 +302,7 @@ ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)  {  	unsigned long flags; -	spin_lock_irqsave(&pdata->rtc->irq_lock, flags); +	spin_lock_irqsave(&pdata->lock, flags);  	rtc_write(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?  	       0x80 : bin2bcd(pdata->alrm_mday) & 0x3f,  	       RTC_ALARM_DATE); @@ -317,7 +317,7 @@ ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)  	       RTC_ALARM_SEC);  	rtc_write(rtc_read(RTC_CMD) | (pdata->irqen ? RTC_TIE : 0), RTC_CMD);  	rtc_read(RTC_CMD1);	/* clear interrupts */ -	spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags); +	spin_unlock_irqrestore(&pdata->lock, flags);  }   static int @@ -362,61 +362,63 @@ ds1511_interrupt(int irq, void *dev_id)  {  	struct platform_device *pdev = dev_id;  	struct rtc_plat_data *pdata = platform_get_drvdata(pdev); -	unsigned long events = RTC_IRQF; +	unsigned long events = 0; +	spin_lock(&pdata->lock);  	/*  	 * read and clear interrupt  	 */ -	if (!(rtc_read(RTC_CMD1) & DS1511_IRQF)) { -		return IRQ_NONE; -	} -	if (rtc_read(RTC_ALARM_SEC) & 0x80) { -		events |= RTC_UF; -	} else { -		events |= RTC_AF; -	} -	rtc_update_irq(pdata->rtc, 1, events); -	return IRQ_HANDLED; +	if (rtc_read(RTC_CMD1) & DS1511_IRQF) { +		events = RTC_IRQF; +		if (rtc_read(RTC_ALARM_SEC) & 0x80) +			events |= RTC_UF; +		else +			events |= RTC_AF; +		if (likely(pdata->rtc)) +			rtc_update_irq(pdata->rtc, 1, events); +	} +	spin_unlock(&pdata->lock); +	return events ? IRQ_HANDLED : IRQ_NONE;  } - static int -ds1511_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +static int ds1511_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)  {  	struct platform_device *pdev = to_platform_device(dev);  	struct rtc_plat_data *pdata = platform_get_drvdata(pdev); -	if (pdata->irq <= 0) { -		return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ -	} -	switch (cmd) { -	case RTC_AIE_OFF: -		pdata->irqen &= ~RTC_AF; -		ds1511_rtc_update_alarm(pdata); -		break; -	case RTC_AIE_ON: +	if (pdata->irq <= 0) +		return -EINVAL; +	if (enabled)  		pdata->irqen |= RTC_AF; -		ds1511_rtc_update_alarm(pdata); -		break; -	case RTC_UIE_OFF: -		pdata->irqen &= ~RTC_UF; -		ds1511_rtc_update_alarm(pdata); -		break; -	case RTC_UIE_ON: +	else +		pdata->irqen &= ~RTC_AF; +	ds1511_rtc_update_alarm(pdata); +	return 0; +} + +static int ds1511_rtc_update_irq_enable(struct device *dev, +	unsigned int enabled) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct rtc_plat_data *pdata = platform_get_drvdata(pdev); + +	if (pdata->irq <= 0) +		return -EINVAL; +	if (enabled)  		pdata->irqen |= RTC_UF; -		ds1511_rtc_update_alarm(pdata); -		break; -	default: -		return -ENOIOCTLCMD; -	} +	else +		pdata->irqen &= ~RTC_UF; +	ds1511_rtc_update_alarm(pdata);  	return 0;  }  static const struct rtc_class_ops ds1511_rtc_ops = { -	.read_time	= ds1511_rtc_read_time, -	.set_time	= ds1511_rtc_set_time, -	.read_alarm	= ds1511_rtc_read_alarm, -	.set_alarm	= ds1511_rtc_set_alarm, -	.ioctl		= ds1511_rtc_ioctl, +	.read_time		= ds1511_rtc_read_time, +	.set_time		= ds1511_rtc_set_time, +	.read_alarm		= ds1511_rtc_read_alarm, +	.set_alarm		= ds1511_rtc_set_alarm, +	.alarm_irq_enable	= ds1511_rtc_alarm_irq_enable, +	.update_irq_enable	= ds1511_rtc_update_irq_enable,  };   static ssize_t @@ -492,29 +494,23 @@ ds1511_rtc_probe(struct platform_device *pdev)  {  	struct rtc_device *rtc;  	struct resource *res; -	struct rtc_plat_data *pdata = NULL; +	struct rtc_plat_data *pdata;  	int ret = 0;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!res) {  		return -ENODEV;  	} -	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); -	if (!pdata) { +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL); +	if (!pdata)  		return -ENOMEM; -	}  	pdata->size = res->end - res->start + 1; -	if (!request_mem_region(res->start, pdata->size, pdev->name)) { -		ret = -EBUSY; -		goto out; -	} -	pdata->baseaddr = res->start; -	pdata->size = pdata->size; -	ds1511_base = ioremap(pdata->baseaddr, pdata->size); -	if (!ds1511_base) { -		ret = -ENOMEM; -		goto out; -	} +	if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size, +			pdev->name)) +		return -EBUSY; +	ds1511_base = devm_ioremap(&pdev->dev, res->start, pdata->size); +	if (!ds1511_base) +		return -ENOMEM;  	pdata->ioaddr = ds1511_base;  	pdata->irq = platform_get_irq(pdev, 0); @@ -540,13 +536,15 @@ ds1511_rtc_probe(struct platform_device *pdev)  		dev_warn(&pdev->dev, "voltage-low detected.\n");  	} +	spin_lock_init(&pdata->lock); +	platform_set_drvdata(pdev, pdata);  	/*  	 * if the platform has an interrupt in mind for this device,  	 * then by all means, set it  	 */  	if (pdata->irq > 0) {  		rtc_read(RTC_CMD1); -		if (request_irq(pdata->irq, ds1511_interrupt, +		if (devm_request_irq(&pdev->dev, pdata->irq, ds1511_interrupt,  			IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) {  			dev_warn(&pdev->dev, "interrupt not available.\n"); @@ -556,33 +554,13 @@ ds1511_rtc_probe(struct platform_device *pdev)  	rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1511_rtc_ops,  		THIS_MODULE); -	if (IS_ERR(rtc)) { -		ret = PTR_ERR(rtc); -		goto out; -	} +	if (IS_ERR(rtc)) +		return PTR_ERR(rtc);  	pdata->rtc = rtc; -	platform_set_drvdata(pdev, pdata); +  	ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr); -	if (ret) { -		goto out; -	} -	return 0; - out: -	if (pdata->rtc) { +	if (ret)  		rtc_device_unregister(pdata->rtc); -	} -	if (pdata->irq > 0) { -		free_irq(pdata->irq, pdev); -	} -	if (ds1511_base) { -		iounmap(ds1511_base); -		ds1511_base = NULL; -	} -	if (pdata->baseaddr) { -		release_mem_region(pdata->baseaddr, pdata->size); -	} - -	kfree(pdata);  	return ret;  } @@ -593,19 +571,13 @@ ds1511_rtc_remove(struct platform_device *pdev)  	sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);  	rtc_device_unregister(pdata->rtc); -	pdata->rtc = NULL;  	if (pdata->irq > 0) {  		/*  		 * disable the alarm interrupt  		 */  		rtc_write(rtc_read(RTC_CMD) & ~RTC_TIE, RTC_CMD);  		rtc_read(RTC_CMD1); -		free_irq(pdata->irq, pdev);  	} -	iounmap(pdata->ioaddr); -	ds1511_base = NULL; -	release_mem_region(pdata->baseaddr, pdata->size); -	kfree(pdata);  	return 0;  } @@ -636,7 +608,7 @@ ds1511_rtc_exit(void)  module_init(ds1511_rtc_init);  module_exit(ds1511_rtc_exit); -MODULE_AUTHOR("Andrew Sharp <andy.sharp@onstor.com>"); +MODULE_AUTHOR("Andrew Sharp <andy.sharp@lsi.com>");  MODULE_DESCRIPTION("Dallas DS1511 RTC driver");  MODULE_LICENSE("GPL");  MODULE_VERSION(DRV_VERSION); diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index 717288527c6..ed1ef7c9cc0 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -18,7 +18,7 @@  #include <linux/platform_device.h>  #include <linux/io.h> -#define DRV_VERSION "0.2" +#define DRV_VERSION "0.3"  #define RTC_REG_SIZE		0x2000  #define RTC_OFFSET		0x1ff0 @@ -61,7 +61,6 @@  struct rtc_plat_data {  	struct rtc_device *rtc;  	void __iomem *ioaddr; -	resource_size_t baseaddr;  	unsigned long last_jiffies;  	int irq;  	unsigned int irqen; @@ -69,6 +68,7 @@ struct rtc_plat_data {  	int alrm_min;  	int alrm_hour;  	int alrm_mday; +	spinlock_t lock;  };  static int ds1553_rtc_set_time(struct device *dev, struct rtc_time *tm) @@ -139,7 +139,7 @@ static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata)  	void __iomem *ioaddr = pdata->ioaddr;  	unsigned long flags; -	spin_lock_irqsave(&pdata->rtc->irq_lock, flags); +	spin_lock_irqsave(&pdata->lock, flags);  	writeb(pdata->alrm_mday < 0 || (pdata->irqen & RTC_UF) ?  	       0x80 : bin2bcd(pdata->alrm_mday),  	       ioaddr + RTC_DATE_ALARM); @@ -154,7 +154,7 @@ static void ds1553_rtc_update_alarm(struct rtc_plat_data *pdata)  	       ioaddr + RTC_SECONDS_ALARM);  	writeb(pdata->irqen ? RTC_INTS_AE : 0, ioaddr + RTC_INTERRUPTS);  	readb(ioaddr + RTC_FLAGS);	/* clear interrupts */ -	spin_unlock_irqrestore(&pdata->rtc->irq_lock, flags); +	spin_unlock_irqrestore(&pdata->lock, flags);  }  static int ds1553_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -194,64 +194,69 @@ static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id)  	struct platform_device *pdev = dev_id;  	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);  	void __iomem *ioaddr = pdata->ioaddr; -	unsigned long events = RTC_IRQF; +	unsigned long events = 0; +	spin_lock(&pdata->lock);  	/* read and clear interrupt */ -	if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF)) -		return IRQ_NONE; -	if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) -		events |= RTC_UF; -	else -		events |= RTC_AF; -	rtc_update_irq(pdata->rtc, 1, events); -	return IRQ_HANDLED; +	if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF) { +		events = RTC_IRQF; +		if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) +			events |= RTC_UF; +		else +			events |= RTC_AF; +		if (likely(pdata->rtc)) +			rtc_update_irq(pdata->rtc, 1, events); +	} +	spin_unlock(&pdata->lock); +	return events ? IRQ_HANDLED : IRQ_NONE;  } -static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd, -			    unsigned long arg) +static int ds1553_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)  {  	struct platform_device *pdev = to_platform_device(dev);  	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);  	if (pdata->irq <= 0) -		return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ -	switch (cmd) { -	case RTC_AIE_OFF: -		pdata->irqen &= ~RTC_AF; -		ds1553_rtc_update_alarm(pdata); -		break; -	case RTC_AIE_ON: +		return -EINVAL; +	if (enabled)  		pdata->irqen |= RTC_AF; -		ds1553_rtc_update_alarm(pdata); -		break; -	case RTC_UIE_OFF: -		pdata->irqen &= ~RTC_UF; -		ds1553_rtc_update_alarm(pdata); -		break; -	case RTC_UIE_ON: +	else +		pdata->irqen &= ~RTC_AF; +	ds1553_rtc_update_alarm(pdata); +	return 0; +} + +static int ds1553_rtc_update_irq_enable(struct device *dev, +	unsigned int enabled) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct rtc_plat_data *pdata = platform_get_drvdata(pdev); + +	if (pdata->irq <= 0) +		return -EINVAL; +	if (enabled)  		pdata->irqen |= RTC_UF; -		ds1553_rtc_update_alarm(pdata); -		break; -	default: -		return -ENOIOCTLCMD; -	} +	else +		pdata->irqen &= ~RTC_UF; +	ds1553_rtc_update_alarm(pdata);  	return 0;  }  static const struct rtc_class_ops ds1553_rtc_ops = { -	.read_time	= ds1553_rtc_read_time, -	.set_time	= ds1553_rtc_set_time, -	.read_alarm	= ds1553_rtc_read_alarm, -	.set_alarm	= ds1553_rtc_set_alarm, -	.ioctl		= ds1553_rtc_ioctl, +	.read_time		= ds1553_rtc_read_time, +	.set_time		= ds1553_rtc_set_time, +	.read_alarm		= ds1553_rtc_read_alarm, +	.set_alarm		= ds1553_rtc_set_alarm, +	.alarm_irq_enable	= ds1553_rtc_alarm_irq_enable, +	.update_irq_enable	= ds1553_rtc_update_irq_enable,  };  static ssize_t ds1553_nvram_read(struct kobject *kobj,  				 struct bin_attribute *bin_attr,  				 char *buf, loff_t pos, size_t size)  { -	struct platform_device *pdev = -		to_platform_device(container_of(kobj, struct device, kobj)); +	struct device *dev = container_of(kobj, struct device, kobj); +	struct platform_device *pdev = to_platform_device(dev);  	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);  	void __iomem *ioaddr = pdata->ioaddr;  	ssize_t count; @@ -265,8 +270,8 @@ static ssize_t ds1553_nvram_write(struct kobject *kobj,  				  struct bin_attribute *bin_attr,  				  char *buf, loff_t pos, size_t size)  { -	struct platform_device *pdev = -		to_platform_device(container_of(kobj, struct device, kobj)); +	struct device *dev = container_of(kobj, struct device, kobj); +	struct platform_device *pdev = to_platform_device(dev);  	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);  	void __iomem *ioaddr = pdata->ioaddr;  	ssize_t count; @@ -291,26 +296,23 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev)  	struct rtc_device *rtc;  	struct resource *res;  	unsigned int cen, sec; -	struct rtc_plat_data *pdata = NULL; -	void __iomem *ioaddr = NULL; +	struct rtc_plat_data *pdata; +	void __iomem *ioaddr;  	int ret = 0;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!res)  		return -ENODEV; -	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);  	if (!pdata)  		return -ENOMEM; -	if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { -		ret = -EBUSY; -		goto out; -	} -	pdata->baseaddr = res->start; -	ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE); -	if (!ioaddr) { -		ret = -ENOMEM; -		goto out; -	} +	if (!devm_request_mem_region(&pdev->dev, res->start, RTC_REG_SIZE, +			pdev->name)) +		return -EBUSY; + +	ioaddr = devm_ioremap(&pdev->dev, res->start, RTC_REG_SIZE); +	if (!ioaddr) +		return -ENOMEM;  	pdata->ioaddr = ioaddr;  	pdata->irq = platform_get_irq(pdev, 0); @@ -326,9 +328,13 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev)  	if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_BLF)  		dev_warn(&pdev->dev, "voltage-low detected.\n"); +	spin_lock_init(&pdata->lock); +	pdata->last_jiffies = jiffies; +	platform_set_drvdata(pdev, pdata);  	if (pdata->irq > 0) {  		writeb(0, ioaddr + RTC_INTERRUPTS); -		if (request_irq(pdata->irq, ds1553_rtc_interrupt, +		if (devm_request_irq(&pdev->dev, pdata->irq, +				ds1553_rtc_interrupt,  				IRQF_DISABLED, pdev->name, pdev) < 0) {  			dev_warn(&pdev->dev, "interrupt not available.\n");  			pdata->irq = 0; @@ -337,27 +343,13 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev)  	rtc = rtc_device_register(pdev->name, &pdev->dev,  				  &ds1553_rtc_ops, THIS_MODULE); -	if (IS_ERR(rtc)) { -		ret = PTR_ERR(rtc); -		goto out; -	} +	if (IS_ERR(rtc)) +		return PTR_ERR(rtc);  	pdata->rtc = rtc; -	pdata->last_jiffies = jiffies; -	platform_set_drvdata(pdev, pdata); +  	ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);  	if (ret) -		goto out; -	return 0; - out: -	if (pdata->rtc) -		rtc_device_unregister(pdata->rtc); -	if (pdata->irq > 0) -		free_irq(pdata->irq, pdev); -	if (ioaddr) -		iounmap(ioaddr); -	if (pdata->baseaddr) -		release_mem_region(pdata->baseaddr, RTC_REG_SIZE); -	kfree(pdata); +		rtc_device_unregister(rtc);  	return ret;  } @@ -367,13 +359,8 @@ static int __devexit ds1553_rtc_remove(struct platform_device *pdev)  	sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);  	rtc_device_unregister(pdata->rtc); -	if (pdata->irq > 0) { +	if (pdata->irq > 0)  		writeb(0, pdata->ioaddr + RTC_INTERRUPTS); -		free_irq(pdata->irq, pdev); -	} -	iounmap(pdata->ioaddr); -	release_mem_region(pdata->baseaddr, RTC_REG_SIZE); -	kfree(pdata);  	return 0;  } diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 09249459e9a..a1273360a44 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -21,7 +21,7 @@  #include <linux/platform_device.h>  #include <linux/io.h> -#define DRV_VERSION "0.3" +#define DRV_VERSION "0.4"  #define RTC_SIZE		8 @@ -55,7 +55,6 @@ struct rtc_plat_data {  	void __iomem *ioaddr_rtc;  	size_t size_nvram;  	size_t size; -	resource_size_t baseaddr;  	unsigned long last_jiffies;  	struct bin_attribute nvram_attr;  }; @@ -132,8 +131,8 @@ static ssize_t ds1742_nvram_read(struct kobject *kobj,  				 struct bin_attribute *bin_attr,  				 char *buf, loff_t pos, size_t size)  { -	struct platform_device *pdev = -		to_platform_device(container_of(kobj, struct device, kobj)); +	struct device *dev = container_of(kobj, struct device, kobj); +	struct platform_device *pdev = to_platform_device(dev);  	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);  	void __iomem *ioaddr = pdata->ioaddr_nvram;  	ssize_t count; @@ -147,8 +146,8 @@ static ssize_t ds1742_nvram_write(struct kobject *kobj,  				  struct bin_attribute *bin_attr,  				  char *buf, loff_t pos, size_t size)  { -	struct platform_device *pdev = -		to_platform_device(container_of(kobj, struct device, kobj)); +	struct device *dev = container_of(kobj, struct device, kobj); +	struct platform_device *pdev = to_platform_device(dev);  	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);  	void __iomem *ioaddr = pdata->ioaddr_nvram;  	ssize_t count; @@ -163,27 +162,24 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev)  	struct rtc_device *rtc;  	struct resource *res;  	unsigned int cen, sec; -	struct rtc_plat_data *pdata = NULL; -	void __iomem *ioaddr = NULL; +	struct rtc_plat_data *pdata; +	void __iomem *ioaddr;  	int ret = 0;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!res)  		return -ENODEV; -	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);  	if (!pdata)  		return -ENOMEM;  	pdata->size = res->end - res->start + 1; -	if (!request_mem_region(res->start, pdata->size, pdev->name)) { -		ret = -EBUSY; -		goto out; -	} -	pdata->baseaddr = res->start; -	ioaddr = ioremap(pdata->baseaddr, pdata->size); -	if (!ioaddr) { -		ret = -ENOMEM; -		goto out; -	} +	if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size, +		pdev->name)) +		return -EBUSY; +	ioaddr = devm_ioremap(&pdev->dev, res->start, pdata->size); +	if (!ioaddr) +		return -ENOMEM; +  	pdata->ioaddr_nvram = ioaddr;  	pdata->size_nvram = pdata->size - RTC_SIZE;  	pdata->ioaddr_rtc = ioaddr + pdata->size_nvram; @@ -207,31 +203,19 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev)  	if (!(readb(ioaddr + RTC_DAY) & RTC_BATT_FLAG))  		dev_warn(&pdev->dev, "voltage-low detected.\n"); +	pdata->last_jiffies = jiffies; +	platform_set_drvdata(pdev, pdata);  	rtc = rtc_device_register(pdev->name, &pdev->dev,  				  &ds1742_rtc_ops, THIS_MODULE); -	if (IS_ERR(rtc)) { -		ret = PTR_ERR(rtc); -		goto out; -	} +	if (IS_ERR(rtc)) +		return PTR_ERR(rtc);  	pdata->rtc = rtc; -	pdata->last_jiffies = jiffies; -	platform_set_drvdata(pdev, pdata);  	ret = sysfs_create_bin_file(&pdev->dev.kobj, &pdata->nvram_attr);  	if (ret) {  		dev_err(&pdev->dev, "creating nvram file in sysfs failed\n"); -		goto out; +		rtc_device_unregister(rtc);  	} - -	return 0; - out: -	if (pdata->rtc) -		rtc_device_unregister(pdata->rtc); -	if (pdata->ioaddr_nvram) -		iounmap(pdata->ioaddr_nvram); -	if (pdata->baseaddr) -		release_mem_region(pdata->baseaddr, pdata->size); -	kfree(pdata);  	return ret;  } @@ -241,9 +225,6 @@ static int __devexit ds1742_rtc_remove(struct platform_device *pdev)  	sysfs_remove_bin_file(&pdev->dev.kobj, &pdata->nvram_attr);  	rtc_device_unregister(pdata->rtc); -	iounmap(pdata->ioaddr_nvram); -	release_mem_region(pdata->baseaddr, pdata->size); -	kfree(pdata);  	return 0;  } diff --git a/drivers/rtc/rtc-m48t35.c b/drivers/rtc/rtc-m48t35.c index 0b219755994..8cb5b8959e5 100644 --- a/drivers/rtc/rtc-m48t35.c +++ b/drivers/rtc/rtc-m48t35.c @@ -142,7 +142,6 @@ static const struct rtc_class_ops m48t35_ops = {  static int __devinit m48t35_probe(struct platform_device *pdev)  { -	struct rtc_device *rtc;  	struct resource *res;  	struct m48t35_priv *priv;  	int ret = 0; @@ -171,20 +170,21 @@ static int __devinit m48t35_probe(struct platform_device *pdev)  		ret = -ENOMEM;  		goto out;  	} +  	spin_lock_init(&priv->lock); -	rtc = rtc_device_register("m48t35", &pdev->dev, + +	platform_set_drvdata(pdev, priv); + +	priv->rtc = rtc_device_register("m48t35", &pdev->dev,  				  &m48t35_ops, THIS_MODULE); -	if (IS_ERR(rtc)) { -		ret = PTR_ERR(rtc); +	if (IS_ERR(priv->rtc)) { +		ret = PTR_ERR(priv->rtc);  		goto out;  	} -	priv->rtc = rtc; -	platform_set_drvdata(pdev, priv); +  	return 0;  out: -	if (priv->rtc) -		rtc_device_unregister(priv->rtc);  	if (priv->reg)  		iounmap(priv->reg);  	if (priv->baseaddr) diff --git a/drivers/rtc/rtc-m48t59.c b/drivers/rtc/rtc-m48t59.c index 33921a6b170..ede43b84685 100644 --- a/drivers/rtc/rtc-m48t59.c +++ b/drivers/rtc/rtc-m48t59.c @@ -481,6 +481,9 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)  		goto out;  	} +	spin_lock_init(&m48t59->lock); +	platform_set_drvdata(pdev, m48t59); +  	m48t59->rtc = rtc_device_register(name, &pdev->dev, ops, THIS_MODULE);  	if (IS_ERR(m48t59->rtc)) {  		ret = PTR_ERR(m48t59->rtc); @@ -490,16 +493,14 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)  	m48t59_nvram_attr.size = pdata->offset;  	ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr); -	if (ret) +	if (ret) { +		rtc_device_unregister(m48t59->rtc);  		goto out; +	} -	spin_lock_init(&m48t59->lock); -	platform_set_drvdata(pdev, m48t59);  	return 0;  out: -	if (!IS_ERR(m48t59->rtc)) -		rtc_device_unregister(m48t59->rtc);  	if (m48t59->irq != NO_IRQ)  		free_irq(m48t59->irq, &pdev->dev);  	if (m48t59->ioaddr) diff --git a/drivers/rtc/rtc-mc13783.c b/drivers/rtc/rtc-mc13783.c new file mode 100644 index 00000000000..850f983c039 --- /dev/null +++ b/drivers/rtc/rtc-mc13783.c @@ -0,0 +1,262 @@ +/* + * Real Time Clock driver for Freescale MC13783 PMIC + * + * (C) 2009 Sascha Hauer, Pengutronix + * (C) 2009 Uwe Kleine-Koenig, Pengutronix + * + * 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/mfd/mc13783.h> +#include <linux/platform_device.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/rtc.h> + +#define DRIVER_NAME "mc13783-rtc" + +#define MC13783_RTCTOD	20 +#define MC13783_RTCTODA	21 +#define MC13783_RTCDAY	22 +#define MC13783_RTCDAYA	23 + +struct mc13783_rtc { +	struct rtc_device *rtc; +	struct mc13783 *mc13783; +	int valid; +}; + +static int mc13783_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ +	struct mc13783_rtc *priv = dev_get_drvdata(dev); +	unsigned int seconds, days1, days2; +	unsigned long s1970; +	int ret; + +	mc13783_lock(priv->mc13783); + +	if (!priv->valid) { +		ret = -ENODATA; +		goto out; +	} + +	ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days1); +	if (unlikely(ret)) +		goto out; + +	ret = mc13783_reg_read(priv->mc13783, MC13783_RTCTOD, &seconds); +	if (unlikely(ret)) +		goto out; + +	ret = mc13783_reg_read(priv->mc13783, MC13783_RTCDAY, &days2); +out: +	mc13783_unlock(priv->mc13783); + +	if (ret) +		return ret; + +	if (days2 == days1 + 1) { +		if (seconds >= 86400 / 2) +			days2 = days1; +		else +			days1 = days2; +	} + +	if (days1 != days2) +		return -EIO; + +	s1970 = days1 * 86400 + seconds; + +	rtc_time_to_tm(s1970, tm); + +	return rtc_valid_tm(tm); +} + +static int mc13783_rtc_set_mmss(struct device *dev, unsigned long secs) +{ +	struct mc13783_rtc *priv = dev_get_drvdata(dev); +	unsigned int seconds, days; +	int ret; + +	seconds = secs % 86400; +	days = secs / 86400; + +	mc13783_lock(priv->mc13783); + +	/* +	 * first write seconds=0 to prevent a day switch between writing days +	 * and seconds below +	 */ +	ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTOD, 0); +	if (unlikely(ret)) +		goto out; + +	ret = mc13783_reg_write(priv->mc13783, MC13783_RTCDAY, days); +	if (unlikely(ret)) +		goto out; + +	ret = mc13783_reg_write(priv->mc13783, MC13783_RTCTOD, seconds); +	if (unlikely(ret)) +		goto out; + +	ret = mc13783_ackirq(priv->mc13783, MC13783_IRQ_RTCRST); +	if (unlikely(ret)) +		goto out; + +	ret = mc13783_unmask(priv->mc13783, MC13783_IRQ_RTCRST); +out: +	priv->valid = !ret; + +	mc13783_unlock(priv->mc13783); + +	return ret; +} + +static irqreturn_t mc13783_rtc_update_handler(int irq, void *dev) +{ +	struct mc13783_rtc *priv = dev; +	struct mc13783 *mc13783 = priv->mc13783; + +	dev_dbg(&priv->rtc->dev, "1HZ\n"); + +	rtc_update_irq(priv->rtc, 1, RTC_IRQF | RTC_UF); + +	mc13783_ackirq(mc13783, irq); + +	return IRQ_HANDLED; +} + +static int mc13783_rtc_update_irq_enable(struct device *dev, +		unsigned int enabled) +{ +	struct mc13783_rtc *priv = dev_get_drvdata(dev); +	int ret = -ENODATA; + +	mc13783_lock(priv->mc13783); +	if (!priv->valid) +		goto out; + +	ret = (enabled ? mc13783_unmask : mc13783_mask)(priv->mc13783, +			MC13783_IRQ_1HZ); +out: +	mc13783_unlock(priv->mc13783); + +	return ret; +} + +static const struct rtc_class_ops mc13783_rtc_ops = { +	.read_time = mc13783_rtc_read_time, +	.set_mmss = mc13783_rtc_set_mmss, +	.update_irq_enable = mc13783_rtc_update_irq_enable, +}; + +static irqreturn_t mc13783_rtc_reset_handler(int irq, void *dev) +{ +	struct mc13783_rtc *priv = dev; +	struct mc13783 *mc13783 = priv->mc13783; + +	dev_dbg(&priv->rtc->dev, "RTCRST\n"); +	priv->valid = 0; + +	mc13783_mask(mc13783, irq); + +	return IRQ_HANDLED; +} + +static int __devinit mc13783_rtc_probe(struct platform_device *pdev) +{ +	int ret; +	struct mc13783_rtc *priv; + +	priv = kzalloc(sizeof(*priv), GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	priv->mc13783 = dev_get_drvdata(pdev->dev.parent); +	platform_set_drvdata(pdev, priv); + +	priv->valid = 1; + +	mc13783_lock(priv->mc13783); + +	ret = mc13783_irq_request(priv->mc13783, MC13783_IRQ_RTCRST, +			mc13783_rtc_reset_handler, DRIVER_NAME, priv); +	if (ret) +		goto err_reset_irq_request; + +	ret = mc13783_irq_request_nounmask(priv->mc13783, MC13783_IRQ_1HZ, +			mc13783_rtc_update_handler, DRIVER_NAME, priv); +	if (ret) +		goto err_update_irq_request; + +	mc13783_unlock(priv->mc13783); + +	priv->rtc = rtc_device_register(pdev->name, +			&pdev->dev, &mc13783_rtc_ops, THIS_MODULE); + +	if (IS_ERR(priv->rtc)) { +		ret = PTR_ERR(priv->rtc); + +		mc13783_lock(priv->mc13783); + +		mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv); +err_update_irq_request: + +		mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv); +err_reset_irq_request: + +		mc13783_unlock(priv->mc13783); + +		platform_set_drvdata(pdev, NULL); +		kfree(priv); +	} + +	return ret; +} + +static int __devexit mc13783_rtc_remove(struct platform_device *pdev) +{ +	struct mc13783_rtc *priv = platform_get_drvdata(pdev); + +	rtc_device_unregister(priv->rtc); + +	mc13783_lock(priv->mc13783); + +	mc13783_irq_free(priv->mc13783, MC13783_IRQ_1HZ, priv); +	mc13783_irq_free(priv->mc13783, MC13783_IRQ_RTCRST, priv); + +	mc13783_unlock(priv->mc13783); + +	platform_set_drvdata(pdev, NULL); + +	kfree(priv); + +	return 0; +} + +static struct platform_driver mc13783_rtc_driver = { +	.remove = __devexit_p(mc13783_rtc_remove), +	.driver = { +		.name = DRIVER_NAME, +		.owner = THIS_MODULE, +	}, +}; + +static int __init mc13783_rtc_init(void) +{ +	return platform_driver_probe(&mc13783_rtc_driver, &mc13783_rtc_probe); +} +module_init(mc13783_rtc_init); + +static void __exit mc13783_rtc_exit(void) +{ +	platform_driver_unregister(&mc13783_rtc_driver); +} +module_exit(mc13783_rtc_exit); + +MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); +MODULE_DESCRIPTION("RTC driver for Freescale MC13783 PMIC"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:" DRIVER_NAME); diff --git a/drivers/rtc/rtc-msm6242.c b/drivers/rtc/rtc-msm6242.c new file mode 100644 index 00000000000..5f5968a4892 --- /dev/null +++ b/drivers/rtc/rtc-msm6242.c @@ -0,0 +1,269 @@ +/* + *  Oki MSM6242 RTC Driver + * + *  Copyright 2009 Geert Uytterhoeven + * + *  Based on the A2000 TOD code in arch/m68k/amiga/config.c + *  Copyright (C) 1993 Hamish Macdonald + */ + +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> + + +enum { +	MSM6242_SECOND1		= 0x0,	/* 1-second digit register */ +	MSM6242_SECOND10	= 0x1,	/* 10-second digit register */ +	MSM6242_MINUTE1		= 0x2,	/* 1-minute digit register */ +	MSM6242_MINUTE10	= 0x3,	/* 10-minute digit register */ +	MSM6242_HOUR1		= 0x4,	/* 1-hour digit register */ +	MSM6242_HOUR10		= 0x5,	/* PM/AM, 10-hour digit register */ +	MSM6242_DAY1		= 0x6,	/* 1-day digit register */ +	MSM6242_DAY10		= 0x7,	/* 10-day digit register */ +	MSM6242_MONTH1		= 0x8,	/* 1-month digit register */ +	MSM6242_MONTH10		= 0x9,	/* 10-month digit register */ +	MSM6242_YEAR1		= 0xa,	/* 1-year digit register */ +	MSM6242_YEAR10		= 0xb,	/* 10-year digit register */ +	MSM6242_WEEK		= 0xc,	/* Week register */ +	MSM6242_CD		= 0xd,	/* Control Register D */ +	MSM6242_CE		= 0xe,	/* Control Register E */ +	MSM6242_CF		= 0xf,	/* Control Register F */ +}; + +#define MSM6242_HOUR10_AM	(0 << 2) +#define MSM6242_HOUR10_PM	(1 << 2) +#define MSM6242_HOUR10_HR_MASK	(3 << 0) + +#define MSM6242_WEEK_SUNDAY	0 +#define MSM6242_WEEK_MONDAY	1 +#define MSM6242_WEEK_TUESDAY	2 +#define MSM6242_WEEK_WEDNESDAY	3 +#define MSM6242_WEEK_THURSDAY	4 +#define MSM6242_WEEK_FRIDAY	5 +#define MSM6242_WEEK_SATURDAY	6 + +#define MSM6242_CD_30_S_ADJ	(1 << 3)	/* 30-second adjustment */ +#define MSM6242_CD_IRQ_FLAG	(1 << 2) +#define MSM6242_CD_BUSY		(1 << 1) +#define MSM6242_CD_HOLD		(1 << 0) + +#define MSM6242_CE_T_MASK	(3 << 2) +#define MSM6242_CE_T_64HZ	(0 << 2)	/* period 1/64 second */ +#define MSM6242_CE_T_1HZ	(1 << 2)	/* period 1 second */ +#define MSM6242_CE_T_1MINUTE	(2 << 2)	/* period 1 minute */ +#define MSM6242_CE_T_1HOUR	(3 << 2)	/* period 1 hour */ + +#define MSM6242_CE_ITRPT_STND	(1 << 1) +#define MSM6242_CE_MASK		(1 << 0)	/* STD.P output control */ + +#define MSM6242_CF_TEST		(1 << 3) +#define MSM6242_CF_12H		(0 << 2) +#define MSM6242_CF_24H		(1 << 2) +#define MSM6242_CF_STOP		(1 << 1) +#define MSM6242_CF_REST		(1 << 0)	/* reset */ + + +struct msm6242_priv { +	u32 __iomem *regs; +	struct rtc_device *rtc; +}; + +static inline unsigned int msm6242_read(struct msm6242_priv *priv, +				       unsigned int reg) +{ +	return __raw_readl(&priv->regs[reg]) & 0xf; +} + +static inline void msm6242_write(struct msm6242_priv *priv, unsigned int val, +				unsigned int reg) +{ +	return __raw_writel(val, &priv->regs[reg]); +} + +static inline void msm6242_set(struct msm6242_priv *priv, unsigned int val, +			       unsigned int reg) +{ +	msm6242_write(priv, msm6242_read(priv, reg) | val, reg); +} + +static inline void msm6242_clear(struct msm6242_priv *priv, unsigned int val, +				 unsigned int reg) +{ +	msm6242_write(priv, msm6242_read(priv, reg) & ~val, reg); +} + +static void msm6242_lock(struct msm6242_priv *priv) +{ +	int cnt = 5; + +	msm6242_set(priv, MSM6242_CD_HOLD, MSM6242_CD); + +	while ((msm6242_read(priv, MSM6242_CD) & MSM6242_CD_BUSY) && cnt) { +		msm6242_clear(priv, MSM6242_CD_HOLD, MSM6242_CD); +		udelay(70); +		msm6242_set(priv, MSM6242_CD_HOLD, MSM6242_CD); +		cnt--; +	} + +	if (!cnt) +		pr_warning("msm6242: timed out waiting for RTC (0x%x)\n", +			   msm6242_read(priv, MSM6242_CD)); +} + +static void msm6242_unlock(struct msm6242_priv *priv) +{ +	msm6242_clear(priv, MSM6242_CD_HOLD, MSM6242_CD); +} + +static int msm6242_read_time(struct device *dev, struct rtc_time *tm) +{ +	struct msm6242_priv *priv = dev_get_drvdata(dev); + +	msm6242_lock(priv); + +	tm->tm_sec  = msm6242_read(priv, MSM6242_SECOND10) * 10 + +		      msm6242_read(priv, MSM6242_SECOND1); +	tm->tm_min  = msm6242_read(priv, MSM6242_MINUTE10) * 10 + +		      msm6242_read(priv, MSM6242_MINUTE1); +	tm->tm_hour = (msm6242_read(priv, MSM6242_HOUR10 & 3)) * 10 + +		      msm6242_read(priv, MSM6242_HOUR1); +	tm->tm_mday = msm6242_read(priv, MSM6242_DAY10) * 10 + +		      msm6242_read(priv, MSM6242_DAY1); +	tm->tm_wday = msm6242_read(priv, MSM6242_WEEK); +	tm->tm_mon  = msm6242_read(priv, MSM6242_MONTH10) * 10 + +		      msm6242_read(priv, MSM6242_MONTH1) - 1; +	tm->tm_year = msm6242_read(priv, MSM6242_YEAR10) * 10 + +		      msm6242_read(priv, MSM6242_YEAR1); +	if (tm->tm_year <= 69) +		tm->tm_year += 100; + +	if (!(msm6242_read(priv, MSM6242_CF) & MSM6242_CF_24H)) { +		unsigned int pm = msm6242_read(priv, MSM6242_HOUR10) & +				  MSM6242_HOUR10_PM; +		if (!pm && tm->tm_hour == 12) +			tm->tm_hour = 0; +		else if (pm && tm->tm_hour != 12) +			tm->tm_hour += 12; +	} + +	msm6242_unlock(priv); + +	return rtc_valid_tm(tm); +} + +static int msm6242_set_time(struct device *dev, struct rtc_time *tm) +{ +	struct msm6242_priv *priv = dev_get_drvdata(dev); + +	msm6242_lock(priv); + +	msm6242_write(priv, tm->tm_sec / 10, MSM6242_SECOND10); +	msm6242_write(priv, tm->tm_sec % 10, MSM6242_SECOND1); +	msm6242_write(priv, tm->tm_min / 10, MSM6242_MINUTE10); +	msm6242_write(priv, tm->tm_min % 10, MSM6242_MINUTE1); +	if (msm6242_read(priv, MSM6242_CF) & MSM6242_CF_24H) +		msm6242_write(priv, tm->tm_hour / 10, MSM6242_HOUR10); +	else if (tm->tm_hour >= 12) +		msm6242_write(priv, MSM6242_HOUR10_PM + (tm->tm_hour - 12) / 10, +			      MSM6242_HOUR10); +	else +		msm6242_write(priv, tm->tm_hour / 10, MSM6242_HOUR10); +	msm6242_write(priv, tm->tm_hour % 10, MSM6242_HOUR1); +	msm6242_write(priv, tm->tm_mday / 10, MSM6242_DAY10); +	msm6242_write(priv, tm->tm_mday % 10, MSM6242_DAY1); +	if (tm->tm_wday != -1) +		msm6242_write(priv, tm->tm_wday, MSM6242_WEEK); +	msm6242_write(priv, (tm->tm_mon + 1) / 10, MSM6242_MONTH10); +	msm6242_write(priv, (tm->tm_mon + 1) % 10, MSM6242_MONTH1); +	if (tm->tm_year >= 100) +		tm->tm_year -= 100; +	msm6242_write(priv, tm->tm_year / 10, MSM6242_YEAR10); +	msm6242_write(priv, tm->tm_year % 10, MSM6242_YEAR1); + +	msm6242_unlock(priv); +	return 0; +} + +static const struct rtc_class_ops msm6242_rtc_ops = { +	.read_time	= msm6242_read_time, +	.set_time	= msm6242_set_time, +}; + +static int __init msm6242_rtc_probe(struct platform_device *dev) +{ +	struct resource *res; +	struct msm6242_priv *priv; +	struct rtc_device *rtc; +	int error; + +	res = platform_get_resource(dev, IORESOURCE_MEM, 0); +	if (!res) +		return -ENODEV; + +	priv = kzalloc(sizeof(*priv), GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	priv->regs = ioremap(res->start, resource_size(res)); +	if (!priv->regs) { +		error = -ENOMEM; +		goto out_free_priv; +	} + +	rtc = rtc_device_register("rtc-msm6242", &dev->dev, &msm6242_rtc_ops, +				  THIS_MODULE); +	if (IS_ERR(rtc)) { +		error = PTR_ERR(rtc); +		goto out_unmap; +	} + +	priv->rtc = rtc; +	platform_set_drvdata(dev, priv); +	return 0; + +out_unmap: +	iounmap(priv->regs); +out_free_priv: +	kfree(priv); +	return error; +} + +static int __exit msm6242_rtc_remove(struct platform_device *dev) +{ +	struct msm6242_priv *priv = platform_get_drvdata(dev); + +	rtc_device_unregister(priv->rtc); +	iounmap(priv->regs); +	kfree(priv); +	return 0; +} + +static struct platform_driver msm6242_rtc_driver = { +	.driver	= { +		.name	= "rtc-msm6242", +		.owner	= THIS_MODULE, +	}, +	.remove	= __exit_p(msm6242_rtc_remove), +}; + +static int __init msm6242_rtc_init(void) +{ +	return platform_driver_probe(&msm6242_rtc_driver, msm6242_rtc_probe); +} + +static void __exit msm6242_rtc_fini(void) +{ +	platform_driver_unregister(&msm6242_rtc_driver); +} + +module_init(msm6242_rtc_init); +module_exit(msm6242_rtc_fini); + +MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Oki MSM6242 RTC driver"); +MODULE_ALIAS("platform:rtc-msm6242"); diff --git a/drivers/rtc/rtc-mv.c b/drivers/rtc/rtc-mv.c index e0263d2005e..dc052ce6e63 100644 --- a/drivers/rtc/rtc-mv.c +++ b/drivers/rtc/rtc-mv.c @@ -27,10 +27,17 @@  #define RTC_MONTH_OFFS		8  #define RTC_YEAR_OFFS		16 +#define RTC_ALARM_TIME_REG_OFFS	8 +#define RTC_ALARM_DATE_REG_OFFS	0xc +#define RTC_ALARM_VALID		(1 << 7) + +#define RTC_ALARM_INTERRUPT_MASK_REG_OFFS	0x10 +#define RTC_ALARM_INTERRUPT_CASUE_REG_OFFS	0x14  struct rtc_plat_data {  	struct rtc_device *rtc;  	void __iomem *ioaddr; +	int		irq;  };  static int mv_rtc_set_time(struct device *dev, struct rtc_time *tm) @@ -84,12 +91,134 @@ static int mv_rtc_read_time(struct device *dev, struct rtc_time *tm)  	return rtc_valid_tm(tm);  } +static int mv_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ +	struct rtc_plat_data *pdata = dev_get_drvdata(dev); +	void __iomem *ioaddr = pdata->ioaddr; +	u32	rtc_time, rtc_date; +	unsigned int year, month, day, hour, minute, second, wday; + +	rtc_time = readl(ioaddr + RTC_ALARM_TIME_REG_OFFS); +	rtc_date = readl(ioaddr + RTC_ALARM_DATE_REG_OFFS); + +	second = rtc_time & 0x7f; +	minute = (rtc_time >> RTC_MINUTES_OFFS) & 0x7f; +	hour = (rtc_time >> RTC_HOURS_OFFS) & 0x3f; /* assume 24 hours mode */ +	wday = (rtc_time >> RTC_WDAY_OFFS) & 0x7; + +	day = rtc_date & 0x3f; +	month = (rtc_date >> RTC_MONTH_OFFS) & 0x3f; +	year = (rtc_date >> RTC_YEAR_OFFS) & 0xff; + +	alm->time.tm_sec = bcd2bin(second); +	alm->time.tm_min = bcd2bin(minute); +	alm->time.tm_hour = bcd2bin(hour); +	alm->time.tm_mday = bcd2bin(day); +	alm->time.tm_wday = bcd2bin(wday); +	alm->time.tm_mon = bcd2bin(month) - 1; +	/* hw counts from year 2000, but tm_year is relative to 1900 */ +	alm->time.tm_year = bcd2bin(year) + 100; + +	if (rtc_valid_tm(&alm->time) < 0) { +		dev_err(dev, "retrieved alarm date/time is not valid.\n"); +		rtc_time_to_tm(0, &alm->time); +	} + +	alm->enabled = !!readl(ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); +	return 0; +} + +static int mv_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +{ +	struct rtc_plat_data *pdata = dev_get_drvdata(dev); +	void __iomem *ioaddr = pdata->ioaddr; +	u32 rtc_reg = 0; + +	if (alm->time.tm_sec >= 0) +		rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_sec)) +			<< RTC_SECONDS_OFFS; +	if (alm->time.tm_min >= 0) +		rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_min)) +			<< RTC_MINUTES_OFFS; +	if (alm->time.tm_hour >= 0) +		rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_hour)) +			<< RTC_HOURS_OFFS; + +	writel(rtc_reg, ioaddr + RTC_ALARM_TIME_REG_OFFS); + +	if (alm->time.tm_mday >= 0) +		rtc_reg = (RTC_ALARM_VALID | bin2bcd(alm->time.tm_mday)) +			<< RTC_MDAY_OFFS; +	else +		rtc_reg = 0; + +	if (alm->time.tm_mon >= 0) +		rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_mon + 1)) +			<< RTC_MONTH_OFFS; + +	if (alm->time.tm_year >= 0) +		rtc_reg |= (RTC_ALARM_VALID | bin2bcd(alm->time.tm_year % 100)) +			<< RTC_YEAR_OFFS; + +	writel(rtc_reg, ioaddr + RTC_ALARM_DATE_REG_OFFS); +	writel(0, ioaddr + RTC_ALARM_INTERRUPT_CASUE_REG_OFFS); +	writel(alm->enabled ? 1 : 0, +	       ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); + +	return 0; +} + +static int mv_rtc_ioctl(struct device *dev, unsigned int cmd, +			unsigned long arg) +{ +	struct platform_device *pdev = to_platform_device(dev); +	struct rtc_plat_data *pdata = platform_get_drvdata(pdev); +	void __iomem *ioaddr = pdata->ioaddr; + +	if (pdata->irq < 0) +		return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ +	switch (cmd) { +	case RTC_AIE_OFF: +		writel(0, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); +		break; +	case RTC_AIE_ON: +		writel(1, ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); +		break; +	default: +		return -ENOIOCTLCMD; +	} +	return 0; +} + +static irqreturn_t mv_rtc_interrupt(int irq, void *data) +{ +	struct rtc_plat_data *pdata = data; +	void __iomem *ioaddr = pdata->ioaddr; + +	/* alarm irq? */ +	if (!readl(ioaddr + RTC_ALARM_INTERRUPT_CASUE_REG_OFFS)) +		return IRQ_NONE; + +	/* clear interrupt */ +	writel(0, ioaddr + RTC_ALARM_INTERRUPT_CASUE_REG_OFFS); +	rtc_update_irq(pdata->rtc, 1, RTC_IRQF | RTC_AF); +	return IRQ_HANDLED; +} +  static const struct rtc_class_ops mv_rtc_ops = {  	.read_time	= mv_rtc_read_time,  	.set_time	= mv_rtc_set_time,  }; -static int __init mv_rtc_probe(struct platform_device *pdev) +static const struct rtc_class_ops mv_rtc_alarm_ops = { +	.read_time	= mv_rtc_read_time, +	.set_time	= mv_rtc_set_time, +	.read_alarm	= mv_rtc_read_alarm, +	.set_alarm	= mv_rtc_set_alarm, +	.ioctl		= mv_rtc_ioctl, +}; + +static int __devinit mv_rtc_probe(struct platform_device *pdev)  {  	struct resource *res;  	struct rtc_plat_data *pdata; @@ -130,12 +259,31 @@ static int __init mv_rtc_probe(struct platform_device *pdev)  		}  	} +	pdata->irq = platform_get_irq(pdev, 0); +  	platform_set_drvdata(pdev, pdata); -	pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, -					 &mv_rtc_ops, THIS_MODULE); + +	if (pdata->irq >= 0) { +		device_init_wakeup(&pdev->dev, 1); +		pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, +						 &mv_rtc_alarm_ops, +						 THIS_MODULE); +	} else +		pdata->rtc = rtc_device_register(pdev->name, &pdev->dev, +						 &mv_rtc_ops, THIS_MODULE);  	if (IS_ERR(pdata->rtc))  		return PTR_ERR(pdata->rtc); +	if (pdata->irq >= 0) { +		writel(0, pdata->ioaddr + RTC_ALARM_INTERRUPT_MASK_REG_OFFS); +		if (devm_request_irq(&pdev->dev, pdata->irq, mv_rtc_interrupt, +				     IRQF_DISABLED | IRQF_SHARED, +				     pdev->name, pdata) < 0) { +			dev_warn(&pdev->dev, "interrupt not available.\n"); +			pdata->irq = -1; +		} +	} +  	return 0;  } @@ -143,6 +291,9 @@ static int __exit mv_rtc_remove(struct platform_device *pdev)  {  	struct rtc_plat_data *pdata = platform_get_drvdata(pdev); +	if (pdata->irq >= 0) +		device_init_wakeup(&pdev->dev, 0); +  	rtc_device_unregister(pdata->rtc);  	return 0;  } diff --git a/drivers/rtc/rtc-nuc900.c b/drivers/rtc/rtc-nuc900.c new file mode 100644 index 00000000000..bf59c9c586b --- /dev/null +++ b/drivers/rtc/rtc-nuc900.c @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2008-2009 Nuvoton technology corporation. + * + * Wan ZongShun <mcuos.com@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;version 2 of the License. + * + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/delay.h> +#include <linux/io.h> +#include <linux/bcd.h> + +/* RTC Control Registers */ +#define REG_RTC_INIR		0x00 +#define REG_RTC_AER		0x04 +#define REG_RTC_FCR		0x08 +#define REG_RTC_TLR		0x0C +#define REG_RTC_CLR		0x10 +#define REG_RTC_TSSR		0x14 +#define REG_RTC_DWR		0x18 +#define REG_RTC_TAR		0x1C +#define REG_RTC_CAR		0x20 +#define REG_RTC_LIR		0x24 +#define REG_RTC_RIER		0x28 +#define REG_RTC_RIIR		0x2C +#define REG_RTC_TTR		0x30 + +#define RTCSET			0x01 +#define AERRWENB		0x10000 +#define INIRRESET		0xa5eb1357 +#define AERPOWERON		0xA965 +#define AERPOWEROFF		0x0000 +#define LEAPYEAR		0x0001 +#define TICKENB			0x80 +#define TICKINTENB		0x0002 +#define ALARMINTENB		0x0001 +#define MODE24			0x0001 + +struct nuc900_rtc { +	int			irq_num; +	void __iomem		*rtc_reg; +	struct rtc_device	*rtcdev; +}; + +struct nuc900_bcd_time { +	int bcd_sec; +	int bcd_min; +	int bcd_hour; +	int bcd_mday; +	int bcd_mon; +	int bcd_year; +}; + +static irqreturn_t nuc900_rtc_interrupt(int irq, void *_rtc) +{ +	struct nuc900_rtc *rtc = _rtc; +	unsigned long events = 0, rtc_irq; + +	rtc_irq = __raw_readl(rtc->rtc_reg + REG_RTC_RIIR); + +	if (rtc_irq & ALARMINTENB) { +		rtc_irq &= ~ALARMINTENB; +		__raw_writel(rtc_irq, rtc->rtc_reg + REG_RTC_RIIR); +		events |= RTC_AF | RTC_IRQF; +	} + +	if (rtc_irq & TICKINTENB) { +		rtc_irq &= ~TICKINTENB; +		__raw_writel(rtc_irq, rtc->rtc_reg + REG_RTC_RIIR); +		events |= RTC_UF | RTC_IRQF; +	} + +	rtc_update_irq(rtc->rtcdev, 1, events); + +	return IRQ_HANDLED; +} + +static int *check_rtc_access_enable(struct nuc900_rtc *nuc900_rtc) +{ +	unsigned int i; +	__raw_writel(INIRRESET, nuc900_rtc->rtc_reg + REG_RTC_INIR); + +	mdelay(10); + +	__raw_writel(AERPOWERON, nuc900_rtc->rtc_reg + REG_RTC_AER); + +	for (i = 0; i < 1000; i++) { +		if (__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB) +			return 0; +	} + +	if ((__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_AER) & AERRWENB) == 0x0) +		return ERR_PTR(-ENODEV); + +	return ERR_PTR(-EPERM); +} + +static void nuc900_rtc_bcd2bin(unsigned int timereg, +				unsigned int calreg, struct rtc_time *tm) +{ +	tm->tm_mday	= bcd2bin(calreg >> 0); +	tm->tm_mon	= bcd2bin(calreg >> 8); +	tm->tm_year	= bcd2bin(calreg >> 16) + 100; + +	tm->tm_sec	= bcd2bin(timereg >> 0); +	tm->tm_min	= bcd2bin(timereg >> 8); +	tm->tm_hour	= bcd2bin(timereg >> 16); + +	rtc_valid_tm(tm); +} + +static void nuc900_rtc_bin2bcd(struct rtc_time *settm, +						struct nuc900_bcd_time *gettm) +{ +	gettm->bcd_mday = bin2bcd(settm->tm_mday) << 0; +	gettm->bcd_mon  = bin2bcd(settm->tm_mon) << 8; +	gettm->bcd_year = bin2bcd(settm->tm_year - 100) << 16; + +	gettm->bcd_sec  = bin2bcd(settm->tm_sec) << 0; +	gettm->bcd_min  = bin2bcd(settm->tm_min) << 8; +	gettm->bcd_hour = bin2bcd(settm->tm_hour) << 16; +} + +static int nuc900_update_irq_enable(struct device *dev, unsigned int enabled) +{ +	struct nuc900_rtc *rtc = dev_get_drvdata(dev); + +	if (enabled) +		__raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)| +				(TICKINTENB), rtc->rtc_reg + REG_RTC_RIER); +	else +		__raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)& +				(~TICKINTENB), rtc->rtc_reg + REG_RTC_RIER); + +	return 0; +} + +static int nuc900_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ +	struct nuc900_rtc *rtc = dev_get_drvdata(dev); + +	if (enabled) +		__raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)| +				(ALARMINTENB), rtc->rtc_reg + REG_RTC_RIER); +	else +		__raw_writel(__raw_readl(rtc->rtc_reg + REG_RTC_RIER)& +				(~ALARMINTENB), rtc->rtc_reg + REG_RTC_RIER); + +	return 0; +} + +static int nuc900_rtc_read_time(struct device *dev, struct rtc_time *tm) +{ +	struct nuc900_rtc *rtc = dev_get_drvdata(dev); +	unsigned int timeval, clrval; + +	timeval = __raw_readl(rtc->rtc_reg + REG_RTC_TLR); +	clrval	= __raw_readl(rtc->rtc_reg + REG_RTC_CLR); + +	nuc900_rtc_bcd2bin(timeval, clrval, tm); + +	return 0; +} + +static int nuc900_rtc_set_time(struct device *dev, struct rtc_time *tm) +{ +	struct nuc900_rtc *rtc = dev_get_drvdata(dev); +	struct nuc900_bcd_time gettm; +	unsigned long val; +	int *err; + +	nuc900_rtc_bin2bcd(tm, &gettm); + +	err = check_rtc_access_enable(rtc); +	if (IS_ERR(err)) +		return PTR_ERR(err); + +	val = gettm.bcd_mday | gettm.bcd_mon | gettm.bcd_year; +	__raw_writel(val, rtc->rtc_reg + REG_RTC_CLR); + +	val = gettm.bcd_sec | gettm.bcd_min | gettm.bcd_hour; +	__raw_writel(val, rtc->rtc_reg + REG_RTC_TLR); + +	return 0; +} + +static int nuc900_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	struct nuc900_rtc *rtc = dev_get_drvdata(dev); +	unsigned int timeval, carval; + +	timeval = __raw_readl(rtc->rtc_reg + REG_RTC_TAR); +	carval	= __raw_readl(rtc->rtc_reg + REG_RTC_CAR); + +	nuc900_rtc_bcd2bin(timeval, carval, &alrm->time); + +	return 0; +} + +static int nuc900_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) +{ +	struct nuc900_rtc *rtc = dev_get_drvdata(dev); +	struct nuc900_bcd_time tm; +	unsigned long val; +	int *err; + +	nuc900_rtc_bin2bcd(&alrm->time, &tm); + +	err = check_rtc_access_enable(rtc); +	if (IS_ERR(err)) +		return PTR_ERR(err); + +	val = tm.bcd_mday | tm.bcd_mon | tm.bcd_year; +	__raw_writel(val, rtc->rtc_reg + REG_RTC_CAR); + +	val = tm.bcd_sec | tm.bcd_min | tm.bcd_hour; +	__raw_writel(val, rtc->rtc_reg + REG_RTC_TAR); + +	return 0; +} + +static struct rtc_class_ops nuc900_rtc_ops = { +	.read_time = nuc900_rtc_read_time, +	.set_time = nuc900_rtc_set_time, +	.read_alarm = nuc900_rtc_read_alarm, +	.set_alarm = nuc900_rtc_set_alarm, +	.alarm_irq_enable = nuc900_alarm_irq_enable, +	.update_irq_enable = nuc900_update_irq_enable, +}; + +static int __devinit nuc900_rtc_probe(struct platform_device *pdev) +{ +	struct resource *res; +	struct nuc900_rtc *nuc900_rtc; +	int err = 0; + +	nuc900_rtc = kzalloc(sizeof(struct nuc900_rtc), GFP_KERNEL); +	if (!nuc900_rtc) { +		dev_err(&pdev->dev, "kzalloc nuc900_rtc failed\n"); +		return -ENOMEM; +	} +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	if (!res) { +		dev_err(&pdev->dev, "platform_get_resource failed\n"); +		err = -ENXIO; +		goto fail1; +	} + +	if (!request_mem_region(res->start, resource_size(res), +				pdev->name)) { +		dev_err(&pdev->dev, "request_mem_region failed\n"); +		err = -EBUSY; +		goto fail1; +	} + +	nuc900_rtc->rtc_reg = ioremap(res->start, resource_size(res)); +	if (!nuc900_rtc->rtc_reg) { +		dev_err(&pdev->dev, "ioremap rtc_reg failed\n"); +		err = -ENOMEM; +		goto fail2; +	} + +	nuc900_rtc->irq_num = platform_get_irq(pdev, 0); +	if (request_irq(nuc900_rtc->irq_num, nuc900_rtc_interrupt, +				IRQF_DISABLED, "nuc900rtc", nuc900_rtc)) { +		dev_err(&pdev->dev, "NUC900 RTC request irq failed\n"); +		err = -EBUSY; +		goto fail3; +	} + +	nuc900_rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev, +						&nuc900_rtc_ops, THIS_MODULE); +	if (IS_ERR(nuc900_rtc->rtcdev)) { +		dev_err(&pdev->dev, "rtc device register faild\n"); +		err = PTR_ERR(nuc900_rtc->rtcdev); +		goto fail4; +	} + +	platform_set_drvdata(pdev, nuc900_rtc); +	__raw_writel(__raw_readl(nuc900_rtc->rtc_reg + REG_RTC_TSSR) | MODE24, +					nuc900_rtc->rtc_reg + REG_RTC_TSSR); + +	return 0; + +fail4:	free_irq(nuc900_rtc->irq_num, nuc900_rtc); +fail3:	iounmap(nuc900_rtc->rtc_reg); +fail2:	release_mem_region(res->start, resource_size(res)); +fail1:	kfree(nuc900_rtc); +	return err; +} + +static int __devexit nuc900_rtc_remove(struct platform_device *pdev) +{ +	struct nuc900_rtc *nuc900_rtc = platform_get_drvdata(pdev); +	struct resource *res; + +	rtc_device_unregister(nuc900_rtc->rtcdev); +	free_irq(nuc900_rtc->irq_num, nuc900_rtc); +	iounmap(nuc900_rtc->rtc_reg); + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	release_mem_region(res->start, resource_size(res)); + +	kfree(nuc900_rtc); + +	platform_set_drvdata(pdev, NULL); + +	return 0; +} + +static struct platform_driver nuc900_rtc_driver = { +	.remove		= __devexit_p(nuc900_rtc_remove), +	.driver		= { +		.name	= "nuc900-rtc", +		.owner	= THIS_MODULE, +	}, +}; + +static int __init nuc900_rtc_init(void) +{ +	return platform_driver_probe(&nuc900_rtc_driver, nuc900_rtc_probe); +} + +static void __exit nuc900_rtc_exit(void) +{ +	platform_driver_unregister(&nuc900_rtc_driver); +} + +module_init(nuc900_rtc_init); +module_exit(nuc900_rtc_exit); + +MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); +MODULE_DESCRIPTION("nuc910/nuc920 RTC driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:nuc900-rtc"); diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c index 0587d53987f..64d9727b722 100644 --- a/drivers/rtc/rtc-omap.c +++ b/drivers/rtc/rtc-omap.c @@ -87,9 +87,10 @@  #define OMAP_RTC_INTERRUPTS_IT_ALARM    (1<<3)  #define OMAP_RTC_INTERRUPTS_IT_TIMER    (1<<2) +static void __iomem	*rtc_base; -#define rtc_read(addr)		omap_readb(OMAP_RTC_BASE + (addr)) -#define rtc_write(val, addr)	omap_writeb(val, OMAP_RTC_BASE + (addr)) +#define rtc_read(addr)		__raw_readb(rtc_base + (addr)) +#define rtc_write(val, addr)	__raw_writeb(val, rtc_base + (addr))  /* we rely on the rtc framework to handle locking (rtc->ops_lock), @@ -330,32 +331,31 @@ static int __init omap_rtc_probe(struct platform_device *pdev)  		return -ENOENT;  	} -	/* NOTE:  using static mapping for RTC registers */  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); -	if (res && res->start != OMAP_RTC_BASE) { -		pr_debug("%s: RTC registers at %08x, expected %08x\n", -			pdev->name, (unsigned) res->start, OMAP_RTC_BASE); +	if (!res) { +		pr_debug("%s: RTC resource data missing\n", pdev->name);  		return -ENOENT;  	} -	if (res) -		mem = request_mem_region(res->start, -				res->end - res->start + 1, -				pdev->name); -	else -		mem = NULL; +	mem = request_mem_region(res->start, resource_size(res), pdev->name);  	if (!mem) {  		pr_debug("%s: RTC registers at %08x are not free\n", -			pdev->name, OMAP_RTC_BASE); +			pdev->name, res->start);  		return -EBUSY;  	} +	rtc_base = ioremap(res->start, resource_size(res)); +	if (!rtc_base) { +		pr_debug("%s: RTC registers can't be mapped\n", pdev->name); +		goto fail; +	} +  	rtc = rtc_device_register(pdev->name, &pdev->dev,  			&omap_rtc_ops, THIS_MODULE);  	if (IS_ERR(rtc)) {  		pr_debug("%s: can't register RTC device, err %ld\n",  			pdev->name, PTR_ERR(rtc)); -		goto fail; +		goto fail0;  	}  	platform_set_drvdata(pdev, rtc);  	dev_set_drvdata(&rtc->dev, mem); @@ -380,13 +380,14 @@ static int __init omap_rtc_probe(struct platform_device *pdev)  			dev_name(&rtc->dev), rtc)) {  		pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n",  			pdev->name, omap_rtc_timer); -		goto fail0; +		goto fail1;  	} -	if (request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED, -			dev_name(&rtc->dev), rtc)) { +	if ((omap_rtc_timer != omap_rtc_alarm) && +		(request_irq(omap_rtc_alarm, rtc_irq, IRQF_DISABLED, +			dev_name(&rtc->dev), rtc))) {  		pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n",  			pdev->name, omap_rtc_alarm); -		goto fail1; +		goto fail2;  	}  	/* On boards with split power, RTC_ON_NOFF won't reset the RTC */ @@ -419,10 +420,12 @@ static int __init omap_rtc_probe(struct platform_device *pdev)  	return 0; -fail1: +fail2:  	free_irq(omap_rtc_timer, NULL); -fail0: +fail1:  	rtc_device_unregister(rtc); +fail0: +	iounmap(rtc_base);  fail:  	release_resource(mem);  	return -EIO; @@ -438,7 +441,9 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)  	rtc_write(0, OMAP_RTC_INTERRUPTS_REG);  	free_irq(omap_rtc_timer, rtc); -	free_irq(omap_rtc_alarm, rtc); + +	if (omap_rtc_timer != omap_rtc_alarm) +		free_irq(omap_rtc_alarm, rtc);  	release_resource(dev_get_drvdata(&rtc->dev));  	rtc_device_unregister(rtc); diff --git a/drivers/rtc/rtc-pcf50633.c b/drivers/rtc/rtc-pcf50633.c index f4dd87e2907..854c3cb365a 100644 --- a/drivers/rtc/rtc-pcf50633.c +++ b/drivers/rtc/rtc-pcf50633.c @@ -58,6 +58,7 @@ struct pcf50633_time {  struct pcf50633_rtc {  	int alarm_enabled;  	int second_enabled; +	int alarm_pending;  	struct pcf50633 *pcf;  	struct rtc_device *rtc_dev; @@ -70,7 +71,7 @@ static void pcf2rtc_time(struct rtc_time *rtc, struct pcf50633_time *pcf)  	rtc->tm_hour = bcd2bin(pcf->time[PCF50633_TI_HOUR]);  	rtc->tm_wday = bcd2bin(pcf->time[PCF50633_TI_WKDAY]);  	rtc->tm_mday = bcd2bin(pcf->time[PCF50633_TI_DAY]); -	rtc->tm_mon = bcd2bin(pcf->time[PCF50633_TI_MONTH]); +	rtc->tm_mon = bcd2bin(pcf->time[PCF50633_TI_MONTH]) - 1;  	rtc->tm_year = bcd2bin(pcf->time[PCF50633_TI_YEAR]) + 100;  } @@ -81,7 +82,7 @@ static void rtc2pcf_time(struct pcf50633_time *pcf, struct rtc_time *rtc)  	pcf->time[PCF50633_TI_HOUR] = bin2bcd(rtc->tm_hour);  	pcf->time[PCF50633_TI_WKDAY] = bin2bcd(rtc->tm_wday);  	pcf->time[PCF50633_TI_DAY] = bin2bcd(rtc->tm_mday); -	pcf->time[PCF50633_TI_MONTH] = bin2bcd(rtc->tm_mon); +	pcf->time[PCF50633_TI_MONTH] = bin2bcd(rtc->tm_mon + 1);  	pcf->time[PCF50633_TI_YEAR] = bin2bcd(rtc->tm_year % 100);  } @@ -209,6 +210,7 @@ static int pcf50633_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)  	rtc = dev_get_drvdata(dev);  	alrm->enabled = rtc->alarm_enabled; +	alrm->pending = rtc->alarm_pending;  	ret = pcf50633_read_block(rtc->pcf, PCF50633_REG_RTCSCA,  				PCF50633_TI_EXTENT, &pcf_tm.time[0]); @@ -244,9 +246,12 @@ static int pcf50633_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)  	/* Returns 0 on success */  	ret = pcf50633_write_block(rtc->pcf, PCF50633_REG_RTCSCA,  				PCF50633_TI_EXTENT, &pcf_tm.time[0]); +	if (!alrm->enabled) +		rtc->alarm_pending = 0; -	if (!alarm_masked) +	if (!alarm_masked || alrm->enabled)  		pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM); +	rtc->alarm_enabled = alrm->enabled;  	return ret;  } @@ -267,6 +272,7 @@ static void pcf50633_rtc_irq(int irq, void *data)  	switch (irq) {  	case PCF50633_IRQ_ALARM:  		rtc_update_irq(rtc->rtc_dev, 1, RTC_AF | RTC_IRQF); +		rtc->alarm_pending = 1;  		break;  	case PCF50633_IRQ_SECOND:  		rtc_update_irq(rtc->rtc_dev, 1, RTC_UF | RTC_IRQF); @@ -276,23 +282,21 @@ static void pcf50633_rtc_irq(int irq, void *data)  static int __devinit pcf50633_rtc_probe(struct platform_device *pdev)  { -	struct pcf50633_subdev_pdata *pdata;  	struct pcf50633_rtc *rtc; -  	rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);  	if (!rtc)  		return -ENOMEM; -	pdata = pdev->dev.platform_data; -	rtc->pcf = pdata->pcf; +	rtc->pcf = dev_to_pcf50633(pdev->dev.parent);  	platform_set_drvdata(pdev, rtc);  	rtc->rtc_dev = rtc_device_register("pcf50633-rtc", &pdev->dev,  				&pcf50633_rtc_ops, THIS_MODULE);  	if (IS_ERR(rtc->rtc_dev)) { +		int ret =  PTR_ERR(rtc->rtc_dev);  		kfree(rtc); -		return PTR_ERR(rtc->rtc_dev); +		return ret;  	}  	pcf50633_register_irq(rtc->pcf, PCF50633_IRQ_ALARM, diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index b725913ccbe..65f346b2fba 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -212,6 +212,8 @@ static int pcf8563_probe(struct i2c_client *client,  	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); +	i2c_set_clientdata(client, pcf8563); +  	pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name,  				&client->dev, &pcf8563_rtc_ops, THIS_MODULE); @@ -220,8 +222,6 @@ static int pcf8563_probe(struct i2c_client *client,  		goto exit_kfree;  	} -	i2c_set_clientdata(client, pcf8563); -  	return 0;  exit_kfree: diff --git a/drivers/rtc/rtc-pcf8583.c b/drivers/rtc/rtc-pcf8583.c index 7d33cda3f8f..2d201afead3 100644 --- a/drivers/rtc/rtc-pcf8583.c +++ b/drivers/rtc/rtc-pcf8583.c @@ -277,6 +277,8 @@ static int pcf8583_probe(struct i2c_client *client,  	if (!pcf8583)  		return -ENOMEM; +	i2c_set_clientdata(client, pcf8583); +  	pcf8583->rtc = rtc_device_register(pcf8583_driver.driver.name,  			&client->dev, &pcf8583_rtc_ops, THIS_MODULE); @@ -285,7 +287,6 @@ static int pcf8583_probe(struct i2c_client *client,  		goto exit_kfree;  	} -	i2c_set_clientdata(client, pcf8583);  	return 0;  exit_kfree: diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index f41873f98f6..0264b117893 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -51,10 +51,10 @@ static int pl031_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)  	switch (cmd) {  	case RTC_AIE_OFF: -		__raw_writel(1, ldata->base + RTC_MIS); +		writel(1, ldata->base + RTC_MIS);  		return 0;  	case RTC_AIE_ON: -		__raw_writel(0, ldata->base + RTC_MIS); +		writel(0, ldata->base + RTC_MIS);  		return 0;  	} @@ -65,7 +65,7 @@ static int pl031_read_time(struct device *dev, struct rtc_time *tm)  {  	struct pl031_local *ldata = dev_get_drvdata(dev); -	rtc_time_to_tm(__raw_readl(ldata->base + RTC_DR), tm); +	rtc_time_to_tm(readl(ldata->base + RTC_DR), tm);  	return 0;  } @@ -76,7 +76,7 @@ static int pl031_set_time(struct device *dev, struct rtc_time *tm)  	struct pl031_local *ldata = dev_get_drvdata(dev);  	rtc_tm_to_time(tm, &time); -	__raw_writel(time, ldata->base + RTC_LR); +	writel(time, ldata->base + RTC_LR);  	return 0;  } @@ -85,9 +85,9 @@ static int pl031_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)  {  	struct pl031_local *ldata = dev_get_drvdata(dev); -	rtc_time_to_tm(__raw_readl(ldata->base + RTC_MR), &alarm->time); -	alarm->pending = __raw_readl(ldata->base + RTC_RIS); -	alarm->enabled = __raw_readl(ldata->base + RTC_IMSC); +	rtc_time_to_tm(readl(ldata->base + RTC_MR), &alarm->time); +	alarm->pending = readl(ldata->base + RTC_RIS); +	alarm->enabled = readl(ldata->base + RTC_IMSC);  	return 0;  } @@ -99,8 +99,8 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)  	rtc_tm_to_time(&alarm->time, &time); -	__raw_writel(time, ldata->base + RTC_MR); -	__raw_writel(!alarm->enabled, ldata->base + RTC_MIS); +	writel(time, ldata->base + RTC_MR); +	writel(!alarm->enabled, ldata->base + RTC_MIS);  	return 0;  } @@ -180,8 +180,9 @@ err_req:  static struct amba_id pl031_ids[] __initdata = {  	{ -		 .id = 0x00041031, -	 	.mask = 0x000fffff, }, +		.id = 0x00041031, +		.mask = 0x000fffff, +	},  	{0, 0},  }; diff --git a/drivers/rtc/rtc-pxa.c b/drivers/rtc/rtc-pxa.c index bb8cc05605a..e6351b743da 100644 --- a/drivers/rtc/rtc-pxa.c +++ b/drivers/rtc/rtc-pxa.c @@ -438,34 +438,37 @@ static int __exit pxa_rtc_remove(struct platform_device *pdev)  }  #ifdef CONFIG_PM -static int pxa_rtc_suspend(struct platform_device *pdev, pm_message_t state) +static int pxa_rtc_suspend(struct device *dev)  { -	struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); +	struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); -	if (device_may_wakeup(&pdev->dev)) +	if (device_may_wakeup(dev))  		enable_irq_wake(pxa_rtc->irq_Alrm);  	return 0;  } -static int pxa_rtc_resume(struct platform_device *pdev) +static int pxa_rtc_resume(struct device *dev)  { -	struct pxa_rtc *pxa_rtc = platform_get_drvdata(pdev); +	struct pxa_rtc *pxa_rtc = dev_get_drvdata(dev); -	if (device_may_wakeup(&pdev->dev)) +	if (device_may_wakeup(dev))  		disable_irq_wake(pxa_rtc->irq_Alrm);  	return 0;  } -#else -#define pxa_rtc_suspend	NULL -#define pxa_rtc_resume	NULL + +static const struct dev_pm_ops pxa_rtc_pm_ops = { +	.suspend	= pxa_rtc_suspend, +	.resume		= pxa_rtc_resume, +};  #endif  static struct platform_driver pxa_rtc_driver = {  	.remove		= __exit_p(pxa_rtc_remove), -	.suspend	= pxa_rtc_suspend, -	.resume		= pxa_rtc_resume,  	.driver		= { -		.name		= "pxa-rtc", +		.name	= "pxa-rtc", +#ifdef CONFIG_PM +		.pm	= &pxa_rtc_pm_ops, +#endif  	},  }; diff --git a/drivers/rtc/rtc-rp5c01.c b/drivers/rtc/rtc-rp5c01.c new file mode 100644 index 00000000000..e1313feb060 --- /dev/null +++ b/drivers/rtc/rtc-rp5c01.c @@ -0,0 +1,222 @@ +/* + *  Ricoh RP5C01 RTC Driver + * + *  Copyright 2009 Geert Uytterhoeven + * + *  Based on the A3000 TOD code in arch/m68k/amiga/config.c + *  Copyright (C) 1993 Hamish Macdonald + */ + +#include <linux/io.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> + + +enum { +	RP5C01_1_SECOND		= 0x0,	/* MODE 00 */ +	RP5C01_10_SECOND	= 0x1,	/* MODE 00 */ +	RP5C01_1_MINUTE		= 0x2,	/* MODE 00 and MODE 01 */ +	RP5C01_10_MINUTE	= 0x3,	/* MODE 00 and MODE 01 */ +	RP5C01_1_HOUR		= 0x4,	/* MODE 00 and MODE 01 */ +	RP5C01_10_HOUR		= 0x5,	/* MODE 00 and MODE 01 */ +	RP5C01_DAY_OF_WEEK	= 0x6,	/* MODE 00 and MODE 01 */ +	RP5C01_1_DAY		= 0x7,	/* MODE 00 and MODE 01 */ +	RP5C01_10_DAY		= 0x8,	/* MODE 00 and MODE 01 */ +	RP5C01_1_MONTH		= 0x9,	/* MODE 00 */ +	RP5C01_10_MONTH		= 0xa,	/* MODE 00 */ +	RP5C01_1_YEAR		= 0xb,	/* MODE 00 */ +	RP5C01_10_YEAR		= 0xc,	/* MODE 00 */ + +	RP5C01_12_24_SELECT	= 0xa,	/* MODE 01 */ +	RP5C01_LEAP_YEAR	= 0xb,	/* MODE 01 */ + +	RP5C01_MODE		= 0xd,	/* all modes */ +	RP5C01_TEST		= 0xe,	/* all modes */ +	RP5C01_RESET		= 0xf,	/* all modes */ +}; + +#define RP5C01_12_24_SELECT_12	(0 << 0) +#define RP5C01_12_24_SELECT_24	(1 << 0) + +#define RP5C01_10_HOUR_AM	(0 << 1) +#define RP5C01_10_HOUR_PM	(1 << 1) + +#define RP5C01_MODE_TIMER_EN	(1 << 3)	/* timer enable */ +#define RP5C01_MODE_ALARM_EN	(1 << 2)	/* alarm enable */ + +#define RP5C01_MODE_MODE_MASK	(3 << 0) +#define RP5C01_MODE_MODE00	(0 << 0)	/* time */ +#define RP5C01_MODE_MODE01	(1 << 0)	/* alarm, 12h/24h, leap year */ +#define RP5C01_MODE_RAM_BLOCK10	(2 << 0)	/* RAM 4 bits x 13 */ +#define RP5C01_MODE_RAM_BLOCK11	(3 << 0)	/* RAM 4 bits x 13 */ + +#define RP5C01_RESET_1HZ_PULSE	(1 << 3) +#define RP5C01_RESET_16HZ_PULSE	(1 << 2) +#define RP5C01_RESET_SECOND	(1 << 1)	/* reset divider stages for */ +						/* seconds or smaller units */ +#define RP5C01_RESET_ALARM	(1 << 0)	/* reset all alarm registers */ + + +struct rp5c01_priv { +	u32 __iomem *regs; +	struct rtc_device *rtc; +}; + +static inline unsigned int rp5c01_read(struct rp5c01_priv *priv, +				       unsigned int reg) +{ +	return __raw_readl(&priv->regs[reg]) & 0xf; +} + +static inline void rp5c01_write(struct rp5c01_priv *priv, unsigned int val, +				unsigned int reg) +{ +	return __raw_writel(val, &priv->regs[reg]); +} + +static void rp5c01_lock(struct rp5c01_priv *priv) +{ +	rp5c01_write(priv, RP5C01_MODE_MODE00, RP5C01_MODE); +} + +static void rp5c01_unlock(struct rp5c01_priv *priv) +{ +	rp5c01_write(priv, RP5C01_MODE_TIMER_EN | RP5C01_MODE_MODE01, +		     RP5C01_MODE); +} + +static int rp5c01_read_time(struct device *dev, struct rtc_time *tm) +{ +	struct rp5c01_priv *priv = dev_get_drvdata(dev); + +	rp5c01_lock(priv); + +	tm->tm_sec  = rp5c01_read(priv, RP5C01_10_SECOND) * 10 + +		      rp5c01_read(priv, RP5C01_1_SECOND); +	tm->tm_min  = rp5c01_read(priv, RP5C01_10_MINUTE) * 10 + +		      rp5c01_read(priv, RP5C01_1_MINUTE); +	tm->tm_hour = rp5c01_read(priv, RP5C01_10_HOUR) * 10 + +		      rp5c01_read(priv, RP5C01_1_HOUR); +	tm->tm_mday = rp5c01_read(priv, RP5C01_10_DAY) * 10 + +		      rp5c01_read(priv, RP5C01_1_DAY); +	tm->tm_wday = rp5c01_read(priv, RP5C01_DAY_OF_WEEK); +	tm->tm_mon  = rp5c01_read(priv, RP5C01_10_MONTH) * 10 + +		      rp5c01_read(priv, RP5C01_1_MONTH) - 1; +	tm->tm_year = rp5c01_read(priv, RP5C01_10_YEAR) * 10 + +		      rp5c01_read(priv, RP5C01_1_YEAR); +	if (tm->tm_year <= 69) +		tm->tm_year += 100; + +	rp5c01_unlock(priv); + +	return rtc_valid_tm(tm); +} + +static int rp5c01_set_time(struct device *dev, struct rtc_time *tm) +{ +	struct rp5c01_priv *priv = dev_get_drvdata(dev); + +	rp5c01_lock(priv); + +	rp5c01_write(priv, tm->tm_sec / 10, RP5C01_10_SECOND); +	rp5c01_write(priv, tm->tm_sec % 10, RP5C01_1_SECOND); +	rp5c01_write(priv, tm->tm_min / 10, RP5C01_10_MINUTE); +	rp5c01_write(priv, tm->tm_min % 10, RP5C01_1_MINUTE); +	rp5c01_write(priv, tm->tm_hour / 10, RP5C01_10_HOUR); +	rp5c01_write(priv, tm->tm_hour % 10, RP5C01_1_HOUR); +	rp5c01_write(priv, tm->tm_mday / 10, RP5C01_10_DAY); +	rp5c01_write(priv, tm->tm_mday % 10, RP5C01_1_DAY); +	if (tm->tm_wday != -1) +		rp5c01_write(priv, tm->tm_wday, RP5C01_DAY_OF_WEEK); +	rp5c01_write(priv, (tm->tm_mon + 1) / 10, RP5C01_10_MONTH); +	rp5c01_write(priv, (tm->tm_mon + 1) % 10, RP5C01_1_MONTH); +	if (tm->tm_year >= 100) +		tm->tm_year -= 100; +	rp5c01_write(priv, tm->tm_year / 10, RP5C01_10_YEAR); +	rp5c01_write(priv, tm->tm_year % 10, RP5C01_1_YEAR); + +	rp5c01_unlock(priv); +	return 0; +} + +static const struct rtc_class_ops rp5c01_rtc_ops = { +	.read_time	= rp5c01_read_time, +	.set_time	= rp5c01_set_time, +}; + +static int __init rp5c01_rtc_probe(struct platform_device *dev) +{ +	struct resource *res; +	struct rp5c01_priv *priv; +	struct rtc_device *rtc; +	int error; + +	res = platform_get_resource(dev, IORESOURCE_MEM, 0); +	if (!res) +		return -ENODEV; + +	priv = kzalloc(sizeof(*priv), GFP_KERNEL); +	if (!priv) +		return -ENOMEM; + +	priv->regs = ioremap(res->start, resource_size(res)); +	if (!priv->regs) { +		error = -ENOMEM; +		goto out_free_priv; +	} + +	rtc = rtc_device_register("rtc-rp5c01", &dev->dev, &rp5c01_rtc_ops, +				  THIS_MODULE); +	if (IS_ERR(rtc)) { +		error = PTR_ERR(rtc); +		goto out_unmap; +	} + +	priv->rtc = rtc; +	platform_set_drvdata(dev, priv); +	return 0; + +out_unmap: +	iounmap(priv->regs); +out_free_priv: +	kfree(priv); +	return error; +} + +static int __exit rp5c01_rtc_remove(struct platform_device *dev) +{ +	struct rp5c01_priv *priv = platform_get_drvdata(dev); + +	rtc_device_unregister(priv->rtc); +	iounmap(priv->regs); +	kfree(priv); +	return 0; +} + +static struct platform_driver rp5c01_rtc_driver = { +	.driver	= { +		.name	= "rtc-rp5c01", +		.owner	= THIS_MODULE, +	}, +	.remove	= __exit_p(rp5c01_rtc_remove), +}; + +static int __init rp5c01_rtc_init(void) +{ +	return platform_driver_probe(&rp5c01_rtc_driver, rp5c01_rtc_probe); +} + +static void __exit rp5c01_rtc_fini(void) +{ +	platform_driver_unregister(&rp5c01_rtc_driver); +} + +module_init(rp5c01_rtc_init); +module_exit(rp5c01_rtc_fini); + +MODULE_AUTHOR("Geert Uytterhoeven <geert@linux-m68k.org>"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Ricoh RP5C01 RTC driver"); +MODULE_ALIAS("platform:rtc-rp5c01"); diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 021b2928f0b..e4a44b64170 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -393,31 +393,34 @@ static int sa1100_rtc_remove(struct platform_device *pdev)  }  #ifdef CONFIG_PM -static int sa1100_rtc_suspend(struct platform_device *pdev, pm_message_t state) +static int sa1100_rtc_suspend(struct device *dev)  { -	if (device_may_wakeup(&pdev->dev)) +	if (device_may_wakeup(dev))  		enable_irq_wake(IRQ_RTCAlrm);  	return 0;  } -static int sa1100_rtc_resume(struct platform_device *pdev) +static int sa1100_rtc_resume(struct device *dev)  { -	if (device_may_wakeup(&pdev->dev)) +	if (device_may_wakeup(dev))  		disable_irq_wake(IRQ_RTCAlrm);  	return 0;  } -#else -#define sa1100_rtc_suspend	NULL -#define sa1100_rtc_resume	NULL + +static const struct dev_pm_ops sa1100_rtc_pm_ops = { +	.suspend	= sa1100_rtc_suspend, +	.resume		= sa1100_rtc_resume, +};  #endif  static struct platform_driver sa1100_rtc_driver = {  	.probe		= sa1100_rtc_probe,  	.remove		= sa1100_rtc_remove, -	.suspend	= sa1100_rtc_suspend, -	.resume		= sa1100_rtc_resume,  	.driver		= { -		.name		= "sa1100-rtc", +		.name	= "sa1100-rtc", +#ifdef CONFIG_PM +		.pm	= &sa1100_rtc_pm_ops, +#endif  	},  }; diff --git a/drivers/rtc/rtc-sh.c b/drivers/rtc/rtc-sh.c index e6ed5404bca..e95cc6f8d61 100644 --- a/drivers/rtc/rtc-sh.c +++ b/drivers/rtc/rtc-sh.c @@ -826,7 +826,7 @@ static int sh_rtc_resume(struct device *dev)  	return 0;  } -static struct dev_pm_ops sh_rtc_dev_pm_ops = { +static const struct dev_pm_ops sh_rtc_dev_pm_ops = {  	.suspend = sh_rtc_suspend,  	.resume = sh_rtc_resume,  }; diff --git a/drivers/rtc/rtc-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c index 7d1547b0070..67700831b5c 100644 --- a/drivers/rtc/rtc-stk17ta8.c +++ b/drivers/rtc/rtc-stk17ta8.c @@ -62,7 +62,6 @@  struct rtc_plat_data {  	struct rtc_device *rtc;  	void __iomem *ioaddr; -	unsigned long baseaddr;  	unsigned long last_jiffies;  	int irq;  	unsigned int irqen; @@ -70,6 +69,7 @@ struct rtc_plat_data {  	int alrm_min;  	int alrm_hour;  	int alrm_mday; +	spinlock_t lock;  };  static int stk17ta8_rtc_set_time(struct device *dev, struct rtc_time *tm) @@ -142,7 +142,7 @@ static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata)  	unsigned long irqflags;  	u8 flags; -	spin_lock_irqsave(&pdata->rtc->irq_lock, irqflags); +	spin_lock_irqsave(&pdata->lock, irqflags);  	flags = readb(ioaddr + RTC_FLAGS);  	writeb(flags | RTC_WRITE, ioaddr + RTC_FLAGS); @@ -162,7 +162,7 @@ static void stk17ta8_rtc_update_alarm(struct rtc_plat_data *pdata)  	writeb(pdata->irqen ? RTC_INTS_AIE : 0, ioaddr + RTC_INTERRUPTS);  	readb(ioaddr + RTC_FLAGS);	/* clear interrupts */  	writeb(flags & ~RTC_WRITE, ioaddr + RTC_FLAGS); -	spin_unlock_irqrestore(&pdata->rtc->irq_lock, irqflags); +	spin_unlock_irqrestore(&pdata->lock, irqflags);  }  static int stk17ta8_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm) @@ -202,56 +202,53 @@ static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)  	struct platform_device *pdev = dev_id;  	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);  	void __iomem *ioaddr = pdata->ioaddr; -	unsigned long events = RTC_IRQF; +	unsigned long events = 0; +	spin_lock(&pdata->lock);  	/* read and clear interrupt */ -	if (!(readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF)) -		return IRQ_NONE; -	if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) -		events |= RTC_UF; -	else -		events |= RTC_AF; -	rtc_update_irq(pdata->rtc, 1, events); -	return IRQ_HANDLED; +	if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_AF) { +		events = RTC_IRQF; +		if (readb(ioaddr + RTC_SECONDS_ALARM) & 0x80) +			events |= RTC_UF; +		else +			events |= RTC_AF; +		if (likely(pdata->rtc)) +			rtc_update_irq(pdata->rtc, 1, events); +	} +	spin_unlock(&pdata->lock); +	return events ? IRQ_HANDLED : IRQ_NONE;  } -static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd, -			    unsigned long arg) +static int stk17ta8_rtc_alarm_irq_enable(struct device *dev, +	unsigned int enabled)  {  	struct platform_device *pdev = to_platform_device(dev);  	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);  	if (pdata->irq <= 0) -		return -ENOIOCTLCMD; /* fall back into rtc-dev's emulation */ -	switch (cmd) { -	case RTC_AIE_OFF: -		pdata->irqen &= ~RTC_AF; -		stk17ta8_rtc_update_alarm(pdata); -		break; -	case RTC_AIE_ON: +		return -EINVAL; +	if (enabled)  		pdata->irqen |= RTC_AF; -		stk17ta8_rtc_update_alarm(pdata); -		break; -	default: -		return -ENOIOCTLCMD; -	} +	else +		pdata->irqen &= ~RTC_AF; +	stk17ta8_rtc_update_alarm(pdata);  	return 0;  }  static const struct rtc_class_ops stk17ta8_rtc_ops = { -	.read_time	= stk17ta8_rtc_read_time, -	.set_time	= stk17ta8_rtc_set_time, -	.read_alarm	= stk17ta8_rtc_read_alarm, -	.set_alarm	= stk17ta8_rtc_set_alarm, -	.ioctl		= stk17ta8_rtc_ioctl, +	.read_time		= stk17ta8_rtc_read_time, +	.set_time		= stk17ta8_rtc_set_time, +	.read_alarm		= stk17ta8_rtc_read_alarm, +	.set_alarm		= stk17ta8_rtc_set_alarm, +	.alarm_irq_enable	= stk17ta8_rtc_alarm_irq_enable,  };  static ssize_t stk17ta8_nvram_read(struct kobject *kobj,  				 struct bin_attribute *attr, char *buf,  				 loff_t pos, size_t size)  { -	struct platform_device *pdev = -		to_platform_device(container_of(kobj, struct device, kobj)); +	struct device *dev = container_of(kobj, struct device, kobj); +	struct platform_device *pdev = to_platform_device(dev);  	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);  	void __iomem *ioaddr = pdata->ioaddr;  	ssize_t count; @@ -265,8 +262,8 @@ static ssize_t stk17ta8_nvram_write(struct kobject *kobj,  				  struct bin_attribute *attr, char *buf,  				  loff_t pos, size_t size)  { -	struct platform_device *pdev = -		to_platform_device(container_of(kobj, struct device, kobj)); +	struct device *dev = container_of(kobj, struct device, kobj); +	struct platform_device *pdev = to_platform_device(dev);  	struct rtc_plat_data *pdata = platform_get_drvdata(pdev);  	void __iomem *ioaddr = pdata->ioaddr;  	ssize_t count; @@ -286,33 +283,28 @@ static struct bin_attribute stk17ta8_nvram_attr = {  	.write = stk17ta8_nvram_write,  }; -static int __init stk17ta8_rtc_probe(struct platform_device *pdev) +static int __devinit stk17ta8_rtc_probe(struct platform_device *pdev)  { -	struct rtc_device *rtc;  	struct resource *res;  	unsigned int cal;  	unsigned int flags;  	struct rtc_plat_data *pdata; -	void __iomem *ioaddr = NULL; +	void __iomem *ioaddr;  	int ret = 0;  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);  	if (!res)  		return -ENODEV; -	pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); +	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);  	if (!pdata)  		return -ENOMEM; -	if (!request_mem_region(res->start, RTC_REG_SIZE, pdev->name)) { -		ret = -EBUSY; -		goto out; -	} -	pdata->baseaddr = res->start; -	ioaddr = ioremap(pdata->baseaddr, RTC_REG_SIZE); -	if (!ioaddr) { -		ret = -ENOMEM; -		goto out; -	} +	if (!devm_request_mem_region(&pdev->dev, res->start, RTC_REG_SIZE, +			pdev->name)) +		return -EBUSY; +	ioaddr = devm_ioremap(&pdev->dev, res->start, RTC_REG_SIZE); +	if (!ioaddr) +		return -ENOMEM;  	pdata->ioaddr = ioaddr;  	pdata->irq = platform_get_irq(pdev, 0); @@ -328,9 +320,13 @@ static int __init stk17ta8_rtc_probe(struct platform_device *pdev)  	if (readb(ioaddr + RTC_FLAGS) & RTC_FLAGS_PF)  		dev_warn(&pdev->dev, "voltage-low detected.\n"); +	spin_lock_init(&pdata->lock); +	pdata->last_jiffies = jiffies; +	platform_set_drvdata(pdev, pdata);  	if (pdata->irq > 0) {  		writeb(0, ioaddr + RTC_INTERRUPTS); -		if (request_irq(pdata->irq, stk17ta8_rtc_interrupt, +		if (devm_request_irq(&pdev->dev, pdata->irq, +				stk17ta8_rtc_interrupt,  				IRQF_DISABLED | IRQF_SHARED,  				pdev->name, pdev) < 0) {  			dev_warn(&pdev->dev, "interrupt not available.\n"); @@ -338,29 +334,14 @@ static int __init stk17ta8_rtc_probe(struct platform_device *pdev)  		}  	} -	rtc = rtc_device_register(pdev->name, &pdev->dev, +	pdata->rtc = rtc_device_register(pdev->name, &pdev->dev,  				  &stk17ta8_rtc_ops, THIS_MODULE); -	if (IS_ERR(rtc)) { -		ret = PTR_ERR(rtc); -		goto out; -	} -	pdata->rtc = rtc; -	pdata->last_jiffies = jiffies; -	platform_set_drvdata(pdev, pdata); +	if (IS_ERR(pdata->rtc)) +		return PTR_ERR(pdata->rtc); +  	ret = sysfs_create_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);  	if (ret) -		goto out; -	return 0; - out: -	if (pdata->rtc)  		rtc_device_unregister(pdata->rtc); -	if (pdata->irq > 0) -		free_irq(pdata->irq, pdev); -	if (ioaddr) -		iounmap(ioaddr); -	if (pdata->baseaddr) -		release_mem_region(pdata->baseaddr, RTC_REG_SIZE); -	kfree(pdata);  	return ret;  } @@ -370,13 +351,8 @@ static int __devexit stk17ta8_rtc_remove(struct platform_device *pdev)  	sysfs_remove_bin_file(&pdev->dev.kobj, &stk17ta8_nvram_attr);  	rtc_device_unregister(pdata->rtc); -	if (pdata->irq > 0) { +	if (pdata->irq > 0)  		writeb(0, pdata->ioaddr + RTC_INTERRUPTS); -		free_irq(pdata->irq, pdev); -	} -	iounmap(pdata->ioaddr); -	release_mem_region(pdata->baseaddr, RTC_REG_SIZE); -	kfree(pdata);  	return 0;  } diff --git a/drivers/rtc/rtc-twl4030.c b/drivers/rtc/rtc-twl.c index 9c8c70c497d..c6a83a2a722 100644 --- a/drivers/rtc/rtc-twl4030.c +++ b/drivers/rtc/rtc-twl.c @@ -1,5 +1,5 @@  /* - * rtc-twl4030.c -- TWL4030 Real Time Clock interface + * rtc-twl.c -- TWL Real Time Clock interface   *   * Copyright (C) 2007 MontaVista Software, Inc   * Author: Alexandre Rusev <source@mvista.com> @@ -28,33 +28,81 @@  #include <linux/platform_device.h>  #include <linux/interrupt.h> -#include <linux/i2c/twl4030.h> +#include <linux/i2c/twl.h>  /*   * RTC block register offsets (use TWL_MODULE_RTC)   */ -#define REG_SECONDS_REG                          0x00 -#define REG_MINUTES_REG                          0x01 -#define REG_HOURS_REG                            0x02 -#define REG_DAYS_REG                             0x03 -#define REG_MONTHS_REG                           0x04 -#define REG_YEARS_REG                            0x05 -#define REG_WEEKS_REG                            0x06 - -#define REG_ALARM_SECONDS_REG                    0x07 -#define REG_ALARM_MINUTES_REG                    0x08 -#define REG_ALARM_HOURS_REG                      0x09 -#define REG_ALARM_DAYS_REG                       0x0A -#define REG_ALARM_MONTHS_REG                     0x0B -#define REG_ALARM_YEARS_REG                      0x0C - -#define REG_RTC_CTRL_REG                         0x0D -#define REG_RTC_STATUS_REG                       0x0E -#define REG_RTC_INTERRUPTS_REG                   0x0F - -#define REG_RTC_COMP_LSB_REG                     0x10 -#define REG_RTC_COMP_MSB_REG                     0x11 +enum { +	REG_SECONDS_REG = 0, +	REG_MINUTES_REG, +	REG_HOURS_REG, +	REG_DAYS_REG, +	REG_MONTHS_REG, +	REG_YEARS_REG, +	REG_WEEKS_REG, + +	REG_ALARM_SECONDS_REG, +	REG_ALARM_MINUTES_REG, +	REG_ALARM_HOURS_REG, +	REG_ALARM_DAYS_REG, +	REG_ALARM_MONTHS_REG, +	REG_ALARM_YEARS_REG, + +	REG_RTC_CTRL_REG, +	REG_RTC_STATUS_REG, +	REG_RTC_INTERRUPTS_REG, + +	REG_RTC_COMP_LSB_REG, +	REG_RTC_COMP_MSB_REG, +}; +const static u8 twl4030_rtc_reg_map[] = { +	[REG_SECONDS_REG] = 0x00, +	[REG_MINUTES_REG] = 0x01, +	[REG_HOURS_REG] = 0x02, +	[REG_DAYS_REG] = 0x03, +	[REG_MONTHS_REG] = 0x04, +	[REG_YEARS_REG] = 0x05, +	[REG_WEEKS_REG] = 0x06, + +	[REG_ALARM_SECONDS_REG] = 0x07, +	[REG_ALARM_MINUTES_REG] = 0x08, +	[REG_ALARM_HOURS_REG] = 0x09, +	[REG_ALARM_DAYS_REG] = 0x0A, +	[REG_ALARM_MONTHS_REG] = 0x0B, +	[REG_ALARM_YEARS_REG] = 0x0C, + +	[REG_RTC_CTRL_REG] = 0x0D, +	[REG_RTC_STATUS_REG] = 0x0E, +	[REG_RTC_INTERRUPTS_REG] = 0x0F, + +	[REG_RTC_COMP_LSB_REG] = 0x10, +	[REG_RTC_COMP_MSB_REG] = 0x11, +}; +const static u8 twl6030_rtc_reg_map[] = { +	[REG_SECONDS_REG] = 0x00, +	[REG_MINUTES_REG] = 0x01, +	[REG_HOURS_REG] = 0x02, +	[REG_DAYS_REG] = 0x03, +	[REG_MONTHS_REG] = 0x04, +	[REG_YEARS_REG] = 0x05, +	[REG_WEEKS_REG] = 0x06, + +	[REG_ALARM_SECONDS_REG] = 0x08, +	[REG_ALARM_MINUTES_REG] = 0x09, +	[REG_ALARM_HOURS_REG] = 0x0A, +	[REG_ALARM_DAYS_REG] = 0x0B, +	[REG_ALARM_MONTHS_REG] = 0x0C, +	[REG_ALARM_YEARS_REG] = 0x0D, + +	[REG_RTC_CTRL_REG] = 0x10, +	[REG_RTC_STATUS_REG] = 0x11, +	[REG_RTC_INTERRUPTS_REG] = 0x12, + +	[REG_RTC_COMP_LSB_REG] = 0x13, +	[REG_RTC_COMP_MSB_REG] = 0x14, +};  /* RTC_CTRL_REG bitfields */  #define BIT_RTC_CTRL_REG_STOP_RTC_M              0x01 @@ -84,31 +132,32 @@  #define ALL_TIME_REGS		6  /*----------------------------------------------------------------------*/ +static u8  *rtc_reg_map;  /* - * Supports 1 byte read from TWL4030 RTC register. + * Supports 1 byte read from TWL RTC register.   */ -static int twl4030_rtc_read_u8(u8 *data, u8 reg) +static int twl_rtc_read_u8(u8 *data, u8 reg)  {  	int ret; -	ret = twl4030_i2c_read_u8(TWL4030_MODULE_RTC, data, reg); +	ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg]));  	if (ret < 0) -		pr_err("twl4030_rtc: Could not read TWL4030" +		pr_err("twl_rtc: Could not read TWL"  		       "register %X - error %d\n", reg, ret);  	return ret;  }  /* - * Supports 1 byte write to TWL4030 RTC registers. + * Supports 1 byte write to TWL RTC registers.   */ -static int twl4030_rtc_write_u8(u8 data, u8 reg) +static int twl_rtc_write_u8(u8 data, u8 reg)  {  	int ret; -	ret = twl4030_i2c_write_u8(TWL4030_MODULE_RTC, data, reg); +	ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (rtc_reg_map[reg]));  	if (ret < 0) -		pr_err("twl4030_rtc: Could not write TWL4030" +		pr_err("twl_rtc: Could not write TWL"  		       "register %X - error %d\n", reg, ret);  	return ret;  } @@ -129,7 +178,7 @@ static int set_rtc_irq_bit(unsigned char bit)  	val = rtc_irq_bits | bit;  	val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M; -	ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); +	ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);  	if (ret == 0)  		rtc_irq_bits = val; @@ -145,14 +194,14 @@ static int mask_rtc_irq_bit(unsigned char bit)  	int ret;  	val = rtc_irq_bits & ~bit; -	ret = twl4030_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG); +	ret = twl_rtc_write_u8(val, REG_RTC_INTERRUPTS_REG);  	if (ret == 0)  		rtc_irq_bits = val;  	return ret;  } -static int twl4030_rtc_alarm_irq_enable(struct device *dev, unsigned enabled) +static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)  {  	int ret; @@ -164,7 +213,7 @@ static int twl4030_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)  	return ret;  } -static int twl4030_rtc_update_irq_enable(struct device *dev, unsigned enabled) +static int twl_rtc_update_irq_enable(struct device *dev, unsigned enabled)  {  	int ret; @@ -177,7 +226,7 @@ static int twl4030_rtc_update_irq_enable(struct device *dev, unsigned enabled)  }  /* - * Gets current TWL4030 RTC time and date parameters. + * Gets current TWL RTC time and date parameters.   *   * The RTC's time/alarm representation is not what gmtime(3) requires   * Linux to use: @@ -185,24 +234,24 @@ static int twl4030_rtc_update_irq_enable(struct device *dev, unsigned enabled)   *  - Months are 1..12 vs Linux 0-11   *  - Years are 0..99 vs Linux 1900..N (we assume 21st century)   */ -static int twl4030_rtc_read_time(struct device *dev, struct rtc_time *tm) +static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)  {  	unsigned char rtc_data[ALL_TIME_REGS + 1];  	int ret;  	u8 save_control; -	ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); +	ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);  	if (ret < 0)  		return ret;  	save_control |= BIT_RTC_CTRL_REG_GET_TIME_M; -	ret = twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG); +	ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);  	if (ret < 0)  		return ret; -	ret = twl4030_i2c_read(TWL4030_MODULE_RTC, rtc_data, -			       REG_SECONDS_REG, ALL_TIME_REGS); +	ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, +			(rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);  	if (ret < 0) {  		dev_err(dev, "rtc_read_time error %d\n", ret); @@ -219,7 +268,7 @@ static int twl4030_rtc_read_time(struct device *dev, struct rtc_time *tm)  	return ret;  } -static int twl4030_rtc_set_time(struct device *dev, struct rtc_time *tm) +static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)  {  	unsigned char save_control;  	unsigned char rtc_data[ALL_TIME_REGS + 1]; @@ -233,18 +282,18 @@ static int twl4030_rtc_set_time(struct device *dev, struct rtc_time *tm)  	rtc_data[6] = bin2bcd(tm->tm_year - 100);  	/* Stop RTC while updating the TC registers */ -	ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG); +	ret = twl_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);  	if (ret < 0)  		goto out;  	save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M; -	twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG); +	twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);  	if (ret < 0)  		goto out;  	/* update all the time registers in one shot */ -	ret = twl4030_i2c_write(TWL4030_MODULE_RTC, rtc_data, -			REG_SECONDS_REG, ALL_TIME_REGS); +	ret = twl_i2c_write(TWL_MODULE_RTC, rtc_data, +		(rtc_reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);  	if (ret < 0) {  		dev_err(dev, "rtc_set_time error %d\n", ret);  		goto out; @@ -252,22 +301,22 @@ static int twl4030_rtc_set_time(struct device *dev, struct rtc_time *tm)  	/* Start back RTC */  	save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M; -	ret = twl4030_rtc_write_u8(save_control, REG_RTC_CTRL_REG); +	ret = twl_rtc_write_u8(save_control, REG_RTC_CTRL_REG);  out:  	return ret;  }  /* - * Gets current TWL4030 RTC alarm time. + * Gets current TWL RTC alarm time.   */ -static int twl4030_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm) +static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)  {  	unsigned char rtc_data[ALL_TIME_REGS + 1];  	int ret; -	ret = twl4030_i2c_read(TWL4030_MODULE_RTC, rtc_data, -			       REG_ALARM_SECONDS_REG, ALL_TIME_REGS); +	ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data, +			(rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS);  	if (ret < 0) {  		dev_err(dev, "rtc_read_alarm error %d\n", ret);  		return ret; @@ -288,12 +337,12 @@ static int twl4030_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)  	return ret;  } -static int twl4030_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm) +static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)  {  	unsigned char alarm_data[ALL_TIME_REGS + 1];  	int ret; -	ret = twl4030_rtc_alarm_irq_enable(dev, 0); +	ret = twl_rtc_alarm_irq_enable(dev, 0);  	if (ret)  		goto out; @@ -305,20 +354,20 @@ static int twl4030_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)  	alarm_data[6] = bin2bcd(alm->time.tm_year - 100);  	/* update all the alarm registers in one shot */ -	ret = twl4030_i2c_write(TWL4030_MODULE_RTC, alarm_data, -			REG_ALARM_SECONDS_REG, ALL_TIME_REGS); +	ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data, +		(rtc_reg_map[REG_ALARM_SECONDS_REG]), ALL_TIME_REGS);  	if (ret) {  		dev_err(dev, "rtc_set_alarm error %d\n", ret);  		goto out;  	}  	if (alm->enabled) -		ret = twl4030_rtc_alarm_irq_enable(dev, 1); +		ret = twl_rtc_alarm_irq_enable(dev, 1);  out:  	return ret;  } -static irqreturn_t twl4030_rtc_interrupt(int irq, void *rtc) +static irqreturn_t twl_rtc_interrupt(int irq, void *rtc)  {  	unsigned long events = 0;  	int ret = IRQ_NONE; @@ -333,7 +382,7 @@ static irqreturn_t twl4030_rtc_interrupt(int irq, void *rtc)  	local_irq_enable();  #endif -	res = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); +	res = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);  	if (res)  		goto out;  	/* @@ -347,26 +396,28 @@ static irqreturn_t twl4030_rtc_interrupt(int irq, void *rtc)  	else  		events |= RTC_IRQF | RTC_UF; -	res = twl4030_rtc_write_u8(rd_reg | BIT_RTC_STATUS_REG_ALARM_M, +	res = twl_rtc_write_u8(rd_reg | BIT_RTC_STATUS_REG_ALARM_M,  				   REG_RTC_STATUS_REG);  	if (res)  		goto out; -	/* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1 -	 * needs 2 reads to clear the interrupt. One read is done in -	 * do_twl4030_pwrirq(). Doing the second read, to clear -	 * the bit. -	 * -	 * FIXME the reason PWR_ISR1 needs an extra read is that -	 * RTC_IF retriggered until we cleared REG_ALARM_M above. -	 * But re-reading like this is a bad hack; by doing so we -	 * risk wrongly clearing status for some other IRQ (losing -	 * the interrupt).  Be smarter about handling RTC_UF ... -	 */ -	res = twl4030_i2c_read_u8(TWL4030_MODULE_INT, +	if (twl_class_is_4030()) { +		/* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1 +		 * needs 2 reads to clear the interrupt. One read is done in +		 * do_twl_pwrirq(). Doing the second read, to clear +		 * the bit. +		 * +		 * FIXME the reason PWR_ISR1 needs an extra read is that +		 * RTC_IF retriggered until we cleared REG_ALARM_M above. +		 * But re-reading like this is a bad hack; by doing so we +		 * risk wrongly clearing status for some other IRQ (losing +		 * the interrupt).  Be smarter about handling RTC_UF ... +		 */ +		res = twl_i2c_read_u8(TWL4030_MODULE_INT,  			&rd_reg, TWL4030_INT_PWR_ISR1); -	if (res) -		goto out; +		if (res) +			goto out; +	}  	/* Notify RTC core on event */  	rtc_update_irq(rtc, 1, events); @@ -376,18 +427,18 @@ out:  	return ret;  } -static struct rtc_class_ops twl4030_rtc_ops = { -	.read_time	= twl4030_rtc_read_time, -	.set_time	= twl4030_rtc_set_time, -	.read_alarm	= twl4030_rtc_read_alarm, -	.set_alarm	= twl4030_rtc_set_alarm, -	.alarm_irq_enable = twl4030_rtc_alarm_irq_enable, -	.update_irq_enable = twl4030_rtc_update_irq_enable, +static struct rtc_class_ops twl_rtc_ops = { +	.read_time	= twl_rtc_read_time, +	.set_time	= twl_rtc_set_time, +	.read_alarm	= twl_rtc_read_alarm, +	.set_alarm	= twl_rtc_set_alarm, +	.alarm_irq_enable = twl_rtc_alarm_irq_enable, +	.update_irq_enable = twl_rtc_update_irq_enable,  };  /*----------------------------------------------------------------------*/ -static int __devinit twl4030_rtc_probe(struct platform_device *pdev) +static int __devinit twl_rtc_probe(struct platform_device *pdev)  {  	struct rtc_device *rtc;  	int ret = 0; @@ -398,7 +449,7 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev)  		return -EINVAL;  	rtc = rtc_device_register(pdev->name, -				  &pdev->dev, &twl4030_rtc_ops, THIS_MODULE); +				  &pdev->dev, &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", @@ -409,7 +460,7 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, rtc); -	ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG); +	ret = twl_rtc_read_u8(&rd_reg, REG_RTC_STATUS_REG);  	if (ret < 0)  		goto out1; @@ -420,11 +471,11 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev)  		dev_warn(&pdev->dev, "Pending Alarm interrupt detected.\n");  	/* Clear RTC Power up reset and pending alarm interrupts */ -	ret = twl4030_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG); +	ret = twl_rtc_write_u8(rd_reg, REG_RTC_STATUS_REG);  	if (ret < 0)  		goto out1; -	ret = request_irq(irq, twl4030_rtc_interrupt, +	ret = request_irq(irq, twl_rtc_interrupt,  				IRQF_TRIGGER_RISING,  				dev_name(&rtc->dev), rtc);  	if (ret < 0) { @@ -432,21 +483,28 @@ static int __devinit twl4030_rtc_probe(struct platform_device *pdev)  		goto out1;  	} +	if (twl_class_is_6030()) { +		twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, +			REG_INT_MSK_LINE_A); +		twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK, +			REG_INT_MSK_STS_A); +	} +  	/* Check RTC module status, Enable if it is off */ -	ret = twl4030_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG); +	ret = twl_rtc_read_u8(&rd_reg, REG_RTC_CTRL_REG);  	if (ret < 0)  		goto out2;  	if (!(rd_reg & BIT_RTC_CTRL_REG_STOP_RTC_M)) { -		dev_info(&pdev->dev, "Enabling TWL4030-RTC.\n"); +		dev_info(&pdev->dev, "Enabling TWL-RTC.\n");  		rd_reg = BIT_RTC_CTRL_REG_STOP_RTC_M; -		ret = twl4030_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG); +		ret = twl_rtc_write_u8(rd_reg, REG_RTC_CTRL_REG);  		if (ret < 0)  			goto out2;  	}  	/* init cached IRQ enable bits */ -	ret = twl4030_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG); +	ret = twl_rtc_read_u8(&rtc_irq_bits, REG_RTC_INTERRUPTS_REG);  	if (ret < 0)  		goto out2; @@ -461,10 +519,10 @@ out0:  }  /* - * Disable all TWL4030 RTC module interrupts. + * Disable all TWL RTC module interrupts.   * Sets status flag to free.   */ -static int __devexit twl4030_rtc_remove(struct platform_device *pdev) +static int __devexit twl_rtc_remove(struct platform_device *pdev)  {  	/* leave rtc running, but disable irqs */  	struct rtc_device *rtc = platform_get_drvdata(pdev); @@ -472,6 +530,13 @@ static int __devexit twl4030_rtc_remove(struct platform_device *pdev)  	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()) { +		twl6030_interrupt_mask(TWL6030_RTC_INT_MASK, +			REG_INT_MSK_LINE_A); +		twl6030_interrupt_mask(TWL6030_RTC_INT_MASK, +			REG_INT_MSK_STS_A); +	} +  	free_irq(irq, rtc); @@ -480,7 +545,7 @@ static int __devexit twl4030_rtc_remove(struct platform_device *pdev)  	return 0;  } -static void twl4030_rtc_shutdown(struct platform_device *pdev) +static void twl_rtc_shutdown(struct platform_device *pdev)  {  	/* mask timer interrupts, but leave alarm interrupts on to enable  	   power-on when alarm is triggered */ @@ -491,7 +556,7 @@ static void twl4030_rtc_shutdown(struct platform_device *pdev)  static unsigned char irqstat; -static int twl4030_rtc_suspend(struct platform_device *pdev, pm_message_t state) +static int twl_rtc_suspend(struct platform_device *pdev, pm_message_t state)  {  	irqstat = rtc_irq_bits; @@ -499,42 +564,47 @@ static int twl4030_rtc_suspend(struct platform_device *pdev, pm_message_t state)  	return 0;  } -static int twl4030_rtc_resume(struct platform_device *pdev) +static int twl_rtc_resume(struct platform_device *pdev)  {  	set_rtc_irq_bit(irqstat);  	return 0;  }  #else -#define twl4030_rtc_suspend NULL -#define twl4030_rtc_resume  NULL +#define twl_rtc_suspend NULL +#define twl_rtc_resume  NULL  #endif -MODULE_ALIAS("platform:twl4030_rtc"); +MODULE_ALIAS("platform:twl_rtc");  static struct platform_driver twl4030rtc_driver = { -	.probe		= twl4030_rtc_probe, -	.remove		= __devexit_p(twl4030_rtc_remove), -	.shutdown	= twl4030_rtc_shutdown, -	.suspend	= twl4030_rtc_suspend, -	.resume		= twl4030_rtc_resume, +	.probe		= twl_rtc_probe, +	.remove		= __devexit_p(twl_rtc_remove), +	.shutdown	= twl_rtc_shutdown, +	.suspend	= twl_rtc_suspend, +	.resume		= twl_rtc_resume,  	.driver		= {  		.owner	= THIS_MODULE, -		.name	= "twl4030_rtc", +		.name	= "twl_rtc",  	},  }; -static int __init twl4030_rtc_init(void) +static int __init twl_rtc_init(void)  { +	if (twl_class_is_4030()) +		rtc_reg_map = (u8 *) twl4030_rtc_reg_map; +	else +		rtc_reg_map = (u8 *) twl6030_rtc_reg_map; +  	return platform_driver_register(&twl4030rtc_driver);  } -module_init(twl4030_rtc_init); +module_init(twl_rtc_init); -static void __exit twl4030_rtc_exit(void) +static void __exit twl_rtc_exit(void)  {  	platform_driver_unregister(&twl4030rtc_driver);  } -module_exit(twl4030_rtc_exit); +module_exit(twl_rtc_exit);  MODULE_AUTHOR("Texas Instruments, MontaVista Software");  MODULE_LICENSE("GPL"); diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c index 4a6ed1104fb..9ee81d8aa7c 100644 --- a/drivers/rtc/rtc-tx4939.c +++ b/drivers/rtc/rtc-tx4939.c @@ -17,6 +17,7 @@  struct tx4939rtc_plat_data {  	struct rtc_device *rtc;  	struct tx4939_rtc_reg __iomem *rtcreg; +	spinlock_t lock;  };  static struct tx4939rtc_plat_data *get_tx4939rtc_plat_data(struct device *dev) @@ -52,14 +53,14 @@ static int tx4939_rtc_set_mmss(struct device *dev, unsigned long secs)  	buf[3] = secs >> 8;  	buf[4] = secs >> 16;  	buf[5] = secs >> 24; -	spin_lock_irq(&pdata->rtc->irq_lock); +	spin_lock_irq(&pdata->lock);  	__raw_writel(0, &rtcreg->adr);  	for (i = 0; i < 6; i++)  		__raw_writel(buf[i], &rtcreg->dat);  	ret = tx4939_rtc_cmd(rtcreg,  			     TX4939_RTCCTL_COMMAND_SETTIME |  			     (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME)); -	spin_unlock_irq(&pdata->rtc->irq_lock); +	spin_unlock_irq(&pdata->lock);  	return ret;  } @@ -71,18 +72,18 @@ static int tx4939_rtc_read_time(struct device *dev, struct rtc_time *tm)  	unsigned long sec;  	unsigned char buf[6]; -	spin_lock_irq(&pdata->rtc->irq_lock); +	spin_lock_irq(&pdata->lock);  	ret = tx4939_rtc_cmd(rtcreg,  			     TX4939_RTCCTL_COMMAND_GETTIME |  			     (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME));  	if (ret) { -		spin_unlock_irq(&pdata->rtc->irq_lock); +		spin_unlock_irq(&pdata->lock);  		return ret;  	}  	__raw_writel(2, &rtcreg->adr);  	for (i = 2; i < 6; i++)  		buf[i] = __raw_readl(&rtcreg->dat); -	spin_unlock_irq(&pdata->rtc->irq_lock); +	spin_unlock_irq(&pdata->lock);  	sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2];  	rtc_time_to_tm(sec, tm);  	return rtc_valid_tm(tm); @@ -110,13 +111,13 @@ static int tx4939_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)  	buf[3] = sec >> 8;  	buf[4] = sec >> 16;  	buf[5] = sec >> 24; -	spin_lock_irq(&pdata->rtc->irq_lock); +	spin_lock_irq(&pdata->lock);  	__raw_writel(0, &rtcreg->adr);  	for (i = 0; i < 6; i++)  		__raw_writel(buf[i], &rtcreg->dat);  	ret = tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_SETALARM |  			     (alrm->enabled ? TX4939_RTCCTL_ALME : 0)); -	spin_unlock_irq(&pdata->rtc->irq_lock); +	spin_unlock_irq(&pdata->lock);  	return ret;  } @@ -129,12 +130,12 @@ static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)  	unsigned char buf[6];  	u32 ctl; -	spin_lock_irq(&pdata->rtc->irq_lock); +	spin_lock_irq(&pdata->lock);  	ret = tx4939_rtc_cmd(rtcreg,  			     TX4939_RTCCTL_COMMAND_GETALARM |  			     (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALME));  	if (ret) { -		spin_unlock_irq(&pdata->rtc->irq_lock); +		spin_unlock_irq(&pdata->lock);  		return ret;  	}  	__raw_writel(2, &rtcreg->adr); @@ -143,7 +144,7 @@ static int tx4939_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)  	ctl = __raw_readl(&rtcreg->ctl);  	alrm->enabled = (ctl & TX4939_RTCCTL_ALME) ? 1 : 0;  	alrm->pending = (ctl & TX4939_RTCCTL_ALMD) ? 1 : 0; -	spin_unlock_irq(&pdata->rtc->irq_lock); +	spin_unlock_irq(&pdata->lock);  	sec = (buf[5] << 24) | (buf[4] << 16) | (buf[3] << 8) | buf[2];  	rtc_time_to_tm(sec, &alrm->time);  	return rtc_valid_tm(&alrm->time); @@ -153,11 +154,11 @@ static int tx4939_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)  {  	struct tx4939rtc_plat_data *pdata = get_tx4939rtc_plat_data(dev); -	spin_lock_irq(&pdata->rtc->irq_lock); +	spin_lock_irq(&pdata->lock);  	tx4939_rtc_cmd(pdata->rtcreg,  		       TX4939_RTCCTL_COMMAND_NOP |  		       (enabled ? TX4939_RTCCTL_ALME : 0)); -	spin_unlock_irq(&pdata->rtc->irq_lock); +	spin_unlock_irq(&pdata->lock);  	return 0;  } @@ -167,13 +168,14 @@ static irqreturn_t tx4939_rtc_interrupt(int irq, void *dev_id)  	struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg;  	unsigned long events = RTC_IRQF; -	spin_lock(&pdata->rtc->irq_lock); +	spin_lock(&pdata->lock);  	if (__raw_readl(&rtcreg->ctl) & TX4939_RTCCTL_ALMD) {  		events |= RTC_AF;  		tx4939_rtc_cmd(rtcreg, TX4939_RTCCTL_COMMAND_NOP);  	} -	spin_unlock(&pdata->rtc->irq_lock); -	rtc_update_irq(pdata->rtc, 1, events); +	spin_unlock(&pdata->lock); +	if (likely(pdata->rtc)) +		rtc_update_irq(pdata->rtc, 1, events);  	return IRQ_HANDLED;  } @@ -194,13 +196,13 @@ static ssize_t tx4939_rtc_nvram_read(struct kobject *kobj,  	struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg;  	ssize_t count; -	spin_lock_irq(&pdata->rtc->irq_lock); +	spin_lock_irq(&pdata->lock);  	for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE;  	     count++, size--) {  		__raw_writel(pos++, &rtcreg->adr);  		*buf++ = __raw_readl(&rtcreg->dat);  	} -	spin_unlock_irq(&pdata->rtc->irq_lock); +	spin_unlock_irq(&pdata->lock);  	return count;  } @@ -213,13 +215,13 @@ static ssize_t tx4939_rtc_nvram_write(struct kobject *kobj,  	struct tx4939_rtc_reg __iomem *rtcreg = pdata->rtcreg;  	ssize_t count; -	spin_lock_irq(&pdata->rtc->irq_lock); +	spin_lock_irq(&pdata->lock);  	for (count = 0; size > 0 && pos < TX4939_RTC_REG_RAMSIZE;  	     count++, size--) {  		__raw_writel(pos++, &rtcreg->adr);  		__raw_writel(*buf++, &rtcreg->dat);  	} -	spin_unlock_irq(&pdata->rtc->irq_lock); +	spin_unlock_irq(&pdata->lock);  	return count;  } @@ -259,6 +261,7 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev)  	if (!pdata->rtcreg)  		return -EBUSY; +	spin_lock_init(&pdata->lock);  	tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP);  	if (devm_request_irq(&pdev->dev, irq, tx4939_rtc_interrupt,  			     IRQF_DISABLED, pdev->name, &pdev->dev) < 0) @@ -277,14 +280,12 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev)  static int __exit tx4939_rtc_remove(struct platform_device *pdev)  {  	struct tx4939rtc_plat_data *pdata = platform_get_drvdata(pdev); -	struct rtc_device *rtc = pdata->rtc; -	spin_lock_irq(&rtc->irq_lock); -	tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP); -	spin_unlock_irq(&rtc->irq_lock);  	sysfs_remove_bin_file(&pdev->dev.kobj, &tx4939_rtc_nvram_attr); -	rtc_device_unregister(rtc); -	platform_set_drvdata(pdev, NULL); +	rtc_device_unregister(pdata->rtc); +	spin_lock_irq(&pdata->lock); +	tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP); +	spin_unlock_irq(&pdata->lock);  	return 0;  } diff --git a/drivers/rtc/rtc-v3020.c b/drivers/rtc/rtc-v3020.c index ad164056feb..bed4cab0704 100644 --- a/drivers/rtc/rtc-v3020.c +++ b/drivers/rtc/rtc-v3020.c @@ -96,7 +96,7 @@ static void v3020_mmio_write_bit(struct v3020 *chip, unsigned char bit)  static unsigned char v3020_mmio_read_bit(struct v3020 *chip)  { -	return readl(chip->ioaddress) & (1 << chip->leftshift); +	return !!(readl(chip->ioaddress) & (1 << chip->leftshift));  }  static struct v3020_chip_ops v3020_mmio_ops = { @@ -304,7 +304,6 @@ static int rtc_probe(struct platform_device *pdev)  {  	struct v3020_platform_data *pdata = pdev->dev.platform_data;  	struct v3020 *chip; -	struct rtc_device *rtc;  	int retval = -EBUSY;  	int i;  	int temp; @@ -335,7 +334,7 @@ static int rtc_probe(struct platform_device *pdev)  		goto err_io;  	} -	/* Make sure frequency measurment mode, test modes, and lock +	/* Make sure frequency measurement mode, test modes, and lock  	 * are all disabled */  	v3020_set_reg(chip, V3020_STATUS_0, 0x0); @@ -353,13 +352,12 @@ static int rtc_probe(struct platform_device *pdev)  	platform_set_drvdata(pdev, chip); -	rtc = rtc_device_register("v3020", +	chip->rtc = rtc_device_register("v3020",  				&pdev->dev, &v3020_rtc_ops, THIS_MODULE); -	if (IS_ERR(rtc)) { -		retval = PTR_ERR(rtc); +	if (IS_ERR(chip->rtc)) { +		retval = PTR_ERR(chip->rtc);  		goto err_io;  	} -	chip->rtc = rtc;  	return 0; diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c index 2c839d0d21b..c3244244e8c 100644 --- a/drivers/rtc/rtc-vr41xx.c +++ b/drivers/rtc/rtc-vr41xx.c @@ -209,19 +209,18 @@ static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)  static int vr41xx_rtc_irq_set_freq(struct device *dev, int freq)  { -	unsigned long count; +	u64 count;  	if (!is_power_of_2(freq))  		return -EINVAL;  	count = RTC_FREQUENCY;  	do_div(count, freq); -	periodic_count = count; -  	spin_lock_irq(&rtc_lock); -	rtc1_write(RTCL1LREG, count); -	rtc1_write(RTCL1HREG, count >> 16); +	periodic_count = count; +	rtc1_write(RTCL1LREG, periodic_count); +	rtc1_write(RTCL1HREG, periodic_count >> 16);  	spin_unlock_irq(&rtc_lock); @@ -328,7 +327,7 @@ static int __devinit rtc_probe(struct platform_device *pdev)  	if (!res)  		return -EBUSY; -	rtc1_base = ioremap(res->start, res->end - res->start + 1); +	rtc1_base = ioremap(res->start, resource_size(res));  	if (!rtc1_base)  		return -EBUSY; @@ -338,7 +337,7 @@ static int __devinit rtc_probe(struct platform_device *pdev)  		goto err_rtc1_iounmap;  	} -	rtc2_base = ioremap(res->start, res->end - res->start + 1); +	rtc2_base = ioremap(res->start, resource_size(res));  	if (!rtc2_base) {  		retval = -EBUSY;  		goto err_rtc1_iounmap; diff --git a/drivers/rtc/rtc-wm831x.c b/drivers/rtc/rtc-wm831x.c index 79795cdf6ed..000c7e481e5 100644 --- a/drivers/rtc/rtc-wm831x.c +++ b/drivers/rtc/rtc-wm831x.c @@ -485,7 +485,7 @@ static int __devexit wm831x_rtc_remove(struct platform_device *pdev)  	return 0;  } -static struct dev_pm_ops wm831x_rtc_pm_ops = { +static const struct dev_pm_ops wm831x_rtc_pm_ops = {  	.suspend = wm831x_rtc_suspend,  	.resume = wm831x_rtc_resume, diff --git a/drivers/rtc/rtc-wm8350.c b/drivers/rtc/rtc-wm8350.c index c91edc572eb..f1e440521c5 100644 --- a/drivers/rtc/rtc-wm8350.c +++ b/drivers/rtc/rtc-wm8350.c @@ -315,9 +315,9 @@ static int wm8350_rtc_update_irq_enable(struct device *dev,  	return 0;  } -static void wm8350_rtc_alarm_handler(struct wm8350 *wm8350, int irq, -				     void *data) +static irqreturn_t wm8350_rtc_alarm_handler(int irq, void *data)  { +	struct wm8350 *wm8350 = data;  	struct rtc_device *rtc = wm8350->rtc.rtc;  	int ret; @@ -330,14 +330,18 @@ static void wm8350_rtc_alarm_handler(struct wm8350 *wm8350, int irq,  		dev_err(&(wm8350->rtc.pdev->dev),  			"Failed to disable alarm: %d\n", ret);  	} + +	return IRQ_HANDLED;  } -static void wm8350_rtc_update_handler(struct wm8350 *wm8350, int irq, -				      void *data) +static irqreturn_t wm8350_rtc_update_handler(int irq, void *data)  { +	struct wm8350 *wm8350 = data;  	struct rtc_device *rtc = wm8350->rtc.rtc;  	rtc_update_irq(rtc, 1, RTC_IRQF | RTC_UF); + +	return IRQ_HANDLED;  }  static const struct rtc_class_ops wm8350_rtc_ops = { @@ -350,8 +354,9 @@ static const struct rtc_class_ops wm8350_rtc_ops = {  };  #ifdef CONFIG_PM -static int wm8350_rtc_suspend(struct platform_device *pdev, pm_message_t state) +static int wm8350_rtc_suspend(struct device *dev)  { +	struct platform_device *pdev = to_platform_device(dev);  	struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev);  	int ret = 0;  	u16 reg; @@ -369,8 +374,9 @@ static int wm8350_rtc_suspend(struct platform_device *pdev, pm_message_t state)  	return ret;  } -static int wm8350_rtc_resume(struct platform_device *pdev) +static int wm8350_rtc_resume(struct device *dev)  { +	struct platform_device *pdev = to_platform_device(dev);  	struct wm8350 *wm8350 = dev_get_drvdata(&pdev->dev);  	int ret; @@ -455,15 +461,14 @@ static int wm8350_rtc_probe(struct platform_device *pdev)  		return ret;  	} -	wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC); -	wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_PER); -  	wm8350_register_irq(wm8350, WM8350_IRQ_RTC_SEC, -			    wm8350_rtc_update_handler, NULL); +			    wm8350_rtc_update_handler, 0, +			    "RTC Seconds", wm8350); +	wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC);  	wm8350_register_irq(wm8350, WM8350_IRQ_RTC_ALM, -			    wm8350_rtc_alarm_handler, NULL); -	wm8350_unmask_irq(wm8350, WM8350_IRQ_RTC_ALM); +			    wm8350_rtc_alarm_handler, 0, +			    "RTC Alarm", wm8350);  	return 0;  } @@ -473,8 +478,6 @@ static int __devexit wm8350_rtc_remove(struct platform_device *pdev)  	struct wm8350 *wm8350 = platform_get_drvdata(pdev);  	struct wm8350_rtc *wm_rtc = &wm8350->rtc; -	wm8350_mask_irq(wm8350, WM8350_IRQ_RTC_SEC); -  	wm8350_free_irq(wm8350, WM8350_IRQ_RTC_SEC);  	wm8350_free_irq(wm8350, WM8350_IRQ_RTC_ALM); @@ -483,13 +486,17 @@ static int __devexit wm8350_rtc_remove(struct platform_device *pdev)  	return 0;  } +static struct dev_pm_ops wm8350_rtc_pm_ops = { +	.suspend = wm8350_rtc_suspend, +	.resume = wm8350_rtc_resume, +}; +  static struct platform_driver wm8350_rtc_driver = {  	.probe = wm8350_rtc_probe,  	.remove = __devexit_p(wm8350_rtc_remove), -	.suspend = wm8350_rtc_suspend, -	.resume = wm8350_rtc_resume,  	.driver = {  		.name = "wm8350-rtc", +		.pm = &wm8350_rtc_pm_ops,  	},  }; diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index 310c10795e9..9aae49139a0 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -155,11 +155,11 @@ static int x1205_get_status(struct i2c_client *client, unsigned char *sr)  }  static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm, -			int datetoo, u8 reg_base, unsigned char alm_enable) +			u8 reg_base, unsigned char alm_enable)  { -	int i, xfer, nbytes; -	unsigned char buf[8]; +	int i, xfer;  	unsigned char rdata[10] = { 0, reg_base }; +	unsigned char *buf = rdata + 2;  	static const unsigned char wel[3] = { 0, X1205_REG_SR,  						X1205_SR_WEL }; @@ -170,9 +170,9 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,  	static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 };  	dev_dbg(&client->dev, -		"%s: secs=%d, mins=%d, hours=%d\n", -		__func__, -		tm->tm_sec, tm->tm_min, tm->tm_hour); +		"%s: sec=%d min=%d hour=%d mday=%d mon=%d year=%d wday=%d\n", +		__func__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, +		tm->tm_mon, tm->tm_year, tm->tm_wday);  	buf[CCR_SEC] = bin2bcd(tm->tm_sec);  	buf[CCR_MIN] = bin2bcd(tm->tm_min); @@ -180,23 +180,15 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,  	/* set hour and 24hr bit */  	buf[CCR_HOUR] = bin2bcd(tm->tm_hour) | X1205_HR_MIL; -	/* should we also set the date? */ -	if (datetoo) { -		dev_dbg(&client->dev, -			"%s: mday=%d, mon=%d, year=%d, wday=%d\n", -			__func__, -			tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); +	buf[CCR_MDAY] = bin2bcd(tm->tm_mday); -		buf[CCR_MDAY] = bin2bcd(tm->tm_mday); +	/* month, 1 - 12 */ +	buf[CCR_MONTH] = bin2bcd(tm->tm_mon + 1); -		/* month, 1 - 12 */ -		buf[CCR_MONTH] = bin2bcd(tm->tm_mon + 1); - -		/* year, since the rtc epoch*/ -		buf[CCR_YEAR] = bin2bcd(tm->tm_year % 100); -		buf[CCR_WDAY] = tm->tm_wday & 0x07; -		buf[CCR_Y2K] = bin2bcd(tm->tm_year / 100); -	} +	/* year, since the rtc epoch*/ +	buf[CCR_YEAR] = bin2bcd(tm->tm_year % 100); +	buf[CCR_WDAY] = tm->tm_wday & 0x07; +	buf[CCR_Y2K] = bin2bcd((tm->tm_year + 1900) / 100);  	/* If writing alarm registers, set compare bits on registers 0-4 */  	if (reg_base < X1205_CCR_BASE) @@ -214,17 +206,8 @@ static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,  		return -EIO;  	} - -	/* write register's data */ -	if (datetoo) -		nbytes = 8; -	else -		nbytes = 3; -	for (i = 0; i < nbytes; i++) -		rdata[2+i] = buf[i]; - -	xfer = i2c_master_send(client, rdata, nbytes+2); -	if (xfer != nbytes+2) { +	xfer = i2c_master_send(client, rdata, sizeof(rdata)); +	if (xfer != sizeof(rdata)) {  		dev_err(&client->dev,  			"%s: result=%d addr=%02x, data=%02x\n",  			__func__, @@ -280,9 +263,9 @@ static int x1205_fix_osc(struct i2c_client *client)  	int err;  	struct rtc_time tm; -	tm.tm_hour = tm.tm_min = tm.tm_sec = 0; +	memset(&tm, 0, sizeof(tm)); -	err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE, 0); +	err = x1205_set_datetime(client, &tm, X1205_CCR_BASE, 0);  	if (err < 0)  		dev_err(&client->dev, "unable to restart the oscillator\n"); @@ -481,7 +464,7 @@ static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)  static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)  {  	return x1205_set_datetime(to_i2c_client(dev), -		&alrm->time, 1, X1205_ALM0_BASE, alrm->enabled); +		&alrm->time, X1205_ALM0_BASE, alrm->enabled);  }  static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm) @@ -493,7 +476,7 @@ static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm)  static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm)  {  	return x1205_set_datetime(to_i2c_client(dev), -		tm, 1, X1205_CCR_BASE, 0); +		tm, X1205_CCR_BASE, 0);  }  static int x1205_rtc_proc(struct device *dev, struct seq_file *seq) | 
