diff options
Diffstat (limited to 'drivers/rtc')
-rw-r--r-- | drivers/rtc/Kconfig | 10 | ||||
-rw-r--r-- | drivers/rtc/Makefile | 1 | ||||
-rw-r--r-- | drivers/rtc/class.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-ds1672.c | 72 | ||||
-rw-r--r-- | drivers/rtc/rtc-ep93xx.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-m48t86.c | 9 | ||||
-rw-r--r-- | drivers/rtc/rtc-pcf8563.c | 11 | ||||
-rw-r--r-- | drivers/rtc/rtc-proc.c | 2 | ||||
-rw-r--r-- | drivers/rtc/rtc-rs5c372.c | 28 | ||||
-rw-r--r-- | drivers/rtc/rtc-sa1100.c | 14 | ||||
-rw-r--r-- | drivers/rtc/rtc-test.c | 3 | ||||
-rw-r--r-- | drivers/rtc/rtc-vr41xx.c | 471 | ||||
-rw-r--r-- | drivers/rtc/rtc-x1205.c | 29 |
13 files changed, 575 insertions, 79 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 929dd809057..65d090dbef4 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig @@ -147,6 +147,16 @@ config RTC_DRV_SA1100 To compile this driver as a module, choose M here: the module will be called rtc-sa1100. +config RTC_DRV_VR41XX + tristate "NEC VR41XX" + depends on RTC_CLASS && CPU_VR41XX + help + If you say Y here you will get access to the real time clock + built into your NEC VR41XX CPU. + + To compile this driver as a module, choose M here: the + module will be called rtc-vr41xx. + config RTC_DRV_TEST tristate "Test driver/device" depends on RTC_CLASS diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile index 8d4c7fe88d5..a9ca0f17168 100644 --- a/drivers/rtc/Makefile +++ b/drivers/rtc/Makefile @@ -19,3 +19,4 @@ obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o +obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c index 8533936d50d..413c7d54ea1 100644 --- a/drivers/rtc/class.c +++ b/drivers/rtc/class.c @@ -96,6 +96,8 @@ exit_idr: idr_remove(&rtc_idr, id); exit: + dev_err(dev, "rtc core: unable to register %s, err = %d\n", + name, err); return ERR_PTR(err); } EXPORT_SYMBOL_GPL(rtc_device_register); diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c index 358695a416f..9be81fd4737 100644 --- a/drivers/rtc/rtc-ds1672.c +++ b/drivers/rtc/rtc-ds1672.c @@ -1,6 +1,8 @@ /* * An rtc/i2c driver for the Dallas DS1672 - * Copyright 2005 Alessandro Zummo + * Copyright 2005-06 Tower Technologies + * + * Author: Alessandro Zummo <a.zummo@towertech.it> * * 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 @@ -11,7 +13,7 @@ #include <linux/i2c.h> #include <linux/rtc.h> -#define DRV_VERSION "0.2" +#define DRV_VERSION "0.3" /* Addresses to scan: none. This chip cannot be detected. */ static unsigned short normal_i2c[] = { I2C_CLIENT_END }; @@ -25,6 +27,7 @@ I2C_CLIENT_INSMOD; #define DS1672_REG_CONTROL 4 #define DS1672_REG_TRICKLE 5 +#define DS1672_REG_CONTROL_EOSC 0x80 /* Prototypes */ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind); @@ -53,8 +56,7 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) dev_dbg(&client->dev, "%s: raw read data - counters=%02x,%02x,%02x,%02x\n" - __FUNCTION__, - buf[0], buf[1], buf[2], buf[3]); + __FUNCTION__, buf[0], buf[1], buf[2], buf[3]); time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0]; @@ -62,8 +64,7 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " "mday=%d, mon=%d, year=%d, wday=%d\n", - __FUNCTION__, - tm->tm_sec, tm->tm_min, tm->tm_hour, + __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour, tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); return 0; @@ -72,16 +73,17 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm) static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs) { int xfer; - unsigned char buf[5]; + unsigned char buf[6]; buf[0] = DS1672_REG_CNT_BASE; buf[1] = secs & 0x000000FF; buf[2] = (secs & 0x0000FF00) >> 8; buf[3] = (secs & 0x00FF0000) >> 16; buf[4] = (secs & 0xFF000000) >> 24; + buf[5] = 0; /* set control reg to enable counting */ - xfer = i2c_master_send(client, buf, 5); - if (xfer != 5) { + xfer = i2c_master_send(client, buf, 6); + if (xfer != 6) { dev_err(&client->dev, "%s: send: %d\n", __FUNCTION__, xfer); return -EIO; } @@ -120,6 +122,40 @@ static int ds1672_rtc_set_mmss(struct device *dev, unsigned long secs) return ds1672_set_mmss(to_i2c_client(dev), secs); } +static int ds1672_get_control(struct i2c_client *client, u8 *status) +{ + unsigned char addr = DS1672_REG_CONTROL; + + struct i2c_msg msgs[] = { + { client->addr, 0, 1, &addr }, /* setup read ptr */ + { client->addr, I2C_M_RD, 1, status }, /* read control */ + }; + + /* read control register */ + if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) { + dev_err(&client->dev, "%s: read error\n", __FUNCTION__); + return -EIO; + } + + return 0; +} + +/* following are the sysfs callback functions */ +static ssize_t show_control(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct i2c_client *client = to_i2c_client(dev); + u8 control; + int err; + + err = ds1672_get_control(client, &control); + if (err) + return err; + + return sprintf(buf, "%s\n", (control & DS1672_REG_CONTROL_EOSC) + ? "disabled" : "enabled"); +} +static DEVICE_ATTR(control, S_IRUGO, show_control, NULL); + static struct rtc_class_ops ds1672_rtc_ops = { .read_time = ds1672_rtc_read_time, .set_time = ds1672_rtc_set_time, @@ -128,7 +164,6 @@ static struct rtc_class_ops ds1672_rtc_ops = { static int ds1672_attach(struct i2c_adapter *adapter) { - dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); return i2c_probe(adapter, &addr_data, ds1672_probe); } @@ -137,8 +172,6 @@ static int ds1672_detach(struct i2c_client *client) int err; struct rtc_device *rtc = i2c_get_clientdata(client); - dev_dbg(&client->dev, "%s\n", __FUNCTION__); - if (rtc) rtc_device_unregister(rtc); @@ -162,6 +195,7 @@ static struct i2c_driver ds1672_driver = { static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind) { int err = 0; + u8 control; struct i2c_client *client; struct rtc_device *rtc; @@ -195,13 +229,23 @@ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind) if (IS_ERR(rtc)) { err = PTR_ERR(rtc); - dev_err(&client->dev, - "unable to register the class device\n"); goto exit_detach; } i2c_set_clientdata(client, rtc); + /* read control register */ + err = ds1672_get_control(client, &control); + if (err) + goto exit_detach; + + if (control & DS1672_REG_CONTROL_EOSC) + dev_warn(&client->dev, "Oscillator not enabled. " + "Set time to enable.\n"); + + /* Register sysfs hooks */ + device_create_file(&client->dev, &dev_attr_control); + return 0; exit_detach: diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c index 0dd80ea686a..e1a1169e466 100644 --- a/drivers/rtc/rtc-ep93xx.c +++ b/drivers/rtc/rtc-ep93xx.c @@ -67,7 +67,6 @@ static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq) ep93xx_get_swcomp(dev, &preload, &delete); - seq_printf(seq, "24hr\t\t: yes\n"); seq_printf(seq, "preload\t\t: %d\n", preload); seq_printf(seq, "delete\t\t: %d\n", delete); @@ -110,7 +109,6 @@ static int __devinit ep93xx_rtc_probe(struct platform_device *dev) &dev->dev, &ep93xx_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { - dev_err(&dev->dev, "unable to register\n"); return PTR_ERR(rtc); } diff --git a/drivers/rtc/rtc-m48t86.c b/drivers/rtc/rtc-m48t86.c index db445c872b1..f6e7ee04f3d 100644 --- a/drivers/rtc/rtc-m48t86.c +++ b/drivers/rtc/rtc-m48t86.c @@ -23,7 +23,7 @@ #define M48T86_REG_SECALRM 0x01 #define M48T86_REG_MIN 0x02 #define M48T86_REG_MINALRM 0x03 -#define M48T86_REG_HOUR 0x04 +#define M48T86_REG_HOUR 0x04 #define M48T86_REG_HOURALRM 0x05 #define M48T86_REG_DOW 0x06 /* 1 = sunday */ #define M48T86_REG_DOM 0x07 @@ -127,9 +127,6 @@ static int m48t86_rtc_proc(struct device *dev, struct seq_file *seq) reg = ops->readb(M48T86_REG_B); - seq_printf(seq, "24hr\t\t: %s\n", - (reg & M48T86_REG_B_H24) ? "yes" : "no"); - seq_printf(seq, "mode\t\t: %s\n", (reg & M48T86_REG_B_DM) ? "binary" : "bcd"); @@ -154,10 +151,8 @@ static int __devinit m48t86_rtc_probe(struct platform_device *dev) struct rtc_device *rtc = rtc_device_register("m48t86", &dev->dev, &m48t86_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - dev_err(&dev->dev, "unable to register\n"); + if (IS_ERR(rtc)) return PTR_ERR(rtc); - } platform_set_drvdata(dev, rtc); diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c index d857d45bdbe..ba9a583b7b6 100644 --- a/drivers/rtc/rtc-pcf8563.c +++ b/drivers/rtc/rtc-pcf8563.c @@ -227,14 +227,7 @@ static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm) return pcf8563_set_datetime(to_i2c_client(dev), tm); } -static int pcf8563_rtc_proc(struct device *dev, struct seq_file *seq) -{ - seq_printf(seq, "24hr\t\t: yes\n"); - return 0; -} - static struct rtc_class_ops pcf8563_rtc_ops = { - .proc = pcf8563_rtc_proc, .read_time = pcf8563_rtc_read_time, .set_time = pcf8563_rtc_set_time, }; @@ -297,8 +290,6 @@ static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind) if (IS_ERR(rtc)) { err = PTR_ERR(rtc); - dev_err(&client->dev, - "unable to register the class device\n"); goto exit_detach; } @@ -321,8 +312,6 @@ static int pcf8563_detach(struct i2c_client *client) int err; struct rtc_device *rtc = i2c_get_clientdata(client); - dev_dbg(&client->dev, "%s\n", __FUNCTION__); - if (rtc) rtc_device_unregister(rtc); diff --git a/drivers/rtc/rtc-proc.c b/drivers/rtc/rtc-proc.c index 90b8a97a091..cef5f5a3bbf 100644 --- a/drivers/rtc/rtc-proc.c +++ b/drivers/rtc/rtc-proc.c @@ -71,6 +71,8 @@ static int rtc_proc_show(struct seq_file *seq, void *offset) alrm.pending ? "yes" : "no"); } + seq_printf(seq, "24hr\t\t: yes\n"); + if (ops->proc) ops->proc(class_dev->dev, seq); diff --git a/drivers/rtc/rtc-rs5c372.c b/drivers/rtc/rtc-rs5c372.c index 396c8681f66..7553d797603 100644 --- a/drivers/rtc/rtc-rs5c372.c +++ b/drivers/rtc/rtc-rs5c372.c @@ -151,9 +151,8 @@ static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq) { int err, osc, trim; - seq_printf(seq, "24hr\t\t: yes\n"); - - if ((err = rs5c372_get_trim(to_i2c_client(dev), &osc, &trim)) == 0) { + err = rs5c372_get_trim(to_i2c_client(dev), &osc, &trim); + if (err == 0) { seq_printf(seq, "%d.%03d KHz\n", osc / 1000, osc % 1000); seq_printf(seq, "trim\t: %d\n", trim); } @@ -170,30 +169,31 @@ static struct rtc_class_ops rs5c372_rtc_ops = { static ssize_t rs5c372_sysfs_show_trim(struct device *dev, struct device_attribute *attr, char *buf) { - int trim; + int err, trim; - if (rs5c372_get_trim(to_i2c_client(dev), NULL, &trim) == 0) - return sprintf(buf, "0x%2x\n", trim); + err = rs5c372_get_trim(to_i2c_client(dev), NULL, &trim); + if (err) + return err; - return 0; + return sprintf(buf, "0x%2x\n", trim); } static DEVICE_ATTR(trim, S_IRUGO, rs5c372_sysfs_show_trim, NULL); static ssize_t rs5c372_sysfs_show_osc(struct device *dev, struct device_attribute *attr, char *buf) { - int osc; + int err, osc; - if (rs5c372_get_trim(to_i2c_client(dev), &osc, NULL) == 0) - return sprintf(buf, "%d.%03d KHz\n", osc / 1000, osc % 1000); + err = rs5c372_get_trim(to_i2c_client(dev), &osc, NULL); + if (err) + return err; - return 0; + return sprintf(buf, "%d.%03d KHz\n", osc / 1000, osc % 1000); } static DEVICE_ATTR(osc, S_IRUGO, rs5c372_sysfs_show_osc, NULL); static int rs5c372_attach(struct i2c_adapter *adapter) { - dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); return i2c_probe(adapter, &addr_data, rs5c372_probe); } @@ -233,8 +233,6 @@ static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) if (IS_ERR(rtc)) { err = PTR_ERR(rtc); - dev_err(&client->dev, - "unable to register the class device\n"); goto exit_detach; } @@ -260,8 +258,6 @@ static int rs5c372_detach(struct i2c_client *client) int err; struct rtc_device *rtc = i2c_get_clientdata(client); - dev_dbg(&client->dev, "%s\n", __FUNCTION__); - if (rtc) rtc_device_unregister(rtc); diff --git a/drivers/rtc/rtc-sa1100.c b/drivers/rtc/rtc-sa1100.c index 83b2bb480a1..a23ec54989f 100644 --- a/drivers/rtc/rtc-sa1100.c +++ b/drivers/rtc/rtc-sa1100.c @@ -160,19 +160,19 @@ static int sa1100_rtc_open(struct device *dev) ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, SA_INTERRUPT, "rtc 1Hz", dev); if (ret) { - printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTC1Hz); + dev_err(dev, "IRQ %d already in use.\n", IRQ_RTC1Hz); goto fail_ui; } ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, SA_INTERRUPT, "rtc Alrm", dev); if (ret) { - printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTCAlrm); + dev_err(dev, "IRQ %d already in use.\n", IRQ_RTCAlrm); goto fail_ai; } ret = request_irq(IRQ_OST1, timer1_interrupt, SA_INTERRUPT, "rtc timer", dev); if (ret) { - printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_OST1); + dev_err(dev, "IRQ %d already in use.\n", IRQ_OST1); goto fail_pi; } return 0; @@ -332,7 +332,7 @@ static int sa1100_rtc_probe(struct platform_device *pdev) */ if (RTTR == 0) { RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16); - printk(KERN_WARNING "rtc: warning: initializing default clock divider/trim value\n"); + dev_warn(&pdev->dev, "warning: initializing default clock divider/trim value\n"); /* The current RTC value probably doesn't make sense either */ RCNR = 0; } @@ -340,15 +340,11 @@ static int sa1100_rtc_probe(struct platform_device *pdev) rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops, THIS_MODULE); - if (IS_ERR(rtc)) { - dev_err(&pdev->dev, "Unable to register the RTC device\n"); + if (IS_ERR(rtc)) return PTR_ERR(rtc); - } platform_set_drvdata(pdev, rtc); - dev_info(&pdev->dev, "SA11xx/PXA2xx RTC Registered\n"); - return 0; } diff --git a/drivers/rtc/rtc-test.c b/drivers/rtc/rtc-test.c index 43d10748782..e1f7e8e86da 100644 --- a/drivers/rtc/rtc-test.c +++ b/drivers/rtc/rtc-test.c @@ -49,7 +49,6 @@ static int test_rtc_proc(struct device *dev, struct seq_file *seq) { struct platform_device *plat_dev = to_platform_device(dev); - seq_printf(seq, "24hr\t\t: yes\n"); seq_printf(seq, "test\t\t: yes\n"); seq_printf(seq, "id\t\t: %d\n", plat_dev->id); @@ -120,8 +119,6 @@ static int test_probe(struct platform_device *plat_dev) &test_rtc_ops, THIS_MODULE); if (IS_ERR(rtc)) { err = PTR_ERR(rtc); - dev_err(&plat_dev->dev, - "unable to register the class device\n"); return err; } device_create_file(&plat_dev->dev, &dev_attr_irq); diff --git a/drivers/rtc/rtc-vr41xx.c b/drivers/rtc/rtc-vr41xx.c new file mode 100644 index 00000000000..4d49fd50119 --- /dev/null +++ b/drivers/rtc/rtc-vr41xx.c @@ -0,0 +1,471 @@ +/* + * Driver for NEC VR4100 series Real Time Clock unit. + * + * Copyright (C) 2003-2006 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include <linux/fs.h> +#include <linux/init.h> +#include <linux/ioport.h> +#include <linux/irq.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/rtc.h> +#include <linux/spinlock.h> +#include <linux/types.h> + +#include <asm/div64.h> +#include <asm/io.h> +#include <asm/uaccess.h> +#include <asm/vr41xx/vr41xx.h> + +MODULE_AUTHOR("Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>"); +MODULE_DESCRIPTION("NEC VR4100 series RTC driver"); +MODULE_LICENSE("GPL"); + +#define RTC1_TYPE1_START 0x0b0000c0UL +#define RTC1_TYPE1_END 0x0b0000dfUL +#define RTC2_TYPE1_START 0x0b0001c0UL +#define RTC2_TYPE1_END 0x0b0001dfUL + +#define RTC1_TYPE2_START 0x0f000100UL +#define RTC1_TYPE2_END 0x0f00011fUL +#define RTC2_TYPE2_START 0x0f000120UL +#define RTC2_TYPE2_END 0x0f00013fUL + +#define RTC1_SIZE 0x20 +#define RTC2_SIZE 0x20 + +/* RTC 1 registers */ +#define ETIMELREG 0x00 +#define ETIMEMREG 0x02 +#define ETIMEHREG 0x04 +/* RFU */ +#define ECMPLREG 0x08 +#define ECMPMREG 0x0a +#define ECMPHREG 0x0c +/* RFU */ +#define RTCL1LREG 0x10 +#define RTCL1HREG 0x12 +#define RTCL1CNTLREG 0x14 +#define RTCL1CNTHREG 0x16 +#define RTCL2LREG 0x18 +#define RTCL2HREG 0x1a +#define RTCL2CNTLREG 0x1c +#define RTCL2CNTHREG 0x1e + +/* RTC 2 registers */ +#define TCLKLREG 0x00 +#define TCLKHREG 0x02 +#define TCLKCNTLREG 0x04 +#define TCLKCNTHREG 0x06 +/* RFU */ +#define RTCINTREG 0x1e + #define TCLOCK_INT 0x08 + #define RTCLONG2_INT 0x04 + #define RTCLONG1_INT 0x02 + #define ELAPSEDTIME_INT 0x01 + +#define RTC_FREQUENCY 32768 +#define MAX_PERIODIC_RATE 6553 +#define MAX_USER_PERIODIC_RATE 64 + +static void __iomem *rtc1_base; +static void __iomem *rtc2_base; + +#define rtc1_read(offset) readw(rtc1_base + (offset)) +#define rtc1_write(offset, value) writew((value), rtc1_base + (offset)) + +#define rtc2_read(offset) readw(rtc2_base + (offset)) +#define rtc2_write(offset, value) writew((value), rtc2_base + (offset)) + +static unsigned long epoch = 1970; /* Jan 1 1970 00:00:00 */ + +static spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED; +static char rtc_name[] = "RTC"; +static unsigned long periodic_frequency; +static unsigned long periodic_count; + +struct resource rtc_resource[2] = { + { .name = rtc_name, + .flags = IORESOURCE_MEM, }, + { .name = rtc_name, + .flags = IORESOURCE_MEM, }, +}; + +static inline unsigned long read_elapsed_second(void) +{ + + unsigned long first_low, first_mid, first_high; + + unsigned long second_low, second_mid, second_high; + + do { + first_low = rtc1_read(ETIMELREG); + first_mid = rtc1_read(ETIMEMREG); + first_high = rtc1_read(ETIMEHREG); + second_low = rtc1_read(ETIMELREG); + second_mid = rtc1_read(ETIMEMREG); + second_high = rtc1_read(ETIMEHREG); + } while (first_low != second_low || first_mid != second_mid || + first_high != second_high); + + return (first_high << 17) | (first_mid << 1) | (first_low >> 15); +} + +static inline void write_elapsed_second(unsigned long sec) +{ + spin_lock_irq(&rtc_lock); + + rtc1_write(ETIMELREG, (uint16_t)(sec << 15)); + rtc1_write(ETIMEMREG, (uint16_t)(sec >> 1)); + rtc1_write(ETIMEHREG, (uint16_t)(sec >> 17)); + + spin_unlock_irq(&rtc_lock); +} + +static void vr41xx_rtc_release(struct device *dev) +{ + + spin_lock_irq(&rtc_lock); + + rtc1_write(ECMPLREG, 0); + rtc1_write(ECMPMREG, 0); + rtc1_write(ECMPHREG, 0); + rtc1_write(RTCL1LREG, 0); + rtc1_write(RTCL1HREG, 0); + + spin_unlock_irq(&rtc_lock); + + disable_irq(ELAPSEDTIME_IRQ); + disable_irq(RTCLONG1_IRQ); +} + +static int vr41xx_rtc_read_time(struct device *dev, struct rtc_time *time) +{ + unsigned long epoch_sec, elapsed_sec; + + epoch_sec = mktime(epoch, 1, 1, 0, 0, 0); + elapsed_sec = read_elapsed_second(); + + rtc_time_to_tm(epoch_sec + elapsed_sec, time); + + return 0; +} + +static int vr41xx_rtc_set_time(struct device *dev, struct rtc_time *time) +{ + unsigned long epoch_sec, current_sec; + + epoch_sec = mktime(epoch, 1, 1, 0, 0, 0); + current_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, + time->tm_hour, time->tm_min, time->tm_sec); + + write_elapsed_second(current_sec - epoch_sec); + + return 0; +} + +static int vr41xx_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + unsigned long low, mid, high; + struct rtc_time *time = &wkalrm->time; + + spin_lock_irq(&rtc_lock); + + low = rtc1_read(ECMPLREG); + mid = rtc1_read(ECMPMREG); + high = rtc1_read(ECMPHREG); + + spin_unlock_irq(&rtc_lock); + + rtc_time_to_tm((high << 17) | (mid << 1) | (low >> 15), time); + + return 0; +} + +static int vr41xx_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm) +{ + unsigned long alarm_sec; + struct rtc_time *time = &wkalrm->time; + + alarm_sec = mktime(time->tm_year + 1900, time->tm_mon + 1, time->tm_mday, + time->tm_hour, time->tm_min, time->tm_sec); + + spin_lock_irq(&rtc_lock); + + rtc1_write(ECMPLREG, (uint16_t)(alarm_sec << 15)); + rtc1_write(ECMPMREG, (uint16_t)(alarm_sec >> 1)); + rtc1_write(ECMPHREG, (uint16_t)(alarm_sec >> 17)); + + spin_unlock_irq(&rtc_lock); + + return 0; +} + +static int vr41xx_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) +{ + unsigned long count; + + switch (cmd) { + case RTC_AIE_ON: + enable_irq(ELAPSEDTIME_IRQ); + break; + case RTC_AIE_OFF: + disable_irq(ELAPSEDTIME_IRQ); + break; + case RTC_PIE_ON: + enable_irq(RTCLONG1_IRQ); + break; + case RTC_PIE_OFF: + disable_irq(RTCLONG1_IRQ); + break; + case RTC_IRQP_READ: + return put_user(periodic_frequency, (unsigned long __user *)arg); + break; + case RTC_IRQP_SET: + if (arg > MAX_PERIODIC_RATE) + return -EINVAL; + + if (arg > MAX_USER_PERIODIC_RATE && capable(CAP_SYS_RESOURCE) == 0) + return -EACCES; + + periodic_frequency = arg; + + count = RTC_FREQUENCY; + do_div(count, arg); + + periodic_count = count; + + spin_lock_irq(&rtc_lock); + + rtc1_write(RTCL1LREG, count); + rtc1_write(RTCL1HREG, count >> 16); + + spin_unlock_irq(&rtc_lock); + break; + case RTC_EPOCH_READ: + return put_user(epoch, (unsigned long __user *)arg); + case RTC_EPOCH_SET: + /* Doesn't support before 1900 */ + if (arg < 1900) + return -EINVAL; + + if (capable(CAP_SYS_TIME) == 0) + return -EACCES; + + epoch = arg; + break; + default: + return -EINVAL; + } + + return 0; +} + +static irqreturn_t elapsedtime_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct platform_device *pdev = (struct platform_device *)dev_id; + struct rtc_device *rtc = platform_get_drvdata(pdev); + + rtc2_write(RTCINTREG, ELAPSEDTIME_INT); + + rtc_update_irq(&rtc->class_dev, 1, RTC_AF); + + return IRQ_HANDLED; +} + +static irqreturn_t rtclong1_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct platform_device *pdev = (struct platform_device *)dev_id; + struct rtc_device *rtc = platform_get_drvdata(pdev); + unsigned long count = periodic_count; + + rtc2_write(RTCINTREG, RTCLONG1_INT); + + rtc1_write(RTCL1LREG, count); + rtc1_write(RTCL1HREG, count >> 16); + + rtc_update_irq(&rtc->class_dev, 1, RTC_PF); + + return IRQ_HANDLED; +} + +static struct rtc_class_ops vr41xx_rtc_ops = { + .release = vr41xx_rtc_release, + .ioctl = vr41xx_rtc_ioctl, + .read_time = vr41xx_rtc_read_time, + .set_time = vr41xx_rtc_set_time, + .read_alarm = vr41xx_rtc_read_alarm, + .set_alarm = vr41xx_rtc_set_alarm, +}; + +static int __devinit rtc_probe(struct platform_device *pdev) +{ + struct rtc_device *rtc; + unsigned int irq; + int retval; + + if (pdev->num_resources != 2) + return -EBUSY; + + rtc1_base = ioremap(pdev->resource[0].start, RTC1_SIZE); + if (rtc1_base == NULL) + return -EBUSY; + + rtc2_base = ioremap(pdev->resource[1].start, RTC2_SIZE); + if (rtc2_base == NULL) { + iounmap(rtc1_base); + rtc1_base = NULL; + return -EBUSY; + } + + rtc = rtc_device_register(rtc_name, &pdev->dev, &vr41xx_rtc_ops, THIS_MODULE); + if (IS_ERR(rtc)) { + iounmap(rtc1_base); + iounmap(rtc2_base); + rtc1_base = NULL; + rtc2_base = NULL; + return PTR_ERR(rtc); + } + + spin_lock_irq(&rtc_lock); + + rtc1_write(ECMPLREG, 0); + rtc1_write(ECMPMREG, 0); + rtc1_write(ECMPHREG, 0); + rtc1_write(RTCL1LREG, 0); + rtc1_write(RTCL1HREG, 0); + + spin_unlock_irq(&rtc_lock); + + irq = ELAPSEDTIME_IRQ; + retval = request_irq(irq, elapsedtime_interrupt, SA_INTERRUPT, + "elapsed_time", pdev); + if (retval == 0) { + irq = RTCLONG1_IRQ; + retval = request_irq(irq, rtclong1_interrupt, SA_INTERRUPT, + "rtclong1", pdev); + } + + if (retval < 0) { + printk(KERN_ERR "rtc: IRQ%d is busy\n", irq); + rtc_device_unregister(rtc); + if (irq == RTCLONG1_IRQ) + free_irq(ELAPSEDTIME_IRQ, NULL); + iounmap(rtc1_base); + iounmap(rtc2_base); + rtc1_base = NULL; + rtc2_base = NULL; + return retval; + } + + platform_set_drvdata(pdev, rtc); + + disable_irq(ELAPSEDTIME_IRQ); + disable_irq(RTCLONG1_IRQ); + + printk(KERN_INFO "rtc: Real Time Clock of NEC VR4100 series\n"); + + return 0; +} + +static int __devexit rtc_remove(struct platform_device *pdev) +{ + struct rtc_device *rtc; + + rtc = platform_get_drvdata(pdev); + if (rtc != NULL) + rtc_device_unregister(rtc); + + platform_set_drvdata(pdev, NULL); + + free_irq(ELAPSEDTIME_IRQ, NULL); + free_irq(RTCLONG1_IRQ, NULL); + if (rtc1_base != NULL) + iounmap(rtc1_base); + if (rtc2_base != NULL) + iounmap(rtc2_base); + + return 0; +} + +static struct platform_device *rtc_platform_device; + +static struct platform_driver rtc_platform_driver = { + .probe = rtc_probe, + .remove = __devexit_p(rtc_remove), + .driver = { + .name = rtc_name, + .owner = THIS_MODULE, + }, +}; + +static int __init vr41xx_rtc_init(void) +{ + int retval; + + switch (current_cpu_data.cputype) { + case CPU_VR4111: + case CPU_VR4121: + rtc_resource[0].start = RTC1_TYPE1_START; + rtc_resource[0].end = RTC1_TYPE1_END; + rtc_resource[1].start = RTC2_TYPE1_START; + rtc_resource[1].end = RTC2_TYPE1_END; + break; + case CPU_VR4122: + case CPU_VR4131: + case CPU_VR4133: + rtc_resource[0].start = RTC1_TYPE2_START; + rtc_resource[0].end = RTC1_TYPE2_END; + rtc_resource[1].start = RTC2_TYPE2_START; + rtc_resource[1].end = RTC2_TYPE2_END; + break; + default: + return -ENODEV; + break; + } + + rtc_platform_device = platform_device_alloc("RTC", -1); + if (rtc_platform_device == NULL) + return -ENOMEM; + + retval = platform_device_add_resources(rtc_platform_device, + rtc_resource, ARRAY_SIZE(rtc_resource)); + + if (retval == 0) + retval = platform_device_add(rtc_platform_device); + + if (retval < 0) { + platform_device_put(rtc_platform_device); + return retval; + } + + retval = platform_driver_register(&rtc_platform_driver); + if (retval < 0) + platform_device_unregister(rtc_platform_device); + + return retval; +} + +static void __exit vr41xx_rtc_exit(void) +{ + platform_driver_unregister(&rtc_platform_driver); + platform_device_unregister(rtc_platform_device); +} + +module_init(vr41xx_rtc_init); +module_exit(vr41xx_rtc_exit); diff --git a/drivers/rtc/rtc-x1205.c b/drivers/rtc/rtc-x1205.c index 621d17afc0d..788b6d1f8f2 100644 --- a/drivers/rtc/rtc-x1205.c +++ b/drivers/rtc/rtc-x1205.c @@ -19,7 +19,7 @@ #include <linux/rtc.h> #include <linux/delay.h> -#define DRV_VERSION "1.0.6" +#define DRV_VERSION "1.0.7" /* Addresses to scan: none. This chip is located at * 0x6f and uses a two bytes register addressing. @@ -451,8 +451,6 @@ static int x1205_rtc_proc(struct device *dev, struct seq_file *seq) { int err, dtrim, atrim; - seq_printf(seq, "24hr\t\t: yes\n"); - if ((err = x1205_get_dtrim(to_i2c_client(dev), &dtrim)) == 0) seq_printf(seq, "digital_trim\t: %d ppm\n", dtrim); @@ -473,30 +471,31 @@ static struct rtc_class_ops x1205_rtc_ops = { static ssize_t x1205_sysfs_show_atrim(struct device *dev, struct device_attribute *attr, char *buf) { - int atrim; + int err, atrim; - if (x1205_get_atrim(to_i2c_client(dev), &atrim) == 0) - return sprintf(buf, "%d.%02d pF\n", - atrim / 1000, atrim % 1000); - return 0; + err = x1205_get_atrim(to_i2c_client(dev), &atrim); + if (err) + return err; + + return sprintf(buf, "%d.%02d pF\n", atrim / 1000, atrim % 1000); } static DEVICE_ATTR(atrim, S_IRUGO, x1205_sysfs_show_atrim, NULL); static ssize_t x1205_sysfs_show_dtrim(struct device *dev, struct device_attribute *attr, char *buf) { - int dtrim; + int err, dtrim; - if (x1205_get_dtrim(to_i2c_client(dev), &dtrim) == 0) - return sprintf(buf, "%d ppm\n", dtrim); + err = x1205_get_dtrim(to_i2c_client(dev), &dtrim); + if (err) + return err; - return 0; + return sprintf(buf, "%d ppm\n", dtrim); } static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL); static int x1205_attach(struct i2c_adapter *adapter) { - dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); return i2c_probe(adapter, &addr_data, x1205_probe); } @@ -545,8 +544,6 @@ static int x1205_probe(struct i2c_adapter *adapter, int address, int kind) if (IS_ERR(rtc)) { err = PTR_ERR(rtc); - dev_err(&client->dev, - "unable to register the class device\n"); goto exit_detach; } @@ -585,8 +582,6 @@ static int x1205_detach(struct i2c_client *client) int err; struct rtc_device *rtc = i2c_get_clientdata(client); - dev_dbg(&client->dev, "%s\n", __FUNCTION__); - if (rtc) rtc_device_unregister(rtc); |