Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6

Conflicts:

	Documentation/kernel-parameters.txt
	arch/sh/include/asm/elf.h
This commit is contained in:
Paul Mundt 2008-10-20 11:17:52 +09:00
commit 4cb40f795a
6752 changed files with 538692 additions and 172011 deletions

View file

@ -220,22 +220,22 @@ config RTC_DRV_PCF8583
will be called rtc-pcf8583.
config RTC_DRV_M41T80
tristate "ST M41T80/81/82/83/84/85/87"
tristate "ST M41T65/M41T80/81/82/83/84/85/87"
help
If you say Y here you will get support for the
ST M41T80 RTC chips series. Currently following chips are
supported: M41T80, M41T81, M41T82, M41T83, M41ST84, M41ST85
and M41ST87.
If you say Y here you will get support for the ST M41T60
and M41T80 RTC chips series. Currently, the following chips are
supported: M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84,
M41ST85, and M41ST87.
This driver can also be built as a module. If so, the module
will be called rtc-m41t80.
config RTC_DRV_M41T80_WDT
bool "ST M41T80 series RTC watchdog timer"
bool "ST M41T65/M41T80 series RTC watchdog timer"
depends on RTC_DRV_M41T80
help
If you say Y here you will get support for the
watchdog timer in ST M41T80 RTC chips series.
watchdog timer in the ST M41T60 and M41T80 RTC chips series.
config RTC_DRV_TWL92330
boolean "TI TWL92330/Menelaus"
@ -319,6 +319,15 @@ config RTC_DRV_RS5C348
This driver can also be built as a module. If so, the module
will be called rtc-rs5c348.
config RTC_DRV_DS3234
tristate "Maxim/Dallas DS3234"
help
If you say yes here you get support for the
Maxim/Dallas DS3234 SPI RTC chip.
This driver can also be built as a module. If so, the module
will be called rtc-ds3234.
endif # SPI_MASTER
comment "Platform RTC drivers"
@ -329,7 +338,7 @@ comment "Platform RTC drivers"
config RTC_DRV_CMOS
tristate "PC-style 'CMOS'"
depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS
depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS || SPARC64
default y if X86
help
Say "yes" here to get direct support for the real time clock
@ -352,6 +361,11 @@ config RTC_DRV_DS1216
help
If you say yes here you get support for the Dallas DS1216 RTC chips.
config RTC_DRV_DS1286
tristate "Dallas DS1286"
help
If you say yes here you get support for the Dallas DS1286 RTC chips.
config RTC_DRV_DS1302
tristate "Dallas DS1302"
depends on SH_SECUREEDGE5410
@ -405,15 +419,36 @@ config RTC_DRV_M48T86
This driver can also be built as a module. If so, the module
will be called rtc-m48t86.
config RTC_DRV_M48T59
tristate "ST M48T59"
config RTC_DRV_M48T35
tristate "ST M48T35"
help
If you say Y here you will get support for the
ST M48T59 RTC chip.
ST M48T35 RTC chip.
This driver can also be built as a module, if so, the module
will be called "rtc-m48t35".
config RTC_DRV_M48T59
tristate "ST M48T59/M48T08/M48T02"
help
If you say Y here you will get support for the
ST M48T59 RTC chip and compatible ST M48T08 and M48T02.
These chips are usually found in Sun SPARC and UltraSPARC
workstations.
This driver can also be built as a module, if so, the module
will be called "rtc-m48t59".
config RTC_DRV_BQ4802
tristate "TI BQ4802"
help
If you say Y here you will get support for the TI
BQ4802 RTC chip.
This driver can also be built as a module. If so, the module
will be called rtc-bq4802.
config RTC_DRV_V3020
tristate "EM Microelectronic V3020"
help
@ -577,10 +612,24 @@ config RTC_DRV_RS5C313
config RTC_DRV_PPC
tristate "PowerPC machine dependent RTC support"
depends on PPC_MERGE
depends on PPC
help
The PowerPC kernel has machine-specific functions for accessing
the RTC. This exposes that functionality through the generic RTC
class.
config RTC_DRV_SUN4V
bool "SUN4V Hypervisor RTC"
depends on SPARC64
help
If you say Y here you will get support for the Hypervisor
based RTC on SUN4V systems.
config RTC_DRV_STARFIRE
bool "Starfire RTC"
depends on SPARC64
help
If you say Y here you will get support for the RTC found on
Starfire systems.
endif # RTC_CLASS

View file

@ -23,6 +23,7 @@ obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
obj-$(CONFIG_RTC_DRV_BFIN) += rtc-bfin.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_DS1216) += rtc-ds1216.o
obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o
obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o
obj-$(CONFIG_RTC_DRV_DS1305) += rtc-ds1305.o
obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
@ -31,13 +32,18 @@ obj-$(CONFIG_RTC_DRV_DS1511) += rtc-ds1511.o
obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o
obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o
obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o

View file

@ -29,10 +29,10 @@
#include <linux/completion.h>
#include <asm/uaccess.h>
#include <mach/at91_rtc.h>
#define AT91_RTC_FREQ 1
#define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */
static DECLARE_COMPLETION(at91_rtc_updated);
@ -228,8 +228,6 @@ static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
(imr & AT91_RTC_ACKUPD) ? "yes" : "no");
seq_printf(seq, "periodic_IRQ\t: %s\n",
(imr & AT91_RTC_SECEV) ? "yes" : "no");
seq_printf(seq, "periodic_freq\t: %ld\n",
(unsigned long) AT91_RTC_FREQ);
return 0;
}

230
drivers/rtc/rtc-bq4802.c Normal file
View file

@ -0,0 +1,230 @@
/* rtc-bq4802.c: TI BQ4802 RTC driver.
*
* Copyright (C) 2008 David S. Miller <davem@davemloft.net>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
MODULE_AUTHOR("David S. Miller <[email protected]>");
MODULE_DESCRIPTION("TI BQ4802 RTC driver");
MODULE_LICENSE("GPL");
struct bq4802 {
void __iomem *regs;
unsigned long ioport;
struct rtc_device *rtc;
spinlock_t lock;
struct resource *r;
u8 (*read)(struct bq4802 *, int);
void (*write)(struct bq4802 *, int, u8);
};
static u8 bq4802_read_io(struct bq4802 *p, int off)
{
return inb(p->ioport + off);
}
static void bq4802_write_io(struct bq4802 *p, int off, u8 val)
{
outb(val, p->ioport + off);
}
static u8 bq4802_read_mem(struct bq4802 *p, int off)
{
return readb(p->regs + off);
}
static void bq4802_write_mem(struct bq4802 *p, int off, u8 val)
{
writeb(val, p->regs + off);
}
static int bq4802_read_time(struct device *dev, struct rtc_time *tm)
{
struct platform_device *pdev = to_platform_device(dev);
struct bq4802 *p = platform_get_drvdata(pdev);
unsigned long flags;
unsigned int century;
u8 val;
spin_lock_irqsave(&p->lock, flags);
val = p->read(p, 0x0e);
p->write(p, 0xe, val | 0x08);
tm->tm_sec = p->read(p, 0x00);
tm->tm_min = p->read(p, 0x02);
tm->tm_hour = p->read(p, 0x04);
tm->tm_mday = p->read(p, 0x06);
tm->tm_mon = p->read(p, 0x09);
tm->tm_year = p->read(p, 0x0a);
tm->tm_wday = p->read(p, 0x08);
century = p->read(p, 0x0f);
p->write(p, 0x0e, val);
spin_unlock_irqrestore(&p->lock, flags);
BCD_TO_BIN(tm->tm_sec);
BCD_TO_BIN(tm->tm_min);
BCD_TO_BIN(tm->tm_hour);
BCD_TO_BIN(tm->tm_mday);
BCD_TO_BIN(tm->tm_mon);
BCD_TO_BIN(tm->tm_year);
BCD_TO_BIN(tm->tm_wday);
BCD_TO_BIN(century);
tm->tm_year += (century * 100);
tm->tm_year -= 1900;
tm->tm_mon--;
return 0;
}
static int bq4802_set_time(struct device *dev, struct rtc_time *tm)
{
struct platform_device *pdev = to_platform_device(dev);
struct bq4802 *p = platform_get_drvdata(pdev);
u8 sec, min, hrs, day, mon, yrs, century, val;
unsigned long flags;
unsigned int year;
year = tm->tm_year + 1900;
century = year / 100;
yrs = year % 100;
mon = tm->tm_mon + 1; /* tm_mon starts at zero */
day = tm->tm_mday;
hrs = tm->tm_hour;
min = tm->tm_min;
sec = tm->tm_sec;
BIN_TO_BCD(sec);
BIN_TO_BCD(min);
BIN_TO_BCD(hrs);
BIN_TO_BCD(day);
BIN_TO_BCD(mon);
BIN_TO_BCD(yrs);
BIN_TO_BCD(century);
spin_lock_irqsave(&p->lock, flags);
val = p->read(p, 0x0e);
p->write(p, 0x0e, val | 0x08);
p->write(p, 0x00, sec);
p->write(p, 0x02, min);
p->write(p, 0x04, hrs);
p->write(p, 0x06, day);
p->write(p, 0x09, mon);
p->write(p, 0x0a, yrs);
p->write(p, 0x0f, century);
p->write(p, 0x0e, val);
spin_unlock_irqrestore(&p->lock, flags);
return 0;
}
static const struct rtc_class_ops bq4802_ops = {
.read_time = bq4802_read_time,
.set_time = bq4802_set_time,
};
static int __devinit bq4802_probe(struct platform_device *pdev)
{
struct bq4802 *p = kzalloc(sizeof(*p), GFP_KERNEL);
int err = -ENOMEM;
if (!p)
goto out;
spin_lock_init(&p->lock);
p->r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!p->r) {
p->r = platform_get_resource(pdev, IORESOURCE_IO, 0);
err = -EINVAL;
if (!p->r)
goto out_free;
}
if (p->r->flags & IORESOURCE_IO) {
p->ioport = p->r->start;
p->read = bq4802_read_io;
p->write = bq4802_write_io;
} else if (p->r->flags & IORESOURCE_MEM) {
p->regs = ioremap(p->r->start, resource_size(p->r));
p->read = bq4802_read_mem;
p->write = bq4802_write_mem;
} else {
err = -EINVAL;
goto out_free;
}
p->rtc = rtc_device_register("bq4802", &pdev->dev,
&bq4802_ops, THIS_MODULE);
if (IS_ERR(p->rtc)) {
err = PTR_ERR(p->rtc);
goto out_iounmap;
}
platform_set_drvdata(pdev, p);
err = 0;
out:
return err;
out_iounmap:
if (p->r->flags & IORESOURCE_MEM)
iounmap(p->regs);
out_free:
kfree(p);
goto out;
}
static int __devexit bq4802_remove(struct platform_device *pdev)
{
struct bq4802 *p = platform_get_drvdata(pdev);
rtc_device_unregister(p->rtc);
if (p->r->flags & IORESOURCE_MEM)
iounmap(p->regs);
platform_set_drvdata(pdev, NULL);
kfree(p);
return 0;
}
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:rtc-bq4802");
static struct platform_driver bq4802_driver = {
.driver = {
.name = "rtc-bq4802",
.owner = THIS_MODULE,
},
.probe = bq4802_probe,
.remove = __devexit_p(bq4802_remove),
};
static int __init bq4802_init(void)
{
return platform_driver_register(&bq4802_driver);
}
static void __exit bq4802_exit(void)
{
platform_driver_unregister(&bq4802_driver);
}
module_init(bq4802_init);
module_exit(bq4802_exit);

View file

