diff options
Diffstat (limited to 'drivers/rtc')
| -rw-r--r-- | drivers/rtc/Kconfig | 11 | ||||
| -rw-r--r-- | drivers/rtc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/rtc/interface.c | 12 | ||||
| -rw-r--r-- | drivers/rtc/rtc-dev.c | 6 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ds1305.c | 3 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ds1307.c | 46 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ds1374.c | 5 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ds1553.c | 3 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ds1742.c | 31 | ||||
| -rw-r--r-- | drivers/rtc/rtc-ep93xx.c | 149 | ||||
| -rw-r--r-- | drivers/rtc/rtc-pl030.c | 2 | ||||
| -rw-r--r-- | drivers/rtc/rtc-pl031.c | 3 | ||||
| -rw-r--r-- | drivers/rtc/rtc-rx8025.c | 688 | ||||
| -rw-r--r-- | drivers/rtc/rtc-test.c | 2 | ||||
| -rw-r--r-- | drivers/rtc/rtc-tx4939.c | 4 | 
15 files changed, 871 insertions, 95 deletions
| diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 4e9851fc174..81adbdbd504 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -296,6 +296,15 @@ config RTC_DRV_RX8581  	  This driver can also be built as a module. If so the module  	  will be called rtc-rx8581. +config RTC_DRV_RX8025 +	tristate "Epson RX-8025SA/NB" +	help +	  If you say yes here you get support for the Epson +	  RX-8025SA/NB RTC chips. + +	  This driver can also be built as a module. If so, the module +	  will be called rtc-rx8025. +  endif # I2C  comment "SPI RTC drivers" @@ -692,7 +701,7 @@ config RTC_DRV_GENERIC  	tristate "Generic RTC support"  	# Please consider writing a new RTC driver instead of using the generic  	# RTC abstraction -	depends on PARISC || M68K || PPC +	depends on PARISC || M68K || PPC || SUPERH32  	help  	  Say Y or M here to enable RTC support on systems using the generic  	  RTC abstraction. If you do not know what you are doing, you should diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 6c0639a14f0..3c0f2b2ac92 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -62,6 +62,7 @@ obj-$(CONFIG_RTC_DRV_R9701)	+= rtc-r9701.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 +obj-$(CONFIG_RTC_DRV_RX8025)	+= rtc-rx8025.o  obj-$(CONFIG_RTC_DRV_RX8581)	+= rtc-rx8581.o  obj-$(CONFIG_RTC_DRV_S35390A)	+= rtc-s35390a.o  obj-$(CONFIG_RTC_DRV_S3C)	+= rtc-s3c.o diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c index 4348c4b0d45..4cdb31a362c 100644 --- a/drivers/rtc/interface.c +++ b/drivers/rtc/interface.c @@ -371,19 +371,21 @@ EXPORT_SYMBOL_GPL(rtc_update_irq_enable);   * @rtc: the rtc device   * @num: how many irqs are being reported (usually one)   * @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF - * Context: in_interrupt(), irqs blocked + * Context: any   */  void rtc_update_irq(struct rtc_device *rtc,  		unsigned long num, unsigned long events)  { -	spin_lock(&rtc->irq_lock); +	unsigned long flags; + +	spin_lock_irqsave(&rtc->irq_lock, flags);  	rtc->irq_data = (rtc->irq_data + (num << 8)) | events; -	spin_unlock(&rtc->irq_lock); +	spin_unlock_irqrestore(&rtc->irq_lock, flags); -	spin_lock(&rtc->irq_task_lock); +	spin_lock_irqsave(&rtc->irq_task_lock, flags);  	if (rtc->irq_task)  		rtc->irq_task->func(rtc->irq_task->private_data); -	spin_unlock(&rtc->irq_task_lock); +	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);  	wake_up_interruptible(&rtc->irq_queue);  	kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c index 45152f4952d..8a11de9552c 100644 --- a/drivers/rtc/rtc-dev.c +++ b/drivers/rtc/rtc-dev.c @@ -60,8 +60,7 @@ static void rtc_uie_task(struct work_struct *work)  	err = rtc_read_time(rtc, &tm); -	local_irq_disable(); -	spin_lock(&rtc->irq_lock); +	spin_lock_irq(&rtc->irq_lock);  	if (rtc->stop_uie_polling || err) {  		rtc->uie_task_active = 0;  	} else if (rtc->oldsecs != tm.tm_sec) { @@ -74,10 +73,9 @@ static void rtc_uie_task(struct work_struct *work)  	} else if (schedule_work(&rtc->uie_task) == 0) {  		rtc->uie_task_active = 0;  	} -	spin_unlock(&rtc->irq_lock); +	spin_unlock_irq(&rtc->irq_lock);  	if (num)  		rtc_update_irq(rtc, num, RTC_UF | RTC_IRQF); -	local_irq_enable();  }  static void rtc_uie_timer(unsigned long data)  { diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c index fc372df6534..8f410e59d9f 100644 --- a/drivers/rtc/rtc-ds1305.c +++ b/drivers/rtc/rtc-ds1305.c @@ -499,10 +499,7 @@ static void ds1305_work(struct work_struct *work)  	if (!test_bit(FLAG_EXITING, &ds1305->flags))  		enable_irq(spi->irq); -	/* rtc_update_irq() requires an IRQ-disabled context */ -	local_irq_disable();  	rtc_update_irq(ds1305->rtc, 1, RTC_AF | RTC_IRQF); -	local_irq_enable();  }  /* diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c index 2c4a65302a9..47a93c022d9 100644 --- a/drivers/rtc/rtc-ds1307.c +++ b/drivers/rtc/rtc-ds1307.c @@ -31,6 +31,8 @@ enum ds_type {  	ds_1338,  	ds_1339,  	ds_1340, +	ds_1388, +	ds_3231,  	m41t00,  	rx_8025,  	// rs5c372 too?  different address... @@ -66,6 +68,7 @@ enum ds_type {  #define DS1337_REG_CONTROL	0x0e  #	define DS1337_BIT_nEOSC		0x80  #	define DS1339_BIT_BBSQI		0x20 +#	define DS3231_BIT_BBSQW		0x40 /* same as BBSQI */  #	define DS1337_BIT_RS2		0x10  #	define DS1337_BIT_RS1		0x08  #	define DS1337_BIT_INTCN		0x04 @@ -94,6 +97,7 @@ enum ds_type {  struct ds1307 { +	u8			offset; /* register's offset */  	u8			regs[11];  	enum ds_type		type;  	unsigned long		flags; @@ -128,6 +132,9 @@ static const struct chip_desc chips[] = {  },  [ds_1340] = {  }, +[ds_3231] = { +	.alarm		= 1, +},  [m41t00] = {  },  [rx_8025] = { @@ -138,7 +145,9 @@ static const struct i2c_device_id ds1307_id[] = {  	{ "ds1337", ds_1337 },  	{ "ds1338", ds_1338 },  	{ "ds1339", ds_1339 }, +	{ "ds1388", ds_1388 },  	{ "ds1340", ds_1340 }, +	{ "ds3231", ds_3231 },  	{ "m41t00", m41t00 },  	{ "rx8025", rx_8025 },  	{ } @@ -258,12 +267,7 @@ static void ds1307_work(struct work_struct *work)  		control &= ~DS1337_BIT_A1IE;  		i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, control); -		/* rtc_update_irq() assumes that it is called -		 * from IRQ-disabled context. -		 */ -		local_irq_disable();  		rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF); -		local_irq_enable();  	}  out: @@ -291,7 +295,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)  	/* read the RTC date and time registers all at once */  	tmp = ds1307->read_block_data(ds1307->client, -		DS1307_REG_SECS, 7, ds1307->regs); +		ds1307->offset, 7, ds1307->regs);  	if (tmp != 7) {  		dev_err(dev, "%s error %d\n", "read", tmp);  		return -EIO; @@ -353,6 +357,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)  	switch (ds1307->type) {  	case ds_1337:  	case ds_1339: +	case ds_3231:  		buf[DS1307_REG_MONTH] |= DS1337_BIT_CENTURY;  		break;  	case ds_1340: @@ -367,7 +372,8 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)  		"write", buf[0], buf[1], buf[2], buf[3],  		buf[4], buf[5], buf[6]); -	result = ds1307->write_block_data(ds1307->client, 0, 7, buf); +	result = ds1307->write_block_data(ds1307->client, +		ds1307->offset, 7, buf);  	if (result < 0) {  		dev_err(dev, "%s error %d\n", "write", result);  		return result; @@ -624,6 +630,11 @@ static int __devinit ds1307_probe(struct i2c_client *client,  	struct i2c_adapter	*adapter = to_i2c_adapter(client->dev.parent);  	int			want_irq = false;  	unsigned char		*buf; +	static const int	bbsqi_bitpos[] = { +		[ds_1337] = 0, +		[ds_1339] = DS1339_BIT_BBSQI, +		[ds_3231] = DS3231_BIT_BBSQW, +	};  	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)  	    && !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) @@ -632,9 +643,12 @@ static int __devinit ds1307_probe(struct i2c_client *client,  	if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL)))  		return -ENOMEM; -	ds1307->client = client;  	i2c_set_clientdata(client, ds1307); -	ds1307->type = id->driver_data; + +	ds1307->client	= client; +	ds1307->type	= id->driver_data; +	ds1307->offset	= 0; +  	buf = ds1307->regs;  	if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {  		ds1307->read_block_data = i2c_smbus_read_i2c_block_data; @@ -647,6 +661,7 @@ static int __devinit ds1307_probe(struct i2c_client *client,  	switch (ds1307->type) {  	case ds_1337:  	case ds_1339: +	case ds_3231:  		/* has IRQ? */  		if (ds1307->client->irq > 0 && chip->alarm) {  			INIT_WORK(&ds1307->work, ds1307_work); @@ -666,12 +681,12 @@ static int __devinit ds1307_probe(struct i2c_client *client,  			ds1307->regs[0] &= ~DS1337_BIT_nEOSC;  		/* Using IRQ?  Disable the square wave and both alarms. -		 * For ds1339, be sure alarms can trigger when we're -		 * running on Vbackup (BBSQI); we assume ds1337 will -		 * ignore that bit +		 * For some variants, be sure alarms can trigger when we're +		 * running on Vbackup (BBSQI/BBSQW)  		 */  		if (want_irq) { -			ds1307->regs[0] |= DS1337_BIT_INTCN | DS1339_BIT_BBSQI; +			ds1307->regs[0] |= DS1337_BIT_INTCN +					| bbsqi_bitpos[ds1307->type];  			ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);  		} @@ -751,6 +766,9 @@ static int __devinit ds1307_probe(struct i2c_client *client,  						  hour);  		}  		break; +	case ds_1388: +		ds1307->offset = 1; /* Seconds starts at 1 */ +		break;  	default:  		break;  	} @@ -814,6 +832,8 @@ read_rtc:  	case rx_8025:  	case ds_1337:  	case ds_1339: +	case ds_1388: +	case ds_3231:  		break;  	} diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c index 4d32e328f6c..32b27739ec2 100644 --- a/drivers/rtc/rtc-ds1374.c +++ b/drivers/rtc/rtc-ds1374.c @@ -296,12 +296,7 @@ static void ds1374_work(struct work_struct *work)  		control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE);  		i2c_smbus_write_byte_data(client, DS1374_REG_CR, control); -		/* rtc_update_irq() assumes that it is called -		 * from IRQ-disabled context. -		 */ -		local_irq_disable();  		rtc_update_irq(ds1374->rtc, 1, RTC_AF | RTC_IRQF); -		local_irq_enable();  	}  out: diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c index 38d472b6340..717288527c6 100644 --- a/drivers/rtc/rtc-ds1553.c +++ b/drivers/rtc/rtc-ds1553.c @@ -329,8 +329,7 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev)  	if (pdata->irq > 0) {  		writeb(0, ioaddr + RTC_INTERRUPTS);  		if (request_irq(pdata->irq, ds1553_rtc_interrupt, -				IRQF_DISABLED | IRQF_SHARED, -				pdev->name, pdev) < 0) { +				IRQF_DISABLED, pdev->name, pdev) < 0) {  			dev_warn(&pdev->dev, "interrupt not available.\n");  			pdata->irq = 0;  		} diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c index 8bc8501bffc..09249459e9a 100644 --- a/drivers/rtc/rtc-ds1742.c +++ b/drivers/rtc/rtc-ds1742.c @@ -57,6 +57,7 @@ struct rtc_plat_data {  	size_t size;  	resource_size_t baseaddr;  	unsigned long last_jiffies; +	struct bin_attribute nvram_attr;  };  static int ds1742_rtc_set_time(struct device *dev, struct rtc_time *tm) @@ -157,18 +158,6 @@ static ssize_t ds1742_nvram_write(struct kobject *kobj,  	return count;  } -static struct bin_attribute ds1742_nvram_attr = { -	.attr = { -		.name = "nvram", -		.mode = S_IRUGO | S_IWUSR, -	}, -	.read = ds1742_nvram_read, -	.write = ds1742_nvram_write, -	/* REVISIT: size in sysfs won't match actual size... if it's -	 * not a constant, each RTC should have its own attribute. -	 */ -}; -  static int __devinit ds1742_rtc_probe(struct platform_device *pdev)  {  	struct rtc_device *rtc; @@ -199,6 +188,12 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev)  	pdata->size_nvram = pdata->size - RTC_SIZE;  	pdata->ioaddr_rtc = ioaddr + pdata->size_nvram; +	pdata->nvram_attr.attr.name = "nvram"; +	pdata->nvram_attr.attr.mode = S_IRUGO | S_IWUSR; +	pdata->nvram_attr.read = ds1742_nvram_read; +	pdata->nvram_attr.write = ds1742_nvram_write; +	pdata->nvram_attr.size = pdata->size_nvram; +  	/* turn RTC on if it was not on */  	ioaddr = pdata->ioaddr_rtc;  	sec = readb(ioaddr + RTC_SECONDS); @@ -221,11 +216,13 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev)  	pdata->rtc = rtc;  	pdata->last_jiffies = jiffies;  	platform_set_drvdata(pdev, pdata); -	ds1742_nvram_attr.size = max(ds1742_nvram_attr.size, -				     pdata->size_nvram); -	ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr); -	if (ret) + +	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; +	} +  	return 0;   out:  	if (pdata->rtc) @@ -242,7 +239,7 @@ static int __devexit ds1742_rtc_remove(struct platform_device *pdev)  {  	struct rtc_plat_data *pdata = platform_get_drvdata(pdev); -	sysfs_remove_bin_file(&pdev->dev.kobj, &ds1742_nvram_attr); +	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); diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index f7a3283dd02..551332e4ed0 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -12,32 +12,56 @@  #include <linux/module.h>  #include <linux/rtc.h>  #include <linux/platform_device.h> -#include <mach/hardware.h> +#include <linux/io.h> + +#define EP93XX_RTC_DATA			0x000 +#define EP93XX_RTC_MATCH		0x004 +#define EP93XX_RTC_STATUS		0x008 +#define  EP93XX_RTC_STATUS_INTR		 (1<<0) +#define EP93XX_RTC_LOAD			0x00C +#define EP93XX_RTC_CONTROL		0x010 +#define  EP93XX_RTC_CONTROL_MIE		 (1<<0) +#define EP93XX_RTC_SWCOMP		0x108 +#define  EP93XX_RTC_SWCOMP_DEL_MASK	 0x001f0000 +#define  EP93XX_RTC_SWCOMP_DEL_SHIFT	 16 +#define  EP93XX_RTC_SWCOMP_INT_MASK	 0x0000ffff +#define  EP93XX_RTC_SWCOMP_INT_SHIFT	 0 + +#define DRV_VERSION "0.3" -#define EP93XX_RTC_REG(x)	(EP93XX_RTC_BASE + (x)) -#define EP93XX_RTC_DATA		EP93XX_RTC_REG(0x0000) -#define EP93XX_RTC_LOAD		EP93XX_RTC_REG(0x000C) -#define EP93XX_RTC_SWCOMP	EP93XX_RTC_REG(0x0108) - -#define DRV_VERSION "0.2" +/* + * struct device dev.platform_data is used to store our private data + * because struct rtc_device does not have a variable to hold it. + */ +struct ep93xx_rtc { +	void __iomem	*mmio_base; +}; -static int ep93xx_get_swcomp(struct device *dev, unsigned short *preload, +static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,  				unsigned short *delete)  { -	unsigned short comp = __raw_readl(EP93XX_RTC_SWCOMP); +	struct ep93xx_rtc *ep93xx_rtc = dev->platform_data; +	unsigned long comp; + +	comp = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_SWCOMP);  	if (preload) -		*preload = comp & 0xffff; +		*preload = (comp & EP93XX_RTC_SWCOMP_INT_MASK) +				>> EP93XX_RTC_SWCOMP_INT_SHIFT;  	if (delete) -		*delete = (comp >> 16) & 0x1f; +		*delete = (comp & EP93XX_RTC_SWCOMP_DEL_MASK) +				>> EP93XX_RTC_SWCOMP_DEL_SHIFT;  	return 0;  }  static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)  { -	unsigned long time = __raw_readl(EP93XX_RTC_DATA); +	struct ep93xx_rtc *ep93xx_rtc = dev->platform_data; +	unsigned long time; + +	 time = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA);  	rtc_time_to_tm(time, tm);  	return 0; @@ -45,7 +69,9 @@ static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)  static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs)  { -	__raw_writel(secs + 1, EP93XX_RTC_LOAD); +	struct ep93xx_rtc *ep93xx_rtc = dev->platform_data; + +	__raw_writel(secs + 1, ep93xx_rtc->mmio_base + EP93XX_RTC_LOAD);  	return 0;  } @@ -53,7 +79,7 @@ static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq)  {  	unsigned short preload, delete; -	ep93xx_get_swcomp(dev, &preload, &delete); +	ep93xx_rtc_get_swcomp(dev, &preload, &delete);  	seq_printf(seq, "preload\t\t: %d\n", preload);  	seq_printf(seq, "delete\t\t: %d\n", delete); @@ -67,54 +93,104 @@ static const struct rtc_class_ops ep93xx_rtc_ops = {  	.proc		= ep93xx_rtc_proc,  }; -static ssize_t ep93xx_sysfs_show_comp_preload(struct device *dev, +static ssize_t ep93xx_rtc_show_comp_preload(struct device *dev,  			struct device_attribute *attr, char *buf)  {  	unsigned short preload; -	ep93xx_get_swcomp(dev, &preload, NULL); +	ep93xx_rtc_get_swcomp(dev, &preload, NULL);  	return sprintf(buf, "%d\n", preload);  } -static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_sysfs_show_comp_preload, NULL); +static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_rtc_show_comp_preload, NULL); -static ssize_t ep93xx_sysfs_show_comp_delete(struct device *dev, +static ssize_t ep93xx_rtc_show_comp_delete(struct device *dev,  			struct device_attribute *attr, char *buf)  {  	unsigned short delete; -	ep93xx_get_swcomp(dev, NULL, &delete); +	ep93xx_rtc_get_swcomp(dev, NULL, &delete);  	return sprintf(buf, "%d\n", delete);  } -static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_sysfs_show_comp_delete, NULL); +static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_rtc_show_comp_delete, NULL); -static int __devinit ep93xx_rtc_probe(struct platform_device *dev) +static int __init ep93xx_rtc_probe(struct platform_device *pdev)  { -	struct rtc_device *rtc = rtc_device_register("ep93xx", -				&dev->dev, &ep93xx_rtc_ops, THIS_MODULE); +	struct ep93xx_rtc *ep93xx_rtc; +	struct resource *res; +	struct rtc_device *rtc; +	int err; + +	ep93xx_rtc = kzalloc(sizeof(struct ep93xx_rtc), GFP_KERNEL); +	if (ep93xx_rtc == NULL) +		return -ENOMEM; + +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	if (res == NULL) +		return -ENXIO; + +	res = request_mem_region(res->start, resource_size(res), pdev->name); +	if (res == NULL) +		return -EBUSY; + +	ep93xx_rtc->mmio_base = ioremap(res->start, resource_size(res)); +	if (ep93xx_rtc->mmio_base == NULL) { +		err = -ENXIO; +		goto fail; +	} +	pdev->dev.platform_data = ep93xx_rtc; + +	rtc = rtc_device_register(pdev->name, +				&pdev->dev, &ep93xx_rtc_ops, THIS_MODULE);  	if (IS_ERR(rtc)) { -		return PTR_ERR(rtc); +		err = PTR_ERR(rtc); +		goto fail;  	} -	platform_set_drvdata(dev, rtc); +	platform_set_drvdata(pdev, rtc); -	device_create_file(&dev->dev, &dev_attr_comp_preload); -	device_create_file(&dev->dev, &dev_attr_comp_delete); +	err = device_create_file(&pdev->dev, &dev_attr_comp_preload); +	if (err) +		goto fail; +	err = device_create_file(&pdev->dev, &dev_attr_comp_delete); +	if (err) { +		device_remove_file(&pdev->dev, &dev_attr_comp_preload); +		goto fail; +	}  	return 0; + +fail: +	if (ep93xx_rtc->mmio_base) { +		iounmap(ep93xx_rtc->mmio_base); +		pdev->dev.platform_data = NULL; +	} +	release_mem_region(res->start, resource_size(res)); +	return err;  } -static int __devexit ep93xx_rtc_remove(struct platform_device *dev) +static int __exit ep93xx_rtc_remove(struct platform_device *pdev)  { -	struct rtc_device *rtc = platform_get_drvdata(dev); +	struct rtc_device *rtc = platform_get_drvdata(pdev); +	struct ep93xx_rtc *ep93xx_rtc = pdev->dev.platform_data; +	struct resource *res; + +	/* cleanup sysfs */ +	device_remove_file(&pdev->dev, &dev_attr_comp_delete); +	device_remove_file(&pdev->dev, &dev_attr_comp_preload); + +	rtc_device_unregister(rtc); + +	iounmap(ep93xx_rtc->mmio_base); +	pdev->dev.platform_data = NULL; - 	if (rtc) -		rtc_device_unregister(rtc); +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0); +	release_mem_region(res->start, resource_size(res)); -	platform_set_drvdata(dev, NULL); +	platform_set_drvdata(pdev, NULL);  	return 0;  } @@ -122,23 +198,22 @@ static int __devexit ep93xx_rtc_remove(struct platform_device *dev)  /* work with hotplug and coldplug */  MODULE_ALIAS("platform:ep93xx-rtc"); -static struct platform_driver ep93xx_rtc_platform_driver = { +static struct platform_driver ep93xx_rtc_driver = {  	.driver		= {  		.name	= "ep93xx-rtc",  		.owner	= THIS_MODULE,  	}, -	.probe		= ep93xx_rtc_probe, -	.remove		= __devexit_p(ep93xx_rtc_remove), +	.remove		= __exit_p(ep93xx_rtc_remove),  };  static int __init ep93xx_rtc_init(void)  { -	return platform_driver_register(&ep93xx_rtc_platform_driver); +        return platform_driver_probe(&ep93xx_rtc_driver, ep93xx_rtc_probe);  }  static void __exit ep93xx_rtc_exit(void)  { -	platform_driver_unregister(&ep93xx_rtc_platform_driver); +	platform_driver_unregister(&ep93xx_rtc_driver);  }  MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>"); diff --git a/drivers/rtc/rtc-pl030.c b/drivers/rtc/rtc-pl030.c index aaf1f75fa29..457231bb102 100644 --- a/drivers/rtc/rtc-pl030.c +++ b/drivers/rtc/rtc-pl030.c @@ -117,7 +117,7 @@ static int pl030_probe(struct amba_device *dev, struct amba_id *id)  		goto err_rtc;  	} -	rtc->base = ioremap(dev->res.start, SZ_4K); +	rtc->base = ioremap(dev->res.start, resource_size(&dev->res));  	if (!rtc->base) {  		ret = -ENOMEM;  		goto err_map; diff --git a/drivers/rtc/rtc-pl031.c b/drivers/rtc/rtc-pl031.c index 451fc13784d..f41873f98f6 100644 --- a/drivers/rtc/rtc-pl031.c +++ b/drivers/rtc/rtc-pl031.c @@ -142,8 +142,7 @@ static int pl031_probe(struct amba_device *adev, struct amba_id *id)  		goto out;  	} -	ldata->base = ioremap(adev->res.start, -			      adev->res.end - adev->res.start + 1); +	ldata->base = ioremap(adev->res.start, resource_size(&adev->res));  	if (!ldata->base) {  		ret = -ENOMEM;  		goto out_no_remap; diff --git a/drivers/rtc/rtc-rx8025.c b/drivers/rtc/rtc-rx8025.c new file mode 100644 index 00000000000..b1a29bcfdf1 --- /dev/null +++ b/drivers/rtc/rtc-rx8025.c @@ -0,0 +1,688 @@ +/* + * Driver for Epson's RTC module RX-8025 SA/NB + * + * Copyright (C) 2009 Wolfgang Grandegger <wg@grandegger.com> + * + * Copyright (C) 2005 by Digi International Inc. + * All rights reserved. + * + * Modified by fengjh at rising.com.cn + * <http://lists.lm-sensors.org/mailman/listinfo/lm-sensors> + * 2006.11 + * + * Code cleanup by Sergei Poselenov, <sposelenov@emcraft.com> + * Converted to new style by Wolfgang Grandegger <wg@grandegger.com> + * Alarm and periodic interrupt added by Dmitry Rakhchev <rda@emcraft.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/bcd.h> +#include <linux/i2c.h> +#include <linux/list.h> +#include <linux/rtc.h> + +/* Register definitions */ +#define RX8025_REG_SEC		0x00 +#define RX8025_REG_MIN		0x01 +#define RX8025_REG_HOUR		0x02 +#define RX8025_REG_WDAY		0x03 +#define RX8025_REG_MDAY		0x04 +#define RX8025_REG_MONTH	0x05 +#define RX8025_REG_YEAR		0x06 +#define RX8025_REG_DIGOFF	0x07 +#define RX8025_REG_ALWMIN	0x08 +#define RX8025_REG_ALWHOUR	0x09 +#define RX8025_REG_ALWWDAY	0x0a +#define RX8025_REG_ALDMIN	0x0b +#define RX8025_REG_ALDHOUR	0x0c +/* 0x0d is reserved */ +#define RX8025_REG_CTRL1	0x0e +#define RX8025_REG_CTRL2	0x0f + +#define RX8025_BIT_CTRL1_CT	(7 << 0) +/* 1 Hz periodic level irq */ +#define RX8025_BIT_CTRL1_CT_1HZ	4 +#define RX8025_BIT_CTRL1_TEST	(1 << 3) +#define RX8025_BIT_CTRL1_1224	(1 << 5) +#define RX8025_BIT_CTRL1_DALE	(1 << 6) +#define RX8025_BIT_CTRL1_WALE	(1 << 7) + +#define RX8025_BIT_CTRL2_DAFG	(1 << 0) +#define RX8025_BIT_CTRL2_WAFG	(1 << 1) +#define RX8025_BIT_CTRL2_CTFG	(1 << 2) +#define RX8025_BIT_CTRL2_PON	(1 << 4) +#define RX8025_BIT_CTRL2_XST	(1 << 5) +#define RX8025_BIT_CTRL2_VDET	(1 << 6) + +/* Clock precision adjustment */ +#define RX8025_ADJ_RESOLUTION	3050 /* in ppb */ +#define RX8025_ADJ_DATA_MAX	62 +#define RX8025_ADJ_DATA_MIN	-62 + +static const struct i2c_device_id rx8025_id[] = { +	{ "rx8025", 0 }, +	{ } +}; +MODULE_DEVICE_TABLE(i2c, rx8025_id); + +struct rx8025_data { +	struct i2c_client *client; +	struct rtc_device *rtc; +	struct work_struct work; +	u8 ctrl1; +	unsigned exiting:1; +}; + +static int rx8025_read_reg(struct i2c_client *client, int number, u8 *value) +{ +	int ret = i2c_smbus_read_byte_data(client, (number << 4) | 0x08); + +	if (ret < 0) { +		dev_err(&client->dev, "Unable to read register #%d\n", number); +		return ret; +	} + +	*value = ret; +	return 0; +} + +static int rx8025_read_regs(struct i2c_client *client, +			    int number, u8 length, u8 *values) +{ +	int ret = i2c_smbus_read_i2c_block_data(client, (number << 4) | 0x08, +						length, values); + +	if (ret != length) { +		dev_err(&client->dev, "Unable to read registers #%d..#%d\n", +			number, number + length - 1); +		return ret < 0 ? ret : -EIO; +	} + +	return 0; +} + +static int rx8025_write_reg(struct i2c_client *client, int number, u8 value) +{ +	int ret = i2c_smbus_write_byte_data(client, number << 4, value); + +	if (ret) +		dev_err(&client->dev, "Unable to write register #%d\n", +			number); + +	return ret; +} + +static int rx8025_write_regs(struct i2c_client *client, +			     int number, u8 length, u8 *values) +{ +	int ret = i2c_smbus_write_i2c_block_data(client, (number << 4) | 0x08, +						 length, values); + +	if (ret) +		dev_err(&client->dev, "Unable to write registers #%d..#%d\n", +			number, number + length - 1); + +	return ret; +} + +static irqreturn_t rx8025_irq(int irq, void *dev_id) +{ +	struct i2c_client *client = dev_id; +	struct rx8025_data *rx8025 = i2c_get_clientdata(client); + +	disable_irq_nosync(irq); +	schedule_work(&rx8025->work); +	return IRQ_HANDLED; +} + +static void rx8025_work(struct work_struct *work) +{ +	struct rx8025_data *rx8025 = container_of(work, struct rx8025_data, +						  work); +	struct i2c_client *client = rx8025->client; +	struct mutex *lock = &rx8025->rtc->ops_lock; +	u8 status; + +	mutex_lock(lock); + +	if (rx8025_read_reg(client, RX8025_REG_CTRL2, &status)) +		goto out; + +	if (!(status & RX8025_BIT_CTRL2_XST)) +		dev_warn(&client->dev, "Oscillation stop was detected," +			 "you may have to readjust the clock\n"); + +	if (status & RX8025_BIT_CTRL2_CTFG) { +		/* periodic */ +		status &= ~RX8025_BIT_CTRL2_CTFG; +		local_irq_disable(); +		rtc_update_irq(rx8025->rtc, 1, RTC_PF | RTC_IRQF); +		local_irq_enable(); +	} + +	if (status & RX8025_BIT_CTRL2_DAFG) { +		/* alarm */ +		status &= RX8025_BIT_CTRL2_DAFG; +		if (rx8025_write_reg(client, RX8025_REG_CTRL1, +				     rx8025->ctrl1 & ~RX8025_BIT_CTRL1_DALE)) +			goto out; +		local_irq_disable(); +		rtc_update_irq(rx8025->rtc, 1, RTC_AF | RTC_IRQF); +		local_irq_enable(); +	} + +	/* acknowledge IRQ */ +	rx8025_write_reg(client, RX8025_REG_CTRL2, +			 status | RX8025_BIT_CTRL2_XST); + +out: +	if (!rx8025->exiting) +		enable_irq(client->irq); + +	mutex_unlock(lock); +} + +static int rx8025_get_time(struct device *dev, struct rtc_time *dt) +{ +	struct rx8025_data *rx8025 = dev_get_drvdata(dev); +	u8 date[7]; +	int err; + +	err = rx8025_read_regs(rx8025->client, RX8025_REG_SEC, 7, date); +	if (err) +		return err; + +	dev_dbg(dev, "%s: read 0x%02x 0x%02x " +		"0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", __func__, +		date[0], date[1], date[2], date[3], date[4], +		date[5], date[6]); + +	dt->tm_sec = bcd2bin(date[RX8025_REG_SEC] & 0x7f); +	dt->tm_min = bcd2bin(date[RX8025_REG_MIN] & 0x7f); +	if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224) +		dt->tm_hour = bcd2bin(date[RX8025_REG_HOUR] & 0x3f); +	else +		dt->tm_hour = bcd2bin(date[RX8025_REG_HOUR] & 0x1f) % 12 +			+ (date[RX8025_REG_HOUR] & 0x20 ? 12 : 0); + +	dt->tm_mday = bcd2bin(date[RX8025_REG_MDAY] & 0x3f); +	dt->tm_mon = bcd2bin(date[RX8025_REG_MONTH] & 0x1f) - 1; +	dt->tm_year = bcd2bin(date[RX8025_REG_YEAR]); + +	if (dt->tm_year < 70) +		dt->tm_year += 100; + +	dev_dbg(dev, "%s: date %ds %dm %dh %dmd %dm %dy\n", __func__, +		dt->tm_sec, dt->tm_min, dt->tm_hour, +		dt->tm_mday, dt->tm_mon, dt->tm_year); + +	return rtc_valid_tm(dt); +} + +static int rx8025_set_time(struct device *dev, struct rtc_time *dt) +{ +	struct rx8025_data *rx8025 = dev_get_drvdata(dev); +	u8 date[7]; + +	/* +	 * BUG: The HW assumes every year that is a multiple of 4 to be a leap +	 * year.  Next time this is wrong is 2100, which will not be a leap +	 * year. +	 */ + +	/* +	 * Here the read-only bits are written as "0".  I'm not sure if that +	 * is sound. +	 */ +	date[RX8025_REG_SEC] = bin2bcd(dt->tm_sec); +	date[RX8025_REG_MIN] = bin2bcd(dt->tm_min); +	if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224) +		date[RX8025_REG_HOUR] = bin2bcd(dt->tm_hour); +	else +		date[RX8025_REG_HOUR] = (dt->tm_hour >= 12 ? 0x20 : 0) +			| bin2bcd((dt->tm_hour + 11) % 12 + 1); + +	date[RX8025_REG_WDAY] = bin2bcd(dt->tm_wday); +	date[RX8025_REG_MDAY] = bin2bcd(dt->tm_mday); +	date[RX8025_REG_MONTH] = bin2bcd(dt->tm_mon + 1); +	date[RX8025_REG_YEAR] = bin2bcd(dt->tm_year % 100); + +	dev_dbg(dev, +		"%s: write 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", +		__func__, +		date[0], date[1], date[2], date[3], date[4], date[5], date[6]); + +	return rx8025_write_regs(rx8025->client, RX8025_REG_SEC, 7, date); +} + +static int rx8025_init_client(struct i2c_client *client, int *need_reset) +{ +	struct rx8025_data *rx8025 = i2c_get_clientdata(client); +	u8 ctrl[2], ctrl2; +	int need_clear = 0; +	int err; + +	err = rx8025_read_regs(rx8025->client, RX8025_REG_CTRL1, 2, ctrl); +	if (err) +		goto out; + +	/* Keep test bit zero ! */ +	rx8025->ctrl1 = ctrl[0] & ~RX8025_BIT_CTRL1_TEST; + +	if (ctrl[1] & RX8025_BIT_CTRL2_PON) { +		dev_warn(&client->dev, "power-on reset was detected, " +			 "you may have to readjust the clock\n"); +		*need_reset = 1; +	} + +	if (ctrl[1] & RX8025_BIT_CTRL2_VDET) { +		dev_warn(&client->dev, "a power voltage drop was detected, " +			 "you may have to readjust the clock\n"); +		*need_reset = 1; +	} + +	if (!(ctrl[1] & RX8025_BIT_CTRL2_XST)) { +		dev_warn(&client->dev, "Oscillation stop was detected," +			 "you may have to readjust the clock\n"); +		*need_reset = 1; +	} + +	if (ctrl[1] & (RX8025_BIT_CTRL2_DAFG | RX8025_BIT_CTRL2_WAFG)) { +		dev_warn(&client->dev, "Alarm was detected\n"); +		need_clear = 1; +	} + +	if (!(ctrl[1] & RX8025_BIT_CTRL2_CTFG)) +		need_clear = 1; + +	if (*need_reset || need_clear) { +		ctrl2 = ctrl[0]; +		ctrl2 &= ~(RX8025_BIT_CTRL2_PON | RX8025_BIT_CTRL2_VDET | +			   RX8025_BIT_CTRL2_CTFG | RX8025_BIT_CTRL2_WAFG | +			   RX8025_BIT_CTRL2_DAFG); +		ctrl2 |= RX8025_BIT_CTRL2_XST; + +		err = rx8025_write_reg(client, RX8025_REG_CTRL2, ctrl2); +	} +out: +	return err; +} + +/* Alarm support */ +static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t) +{ +	struct rx8025_data *rx8025 = dev_get_drvdata(dev); +	struct i2c_client *client = rx8025->client; +	u8 ctrl2, ald[2]; +	int err; + +	if (client->irq <= 0) +		return -EINVAL; + +	err = rx8025_read_regs(client, RX8025_REG_ALDMIN, 2, ald); +	if (err) +		return err; + +	err = rx8025_read_reg(client, RX8025_REG_CTRL2, &ctrl2); +	if (err) +		return err; + +	dev_dbg(dev, "%s: read alarm 0x%02x 0x%02x ctrl2 %02x\n", +		__func__, ald[0], ald[1], ctrl2); + +	/* Hardware alarms precision is 1 minute! */ +	t->time.tm_sec = 0; +	t->time.tm_min = bcd2bin(ald[0] & 0x7f); +	if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224) +		t->time.tm_hour = bcd2bin(ald[1] & 0x3f); +	else +		t->time.tm_hour = bcd2bin(ald[1] & 0x1f) % 12 +			+ (ald[1] & 0x20 ? 12 : 0); + +	t->time.tm_wday = -1; +	t->time.tm_mday = -1; +	t->time.tm_mon = -1; +	t->time.tm_year = -1; + +	dev_dbg(dev, "%s: date: %ds %dm %dh %dmd %dm %dy\n", +		__func__, +		t->time.tm_sec, t->time.tm_min, t->time.tm_hour, +		t->time.tm_mday, t->time.tm_mon, t->time.tm_year); +	t->enabled = !!(rx8025->ctrl1 & RX8025_BIT_CTRL1_DALE); +	t->pending = (ctrl2 & RX8025_BIT_CTRL2_DAFG) && t->enabled; + +	return err; +} + +static int rx8025_set_alarm(struct device *dev, struct rtc_wkalrm *t) +{ +	struct i2c_client *client = to_i2c_client(dev); +	struct rx8025_data *rx8025 = dev_get_drvdata(dev); +	u8 ald[2]; +	int err; + +	if (client->irq <= 0) +		return -EINVAL; + +	/* Hardware alarm precision is 1 minute! */ +	ald[0] = bin2bcd(t->time.tm_min); +	if (rx8025->ctrl1 & RX8025_BIT_CTRL1_1224) +		ald[1] = bin2bcd(t->time.tm_hour); +	else +		ald[1] = (t->time.tm_hour >= 12 ? 0x20 : 0) +			| bin2bcd((t->time.tm_hour + 11) % 12 + 1); + +	dev_dbg(dev, "%s: write 0x%02x 0x%02x\n", __func__, ald[0], ald[1]); + +	if (rx8025->ctrl1 & RX8025_BIT_CTRL1_DALE) { +		rx8025->ctrl1 &= ~RX8025_BIT_CTRL1_DALE; +		err = rx8025_write_reg(rx8025->client, RX8025_REG_CTRL1, +				       rx8025->ctrl1); +		if (err) +			return err; +	} +	err = rx8025_write_regs(rx8025->client, RX8025_REG_ALDMIN, 2, ald); +	if (err) +		return err; + +	if (t->enabled) { +		rx8025->ctrl1 |= RX8025_BIT_CTRL1_DALE; +		err = rx8025_write_reg(rx8025->client, RX8025_REG_CTRL1, +				       rx8025->ctrl1); +		if (err) +			return err; +	} + +	return 0; +} + +static int rx8025_alarm_irq_enable(struct device *dev, unsigned int enabled) +{ +	struct rx8025_data *rx8025 = dev_get_drvdata(dev); +	u8 ctrl1; +	int err; + +	ctrl1 = rx8025->ctrl1; +	if (enabled) +		ctrl1 |= RX8025_BIT_CTRL1_DALE; +	else +		ctrl1 &= ~RX8025_BIT_CTRL1_DALE; + +	if (ctrl1 != rx8025->ctrl1) { +		rx8025->ctrl1 = ctrl1; +		err = rx8025_write_reg(rx8025->client, RX8025_REG_CTRL1, +				       rx8025->ctrl1); +		if (err) +			return err; +	} +	return 0; +} + +static int rx8025_irq_set_state(struct device *dev, int enabled) +{ +	struct i2c_client *client = to_i2c_client(dev); +	struct rx8025_data *rx8025 = i2c_get_clientdata(client); +	int ctrl1; +	int err; + +	if (client->irq <= 0) +		return -ENXIO; + +	ctrl1 = rx8025->ctrl1 & ~RX8025_BIT_CTRL1_CT; +	if (enabled) +		ctrl1 |= RX8025_BIT_CTRL1_CT_1HZ; +	if (ctrl1 != rx8025->ctrl1) { +		rx8025->ctrl1 = ctrl1; +		err = rx8025_write_reg(rx8025->client, RX8025_REG_CTRL1, +				       rx8025->ctrl1); +		if (err) +			return err; +	} + +	return 0; +} + +static struct rtc_class_ops rx8025_rtc_ops = { +	.read_time = rx8025_get_time, +	.set_time = rx8025_set_time, +	.read_alarm = rx8025_read_alarm, +	.set_alarm = rx8025_set_alarm, +	.alarm_irq_enable = rx8025_alarm_irq_enable, +	.irq_set_state  = rx8025_irq_set_state, +}; + +/* + * Clock precision adjustment support + * + * According to the RX8025 SA/NB application manual the frequency and + * temperature charateristics can be approximated using the following + * equation: + * + *   df = a * (ut - t)**2 + * + *   df: Frequency deviation in any temperature + *   a : Coefficient = (-35 +-5) * 10**-9 + *   ut: Ultimate temperature in degree = +25 +-5 degree + *   t : Any temperature in degree + * + * Note that the clock adjustment in ppb must be entered (which is + * the negative value of the deviation). + */ +static int rx8025_get_clock_adjust(struct device *dev, int *adj) +{ +	struct i2c_client *client = to_i2c_client(dev); +	u8 digoff; +	int err; + +	err = rx8025_read_reg(client, RX8025_REG_DIGOFF, &digoff); +	if (err) +		return err; + +	*adj = digoff >= 64 ? digoff - 128 : digoff; +	if (*adj > 0) +		(*adj)--; +	*adj *= -RX8025_ADJ_RESOLUTION; + +	return 0; +} + +static int rx8025_set_clock_adjust(struct device *dev, int adj) +{ +	struct i2c_client *client = to_i2c_client(dev); +	u8 digoff; +	int err; + +	adj /= -RX8025_ADJ_RESOLUTION; +	if (adj > RX8025_ADJ_DATA_MAX) +		adj = RX8025_ADJ_DATA_MAX; +	else if (adj < RX8025_ADJ_DATA_MIN) +		adj = RX8025_ADJ_DATA_MIN; +	else if (adj > 0) +		adj++; +	else if (adj < 0) +		adj += 128; +	digoff = adj; + +	err = rx8025_write_reg(client, RX8025_REG_DIGOFF, digoff); +	if (err) +		return err; + +	dev_dbg(dev, "%s: write 0x%02x\n", __func__, digoff); + +	return 0; +} + +static ssize_t rx8025_sysfs_show_clock_adjust(struct device *dev, +					      struct device_attribute *attr, +					      char *buf) +{ +	int err, adj; + +	err = rx8025_get_clock_adjust(dev, &adj); +	if (err) +		return err; + +	return sprintf(buf, "%d\n", adj); +} + +static ssize_t rx8025_sysfs_store_clock_adjust(struct device *dev, +					       struct device_attribute *attr, +					       const char *buf, size_t count) +{ +	int adj, err; + +	if (sscanf(buf, "%i", &adj) != 1) +		return -EINVAL; + +	err = rx8025_set_clock_adjust(dev, adj); + +	return err ? err : count; +} + +static DEVICE_ATTR(clock_adjust_ppb, S_IRUGO | S_IWUSR, +		   rx8025_sysfs_show_clock_adjust, +		   rx8025_sysfs_store_clock_adjust); + +static int rx8025_sysfs_register(struct device *dev) +{ +	return device_create_file(dev, &dev_attr_clock_adjust_ppb); +} + +static void rx8025_sysfs_unregister(struct device *dev) +{ +	device_remove_file(dev, &dev_attr_clock_adjust_ppb); +} + +static int __devinit rx8025_probe(struct i2c_client *client, +				  const struct i2c_device_id *id) +{ +	struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); +	struct rx8025_data *rx8025; +	int err, need_reset = 0; + +	if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA +				     | I2C_FUNC_SMBUS_I2C_BLOCK)) { +		dev_err(&adapter->dev, +			"doesn't support required functionality\n"); +		err = -EIO; +		goto errout; +	} + +	rx8025 = kzalloc(sizeof(*rx8025), GFP_KERNEL); +	if (!rx8025) { +		dev_err(&adapter->dev, "failed to alloc memory\n"); +		err = -ENOMEM; +		goto errout; +	} + +	rx8025->client = client; +	i2c_set_clientdata(client, rx8025); +	INIT_WORK(&rx8025->work, rx8025_work); + +	err = rx8025_init_client(client, &need_reset); +	if (err) +		goto errout_free; + +	if (need_reset) { +		struct rtc_time tm; +		dev_info(&client->dev, +			 "bad conditions detected, resetting date\n"); +		rtc_time_to_tm(0, &tm);	/* 1970/1/1 */ +		rx8025_set_time(&client->dev, &tm); +	} + +	rx8025->rtc = rtc_device_register(client->name, &client->dev, +					  &rx8025_rtc_ops, THIS_MODULE); +	if (IS_ERR(rx8025->rtc)) { +		err = PTR_ERR(rx8025->rtc); +		dev_err(&client->dev, "unable to register the class device\n"); +		goto errout_free; +	} + +	if (client->irq > 0) { +		dev_info(&client->dev, "IRQ %d supplied\n", client->irq); +		err = request_irq(client->irq, rx8025_irq, +				  0, "rx8025", client); +		if (err) { +			dev_err(&client->dev, "unable to request IRQ\n"); +			goto errout_reg; +		} +	} + +	rx8025->rtc->irq_freq = 1; +	rx8025->rtc->max_user_freq = 1; + +	err = rx8025_sysfs_register(&client->dev); +	if (err) +		goto errout_irq; + +	return 0; + +errout_irq: +	if (client->irq > 0) +		free_irq(client->irq, client); + +errout_reg: +	rtc_device_unregister(rx8025->rtc); + +errout_free: +	i2c_set_clientdata(client, NULL); +	kfree(rx8025); + +errout: +	dev_err(&adapter->dev, "probing for rx8025 failed\n"); +	return err; +} + +static int __devexit rx8025_remove(struct i2c_client *client) +{ +	struct rx8025_data *rx8025 = i2c_get_clientdata(client); +	struct mutex *lock = &rx8025->rtc->ops_lock; + +	if (client->irq > 0) { +		mutex_lock(lock); +		rx8025->exiting = 1; +		mutex_unlock(lock); + +		free_irq(client->irq, client); +		flush_scheduled_work(); +	} + +	rx8025_sysfs_unregister(&client->dev); +	rtc_device_unregister(rx8025->rtc); +	i2c_set_clientdata(client, NULL); +	kfree(rx8025); +	return 0; +} + +static struct i2c_driver rx8025_driver = { +	.driver = { +		.name = "rtc-rx8025", +		.owner = THIS_MODULE, +	}, +	.probe		= rx8025_probe, +	.remove		= __devexit_p(rx8025_remove), +	.id_table	= rx8025_id, +}; + +static int __init rx8025_init(void) +{ +	return i2c_add_driver(&rx8025_driver); +} + +static void __exit rx8025_exit(void) +{ +	i2c_del_driver(&rx8025_driver); +} + +MODULE_AUTHOR("Wolfgang Grandegger <wg@grandegger.com>"); +MODULE_DESCRIPTION("RX-8025 SA/NB RTC driver"); +MODULE_LICENSE("GPL"); + +module_init(rx8025_init); +module_exit(rx8025_exit); diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index e478280ff62..51725f7755b 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -93,7 +93,6 @@ static ssize_t test_irq_store(struct device *dev,  	struct rtc_device *rtc = platform_get_drvdata(plat_dev);  	retval = count; -	local_irq_disable();  	if (strncmp(buf, "tick", 4) == 0)  		rtc_update_irq(rtc, 1, RTC_PF | RTC_IRQF);  	else if (strncmp(buf, "alarm", 5) == 0) @@ -102,7 +101,6 @@ static ssize_t test_irq_store(struct device *dev,  		rtc_update_irq(rtc, 1, RTC_UF | RTC_IRQF);  	else  		retval = -EINVAL; -	local_irq_enable();  	return retval;  } diff --git a/drivers/rtc/rtc-tx4939.c b/drivers/rtc/rtc-tx4939.c index 4ee4857ff20..4a6ed1104fb 100644 --- a/drivers/rtc/rtc-tx4939.c +++ b/drivers/rtc/rtc-tx4939.c @@ -261,10 +261,8 @@ static int __init tx4939_rtc_probe(struct platform_device *pdev)  	tx4939_rtc_cmd(pdata->rtcreg, TX4939_RTCCTL_COMMAND_NOP);  	if (devm_request_irq(&pdev->dev, irq, tx4939_rtc_interrupt, -			     IRQF_DISABLED | IRQF_SHARED, -			     pdev->name, &pdev->dev) < 0) { +			     IRQF_DISABLED, pdev->name, &pdev->dev) < 0)  		return -EBUSY; -	}  	rtc = rtc_device_register(pdev->name, &pdev->dev,  				  &tx4939_rtc_ops, THIS_MODULE);  	if (IS_ERR(rtc)) | 
