mirror of
https://github.com/FEX-Emu/linux.git
synced 2024-12-14 21:01:29 +00:00
RTC for 4.8
Cleanups: - huge cleanup of rtc-generic and char/genrtc this allowed to cleanup rtc-cmos, rtc-sh, rtc-m68k, rtc-powerpc and rtc-parisc - move mn10300 to rtc-cmos Subsystem: - fix wakealarms after hibernate - multiples fixes for rctest - simplify implementations of .read_alarm New drivers: - Maxim MAX6916 Drivers: - ds1307: fix weekday - m41t80: add wakeup support - pcf85063: add support for PCF85063A variant - rv8803: extend i2c fix and other fixes - s35390a: fix alarm reading, this fixes instant reboot after shutdown for QNAP TS-41x - s3c: clock fixes -----BEGIN PGP SIGNATURE----- iQIcBAABCgAGBQJXokhIAAoJENiigzvaE+LCZqQP+wWzintN/N1u3dKiVB7iSdwq +S/jAXD9wW8OK9PI60/YUGRYeUXmZW9t4XYg1VKCxU9KpVC17LgOtDyXD8BufP1V uREJEzZw9O7zCCjeHp/ICFjBkc62Net6ZDOO+ZyXPNfddpS1Xq1uUgXLZc/202UR ID/kewu0pJRDnoxyqznWn9+8D33w/ygXs2slY2Ive0ONtjdgxGcsj2rNbb2RYn2z OP7br3lLg7qkFh4TtXb61eh/9GYIk6wzP/CrX5l/jH4SjQnrIk5g/X/Cd1qQ/qso JZzFoonOKvIp5Gw/+fZ9NP3YFcnkoRMv4NjZV8PAmsYLds+ibRiBcoB8u6FmiJV7 WW5uopgPkfCGN5BV3+QHwJDVe+WlgnlzaT5zPUCcP5KWusDts4fWIgzP7vrtAzf4 3OJLrgSGdBeOqWnJD21nxKUD27JOseX7D+BFtwxR4lMsXHqlHJfETpZ8gts1ZGH3 2U353j/jkZvGWmc6dMcuxOXT2K4VqpYeIIqs0IcLu6hM9crtR89zPR2Iu1AilfDW h2NroF+Q//SgMMzWoTEG6Tn7RAc7MthgA/tRCFZF9CBMzNs988w0CTHnKsIHmjpU UKkMeJGAC9YrPYIcqrg0oYsmLUWXc8JuZbGJBnei3BzbaMTlcwIN9qj36zfq6xWc TMLpbWEoIsgFIZMP/hAP =rpGB -----END PGP SIGNATURE----- Merge tag 'rtc-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux Pull RTC updates from Alexandre Belloni: "RTC for 4.8 Cleanups: - huge cleanup of rtc-generic and char/genrtc this allowed to cleanup rtc-cmos, rtc-sh, rtc-m68k, rtc-powerpc and rtc-parisc - move mn10300 to rtc-cmos Subsystem: - fix wakealarms after hibernate - multiples fixes for rctest - simplify implementations of .read_alarm New drivers: - Maxim MAX6916 Drivers: - ds1307: fix weekday - m41t80: add wakeup support - pcf85063: add support for PCF85063A variant - rv8803: extend i2c fix and other fixes - s35390a: fix alarm reading, this fixes instant reboot after shutdown for QNAP TS-41x - s3c: clock fixes" * tag 'rtc-4.8' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux: (65 commits) rtc: rv8803: Clear V1F when setting the time rtc: rv8803: Stop the clock while setting the time rtc: rv8803: Always apply the I²C workaround rtc: rv8803: Fix read day of week rtc: rv8803: Remove the check for valid time rtc: rv8803: Kconfig: Indicate rx8900 support rtc: asm9260: remove .owner field for driver rtc: at91sam9: Fix missing spin_lock_init() rtc: m41t80: add suspend handlers for alarm IRQ rtc: m41t80: make it a real error message rtc: pcf85063: Add support for the PCF85063A device rtc: pcf85063: fix year range rtc: hym8563: in .read_alarm set .tm_sec to 0 to signal minute accuracy rtc: explicitly set tm_sec = 0 for drivers with minute accurancy rtc: s3c: Add s3c_rtc_{enable/disable}_clk in s3c_rtc_setfreq() rtc: s3c: Remove unnecessary call to disable already disabled clock rtc: abx80x: use devm_add_action_or_reset() rtc: m41t80: use devm_add_action_or_reset() rtc: fix a typo and reduce three empty lines to one rtc: s35390a: improve two comments in .set_alarm ...
This commit is contained in:
commit
6c84239d59
@ -9828,10 +9828,14 @@ L: rtc-linux@googlegroups.com
|
||||
Q: http://patchwork.ozlabs.org/project/rtc-linux/list/
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux.git
|
||||
S: Maintained
|
||||
F: Documentation/devicetree/bindings/rtc/
|
||||
F: Documentation/rtc.txt
|
||||
F: drivers/rtc/
|
||||
F: include/linux/rtc.h
|
||||
F: include/uapi/linux/rtc.h
|
||||
F: include/linux/rtc/
|
||||
F: include/linux/platform_data/rtc-*
|
||||
F: tools/testing/selftests/timers/rtctest.c
|
||||
|
||||
REALTEK AUDIO CODECS
|
||||
M: Bard Liao <bardliao@realtek.com>
|
||||
|
@ -1 +0,0 @@
|
||||
#include <asm-generic/rtc.h>
|
@ -24,7 +24,6 @@
|
||||
#include <asm/gct.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/vga.h>
|
||||
|
||||
#include "proto.h"
|
||||
|
@ -15,8 +15,6 @@
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/rtc.h>
|
||||
|
||||
#include "proto.h"
|
||||
|
||||
|
||||
@ -81,7 +79,7 @@ init_rtc_epoch(void)
|
||||
static int
|
||||
alpha_rtc_read_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
__get_rtc_time(tm);
|
||||
mc146818_get_time(tm);
|
||||
|
||||
/* Adjust for non-default epochs. It's easier to depend on the
|
||||
generic __get_rtc_time and adjust the epoch here than create
|
||||
@ -112,7 +110,7 @@ alpha_rtc_set_time(struct device *dev, struct rtc_time *tm)
|
||||
tm = &xtm;
|
||||
}
|
||||
|
||||
return __set_rtc_time(tm);
|
||||
return mc146818_set_time(tm);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/m48t86.h>
|
||||
#include <linux/platform_data/rtc-m48t86.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mv643xx_eth.h>
|
||||
#include <linux/ata_platform.h>
|
||||
#include <linux/m48t86.h>
|
||||
#include <linux/platform_data/rtc-m48t86.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/timeriomem-rng.h>
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/rtc-v3020.h>
|
||||
#include <linux/platform_data/rtc-v3020.h>
|
||||
#include <video/mbxfb.h>
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/dm9000.h>
|
||||
#include <linux/leds.h>
|
||||
#include <linux/rtc-v3020.h>
|
||||
#include <linux/platform_data/rtc-v3020.h>
|
||||
#include <linux/pwm.h>
|
||||
#include <linux/pwm_backlight.h>
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/dm9000.h>
|
||||
#include <linux/rtc-v3020.h>
|
||||
#include <linux/platform_data/rtc-v3020.h>
|
||||
#include <linux/mtd/nand.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/mtd/physmap.h>
|
||||
|
@ -1,16 +0,0 @@
|
||||
/* mc146818rtc.h: RTC defs
|
||||
*
|
||||
* Copyright (C) 2005 Red Hat, Inc. All Rights Reserved.
|
||||
* Written by David Howells (dhowells@redhat.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_MC146818RTC_H
|
||||
#define _ASM_MC146818RTC_H
|
||||
|
||||
|
||||
#endif /* _ASM_MC146818RTC_H */
|
@ -1,9 +0,0 @@
|
||||
/*
|
||||
* Machine dependent access functions for RTC registers.
|
||||
*/
|
||||
#ifndef _H8300_MC146818RTC_H
|
||||
#define _H8300_MC146818RTC_H
|
||||
|
||||
/* empty include file to satisfy the include in genrtc.c/ide-geometry.c */
|
||||
|
||||
#endif /* _H8300_MC146818RTC_H */
|
@ -1,10 +0,0 @@
|
||||
#ifndef _ASM_IA64_MC146818RTC_H
|
||||
#define _ASM_IA64_MC146818RTC_H
|
||||
|
||||
/*
|
||||
* Machine dependent access functions for RTC registers.
|
||||
*/
|
||||
|
||||
/* empty include file to satisfy the include in genrtc.c */
|
||||
|
||||
#endif /* _ASM_IA64_MC146818RTC_H */
|
@ -35,7 +35,6 @@
|
||||
#include <asm/amigahw.h>
|
||||
#include <asm/amigaints.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/apollohw.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/machdep.h>
|
||||
|
||||
u_long sio01_physaddr;
|
||||
|
@ -34,7 +34,6 @@
|
||||
#include <asm/setup.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/bvme6000hw.h>
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/console.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/bootinfo-hp300.h>
|
||||
@ -20,7 +21,6 @@
|
||||
#include <asm/blinken.h>
|
||||
#include <asm/io.h> /* readb() and writeb() */
|
||||
#include <asm/hp300hw.h>
|
||||
#include <asm/rtc.h>
|
||||
|
||||
#include "time.h"
|
||||
|
||||
|
@ -1,79 +0,0 @@
|
||||
/* include/asm-m68k/rtc.h
|
||||
*
|
||||
* Copyright Richard Zidlicky
|
||||
* implementation details for genrtc/q40rtc driver
|
||||
*/
|
||||
/* permission is hereby granted to copy, modify and redistribute this code
|
||||
* in terms of the GNU Library General Public License, Version 2 or later,
|
||||
* at your option.
|
||||
*/
|
||||
|
||||
#ifndef _ASM_RTC_H
|
||||
#define _ASM_RTC_H
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/rtc.h>
|
||||
#include <asm/errno.h>
|
||||
#include <asm/machdep.h>
|
||||
|
||||
#define RTC_PIE 0x40 /* periodic interrupt enable */
|
||||
#define RTC_AIE 0x20 /* alarm interrupt enable */
|
||||
#define RTC_UIE 0x10 /* update-finished interrupt enable */
|
||||
|
||||
/* some dummy definitions */
|
||||
#define RTC_BATT_BAD 0x100 /* battery bad */
|
||||
#define RTC_SQWE 0x08 /* enable square-wave output */
|
||||
#define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
|
||||
#define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
|
||||
#define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
|
||||
|
||||
static inline unsigned int get_rtc_time(struct rtc_time *time)
|
||||
{
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
if (mach_hwclk)
|
||||
mach_hwclk(0, time);
|
||||
return RTC_24H;
|
||||
}
|
||||
|
||||
static inline int set_rtc_time(struct rtc_time *time)
|
||||
{
|
||||
if (mach_hwclk)
|
||||
return mach_hwclk(1, time);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline unsigned int get_rtc_ss(void)
|
||||
{
|
||||
if (mach_get_ss)
|
||||
return mach_get_ss();
|
||||
else{
|
||||
struct rtc_time h;
|
||||
|
||||
get_rtc_time(&h);
|
||||
return h.tm_sec;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int get_rtc_pll(struct rtc_pll_info *pll)
|
||||
{
|
||||
if (mach_get_rtc_pll)
|
||||
return mach_get_rtc_pll(pll);
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
static inline int set_rtc_pll(struct rtc_pll_info *pll)
|
||||
{
|
||||
if (mach_set_rtc_pll)
|
||||
return mach_set_rtc_pll(pll);
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _ASM__RTC_H */
|
@ -86,7 +86,49 @@ void read_persistent_clock(struct timespec *ts)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ARCH_USES_GETTIMEOFFSET
|
||||
#if defined(CONFIG_ARCH_USES_GETTIMEOFFSET) && IS_ENABLED(CONFIG_RTC_DRV_GENERIC)
|
||||
static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
mach_hwclk(0, tm);
|
||||
return rtc_valid_tm(tm);
|
||||
}
|
||||
|
||||
static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
if (mach_hwclk(1, tm) < 0)
|
||||
return -EOPNOTSUPP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct rtc_pll_info pll;
|
||||
struct rtc_pll_info __user *argp = (void __user *)arg;
|
||||
|
||||
switch (cmd) {
|
||||
case RTC_PLL_GET:
|
||||
if (!mach_get_rtc_pll || mach_get_rtc_pll(&pll))
|
||||
return -EINVAL;
|
||||
return copy_to_user(argp, &pll, sizeof pll) ? -EFAULT : 0;
|
||||
|
||||
case RTC_PLL_SET:
|
||||
if (!mach_set_rtc_pll)
|
||||
return -EINVAL;
|
||||
if (!capable(CAP_SYS_TIME))
|
||||
return -EACCES;
|
||||
if (copy_from_user(&pll, argp, sizeof(pll)))
|
||||
return -EFAULT;
|
||||
return mach_set_rtc_pll(&pll);
|
||||
}
|
||||
|
||||
return -ENOIOCTLCMD;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops generic_rtc_ops = {
|
||||
.ioctl = rtc_ioctl,
|
||||
.read_time = rtc_generic_get_time,
|
||||
.set_time = rtc_generic_set_time,
|
||||
};
|
||||
|
||||
static int __init rtc_init(void)
|
||||
{
|
||||
@ -95,7 +137,9 @@ static int __init rtc_init(void)
|
||||
if (!mach_hwclk)
|
||||
return -ENODEV;
|
||||
|
||||
pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
|
||||
pdev = platform_device_register_data(NULL, "rtc-generic", -1,
|
||||
&generic_rtc_ops,
|
||||
sizeof(generic_rtc_ops));
|
||||
return PTR_ERR_OR_ZERO(pdev);
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
* Miscellaneous linux stuff
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/mm.h>
|
||||
@ -25,6 +26,7 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/adb.h>
|
||||
#include <linux/cuda.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#include <asm/setup.h>
|
||||
#include <asm/bootinfo.h>
|
||||
@ -34,7 +36,6 @@
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/machdep.h>
|
||||
|
||||
#include <asm/macintosh.h>
|
||||
|
@ -18,7 +18,6 @@
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/segment.h>
|
||||
#include <asm/setup.h>
|
||||
#include <asm/macintosh.h>
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include <asm/setup.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/mvme147hw.h>
|
||||
|
||||
|
@ -35,7 +35,6 @@
|
||||
#include <asm/setup.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/mvme16xhw.h>
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
* for more details.
|
||||
*/
|
||||
|
||||
#include <linux/errno.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
@ -27,7 +28,6 @@
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/setup.h>
|
||||
|
@ -26,7 +26,6 @@
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/sun3-head.h>
|
||||
#include <asm/sun3mmu.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/machines.h>
|
||||
#include <asm/idprom.h>
|
||||
|
@ -14,8 +14,8 @@
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#include <asm/errno.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/intersil.h>
|
||||
#include <asm/machdep.h>
|
||||
|
||||
|
||||
/* bits to set for start/run of the intersil */
|
||||
|
@ -15,10 +15,10 @@
|
||||
|
||||
#include <asm/irq.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/sun3x.h>
|
||||
#include <asm/sun3ints.h>
|
||||
#include <asm/rtc.h>
|
||||
|
||||
#include "time.h"
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
*/
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/ds1286.h>
|
||||
#include <linux/rtc/ds1286.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
#include <asm/sni.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm-generic/rtc.h>
|
||||
|
||||
#define SNI_CLOCK_TICK_RATE 3686400
|
||||
#define SNI_COUNTER2_DIV 64
|
||||
|
@ -236,7 +236,9 @@ source "kernel/Kconfig.hz"
|
||||
config MN10300_RTC
|
||||
bool "Using MN10300 RTC"
|
||||
depends on MN10300_PROC_MN103E010 || MN10300_PROC_MN2WS0050
|
||||
select GENERIC_CMOS_UPDATE
|
||||
select RTC_CLASS
|
||||
select RTC_DRV_CMOS
|
||||
select RTC_SYSTOHC
|
||||
default n
|
||||
help
|
||||
This option enables support for the RTC, thus enabling time to be
|
||||
|
@ -75,9 +75,9 @@
|
||||
#define RTC_PORT(x) 0xd8600000
|
||||
#define RTC_ALWAYS_BCD 1 /* RTC operates in binary mode */
|
||||
|
||||
#define CMOS_READ(addr) __SYSREG(0xd8600000 + (addr), u8)
|
||||
#define CMOS_READ(addr) __SYSREG(0xd8600000 + (u32)(addr), u8)
|
||||
#define CMOS_WRITE(val, addr) \
|
||||
do { __SYSREG(0xd8600000 + (addr), u8) = val; } while (0)
|
||||
do { __SYSREG(0xd8600000 + (u32)(addr), u8) = val; } while (0)
|
||||
|
||||
#define RTC_IRQ RTIRQ
|
||||
|
||||
|
@ -25,6 +25,4 @@ static inline void calibrate_clock(void)
|
||||
|
||||
#endif /* !CONFIG_MN10300_RTC */
|
||||
|
||||
#include <asm-generic/rtc.h>
|
||||
|
||||
#endif /* _ASM_RTC_H */
|
||||
|
@ -12,107 +12,19 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/rtc-regs.h>
|
||||
#include <asm/rtc.h>
|
||||
|
||||
DEFINE_SPINLOCK(rtc_lock);
|
||||
EXPORT_SYMBOL(rtc_lock);
|
||||
|
||||
/*
|
||||
* Read the current RTC time
|
||||
*/
|
||||
void read_persistent_clock(struct timespec *ts)
|
||||
{
|
||||
struct rtc_time tm;
|
||||
|
||||
get_rtc_time(&tm);
|
||||
|
||||
ts->tv_nsec = 0;
|
||||
ts->tv_sec = mktime(tm.tm_year, tm.tm_mon, tm.tm_mday,
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec);
|
||||
|
||||
/* if rtc is way off in the past, set something reasonable */
|
||||
if (ts->tv_sec < 0)
|
||||
ts->tv_sec = mktime(2009, 1, 1, 12, 0, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* In order to set the CMOS clock precisely, set_rtc_mmss has to be called 500
|
||||
* ms after the second nowtime has started, because when nowtime is written
|
||||
* into the registers of the CMOS clock, it will jump to the next second
|
||||
* precisely 500 ms later. Check the Motorola MC146818A or Dallas DS12887 data
|
||||
* sheet for details.
|
||||
*
|
||||
* BUG: This routine does not handle hour overflow properly; it just
|
||||
* sets the minutes. Usually you'll only notice that after reboot!
|
||||
*/
|
||||
static int set_rtc_mmss(unsigned long nowtime)
|
||||
{
|
||||
unsigned char save_control, save_freq_select;
|
||||
int retval = 0;
|
||||
int real_seconds, real_minutes, cmos_minutes;
|
||||
|
||||
/* gets recalled with irq locally disabled */
|
||||
spin_lock(&rtc_lock);
|
||||
save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being
|
||||
* set */
|
||||
CMOS_WRITE(save_control | RTC_SET, RTC_CONTROL);
|
||||
|
||||
save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset
|
||||
* prescaler */
|
||||
CMOS_WRITE(save_freq_select | RTC_DIV_RESET2, RTC_FREQ_SELECT);
|
||||
|
||||
cmos_minutes = CMOS_READ(RTC_MINUTES);
|
||||
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
|
||||
cmos_minutes = bcd2bin(cmos_minutes);
|
||||
|
||||
/*
|
||||
* since we're only adjusting minutes and seconds,
|
||||
* don't interfere with hour overflow. This avoids
|
||||
* messing with unknown time zones but requires your
|
||||
* RTC not to be off by more than 15 minutes
|
||||
*/
|
||||
real_seconds = nowtime % 60;
|
||||
real_minutes = nowtime / 60;
|
||||
if (((abs(real_minutes - cmos_minutes) + 15) / 30) & 1)
|
||||
/* correct for half hour time zone */
|
||||
real_minutes += 30;
|
||||
real_minutes %= 60;
|
||||
|
||||
if (abs(real_minutes - cmos_minutes) < 30) {
|
||||
if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD) {
|
||||
real_seconds = bin2bcd(real_seconds);
|
||||
real_minutes = bin2bcd(real_minutes);
|
||||
}
|
||||
CMOS_WRITE(real_seconds, RTC_SECONDS);
|
||||
CMOS_WRITE(real_minutes, RTC_MINUTES);
|
||||
} else {
|
||||
printk_once(KERN_NOTICE
|
||||
"set_rtc_mmss: can't update from %d to %d\n",
|
||||
cmos_minutes, real_minutes);
|
||||
retval = -1;
|
||||
}
|
||||
|
||||
/* The following flags have to be released exactly in this order,
|
||||
* otherwise the DS12887 (popular MC146818A clone with integrated
|
||||
* battery and quartz) will not reset the oscillator and will not
|
||||
* update precisely 500 ms later. You won't find this mentioned in
|
||||
* the Dallas Semiconductor data sheets, but who believes data
|
||||
* sheets anyway ... -- Markus Kuhn
|
||||
*/
|
||||
CMOS_WRITE(save_control, RTC_CONTROL);
|
||||
CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
|
||||
spin_unlock(&rtc_lock);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
int update_persistent_clock(struct timespec now)
|
||||
{
|
||||
return set_rtc_mmss(now.tv_sec);
|
||||
}
|
||||
static const __initdata struct resource res[] = {
|
||||
DEFINE_RES_IO(RTC_PORT(0), RTC_IO_EXTENT),
|
||||
DEFINE_RES_IRQ(RTC_IRQ),
|
||||
};
|
||||
|
||||
/*
|
||||
* calibrate the TSC clock against the RTC
|
||||
@ -129,4 +41,6 @@ void __init calibrate_clock(void)
|
||||
RTCRA |= RTCRA_DVR;
|
||||
RTCRA &= ~RTCRA_DVR;
|
||||
RTCRB &= ~RTCRB_SET;
|
||||
|
||||
platform_device_register_simple("rtc_cmos", -1, res, ARRAY_SIZE(res));
|
||||
}
|
||||
|
@ -9,7 +9,10 @@
|
||||
* 2 of the Licence, or (at your option) any later version.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/irq.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/fpu.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/busctl-regs.h>
|
||||
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/interrupt.h>
|
||||
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/io.h>
|
||||
|
@ -1,9 +0,0 @@
|
||||
/*
|
||||
* Machine dependent access functions for RTC registers.
|
||||
*/
|
||||
#ifndef _ASM_MC146818RTC_H
|
||||
#define _ASM_MC146818RTC_H
|
||||
|
||||
/* empty include file to satisfy the include in genrtc.c */
|
||||
|
||||
#endif /* _ASM_MC146818RTC_H */
|
@ -1,131 +0,0 @@
|
||||
/*
|
||||
* include/asm-parisc/rtc.h
|
||||
*
|
||||
* Copyright 2002 Randolph CHung <tausq@debian.org>
|
||||
*
|
||||
* Based on: include/asm-ppc/rtc.h and the genrtc driver in the
|
||||
* 2.4 parisc linux tree
|
||||
*/
|
||||
|
||||
#ifndef __ASM_RTC_H__
|
||||
#define __ASM_RTC_H__
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#include <asm/pdc.h>
|
||||
|
||||
#define SECS_PER_HOUR (60 * 60)
|
||||
#define SECS_PER_DAY (SECS_PER_HOUR * 24)
|
||||
|
||||
|
||||
#define RTC_PIE 0x40 /* periodic interrupt enable */
|
||||
#define RTC_AIE 0x20 /* alarm interrupt enable */
|
||||
#define RTC_UIE 0x10 /* update-finished interrupt enable */
|
||||
|
||||
#define RTC_BATT_BAD 0x100 /* battery bad */
|
||||
|
||||
/* some dummy definitions */
|
||||
#define RTC_SQWE 0x08 /* enable square-wave output */
|
||||
#define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
|
||||
#define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
|
||||
#define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
|
||||
|
||||
# define __isleap(year) \
|
||||
((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
|
||||
|
||||
/* How many days come before each month (0-12). */
|
||||
static const unsigned short int __mon_yday[2][13] =
|
||||
{
|
||||
/* Normal years. */
|
||||
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
|
||||
/* Leap years. */
|
||||
{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
|
||||
};
|
||||
|
||||
static inline unsigned int get_rtc_time(struct rtc_time *wtime)
|
||||
{
|
||||
struct pdc_tod tod_data;
|
||||
long int days, rem, y;
|
||||
const unsigned short int *ip;
|
||||
|
||||
memset(wtime, 0, sizeof(*wtime));
|
||||
if (pdc_tod_read(&tod_data) < 0)
|
||||
return RTC_24H | RTC_BATT_BAD;
|
||||
|
||||
// most of the remainder of this function is:
|
||||
// Copyright (C) 1991, 1993, 1997, 1998 Free Software Foundation, Inc.
|
||||
// This was originally a part of the GNU C Library.
|
||||
// It is distributed under the GPL, and was swiped from offtime.c
|
||||
|
||||
|
||||
days = tod_data.tod_sec / SECS_PER_DAY;
|
||||
rem = tod_data.tod_sec % SECS_PER_DAY;
|
||||
|
||||
wtime->tm_hour = rem / SECS_PER_HOUR;
|
||||
rem %= SECS_PER_HOUR;
|
||||
wtime->tm_min = rem / 60;
|
||||
wtime->tm_sec = rem % 60;
|
||||
|
||||
y = 1970;
|
||||
|
||||
#define DIV(a, b) ((a) / (b) - ((a) % (b) < 0))
|
||||
#define LEAPS_THRU_END_OF(y) (DIV (y, 4) - DIV (y, 100) + DIV (y, 400))
|
||||
|
||||
while (days < 0 || days >= (__isleap (y) ? 366 : 365))
|
||||
{
|
||||
/* Guess a corrected year, assuming 365 days per year. */
|
||||
long int yg = y + days / 365 - (days % 365 < 0);
|
||||
|
||||
/* Adjust DAYS and Y to match the guessed year. */
|
||||
days -= ((yg - y) * 365
|
||||
+ LEAPS_THRU_END_OF (yg - 1)
|
||||
- LEAPS_THRU_END_OF (y - 1));
|
||||
y = yg;
|
||||
}
|
||||
wtime->tm_year = y - 1900;
|
||||
|
||||
ip = __mon_yday[__isleap(y)];
|
||||
for (y = 11; days < (long int) ip[y]; --y)
|
||||
continue;
|
||||
days -= ip[y];
|
||||
wtime->tm_mon = y;
|
||||
wtime->tm_mday = days + 1;
|
||||
|
||||
return RTC_24H;
|
||||
}
|
||||
|
||||
static int set_rtc_time(struct rtc_time *wtime)
|
||||
{
|
||||
u_int32_t secs;
|
||||
|
||||
secs = mktime(wtime->tm_year + 1900, wtime->tm_mon + 1, wtime->tm_mday,
|
||||
wtime->tm_hour, wtime->tm_min, wtime->tm_sec);
|
||||
|
||||
if(pdc_tod_set(secs, 0) < 0)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static inline unsigned int get_rtc_ss(void)
|
||||
{
|
||||
struct rtc_time h;
|
||||
|
||||
get_rtc_time(&h);
|
||||
return h.tm_sec;
|
||||
}
|
||||
|
||||
static inline int get_rtc_pll(struct rtc_pll_info *pll)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
static inline int set_rtc_pll(struct rtc_pll_info *pll)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* __ASM_RTC_H__ */
|
@ -12,6 +12,7 @@
|
||||
*/
|
||||
#include <linux/errno.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/param.h>
|
||||
@ -248,14 +249,47 @@ void __init start_cpu_itimer(void)
|
||||
per_cpu(cpu_data, cpu).it_value = next_tick;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_RTC_DRV_GENERIC)
|
||||
static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct pdc_tod tod_data;
|
||||
|
||||
memset(tm, 0, sizeof(*tm));
|
||||
if (pdc_tod_read(&tod_data) < 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* we treat tod_sec as unsigned, so this can work until year 2106 */
|
||||
rtc_time64_to_tm(tod_data.tod_sec, tm);
|
||||
return rtc_valid_tm(tm);
|
||||
}
|
||||
|
||||
static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
time64_t secs = rtc_tm_to_time64(tm);
|
||||
|
||||
if (pdc_tod_set(secs, 0) < 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops rtc_generic_ops = {
|
||||
.read_time = rtc_generic_get_time,
|
||||
.set_time = rtc_generic_set_time,
|
||||
};
|
||||
|
||||
static int __init rtc_init(void)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
|
||||
pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
|
||||
pdev = platform_device_register_data(NULL, "rtc-generic", -1,
|
||||
&rtc_generic_ops,
|
||||
sizeof(rtc_generic_ops));
|
||||
|
||||
return PTR_ERR_OR_ZERO(pdev);
|
||||
}
|
||||
device_initcall(rtc_init);
|
||||
#endif
|
||||
|
||||
void read_persistent_clock(struct timespec *ts)
|
||||
{
|
||||
|
@ -1,78 +0,0 @@
|
||||
/*
|
||||
* Real-time clock definitions and interfaces
|
||||
*
|
||||
* Author: Tom Rini <trini@mvista.com>
|
||||
*
|
||||
* 2002 (c) MontaVista, Software, Inc. This file is licensed under
|
||||
* the terms of the GNU General Public License version 2. This program
|
||||
* is licensed "as is" without any warranty of any kind, whether express
|
||||
* or implied.
|
||||
*
|
||||
* Based on:
|
||||
* include/asm-m68k/rtc.h
|
||||
*
|
||||
* Copyright Richard Zidlicky
|
||||
* implementation details for genrtc/q40rtc driver
|
||||
*
|
||||
* And the old drivers/macintosh/rtc.c which was heavily based on:
|
||||
* Linux/SPARC Real Time Clock Driver
|
||||
* Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu)
|
||||
*
|
||||
* With additional work by Paul Mackerras and Franz Sirl.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_POWERPC_RTC_H__
|
||||
#define __ASM_POWERPC_RTC_H__
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#include <asm/machdep.h>
|
||||
#include <asm/time.h>
|
||||
|
||||
#define RTC_PIE 0x40 /* periodic interrupt enable */
|
||||
#define RTC_AIE 0x20 /* alarm interrupt enable */
|
||||
#define RTC_UIE 0x10 /* update-finished interrupt enable */
|
||||
|
||||
/* some dummy definitions */
|
||||
#define RTC_BATT_BAD 0x100 /* battery bad */
|
||||
#define RTC_SQWE 0x08 /* enable square-wave output */
|
||||
#define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
|
||||
#define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
|
||||
#define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
|
||||
|
||||
static inline unsigned int get_rtc_time(struct rtc_time *time)
|
||||
{
|
||||
if (ppc_md.get_rtc_time)
|
||||
ppc_md.get_rtc_time(time);
|
||||
return RTC_24H;
|
||||
}
|
||||
|
||||
/* Set the current date and time in the real time clock. */
|
||||
static inline int set_rtc_time(struct rtc_time *time)
|
||||
{
|
||||
if (ppc_md.set_rtc_time)
|
||||
return ppc_md.set_rtc_time(time);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static inline unsigned int get_rtc_ss(void)
|
||||
{
|
||||
struct rtc_time h;
|
||||
|
||||
get_rtc_time(&h);
|
||||
return h.tm_sec;
|
||||
}
|
||||
|
||||
static inline int get_rtc_pll(struct rtc_pll_info *pll)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
static inline int set_rtc_pll(struct rtc_pll_info *pll)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif /* __ASM_POWERPC_RTC_H__ */
|
@ -56,6 +56,7 @@
|
||||
#include <linux/irq_work.h>
|
||||
#include <linux/clk-provider.h>
|
||||
#include <linux/suspend.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <asm/trace.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
@ -1159,6 +1160,29 @@ void calibrate_delay(void)
|
||||
loops_per_jiffy = tb_ticks_per_jiffy;
|
||||
}
|
||||
|
||||
#if IS_ENABLED(CONFIG_RTC_DRV_GENERIC)
|
||||
static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
ppc_md.get_rtc_time(tm);
|
||||
return rtc_valid_tm(tm);
|
||||
}
|
||||
|
||||
static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
if (!ppc_md.set_rtc_time)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (ppc_md.set_rtc_time(tm) < 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops rtc_generic_ops = {
|
||||
.read_time = rtc_generic_get_time,
|
||||
.set_time = rtc_generic_set_time,
|
||||
};
|
||||
|
||||
static int __init rtc_init(void)
|
||||
{
|
||||
struct platform_device *pdev;
|
||||
@ -1166,9 +1190,12 @@ static int __init rtc_init(void)
|
||||
if (!ppc_md.get_rtc_time)
|
||||
return -ENODEV;
|
||||
|
||||
pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
|
||||
pdev = platform_device_register_data(NULL, "rtc-generic", -1,
|
||||
&rtc_generic_ops,
|
||||
sizeof(rtc_generic_ops));
|
||||
|
||||
return PTR_ERR_OR_ZERO(pdev);
|
||||
}
|
||||
|
||||
device_initcall(rtc_init);
|
||||
#endif
|
||||
|
@ -321,6 +321,17 @@ config OF_RTC
|
||||
Uses information from the OF or flattened device tree to instantiate
|
||||
platform devices for direct mapped RTC chips like the DS1742 or DS1743.
|
||||
|
||||
config GEN_RTC
|
||||
bool "Use the platform RTC operations from user space"
|
||||
select RTC_CLASS
|
||||
select RTC_DRV_GENERIC
|
||||
help
|
||||
This option provides backwards compatibility with the old gen_rtc.ko
|
||||
module that was traditionally used for old PowerPC machines.
|
||||
Platforms should migrate to enabling the RTC_DRV_GENERIC by hand
|
||||
replacing their get_rtc_time/set_rtc_time callbacks with
|
||||
a proper RTC device driver.
|
||||
|
||||
config SIMPLE_GPIO
|
||||
bool "Support for simple, memory-mapped GPIO controllers"
|
||||
depends on PPC
|
||||
|
@ -20,9 +20,9 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#include <asm/firmware.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/lv1call.h>
|
||||
#include <asm/ps3.h>
|
||||
|
||||
|
@ -1,7 +0,0 @@
|
||||
/*
|
||||
* Machine dependent access functions for RTC registers.
|
||||
*/
|
||||
#ifndef _ASM_MC146818RTC_H
|
||||
#define _ASM_MC146818RTC_H
|
||||
|
||||
#endif /* _ASM_MC146818RTC_H */
|
@ -6,17 +6,6 @@ extern void (*board_time_init)(void);
|
||||
extern void (*rtc_sh_get_time)(struct timespec *);
|
||||
extern int (*rtc_sh_set_time)(const time_t);
|
||||
|
||||
/* some dummy definitions */
|
||||
#define RTC_BATT_BAD 0x100 /* battery bad */
|
||||
#define RTC_SQWE 0x08 /* enable square-wave output */
|
||||
#define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
|
||||
#define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
|
||||
#define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
|
||||
|
||||
struct rtc_time;
|
||||
unsigned int get_rtc_time(struct rtc_time *);
|
||||
int set_rtc_time(struct rtc_time *);
|
||||
|
||||
#define RTC_CAP_4_DIGIT_YEAR (1 << 0)
|
||||
|
||||
struct sh_rtc_platform_info {
|
||||
|
@ -50,27 +50,31 @@ int update_persistent_clock(struct timespec now)
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned int get_rtc_time(struct rtc_time *tm)
|
||||
static int rtc_generic_get_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
if (rtc_sh_get_time != null_rtc_get_time) {
|
||||
struct timespec tv;
|
||||
struct timespec tv;
|
||||
|
||||
rtc_sh_get_time(&tv);
|
||||
rtc_time_to_tm(tv.tv_sec, tm);
|
||||
}
|
||||
|
||||
return RTC_24H;
|
||||
rtc_sh_get_time(&tv);
|
||||
rtc_time_to_tm(tv.tv_sec, tm);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(get_rtc_time);
|
||||
|
||||
int set_rtc_time(struct rtc_time *tm)
|
||||
static int rtc_generic_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
unsigned long secs;
|
||||
|
||||
rtc_tm_to_time(tm, &secs);
|
||||
return rtc_sh_set_time(secs);
|
||||
if ((rtc_sh_set_time == null_rtc_set_time) ||
|
||||
(rtc_sh_set_time(secs) < 0))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(set_rtc_time);
|
||||
|
||||
static const struct rtc_class_ops rtc_generic_ops = {
|
||||
.read_time = rtc_generic_get_time,
|
||||
.set_time = rtc_generic_set_time,
|
||||
};
|
||||
|
||||
static int __init rtc_generic_init(void)
|
||||
{
|
||||
@ -79,7 +83,10 @@ static int __init rtc_generic_init(void)
|
||||
if (rtc_sh_get_time == null_rtc_get_time)
|
||||
return -ENODEV;
|
||||
|
||||
pdev = platform_device_register_simple("rtc-generic", -1, NULL, 0);
|
||||
pdev = platform_device_register_data(NULL, "rtc-generic", -1,
|
||||
&rtc_generic_ops,
|
||||
sizeof(rtc_generic_ops));
|
||||
|
||||
|
||||
return PTR_ERR_OR_ZERO(pdev);
|
||||
}
|
||||
|
@ -140,16 +140,6 @@ void ioport_unmap(void __iomem *);
|
||||
struct pci_dev;
|
||||
void pci_iounmap(struct pci_dev *dev, void __iomem *);
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* At the moment, we do not use CMOS_READ anywhere outside of rtc.c,
|
||||
* so rtc_port is static in it. This should not change unless a new
|
||||
* hardware pops up.
|
||||
*/
|
||||
#define RTC_PORT(x) (rtc_port + (x))
|
||||
#define RTC_ALWAYS_BCD 0
|
||||
|
||||
static inline int sbus_can_dma_64bit(void)
|
||||
{
|
||||
return 0; /* actually, sparc_cpu_model==sun4d */
|
||||
|
@ -152,6 +152,7 @@ config X86
|
||||
select OLD_SIGSUSPEND3 if X86_32 || IA32_EMULATION
|
||||
select PERF_EVENTS
|
||||
select RTC_LIB
|
||||
select RTC_MC146818_LIB
|
||||
select SPARSE_IRQ
|
||||
select SRCU
|
||||
select SYSCTL_EXCEPTION_TRACE
|
||||
|
@ -6,7 +6,6 @@
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/processor.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
#ifndef RTC_PORT
|
||||
#define RTC_PORT(x) (0x70 + (x))
|
||||
|
@ -1 +0,0 @@
|
||||
#include <asm-generic/rtc.h>
|
@ -1019,7 +1019,6 @@ void hpet_disable(void)
|
||||
*/
|
||||
#include <linux/mc146818rtc.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <asm/rtc.h>
|
||||
|
||||
#define DEFAULT_RTC_INT_FREQ 64
|
||||
#define DEFAULT_RTC_SHIFT 6
|
||||
@ -1243,7 +1242,7 @@ irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id)
|
||||
memset(&curr_time, 0, sizeof(struct rtc_time));
|
||||
|
||||
if (hpet_rtc_flags & (RTC_UIE | RTC_AIE))
|
||||
get_rtc_time(&curr_time);
|
||||
mc146818_set_time(&curr_time);
|
||||
|
||||
if (hpet_rtc_flags & RTC_UIE &&
|
||||
curr_time.tm_sec != hpet_prev_update_sec) {
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <linux/ratelimit.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include <asm/x86_init.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/intel-mid.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
#ifdef CONFIG_X86_32
|
||||
@ -47,7 +46,7 @@ int mach_set_rtc_mmss(const struct timespec *now)
|
||||
|
||||
rtc_time_to_tm(nowtime, &tm);
|
||||
if (!rtc_valid_tm(&tm)) {
|
||||
retval = set_rtc_time(&tm);
|
||||
retval = mc146818_set_time(&tm);
|
||||
if (retval)
|
||||
printk(KERN_ERR "%s: RTC write failed with error %d\n",
|
||||
__func__, retval);
|
||||
|
@ -51,7 +51,6 @@
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/tlbflush.h>
|
||||
#include <asm/x86_init.h>
|
||||
#include <asm/rtc.h>
|
||||
#include <asm/uv/uv.h>
|
||||
|
||||
static struct efi efi_phys __initdata;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
#include <linux/efi.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/io.h>
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/sfi.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
#include <asm/intel-mid.h>
|
||||
#include <asm/intel_mid_vrtc.h>
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include <linux/err.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm-generic/rtc.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
|
@ -11,7 +11,7 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#include <asm/rtc.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
#include "power.h"
|
||||
|
||||
@ -103,7 +103,7 @@ static int set_magic_time(unsigned int user, unsigned int file, unsigned int dev
|
||||
n /= 24;
|
||||
time.tm_min = (n % 20) * 3;
|
||||
n /= 20;
|
||||
set_rtc_time(&time);
|
||||
mc146818_set_time(&time);
|
||||
return n ? -1 : 0;
|
||||
}
|
||||
|
||||
@ -112,7 +112,7 @@ static unsigned int read_magic_time(void)
|
||||
struct rtc_time time;
|
||||
unsigned int val;
|
||||
|
||||
get_rtc_time(&time);
|
||||
mc146818_get_time(&time);
|
||||
pr_info("RTC time: %2d:%02d:%02d, date: %02d/%02d/%02d\n",
|
||||
time.tm_hour, time.tm_min, time.tm_sec,
|
||||
time.tm_mon + 1, time.tm_mday, time.tm_year % 100);
|
||||
|
@ -293,7 +293,7 @@ if RTC_LIB=n
|
||||
|
||||
config RTC
|
||||
tristate "Enhanced Real Time Clock Support (legacy PC RTC driver)"
|
||||
depends on ALPHA || (MIPS && MACH_LOONGSON64) || MN10300
|
||||
depends on ALPHA || (MIPS && MACH_LOONGSON64)
|
||||
---help---
|
||||
If you say Y here and create a character special file /dev/rtc with
|
||||
major number 10 and minor number 135 using mknod ("man mknod"), you
|
||||
@ -339,32 +339,6 @@ config JS_RTC
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called js-rtc.
|
||||
|
||||
config GEN_RTC
|
||||
tristate "Generic /dev/rtc emulation"
|
||||
depends on RTC!=y
|
||||
depends on ALPHA || M68K || MN10300 || PARISC || PPC || X86
|
||||
---help---
|
||||
If you say Y here and create a character special file /dev/rtc with
|
||||
major number 10 and minor number 135 using mknod ("man mknod"), you
|
||||
will get access to the real time clock (or hardware clock) built
|
||||
into your computer.
|
||||
|
||||
It reports status information via the file /proc/driver/rtc and its
|
||||
behaviour is set by various ioctls on /dev/rtc. If you enable the
|
||||
"extended RTC operation" below it will also provide an emulation
|
||||
for RTC_UIE which is required by some programs and may improve
|
||||
precision in some cases.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called genrtc.
|
||||
|
||||
config GEN_RTC_X
|
||||
bool "Extended RTC operation"
|
||||
depends on GEN_RTC
|
||||
help
|
||||
Provides an emulation for RTC_UIE which is required by some programs
|
||||
and may improve precision of the generic RTC support in some cases.
|
||||
|
||||
config EFI_RTC
|
||||
bool "EFI Real Time Clock Services"
|
||||
depends on IA64
|
||||
|
@ -25,7 +25,6 @@ obj-$(CONFIG_APPLICOM) += applicom.o
|
||||
obj-$(CONFIG_SONYPI) += sonypi.o
|
||||
obj-$(CONFIG_RTC) += rtc.o
|
||||
obj-$(CONFIG_HPET) += hpet.o
|
||||
obj-$(CONFIG_GEN_RTC) += genrtc.o
|
||||
obj-$(CONFIG_EFI_RTC) += efirtc.o
|
||||
obj-$(CONFIG_DS1302) += ds1302.o
|
||||
obj-$(CONFIG_XILINX_HWICAP) += xilinx_hwicap/
|
||||
|
@ -1,539 +0,0 @@
|
||||
/*
|
||||
* Real Time Clock interface for
|
||||
* - q40 and other m68k machines,
|
||||
* - HP PARISC machines
|
||||
* - PowerPC machines
|
||||
* emulate some RTC irq capabilities in software
|
||||
*
|
||||
* Copyright (C) 1999 Richard Zidlicky
|
||||
*
|
||||
* based on Paul Gortmaker's rtc.c device and
|
||||
* Sam Creasey Generic rtc driver
|
||||
*
|
||||
* This driver allows use of the real time clock (built into
|
||||
* nearly all computers) from user space. It exports the /dev/rtc
|
||||
* interface supporting various ioctl() and also the /proc/driver/rtc
|
||||
* pseudo-file for status information.
|
||||
*
|
||||
* The ioctls can be used to set the interrupt behaviour where
|
||||
* supported.
|
||||
*
|
||||
* The /dev/rtc interface will block on reads until an interrupt
|
||||
* has been received. If a RTC interrupt has already happened,
|
||||
* it will output an unsigned long and then block. The output value
|
||||
* contains the interrupt status in the low byte and the number of
|
||||
* interrupts since the last read in the remaining high bytes. The
|
||||
* /dev/rtc interface can also be used with the select(2) call.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
|
||||
* 1.01 fix for 2.3.X rz@linux-m68k.org
|
||||
* 1.02 merged with code from genrtc.c rz@linux-m68k.org
|
||||
* 1.03 make it more portable zippel@linux-m68k.org
|
||||
* 1.04 removed useless timer code rz@linux-m68k.org
|
||||
* 1.05 portable RTC_UIE emulation rz@linux-m68k.org
|
||||
* 1.06 set_rtc_time can return an error trini@kernel.crashing.org
|
||||
* 1.07 ported to HP PARISC (hppa) Helge Deller <deller@gmx.de>
|
||||
*/
|
||||
|
||||
#define RTC_VERSION "1.07"
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/miscdevice.h>
|
||||
#include <linux/fcntl.h>
|
||||
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/rtc.h>
|
||||
|
||||
/*
|
||||
* We sponge a minor off of the misc major. No need slurping
|
||||
* up another valuable major dev number for this. If you add
|
||||
* an ioctl, make sure you don't conflict with SPARC's RTC
|
||||
* ioctls.
|
||||
*/
|
||||
|
||||
static DEFINE_MUTEX(gen_rtc_mutex);
|
||||
static DECLARE_WAIT_QUEUE_HEAD(gen_rtc_wait);
|
||||
|
||||
/*
|
||||
* Bits in gen_rtc_status.
|
||||
*/
|
||||
|
||||
#define RTC_IS_OPEN 0x01 /* means /dev/rtc is in use */
|
||||
|
||||
static unsigned char gen_rtc_status; /* bitmapped status byte. */
|
||||
static unsigned long gen_rtc_irq_data; /* our output to the world */
|
||||
|
||||
/* months start at 0 now */
|
||||
static unsigned char days_in_mo[] =
|
||||
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
|
||||
|
||||
static int irq_active;
|
||||
|
||||
#ifdef CONFIG_GEN_RTC_X
|
||||
static struct work_struct genrtc_task;
|
||||
static struct timer_list timer_task;
|
||||
|
||||
static unsigned int oldsecs;
|
||||
static int lostint;
|
||||
static unsigned long tt_exp;
|
||||
|
||||
static void gen_rtc_timer(unsigned long data);
|
||||
|
||||
static volatile int stask_active; /* schedule_work */
|
||||
static volatile int ttask_active; /* timer_task */
|
||||
static int stop_rtc_timers; /* don't requeue tasks */
|
||||
static DEFINE_SPINLOCK(gen_rtc_lock);
|
||||
|
||||
static void gen_rtc_interrupt(unsigned long arg);
|
||||
|
||||
/*
|
||||
* Routine to poll RTC seconds field for change as often as possible,
|
||||
* after first RTC_UIE use timer to reduce polling
|
||||
*/
|
||||
static void genrtc_troutine(struct work_struct *work)
|
||||
{
|
||||
unsigned int tmp = get_rtc_ss();
|
||||
|
||||
if (stop_rtc_timers) {
|
||||
stask_active = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (oldsecs != tmp){
|
||||
oldsecs = tmp;
|
||||
|
||||
timer_task.function = gen_rtc_timer;
|
||||
timer_task.expires = jiffies + HZ - (HZ/10);
|
||||
tt_exp=timer_task.expires;
|
||||
ttask_active=1;
|
||||
stask_active=0;
|
||||
add_timer(&timer_task);
|
||||
|
||||
gen_rtc_interrupt(0);
|
||||
} else if (schedule_work(&genrtc_task) == 0)
|
||||
stask_active = 0;
|
||||
}
|
||||
|
||||
static void gen_rtc_timer(unsigned long data)
|
||||
{
|
||||
lostint = get_rtc_ss() - oldsecs ;
|
||||
if (lostint<0)
|
||||
lostint = 60 - lostint;
|
||||
if (time_after(jiffies, tt_exp))
|
||||
printk(KERN_INFO "genrtc: timer task delayed by %ld jiffies\n",
|
||||
jiffies-tt_exp);
|
||||
ttask_active=0;
|
||||
stask_active=1;
|
||||
if ((schedule_work(&genrtc_task) == 0))
|
||||
stask_active = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* call gen_rtc_interrupt function to signal an RTC_UIE,
|
||||
* arg is unused.
|
||||
* Could be invoked either from a real interrupt handler or
|
||||
* from some routine that periodically (eg 100HZ) monitors
|
||||
* whether RTC_SECS changed
|
||||
*/
|
||||
static void gen_rtc_interrupt(unsigned long arg)
|
||||
{
|
||||
/* We store the status in the low byte and the number of
|
||||
* interrupts received since the last read in the remainder
|
||||
* of rtc_irq_data. */
|
||||
|
||||
gen_rtc_irq_data += 0x100;
|
||||
gen_rtc_irq_data &= ~0xff;
|
||||
gen_rtc_irq_data |= RTC_UIE;
|
||||
|
||||
if (lostint){
|
||||
printk("genrtc: system delaying clock ticks?\n");
|
||||
/* increment count so that userspace knows something is wrong */
|
||||
gen_rtc_irq_data += ((lostint-1)<<8);
|
||||
lostint = 0;
|
||||
}
|
||||
|
||||
wake_up_interruptible(&gen_rtc_wait);
|
||||
}
|
||||
|
||||
/*
|
||||
* Now all the various file operations that we export.
|
||||
*/
|
||||
static ssize_t gen_rtc_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
unsigned long data;
|
||||
ssize_t retval;
|
||||
|
||||
if (count != sizeof (unsigned int) && count != sizeof (unsigned long))
|
||||
return -EINVAL;
|
||||
|
||||
if (file->f_flags & O_NONBLOCK && !gen_rtc_irq_data)
|
||||
return -EAGAIN;
|
||||
|
||||
retval = wait_event_interruptible(gen_rtc_wait,
|
||||
(data = xchg(&gen_rtc_irq_data, 0)));
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
/* first test allows optimizer to nuke this case for 32-bit machines */
|
||||
if (sizeof (int) != sizeof (long) && count == sizeof (unsigned int)) {
|
||||
unsigned int uidata = data;
|
||||
retval = put_user(uidata, (unsigned int __user *)buf) ?:
|
||||
sizeof(unsigned int);
|
||||
}
|
||||
else {
|
||||
retval = put_user(data, (unsigned long __user *)buf) ?:
|
||||
sizeof(unsigned long);
|
||||
}
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static unsigned int gen_rtc_poll(struct file *file,
|
||||
struct poll_table_struct *wait)
|
||||
{
|
||||
poll_wait(file, &gen_rtc_wait, wait);
|
||||
if (gen_rtc_irq_data != 0)
|
||||
return POLLIN | POLLRDNORM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Used to disable/enable interrupts, only RTC_UIE supported
|
||||
* We also clear out any old irq data after an ioctl() that
|
||||
* meddles with the interrupt enable/disable bits.
|
||||
*/
|
||||
|
||||
static inline void gen_clear_rtc_irq_bit(unsigned char bit)
|
||||
{
|
||||
#ifdef CONFIG_GEN_RTC_X
|
||||
stop_rtc_timers = 1;
|
||||
if (ttask_active){
|
||||
del_timer_sync(&timer_task);
|
||||
ttask_active = 0;
|
||||
}
|
||||
while (stask_active)
|
||||
schedule();
|
||||
|
||||
spin_lock(&gen_rtc_lock);
|
||||
irq_active = 0;
|
||||
spin_unlock(&gen_rtc_lock);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int gen_set_rtc_irq_bit(unsigned char bit)
|
||||
{
|
||||
#ifdef CONFIG_GEN_RTC_X
|
||||
spin_lock(&gen_rtc_lock);
|
||||
if ( !irq_active ) {
|
||||
irq_active = 1;
|
||||
stop_rtc_timers = 0;
|
||||
lostint = 0;
|
||||
INIT_WORK(&genrtc_task, genrtc_troutine);
|
||||
oldsecs = get_rtc_ss();
|
||||
init_timer(&timer_task);
|
||||
|
||||
stask_active = 1;
|
||||
if (schedule_work(&genrtc_task) == 0){
|
||||
stask_active = 0;
|
||||
}
|
||||
}
|
||||
spin_unlock(&gen_rtc_lock);
|
||||
gen_rtc_irq_data = 0;
|
||||
return 0;
|
||||
#else
|
||||
return -EINVAL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int gen_rtc_ioctl(struct file *file,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct rtc_time wtime;
|
||||
struct rtc_pll_info pll;
|
||||
void __user *argp = (void __user *)arg;
|
||||
|
||||
switch (cmd) {
|
||||
|
||||
case RTC_PLL_GET:
|
||||
if (get_rtc_pll(&pll))
|
||||
return -EINVAL;
|
||||
else
|
||||
return copy_to_user(argp, &pll, sizeof pll) ? -EFAULT : 0;
|
||||
|
||||
case RTC_PLL_SET:
|
||||
if (!capable(CAP_SYS_TIME))
|
||||
return -EACCES;
|
||||
if (copy_from_user(&pll, argp, sizeof(pll)))
|
||||
return -EFAULT;
|
||||
return set_rtc_pll(&pll);
|
||||
|
||||
case RTC_UIE_OFF: /* disable ints from RTC updates. */
|
||||
gen_clear_rtc_irq_bit(RTC_UIE);
|
||||
return 0;
|
||||
|
||||
case RTC_UIE_ON: /* enable ints for RTC updates. */
|
||||
return gen_set_rtc_irq_bit(RTC_UIE);
|
||||
|
||||
case RTC_RD_TIME: /* Read the time/date from RTC */
|
||||
/* this doesn't get week-day, who cares */
|
||||
memset(&wtime, 0, sizeof(wtime));
|
||||
get_rtc_time(&wtime);
|
||||
|
||||
return copy_to_user(argp, &wtime, sizeof(wtime)) ? -EFAULT : 0;
|
||||
|
||||
case RTC_SET_TIME: /* Set the RTC */
|
||||
{
|
||||
int year;
|
||||
unsigned char leap_yr;
|
||||
|
||||
if (!capable(CAP_SYS_TIME))
|
||||
return -EACCES;
|
||||
|
||||
if (copy_from_user(&wtime, argp, sizeof(wtime)))
|
||||
return -EFAULT;
|
||||
|
||||
year = wtime.tm_year + 1900;
|
||||
leap_yr = ((!(year % 4) && (year % 100)) ||
|
||||
!(year % 400));
|
||||
|
||||
if ((wtime.tm_mon < 0 || wtime.tm_mon > 11) || (wtime.tm_mday < 1))
|
||||
return -EINVAL;
|
||||
|
||||
if (wtime.tm_mday < 0 || wtime.tm_mday >
|
||||
(days_in_mo[wtime.tm_mon] + ((wtime.tm_mon == 1) && leap_yr)))
|
||||
return -EINVAL;
|
||||
|
||||
if (wtime.tm_hour < 0 || wtime.tm_hour >= 24 ||
|
||||
wtime.tm_min < 0 || wtime.tm_min >= 60 ||
|
||||
wtime.tm_sec < 0 || wtime.tm_sec >= 60)
|
||||
return -EINVAL;
|
||||
|
||||
return set_rtc_time(&wtime);
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static long gen_rtc_unlocked_ioctl(struct file *file, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&gen_rtc_mutex);
|
||||
ret = gen_rtc_ioctl(file, cmd, arg);
|
||||
mutex_unlock(&gen_rtc_mutex);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* We enforce only one user at a time here with the open/close.
|
||||
* Also clear the previous interrupt data on an open, and clean
|
||||
* up things on a close.
|
||||
*/
|
||||
|
||||
static int gen_rtc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
mutex_lock(&gen_rtc_mutex);
|
||||
if (gen_rtc_status & RTC_IS_OPEN) {
|
||||
mutex_unlock(&gen_rtc_mutex);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
gen_rtc_status |= RTC_IS_OPEN;
|
||||
gen_rtc_irq_data = 0;
|
||||
irq_active = 0;
|
||||
mutex_unlock(&gen_rtc_mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gen_rtc_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
/*
|
||||
* Turn off all interrupts once the device is no longer
|
||||
* in use and clear the data.
|
||||
*/
|
||||
|
||||
gen_clear_rtc_irq_bit(RTC_PIE|RTC_AIE|RTC_UIE);
|
||||
|
||||
gen_rtc_status &= ~RTC_IS_OPEN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
/*
|
||||
* Info exported via "/proc/driver/rtc".
|
||||
*/
|
||||
|
||||
static int gen_rtc_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct rtc_time tm;
|
||||
unsigned int flags;
|
||||
struct rtc_pll_info pll;
|
||||
|
||||
flags = get_rtc_time(&tm);
|
||||
|
||||
seq_printf(m,
|
||||
"rtc_time\t: %02d:%02d:%02d\n"
|
||||
"rtc_date\t: %04d-%02d-%02d\n"
|
||||
"rtc_epoch\t: %04u\n",
|
||||
tm.tm_hour, tm.tm_min, tm.tm_sec,
|
||||
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, 1900);
|
||||
|
||||
tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
|
||||
|
||||
seq_puts(m, "alarm\t\t: ");
|
||||
if (tm.tm_hour <= 24)
|
||||
seq_printf(m, "%02d:", tm.tm_hour);
|
||||
else
|
||||
seq_puts(m, "**:");
|
||||
|
||||
if (tm.tm_min <= 59)
|
||||
seq_printf(m, "%02d:", tm.tm_min);
|
||||
else
|
||||
seq_puts(m, "**:");
|
||||
|
||||
if (tm.tm_sec <= 59)
|
||||
seq_printf(m, "%02d\n", tm.tm_sec);
|
||||
else
|
||||
seq_puts(m, "**\n");
|
||||
|
||||
seq_printf(m,
|
||||
"DST_enable\t: %s\n"
|
||||
"BCD\t\t: %s\n"
|
||||
"24hr\t\t: %s\n"
|
||||
"square_wave\t: %s\n"
|
||||
"alarm_IRQ\t: %s\n"
|
||||
"update_IRQ\t: %s\n"
|
||||
"periodic_IRQ\t: %s\n"
|
||||
"periodic_freq\t: %ld\n"
|
||||
"batt_status\t: %s\n",
|
||||
(flags & RTC_DST_EN) ? "yes" : "no",
|
||||
(flags & RTC_DM_BINARY) ? "no" : "yes",
|
||||
(flags & RTC_24H) ? "yes" : "no",
|
||||
(flags & RTC_SQWE) ? "yes" : "no",
|
||||
(flags & RTC_AIE) ? "yes" : "no",
|
||||
irq_active ? "yes" : "no",
|
||||
(flags & RTC_PIE) ? "yes" : "no",
|
||||
0L /* freq */,
|
||||
(flags & RTC_BATT_BAD) ? "bad" : "okay");
|
||||
if (!get_rtc_pll(&pll))
|
||||
seq_printf(m,
|
||||
"PLL adjustment\t: %d\n"
|
||||
"PLL max +ve adjustment\t: %d\n"
|
||||
"PLL max -ve adjustment\t: %d\n"
|
||||
"PLL +ve adjustment factor\t: %d\n"
|
||||
"PLL -ve adjustment factor\t: %d\n"
|
||||
"PLL frequency\t: %ld\n",
|
||||
pll.pll_value,
|
||||
pll.pll_max,
|
||||
pll.pll_min,
|
||||
pll.pll_posmult,
|
||||
pll.pll_negmult,
|
||||
pll.pll_clock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int gen_rtc_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, gen_rtc_proc_show, NULL);
|
||||
}
|
||||
|
||||
static const struct file_operations gen_rtc_proc_fops = {
|
||||
.open = gen_rtc_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static int __init gen_rtc_proc_init(void)
|
||||
{
|
||||
struct proc_dir_entry *r;
|
||||
|
||||
r = proc_create("driver/rtc", 0, NULL, &gen_rtc_proc_fops);
|
||||
if (!r)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int gen_rtc_proc_init(void) { return 0; }
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
|
||||
/*
|
||||
* The various file operations we support.
|
||||
*/
|
||||
|
||||
static const struct file_operations gen_rtc_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
#ifdef CONFIG_GEN_RTC_X
|
||||
.read = gen_rtc_read,
|
||||
.poll = gen_rtc_poll,
|
||||
#endif
|
||||
.unlocked_ioctl = gen_rtc_unlocked_ioctl,
|
||||
.open = gen_rtc_open,
|
||||
.release = gen_rtc_release,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
static struct miscdevice rtc_gen_dev =
|
||||
{
|
||||
.minor = RTC_MINOR,
|
||||
.name = "rtc",
|
||||
.fops = &gen_rtc_fops,
|
||||
};
|
||||
|
||||
static int __init rtc_generic_init(void)
|
||||
{
|
||||
int retval;
|
||||
|
||||
printk(KERN_INFO "Generic RTC Driver v%s\n", RTC_VERSION);
|
||||
|
||||
retval = misc_register(&rtc_gen_dev);
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
retval = gen_rtc_proc_init();
|
||||
if (retval) {
|
||||
misc_deregister(&rtc_gen_dev);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __exit rtc_generic_exit(void)
|
||||
{
|
||||
remove_proc_entry ("driver/rtc", NULL);
|
||||
misc_deregister(&rtc_gen_dev);
|
||||
}
|
||||
|
||||
|
||||
module_init(rtc_generic_init);
|
||||
module_exit(rtc_generic_exit);
|
||||
|
||||
MODULE_AUTHOR("Richard Zidlicky");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_ALIAS_MISCDEV(RTC_MINOR);
|
@ -5,6 +5,10 @@
|
||||
config RTC_LIB
|
||||
bool
|
||||
|
||||
config RTC_MC146818_LIB
|
||||
bool
|
||||
select RTC_LIB
|
||||
|
||||
menuconfig RTC_CLASS
|
||||
bool "Real Time Clock"
|
||||
default n
|
||||
@ -574,10 +578,10 @@ config RTC_DRV_EM3027
|
||||
will be called rtc-em3027.
|
||||
|
||||
config RTC_DRV_RV8803
|
||||
tristate "Micro Crystal RV8803"
|
||||
tristate "Micro Crystal RV8803, Epson RX8900"
|
||||
help
|
||||
If you say yes here you get support for the Micro Crystal
|
||||
RV8803 RTC chips.
|
||||
If you say yes here you get support for the Micro Crystal RV8803 and
|
||||
Epson RX8900 RTC chips.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-rv8803.
|
||||
@ -670,6 +674,18 @@ config RTC_DRV_DS1390
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-ds1390.
|
||||
|
||||
config RTC_DRV_MAX6916
|
||||
tristate "Maxim MAX6916"
|
||||
help
|
||||
If you say yes here you will get support for the
|
||||
Maxim MAX6916 SPI RTC chip.
|
||||
|
||||
This driver only supports the RTC feature, and not other chip
|
||||
features such as alarms.
|
||||
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called rtc-max6916.
|
||||
|
||||
config RTC_DRV_R9701
|
||||
tristate "Epson RTC-9701JE"
|
||||
help
|
||||
@ -795,8 +811,9 @@ comment "Platform RTC drivers"
|
||||
|
||||
config RTC_DRV_CMOS
|
||||
tristate "PC-style 'CMOS'"
|
||||
depends on X86 || ARM || M32R || PPC || MIPS || SPARC64
|
||||
depends on X86 || ARM || M32R || PPC || MIPS || SPARC64 || MN10300
|
||||
default y if X86
|
||||
select RTC_MC146818_LIB
|
||||
help
|
||||
Say "yes" here to get direct support for the real time clock
|
||||
found in every PC or ACPI-based system, and some other boards.
|
||||
@ -815,6 +832,7 @@ config RTC_DRV_CMOS
|
||||
config RTC_DRV_ALPHA
|
||||
bool "Alpha PC-style CMOS"
|
||||
depends on ALPHA
|
||||
select RTC_MC146818_LIB
|
||||
default y
|
||||
help
|
||||
Direct support for the real-time clock found on every Alpha
|
||||
|
@ -8,6 +8,7 @@ obj-$(CONFIG_RTC_LIB) += rtc-lib.o
|
||||
obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o
|
||||
obj-$(CONFIG_RTC_SYSTOHC) += systohc.o
|
||||
obj-$(CONFIG_RTC_CLASS) += rtc-core.o
|
||||
obj-$(CONFIG_RTC_MC146818_LIB) += rtc-mc146818-lib.o
|
||||
rtc-core-y := class.o interface.o
|
||||
|
||||
ifdef CONFIG_RTC_DRV_EFI
|
||||
@ -85,6 +86,7 @@ obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
|
||||
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX6916) += rtc-max6916.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o
|
||||
obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o
|
||||
|
@ -104,7 +104,17 @@ static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *al
|
||||
else if (!rtc->ops->read_alarm)
|
||||
err = -EINVAL;
|
||||
else {
|
||||
memset(alarm, 0, sizeof(struct rtc_wkalrm));
|
||||
alarm->enabled = 0;
|
||||
alarm->pending = 0;
|
||||
alarm->time.tm_sec = -1;
|
||||
alarm->time.tm_min = -1;
|
||||
alarm->time.tm_hour = -1;
|
||||
alarm->time.tm_mday = -1;
|
||||
alarm->time.tm_mon = -1;
|
||||
alarm->time.tm_year = -1;
|
||||
alarm->time.tm_wday = -1;
|
||||
alarm->time.tm_yday = -1;
|
||||
alarm->time.tm_isdst = -1;
|
||||
err = rtc->ops->read_alarm(rtc->dev.parent, alarm);
|
||||
}
|
||||
|
||||
@ -383,7 +393,7 @@ int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
|
||||
rtc->aie_timer.period = ktime_set(0, 0);
|
||||
|
||||
/* Alarm has to be enabled & in the futrure for us to enqueue it */
|
||||
/* Alarm has to be enabled & in the future for us to enqueue it */
|
||||
if (alarm->enabled && (rtc_tm_to_ktime(now).tv64 <
|
||||
rtc->aie_timer.node.expires.tv64)) {
|
||||
|
||||
@ -395,8 +405,6 @@ int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtc_initialize_alarm);
|
||||
|
||||
|
||||
|
||||
int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
|
||||
{
|
||||
int err = mutex_lock_interruptible(&rtc->ops_lock);
|
||||
@ -748,9 +756,23 @@ EXPORT_SYMBOL_GPL(rtc_irq_set_freq);
|
||||
*/
|
||||
static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
|
||||
{
|
||||
struct timerqueue_node *next = timerqueue_getnext(&rtc->timerqueue);
|
||||
struct rtc_time tm;
|
||||
ktime_t now;
|
||||
|
||||
timer->enabled = 1;
|
||||
__rtc_read_time(rtc, &tm);
|
||||
now = rtc_tm_to_ktime(tm);
|
||||
|
||||
/* Skip over expired timers */
|
||||
while (next) {
|
||||
if (next->expires.tv64 >= now.tv64)
|
||||
break;
|
||||
next = timerqueue_iterate_next(next);
|
||||
}
|
||||
|
||||
timerqueue_add(&rtc->timerqueue, &timer->node);
|
||||
if (&timer->node == timerqueue_getnext(&rtc->timerqueue)) {
|
||||
if (!next) {
|
||||
struct rtc_wkalrm alarm;
|
||||
int err;
|
||||
alarm.time = rtc_ktime_to_tm(timer->node.expires);
|
||||
|
@ -643,17 +643,15 @@ static int abx80x_probe(struct i2c_client *client,
|
||||
return err;
|
||||
}
|
||||
|
||||
err = devm_add_action(&client->dev, rtc_calib_remove_sysfs_group,
|
||||
&client->dev);
|
||||
if (err) {
|
||||
rtc_calib_remove_sysfs_group(&client->dev);
|
||||
err = devm_add_action_or_reset(&client->dev,
|
||||
rtc_calib_remove_sysfs_group,
|
||||
&client->dev);
|
||||
if (err)
|
||||
dev_err(&client->dev,
|
||||
"Failed to add sysfs cleanup action: %d\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int abx80x_remove(struct i2c_client *client)
|
||||
|
@ -343,7 +343,6 @@ static struct platform_driver asm9260_rtc_driver = {
|
||||
.remove = asm9260_rtc_remove,
|
||||
.driver = {
|
||||
.name = "asm9260-rtc",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = asm9260_dt_ids,
|
||||
},
|
||||
};
|
||||
|
@ -375,6 +375,7 @@ static int at91_rtc_probe(struct platform_device *pdev)
|
||||
if (!rtc)
|
||||
return -ENOMEM;
|
||||
|
||||
spin_lock_init(&rtc->lock);
|
||||
rtc->irq = irq;
|
||||
|
||||
/* platform setup code should have handled this; sigh */
|
||||
|
@ -43,7 +43,7 @@
|
||||
#include <linux/of_platform.h>
|
||||
|
||||
/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
|
||||
#include <asm-generic/rtc.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
struct cmos_rtc {
|
||||
struct rtc_device *rtc;
|
||||
@ -190,10 +190,10 @@ static inline void cmos_write_bank2(unsigned char val, unsigned char addr)
|
||||
static int cmos_read_time(struct device *dev, struct rtc_time *t)
|
||||
{
|
||||
/* REVISIT: if the clock has a "century" register, use
|
||||
* that instead of the heuristic in get_rtc_time().
|
||||
* that instead of the heuristic in mc146818_get_time().
|
||||
* That'll make Y3K compatility (year > 2070) easy!
|
||||
*/
|
||||
get_rtc_time(t);
|
||||
mc146818_get_time(t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -205,7 +205,7 @@ static int cmos_set_time(struct device *dev, struct rtc_time *t)
|
||||
* takes effect exactly 500ms after we write the register.
|
||||
* (Also queueing and other delays before we get this far.)
|
||||
*/
|
||||
return set_rtc_time(t);
|
||||
return mc146818_set_time(t);
|
||||
}
|
||||
|
||||
static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
@ -220,8 +220,6 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
* Some also support day and month, for alarms up to a year in
|
||||
* the future.
|
||||
*/
|
||||
t->time.tm_mday = -1;
|
||||
t->time.tm_mon = -1;
|
||||
|
||||
spin_lock_irq(&rtc_lock);
|
||||
t->time.tm_sec = CMOS_READ(RTC_SECONDS_ALARM);
|
||||
@ -272,7 +270,6 @@ static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
}
|
||||
}
|
||||
}
|
||||
t->time.tm_year = -1;
|
||||
|
||||
t->enabled = !!(rtc_control & RTC_AIE);
|
||||
t->pending = 0;
|
||||
@ -630,7 +627,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
|
||||
address_space = 64;
|
||||
#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) \
|
||||
|| defined(__sparc__) || defined(__mips__) \
|
||||
|| defined(__powerpc__)
|
||||
|| defined(__powerpc__) || defined(CONFIG_MN10300)
|
||||
address_space = 128;
|
||||
#else
|
||||
#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
|
||||
@ -1142,14 +1139,14 @@ static __init void cmos_of_init(struct platform_device *pdev)
|
||||
if (val)
|
||||
CMOS_WRITE(be32_to_cpup(val), RTC_FREQ_SELECT);
|
||||
|
||||
get_rtc_time(&time);
|
||||
cmos_read_time(&pdev->dev, &time);
|
||||
ret = rtc_valid_tm(&time);
|
||||
if (ret) {
|
||||
struct rtc_time def_time = {
|
||||
.tm_year = 1,
|
||||
.tm_mday = 1,
|
||||
};
|
||||
set_rtc_time(&def_time);
|
||||
cmos_set_time(&pdev->dev, &def_time);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
@ -85,6 +85,7 @@ static int da9052_read_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm)
|
||||
rtc_tm->tm_mday = v[0][2] & DA9052_RTC_DAY;
|
||||
rtc_tm->tm_hour = v[0][1] & DA9052_RTC_HOUR;
|
||||
rtc_tm->tm_min = v[0][0] & DA9052_RTC_MIN;
|
||||
rtc_tm->tm_sec = 0;
|
||||
|
||||
ret = rtc_valid_tm(rtc_tm);
|
||||
return ret;
|
||||
|
@ -74,6 +74,7 @@ static int da9055_read_alarm(struct da9055 *da9055, struct rtc_time *rtc_tm)
|
||||
rtc_tm->tm_mday = v[2] & DA9055_RTC_ALM_DAY;
|
||||
rtc_tm->tm_hour = v[1] & DA9055_RTC_ALM_HOUR;
|
||||
rtc_tm->tm_min = v[0] & DA9055_RTC_ALM_MIN;
|
||||
rtc_tm->tm_sec = 0;
|
||||
|
||||
return rtc_valid_tm(rtc_tm);
|
||||
}
|
||||
|
@ -388,6 +388,8 @@ static int davinci_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
u8 day0, day1;
|
||||
unsigned long flags;
|
||||
|
||||
alm->time.tm_sec = 0;
|
||||
|
||||
spin_lock_irqsave(&davinci_rtc_lock, flags);
|
||||
|
||||
davinci_rtcss_calendar_wait(davinci_rtc);
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/ds1286.h>
|
||||
#include <linux/rtc/ds1286.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
|
@ -313,13 +313,6 @@ static int ds1305_get_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
alm->time.tm_sec = bcd2bin(buf[DS1305_SEC]);
|
||||
alm->time.tm_min = bcd2bin(buf[DS1305_MIN]);
|
||||
alm->time.tm_hour = bcd2hour(buf[DS1305_HOUR]);
|
||||
alm->time.tm_mday = -1;
|
||||
alm->time.tm_mon = -1;
|
||||
alm->time.tm_year = -1;
|
||||
/* next three fields are unused by Linux */
|
||||
alm->time.tm_wday = -1;
|
||||
alm->time.tm_mday = -1;
|
||||
alm->time.tm_isdst = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -482,11 +482,6 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
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);
|
||||
@ -602,6 +597,8 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
|
||||
* Alarm support for mcp794xx devices.
|
||||
*/
|
||||
|
||||
#define MCP794XX_REG_WEEKDAY 0x3
|
||||
#define MCP794XX_REG_WEEKDAY_WDAY_MASK 0x7
|
||||
#define MCP794XX_REG_CONTROL 0x07
|
||||
# define MCP794XX_BIT_ALM0_EN 0x10
|
||||
# define MCP794XX_BIT_ALM1_EN 0x20
|
||||
@ -1231,13 +1228,16 @@ static int ds1307_probe(struct i2c_client *client,
|
||||
{
|
||||
struct ds1307 *ds1307;
|
||||
int err = -ENODEV;
|
||||
int tmp;
|
||||
int tmp, wday;
|
||||
struct chip_desc *chip = &chips[id->driver_data];
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
bool want_irq = false;
|
||||
bool ds1307_can_wakeup_device = false;
|
||||
unsigned char *buf;
|
||||
struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev);
|
||||
struct rtc_time tm;
|
||||
unsigned long timestamp;
|
||||
|
||||
irq_handler_t irq_handler = ds1307_irq;
|
||||
|
||||
static const int bbsqi_bitpos[] = {
|
||||
@ -1526,6 +1526,27 @@ read_rtc:
|
||||
bin2bcd(tmp));
|
||||
}
|
||||
|
||||
/*
|
||||
* Some IPs have weekday reset value = 0x1 which might not correct
|
||||
* hence compute the wday using the current date/month/year values
|
||||
*/
|
||||
ds1307_get_time(&client->dev, &tm);
|
||||
wday = tm.tm_wday;
|
||||
timestamp = rtc_tm_to_time64(&tm);
|
||||
rtc_time64_to_tm(timestamp, &tm);
|
||||
|
||||
/*
|
||||
* Check if reset wday is different from the computed wday
|
||||
* If different then set the wday which we computed using
|
||||
* timestamp
|
||||
*/
|
||||
if (wday != tm.tm_wday) {
|
||||
wday = i2c_smbus_read_byte_data(client, MCP794XX_REG_WEEKDAY);
|
||||
wday = wday & ~MCP794XX_REG_WEEKDAY_WDAY_MASK;
|
||||
wday = wday | (tm.tm_wday + 1);
|
||||
i2c_smbus_write_byte_data(client, MCP794XX_REG_WEEKDAY, wday);
|
||||
}
|
||||
|
||||
if (want_irq) {
|
||||
device_set_wakeup_capable(&client->dev, true);
|
||||
set_bit(HAS_ALARM, &ds1307->flags);
|
||||
|
@ -504,12 +504,6 @@ static int ds1343_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
alarm->time.tm_hour = priv->alarm_hour < 0 ? 0 : priv->alarm_hour;
|
||||
alarm->time.tm_mday = priv->alarm_mday < 0 ? 0 : priv->alarm_mday;
|
||||
|
||||
alarm->time.tm_mon = -1;
|
||||
alarm->time.tm_year = -1;
|
||||
alarm->time.tm_wday = -1;
|
||||
alarm->time.tm_yday = -1;
|
||||
alarm->time.tm_isdst = -1;
|
||||
|
||||
out:
|
||||
mutex_unlock(&priv->mutex);
|
||||
return res;
|
||||
|
@ -102,6 +102,26 @@ ds1685_rtc_bin2bcd(struct ds1685_priv *rtc, u8 val, u8 bin_mask, u8 bcd_mask)
|
||||
return (val & bin_mask);
|
||||
}
|
||||
|
||||
/**
|
||||
* s1685_rtc_check_mday - check validity of the day of month.
|
||||
* @rtc: pointer to the ds1685 rtc structure.
|
||||
* @mday: day of month.
|
||||
*
|
||||
* Returns -EDOM if the day of month is not within 1..31 range.
|
||||
*/
|
||||
static inline int
|
||||
ds1685_rtc_check_mday(struct ds1685_priv *rtc, u8 mday)
|
||||
{
|
||||
if (rtc->bcd_mode) {
|
||||
if (mday < 0x01 || mday > 0x31 || (mday & 0x0f) > 0x09)
|
||||
return -EDOM;
|
||||
} else {
|
||||
if (mday < 1 || mday > 31)
|
||||
return -EDOM;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* ds1685_rtc_switch_to_bank0 - switch the rtc to bank 0.
|
||||
* @rtc: pointer to the ds1685 rtc structure.
|
||||
@ -377,6 +397,7 @@ ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
|
||||
u8 seconds, minutes, hours, mday, ctrlb, ctrlc;
|
||||
int ret;
|
||||
|
||||
/* Fetch the alarm info from the RTC alarm registers. */
|
||||
ds1685_rtc_begin_data_access(rtc);
|
||||
@ -388,34 +409,29 @@ ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
ctrlc = rtc->read(rtc, RTC_CTRL_C);
|
||||
ds1685_rtc_end_data_access(rtc);
|
||||
|
||||
/* Check month date. */
|
||||
if (!(mday >= 1) && (mday <= 31))
|
||||
return -EDOM;
|
||||
/* Check the month date for validity. */
|
||||
ret = ds1685_rtc_check_mday(rtc, mday);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Check the three alarm bytes.
|
||||
*
|
||||
* The Linux RTC system doesn't support the "don't care" capability
|
||||
* of this RTC chip. We check for it anyways in case support is
|
||||
* added in the future.
|
||||
* added in the future and only assign when we care.
|
||||
*/
|
||||
if (unlikely(seconds >= 0xc0))
|
||||
alrm->time.tm_sec = -1;
|
||||
else
|
||||
if (likely(seconds < 0xc0))
|
||||
alrm->time.tm_sec = ds1685_rtc_bcd2bin(rtc, seconds,
|
||||
RTC_SECS_BCD_MASK,
|
||||
RTC_SECS_BIN_MASK);
|
||||
|
||||
if (unlikely(minutes >= 0xc0))
|
||||
alrm->time.tm_min = -1;
|
||||
else
|
||||
if (likely(minutes < 0xc0))
|
||||
alrm->time.tm_min = ds1685_rtc_bcd2bin(rtc, minutes,
|
||||
RTC_MINS_BCD_MASK,
|
||||
RTC_MINS_BIN_MASK);
|
||||
|
||||
if (unlikely(hours >= 0xc0))
|
||||
alrm->time.tm_hour = -1;
|
||||
else
|
||||
if (likely(hours < 0xc0))
|
||||
alrm->time.tm_hour = ds1685_rtc_bcd2bin(rtc, hours,
|
||||
RTC_HRS_24_BCD_MASK,
|
||||
RTC_HRS_24_BIN_MASK);
|
||||
@ -423,11 +439,6 @@ ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
/* Write the data to rtc_wkalrm. */
|
||||
alrm->time.tm_mday = ds1685_rtc_bcd2bin(rtc, mday, RTC_MDAY_BCD_MASK,
|
||||
RTC_MDAY_BIN_MASK);
|
||||
alrm->time.tm_mon = -1;
|
||||
alrm->time.tm_year = -1;
|
||||
alrm->time.tm_wday = -1;
|
||||
alrm->time.tm_yday = -1;
|
||||
alrm->time.tm_isdst = -1;
|
||||
alrm->enabled = !!(ctrlb & RTC_CTRL_B_AIE);
|
||||
alrm->pending = !!(ctrlc & RTC_CTRL_C_AF);
|
||||
|
||||
@ -445,6 +456,7 @@ ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct ds1685_priv *rtc = platform_get_drvdata(pdev);
|
||||
u8 ctrlb, seconds, minutes, hours, mday;
|
||||
int ret;
|
||||
|
||||
/* Fetch the alarm info and convert to BCD. */
|
||||
seconds = ds1685_rtc_bin2bcd(rtc, alrm->time.tm_sec,
|
||||
@ -461,8 +473,9 @@ ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
RTC_MDAY_BCD_MASK);
|
||||
|
||||
/* Check the month date for validity. */
|
||||
if (!(mday >= 1) && (mday <= 31))
|
||||
return -EDOM;
|
||||
ret = ds1685_rtc_check_mday(rtc, mday);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* Check the three alarm bytes.
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/rtc-ds2404.h>
|
||||
#include <linux/platform_data/rtc-ds2404.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -197,12 +197,6 @@ static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
alarm->time.tm_hour = bcd2bin(buf[2] & 0x7F);
|
||||
alarm->time.tm_mday = bcd2bin(buf[3] & 0x7F);
|
||||
|
||||
alarm->time.tm_mon = -1;
|
||||
alarm->time.tm_year = -1;
|
||||
alarm->time.tm_wday = -1;
|
||||
alarm->time.tm_yday = -1;
|
||||
alarm->time.tm_isdst = -1;
|
||||
|
||||
alarm->enabled = !!(control & DS3232_REG_CR_A1IE);
|
||||
alarm->pending = !!(stat & DS3232_REG_SR_A1F);
|
||||
|
||||
|
@ -259,6 +259,12 @@ static const struct rtc_class_ops efi_rtc_ops = {
|
||||
static int __init efi_rtc_probe(struct platform_device *dev)
|
||||
{
|
||||
struct rtc_device *rtc;
|
||||
efi_time_t eft;
|
||||
efi_time_cap_t cap;
|
||||
|
||||
/* First check if the RTC is usable */
|
||||
if (efi.get_time(&eft, &cap) != EFI_SUCCESS)
|
||||
return -ENODEV;
|
||||
|
||||
rtc = devm_rtc_device_register(&dev->dev, "rtc-efi", &efi_rtc_ops,
|
||||
THIS_MODULE);
|
||||
|
@ -9,44 +9,10 @@
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#if defined(CONFIG_M68K) || defined(CONFIG_PARISC) || \
|
||||
defined(CONFIG_PPC) || defined(CONFIG_SUPERH32)
|
||||
#include <asm/rtc.h>
|
||||
|
||||
static int generic_get_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
unsigned int ret = get_rtc_time(tm);
|
||||
|
||||
if (ret & RTC_BATT_BAD)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return rtc_valid_tm(tm);
|
||||
}
|
||||
|
||||
static int generic_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
if (set_rtc_time(tm) < 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops generic_rtc_ops = {
|
||||
.read_time = generic_get_time,
|
||||
.set_time = generic_set_time,
|
||||
};
|
||||
#else
|
||||
#define generic_rtc_ops *(struct rtc_class_ops*)NULL
|
||||
#endif
|
||||
|
||||
static int __init generic_rtc_probe(struct platform_device *dev)
|
||||
{
|
||||
struct rtc_device *rtc;
|
||||
const struct rtc_class_ops *ops;
|
||||
|
||||
ops = dev_get_platdata(&dev->dev);
|
||||
if (!ops)
|
||||
ops = &generic_rtc_ops;
|
||||
const struct rtc_class_ops *ops = dev_get_platdata(&dev->dev);
|
||||
|
||||
rtc = devm_rtc_device_register(&dev->dev, "rtc-generic",
|
||||
ops, THIS_MODULE);
|
||||
|
@ -198,7 +198,7 @@ static int hym8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
return ret;
|
||||
|
||||
/* The alarm only has a minute accuracy */
|
||||
alm_tm->tm_sec = -1;
|
||||
alm_tm->tm_sec = 0;
|
||||
|
||||
alm_tm->tm_min = (buf[0] & HYM8563_ALM_BIT_DISABLE) ?
|
||||
-1 :
|
||||
@ -213,9 +213,6 @@ static int hym8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
-1 :
|
||||
bcd2bin(buf[3] & HYM8563_WEEKDAY_MASK);
|
||||
|
||||
alm_tm->tm_mon = -1;
|
||||
alm_tm->tm_year = -1;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, HYM8563_CTL2);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
@ -245,8 +245,7 @@ static int isl12057_rtc_update_alarm(struct device *dev, int enable)
|
||||
static int isl12057_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
{
|
||||
struct isl12057_rtc_data *data = dev_get_drvdata(dev);
|
||||
struct rtc_time rtc_tm, *alarm_tm = &alarm->time;
|
||||
unsigned long rtc_secs, alarm_secs;
|
||||
struct rtc_time *alarm_tm = &alarm->time;
|
||||
u8 regs[ISL12057_A1_SEC_LEN];
|
||||
unsigned int ir;
|
||||
int ret;
|
||||
@ -264,36 +263,6 @@ static int isl12057_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
alarm_tm->tm_min = bcd2bin(regs[1] & 0x7f);
|
||||
alarm_tm->tm_hour = bcd2bin(regs[2] & 0x3f);
|
||||
alarm_tm->tm_mday = bcd2bin(regs[3] & 0x3f);
|
||||
alarm_tm->tm_wday = -1;
|
||||
|
||||
/*
|
||||
* The alarm section does not store year/month. We use the ones in rtc
|
||||
* section as a basis and increment month and then year if needed to get
|
||||
* alarm after current time.
|
||||
*/
|
||||
ret = _isl12057_rtc_read_time(dev, &rtc_tm);
|
||||
if (ret)
|
||||
goto err_unlock;
|
||||
|
||||
alarm_tm->tm_year = rtc_tm.tm_year;
|
||||
alarm_tm->tm_mon = rtc_tm.tm_mon;
|
||||
|
||||
ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
|
||||
if (ret)
|
||||
goto err_unlock;
|
||||
|
||||
ret = rtc_tm_to_time(alarm_tm, &alarm_secs);
|
||||
if (ret)
|
||||
goto err_unlock;
|
||||
|
||||
if (alarm_secs < rtc_secs) {
|
||||
if (alarm_tm->tm_mon == 11) {
|
||||
alarm_tm->tm_mon = 0;
|
||||
alarm_tm->tm_year += 1;
|
||||
} else {
|
||||
alarm_tm->tm_mon += 1;
|
||||
}
|
||||
}
|
||||
|
||||
ret = regmap_read(data->regmap, ISL12057_REG_INT, &ir);
|
||||
if (ret) {
|
||||
|
@ -244,7 +244,7 @@ static int m41t80_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
|
||||
retval = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, flags);
|
||||
if (retval < 0) {
|
||||
dev_info(dev, "Unable to enable alarm IRQ %d\n", retval);
|
||||
dev_err(dev, "Unable to enable alarm IRQ %d\n", retval);
|
||||
return retval;
|
||||
}
|
||||
return 0;
|
||||
@ -320,10 +320,8 @@ static int m41t80_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
alrm->time.tm_sec = bcd2bin(alarmvals[4] & 0x7f);
|
||||
alrm->time.tm_min = bcd2bin(alarmvals[3] & 0x7f);
|
||||
alrm->time.tm_hour = bcd2bin(alarmvals[2] & 0x3f);
|
||||
alrm->time.tm_wday = -1;
|
||||
alrm->time.tm_mday = bcd2bin(alarmvals[1] & 0x3f);
|
||||
alrm->time.tm_mon = bcd2bin(alarmvals[0] & 0x3f);
|
||||
alrm->time.tm_year = -1;
|
||||
|
||||
alrm->enabled = !!(alarmvals[0] & M41T80_ALMON_AFE);
|
||||
alrm->pending = (flags & M41T80_FLAGS_AF) && alrm->enabled;
|
||||
@ -337,6 +335,30 @@ static struct rtc_class_ops m41t80_rtc_ops = {
|
||||
.proc = m41t80_rtc_proc,
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int m41t80_suspend(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
if (client->irq >= 0 && device_may_wakeup(dev))
|
||||
enable_irq_wake(client->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int m41t80_resume(struct device *dev)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
|
||||
if (client->irq >= 0 && device_may_wakeup(dev))
|
||||
disable_irq_wake(client->irq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static SIMPLE_DEV_PM_OPS(m41t80_pm, m41t80_suspend, m41t80_resume);
|
||||
|
||||
static ssize_t flags_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -831,10 +853,9 @@ static int m41t80_probe(struct i2c_client *client,
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = devm_add_action(&client->dev, m41t80_remove_sysfs_group,
|
||||
&client->dev);
|
||||
rc = devm_add_action_or_reset(&client->dev, m41t80_remove_sysfs_group,
|
||||
&client->dev);
|
||||
if (rc) {
|
||||
m41t80_remove_sysfs_group(&client->dev);
|
||||
dev_err(&client->dev,
|
||||
"Failed to add sysfs cleanup action: %d\n", rc);
|
||||
return rc;
|
||||
@ -873,6 +894,7 @@ static int m41t80_remove(struct i2c_client *client)
|
||||
static struct i2c_driver m41t80_driver = {
|
||||
.driver = {
|
||||
.name = "rtc-m41t80",
|
||||
.pm = &m41t80_pm,
|
||||
},
|
||||
.probe = m41t80_probe,
|
||||
.remove = m41t80_remove,
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/m48t86.h>
|
||||
#include <linux/platform_data/rtc-m48t86.h>
|
||||
#include <linux/bcd.h>
|
||||
|
||||
#define M48T86_REG_SEC 0x00
|
||||
|
164
drivers/rtc/rtc-max6916.c
Normal file
164
drivers/rtc/rtc-max6916.c
Normal file
@ -0,0 +1,164 @@
|
||||
/* rtc-max6916.c
|
||||
*
|
||||
* Driver for MAXIM max6916 Low Current, SPI Compatible
|
||||
* Real Time Clock
|
||||
*
|
||||
* Author : Venkat Prashanth B U <venkat.prashanth2498@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/bcd.h>
|
||||
|
||||
/* Registers in max6916 rtc */
|
||||
|
||||
#define MAX6916_SECONDS_REG 0x01
|
||||
#define MAX6916_MINUTES_REG 0x02
|
||||
#define MAX6916_HOURS_REG 0x03
|
||||
#define MAX6916_DATE_REG 0x04
|
||||
#define MAX6916_MONTH_REG 0x05
|
||||
#define MAX6916_DAY_REG 0x06
|
||||
#define MAX6916_YEAR_REG 0x07
|
||||
#define MAX6916_CONTROL_REG 0x08
|
||||
#define MAX6916_STATUS_REG 0x0C
|
||||
#define MAX6916_CLOCK_BURST 0x3F
|
||||
|
||||
static int max6916_read_reg(struct device *dev, unsigned char address,
|
||||
unsigned char *data)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
|
||||
*data = address | 0x80;
|
||||
|
||||
return spi_write_then_read(spi, data, 1, data, 1);
|
||||
}
|
||||
|
||||
static int max6916_write_reg(struct device *dev, unsigned char address,
|
||||
unsigned char data)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
unsigned char buf[2];
|
||||
|
||||
buf[0] = address & 0x7F;
|
||||
buf[1] = data;
|
||||
|
||||
return spi_write_then_read(spi, buf, 2, NULL, 0);
|
||||
}
|
||||
|
||||
static int max6916_read_time(struct device *dev, struct rtc_time *dt)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
int err;
|
||||
unsigned char buf[8];
|
||||
|
||||
buf[0] = MAX6916_CLOCK_BURST | 0x80;
|
||||
|
||||
err = spi_write_then_read(spi, buf, 1, buf, 8);
|
||||
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
dt->tm_sec = bcd2bin(buf[0]);
|
||||
dt->tm_min = bcd2bin(buf[1]);
|
||||
dt->tm_hour = bcd2bin(buf[2] & 0x3F);
|
||||
dt->tm_mday = bcd2bin(buf[3]);
|
||||
dt->tm_mon = bcd2bin(buf[4]) - 1;
|
||||
dt->tm_wday = bcd2bin(buf[5]) - 1;
|
||||
dt->tm_year = bcd2bin(buf[6]) + 100;
|
||||
|
||||
return rtc_valid_tm(dt);
|
||||
}
|
||||
|
||||
static int max6916_set_time(struct device *dev, struct rtc_time *dt)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
unsigned char buf[9];
|
||||
|
||||
if (dt->tm_year < 100 || dt->tm_year > 199) {
|
||||
dev_err(&spi->dev, "Year must be between 2000 and 2099. It's %d.\n",
|
||||
dt->tm_year + 1900);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
buf[0] = MAX6916_CLOCK_BURST & 0x7F;
|
||||
buf[1] = bin2bcd(dt->tm_sec);
|
||||
buf[2] = bin2bcd(dt->tm_min);
|
||||
buf[3] = (bin2bcd(dt->tm_hour) & 0X3F);
|
||||
buf[4] = bin2bcd(dt->tm_mday);
|
||||
buf[5] = bin2bcd(dt->tm_mon + 1);
|
||||
buf[6] = bin2bcd(dt->tm_wday + 1);
|
||||
buf[7] = bin2bcd(dt->tm_year % 100);
|
||||
buf[8] = bin2bcd(0x00);
|
||||
|
||||
/* write the rtc settings */
|
||||
return spi_write_then_read(spi, buf, 9, NULL, 0);
|
||||
}
|
||||
|
||||
static const struct rtc_class_ops max6916_rtc_ops = {
|
||||
.read_time = max6916_read_time,
|
||||
.set_time = max6916_set_time,
|
||||
};
|
||||
|
||||
static int max6916_probe(struct spi_device *spi)
|
||||
{
|
||||
struct rtc_device *rtc;
|
||||
unsigned char data;
|
||||
int res;
|
||||
|
||||
/* spi setup with max6916 in mode 3 and bits per word as 8 */
|
||||
spi->mode = SPI_MODE_3;
|
||||
spi->bits_per_word = 8;
|
||||
spi_setup(spi);
|
||||
|
||||
/* RTC Settings */
|
||||
res = max6916_read_reg(&spi->dev, MAX6916_SECONDS_REG, &data);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
/* Disable the write protect of rtc */
|
||||
max6916_read_reg(&spi->dev, MAX6916_CONTROL_REG, &data);
|
||||
data = data & ~(1 << 7);
|
||||
max6916_write_reg(&spi->dev, MAX6916_CONTROL_REG, data);
|
||||
|
||||
/*Enable oscillator,disable oscillator stop flag, glitch filter*/
|
||||
max6916_read_reg(&spi->dev, MAX6916_STATUS_REG, &data);
|
||||
data = data & 0x1B;
|
||||
max6916_write_reg(&spi->dev, MAX6916_STATUS_REG, data);
|
||||
|
||||
/* display the settings */
|
||||
max6916_read_reg(&spi->dev, MAX6916_CONTROL_REG, &data);
|
||||
dev_info(&spi->dev, "MAX6916 RTC CTRL Reg = 0x%02x\n", data);
|
||||
|
||||
max6916_read_reg(&spi->dev, MAX6916_STATUS_REG, &data);
|
||||
dev_info(&spi->dev, "MAX6916 RTC Status Reg = 0x%02x\n", data);
|
||||
|
||||
rtc = devm_rtc_device_register(&spi->dev, "max6916",
|
||||
&max6916_rtc_ops, THIS_MODULE);
|
||||
if (IS_ERR(rtc))
|
||||
return PTR_ERR(rtc);
|
||||
|
||||
spi_set_drvdata(spi, rtc);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct spi_driver max6916_driver = {
|
||||
.driver = {
|
||||
.name = "max6916",
|
||||
},
|
||||
.probe = max6916_probe,
|
||||
};
|
||||
module_spi_driver(max6916_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MAX6916 SPI RTC DRIVER");
|
||||
MODULE_AUTHOR("Venkat Prashanth B U <venkat.prashanth2498@gmail.com>");
|
||||
MODULE_LICENSE("GPL v2");
|
@ -1,40 +1,16 @@
|
||||
/*
|
||||
* include/asm-generic/rtc.h
|
||||
*
|
||||
* Author: Tom Rini <trini@mvista.com>
|
||||
*
|
||||
* Based on:
|
||||
* drivers/char/rtc.c
|
||||
*
|
||||
* Please read the COPYING file for all license details.
|
||||
*/
|
||||
|
||||
#ifndef __ASM_RTC_H__
|
||||
#define __ASM_RTC_H__
|
||||
|
||||
#include <linux/mc146818rtc.h>
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
#ifdef CONFIG_ACPI
|
||||
#include <linux/acpi.h>
|
||||
#endif
|
||||
|
||||
#define RTC_PIE 0x40 /* periodic interrupt enable */
|
||||
#define RTC_AIE 0x20 /* alarm interrupt enable */
|
||||
#define RTC_UIE 0x10 /* update-finished interrupt enable */
|
||||
|
||||
/* some dummy definitions */
|
||||
#define RTC_BATT_BAD 0x100 /* battery bad */
|
||||
#define RTC_SQWE 0x08 /* enable square-wave output */
|
||||
#define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
|
||||
#define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
|
||||
#define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
|
||||
|
||||
/*
|
||||
* Returns true if a clock update is in progress
|
||||
*/
|
||||
static inline unsigned char rtc_is_updating(void)
|
||||
static inline unsigned char mc146818_is_updating(void)
|
||||
{
|
||||
unsigned char uip;
|
||||
unsigned long flags;
|
||||
@ -45,7 +21,7 @@ static inline unsigned char rtc_is_updating(void)
|
||||
return uip;
|
||||
}
|
||||
|
||||
static inline unsigned int __get_rtc_time(struct rtc_time *time)
|
||||
unsigned int mc146818_get_time(struct rtc_time *time)
|
||||
{
|
||||
unsigned char ctrl;
|
||||
unsigned long flags;
|
||||
@ -60,11 +36,11 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time)
|
||||
* can take just over 2ms. We wait 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
|
||||
* 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 (rtc_is_updating())
|
||||
if (mc146818_is_updating())
|
||||
mdelay(20);
|
||||
|
||||
/*
|
||||
@ -120,13 +96,10 @@ static inline unsigned int __get_rtc_time(struct rtc_time *time)
|
||||
|
||||
return RTC_24H;
|
||||
}
|
||||
|
||||
#ifndef get_rtc_time
|
||||
#define get_rtc_time __get_rtc_time
|
||||
#endif
|
||||
EXPORT_SYMBOL_GPL(mc146818_get_time);
|
||||
|
||||
/* Set the current date and time in the real time clock. */
|
||||
static inline int __set_rtc_time(struct rtc_time *time)
|
||||
int mc146818_set_time(struct rtc_time *time)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned char mon, day, hrs, min, sec;
|
||||
@ -222,26 +195,4 @@ static inline int __set_rtc_time(struct rtc_time *time)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef set_rtc_time
|
||||
#define set_rtc_time __set_rtc_time
|
||||
#endif
|
||||
|
||||
static inline unsigned int get_rtc_ss(void)
|
||||
{
|
||||
struct rtc_time h;
|
||||
|
||||
get_rtc_time(&h);
|
||||
return h.tm_sec;
|
||||
}
|
||||
|
||||
static inline int get_rtc_pll(struct rtc_pll_info *pll)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
static inline int set_rtc_pll(struct rtc_pll_info *pll)
|
||||
{
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
#endif /* __ASM_RTC_H__ */
|
||||
EXPORT_SYMBOL_GPL(mc146818_set_time);
|
@ -32,11 +32,11 @@
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mc146818rtc.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sfi.h>
|
||||
|
||||
#include <asm-generic/rtc.h>
|
||||
#include <asm/intel_scu_ipc.h>
|
||||
#include <asm/intel-mid.h>
|
||||
#include <asm/intel_mid_vrtc.h>
|
||||
@ -149,14 +149,6 @@ static int mrst_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
if (mrst->irq <= 0)
|
||||
return -EIO;
|
||||
|
||||
/* Basic alarms only support hour, minute, and seconds fields.
|
||||
* Some also support day and month, for alarms up to a year in
|
||||
* the future.
|
||||
*/
|
||||
t->time.tm_mday = -1;
|
||||
t->time.tm_mon = -1;
|
||||
t->time.tm_year = -1;
|
||||
|
||||
/* vRTC only supports binary mode */
|
||||
spin_lock_irq(&rtc_lock);
|
||||
t->time.tm_sec = vrtc_cmos_read(RTC_SECONDS_ALARM);
|
||||
|
@ -96,7 +96,7 @@
|
||||
#define CD_TMR_TE BIT(3) /* Countdown timer enable */
|
||||
|
||||
/* PCF2123_REG_OFFSET BITS */
|
||||
#define OFFSET_SIGN_BIT BIT(6) /* 2's complement sign bit */
|
||||
#define OFFSET_SIGN_BIT 6 /* 2's complement sign bit */
|
||||
#define OFFSET_COARSE BIT(7) /* Coarse mode offset */
|
||||
#define OFFSET_STEP (2170) /* Offset step in parts per billion */
|
||||
|
||||
@ -217,7 +217,7 @@ static int pcf2123_read_offset(struct device *dev, long *offset)
|
||||
if (reg & OFFSET_COARSE)
|
||||
reg <<= 1; /* multiply by 2 and sign extend */
|
||||
else
|
||||
reg |= (reg & OFFSET_SIGN_BIT) << 1; /* sign extend only */
|
||||
reg = sign_extend32(reg, OFFSET_SIGN_BIT);
|
||||
|
||||
*offset = ((long)reg) * OFFSET_STEP;
|
||||
|
||||
|
@ -16,6 +16,16 @@
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
/*
|
||||
* Information for this driver was pulled from the following datasheets.
|
||||
*
|
||||
* http://www.nxp.com/documents/data_sheet/PCF85063A.pdf
|
||||
* http://www.nxp.com/documents/data_sheet/PCF85063TP.pdf
|
||||
*
|
||||
* PCF85063A -- Rev. 6 — 18 November 2015
|
||||
* PCF85063TP -- Rev. 4 — 6 May 2015
|
||||
*/
|
||||
|
||||
#define PCF85063_REG_CTRL1 0x00 /* status */
|
||||
#define PCF85063_REG_CTRL1_STOP BIT(5)
|
||||
#define PCF85063_REG_CTRL2 0x01
|
||||
@ -55,10 +65,22 @@ static int pcf85063_stop_clock(struct i2c_client *client, u8 *ctrl1)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* In the routines that deal directly with the pcf85063 hardware, we use
|
||||
* rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
|
||||
*/
|
||||
static int pcf85063_start_clock(struct i2c_client *client, u8 ctrl1)
|
||||
{
|
||||
s32 ret;
|
||||
|
||||
/* start the clock */
|
||||
ctrl1 &= PCF85063_REG_CTRL1_STOP;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, PCF85063_REG_CTRL1, ctrl1);
|
||||
if (ret < 0) {
|
||||
dev_err(&client->dev, "Failing to start the clock\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
{
|
||||
int rc;
|
||||
@ -90,8 +112,7 @@ static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
tm->tm_wday = regs[4] & 0x07;
|
||||
tm->tm_mon = bcd2bin(regs[5] & 0x1F) - 1; /* rtc mn 1-12 */
|
||||
tm->tm_year = bcd2bin(regs[6]);
|
||||
if (tm->tm_year < 70)
|
||||
tm->tm_year += 100; /* assume we are in 1970...2069 */
|
||||
tm->tm_year += 100;
|
||||
|
||||
return rtc_valid_tm(tm);
|
||||
}
|
||||
@ -99,13 +120,17 @@ static int pcf85063_get_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
{
|
||||
int rc;
|
||||
u8 regs[8];
|
||||
u8 regs[7];
|
||||
u8 ctrl1;
|
||||
|
||||
if ((tm->tm_year < 100) || (tm->tm_year > 199))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* to accurately set the time, reset the divider chain and keep it in
|
||||
* reset state until all time/date registers are written
|
||||
*/
|
||||
rc = pcf85063_stop_clock(client, ®s[7]);
|
||||
rc = pcf85063_stop_clock(client, &ctrl1);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
@ -125,14 +150,7 @@ static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
regs[5] = bin2bcd(tm->tm_mon + 1);
|
||||
|
||||
/* year and century */
|
||||
regs[6] = bin2bcd(tm->tm_year % 100);
|
||||
|
||||
/*
|
||||
* after all time/date registers are written, let the 'address auto
|
||||
* increment' feature wrap around and write register CTRL1 to re-enable
|
||||
* the clock divider chain again
|
||||
*/
|
||||
regs[7] &= ~PCF85063_REG_CTRL1_STOP;
|
||||
regs[6] = bin2bcd(tm->tm_year - 100);
|
||||
|
||||
/* write all registers at once */
|
||||
rc = i2c_smbus_write_i2c_block_data(client, PCF85063_REG_SC,
|
||||
@ -142,6 +160,15 @@ static int pcf85063_set_datetime(struct i2c_client *client, struct rtc_time *tm)
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the control register as a separate action since the size of
|
||||
* the register space is different between the PCF85063TP and
|
||||
* PCF85063A devices. The rollover point can not be used.
|
||||
*/
|
||||
rc = pcf85063_start_clock(client, ctrl1);
|
||||
if (rc != 0)
|
||||
return rc;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -341,14 +341,11 @@ static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
|
||||
"%s: raw data is min=%02x, hr=%02x, mday=%02x, wday=%02x\n",
|
||||
__func__, buf[0], buf[1], buf[2], buf[3]);
|
||||
|
||||
tm->time.tm_sec = 0;
|
||||
tm->time.tm_min = bcd2bin(buf[0] & 0x7F);
|
||||
tm->time.tm_hour = bcd2bin(buf[1] & 0x3F);
|
||||
tm->time.tm_mday = bcd2bin(buf[2] & 0x3F);
|
||||
tm->time.tm_wday = bcd2bin(buf[3] & 0x7);
|
||||
tm->time.tm_mon = -1;
|
||||
tm->time.tm_year = -1;
|
||||
tm->time.tm_yday = -1;
|
||||
tm->time.tm_isdst = -1;
|
||||
|
||||
err = pcf8563_get_alarm_mode(client, &tm->enabled, &tm->pending);
|
||||
if (err < 0)
|
||||
|
@ -128,6 +128,7 @@ static int rc5t583_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
|
||||
return ret;
|
||||
}
|
||||
|
||||
alm->time.tm_sec = 0;
|
||||
alm->time.tm_min = bcd2bin(alarm_data[0]);
|
||||
alm->time.tm_hour = bcd2bin(alarm_data[1]);
|
||||
alm->time.tm_mday = bcd2bin(alarm_data[2]);
|
||||
|
@ -341,12 +341,6 @@ static int rs5c_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
t->time.tm_sec = 0;
|
||||
t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f);
|
||||
t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]);
|
||||
t->time.tm_mday = -1;
|
||||
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 = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE);
|
||||
|
@ -13,12 +13,15 @@
|
||||
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/log2.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/rtc.h>
|
||||
|
||||
#define RV8803_I2C_TRY_COUNT 4
|
||||
|
||||
#define RV8803_SEC 0x00
|
||||
#define RV8803_MIN 0x01
|
||||
#define RV8803_HOUR 0x02
|
||||
@ -56,19 +59,85 @@ struct rv8803_data {
|
||||
u8 ctrl;
|
||||
};
|
||||
|
||||
static int rv8803_read_reg(const struct i2c_client *client, u8 reg)
|
||||
{
|
||||
int try = RV8803_I2C_TRY_COUNT;
|
||||
s32 ret;
|
||||
|
||||
/*
|
||||
* There is a 61µs window during which the RTC does not acknowledge I2C
|
||||
* transfers. In that case, ensure that there are multiple attempts.
|
||||
*/
|
||||
do
|
||||
ret = i2c_smbus_read_byte_data(client, reg);
|
||||
while ((ret == -ENXIO || ret == -EIO) && --try);
|
||||
if (ret < 0)
|
||||
dev_err(&client->dev, "Unable to read register 0x%02x\n", reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rv8803_read_regs(const struct i2c_client *client,
|
||||
u8 reg, u8 count, u8 *values)
|
||||
{
|
||||
int try = RV8803_I2C_TRY_COUNT;
|
||||
s32 ret;
|
||||
|
||||
do
|
||||
ret = i2c_smbus_read_i2c_block_data(client, reg, count, values);
|
||||
while ((ret == -ENXIO || ret == -EIO) && --try);
|
||||
if (ret != count) {
|
||||
dev_err(&client->dev,
|
||||
"Unable to read registers 0x%02x..0x%02x\n",
|
||||
reg, reg + count - 1);
|
||||
return ret < 0 ? ret : -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rv8803_write_reg(const struct i2c_client *client, u8 reg, u8 value)
|
||||
{
|
||||
int try = RV8803_I2C_TRY_COUNT;
|
||||
s32 ret;
|
||||
|
||||
do
|
||||
ret = i2c_smbus_write_byte_data(client, reg, value);
|
||||
while ((ret == -ENXIO || ret == -EIO) && --try);
|
||||
if (ret)
|
||||
dev_err(&client->dev, "Unable to write register 0x%02x\n", reg);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rv8803_write_regs(const struct i2c_client *client,
|
||||
u8 reg, u8 count, const u8 *values)
|
||||
{
|
||||
int try = RV8803_I2C_TRY_COUNT;
|
||||
s32 ret;
|
||||
|
||||
do
|
||||
ret = i2c_smbus_write_i2c_block_data(client, reg, count,
|
||||
values);
|
||||
while ((ret == -ENXIO || ret == -EIO) && --try);
|
||||
if (ret)
|
||||
dev_err(&client->dev,
|
||||
"Unable to write registers 0x%02x..0x%02x\n",
|
||||
reg, reg + count - 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
|
||||
{
|
||||
struct i2c_client *client = dev_id;
|
||||
struct rv8803_data *rv8803 = i2c_get_clientdata(client);
|
||||
unsigned long events = 0;
|
||||
int flags, try = 0;
|
||||
int flags;
|
||||
|
||||
mutex_lock(&rv8803->flags_lock);
|
||||
|
||||
do {
|
||||
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
|
||||
try++;
|
||||
} while ((flags == -ENXIO) && (try < 3));
|
||||
flags = rv8803_read_reg(client, RV8803_FLAG);
|
||||
if (flags <= 0) {
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
return IRQ_NONE;
|
||||
@ -100,9 +169,8 @@ static irqreturn_t rv8803_handle_irq(int irq, void *dev_id)
|
||||
|
||||
if (events) {
|
||||
rtc_update_irq(rv8803->rtc, 1, events);
|
||||
i2c_smbus_write_byte_data(client, RV8803_FLAG, flags);
|
||||
i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL,
|
||||
rv8803->ctrl);
|
||||
rv8803_write_reg(client, RV8803_FLAG, flags);
|
||||
rv8803_write_reg(rv8803->client, RV8803_CTRL, rv8803->ctrl);
|
||||
}
|
||||
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
@ -118,7 +186,7 @@ static int rv8803_get_time(struct device *dev, struct rtc_time *tm)
|
||||
u8 *date = date1;
|
||||
int ret, flags;
|
||||
|
||||
flags = i2c_smbus_read_byte_data(rv8803->client, RV8803_FLAG);
|
||||
flags = rv8803_read_reg(rv8803->client, RV8803_FLAG);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
|
||||
@ -127,16 +195,14 @@ static int rv8803_get_time(struct device *dev, struct rtc_time *tm)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(rv8803->client, RV8803_SEC,
|
||||
7, date);
|
||||
if (ret != 7)
|
||||
return ret < 0 ? ret : -EIO;
|
||||
ret = rv8803_read_regs(rv8803->client, RV8803_SEC, 7, date);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if ((date1[RV8803_SEC] & 0x7f) == bin2bcd(59)) {
|
||||
ret = i2c_smbus_read_i2c_block_data(rv8803->client, RV8803_SEC,
|
||||
7, date2);
|
||||
if (ret != 7)
|
||||
return ret < 0 ? ret : -EIO;
|
||||
ret = rv8803_read_regs(rv8803->client, RV8803_SEC, 7, date2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if ((date2[RV8803_SEC] & 0x7f) != bin2bcd(59))
|
||||
date = date2;
|
||||
@ -145,23 +211,33 @@ static int rv8803_get_time(struct device *dev, struct rtc_time *tm)
|
||||
tm->tm_sec = bcd2bin(date[RV8803_SEC] & 0x7f);
|
||||
tm->tm_min = bcd2bin(date[RV8803_MIN] & 0x7f);
|
||||
tm->tm_hour = bcd2bin(date[RV8803_HOUR] & 0x3f);
|
||||
tm->tm_wday = ffs(date[RV8803_WEEK] & 0x7f);
|
||||
tm->tm_wday = ilog2(date[RV8803_WEEK] & 0x7f);
|
||||
tm->tm_mday = bcd2bin(date[RV8803_DAY] & 0x3f);
|
||||
tm->tm_mon = bcd2bin(date[RV8803_MONTH] & 0x1f) - 1;
|
||||
tm->tm_year = bcd2bin(date[RV8803_YEAR]) + 100;
|
||||
|
||||
return rtc_valid_tm(tm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
|
||||
{
|
||||
struct rv8803_data *rv8803 = dev_get_drvdata(dev);
|
||||
u8 date[7];
|
||||
int flags, ret;
|
||||
int ctrl, flags, ret;
|
||||
|
||||
if ((tm->tm_year < 100) || (tm->tm_year > 199))
|
||||
return -EINVAL;
|
||||
|
||||
ctrl = rv8803_read_reg(rv8803->client, RV8803_CTRL);
|
||||
if (ctrl < 0)
|
||||
return ctrl;
|
||||
|
||||
/* Stop the clock */
|
||||
ret = rv8803_write_reg(rv8803->client, RV8803_CTRL,
|
||||
ctrl | RV8803_CTRL_RESET);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
date[RV8803_SEC] = bin2bcd(tm->tm_sec);
|
||||
date[RV8803_MIN] = bin2bcd(tm->tm_min);
|
||||
date[RV8803_HOUR] = bin2bcd(tm->tm_hour);
|
||||
@ -170,21 +246,26 @@ static int rv8803_set_time(struct device *dev, struct rtc_time *tm)
|
||||
date[RV8803_MONTH] = bin2bcd(tm->tm_mon + 1);
|
||||
date[RV8803_YEAR] = bin2bcd(tm->tm_year - 100);
|
||||
|
||||
ret = i2c_smbus_write_i2c_block_data(rv8803->client, RV8803_SEC,
|
||||
7, date);
|
||||
if (ret < 0)
|
||||
ret = rv8803_write_regs(rv8803->client, RV8803_SEC, 7, date);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* Restart the clock */
|
||||
ret = rv8803_write_reg(rv8803->client, RV8803_CTRL,
|
||||
ctrl & ~RV8803_CTRL_RESET);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mutex_lock(&rv8803->flags_lock);
|
||||
|
||||
flags = i2c_smbus_read_byte_data(rv8803->client, RV8803_FLAG);
|
||||
flags = rv8803_read_reg(rv8803->client, RV8803_FLAG);
|
||||
if (flags < 0) {
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
return flags;
|
||||
}
|
||||
|
||||
ret = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG,
|
||||
flags & ~RV8803_FLAG_V2F);
|
||||
ret = rv8803_write_reg(rv8803->client, RV8803_FLAG,
|
||||
flags & ~(RV8803_FLAG_V1F | RV8803_FLAG_V2F));
|
||||
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
|
||||
@ -198,22 +279,18 @@ static int rv8803_get_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
u8 alarmvals[3];
|
||||
int flags, ret;
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(client, RV8803_ALARM_MIN,
|
||||
3, alarmvals);
|
||||
if (ret != 3)
|
||||
return ret < 0 ? ret : -EIO;
|
||||
ret = rv8803_read_regs(client, RV8803_ALARM_MIN, 3, alarmvals);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
|
||||
flags = rv8803_read_reg(client, RV8803_FLAG);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
|
||||
alrm->time.tm_sec = 0;
|
||||
alrm->time.tm_min = bcd2bin(alarmvals[0] & 0x7f);
|
||||
alrm->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f);
|
||||
alrm->time.tm_wday = -1;
|
||||
alrm->time.tm_mday = bcd2bin(alarmvals[2] & 0x3f);
|
||||
alrm->time.tm_mon = -1;
|
||||
alrm->time.tm_year = -1;
|
||||
|
||||
alrm->enabled = !!(rv8803->ctrl & RV8803_CTRL_AIE);
|
||||
alrm->pending = (flags & RV8803_FLAG_AF) && alrm->enabled;
|
||||
@ -239,10 +316,10 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
mutex_lock(&rv8803->flags_lock);
|
||||
|
||||
ret = i2c_smbus_read_i2c_block_data(client, RV8803_FLAG, 2, ctrl);
|
||||
if (ret != 2) {
|
||||
ret = rv8803_read_regs(client, RV8803_FLAG, 2, ctrl);
|
||||
if (ret) {
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
return ret < 0 ? ret : -EIO;
|
||||
return ret;
|
||||
}
|
||||
|
||||
alarmvals[0] = bin2bcd(alrm->time.tm_min);
|
||||
@ -251,8 +328,8 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
|
||||
if (rv8803->ctrl & (RV8803_CTRL_AIE | RV8803_CTRL_UIE)) {
|
||||
rv8803->ctrl &= ~(RV8803_CTRL_AIE | RV8803_CTRL_UIE);
|
||||
err = i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL,
|
||||
rv8803->ctrl);
|
||||
err = rv8803_write_reg(rv8803->client, RV8803_CTRL,
|
||||
rv8803->ctrl);
|
||||
if (err) {
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
return err;
|
||||
@ -260,13 +337,12 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
}
|
||||
|
||||
ctrl[1] &= ~RV8803_FLAG_AF;
|
||||
err = i2c_smbus_write_byte_data(rv8803->client, RV8803_FLAG, ctrl[1]);
|
||||
err = rv8803_write_reg(rv8803->client, RV8803_FLAG, ctrl[1]);
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = i2c_smbus_write_i2c_block_data(rv8803->client, RV8803_ALARM_MIN,
|
||||
3, alarmvals);
|
||||
err = rv8803_write_regs(rv8803->client, RV8803_ALARM_MIN, 3, alarmvals);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@ -276,8 +352,8 @@ static int rv8803_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
if (rv8803->rtc->aie_timer.enabled)
|
||||
rv8803->ctrl |= RV8803_CTRL_AIE;
|
||||
|
||||
err = i2c_smbus_write_byte_data(rv8803->client, RV8803_CTRL,
|
||||
rv8803->ctrl);
|
||||
err = rv8803_write_reg(rv8803->client, RV8803_CTRL,
|
||||
rv8803->ctrl);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@ -306,21 +382,20 @@ static int rv8803_alarm_irq_enable(struct device *dev, unsigned int enabled)
|
||||
}
|
||||
|
||||
mutex_lock(&rv8803->flags_lock);
|
||||
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
|
||||
flags = rv8803_read_reg(client, RV8803_FLAG);
|
||||
if (flags < 0) {
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
return flags;
|
||||
}
|
||||
flags &= ~(RV8803_FLAG_AF | RV8803_FLAG_UF);
|
||||
err = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags);
|
||||
err = rv8803_write_reg(client, RV8803_FLAG, flags);
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (ctrl != rv8803->ctrl) {
|
||||
rv8803->ctrl = ctrl;
|
||||
err = i2c_smbus_write_byte_data(client, RV8803_CTRL,
|
||||
rv8803->ctrl);
|
||||
err = rv8803_write_reg(client, RV8803_CTRL, rv8803->ctrl);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
@ -336,7 +411,7 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
|
||||
|
||||
switch (cmd) {
|
||||
case RTC_VL_READ:
|
||||
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
|
||||
flags = rv8803_read_reg(client, RV8803_FLAG);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
|
||||
@ -355,16 +430,16 @@ static int rv8803_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
|
||||
|
||||
case RTC_VL_CLR:
|
||||
mutex_lock(&rv8803->flags_lock);
|
||||
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
|
||||
flags = rv8803_read_reg(client, RV8803_FLAG);
|
||||
if (flags < 0) {
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
return flags;
|
||||
}
|
||||
|
||||
flags &= ~(RV8803_FLAG_V1F | RV8803_FLAG_V2F);
|
||||
ret = i2c_smbus_write_byte_data(client, RV8803_FLAG, flags);
|
||||
ret = rv8803_write_reg(client, RV8803_FLAG, flags);
|
||||
mutex_unlock(&rv8803->flags_lock);
|
||||
if (ret < 0)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 0;
|
||||
@ -382,8 +457,8 @@ static ssize_t rv8803_nvram_write(struct file *filp, struct kobject *kobj,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_write_byte_data(client, RV8803_RAM, buf[0]);
|
||||
if (ret < 0)
|
||||
ret = rv8803_write_reg(client, RV8803_RAM, buf[0]);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return 1;
|
||||
@ -397,7 +472,7 @@ static ssize_t rv8803_nvram_read(struct file *filp, struct kobject *kobj,
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
int ret;
|
||||
|
||||
ret = i2c_smbus_read_byte_data(client, RV8803_RAM);
|
||||
ret = rv8803_read_reg(client, RV8803_RAM);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
@ -427,7 +502,7 @@ static int rv8803_probe(struct i2c_client *client,
|
||||
{
|
||||
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
|
||||
struct rv8803_data *rv8803;
|
||||
int err, flags, try = 0;
|
||||
int err, flags;
|
||||
|
||||
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA |
|
||||
I2C_FUNC_SMBUS_I2C_BLOCK)) {
|
||||
@ -444,16 +519,7 @@ static int rv8803_probe(struct i2c_client *client,
|
||||
rv8803->client = client;
|
||||
i2c_set_clientdata(client, rv8803);
|
||||
|
||||
/*
|
||||
* There is a 60µs window where the RTC may not reply on the i2c bus in
|
||||
* that case, the transfer is not ACKed. In that case, ensure there are
|
||||
* multiple attempts.
|
||||
*/
|
||||
do {
|
||||
flags = i2c_smbus_read_byte_data(client, RV8803_FLAG);
|
||||
try++;
|
||||
} while ((flags == -ENXIO) && (try < 3));
|
||||
|
||||
flags = rv8803_read_reg(client, RV8803_FLAG);
|
||||
if (flags < 0)
|
||||
return flags;
|
||||
|
||||
@ -488,12 +554,7 @@ static int rv8803_probe(struct i2c_client *client,
|
||||
return PTR_ERR(rv8803->rtc);
|
||||
}
|
||||
|
||||
try = 0;
|
||||
do {
|
||||
err = i2c_smbus_write_byte_data(rv8803->client, RV8803_EXT,
|
||||
RV8803_EXT_WADA);
|
||||
try++;
|
||||
} while ((err == -ENXIO) && (try < 3));
|
||||
err = rv8803_write_reg(rv8803->client, RV8803_EXT, RV8803_EXT_WADA);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -272,15 +272,9 @@ static int rx8010_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
t->time.tm_min = bcd2bin(alarmvals[0] & 0x7f);
|
||||
t->time.tm_hour = bcd2bin(alarmvals[1] & 0x3f);
|
||||
|
||||
if (alarmvals[2] & RX8010_ALARM_AE)
|
||||
t->time.tm_mday = -1;
|
||||
else
|
||||
if (!(alarmvals[2] & RX8010_ALARM_AE))
|
||||
t->time.tm_mday = bcd2bin(alarmvals[2] & 0x7f);
|
||||
|
||||
t->time.tm_wday = -1;
|
||||
t->time.tm_mon = -1;
|
||||
t->time.tm_year = -1;
|
||||
|
||||
t->enabled = !!(rx8010->ctrlreg & RX8010_CTRL_AIE);
|
||||
t->pending = (flagreg & RX8010_FLAG_AF) && t->enabled;
|
||||
|
||||
|
@ -319,11 +319,6 @@ static int rx8025_read_alarm(struct device *dev, struct rtc_wkalrm *t)
|
||||
t->time.tm_hour = bcd2bin(ald[1] & 0x1f) % 12
|
||||
+ (ald[1] & 0x20 ? 12 : 0);
|
||||
|
||||
t->time.tm_wday = -1;
|
||||
t->time.tm_mday = -1;
|
||||
t->time.tm_mon = -1;
|
||||
t->time.tm_year = -1;
|
||||
|
||||
dev_dbg(dev, "%s: date: %ds %dm %dh %dmd %dm %dy\n",
|
||||
__func__,
|
||||
t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/bitrev.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define S35390A_CMD_STATUS1 0
|
||||
#define S35390A_CMD_STATUS2 1
|
||||
@ -34,10 +35,14 @@
|
||||
#define S35390A_ALRM_BYTE_HOURS 1
|
||||
#define S35390A_ALRM_BYTE_MINS 2
|
||||
|
||||
/* flags for STATUS1 */
|
||||
#define S35390A_FLAG_POC 0x01
|
||||
#define S35390A_FLAG_BLD 0x02
|
||||
#define S35390A_FLAG_INT2 0x04
|
||||
#define S35390A_FLAG_24H 0x40
|
||||
#define S35390A_FLAG_RESET 0x80
|
||||
|
||||
/* flag for STATUS2 */
|
||||
#define S35390A_FLAG_TEST 0x01
|
||||
|
||||
#define S35390A_INT2_MODE_MASK 0xF0
|
||||
@ -94,19 +99,63 @@ static int s35390a_get_reg(struct s35390a *s35390a, int reg, char *buf, int len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int s35390a_reset(struct s35390a *s35390a)
|
||||
/*
|
||||
* Returns <0 on error, 0 if rtc is setup fine and 1 if the chip was reset.
|
||||
* To keep the information if an irq is pending, pass the value read from
|
||||
* STATUS1 to the caller.
|
||||
*/
|
||||
static int s35390a_reset(struct s35390a *s35390a, char *status1)
|
||||
{
|
||||
char buf[1];
|
||||
char buf;
|
||||
int ret;
|
||||
unsigned initcount = 0;
|
||||
|
||||
if (s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf)) < 0)
|
||||
return -EIO;
|
||||
ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, status1, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!(buf[0] & (S35390A_FLAG_POC | S35390A_FLAG_BLD)))
|
||||
if (*status1 & S35390A_FLAG_POC)
|
||||
/*
|
||||
* Do not communicate for 0.5 seconds since the power-on
|
||||
* detection circuit is in operation.
|
||||
*/
|
||||
msleep(500);
|
||||
else if (!(*status1 & S35390A_FLAG_BLD))
|
||||
/*
|
||||
* If both POC and BLD are unset everything is fine.
|
||||
*/
|
||||
return 0;
|
||||
|
||||
buf[0] |= (S35390A_FLAG_RESET | S35390A_FLAG_24H);
|
||||
buf[0] &= 0xf0;
|
||||
return s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf));
|
||||
/*
|
||||
* At least one of POC and BLD are set, so reinitialise chip. Keeping
|
||||
* this information in the hardware to know later that the time isn't
|
||||
* valid is unfortunately not possible because POC and BLD are cleared
|
||||
* on read. So the reset is best done now.
|
||||
*
|
||||
* The 24H bit is kept over reset, so set it already here.
|
||||
*/
|
||||
initialize:
|
||||
*status1 = S35390A_FLAG_24H;
|
||||
buf = S35390A_FLAG_RESET | S35390A_FLAG_24H;
|
||||
ret = s35390a_set_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &buf, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (buf & (S35390A_FLAG_POC | S35390A_FLAG_BLD)) {
|
||||
/* Try up to five times to reset the chip */
|
||||
if (initcount < 5) {
|
||||
++initcount;
|
||||
goto initialize;
|
||||
} else
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int s35390a_disable_test_mode(struct s35390a *s35390a)
|
||||
@ -217,12 +266,12 @@ static int s35390a_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alm)
|
||||
alm->time.tm_min, alm->time.tm_hour, alm->time.tm_mday,
|
||||
alm->time.tm_mon, alm->time.tm_year, alm->time.tm_wday);
|
||||
|
||||
/* disable interrupt */
|
||||
/* disable interrupt (which deasserts the irq line) */
|
||||
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &sts, sizeof(sts));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* clear pending interrupt, if any */
|
||||
/* clear pending interrupt (in STATUS1 only), if any */
|
||||
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, &sts, sizeof(sts));
|
||||
if (err < 0)
|
||||
return err;
|
||||
@ -242,6 +291,8 @@ static int s35390a_set_alarm(struct i2c_client *client, struct rtc_wkalrm *alm)
|
||||
|
||||
if (alm->time.tm_wday != -1)
|
||||
buf[S35390A_ALRM_BYTE_WDAY] = bin2bcd(alm->time.tm_wday) | 0x80;
|
||||
else
|
||||
buf[S35390A_ALRM_BYTE_WDAY] = 0;
|
||||
|
||||
buf[S35390A_ALRM_BYTE_HOURS] = s35390a_hr2reg(s35390a,
|
||||
alm->time.tm_hour) | 0x80;
|
||||
@ -269,23 +320,43 @@ static int s35390a_read_alarm(struct i2c_client *client, struct rtc_wkalrm *alm)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (bitrev8(sts) != S35390A_INT2_MODE_ALARM)
|
||||
return -EINVAL;
|
||||
if ((bitrev8(sts) & S35390A_INT2_MODE_MASK) != S35390A_INT2_MODE_ALARM) {
|
||||
/*
|
||||
* When the alarm isn't enabled, the register to configure
|
||||
* the alarm time isn't accessible.
|
||||
*/
|
||||
alm->enabled = 0;
|
||||
return 0;
|
||||
} else {
|
||||
alm->enabled = 1;
|
||||
}
|
||||
|
||||
err = s35390a_get_reg(s35390a, S35390A_CMD_INT2_REG1, buf, sizeof(buf));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* This chip returns the bits of each byte in reverse order */
|
||||
for (i = 0; i < 3; ++i) {
|
||||
for (i = 0; i < 3; ++i)
|
||||
buf[i] = bitrev8(buf[i]);
|
||||
buf[i] &= ~0x80;
|
||||
}
|
||||
|
||||
alm->time.tm_wday = bcd2bin(buf[S35390A_ALRM_BYTE_WDAY]);
|
||||
alm->time.tm_hour = s35390a_reg2hr(s35390a,
|
||||
buf[S35390A_ALRM_BYTE_HOURS]);
|
||||
alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS]);
|
||||
/*
|
||||
* B0 of the three matching registers is an enable flag. Iff it is set
|
||||
* the configured value is used for matching.
|
||||
*/
|
||||
if (buf[S35390A_ALRM_BYTE_WDAY] & 0x80)
|
||||
alm->time.tm_wday =
|
||||
bcd2bin(buf[S35390A_ALRM_BYTE_WDAY] & ~0x80);
|
||||
|
||||
if (buf[S35390A_ALRM_BYTE_HOURS] & 0x80)
|
||||
alm->time.tm_hour =
|
||||
s35390a_reg2hr(s35390a,
|
||||
buf[S35390A_ALRM_BYTE_HOURS] & ~0x80);
|
||||
|
||||
if (buf[S35390A_ALRM_BYTE_MINS] & 0x80)
|
||||
alm->time.tm_min = bcd2bin(buf[S35390A_ALRM_BYTE_MINS] & ~0x80);
|
||||
|
||||
/* alarm triggers always at s=0 */
|
||||
alm->time.tm_sec = 0;
|
||||
|
||||
dev_dbg(&client->dev, "%s: alm is mins=%d, hours=%d, wday=%d\n",
|
||||
__func__, alm->time.tm_min, alm->time.tm_hour,
|
||||
@ -327,11 +398,11 @@ static struct i2c_driver s35390a_driver;
|
||||
static int s35390a_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
int err;
|
||||
int err, err_reset;
|
||||
unsigned int i;
|
||||
struct s35390a *s35390a;
|
||||
struct rtc_time tm;
|
||||
char buf[1];
|
||||
char buf, status1;
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
err = -ENODEV;
|
||||
@ -360,29 +431,35 @@ static int s35390a_probe(struct i2c_client *client,
|
||||
}
|
||||
}
|
||||
|
||||
err = s35390a_reset(s35390a);
|
||||
if (err < 0) {
|
||||
err_reset = s35390a_reset(s35390a, &status1);
|
||||
if (err_reset < 0) {
|
||||
err = err_reset;
|
||||
dev_err(&client->dev, "error resetting chip\n");
|
||||
goto exit_dummy;
|
||||
}
|
||||
|
||||
err = s35390a_disable_test_mode(s35390a);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "error disabling test mode\n");
|
||||
goto exit_dummy;
|
||||
}
|
||||
|
||||
err = s35390a_get_reg(s35390a, S35390A_CMD_STATUS1, buf, sizeof(buf));
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "error checking 12/24 hour mode\n");
|
||||
goto exit_dummy;
|
||||
}
|
||||
if (buf[0] & S35390A_FLAG_24H)
|
||||
if (status1 & S35390A_FLAG_24H)
|
||||
s35390a->twentyfourhour = 1;
|
||||
else
|
||||
s35390a->twentyfourhour = 0;
|
||||
|
||||
if (s35390a_get_datetime(client, &tm) < 0)
|
||||
if (status1 & S35390A_FLAG_INT2) {
|
||||
/* disable alarm (and maybe test mode) */
|
||||
buf = 0;
|
||||
err = s35390a_set_reg(s35390a, S35390A_CMD_STATUS2, &buf, 1);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "error disabling alarm");
|
||||
goto exit_dummy;
|
||||
}
|
||||
} else {
|
||||
err = s35390a_disable_test_mode(s35390a);
|
||||
if (err < 0) {
|
||||
dev_err(&client->dev, "error disabling test mode\n");
|
||||
goto exit_dummy;
|
||||
}
|
||||
}
|
||||
|
||||
if (err_reset > 0 || s35390a_get_datetime(client, &tm) < 0)
|
||||
dev_warn(&client->dev, "clock needs to be set\n");
|
||||
|
||||
device_set_wakeup_capable(&client->dev, 1);
|
||||
@ -395,6 +472,10 @@ static int s35390a_probe(struct i2c_client *client,
|
||||
err = PTR_ERR(s35390a->rtc);
|
||||
goto exit_dummy;
|
||||
}
|
||||
|
||||
if (status1 & S35390A_FLAG_INT2)
|
||||
rtc_update_irq(s35390a->rtc, 1, RTC_AF);
|
||||
|
||||
return 0;
|
||||
|
||||
exit_dummy:
|
||||
|
@ -149,12 +149,14 @@ static int s3c_rtc_setfreq(struct s3c_rtc *info, int freq)
|
||||
if (!is_power_of_2(freq))
|
||||
return -EINVAL;
|
||||
|
||||
s3c_rtc_enable_clk(info);
|
||||
spin_lock_irq(&info->pie_lock);
|
||||
|
||||
if (info->data->set_freq)
|
||||
info->data->set_freq(info, freq);
|
||||
|
||||
spin_unlock_irq(&info->pie_lock);
|
||||
s3c_rtc_disable_clk(info);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -264,35 +266,23 @@ static int s3c_rtc_getalarm(struct device *dev, struct rtc_wkalrm *alrm)
|
||||
/* decode the alarm enable field */
|
||||
if (alm_en & S3C2410_RTCALM_SECEN)
|
||||
alm_tm->tm_sec = bcd2bin(alm_tm->tm_sec);
|
||||
else
|
||||
alm_tm->tm_sec = -1;
|
||||
|
||||
if (alm_en & S3C2410_RTCALM_MINEN)
|
||||
alm_tm->tm_min = bcd2bin(alm_tm->tm_min);
|
||||
else
|
||||
alm_tm->tm_min = -1;
|
||||
|
||||
if (alm_en & S3C2410_RTCALM_HOUREN)
|
||||
alm_tm->tm_hour = bcd2bin(alm_tm->tm_hour);
|
||||
else
|
||||
alm_tm->tm_hour = -1;
|
||||
|
||||
if (alm_en & S3C2410_RTCALM_DAYEN)
|
||||
alm_tm->tm_mday = bcd2bin(alm_tm->tm_mday);
|
||||
else
|
||||
alm_tm->tm_mday = -1;
|
||||
|
||||
if (alm_en & S3C2410_RTCALM_MONEN) {
|
||||
alm_tm->tm_mon = bcd2bin(alm_tm->tm_mon);
|
||||
alm_tm->tm_mon -= 1;
|
||||
} else {
|
||||
alm_tm->tm_mon = -1;
|
||||
}
|
||||
|
||||
if (alm_en & S3C2410_RTCALM_YEAREN)
|
||||
alm_tm->tm_year = bcd2bin(alm_tm->tm_year);
|
||||
else
|
||||
alm_tm->tm_year = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -577,8 +567,6 @@ static int s3c_rtc_probe(struct platform_device *pdev)
|
||||
|
||||
s3c_rtc_setfreq(info, 1);
|
||||
|
||||
s3c_rtc_disable_clk(info);
|
||||
|
||||
return 0;
|
||||
|
||||
err_nortc:
|
||||
|
@ -481,7 +481,6 @@ static int sh_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
||||
tm->tm_mon = sh_rtc_read_alarm_value(rtc, RMONAR);
|
||||
if (tm->tm_mon > 0)
|
||||
tm->tm_mon -= 1; /* RTC is 1-12, tm_mon is 0-11 */
|
||||
tm->tm_year = 0xffff;
|
||||
|
||||
wkalrm->enabled = (readb(rtc->regbase + RCR1) & RCR1_AIE) ? 1 : 0;
|
||||
|
||||
@ -500,52 +499,13 @@ static inline void sh_rtc_write_alarm_value(struct sh_rtc *rtc,
|
||||
writeb(bin2bcd(value) | AR_ENB, rtc->regbase + reg_off);
|
||||
}
|
||||
|
||||
static int sh_rtc_check_alarm(struct rtc_time *tm)
|
||||
{
|
||||
/*
|
||||
* The original rtc says anything > 0xc0 is "don't care" or "match
|
||||
* all" - most users use 0xff but rtc-dev uses -1 for the same thing.
|
||||
* The original rtc doesn't support years - some things use -1 and
|
||||
* some 0xffff. We use -1 to make out tests easier.
|
||||
*/
|
||||
if (tm->tm_year == 0xffff)
|
||||
tm->tm_year = -1;
|
||||
if (tm->tm_mon >= 0xff)
|
||||
tm->tm_mon = -1;
|
||||
if (tm->tm_mday >= 0xff)
|
||||
tm->tm_mday = -1;
|
||||
if (tm->tm_wday >= 0xff)
|
||||
tm->tm_wday = -1;
|
||||
if (tm->tm_hour >= 0xff)
|
||||
tm->tm_hour = -1;
|
||||
if (tm->tm_min >= 0xff)
|
||||
tm->tm_min = -1;
|
||||
if (tm->tm_sec >= 0xff)
|
||||
tm->tm_sec = -1;
|
||||
|
||||
if (tm->tm_year > 9999 ||
|
||||
tm->tm_mon >= 12 ||
|
||||
tm->tm_mday == 0 || tm->tm_mday >= 32 ||
|
||||
tm->tm_wday >= 7 ||
|
||||
tm->tm_hour >= 24 ||
|
||||
tm->tm_min >= 60 ||
|
||||
tm->tm_sec >= 60)
|
||||
return -EINVAL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sh_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
|
||||
{
|
||||
struct platform_device *pdev = to_platform_device(dev);
|
||||
struct sh_rtc *rtc = platform_get_drvdata(pdev);
|
||||
unsigned int rcr1;
|
||||
struct rtc_time *tm = &wkalrm->time;
|
||||
int mon, err;
|
||||
|
||||
err = sh_rtc_check_alarm(tm);
|
||||
if (unlikely(err < 0))
|
||||
return err;
|
||||
int mon;
|
||||
|
||||
spin_lock_irq(&rtc->lock);
|
||||
|
||||
|
@ -179,12 +179,6 @@ static int tegra_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
|
||||
if (sec == 0) {
|
||||
/* alarm is disabled. */
|
||||
alarm->enabled = 0;
|
||||
alarm->time.tm_mon = -1;
|
||||
alarm->time.tm_mday = -1;
|
||||
alarm->time.tm_year = -1;
|
||||
alarm->time.tm_hour = -1;
|
||||
alarm->time.tm_min = -1;
|
||||
alarm->time.tm_sec = -1;
|
||||
} else {
|
||||
/* alarm is enabled. */
|
||||
alarm->enabled = 1;
|
||||
|
@ -25,7 +25,7 @@
|
||||
#include <linux/rtc.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/rtc-v3020.h>
|
||||
#include <linux/platform_data/rtc-v3020.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* ds17287rtc.h - register definitions for the ds1728[57] RTC / CMOS RAM
|
||||
*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* (C) 2003 Guido Guenther <agx@sigxcpu.org>
|
||||
*/
|
||||
#ifndef __LINUX_DS17287RTC_H
|
||||
#define __LINUX_DS17287RTC_H
|
||||
|
||||
#include <linux/rtc.h> /* get the user-level API */
|
||||
#include <linux/mc146818rtc.h>
|
||||
|
||||
/* Register A */
|
||||
#define DS_REGA_DV2 0x40 /* countdown chain */
|
||||
#define DS_REGA_DV1 0x20 /* oscillator enable */
|
||||
#define DS_REGA_DV0 0x10 /* bank select */
|
||||
|
||||
/* bank 1 registers */
|
||||
#define DS_B1_MODEL 0x40 /* model number byte */
|
||||
#define DS_B1_SN1 0x41 /* serial number byte 1 */
|
||||
#define DS_B1_SN2 0x42 /* serial number byte 2 */
|
||||
#define DS_B1_SN3 0x43 /* serial number byte 3 */
|
||||
#define DS_B1_SN4 0x44 /* serial number byte 4 */
|
||||
#define DS_B1_SN5 0x45 /* serial number byte 5 */
|
||||
#define DS_B1_SN6 0x46 /* serial number byte 6 */
|
||||
#define DS_B1_CRC 0x47 /* CRC byte */
|
||||
#define DS_B1_CENTURY 0x48 /* Century byte */
|
||||
#define DS_B1_DALARM 0x49 /* date alarm */
|
||||
#define DS_B1_XCTRL4A 0x4a /* extendec control register 4a */
|
||||
#define DS_B1_XCTRL4B 0x4b /* extendec control register 4b */
|
||||
#define DS_B1_RTCADDR2 0x4e /* rtc address 2 */
|
||||
#define DS_B1_RTCADDR3 0x4f /* rtc address 3 */
|
||||
#define DS_B1_RAMLSB 0x50 /* extended ram LSB */
|
||||
#define DS_B1_RAMMSB 0x51 /* extended ram MSB */
|
||||
#define DS_B1_RAMDPORT 0x53 /* extended ram data port */
|
||||
|
||||
/* register details */
|
||||
/* extended control register 4a */
|
||||
#define DS_XCTRL4A_VRT2 0x80 /* valid ram and time */
|
||||
#define DS_XCTRL4A_INCR 0x40 /* increment progress status */
|
||||
#define DS_XCTRL4A_BME 0x20 /* burst mode enable */
|
||||
#define DS_XCTRL4A_PAB 0x08 /* power active bar ctrl */
|
||||
#define DS_XCTRL4A_RF 0x04 /* ram clear flag */
|
||||
#define DS_XCTRL4A_WF 0x02 /* wake up alarm flag */
|
||||
#define DS_XCTRL4A_KF 0x01 /* kickstart flag */
|
||||
|
||||
/* interrupt causes */
|
||||
#define DS_XCTRL4A_IFS (DS_XCTRL4A_RF|DS_XCTRL4A_WF|DS_XCTRL4A_KF)
|
||||
|
||||
/* extended control register 4b */
|
||||
#define DS_XCTRL4B_ABE 0x80 /* auxiliary battery enable */
|
||||
#define DS_XCTRL4B_E32K 0x40 /* enable 32.768 kHz Output */
|
||||
#define DS_XCTRL4B_CS 0x20 /* crystal select */
|
||||
#define DS_XCTRL4B_RCE 0x10 /* ram clear enable */
|
||||
#define DS_XCTRL4B_PRS 0x08 /* PAB resec select */
|
||||
#define DS_XCTRL4B_RIE 0x04 /* ram clear interrupt enable */
|
||||
#define DS_XCTRL4B_WFE 0x02 /* wake up alarm interrupt enable */
|
||||
#define DS_XCTRL4B_KFE 0x01 /* kickstart interrupt enable */
|
||||
|
||||
/* interrupt enable bits */
|
||||
#define DS_XCTRL4B_IFES (DS_XCTRL4B_RIE|DS_XCTRL4B_WFE|DS_XCTRL4B_KFE)
|
||||
|
||||
#endif /* __LINUX_DS17287RTC_H */
|
@ -14,6 +14,8 @@
|
||||
#include <asm/io.h>
|
||||
#include <linux/rtc.h> /* get the user-level API */
|
||||
#include <asm/mc146818rtc.h> /* register access macros */
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/spinlock.h> /* spinlock_t */
|
||||
@ -120,4 +122,7 @@ struct cmos_rtc_board_info {
|
||||
#define RTC_IO_EXTENT_USED RTC_IO_EXTENT
|
||||
#endif /* ARCH_RTC_LOCATION */
|
||||
|
||||
unsigned int mc146818_get_time(struct rtc_time *time);
|
||||
int mc146818_set_time(struct rtc_time *time);
|
||||
|
||||
#endif /* _MC146818RTC_H */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user