@ -636,7 +636,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
*/
#if defined(CONFIG_ATARI)
address_space = 64;
#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)
#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) || defined(__sparc__)
address_space = 128;
#else
#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
@ -699,7 +699,8 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
/* FIXME teach the alarm code how to handle binary mode;
* <asm-generic/rtc.h> doesn't know 12-hour mode either.
*/
if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY))) {
if (is_valid_irq(rtc_irq) &&
(!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY)))) {
dev_dbg(dev, "only 24-hr BCD mode supported\n");
retval = -ENXIO;
goto cleanup1;
@ -912,6 +913,92 @@ static inline int cmos_poweroff(struct device *dev)
* predate even PNPBIOS should set up platform_bus devices.
*/
#ifdef CONFIG_ACPI
#include <linux/acpi.h>
#ifdef CONFIG_PM
static u32 rtc_handler(void *context)
{
acpi_clear_event(ACPI_EVENT_RTC);
acpi_disable_event(ACPI_EVENT_RTC, 0);
return ACPI_INTERRUPT_HANDLED;
}
static inline void rtc_wake_setup(void)
{
acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
/*
* After the RTC handler is installed, the Fixed_RTC event should
* be disabled. Only when the RTC alarm is set will it be enabled.
*/
acpi_clear_event(ACPI_EVENT_RTC);
acpi_disable_event(ACPI_EVENT_RTC, 0);
}
static void rtc_wake_on(struct device *dev)
{
acpi_clear_event(ACPI_EVENT_RTC);
acpi_enable_event(ACPI_EVENT_RTC, 0);
}
static void rtc_wake_off(struct device *dev)
{
acpi_disable_event(ACPI_EVENT_RTC, 0);
}
#else
#define rtc_wake_setup() do{}while(0)
#define rtc_wake_on NULL
#define rtc_wake_off NULL
#endif
/* Every ACPI platform has a mc146818 compatible "cmos rtc". Here we find
* its device node and pass extra config data. This helps its driver use
* capabilities that the now-obsolete mc146818 didn't have, and informs it
* that this board's RTC is wakeup-capable (per ACPI spec).
*/
static struct cmos_rtc_board_info acpi_rtc_info;
static void __devinit
cmos_wake_setup(struct device *dev)
{
if (acpi_disabled)
return;
rtc_wake_setup();
acpi_rtc_info.wake_on = rtc_wake_on;
acpi_rtc_info.wake_off = rtc_wake_off;
/* workaround bug in some ACPI tables */
if (acpi_gbl_FADT.month_alarm && !acpi_gbl_FADT.day_alarm) {
dev_dbg(dev, "bogus FADT month_alarm (%d)\n",
acpi_gbl_FADT.month_alarm);
acpi_gbl_FADT.month_alarm = 0;
}
acpi_rtc_info.rtc_day_alarm = acpi_gbl_FADT.day_alarm;
acpi_rtc_info.rtc_mon_alarm = acpi_gbl_FADT.month_alarm;
acpi_rtc_info.rtc_century = acpi_gbl_FADT.century;
/* NOTE: S4_RTC_WAKE is NOT currently useful to Linux */
if (acpi_gbl_FADT.flags & ACPI_FADT_S4_RTC_WAKE)
dev_info(dev, "RTC can wake from S4\n");
dev->platform_data = &acpi_rtc_info;
/* RTC always wakes from S1/S2/S3, and often S4/STD */
device_init_wakeup(dev, 1);
}
#else
static void __devinit
cmos_wake_setup(struct device *dev)
{
}
#endif
#ifdef CONFIG_PNP
#include <linux/pnp.h>
@ -919,6 +1006,8 @@ static inline int cmos_poweroff(struct device *dev)
static int __devinit
cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
{
cmos_wake_setup(&pnp->dev);
if (pnp_port_start(pnp,0) == 0x70 && !pnp_irq_valid(pnp,0))
/* Some machines contain a PNP entry for the RTC, but
* don't define the IRQ. It should always be safe to
@ -996,6 +1085,7 @@ static struct pnp_driver cmos_pnp_driver = {
static int __init cmos_platform_probe(struct platform_device *pdev)
{
cmos_wake_setup(&pdev->dev);
return cmos_do_probe(&pdev->dev,
platform_get_resource(pdev, IORESOURCE_IO, 0),
platform_get_irq(pdev, 0));
@ -1030,29 +1120,32 @@ static struct platform_driver cmos_platform_driver = {
static int __init cmos_init(void)
{
int retval = 0;
#ifdef CONFIG_PNP
if (pnp_platform_devices)
return pnp_register_driver(&cmos_pnp_driver);
else
return platform_driver_probe(&cmos_platform_driver,
cmos_platform_probe);
#else
return platform_driver_probe(&cmos_platform_driver,
cmos_platform_probe);
#endif /* CONFIG_PNP */
pnp_register_driver(&cmos_pnp_driver);
#endif
if (!cmos_rtc.dev)
retval = platform_driver_probe(&cmos_platform_driver,
cmos_platform_probe);
if (retval == 0)
return 0;
#ifdef CONFIG_PNP
pnp_unregister_driver(&cmos_pnp_driver);
#endif
return retval;
}
module_init(cmos_init);
static void __exit cmos_exit(void)
{
#ifdef CONFIG_PNP
if (pnp_platform_devices)
pnp_unregister_driver(&cmos_pnp_driver);
else
platform_driver_unregister(&cmos_platform_driver);
#else
pnp_unregister_driver(&cmos_pnp_driver);
#endif
platform_driver_unregister(&cmos_platform_driver);
#endif /* CONFIG_PNP */
}
module_exit(cmos_exit);

View file

@ -422,28 +422,37 @@ done:
return err;
}
static int rtc_dev_fasync(int fd, struct file *file, int on)
{
struct rtc_device *rtc = file->private_data;
return fasync_helper(fd, file, on, &rtc->async_queue);
}
static int rtc_dev_release(struct inode *inode, struct file *file)
{
struct rtc_device *rtc = file->private_data;
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
clear_uie(rtc);
#endif
/* We shut down the repeating IRQs that userspace enabled,
* since nothing is listening to them.
* - Update (UIE) ... currently only managed through ioctls
* - Periodic (PIE) ... also used through rtc_*() interface calls
*
* Leave the alarm alone; it may be set to trigger a system wakeup
* later, or be used by kernel code, and is a one-shot event anyway.
*/
rtc_dev_ioctl(file, RTC_UIE_OFF, 0);
rtc_irq_set_state(rtc, NULL, 0);
if (rtc->ops->release)
rtc->ops->release(rtc->dev.parent);
if (file->f_flags & FASYNC)
rtc_dev_fasync(-1, file, 0);
clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
return 0;
}
static int rtc_dev_fasync(int fd, struct file *file, int on)
{
struct rtc_device *rtc = file->private_data;
return fasync_helper(fd, file, on, &rtc->async_queue);
}
static const struct file_operations rtc_dev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,

410
drivers/rtc/rtc-ds1286.c Normal file
View file

