summaryrefslogtreecommitdiffstats
path: root/drivers/rtc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rtc')
-rw-r--r--drivers/rtc/Kconfig28
-rw-r--r--drivers/rtc/Makefile3
-rw-r--r--drivers/rtc/rtc-at32ap700x.c4
-rw-r--r--drivers/rtc/rtc-bq32k.c204
-rw-r--r--drivers/rtc/rtc-bq4802.c3
-rw-r--r--drivers/rtc/rtc-cmos.c78
-rw-r--r--drivers/rtc/rtc-ds1302.c1
-rw-r--r--drivers/rtc/rtc-ds1305.c14
-rw-r--r--drivers/rtc/rtc-ds1307.c2
-rw-r--r--drivers/rtc/rtc-ds1511.c148
-rw-r--r--drivers/rtc/rtc-ds1553.c149
-rw-r--r--drivers/rtc/rtc-ds1742.c59
-rw-r--r--drivers/rtc/rtc-m48t35.c16
-rw-r--r--drivers/rtc/rtc-m48t59.c11
-rw-r--r--drivers/rtc/rtc-mc13783.c262
-rw-r--r--drivers/rtc/rtc-mv.c157
-rw-r--r--drivers/rtc/rtc-nuc900.c342
-rw-r--r--drivers/rtc/rtc-omap.c47
-rw-r--r--drivers/rtc/rtc-pcf50633.c5
-rw-r--r--drivers/rtc/rtc-pcf8563.c4
-rw-r--r--drivers/rtc/rtc-pcf8583.c3
-rw-r--r--drivers/rtc/rtc-pl031.c23
-rw-r--r--drivers/rtc/rtc-stk17ta8.c124
-rw-r--r--drivers/rtc/rtc-tx4939.c51
-rw-r--r--drivers/rtc/rtc-v3020.c8
-rw-r--r--drivers/rtc/rtc-vr41xx.c4
-rw-r--r--drivers/rtc/rtc-wm8350.c14
-rw-r--r--drivers/rtc/rtc-x1205.c53
28 files changed, 1357 insertions, 460 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 71fbd6e8edf..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
@@ -592,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"
@@ -846,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 7da6efb3e95..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,8 +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
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, &regs, 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, &regs, 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, &reg, BQ32K_SECONDS, 1);
+ if (!error && (reg & BQ32K_STOP)) {
+ dev_warn(dev, "Oscillator was halted. Restarting...\n");
+ reg &= ~BQ32K_STOP;
+ error = bq32k_write(dev, &reg, BQ32K_SECONDS, 1);
+ }
+ if (error)
+ return error;
+
+ /* Check Oscillator Failure flag */
+ error = bq32k_read(dev, &reg, BQ32K_MINUTES, 1);
+ if (!error && (reg & BQ32K_OF)) {
+ dev_warn(dev, "Oscillator Failure. Check RTC battery.\n");
+ reg &= ~BQ32K_OF;
+ error = bq32k_write(dev, &reg, 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-ds1302.c b/drivers/rtc/rtc-ds1302.c
index 1e73c8f42e3..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)))
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 539676e25fd..4166b84cb51 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -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;
}
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-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 9b74e9c9151..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;
@@ -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,6 +246,8 @@ 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 || alrm->enabled)
pcf50633_irq_unmask(rtc->pcf, PCF50633_IRQ_ALARM);
@@ -268,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);
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-stk17ta8.c b/drivers/rtc/rtc-stk17ta8.c
index d491eb265c3..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;
@@ -288,31 +285,26 @@ static struct bin_attribute stk17ta8_nvram_attr = {
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 __devinit 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 __devinit 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-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 ad741afd47d..bed4cab0704 100644
--- a/drivers/rtc/rtc-v3020.c
+++ b/drivers/rtc/rtc-v3020.c
@@ -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;
@@ -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 fadddac1e5a..c3244244e8c 100644
--- a/drivers/rtc/rtc-vr41xx.c
+++ b/drivers/rtc/rtc-vr41xx.c
@@ -327,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;
@@ -337,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-wm8350.c b/drivers/rtc/rtc-wm8350.c
index f16486635a8..f1e440521c5 100644
--- a/drivers/rtc/rtc-wm8350.c
+++ b/drivers/rtc/rtc-wm8350.c
@@ -354,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;
@@ -373,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;
@@ -484,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 6583c1a8b07..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 + 1900) / 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__,
@@ -282,7 +265,7 @@ static int x1205_fix_osc(struct i2c_client *client)
memset(&tm, 0, sizeof(tm));
- err = x1205_set_datetime(client, &tm, 1, 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)