@ -0,0 +1,410 @@
/*
* DS1286 Real Time Clock interface for Linux
*
* Copyright (C) 1998, 1999, 2000 Ralf Baechle
* Copyright (C) 2008 Thomas Bogendoerfer
*
* Based on code written by Paul Gortmaker.
*
* 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.
*/
#include <linux/module.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <linux/bcd.h>
#include <linux/ds1286.h>
#include <linux/io.h>
#define DRV_VERSION "1.0"
struct ds1286_priv {
struct rtc_device *rtc;
u32 __iomem *rtcregs;
size_t size;
unsigned long baseaddr;
spinlock_t lock;
};
static inline u8 ds1286_rtc_read(struct ds1286_priv *priv, int reg)
{
return __raw_readl(&priv->rtcregs[reg]) & 0xff;
}
static inline void ds1286_rtc_write(struct ds1286_priv *priv, u8 data, int reg)
{
__raw_writel(data, &priv->rtcregs[reg]);
}
#ifdef CONFIG_RTC_INTF_DEV
static int ds1286_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
struct ds1286_priv *priv = dev_get_drvdata(dev);
unsigned long flags;
unsigned char val;
switch (cmd) {
case RTC_AIE_OFF:
/* Mask alarm int. enab. bit */
spin_lock_irqsave(&priv->lock, flags);
val = ds1286_rtc_read(priv, RTC_CMD);
val |= RTC_TDM;
ds1286_rtc_write(priv, val, RTC_CMD);
spin_unlock_irqrestore(&priv->lock, flags);
break;
case RTC_AIE_ON:
/* Allow alarm interrupts. */
spin_lock_irqsave(&priv->lock, flags);
val = ds1286_rtc_read(priv, RTC_CMD);
val &= ~RTC_TDM;
ds1286_rtc_write(priv, val, RTC_CMD);
spin_unlock_irqrestore(&priv->lock, flags);
break;
case RTC_WIE_OFF:
/* Mask watchdog int. enab. bit */
spin_lock_irqsave(&priv->lock, flags);
val = ds1286_rtc_read(priv, RTC_CMD);
val |= RTC_WAM;
ds1286_rtc_write(priv, val, RTC_CMD);
spin_unlock_irqrestore(&priv->lock, flags);
break;
case RTC_WIE_ON:
/* Allow watchdog interrupts. */
spin_lock_irqsave(&priv->lock, flags);
val = ds1286_rtc_read(priv, RTC_CMD);
val &= ~RTC_WAM;
ds1286_rtc_write(priv, val, RTC_CMD);
spin_unlock_irqrestore(&priv->lock, flags);
break;
default:
return -ENOIOCTLCMD;
}
return 0;
}
#else
#define ds1286_ioctl NULL
#endif
#ifdef CONFIG_PROC_FS
static int ds1286_proc(struct device *dev, struct seq_file *seq)
{
struct ds1286_priv *priv = dev_get_drvdata(dev);
unsigned char month, cmd, amode;
const char *s;
month = ds1286_rtc_read(priv, RTC_MONTH);
seq_printf(seq,
"oscillator\t: %s\n"
"square_wave\t: %s\n",
(month & RTC_EOSC) ? "disabled" : "enabled",
(month & RTC_ESQW) ? "disabled" : "enabled");
amode = ((ds1286_rtc_read(priv, RTC_MINUTES_ALARM) & 0x80) >> 5) |
((ds1286_rtc_read(priv, RTC_HOURS_ALARM) & 0x80) >> 6) |
((ds1286_rtc_read(priv, RTC_DAY_ALARM) & 0x80) >> 7);
switch (amode) {
case 7:
s = "each minute";
break;
case 3:
s = "minutes match";
break;
case 1:
s = "hours and minutes match";
break;
case 0:
s = "days, hours and minutes match";
break;
default:
s = "invalid";
break;
}
seq_printf(seq, "alarm_mode\t: %s\n", s);
cmd = ds1286_rtc_read(priv, RTC_CMD);
seq_printf(seq,
"alarm_enable\t: %s\n"
"wdog_alarm\t: %s\n"
"alarm_mask\t: %s\n"
"wdog_alarm_mask\t: %s\n"
"interrupt_mode\t: %s\n"
"INTB_mode\t: %s_active\n"
"interrupt_pins\t: %s\n",
(cmd & RTC_TDF) ? "yes" : "no",
(cmd & RTC_WAF) ? "yes" : "no",
(cmd & RTC_TDM) ? "disabled" : "enabled",
(cmd & RTC_WAM) ? "disabled" : "enabled",
(cmd & RTC_PU_LVL) ? "pulse" : "level",
(cmd & RTC_IBH_LO) ? "low" : "high",
(cmd & RTC_IPSW) ? "unswapped" : "swapped");
return 0;
}
#else
#define ds1286_proc NULL
#endif
static int ds1286_read_time(struct device *dev, struct rtc_time *tm)
{
struct ds1286_priv *priv = dev_get_drvdata(dev);
unsigned char save_control;
unsigned long flags;
unsigned long uip_watchdog = jiffies;
/*
* read RTC once any update in progress is done. The update
* can take just over 2ms. We wait 10 to 20ms. There is no need to
* to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP.
* If you need to know *exactly* when a second has started, enable
* periodic update complete interrupts, (via ioctl) and then
* immediately read /dev/rtc which will block until you get the IRQ.
* Once the read clears, read the RTC time (again via ioctl). Easy.
*/
if (ds1286_rtc_read(priv, RTC_CMD) & RTC_TE)
while (time_before(jiffies, uip_watchdog + 2*HZ/100))
barrier();
/*
* Only the values that we read from the RTC are set. We leave
* tm_wday, tm_yday and tm_isdst untouched. Even though the
* RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
* by the RTC when initially set to a non-zero value.
*/
spin_lock_irqsave(&priv->lock, flags);
save_control = ds1286_rtc_read(priv, RTC_CMD);
ds1286_rtc_write(priv, (save_control|RTC_TE), RTC_CMD);
tm->tm_sec = ds1286_rtc_read(priv, RTC_SECONDS);
tm->tm_min = ds1286_rtc_read(priv, RTC_MINUTES);
tm->tm_hour = ds1286_rtc_read(priv, RTC_HOURS) & 0x3f;
tm->tm_mday = ds1286_rtc_read(priv, RTC_DATE);
tm->tm_mon = ds1286_rtc_read(priv, RTC_MONTH) & 0x1f;
tm->tm_year = ds1286_rtc_read(priv, RTC_YEAR);
ds1286_rtc_write(priv, save_control, RTC_CMD);
spin_unlock_irqrestore(&priv->lock, flags);
tm->tm_sec = bcd2bin(tm->tm_sec);
tm->tm_min = bcd2bin(tm->tm_min);
tm->tm_hour = bcd2bin(tm->tm_hour);
tm->tm_mday = bcd2bin(tm->tm_mday);
tm->tm_mon = bcd2bin(tm->tm_mon);
tm->tm_year = bcd2bin(tm->tm_year);
/*
* Account for differences between how the RTC uses the values
* and how they are defined in a struct rtc_time;
*/
if (tm->tm_year < 45)
tm->tm_year += 30;
tm->tm_year += 40;
if (tm->tm_year < 70)
tm->tm_year += 100;
tm->tm_mon--;
return rtc_valid_tm(tm);
}
static int ds1286_set_time(struct device *dev, struct rtc_time *tm)
{
struct ds1286_priv *priv = dev_get_drvdata(dev);
unsigned char mon, day, hrs, min, sec;
unsigned char save_control;
unsigned int yrs;
unsigned long flags;
yrs = tm->tm_year + 1900;
mon = tm->tm_mon + 1; /* tm_mon starts at zero */
day = tm->tm_mday;
hrs = tm->tm_hour;
min = tm->tm_min;
sec = tm->tm_sec;
if (yrs < 1970)
return -EINVAL;
yrs -= 1940;
if (yrs > 255) /* They are unsigned */
return -EINVAL;
if (yrs >= 100)
yrs -= 100;
sec = bin2bcd(sec);
min = bin2bcd(min);
hrs = bin2bcd(hrs);
day = bin2bcd(day);
mon = bin2bcd(mon);
yrs = bin2bcd(yrs);
spin_lock_irqsave(&priv->lock, flags);
save_control = ds1286_rtc_read(priv, RTC_CMD);
ds1286_rtc_write(priv, (save_control|RTC_TE), RTC_CMD);
ds1286_rtc_write(priv, yrs, RTC_YEAR);
ds1286_rtc_write(priv, mon, RTC_MONTH);
ds1286_rtc_write(priv, day, RTC_DATE);
ds1286_rtc_write(priv, hrs, RTC_HOURS);
ds1286_rtc_write(priv, min, RTC_MINUTES);
ds1286_rtc_write(priv, sec, RTC_SECONDS);
ds1286_rtc_write(priv, 0, RTC_HUNDREDTH_SECOND);
ds1286_rtc_write(priv, save_control, RTC_CMD);
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
static int ds1286_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
struct ds1286_priv *priv = dev_get_drvdata(dev);
unsigned char cmd;
unsigned long flags;
/*
* Only the values that we read from the RTC are set. That
* means only tm_wday, tm_hour, tm_min.
*/
spin_lock_irqsave(&priv->lock, flags);
alm->time.tm_min = ds1286_rtc_read(priv, RTC_MINUTES_ALARM) & 0x7f;
alm->time.tm_hour = ds1286_rtc_read(priv, RTC_HOURS_ALARM) & 0x1f;
alm->time.tm_wday = ds1286_rtc_read(priv, RTC_DAY_ALARM) & 0x07;
cmd = ds1286_rtc_read(priv, RTC_CMD);
spin_unlock_irqrestore(&priv->lock, flags);
alm->time.tm_min = bcd2bin(alm->time.tm_min);
alm->time.tm_hour = bcd2bin(alm->time.tm_hour);
alm->time.tm_sec = 0;
return 0;
}
static int ds1286_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
struct ds1286_priv *priv = dev_get_drvdata(dev);
unsigned char hrs, min, sec;
hrs = alm->time.tm_hour;
min = alm->time.tm_min;
sec = alm->time.tm_sec;
if (hrs >= 24)
hrs = 0xff;
if (min >= 60)
min = 0xff;
if (sec != 0)
return -EINVAL;
min = bin2bcd(min);
hrs = bin2bcd(hrs);
spin_lock(&priv->lock);
ds1286_rtc_write(priv, hrs, RTC_HOURS_ALARM);
ds1286_rtc_write(priv, min, RTC_MINUTES_ALARM);
spin_unlock(&priv->lock);
return 0;
}
static const struct rtc_class_ops ds1286_ops = {
.ioctl = ds1286_ioctl,
.proc = ds1286_proc,
.read_time = ds1286_read_time,
.set_time = ds1286_set_time,
.read_alarm = ds1286_read_alarm,
.set_alarm = ds1286_set_alarm,
};
static int __devinit ds1286_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
struct resource *res;
struct ds1286_priv *priv;
int ret = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
priv = kzalloc(sizeof(struct ds1286_priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->size = res->end - res->start + 1;
if (!request_mem_region(res->start, priv->size, pdev->name)) {
ret = -EBUSY;
goto out;
}
priv->baseaddr = res->start;
priv->rtcregs = ioremap(priv->baseaddr, priv->size);
if (!priv->rtcregs) {
ret = -ENOMEM;
goto out;
}
spin_lock_init(&priv->lock);
rtc = rtc_device_register("ds1286", &pdev->dev,
&ds1286_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
ret = PTR_ERR(rtc);
goto out;
}
priv->rtc = rtc;
platform_set_drvdata(pdev, priv);
return 0;
out:
if (priv->rtc)
rtc_device_unregister(priv->rtc);
if (priv->rtcregs)
iounmap(priv->rtcregs);
if (priv->baseaddr)
release_mem_region(priv->baseaddr, priv->size);
kfree(priv);
return ret;
}
static int __devexit ds1286_remove(struct platform_device *pdev)
{
struct ds1286_priv *priv = platform_get_drvdata(pdev);
rtc_device_unregister(priv->rtc);
iounmap(priv->rtcregs);
release_mem_region(priv->baseaddr, priv->size);
kfree(priv);
return 0;
}
static struct platform_driver ds1286_platform_driver = {
.driver = {
.name = "rtc-ds1286",
.owner = THIS_MODULE,
},
.probe = ds1286_probe,
.remove = __devexit_p(ds1286_remove),
};
static int __init ds1286_init(void)
{
return platform_driver_register(&ds1286_platform_driver);
}
static void __exit ds1286_exit(void)
{
platform_driver_unregister(&ds1286_platform_driver);
}
MODULE_AUTHOR("Thomas Bogendoerfer <[email protected]>");
MODULE_DESCRIPTION("DS1286 RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
MODULE_ALIAS("platform:rtc-ds1286");
module_init(ds1286_init);
module_exit(ds1286_exit);

View file

@ -23,10 +23,6 @@
* to have set the chip up as a clock (turning on the oscillator and
* setting the date and time), Linux can ignore the non-clock features.
* That's a natural job for a factory or repair bench.
*
* This is currently a simple no-alarms driver. If your board has the
* alarm irq wired up on a ds1337 or ds1339, and you want to use that,
* then look at the rtc-rs5c372 driver for code to steal...
*/
enum ds_type {
ds_1307,
@ -67,6 +63,7 @@ enum ds_type {
# define DS1307_BIT_RS0 0x01
#define DS1337_REG_CONTROL 0x0e
# define DS1337_BIT_nEOSC 0x80
# define DS1339_BIT_BBSQI 0x20
# define DS1337_BIT_RS2 0x10
# define DS1337_BIT_RS1 0x08
# define DS1337_BIT_INTCN 0x04
@ -83,19 +80,22 @@ enum ds_type {
# define DS1337_BIT_OSF 0x80
# define DS1337_BIT_A2I 0x02
# define DS1337_BIT_A1I 0x01
#define DS1339_REG_ALARM1_SECS 0x07
#define DS1339_REG_TRICKLE 0x10
struct ds1307 {
u8 reg_addr;
bool has_nvram;
u8 regs[8];
u8 regs[11];
enum ds_type type;
unsigned long flags;
#define HAS_NVRAM 0 /* bit 0 == sysfs file active */
#define HAS_ALARM 1 /* bit 1 == irq claimed */
struct i2c_msg msg[2];
struct i2c_client *client;
struct i2c_client dev;
struct rtc_device *rtc;
struct work_struct work;
};
struct chip_desc {
@ -132,12 +132,79 @@ static const struct i2c_device_id ds1307_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ds1307_id);
/*----------------------------------------------------------------------*/
/*
* The IRQ logic includes a "real" handler running in IRQ context just
* long enough to schedule this workqueue entry. We need a task context
* to talk to the RTC, since I2C I/O calls require that; and disable the
* IRQ until we clear its status on the chip, so that this handler can
* work with any type of triggering (not just falling edge).
*
* The ds1337 and ds1339 both have two alarms, but we only use the first
* one (with a "seconds" field). For ds1337 we expect nINTA is our alarm
* signal; ds1339 chips have only one alarm signal.
*/
static void ds1307_work(struct work_struct *work)
{
struct ds1307 *ds1307;
struct i2c_client *client;
struct mutex *lock;
int stat, control;
ds1307 = container_of(work, struct ds1307, work);
client = ds1307->client;
lock = &ds1307->rtc->ops_lock;
mutex_lock(lock);
stat = i2c_smbus_read_byte_data(client, DS1337_REG_STATUS);
if (stat < 0)
goto out;
if (stat & DS1337_BIT_A1I) {
stat &= ~DS1337_BIT_A1I;
i2c_smbus_write_byte_data(client, DS1337_REG_STATUS, stat);
control = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
if (control < 0)
goto out;
control &= ~DS1337_BIT_A1IE;
i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL, control);
/* rtc_update_irq() assumes that it is called
* from IRQ-disabled context.
*/
local_irq_disable();
rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
local_irq_enable();
}
out:
if (test_bit(HAS_ALARM, &ds1307->flags))
enable_irq(client->irq);
mutex_unlock(lock);
}
static irqreturn_t ds1307_irq(int irq, void *dev_id)
{
struct i2c_client *client = dev_id;
struct ds1307 *ds1307 = i2c_get_clientdata(client);
disable_irq_nosync(irq);
schedule_work(&ds1307->work);
return IRQ_HANDLED;
}
/*----------------------------------------------------------------------*/
static int ds1307_get_time(struct device *dev, struct rtc_time *t)
{
struct ds1307 *ds1307 = dev_get_drvdata(dev);
int tmp;
/* read the RTC date and time registers all at once */
ds1307->reg_addr = 0;
ds1307->msg[1].flags = I2C_M_RD;
ds1307->msg[1].len = 7;
@ -231,9 +298,186 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
return 0;
}
static int ds1307_read_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds1307 *ds1307 = i2c_get_clientdata(client);
int ret;
if (!test_bit(HAS_ALARM, &ds1307->flags))
return -EINVAL;
/* read all ALARM1, ALARM2, and status registers at once */
ds1307->reg_addr = DS1339_REG_ALARM1_SECS;
ds1307->msg[1].flags = I2C_M_RD;
ds1307->msg[1].len = 9;
ret = i2c_transfer(to_i2c_adapter(client->dev.parent),
ds1307->msg, 2);
if (ret != 2) {
dev_err(dev, "%s error %d\n", "alarm read", ret);
return -EIO;
}
dev_dbg(dev, "%s: %02x %02x %02x %02x, %02x %02x %02x, %02x %02x\n",
"alarm read",
ds1307->regs[0], ds1307->regs[1],
ds1307->regs[2], ds1307->regs[3],
ds1307->regs[4], ds1307->regs[5],
ds1307->regs[6], ds1307->regs[7],
ds1307->regs[8]);
/* report alarm time (ALARM1); assume 24 hour and day-of-month modes,
* and that all four fields are checked matches
*/
t->time.tm_sec = bcd2bin(ds1307->regs[0] & 0x7f);
t->time.tm_min = bcd2bin(ds1307->regs[1] & 0x7f);
t->time.tm_hour = bcd2bin(ds1307->regs[2] & 0x3f);
t->time.tm_mday = bcd2bin(ds1307->regs[3] & 0x3f);
t->time.tm_mon = -1;
t->time.tm_year = -1;
t->time.tm_wday = -1;
t->time.tm_yday = -1;
t->time.tm_isdst = -1;
/* ... and status */
t->enabled = !!(ds1307->regs[7] & DS1337_BIT_A1IE);
t->pending = !!(ds1307->regs[8] & DS1337_BIT_A1I);
dev_dbg(dev, "%s secs=%d, mins=%d, "
"hours=%d, mday=%d, enabled=%d, pending=%d\n",
"alarm read", t->time.tm_sec, t->time.tm_min,
t->time.tm_hour, t->time.tm_mday,
t->enabled, t->pending);
return 0;
}
static int ds1307_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds1307 *ds1307 = i2c_get_clientdata(client);
unsigned char *buf = ds1307->regs;
u8 control, status;
int ret;
if (!test_bit(HAS_ALARM, &ds1307->flags))
return -EINVAL;
dev_dbg(dev, "%s secs=%d, mins=%d, "
"hours=%d, mday=%d, enabled=%d, pending=%d\n",
"alarm set", t->time.tm_sec, t->time.tm_min,
t->time.tm_hour, t->time.tm_mday,
t->enabled, t->pending);
/* read current status of both alarms and the chip */
ds1307->reg_addr = DS1339_REG_ALARM1_SECS;
ds1307->msg[1].flags = I2C_M_RD;
ds1307->msg[1].len = 9;
ret = i2c_transfer(to_i2c_adapter(client->dev.parent),
ds1307->msg, 2);
if (ret != 2) {
dev_err(dev, "%s error %d\n", "alarm write", ret);
return -EIO;
}
control = ds1307->regs[7];
status = ds1307->regs[8];
dev_dbg(dev, "%s: %02x %02x %02x %02x, %02x %02x %02x, %02x %02x\n",
"alarm set (old status)",
ds1307->regs[0], ds1307->regs[1],
ds1307->regs[2], ds1307->regs[3],
ds1307->regs[4], ds1307->regs[5],
ds1307->regs[6], control, status);
/* set ALARM1, using 24 hour and day-of-month modes */
*buf++ = DS1339_REG_ALARM1_SECS; /* first register addr */
buf[0] = bin2bcd(t->time.tm_sec);
buf[1] = bin2bcd(t->time.tm_min);
buf[2] = bin2bcd(t->time.tm_hour);
buf[3] = bin2bcd(t->time.tm_mday);
/* set ALARM2 to non-garbage */
buf[4] = 0;
buf[5] = 0;
buf[6] = 0;
/* optionally enable ALARM1 */
buf[7] = control & ~(DS1337_BIT_A1IE | DS1337_BIT_A2IE);
if (t->enabled) {
dev_dbg(dev, "alarm IRQ armed\n");
buf[7] |= DS1337_BIT_A1IE; /* only ALARM1 is used */
}
buf[8] = status & ~(DS1337_BIT_A1I | DS1337_BIT_A2I);
ds1307->msg[1].flags = 0;
ds1307->msg[1].len = 10;
ret = i2c_transfer(to_i2c_adapter(client->dev.parent),
&ds1307->msg[1], 1);
if (ret != 1) {
dev_err(dev, "can't set alarm time\n");
return -EIO;
}
return 0;
}
static int ds1307_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds1307 *ds1307 = i2c_get_clientdata(client);
int ret;
switch (cmd) {
case RTC_AIE_OFF:
if (!test_bit(HAS_ALARM, &ds1307->flags))
return -ENOTTY;
ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
if (ret < 0)
return ret;
ret &= ~DS1337_BIT_A1IE;
ret = i2c_smbus_write_byte_data(client,
DS1337_REG_CONTROL, ret);
if (ret < 0)
return ret;
break;
case RTC_AIE_ON:
if (!test_bit(HAS_ALARM, &ds1307->flags))
return -ENOTTY;
ret = i2c_smbus_read_byte_data(client, DS1337_REG_CONTROL);
if (ret < 0)
return ret;
ret |= DS1337_BIT_A1IE;
ret = i2c_smbus_write_byte_data(client,
DS1337_REG_CONTROL, ret);
if (ret < 0)
return ret;
break;
default:
return -ENOIOCTLCMD;
}
return 0;
}
static const struct rtc_class_ops ds13xx_rtc_ops = {
.read_time = ds1307_get_time,
.set_time = ds1307_set_time,
.read_alarm = ds1307_read_alarm,
.set_alarm = ds1307_set_alarm,
.ioctl = ds1307_ioctl,
};
/*----------------------------------------------------------------------*/
@ -327,6 +571,7 @@ static int __devinit ds1307_probe(struct i2c_client *client,
int tmp;
const struct chip_desc *chip = &chips[id->driver_data];
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
int want_irq = false;
if (!i2c_check_functionality(adapter,
I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
@ -353,6 +598,12 @@ static int __devinit ds1307_probe(struct i2c_client *client,
switch (ds1307->type) {
case ds_1337:
case ds_1339:
/* has IRQ? */
if (ds1307->client->irq > 0 && chip->alarm) {
INIT_WORK(&ds1307->work, ds1307_work);
want_irq = true;
}
ds1307->reg_addr = DS1337_REG_CONTROL;
ds1307->msg[1].len = 2;
@ -369,8 +620,20 @@ static int __devinit ds1307_probe(struct i2c_client *client,
/* oscillator off? turn it on, so clock can tick. */
if (ds1307->regs[0] & DS1337_BIT_nEOSC)
i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL,
ds1307->regs[0] & ~DS1337_BIT_nEOSC);
ds1307->regs[0] &= ~DS1337_BIT_nEOSC;
/* Using IRQ? Disable the square wave and both alarms.
* For ds1339, be sure alarms can trigger when we're
* running on Vbackup (BBSQI); we assume ds1337 will
* ignore that bit
*/
if (want_irq) {
ds1307->regs[0] |= DS1337_BIT_INTCN | DS1339_BIT_BBSQI;
ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
}
i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL,
ds1307->regs[0]);
/* oscillator fault? clear flag, and warn */
if (ds1307->regs[1] & DS1337_BIT_OSF) {
@ -495,10 +758,22 @@ read_rtc:
goto exit_free;
}
if (want_irq) {
err = request_irq(client->irq, ds1307_irq, 0,
ds1307->rtc->name, client);
if (err) {
dev_err(&client->dev,
"unable to request IRQ!\n");
goto exit_irq;
}
set_bit(HAS_ALARM, &ds1307->flags);
dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
}
if (chip->nvram56) {
err = sysfs_create_bin_file(&client->dev.kobj, &nvram);
if (err == 0) {
ds1307->has_nvram = true;
set_bit(HAS_NVRAM, &ds1307->flags);
dev_info(&client->dev, "56 bytes nvram\n");
}
}
@ -512,7 +787,9 @@ exit_bad:
ds1307->regs[2], ds1307->regs[3],
ds1307->regs[4], ds1307->regs[5],
ds1307->regs[6]);
exit_irq:
if (ds1307->rtc)
rtc_device_unregister(ds1307->rtc);
exit_free:
kfree(ds1307);
return err;
@ -520,9 +797,14 @@ exit_free:
static int __devexit ds1307_remove(struct i2c_client *client)
{
struct ds1307 *ds1307 = i2c_get_clientdata(client);
struct ds1307 *ds1307 = i2c_get_clientdata(client);
if (ds1307->has_nvram)
if (test_and_clear_bit(HAS_ALARM, &ds1307->flags)) {
free_irq(client->irq, client);
cancel_work_sync(&ds1307->work);
}
if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags))
sysfs_remove_bin_file(&client->dev.kobj, &nvram);
rtc_device_unregister(ds1307->rtc);

View file

@ -429,12 +429,33 @@ static int __devexit ds1374_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_PM
static int ds1374_suspend(struct i2c_client *client, pm_message_t state)
{
if (client->irq >= 0 && device_may_wakeup(&client->dev))
enable_irq_wake(client->irq);
return 0;
}
static int ds1374_resume(struct i2c_client *client)
{
if (client->irq >= 0 && device_may_wakeup(&client->dev))
disable_irq_wake(client->irq);
return 0;
}
#else
#define ds1374_suspend NULL
#define ds1374_resume NULL
#endif
static struct i2c_driver ds1374_driver = {
.driver = {
.name = "rtc-ds1374",
.owner = THIS_MODULE,
},
.probe = ds1374_probe,
.suspend = ds1374_suspend,
.resume = ds1374_resume,
.remove = __devexit_p(ds1374_remove),
.id_table = ds1374_id,
};

View file

@ -379,18 +379,6 @@ ds1511_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
static void
ds1511_rtc_release(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
if (pdata->irq >= 0) {
pdata->irqen = 0;
ds1511_rtc_update_alarm(pdata);
}
}
static int
ds1511_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
@ -428,7 +416,6 @@ static const struct rtc_class_ops ds1511_rtc_ops = {
.set_time = ds1511_rtc_set_time,
.read_alarm = ds1511_rtc_read_alarm,
.set_alarm = ds1511_rtc_set_alarm,
.release = ds1511_rtc_release,
.ioctl = ds1511_rtc_ioctl,
};

View file

@ -207,17 +207,6 @@ static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
static void ds1553_rtc_release(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
if (pdata->irq >= 0) {
pdata->irqen = 0;
ds1553_rtc_update_alarm(pdata);
}
}
static int ds1553_rtc_ioctl(struct device *dev, unsigned int cmd,
unsigned long arg)
{
@ -254,7 +243,6 @@ static const struct rtc_class_ops ds1553_rtc_ops = {
.set_time = ds1553_rtc_set_time,
.read_alarm = ds1553_rtc_read_alarm,
.set_alarm = ds1553_rtc_set_alarm,
.release = ds1553_rtc_release,
.ioctl = ds1553_rtc_ioctl,
};

View file

@ -9,17 +9,10 @@
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/rtc.h>
#define DRV_VERSION "0.3"
/* Addresses to scan: none. This chip cannot be detected. */
static const unsigned short normal_i2c[] = { I2C_CLIENT_END };
/* Insmod parameters */
I2C_CLIENT_INSMOD;
#define DRV_VERSION "0.4"
/* Registers */
@ -29,8 +22,7 @@ I2C_CLIENT_INSMOD;
#define DS1672_REG_CONTROL_EOSC 0x80
/* Prototypes */
static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind);
static struct i2c_driver ds1672_driver;
/*
* In the routines that deal directly with the ds1672 hardware, we use
@ -44,8 +36,8 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
unsigned char buf[4];
struct i2c_msg msgs[] = {
{ client->addr, 0, 1, &addr }, /* setup read ptr */
{ client->addr, I2C_M_RD, 4, buf }, /* read date */
{client->addr, 0, 1, &addr}, /* setup read ptr */
{client->addr, I2C_M_RD, 4, buf}, /* read date */
};
/* read date registers */
@ -80,7 +72,7 @@ static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs)
buf[2] = (secs & 0x0000FF00) >> 8;
buf[3] = (secs & 0x00FF0000) >> 16;
buf[4] = (secs & 0xFF000000) >> 24;
buf[5] = 0; /* set control reg to enable counting */
buf[5] = 0; /* set control reg to enable counting */
xfer = i2c_master_send(client, buf, 6);
if (xfer != 6) {
@ -127,8 +119,8 @@ 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 */
{client->addr, 0, 1, &addr}, /* setup read ptr */
{client->addr, I2C_M_RD, 1, status}, /* read control */
};
/* read control register */
@ -141,7 +133,8 @@ static int ds1672_get_control(struct i2c_client *client, u8 *status)
}
/* following are the sysfs callback functions */
static ssize_t show_control(struct device *dev, struct device_attribute *attr, char *buf)
static ssize_t show_control(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
u8 control;
@ -152,85 +145,46 @@ static ssize_t show_control(struct device *dev, struct device_attribute *attr, c
return err;
return sprintf(buf, "%s\n", (control & DS1672_REG_CONTROL_EOSC)
? "disabled" : "enabled");
? "disabled" : "enabled");
}
static DEVICE_ATTR(control, S_IRUGO, show_control, NULL);
static const struct rtc_class_ops ds1672_rtc_ops = {
.read_time = ds1672_rtc_read_time,
.set_time = ds1672_rtc_set_time,
.set_mmss = ds1672_rtc_set_mmss,
.read_time = ds1672_rtc_read_time,
.set_time = ds1672_rtc_set_time,
.set_mmss = ds1672_rtc_set_mmss,
};
static int ds1672_attach(struct i2c_adapter *adapter)
static int ds1672_remove(struct i2c_client *client)
{
return i2c_probe(adapter, &addr_data, ds1672_probe);
}
static int ds1672_detach(struct i2c_client *client)
{
int err;
struct rtc_device *rtc = i2c_get_clientdata(client);
if (rtc)
if (rtc)
rtc_device_unregister(rtc);
if ((err = i2c_detach_client(client)))
return err;
kfree(client);
return 0;
}
static struct i2c_driver ds1672_driver = {
.driver = {
.name = "ds1672",
},
.id = I2C_DRIVERID_DS1672,
.attach_adapter = &ds1672_attach,
.detach_client = &ds1672_detach,
};
static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
static int ds1672_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int err = 0;
u8 control;
struct i2c_client *client;
struct rtc_device *rtc;
dev_dbg(&adapter->dev, "%s\n", __func__);
dev_dbg(&client->dev, "%s\n", __func__);
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
goto exit;
}
if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
err = -ENOMEM;
goto exit;
}
/* I2C client */
client->addr = address;
client->driver = &ds1672_driver;
client->adapter = adapter;
strlcpy(client->name, ds1672_driver.driver.name, I2C_NAME_SIZE);
/* Inform the i2c layer */
if ((err = i2c_attach_client(client)))
goto exit_kfree;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
rtc = rtc_device_register(ds1672_driver.driver.name, &client->dev,
&ds1672_rtc_ops, THIS_MODULE);
&ds1672_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
err = PTR_ERR(rtc);
goto exit_detach;
}
if (IS_ERR(rtc))
return PTR_ERR(rtc);
i2c_set_clientdata(client, rtc);
@ -241,7 +195,7 @@ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
if (control & DS1672_REG_CONTROL_EOSC)
dev_warn(&client->dev, "Oscillator not enabled. "
"Set time to enable.\n");
"Set time to enable.\n");
/* Register sysfs hooks */
err = device_create_file(&client->dev, &dev_attr_control);
@ -250,19 +204,19 @@ static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
return 0;
exit_devreg:
exit_devreg:
rtc_device_unregister(rtc);
exit_detach:
i2c_detach_client(client);
exit_kfree:
kfree(client);
exit:
return err;
}
static struct i2c_driver ds1672_driver = {
.driver = {
.name = "rtc-ds1672",
},
.probe = &ds1672_probe,
.remove = &ds1672_remove,
};
static int __init ds1672_init(void)
{
return i2c_add_driver(&ds1672_driver);

290
drivers/rtc/rtc-ds3234.c Normal file
View file

@ -0,0 +1,290 @@
/* drivers/rtc/rtc-ds3234.c
*
* Driver for Dallas Semiconductor (DS3234) SPI RTC with Integrated Crystal
* and SRAM.
*
* Copyright (C) 2008 MIMOMax Wireless Ltd.
*
* 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.
*
* Changelog:
*
* 07-May-2008: Dennis Aberilla <denzzzhome@yahoo.com>
* - Created based on the max6902 code. Only implements the
* date/time keeping functions; no SRAM yet.
*/
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/spi/spi.h>
#include <linux/bcd.h>
#define DS3234_REG_SECONDS 0x00
#define DS3234_REG_MINUTES 0x01
#define DS3234_REG_HOURS 0x02
#define DS3234_REG_DAY 0x03
#define DS3234_REG_DATE 0x04
#define DS3234_REG_MONTH 0x05
#define DS3234_REG_YEAR 0x06
#define DS3234_REG_CENTURY (1 << 7) /* Bit 7 of the Month register */
#define DS3234_REG_CONTROL 0x0E
#define DS3234_REG_CONT_STAT 0x0F
#undef DS3234_DEBUG
struct ds3234 {
struct rtc_device *rtc;
u8 buf[8]; /* Burst read: addr + 7 regs */
u8 tx_buf[2];
u8 rx_buf[2];
};
static void ds3234_set_reg(struct device *dev, unsigned char address,
unsigned char data)
{
struct spi_device *spi = to_spi_device(dev);
unsigned char buf[2];
/* MSB must be '1' to indicate write */
buf[0] = address | 0x80;
buf[1] = data;
spi_write(spi, buf, 2);
}
static int ds3234_get_reg(struct device *dev, unsigned char address,
unsigned char *data)
{
struct spi_device *spi = to_spi_device(dev);
struct ds3234 *chip = dev_get_drvdata(dev);
struct spi_message message;
struct spi_transfer xfer;
int status;
if (!data)
return -EINVAL;
/* Build our spi message */
spi_message_init(&message);
memset(&xfer, 0, sizeof(xfer));
/* Address + dummy tx byte */
xfer.len = 2;
xfer.tx_buf = chip->tx_buf;
xfer.rx_buf = chip->rx_buf;
chip->tx_buf[0] = address;
chip->tx_buf[1] = 0xff;
spi_message_add_tail(&xfer, &message);
/* do the i/o */
status = spi_sync(spi, &message);
if (status == 0)
status = message.status;
else
return status;
*data = chip->rx_buf[1];
return status;
}
static int ds3234_get_datetime(struct device *dev, struct rtc_time *dt)
{
struct spi_device *spi = to_spi_device(dev);
struct ds3234 *chip = dev_get_drvdata(dev);
struct spi_message message;
struct spi_transfer xfer;
int status;
/* build the message */
spi_message_init(&message);
memset(&xfer, 0, sizeof(xfer));
xfer.len = 1 + 7; /* Addr + 7 registers */
xfer.tx_buf = chip->buf;
xfer.rx_buf = chip->buf;
chip->buf[0] = 0x00; /* Start address */
spi_message_add_tail(&xfer, &message);
/* do the i/o */
status = spi_sync(spi, &message);
if (status == 0)
status = message.status;
else
return status;
/* Seconds, Minutes, Hours, Day, Date, Month, Year */
dt->tm_sec = bcd2bin(chip->buf[1]);
dt->tm_min = bcd2bin(chip->buf[2]);
dt->tm_hour = bcd2bin(chip->buf[3] & 0x3f);
dt->tm_wday = bcd2bin(chip->buf[4]) - 1; /* 0 = Sun */
dt->tm_mday = bcd2bin(chip->buf[5]);
dt->tm_mon = bcd2bin(chip->buf[6] & 0x1f) - 1; /* 0 = Jan */
dt->tm_year = bcd2bin(chip->buf[7] & 0xff) + 100; /* Assume 20YY */
#ifdef DS3234_DEBUG
dev_dbg(dev, "\n%s : Read RTC values\n", __func__);
dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour);
dev_dbg(dev, "tm_min : %i\n", dt->tm_min);
dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec);
dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday);
dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday);
dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon);
dev_dbg(dev, "tm_year: %i\n", dt->tm_year);
#endif
return 0;
}
static int ds3234_set_datetime(struct device *dev, struct rtc_time *dt)
{
#ifdef DS3234_DEBUG
dev_dbg(dev, "\n%s : Setting RTC values\n", __func__);
dev_dbg(dev, "tm_sec : %i\n", dt->tm_sec);
dev_dbg(dev, "tm_min : %i\n", dt->tm_min);
dev_dbg(dev, "tm_hour: %i\n", dt->tm_hour);
dev_dbg(dev, "tm_wday: %i\n", dt->tm_wday);
dev_dbg(dev, "tm_mday: %i\n", dt->tm_mday);
dev_dbg(dev, "tm_mon : %i\n", dt->tm_mon);
dev_dbg(dev, "tm_year: %i\n", dt->tm_year);
#endif
ds3234_set_reg(dev, DS3234_REG_SECONDS, bin2bcd(dt->tm_sec));
ds3234_set_reg(dev, DS3234_REG_MINUTES, bin2bcd(dt->tm_min));
ds3234_set_reg(dev, DS3234_REG_HOURS, bin2bcd(dt->tm_hour) & 0x3f);
/* 0 = Sun */
ds3234_set_reg(dev, DS3234_REG_DAY, bin2bcd(dt->tm_wday + 1));
ds3234_set_reg(dev, DS3234_REG_DATE, bin2bcd(dt->tm_mday));
/* 0 = Jan */
ds3234_set_reg(dev, DS3234_REG_MONTH, bin2bcd(dt->tm_mon + 1));
/* Assume 20YY although we just want to make sure not to go negative. */
if (dt->tm_year > 100)
dt->tm_year -= 100;
ds3234_set_reg(dev, DS3234_REG_YEAR, bin2bcd(dt->tm_year));
return 0;
}
static int ds3234_read_time(struct device *dev, struct rtc_time *tm)
{
return ds3234_get_datetime(dev, tm);
}
static int ds3234_set_time(struct device *dev, struct rtc_time *tm)
{
return ds3234_set_datetime(dev, tm);
}
static const struct rtc_class_ops ds3234_rtc_ops = {
.read_time = ds3234_read_time,
.set_time = ds3234_set_time,
};
static int ds3234_probe(struct spi_device *spi)
{
struct rtc_device *rtc;
unsigned char tmp;
struct ds3234 *chip;
int res;
rtc = rtc_device_register("ds3234",
&spi->dev, &ds3234_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
spi->mode = SPI_MODE_3;
spi->bits_per_word = 8;
spi_setup(spi);
chip = kzalloc(sizeof(struct ds3234), GFP_KERNEL);
if (!chip) {
rtc_device_unregister(rtc);
return -ENOMEM;
}
chip->rtc = rtc;
dev_set_drvdata(&spi->dev, chip);
res = ds3234_get_reg(&spi->dev, DS3234_REG_SECONDS, &tmp);
if (res) {
rtc_device_unregister(rtc);
return res;
}
/* Control settings
*
* CONTROL_REG
* BIT 7 6 5 4 3 2 1 0
* EOSC BBSQW CONV RS2 RS1 INTCN A2IE A1IE
*
* 0 0 0 1 1 1 0 0
*
* CONTROL_STAT_REG
* BIT 7 6 5 4 3 2 1 0
* OSF BB32kHz CRATE1 CRATE0 EN32kHz BSY A2F A1F
*
* 1 0 0 0 1 0 0 0
*/
ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp);
ds3234_set_reg(&spi->dev, DS3234_REG_CONTROL, tmp & 0x1c);
ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp);
ds3234_set_reg(&spi->dev, DS3234_REG_CONT_STAT, tmp & 0x88);
/* Print our settings */
ds3234_get_reg(&spi->dev, DS3234_REG_CONTROL, &tmp);
dev_info(&spi->dev, "Control Reg: 0x%02x\n", tmp);
ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp);
dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp);
return 0;
}
static int __exit ds3234_remove(struct spi_device *spi)
{
struct ds3234 *chip = platform_get_drvdata(spi);
struct rtc_device *rtc = chip->rtc;
if (rtc)
rtc_device_unregister(rtc);
kfree(chip);
return 0;
}
static struct spi_driver ds3234_driver = {
.driver = {
.name = "ds3234",
.bus = &spi_bus_type,
.owner = THIS_MODULE,
},
.probe = ds3234_probe,
.remove = __devexit_p(ds3234_remove),
};
static __init int ds3234_init(void)
{
printk(KERN_INFO "DS3234 SPI RTC Driver\n");
return spi_register_driver(&ds3234_driver);
}
module_init(ds3234_init);
static __exit void ds3234_exit(void)
{
spi_unregister_driver(&ds3234_driver);
}
module_exit(ds3234_exit);
MODULE_DESCRIPTION("DS3234 SPI RTC driver");
MODULE_AUTHOR("Dennis Aberilla <[email protected]>");
MODULE_LICENSE("GPL");

View file

@ -56,21 +56,27 @@
#define M41T80_ALHOUR_HT (1 << 6) /* HT: Halt Update Bit */
#define M41T80_FLAGS_AF (1 << 6) /* AF: Alarm Flag Bit */
#define M41T80_FLAGS_BATT_LOW (1 << 4) /* BL: Battery Low Bit */
#define M41T80_WATCHDOG_RB2 (1 << 7) /* RB: Watchdog resolution */
#define M41T80_WATCHDOG_RB1 (1 << 1) /* RB: Watchdog resolution */
#define M41T80_WATCHDOG_RB0 (1 << 0) /* RB: Watchdog resolution */
#define M41T80_FEATURE_HT (1 << 0)
#define M41T80_FEATURE_BL (1 << 1)
#define M41T80_FEATURE_HT (1 << 0) /* Halt feature */
#define M41T80_FEATURE_BL (1 << 1) /* Battery low indicator */
#define M41T80_FEATURE_SQ (1 << 2) /* Squarewave feature */
#define M41T80_FEATURE_WD (1 << 3) /* Extra watchdog resolution */
#define DRV_VERSION "0.05"
static const struct i2c_device_id m41t80_id[] = {
{ "m41t80", 0 },
{ "m41t81", M41T80_FEATURE_HT },
{ "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
{ "m41t82", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
{ "m41t83", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
{ "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
{ "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
{ "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL },
{ "m41t65", M41T80_FEATURE_HT | M41T80_FEATURE_WD },
{ "m41t80", M41T80_FEATURE_SQ },
{ "m41t81", M41T80_FEATURE_HT | M41T80_FEATURE_SQ},
{ "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
{ "m41t82", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
{ "m41t83", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
{ "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
{ "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
{ "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
{ }
};
MODULE_DEVICE_TABLE(i2c, m41t80_id);
@ -386,8 +392,12 @@ static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct m41t80_data *clientdata = i2c_get_clientdata(client);
int val;
if (!(clientdata->features & M41T80_FEATURE_SQ))
return -EINVAL;
val = i2c_smbus_read_byte_data(client, M41T80_REG_SQW);
if (val < 0)
return -EIO;
@ -408,9 +418,13 @@ static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev,
const char *buf, size_t count)
{
struct i2c_client *client = to_i2c_client(dev);
struct m41t80_data *clientdata = i2c_get_clientdata(client);
int almon, sqw;
int val = simple_strtoul(buf, NULL, 0);
if (!(clientdata->features & M41T80_FEATURE_SQ))
return -EINVAL;
if (val) {
if (!is_power_of_2(val))
return -EINVAL;
@ -499,6 +513,8 @@ static void wdt_ping(void)
.buf = i2c_data,
},
};
struct m41t80_data *clientdata = i2c_get_clientdata(save_client);
i2c_data[0] = 0x09; /* watchdog register */
if (wdt_margin > 31)
@ -509,6 +525,13 @@ static void wdt_ping(void)
*/
i2c_data[1] = wdt_margin<<2 | 0x82;
/*
* M41T65 has three bits for watchdog resolution. Don't set bit 7, as
* that would be an invalid resolution.
*/
if (clientdata->features & M41T80_FEATURE_WD)
i2c_data[1] &= ~M41T80_WATCHDOG_RB2;
i2c_transfer(save_client->adapter, msgs1, 1);
}

235
drivers/rtc/rtc-m48t35.c Normal file
View file

@ -0,0 +1,235 @@
/*
* Driver for the SGS-Thomson M48T35 Timekeeper RAM chip
*
* Copyright (C) 2000 Silicon Graphics, Inc.
* Written by Ulf Carlsson (ulfc@engr.sgi.com)
*
* Copyright (C) 2008 Thomas Bogendoerfer
*
* Based on code written by Paul Gortmaker.
*
* 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.
*/
#include <linux/module.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <linux/bcd.h>
#include <linux/io.h>
#define DRV_VERSION "1.0"
struct m48t35_rtc {
u8 pad[0x7ff8]; /* starts at 0x7ff8 */
u8 control;
u8 sec;
u8 min;
u8 hour;
u8 day;
u8 date;
u8 month;
u8 year;
};
#define M48T35_RTC_SET 0x80
#define M48T35_RTC_READ 0x40
struct m48t35_priv {
struct rtc_device *rtc;
struct m48t35_rtc __iomem *reg;
size_t size;
unsigned long baseaddr;
spinlock_t lock;
};
static int m48t35_read_time(struct device *dev, struct rtc_time *tm)
{
struct m48t35_priv *priv = dev_get_drvdata(dev);
u8 control;
/*
* Only the values that we read from the RTC are set. We leave
* tm_wday, tm_yday and tm_isdst untouched. Even though the
* RTC has RTC_DAY_OF_WEEK, we ignore it, as it is only updated
* by the RTC when initially set to a non-zero value.
*/
spin_lock_irq(&priv->lock);
control = readb(&priv->reg->control);
writeb(control | M48T35_RTC_READ, &priv->reg->control);
tm->tm_sec = readb(&priv->reg->sec);
tm->tm_min = readb(&priv->reg->min);
tm->tm_hour = readb(&priv->reg->hour);
tm->tm_mday = readb(&priv->reg->date);
tm->tm_mon = readb(&priv->reg->month);
tm->tm_year = readb(&priv->reg->year);
writeb(control, &priv->reg->control);
spin_unlock_irq(&priv->lock);
tm->tm_sec = bcd2bin(tm->tm_sec);
tm->tm_min = bcd2bin(tm->tm_min);
tm->tm_hour = bcd2bin(tm->tm_hour);
tm->tm_mday = bcd2bin(tm->tm_mday);
tm->tm_mon = bcd2bin(tm->tm_mon);
tm->tm_year = bcd2bin(tm->tm_year);
/*
* Account for differences between how the RTC uses the values
* and how they are defined in a struct rtc_time;
*/
tm->tm_year += 70;
if (tm->tm_year <= 69)
tm->tm_year += 100;
tm->tm_mon--;
return rtc_valid_tm(tm);
}
static int m48t35_set_time(struct device *dev, struct rtc_time *tm)
{
struct m48t35_priv *priv = dev_get_drvdata(dev);
unsigned char mon, day, hrs, min, sec;
unsigned int yrs;
u8 control;
yrs = tm->tm_year + 1900;
mon = tm->tm_mon + 1; /* tm_mon starts at zero */
day = tm->tm_mday;
hrs = tm->tm_hour;
min = tm->tm_min;
sec = tm->tm_sec;
if (yrs < 1970)
return -EINVAL;
yrs -= 1970;
if (yrs > 255) /* They are unsigned */
return -EINVAL;
if (yrs > 169)
return -EINVAL;
if (yrs >= 100)
yrs -= 100;
sec = bin2bcd(sec);
min = bin2bcd(min);
hrs = bin2bcd(hrs);
day = bin2bcd(day);
mon = bin2bcd(mon);
yrs = bin2bcd(yrs);
spin_lock_irq(&priv->lock);
control = readb(&priv->reg->control);
writeb(control | M48T35_RTC_SET, &priv->reg->control);
writeb(yrs, &priv->reg->year);
writeb(mon, &priv->reg->month);
writeb(day, &priv->reg->date);
writeb(hrs, &priv->reg->hour);
writeb(min, &priv->reg->min);
writeb(sec, &priv->reg->sec);
writeb(control, &priv->reg->control);
spin_unlock_irq(&priv->lock);
return 0;
}
static const struct rtc_class_ops m48t35_ops = {
.read_time = m48t35_read_time,
.set_time = m48t35_set_time,
};
static int __devinit m48t35_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
struct resource *res;
struct m48t35_priv *priv;
int ret = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
priv = kzalloc(sizeof(struct m48t35_priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
priv->size = res->end - res->start + 1;
/*
* kludge: remove the #ifndef after ioc3 resource
* conflicts are resolved
*/
#ifndef CONFIG_SGI_IP27
if (!request_mem_region(res->start, priv->size, pdev->name)) {
ret = -EBUSY;
goto out;
}
#endif
priv->baseaddr = res->start;
priv->reg = ioremap(priv->baseaddr, priv->size);
if (!priv->reg) {
ret = -ENOMEM;
goto out;
}
spin_lock_init(&priv->lock);
rtc = rtc_device_register("m48t35", &pdev->dev,
&m48t35_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
ret = PTR_ERR(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)
release_mem_region(priv->baseaddr, priv->size);
kfree(priv);
return ret;
}
static int __devexit m48t35_remove(struct platform_device *pdev)
{
struct m48t35_priv *priv = platform_get_drvdata(pdev);
rtc_device_unregister(priv->rtc);
iounmap(priv->reg);
#ifndef CONFIG_SGI_IP27
release_mem_region(priv->baseaddr, priv->size);
#endif
kfree(priv);
return 0;
}
static struct platform_driver m48t35_platform_driver = {
.driver = {
.name = "rtc-m48t35",
.owner = THIS_MODULE,
},
.probe = m48t35_probe,
.remove = __devexit_p(m48t35_remove),
};
static int __init m48t35_init(void)
{
return platform_driver_register(&m48t35_platform_driver);
}
static void __exit m48t35_exit(void)
{
platform_driver_unregister(&m48t35_platform_driver);
}
MODULE_AUTHOR("Thomas Bogendoerfer <[email protected]>");
MODULE_DESCRIPTION("M48T35 RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
MODULE_ALIAS("platform:rtc-m48t35");
module_init(m48t35_init);
module_exit(m48t35_exit);

View file

@ -24,8 +24,9 @@
#define NO_IRQ (-1)
#endif
#define M48T59_READ(reg) pdata->read_byte(dev, reg)
#define M48T59_WRITE(val, reg) pdata->write_byte(dev, reg, val)
#define M48T59_READ(reg) (pdata->read_byte(dev, pdata->offset + reg))
#define M48T59_WRITE(val, reg) \
(pdata->write_byte(dev, pdata->offset + reg, val))
#define M48T59_SET_BITS(mask, reg) \
M48T59_WRITE((M48T59_READ(reg) | (mask)), (reg))
@ -34,7 +35,6 @@
struct m48t59_private {
void __iomem *ioaddr;
unsigned int size; /* iomem size */
int irq;
struct rtc_device *rtc;
spinlock_t lock; /* serialize the NVRAM and RTC access */
@ -82,7 +82,8 @@ static int m48t59_rtc_read_time(struct device *dev, struct rtc_time *tm)
tm->tm_mday = BCD2BIN(M48T59_READ(M48T59_MDAY));
val = M48T59_READ(M48T59_WDAY);
if ((val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) {
if ((pdata->type == M48T59RTC_TYPE_M48T59) &&
(val & M48T59_WDAY_CEB) && (val & M48T59_WDAY_CB)) {
dev_dbg(dev, "Century bit is enabled\n");
tm->tm_year += 100; /* one century */
}
@ -126,7 +127,7 @@ static int m48t59_rtc_set_time(struct device *dev, struct rtc_time *tm)
M48T59_WRITE((BIN2BCD(tm->tm_mon + 1) & 0x1F), M48T59_MONTH);
M48T59_WRITE(BIN2BCD(tm->tm_year % 100), M48T59_YEAR);
if (tm->tm_year/100)
if (pdata->type == M48T59RTC_TYPE_M48T59 && (tm->tm_year / 100))
val = (M48T59_WDAY_CEB | M48T59_WDAY_CB);
val |= (BIN2BCD(tm->tm_wday) & 0x07);
M48T59_WRITE(val, M48T59_WDAY);
@ -310,6 +311,11 @@ static const struct rtc_class_ops m48t59_rtc_ops = {
.proc = m48t59_rtc_proc,
};
static const struct rtc_class_ops m48t02_rtc_ops = {
.read_time = m48t59_rtc_read_time,
.set_time = m48t59_rtc_set_time,
};
static ssize_t m48t59_nvram_read(struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t size)
@ -321,7 +327,7 @@ static ssize_t m48t59_nvram_read(struct kobject *kobj,
ssize_t cnt = 0;
unsigned long flags;
for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) {
for (; size > 0 && pos < pdata->offset; cnt++, size--) {
spin_lock_irqsave(&m48t59->lock, flags);
*buf++ = M48T59_READ(cnt);
spin_unlock_irqrestore(&m48t59->lock, flags);
@ -341,7 +347,7 @@ static ssize_t m48t59_nvram_write(struct kobject *kobj,
ssize_t cnt = 0;
unsigned long flags;
for (; size > 0 && pos < M48T59_NVRAM_SIZE; cnt++, size--) {
for (; size > 0 && pos < pdata->offset; cnt++, size--) {
spin_lock_irqsave(&m48t59->lock, flags);
M48T59_WRITE(*buf++, cnt);
spin_unlock_irqrestore(&m48t59->lock, flags);
@ -358,7 +364,6 @@ static struct bin_attribute m48t59_nvram_attr = {
},
.read = m48t59_nvram_read,
.write = m48t59_nvram_write,
.size = M48T59_NVRAM_SIZE,
};
static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
@ -367,6 +372,8 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
struct m48t59_private *m48t59 = NULL;
struct resource *res;
int ret = -ENOMEM;
char *name;
const struct rtc_class_ops *ops;
/* This chip could be memory-mapped or I/O-mapped */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@ -391,6 +398,8 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
/* Ensure we only kmalloc platform data once */
pdev->dev.platform_data = pdata;
}
if (!pdata->type)
pdata->type = M48T59RTC_TYPE_M48T59;
/* Try to use the generic memory read/write ops */
if (!pdata->write_byte)
@ -403,10 +412,14 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
if (!m48t59)
return -ENOMEM;
m48t59->size = res->end - res->start + 1;
m48t59->ioaddr = ioremap(res->start, m48t59->size);
if (!m48t59->ioaddr)
goto out;
m48t59->ioaddr = pdata->ioaddr;
if (!m48t59->ioaddr) {
/* ioaddr not mapped externally */
m48t59->ioaddr = ioremap(res->start, res->end - res->start + 1);
if (!m48t59->ioaddr)
goto out;
}
/* Try to get irq number. We also can work in
* the mode without IRQ.
@ -421,14 +434,36 @@ static int __devinit m48t59_rtc_probe(struct platform_device *pdev)
if (ret)
goto out;
}
switch (pdata->type) {
case M48T59RTC_TYPE_M48T59:
name = "m48t59";
ops = &m48t59_rtc_ops;
pdata->offset = 0x1ff0;
break;
case M48T59RTC_TYPE_M48T02:
name = "m48t02";
ops = &m48t02_rtc_ops;
pdata->offset = 0x7f0;
break;
case M48T59RTC_TYPE_M48T08:
name = "m48t08";
ops = &m48t02_rtc_ops;
pdata->offset = 0x1ff0;
break;
default:
dev_err(&pdev->dev, "Unknown RTC type\n");
ret = -ENODEV;
goto out;
}
m48t59->rtc = rtc_device_register("m48t59", &pdev->dev,
&m48t59_rtc_ops, THIS_MODULE);
m48t59->rtc = rtc_device_register(name, &pdev->dev, ops, THIS_MODULE);
if (IS_ERR(m48t59->rtc)) {
ret = PTR_ERR(m48t59->rtc);
goto out;
}
m48t59_nvram_attr.size = pdata->offset;
ret = sysfs_create_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
if (ret)
goto out;
@ -452,11 +487,12 @@ out:
static int __devexit m48t59_rtc_remove(struct platform_device *pdev)
{
struct m48t59_private *m48t59 = platform_get_drvdata(pdev);
struct m48t59_plat_data *pdata = pdev->dev.platform_data;
sysfs_remove_bin_file(&pdev->dev.kobj, &m48t59_nvram_attr);
if (!IS_ERR(m48t59->rtc))
rtc_device_unregister(m48t59->rtc);
if (m48t59->ioaddr)
if (m48t59->ioaddr && !pdata->ioaddr)
iounmap(m48t59->ioaddr);
if (m48t59->irq != NO_IRQ)
free_irq(m48t59->irq, &pdev->dev);
@ -491,5 +527,5 @@ module_init(m48t59_rtc_init);
module_exit(m48t59_rtc_exit);
MODULE_AUTHOR("Mark Zhan <[email protected]>");
MODULE_DESCRIPTION("M48T59 RTC driver");
MODULE_DESCRIPTION("M48T59/M48T02/M48T08 RTC driver");
MODULE_LICENSE("GPL");

View file

@ -17,19 +17,18 @@
#include <linux/rtc.h>
#include <linux/delay.h>
#define DRV_NAME "max6900"
#define DRV_VERSION "0.1"
#define DRV_VERSION "0.2"
/*
* register indices
*/
#define MAX6900_REG_SC 0 /* seconds 00-59 */
#define MAX6900_REG_MN 1 /* minutes 00-59 */
#define MAX6900_REG_HR 2 /* hours 00-23 */
#define MAX6900_REG_DT 3 /* day of month 00-31 */
#define MAX6900_REG_MO 4 /* month 01-12 */
#define MAX6900_REG_DW 5 /* day of week 1-7 */
#define MAX6900_REG_YR 6 /* year 00-99 */
#define MAX6900_REG_SC 0 /* seconds 00-59 */
#define MAX6900_REG_MN 1 /* minutes 00-59 */
#define MAX6900_REG_HR 2 /* hours 00-23 */
#define MAX6900_REG_DT 3 /* day of month 00-31 */
#define MAX6900_REG_MO 4 /* month 01-12 */
#define MAX6900_REG_DW 5 /* day of week 1-7 */
#define MAX6900_REG_YR 6 /* year 00-99 */
#define MAX6900_REG_CT 7 /* control */
/* register 8 is undocumented */
#define MAX6900_REG_CENTURY 9 /* century */
@ -39,7 +38,6 @@
#define MAX6900_REG_CT_WP (1 << 7) /* Write Protect */
/*
* register read/write commands
*/
@ -52,16 +50,7 @@
#define MAX6900_IDLE_TIME_AFTER_WRITE 3 /* specification says 2.5 mS */
#define MAX6900_I2C_ADDR 0xa0
static const unsigned short normal_i2c[] = {
MAX6900_I2C_ADDR >> 1,
I2C_CLIENT_END
};
I2C_CLIENT_INSMOD; /* defines addr_data */
static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind);
static struct i2c_driver max6900_driver;
static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
{
@ -69,36 +58,35 @@ static int max6900_i2c_read_regs(struct i2c_client *client, u8 *buf)
u8 reg_century_read[1] = { MAX6900_REG_CENTURY_READ };
struct i2c_msg msgs[4] = {
{
.addr = client->addr,
.flags = 0, /* write */
.len = sizeof(reg_burst_read),
.buf = reg_burst_read
},
.addr = client->addr,
.flags = 0, /* write */
.len = sizeof(reg_burst_read),
.buf = reg_burst_read}
,
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = MAX6900_BURST_LEN,
.buf = buf
},
.addr = client->addr,
.flags = I2C_M_RD,
.len = MAX6900_BURST_LEN,
.buf = buf}
,
{
.addr = client->addr,
.flags = 0, /* write */
.len = sizeof(reg_century_read),
.buf = reg_century_read
},
.addr = client->addr,
.flags = 0, /* write */
.len = sizeof(reg_century_read),
.buf = reg_century_read}
,
{
.addr = client->addr,
.flags = I2C_M_RD,
.len = sizeof(buf[MAX6900_REG_CENTURY]),
.buf = &buf[MAX6900_REG_CENTURY]
}
.addr = client->addr,
.flags = I2C_M_RD,
.len = sizeof(buf[MAX6900_REG_CENTURY]),
.buf = &buf[MAX6900_REG_CENTURY]
}
};
int rc;
rc = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (rc != ARRAY_SIZE(msgs)) {
dev_err(&client->dev, "%s: register read failed\n",
__func__);
dev_err(&client->dev, "%s: register read failed\n", __func__);
return -EIO;
}
return 0;
@ -109,20 +97,18 @@ static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
u8 i2c_century_buf[1 + 1] = { MAX6900_REG_CENTURY_WRITE };
struct i2c_msg century_msgs[1] = {
{
.addr = client->addr,
.flags = 0, /* write */
.len = sizeof(i2c_century_buf),
.buf = i2c_century_buf
}
.addr = client->addr,
.flags = 0, /* write */
.len = sizeof(i2c_century_buf),
.buf = i2c_century_buf}
};
u8 i2c_burst_buf[MAX6900_BURST_LEN + 1] = { MAX6900_REG_BURST_WRITE };
struct i2c_msg burst_msgs[1] = {
{
.addr = client->addr,
.flags = 0, /* write */
.len = sizeof(i2c_burst_buf),
.buf = i2c_burst_buf
}
.addr = client->addr,
.flags = 0, /* write */
.len = sizeof(i2c_burst_buf),
.buf = i2c_burst_buf}
};
int rc;
@ -133,10 +119,12 @@ static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
* bit as part of the burst write.
*/
i2c_century_buf[1] = buf[MAX6900_REG_CENTURY];
rc = i2c_transfer(client->adapter, century_msgs,
ARRAY_SIZE(century_msgs));
if (rc != ARRAY_SIZE(century_msgs))
goto write_failed;
msleep(MAX6900_IDLE_TIME_AFTER_WRITE);
memcpy(&i2c_burst_buf[1], buf, MAX6900_BURST_LEN);
@ -148,45 +136,11 @@ static int max6900_i2c_write_regs(struct i2c_client *client, u8 const *buf)
return 0;
write_failed:
dev_err(&client->dev, "%s: register write failed\n",
__func__);
write_failed:
dev_err(&client->dev, "%s: register write failed\n", __func__);
return -EIO;
}
static int max6900_i2c_validate_client(struct i2c_client *client)
{
u8 regs[MAX6900_REG_LEN];
u8 zero_mask[] = {
0x80, /* seconds */
0x80, /* minutes */
0x40, /* hours */
0xc0, /* day of month */
0xe0, /* month */
0xf8, /* day of week */
0x00, /* year */
0x7f, /* control */
};
int i;
int rc;
int reserved;
reserved = i2c_smbus_read_byte_data(client, MAX6900_REG_RESERVED_READ);
if (reserved != 0x07)
return -ENODEV;
rc = max6900_i2c_read_regs(client, regs);
if (rc < 0)
return rc;
for (i = 0; i < ARRAY_SIZE(zero_mask); ++i) {
if (regs[i] & zero_mask[i])
return -ENODEV;
}
return 0;
}
static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
{
int rc;
@ -202,7 +156,7 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
tm->tm_mday = BCD2BIN(regs[MAX6900_REG_DT]);
tm->tm_mon = BCD2BIN(regs[MAX6900_REG_MO]) - 1;
tm->tm_year = BCD2BIN(regs[MAX6900_REG_YR]) +
BCD2BIN(regs[MAX6900_REG_CENTURY]) * 100 - 1900;
BCD2BIN(regs[MAX6900_REG_CENTURY]) * 100 - 1900;
tm->tm_wday = BCD2BIN(regs[MAX6900_REG_DW]);
return 0;
@ -211,7 +165,7 @@ static int max6900_i2c_read_time(struct i2c_client *client, struct rtc_time *tm)
static int max6900_i2c_clear_write_protect(struct i2c_client *client)
{
int rc;
rc = i2c_smbus_write_byte_data (client, MAX6900_REG_CONTROL_WRITE, 0);
rc = i2c_smbus_write_byte_data(client, MAX6900_REG_CONTROL_WRITE, 0);
if (rc < 0) {
dev_err(&client->dev, "%s: control register write failed\n",
__func__);
@ -220,8 +174,8 @@ static int max6900_i2c_clear_write_protect(struct i2c_client *client)
return 0;
}
static int max6900_i2c_set_time(struct i2c_client *client,
struct rtc_time const *tm)
static int
max6900_i2c_set_time(struct i2c_client *client, struct rtc_time const *tm)
{
u8 regs[MAX6900_REG_LEN];
int rc;
@ -258,89 +212,49 @@ static int max6900_rtc_set_time(struct device *dev, struct rtc_time *tm)
return max6900_i2c_set_time(to_i2c_client(dev), tm);
}
static int max6900_attach_adapter(struct i2c_adapter *adapter)
static int max6900_remove(struct i2c_client *client)
{
return i2c_probe(adapter, &addr_data, max6900_probe);
}
static int max6900_detach_client(struct i2c_client *client)
{
struct rtc_device *const rtc = i2c_get_clientdata(client);
struct rtc_device *rtc = i2c_get_clientdata(client);
if (rtc)
rtc_device_unregister(rtc);
return i2c_detach_client(client);
return 0;
}
static struct i2c_driver max6900_driver = {
.driver = {
.name = DRV_NAME,
},
.id = I2C_DRIVERID_MAX6900,
.attach_adapter = max6900_attach_adapter,
.detach_client = max6900_detach_client,
};
static const struct rtc_class_ops max6900_rtc_ops = {
.read_time = max6900_rtc_read_time,
.set_time = max6900_rtc_set_time,
.read_time = max6900_rtc_read_time,
.set_time = max6900_rtc_set_time,
};
static int max6900_probe(struct i2c_adapter *adapter, int addr, int kind)
static int
max6900_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
int rc = 0;
struct i2c_client *client = NULL;
struct rtc_device *rtc = NULL;
struct rtc_device *rtc;
if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
rc = -ENODEV;
goto failout;
}
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
if (client == NULL) {
rc = -ENOMEM;
goto failout;
}
client->addr = addr;
client->adapter = adapter;
client->driver = &max6900_driver;
strlcpy(client->name, DRV_NAME, I2C_NAME_SIZE);
if (kind < 0) {
rc = max6900_i2c_validate_client(client);
if (rc < 0)
goto failout;
}
rc = i2c_attach_client(client);
if (rc < 0)
goto failout;
dev_info(&client->dev,
"chip found, driver version " DRV_VERSION "\n");
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
rtc = rtc_device_register(max6900_driver.driver.name,
&client->dev,
&max6900_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
rc = PTR_ERR(rtc);
goto failout_detach;
}
&client->dev, &max6900_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
i2c_set_clientdata(client, rtc);
return 0;
failout_detach:
i2c_detach_client(client);
failout:
kfree(client);
return rc;
}
static struct i2c_driver max6900_driver = {
.driver = {
.name = "rtc-max6900",
},
.probe = max6900_probe,
.remove = max6900_remove,
};
static int __init max6900_init(void)
{
return i2c_add_driver(&max6900_driver);
@ -352,6 +266,7 @@ static void __exit max6900_exit(void)
}
MODULE_DESCRIPTION("Maxim MAX6900 RTC driver");
MODULE_AUTHOR("Dale Farnsworth <[email protected]>");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);

View file

@ -179,58 +179,6 @@ struct pcf8563_limit
unsigned char max;
};
static int pcf8563_validate_client(struct i2c_client *client)
{
int i;
static const struct pcf8563_limit pattern[] = {
/* register, mask, min, max */
{ PCF8563_REG_SC, 0x7F, 0, 59 },
{ PCF8563_REG_MN, 0x7F, 0, 59 },
{ PCF8563_REG_HR, 0x3F, 0, 23 },
{ PCF8563_REG_DM, 0x3F, 0, 31 },
{ PCF8563_REG_MO, 0x1F, 0, 12 },
};
/* check limits (only registers with bcd values) */
for (i = 0; i < ARRAY_SIZE(pattern); i++) {
int xfer;
unsigned char value;
unsigned char buf = pattern[i].reg;
struct i2c_msg msgs[] = {
{ client->addr, 0, 1, &buf },
{ client->addr, I2C_M_RD, 1, &buf },
};
xfer = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
if (xfer != ARRAY_SIZE(msgs)) {
dev_err(&client->dev,
"%s: could not read register 0x%02X\n",
__func__, pattern[i].reg);
return -EIO;
}
value = BCD2BIN(buf & pattern[i].mask);
if (value > pattern[i].max ||
value < pattern[i].min) {
dev_dbg(&client->dev,
"%s: pattern=%d, reg=%x, mask=0x%02x, min=%d, "
"max=%d, value=%d, raw=0x%02X\n",
__func__, i, pattern[i].reg, pattern[i].mask,
pattern[i].min, pattern[i].max,
value, buf);
return -ENODEV;
}
}
return 0;
}
static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
return pcf8563_get_datetime(to_i2c_client(dev), tm);
@ -262,12 +210,6 @@ static int pcf8563_probe(struct i2c_client *client,
if (!pcf8563)
return -ENOMEM;
/* Verify the chip is really an PCF8563 */
if (pcf8563_validate_client(client) < 0) {
err = -ENODEV;
goto exit_kfree;
}
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
pcf8563->rtc = rtc_device_register(pcf8563_driver.driver.name,

View file

@ -34,15 +34,6 @@ static irqreturn_t pl030_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int pl030_open(struct device *dev)
{
return 0;
}
static void pl030_release(struct device *dev)
{
}
static int pl030_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
return -ENOIOCTLCMD;
@ -104,8 +95,6 @@ static int pl030_set_time(struct device *dev, struct rtc_time *tm)
}
static const struct rtc_class_ops pl030_ops = {
.open = pl030_open,
.release = pl030_release,
.ioctl = pl030_ioctl,
.read_time = pl030_read_time,
.set_time = pl030_set_time,

View file

@ -45,18 +45,6 @@ static irqreturn_t pl031_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int pl031_open(struct device *dev)
{
/*
* We request IRQ in pl031_probe, so nothing to do here...
*/
return 0;
}
static void pl031_release(struct device *dev)
{
}
static int pl031_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
struct pl031_local *ldata = dev_get_drvdata(dev);
@ -118,8 +106,6 @@ static int pl031_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
}
static const struct rtc_class_ops pl031_ops = {
.open = pl031_open,
.release = pl031_release,
.ioctl = pl031_ioctl,
.read_time = pl031_read_time,
.set_time = pl031_set_time,

View file

@ -1,8 +1,9 @@
/*
* An I2C driver for Ricoh RS5C372 and RV5C38[67] RTCs
* An I2C driver for Ricoh RS5C372, R2025S/D and RV5C38[67] RTCs
*
* Copyright (C) 2005 Pavel Mironchik <pmironchik@optifacio.net>
* Copyright (C) 2006 Tower Technologies
* Copyright (C) 2008 Paul Mundt
*
* 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
@ -13,7 +14,7 @@
#include <linux/rtc.h>
#include <linux/bcd.h>
#define DRV_VERSION "0.5"
#define DRV_VERSION "0.6"
/*
@ -51,7 +52,8 @@
# define RS5C_CTRL1_CT4 (4 << 0) /* 1 Hz level irq */
#define RS5C_REG_CTRL2 15
# define RS5C372_CTRL2_24 (1 << 5)
# define RS5C_CTRL2_XSTP (1 << 4)
# define R2025_CTRL2_XST (1 << 5)
# define RS5C_CTRL2_XSTP (1 << 4) /* only if !R2025S/D */
# define RS5C_CTRL2_CTFG (1 << 2)
# define RS5C_CTRL2_AAFG (1 << 1) /* or WAFG */
# define RS5C_CTRL2_BAFG (1 << 0) /* or DAFG */
@ -63,6 +65,7 @@
enum rtc_type {
rtc_undef = 0,
rtc_r2025sd,
rtc_rs5c372a,
rtc_rs5c372b,
rtc_rv5c386,
@ -70,6 +73,7 @@ enum rtc_type {
};
static const struct i2c_device_id rs5c372_id[] = {
{ "r2025sd", rtc_r2025sd },
{ "rs5c372a", rtc_rs5c372a },
{ "rs5c372b", rtc_rs5c372b },
{ "rv5c386", rtc_rv5c386 },
@ -89,6 +93,7 @@ struct rs5c372 {
enum rtc_type type;
unsigned time24:1;
unsigned has_irq:1;
unsigned smbus:1;
char buf[17];
char *regs;
};
@ -106,10 +111,25 @@ static int rs5c_get_regs(struct rs5c372 *rs5c)
*
* The first method doesn't work with the iop3xx adapter driver, on at
* least 80219 chips; this works around that bug.
*
* The third method on the other hand doesn't work for the SMBus-only
* configurations, so we use the the first method there, stripping off
* the extra register in the process.
*/
if ((i2c_transfer(client->adapter, msgs, 1)) != 1) {
dev_warn(&client->dev, "can't read registers\n");
return -EIO;
if (rs5c->smbus) {
int addr = RS5C_ADDR(RS5C372_REG_SECS);
int size = sizeof(rs5c->buf) - 1;
if (i2c_smbus_read_i2c_block_data(client, addr, size,
rs5c->buf + 1) != size) {
dev_warn(&client->dev, "can't read registers\n");
return -EIO;
}
} else {
if ((i2c_transfer(client->adapter, msgs, 1)) != 1) {
dev_warn(&client->dev, "can't read registers\n");
return -EIO;
}
}
dev_dbg(&client->dev,
@ -187,6 +207,7 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
{
struct rs5c372 *rs5c = i2c_get_clientdata(client);
unsigned char buf[8];
int addr;
dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d "
"mday=%d, mon=%d, year=%d, wday=%d\n",
@ -194,16 +215,16 @@ static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
tm->tm_sec, tm->tm_min, tm->tm_hour,
tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
buf[0] = RS5C_ADDR(RS5C372_REG_SECS);
buf[1] = BIN2BCD(tm->tm_sec);
buf[2] = BIN2BCD(tm->tm_min);
buf[3] = rs5c_hr2reg(rs5c, tm->tm_hour);
buf[4] = BIN2BCD(tm->tm_wday);
buf[5] = BIN2BCD(tm->tm_mday);
buf[6] = BIN2BCD(tm->tm_mon + 1);
buf[7] = BIN2BCD(tm->tm_year - 100);
addr = RS5C_ADDR(RS5C372_REG_SECS);
buf[0] = BIN2BCD(tm->tm_sec);
buf[1] = BIN2BCD(tm->tm_min);
buf[2] = rs5c_hr2reg(rs5c, tm->tm_hour);
buf[3] = BIN2BCD(tm->tm_wday);
buf[4] = BIN2BCD(tm->tm_mday);
buf[5] = BIN2BCD(tm->tm_mon + 1);
buf[6] = BIN2BCD(tm->tm_year - 100);
if ((i2c_master_send(client, buf, 8)) != 8) {
if (i2c_smbus_write_i2c_block_data(client, addr, sizeof(buf), buf) < 0) {
dev_err(&client->dev, "%s: write error\n", __func__);
return -EIO;
}
@ -266,16 +287,16 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
{
struct i2c_client *client = to_i2c_client(dev);
struct rs5c372 *rs5c = i2c_get_clientdata(client);
unsigned char buf[2];
int status;
unsigned char buf;
int status, addr;
buf[1] = rs5c->regs[RS5C_REG_CTRL1];
buf = rs5c->regs[RS5C_REG_CTRL1];
switch (cmd) {
case RTC_UIE_OFF:
case RTC_UIE_ON:
/* some 327a modes use a different IRQ pin for 1Hz irqs */
if (rs5c->type == rtc_rs5c372a
&& (buf[1] & RS5C372A_CTRL1_SL1))
&& (buf & RS5C372A_CTRL1_SL1))
return -ENOIOCTLCMD;
case RTC_AIE_OFF:
case RTC_AIE_ON:
@ -293,28 +314,30 @@ rs5c_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
if (status < 0)
return status;
buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
addr = RS5C_ADDR(RS5C_REG_CTRL1);
switch (cmd) {
case RTC_AIE_OFF: /* alarm off */
buf[1] &= ~RS5C_CTRL1_AALE;
buf &= ~RS5C_CTRL1_AALE;
break;
case RTC_AIE_ON: /* alarm on */
buf[1] |= RS5C_CTRL1_AALE;
buf |= RS5C_CTRL1_AALE;
break;
case RTC_UIE_OFF: /* update off */
buf[1] &= ~RS5C_CTRL1_CT_MASK;
buf &= ~RS5C_CTRL1_CT_MASK;
break;
case RTC_UIE_ON: /* update on */
buf[1] &= ~RS5C_CTRL1_CT_MASK;
buf[1] |= RS5C_CTRL1_CT4;
buf &= ~RS5C_CTRL1_CT_MASK;
buf |= RS5C_CTRL1_CT4;
break;
}
if ((i2c_master_send(client, buf, 2)) != 2) {
if (i2c_smbus_write_byte_data(client, addr, buf) < 0) {
printk(KERN_WARNING "%s: can't update alarm\n",
rs5c->rtc->name);
status = -EIO;
} else
rs5c->regs[RS5C_REG_CTRL1] = buf[1];
rs5c->regs[RS5C_REG_CTRL1] = buf;
return status;
}
@ -364,8 +387,8 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct i2c_client *client = to_i2c_client(dev);
struct rs5c372 *rs5c = i2c_get_clientdata(client);
int status;
unsigned char buf[4];
int status, addr, i;
unsigned char buf[3];
/* only handle up to 24 hours in the future, like RTC_ALM_SET */
if (t->time.tm_mday != -1
@ -380,33 +403,36 @@ static int rs5c_set_alarm(struct device *dev, struct rtc_wkalrm *t)
if (status < 0)
return status;
if (rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE) {
buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
buf[1] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE;
if (i2c_master_send(client, buf, 2) != 2) {
addr = RS5C_ADDR(RS5C_REG_CTRL1);
buf[0] = rs5c->regs[RS5C_REG_CTRL1] & ~RS5C_CTRL1_AALE;
if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0) {
pr_debug("%s: can't disable alarm\n", rs5c->rtc->name);
return -EIO;
}
rs5c->regs[RS5C_REG_CTRL1] = buf[1];
rs5c->regs[RS5C_REG_CTRL1] = buf[0];
}
/* set alarm */
buf[0] = RS5C_ADDR(RS5C_REG_ALARM_A_MIN);
buf[1] = BIN2BCD(t->time.tm_min);
buf[2] = rs5c_hr2reg(rs5c, t->time.tm_hour);
buf[3] = 0x7f; /* any/all days */
if ((i2c_master_send(client, buf, 4)) != 4) {
pr_debug("%s: can't set alarm time\n", rs5c->rtc->name);
return -EIO;
buf[0] = BIN2BCD(t->time.tm_min);
buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour);
buf[2] = 0x7f; /* any/all days */
for (i = 0; i < sizeof(buf); i++) {
addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i);
if (i2c_smbus_write_byte_data(client, addr, buf[i]) < 0) {
pr_debug("%s: can't set alarm time\n", rs5c->rtc->name);
return -EIO;
}
}
/* ... and maybe enable its irq */
if (t->enabled) {
buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
buf[1] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE;
if ((i2c_master_send(client, buf, 2)) != 2)
addr = RS5C_ADDR(RS5C_REG_CTRL1);
buf[0] = rs5c->regs[RS5C_REG_CTRL1] | RS5C_CTRL1_AALE;
if (i2c_smbus_write_byte_data(client, addr, buf[0]) < 0)
printk(KERN_WARNING "%s: can't enable alarm\n",
rs5c->rtc->name);
rs5c->regs[RS5C_REG_CTRL1] = buf[1];
rs5c->regs[RS5C_REG_CTRL1] = buf[0];
}
return 0;
@ -503,18 +529,81 @@ static void rs5c_sysfs_unregister(struct device *dev)
static struct i2c_driver rs5c372_driver;
static int rs5c_oscillator_setup(struct rs5c372 *rs5c372)
{
unsigned char buf[2];
int addr, i, ret = 0;
if (rs5c372->type == rtc_r2025sd) {
if (!(rs5c372->regs[RS5C_REG_CTRL2] & R2025_CTRL2_XST))
return ret;
rs5c372->regs[RS5C_REG_CTRL2] &= ~R2025_CTRL2_XST;
} else {
if (!(rs5c372->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_XSTP))
return ret;
rs5c372->regs[RS5C_REG_CTRL2] &= ~RS5C_CTRL2_XSTP;
}
addr = RS5C_ADDR(RS5C_REG_CTRL1);
buf[0] = rs5c372->regs[RS5C_REG_CTRL1];
buf[1] = rs5c372->regs[RS5C_REG_CTRL2];
/* use 24hr mode */
switch (rs5c372->type) {
case rtc_rs5c372a:
case rtc_rs5c372b:
buf[1] |= RS5C372_CTRL2_24;
rs5c372->time24 = 1;
break;
case rtc_r2025sd:
case rtc_rv5c386:
case rtc_rv5c387a:
buf[0] |= RV5C387_CTRL1_24;
rs5c372->time24 = 1;
break;
default:
/* impossible */
break;
}
for (i = 0; i < sizeof(buf); i++) {
addr = RS5C_ADDR(RS5C_REG_CTRL1 + i);
ret = i2c_smbus_write_byte_data(rs5c372->client, addr, buf[i]);
if (unlikely(ret < 0))
return ret;
}
rs5c372->regs[RS5C_REG_CTRL1] = buf[0];
rs5c372->regs[RS5C_REG_CTRL2] = buf[1];
return 0;
}
static int rs5c372_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int err = 0;
int smbus_mode = 0;
struct rs5c372 *rs5c372;
struct rtc_time tm;
dev_dbg(&client->dev, "%s\n", __func__);
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
err = -ENODEV;
goto exit;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK)) {
/*
* If we don't have any master mode adapter, try breaking
* it down in to the barest of capabilities.
*/
if (i2c_check_functionality(client->adapter,
I2C_FUNC_SMBUS_BYTE_DATA |
I2C_FUNC_SMBUS_I2C_BLOCK))
smbus_mode = 1;
else {
/* Still no good, give up */
err = -ENODEV;
goto exit;
}
}
if (!(rs5c372 = kzalloc(sizeof(struct rs5c372), GFP_KERNEL))) {
@ -528,6 +617,7 @@ static int rs5c372_probe(struct i2c_client *client,
/* we read registers 0x0f then 0x00-0x0f; skip the first one */
rs5c372->regs = &rs5c372->buf[1];
rs5c372->smbus = smbus_mode;
err = rs5c_get_regs(rs5c372);
if (err < 0)
@ -543,6 +633,7 @@ static int rs5c372_probe(struct i2c_client *client,
if (rs5c372->regs[RS5C_REG_CTRL2] & RS5C372_CTRL2_24)
rs5c372->time24 = 1;
break;
case rtc_r2025sd:
case rtc_rv5c386:
case rtc_rv5c387a:
if (rs5c372->regs[RS5C_REG_CTRL1] & RV5C387_CTRL1_24)
@ -558,39 +649,14 @@ static int rs5c372_probe(struct i2c_client *client,
/* if the oscillator lost power and no other software (like
* the bootloader) set it up, do it here.
*
* The R2025S/D does this a little differently than the other
* parts, so we special case that..
*/
if (rs5c372->regs[RS5C_REG_CTRL2] & RS5C_CTRL2_XSTP) {
unsigned char buf[3];
rs5c372->regs[RS5C_REG_CTRL2] &= ~RS5C_CTRL2_XSTP;
buf[0] = RS5C_ADDR(RS5C_REG_CTRL1);
buf[1] = rs5c372->regs[RS5C_REG_CTRL1];
buf[2] = rs5c372->regs[RS5C_REG_CTRL2];
/* use 24hr mode */
switch (rs5c372->type) {
case rtc_rs5c372a:
case rtc_rs5c372b:
buf[2] |= RS5C372_CTRL2_24;
rs5c372->time24 = 1;
break;
case rtc_rv5c386:
case rtc_rv5c387a:
buf[1] |= RV5C387_CTRL1_24;
rs5c372->time24 = 1;
break;
default:
/* impossible */
break;
}
if ((i2c_master_send(client, buf, 3)) != 3) {
dev_err(&client->dev, "setup error\n");
goto exit_kfree;
}
rs5c372->regs[RS5C_REG_CTRL1] = buf[1];
rs5c372->regs[RS5C_REG_CTRL2] = buf[2];
err = rs5c_oscillator_setup(rs5c372);
if (unlikely(err < 0)) {
dev_err(&client->dev, "setup error\n");
goto exit_kfree;
}
if (rs5c372_get_datetime(client, &tm) < 0)
@ -598,6 +664,7 @@ static int rs5c372_probe(struct i2c_client *client,
dev_info(&client->dev, "%s found, %s, driver version " DRV_VERSION "\n",
({ char *s; switch (rs5c372->type) {
case rtc_r2025sd: s = "r2025sd"; break;
case rtc_rs5c372a: s = "rs5c372a"; break;
case rtc_rs5c372b: s = "rs5c372b"; break;
case rtc_rv5c386: s = "rv5c386"; break;
@ -667,7 +734,8 @@ module_exit(rs5c372_exit);
MODULE_AUTHOR(
"Pavel Mironchik <[email protected]>, "
"Alessandro Zummo <[email protected]>");
"Alessandro Zummo <[email protected]>, "
"Paul Mundt <[email protected]>");
MODULE_DESCRIPTION("Ricoh RS5C372 RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);

View file

@ -257,12 +257,6 @@ static inline void sh_rtc_setaie(struct device *dev, unsigned int enable)
spin_unlock_irq(&rtc->lock);
}
static void sh_rtc_release(struct device *dev)
{
sh_rtc_setpie(dev, 0);
sh_rtc_setaie(dev, 0);
}
static int sh_rtc_proc(struct device *dev, struct seq_file *seq)
{
struct sh_rtc *rtc = dev_get_drvdata(dev);
@ -559,7 +553,6 @@ static int sh_rtc_irq_set_freq(struct device *dev, int freq)
}
static struct rtc_class_ops sh_rtc_ops = {
.release = sh_rtc_release,
.ioctl = sh_rtc_ioctl,
.read_time = sh_rtc_read_time,
.set_time = sh_rtc_set_time,

120
drivers/rtc/rtc-starfire.c Normal file
View file

@ -0,0 +1,120 @@
/* rtc-starfire.c: Starfire platform RTC driver.
*
* Copyright (C) 2008 David S. Miller <davem@davemloft.net>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <asm/oplib.h>
MODULE_AUTHOR("David S. Miller <[email protected]>");
MODULE_DESCRIPTION("Starfire RTC driver");
MODULE_LICENSE("GPL");
struct starfire_rtc {
struct rtc_device *rtc;
spinlock_t lock;
};
static u32 starfire_get_time(void)
{
static char obp_gettod[32];
static u32 unix_tod;
sprintf(obp_gettod, "h# %08x unix-gettod",
(unsigned int) (long) &unix_tod);
prom_feval(obp_gettod);
return unix_tod;
}
static int starfire_read_time(struct device *dev, struct rtc_time *tm)
{
struct starfire_rtc *p = dev_get_drvdata(dev);
unsigned long flags, secs;
spin_lock_irqsave(&p->lock, flags);
secs = starfire_get_time();
spin_unlock_irqrestore(&p->lock, flags);
rtc_time_to_tm(secs, tm);
return 0;
}
static int starfire_set_time(struct device *dev, struct rtc_time *tm)
{
unsigned long secs;
int err;
err = rtc_tm_to_time(tm, &secs);
if (err)
return err;
/* Do nothing, time is set using the service processor
* console on this platform.
*/
return 0;
}
static const struct rtc_class_ops starfire_rtc_ops = {
.read_time = starfire_read_time,
.set_time = starfire_set_time,
};
static int __devinit starfire_rtc_probe(struct platform_device *pdev)
{
struct starfire_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
spin_lock_init(&p->lock);
p->rtc = rtc_device_register("starfire", &pdev->dev,
&starfire_rtc_ops, THIS_MODULE);
if (IS_ERR(p->rtc)) {
int err = PTR_ERR(p->rtc);
kfree(p);
return err;
}
platform_set_drvdata(pdev, p);
return 0;
}
static int __devexit starfire_rtc_remove(struct platform_device *pdev)
{
struct starfire_rtc *p = platform_get_drvdata(pdev);
rtc_device_unregister(p->rtc);
kfree(p);
return 0;
}
static struct platform_driver starfire_rtc_driver = {
.driver = {
.name = "rtc-starfire",
.owner = THIS_MODULE,
},
.probe = starfire_rtc_probe,
.remove = __devexit_p(starfire_rtc_remove),
};
static int __init starfire_rtc_init(void)
{
return platform_driver_register(&starfire_rtc_driver);
}
static void __exit starfire_rtc_exit(void)
{
platform_driver_unregister(&starfire_rtc_driver);
}
module_init(starfire_rtc_init);
module_exit(starfire_rtc_exit);

View file

@ -215,17 +215,6 @@ static irqreturn_t stk17ta8_rtc_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
static void stk17ta8_rtc_release(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
if (pdata->irq >= 0) {
pdata->irqen = 0;
stk17ta8_rtc_update_alarm(pdata);
}
}
static int stk17ta8_rtc_ioctl(struct device *dev, unsigned int cmd,
unsigned long arg)
{
@ -254,7 +243,6 @@ static const struct rtc_class_ops stk17ta8_rtc_ops = {
.set_time = stk17ta8_rtc_set_time,
.read_alarm = stk17ta8_rtc_read_alarm,
.set_alarm = stk17ta8_rtc_set_alarm,
.release = stk17ta8_rtc_release,
.ioctl = stk17ta8_rtc_ioctl,
};

153
drivers/rtc/rtc-sun4v.c Normal file
View file

@ -0,0 +1,153 @@
/* rtc-sun4c.c: Hypervisor based RTC for SUN4V systems.
*
* Copyright (C) 2008 David S. Miller <davem@davemloft.net>
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/rtc.h>
#include <linux/platform_device.h>
#include <asm/hypervisor.h>
MODULE_AUTHOR("David S. Miller <[email protected]>");
MODULE_DESCRIPTION("SUN4V RTC driver");
MODULE_LICENSE("GPL");
struct sun4v_rtc {
struct rtc_device *rtc;
spinlock_t lock;
};
static unsigned long hypervisor_get_time(void)
{
unsigned long ret, time;
int retries = 10000;
retry:
ret = sun4v_tod_get(&time);
if (ret == HV_EOK)
return time;
if (ret == HV_EWOULDBLOCK) {
if (--retries > 0) {
udelay(100);
goto retry;
}
printk(KERN_WARNING "SUN4V: tod_get() timed out.\n");
return 0;
}
printk(KERN_WARNING "SUN4V: tod_get() not supported.\n");
return 0;
}
static int sun4v_read_time(struct device *dev, struct rtc_time *tm)
{
struct sun4v_rtc *p = dev_get_drvdata(dev);
unsigned long flags, secs;
spin_lock_irqsave(&p->lock, flags);
secs = hypervisor_get_time();
spin_unlock_irqrestore(&p->lock, flags);
rtc_time_to_tm(secs, tm);
return 0;
}
static int hypervisor_set_time(unsigned long secs)
{
unsigned long ret;
int retries = 10000;
retry:
ret = sun4v_tod_set(secs);
if (ret == HV_EOK)
return 0;
if (ret == HV_EWOULDBLOCK) {
if (--retries > 0) {
udelay(100);
goto retry;
}
printk(KERN_WARNING "SUN4V: tod_set() timed out.\n");
return -EAGAIN;
}
printk(KERN_WARNING "SUN4V: tod_set() not supported.\n");
return -EOPNOTSUPP;
}
static int sun4v_set_time(struct device *dev, struct rtc_time *tm)
{
struct sun4v_rtc *p = dev_get_drvdata(dev);
unsigned long flags, secs;
int err;
err = rtc_tm_to_time(tm, &secs);
if (err)
return err;
spin_lock_irqsave(&p->lock, flags);
err = hypervisor_set_time(secs);
spin_unlock_irqrestore(&p->lock, flags);
return err;
}
static const struct rtc_class_ops sun4v_rtc_ops = {
.read_time = sun4v_read_time,
.set_time = sun4v_set_time,
};
static int __devinit sun4v_rtc_probe(struct platform_device *pdev)
{
struct sun4v_rtc *p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p)
return -ENOMEM;
spin_lock_init(&p->lock);
p->rtc = rtc_device_register("sun4v", &pdev->dev,
&sun4v_rtc_ops, THIS_MODULE);
if (IS_ERR(p->rtc)) {
int err = PTR_ERR(p->rtc);
kfree(p);
return err;
}
platform_set_drvdata(pdev, p);
return 0;
}
static int __devexit sun4v_rtc_remove(struct platform_device *pdev)
{
struct sun4v_rtc *p = platform_get_drvdata(pdev);
rtc_device_unregister(p->rtc);
kfree(p);
return 0;
}
static struct platform_driver sun4v_rtc_driver = {
.driver = {
.name = "rtc-sun4v",
.owner = THIS_MODULE,
},
.probe = sun4v_rtc_probe,
.remove = __devexit_p(sun4v_rtc_remove),
};
static int __init sun4v_rtc_init(void)
{
return platform_driver_register(&sun4v_rtc_driver);
}
static void __exit sun4v_rtc_exit(void)
{
platform_driver_unregister(&sun4v_rtc_driver);
}
module_init(sun4v_rtc_init);
module_exit(sun4v_rtc_exit);