aboutsummaryrefslogtreecommitdiff
path: root/arch/m32r/include/asm/processor.h
blob: 8397c249989b36561eca1fc0c99ddd842dedc061 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#ifndef _ASM_M32R_PROCESSOR_H
#define _ASM_M32R_PROCESSOR_H

/*
 * include/asm-m32r/processor.h
 *
 * 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.
 *
 * Copyright (C) 1994  Linus Torvalds
 * Copyright (C) 2001  Hiroyuki Kondo, Hirokazu Takata, and Hitoshi Yamamoto
 * Copyright (C) 2004  Hirokazu Takata <takata at linux-m32r.org>
 */

#include <linux/kernel.h>
#include <asm/cache.h>
#include <asm/ptrace.h>  /* pt_regs */

/*
 * Default implementation of macro that returns current
 * instruction pointer ("program counter").
 */
#define current_text_addr() ({ __label__ _l; _l: &&_l; })

/*
 *  CPU type and hardware bug flags. Kept separately for each CPU.
 *  Members of this structure are referenced in head.S, so think twice
 *  before touching them. [mj]
 */

struct cpuinfo_m32r {
	unsigned long pgtable_cache_sz;
	unsigned long cpu_clock;
	unsigned long bus_clock;
	unsigned long timer_divide;
	unsigned long loops_per_jiffy;
};

/*
 * capabilities of CPUs
 */

extern struct cpuinfo_m32r boot_cpu_data;

#ifdef CONFIG_SMP
extern struct cpuinfo_m32r cpu_data[];
#define current_cpu_data cpu_data[smp_processor_id()]
#else
#define cpu_data (&boot_cpu_data)
#define current_cpu_data boot_cpu_data
#endif

/*
 * User space process size: 2GB (default).
 */
#ifdef CONFIG_MMU
#define TASK_SIZE  (0x80000000UL)
#else
#define TASK_SIZE  (0x00400000UL)
#endif

#ifdef __KERNEL__
#define STACK_TOP	TASK_SIZE
#define STACK_TOP_MAX	STACK_TOP
#endif

/* This decides where the kernel will search for a free chunk of vm
 * space during mmap's.
 */
#define TASK_UNMAPPED_BASE	PAGE_ALIGN(TASK_SIZE / 3)

typedef struct {
	unsigned long seg;
} mm_segment_t;

#define MAX_TRAPS 10

struct debug_trap {
	int nr_trap;
	unsigned long	addr[MAX_TRAPS];
	unsigned long	insn[MAX_TRAPS];
};

struct thread_struct {
	unsigned long address;
	unsigned long trap_no;		/* Trap number  */
	unsigned long error_code;	/* Error code of trap */
	unsigned long lr;		/* saved pc */
	unsigned long sp;		/* user stack pointer */
	struct debug_trap debug_trap;
};

#define INIT_SP	(sizeof(init_stack) + (unsigned long) &init_stack)

#define INIT_THREAD	{	\
	.sp = INIT_SP,		\
}

/*
 * Do necessary setup to start up a newly executed thread.
 */

/* User process Backup PSW */
#define USERPS_BPSW (M32R_PSW_BSM|M32R_PSW_BIE|M32R_PSW_BPM)

#define start_thread(regs, new_pc, new_spu) 				\
	do {								\
		set_fs(USER_DS); 					\
		regs->psw = (regs->psw | USERPS_BPSW) & 0x0000FFFFUL;	\
		regs->bpc = new_pc;					\
		regs->spu = new_spu;					\
	} while (0)

/* Forward declaration, a strange C thing */
struct task_struct;
struct mm_struct;

/* Free all resources held by a thread. */
extern void release_thread(struct task_struct *);

#define prepare_to_copy(tsk)	do { } while (0)

/*
 * create a kernel thread without removing it from tasklists
 */
extern int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags);

/* Copy and release all segment info associated with a VM */
extern void copy_segments(struct task_struct *p, struct mm_struct * mm);
extern void release_segments(struct mm_struct * mm);

extern unsigned long thread_saved_pc(struct task_struct *);

/* Copy and release all segment info associated with a VM */
#define copy_segments(p, mm)  do { } while (0)
#define release_segments(mm)  do { } while (0)

unsigned long get_wchan(struct task_struct *p);
#define KSTK_EIP(tsk)  ((tsk)->thread.lr)
#define KSTK_ESP(tsk)  ((tsk)->thread.sp)

#define cpu_relax()	barrier()

#endif /* _ASM_M32R_PROCESSOR_H */
3a60e1ca563a0'>drivers/rtc/rtc-jz4740.c83
-rw-r--r--drivers/rtc/rtc-lp8788.c327
-rw-r--r--drivers/rtc/rtc-lpc32xx.c57
-rw-r--r--drivers/rtc/rtc-ls1x.c199
-rw-r--r--drivers/rtc/rtc-m41t80.c292
-rw-r--r--drivers/rtc/rtc-m41t93.c78
-rw-r--r--drivers/rtc/rtc-m41t94.c33
-rw-r--r--drivers/rtc/rtc-m48t35.c52
-rw-r--r--drivers/rtc/rtc-m48t59.c80
-rw-r--r--drivers/rtc/rtc-m48t86.c29
-rw-r--r--drivers/rtc/rtc-max6900.c37
-rw-r--r--drivers/rtc/rtc-max6902.c55
-rw-r--r--drivers/rtc/rtc-max77686.c616
-rw-r--r--drivers/rtc/rtc-max8907.c225
-rw-r--r--drivers/rtc/rtc-max8925.c63
-rw-r--r--drivers/rtc/rtc-max8997.c537
-rw-r--r--drivers/rtc/rtc-max8998.c48
-rw-r--r--drivers/rtc/rtc-mc13xxx.c170
-rw-r--r--drivers/rtc/rtc-mcp795.c199
-rw-r--r--drivers/rtc/rtc-moxart.c328
-rw-r--r--drivers/rtc/rtc-mpc5121.c40
-rw-r--r--drivers/rtc/rtc-mrst.c20
-rw-r--r--drivers/rtc/rtc-msm6242.c62
-rw-r--r--drivers/rtc/rtc-mv.c89
-rw-r--r--drivers/rtc/rtc-mxc.c111
-rw-r--r--drivers/rtc/rtc-nuc900.c86
-rw-r--r--drivers/rtc/rtc-omap.c272
-rw-r--r--drivers/rtc/rtc-palmas.c378
-rw-r--r--drivers/rtc/rtc-pcap.c58
-rw-r--r--drivers/rtc/rtc-pcf2123.c60
-rw-r--r--drivers/rtc/rtc-pcf2127.c232
-rw-r--r--drivers/rtc/rtc-pcf50633.c21
-rw-r--r--drivers/rtc/rtc-pcf8523.c347
-rw-r--r--drivers/rtc/rtc-pcf8563.c119
-rw-r--r--drivers/rtc/rtc-pcf8583.c52
-rw-r--r--drivers/rtc/rtc-pl030.c24
-rw-r--r--drivers/rtc/rtc-pl031.c152
-rw-r--r--drivers/rtc/rtc-pm8xxx.c317
-rw-r--r--drivers/rtc/rtc-proc.c26
-rw-r--r--drivers/rtc/rtc-ps3.c22
-rw-r--r--drivers/rtc/rtc-puv3.c56
-rw-r--r--drivers/rtc/rtc-pxa.c100
-rw-r--r--drivers/rtc/rtc-r9701.c61
-rw-r--r--drivers/rtc/rtc-rc5t583.c322
-rw-r--r--drivers/rtc/rtc-rp5c01.c45
-rw-r--r--drivers/rtc/rtc-rs5c313.c35
-rw-r--r--drivers/rtc/rtc-rs5c348.c44
-rw-r--r--drivers/rtc/rtc-rs5c372.c65
-rw-r--r--drivers/rtc/rtc-rv3029c2.c47
-rw-r--r--drivers/rtc/rtc-rx4581.c305
-rw-r--r--drivers/rtc/rtc-rx8025.c40
-rw-r--r--drivers/rtc/rtc-rx8581.c104
-rw-r--r--drivers/rtc/rtc-s35390a.c156
-rw-r--r--drivers/rtc/rtc-s3c.c249
-rw-r--r--drivers/rtc/rtc-s3c.h70
-rw-r--r--drivers/rtc/rtc-s5m.c848
-rw-r--r--drivers/rtc/rtc-sa1100.c218
-rw-r--r--drivers/rtc/rtc-sh.c101
-rw-r--r--drivers/rtc/rtc-sirfsoc.c423
-rw-r--r--drivers/rtc/rtc-snvs.c340
-rw-r--r--drivers/rtc/rtc-spear.c233
-rw-r--r--drivers/rtc/rtc-starfire.c29
-rw-r--r--drivers/rtc/rtc-stk17ta8.c32
-rw-r--r--drivers/rtc/rtc-stmp3xxx.c177
-rw-r--r--drivers/rtc/rtc-sun4v.c38
-rw-r--r--drivers/rtc/rtc-sunxi.c523
-rw-r--r--drivers/rtc/rtc-sysfs.c74
-rw-r--r--drivers/rtc/rtc-tegra.c123
-rw-r--r--drivers/rtc/rtc-test.c37
-rw-r--r--drivers/rtc/rtc-tile.c23
-rw-r--r--drivers/rtc/rtc-tps6586x.c351
-rw-r--r--drivers/rtc/rtc-tps65910.c338
-rw-r--r--drivers/rtc/rtc-tps80031.c338
-rw-r--r--drivers/rtc/rtc-twl.c216
-rw-r--r--drivers/rtc/rtc-tx4939.c39
-rw-r--r--drivers/rtc/rtc-v3020.c31
-rw-r--r--drivers/rtc/rtc-vr41xx.c70
-rw-r--r--drivers/rtc/rtc-vt8500.c93
-rw-r--r--drivers/rtc/rtc-wm831x.c47
-rw-r--r--drivers/rtc/rtc-wm8350.c23
-rw-r--r--drivers/rtc/rtc-x1205.c152
-rw-r--r--drivers/rtc/rtc-xgene.c278
-rw-r--r--drivers/rtc/systohc.c44
136 files changed, 16167 insertions, 4728 deletions
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 3a125b83554..0754f5c7cb3 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -19,16 +19,23 @@ if RTC_CLASS
config RTC_HCTOSYS
bool "Set system time from RTC on startup and resume"
- depends on RTC_CLASS = y
default y
help
If you say yes here, the system time (wall clock) will be set using
the value read from a specified RTC device. This is useful to avoid
unnecessary fsck runs at boot time, and to network better.
+config RTC_SYSTOHC
+ bool "Set the RTC time based on NTP synchronization"
+ default y
+ help
+ If you say yes here, the system time (wall clock) will be stored
+ in the RTC specified by RTC_HCTOSYS_DEVICE approximately every 11
+ minutes if userspace reports synchronized NTP status.
+
config RTC_HCTOSYS_DEVICE
string "RTC used to set the system time"
- depends on RTC_HCTOSYS = y
+ depends on RTC_HCTOSYS = y || RTC_SYSTOHC = y
default "rtc0"
help
The RTC device that will be used to (re)initialize the system
@@ -51,7 +58,6 @@ config RTC_HCTOSYS_DEVICE
config RTC_DEBUG
bool "RTC debug support"
- depends on RTC_CLASS = y
help
Say yes here to enable debugging support in the RTC framework
and individual RTC drivers.
@@ -69,13 +75,15 @@ config RTC_INTF_SYSFS
If unsure, say Y.
config RTC_INTF_PROC
- boolean "/proc/driver/rtc (procfs for rtc0)"
+ boolean "/proc/driver/rtc (procfs for rtcN)"
depends on PROC_FS
default RTC_CLASS
help
- Say yes here if you want to use your first RTC through the proc
- interface, /proc/driver/rtc. Other RTCs will not be available
- through that API.
+ Say yes here if you want to use your system clock RTC through
+ the proc interface, /proc/driver/rtc.
+ Other RTCs will not be available through that API.
+ If there is no RTC for the system clock, then the first RTC(rtc0)
+ is used by default.
If unsure, say Y.
@@ -127,7 +135,7 @@ if I2C
config RTC_DRV_88PM860X
tristate "Marvell 88PM860x"
- depends on RTC_CLASS && I2C && MFD_88PM860X
+ depends on I2C && MFD_88PM860X
help
If you say yes here you get support for RTC function in Marvell
88PM860x chips.
@@ -135,6 +143,26 @@ config RTC_DRV_88PM860X
This driver can also be built as a module. If so, the module
will be called rtc-88pm860x.
+config RTC_DRV_88PM80X
+ tristate "Marvell 88PM80x"
+ depends on I2C && MFD_88PM800
+ help
+ If you say yes here you get support for RTC function in Marvell
+ 88PM80x chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-88pm80x.
+
+config RTC_DRV_AS3722
+ tristate "ams AS3722 RTC driver"
+ depends on MFD_AS3722
+ help
+ If you say yes here you get support for the RTC of ams AS3722 PMIC
+ chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-as3722.
+
config RTC_DRV_DS1307
tristate "Dallas/Maxim DS1307/37/38/39/40, ST M41T00, EPSON RX-8025"
help
@@ -155,7 +183,7 @@ config RTC_DRV_DS1307
config RTC_DRV_DS1374
tristate "Dallas/Maxim DS1374"
- depends on RTC_CLASS && I2C
+ depends on I2C
help
If you say yes here you get support for Dallas Semiconductor
DS1374 real-time clock chips. If an interrupt is associated
@@ -175,7 +203,7 @@ config RTC_DRV_DS1672
config RTC_DRV_DS3232
tristate "Dallas/Maxim DS3232"
- depends on RTC_CLASS && I2C
+ depends on I2C
help
If you say yes here you get support for Dallas Semiconductor
DS3232 real-time clock chips. If an interrupt is associated
@@ -184,6 +212,23 @@ config RTC_DRV_DS3232
This driver can also be built as a module. If so, the module
will be called rtc-ds3232.
+config RTC_DRV_HYM8563
+ tristate "Haoyu Microelectronics HYM8563"
+ depends on I2C && OF
+ help
+ Say Y to enable support for the HYM8563 I2C RTC chip. Apart
+ from the usual rtc functions it provides a clock output of
+ up to 32kHz.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-hym8563.
+
+config RTC_DRV_LP8788
+ tristate "TI LP8788 RTC driver"
+ depends on MFD_LP8788
+ help
+ Say Y to enable support for the LP8788 RTC/ALARM driver.
+
config RTC_DRV_MAX6900
tristate "Maxim MAX6900"
help
@@ -193,6 +238,16 @@ config RTC_DRV_MAX6900
This driver can also be built as a module. If so, the module
will be called rtc-max6900.
+config RTC_DRV_MAX8907
+ tristate "Maxim MAX8907"
+ depends on MFD_MAX8907
+ help
+ If you say yes here you will get support for the
+ RTC of Maxim MAX8907 PMIC.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-max8907.
+
config RTC_DRV_MAX8925
tristate "Maxim MAX8925"
depends on MFD_MAX8925
@@ -213,6 +268,26 @@ config RTC_DRV_MAX8998
This driver can also be built as a module. If so, the module
will be called rtc-max8998.
+config RTC_DRV_MAX8997
+ tristate "Maxim MAX8997"
+ depends on MFD_MAX8997
+ help
+ If you say yes here you will get support for the
+ RTC of Maxim MAX8997 PMIC.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-max8997.
+
+config RTC_DRV_MAX77686
+ tristate "Maxim MAX77686"
+ depends on MFD_MAX77686
+ help
+ If you say yes here you will get support for the
+ RTC of Maxim MAX77686 PMIC.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-max77686.
+
config RTC_DRV_RS5C372
tristate "Ricoh R2025S/D, RS5C372A/B, RV5C386, RV5C387A"
help
@@ -240,6 +315,17 @@ config RTC_DRV_ISL12022
This driver can also be built as a module. If so, the module
will be called rtc-isl12022.
+config RTC_DRV_ISL12057
+ depends on I2C
+ select REGMAP_I2C
+ tristate "Intersil ISL12057"
+ help
+ If you say yes here you get support for the Intersil ISL12057
+ I2C RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-isl12057.
+
config RTC_DRV_X1205
tristate "Xicor/Intersil X1205"
help
@@ -249,6 +335,34 @@ config RTC_DRV_X1205
This driver can also be built as a module. If so, the module
will be called rtc-x1205.
+config RTC_DRV_PALMAS
+ tristate "TI Palmas RTC driver"
+ depends on MFD_PALMAS
+ help
+ If you say yes here you get support for the RTC of TI PALMA series PMIC
+ chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-palma.
+
+config RTC_DRV_PCF2127
+ tristate "NXP PCF2127"
+ help
+ If you say yes here you get support for the NXP PCF2127/29 RTC
+ chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-pcf2127.
+
+config RTC_DRV_PCF8523
+ tristate "NXP PCF8523"
+ help
+ If you say yes here you get support for the NXP PCF8523 RTC
+ chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-pcf8523.
+
config RTC_DRV_PCF8563
tristate "Philips PCF8563/Epson RTC8564"
help
@@ -272,12 +386,12 @@ config RTC_DRV_PCF8583
will be called rtc-pcf8583.
config RTC_DRV_M41T80
- tristate "ST M41T62/65/M41T80/81/82/83/84/85/87"
+ tristate "ST M41T62/65/M41T80/81/82/83/84/85/87 and compatible"
help
If you say Y here you will get support for the ST M41T60
and M41T80 RTC chips series. Currently, the following chips are
supported: M41T62, M41T65, M41T80, M41T81, M41T82, M41T83, M41ST84,
- M41ST85, and M41ST87.
+ M41ST85, M41ST87, and MicroCrystal RV4162.
This driver can also be built as a module. If so, the module
will be called rtc-m41t80.
@@ -315,7 +429,7 @@ config RTC_DRV_TWL92330
config RTC_DRV_TWL4030
tristate "TI TWL4030/TWL5030/TWL6030/TPS659x0"
- depends on RTC_CLASS && TWL4030_CORE
+ depends on TWL4030_CORE
help
If you say yes here you get support for the RTC on the
TWL4030/TWL5030/TWL6030 family chips, used mostly with OMAP3 platforms.
@@ -323,6 +437,42 @@ config RTC_DRV_TWL4030
This driver can also be built as a module. If so, the module
will be called rtc-twl.
+config RTC_DRV_TPS6586X
+ tristate "TI TPS6586X RTC driver"
+ depends on MFD_TPS6586X
+ help
+ TI Power Management IC TPS6586X supports RTC functionality
+ along with alarm. This driver supports the RTC driver for
+ the TPS6586X RTC module.
+
+config RTC_DRV_TPS65910
+ tristate "TI TPS65910 RTC driver"
+ depends on RTC_CLASS && MFD_TPS65910
+ help
+ If you say yes here you get support for the RTC on the
+ TPS65910 chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-tps65910.
+
+config RTC_DRV_TPS80031
+ tristate "TI TPS80031/TPS80032 RTC driver"
+ depends on MFD_TPS80031
+ help
+ TI Power Management IC TPS80031 supports RTC functionality
+ along with alarm. This driver supports the RTC driver for
+ the TPS80031 RTC module.
+
+config RTC_DRV_RC5T583
+ tristate "RICOH 5T583 RTC driver"
+ depends on MFD_RC5T583
+ help
+ If you say yes here you get support for the RTC on the
+ RICOH 5T583 chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-rc5t583.
+
config RTC_DRV_S35390A
tristate "Seiko Instruments S-35390A"
select BITREVERSE
@@ -379,6 +529,16 @@ config RTC_DRV_RV3029C2
This driver can also be built as a module. If so, the module
will be called rtc-rv3029c2.
+config RTC_DRV_S5M
+ tristate "Samsung S2M/S5M series"
+ depends on MFD_SEC_CORE
+ help
+ If you say yes here you will get support for the
+ RTC of Samsung S2MPS14 and S5M PMIC series.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-s5m.
+
endif # I2C
comment "SPI RTC drivers"
@@ -413,6 +573,29 @@ config RTC_DRV_DS1305
This driver can also be built as a module. If so, the module
will be called rtc-ds1305.
+config RTC_DRV_DS1343
+ select REGMAP_SPI
+ tristate "Dallas/Maxim DS1343/DS1344"
+ help
+ If you say yes here you get support for the
+ Dallas/Maxim DS1343 and DS1344 real time clock chips.
+ Support for trickle charger, alarm is provided.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1343.
+
+config RTC_DRV_DS1347
+ tristate "Dallas/Maxim DS1347"
+ help
+ If you say yes here you get support for the
+ Dallas/Maxim DS1347 chips.
+
+ 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-ds1347.
+
config RTC_DRV_DS1390
tristate "Dallas/Maxim DS1390/93/94"
help
@@ -470,6 +653,22 @@ config RTC_DRV_PCF2123
This driver can also be built as a module. If so, the module
will be called rtc-pcf2123.
+config RTC_DRV_RX4581
+ tristate "Epson RX-4581"
+ help
+ If you say yes here you will get support for the Epson RX-4581.
+
+ This driver can also be built as a module. If so the module
+ will be called rtc-rx4581.
+
+config RTC_DRV_MCP795
+ tristate "Microchip MCP795"
+ help
+ If you say yes here you will get support for the Microchip MCP795.
+
+ This driver can also be built as a module. If so the module
+ will be called rtc-mcp795.
+
endif # SPI_MASTER
comment "Platform RTC drivers"
@@ -480,7 +679,7 @@ comment "Platform RTC drivers"
config RTC_DRV_CMOS
tristate "PC-style 'CMOS'"
- depends on X86 || ALPHA || ARM || M32R || ATARI || PPC || MIPS || SPARC64
+ depends on X86 || ARM || M32R || PPC || MIPS || SPARC64
default y if X86
help
Say "yes" here to get direct support for the real time clock
@@ -497,6 +696,14 @@ config RTC_DRV_CMOS
This driver can also be built as a module. If so, the module
will be called rtc-cmos.
+config RTC_DRV_ALPHA
+ bool "Alpha PC-style CMOS"
+ depends on ALPHA
+ default y
+ help
+ Direct support for the real-time clock found on every Alpha
+ system, specifically MC146818 compatibles. If in doubt, say Y.
+
config RTC_DRV_VRTC
tristate "Virtual RTC for Intel MID platforms"
depends on X86_INTEL_MID
@@ -528,7 +735,6 @@ config RTC_DRV_DS1302
config RTC_DRV_DS1511
tristate "Dallas DS1511"
- depends on RTC_CLASS
help
If you say yes here you get support for the
Dallas DS1511 timekeeping/watchdog chip.
@@ -554,6 +760,33 @@ config RTC_DRV_DS1742
This driver can also be built as a module. If so, the module
will be called rtc-ds1742.
+config RTC_DRV_DA9052
+ tristate "Dialog DA9052/DA9053 RTC"
+ depends on PMIC_DA9052
+ help
+ Say y here to support the RTC driver for Dialog Semiconductor
+ DA9052-BC and DA9053-AA/Bx PMICs.
+
+config RTC_DRV_DA9055
+ tristate "Dialog Semiconductor DA9055 RTC"
+ depends on MFD_DA9055
+ help
+ If you say yes here you will get support for the
+ RTC of the Dialog DA9055 PMIC.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-da9055
+
+config RTC_DRV_DA9063
+ tristate "Dialog Semiconductor DA9063 RTC"
+ depends on MFD_DA9063
+ help
+ If you say yes here you will get support for the RTC subsystem
+ of the Dialog Semiconductor DA9063.
+
+ This driver can also be built as a module. If so, the module
+ will be called "rtc-da9063".
+
config RTC_DRV_EFI
tristate "EFI RTC"
depends on IA64
@@ -566,7 +799,6 @@ config RTC_DRV_EFI
config RTC_DRV_STK17TA8
tristate "Simtek STK17TA8"
- depends on RTC_CLASS
help
If you say yes here you get support for the
Simtek STK17TA8 timekeeping chip.
@@ -613,27 +845,6 @@ config RTC_DRV_MSM6242
This driver can also be built as a module. If so, the module
will be called rtc-msm6242.
-config RTC_DRV_IMXDI
- tristate "Freescale IMX DryIce Real Time Clock"
- depends on ARCH_MX25
- depends on RTC_CLASS
- help
- Support for Freescale IMX DryIce RTC
-
- This driver can also be built as a module, if so, the module
- will be called "rtc-imxdi".
-
-config RTC_MXC
- tristate "Freescale MXC Real Time Clock"
- depends on ARCH_MXC
- depends on RTC_CLASS
- help
- If you say yes here you get support for the Freescale MXC
- RTC module.
-
- This driver can also be built as a module, if so, the module
- will be called "rtc-mxc".
-
config RTC_DRV_BQ4802
tristate "TI BQ4802"
help
@@ -662,6 +873,15 @@ config RTC_DRV_V3020
This driver can also be built as a module. If so, the module
will be called rtc-v3020.
+config RTC_DRV_DS2404
+ tristate "Dallas DS2404"
+ help
+ If you say yes here you get support for the
+ Dallas DS2404 RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds2404.
+
config RTC_DRV_WM831X
tristate "Wolfson Microelectronics WM831x RTC"
depends on MFD_WM831X
@@ -708,13 +928,15 @@ config RTC_DRV_AB3100
config RTC_DRV_AB8500
tristate "ST-Ericsson AB8500 RTC"
depends on AB8500_CORE
+ select RTC_INTF_DEV
+ select RTC_INTF_DEV_UIE_EMUL
help
Select this to enable the ST-Ericsson AB8500 power management IC RTC
support. This chip contains a battery- and capacitor-backed RTC.
config RTC_DRV_NUC900
tristate "NUC910/NUC920 RTC driver"
- depends on RTC_CLASS && ARCH_W90X900
+ depends on ARCH_W90X900
help
If you say yes here you get support for the RTC subsystem of the
NUC910/NUC920 used in embedded systems.
@@ -731,13 +953,24 @@ config RTC_DRV_DAVINCI
This driver can also be built as a module. If so, the module
will be called rtc-davinci.
+config RTC_DRV_IMXDI
+ tristate "Freescale IMX DryIce Real Time Clock"
+ depends on ARCH_MXC
+ help
+ Support for Freescale IMX DryIce RTC
+
+ This driver can also be built as a module, if so, the module
+ will be called "rtc-imxdi".
+
config RTC_DRV_OMAP
tristate "TI OMAP1"
- depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_DAVINCI_DA8XX
+ depends on ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 || ARCH_DAVINCI_DA8XX || SOC_AM33XX
help
- Say "yes" here to support the real time clock on TI OMAP1 and
- DA8xx/OMAP-L13x chips. This driver can also be built as a
- module called rtc-omap.
+ Say "yes" here to support the on chip real time clock
+ present on TI OMAP1, AM33xx and DA8xx/OMAP-L13x.
+
+ This driver can also be built as a module, if so, module
+ will be called rtc-omap.
config HAVE_S3C_RTC
bool
@@ -748,7 +981,7 @@ config HAVE_S3C_RTC
config RTC_DRV_S3C
tristate "Samsung S3C series SoC RTC"
- depends on ARCH_S3C2410 || ARCH_S3C64XX || HAVE_S3C_RTC
+ depends on ARCH_S3C64XX || HAVE_S3C_RTC
help
RTC (Realtime Clock) driver for the clock inbuilt into the
Samsung S3C24XX series of SoCs. This can provide periodic
@@ -773,8 +1006,8 @@ config RTC_DRV_EP93XX
will be called rtc-ep93xx.
config RTC_DRV_SA1100
- tristate "SA11x0/PXA2xx"
- depends on ARCH_SA1100 || ARCH_PXA
+ tristate "SA11x0/PXA2xx/PXA910"
+ depends on ARCH_SA1100 || ARCH_PXA || ARCH_MMP
help
If you say Y here you will get access to the real time clock
built into your SA11x0 or PXA2xx CPU.
@@ -784,7 +1017,7 @@ config RTC_DRV_SA1100
config RTC_DRV_SH
tristate "SuperH On-Chip RTC"
- depends on RTC_CLASS && SUPERH && HAVE_CLK
+ depends on SUPERH && HAVE_CLK
help
Say Y here to enable support for the on-chip RTC found in
most SuperH processors.
@@ -831,7 +1064,7 @@ config RTC_DRV_AT32AP700X
config RTC_DRV_AT91RM9200
tristate "AT91RM9200 or some AT91SAM9 RTC"
- depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
+ depends on ARCH_AT91
help
Driver for the internal RTC (Realtime Clock) module found on
Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips
@@ -934,6 +1167,13 @@ config RTC_DRV_SUN4V
If you say Y here you will get support for the Hypervisor
based RTC on SUN4V systems.
+config RTC_DRV_SUNXI
+ tristate "Allwinner sun4i/sun7i RTC"
+ depends on ARCH_SUNXI
+ help
+ If you say Y here you will get support for the RTC found on
+ Allwinner A10/A20.
+
config RTC_DRV_STARFIRE
bool "Starfire RTC"
depends on SPARC64
@@ -950,7 +1190,7 @@ config RTC_DRV_TX4939
config RTC_DRV_MV
tristate "Marvell SoC RTC"
- depends on ARCH_KIRKWOOD || ARCH_DOVE
+ depends on ARCH_KIRKWOOD || ARCH_DOVE || ARCH_MVEBU
help
If you say yes here you will get support for the in-chip RTC
that can be found in some of Marvell's SoC devices, such as
@@ -1016,7 +1256,6 @@ config RTC_DRV_MPC5121
config RTC_DRV_JZ4740
tristate "Ingenic JZ4740 SoC"
- depends on RTC_CLASS
depends on MACH_JZ4740
help
If you say yes here you get support for the Ingenic JZ4740 SoC RTC
@@ -1046,7 +1285,7 @@ config RTC_DRV_PM8XXX
config RTC_DRV_TEGRA
tristate "NVIDIA Tegra Internal RTC driver"
- depends on RTC_CLASS && ARCH_TEGRA
+ depends on ARCH_TEGRA
help
If you say yes here you get support for the
Tegra 200 series internal RTC module.
@@ -1070,4 +1309,76 @@ config RTC_DRV_PUV3
This drive can also be built as a module. If so, the module
will be called rtc-puv3.
+config RTC_DRV_LOONGSON1
+ tristate "loongson1 RTC support"
+ depends on MACH_LOONGSON1
+ help
+ This is a driver for the loongson1 on-chip Counter0 (Time-Of-Year
+ counter) to be used as a RTC.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ls1x.
+
+config RTC_DRV_MXC
+ tristate "Freescale MXC Real Time Clock"
+ depends on ARCH_MXC
+ help
+ If you say yes here you get support for the Freescale MXC
+ RTC module.
+
+ This driver can also be built as a module, if so, the module
+ will be called "rtc-mxc".
+
+config RTC_DRV_SNVS
+ tristate "Freescale SNVS RTC support"
+ depends on HAS_IOMEM
+ depends on OF
+ help
+ If you say yes here you get support for the Freescale SNVS
+ Low Power (LP) RTC module.
+
+ This driver can also be built as a module, if so, the module
+ will be called "rtc-snvs".
+
+config RTC_DRV_SIRFSOC
+ tristate "SiRFSOC RTC"
+ depends on ARCH_SIRF
+ help
+ Say "yes" here to support the real time clock on SiRF SOC chips.
+ This driver can also be built as a module called rtc-sirfsoc.
+
+config RTC_DRV_MOXART
+ tristate "MOXA ART RTC"
+ help
+ If you say yes here you get support for the MOXA ART
+ RTC module.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-moxart
+
+config RTC_DRV_XGENE
+ tristate "APM X-Gene RTC"
+ help
+ If you say yes here you get support for the APM X-Gene SoC real time
+ clock.
+
+ This driver can also be built as a module, if so, the module
+ will be called "rtc-xgene".
+
+comment "HID Sensor RTC drivers"
+
+config RTC_DRV_HID_SENSOR_TIME
+ tristate "HID Sensor Time"
+ depends on USB_HID
+ select IIO
+ select HID_SENSOR_HUB
+ select HID_SENSOR_IIO_COMMON
+ help
+ Say yes here to build support for the HID Sensors of type Time.
+ This drivers makes such sensors available as RTCs.
+
+ If this driver is compiled as a module, it will be named
+ rtc-hid-sensor-time.
+
+
endif # RTC_CLASS
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index 6e6982335c1..70347d041d1 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -6,6 +6,7 @@ ccflags-$(CONFIG_RTC_DEBUG) := -DDEBUG
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
rtc-core-y := class.o interface.o
@@ -16,8 +17,10 @@ rtc-core-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o
# Keep the list ordered.
obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o
+obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o
obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
+obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o
obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
obj-$(CONFIG_RTC_DRV_AT91SAM9) += rtc-at91sam9.o
@@ -27,6 +30,9 @@ obj-$(CONFIG_RTC_DRV_BQ32K) += rtc-bq32k.o
obj-$(CONFIG_RTC_DRV_BQ4802) += rtc-bq4802.o
obj-$(CONFIG_RTC_DRV_CMOS) += rtc-cmos.o
obj-$(CONFIG_RTC_DRV_COH901331) += rtc-coh901331.o
+obj-$(CONFIG_RTC_DRV_DA9052) += rtc-da9052.o
+obj-$(CONFIG_RTC_DRV_DA9055) += rtc-da9055.o
+obj-$(CONFIG_RTC_DRV_DA9063) += rtc-da9063.o
obj-$(CONFIG_RTC_DRV_DAVINCI) += rtc-davinci.o
obj-$(CONFIG_RTC_DRV_DM355EVM) += rtc-dm355evm.o
obj-$(CONFIG_RTC_DRV_VRTC) += rtc-mrst.o
@@ -35,12 +41,15 @@ obj-$(CONFIG_RTC_DRV_DS1286) += rtc-ds1286.o
obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds1302.o
obj-$(CONFIG_RTC_DRV_DS1305) += rtc-ds1305.o
obj-$(CONFIG_RTC_DRV_DS1307) += rtc-ds1307.o
+obj-$(CONFIG_RTC_DRV_DS1343) += rtc-ds1343.o
+obj-$(CONFIG_RTC_DRV_DS1347) += rtc-ds1347.o
obj-$(CONFIG_RTC_DRV_DS1374) += rtc-ds1374.o
obj-$(CONFIG_RTC_DRV_DS1390) += rtc-ds1390.o
obj-$(CONFIG_RTC_DRV_DS1511) += rtc-ds1511.o
obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
+obj-$(CONFIG_RTC_DRV_DS2404) += rtc-ds2404.o
obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o
obj-$(CONFIG_RTC_DRV_DS3234) += rtc-ds3234.o
obj-$(CONFIG_RTC_DRV_EFI) += rtc-efi.o
@@ -48,29 +57,41 @@ obj-$(CONFIG_RTC_DRV_EM3027) += rtc-em3027.o
obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o
obj-$(CONFIG_RTC_DRV_FM3130) += rtc-fm3130.o
obj-$(CONFIG_RTC_DRV_GENERIC) += rtc-generic.o
+obj-$(CONFIG_RTC_DRV_HID_SENSOR_TIME) += rtc-hid-sensor-time.o
+obj-$(CONFIG_RTC_DRV_HYM8563) += rtc-hym8563.o
obj-$(CONFIG_RTC_DRV_IMXDI) += rtc-imxdi.o
obj-$(CONFIG_RTC_DRV_ISL1208) += rtc-isl1208.o
obj-$(CONFIG_RTC_DRV_ISL12022) += rtc-isl12022.o
+obj-$(CONFIG_RTC_DRV_ISL12057) += rtc-isl12057.o
obj-$(CONFIG_RTC_DRV_JZ4740) += rtc-jz4740.o
+obj-$(CONFIG_RTC_DRV_LP8788) += rtc-lp8788.o
obj-$(CONFIG_RTC_DRV_LPC32XX) += rtc-lpc32xx.o
+obj-$(CONFIG_RTC_DRV_LOONGSON1) += rtc-ls1x.o
obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o
obj-$(CONFIG_RTC_DRV_M41T93) += rtc-m41t93.o
obj-$(CONFIG_RTC_DRV_M41T94) += rtc-m41t94.o
obj-$(CONFIG_RTC_DRV_M48T35) += rtc-m48t35.o
obj-$(CONFIG_RTC_DRV_M48T59) += rtc-m48t59.o
obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o
-obj-$(CONFIG_RTC_MXC) += rtc-mxc.o
+obj-$(CONFIG_RTC_DRV_MXC) += rtc-mxc.o
obj-$(CONFIG_RTC_DRV_MAX6900) += rtc-max6900.o
+obj-$(CONFIG_RTC_DRV_MAX8907) += rtc-max8907.o
obj-$(CONFIG_RTC_DRV_MAX8925) += rtc-max8925.o
obj-$(CONFIG_RTC_DRV_MAX8998) += rtc-max8998.o
+obj-$(CONFIG_RTC_DRV_MAX8997) += rtc-max8997.o
obj-$(CONFIG_RTC_DRV_MAX6902) += rtc-max6902.o
+obj-$(CONFIG_RTC_DRV_MAX77686) += rtc-max77686.o
obj-$(CONFIG_RTC_DRV_MC13XXX) += rtc-mc13xxx.o
+obj-$(CONFIG_RTC_DRV_MCP795) += rtc-mcp795.o
obj-$(CONFIG_RTC_DRV_MSM6242) += rtc-msm6242.o
obj-$(CONFIG_RTC_DRV_MPC5121) += rtc-mpc5121.o
obj-$(CONFIG_RTC_DRV_MV) += rtc-mv.o
obj-$(CONFIG_RTC_DRV_NUC900) += rtc-nuc900.o
obj-$(CONFIG_RTC_DRV_OMAP) += rtc-omap.o
+obj-$(CONFIG_RTC_DRV_PALMAS) += rtc-palmas.o
obj-$(CONFIG_RTC_DRV_PCAP) += rtc-pcap.o
+obj-$(CONFIG_RTC_DRV_PCF2127) += rtc-pcf2127.o
+obj-$(CONFIG_RTC_DRV_PCF8523) += rtc-pcf8523.o
obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o
obj-$(CONFIG_RTC_DRV_PCF8583) += rtc-pcf8583.o
obj-$(CONFIG_RTC_DRV_PCF2123) += rtc-pcf2123.o
@@ -82,26 +103,34 @@ obj-$(CONFIG_RTC_DRV_PS3) += rtc-ps3.o
obj-$(CONFIG_RTC_DRV_PUV3) += rtc-puv3.o
obj-$(CONFIG_RTC_DRV_PXA) += rtc-pxa.o
obj-$(CONFIG_RTC_DRV_R9701) += rtc-r9701.o
+obj-$(CONFIG_RTC_DRV_RC5T583) += rtc-rc5t583.o
obj-$(CONFIG_RTC_DRV_RP5C01) += rtc-rp5c01.o
obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o
obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o
obj-$(CONFIG_RTC_DRV_RV3029C2) += rtc-rv3029c2.o
+obj-$(CONFIG_RTC_DRV_RX4581) += rtc-rx4581.o
obj-$(CONFIG_RTC_DRV_RX8025) += rtc-rx8025.o
obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx8581.o
obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o
obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o
+obj-$(CONFIG_RTC_DRV_S5M) += rtc-s5m.o
obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o
obj-$(CONFIG_RTC_DRV_SH) += rtc-sh.o
+obj-$(CONFIG_RTC_DRV_SNVS) += rtc-snvs.o
obj-$(CONFIG_RTC_DRV_SPEAR) += rtc-spear.o
obj-$(CONFIG_RTC_DRV_STARFIRE) += rtc-starfire.o
obj-$(CONFIG_RTC_DRV_STK17TA8) += rtc-stk17ta8.o
obj-$(CONFIG_RTC_DRV_STMP) += rtc-stmp3xxx.o
obj-$(CONFIG_RTC_DRV_SUN4V) += rtc-sun4v.o
+obj-$(CONFIG_RTC_DRV_SUNXI) += rtc-sunxi.o
obj-$(CONFIG_RTC_DRV_TEGRA) += rtc-tegra.o
obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o
obj-$(CONFIG_RTC_DRV_TILE) += rtc-tile.o
obj-$(CONFIG_RTC_DRV_TWL4030) += rtc-twl.o
+obj-$(CONFIG_RTC_DRV_TPS6586X) += rtc-tps6586x.o
+obj-$(CONFIG_RTC_DRV_TPS65910) += rtc-tps65910.o
+obj-$(CONFIG_RTC_DRV_TPS80031) += rtc-tps80031.o
obj-$(CONFIG_RTC_DRV_TX4939) += rtc-tx4939.o
obj-$(CONFIG_RTC_DRV_V3020) += rtc-v3020.o
obj-$(CONFIG_RTC_DRV_VR41XX) += rtc-vr41xx.o
@@ -109,3 +138,6 @@ obj-$(CONFIG_RTC_DRV_VT8500) += rtc-vt8500.o
obj-$(CONFIG_RTC_DRV_WM831X) += rtc-wm831x.o
obj-$(CONFIG_RTC_DRV_WM8350) += rtc-wm8350.o
obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o
+obj-$(CONFIG_RTC_DRV_XGENE) += rtc-xgene.o
+obj-$(CONFIG_RTC_DRV_SIRFSOC) += rtc-sirfsoc.o
+obj-$(CONFIG_RTC_DRV_MOXART) += rtc-moxart.o
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index dc4c2748bbc..589351ef75d 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -11,7 +11,10 @@
* published by the Free Software Foundation.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/rtc.h>
#include <linux/kdev_t.h>
#include <linux/idr.h>
@@ -31,8 +34,12 @@ static void rtc_device_release(struct device *dev)
kfree(rtc);
}
-#if defined(CONFIG_PM) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
+#ifdef CONFIG_RTC_HCTOSYS_DEVICE
+/* Result of the last RTC to system clock attempt. */
+int rtc_hctosys_ret = -ENODEV;
+#endif
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_RTC_HCTOSYS_DEVICE)
/*
* On suspend(), measure the delta between one RTC and the
* system's wall clock; restore it on resume().
@@ -41,11 +48,15 @@ static void rtc_device_release(struct device *dev)
static struct timespec old_rtc, old_system, old_delta;
-static int rtc_suspend(struct device *dev, pm_message_t mesg)
+static int rtc_suspend(struct device *dev)
{
struct rtc_device *rtc = to_rtc_device(dev);
struct rtc_time tm;
struct timespec delta, delta_delta;
+
+ if (has_persistent_clock())
+ return 0;
+
if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
return 0;
@@ -84,6 +95,10 @@ static int rtc_resume(struct device *dev)
struct timespec new_system, new_rtc;
struct timespec sleep_time;
+ if (has_persistent_clock())
+ return 0;
+
+ rtc_hctosys_ret = -ENODEV;
if (strcmp(dev_name(&rtc->dev), CONFIG_RTC_HCTOSYS_DEVICE) != 0)
return 0;
@@ -117,12 +132,14 @@ static int rtc_resume(struct device *dev)
if (sleep_time.tv_sec >= 0)
timekeeping_inject_sleeptime(&sleep_time);
+ rtc_hctosys_ret = 0;
return 0;
}
+static SIMPLE_DEV_PM_OPS(rtc_class_dev_pm_ops, rtc_suspend, rtc_resume);
+#define RTC_CLASS_DEV_PM_OPS (&rtc_class_dev_pm_ops)
#else
-#define rtc_suspend NULL
-#define rtc_resume NULL
+#define RTC_CLASS_DEV_PM_OPS NULL
#endif
@@ -141,12 +158,27 @@ struct rtc_device *rtc_device_register(const char *name, struct device *dev,
{
struct rtc_device *rtc;
struct rtc_wkalrm alrm;
- int id, err;
+ int of_id = -1, id = -1, err;
+
+ if (dev->of_node)
+ of_id = of_alias_get_id(dev->of_node, "rtc");
+ else if (dev->parent && dev->parent->of_node)
+ of_id = of_alias_get_id(dev->parent->of_node, "rtc");
+
+ if (of_id >= 0) {
+ id = ida_simple_get(&rtc_ida, of_id, of_id + 1,
+ GFP_KERNEL);
+ if (id < 0)
+ dev_warn(dev, "/aliases ID %d not available\n",
+ of_id);
+ }
- id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);
if (id < 0) {
- err = id;
- goto exit;
+ id = ida_simple_get(&rtc_ida, 0, 0, GFP_KERNEL);
+ if (id < 0) {
+ err = id;
+ goto exit;
+ }
}
rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
@@ -244,15 +276,84 @@ void rtc_device_unregister(struct rtc_device *rtc)
}
EXPORT_SYMBOL_GPL(rtc_device_unregister);
+static void devm_rtc_device_release(struct device *dev, void *res)
+{
+ struct rtc_device *rtc = *(struct rtc_device **)res;
+
+ rtc_device_unregister(rtc);
+}
+
+static int devm_rtc_device_match(struct device *dev, void *res, void *data)
+{
+ struct rtc **r = res;
+
+ return *r == data;
+}
+
+/**
+ * devm_rtc_device_register - resource managed rtc_device_register()
+ * @dev: the device to register
+ * @name: the name of the device
+ * @ops: the rtc operations structure
+ * @owner: the module owner
+ *
+ * @return a struct rtc on success, or an ERR_PTR on error
+ *
+ * Managed rtc_device_register(). The rtc_device returned from this function
+ * are automatically freed on driver detach. See rtc_device_register()
+ * for more information.
+ */
+
+struct rtc_device *devm_rtc_device_register(struct device *dev,
+ const char *name,
+ const struct rtc_class_ops *ops,
+ struct module *owner)
+{
+ struct rtc_device **ptr, *rtc;
+
+ ptr = devres_alloc(devm_rtc_device_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ rtc = rtc_device_register(name, dev, ops, owner);
+ if (!IS_ERR(rtc)) {
+ *ptr = rtc;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return rtc;
+}
+EXPORT_SYMBOL_GPL(devm_rtc_device_register);
+
+/**
+ * devm_rtc_device_unregister - resource managed devm_rtc_device_unregister()
+ * @dev: the device to unregister
+ * @rtc: the RTC class device to unregister
+ *
+ * Deallocated a rtc allocated with devm_rtc_device_register(). Normally this
+ * function will not need to be called and the resource management code will
+ * ensure that the resource is freed.
+ */
+void devm_rtc_device_unregister(struct device *dev, struct rtc_device *rtc)
+{
+ int rc;
+
+ rc = devres_release(dev, devm_rtc_device_release,
+ devm_rtc_device_match, rtc);
+ WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_rtc_device_unregister);
+
static int __init rtc_init(void)
{
rtc_class = class_create(THIS_MODULE, "rtc");
if (IS_ERR(rtc_class)) {
- printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
+ pr_err("couldn't create class\n");
return PTR_ERR(rtc_class);
}
- rtc_class->suspend = rtc_suspend;
- rtc_class->resume = rtc_resume;
+ rtc_class->pm = RTC_CLASS_DEV_PM_OPS;
rtc_dev_init();
rtc_sysfs_init(rtc_class);
return 0;
diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c
index bc90b091f19..4aa60d74004 100644
--- a/drivers/rtc/hctosys.c
+++ b/drivers/rtc/hctosys.c
@@ -22,8 +22,6 @@
* the best guess is to add 0.5s.
*/
-int rtc_hctosys_ret = -ENODEV;
-
static int __init rtc_hctosys(void)
{
int err = -ENODEV;
@@ -56,7 +54,7 @@ static int __init rtc_hctosys(void)
rtc_tm_to_time(&tm, &tv.tv_sec);
- do_settimeofday(&tv);
+ err = do_settimeofday(&tv);
dev_info(rtc->dev.parent,
"setting system clock to "
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 8a1c031391d..5813fa52c3d 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -72,7 +72,10 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
} else
err = -EINVAL;
+ pm_stay_awake(rtc->dev.parent);
mutex_unlock(&rtc->ops_lock);
+ /* A timer might have just expired */
+ schedule_work(&rtc->irqwork);
return err;
}
EXPORT_SYMBOL_GPL(rtc_set_time);
@@ -107,11 +110,14 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
err = rtc->ops->set_time(rtc->dev.parent,
&new);
}
- }
- else
+ } else {
err = -EINVAL;
+ }
+ pm_stay_awake(rtc->dev.parent);
mutex_unlock(&rtc->ops_lock);
+ /* A timer might have just expired */
+ schedule_work(&rtc->irqwork);
return err;
}
@@ -286,7 +292,8 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
dev_dbg(&rtc->dev, "alarm rollover: %s\n", "year");
do {
alarm->time.tm_year++;
- } while (rtc_valid_tm(&alarm->time) != 0);
+ } while (!is_leap_year(alarm->time.tm_year + 1900)
+ && rtc_valid_tm(&alarm->time) != 0);
break;
default:
@@ -294,7 +301,16 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
}
done:
- return 0;
+ err = rtc_valid_tm(&alarm->time);
+
+ if (err) {
+ dev_warn(&rtc->dev, "invalid alarm value: %d-%d-%d %d:%d:%d\n",
+ alarm->time.tm_year + 1900, alarm->time.tm_mon + 1,
+ alarm->time.tm_mday, alarm->time.tm_hour, alarm->time.tm_min,
+ alarm->time.tm_sec);
+ }
+
+ return err;
}
int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
@@ -363,14 +379,14 @@ int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return err;
- if (rtc->aie_timer.enabled) {
+ if (rtc->aie_timer.enabled)
rtc_timer_remove(rtc, &rtc->aie_timer);
- }
+
rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
rtc->aie_timer.period = ktime_set(0, 0);
- if (alarm->enabled) {
+ if (alarm->enabled)
err = rtc_timer_enqueue(rtc, &rtc->aie_timer);
- }
+
mutex_unlock(&rtc->ops_lock);
return err;
}
@@ -380,18 +396,27 @@ EXPORT_SYMBOL_GPL(rtc_set_alarm);
int rtc_initialize_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
int err;
+ struct rtc_time now;
err = rtc_valid_tm(&alarm->time);
if (err != 0)
return err;
+ err = rtc_read_time(rtc, &now);
+ if (err)
+ return err;
+
err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return err;
rtc->aie_timer.node.expires = rtc_tm_to_ktime(alarm->time);
rtc->aie_timer.period = ktime_set(0, 0);
- if (alarm->enabled) {
+
+ /* Alarm has to be enabled & in the futrure for us to enqueue it */
+ if (alarm->enabled && (rtc_tm_to_ktime(now).tv64 <
+ rtc->aie_timer.node.expires.tv64)) {
+
rtc->aie_timer.enabled = 1;
timerqueue_add(&rtc->timerqueue, &rtc->aie_timer.node);
}
@@ -445,6 +470,11 @@ int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
if (rtc->uie_rtctimer.enabled == enabled)
goto out;
+ if (rtc->uie_unsupported) {
+ err = -EINVAL;
+ goto out;
+ }
+
if (enabled) {
struct rtc_time tm;
ktime_t now, onesec;
@@ -564,20 +594,24 @@ enum hrtimer_restart rtc_pie_update_irq(struct hrtimer *timer)
void rtc_update_irq(struct rtc_device *rtc,
unsigned long num, unsigned long events)
{
+ if (unlikely(IS_ERR_OR_NULL(rtc)))
+ return;
+
+ pm_stay_awake(rtc->dev.parent);
schedule_work(&rtc->irqwork);
}
EXPORT_SYMBOL_GPL(rtc_update_irq);
-static int __rtc_match(struct device *dev, void *data)
+static int __rtc_match(struct device *dev, const void *data)
{
- char *name = (char *)data;
+ const char *name = data;
if (strcmp(dev_name(dev), name) == 0)
return 1;
return 0;
}
-struct rtc_device *rtc_class_open(char *name)
+struct rtc_device *rtc_class_open(const char *name)
{
struct device *dev;
struct rtc_device *rtc = NULL;
@@ -679,9 +713,9 @@ retry:
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != NULL && task == NULL)
err = -EBUSY;
- if (rtc->irq_task != task)
+ else if (rtc->irq_task != task)
err = -EACCES;
- if (!err) {
+ else {
if (rtc_update_hrtimer(rtc, enabled) < 0) {
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
cpu_relax();
@@ -715,9 +749,9 @@ retry:
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != NULL && task == NULL)
err = -EBUSY;
- if (rtc->irq_task != task)
+ else if (rtc->irq_task != task)
err = -EACCES;
- if (!err) {
+ else {
rtc->irq_freq = freq;
if (rtc->pie_enabled && rtc_update_hrtimer(rtc, 1) < 0) {
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
@@ -752,9 +786,10 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
alarm.time = rtc_ktime_to_tm(timer->node.expires);
alarm.enabled = 1;
err = __rtc_set_alarm(rtc, &alarm);
- if (err == -ETIME)
+ if (err == -ETIME) {
+ pm_stay_awake(rtc->dev.parent);
schedule_work(&rtc->irqwork);
- else if (err) {
+ } else if (err) {
timerqueue_del(&rtc->timerqueue, &timer->node);
timer->enabled = 0;
return err;
@@ -763,6 +798,14 @@ static int rtc_timer_enqueue(struct rtc_device *rtc, struct rtc_timer *timer)
return 0;
}
+static void rtc_alarm_disable(struct rtc_device *rtc)
+{
+ if (!rtc->ops || !rtc->ops->alarm_irq_enable)
+ return;
+
+ rtc->ops->alarm_irq_enable(rtc->dev.parent, false);
+}
+
/**
* rtc_timer_remove - Removes a rtc_timer from the rtc_device timerqueue
* @rtc rtc device
@@ -784,13 +827,17 @@ static void rtc_timer_remove(struct rtc_device *rtc, struct rtc_timer *timer)
struct rtc_wkalrm alarm;
int err;
next = timerqueue_getnext(&rtc->timerqueue);
- if (!next)
+ if (!next) {
+ rtc_alarm_disable(rtc);
return;
+ }
alarm.time = rtc_ktime_to_tm(next->expires);
alarm.enabled = 1;
err = __rtc_set_alarm(rtc, &alarm);
- if (err == -ETIME)
+ if (err == -ETIME) {
+ pm_stay_awake(rtc->dev.parent);
schedule_work(&rtc->irqwork);
+ }
}
}
@@ -847,8 +894,10 @@ again:
err = __rtc_set_alarm(rtc, &alarm);
if (err == -ETIME)
goto again;
- }
+ } else
+ rtc_alarm_disable(rtc);
+ pm_relax(rtc->dev.parent);
mutex_unlock(&rtc->ops_lock);
}
@@ -860,7 +909,7 @@ again:
*
* Kernel interface to initializing an rtc_timer.
*/
-void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data)
+void rtc_timer_init(struct rtc_timer *timer, void (*f)(void *p), void *data)
{
timerqueue_init(&timer->node);
timer->enabled = 0;
@@ -876,7 +925,7 @@ void rtc_timer_init(struct rtc_timer *timer, void (*f)(void* p), void* data)
*
* Kernel interface to set an rtc_timer
*/
-int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer,
+int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer *timer,
ktime_t expires, ktime_t period)
{
int ret = 0;
@@ -899,7 +948,7 @@ int rtc_timer_start(struct rtc_device *rtc, struct rtc_timer* timer,
*
* Kernel interface to cancel an rtc_timer
*/
-int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer* timer)
+int rtc_timer_cancel(struct rtc_device *rtc, struct rtc_timer *timer)
{
int ret = 0;
mutex_lock(&rtc->ops_lock);
diff --git a/drivers/rtc/rtc-88pm80x.c b/drivers/rtc/rtc-88pm80x.c
new file mode 100644
index 00000000000..0916089c7c3
--- /dev/null
+++ b/drivers/rtc/rtc-88pm80x.c
@@ -0,0 +1,367 @@
+/*
+ * Real Time Clock driver for Marvell 88PM80x PMIC
+ *
+ * Copyright (c) 2012 Marvell International Ltd.
+ * Wenzeng Chen<wzch@marvell.com>
+ * Qiao Zhou <zhouqiao@marvell.com>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/88pm80x.h>
+#include <linux/rtc.h>
+
+#define PM800_RTC_COUNTER1 (0xD1)
+#define PM800_RTC_COUNTER2 (0xD2)
+#define PM800_RTC_COUNTER3 (0xD3)
+#define PM800_RTC_COUNTER4 (0xD4)
+#define PM800_RTC_EXPIRE1_1 (0xD5)
+#define PM800_RTC_EXPIRE1_2 (0xD6)
+#define PM800_RTC_EXPIRE1_3 (0xD7)
+#define PM800_RTC_EXPIRE1_4 (0xD8)
+#define PM800_RTC_TRIM1 (0xD9)
+#define PM800_RTC_TRIM2 (0xDA)
+#define PM800_RTC_TRIM3 (0xDB)
+#define PM800_RTC_TRIM4 (0xDC)
+#define PM800_RTC_EXPIRE2_1 (0xDD)
+#define PM800_RTC_EXPIRE2_2 (0xDE)
+#define PM800_RTC_EXPIRE2_3 (0xDF)
+#define PM800_RTC_EXPIRE2_4 (0xE0)
+
+#define PM800_POWER_DOWN_LOG1 (0xE5)
+#define PM800_POWER_DOWN_LOG2 (0xE6)
+
+struct pm80x_rtc_info {
+ struct pm80x_chip *chip;
+ struct regmap *map;
+ struct rtc_device *rtc_dev;
+ struct device *dev;
+ struct delayed_work calib_work;
+
+ int irq;
+ int vrtc;
+};
+
+static irqreturn_t rtc_update_handler(int irq, void *data)
+{
+ struct pm80x_rtc_info *info = (struct pm80x_rtc_info *)data;
+ int mask;
+
+ mask = PM800_ALARM | PM800_ALARM_WAKEUP;
+ regmap_update_bits(info->map, PM800_RTC_CONTROL, mask | PM800_ALARM1_EN,
+ mask);
+ rtc_update_irq(info->rtc_dev, 1, RTC_AF);
+ return IRQ_HANDLED;
+}
+
+static int pm80x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct pm80x_rtc_info *info = dev_get_drvdata(dev);
+
+ if (enabled)
+ regmap_update_bits(info->map, PM800_RTC_CONTROL,
+ PM800_ALARM1_EN, PM800_ALARM1_EN);
+ else
+ regmap_update_bits(info->map, PM800_RTC_CONTROL,
+ PM800_ALARM1_EN, 0);
+ return 0;
+}
+
+/*
+ * Calculate the next alarm time given the requested alarm time mask
+ * and the current time.
+ */
+static void rtc_next_alarm_time(struct rtc_time *next, struct rtc_time *now,
+ struct rtc_time *alrm)
+{
+ unsigned long next_time;
+ unsigned long now_time;
+
+ next->tm_year = now->tm_year;
+ next->tm_mon = now->tm_mon;
+ next->tm_mday = now->tm_mday;
+ next->tm_hour = alrm->tm_hour;
+ next->tm_min = alrm->tm_min;
+ next->tm_sec = alrm->tm_sec;
+
+ rtc_tm_to_time(now, &now_time);
+ rtc_tm_to_time(next, &next_time);
+
+ if (next_time < now_time) {
+ /* Advance one day */
+ next_time += 60 * 60 * 24;
+ rtc_time_to_tm(next_time, next);
+ }
+}
+
+static int pm80x_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pm80x_rtc_info *info = dev_get_drvdata(dev);
+ unsigned char buf[4];
+ unsigned long ticks, base, data;
+ regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4);
+ base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+ dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]);
+
+ /* load 32-bit read-only counter */
+ regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4);
+ data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+ ticks = base + data;
+ dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+ base, data, ticks);
+ rtc_time_to_tm(ticks, tm);
+ return 0;
+}
+
+static int pm80x_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct pm80x_rtc_info *info = dev_get_drvdata(dev);
+ unsigned char buf[4];
+ unsigned long ticks, base, data;
+ if ((tm->tm_year < 70) || (tm->tm_year > 138)) {
+ dev_dbg(info->dev,
+ "Set time %d out of range. Please set time between 1970 to 2038.\n",
+ 1900 + tm->tm_year);
+ return -EINVAL;
+ }
+ rtc_tm_to_time(tm, &ticks);
+
+ /* load 32-bit read-only counter */
+ regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4);
+ data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+ base = ticks - data;
+ dev_dbg(info->dev, "set base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+ base, data, ticks);
+ buf[0] = base & 0xFF;
+ buf[1] = (base >> 8) & 0xFF;
+ buf[2] = (base >> 16) & 0xFF;
+ buf[3] = (base >> 24) & 0xFF;
+ regmap_raw_write(info->map, PM800_RTC_EXPIRE2_1, buf, 4);
+
+ return 0;
+}
+
+static int pm80x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct pm80x_rtc_info *info = dev_get_drvdata(dev);
+ unsigned char buf[4];
+ unsigned long ticks, base, data;
+ int ret;
+
+ regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4);
+ base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+ dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]);
+
+ regmap_raw_read(info->map, PM800_RTC_EXPIRE1_1, buf, 4);
+ data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+ ticks = base + data;
+ dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+ base, data, ticks);
+
+ rtc_time_to_tm(ticks, &alrm->time);
+ regmap_read(info->map, PM800_RTC_CONTROL, &ret);
+ alrm->enabled = (ret & PM800_ALARM1_EN) ? 1 : 0;
+ alrm->pending = (ret & (PM800_ALARM | PM800_ALARM_WAKEUP)) ? 1 : 0;
+ return 0;
+}
+
+static int pm80x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct pm80x_rtc_info *info = dev_get_drvdata(dev);
+ struct rtc_time now_tm, alarm_tm;
+ unsigned long ticks, base, data;
+ unsigned char buf[4];
+ int mask;
+
+ regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_ALARM1_EN, 0);
+
+ regmap_raw_read(info->map, PM800_RTC_EXPIRE2_1, buf, 4);
+ base = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+ dev_dbg(info->dev, "%x-%x-%x-%x\n", buf[0], buf[1], buf[2], buf[3]);
+
+ /* load 32-bit read-only counter */
+ regmap_raw_read(info->map, PM800_RTC_COUNTER1, buf, 4);
+ data = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+ ticks = base + data;
+ dev_dbg(info->dev, "get base:0x%lx, RO count:0x%lx, ticks:0x%lx\n",
+ base, data, ticks);
+
+ rtc_time_to_tm(ticks, &now_tm);
+ dev_dbg(info->dev, "%s, now time : %lu\n", __func__, ticks);
+ rtc_next_alarm_time(&alarm_tm, &now_tm, &alrm->time);
+ /* get new ticks for alarm in 24 hours */
+ rtc_tm_to_time(&alarm_tm, &ticks);
+ dev_dbg(info->dev, "%s, alarm time: %lu\n", __func__, ticks);
+ data = ticks - base;
+
+ buf[0] = data & 0xff;
+ buf[1] = (data >> 8) & 0xff;
+ buf[2] = (data >> 16) & 0xff;
+ buf[3] = (data >> 24) & 0xff;
+ regmap_raw_write(info->map, PM800_RTC_EXPIRE1_1, buf, 4);
+ if (alrm->enabled) {
+ mask = PM800_ALARM | PM800_ALARM_WAKEUP | PM800_ALARM1_EN;
+ regmap_update_bits(info->map, PM800_RTC_CONTROL, mask, mask);
+ } else {
+ mask = PM800_ALARM | PM800_ALARM_WAKEUP | PM800_ALARM1_EN;
+ regmap_update_bits(info->map, PM800_RTC_CONTROL, mask,
+ PM800_ALARM | PM800_ALARM_WAKEUP);
+ }
+ return 0;
+}
+
+static const struct rtc_class_ops pm80x_rtc_ops = {
+ .read_time = pm80x_rtc_read_time,
+ .set_time = pm80x_rtc_set_time,
+ .read_alarm = pm80x_rtc_read_alarm,
+ .set_alarm = pm80x_rtc_set_alarm,
+ .alarm_irq_enable = pm80x_rtc_alarm_irq_enable,
+};
+
+#ifdef CONFIG_PM_SLEEP
+static int pm80x_rtc_suspend(struct device *dev)
+{
+ return pm80x_dev_suspend(dev);
+}
+
+static int pm80x_rtc_resume(struct device *dev)
+{
+ return pm80x_dev_resume(dev);
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm80x_rtc_pm_ops, pm80x_rtc_suspend, pm80x_rtc_resume);
+
+static int pm80x_rtc_probe(struct platform_device *pdev)
+{
+ struct pm80x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+ struct pm80x_platform_data *pm80x_pdata =
+ dev_get_platdata(pdev->dev.parent);
+ struct pm80x_rtc_pdata *pdata = NULL;
+ struct pm80x_rtc_info *info;
+ struct rtc_time tm;
+ unsigned long ticks = 0;
+ int ret;
+
+ pdata = dev_get_platdata(&pdev->dev);
+ if (pdata == NULL)
+ dev_warn(&pdev->dev, "No platform data!\n");
+
+ info =
+ devm_kzalloc(&pdev->dev, sizeof(struct pm80x_rtc_info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+ info->irq = platform_get_irq(pdev, 0);
+ if (info->irq < 0) {
+ dev_err(&pdev->dev, "No IRQ resource!\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ info->chip = chip;
+ info->map = chip->regmap;
+ if (!info->map) {
+ dev_err(&pdev->dev, "no regmap!\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ info->dev = &pdev->dev;
+ dev_set_drvdata(&pdev->dev, info);
+
+ ret = pm80x_request_irq(chip, info->irq, rtc_update_handler,
+ IRQF_ONESHOT, "rtc", info);
+ if (ret < 0) {
+ dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
+ info->irq, ret);
+ goto out;
+ }
+
+ ret = pm80x_rtc_read_time(&pdev->dev, &tm);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to read initial time.\n");
+ goto out_rtc;
+ }
+ if ((tm.tm_year < 70) || (tm.tm_year > 138)) {
+ tm.tm_year = 70;
+ tm.tm_mon = 0;
+ tm.tm_mday = 1;
+ tm.tm_hour = 0;
+ tm.tm_min = 0;
+ tm.tm_sec = 0;
+ ret = pm80x_rtc_set_time(&pdev->dev, &tm);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to set initial time.\n");
+ goto out_rtc;
+ }
+ }
+ rtc_tm_to_time(&tm, &ticks);
+
+ info->rtc_dev = devm_rtc_device_register(&pdev->dev, "88pm80x-rtc",
+ &pm80x_rtc_ops, THIS_MODULE);
+ if (IS_ERR(info->rtc_dev)) {
+ ret = PTR_ERR(info->rtc_dev);
+ dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
+ goto out_rtc;
+ }
+ /*
+ * enable internal XO instead of internal 3.25MHz clock since it can
+ * free running in PMIC power-down state.
+ */
+ regmap_update_bits(info->map, PM800_RTC_CONTROL, PM800_RTC1_USE_XO,
+ PM800_RTC1_USE_XO);
+
+ if (pm80x_pdata) {
+ pdata = pm80x_pdata->rtc;
+ if (pdata)
+ info->rtc_dev->dev.platform_data = &pdata->rtc_wakeup;
+ }
+
+ device_init_wakeup(&pdev->dev, 1);
+
+ return 0;
+out_rtc:
+ pm80x_free_irq(chip, info->irq, info);
+out:
+ return ret;
+}
+
+static int pm80x_rtc_remove(struct platform_device *pdev)
+{
+ struct pm80x_rtc_info *info = platform_get_drvdata(pdev);
+ pm80x_free_irq(info->chip, info->irq, info);
+ return 0;
+}
+
+static struct platform_driver pm80x_rtc_driver = {
+ .driver = {
+ .name = "88pm80x-rtc",
+ .owner = THIS_MODULE,
+ .pm = &pm80x_rtc_pm_ops,
+ },
+ .probe = pm80x_rtc_probe,
+ .remove = pm80x_rtc_remove,
+};
+
+module_platform_driver(pm80x_rtc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Marvell 88PM80x RTC driver");
+MODULE_AUTHOR("Qiao Zhou <zhouqiao@marvell.com>");
+MODULE_ALIAS("platform:88pm80x-rtc");
diff --git a/drivers/rtc/rtc-88pm860x.c b/drivers/rtc/rtc-88pm860x.c
index f04761e6622..0c6add1a38d 100644
--- a/drivers/rtc/rtc-88pm860x.c
+++ b/drivers/rtc/rtc-88pm860x.c
@@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mutex.h>
@@ -72,9 +73,9 @@ static int pm860x_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
struct pm860x_rtc_info *info = dev_get_drvdata(dev);
if (enabled)
- pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, ALARM);
+ pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM_EN, ALARM_EN);
else
- pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM, 0);
+ pm860x_set_bits(info->i2c, PM8607_RTC1, ALARM_EN, 0);
return 0;
}
@@ -284,7 +285,30 @@ out:
}
#endif
-static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
+#ifdef CONFIG_OF
+static int pm860x_rtc_dt_init(struct platform_device *pdev,
+ struct pm860x_rtc_info *info)
+{
+ struct device_node *np = pdev->dev.parent->of_node;
+ int ret;
+ if (!np)
+ return -ENODEV;
+ np = of_get_child_by_name(np, "rtc");
+ if (!np) {
+ dev_err(&pdev->dev, "failed to find rtc node\n");
+ return -ENODEV;
+ }
+ ret = of_property_read_u32(np, "marvell,88pm860x-vrtc", &info->vrtc);
+ if (ret)
+ info->vrtc = 0;
+ of_node_put(np);
+ return 0;
+}
+#else
+#define pm860x_rtc_dt_init(x, y) (-1)
+#endif
+
+static int pm860x_rtc_probe(struct platform_device *pdev)
{
struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
struct pm860x_rtc_pdata *pdata = NULL;
@@ -293,18 +317,16 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
unsigned long ticks = 0;
int ret;
- pdata = pdev->dev.platform_data;
- if (pdata == NULL)
- dev_warn(&pdev->dev, "No platform data!\n");
+ pdata = dev_get_platdata(&pdev->dev);
- info = kzalloc(sizeof(struct pm860x_rtc_info), GFP_KERNEL);
+ info = devm_kzalloc(&pdev->dev, sizeof(struct pm860x_rtc_info),
+ GFP_KERNEL);
if (!info)
return -ENOMEM;
info->irq = platform_get_irq(pdev, 0);
if (info->irq < 0) {
dev_err(&pdev->dev, "No IRQ resource!\n");
- ret = -EINVAL;
- goto out;
+ return info->irq;
}
info->chip = chip;
@@ -312,12 +334,13 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
info->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, info);
- ret = request_threaded_irq(info->irq, NULL, rtc_update_handler,
- IRQF_ONESHOT, "rtc", info);
+ ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
+ rtc_update_handler, IRQF_ONESHOT, "rtc",
+ info);
if (ret < 0) {
dev_err(chip->dev, "Failed to request IRQ: #%d: %d\n",
info->irq, ret);
- goto out;
+ return ret;
}
/* set addresses of 32-bit base value for RTC time */
@@ -329,7 +352,7 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
ret = pm860x_rtc_read_time(&pdev->dev, &tm);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to read initial time.\n");
- goto out_rtc;
+ return ret;
}
if ((tm.tm_year < 70) || (tm.tm_year > 138)) {
tm.tm_year = 70;
@@ -341,21 +364,23 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
ret = pm860x_rtc_set_time(&pdev->dev, &tm);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to set initial time.\n");
- goto out_rtc;
+ return ret;
}
}
rtc_tm_to_time(&tm, &ticks);
- if (pdata && pdata->sync) {
- pdata->sync(ticks);
- info->sync = pdata->sync;
+ if (pm860x_rtc_dt_init(pdev, info)) {
+ if (pdata && pdata->sync) {
+ pdata->sync(ticks);
+ info->sync = pdata->sync;
+ }
}
- info->rtc_dev = rtc_device_register("88pm860x-rtc", &pdev->dev,
+ info->rtc_dev = devm_rtc_device_register(&pdev->dev, "88pm860x-rtc",
&pm860x_rtc_ops, THIS_MODULE);
ret = PTR_ERR(info->rtc_dev);
if (IS_ERR(info->rtc_dev)) {
dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
- goto out_rtc;
+ return ret;
}
/*
@@ -366,25 +391,25 @@ static int __devinit pm860x_rtc_probe(struct platform_device *pdev)
#ifdef VRTC_CALIBRATION
/* <00> -- 2.7V, <01> -- 2.9V, <10> -- 3.1V, <11> -- 3.3V */
- if (pdata && pdata->vrtc)
- info->vrtc = pdata->vrtc & 0x3;
- else
- info->vrtc = 1;
+ if (pm860x_rtc_dt_init(pdev, info)) {
+ if (pdata && pdata->vrtc)
+ info->vrtc = pdata->vrtc & 0x3;
+ else
+ info->vrtc = 1;
+ }
pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, MEAS2_VRTC);
/* calibrate VRTC */
INIT_DELAYED_WORK(&info->calib_work, calibrate_vrtc_work);
schedule_delayed_work(&info->calib_work, VRTC_CALIB_INTERVAL);
#endif /* VRTC_CALIBRATION */
+
+ device_init_wakeup(&pdev->dev, 1);
+
return 0;
-out_rtc:
- free_irq(info->irq, info);
-out:
- kfree(info);
- return ret;
}
-static int __devexit pm860x_rtc_remove(struct platform_device *pdev)
+static int pm860x_rtc_remove(struct platform_device *pdev)
{
struct pm860x_rtc_info *info = platform_get_drvdata(pdev);
@@ -394,20 +419,40 @@ static int __devexit pm860x_rtc_remove(struct platform_device *pdev)
pm860x_set_bits(info->i2c, PM8607_MEAS_EN2, MEAS2_VRTC, 0);
#endif /* VRTC_CALIBRATION */
- platform_set_drvdata(pdev, NULL);
- rtc_device_unregister(info->rtc_dev);
- free_irq(info->irq, info);
- kfree(info);
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int pm860x_rtc_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+ if (device_may_wakeup(dev))
+ chip->wakeup_flag |= 1 << PM8607_IRQ_RTC;
+ return 0;
+}
+static int pm860x_rtc_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct pm860x_chip *chip = dev_get_drvdata(pdev->dev.parent);
+
+ if (device_may_wakeup(dev))
+ chip->wakeup_flag &= ~(1 << PM8607_IRQ_RTC);
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(pm860x_rtc_pm_ops, pm860x_rtc_suspend, pm860x_rtc_resume);
+
static struct platform_driver pm860x_rtc_driver = {
.driver = {
.name = "88pm860x-rtc",
.owner = THIS_MODULE,
+ .pm = &pm860x_rtc_pm_ops,
},
.probe = pm860x_rtc_probe,
- .remove = __devexit_p(pm860x_rtc_remove),
+ .remove = pm860x_rtc_remove,
};
module_platform_driver(pm860x_rtc_driver);
diff --git a/drivers/rtc/rtc-ab3100.c b/drivers/rtc/rtc-ab3100.c
index 261a07e0fb2..ff435343ba9 100644
--- a/drivers/rtc/rtc-ab3100.c
+++ b/drivers/rtc/rtc-ab3100.c
@@ -229,8 +229,8 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev)
/* Ignore any error on this write */
}
- rtc = rtc_device_register("ab3100-rtc", &pdev->dev, &ab3100_rtc_ops,
- THIS_MODULE);
+ rtc = devm_rtc_device_register(&pdev->dev, "ab3100-rtc",
+ &ab3100_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
err = PTR_ERR(rtc);
return err;
@@ -240,36 +240,14 @@ static int __init ab3100_rtc_probe(struct platform_device *pdev)
return 0;
}
-static int __exit ab3100_rtc_remove(struct platform_device *pdev)
-{
- struct rtc_device *rtc = platform_get_drvdata(pdev);
-
- rtc_device_unregister(rtc);
- platform_set_drvdata(pdev, NULL);
- return 0;
-}
-
static struct platform_driver ab3100_rtc_driver = {
.driver = {
.name = "ab3100-rtc",
.owner = THIS_MODULE,
},
- .remove = __exit_p(ab3100_rtc_remove),
};
-static int __init ab3100_rtc_init(void)
-{
- return platform_driver_probe(&ab3100_rtc_driver,
- ab3100_rtc_probe);
-}
-
-static void __exit ab3100_rtc_exit(void)
-{
- platform_driver_unregister(&ab3100_rtc_driver);
-}
-
-module_init(ab3100_rtc_init);
-module_exit(ab3100_rtc_exit);
+module_platform_driver_probe(ab3100_rtc_driver, ab3100_rtc_probe);
MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
MODULE_DESCRIPTION("AB3100 RTC Driver");
diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c
index 4bcf9ca2818..727e2f5d14d 100644
--- a/drivers/rtc/rtc-ab8500.c
+++ b/drivers/rtc/rtc-ab8500.c
@@ -17,6 +17,7 @@
#include <linux/mfd/abx500.h>
#include <linux/mfd/abx500/ab8500.h>
#include <linux/delay.h>
+#include <linux/of.h>
#define AB8500_RTC_SOFF_STAT_REG 0x00
#define AB8500_RTC_CC_CONF_REG 0x01
@@ -34,6 +35,10 @@
#define AB8500_RTC_FORCE_BKUP_REG 0x0D
#define AB8500_RTC_CALIB_REG 0x0E
#define AB8500_RTC_SWITCH_STAT_REG 0x0F
+#define AB8540_RTC_ALRM_SEC 0x22
+#define AB8540_RTC_ALRM_MIN_LOW_REG 0x23
+#define AB8540_RTC_ALRM_MIN_MID_REG 0x24
+#define AB8540_RTC_ALRM_MIN_HI_REG 0x25
/* RtcReadRequest bits */
#define RTC_READ_REQUEST 0x01
@@ -57,6 +62,11 @@ static const u8 ab8500_rtc_alarm_regs[] = {
AB8500_RTC_ALRM_MIN_LOW_REG
};
+static const u8 ab8540_rtc_alarm_regs[] = {
+ AB8540_RTC_ALRM_MIN_HI_REG, AB8540_RTC_ALRM_MIN_MID_REG,
+ AB8540_RTC_ALRM_MIN_LOW_REG, AB8540_RTC_ALRM_SEC
+};
+
/* Calculate the seconds from 1970 to 01-01-2000 00:00:00 */
static unsigned long get_elapsed_seconds(int year)
{
@@ -88,22 +98,17 @@ static int ab8500_rtc_read_time(struct device *dev, struct rtc_time *tm)
if (retval < 0)
return retval;
- /* Early AB8500 chips will not clear the rtc read request bit */
- if (abx500_get_chip_id(dev) == 0) {
- usleep_range(1000, 1000);
- } else {
- /* Wait for some cycles after enabling the rtc read in ab8500 */
- while (time_before(jiffies, timeout)) {
- retval = abx500_get_register_interruptible(dev,
- AB8500_RTC, AB8500_RTC_READ_REQ_REG, &value);
- if (retval < 0)
- return retval;
-
- if (!(value & RTC_READ_REQUEST))
- break;
-
- usleep_range(1000, 5000);
- }
+ /* Wait for some cycles after enabling the rtc read in ab8500 */
+ while (time_before(jiffies, timeout)) {
+ retval = abx500_get_register_interruptible(dev,
+ AB8500_RTC, AB8500_RTC_READ_REQ_REG, &value);
+ if (retval < 0)
+ return retval;
+
+ if (!(value & RTC_READ_REQUEST))
+ break;
+
+ usleep_range(1000, 5000);
}
/* Read the Watchtime registers */
@@ -224,7 +229,8 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
{
int retval, i;
unsigned char buf[ARRAY_SIZE(ab8500_rtc_alarm_regs)];
- unsigned long mins, secs = 0;
+ unsigned long mins, secs = 0, cursec = 0;
+ struct rtc_time curtm;
if (alarm->time.tm_year < (AB8500_RTC_EPOCH - 1900)) {
dev_dbg(dev, "year should be equal to or greater than %d\n",
@@ -236,6 +242,18 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
rtc_tm_to_time(&alarm->time, &secs);
/*
+ * Check whether alarm is set less than 1min.
+ * Since our RTC doesn't support alarm resolution less than 1min,
+ * return -EINVAL, so UIE EMUL can take it up, incase of UIE_ON
+ */
+ ab8500_rtc_read_time(dev, &curtm); /* Read current time */
+ rtc_tm_to_time(&curtm, &cursec);
+ if ((secs - cursec) < 59) {
+ dev_dbg(dev, "Alarm less than 1 minute not supported\r\n");
+ return -EINVAL;
+ }
+
+ /*
* Convert it to the number of seconds since 01-01-2000 00:00:00, since
* we only have a small counter in the RTC.
*/
@@ -258,6 +276,42 @@ static int ab8500_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
return ab8500_rtc_irq_enable(dev, alarm->enabled);
}
+static int ab8540_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ int retval, i;
+ unsigned char buf[ARRAY_SIZE(ab8540_rtc_alarm_regs)];
+ unsigned long mins, secs = 0;
+
+ if (alarm->time.tm_year < (AB8500_RTC_EPOCH - 1900)) {
+ dev_dbg(dev, "year should be equal to or greater than %d\n",
+ AB8500_RTC_EPOCH);
+ return -EINVAL;
+ }
+
+ /* Get the number of seconds since 1970 */
+ rtc_tm_to_time(&alarm->time, &secs);
+
+ /*
+ * Convert it to the number of seconds since 01-01-2000 00:00:00
+ */
+ secs -= get_elapsed_seconds(AB8500_RTC_EPOCH);
+ mins = secs / 60;
+
+ buf[3] = secs % 60;
+ buf[2] = mins & 0xFF;
+ buf[1] = (mins >> 8) & 0xFF;
+ buf[0] = (mins >> 16) & 0xFF;
+
+ /* Set the alarm time */
+ for (i = 0; i < ARRAY_SIZE(ab8540_rtc_alarm_regs); i++) {
+ retval = abx500_set_register_interruptible(dev, AB8500_RTC,
+ ab8540_rtc_alarm_regs[i], buf[i]);
+ if (retval < 0)
+ return retval;
+ }
+
+ return ab8500_rtc_irq_enable(dev, alarm->enabled);
+}
static int ab8500_rtc_set_calibration(struct device *dev, int calibration)
{
@@ -380,8 +434,22 @@ static const struct rtc_class_ops ab8500_rtc_ops = {
.alarm_irq_enable = ab8500_rtc_irq_enable,
};
-static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
+static const struct rtc_class_ops ab8540_rtc_ops = {
+ .read_time = ab8500_rtc_read_time,
+ .set_time = ab8500_rtc_set_time,
+ .read_alarm = ab8500_rtc_read_alarm,
+ .set_alarm = ab8540_rtc_set_alarm,
+ .alarm_irq_enable = ab8500_rtc_irq_enable,
+};
+
+static struct platform_device_id ab85xx_rtc_ids[] = {
+ { "ab8500-rtc", (kernel_ulong_t)&ab8500_rtc_ops, },
+ { "ab8540-rtc", (kernel_ulong_t)&ab8540_rtc_ops, },
+};
+
+static int ab8500_rtc_probe(struct platform_device *pdev)
{
+ const struct platform_device_id *platid = platform_get_device_id(pdev);
int err;
struct rtc_device *rtc;
u8 rtc_ctrl;
@@ -413,24 +481,23 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, true);
- rtc = rtc_device_register("ab8500-rtc", &pdev->dev, &ab8500_rtc_ops,
- THIS_MODULE);
+ rtc = devm_rtc_device_register(&pdev->dev, "ab8500-rtc",
+ (struct rtc_class_ops *)platid->driver_data,
+ THIS_MODULE);
if (IS_ERR(rtc)) {
dev_err(&pdev->dev, "Registration failed\n");
err = PTR_ERR(rtc);
return err;
}
- err = request_threaded_irq(irq, NULL, rtc_alarm_handler,
- IRQF_NO_SUSPEND, "ab8500-rtc", rtc);
- if (err < 0) {
- rtc_device_unregister(rtc);
+ err = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ rtc_alarm_handler, IRQF_NO_SUSPEND | IRQF_ONESHOT,
+ "ab8500-rtc", rtc);
+ if (err < 0)
return err;
- }
platform_set_drvdata(pdev, rtc);
-
err = ab8500_sysfs_rtc_register(&pdev->dev);
if (err) {
dev_err(&pdev->dev, "sysfs RTC failed to register\n");
@@ -440,17 +507,10 @@ static int __devinit ab8500_rtc_probe(struct platform_device *pdev)
return 0;
}
-static int __devexit ab8500_rtc_remove(struct platform_device *pdev)
+static int ab8500_rtc_remove(struct platform_device *pdev)
{
- struct rtc_device *rtc = platform_get_drvdata(pdev);
- int irq = platform_get_irq_byname(pdev, "ALARM");
-
ab8500_sysfs_rtc_unregister(&pdev->dev);
- free_irq(irq, rtc);
- rtc_device_unregister(rtc);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
@@ -460,7 +520,8 @@ static struct platform_driver ab8500_rtc_driver = {
.owner = THIS_MODULE,
},
.probe = ab8500_rtc_probe,
- .remove = __devexit_p(ab8500_rtc_remove),
+ .remove = ab8500_rtc_remove,
+ .id_table = ab85xx_rtc_ids,
};
module_platform_driver(ab8500_rtc_driver);
diff --git a/drivers/rtc/rtc-as3722.c b/drivers/rtc/rtc-as3722.c
new file mode 100644
index 00000000000..9f38eda6915
--- /dev/null
+++ b/drivers/rtc/rtc-as3722.c
@@ -0,0 +1,261 @@
+/*
+ * rtc-as3722.c - Real Time Clock driver for ams AS3722 PMICs
+ *
+ * Copyright (C) 2013 ams AG
+ * Copyright (c) 2013, NVIDIA Corporation. All rights reserved.
+ *
+ * Author: Florian Lobmaier <florian.lobmaier@ams.com>
+ * Author: Laxman Dewangan <ldewangan@nvidia.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/bcd.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mfd/as3722.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/time.h>
+
+#define AS3722_RTC_START_YEAR 2000
+struct as3722_rtc {
+ struct rtc_device *rtc;
+ struct device *dev;
+ struct as3722 *as3722;
+ int alarm_irq;
+ bool irq_enable;
+};
+
+static void as3722_time_to_reg(u8 *rbuff, struct rtc_time *tm)
+{
+ rbuff[0] = bin2bcd(tm->tm_sec);
+ rbuff[1] = bin2bcd(tm->tm_min);
+ rbuff[2] = bin2bcd(tm->tm_hour);
+ rbuff[3] = bin2bcd(tm->tm_mday);
+ rbuff[4] = bin2bcd(tm->tm_mon);
+ rbuff[5] = bin2bcd(tm->tm_year - (AS3722_RTC_START_YEAR - 1900));
+}
+
+static void as3722_reg_to_time(u8 *rbuff, struct rtc_time *tm)
+{
+ tm->tm_sec = bcd2bin(rbuff[0] & 0x7F);
+ tm->tm_min = bcd2bin(rbuff[1] & 0x7F);
+ tm->tm_hour = bcd2bin(rbuff[2] & 0x3F);
+ tm->tm_mday = bcd2bin(rbuff[3] & 0x3F);
+ tm->tm_mon = bcd2bin(rbuff[4] & 0x1F);
+ tm->tm_year = (AS3722_RTC_START_YEAR - 1900) + bcd2bin(rbuff[5] & 0x7F);
+ return;
+}
+
+static int as3722_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);
+ struct as3722 *as3722 = as3722_rtc->as3722;
+ u8 as_time_array[6];
+ int ret;
+
+ ret = as3722_block_read(as3722, AS3722_RTC_SECOND_REG,
+ 6, as_time_array);
+ if (ret < 0) {
+ dev_err(dev, "RTC_SECOND reg block read failed %d\n", ret);
+ return ret;
+ }
+ as3722_reg_to_time(as_time_array, tm);
+ return 0;
+}
+
+static int as3722_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);
+ struct as3722 *as3722 = as3722_rtc->as3722;
+ u8 as_time_array[6];
+ int ret;
+
+ if (tm->tm_year < (AS3722_RTC_START_YEAR - 1900))
+ return -EINVAL;
+
+ as3722_time_to_reg(as_time_array, tm);
+ ret = as3722_block_write(as3722, AS3722_RTC_SECOND_REG, 6,
+ as_time_array);
+ if (ret < 0)
+ dev_err(dev, "RTC_SECOND reg block write failed %d\n", ret);
+ return ret;
+}
+
+static int as3722_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);
+
+ if (enabled && !as3722_rtc->irq_enable) {
+ enable_irq(as3722_rtc->alarm_irq);
+ as3722_rtc->irq_enable = true;
+ } else if (!enabled && as3722_rtc->irq_enable) {
+ disable_irq(as3722_rtc->alarm_irq);
+ as3722_rtc->irq_enable = false;
+ }
+ return 0;
+}
+
+static int as3722_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);
+ struct as3722 *as3722 = as3722_rtc->as3722;
+ u8 as_time_array[6];
+ int ret;
+
+ ret = as3722_block_read(as3722, AS3722_RTC_ALARM_SECOND_REG, 6,
+ as_time_array);
+ if (ret < 0) {
+ dev_err(dev, "RTC_ALARM_SECOND block read failed %d\n", ret);
+ return ret;
+ }
+
+ as3722_reg_to_time(as_time_array, &alrm->time);
+ return 0;
+}
+
+static int as3722_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);
+ struct as3722 *as3722 = as3722_rtc->as3722;
+ u8 as_time_array[6];
+ int ret;
+
+ if (alrm->time.tm_year < (AS3722_RTC_START_YEAR - 1900))
+ return -EINVAL;
+
+ ret = as3722_rtc_alarm_irq_enable(dev, 0);
+ if (ret < 0) {
+ dev_err(dev, "Disable RTC alarm failed\n");
+ return ret;
+ }
+
+ as3722_time_to_reg(as_time_array, &alrm->time);
+ ret = as3722_block_write(as3722, AS3722_RTC_ALARM_SECOND_REG, 6,
+ as_time_array);
+ if (ret < 0) {
+ dev_err(dev, "RTC_ALARM_SECOND block write failed %d\n", ret);
+ return ret;
+ }
+
+ if (alrm->enabled)
+ ret = as3722_rtc_alarm_irq_enable(dev, alrm->enabled);
+ return ret;
+}
+
+static irqreturn_t as3722_alarm_irq(int irq, void *data)
+{
+ struct as3722_rtc *as3722_rtc = data;
+
+ rtc_update_irq(as3722_rtc->rtc, 1, RTC_IRQF | RTC_AF);
+ return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops as3722_rtc_ops = {
+ .read_time = as3722_rtc_read_time,
+ .set_time = as3722_rtc_set_time,
+ .read_alarm = as3722_rtc_read_alarm,
+ .set_alarm = as3722_rtc_set_alarm,
+ .alarm_irq_enable = as3722_rtc_alarm_irq_enable,
+};
+
+static int as3722_rtc_probe(struct platform_device *pdev)
+{
+ struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent);
+ struct as3722_rtc *as3722_rtc;
+ int ret;
+
+ as3722_rtc = devm_kzalloc(&pdev->dev, sizeof(*as3722_rtc), GFP_KERNEL);
+ if (!as3722_rtc)
+ return -ENOMEM;
+
+ as3722_rtc->as3722 = as3722;
+ as3722_rtc->dev = &pdev->dev;
+ platform_set_drvdata(pdev, as3722_rtc);
+
+ /* Enable the RTC to make sure it is running. */
+ ret = as3722_update_bits(as3722, AS3722_RTC_CONTROL_REG,
+ AS3722_RTC_ON | AS3722_RTC_ALARM_WAKEUP_EN,
+ AS3722_RTC_ON | AS3722_RTC_ALARM_WAKEUP_EN);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "RTC_CONTROL reg write failed: %d\n", ret);
+ return ret;
+ }
+
+ device_init_wakeup(&pdev->dev, 1);
+
+ as3722_rtc->rtc = devm_rtc_device_register(&pdev->dev, "as3722-rtc",
+ &as3722_rtc_ops, THIS_MODULE);
+ if (IS_ERR(as3722_rtc->rtc)) {
+ ret = PTR_ERR(as3722_rtc->rtc);
+ dev_err(&pdev->dev, "RTC register failed: %d\n", ret);
+ return ret;
+ }
+
+ as3722_rtc->alarm_irq = platform_get_irq(pdev, 0);
+ dev_info(&pdev->dev, "RTC interrupt %d\n", as3722_rtc->alarm_irq);
+
+ ret = devm_request_threaded_irq(&pdev->dev, as3722_rtc->alarm_irq, NULL,
+ as3722_alarm_irq, IRQF_ONESHOT | IRQF_EARLY_RESUME,
+ "rtc-alarm", as3722_rtc);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to request alarm IRQ %d: %d\n",
+ as3722_rtc->alarm_irq, ret);
+ return ret;
+ }
+ disable_irq(as3722_rtc->alarm_irq);
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int as3722_rtc_suspend(struct device *dev)
+{
+ struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(as3722_rtc->alarm_irq);
+
+ return 0;
+}
+
+static int as3722_rtc_resume(struct device *dev)
+{
+ struct as3722_rtc *as3722_rtc = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(as3722_rtc->alarm_irq);
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(as3722_rtc_pm_ops, as3722_rtc_suspend,
+ as3722_rtc_resume);
+
+static struct platform_driver as3722_rtc_driver = {
+ .probe = as3722_rtc_probe,
+ .driver = {
+ .name = "as3722-rtc",
+ .pm = &as3722_rtc_pm_ops,
+ },
+};
+module_platform_driver(as3722_rtc_driver);
+
+MODULE_DESCRIPTION("RTC driver for AS3722 PMICs");
+MODULE_ALIAS("platform:as3722-rtc");
+MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@ams.com>");
+MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-at32ap700x.c b/drivers/rtc/rtc-at32ap700x.c
index 8dd08305aae..aee3387fb09 100644
--- a/drivers/rtc/rtc-at32ap700x.c
+++ b/drivers/rtc/rtc-at32ap700x.c
@@ -141,7 +141,7 @@ static int at32_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
spin_lock_irq(&rtc->lock);
- if(enabled) {
+ if (enabled) {
if (rtc_readl(rtc, VAL) > rtc->alarm_time) {
ret = -EINVAL;
goto out;
@@ -202,32 +202,28 @@ static int __init at32_rtc_probe(struct platform_device *pdev)
int irq;
int ret;
- rtc = kzalloc(sizeof(struct rtc_at32ap700x), GFP_KERNEL);
- if (!rtc) {
- dev_dbg(&pdev->dev, "out of memory\n");
+ rtc = devm_kzalloc(&pdev->dev, sizeof(struct rtc_at32ap700x),
+ GFP_KERNEL);
+ if (!rtc)
return -ENOMEM;
- }
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
dev_dbg(&pdev->dev, "no mmio resource defined\n");
- ret = -ENXIO;
- goto out;
+ return -ENXIO;
}
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_dbg(&pdev->dev, "could not get irq\n");
- ret = -ENXIO;
- goto out;
+ return -ENXIO;
}
rtc->irq = irq;
- rtc->regs = ioremap(regs->start, resource_size(regs));
+ rtc->regs = devm_ioremap(&pdev->dev, regs->start, resource_size(regs));
if (!rtc->regs) {
- ret = -ENOMEM;
dev_dbg(&pdev->dev, "could not map I/O memory\n");
- goto out;
+ return -ENOMEM;
}
spin_lock_init(&rtc->lock);
@@ -244,20 +240,20 @@ static int __init at32_rtc_probe(struct platform_device *pdev)
| RTC_BIT(CTRL_EN));
}
- ret = request_irq(irq, at32_rtc_interrupt, IRQF_SHARED, "rtc", rtc);
+ ret = devm_request_irq(&pdev->dev, irq, at32_rtc_interrupt, IRQF_SHARED,
+ "rtc", rtc);
if (ret) {
dev_dbg(&pdev->dev, "could not request irq %d\n", irq);
- goto out_iounmap;
+ return ret;
}
platform_set_drvdata(pdev, rtc);
- rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&at32_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc->rtc)) {
dev_dbg(&pdev->dev, "could not register rtc device\n");
- ret = PTR_ERR(rtc->rtc);
- goto out_free_irq;
+ return PTR_ERR(rtc->rtc);
}
device_init_wakeup(&pdev->dev, 1);
@@ -266,29 +262,12 @@ static int __init at32_rtc_probe(struct platform_device *pdev)
(unsigned long)rtc->regs, rtc->irq);
return 0;
-
-out_free_irq:
- platform_set_drvdata(pdev, NULL);
- free_irq(irq, rtc);
-out_iounmap:
- iounmap(rtc->regs);
-out:
- kfree(rtc);
- return ret;
}
static int __exit at32_rtc_remove(struct platform_device *pdev)
{
- struct rtc_at32ap700x *rtc = platform_get_drvdata(pdev);
-
device_init_wakeup(&pdev->dev, 0);
- free_irq(rtc->irq, rtc);
- iounmap(rtc->regs);
- rtc_device_unregister(rtc->rtc);
- kfree(rtc);
- platform_set_drvdata(pdev, NULL);
-
return 0;
}
@@ -302,17 +281,7 @@ static struct platform_driver at32_rtc_driver = {
},
};
-static int __init at32_rtc_init(void)
-{
- return platform_driver_probe(&at32_rtc_driver, at32_rtc_probe);
-}
-module_init(at32_rtc_init);
-
-static void __exit at32_rtc_exit(void)
-{
- platform_driver_unregister(&at32_rtc_driver);
-}
-module_exit(at32_rtc_exit);
+module_platform_driver_probe(at32_rtc_driver, at32_rtc_probe);
MODULE_AUTHOR("Hans-Christian Egtvedt <hcegtvedt@atmel.com>");
MODULE_DESCRIPTION("Real time clock for AVR32 AT32AP700x");
diff --git a/drivers/rtc/rtc-at91rm9200.c b/drivers/rtc/rtc-at91rm9200.c
index dc474bc6522..44fe83ee9be 100644
--- a/drivers/rtc/rtc-at91rm9200.c
+++ b/drivers/rtc/rtc-at91rm9200.c
@@ -25,12 +25,15 @@
#include <linux/rtc.h>
#include <linux/bcd.h>
#include <linux/interrupt.h>
+#include <linux/spinlock.h>
#include <linux/ioctl.h>
#include <linux/completion.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/uaccess.h>
-#include <asm/uaccess.h>
-
-#include <mach/at91_rtc.h>
+#include "rtc-at91rm9200.h"
#define at91_rtc_read(field) \
__raw_readl(at91_rtc_regs + field)
@@ -39,10 +42,66 @@
#define AT91_RTC_EPOCH 1900UL /* just like arch/arm/common/rtctime.c */
+struct at91_rtc_config {
+ bool use_shadow_imr;
+};
+
+static const struct at91_rtc_config *at91_rtc_config;
static DECLARE_COMPLETION(at91_rtc_updated);
+static DECLARE_COMPLETION(at91_rtc_upd_rdy);
static unsigned int at91_alarm_year = AT91_RTC_EPOCH;
static void __iomem *at91_rtc_regs;
static int irq;
+static DEFINE_SPINLOCK(at91_rtc_lock);
+static u32 at91_rtc_shadow_imr;
+
+static void at91_rtc_write_ier(u32 mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&at91_rtc_lock, flags);
+ at91_rtc_shadow_imr |= mask;
+ at91_rtc_write(AT91_RTC_IER, mask);
+ spin_unlock_irqrestore(&at91_rtc_lock, flags);
+}
+
+static void at91_rtc_write_idr(u32 mask)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&at91_rtc_lock, flags);
+ at91_rtc_write(AT91_RTC_IDR, mask);
+ /*
+ * Register read back (of any RTC-register) needed to make sure
+ * IDR-register write has reached the peripheral before updating
+ * shadow mask.
+ *
+ * Note that there is still a possibility that the mask is updated
+ * before interrupts have actually been disabled in hardware. The only
+ * way to be certain would be to poll the IMR-register, which is is
+ * the very register we are trying to emulate. The register read back
+ * is a reasonable heuristic.
+ */
+ at91_rtc_read(AT91_RTC_SR);
+ at91_rtc_shadow_imr &= ~mask;
+ spin_unlock_irqrestore(&at91_rtc_lock, flags);
+}
+
+static u32 at91_rtc_read_imr(void)
+{
+ unsigned long flags;
+ u32 mask;
+
+ if (at91_rtc_config->use_shadow_imr) {
+ spin_lock_irqsave(&at91_rtc_lock, flags);
+ mask = at91_rtc_shadow_imr;
+ spin_unlock_irqrestore(&at91_rtc_lock, flags);
+ } else {
+ mask = at91_rtc_read(AT91_RTC_IMR);
+ }
+
+ return mask;
+}
/*
* Decode time/date into rtc_time structure
@@ -85,7 +144,7 @@ static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
tm->tm_year = tm->tm_year - 1900;
- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
+ dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
@@ -99,17 +158,19 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
{
unsigned long cr;
- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
+ dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
+ wait_for_completion(&at91_rtc_upd_rdy);
+
/* Stop Time/Calendar from counting */
cr = at91_rtc_read(AT91_RTC_CR);
at91_rtc_write(AT91_RTC_CR, cr | AT91_RTC_UPDCAL | AT91_RTC_UPDTIM);
- at91_rtc_write(AT91_RTC_IER, AT91_RTC_ACKUPD);
+ at91_rtc_write_ier(AT91_RTC_ACKUPD);
wait_for_completion(&at91_rtc_updated); /* wait for ACKUPD interrupt */
- at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD);
+ at91_rtc_write_idr(AT91_RTC_ACKUPD);
at91_rtc_write(AT91_RTC_TIMR,
bin2bcd(tm->tm_sec) << 0
@@ -125,7 +186,9 @@ static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
/* Restart Time/Calendar */
cr = at91_rtc_read(AT91_RTC_CR);
+ at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_SECEV);
at91_rtc_write(AT91_RTC_CR, cr & ~(AT91_RTC_UPDCAL | AT91_RTC_UPDTIM));
+ at91_rtc_write_ier(AT91_RTC_SECEV);
return 0;
}
@@ -141,10 +204,10 @@ static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
tm->tm_year = at91_alarm_year - 1900;
- alrm->enabled = (at91_rtc_read(AT91_RTC_IMR) & AT91_RTC_ALARM)
+ alrm->enabled = (at91_rtc_read_imr() & AT91_RTC_ALARM)
? 1 : 0;
- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
+ dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
@@ -162,11 +225,13 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
at91_alarm_year = tm.tm_year;
+ tm.tm_mon = alrm->time.tm_mon;
+ tm.tm_mday = alrm->time.tm_mday;
tm.tm_hour = alrm->time.tm_hour;
tm.tm_min = alrm->time.tm_min;
tm.tm_sec = alrm->time.tm_sec;
- at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ALARM);
+ at91_rtc_write_idr(AT91_RTC_ALARM);
at91_rtc_write(AT91_RTC_TIMALR,
bin2bcd(tm.tm_sec) << 0
| bin2bcd(tm.tm_min) << 8
@@ -179,10 +244,10 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
if (alrm->enabled) {
at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
- at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM);
+ at91_rtc_write_ier(AT91_RTC_ALARM);
}
- pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
+ dev_dbg(dev, "%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __func__,
at91_alarm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour,
tm.tm_min, tm.tm_sec);
@@ -191,13 +256,13 @@ static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
- pr_debug("%s(): cmd=%08x\n", __func__, enabled);
+ dev_dbg(dev, "%s(): cmd=%08x\n", __func__, enabled);
if (enabled) {
at91_rtc_write(AT91_RTC_SCCR, AT91_RTC_ALARM);
- at91_rtc_write(AT91_RTC_IER, AT91_RTC_ALARM);
+ at91_rtc_write_ier(AT91_RTC_ALARM);
} else
- at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ALARM);
+ at91_rtc_write_idr(AT91_RTC_ALARM);
return 0;
}
@@ -206,7 +271,7 @@ static int at91_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
*/
static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
{
- unsigned long imr = at91_rtc_read(AT91_RTC_IMR);
+ unsigned long imr = at91_rtc_read_imr();
seq_printf(seq, "update_IRQ\t: %s\n",
(imr & AT91_RTC_ACKUPD) ? "yes" : "no");
@@ -226,12 +291,14 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
unsigned int rtsr;
unsigned long events = 0;
- rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read(AT91_RTC_IMR);
+ rtsr = at91_rtc_read(AT91_RTC_SR) & at91_rtc_read_imr();
if (rtsr) { /* this interrupt is shared! Is it ours? */
if (rtsr & AT91_RTC_ALARM)
events |= (RTC_AF | RTC_IRQF);
- if (rtsr & AT91_RTC_SECEV)
- events |= (RTC_UF | RTC_IRQF);
+ if (rtsr & AT91_RTC_SECEV) {
+ complete(&at91_rtc_upd_rdy);
+ at91_rtc_write_idr(AT91_RTC_SECEV);
+ }
if (rtsr & AT91_RTC_ACKUPD)
complete(&at91_rtc_updated);
@@ -239,7 +306,7 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
rtc_update_irq(rtc, 1, events);
- pr_debug("%s(): num=%ld, events=0x%02lx\n", __func__,
+ dev_dbg(&pdev->dev, "%s(): num=%ld, events=0x%02lx\n", __func__,
events >> 8, events & 0x000000FF);
return IRQ_HANDLED;
@@ -247,6 +314,43 @@ static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
return IRQ_NONE; /* not handled */
}
+static const struct at91_rtc_config at91rm9200_config = {
+};
+
+static const struct at91_rtc_config at91sam9x5_config = {
+ .use_shadow_imr = true,
+};
+
+#ifdef CONFIG_OF
+static const struct of_device_id at91_rtc_dt_ids[] = {
+ {
+ .compatible = "atmel,at91rm9200-rtc",
+ .data = &at91rm9200_config,
+ }, {
+ .compatible = "atmel,at91sam9x5-rtc",
+ .data = &at91sam9x5_config,
+ }, {
+ /* sentinel */
+ }
+};
+MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids);
+#endif
+
+static const struct at91_rtc_config *
+at91_rtc_get_config(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+
+ if (pdev->dev.of_node) {
+ match = of_match_node(at91_rtc_dt_ids, pdev->dev.of_node);
+ if (!match)
+ return NULL;
+ return (const struct at91_rtc_config *)match->data;
+ }
+
+ return &at91rm9200_config;
+}
+
static const struct rtc_class_ops at91_rtc_ops = {
.read_time = at91_rtc_readtime,
.set_time = at91_rtc_settime,
@@ -265,6 +369,10 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
struct resource *regs;
int ret = 0;
+ at91_rtc_config = at91_rtc_get_config(pdev);
+ if (!at91_rtc_config)
+ return -ENODEV;
+
regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!regs) {
dev_err(&pdev->dev, "no mmio resource defined\n");
@@ -277,7 +385,8 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
return -ENXIO;
}
- at91_rtc_regs = ioremap(regs->start, resource_size(regs));
+ at91_rtc_regs = devm_ioremap(&pdev->dev, regs->start,
+ resource_size(regs));
if (!at91_rtc_regs) {
dev_err(&pdev->dev, "failed to map registers, aborting.\n");
return -ENOMEM;
@@ -287,16 +396,15 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
at91_rtc_write(AT91_RTC_MR, 0); /* 24 hour mode */
/* Disable all interrupts */
- at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
+ at91_rtc_write_idr(AT91_RTC_ACKUPD | AT91_RTC_ALARM |
AT91_RTC_SECEV | AT91_RTC_TIMEV |
AT91_RTC_CALEV);
- ret = request_irq(irq, at91_rtc_interrupt,
+ ret = devm_request_irq(&pdev->dev, irq, at91_rtc_interrupt,
IRQF_SHARED,
"at91_rtc", pdev);
if (ret) {
- printk(KERN_ERR "at91_rtc: IRQ %d already in use.\n",
- irq);
+ dev_err(&pdev->dev, "IRQ %d already in use.\n", irq);
return ret;
}
@@ -306,15 +414,18 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
if (!device_can_wakeup(&pdev->dev))
device_init_wakeup(&pdev->dev, 1);
- rtc = rtc_device_register(pdev->name, &pdev->dev,
+ rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&at91_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc)) {
- free_irq(irq, pdev);
+ if (IS_ERR(rtc))
return PTR_ERR(rtc);
- }
platform_set_drvdata(pdev, rtc);
- printk(KERN_INFO "AT91 Real Time Clock driver.\n");
+ /* enable SECEV interrupt in order to initialize at91_rtc_upd_rdy
+ * completion.
+ */
+ at91_rtc_write_ier(AT91_RTC_SECEV);
+
+ dev_info(&pdev->dev, "AT91 Real Time Clock driver.\n");
return 0;
}
@@ -323,21 +434,23 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
*/
static int __exit at91_rtc_remove(struct platform_device *pdev)
{
- struct rtc_device *rtc = platform_get_drvdata(pdev);
-
/* Disable all interrupts */
- at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
+ at91_rtc_write_idr(AT91_RTC_ACKUPD | AT91_RTC_ALARM |
AT91_RTC_SECEV | AT91_RTC_TIMEV |
AT91_RTC_CALEV);
- free_irq(irq, pdev);
-
- rtc_device_unregister(rtc);
- platform_set_drvdata(pdev, NULL);
return 0;
}
-#ifdef CONFIG_PM
+static void at91_rtc_shutdown(struct platform_device *pdev)
+{
+ /* Disable all interrupts */
+ at91_rtc_write(AT91_RTC_IDR, AT91_RTC_ACKUPD | AT91_RTC_ALARM |
+ AT91_RTC_SECEV | AT91_RTC_TIMEV |
+ AT91_RTC_CALEV);
+}
+
+#ifdef CONFIG_PM_SLEEP
/* AT91RM9200 RTC Power management control */
@@ -348,13 +461,13 @@ static int at91_rtc_suspend(struct device *dev)
/* this IRQ is shared with DBGU and other hardware which isn't
* necessarily doing PM like we are...
*/
- at91_rtc_imr = at91_rtc_read(AT91_RTC_IMR)
+ at91_rtc_imr = at91_rtc_read_imr()
& (AT91_RTC_ALARM|AT91_RTC_SECEV);
if (at91_rtc_imr) {
if (device_may_wakeup(dev))
enable_irq_wake(irq);
else
- at91_rtc_write(AT91_RTC_IDR, at91_rtc_imr);
+ at91_rtc_write_idr(at91_rtc_imr);
}
return 0;
}
@@ -365,43 +478,26 @@ static int at91_rtc_resume(struct device *dev)
if (device_may_wakeup(dev))
disable_irq_wake(irq);
else
- at91_rtc_write(AT91_RTC_IER, at91_rtc_imr);
+ at91_rtc_write_ier(at91_rtc_imr);
}
return 0;
}
-
-static const struct dev_pm_ops at91_rtc_pm = {
- .suspend = at91_rtc_suspend,
- .resume = at91_rtc_resume,
-};
-
-#define at91_rtc_pm_ptr &at91_rtc_pm
-
-#else
-#define at91_rtc_pm_ptr NULL
#endif
+static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume);
+
static struct platform_driver at91_rtc_driver = {
.remove = __exit_p(at91_rtc_remove),
+ .shutdown = at91_rtc_shutdown,
.driver = {
.name = "at91_rtc",
.owner = THIS_MODULE,
- .pm = at91_rtc_pm_ptr,
+ .pm = &at91_rtc_pm_ops,
+ .of_match_table = of_match_ptr(at91_rtc_dt_ids),
},
};
-static int __init at91_rtc_init(void)
-{
- return platform_driver_probe(&at91_rtc_driver, at91_rtc_probe);
-}
-
-static void __exit at91_rtc_exit(void)
-{
- platform_driver_unregister(&at91_rtc_driver);
-}
-
-module_init(at91_rtc_init);
-module_exit(at91_rtc_exit);
+module_platform_driver_probe(at91_rtc_driver, at91_rtc_probe);
MODULE_AUTHOR("Rick Bronson");
MODULE_DESCRIPTION("RTC driver for Atmel AT91RM9200");
diff --git a/drivers/rtc/rtc-at91rm9200.h b/drivers/rtc/rtc-at91rm9200.h
new file mode 100644
index 00000000000..da1945e5f71
--- /dev/null
+++ b/drivers/rtc/rtc-at91rm9200.h
@@ -0,0 +1,75 @@
+/*
+ * arch/arm/mach-at91/include/mach/at91_rtc.h
+ *
+ * Copyright (C) 2005 Ivan Kokshaysky
+ * Copyright (C) SAN People
+ *
+ * Real Time Clock (RTC) - System peripheral registers.
+ * Based on AT91RM9200 datasheet revision E.
+ *
+ * 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 AT91_RTC_H
+#define AT91_RTC_H
+
+#define AT91_RTC_CR 0x00 /* Control Register */
+#define AT91_RTC_UPDTIM (1 << 0) /* Update Request Time Register */
+#define AT91_RTC_UPDCAL (1 << 1) /* Update Request Calendar Register */
+#define AT91_RTC_TIMEVSEL (3 << 8) /* Time Event Selection */
+#define AT91_RTC_TIMEVSEL_MINUTE (0 << 8)
+#define AT91_RTC_TIMEVSEL_HOUR (1 << 8)
+#define AT91_RTC_TIMEVSEL_DAY24 (2 << 8)
+#define AT91_RTC_TIMEVSEL_DAY12 (3 << 8)
+#define AT91_RTC_CALEVSEL (3 << 16) /* Calendar Event Selection */
+#define AT91_RTC_CALEVSEL_WEEK (0 << 16)
+#define AT91_RTC_CALEVSEL_MONTH (1 << 16)
+#define AT91_RTC_CALEVSEL_YEAR (2 << 16)
+
+#define AT91_RTC_MR 0x04 /* Mode Register */
+#define AT91_RTC_HRMOD (1 << 0) /* 12/24 Hour Mode */
+
+#define AT91_RTC_TIMR 0x08 /* Time Register */
+#define AT91_RTC_SEC (0x7f << 0) /* Current Second */
+#define AT91_RTC_MIN (0x7f << 8) /* Current Minute */
+#define AT91_RTC_HOUR (0x3f << 16) /* Current Hour */
+#define AT91_RTC_AMPM (1 << 22) /* Ante Meridiem Post Meridiem Indicator */
+
+#define AT91_RTC_CALR 0x0c /* Calendar Register */
+#define AT91_RTC_CENT (0x7f << 0) /* Current Century */
+#define AT91_RTC_YEAR (0xff << 8) /* Current Year */
+#define AT91_RTC_MONTH (0x1f << 16) /* Current Month */
+#define AT91_RTC_DAY (7 << 21) /* Current Day */
+#define AT91_RTC_DATE (0x3f << 24) /* Current Date */
+
+#define AT91_RTC_TIMALR 0x10 /* Time Alarm Register */
+#define AT91_RTC_SECEN (1 << 7) /* Second Alarm Enable */
+#define AT91_RTC_MINEN (1 << 15) /* Minute Alarm Enable */
+#define AT91_RTC_HOUREN (1 << 23) /* Hour Alarm Enable */
+
+#define AT91_RTC_CALALR 0x14 /* Calendar Alarm Register */
+#define AT91_RTC_MTHEN (1 << 23) /* Month Alarm Enable */
+#define AT91_RTC_DATEEN (1 << 31) /* Date Alarm Enable */
+
+#define AT91_RTC_SR 0x18 /* Status Register */
+#define AT91_RTC_ACKUPD (1 << 0) /* Acknowledge for Update */
+#define AT91_RTC_ALARM (1 << 1) /* Alarm Flag */
+#define AT91_RTC_SECEV (1 << 2) /* Second Event */
+#define AT91_RTC_TIMEV (1 << 3) /* Time Event */
+#define AT91_RTC_CALEV (1 << 4) /* Calendar Event */
+
+#define AT91_RTC_SCCR 0x1c /* Status Clear Command Register */
+#define AT91_RTC_IER 0x20 /* Interrupt Enable Register */
+#define AT91_RTC_IDR 0x24 /* Interrupt Disable Register */
+#define AT91_RTC_IMR 0x28 /* Interrupt Mask Register */
+
+#define AT91_RTC_VER 0x2c /* Valid Entry Register */
+#define AT91_RTC_NVTIM (1 << 0) /* Non valid Time */
+#define AT91_RTC_NVCAL (1 << 1) /* Non valid Calendar */
+#define AT91_RTC_NVTIMALR (1 << 2) /* Non valid Time Alarm */
+#define AT91_RTC_NVCALALR (1 << 3) /* Non valid Calendar Alarm */
+
+#endif
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
index ee3c122c059..59637430453 100644
--- a/drivers/rtc/rtc-at91sam9.c
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -19,11 +19,12 @@
#include <linux/interrupt.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
+#include <linux/platform_data/atmel.h>
+#include <linux/io.h>
-#include <mach/board.h>
#include <mach/at91_rtt.h>
#include <mach/cpu.h>
-
+#include <mach/hardware.h>
/*
* This driver uses two configurable hardware resources that live in the
@@ -57,6 +58,8 @@ struct sam9_rtc {
void __iomem *rtt;
struct rtc_device *rtcdev;
u32 imr;
+ void __iomem *gpbr;
+ int irq;
};
#define rtt_readl(rtc, field) \
@@ -65,9 +68,9 @@ struct sam9_rtc {
__raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field)
#define gpbr_readl(rtc) \
- at91_sys_read(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR)
+ __raw_readl((rtc)->gpbr)
#define gpbr_writel(rtc, val) \
- at91_sys_write(AT91_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR, (val))
+ __raw_writel((val), (rtc)->gpbr)
/*
* Read current time and date in RTC
@@ -287,31 +290,48 @@ static const struct rtc_class_ops at91_rtc_ops = {
/*
* Initialize and install RTC driver
*/
-static int __init at91_rtc_probe(struct platform_device *pdev)
+static int at91_rtc_probe(struct platform_device *pdev)
{
- struct resource *r;
+ struct resource *r, *r_gpbr;
struct sam9_rtc *rtc;
- int ret;
+ int ret, irq;
u32 mr;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r)
+ r_gpbr = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!r || !r_gpbr) {
+ dev_err(&pdev->dev, "need 2 ressources\n");
return -ENODEV;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get interrupt resource\n");
+ return irq;
+ }
- rtc = kzalloc(sizeof *rtc, GFP_KERNEL);
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
if (!rtc)
return -ENOMEM;
+ rtc->irq = irq;
+
/* platform setup code should have handled this; sigh */
if (!device_can_wakeup(&pdev->dev))
device_init_wakeup(&pdev->dev, 1);
platform_set_drvdata(pdev, rtc);
- rtc->rtt = ioremap(r->start, resource_size(r));
+ rtc->rtt = devm_ioremap(&pdev->dev, r->start, resource_size(r));
if (!rtc->rtt) {
dev_err(&pdev->dev, "failed to map registers, aborting.\n");
- ret = -ENOMEM;
- goto fail;
+ return -ENOMEM;
+ }
+
+ rtc->gpbr = devm_ioremap(&pdev->dev, r_gpbr->start,
+ resource_size(r_gpbr));
+ if (!rtc->gpbr) {
+ dev_err(&pdev->dev, "failed to map gpbr registers, aborting.\n");
+ return -ENOMEM;
}
mr = rtt_readl(rtc, MR);
@@ -326,21 +346,17 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
mr &= ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
rtt_writel(rtc, MR, mr);
- rtc->rtcdev = rtc_device_register(pdev->name, &pdev->dev,
- &at91_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc->rtcdev)) {
- ret = PTR_ERR(rtc->rtcdev);
- goto fail_register;
- }
+ rtc->rtcdev = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &at91_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtcdev))
+ return PTR_ERR(rtc->rtcdev);
/* register irq handler after we know what name we'll use */
- ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
- IRQF_DISABLED | IRQF_SHARED,
- dev_name(&rtc->rtcdev->dev), rtc);
+ ret = devm_request_irq(&pdev->dev, rtc->irq, at91_rtc_interrupt,
+ IRQF_SHARED, dev_name(&rtc->rtcdev->dev), rtc);
if (ret) {
- dev_dbg(&pdev->dev, "can't share IRQ %d?\n", AT91_ID_SYS);
- rtc_device_unregister(rtc->rtcdev);
- goto fail;
+ dev_dbg(&pdev->dev, "can't share IRQ %d?\n", rtc->irq);
+ return ret;
}
/* NOTE: sam9260 rev A silicon has a ROM bug which resets the
@@ -354,32 +370,19 @@ static int __init at91_rtc_probe(struct platform_device *pdev)
dev_name(&rtc->rtcdev->dev));
return 0;
-
-fail_register:
- iounmap(rtc->rtt);
-fail:
- platform_set_drvdata(pdev, NULL);
- kfree(rtc);
- return ret;
}
/*
* Disable and remove the RTC driver
*/
-static int __exit at91_rtc_remove(struct platform_device *pdev)
+static int at91_rtc_remove(struct platform_device *pdev)
{
struct sam9_rtc *rtc = platform_get_drvdata(pdev);
u32 mr = rtt_readl(rtc, MR);
/* disable all interrupts */
rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
- free_irq(AT91_ID_SYS, rtc);
-
- rtc_device_unregister(rtc->rtcdev);
- iounmap(rtc->rtt);
- platform_set_drvdata(pdev, NULL);
- kfree(rtc);
return 0;
}
@@ -392,14 +395,13 @@ static void at91_rtc_shutdown(struct platform_device *pdev)
rtt_writel(rtc, MR, mr & ~rtc->imr);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
/* AT91SAM9 RTC Power management control */
-static int at91_rtc_suspend(struct platform_device *pdev,
- pm_message_t state)
+static int at91_rtc_suspend(struct device *dev)
{
- struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+ struct sam9_rtc *rtc = dev_get_drvdata(dev);
u32 mr = rtt_readl(rtc, MR);
/*
@@ -408,8 +410,8 @@ static int at91_rtc_suspend(struct platform_device *pdev,
*/
rtc->imr = mr & (AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN);
if (rtc->imr) {
- if (device_may_wakeup(&pdev->dev) && (mr & AT91_RTT_ALMIEN)) {
- enable_irq_wake(AT91_ID_SYS);
+ if (device_may_wakeup(dev) && (mr & AT91_RTT_ALMIEN)) {
+ enable_irq_wake(rtc->irq);
/* don't let RTTINC cause wakeups */
if (mr & AT91_RTT_RTTINCIEN)
rtt_writel(rtc, MR, mr & ~AT91_RTT_RTTINCIEN);
@@ -420,92 +422,36 @@ static int at91_rtc_suspend(struct platform_device *pdev,
return 0;
}
-static int at91_rtc_resume(struct platform_device *pdev)
+static int at91_rtc_resume(struct device *dev)
{
- struct sam9_rtc *rtc = platform_get_drvdata(pdev);
+ struct sam9_rtc *rtc = dev_get_drvdata(dev);
u32 mr;
if (rtc->imr) {
- if (device_may_wakeup(&pdev->dev))
- disable_irq_wake(AT91_ID_SYS);
+ if (device_may_wakeup(dev))
+ disable_irq_wake(rtc->irq);
mr = rtt_readl(rtc, MR);
rtt_writel(rtc, MR, mr | rtc->imr);
}
return 0;
}
-#else
-#define at91_rtc_suspend NULL
-#define at91_rtc_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume);
+
static struct platform_driver at91_rtc_driver = {
- .driver.name = "rtc-at91sam9",
- .driver.owner = THIS_MODULE,
- .remove = __exit_p(at91_rtc_remove),
+ .probe = at91_rtc_probe,
+ .remove = at91_rtc_remove,
.shutdown = at91_rtc_shutdown,
- .suspend = at91_rtc_suspend,
- .resume = at91_rtc_resume,
+ .driver = {
+ .name = "rtc-at91sam9",
+ .owner = THIS_MODULE,
+ .pm = &at91_rtc_pm_ops,
+ },
};
-/* Chips can have more than one RTT module, and they can be used for more
- * than just RTCs. So we can't just register as "the" RTT driver.
- *
- * A normal approach in such cases is to create a library to allocate and
- * free the modules. Here we just use bus_find_device() as like such a
- * library, binding directly ... no runtime "library" footprint is needed.
- */
-static int __init at91_rtc_match(struct device *dev, void *v)
-{
- struct platform_device *pdev = to_platform_device(dev);
- int ret;
-
- /* continue searching if this isn't the RTT we need */
- if (strcmp("at91_rtt", pdev->name) != 0
- || pdev->id != CONFIG_RTC_DRV_AT91SAM9_RTT)
- goto fail;
-
- /* else we found it ... but fail unless we can bind to the RTC driver */
- if (dev->driver) {
- dev_dbg(dev, "busy, can't use as RTC!\n");
- goto fail;
- }
- dev->driver = &at91_rtc_driver.driver;
- if (device_attach(dev) == 0) {
- dev_dbg(dev, "can't attach RTC!\n");
- goto fail;
- }
- ret = at91_rtc_probe(pdev);
- if (ret == 0)
- return true;
-
- dev_dbg(dev, "RTC probe err %d!\n", ret);
-fail:
- return false;
-}
-
-static int __init at91_rtc_init(void)
-{
- int status;
- struct device *rtc;
-
- status = platform_driver_register(&at91_rtc_driver);
- if (status)
- return status;
- rtc = bus_find_device(&platform_bus_type, NULL,
- NULL, at91_rtc_match);
- if (!rtc)
- platform_driver_unregister(&at91_rtc_driver);
- return rtc ? 0 : -ENODEV;
-}
-module_init(at91_rtc_init);
-
-static void __exit at91_rtc_exit(void)
-{
- platform_driver_unregister(&at91_rtc_driver);
-}
-module_exit(at91_rtc_exit);
-
+module_platform_driver(at91_rtc_driver);
MODULE_AUTHOR("Michel Benoit");
MODULE_DESCRIPTION("RTC driver for Atmel AT91SAM9x");
diff --git a/drivers/rtc/rtc-au1xxx.c b/drivers/rtc/rtc-au1xxx.c
index 979ed0406ce..ed526a192ce 100644
--- a/drivers/rtc/rtc-au1xxx.c
+++ b/drivers/rtc/rtc-au1xxx.c
@@ -62,7 +62,7 @@ static struct rtc_class_ops au1xtoy_rtc_ops = {
.set_time = au1xtoy_rtc_set_time,
};
-static int __devinit au1xtoy_rtc_probe(struct platform_device *pdev)
+static int au1xtoy_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtcdev;
unsigned long t;
@@ -101,7 +101,7 @@ static int __devinit au1xtoy_rtc_probe(struct platform_device *pdev)
while (au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C0S)
msleep(1);
- rtcdev = rtc_device_register("rtc-au1xxx", &pdev->dev,
+ rtcdev = devm_rtc_device_register(&pdev->dev, "rtc-au1xxx",
&au1xtoy_rtc_ops, THIS_MODULE);
if (IS_ERR(rtcdev)) {
ret = PTR_ERR(rtcdev);
@@ -116,36 +116,14 @@ out_err:
return ret;
}
-static int __devexit au1xtoy_rtc_remove(struct platform_device *pdev)
-{
- struct rtc_device *rtcdev = platform_get_drvdata(pdev);
-
- rtc_device_unregister(rtcdev);
- platform_set_drvdata(pdev, NULL);
-
- return 0;
-}
-
static struct platform_driver au1xrtc_driver = {
.driver = {
.name = "rtc-au1xxx",
.owner = THIS_MODULE,
},
- .remove = __devexit_p(au1xtoy_rtc_remove),
};
-static int __init au1xtoy_rtc_init(void)
-{
- return platform_driver_probe(&au1xrtc_driver, au1xtoy_rtc_probe);
-}
-
-static void __exit au1xtoy_rtc_exit(void)
-{
- platform_driver_unregister(&au1xrtc_driver);
-}
-
-module_init(au1xtoy_rtc_init);
-module_exit(au1xtoy_rtc_exit);
+module_platform_driver_probe(au1xrtc_driver, au1xtoy_rtc_probe);
MODULE_DESCRIPTION("Au1xxx TOY-counter-based RTC driver");
MODULE_AUTHOR("Manuel Lauss <manuel.lauss@gmail.com>");
diff --git a/drivers/rtc/rtc-bfin.c b/drivers/rtc/rtc-bfin.c
index abfc1a0c07d..fe4bdb06a55 100644
--- a/drivers/rtc/rtc-bfin.c
+++ b/drivers/rtc/rtc-bfin.c
@@ -342,34 +342,36 @@ static struct rtc_class_ops bfin_rtc_ops = {
.alarm_irq_enable = bfin_rtc_alarm_irq_enable,
};
-static int __devinit bfin_rtc_probe(struct platform_device *pdev)
+static int bfin_rtc_probe(struct platform_device *pdev)
{
struct bfin_rtc *rtc;
struct device *dev = &pdev->dev;
- int ret = 0;
+ int ret;
unsigned long timeout = jiffies + HZ;
dev_dbg_stamp(dev);
/* Allocate memory for our RTC struct */
- rtc = kzalloc(sizeof(*rtc), GFP_KERNEL);
+ rtc = devm_kzalloc(dev, sizeof(*rtc), GFP_KERNEL);
if (unlikely(!rtc))
return -ENOMEM;
platform_set_drvdata(pdev, rtc);
device_init_wakeup(dev, 1);
/* Register our RTC with the RTC framework */
- rtc->rtc_dev = rtc_device_register(pdev->name, dev, &bfin_rtc_ops,
+ rtc->rtc_dev = devm_rtc_device_register(dev, pdev->name, &bfin_rtc_ops,
THIS_MODULE);
- if (unlikely(IS_ERR(rtc->rtc_dev))) {
- ret = PTR_ERR(rtc->rtc_dev);
- goto err;
- }
+ if (unlikely(IS_ERR(rtc->rtc_dev)))
+ return PTR_ERR(rtc->rtc_dev);
/* Grab the IRQ and init the hardware */
- ret = request_irq(IRQ_RTC, bfin_rtc_interrupt, 0, pdev->name, dev);
+ ret = devm_request_irq(dev, IRQ_RTC, bfin_rtc_interrupt, 0,
+ pdev->name, dev);
if (unlikely(ret))
- goto err_reg;
+ dev_err(&pdev->dev,
+ "unable to request IRQ; alarm won't work, "
+ "and writes will be delayed\n");
+
/* sometimes the bootloader touched things, but the write complete was not
* enabled, so let's just do a quick timeout here since the IRQ will not fire ...
*/
@@ -380,33 +382,20 @@ static int __devinit bfin_rtc_probe(struct platform_device *pdev)
bfin_write_RTC_SWCNT(0);
return 0;
-
-err_reg:
- rtc_device_unregister(rtc->rtc_dev);
-err:
- kfree(rtc);
- return ret;
}
-static int __devexit bfin_rtc_remove(struct platform_device *pdev)
+static int bfin_rtc_remove(struct platform_device *pdev)
{
- struct bfin_rtc *rtc = platform_get_drvdata(pdev);
struct device *dev = &pdev->dev;
bfin_rtc_reset(dev, 0);
- free_irq(IRQ_RTC, dev);
- rtc_device_unregister(rtc->rtc_dev);
- platform_set_drvdata(pdev, NULL);
- kfree(rtc);
return 0;
}
-#ifdef CONFIG_PM
-static int bfin_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int bfin_rtc_suspend(struct device *dev)
{
- struct device *dev = &pdev->dev;
-
dev_dbg_stamp(dev);
if (device_may_wakeup(dev)) {
@@ -418,10 +407,8 @@ static int bfin_rtc_suspend(struct platform_device *pdev, pm_message_t state)
return 0;
}
-static int bfin_rtc_resume(struct platform_device *pdev)
+static int bfin_rtc_resume(struct device *dev)
{
- struct device *dev = &pdev->dev;
-
dev_dbg_stamp(dev);
if (device_may_wakeup(dev))
@@ -440,20 +427,18 @@ static int bfin_rtc_resume(struct platform_device *pdev)
return 0;
}
-#else
-# define bfin_rtc_suspend NULL
-# define bfin_rtc_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(bfin_rtc_pm_ops, bfin_rtc_suspend, bfin_rtc_resume);
+
static struct platform_driver bfin_rtc_driver = {
.driver = {
.name = "rtc-bfin",
.owner = THIS_MODULE,
+ .pm = &bfin_rtc_pm_ops,
},
.probe = bfin_rtc_probe,
- .remove = __devexit_p(bfin_rtc_remove),
- .suspend = bfin_rtc_suspend,
- .resume = bfin_rtc_resume,
+ .remove = bfin_rtc_remove,
};
module_platform_driver(bfin_rtc_driver);
diff --git a/drivers/rtc/rtc-bq32k.c b/drivers/rtc/rtc-bq32k.c
index 408cc8f735b..c74bf0dc52c 100644
--- a/drivers/rtc/rtc-bq32k.c
+++ b/drivers/rtc/rtc-bq32k.c
@@ -153,7 +153,7 @@ static int bq32k_probe(struct i2c_client *client,
if (error)
return error;
- rtc = rtc_device_register(bq32k_driver.driver.name, &client->dev,
+ rtc = devm_rtc_device_register(&client->dev, bq32k_driver.driver.name,
&bq32k_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -163,14 +163,6 @@ static int bq32k_probe(struct i2c_client *client,
return 0;
}
-static int __devexit bq32k_remove(struct i2c_client *client)
-{
- struct rtc_device *rtc = i2c_get_clientdata(client);
-
- rtc_device_unregister(rtc);
- return 0;
-}
-
static const struct i2c_device_id bq32k_id[] = {
{ "bq32000", 0 },
{ }
@@ -183,21 +175,10 @@ static struct i2c_driver bq32k_driver = {
.owner = THIS_MODULE,
},
.probe = bq32k_probe,
- .remove = __devexit_p(bq32k_remove),
.id_table = bq32k_id,
};
-static __init int bq32k_init(void)
-{
- return i2c_add_driver(&bq32k_driver);
-}
-module_init(bq32k_init);
-
-static __exit void bq32k_exit(void)
-{
- i2c_del_driver(&bq32k_driver);
-}
-module_exit(bq32k_exit);
+module_i2c_driver(bq32k_driver);
MODULE_AUTHOR("Semihalf, Piotr Ziecik <kosmo@semihalf.com>");
MODULE_DESCRIPTION("TI BQ32000 I2C RTC driver");
diff --git a/drivers/rtc/rtc-bq4802.c b/drivers/rtc/rtc-bq4802.c
index bf612ef2294..fc0ff87aa5d 100644
--- a/drivers/rtc/rtc-bq4802.c
+++ b/drivers/rtc/rtc-bq4802.c
@@ -140,9 +140,9 @@ static const struct rtc_class_ops bq4802_ops = {
.set_time = bq4802_set_time,
};
-static int __devinit bq4802_probe(struct platform_device *pdev)
+static int bq4802_probe(struct platform_device *pdev)
{
- struct bq4802 *p = kzalloc(sizeof(*p), GFP_KERNEL);
+ struct bq4802 *p = devm_kzalloc(&pdev->dev, sizeof(*p), GFP_KERNEL);
int err = -ENOMEM;
if (!p)
@@ -155,55 +155,35 @@ static int __devinit bq4802_probe(struct platform_device *pdev)
p->r = platform_get_resource(pdev, IORESOURCE_IO, 0);
err = -EINVAL;
if (!p->r)
- goto out_free;
+ goto out;
}
if (p->r->flags & IORESOURCE_IO) {
p->ioport = p->r->start;
p->read = bq4802_read_io;
p->write = bq4802_write_io;
} else if (p->r->flags & IORESOURCE_MEM) {
- p->regs = ioremap(p->r->start, resource_size(p->r));
+ p->regs = devm_ioremap(&pdev->dev, p->r->start,
+ resource_size(p->r));
p->read = bq4802_read_mem;
p->write = bq4802_write_mem;
} else {
err = -EINVAL;
- goto out_free;
+ goto out;
}
platform_set_drvdata(pdev, p);
- p->rtc = rtc_device_register("bq4802", &pdev->dev,
- &bq4802_ops, THIS_MODULE);
+ p->rtc = devm_rtc_device_register(&pdev->dev, "bq4802",
+ &bq4802_ops, THIS_MODULE);
if (IS_ERR(p->rtc)) {
err = PTR_ERR(p->rtc);
- goto out_iounmap;
+ goto out;
}
err = 0;
out:
return err;
-out_iounmap:
- if (p->r->flags & IORESOURCE_MEM)
- iounmap(p->regs);
-out_free:
- kfree(p);
- goto out;
-}
-
-static int __devexit bq4802_remove(struct platform_device *pdev)
-{
- struct bq4802 *p = platform_get_drvdata(pdev);
-
- rtc_device_unregister(p->rtc);
- if (p->r->flags & IORESOURCE_MEM)
- iounmap(p->regs);
-
- platform_set_drvdata(pdev, NULL);
-
- kfree(p);
-
- return 0;
}
/* work with hotplug and coldplug */
@@ -215,7 +195,6 @@ static struct platform_driver bq4802_driver = {
.owner = THIS_MODULE,
},
.probe = bq4802_probe,
- .remove = __devexit_p(bq4802_remove),
};
module_platform_driver(bq4802_driver);
diff --git a/drivers/rtc/rtc-cmos.c b/drivers/rtc/rtc-cmos.c
index d7782aa0994..b0e4a3eb33c 100644
--- a/drivers/rtc/rtc-cmos.c
+++ b/drivers/rtc/rtc-cmos.c
@@ -34,11 +34,11 @@
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/platform_device.h>
-#include <linux/mod_devicetable.h>
#include <linux/log2.h>
#include <linux/pm.h>
#include <linux/of.h>
#include <linux/of_platform.h>
+#include <linux/dmi.h>
/* this is for "generic access to PC-style RTC" using CMOS_READ/CMOS_WRITE */
#include <asm-generic/rtc.h>
@@ -326,7 +326,7 @@ static void cmos_irq_disable(struct cmos_rtc *cmos, unsigned char mask)
static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
- unsigned char mon, mday, hrs, min, sec, rtc_control;
+ unsigned char mon, mday, hrs, min, sec, rtc_control;
if (!is_valid_irq(cmos->irq))
return -EIO;
@@ -377,6 +377,51 @@ static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
return 0;
}
+/*
+ * Do not disable RTC alarm on shutdown - workaround for b0rked BIOSes.
+ */
+static bool alarm_disable_quirk;
+
+static int __init set_alarm_disable_quirk(const struct dmi_system_id *id)
+{
+ alarm_disable_quirk = true;
+ pr_info("rtc-cmos: BIOS has alarm-disable quirk. ");
+ pr_info("RTC alarms disabled\n");
+ return 0;
+}
+
+static const struct dmi_system_id rtc_quirks[] __initconst = {
+ /* https://bugzilla.novell.com/show_bug.cgi?id=805740 */
+ {
+ .callback = set_alarm_disable_quirk,
+ .ident = "IBM Truman",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "4852570"),
+ },
+ },
+ /* https://bugzilla.novell.com/show_bug.cgi?id=812592 */
+ {
+ .callback = set_alarm_disable_quirk,
+ .ident = "Gigabyte GA-990XA-UD3",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR,
+ "Gigabyte Technology Co., Ltd."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "GA-990XA-UD3"),
+ },
+ },
+ /* http://permalink.gmane.org/gmane.linux.kernel/1604474 */
+ {
+ .callback = set_alarm_disable_quirk,
+ .ident = "Toshiba Satellite L300",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "TOSHIBA"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Satellite L300"),
+ },
+ },
+ {}
+};
+
static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
@@ -385,6 +430,9 @@ static int cmos_alarm_irq_enable(struct device *dev, unsigned int enabled)
if (!is_valid_irq(cmos->irq))
return -EINVAL;
+ if (alarm_disable_quirk)
+ return 0;
+
spin_lock_irqsave(&rtc_lock, flags);
if (enabled)
@@ -556,17 +604,24 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
rtc_control = CMOS_READ(RTC_CONTROL);
if (is_hpet_enabled())
irqstat = (unsigned long)irq & 0xF0;
- irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+
+ /* If we were suspended, RTC_CONTROL may not be accurate since the
+ * bios may have cleared it.
+ */
+ if (!cmos_rtc.suspend_ctrl)
+ irqstat &= (rtc_control & RTC_IRQMASK) | RTC_IRQF;
+ else
+ irqstat &= (cmos_rtc.suspend_ctrl & RTC_IRQMASK) | RTC_IRQF;
/* All Linux RTC alarms should be treated as if they were oneshot.
* Similar code may be needed in system wakeup paths, in case the
* alarm woke the system.
*/
if (irqstat & RTC_AIE) {
+ cmos_rtc.suspend_ctrl &= ~RTC_AIE;
rtc_control &= ~RTC_AIE;
CMOS_WRITE(rtc_control, RTC_CONTROL);
hpet_mask_rtc_irq_bit(RTC_AIE);
-
CMOS_READ(RTC_INTR_FLAGS);
}
spin_unlock(&rtc_lock);
@@ -588,10 +643,11 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
static int INITSECTION
cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
{
- struct cmos_rtc_board_info *info = dev->platform_data;
+ struct cmos_rtc_board_info *info = dev_get_platdata(dev);
int retval = 0;
unsigned char rtc_control;
unsigned address_space;
+ u32 flags = 0;
/* there can be only one ... */
if (cmos_rtc.dev)
@@ -605,9 +661,12 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
* REVISIT non-x86 systems may instead use memory space resources
* (needing ioremap etc), not i/o space resources like this ...
*/
- ports = request_region(ports->start,
- resource_size(ports),
- driver_name);
+ if (RTC_IOMAPPED)
+ ports = request_region(ports->start, resource_size(ports),
+ driver_name);
+ else
+ ports = request_mem_region(ports->start, resource_size(ports),
+ driver_name);
if (!ports) {
dev_dbg(dev, "i/o registers already in use\n");
return -EBUSY;
@@ -644,6 +703,11 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
* expect CMOS_READ and friends to handle.
*/
if (info) {
+ if (info->flags)
+ flags = info->flags;
+ if (info->address_space)
+ address_space = info->address_space;
+
if (info->rtc_day_alarm && info->rtc_day_alarm < 128)
cmos_rtc.day_alrm = info->rtc_day_alarm;
if (info->rtc_mon_alarm && info->rtc_mon_alarm < 128)
@@ -671,18 +735,21 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
spin_lock_irq(&rtc_lock);
- /* force periodic irq to CMOS reset default of 1024Hz;
- *
- * REVISIT it's been reported that at least one x86_64 ALI mobo
- * doesn't use 32KHz here ... for portability we might need to
- * do something about other clock frequencies.
- */
- cmos_rtc.rtc->irq_freq = 1024;
- hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq);
- CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
+ if (!(flags & CMOS_RTC_FLAGS_NOFREQ)) {
+ /* force periodic irq to CMOS reset default of 1024Hz;
+ *
+ * REVISIT it's been reported that at least one x86_64 ALI
+ * mobo doesn't use 32KHz here ... for portability we might
+ * need to do something about other clock frequencies.
+ */
+ cmos_rtc.rtc->irq_freq = 1024;
+ hpet_set_periodic_freq(cmos_rtc.rtc->irq_freq);
+ CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
+ }
/* disable irqs */
- cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE);
+ if (is_valid_irq(rtc_irq))
+ cmos_irq_disable(&cmos_rtc, RTC_PIE | RTC_AIE | RTC_UIE);
rtc_control = CMOS_READ(RTC_CONTROL);
@@ -691,7 +758,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
/* FIXME:
* <asm-generic/rtc.h> doesn't know 12-hour mode either.
*/
- if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) {
+ if (is_valid_irq(rtc_irq) && !(rtc_control & RTC_24H)) {
dev_warn(dev, "only 24-hr supported\n");
retval = -ENXIO;
goto cleanup1;
@@ -701,12 +768,10 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
irq_handler_t rtc_cmos_int_handler;
if (is_hpet_enabled()) {
- int err;
-
rtc_cmos_int_handler = hpet_rtc_interrupt;
- err = hpet_register_irq_handler(cmos_interrupt);
- if (err != 0) {
- printk(KERN_WARNING "hpet_register_irq_handler "
+ retval = hpet_register_irq_handler(cmos_interrupt);
+ if (retval) {
+ dev_warn(dev, "hpet_register_irq_handler "
" failed in rtc_init().");
goto cleanup1;
}
@@ -714,7 +779,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
rtc_cmos_int_handler = cmos_interrupt;
retval = request_irq(rtc_irq, rtc_cmos_int_handler,
- IRQF_DISABLED, dev_name(&cmos_rtc.rtc->dev),
+ 0, dev_name(&cmos_rtc.rtc->dev),
cmos_rtc.rtc);
if (retval < 0) {
dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
@@ -731,8 +796,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
goto cleanup2;
}
- pr_info("%s: %s%s, %zd bytes nvram%s\n",
- dev_name(&cmos_rtc.rtc->dev),
+ dev_info(dev, "%s%s, %zd bytes nvram%s\n",
!is_valid_irq(rtc_irq) ? "no alarms" :
cmos_rtc.mon_alrm ? "alarms up to one year" :
cmos_rtc.day_alrm ? "alarms up to one month" :
@@ -750,14 +814,18 @@ cleanup1:
cmos_rtc.dev = NULL;
rtc_device_unregister(cmos_rtc.rtc);
cleanup0:
- release_region(ports->start, resource_size(ports));
+ if (RTC_IOMAPPED)
+ release_region(ports->start, resource_size(ports));
+ else
+ release_mem_region(ports->start, resource_size(ports));
return retval;
}
-static void cmos_do_shutdown(void)
+static void cmos_do_shutdown(int rtc_irq)
{
spin_lock_irq(&rtc_lock);
- cmos_irq_disable(&cmos_rtc, RTC_IRQMASK);
+ if (is_valid_irq(rtc_irq))
+ cmos_irq_disable(&cmos_rtc, RTC_IRQMASK);
spin_unlock_irq(&rtc_lock);
}
@@ -766,7 +834,7 @@ static void __exit cmos_do_remove(struct device *dev)
struct cmos_rtc *cmos = dev_get_drvdata(dev);
struct resource *ports;
- cmos_do_shutdown();
+ cmos_do_shutdown(cmos->irq);
sysfs_remove_bin_file(&dev->kobj, &nvram);
@@ -779,14 +847,16 @@ static void __exit cmos_do_remove(struct device *dev)
cmos->rtc = NULL;
ports = cmos->iomem;
- release_region(ports->start, resource_size(ports));
+ if (RTC_IOMAPPED)
+ release_region(ports->start, resource_size(ports));
+ else
+ release_mem_region(ports->start, resource_size(ports));
cmos->iomem = NULL;
cmos->dev = NULL;
- dev_set_drvdata(dev, NULL);
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int cmos_suspend(struct device *dev)
{
@@ -805,9 +875,8 @@ static int cmos_suspend(struct device *dev)
mask = RTC_IRQMASK;
tmp &= ~mask;
CMOS_WRITE(tmp, RTC_CONTROL);
+ hpet_mask_rtc_irq_bit(mask);
- /* shut down hpet emulation - we don't need it for alarm */
- hpet_mask_rtc_irq_bit(RTC_PIE|RTC_AIE|RTC_UIE);
cmos_checkintr(cmos, tmp);
}
spin_unlock_irq(&rtc_lock);
@@ -820,8 +889,7 @@ static int cmos_suspend(struct device *dev)
enable_irq_wake(cmos->irq);
}
- pr_debug("%s: suspend%s, ctrl %02x\n",
- dev_name(&cmos_rtc.rtc->dev),
+ dev_dbg(dev, "suspend%s, ctrl %02x\n",
(tmp & RTC_AIE) ? ", alarm may wake" : "",
tmp);
@@ -842,21 +910,26 @@ static inline int cmos_poweroff(struct device *dev)
static int cmos_resume(struct device *dev)
{
struct cmos_rtc *cmos = dev_get_drvdata(dev);
- unsigned char tmp = cmos->suspend_ctrl;
+ unsigned char tmp;
+
+ if (cmos->enabled_wake) {
+ if (cmos->wake_off)
+ cmos->wake_off(dev);
+ else
+ disable_irq_wake(cmos->irq);
+ cmos->enabled_wake = 0;
+ }
+ spin_lock_irq(&rtc_lock);
+ tmp = cmos->suspend_ctrl;
+ cmos->suspend_ctrl = 0;
/* re-enable any irqs previously active */
if (tmp & RTC_IRQMASK) {
unsigned char mask;
- if (cmos->enabled_wake) {
- if (cmos->wake_off)
- cmos->wake_off(dev);
- else
- disable_irq_wake(cmos->irq);
- cmos->enabled_wake = 0;
- }
+ if (device_may_wakeup(dev))
+ hpet_rtc_timer_init();
- spin_lock_irq(&rtc_lock);
do {
CMOS_WRITE(tmp, RTC_CONTROL);
hpet_set_rtc_irq_bit(tmp & RTC_IRQMASK);
@@ -873,18 +946,14 @@ static int cmos_resume(struct device *dev)
tmp &= ~RTC_AIE;
hpet_mask_rtc_irq_bit(RTC_AIE);
} while (mask & RTC_AIE);
- spin_unlock_irq(&rtc_lock);
}
+ spin_unlock_irq(&rtc_lock);
- pr_debug("%s: resume, ctrl %02x\n",
- dev_name(&cmos_rtc.rtc->dev),
- tmp);
+ dev_dbg(dev, "resume, ctrl %02x\n", tmp);
return 0;
}
-static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume);
-
#else
static inline int cmos_poweroff(struct device *dev)
@@ -894,6 +963,8 @@ static inline int cmos_poweroff(struct device *dev)
#endif
+static SIMPLE_DEV_PM_OPS(cmos_pm_ops, cmos_suspend, cmos_resume);
+
/*----------------------------------------------------------------*/
/* On non-x86 systems, a "CMOS" RTC lives most naturally on platform_bus.
@@ -910,14 +981,17 @@ static inline int cmos_poweroff(struct device *dev)
static u32 rtc_handler(void *context)
{
+ struct device *dev = context;
+
+ pm_wakeup_event(dev, 0);
acpi_clear_event(ACPI_EVENT_RTC);
acpi_disable_event(ACPI_EVENT_RTC, 0);
return ACPI_INTERRUPT_HANDLED;
}
-static inline void rtc_wake_setup(void)
+static inline void rtc_wake_setup(struct device *dev)
{
- acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
+ acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, dev);
/*
* After the RTC handler is installed, the Fixed_RTC event should
* be disabled. Only when the RTC alarm is set will it be enabled.
@@ -944,13 +1018,12 @@ static void rtc_wake_off(struct device *dev)
*/
static struct cmos_rtc_board_info acpi_rtc_info;
-static void __devinit
-cmos_wake_setup(struct device *dev)
+static void cmos_wake_setup(struct device *dev)
{
if (acpi_disabled)
return;
- rtc_wake_setup();
+ rtc_wake_setup(dev);
acpi_rtc_info.wake_on = rtc_wake_on;
acpi_rtc_info.wake_off = rtc_wake_off;
@@ -977,8 +1050,7 @@ cmos_wake_setup(struct device *dev)
#else
-static void __devinit
-cmos_wake_setup(struct device *dev)
+static void cmos_wake_setup(struct device *dev)
{
}
@@ -988,12 +1060,11 @@ cmos_wake_setup(struct device *dev)
#include <linux/pnp.h>
-static int __devinit
-cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
+static int cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
{
cmos_wake_setup(&pnp->dev);
- if (pnp_port_start(pnp,0) == 0x70 && !pnp_irq_valid(pnp,0))
+ if (pnp_port_start(pnp, 0) == 0x70 && !pnp_irq_valid(pnp, 0))
/* Some machines contain a PNP entry for the RTC, but
* don't define the IRQ. It should always be safe to
* hardcode it in these cases
@@ -1011,29 +1082,15 @@ static void __exit cmos_pnp_remove(struct pnp_dev *pnp)
cmos_do_remove(&pnp->dev);
}
-#ifdef CONFIG_PM
-
-static int cmos_pnp_suspend(struct pnp_dev *pnp, pm_message_t mesg)
-{
- return cmos_suspend(&pnp->dev);
-}
-
-static int cmos_pnp_resume(struct pnp_dev *pnp)
-{
- return cmos_resume(&pnp->dev);
-}
-
-#else
-#define cmos_pnp_suspend NULL
-#define cmos_pnp_resume NULL
-#endif
-
static void cmos_pnp_shutdown(struct pnp_dev *pnp)
{
- if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pnp->dev))
+ struct device *dev = &pnp->dev;
+ struct cmos_rtc *cmos = dev_get_drvdata(dev);
+
+ if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev))
return;
- cmos_do_shutdown();
+ cmos_do_shutdown(cmos->irq);
}
static const struct pnp_device_id rtc_ids[] = {
@@ -1053,8 +1110,9 @@ static struct pnp_driver cmos_pnp_driver = {
/* flag ensures resume() gets called, and stops syslog spam */
.flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
- .suspend = cmos_pnp_suspend,
- .resume = cmos_pnp_resume,
+ .driver = {
+ .pm = &cmos_pm_ops,
+ },
};
#endif /* CONFIG_PNP */
@@ -1098,7 +1156,6 @@ static __init void cmos_of_init(struct platform_device *pdev)
}
#else
static inline void cmos_of_init(struct platform_device *pdev) {}
-#define of_cmos_match NULL
#endif
/*----------------------------------------------------------------*/
@@ -1108,11 +1165,21 @@ static inline void cmos_of_init(struct platform_device *pdev) {}
static int __init cmos_platform_probe(struct platform_device *pdev)
{
+ struct resource *resource;
+ int irq;
+
cmos_of_init(pdev);
cmos_wake_setup(&pdev->dev);
- return cmos_do_probe(&pdev->dev,
- platform_get_resource(pdev, IORESOURCE_IO, 0),
- platform_get_irq(pdev, 0));
+
+ if (RTC_IOMAPPED)
+ resource = platform_get_resource(pdev, IORESOURCE_IO, 0);
+ else
+ resource = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ irq = -1;
+
+ return cmos_do_probe(&pdev->dev, resource, irq);
}
static int __exit cmos_platform_remove(struct platform_device *pdev)
@@ -1123,10 +1190,13 @@ static int __exit cmos_platform_remove(struct platform_device *pdev)
static void cmos_platform_shutdown(struct platform_device *pdev)
{
- if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(&pdev->dev))
+ struct device *dev = &pdev->dev;
+ struct cmos_rtc *cmos = dev_get_drvdata(dev);
+
+ if (system_state == SYSTEM_POWER_OFF && !cmos_poweroff(dev))
return;
- cmos_do_shutdown();
+ cmos_do_shutdown(cmos->irq);
}
/* work with hotplug and coldplug */
@@ -1136,11 +1206,11 @@ static struct platform_driver cmos_platform_driver = {
.remove = __exit_p(cmos_platform_remove),
.shutdown = cmos_platform_shutdown,
.driver = {
- .name = (char *) driver_name,
+ .name = driver_name,
#ifdef CONFIG_PM
.pm = &cmos_pm_ops,
#endif
- .of_match_table = of_cmos_match,
+ .of_match_table = of_match_ptr(of_cmos_match),
}
};
@@ -1166,6 +1236,8 @@ static int __init cmos_init(void)
platform_driver_registered = true;
}
+ dmi_check_system(rtc_quirks);
+
if (retval == 0)
return 0;
diff --git a/drivers/rtc/rtc-coh901331.c b/drivers/rtc/rtc-coh901331.c
index 80f9c88214c..869cae27379 100644
--- a/drivers/rtc/rtc-coh901331.c
+++ b/drivers/rtc/rtc-coh901331.c
@@ -43,11 +43,9 @@
struct coh901331_port {
struct rtc_device *rtc;
struct clk *clk;
- u32 phybase;
- u32 physize;
void __iomem *virtbase;
int irq;
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
u32 irqmaskstore;
#endif
};
@@ -152,17 +150,10 @@ static struct rtc_class_ops coh901331_ops = {
static int __exit coh901331_remove(struct platform_device *pdev)
{
- struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
-
- if (rtap) {
- free_irq(rtap->irq, rtap);
- rtc_device_unregister(rtap->rtc);
- clk_put(rtap->clk);
- iounmap(rtap->virtbase);
- release_mem_region(rtap->phybase, rtap->physize);
- platform_set_drvdata(pdev, NULL);
- kfree(rtap);
- }
+ struct coh901331_port *rtap = platform_get_drvdata(pdev);
+
+ if (rtap)
+ clk_unprepare(rtap->clk);
return 0;
}
@@ -174,55 +165,39 @@ static int __init coh901331_probe(struct platform_device *pdev)
struct coh901331_port *rtap;
struct resource *res;
- rtap = kzalloc(sizeof(struct coh901331_port), GFP_KERNEL);
+ rtap = devm_kzalloc(&pdev->dev,
+ sizeof(struct coh901331_port), GFP_KERNEL);
if (!rtap)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- ret = -ENOENT;
- goto out_no_resource;
- }
- rtap->phybase = res->start;
- rtap->physize = resource_size(res);
-
- if (request_mem_region(rtap->phybase, rtap->physize,
- "rtc-coh901331") == NULL) {
- ret = -EBUSY;
- goto out_no_memregion;
- }
-
- rtap->virtbase = ioremap(rtap->phybase, rtap->physize);
- if (!rtap->virtbase) {
- ret = -ENOMEM;
- goto out_no_remap;
- }
+ rtap->virtbase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(rtap->virtbase))
+ return PTR_ERR(rtap->virtbase);
rtap->irq = platform_get_irq(pdev, 0);
- if (request_irq(rtap->irq, coh901331_interrupt, IRQF_DISABLED,
- "RTC COH 901 331 Alarm", rtap)) {
- ret = -EIO;
- goto out_no_irq;
- }
+ if (devm_request_irq(&pdev->dev, rtap->irq, coh901331_interrupt, 0,
+ "RTC COH 901 331 Alarm", rtap))
+ return -EIO;
- rtap->clk = clk_get(&pdev->dev, NULL);
+ rtap->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(rtap->clk)) {
ret = PTR_ERR(rtap->clk);
dev_err(&pdev->dev, "could not get clock\n");
- goto out_no_clk;
+ return ret;
}
/* We enable/disable the clock only to assure it works */
- ret = clk_enable(rtap->clk);
+ ret = clk_prepare_enable(rtap->clk);
if (ret) {
dev_err(&pdev->dev, "could not enable clock\n");
- goto out_no_clk_enable;
+ return ret;
}
clk_disable(rtap->clk);
platform_set_drvdata(pdev, rtap);
- rtap->rtc = rtc_device_register("coh901331", &pdev->dev, &coh901331_ops,
- THIS_MODULE);
+ rtap->rtc = devm_rtc_device_register(&pdev->dev, "coh901331",
+ &coh901331_ops, THIS_MODULE);
if (IS_ERR(rtap->rtc)) {
ret = PTR_ERR(rtap->rtc);
goto out_no_rtc;
@@ -231,33 +206,21 @@ static int __init coh901331_probe(struct platform_device *pdev)
return 0;
out_no_rtc:
- platform_set_drvdata(pdev, NULL);
- out_no_clk_enable:
- clk_put(rtap->clk);
- out_no_clk:
- free_irq(rtap->irq, rtap);
- out_no_irq:
- iounmap(rtap->virtbase);
- out_no_remap:
- platform_set_drvdata(pdev, NULL);
- out_no_memregion:
- release_mem_region(rtap->phybase, SZ_4K);
- out_no_resource:
- kfree(rtap);
+ clk_unprepare(rtap->clk);
return ret;
}
-#ifdef CONFIG_PM
-static int coh901331_suspend(struct platform_device *pdev, pm_message_t state)
+#ifdef CONFIG_PM_SLEEP
+static int coh901331_suspend(struct device *dev)
{
- struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
+ struct coh901331_port *rtap = dev_get_drvdata(dev);
/*
* If this RTC alarm will be used for waking the system up,
* don't disable it of course. Else we just disable the alarm
* and await suspension.
*/
- if (device_may_wakeup(&pdev->dev)) {
+ if (device_may_wakeup(dev)) {
enable_irq_wake(rtap->irq);
} else {
clk_enable(rtap->clk);
@@ -265,14 +228,16 @@ static int coh901331_suspend(struct platform_device *pdev, pm_message_t state)
writel(0, rtap->virtbase + COH901331_IRQ_MASK);
clk_disable(rtap->clk);
}
+ clk_unprepare(rtap->clk);
return 0;
}
-static int coh901331_resume(struct platform_device *pdev)
+static int coh901331_resume(struct device *dev)
{
- struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
+ struct coh901331_port *rtap = dev_get_drvdata(dev);
- if (device_may_wakeup(&pdev->dev)) {
+ clk_prepare(rtap->clk);
+ if (device_may_wakeup(dev)) {
disable_irq_wake(rtap->irq);
} else {
clk_enable(rtap->clk);
@@ -281,43 +246,36 @@ static int coh901331_resume(struct platform_device *pdev)
}
return 0;
}
-#else
-#define coh901331_suspend NULL
-#define coh901331_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(coh901331_pm_ops, coh901331_suspend, coh901331_resume);
+
static void coh901331_shutdown(struct platform_device *pdev)
{
- struct coh901331_port *rtap = dev_get_drvdata(&pdev->dev);
+ struct coh901331_port *rtap = platform_get_drvdata(pdev);
clk_enable(rtap->clk);
writel(0, rtap->virtbase + COH901331_IRQ_MASK);
- clk_disable(rtap->clk);
+ clk_disable_unprepare(rtap->clk);
}
+static const struct of_device_id coh901331_dt_match[] = {
+ { .compatible = "stericsson,coh901331" },
+ {},
+};
+
static struct platform_driver coh901331_driver = {
.driver = {
.name = "rtc-coh901331",
.owner = THIS_MODULE,
+ .pm = &coh901331_pm_ops,
+ .of_match_table = coh901331_dt_match,
},
.remove = __exit_p(coh901331_remove),
- .suspend = coh901331_suspend,
- .resume = coh901331_resume,
.shutdown = coh901331_shutdown,
};
-static int __init coh901331_init(void)
-{
- return platform_driver_probe(&coh901331_driver, coh901331_probe);
-}
-
-static void __exit coh901331_exit(void)
-{
- platform_driver_unregister(&coh901331_driver);
-}
-
-module_init(coh901331_init);
-module_exit(coh901331_exit);
+module_platform_driver_probe(coh901331_driver, coh901331_probe);
MODULE_AUTHOR("Linus Walleij <linus.walleij@stericsson.com>");
MODULE_DESCRIPTION("ST-Ericsson AB COH 901 331 RTC Driver");
diff --git a/drivers/rtc/rtc-da9052.c b/drivers/rtc/rtc-da9052.c
new file mode 100644
index 00000000000..e5c9486cf45
--- /dev/null
+++ b/drivers/rtc/rtc-da9052.c
@@ -0,0 +1,277 @@
+/*
+ * Real time clock driver for DA9052
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: Dajun Dajun Chen <dajun.chen@diasemi.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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/err.h>
+
+#include <linux/mfd/da9052/da9052.h>
+#include <linux/mfd/da9052/reg.h>
+
+#define rtc_err(rtc, fmt, ...) \
+ dev_err(rtc->da9052->dev, "%s: " fmt, __func__, ##__VA_ARGS__)
+
+struct da9052_rtc {
+ struct rtc_device *rtc;
+ struct da9052 *da9052;
+};
+
+static int da9052_rtc_enable_alarm(struct da9052_rtc *rtc, bool enable)
+{
+ int ret;
+ if (enable) {
+ ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG,
+ DA9052_ALARM_Y_ALARM_ON|DA9052_ALARM_Y_TICK_ON,
+ DA9052_ALARM_Y_ALARM_ON);
+ if (ret != 0)
+ rtc_err(rtc, "Failed to enable ALM: %d\n", ret);
+ } else {
+ ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG,
+ DA9052_ALARM_Y_ALARM_ON|DA9052_ALARM_Y_TICK_ON, 0);
+ if (ret != 0)
+ rtc_err(rtc, "Write error: %d\n", ret);
+ }
+ return ret;
+}
+
+static irqreturn_t da9052_rtc_irq(int irq, void *data)
+{
+ struct da9052_rtc *rtc = data;
+
+ rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
+
+ return IRQ_HANDLED;
+}
+
+static int da9052_read_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm)
+{
+ int ret;
+ uint8_t v[5];
+
+ ret = da9052_group_read(rtc->da9052, DA9052_ALARM_MI_REG, 5, v);
+ if (ret != 0) {
+ rtc_err(rtc, "Failed to group read ALM: %d\n", ret);
+ return ret;
+ }
+
+ rtc_tm->tm_year = (v[4] & DA9052_RTC_YEAR) + 100;
+ rtc_tm->tm_mon = (v[3] & DA9052_RTC_MONTH) - 1;
+ rtc_tm->tm_mday = v[2] & DA9052_RTC_DAY;
+ rtc_tm->tm_hour = v[1] & DA9052_RTC_HOUR;
+ rtc_tm->tm_min = v[0] & DA9052_RTC_MIN;
+
+ ret = rtc_valid_tm(rtc_tm);
+ return ret;
+}
+
+static int da9052_set_alarm(struct da9052_rtc *rtc, struct rtc_time *rtc_tm)
+{
+ struct da9052 *da9052 = rtc->da9052;
+ unsigned long alm_time;
+ int ret;
+ uint8_t v[3];
+
+ ret = rtc_tm_to_time(rtc_tm, &alm_time);
+ if (ret != 0)
+ return ret;
+
+ if (rtc_tm->tm_sec > 0) {
+ alm_time += 60 - rtc_tm->tm_sec;
+ rtc_time_to_tm(alm_time, rtc_tm);
+ }
+ BUG_ON(rtc_tm->tm_sec); /* it will cause repeated irqs if not zero */
+
+ rtc_tm->tm_year -= 100;
+ rtc_tm->tm_mon += 1;
+
+ ret = da9052_reg_update(da9052, DA9052_ALARM_MI_REG,
+ DA9052_RTC_MIN, rtc_tm->tm_min);
+ if (ret != 0) {
+ rtc_err(rtc, "Failed to write ALRM MIN: %d\n", ret);
+ return ret;
+ }
+
+ v[0] = rtc_tm->tm_hour;
+ v[1] = rtc_tm->tm_mday;
+ v[2] = rtc_tm->tm_mon;
+
+ ret = da9052_group_write(da9052, DA9052_ALARM_H_REG, 3, v);
+ if (ret < 0)
+ return ret;
+
+ ret = da9052_reg_update(da9052, DA9052_ALARM_Y_REG,
+ DA9052_RTC_YEAR, rtc_tm->tm_year);
+ if (ret != 0)
+ rtc_err(rtc, "Failed to write ALRM YEAR: %d\n", ret);
+
+ return ret;
+}
+
+static int da9052_rtc_get_alarm_status(struct da9052_rtc *rtc)
+{
+ int ret;
+
+ ret = da9052_reg_read(rtc->da9052, DA9052_ALARM_Y_REG);
+ if (ret < 0) {
+ rtc_err(rtc, "Failed to read ALM: %d\n", ret);
+ return ret;
+ }
+
+ return !!(ret&DA9052_ALARM_Y_ALARM_ON);
+}
+
+static int da9052_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+ struct da9052_rtc *rtc = dev_get_drvdata(dev);
+ uint8_t v[6];
+ int ret;
+
+ ret = da9052_group_read(rtc->da9052, DA9052_COUNT_S_REG, 6, v);
+ if (ret < 0) {
+ rtc_err(rtc, "Failed to read RTC time : %d\n", ret);
+ return ret;
+ }
+
+ rtc_tm->tm_year = (v[5] & DA9052_RTC_YEAR) + 100;
+ rtc_tm->tm_mon = (v[4] & DA9052_RTC_MONTH) - 1;
+ rtc_tm->tm_mday = v[3] & DA9052_RTC_DAY;
+ rtc_tm->tm_hour = v[2] & DA9052_RTC_HOUR;
+ rtc_tm->tm_min = v[1] & DA9052_RTC_MIN;
+ rtc_tm->tm_sec = v[0] & DA9052_RTC_SEC;
+
+ ret = rtc_valid_tm(rtc_tm);
+ return ret;
+}
+
+static int da9052_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct da9052_rtc *rtc;
+ uint8_t v[6];
+ int ret;
+
+ rtc = dev_get_drvdata(dev);
+
+ v[0] = tm->tm_sec;
+ v[1] = tm->tm_min;
+ v[2] = tm->tm_hour;
+ v[3] = tm->tm_mday;
+ v[4] = tm->tm_mon + 1;
+ v[5] = tm->tm_year - 100;
+
+ ret = da9052_group_write(rtc->da9052, DA9052_COUNT_S_REG, 6, v);
+ if (ret < 0)
+ rtc_err(rtc, "failed to set RTC time: %d\n", ret);
+ return ret;
+}
+
+static int da9052_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ int ret;
+ struct rtc_time *tm = &alrm->time;
+ struct da9052_rtc *rtc = dev_get_drvdata(dev);
+
+ ret = da9052_read_alarm(rtc, tm);
+ if (ret < 0) {
+ rtc_err(rtc, "failed to read RTC alarm: %d\n", ret);
+ return ret;
+ }
+
+ alrm->enabled = da9052_rtc_get_alarm_status(rtc);
+ return 0;
+}
+
+static int da9052_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ int ret;
+ struct rtc_time *tm = &alrm->time;
+ struct da9052_rtc *rtc = dev_get_drvdata(dev);
+
+ ret = da9052_rtc_enable_alarm(rtc, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = da9052_set_alarm(rtc, tm);
+ if (ret < 0)
+ return ret;
+
+ ret = da9052_rtc_enable_alarm(rtc, 1);
+ return ret;
+}
+
+static int da9052_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct da9052_rtc *rtc = dev_get_drvdata(dev);
+
+ return da9052_rtc_enable_alarm(rtc, enabled);
+}
+
+static const struct rtc_class_ops da9052_rtc_ops = {
+ .read_time = da9052_rtc_read_time,
+ .set_time = da9052_rtc_set_time,
+ .read_alarm = da9052_rtc_read_alarm,
+ .set_alarm = da9052_rtc_set_alarm,
+ .alarm_irq_enable = da9052_rtc_alarm_irq_enable,
+};
+
+static int da9052_rtc_probe(struct platform_device *pdev)
+{
+ struct da9052_rtc *rtc;
+ int ret;
+
+ rtc = devm_kzalloc(&pdev->dev, sizeof(struct da9052_rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->da9052 = dev_get_drvdata(pdev->dev.parent);
+ platform_set_drvdata(pdev, rtc);
+
+ ret = da9052_reg_write(rtc->da9052, DA9052_BBAT_CONT_REG, 0xFE);
+ if (ret < 0) {
+ rtc_err(rtc,
+ "Failed to setup RTC battery charging: %d\n", ret);
+ return ret;
+ }
+
+ ret = da9052_reg_update(rtc->da9052, DA9052_ALARM_Y_REG,
+ DA9052_ALARM_Y_TICK_ON, 0);
+ if (ret != 0)
+ rtc_err(rtc, "Failed to disable TICKS: %d\n", ret);
+
+ ret = da9052_request_irq(rtc->da9052, DA9052_IRQ_ALARM, "ALM",
+ da9052_rtc_irq, rtc);
+ if (ret != 0) {
+ rtc_err(rtc, "irq registration failed: %d\n", ret);
+ return ret;
+ }
+
+ rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &da9052_rtc_ops, THIS_MODULE);
+ return PTR_ERR_OR_ZERO(rtc->rtc);
+}
+
+static struct platform_driver da9052_rtc_driver = {
+ .probe = da9052_rtc_probe,
+ .driver = {
+ .name = "da9052-rtc",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(da9052_rtc_driver);
+
+MODULE_AUTHOR("Anthony Olech <Anthony.Olech@diasemi.com>");
+MODULE_DESCRIPTION("RTC driver for Dialog DA9052 PMIC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9052-rtc");
diff --git a/drivers/rtc/rtc-da9055.c b/drivers/rtc/rtc-da9055.c
new file mode 100644
index 00000000000..a825491331c
--- /dev/null
+++ b/drivers/rtc/rtc-da9055.c
@@ -0,0 +1,404 @@
+/*
+ * Real time clock driver for DA9055
+ *
+ * Copyright(c) 2012 Dialog Semiconductor Ltd.
+ *
+ * Author: Dajun Dajun Chen <dajun.chen@diasemi.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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#include <linux/mfd/da9055/core.h>
+#include <linux/mfd/da9055/reg.h>
+#include <linux/mfd/da9055/pdata.h>
+
+struct da9055_rtc {
+ struct rtc_device *rtc;
+ struct da9055 *da9055;
+ int alarm_enable;
+};
+
+static int da9055_rtc_enable_alarm(struct da9055_rtc *rtc, bool enable)
+{
+ int ret;
+ if (enable) {
+ ret = da9055_reg_update(rtc->da9055, DA9055_REG_ALARM_Y,
+ DA9055_RTC_ALM_EN,
+ DA9055_RTC_ALM_EN);
+ if (ret != 0)
+ dev_err(rtc->da9055->dev, "Failed to enable ALM: %d\n",
+ ret);
+ rtc->alarm_enable = 1;
+ } else {
+ ret = da9055_reg_update(rtc->da9055, DA9055_REG_ALARM_Y,
+ DA9055_RTC_ALM_EN, 0);
+ if (ret != 0)
+ dev_err(rtc->da9055->dev,
+ "Failed to disable ALM: %d\n", ret);
+ rtc->alarm_enable = 0;
+ }
+ return ret;
+}
+
+static irqreturn_t da9055_rtc_alm_irq(int irq, void *data)
+{
+ struct da9055_rtc *rtc = data;
+
+ da9055_rtc_enable_alarm(rtc, 0);
+ rtc_update_irq(rtc->rtc, 1, RTC_IRQF | RTC_AF);
+
+ return IRQ_HANDLED;
+}
+
+static int da9055_read_alarm(struct da9055 *da9055, struct rtc_time *rtc_tm)
+{
+ int ret;
+ uint8_t v[5];
+
+ ret = da9055_group_read(da9055, DA9055_REG_ALARM_MI, 5, v);
+ if (ret != 0) {
+ dev_err(da9055->dev, "Failed to group read ALM: %d\n", ret);
+ return ret;
+ }
+
+ rtc_tm->tm_year = (v[4] & DA9055_RTC_ALM_YEAR) + 100;
+ rtc_tm->tm_mon = (v[3] & DA9055_RTC_ALM_MONTH) - 1;
+ 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;
+
+ return rtc_valid_tm(rtc_tm);
+}
+
+static int da9055_set_alarm(struct da9055 *da9055, struct rtc_time *rtc_tm)
+{
+ int ret;
+ uint8_t v[2];
+
+ rtc_tm->tm_year -= 100;
+ rtc_tm->tm_mon += 1;
+
+ ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MI,
+ DA9055_RTC_ALM_MIN, rtc_tm->tm_min);
+ if (ret != 0) {
+ dev_err(da9055->dev, "Failed to write ALRM MIN: %d\n", ret);
+ return ret;
+ }
+
+ v[0] = rtc_tm->tm_hour;
+ v[1] = rtc_tm->tm_mday;
+
+ ret = da9055_group_write(da9055, DA9055_REG_ALARM_H, 2, v);
+ if (ret < 0)
+ return ret;
+
+ ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MO,
+ DA9055_RTC_ALM_MONTH, rtc_tm->tm_mon);
+ if (ret < 0)
+ dev_err(da9055->dev, "Failed to write ALM Month:%d\n", ret);
+
+ ret = da9055_reg_update(da9055, DA9055_REG_ALARM_Y,
+ DA9055_RTC_ALM_YEAR, rtc_tm->tm_year);
+ if (ret < 0)
+ dev_err(da9055->dev, "Failed to write ALM Year:%d\n", ret);
+
+ return ret;
+}
+
+static int da9055_rtc_get_alarm_status(struct da9055 *da9055)
+{
+ int ret;
+
+ ret = da9055_reg_read(da9055, DA9055_REG_ALARM_Y);
+ if (ret < 0) {
+ dev_err(da9055->dev, "Failed to read ALM: %d\n", ret);
+ return ret;
+ }
+ ret &= DA9055_RTC_ALM_EN;
+ return (ret > 0) ? 1 : 0;
+}
+
+static int da9055_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
+{
+ struct da9055_rtc *rtc = dev_get_drvdata(dev);
+ uint8_t v[6];
+ int ret;
+
+ ret = da9055_reg_read(rtc->da9055, DA9055_REG_COUNT_S);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Registers are only valid when RTC_READ
+ * status bit is asserted
+ */
+ if (!(ret & DA9055_RTC_READ))
+ return -EBUSY;
+
+ ret = da9055_group_read(rtc->da9055, DA9055_REG_COUNT_S, 6, v);
+ if (ret < 0) {
+ dev_err(rtc->da9055->dev, "Failed to read RTC time : %d\n",
+ ret);
+ return ret;
+ }
+
+ rtc_tm->tm_year = (v[5] & DA9055_RTC_YEAR) + 100;
+ rtc_tm->tm_mon = (v[4] & DA9055_RTC_MONTH) - 1;
+ rtc_tm->tm_mday = v[3] & DA9055_RTC_DAY;
+ rtc_tm->tm_hour = v[2] & DA9055_RTC_HOUR;
+ rtc_tm->tm_min = v[1] & DA9055_RTC_MIN;
+ rtc_tm->tm_sec = v[0] & DA9055_RTC_SEC;
+
+ return rtc_valid_tm(rtc_tm);
+}
+
+static int da9055_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct da9055_rtc *rtc;
+ uint8_t v[6];
+
+ rtc = dev_get_drvdata(dev);
+
+ v[0] = tm->tm_sec;
+ v[1] = tm->tm_min;
+ v[2] = tm->tm_hour;
+ v[3] = tm->tm_mday;
+ v[4] = tm->tm_mon + 1;
+ v[5] = tm->tm_year - 100;
+
+ return da9055_group_write(rtc->da9055, DA9055_REG_COUNT_S, 6, v);
+}
+
+static int da9055_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ int ret;
+ struct rtc_time *tm = &alrm->time;
+ struct da9055_rtc *rtc = dev_get_drvdata(dev);
+
+ ret = da9055_read_alarm(rtc->da9055, tm);
+
+ if (ret)
+ return ret;
+
+ alrm->enabled = da9055_rtc_get_alarm_status(rtc->da9055);
+
+ return 0;
+}
+
+static int da9055_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ int ret;
+ struct rtc_time *tm = &alrm->time;
+ struct da9055_rtc *rtc = dev_get_drvdata(dev);
+
+ ret = da9055_rtc_enable_alarm(rtc, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = da9055_set_alarm(rtc->da9055, tm);
+ if (ret)
+ return ret;
+
+ ret = da9055_rtc_enable_alarm(rtc, 1);
+
+ return ret;
+}
+
+static int da9055_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct da9055_rtc *rtc = dev_get_drvdata(dev);
+
+ return da9055_rtc_enable_alarm(rtc, enabled);
+}
+
+static const struct rtc_class_ops da9055_rtc_ops = {
+ .read_time = da9055_rtc_read_time,
+ .set_time = da9055_rtc_set_time,
+ .read_alarm = da9055_rtc_read_alarm,
+ .set_alarm = da9055_rtc_set_alarm,
+ .alarm_irq_enable = da9055_rtc_alarm_irq_enable,
+};
+
+static int da9055_rtc_device_init(struct da9055 *da9055,
+ struct da9055_pdata *pdata)
+{
+ int ret;
+
+ /* Enable RTC and the internal Crystal */
+ ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B,
+ DA9055_RTC_EN, DA9055_RTC_EN);
+ if (ret < 0)
+ return ret;
+ ret = da9055_reg_update(da9055, DA9055_REG_EN_32K,
+ DA9055_CRYSTAL_EN, DA9055_CRYSTAL_EN);
+ if (ret < 0)
+ return ret;
+
+ /* Enable RTC in Power Down mode */
+ ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B,
+ DA9055_RTC_MODE_PD, DA9055_RTC_MODE_PD);
+ if (ret < 0)
+ return ret;
+
+ /* Enable RTC in Reset mode */
+ if (pdata && pdata->reset_enable) {
+ ret = da9055_reg_update(da9055, DA9055_REG_CONTROL_B,
+ DA9055_RTC_MODE_SD,
+ DA9055_RTC_MODE_SD <<
+ DA9055_RTC_MODE_SD_SHIFT);
+ if (ret < 0)
+ return ret;
+ }
+
+ /* Disable the RTC TICK ALM */
+ ret = da9055_reg_update(da9055, DA9055_REG_ALARM_MO,
+ DA9055_RTC_TICK_WAKE_MASK, 0);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int da9055_rtc_probe(struct platform_device *pdev)
+{
+ struct da9055_rtc *rtc;
+ struct da9055_pdata *pdata = NULL;
+ int ret, alm_irq;
+
+ rtc = devm_kzalloc(&pdev->dev, sizeof(struct da9055_rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ rtc->da9055 = dev_get_drvdata(pdev->dev.parent);
+ pdata = dev_get_platdata(rtc->da9055->dev);
+ platform_set_drvdata(pdev, rtc);
+
+ ret = da9055_rtc_device_init(rtc->da9055, pdata);
+ if (ret < 0)
+ goto err_rtc;
+
+ ret = da9055_reg_read(rtc->da9055, DA9055_REG_ALARM_Y);
+ if (ret < 0)
+ goto err_rtc;
+
+ if (ret & DA9055_RTC_ALM_EN)
+ rtc->alarm_enable = 1;
+
+ device_init_wakeup(&pdev->dev, 1);
+
+ rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &da9055_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtc)) {
+ ret = PTR_ERR(rtc->rtc);
+ goto err_rtc;
+ }
+
+ alm_irq = platform_get_irq_byname(pdev, "ALM");
+ if (alm_irq < 0)
+ return alm_irq;
+
+ ret = devm_request_threaded_irq(&pdev->dev, alm_irq, NULL,
+ da9055_rtc_alm_irq,
+ IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ "ALM", rtc);
+ if (ret != 0)
+ dev_err(rtc->da9055->dev, "irq registration failed: %d\n", ret);
+
+err_rtc:
+ return ret;
+
+}
+
+#ifdef CONFIG_PM
+/* Turn off the alarm if it should not be a wake source. */
+static int da9055_rtc_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev);
+ int ret;
+
+ if (!device_may_wakeup(&pdev->dev)) {
+ /* Disable the ALM IRQ */
+ ret = da9055_rtc_enable_alarm(rtc, 0);
+ if (ret < 0)
+ dev_err(&pdev->dev, "Failed to disable RTC ALM\n");
+ }
+
+ return 0;
+}
+
+/* Enable the alarm if it should be enabled (in case it was disabled to
+ * prevent use as a wake source).
+ */
+static int da9055_rtc_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev);
+ int ret;
+
+ if (!device_may_wakeup(&pdev->dev)) {
+ if (rtc->alarm_enable) {
+ ret = da9055_rtc_enable_alarm(rtc, 1);
+ if (ret < 0)
+ dev_err(&pdev->dev,
+ "Failed to restart RTC ALM\n");
+ }
+ }
+
+ return 0;
+}
+
+/* Unconditionally disable the alarm */
+static int da9055_rtc_freeze(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct da9055_rtc *rtc = dev_get_drvdata(&pdev->dev);
+ int ret;
+
+ ret = da9055_rtc_enable_alarm(rtc, 0);
+ if (ret < 0)
+ dev_err(&pdev->dev, "Failed to freeze RTC ALMs\n");
+
+ return 0;
+
+}
+#else
+#define da9055_rtc_suspend NULL
+#define da9055_rtc_resume NULL
+#define da9055_rtc_freeze NULL
+#endif
+
+static const struct dev_pm_ops da9055_rtc_pm_ops = {
+ .suspend = da9055_rtc_suspend,
+ .resume = da9055_rtc_resume,
+
+ .freeze = da9055_rtc_freeze,
+ .thaw = da9055_rtc_resume,
+ .restore = da9055_rtc_resume,
+
+ .poweroff = da9055_rtc_suspend,
+};
+
+static struct platform_driver da9055_rtc_driver = {
+ .probe = da9055_rtc_probe,
+ .driver = {
+ .name = "da9055-rtc",
+ .owner = THIS_MODULE,
+ .pm = &da9055_rtc_pm_ops,
+ },
+};
+
+module_platform_driver(da9055_rtc_driver);
+
+MODULE_AUTHOR("David Dajun Chen <dchen@diasemi.com>");
+MODULE_DESCRIPTION("RTC driver for Dialog DA9055 PMIC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:da9055-rtc");
diff --git a/drivers/rtc/rtc-da9063.c b/drivers/rtc/rtc-da9063.c
new file mode 100644
index 00000000000..595393098b0
--- /dev/null
+++ b/drivers/rtc/rtc-da9063.c
@@ -0,0 +1,333 @@
+/* rtc-da9063.c - Real time clock device driver for DA9063
+ * Copyright (C) 2013-14 Dialog Semiconductor Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/regmap.h>
+#include <linux/mfd/da9063/registers.h>
+#include <linux/mfd/da9063/core.h>
+
+#define YEARS_TO_DA9063(year) ((year) - 100)
+#define MONTHS_TO_DA9063(month) ((month) + 1)
+#define YEARS_FROM_DA9063(year) ((year) + 100)
+#define MONTHS_FROM_DA9063(month) ((month) - 1)
+
+#define RTC_DATA_LEN (DA9063_REG_COUNT_Y - DA9063_REG_COUNT_S + 1)
+#define RTC_SEC 0
+#define RTC_MIN 1
+#define RTC_HOUR 2
+#define RTC_DAY 3
+#define RTC_MONTH 4
+#define RTC_YEAR 5
+
+struct da9063_rtc {
+ struct rtc_device *rtc_dev;
+ struct da9063 *hw;
+ struct rtc_time alarm_time;
+ bool rtc_sync;
+};
+
+static void da9063_data_to_tm(u8 *data, struct rtc_time *tm)
+{
+ tm->tm_sec = data[RTC_SEC] & DA9063_COUNT_SEC_MASK;
+ tm->tm_min = data[RTC_MIN] & DA9063_COUNT_MIN_MASK;
+ tm->tm_hour = data[RTC_HOUR] & DA9063_COUNT_HOUR_MASK;
+ tm->tm_mday = data[RTC_DAY] & DA9063_COUNT_DAY_MASK;
+ tm->tm_mon = MONTHS_FROM_DA9063(data[RTC_MONTH] &
+ DA9063_COUNT_MONTH_MASK);
+ tm->tm_year = YEARS_FROM_DA9063(data[RTC_YEAR] &
+ DA9063_COUNT_YEAR_MASK);
+}
+
+static void da9063_tm_to_data(struct rtc_time *tm, u8 *data)
+{
+ data[RTC_SEC] &= ~DA9063_COUNT_SEC_MASK;
+ data[RTC_SEC] |= tm->tm_sec & DA9063_COUNT_SEC_MASK;
+
+ data[RTC_MIN] &= ~DA9063_COUNT_MIN_MASK;
+ data[RTC_MIN] |= tm->tm_min & DA9063_COUNT_MIN_MASK;
+
+ data[RTC_HOUR] &= ~DA9063_COUNT_HOUR_MASK;
+ data[RTC_HOUR] |= tm->tm_hour & DA9063_COUNT_HOUR_MASK;
+
+ data[RTC_DAY] &= ~DA9063_COUNT_DAY_MASK;
+ data[RTC_DAY] |= tm->tm_mday & DA9063_COUNT_DAY_MASK;
+
+ data[RTC_MONTH] &= ~DA9063_COUNT_MONTH_MASK;
+ data[RTC_MONTH] |= MONTHS_TO_DA9063(tm->tm_mon) &
+ DA9063_COUNT_MONTH_MASK;
+
+ data[RTC_YEAR] &= ~DA9063_COUNT_YEAR_MASK;
+ data[RTC_YEAR] |= YEARS_TO_DA9063(tm->tm_year) &
+ DA9063_COUNT_YEAR_MASK;
+}
+
+static int da9063_rtc_stop_alarm(struct device *dev)
+{
+ struct da9063_rtc *rtc = dev_get_drvdata(dev);
+
+ return regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y,
+ DA9063_ALARM_ON, 0);
+}
+
+static int da9063_rtc_start_alarm(struct device *dev)
+{
+ struct da9063_rtc *rtc = dev_get_drvdata(dev);
+
+ return regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y,
+ DA9063_ALARM_ON, DA9063_ALARM_ON);
+}
+
+static int da9063_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct da9063_rtc *rtc = dev_get_drvdata(dev);
+ unsigned long tm_secs;
+ unsigned long al_secs;
+ u8 data[RTC_DATA_LEN];
+ int ret;
+
+ ret = regmap_bulk_read(rtc->hw->regmap, DA9063_REG_COUNT_S,
+ data, RTC_DATA_LEN);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read RTC time data: %d\n", ret);
+ return ret;
+ }
+
+ if (!(data[RTC_SEC] & DA9063_RTC_READ)) {
+ dev_dbg(dev, "RTC not yet ready to be read by the host\n");
+ return -EINVAL;
+ }
+
+ da9063_data_to_tm(data, tm);
+
+ rtc_tm_to_time(tm, &tm_secs);
+ rtc_tm_to_time(&rtc->alarm_time, &al_secs);
+
+ /* handle the rtc synchronisation delay */
+ if (rtc->rtc_sync == true && al_secs - tm_secs == 1)
+ memcpy(tm, &rtc->alarm_time, sizeof(struct rtc_time));
+ else
+ rtc->rtc_sync = false;
+
+ return rtc_valid_tm(tm);
+}
+
+static int da9063_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct da9063_rtc *rtc = dev_get_drvdata(dev);
+ u8 data[RTC_DATA_LEN];
+ int ret;
+
+ da9063_tm_to_data(tm, data);
+ ret = regmap_bulk_write(rtc->hw->regmap, DA9063_REG_COUNT_S,
+ data, RTC_DATA_LEN);
+ if (ret < 0)
+ dev_err(dev, "Failed to set RTC time data: %d\n", ret);
+
+ return ret;
+}
+
+static int da9063_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct da9063_rtc *rtc = dev_get_drvdata(dev);
+ u8 data[RTC_DATA_LEN];
+ int ret;
+ unsigned int val;
+
+ ret = regmap_bulk_read(rtc->hw->regmap, DA9063_REG_ALARM_S,
+ &data[RTC_SEC], RTC_DATA_LEN);
+ if (ret < 0)
+ return ret;
+
+ da9063_data_to_tm(data, &alrm->time);
+
+ alrm->enabled = !!(data[RTC_YEAR] & DA9063_ALARM_ON);
+
+ ret = regmap_read(rtc->hw->regmap, DA9063_REG_EVENT_A, &val);
+ if (ret < 0)
+ return ret;
+
+ if (val & (DA9063_E_ALARM))
+ alrm->pending = 1;
+ else
+ alrm->pending = 0;
+
+ return 0;
+}
+
+static int da9063_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct da9063_rtc *rtc = dev_get_drvdata(dev);
+ u8 data[RTC_DATA_LEN];
+ int ret;
+
+ da9063_tm_to_data(&alrm->time, data);
+
+ ret = da9063_rtc_stop_alarm(dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to stop alarm: %d\n", ret);
+ return ret;
+ }
+
+ ret = regmap_bulk_write(rtc->hw->regmap, DA9063_REG_ALARM_S,
+ data, RTC_DATA_LEN);
+ if (ret < 0) {
+ dev_err(dev, "Failed to write alarm: %d\n", ret);
+ return ret;
+ }
+
+ rtc->alarm_time = alrm->time;
+
+ if (alrm->enabled) {
+ ret = da9063_rtc_start_alarm(dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to start alarm: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+static int da9063_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ if (enabled)
+ return da9063_rtc_start_alarm(dev);
+ else
+ return da9063_rtc_stop_alarm(dev);
+}
+
+static irqreturn_t da9063_alarm_event(int irq, void *data)
+{
+ struct da9063_rtc *rtc = data;
+
+ regmap_update_bits(rtc->hw->regmap, DA9063_REG_ALARM_Y,
+ DA9063_ALARM_ON, 0);
+
+ rtc->rtc_sync = true;
+ rtc_update_irq(rtc->rtc_dev, 1, RTC_IRQF | RTC_AF);
+
+ return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops da9063_rtc_ops = {
+ .read_time = da9063_rtc_read_time,
+ .set_time = da9063_rtc_set_time,
+ .read_alarm = da9063_rtc_read_alarm,
+ .set_alarm = da9063_rtc_set_alarm,
+ .alarm_irq_enable = da9063_rtc_alarm_irq_enable,
+};
+
+static int da9063_rtc_probe(struct platform_device *pdev)
+{
+ struct da9063 *da9063 = dev_get_drvdata(pdev->dev.parent);
+ struct da9063_rtc *rtc;
+ int irq_alarm;
+ u8 data[RTC_DATA_LEN];
+ int ret;
+
+ ret = regmap_update_bits(da9063->regmap, DA9063_REG_CONTROL_E,
+ DA9063_RTC_EN, DA9063_RTC_EN);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to enable RTC\n");
+ goto err;
+ }
+
+ ret = regmap_update_bits(da9063->regmap, DA9063_REG_EN_32K,
+ DA9063_CRYSTAL, DA9063_CRYSTAL);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to run 32kHz oscillator\n");
+ goto err;
+ }
+
+ ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_S,
+ DA9063_ALARM_STATUS_TICK | DA9063_ALARM_STATUS_ALARM,
+ 0);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to access RTC alarm register\n");
+ goto err;
+ }
+
+ ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_S,
+ DA9063_ALARM_STATUS_ALARM,
+ DA9063_ALARM_STATUS_ALARM);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to access RTC alarm register\n");
+ goto err;
+ }
+
+ ret = regmap_update_bits(da9063->regmap, DA9063_REG_ALARM_Y,
+ DA9063_TICK_ON, 0);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to disable TICKs\n");
+ goto err;
+ }
+
+ ret = regmap_bulk_read(da9063->regmap, DA9063_REG_ALARM_S,
+ data, RTC_DATA_LEN);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to read initial alarm data: %d\n",
+ ret);
+ goto err;
+ }
+
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, rtc);
+
+ irq_alarm = platform_get_irq_byname(pdev, "ALARM");
+ ret = devm_request_threaded_irq(&pdev->dev, irq_alarm, NULL,
+ da9063_alarm_event,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "ALARM", rtc);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request ALARM IRQ %d: %d\n",
+ irq_alarm, ret);
+ goto err;
+ }
+
+ rtc->hw = da9063;
+ rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, DA9063_DRVNAME_RTC,
+ &da9063_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtc_dev))
+ return PTR_ERR(rtc->rtc_dev);
+
+ da9063_data_to_tm(data, &rtc->alarm_time);
+ rtc->rtc_sync = false;
+err:
+ return ret;
+}
+
+static struct platform_driver da9063_rtc_driver = {
+ .probe = da9063_rtc_probe,
+ .driver = {
+ .name = DA9063_DRVNAME_RTC,
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(da9063_rtc_driver);
+
+MODULE_AUTHOR("S Twiss <stwiss.opensource@diasemi.com>");
+MODULE_DESCRIPTION("Real time clock device driver for Dialog DA9063");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DA9063_DRVNAME_RTC);
diff --git a/drivers/rtc/rtc-davinci.c b/drivers/rtc/rtc-davinci.c
index 755e1fe914a..c0a3b59f65a 100644
--- a/drivers/rtc/rtc-davinci.c
+++ b/drivers/rtc/rtc-davinci.c
@@ -117,10 +117,8 @@
static DEFINE_SPINLOCK(davinci_rtc_lock);
struct davinci_rtc {
- struct rtc_device *rtc;
+ struct rtc_device *rtc;
void __iomem *base;
- resource_size_t pbase;
- size_t base_size;
int irq;
};
@@ -482,56 +480,32 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct davinci_rtc *davinci_rtc;
- struct resource *res, *mem;
+ struct resource *res;
int ret = 0;
- davinci_rtc = kzalloc(sizeof(struct davinci_rtc), GFP_KERNEL);
- if (!davinci_rtc) {
- dev_dbg(dev, "could not allocate memory for private data\n");
+ davinci_rtc = devm_kzalloc(&pdev->dev, sizeof(struct davinci_rtc), GFP_KERNEL);
+ if (!davinci_rtc)
return -ENOMEM;
- }
davinci_rtc->irq = platform_get_irq(pdev, 0);
if (davinci_rtc->irq < 0) {
dev_err(dev, "no RTC irq\n");
- ret = davinci_rtc->irq;
- goto fail1;
+ return davinci_rtc->irq;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(dev, "no mem resource\n");
- ret = -EINVAL;
- goto fail1;
- }
-
- davinci_rtc->pbase = res->start;
- davinci_rtc->base_size = resource_size(res);
-
- mem = request_mem_region(davinci_rtc->pbase, davinci_rtc->base_size,
- pdev->name);
- if (!mem) {
- dev_err(dev, "RTC registers at %08x are not free\n",
- davinci_rtc->pbase);
- ret = -EBUSY;
- goto fail1;
- }
-
- davinci_rtc->base = ioremap(davinci_rtc->pbase, davinci_rtc->base_size);
- if (!davinci_rtc->base) {
- dev_err(dev, "unable to ioremap MEM resource\n");
- ret = -ENOMEM;
- goto fail2;
- }
+ davinci_rtc->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(davinci_rtc->base))
+ return PTR_ERR(davinci_rtc->base);
platform_set_drvdata(pdev, davinci_rtc);
- davinci_rtc->rtc = rtc_device_register(pdev->name, &pdev->dev,
+ davinci_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&davinci_rtc_ops, THIS_MODULE);
if (IS_ERR(davinci_rtc->rtc)) {
- dev_err(dev, "unable to register RTC device, err %ld\n",
- PTR_ERR(davinci_rtc->rtc));
- goto fail3;
+ dev_err(dev, "unable to register RTC device, err %d\n",
+ ret);
+ return PTR_ERR(davinci_rtc->rtc);
}
rtcif_write(davinci_rtc, PRTCIF_INTFLG_RTCSS, PRTCIF_INTFLG);
@@ -541,11 +515,11 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CTRL);
rtcss_write(davinci_rtc, 0, PRTCSS_RTC_CCTRL);
- ret = request_irq(davinci_rtc->irq, davinci_rtc_interrupt,
- IRQF_DISABLED, "davinci_rtc", davinci_rtc);
+ ret = devm_request_irq(dev, davinci_rtc->irq, davinci_rtc_interrupt,
+ 0, "davinci_rtc", davinci_rtc);
if (ret < 0) {
dev_err(dev, "unable to register davinci RTC interrupt\n");
- goto fail4;
+ return ret;
}
/* Enable interrupts */
@@ -558,21 +532,9 @@ static int __init davinci_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 0);
return 0;
-
-fail4:
- rtc_device_unregister(davinci_rtc->rtc);
-fail3:
- platform_set_drvdata(pdev, NULL);
- iounmap(davinci_rtc->base);
-fail2:
- release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size);
-fail1:
- kfree(davinci_rtc);
-
- return ret;
}
-static int __devexit davinci_rtc_remove(struct platform_device *pdev)
+static int __exit davinci_rtc_remove(struct platform_device *pdev)
{
struct davinci_rtc *davinci_rtc = platform_get_drvdata(pdev);
@@ -580,40 +542,19 @@ static int __devexit davinci_rtc_remove(struct platform_device *pdev)
rtcif_write(davinci_rtc, 0, PRTCIF_INTEN);
- free_irq(davinci_rtc->irq, davinci_rtc);
-
- rtc_device_unregister(davinci_rtc->rtc);
-
- iounmap(davinci_rtc->base);
- release_mem_region(davinci_rtc->pbase, davinci_rtc->base_size);
-
- platform_set_drvdata(pdev, NULL);
-
- kfree(davinci_rtc);
-
return 0;
}
static struct platform_driver davinci_rtc_driver = {
.probe = davinci_rtc_probe,
- .remove = __devexit_p(davinci_rtc_remove),
+ .remove = __exit_p(davinci_rtc_remove),
.driver = {
.name = "rtc_davinci",
.owner = THIS_MODULE,
},
};
-static int __init rtc_init(void)
-{
- return platform_driver_probe(&davinci_rtc_driver, davinci_rtc_probe);
-}
-module_init(rtc_init);
-
-static void __exit rtc_exit(void)
-{
- platform_driver_unregister(&davinci_rtc_driver);
-}
-module_exit(rtc_exit);
+module_platform_driver_probe(davinci_rtc_driver, davinci_rtc_probe);
MODULE_AUTHOR("Miguel Aguilar <miguel.aguilar@ridgerun.com>");
MODULE_DESCRIPTION("Texas Instruments DaVinci PRTC Driver");
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index cace6d3aed9..d0493936925 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -11,6 +11,8 @@
* published by the Free Software Foundation.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/rtc.h>
#include <linux/sched.h>
@@ -379,25 +381,6 @@ static long rtc_dev_ioctl(struct file *file,
err = put_user(rtc->irq_freq, (unsigned long __user *)uarg);
break;
-#if 0
- case RTC_EPOCH_SET:
-#ifndef rtc_epoch
- /*
- * There were no RTC clocks before 1900.
- */
- if (arg < 1900) {
- err = -EINVAL;
- break;
- }
- rtc_epoch = arg;
- err = 0;
-#endif
- break;
-
- case RTC_EPOCH_READ:
- err = put_user(rtc_epoch, (unsigned long __user *)uarg);
- break;
-#endif
case RTC_WKALM_SET:
mutex_unlock(&rtc->ops_lock);
if (copy_from_user(&alarm, uarg, sizeof(alarm)))
@@ -481,7 +464,7 @@ void rtc_dev_prepare(struct rtc_device *rtc)
return;
if (rtc->id >= RTC_DEV_MAX) {
- pr_debug("%s: too many RTC devices\n", rtc->name);
+ dev_dbg(&rtc->dev, "%s: too many RTC devices\n", rtc->name);
return;
}
@@ -499,10 +482,10 @@ void rtc_dev_prepare(struct rtc_device *rtc)
void rtc_dev_add_device(struct rtc_device *rtc)
{
if (cdev_add(&rtc->char_dev, rtc->dev.devt, 1))
- printk(KERN_WARNING "%s: failed to add char device %d:%d\n",
+ dev_warn(&rtc->dev, "%s: failed to add char device %d:%d\n",
rtc->name, MAJOR(rtc_devt), rtc->id);
else
- pr_debug("%s: dev (%d:%d)\n", rtc->name,
+ dev_dbg(&rtc->dev, "%s: dev (%d:%d)\n", rtc->name,
MAJOR(rtc_devt), rtc->id);
}
@@ -518,8 +501,7 @@ void __init rtc_dev_init(void)
err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");
if (err < 0)
- printk(KERN_ERR "%s: failed to allocate char dev region\n",
- __FILE__);
+ pr_err("failed to allocate char dev region\n");
}
void __exit rtc_dev_exit(void)
diff --git a/drivers/rtc/rtc-dm355evm.c b/drivers/rtc/rtc-dm355evm.c
index d4457afcba8..1aca08394c4 100644
--- a/drivers/rtc/rtc-dm355evm.c
+++ b/drivers/rtc/rtc-dm355evm.c
@@ -123,12 +123,12 @@ static struct rtc_class_ops dm355evm_rtc_ops = {
/*----------------------------------------------------------------------*/
-static int __devinit dm355evm_rtc_probe(struct platform_device *pdev)
+static int dm355evm_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
- rtc = rtc_device_register(pdev->name,
- &pdev->dev, &dm355evm_rtc_ops, THIS_MODULE);
+ rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &dm355evm_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc)) {
dev_err(&pdev->dev, "can't register RTC device, err %ld\n",
PTR_ERR(rtc));
@@ -139,22 +139,12 @@ static int __devinit dm355evm_rtc_probe(struct platform_device *pdev)
return 0;
}
-static int __devexit dm355evm_rtc_remove(struct platform_device *pdev)
-{
- struct rtc_device *rtc = platform_get_drvdata(pdev);
-
- rtc_device_unregister(rtc);
- platform_set_drvdata(pdev, NULL);
- return 0;
-}
-
/*
* I2C is used to talk to the MSP430, but this platform device is
* exposed by an MFD driver that manages I2C communications.
*/
static struct platform_driver rtc_dm355evm_driver = {
.probe = dm355evm_rtc_probe,
- .remove = __devexit_p(dm355evm_rtc_remove),
.driver = {
.owner = THIS_MODULE,
.name = "rtc-dm355evm",
diff --git a/drivers/rtc/rtc-ds1216.c b/drivers/rtc/rtc-ds1216.c
index 45cd8c9f5a3..9c04fd2bc20 100644
--- a/drivers/rtc/rtc-ds1216.c
+++ b/drivers/rtc/rtc-ds1216.c
@@ -30,8 +30,6 @@ struct ds1216_regs {
struct ds1216_priv {
struct rtc_device *rtc;
void __iomem *ioaddr;
- size_t size;
- unsigned long baseaddr;
};
static const u8 magic[] = {
@@ -144,58 +142,29 @@ static int __init ds1216_rtc_probe(struct platform_device *pdev)
{
struct resource *res;
struct ds1216_priv *priv;
- int ret = 0;
u8 dummy[8];
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
- priv = kzalloc(sizeof *priv, GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
platform_set_drvdata(pdev, priv);
- priv->size = resource_size(res);
- if (!request_mem_region(res->start, priv->size, pdev->name)) {
- ret = -EBUSY;
- goto out;
- }
- priv->baseaddr = res->start;
- priv->ioaddr = ioremap(priv->baseaddr, priv->size);
- if (!priv->ioaddr) {
- ret = -ENOMEM;
- goto out;
- }
- priv->rtc = rtc_device_register("ds1216", &pdev->dev,
- &ds1216_rtc_ops, THIS_MODULE);
- if (IS_ERR(priv->rtc)) {
- ret = PTR_ERR(priv->rtc);
- goto out;
- }
+ priv->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->ioaddr))
+ return PTR_ERR(priv->ioaddr);
+
+ priv->rtc = devm_rtc_device_register(&pdev->dev, "ds1216",
+ &ds1216_rtc_ops, THIS_MODULE);
+ if (IS_ERR(priv->rtc))
+ return PTR_ERR(priv->rtc);
/* dummy read to get clock into a known state */
ds1216_read(priv->ioaddr, dummy);
return 0;
-
-out:
- if (priv->ioaddr)
- iounmap(priv->ioaddr);
- if (priv->baseaddr)
- release_mem_region(priv->baseaddr, priv->size);
- kfree(priv);
- return ret;
-}
-
-static int __exit ds1216_rtc_remove(struct platform_device *pdev)
-{
- struct ds1216_priv *priv = platform_get_drvdata(pdev);
-
- rtc_device_unregister(priv->rtc);
- iounmap(priv->ioaddr);
- release_mem_region(priv->baseaddr, priv->size);
- kfree(priv);
- return 0;
}
static struct platform_driver ds1216_rtc_platform_driver = {
@@ -203,24 +172,12 @@ static struct platform_driver ds1216_rtc_platform_driver = {
.name = "rtc-ds1216",
.owner = THIS_MODULE,
},
- .remove = __exit_p(ds1216_rtc_remove),
};
-static int __init ds1216_rtc_init(void)
-{
- return platform_driver_probe(&ds1216_rtc_platform_driver, ds1216_rtc_probe);
-}
-
-static void __exit ds1216_rtc_exit(void)
-{
- platform_driver_unregister(&ds1216_rtc_platform_driver);
-}
+module_platform_driver_probe(ds1216_rtc_platform_driver, ds1216_rtc_probe);
MODULE_AUTHOR("Thomas Bogendoerfer <tsbogend@alpha.franken.de>");
MODULE_DESCRIPTION("DS1216 RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
MODULE_ALIAS("platform:rtc-ds1216");
-
-module_init(ds1216_rtc_init);
-module_exit(ds1216_rtc_exit);
diff --git a/drivers/rtc/rtc-ds1286.c b/drivers/rtc/rtc-ds1286.c
index 990c3ff489b..50e109b7825 100644
--- a/drivers/rtc/rtc-ds1286.c
+++ b/drivers/rtc/rtc-ds1286.c
@@ -25,8 +25,6 @@
struct ds1286_priv {
struct rtc_device *rtc;
u32 __iomem *rtcregs;
- size_t size;
- unsigned long baseaddr;
spinlock_t lock;
};
@@ -270,7 +268,6 @@ static int ds1286_set_time(struct device *dev, struct rtc_time *tm)
static int ds1286_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
struct ds1286_priv *priv = dev_get_drvdata(dev);
- unsigned char cmd;
unsigned long flags;
/*
@@ -281,7 +278,7 @@ static int ds1286_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
alm->time.tm_min = ds1286_rtc_read(priv, RTC_MINUTES_ALARM) & 0x7f;
alm->time.tm_hour = ds1286_rtc_read(priv, RTC_HOURS_ALARM) & 0x1f;
alm->time.tm_wday = ds1286_rtc_read(priv, RTC_DAY_ALARM) & 0x07;
- cmd = ds1286_rtc_read(priv, RTC_CMD);
+ ds1286_rtc_read(priv, RTC_CMD);
spin_unlock_irqrestore(&priv->lock, flags);
alm->time.tm_min = bcd2bin(alm->time.tm_min);
@@ -329,62 +326,31 @@ static const struct rtc_class_ops ds1286_ops = {
.alarm_irq_enable = ds1286_alarm_irq_enable,
};
-static int __devinit ds1286_probe(struct platform_device *pdev)
+static int ds1286_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
struct resource *res;
struct ds1286_priv *priv;
- int ret = 0;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
return -ENODEV;
- priv = kzalloc(sizeof(struct ds1286_priv), GFP_KERNEL);
+ priv = devm_kzalloc(&pdev->dev, sizeof(struct ds1286_priv), GFP_KERNEL);
if (!priv)
return -ENOMEM;
- priv->size = resource_size(res);
- if (!request_mem_region(res->start, priv->size, pdev->name)) {
- ret = -EBUSY;
- goto out;
- }
- priv->baseaddr = res->start;
- priv->rtcregs = ioremap(priv->baseaddr, priv->size);
- if (!priv->rtcregs) {
- ret = -ENOMEM;
- goto out;
- }
+ priv->rtcregs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(priv->rtcregs))
+ return PTR_ERR(priv->rtcregs);
+
spin_lock_init(&priv->lock);
platform_set_drvdata(pdev, priv);
- rtc = rtc_device_register("ds1286", &pdev->dev,
- &ds1286_ops, THIS_MODULE);
- if (IS_ERR(rtc)) {
- ret = PTR_ERR(rtc);
- goto out;
- }
+ rtc = devm_rtc_device_register(&pdev->dev, "ds1286", &ds1286_ops,
+ THIS_MODULE);
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
priv->rtc = rtc;
return 0;
-
-out:
- if (priv->rtc)
- rtc_device_unregister(priv->rtc);
- if (priv->rtcregs)
- iounmap(priv->rtcregs);
- if (priv->baseaddr)
- release_mem_region(priv->baseaddr, priv->size);
- kfree(priv);
- return ret;
-}
-
-static int __devexit ds1286_remove(struct platform_device *pdev)
-{
- struct ds1286_priv *priv = platform_get_drvdata(pdev);
-
- rtc_device_unregister(priv->rtc);
- iounmap(priv->rtcregs);
- release_mem_region(priv->baseaddr, priv->size);
- kfree(priv);
- return 0;
}
static struct platform_driver ds1286_platform_driver = {
@@ -393,7 +359,6 @@ static struct platform_driver ds1286_platform_driver = {
.owner = THIS_MODULE,
},
.probe = ds1286_probe,
- .remove = __devexit_p(ds1286_remove),
};
module_platform_driver(ds1286_platform_driver);
diff --git a/drivers/rtc/rtc-ds1302.c b/drivers/rtc/rtc-ds1302.c
index f0d63892264..07e8d79b4a0 100644
--- a/drivers/rtc/rtc-ds1302.c
+++ b/drivers/rtc/rtc-ds1302.c
@@ -23,8 +23,12 @@
#define RTC_CMD_READ 0x81 /* Read command */
#define RTC_CMD_WRITE 0x80 /* Write command */
+#define RTC_CMD_WRITE_ENABLE 0x00 /* Write enable */
+#define RTC_CMD_WRITE_DISABLE 0x80 /* Write disable */
+
#define RTC_ADDR_RAM0 0x20 /* Address of RAM0 */
#define RTC_ADDR_TCR 0x08 /* Address of trickle charge register */
+#define RTC_ADDR_CTRL 0x07 /* Address of control register */
#define RTC_ADDR_YEAR 0x06 /* Address of year register */
#define RTC_ADDR_DAY 0x05 /* Address of day of week register */
#define RTC_ADDR_MON 0x04 /* Address of month register */
@@ -161,6 +165,7 @@ static int ds1302_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
+ ds1302_writebyte(RTC_ADDR_CTRL, RTC_CMD_WRITE_ENABLE);
/* Stop RTC */
ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) | 0x80);
@@ -175,6 +180,8 @@ static int ds1302_rtc_set_time(struct device *dev, struct rtc_time *tm)
/* Start RTC */
ds1302_writebyte(RTC_ADDR_SEC, ds1302_readbyte(RTC_ADDR_SEC) & ~0x80);
+ ds1302_writebyte(RTC_ADDR_CTRL, RTC_CMD_WRITE_DISABLE);
+
return 0;
}
@@ -224,7 +231,7 @@ static int __init ds1302_rtc_probe(struct platform_device *pdev)
return -ENODEV;
}
- rtc = rtc_device_register("ds1302", &pdev->dev,
+ rtc = devm_rtc_device_register(&pdev->dev, "ds1302",
&ds1302_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -234,36 +241,14 @@ static int __init ds1302_rtc_probe(struct platform_device *pdev)
return 0;
}
-static int __devexit ds1302_rtc_remove(struct platform_device *pdev)
-{
- struct rtc_device *rtc = platform_get_drvdata(pdev);
-
- rtc_device_unregister(rtc);
- platform_set_drvdata(pdev, NULL);
-
- return 0;
-}
-
static struct platform_driver ds1302_platform_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
- .remove = __devexit_p(ds1302_rtc_remove),
};
-static int __init ds1302_rtc_init(void)
-{
- return platform_driver_probe(&ds1302_platform_driver, ds1302_rtc_probe);
-}
-
-static void __exit ds1302_rtc_exit(void)
-{
- platform_driver_unregister(&ds1302_platform_driver);
-}
-
-module_init(ds1302_rtc_init);
-module_exit(ds1302_rtc_exit);
+module_platform_driver_probe(ds1302_platform_driver, ds1302_rtc_probe);
MODULE_DESCRIPTION("Dallas DS1302 RTC driver");
MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/rtc/rtc-ds1305.c b/drivers/rtc/rtc-ds1305.c
index 3a33b1fdbe0..129add77065 100644
--- a/drivers/rtc/rtc-ds1305.c
+++ b/drivers/rtc/rtc-ds1305.c
@@ -158,7 +158,7 @@ static int ds1305_alarm_irq_enable(struct device *dev, unsigned int enabled)
goto done;
buf[1] &= ~DS1305_AEI0;
}
- err = spi_write_then_read(ds1305->spi, buf, sizeof buf, NULL, 0);
+ err = spi_write_then_read(ds1305->spi, buf, sizeof(buf), NULL, 0);
if (err >= 0)
ds1305->ctrl[0] = buf[1];
done:
@@ -181,8 +181,8 @@ static int ds1305_get_time(struct device *dev, struct rtc_time *time)
/* Use write-then-read to get all the date/time registers
* since dma from stack is nonportable
*/
- status = spi_write_then_read(ds1305->spi, &addr, sizeof addr,
- buf, sizeof buf);
+ status = spi_write_then_read(ds1305->spi, &addr, sizeof(addr),
+ buf, sizeof(buf));
if (status < 0)
return status;
@@ -237,7 +237,7 @@ static int ds1305_set_time(struct device *dev, struct rtc_time *time)
buf[4], buf[5], buf[6], buf[7]);
/* use write-then-read since dma from stack is nonportable */
- return spi_write_then_read(ds1305->spi, buf, sizeof buf,
+ return spi_write_then_read(ds1305->spi, buf, sizeof(buf),
NULL, 0);
}
@@ -286,8 +286,8 @@ static int ds1305_get_alarm(struct device *dev, struct rtc_wkalrm *alm)
* of EFI status is at best fragile anyway (given IRQ handlers).
*/
addr = DS1305_CONTROL;
- status = spi_write_then_read(spi, &addr, sizeof addr,
- ds1305->ctrl, sizeof ds1305->ctrl);
+ status = spi_write_then_read(spi, &addr, sizeof(addr),
+ ds1305->ctrl, sizeof(ds1305->ctrl));
if (status < 0)
return status;
@@ -296,8 +296,8 @@ static int ds1305_get_alarm(struct device *dev, struct rtc_wkalrm *alm)
/* get and check ALM0 registers */
addr = DS1305_ALM0(DS1305_SEC);
- status = spi_write_then_read(spi, &addr, sizeof addr,
- buf, sizeof buf);
+ status = spi_write_then_read(spi, &addr, sizeof(addr),
+ buf, sizeof(buf));
if (status < 0)
return status;
@@ -381,7 +381,7 @@ static int ds1305_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
"alm0 write", buf[1 + DS1305_SEC], buf[1 + DS1305_MIN],
buf[1 + DS1305_HOUR], buf[1 + DS1305_WDAY]);
- status = spi_write_then_read(spi, buf, sizeof buf, NULL, 0);
+ status = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
if (status < 0)
return status;
@@ -474,7 +474,7 @@ static void ds1305_work(struct work_struct *work)
buf[1] = ds1305->ctrl[0];
buf[2] = 0;
- status = spi_write_then_read(spi, buf, sizeof buf,
+ status = spi_write_then_read(spi, buf, sizeof(buf),
NULL, 0);
if (status < 0)
dev_dbg(&spi->dev, "clear irq --> %d\n", status);
@@ -601,12 +601,12 @@ static struct bin_attribute nvram = {
* Interface to SPI stack
*/
-static int __devinit ds1305_probe(struct spi_device *spi)
+static int ds1305_probe(struct spi_device *spi)
{
struct ds1305 *ds1305;
int status;
u8 addr, value;
- struct ds1305_platform_data *pdata = spi->dev.platform_data;
+ struct ds1305_platform_data *pdata = dev_get_platdata(&spi->dev);
bool write_ctrl = false;
/* Sanity check board setup data. This may be hooked up
@@ -619,7 +619,7 @@ static int __devinit ds1305_probe(struct spi_device *spi)
return -EINVAL;
/* set up driver data */
- ds1305 = kzalloc(sizeof *ds1305, GFP_KERNEL);
+ ds1305 = devm_kzalloc(&spi->dev, sizeof(*ds1305), GFP_KERNEL);
if (!ds1305)
return -ENOMEM;
ds1305->spi = spi;
@@ -627,17 +627,15 @@ static int __devinit ds1305_probe(struct spi_device *spi)
/* read and cache control registers */
addr = DS1305_CONTROL;
- status = spi_write_then_read(spi, &addr, sizeof addr,
- ds1305->ctrl, sizeof ds1305->ctrl);
+ status = spi_write_then_read(spi, &addr, sizeof(addr),
+ ds1305->ctrl, sizeof(ds1305->ctrl));
if (status < 0) {
dev_dbg(&spi->dev, "can't %s, %d\n",
"read", status);
- goto fail0;
+ return status;
}
- dev_dbg(&spi->dev, "ctrl %s: %02x %02x %02x\n",
- "read", ds1305->ctrl[0],
- ds1305->ctrl[1], ds1305->ctrl[2]);
+ dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "read", ds1305->ctrl);
/* Sanity check register values ... partially compensating for the
* fact that SPI has no device handshake. A pullup on MISO would
@@ -646,8 +644,7 @@ static int __devinit ds1305_probe(struct spi_device *spi)
*/
if ((ds1305->ctrl[0] & 0x38) != 0 || (ds1305->ctrl[1] & 0xfc) != 0) {
dev_dbg(&spi->dev, "RTC chip is not present\n");
- status = -ENODEV;
- goto fail0;
+ return -ENODEV;
}
if (ds1305->ctrl[2] == 0)
dev_dbg(&spi->dev, "chip may not be present\n");
@@ -662,11 +659,11 @@ static int __devinit ds1305_probe(struct spi_device *spi)
buf[0] = DS1305_WRITE | DS1305_CONTROL;
buf[1] = ds1305->ctrl[0];
- status = spi_write_then_read(spi, buf, sizeof buf, NULL, 0);
+ status = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
dev_dbg(&spi->dev, "clear WP --> %d\n", status);
if (status < 0)
- goto fail0;
+ return status;
}
/* on DS1305, maybe start oscillator; like most low power
@@ -716,25 +713,23 @@ static int __devinit ds1305_probe(struct spi_device *spi)
buf[1] = ds1305->ctrl[0];
buf[2] = ds1305->ctrl[1];
buf[3] = ds1305->ctrl[2];
- status = spi_write_then_read(spi, buf, sizeof buf, NULL, 0);
+ status = spi_write_then_read(spi, buf, sizeof(buf), NULL, 0);
if (status < 0) {
dev_dbg(&spi->dev, "can't %s, %d\n",
"write", status);
- goto fail0;
+ return status;
}
- dev_dbg(&spi->dev, "ctrl %s: %02x %02x %02x\n",
- "write", ds1305->ctrl[0],
- ds1305->ctrl[1], ds1305->ctrl[2]);
+ dev_dbg(&spi->dev, "ctrl %s: %3ph\n", "write", ds1305->ctrl);
}
/* see if non-Linux software set up AM/PM mode */
addr = DS1305_HOUR;
- status = spi_write_then_read(spi, &addr, sizeof addr,
- &value, sizeof value);
+ status = spi_write_then_read(spi, &addr, sizeof(addr),
+ &value, sizeof(value));
if (status < 0) {
dev_dbg(&spi->dev, "read HOUR --> %d\n", status);
- goto fail0;
+ return status;
}
ds1305->hr12 = (DS1305_HR_12 & value) != 0;
@@ -742,12 +737,12 @@ static int __devinit ds1305_probe(struct spi_device *spi)
dev_dbg(&spi->dev, "AM/PM\n");
/* register RTC ... from here on, ds1305->ctrl needs locking */
- ds1305->rtc = rtc_device_register("ds1305", &spi->dev,
+ ds1305->rtc = devm_rtc_device_register(&spi->dev, "ds1305",
&ds1305_ops, THIS_MODULE);
if (IS_ERR(ds1305->rtc)) {
status = PTR_ERR(ds1305->rtc);
dev_dbg(&spi->dev, "register rtc --> %d\n", status);
- goto fail0;
+ return status;
}
/* Maybe set up alarm IRQ; be ready to handle it triggering right
@@ -758,36 +753,26 @@ static int __devinit ds1305_probe(struct spi_device *spi)
*/
if (spi->irq) {
INIT_WORK(&ds1305->work, ds1305_work);
- status = request_irq(spi->irq, ds1305_irq,
+ status = devm_request_irq(&spi->dev, spi->irq, ds1305_irq,
0, dev_name(&ds1305->rtc->dev), ds1305);
if (status < 0) {
- dev_dbg(&spi->dev, "request_irq %d --> %d\n",
+ dev_err(&spi->dev, "request_irq %d --> %d\n",
spi->irq, status);
- goto fail1;
+ } else {
+ device_set_wakeup_capable(&spi->dev, 1);
}
-
- device_set_wakeup_capable(&spi->dev, 1);
}
/* export NVRAM */
status = sysfs_create_bin_file(&spi->dev.kobj, &nvram);
if (status < 0) {
- dev_dbg(&spi->dev, "register nvram --> %d\n", status);
- goto fail2;
+ dev_err(&spi->dev, "register nvram --> %d\n", status);
}
return 0;
-
-fail2:
- free_irq(spi->irq, ds1305);
-fail1:
- rtc_device_unregister(ds1305->rtc);
-fail0:
- kfree(ds1305);
- return status;
}
-static int __devexit ds1305_remove(struct spi_device *spi)
+static int ds1305_remove(struct spi_device *spi)
{
struct ds1305 *ds1305 = spi_get_drvdata(spi);
@@ -796,13 +781,10 @@ static int __devexit ds1305_remove(struct spi_device *spi)
/* carefully shut down irq and workqueue, if present */
if (spi->irq) {
set_bit(FLAG_EXITING, &ds1305->flags);
- free_irq(spi->irq, ds1305);
+ devm_free_irq(&spi->dev, spi->irq, ds1305);
cancel_work_sync(&ds1305->work);
}
- rtc_device_unregister(ds1305->rtc);
- spi_set_drvdata(spi, NULL);
- kfree(ds1305);
return 0;
}
@@ -810,21 +792,11 @@ static struct spi_driver ds1305_driver = {
.driver.name = "rtc-ds1305",
.driver.owner = THIS_MODULE,
.probe = ds1305_probe,
- .remove = __devexit_p(ds1305_remove),
+ .remove = ds1305_remove,
/* REVISIT add suspend/resume */
};
-static int __init ds1305_init(void)
-{
- return spi_register_driver(&ds1305_driver);
-}
-module_init(ds1305_init);
-
-static void __exit ds1305_exit(void)
-{
- spi_unregister_driver(&ds1305_driver);
-}
-module_exit(ds1305_exit);
+module_spi_driver(ds1305_driver);
MODULE_DESCRIPTION("RTC driver for DS1305 and DS1306 chips");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index 62b0763b7b9..f03d5ba96db 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -4,6 +4,7 @@
* Copyright (C) 2005 James Chapman (ds1337 core)
* Copyright (C) 2006 David Brownell
* Copyright (C) 2009 Matthias Fuchs (rx8025 support)
+ * Copyright (C) 2012 Bertrand Achard (nvram access fixes)
*
* 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
@@ -17,10 +18,10 @@
#include <linux/string.h>
#include <linux/rtc.h>
#include <linux/bcd.h>
+#include <linux/rtc/ds1307.h>
-
-
-/* We can't determine type by probing, but if we expect pre-Linux code
+/*
+ * We can't determine type by probing, but if we expect pre-Linux code
* to have set the chip up as a clock (turning on the oscillator and
* setting the date and time), Linux can ignore the non-clock features.
* That's a natural job for a factory or repair bench.
@@ -36,7 +37,8 @@ enum ds_type {
m41t00,
mcp7941x,
rx_8025,
- // rs5c372 too? different address...
+ last_ds_type /* always last */
+ /* rs5c372 too? different address... */
};
@@ -58,7 +60,8 @@ enum ds_type {
# define DS1337_BIT_CENTURY 0x80 /* in REG_MONTH */
#define DS1307_REG_YEAR 0x06 /* 00-99 */
-/* Other registers (control, status, alarms, trickle charge, NVRAM, etc)
+/*
+ * Other registers (control, status, alarms, trickle charge, NVRAM, etc)
* start at 7, and they differ a LOT. Only control and status matter for
* basic RTC date and time functionality; be careful using them.
*/
@@ -89,7 +92,8 @@ enum ds_type {
# define DS1337_BIT_A2I 0x02
# define DS1337_BIT_A1I 0x01
#define DS1339_REG_ALARM1_SECS 0x07
-#define DS1339_REG_TRICKLE 0x10
+
+#define DS13XX_TRICKLE_CHARGER_MAGIC 0xa0
#define RX8025_REG_CTRL1 0x0e
# define RX8025_BIT_2412 0x20
@@ -102,6 +106,8 @@ enum ds_type {
struct ds1307 {
u8 offset; /* register's offset */
u8 regs[11];
+ u16 nvram_offset;
+ struct bin_attribute *nvram;
enum ds_type type;
unsigned long flags;
#define HAS_NVRAM 0 /* bit 0 == sysfs file active */
@@ -116,34 +122,44 @@ struct ds1307 {
};
struct chip_desc {
- unsigned nvram56:1;
unsigned alarm:1;
+ u16 nvram_offset;
+ u16 nvram_size;
+ u16 trickle_charger_reg;
};
-static const struct chip_desc chips[] = {
-[ds_1307] = {
- .nvram56 = 1,
-},
-[ds_1337] = {
- .alarm = 1,
-},
-[ds_1338] = {
- .nvram56 = 1,
-},
-[ds_1339] = {
- .alarm = 1,
-},
-[ds_1340] = {
-},
-[ds_3231] = {
- .alarm = 1,
-},
-[m41t00] = {
-},
-[mcp7941x] = {
-},
-[rx_8025] = {
-}, };
+static const struct chip_desc chips[last_ds_type] = {
+ [ds_1307] = {
+ .nvram_offset = 8,
+ .nvram_size = 56,
+ },
+ [ds_1337] = {
+ .alarm = 1,
+ },
+ [ds_1338] = {
+ .nvram_offset = 8,
+ .nvram_size = 56,
+ },
+ [ds_1339] = {
+ .alarm = 1,
+ .trickle_charger_reg = 0x10,
+ },
+ [ds_1340] = {
+ .trickle_charger_reg = 0x08,
+ },
+ [ds_1388] = {
+ .trickle_charger_reg = 0x0a,
+ },
+ [ds_3231] = {
+ .alarm = 1,
+ },
+ [mcp7941x] = {
+ .alarm = 1,
+ /* this is battery backed SRAM */
+ .nvram_offset = 0x20,
+ .nvram_size = 0x40,
+ },
+};
static const struct i2c_device_id ds1307_id[] = {
{ "ds1307", ds_1307 },
@@ -182,7 +198,7 @@ static s32 ds1307_read_block_data_once(const struct i2c_client *client,
static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command,
u8 length, u8 *values)
{
- u8 oldvalues[I2C_SMBUS_BLOCK_MAX];
+ u8 oldvalues[255];
s32 ret;
int tries = 0;
@@ -208,7 +224,7 @@ static s32 ds1307_read_block_data(const struct i2c_client *client, u8 command,
static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command,
u8 length, const u8 *values)
{
- u8 currvalues[I2C_SMBUS_BLOCK_MAX];
+ u8 currvalues[255];
int tries = 0;
dev_dbg(&client->dev, "ds1307_write_block_data (length=%d)\n", length);
@@ -236,6 +252,57 @@ static s32 ds1307_write_block_data(const struct i2c_client *client, u8 command,
/*----------------------------------------------------------------------*/
+/* These RTC devices are not designed to be connected to a SMbus adapter.
+ SMbus limits block operations length to 32 bytes, whereas it's not
+ limited on I2C buses. As a result, accesses may exceed 32 bytes;
+ in that case, split them into smaller blocks */
+
+static s32 ds1307_native_smbus_write_block_data(const struct i2c_client *client,
+ u8 command, u8 length, const u8 *values)
+{
+ u8 suboffset = 0;
+
+ if (length <= I2C_SMBUS_BLOCK_MAX)
+ return i2c_smbus_write_i2c_block_data(client,
+ command, length, values);
+
+ while (suboffset < length) {
+ s32 retval = i2c_smbus_write_i2c_block_data(client,
+ command + suboffset,
+ min(I2C_SMBUS_BLOCK_MAX, length - suboffset),
+ values + suboffset);
+ if (retval < 0)
+ return retval;
+
+ suboffset += I2C_SMBUS_BLOCK_MAX;
+ }
+ return length;
+}
+
+static s32 ds1307_native_smbus_read_block_data(const struct i2c_client *client,
+ u8 command, u8 length, u8 *values)
+{
+ u8 suboffset = 0;
+
+ if (length <= I2C_SMBUS_BLOCK_MAX)
+ return i2c_smbus_read_i2c_block_data(client,
+ command, length, values);
+
+ while (suboffset < length) {
+ s32 retval = i2c_smbus_read_i2c_block_data(client,
+ command + suboffset,
+ min(I2C_SMBUS_BLOCK_MAX, length - suboffset),
+ values + suboffset);
+ if (retval < 0)
+ return retval;
+
+ suboffset += I2C_SMBUS_BLOCK_MAX;
+ }
+ return length;
+}
+
+/*----------------------------------------------------------------------*/
+
/*
* The IRQ logic includes a "real" handler running in IRQ context just
* long enough to schedule this workqueue entry. We need a task context
@@ -308,12 +375,7 @@ static int ds1307_get_time(struct device *dev, struct rtc_time *t)
return -EIO;
}
- dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
- "read",
- ds1307->regs[0], ds1307->regs[1],
- ds1307->regs[2], ds1307->regs[3],
- ds1307->regs[4], ds1307->regs[5],
- ds1307->regs[6]);
+ dev_dbg(dev, "%s: %7ph\n", "read", ds1307->regs);
t->tm_sec = bcd2bin(ds1307->regs[DS1307_REG_SECS] & 0x7f);
t->tm_min = bcd2bin(ds1307->regs[DS1307_REG_MIN] & 0x7f);
@@ -372,6 +434,11 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
| DS1340_BIT_CENTURY;
break;
case mcp7941x:
+ /*
+ * these bits were cleared when preparing the date/time
+ * values and need to be set again before writing the
+ * buffer out to the device.
+ */
buf[DS1307_REG_SECS] |= MCP7941X_BIT_ST;
buf[DS1307_REG_WDAY] |= MCP7941X_BIT_VBATEN;
break;
@@ -379,9 +446,7 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
break;
}
- dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
- "write", buf[0], buf[1], buf[2], buf[3],
- buf[4], buf[5], buf[6]);
+ dev_dbg(dev, "%s: %7ph\n", "write", buf);
result = ds1307->write_block_data(ds1307->client,
ds1307->offset, 7, buf);
@@ -417,7 +482,8 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
ds1307->regs[6], ds1307->regs[7],
ds1307->regs[8]);
- /* report alarm time (ALARM1); assume 24 hour and day-of-month modes,
+ /*
+ * report alarm time (ALARM1); assume 24 hour and day-of-month modes,
* and that all four fields are checked matches
*/
t->time.tm_sec = bcd2bin(ds1307->regs[0] & 0x7f);
@@ -445,7 +511,7 @@ static int ds1337_read_alarm(struct device *dev, struct rtc_wkalrm *t)
static int ds1337_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
- struct i2c_client *client = to_i2c_client(dev);
+ struct i2c_client *client = to_i2c_client(dev);
struct ds1307 *ds1307 = i2c_get_clientdata(client);
unsigned char *buf = ds1307->regs;
u8 control, status;
@@ -541,7 +607,177 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
/*----------------------------------------------------------------------*/
-#define NVRAM_SIZE 56
+/*
+ * Alarm support for mcp7941x devices.
+ */
+
+#define MCP7941X_REG_CONTROL 0x07
+# define MCP7941X_BIT_ALM0_EN 0x10
+# define MCP7941X_BIT_ALM1_EN 0x20
+#define MCP7941X_REG_ALARM0_BASE 0x0a
+#define MCP7941X_REG_ALARM0_CTRL 0x0d
+#define MCP7941X_REG_ALARM1_BASE 0x11
+#define MCP7941X_REG_ALARM1_CTRL 0x14
+# define MCP7941X_BIT_ALMX_IF (1 << 3)
+# define MCP7941X_BIT_ALMX_C0 (1 << 4)
+# define MCP7941X_BIT_ALMX_C1 (1 << 5)
+# define MCP7941X_BIT_ALMX_C2 (1 << 6)
+# define MCP7941X_BIT_ALMX_POL (1 << 7)
+# define MCP7941X_MSK_ALMX_MATCH (MCP7941X_BIT_ALMX_C0 | \
+ MCP7941X_BIT_ALMX_C1 | \
+ MCP7941X_BIT_ALMX_C2)
+
+static void mcp7941x_work(struct work_struct *work)
+{
+ struct ds1307 *ds1307 = container_of(work, struct ds1307, work);
+ struct i2c_client *client = ds1307->client;
+ int reg, ret;
+
+ mutex_lock(&ds1307->rtc->ops_lock);
+
+ /* Check and clear alarm 0 interrupt flag. */
+ reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_ALARM0_CTRL);
+ if (reg < 0)
+ goto out;
+ if (!(reg & MCP7941X_BIT_ALMX_IF))
+ goto out;
+ reg &= ~MCP7941X_BIT_ALMX_IF;
+ ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_ALARM0_CTRL, reg);
+ if (ret < 0)
+ goto out;
+
+ /* Disable alarm 0. */
+ reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL);
+ if (reg < 0)
+ goto out;
+ reg &= ~MCP7941X_BIT_ALM0_EN;
+ ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg);
+ if (ret < 0)
+ goto out;
+
+ rtc_update_irq(ds1307->rtc, 1, RTC_AF | RTC_IRQF);
+
+out:
+ if (test_bit(HAS_ALARM, &ds1307->flags))
+ enable_irq(client->irq);
+ mutex_unlock(&ds1307->rtc->ops_lock);
+}
+
+static int mcp7941x_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ u8 *regs = ds1307->regs;
+ int ret;
+
+ if (!test_bit(HAS_ALARM, &ds1307->flags))
+ return -EINVAL;
+
+ /* Read control and alarm 0 registers. */
+ ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+ if (ret < 0)
+ return ret;
+
+ t->enabled = !!(regs[0] & MCP7941X_BIT_ALM0_EN);
+
+ /* Report alarm 0 time assuming 24-hour and day-of-month modes. */
+ t->time.tm_sec = bcd2bin(ds1307->regs[3] & 0x7f);
+ t->time.tm_min = bcd2bin(ds1307->regs[4] & 0x7f);
+ t->time.tm_hour = bcd2bin(ds1307->regs[5] & 0x3f);
+ t->time.tm_wday = bcd2bin(ds1307->regs[6] & 0x7) - 1;
+ t->time.tm_mday = bcd2bin(ds1307->regs[7] & 0x3f);
+ t->time.tm_mon = bcd2bin(ds1307->regs[8] & 0x1f) - 1;
+ t->time.tm_year = -1;
+ t->time.tm_yday = -1;
+ t->time.tm_isdst = -1;
+
+ dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d "
+ "enabled=%d polarity=%d irq=%d match=%d\n", __func__,
+ t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
+ t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled,
+ !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_POL),
+ !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_IF),
+ (ds1307->regs[6] & MCP7941X_MSK_ALMX_MATCH) >> 4);
+
+ return 0;
+}
+
+static int mcp7941x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ unsigned char *regs = ds1307->regs;
+ int ret;
+
+ if (!test_bit(HAS_ALARM, &ds1307->flags))
+ return -EINVAL;
+
+ dev_dbg(dev, "%s, sec=%d min=%d hour=%d wday=%d mday=%d mon=%d "
+ "enabled=%d pending=%d\n", __func__,
+ t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
+ t->time.tm_wday, t->time.tm_mday, t->time.tm_mon,
+ t->enabled, t->pending);
+
+ /* Read control and alarm 0 registers. */
+ ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+ if (ret < 0)
+ return ret;
+
+ /* Set alarm 0, using 24-hour and day-of-month modes. */
+ regs[3] = bin2bcd(t->time.tm_sec);
+ regs[4] = bin2bcd(t->time.tm_min);
+ regs[5] = bin2bcd(t->time.tm_hour);
+ regs[6] = bin2bcd(t->time.tm_wday) + 1;
+ regs[7] = bin2bcd(t->time.tm_mday);
+ regs[8] = bin2bcd(t->time.tm_mon) + 1;
+
+ /* Clear the alarm 0 interrupt flag. */
+ regs[6] &= ~MCP7941X_BIT_ALMX_IF;
+ /* Set alarm match: second, minute, hour, day, date, month. */
+ regs[6] |= MCP7941X_MSK_ALMX_MATCH;
+
+ if (t->enabled)
+ regs[0] |= MCP7941X_BIT_ALM0_EN;
+ else
+ regs[0] &= ~MCP7941X_BIT_ALM0_EN;
+
+ ret = ds1307->write_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int mcp7941x_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ int reg;
+
+ if (!test_bit(HAS_ALARM, &ds1307->flags))
+ return -EINVAL;
+
+ reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL);
+ if (reg < 0)
+ return reg;
+
+ if (enabled)
+ reg |= MCP7941X_BIT_ALM0_EN;
+ else
+ reg &= ~MCP7941X_BIT_ALM0_EN;
+
+ return i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg);
+}
+
+static const struct rtc_class_ops mcp7941x_rtc_ops = {
+ .read_time = ds1307_get_time,
+ .set_time = ds1307_set_time,
+ .read_alarm = mcp7941x_read_alarm,
+ .set_alarm = mcp7941x_set_alarm,
+ .alarm_irq_enable = mcp7941x_alarm_irq_enable,
+};
+
+/*----------------------------------------------------------------------*/
static ssize_t
ds1307_nvram_read(struct file *filp, struct kobject *kobj,
@@ -555,14 +791,15 @@ ds1307_nvram_read(struct file *filp, struct kobject *kobj,
client = kobj_to_i2c_client(kobj);
ds1307 = i2c_get_clientdata(client);
- if (unlikely(off >= NVRAM_SIZE))
+ if (unlikely(off >= ds1307->nvram->size))
return 0;
- if ((off + count) > NVRAM_SIZE)
- count = NVRAM_SIZE - off;
+ if ((off + count) > ds1307->nvram->size)
+ count = ds1307->nvram->size - off;
if (unlikely(!count))
return count;
- result = ds1307->read_block_data(client, 8 + off, count, buf);
+ result = ds1307->read_block_data(client, ds1307->nvram_offset + off,
+ count, buf);
if (result < 0)
dev_err(&client->dev, "%s error %d\n", "nvram read", result);
return result;
@@ -580,14 +817,15 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj,
client = kobj_to_i2c_client(kobj);
ds1307 = i2c_get_clientdata(client);
- if (unlikely(off >= NVRAM_SIZE))
+ if (unlikely(off >= ds1307->nvram->size))
return -EFBIG;
- if ((off + count) > NVRAM_SIZE)
- count = NVRAM_SIZE - off;
+ if ((off + count) > ds1307->nvram->size)
+ count = ds1307->nvram->size - off;
if (unlikely(!count))
return count;
- result = ds1307->write_block_data(client, 8 + off, count, buf);
+ result = ds1307->write_block_data(client, ds1307->nvram_offset + off,
+ count, buf);
if (result < 0) {
dev_err(&client->dev, "%s error %d\n", "nvram write", result);
return result;
@@ -595,54 +833,47 @@ ds1307_nvram_write(struct file *filp, struct kobject *kobj,
return count;
}
-static struct bin_attribute nvram = {
- .attr = {
- .name = "nvram",
- .mode = S_IRUGO | S_IWUSR,
- },
-
- .read = ds1307_nvram_read,
- .write = ds1307_nvram_write,
- .size = NVRAM_SIZE,
-};
-
/*----------------------------------------------------------------------*/
-static struct i2c_driver ds1307_driver;
-
-static int __devinit ds1307_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ds1307_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct ds1307 *ds1307;
int err = -ENODEV;
int tmp;
const struct chip_desc *chip = &chips[id->driver_data];
struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- int want_irq = false;
+ bool want_irq = false;
unsigned char *buf;
+ struct ds1307_platform_data *pdata = dev_get_platdata(&client->dev);
static const int bbsqi_bitpos[] = {
[ds_1337] = 0,
[ds_1339] = DS1339_BIT_BBSQI,
[ds_3231] = DS3231_BIT_BBSQW,
};
+ const struct rtc_class_ops *rtc_ops = &ds13xx_rtc_ops;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)
&& !i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
return -EIO;
- if (!(ds1307 = kzalloc(sizeof(struct ds1307), GFP_KERNEL)))
+ ds1307 = devm_kzalloc(&client->dev, sizeof(struct ds1307), GFP_KERNEL);
+ if (!ds1307)
return -ENOMEM;
i2c_set_clientdata(client, ds1307);
ds1307->client = client;
ds1307->type = id->driver_data;
- ds1307->offset = 0;
+
+ if (pdata && pdata->trickle_charger_setup && chip->trickle_charger_reg)
+ i2c_smbus_write_byte_data(client, chip->trickle_charger_reg,
+ DS13XX_TRICKLE_CHARGER_MAGIC | pdata->trickle_charger_setup);
buf = ds1307->regs;
if (i2c_check_functionality(adapter, I2C_FUNC_SMBUS_I2C_BLOCK)) {
- ds1307->read_block_data = i2c_smbus_read_i2c_block_data;
- ds1307->write_block_data = i2c_smbus_write_i2c_block_data;
+ ds1307->read_block_data = ds1307_native_smbus_read_block_data;
+ ds1307->write_block_data = ds1307_native_smbus_write_block_data;
} else {
ds1307->read_block_data = ds1307_read_block_data;
ds1307->write_block_data = ds1307_write_block_data;
@@ -652,32 +883,32 @@ static int __devinit ds1307_probe(struct i2c_client *client,
case ds_1337:
case ds_1339:
case ds_3231:
- /* has IRQ? */
- if (ds1307->client->irq > 0 && chip->alarm) {
- INIT_WORK(&ds1307->work, ds1307_work);
- want_irq = true;
- }
/* get registers that the "rtc" read below won't read... */
tmp = ds1307->read_block_data(ds1307->client,
DS1337_REG_CONTROL, 2, buf);
if (tmp != 2) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
- goto exit_free;
+ goto exit;
}
/* oscillator off? turn it on, so clock can tick. */
if (ds1307->regs[0] & DS1337_BIT_nEOSC)
ds1307->regs[0] &= ~DS1337_BIT_nEOSC;
- /* Using IRQ? Disable the square wave and both alarms.
+ /*
+ * Using IRQ? Disable the square wave and both alarms.
* For some variants, be sure alarms can trigger when we're
* running on Vbackup (BBSQI/BBSQW)
*/
- if (want_irq) {
+ if (ds1307->client->irq > 0 && chip->alarm) {
+ INIT_WORK(&ds1307->work, ds1307_work);
+
ds1307->regs[0] |= DS1337_BIT_INTCN
| bbsqi_bitpos[ds1307->type];
ds1307->regs[0] &= ~(DS1337_BIT_A2IE | DS1337_BIT_A1IE);
+
+ want_irq = true;
}
i2c_smbus_write_byte_data(client, DS1337_REG_CONTROL,
@@ -695,9 +926,9 @@ static int __devinit ds1307_probe(struct i2c_client *client,
tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
RX8025_REG_CTRL1 << 4 | 0x08, 2, buf);
if (tmp != 2) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
- goto exit_free;
+ goto exit;
}
/* oscillator off? turn it on, so clock can tick. */
@@ -739,9 +970,9 @@ static int __devinit ds1307_probe(struct i2c_client *client,
tmp = i2c_smbus_read_i2c_block_data(ds1307->client,
RX8025_REG_CTRL1 << 4 | 0x08, 2, buf);
if (tmp != 2) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
- goto exit_free;
+ goto exit;
}
/* correct hour */
@@ -759,6 +990,13 @@ static int __devinit ds1307_probe(struct i2c_client *client,
case ds_1388:
ds1307->offset = 1; /* Seconds starts at 1 */
break;
+ case mcp7941x:
+ rtc_ops = &mcp7941x_rtc_ops;
+ if (ds1307->client->irq > 0 && chip->alarm) {
+ INIT_WORK(&ds1307->work, mcp7941x_work);
+ want_irq = true;
+ }
+ break;
default:
break;
}
@@ -767,12 +1005,13 @@ read_rtc:
/* read RTC registers */
tmp = ds1307->read_block_data(ds1307->client, ds1307->offset, 8, buf);
if (tmp != 8) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
- goto exit_free;
+ goto exit;
}
- /* minimal sanity checking; some chips (like DS1340) don't
+ /*
+ * minimal sanity checking; some chips (like DS1340) don't
* specify the extra bits as must-be-zero, but there are
* still a few values that are clearly out-of-range.
*/
@@ -808,9 +1047,9 @@ read_rtc:
tmp = i2c_smbus_read_byte_data(client, DS1340_REG_FLAG);
if (tmp < 0) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
- goto exit_free;
+ goto exit;
}
/* oscillator fault? clear flag, and warn */
@@ -836,11 +1075,7 @@ read_rtc:
}
break;
- case rx_8025:
- case ds_1337:
- case ds_1339:
- case ds_1388:
- case ds_3231:
+ default:
break;
}
@@ -848,7 +1083,8 @@ read_rtc:
switch (ds1307->type) {
case ds_1340:
case m41t00:
- /* NOTE: ignores century bits; fix before deploying
+ /*
+ * NOTE: ignores century bits; fix before deploying
* systems that will run through year 2100.
*/
break;
@@ -858,7 +1094,8 @@ read_rtc:
if (!(tmp & DS1307_BIT_12HR))
break;
- /* Be sure we're in 24 hour mode. Multi-master systems
+ /*
+ * Be sure we're in 24 hour mode. Multi-master systems
* take note...
*/
tmp = bcd2bin(tmp & 0x1f);
@@ -871,49 +1108,68 @@ read_rtc:
bin2bcd(tmp));
}
- ds1307->rtc = rtc_device_register(client->name, &client->dev,
- &ds13xx_rtc_ops, THIS_MODULE);
+ device_set_wakeup_capable(&client->dev, want_irq);
+ ds1307->rtc = devm_rtc_device_register(&client->dev, client->name,
+ rtc_ops, THIS_MODULE);
if (IS_ERR(ds1307->rtc)) {
- err = PTR_ERR(ds1307->rtc);
- dev_err(&client->dev,
- "unable to register the class device\n");
- goto exit_free;
+ return PTR_ERR(ds1307->rtc);
}
if (want_irq) {
err = request_irq(client->irq, ds1307_irq, IRQF_SHARED,
ds1307->rtc->name, client);
if (err) {
- dev_err(&client->dev,
- "unable to request IRQ!\n");
- goto exit_irq;
- }
+ client->irq = 0;
+ dev_err(&client->dev, "unable to request IRQ!\n");
+ } else {
- device_set_wakeup_capable(&client->dev, 1);
- set_bit(HAS_ALARM, &ds1307->flags);
- dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
+ set_bit(HAS_ALARM, &ds1307->flags);
+ dev_dbg(&client->dev, "got IRQ %d\n", client->irq);
+ }
}
- if (chip->nvram56) {
- err = sysfs_create_bin_file(&client->dev.kobj, &nvram);
- if (err == 0) {
- set_bit(HAS_NVRAM, &ds1307->flags);
- dev_info(&client->dev, "56 bytes nvram\n");
+ if (chip->nvram_size) {
+
+ ds1307->nvram = devm_kzalloc(&client->dev,
+ sizeof(struct bin_attribute),
+ GFP_KERNEL);
+ if (!ds1307->nvram) {
+ dev_err(&client->dev, "cannot allocate memory for nvram sysfs\n");
+ } else {
+
+ ds1307->nvram->attr.name = "nvram";
+ ds1307->nvram->attr.mode = S_IRUGO | S_IWUSR;
+
+ sysfs_bin_attr_init(ds1307->nvram);
+
+ ds1307->nvram->read = ds1307_nvram_read;
+ ds1307->nvram->write = ds1307_nvram_write;
+ ds1307->nvram->size = chip->nvram_size;
+ ds1307->nvram_offset = chip->nvram_offset;
+
+ err = sysfs_create_bin_file(&client->dev.kobj,
+ ds1307->nvram);
+ if (err) {
+ dev_err(&client->dev,
+ "unable to create sysfs file: %s\n",
+ ds1307->nvram->attr.name);
+ } else {
+ set_bit(HAS_NVRAM, &ds1307->flags);
+ dev_info(&client->dev, "%zu bytes nvram\n",
+ ds1307->nvram->size);
+ }
}
}
return 0;
-exit_irq:
- rtc_device_unregister(ds1307->rtc);
-exit_free:
- kfree(ds1307);
+exit:
return err;
}
-static int __devexit ds1307_remove(struct i2c_client *client)
+static int ds1307_remove(struct i2c_client *client)
{
- struct ds1307 *ds1307 = i2c_get_clientdata(client);
+ struct ds1307 *ds1307 = i2c_get_clientdata(client);
if (test_and_clear_bit(HAS_ALARM, &ds1307->flags)) {
free_irq(client->irq, client);
@@ -921,10 +1177,8 @@ static int __devexit ds1307_remove(struct i2c_client *client)
}
if (test_and_clear_bit(HAS_NVRAM, &ds1307->flags))
- sysfs_remove_bin_file(&client->dev.kobj, &nvram);
+ sysfs_remove_bin_file(&client->dev.kobj, ds1307->nvram);
- rtc_device_unregister(ds1307->rtc);
- kfree(ds1307);
return 0;
}
@@ -934,21 +1188,11 @@ static struct i2c_driver ds1307_driver = {
.owner = THIS_MODULE,
},
.probe = ds1307_probe,
- .remove = __devexit_p(ds1307_remove),
+ .remove = ds1307_remove,
.id_table = ds1307_id,
};
-static int __init ds1307_init(void)
-{
- return i2c_add_driver(&ds1307_driver);
-}
-module_init(ds1307_init);
-
-static void __exit ds1307_exit(void)
-{
- i2c_del_driver(&ds1307_driver);
-}
-module_exit(ds1307_exit);
+module_i2c_driver(ds1307_driver);
MODULE_DESCRIPTION("RTC driver for DS1307 and similar chips");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-ds1343.c b/drivers/rtc/rtc-ds1343.c
new file mode 100644
index 00000000000..c3719189dd9
--- /dev/null
+++ b/drivers/rtc/rtc-ds1343.c
@@ -0,0 +1,689 @@
+/* rtc-ds1343.c
+ *
+ * Driver for Dallas Semiconductor DS1343 Low Current, SPI Compatible
+ * Real Time Clock
+ *
+ * Author : Raghavendra Chandra Ganiga <ravi23ganiga@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/interrupt.h>
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/regmap.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/pm.h>
+#include <linux/slab.h>
+
+#define DS1343_DRV_VERSION "01.00"
+#define DALLAS_MAXIM_DS1343 0
+#define DALLAS_MAXIM_DS1344 1
+
+/* RTC DS1343 Registers */
+#define DS1343_SECONDS_REG 0x00
+#define DS1343_MINUTES_REG 0x01
+#define DS1343_HOURS_REG 0x02
+#define DS1343_DAY_REG 0x03
+#define DS1343_DATE_REG 0x04
+#define DS1343_MONTH_REG 0x05
+#define DS1343_YEAR_REG 0x06
+#define DS1343_ALM0_SEC_REG 0x07
+#define DS1343_ALM0_MIN_REG 0x08
+#define DS1343_ALM0_HOUR_REG 0x09
+#define DS1343_ALM0_DAY_REG 0x0A
+#define DS1343_ALM1_SEC_REG 0x0B
+#define DS1343_ALM1_MIN_REG 0x0C
+#define DS1343_ALM1_HOUR_REG 0x0D
+#define DS1343_ALM1_DAY_REG 0x0E
+#define DS1343_CONTROL_REG 0x0F
+#define DS1343_STATUS_REG 0x10
+#define DS1343_TRICKLE_REG 0x11
+
+/* DS1343 Control Registers bits */
+#define DS1343_EOSC 0x80
+#define DS1343_DOSF 0x20
+#define DS1343_EGFIL 0x10
+#define DS1343_SQW 0x08
+#define DS1343_INTCN 0x04
+#define DS1343_A1IE 0x02
+#define DS1343_A0IE 0x01
+
+/* DS1343 Status Registers bits */
+#define DS1343_OSF 0x80
+#define DS1343_IRQF1 0x02
+#define DS1343_IRQF0 0x01
+
+/* DS1343 Trickle Charger Registers bits */
+#define DS1343_TRICKLE_MAGIC 0xa0
+#define DS1343_TRICKLE_DS1 0x08
+#define DS1343_TRICKLE_1K 0x01
+#define DS1343_TRICKLE_2K 0x02
+#define DS1343_TRICKLE_4K 0x03
+
+static const struct spi_device_id ds1343_id[] = {
+ { "ds1343", DALLAS_MAXIM_DS1343 },
+ { "ds1344", DALLAS_MAXIM_DS1344 },
+ { }
+};
+MODULE_DEVICE_TABLE(spi, ds1343_id);
+
+struct ds1343_priv {
+ struct spi_device *spi;
+ struct rtc_device *rtc;
+ struct regmap *map;
+ struct mutex mutex;
+ unsigned int irqen;
+ int irq;
+ int alarm_sec;
+ int alarm_min;
+ int alarm_hour;
+ int alarm_mday;
+};
+
+static int ds1343_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+ switch (cmd) {
+#ifdef RTC_SET_CHARGE
+ case RTC_SET_CHARGE:
+ {
+ int val;
+
+ if (copy_from_user(&val, (int __user *)arg, sizeof(int)))
+ return -EFAULT;
+
+ return regmap_write(priv->map, DS1343_TRICKLE_REG, val);
+ }
+ break;
+#endif
+ }
+
+ return -ENOIOCTLCMD;
+}
+
+static ssize_t ds1343_show_glitchfilter(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ds1343_priv *priv = dev_get_drvdata(dev);
+ int glitch_filt_status, data;
+
+ regmap_read(priv->map, DS1343_CONTROL_REG, &data);
+
+ glitch_filt_status = !!(data & DS1343_EGFIL);
+
+ if (glitch_filt_status)
+ return sprintf(buf, "enabled\n");
+ else
+ return sprintf(buf, "disabled\n");
+}
+
+static ssize_t ds1343_store_glitchfilter(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ds1343_priv *priv = dev_get_drvdata(dev);
+ int data;
+
+ regmap_read(priv->map, DS1343_CONTROL_REG, &data);
+
+ if (strncmp(buf, "enabled", 7) == 0)
+ data |= DS1343_EGFIL;
+
+ else if (strncmp(buf, "disabled", 8) == 0)
+ data &= ~(DS1343_EGFIL);
+
+ else
+ return -EINVAL;
+
+ regmap_write(priv->map, DS1343_CONTROL_REG, data);
+
+ return count;
+}
+
+static DEVICE_ATTR(glitch_filter, S_IRUGO | S_IWUSR, ds1343_show_glitchfilter,
+ ds1343_store_glitchfilter);
+
+static ssize_t ds1343_show_alarmstatus(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ds1343_priv *priv = dev_get_drvdata(dev);
+ int alarmstatus, data;
+
+ regmap_read(priv->map, DS1343_CONTROL_REG, &data);
+
+ alarmstatus = !!(data & DS1343_A0IE);
+
+ if (alarmstatus)
+ return sprintf(buf, "enabled\n");
+ else
+ return sprintf(buf, "disabled\n");
+}
+
+static DEVICE_ATTR(alarm_status, S_IRUGO, ds1343_show_alarmstatus, NULL);
+
+static ssize_t ds1343_show_alarmmode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ds1343_priv *priv = dev_get_drvdata(dev);
+ int alarm_mode, data;
+ char *alarm_str;
+
+ regmap_read(priv->map, DS1343_ALM0_SEC_REG, &data);
+ alarm_mode = (data & 0x80) >> 4;
+
+ regmap_read(priv->map, DS1343_ALM0_MIN_REG, &data);
+ alarm_mode |= (data & 0x80) >> 5;
+
+ regmap_read(priv->map, DS1343_ALM0_HOUR_REG, &data);
+ alarm_mode |= (data & 0x80) >> 6;
+
+ regmap_read(priv->map, DS1343_ALM0_DAY_REG, &data);
+ alarm_mode |= (data & 0x80) >> 7;
+
+ switch (alarm_mode) {
+ case 15:
+ alarm_str = "each second";
+ break;
+
+ case 7:
+ alarm_str = "seconds match";
+ break;
+
+ case 3:
+ alarm_str = "minutes and seconds match";
+ break;
+
+ case 1:
+ alarm_str = "hours, minutes and seconds match";
+ break;
+
+ case 0:
+ alarm_str = "day, hours, minutes and seconds match";
+ break;
+
+ default:
+ alarm_str = "invalid";
+ break;
+ }
+
+ return sprintf(buf, "%s\n", alarm_str);
+}
+
+static DEVICE_ATTR(alarm_mode, S_IRUGO, ds1343_show_alarmmode, NULL);
+
+static ssize_t ds1343_show_tricklecharger(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct ds1343_priv *priv = dev_get_drvdata(dev);
+ int data;
+ char *diodes = "disabled", *resistors = " ";
+
+ regmap_read(priv->map, DS1343_TRICKLE_REG, &data);
+
+ if ((data & 0xf0) == DS1343_TRICKLE_MAGIC) {
+ switch (data & 0x0c) {
+ case DS1343_TRICKLE_DS1:
+ diodes = "one diode,";
+ break;
+
+ default:
+ diodes = "no diode,";
+ break;
+ }
+
+ switch (data & 0x03) {
+ case DS1343_TRICKLE_1K:
+ resistors = "1k Ohm";
+ break;
+
+ case DS1343_TRICKLE_2K:
+ resistors = "2k Ohm";
+ break;
+
+ case DS1343_TRICKLE_4K:
+ resistors = "4k Ohm";
+ break;
+
+ default:
+ diodes = "disabled";
+ break;
+ }
+ }
+
+ return sprintf(buf, "%s %s\n", diodes, resistors);
+}
+
+static DEVICE_ATTR(trickle_charger, S_IRUGO, ds1343_show_tricklecharger, NULL);
+
+static int ds1343_sysfs_register(struct device *dev)
+{
+ struct ds1343_priv *priv = dev_get_drvdata(dev);
+ int err;
+
+ err = device_create_file(dev, &dev_attr_glitch_filter);
+ if (err)
+ return err;
+
+ err = device_create_file(dev, &dev_attr_trickle_charger);
+ if (err)
+ goto error1;
+
+ if (priv->irq <= 0)
+ return err;
+
+ err = device_create_file(dev, &dev_attr_alarm_mode);
+ if (err)
+ goto error2;
+
+ err = device_create_file(dev, &dev_attr_alarm_status);
+ if (!err)
+ return err;
+
+ device_remove_file(dev, &dev_attr_alarm_mode);
+
+error2:
+ device_remove_file(dev, &dev_attr_trickle_charger);
+
+error1:
+ device_remove_file(dev, &dev_attr_glitch_filter);
+
+ return err;
+}
+
+static void ds1343_sysfs_unregister(struct device *dev)
+{
+ struct ds1343_priv *priv = dev_get_drvdata(dev);
+
+ device_remove_file(dev, &dev_attr_glitch_filter);
+ device_remove_file(dev, &dev_attr_trickle_charger);
+
+ if (priv->irq <= 0)
+ return;
+
+ device_remove_file(dev, &dev_attr_alarm_status);
+ device_remove_file(dev, &dev_attr_alarm_mode);
+}
+
+static int ds1343_read_time(struct device *dev, struct rtc_time *dt)
+{
+ struct ds1343_priv *priv = dev_get_drvdata(dev);
+ unsigned char buf[7];
+ int res;
+
+ res = regmap_bulk_read(priv->map, DS1343_SECONDS_REG, buf, 7);
+ if (res)
+ return res;
+
+ dt->tm_sec = bcd2bin(buf[0]);
+ dt->tm_min = bcd2bin(buf[1]);
+ dt->tm_hour = bcd2bin(buf[2] & 0x3F);
+ dt->tm_wday = bcd2bin(buf[3]) - 1;
+ dt->tm_mday = bcd2bin(buf[4]);
+ dt->tm_mon = bcd2bin(buf[5] & 0x1F) - 1;
+ dt->tm_year = bcd2bin(buf[6]) + 100; /* year offset from 1900 */
+
+ return rtc_valid_tm(dt);
+}
+
+static int ds1343_set_time(struct device *dev, struct rtc_time *dt)
+{
+ struct ds1343_priv *priv = dev_get_drvdata(dev);
+ int res;
+
+ res = regmap_write(priv->map, DS1343_SECONDS_REG,
+ bin2bcd(dt->tm_sec));
+ if (res)
+ return res;
+
+ res = regmap_write(priv->map, DS1343_MINUTES_REG,
+ bin2bcd(dt->tm_min));
+ if (res)
+ return res;
+
+ res = regmap_write(priv->map, DS1343_HOURS_REG,
+ bin2bcd(dt->tm_hour) & 0x3F);
+ if (res)
+ return res;
+
+ res = regmap_write(priv->map, DS1343_DAY_REG,
+ bin2bcd(dt->tm_wday + 1));
+ if (res)
+ return res;
+
+ res = regmap_write(priv->map, DS1343_DATE_REG,
+ bin2bcd(dt->tm_mday));
+ if (res)
+ return res;
+
+ res = regmap_write(priv->map, DS1343_MONTH_REG,
+ bin2bcd(dt->tm_mon + 1));
+ if (res)
+ return res;
+
+ dt->tm_year %= 100;
+
+ res = regmap_write(priv->map, DS1343_YEAR_REG,
+ bin2bcd(dt->tm_year));
+ if (res)
+ return res;
+
+ return 0;
+}
+
+static int ds1343_update_alarm(struct device *dev)
+{
+ struct ds1343_priv *priv = dev_get_drvdata(dev);
+ unsigned int control, stat;
+ unsigned char buf[4];
+ int res = 0;
+
+ res = regmap_read(priv->map, DS1343_CONTROL_REG, &control);
+ if (res)
+ return res;
+
+ res = regmap_read(priv->map, DS1343_STATUS_REG, &stat);
+ if (res)
+ return res;
+
+ control &= ~(DS1343_A0IE);
+ stat &= ~(DS1343_IRQF0);
+
+ res = regmap_write(priv->map, DS1343_CONTROL_REG, control);
+ if (res)
+ return res;
+
+ res = regmap_write(priv->map, DS1343_STATUS_REG, stat);
+ if (res)
+ return res;
+
+ buf[0] = priv->alarm_sec < 0 || (priv->irqen & RTC_UF) ?
+ 0x80 : bin2bcd(priv->alarm_sec) & 0x7F;
+ buf[1] = priv->alarm_min < 0 || (priv->irqen & RTC_UF) ?
+ 0x80 : bin2bcd(priv->alarm_min) & 0x7F;
+ buf[2] = priv->alarm_hour < 0 || (priv->irqen & RTC_UF) ?
+ 0x80 : bin2bcd(priv->alarm_hour) & 0x3F;
+ buf[3] = priv->alarm_mday < 0 || (priv->irqen & RTC_UF) ?
+ 0x80 : bin2bcd(priv->alarm_mday) & 0x7F;
+
+ res = regmap_bulk_write(priv->map, DS1343_ALM0_SEC_REG, buf, 4);
+ if (res)
+ return res;
+
+ if (priv->irqen) {
+ control |= DS1343_A0IE;
+ res = regmap_write(priv->map, DS1343_CONTROL_REG, control);
+ }
+
+ return res;
+}
+
+static int ds1343_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct ds1343_priv *priv = dev_get_drvdata(dev);
+ int res = 0;
+ unsigned int stat;
+
+ if (priv->irq <= 0)
+ return -EINVAL;
+
+ mutex_lock(&priv->mutex);
+
+ res = regmap_read(priv->map, DS1343_STATUS_REG, &stat);
+ if (res)
+ goto out;
+
+ alarm->enabled = !!(priv->irqen & RTC_AF);
+ alarm->pending = !!(stat & DS1343_IRQF0);
+
+ alarm->time.tm_sec = priv->alarm_sec < 0 ? 0 : priv->alarm_sec;
+ alarm->time.tm_min = priv->alarm_min < 0 ? 0 : priv->alarm_min;
+ 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;
+}
+
+static int ds1343_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct ds1343_priv *priv = dev_get_drvdata(dev);
+ int res = 0;
+
+ if (priv->irq <= 0)
+ return -EINVAL;
+
+ mutex_lock(&priv->mutex);
+
+ priv->alarm_sec = alarm->time.tm_sec;
+ priv->alarm_min = alarm->time.tm_min;
+ priv->alarm_hour = alarm->time.tm_hour;
+ priv->alarm_mday = alarm->time.tm_mday;
+
+ if (alarm->enabled)
+ priv->irqen |= RTC_AF;
+
+ res = ds1343_update_alarm(dev);
+
+ mutex_unlock(&priv->mutex);
+
+ return res;
+}
+
+static int ds1343_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct ds1343_priv *priv = dev_get_drvdata(dev);
+ int res = 0;
+
+ if (priv->irq <= 0)
+ return -EINVAL;
+
+ mutex_lock(&priv->mutex);
+
+ if (enabled)
+ priv->irqen |= RTC_AF;
+ else
+ priv->irqen &= ~RTC_AF;
+
+ res = ds1343_update_alarm(dev);
+
+ mutex_unlock(&priv->mutex);
+
+ return res;
+}
+
+static irqreturn_t ds1343_thread(int irq, void *dev_id)
+{
+ struct ds1343_priv *priv = dev_id;
+ unsigned int stat, control;
+ int res = 0;
+
+ mutex_lock(&priv->mutex);
+
+ res = regmap_read(priv->map, DS1343_STATUS_REG, &stat);
+ if (res)
+ goto out;
+
+ if (stat & DS1343_IRQF0) {
+ stat &= ~DS1343_IRQF0;
+ regmap_write(priv->map, DS1343_STATUS_REG, stat);
+
+ res = regmap_read(priv->map, DS1343_CONTROL_REG, &control);
+ if (res)
+ goto out;
+
+ control &= ~DS1343_A0IE;
+ regmap_write(priv->map, DS1343_CONTROL_REG, control);
+
+ rtc_update_irq(priv->rtc, 1, RTC_AF | RTC_IRQF);
+ }
+
+out:
+ mutex_unlock(&priv->mutex);
+ return IRQ_HANDLED;
+}
+
+static const struct rtc_class_ops ds1343_rtc_ops = {
+ .ioctl = ds1343_ioctl,
+ .read_time = ds1343_read_time,
+ .set_time = ds1343_set_time,
+ .read_alarm = ds1343_read_alarm,
+ .set_alarm = ds1343_set_alarm,
+ .alarm_irq_enable = ds1343_alarm_irq_enable,
+};
+
+static int ds1343_probe(struct spi_device *spi)
+{
+ struct ds1343_priv *priv;
+ struct regmap_config config;
+ unsigned int data;
+ int res;
+
+ memset(&config, 0, sizeof(config));
+ config.reg_bits = 8;
+ config.val_bits = 8;
+ config.write_flag_mask = 0x80;
+
+ priv = devm_kzalloc(&spi->dev, sizeof(struct ds1343_priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->spi = spi;
+ mutex_init(&priv->mutex);
+
+ /* RTC DS1347 works in spi mode 3 and
+ * its chip select is active high
+ */
+ spi->mode = SPI_MODE_3 | SPI_CS_HIGH;
+ spi->bits_per_word = 8;
+ res = spi_setup(spi);
+ if (res)
+ return res;
+
+ spi_set_drvdata(spi, priv);
+
+ priv->map = devm_regmap_init_spi(spi, &config);
+
+ if (IS_ERR(priv->map)) {
+ dev_err(&spi->dev, "spi regmap init failed for rtc ds1343\n");
+ return PTR_ERR(priv->map);
+ }
+
+ res = regmap_read(priv->map, DS1343_SECONDS_REG, &data);
+ if (res)
+ return res;
+
+ regmap_read(priv->map, DS1343_CONTROL_REG, &data);
+ data |= DS1343_INTCN;
+ data &= ~(DS1343_EOSC | DS1343_A1IE | DS1343_A0IE);
+ regmap_write(priv->map, DS1343_CONTROL_REG, data);
+
+ regmap_read(priv->map, DS1343_STATUS_REG, &data);
+ data &= ~(DS1343_OSF | DS1343_IRQF1 | DS1343_IRQF0);
+ regmap_write(priv->map, DS1343_STATUS_REG, data);
+
+ priv->rtc = devm_rtc_device_register(&spi->dev, "ds1343",
+ &ds1343_rtc_ops, THIS_MODULE);
+ if (IS_ERR(priv->rtc)) {
+ dev_err(&spi->dev, "unable to register rtc ds1343\n");
+ return PTR_ERR(priv->rtc);
+ }
+
+ priv->irq = spi->irq;
+
+ if (priv->irq >= 0) {
+ res = devm_request_threaded_irq(&spi->dev, spi->irq, NULL,
+ ds1343_thread,
+ IRQF_NO_SUSPEND | IRQF_ONESHOT,
+ "ds1343", priv);
+ if (res) {
+ priv->irq = -1;
+ dev_err(&spi->dev,
+ "unable to request irq for rtc ds1343\n");
+ } else {
+ device_set_wakeup_capable(&spi->dev, 1);
+ }
+ }
+
+ res = ds1343_sysfs_register(&spi->dev);
+ if (res)
+ dev_err(&spi->dev,
+ "unable to create sysfs entries for rtc ds1343\n");
+
+ return 0;
+}
+
+static int ds1343_remove(struct spi_device *spi)
+{
+ struct ds1343_priv *priv = spi_get_drvdata(spi);
+
+ if (spi->irq) {
+ mutex_lock(&priv->mutex);
+ priv->irqen &= ~RTC_AF;
+ mutex_unlock(&priv->mutex);
+
+ devm_free_irq(&spi->dev, spi->irq, priv);
+ }
+
+ spi_set_drvdata(spi, NULL);
+
+ ds1343_sysfs_unregister(&spi->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int ds1343_suspend(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+
+ if (spi->irq >= 0 && device_may_wakeup(dev))
+ enable_irq_wake(spi->irq);
+
+ return 0;
+}
+
+static int ds1343_resume(struct device *dev)
+{
+ struct spi_device *spi = to_spi_device(dev);
+
+ if (spi->irq >= 0 && device_may_wakeup(dev))
+ disable_irq_wake(spi->irq);
+
+ return 0;
+}
+
+#endif
+
+static SIMPLE_DEV_PM_OPS(ds1343_pm, ds1343_suspend, ds1343_resume);
+
+static struct spi_driver ds1343_driver = {
+ .driver = {
+ .name = "ds1343",
+ .owner = THIS_MODULE,
+ .pm = &ds1343_pm,
+ },
+ .probe = ds1343_probe,
+ .remove = ds1343_remove,
+ .id_table = ds1343_id,
+};
+
+module_spi_driver(ds1343_driver);
+
+MODULE_DESCRIPTION("DS1343 RTC SPI Driver");
+MODULE_AUTHOR("Raghavendra Chandra Ganiga <ravi23ganiga@gmail.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_VERSION(DS1343_DRV_VERSION);
diff --git a/drivers/rtc/rtc-ds1347.c b/drivers/rtc/rtc-ds1347.c
new file mode 100644
index 00000000000..c82b4c05032
--- /dev/null
+++ b/drivers/rtc/rtc-ds1347.c
@@ -0,0 +1,166 @@
+/* rtc-ds1347.c
+ *
+ * Driver for Dallas Semiconductor DS1347 Low Current, SPI Compatible
+ * Real Time Clock
+ *
+ * Author : Raghavendra Chandra Ganiga <ravi23ganiga@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 ds1347 rtc */
+
+#define DS1347_SECONDS_REG 0x01
+#define DS1347_MINUTES_REG 0x03
+#define DS1347_HOURS_REG 0x05
+#define DS1347_DATE_REG 0x07
+#define DS1347_MONTH_REG 0x09
+#define DS1347_DAY_REG 0x0B
+#define DS1347_YEAR_REG 0x0D
+#define DS1347_CONTROL_REG 0x0F
+#define DS1347_STATUS_REG 0x17
+#define DS1347_CLOCK_BURST 0x3F
+
+static int ds1347_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 ds1347_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 ds1347_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] = DS1347_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 ds1347_set_time(struct device *dev, struct rtc_time *dt)
+{
+ struct spi_device *spi = to_spi_device(dev);
+ unsigned char buf[9];
+
+ buf[0] = DS1347_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);
+
+ /* year in linux is from 1900 i.e in range of 100
+ in rtc it is from 00 to 99 */
+ dt->tm_year = dt->tm_year % 100;
+
+ buf[7] = bin2bcd(dt->tm_year);
+ buf[8] = bin2bcd(0x00);
+
+ /* write the rtc settings */
+ return spi_write_then_read(spi, buf, 9, NULL, 0);
+}
+
+static const struct rtc_class_ops ds1347_rtc_ops = {
+ .read_time = ds1347_read_time,
+ .set_time = ds1347_set_time,
+};
+
+static int ds1347_probe(struct spi_device *spi)
+{
+ struct rtc_device *rtc;
+ unsigned char data;
+ int res;
+
+ /* spi setup with ds1347 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 = ds1347_read_reg(&spi->dev, DS1347_SECONDS_REG, &data);
+ if (res)
+ return res;
+
+ /* Disable the write protect of rtc */
+ ds1347_read_reg(&spi->dev, DS1347_CONTROL_REG, &data);
+ data = data & ~(1<<7);
+ ds1347_write_reg(&spi->dev, DS1347_CONTROL_REG, data);
+
+ /* Enable the oscillator , disable the oscillator stop flag,
+ and glitch filter to reduce current consumption */
+ ds1347_read_reg(&spi->dev, DS1347_STATUS_REG, &data);
+ data = data & 0x1B;
+ ds1347_write_reg(&spi->dev, DS1347_STATUS_REG, data);
+
+ /* display the settings */
+ ds1347_read_reg(&spi->dev, DS1347_CONTROL_REG, &data);
+ dev_info(&spi->dev, "DS1347 RTC CTRL Reg = 0x%02x\n", data);
+
+ ds1347_read_reg(&spi->dev, DS1347_STATUS_REG, &data);
+ dev_info(&spi->dev, "DS1347 RTC Status Reg = 0x%02x\n", data);
+
+ rtc = devm_rtc_device_register(&spi->dev, "ds1347",
+ &ds1347_rtc_ops, THIS_MODULE);
+
+ if (IS_ERR(rtc))
+ return PTR_ERR(rtc);
+
+ spi_set_drvdata(spi, rtc);
+
+ return 0;
+}
+
+static struct spi_driver ds1347_driver = {
+ .driver = {
+ .name = "ds1347",
+ .owner = THIS_MODULE,
+ },
+ .probe = ds1347_probe,
+};
+
+module_spi_driver(ds1347_driver);
+
+MODULE_DESCRIPTION("DS1347 SPI RTC DRIVER");
+MODULE_AUTHOR("Raghavendra C Ganiga <ravi23ganiga@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index e6e71deb188..9e6e14fb53d 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -65,7 +65,7 @@ struct ds1374 {
static struct i2c_driver ds1374_driver;
static int ds1374_read_rtc(struct i2c_client *client, u32 *time,
- int reg, int nbytes)
+ int reg, int nbytes)
{
u8 buf[4];
int ret;
@@ -90,7 +90,7 @@ static int ds1374_read_rtc(struct i2c_client *client, u32 *time,
}
static int ds1374_write_rtc(struct i2c_client *client, u32 time,
- int reg, int nbytes)
+ int reg, int nbytes)
{
u8 buf[4];
int i;
@@ -119,8 +119,7 @@ static int ds1374_check_rtc_status(struct i2c_client *client)
if (stat & DS1374_REG_SR_OSF)
dev_warn(&client->dev,
- "oscillator discontinuity flagged, "
- "time unreliable\n");
+ "oscillator discontinuity flagged, time unreliable\n");
stat &= ~(DS1374_REG_SR_OSF | DS1374_REG_SR_AF);
@@ -347,7 +346,7 @@ static int ds1374_probe(struct i2c_client *client,
struct ds1374 *ds1374;
int ret;
- ds1374 = kzalloc(sizeof(struct ds1374), GFP_KERNEL);
+ ds1374 = devm_kzalloc(&client->dev, sizeof(struct ds1374), GFP_KERNEL);
if (!ds1374)
return -ENOMEM;
@@ -359,39 +358,30 @@ static int ds1374_probe(struct i2c_client *client,
ret = ds1374_check_rtc_status(client);
if (ret)
- goto out_free;
+ return ret;
if (client->irq > 0) {
- ret = request_irq(client->irq, ds1374_irq, 0,
- "ds1374", client);
+ ret = devm_request_irq(&client->dev, client->irq, ds1374_irq, 0,
+ "ds1374", client);
if (ret) {
dev_err(&client->dev, "unable to request IRQ\n");
- goto out_free;
+ return ret;
}
device_set_wakeup_capable(&client->dev, 1);
}
- ds1374->rtc = rtc_device_register(client->name, &client->dev,
- &ds1374_rtc_ops, THIS_MODULE);
+ ds1374->rtc = devm_rtc_device_register(&client->dev, client->name,
+ &ds1374_rtc_ops, THIS_MODULE);
if (IS_ERR(ds1374->rtc)) {
- ret = PTR_ERR(ds1374->rtc);
dev_err(&client->dev, "unable to register the class device\n");
- goto out_irq;
+ return PTR_ERR(ds1374->rtc);
}
return 0;
-
-out_irq:
- if (client->irq > 0)
- free_irq(client->irq, client);
-
-out_free:
- kfree(ds1374);
- return ret;
}
-static int __devexit ds1374_remove(struct i2c_client *client)
+static int ds1374_remove(struct i2c_client *client)
{
struct ds1374 *ds1374 = i2c_get_clientdata(client);
@@ -400,16 +390,14 @@ static int __devexit ds1374_remove(struct i2c_client *client)
ds1374->exiting = 1;
mutex_unlock(&ds1374->mutex);
- free_irq(client->irq, client);
+ devm_free_irq(&client->dev, client->irq, client);
cancel_work_sync(&ds1374->work);
}
- rtc_device_unregister(ds1374->rtc);
- kfree(ds1374);
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int ds1374_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -427,37 +415,22 @@ static int ds1374_resume(struct device *dev)
disable_irq_wake(client->irq);
return 0;
}
+#endif
static SIMPLE_DEV_PM_OPS(ds1374_pm, ds1374_suspend, ds1374_resume);
-#define DS1374_PM (&ds1374_pm)
-#else
-#define DS1374_PM NULL
-#endif
-
static struct i2c_driver ds1374_driver = {
.driver = {
.name = "rtc-ds1374",
.owner = THIS_MODULE,
- .pm = DS1374_PM,
+ .pm = &ds1374_pm,
},
.probe = ds1374_probe,
- .remove = __devexit_p(ds1374_remove),
+ .remove = ds1374_remove,
.id_table = ds1374_id,
};
-static int __init ds1374_init(void)
-{
- return i2c_add_driver(&ds1374_driver);
-}
-
-static void __exit ds1374_exit(void)
-{
- i2c_del_driver(&ds1374_driver);
-}
-
-module_init(ds1374_init);
-module_exit(ds1374_exit);
+module_i2c_driver(ds1374_driver);
MODULE_AUTHOR("Scott Wood <scottwood@freescale.com>");
MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC Driver");
diff --git a/drivers/rtc/rtc-ds1390.c b/drivers/rtc/rtc-ds1390.c
index b038d2cfef2..e67bfcb3a1a 100644
--- a/drivers/rtc/rtc-ds1390.c
+++ b/drivers/rtc/rtc-ds1390.c
@@ -121,7 +121,7 @@ static const struct rtc_class_ops ds1390_rtc_ops = {
.set_time = ds1390_set_time,
};
-static int __devinit ds1390_probe(struct spi_device *spi)
+static int ds1390_probe(struct spi_device *spi)
{
unsigned char tmp;
struct ds1390 *chip;
@@ -131,61 +131,37 @@ static int __devinit ds1390_probe(struct spi_device *spi)
spi->bits_per_word = 8;
spi_setup(spi);
- chip = kzalloc(sizeof *chip, GFP_KERNEL);
- if (!chip) {
- dev_err(&spi->dev, "unable to allocate device memory\n");
+ chip = devm_kzalloc(&spi->dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
return -ENOMEM;
- }
- dev_set_drvdata(&spi->dev, chip);
+
+ spi_set_drvdata(spi, chip);
res = ds1390_get_reg(&spi->dev, DS1390_REG_SECONDS, &tmp);
if (res != 0) {
dev_err(&spi->dev, "unable to read device\n");
- kfree(chip);
return res;
}
- chip->rtc = rtc_device_register("ds1390",
- &spi->dev, &ds1390_rtc_ops, THIS_MODULE);
+ chip->rtc = devm_rtc_device_register(&spi->dev, "ds1390",
+ &ds1390_rtc_ops, THIS_MODULE);
if (IS_ERR(chip->rtc)) {
dev_err(&spi->dev, "unable to register device\n");
res = PTR_ERR(chip->rtc);
- kfree(chip);
}
return res;
}
-static int __devexit ds1390_remove(struct spi_device *spi)
-{
- struct ds1390 *chip = spi_get_drvdata(spi);
-
- rtc_device_unregister(chip->rtc);
- kfree(chip);
-
- return 0;
-}
-
static struct spi_driver ds1390_driver = {
.driver = {
.name = "rtc-ds1390",
.owner = THIS_MODULE,
},
.probe = ds1390_probe,
- .remove = __devexit_p(ds1390_remove),
};
-static __init int ds1390_init(void)
-{
- return spi_register_driver(&ds1390_driver);
-}
-module_init(ds1390_init);
-
-static __exit void ds1390_exit(void)
-{
- spi_unregister_driver(&ds1390_driver);
-}
-module_exit(ds1390_exit);
+module_spi_driver(ds1390_driver);
MODULE_DESCRIPTION("Dallas/Maxim DS1390/93/94 SPI RTC driver");
MODULE_AUTHOR("Mark Jackson <mpfj@mimc.co.uk>");
diff --git a/drivers/rtc/rtc-ds1511.c b/drivers/rtc/rtc-ds1511.c
index 761f36bc83a..b13d1399b81 100644
--- a/drivers/rtc/rtc-ds1511.c
+++ b/drivers/rtc/rtc-ds1511.c
@@ -89,7 +89,6 @@ enum ds1511reg {
struct rtc_plat_data {
struct rtc_device *rtc;
void __iomem *ioaddr; /* virtual base address */
- int size; /* amount of memory mapped */
int irq;
unsigned int irqen;
int alrm_sec;
@@ -104,31 +103,31 @@ static DEFINE_SPINLOCK(ds1511_lock);
static __iomem char *ds1511_base;
static u32 reg_spacing = 1;
- static noinline void
+static noinline void
rtc_write(uint8_t val, uint32_t reg)
{
writeb(val, ds1511_base + (reg * reg_spacing));
}
- static inline void
+static inline void
rtc_write_alarm(uint8_t val, enum ds1511reg reg)
{
rtc_write((val | 0x80), reg);
}
- static noinline uint8_t
+static noinline uint8_t
rtc_read(enum ds1511reg reg)
{
return readb(ds1511_base + (reg * reg_spacing));
}
- static inline void
+static inline void
rtc_disable_update(void)
{
rtc_write((rtc_read(RTC_CMD) & ~RTC_TE), RTC_CMD);
}
- static void
+static void
rtc_enable_update(void)
{
rtc_write((rtc_read(RTC_CMD) | RTC_TE), RTC_CMD);
@@ -145,7 +144,7 @@ rtc_enable_update(void)
* just enough code to set the watchdog timer so that it
* will reboot the system
*/
- void
+void
ds1511_wdog_set(unsigned long deciseconds)
{
/*
@@ -163,7 +162,7 @@ ds1511_wdog_set(unsigned long deciseconds)
rtc_write(DS1511_WDE | DS1511_WDS, RTC_CMD);
}
- void
+void
ds1511_wdog_disable(void)
{
/*
@@ -191,13 +190,12 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
/*
* won't have to change this for a while
*/
- if (rtc_tm->tm_year < 1900) {
+ if (rtc_tm->tm_year < 1900)
rtc_tm->tm_year += 1900;
- }
- if (rtc_tm->tm_year < 1970) {
+ if (rtc_tm->tm_year < 1970)
return -EINVAL;
- }
+
yrs = rtc_tm->tm_year % 100;
cen = rtc_tm->tm_year / 100;
mon = rtc_tm->tm_mon + 1; /* tm_mon starts at zero */
@@ -207,17 +205,14 @@ static int ds1511_rtc_set_time(struct device *dev, struct rtc_time *rtc_tm)
min = rtc_tm->tm_min;
sec = rtc_tm->tm_sec;
- if ((mon > 12) || (day == 0)) {
+ if ((mon > 12) || (day == 0))
return -EINVAL;
- }
- if (day > rtc_month_days(rtc_tm->tm_mon, rtc_tm->tm_year)) {
+ if (day > rtc_month_days(rtc_tm->tm_mon, rtc_tm->tm_year))
return -EINVAL;
- }
- if ((hrs >= 24) || (min >= 60) || (sec >= 60)) {
+ if ((hrs >= 24) || (min >= 60) || (sec >= 60))
return -EINVAL;
- }
/*
* each register is a different number of valid bits
@@ -299,7 +294,7 @@ static int ds1511_rtc_read_time(struct device *dev, struct rtc_time *rtc_tm)
* date/hours/mins/secs matches. the ds1511 has many more
* permutations, but the kernel doesn't.
*/
- static void
+static void
ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
{
unsigned long flags;
@@ -322,7 +317,7 @@ ds1511_rtc_update_alarm(struct rtc_plat_data *pdata)
spin_unlock_irqrestore(&pdata->lock, flags);
}
- static int
+static int
ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -335,14 +330,14 @@ ds1511_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
pdata->alrm_hour = alrm->time.tm_hour;
pdata->alrm_min = alrm->time.tm_min;
pdata->alrm_sec = alrm->time.tm_sec;
- if (alrm->enabled) {
+ if (alrm->enabled)
pdata->irqen |= RTC_AF;
- }
+
ds1511_rtc_update_alarm(pdata);
return 0;
}
- static int
+static int
ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -359,7 +354,7 @@ ds1511_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
return 0;
}
- static irqreturn_t
+static irqreturn_t
ds1511_interrupt(int irq, void *dev_id)
{
struct platform_device *pdev = dev_id;
@@ -376,8 +371,7 @@ ds1511_interrupt(int irq, void *dev_id)
events |= RTC_UF;
else
events |= RTC_AF;
- if (likely(pdata->rtc))
- rtc_update_irq(pdata->rtc, 1, events);
+ rtc_update_irq(pdata->rtc, 1, events);
}
spin_unlock(&pdata->lock);
return events ? IRQ_HANDLED : IRQ_NONE;
@@ -406,7 +400,7 @@ static const struct rtc_class_ops ds1511_rtc_ops = {
.alarm_irq_enable = ds1511_rtc_alarm_irq_enable,
};
- static ssize_t
+static ssize_t
ds1511_nvram_read(struct file *filp, struct kobject *kobj,
struct bin_attribute *ba,
char *buf, loff_t pos, size_t size)
@@ -417,26 +411,26 @@ ds1511_nvram_read(struct file *filp, struct kobject *kobj,
* if count is more than one, turn on "burst" mode
* turn it off when you're done
*/
- if (size > 1) {
+ if (size > 1)
rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD);
- }
- if (pos > DS1511_RAM_MAX) {
+
+ if (pos > DS1511_RAM_MAX)
pos = DS1511_RAM_MAX;
- }
- if (size + pos > DS1511_RAM_MAX + 1) {
+
+ if (size + pos > DS1511_RAM_MAX + 1)
size = DS1511_RAM_MAX - pos + 1;
- }
+
rtc_write(pos, DS1511_RAMADDR_LSB);
- for (count = 0; size > 0; count++, size--) {
+ for (count = 0; size > 0; count++, size--)
*buf++ = rtc_read(DS1511_RAMDATA);
- }
- if (count > 1) {
+
+ if (count > 1)
rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD);
- }
+
return count;
}
- static ssize_t
+static ssize_t
ds1511_nvram_write(struct file *filp, struct kobject *kobj,
struct bin_attribute *bin_attr,
char *buf, loff_t pos, size_t size)
@@ -447,22 +441,22 @@ ds1511_nvram_write(struct file *filp, struct kobject *kobj,
* if count is more than one, turn on "burst" mode
* turn it off when you're done
*/
- if (size > 1) {
+ if (size > 1)
rtc_write((rtc_read(RTC_CMD) | DS1511_BME), RTC_CMD);
- }
- if (pos > DS1511_RAM_MAX) {
+
+ if (pos > DS1511_RAM_MAX)
pos = DS1511_RAM_MAX;
- }
- if (size + pos > DS1511_RAM_MAX + 1) {
+
+ if (size + pos > DS1511_RAM_MAX + 1)
size = DS1511_RAM_MAX - pos + 1;
- }
+
rtc_write(pos, DS1511_RAMADDR_LSB);
- for (count = 0; size > 0; count++, size--) {
+ for (count = 0; size > 0; count++, size--)
rtc_write(*buf++, DS1511_RAMDATA);
- }
- if (count > 1) {
+
+ if (count > 1)
rtc_write((rtc_read(RTC_CMD) & ~DS1511_BME), RTC_CMD);
- }
+
return count;
}
@@ -476,28 +470,20 @@ static struct bin_attribute ds1511_nvram_attr = {
.write = ds1511_nvram_write,
};
- static int __devinit
-ds1511_rtc_probe(struct platform_device *pdev)
+static int ds1511_rtc_probe(struct platform_device *pdev)
{
- struct rtc_device *rtc;
struct resource *res;
struct rtc_plat_data *pdata;
int ret = 0;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- return -ENODEV;
- }
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
- pdata->size = resource_size(res);
- if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size,
- pdev->name))
- return -EBUSY;
- ds1511_base = devm_ioremap(&pdev->dev, res->start, pdata->size);
- if (!ds1511_base)
- return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ds1511_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ds1511_base))
+ return PTR_ERR(ds1511_base);
pdata->ioaddr = ds1511_base;
pdata->irq = platform_get_irq(pdev, 0);
@@ -519,12 +505,17 @@ ds1511_rtc_probe(struct platform_device *pdev)
/*
* check for a dying bat-tree
*/
- if (rtc_read(RTC_CMD1) & DS1511_BLF1) {
+ if (rtc_read(RTC_CMD1) & DS1511_BLF1)
dev_warn(&pdev->dev, "voltage-low detected.\n");
- }
spin_lock_init(&pdata->lock);
platform_set_drvdata(pdev, pdata);
+
+ pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &ds1511_rtc_ops, THIS_MODULE);
+ if (IS_ERR(pdata->rtc))
+ return PTR_ERR(pdata->rtc);
+
/*
* if the platform has an interrupt in mind for this device,
* then by all means, set it
@@ -532,32 +523,26 @@ ds1511_rtc_probe(struct platform_device *pdev)
if (pdata->irq > 0) {
rtc_read(RTC_CMD1);
if (devm_request_irq(&pdev->dev, pdata->irq, ds1511_interrupt,
- IRQF_DISABLED | IRQF_SHARED, pdev->name, pdev) < 0) {
+ IRQF_SHARED, pdev->name, pdev) < 0) {
dev_warn(&pdev->dev, "interrupt not available.\n");
pdata->irq = 0;
}
}
- rtc = rtc_device_register(pdev->name, &pdev->dev, &ds1511_rtc_ops,
- THIS_MODULE);
- if (IS_ERR(rtc))
- return PTR_ERR(rtc);
- pdata->rtc = rtc;
-
ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
if (ret)
- rtc_device_unregister(pdata->rtc);
- return ret;
+ dev_err(&pdev->dev, "Unable to create sysfs entry: %s\n",
+ ds1511_nvram_attr.attr.name);
+
+ return 0;
}
- static int __devexit
-ds1511_rtc_remove(struct platform_device *pdev)
+static int ds1511_rtc_remove(struct platform_device *pdev)
{
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
sysfs_remove_bin_file(&pdev->dev.kobj, &ds1511_nvram_attr);
- rtc_device_unregister(pdata->rtc);
if (pdata->irq > 0) {
/*
* disable the alarm interrupt
@@ -573,7 +558,7 @@ MODULE_ALIAS("platform:ds1511");
static struct platform_driver ds1511_rtc_driver = {
.probe = ds1511_rtc_probe,
- .remove = __devexit_p(ds1511_rtc_remove),
+ .remove = ds1511_rtc_remove,
.driver = {
.name = "ds1511",
.owner = THIS_MODULE,
diff --git a/drivers/rtc/rtc-ds1553.c b/drivers/rtc/rtc-ds1553.c
index 6f0a1b530f2..ab56893aac7 100644
--- a/drivers/rtc/rtc-ds1553.c
+++ b/drivers/rtc/rtc-ds1553.c
@@ -206,8 +206,7 @@ static irqreturn_t ds1553_rtc_interrupt(int irq, void *dev_id)
events |= RTC_UF;
else
events |= RTC_AF;
- if (likely(pdata->rtc))
- rtc_update_irq(pdata->rtc, 1, events);
+ rtc_update_irq(pdata->rtc, 1, events);
}
spin_unlock(&pdata->lock);
return events ? IRQ_HANDLED : IRQ_NONE;
@@ -276,28 +275,22 @@ static struct bin_attribute ds1553_nvram_attr = {
.write = ds1553_nvram_write,
};
-static int __devinit ds1553_rtc_probe(struct platform_device *pdev)
+static int ds1553_rtc_probe(struct platform_device *pdev)
{
- struct rtc_device *rtc;
struct resource *res;
unsigned int cen, sec;
struct rtc_plat_data *pdata;
void __iomem *ioaddr;
int ret = 0;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
- if (!devm_request_mem_region(&pdev->dev, res->start, RTC_REG_SIZE,
- pdev->name))
- return -EBUSY;
- ioaddr = devm_ioremap(&pdev->dev, res->start, RTC_REG_SIZE);
- if (!ioaddr)
- return -ENOMEM;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ioaddr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ioaddr))
+ return PTR_ERR(ioaddr);
pdata->ioaddr = ioaddr;
pdata->irq = platform_get_irq(pdev, 0);
@@ -316,34 +309,35 @@ static int __devinit ds1553_rtc_probe(struct platform_device *pdev)
spin_lock_init(&pdata->lock);
pdata->last_jiffies = jiffies;
platform_set_drvdata(pdev, pdata);
+
+ pdata->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &ds1553_rtc_ops, THIS_MODULE);
+ if (IS_ERR(pdata->rtc))
+ return PTR_ERR(pdata->rtc);
+
if (pdata->irq > 0) {
writeb(0, ioaddr + RTC_INTERRUPTS);
if (devm_request_irq(&pdev->dev, pdata->irq,
ds1553_rtc_interrupt,
- IRQF_DISABLED, pdev->name, pdev) < 0) {
+ 0, pdev->name, pdev) < 0) {
dev_warn(&pdev->dev, "interrupt not available.\n");
pdata->irq = 0;
}
}
- rtc = rtc_device_register(pdev->name, &pdev->dev,
- &ds1553_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc))
- return PTR_ERR(rtc);
- pdata->rtc = rtc;
-
ret = sysfs_create_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
if (ret)
- rtc_device_unregister(rtc);
- return ret;
+ dev_err(&pdev->dev, "unable to create sysfs file: %s\n",
+ ds1553_nvram_attr.attr.name);
+
+ return 0;
}
-static int __devexit ds1553_rtc_remove(struct platform_device *pdev)
+static int ds1553_rtc_remove(struct platform_device *pdev)
{
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
sysfs_remove_bin_file(&pdev->dev.kobj, &ds1553_nvram_attr);
- rtc_device_unregister(pdata->rtc);
if (pdata->irq > 0)
writeb(0, pdata->ioaddr + RTC_INTERRUPTS);
return 0;
@@ -354,7 +348,7 @@ MODULE_ALIAS("platform:rtc-ds1553");
static struct platform_driver ds1553_rtc_driver = {
.probe = ds1553_rtc_probe,
- .remove = __devexit_p(ds1553_rtc_remove),
+ .remove = ds1553_rtc_remove,
.driver = {
.name = "rtc-ds1553",
.owner = THIS_MODULE,
diff --git a/drivers/rtc/rtc-ds1672.c b/drivers/rtc/rtc-ds1672.c
index a319402a544..a4888dbca2e 100644
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -37,8 +37,17 @@ static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
unsigned char buf[4];
struct i2c_msg msgs[] = {
- {client->addr, 0, 1, &addr}, /* setup read ptr */
- {client->addr, I2C_M_RD, 4, buf}, /* read date */
+ {/* setup read ptr */
+ .addr = client->addr,
+ .len = 1,
+ .buf = &addr
+ },
+ {/* read date */
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 4,
+ .buf = buf
+ },
};
/* read date registers */
@@ -99,8 +108,17 @@ static int ds1672_get_control(struct i2c_client *client, u8 *status)
unsigned char addr = DS1672_REG_CONTROL;
struct i2c_msg msgs[] = {
- {client->addr, 0, 1, &addr}, /* setup read ptr */
- {client->addr, I2C_M_RD, 1, status}, /* read control */
+ {/* setup read ptr */
+ .addr = client->addr,
+ .len = 1,
+ .buf = &addr
+ },
+ {/* read control */
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 1,
+ .buf = status
+ },
};
/* read control register */
@@ -135,16 +153,6 @@ static const struct rtc_class_ops ds1672_rtc_ops = {
.set_mmss = ds1672_rtc_set_mmss,
};
-static int ds1672_remove(struct i2c_client *client)
-{
- struct rtc_device *rtc = i2c_get_clientdata(client);
-
- if (rtc)
- rtc_device_unregister(rtc);
-
- return 0;
-}
-
static int ds1672_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -159,7 +167,7 @@ static int ds1672_probe(struct i2c_client *client,
dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
- rtc = rtc_device_register(ds1672_driver.driver.name, &client->dev,
+ rtc = devm_rtc_device_register(&client->dev, ds1672_driver.driver.name,
&ds1672_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
@@ -169,8 +177,9 @@ static int ds1672_probe(struct i2c_client *client,
/* read control register */
err = ds1672_get_control(client, &control);
- if (err)
- goto exit_devreg;
+ if (err) {
+ dev_warn(&client->dev, "Unable to read the control register\n");
+ }
if (control & DS1672_REG_CONTROL_EOSC)
dev_warn(&client->dev, "Oscillator not enabled. "
@@ -179,13 +188,10 @@ static int ds1672_probe(struct i2c_client *client,
/* Register sysfs hooks */
err = device_create_file(&client->dev, &dev_attr_control);
if (err)
- goto exit_devreg;
+ dev_err(&client->dev, "Unable to create sysfs entry: %s\n",
+ dev_attr_control.attr.name);
return 0;
-
- exit_devreg:
- rtc_device_unregister(rtc);
- return err;
}
static struct i2c_device_id ds1672_id[] = {
@@ -198,24 +204,12 @@ static struct i2c_driver ds1672_driver = {
.name = "rtc-ds1672",
},
.probe = &ds1672_probe,
- .remove = &ds1672_remove,
.id_table = ds1672_id,
};
-static int __init ds1672_init(void)
-{
- return i2c_add_driver(&ds1672_driver);
-}
-
-static void __exit ds1672_exit(void)
-{
- i2c_del_driver(&ds1672_driver);
-}
+module_i2c_driver(ds1672_driver);
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
MODULE_DESCRIPTION("Dallas/Maxim DS1672 timekeeper driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
-
-module_init(ds1672_init);
-module_exit(ds1672_exit);
diff --git a/drivers/rtc/rtc-ds1742.c b/drivers/rtc/rtc-ds1742.c
index 76112667c50..c6b2191a412 100644
--- a/drivers/rtc/rtc-ds1742.c
+++ b/drivers/rtc/rtc-ds1742.c
@@ -13,12 +13,13 @@
*/
#include <linux/bcd.h>
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/jiffies.h>
#include <linux/rtc.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/module.h>
@@ -52,11 +53,9 @@
#define RTC_BATT_FLAG 0x80
struct rtc_plat_data {
- struct rtc_device *rtc;
void __iomem *ioaddr_nvram;
void __iomem *ioaddr_rtc;
size_t size_nvram;
- size_t size;
unsigned long last_jiffies;
struct bin_attribute nvram_attr;
};
@@ -117,11 +116,7 @@ static int ds1742_rtc_read_time(struct device *dev, struct rtc_time *tm)
/* year is 1900 + tm->tm_year */
tm->tm_year = bcd2bin(year) + bcd2bin(century) * 100 - 1900;
- if (rtc_valid_tm(tm) < 0) {
- dev_err(dev, "retrieved date/time is not valid.\n");
- rtc_time_to_tm(0, tm);
- }
- return 0;
+ return rtc_valid_tm(tm);
}
static const struct rtc_class_ops ds1742_rtc_ops = {
@@ -159,7 +154,7 @@ static ssize_t ds1742_nvram_write(struct file *filp, struct kobject *kobj,
return count;
}
-static int __devinit ds1742_rtc_probe(struct platform_device *pdev)
+static int ds1742_rtc_probe(struct platform_device *pdev)
{
struct rtc_device *rtc;
struct resource *res;
@@ -168,22 +163,17 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev)
void __iomem *ioaddr;
int ret = 0;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENODEV;
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return -ENOMEM;
- pdata->size = resource_size(res);
- if (!devm_request_mem_region(&pdev->dev, res->start, pdata->size,
- pdev->name))
- return -EBUSY;
- ioaddr = devm_ioremap(&pdev->dev, res->start, pdata->size);
- if (!ioaddr)
- return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ioaddr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ioaddr))
+ return PTR_ERR(ioaddr);
pdata->ioaddr_nvram = ioaddr;
- pdata->size_nvram = pdata->size - RTC_SIZE;
+ pdata->size_nvram = resource_size(res) - RTC_SIZE;
pdata->ioaddr_rtc = ioaddr + pdata->size_nvram;
sysfs_bin_attr_init(&pdata->nvram_attr);
@@ -208,35 +198,40 @@ static int __devinit ds1742_rtc_probe(struct platform_device *pdev)
pdata->last_jiffies = jiffies;
platform_set_drvdata(pdev, pdata);
- rtc = rtc_device_register(pdev->name, &pdev->dev,
+ rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
&ds1742_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
- pdata->rtc = rtc;
ret = sysfs_create_bin_file(&pdev->dev.kobj, &pdata->nvram_attr);
- if (ret) {
- dev_err(&pdev->dev, "creating nvram file in sysfs failed\n");
- rtc_device_unregister(rtc);
- }
- return ret;
+ if (ret)
+ dev_err(&pdev->dev, "Unable to create sysfs entry: %s\n",
+ pdata->nvram_attr.attr.name);
+
+ return 0;
}
-static int __devexit ds1742_rtc_remove(struct platform_device *pdev)
+static int ds1742_rtc_remove(struct platform_device *pdev)
{
struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
sysfs_remove_bin_file(&pdev->dev.kobj, &pdata->nvram_attr);
- rtc_device_unregister(pdata->rtc);
return 0;
}
+static const struct of_device_id __maybe_unused ds1742_rtc_of_match[] = {
+ { .compatible = "maxim,ds1742", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ds1742_rtc_of_match);
+
static struct platform_driver ds1742_rtc_driver = {
.probe = ds1742_rtc_probe,
- .remove = __devexit_p(ds1742_rtc_remove),
+ .remove = ds1742_rtc_remove,
.driver = {
.name = "rtc-ds1742",
.owner = THIS_MODULE,
+ .of_match_table = ds1742_rtc_of_match,
},
};
diff --git a/drivers/rtc/rtc-ds2404.c b/drivers/rtc/rtc-ds2404.c
new file mode 100644
index 00000000000..fc209dc4e24
--- /dev/null
+++ b/drivers/rtc/rtc-ds2404.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2012 Sven Schnelle <svens@stackframe.org>
+ *
+ * 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/platform_device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/rtc.h>
+#include <linux/types.h>
+#include <linux/bcd.h>
+#include <linux/rtc-ds2404.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+
+#include <linux/io.h>
+
+#define DS2404_STATUS_REG 0x200
+#define DS2404_CONTROL_REG 0x201
+#define DS2404_RTC_REG 0x202
+
+#define DS2404_WRITE_SCRATCHPAD_CMD 0x0f
+#define DS2404_READ_SCRATCHPAD_CMD 0xaa
+#define DS2404_COPY_SCRATCHPAD_CMD 0x55
+#define DS2404_READ_MEMORY_CMD 0xf0
+
+struct ds2404;
+
+struct ds2404_chip_ops {
+ int (*map_io)(struct ds2404 *chip, struct platform_device *pdev,
+ struct ds2404_platform_data *pdata);
+ void (*unmap_io)(struct ds2404 *chip);
+};
+
+#define DS2404_RST 0
+#define DS2404_CLK 1
+#define DS2404_DQ 2
+
+struct ds2404_gpio {
+ const char *name;
+ unsigned int gpio;
+};
+
+struct ds2404 {
+ struct ds2404_gpio *gpio;
+ struct ds2404_chip_ops *ops;
+ struct rtc_device *rtc;
+};
+
+static struct ds2404_gpio ds2404_gpio[] = {
+ { "RTC RST", 0 },
+ { "RTC CLK", 0 },
+ { "RTC DQ", 0 },
+};
+
+static int ds2404_gpio_map(struct ds2404 *chip, struct platform_device *pdev,
+ struct ds2404_platform_data *pdata)
+{
+ int i, err;
+
+ ds2404_gpio[DS2404_RST].gpio = pdata->gpio_rst;
+ ds2404_gpio[DS2404_CLK].gpio = pdata->gpio_clk;
+ ds2404_gpio[DS2404_DQ].gpio = pdata->gpio_dq;
+
+ for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++) {
+ err = gpio_request(ds2404_gpio[i].gpio, ds2404_gpio[i].name);
+ if (err) {
+ dev_err(&pdev->dev, "error mapping gpio %s: %d\n",
+ ds2404_gpio[i].name, err);
+ goto err_request;
+ }
+ if (i != DS2404_DQ)
+ gpio_direction_output(ds2404_gpio[i].gpio, 1);
+ }
+
+ chip->gpio = ds2404_gpio;
+ return 0;
+
+err_request:
+ while (--i >= 0)
+ gpio_free(ds2404_gpio[i].gpio);
+ return err;
+}
+
+static void ds2404_gpio_unmap(struct ds2404 *chip)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ds2404_gpio); i++)
+ gpio_free(ds2404_gpio[i].gpio);
+}
+
+static struct ds2404_chip_ops ds2404_gpio_ops = {
+ .map_io = ds2404_gpio_map,
+ .unmap_io = ds2404_gpio_unmap,
+};
+
+static void ds2404_reset(struct device *dev)
+{
+ gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 0);
+ udelay(1000);
+ gpio_set_value(ds2404_gpio[DS2404_RST].gpio, 1);
+ gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0);
+ gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 0);
+ udelay(10);
+}
+
+static void ds2404_write_byte(struct device *dev, u8 byte)
+{
+ int i;
+
+ gpio_direction_output(ds2404_gpio[DS2404_DQ].gpio, 1);
+ for (i = 0; i < 8; i++) {
+ gpio_set_value(ds2404_gpio[DS2404_DQ].gpio, byte & (1 << i));
+ udelay(10);
+ gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1);
+ udelay(10);
+ gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0);
+ udelay(10);
+ }
+}
+
+static u8 ds2404_read_byte(struct device *dev)
+{
+ int i;
+ u8 ret = 0;
+
+ gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio);
+
+ for (i = 0; i < 8; i++) {
+ gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 0);
+ udelay(10);
+ if (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio))
+ ret |= 1 << i;
+ gpio_set_value(ds2404_gpio[DS2404_CLK].gpio, 1);
+ udelay(10);
+ }
+ return ret;
+}
+
+static void ds2404_read_memory(struct device *dev, u16 offset,
+ int length, u8 *out)
+{
+ ds2404_reset(dev);
+ ds2404_write_byte(dev, DS2404_READ_MEMORY_CMD);
+ ds2404_write_byte(dev, offset & 0xff);
+ ds2404_write_byte(dev, (offset >> 8) & 0xff);
+ while (length--)
+ *out++ = ds2404_read_byte(dev);
+}
+
+static void ds2404_write_memory(struct device *dev, u16 offset,
+ int length, u8 *out)
+{
+ int i;
+ u8 ta01, ta02, es;
+
+ ds2404_reset(dev);
+ ds2404_write_byte(dev, DS2404_WRITE_SCRATCHPAD_CMD);
+ ds2404_write_byte(dev, offset & 0xff);
+ ds2404_write_byte(dev, (offset >> 8) & 0xff);
+
+ for (i = 0; i < length; i++)
+ ds2404_write_byte(dev, out[i]);
+
+ ds2404_reset(dev);
+ ds2404_write_byte(dev, DS2404_READ_SCRATCHPAD_CMD);
+
+ ta01 = ds2404_read_byte(dev);
+ ta02 = ds2404_read_byte(dev);
+ es = ds2404_read_byte(dev);
+
+ for (i = 0; i < length; i++) {
+ if (out[i] != ds2404_read_byte(dev)) {
+ dev_err(dev, "read invalid data\n");
+ return;
+ }
+ }
+
+ ds2404_reset(dev);
+ ds2404_write_byte(dev, DS2404_COPY_SCRATCHPAD_CMD);
+ ds2404_write_byte(dev, ta01);
+ ds2404_write_byte(dev, ta02);
+ ds2404_write_byte(dev, es);
+
+ gpio_direction_input(ds2404_gpio[DS2404_DQ].gpio);
+ while (gpio_get_value(ds2404_gpio[DS2404_DQ].gpio))
+ ;
+}
+
+static void ds2404_enable_osc(struct device *dev)
+{
+ u8 in[1] = { 0x10 }; /* enable oscillator */
+ ds2404_write_memory(dev, 0x201, 1, in);
+}
+
+static int ds2404_read_time(struct device *dev, struct rtc_time *dt)
+{
+ unsigned long time = 0;
+
+ ds2404_read_memory(dev, 0x203, 4, (u8 *)&time);
+ time = le32_to_cpu(time);
+
+ rtc_time_to_tm(time, dt);
+ return rtc_valid_tm(dt);
+}
+
+static int ds2404_set_mmss(struct device *dev, unsigned long secs)
+{
+ u32 time = cpu_to_le32(secs);
+ ds2404_write_memory(dev, 0x203, 4, (u8 *)&time);
+ return 0;
+}
+
+static const struct rtc_class_ops ds2404_rtc_ops = {
+ .read_time = ds2404_read_time,
+ .set_mmss = ds2404_set_mmss,
+};
+
+static int rtc_probe(struct platform_device *pdev)
+{
+ struct ds2404_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ struct ds2404 *chip;
+ int retval = -EBUSY;
+
+ chip = devm_kzalloc(&pdev->dev, sizeof(struct ds2404), GFP_KERNEL);
+ if (!chip)
+ return -ENOMEM;
+
+ chip->ops = &ds2404_gpio_ops;
+
+ retval = chip->ops->map_io(chip, pdev, pdata);
+ if (retval)
+ goto err_chip;
+
+ dev_info(&pdev->dev, "using GPIOs RST:%d, CLK:%d, DQ:%d\n",
+ chip->gpio[DS2404_RST].gpio, chip->gpio[DS2404_CLK].gpio,
+ chip->gpio[DS2404_DQ].gpio);
+
+ platform_set_drvdata(pdev, chip);
+
+ chip->rtc = devm_rtc_device_register(&pdev->dev, "ds2404",
+ &ds2404_rtc_ops, THIS_MODULE);
+ if (IS_ERR(chip->rtc)) {
+ retval = PTR_ERR(chip->rtc);
+ goto err_io;
+ }
+
+ ds2404_enable_osc(&pdev->dev);
+ return 0;
+
+err_io:
+ chip->ops->unmap_io(chip);
+err_chip:
+ return retval;
+}
+
+static int rtc_remove(struct platform_device *dev)
+{
+ struct ds2404 *chip = platform_get_drvdata(dev);
+
+ chip->ops->unmap_io(chip);
+
+ return 0;
+}
+
+static struct platform_driver rtc_device_driver = {
+ .probe = rtc_probe,
+ .remove = rtc_remove,
+ .driver = {
+ .name = "ds2404",
+ .owner = THIS_MODULE,
+ },
+};
+module_platform_driver(rtc_device_driver);
+
+MODULE_DESCRIPTION("DS2404 RTC");
+MODULE_AUTHOR("Sven Schnelle");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:ds2404");
diff --git a/drivers/rtc/rtc-ds3232.c b/drivers/rtc/rtc-ds3232.c
index 27b7bf672ac..adaf06c4147 100644
--- a/drivers/rtc/rtc-ds3232.c
+++ b/drivers/rtc/rtc-ds3232.c
@@ -57,6 +57,7 @@ struct ds3232 {
* in the remove function.
*/
struct mutex mutex;
+ bool suspended;
int exiting;
};
@@ -345,7 +346,15 @@ static irqreturn_t ds3232_irq(int irq, void *dev_id)
struct ds3232 *ds3232 = i2c_get_clientdata(client);
disable_irq_nosync(irq);
- schedule_work(&ds3232->work);
+
+ /*
+ * If rtc as a wakeup source, can't schedule the work
+ * at system resume flow, because at this time the i2c bus
+ * has not been resumed.
+ */
+ if (!ds3232->suspended)
+ schedule_work(&ds3232->work);
+
return IRQ_HANDLED;
}
@@ -363,22 +372,26 @@ static void ds3232_work(struct work_struct *work)
if (stat & DS3232_REG_SR_A1F) {
control = i2c_smbus_read_byte_data(client, DS3232_REG_CR);
- if (control < 0)
- goto out;
- /* disable alarm1 interrupt */
- control &= ~(DS3232_REG_CR_A1IE);
- i2c_smbus_write_byte_data(client, DS3232_REG_CR, control);
-
- /* clear the alarm pend flag */
- stat &= ~DS3232_REG_SR_A1F;
- i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
-
- rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
+ if (control < 0) {
+ pr_warn("Read DS3232 Control Register error."
+ "Disable IRQ%d.\n", client->irq);
+ } else {
+ /* disable alarm1 interrupt */
+ control &= ~(DS3232_REG_CR_A1IE);
+ i2c_smbus_write_byte_data(client, DS3232_REG_CR,
+ control);
+
+ /* clear the alarm pend flag */
+ stat &= ~DS3232_REG_SR_A1F;
+ i2c_smbus_write_byte_data(client, DS3232_REG_SR, stat);
+
+ rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
+
+ if (!ds3232->exiting)
+ enable_irq(client->irq);
+ }
}
-out:
- if (!ds3232->exiting)
- enable_irq(client->irq);
unlock:
mutex_unlock(&ds3232->mutex);
}
@@ -391,13 +404,13 @@ static const struct rtc_class_ops ds3232_rtc_ops = {
.alarm_irq_enable = ds3232_alarm_irq_enable,
};
-static int __devinit ds3232_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int ds3232_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct ds3232 *ds3232;
int ret;
- ds3232 = kzalloc(sizeof(struct ds3232), GFP_KERNEL);
+ ds3232 = devm_kzalloc(&client->dev, sizeof(struct ds3232), GFP_KERNEL);
if (!ds3232)
return -ENOMEM;
@@ -409,37 +422,22 @@ static int __devinit ds3232_probe(struct i2c_client *client,
ret = ds3232_check_rtc_status(client);
if (ret)
- goto out_free;
-
- ds3232->rtc = rtc_device_register(client->name, &client->dev,
- &ds3232_rtc_ops, THIS_MODULE);
- if (IS_ERR(ds3232->rtc)) {
- ret = PTR_ERR(ds3232->rtc);
- dev_err(&client->dev, "unable to register the class device\n");
- goto out_irq;
- }
+ return ret;
- if (client->irq >= 0) {
- ret = request_irq(client->irq, ds3232_irq, 0,
- "ds3232", client);
+ if (client->irq > 0) {
+ ret = devm_request_irq(&client->dev, client->irq, ds3232_irq,
+ IRQF_SHARED, "ds3232", client);
if (ret) {
dev_err(&client->dev, "unable to request IRQ\n");
- goto out_free;
}
+ device_init_wakeup(&client->dev, 1);
}
-
- return 0;
-
-out_irq:
- if (client->irq >= 0)
- free_irq(client->irq, client);
-
-out_free:
- kfree(ds3232);
- return ret;
+ ds3232->rtc = devm_rtc_device_register(&client->dev, client->name,
+ &ds3232_rtc_ops, THIS_MODULE);
+ return PTR_ERR_OR_ZERO(ds3232->rtc);
}
-static int __devexit ds3232_remove(struct i2c_client *client)
+static int ds3232_remove(struct i2c_client *client)
{
struct ds3232 *ds3232 = i2c_get_clientdata(client);
@@ -448,15 +446,49 @@ static int __devexit ds3232_remove(struct i2c_client *client)
ds3232->exiting = 1;
mutex_unlock(&ds3232->mutex);
- free_irq(client->irq, client);
+ devm_free_irq(&client->dev, client->irq, client);
cancel_work_sync(&ds3232->work);
}
- rtc_device_unregister(ds3232->rtc);
- kfree(ds3232);
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int ds3232_suspend(struct device *dev)
+{
+ struct ds3232 *ds3232 = dev_get_drvdata(dev);
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (device_can_wakeup(dev)) {
+ ds3232->suspended = true;
+ irq_set_irq_wake(client->irq, 1);
+ }
+
+ return 0;
+}
+
+static int ds3232_resume(struct device *dev)
+{
+ struct ds3232 *ds3232 = dev_get_drvdata(dev);
+ struct i2c_client *client = to_i2c_client(dev);
+
+ if (ds3232->suspended) {
+ ds3232->suspended = false;
+
+ /* Clear the hardware alarm pend flag */
+ schedule_work(&ds3232->work);
+
+ irq_set_irq_wake(client->irq, 0);
+ }
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops ds3232_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume)
+};
+
static const struct i2c_device_id ds3232_id[] = {
{ "ds3232", 0 },
{ }
@@ -467,24 +499,14 @@ static struct i2c_driver ds3232_driver = {
.driver = {
.name = "rtc-ds3232",
.owner = THIS_MODULE,
+ .pm = &ds3232_pm_ops,
},
.probe = ds3232_probe,
- .remove = __devexit_p(ds3232_remove),
+ .remove = ds3232_remove,
.id_table = ds3232_id,
};
-static int __init ds3232_init(void)
-{
- return i2c_add_driver(&ds3232_driver);
-}
-
-static void __exit ds3232_exit(void)
-{
- i2c_del_driver(&ds3232_driver);
-}
-
-module_init(ds3232_init);
-module_exit(ds3232_exit);
+module_i2c_driver(ds3232_driver);
MODULE_AUTHOR("Srikanth Srinivasan <srikanth.srinivasan@freescale.com>");
MODULE_DESCRIPTION("Maxim/Dallas DS3232 RTC Driver");
diff --git a/drivers/rtc/rtc-ds3234.c b/drivers/rtc/rtc-ds3234.c
index bbd26228f53..4c9ba536846 100644
--- a/drivers/rtc/rtc-ds3234.c
+++ b/drivers/rtc/rtc-ds3234.c
@@ -73,7 +73,7 @@ static int ds3234_read_time(struct device *dev, struct rtc_time *dt)
dt->tm_wday = bcd2bin(buf[3]) - 1; /* 0 = Sun */
dt->tm_mday = bcd2bin(buf[4]);
dt->tm_mon = bcd2bin(buf[5] & 0x1f) - 1; /* 0 = Jan */
- dt->tm_year = bcd2bin(buf[6] & 0xff) + 100; /* Assume 20YY */
+ dt->tm_year = bcd2bin(buf[6] & 0xff) + 100; /* Assume 20YY */
return rtc_valid_tm(dt);
}
@@ -105,7 +105,7 @@ static const struct rtc_class_ops ds3234_rtc_ops = {
.set_time = ds3234_set_time,
};
-static int __devinit ds3234_probe(struct spi_device *spi)
+static int ds3234_probe(struct spi_device *spi)
{
struct rtc_device *rtc;
unsigned char tmp;
@@ -146,44 +146,25 @@ static int __devinit ds3234_probe(struct spi_device *spi)
ds3234_get_reg(&spi->dev, DS3234_REG_CONT_STAT, &tmp);
dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x\n", tmp);
- rtc = rtc_device_register("ds3234",
- &spi->dev, &ds3234_rtc_ops, THIS_MODULE);
+ rtc = devm_rtc_device_register(&spi->dev, "ds3234",
+ &ds3234_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
- dev_set_drvdata(&spi->dev, rtc);
+ spi_set_drvdata(spi, rtc);
return 0;
}
-static int __devexit ds3234_remove(struct spi_device *spi)
-{
- struct rtc_device *rtc = spi_get_drvdata(spi);
-
- rtc_device_unregister(rtc);
- return 0;
-}
-
static struct spi_driver ds3234_driver = {
.driver = {
.name = "ds3234",
.owner = THIS_MODULE,
},
.probe = ds3234_probe,
- .remove = __devexit_p(ds3234_remove),
};
-static __init int ds3234_init(void)
-{
- return spi_register_driver(&ds3234_driver);
-}
-module_init(ds3234_init);
-
-static __exit void ds3234_exit(void)
-{
- spi_unregister_driver(&ds3234_driver);
-}
-module_exit(ds3234_exit);
+module_spi_driver(ds3234_driver);
MODULE_DESCRIPTION("DS3234 SPI RTC driver");
MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>");
diff --git a/drivers/rtc/rtc-efi.c b/drivers/rtc/rtc-efi.c
index 550292304b0..c4c38431012 100644
--- a/drivers/rtc/rtc-efi.c
+++ b/drivers/rtc/rtc-efi.c
@@ -13,6 +13,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/time.h>
@@ -33,7 +35,7 @@ static inline int
compute_yday(efi_time_t *eft)
{
/* efi_time_t.month is in the [1-12] so, we need -1 */
- return rtc_year_days(eft->day - 1, eft->month - 1, eft->year);
+ return rtc_year_days(eft->day, eft->month - 1, eft->year);
}
/*
* returns day of the week [0-6] 0=Sunday
@@ -47,7 +49,7 @@ compute_wday(efi_time_t *eft)
int ndays = 0;
if (eft->year < 1998) {
- printk(KERN_ERR "efirtc: EFI year < 1998, invalid date\n");
+ pr_err("EFI year < 1998, invalid date\n");
return -1;
}
@@ -70,7 +72,7 @@ convert_to_efi_time(struct rtc_time *wtime, efi_time_t *eft)
eft->day = wtime->tm_mday;
eft->hour = wtime->tm_hour;
eft->minute = wtime->tm_min;
- eft->second = wtime->tm_sec;
+ eft->second = wtime->tm_sec;
eft->nanosecond = 0;
eft->daylight = wtime->tm_isdst ? EFI_ISDST : 0;
eft->timezone = EFI_UNSPECIFIED_TIMEZONE;
@@ -142,7 +144,7 @@ static int efi_set_alarm(struct device *dev, struct rtc_wkalrm *wkalrm)
*/
status = efi.set_wakeup_time((efi_bool_t)wkalrm->enabled, &eft);
- printk(KERN_WARNING "write status is %d\n", (int)status);
+ dev_warn(dev, "write status is %d\n", (int)status);
return status == EFI_SUCCESS ? 0 : -EINVAL;
}
@@ -157,7 +159,7 @@ static int efi_read_time(struct device *dev, struct rtc_time *tm)
if (status != EFI_SUCCESS) {
/* should never happen */
- printk(KERN_ERR "efitime: can't read time\n");
+ dev_err(dev, "can't read time\n");
return -EINVAL;
}
@@ -189,7 +191,7 @@ static int __init efi_rtc_probe(struct platform_device *dev)
{
struct rtc_device *rtc;
- rtc = rtc_device_register("rtc-efi", &dev->dev, &efi_rtc_ops,
+ rtc = devm_rtc_device_register(&dev->dev, "rtc-efi", &efi_rtc_ops,
THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -199,36 +201,14 @@ static int __init efi_rtc_probe(struct platform_device *dev)
return 0;
}
-static int __exit efi_rtc_remove(struct platform_device *dev)
-{
- struct rtc_device *rtc = platform_get_drvdata(dev);
-
- rtc_device_unregister(rtc);
-
- return 0;
-}
-
static struct platform_driver efi_rtc_driver = {
.driver = {
.name = "rtc-efi",
.owner = THIS_MODULE,
},
- .probe = efi_rtc_probe,
- .remove = __exit_p(efi_rtc_remove),
};
-static int __init efi_rtc_init(void)
-{
- return platform_driver_probe(&efi_rtc_driver, efi_rtc_probe);
-}
-
-static void __exit efi_rtc_exit(void)
-{
- platform_driver_unregister(&efi_rtc_driver);
-}
-
-module_init(efi_rtc_init);
-module_exit(efi_rtc_exit);
+module_platform_driver_probe(efi_rtc_driver, efi_rtc_probe);
MODULE_AUTHOR("dann frazier <dannf@hp.com>");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-em3027.c b/drivers/rtc/rtc-em3027.c
index 8414dea5fb1..fccf3669924 100644
--- a/drivers/rtc/rtc-em3027.c
+++ b/drivers/rtc/rtc-em3027.c
@@ -49,8 +49,17 @@ static int em3027_get_time(struct device *dev, struct rtc_time *tm)
unsigned char buf[7];
struct i2c_msg msgs[] = {
- {client->addr, 0, 1, &addr}, /* setup read addr */
- {client->addr, I2C_M_RD, 7, buf}, /* read time/date */
+ {/* setup read addr */
+ .addr = client->addr,
+ .len = 1,
+ .buf = &addr
+ },
+ {/* read time/date */
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 7,
+ .buf = buf
+ },
};
/* read time/date registers */
@@ -76,7 +85,9 @@ static int em3027_set_time(struct device *dev, struct rtc_time *tm)
unsigned char buf[8];
struct i2c_msg msg = {
- client->addr, 0, 8, buf, /* write time/date */
+ .addr = client->addr,
+ .len = 8,
+ .buf = buf, /* write time/date */
};
buf[0] = EM3027_REG_WATCH_SEC;
@@ -110,7 +121,7 @@ static int em3027_probe(struct i2c_client *client,
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
- rtc = rtc_device_register(em3027_driver.driver.name, &client->dev,
+ rtc = devm_rtc_device_register(&client->dev, em3027_driver.driver.name,
&em3027_rtc_ops, THIS_MODULE);
if (IS_ERR(rtc))
return PTR_ERR(rtc);
@@ -120,16 +131,6 @@ static int em3027_probe(struct i2c_client *client,
return 0;
}
-static int em3027_remove(struct i2c_client *client)
-{
- struct rtc_device *rtc = i2c_get_clientdata(client);
-
- if (rtc)
- rtc_device_unregister(rtc);
-
- return 0;
-}
-
static struct i2c_device_id em3027_id[] = {
{ "em3027", 0 },
{ }
@@ -140,23 +141,11 @@ static struct i2c_driver em3027_driver = {
.name = "rtc-em3027",
},
.probe = &em3027_probe,
- .remove = &em3027_remove,
.id_table = em3027_id,
};
-static int __init em3027_init(void)
-{
- return i2c_add_driver(&em3027_driver);
-}
-
-static void __exit em3027_exit(void)
-{
- i2c_del_driver(&em3027_driver);
-}
+module_i2c_driver(em3027_driver);
MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
MODULE_DESCRIPTION("EM Microelectronic EM3027 RTC driver");
MODULE_LICENSE("GPL");
-
-module_init(em3027_init);
-module_exit(em3027_exit);
diff --git a/drivers/rtc/rtc-ep93xx.c b/drivers/rtc/rtc-ep93xx.c
index 14a42a1edc6..5e4f5dc40ba 100644
--- a/drivers/rtc/rtc-ep93xx.c
+++ b/drivers/rtc/rtc-ep93xx.c
@@ -42,7 +42,7 @@ struct ep93xx_rtc {
static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,
unsigned short *delete)
{
- struct ep93xx_rtc *ep93xx_rtc = dev->platform_data;
+ struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);
unsigned long comp;
comp = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_SWCOMP);
@@ -60,7 +60,7 @@ static int ep93xx_rtc_get_swcomp(struct device *dev, unsigned short *preload,
static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
- struct ep93xx_rtc *ep93xx_rtc = dev->platform_data;
+ struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);
unsigned long time;
time = __raw_readl(ep93xx_rtc->mmio_base + EP93XX_RTC_DATA);
@@ -71,7 +71,7 @@ static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)
static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs)
{
- struct ep93xx_rtc *ep93xx_rtc = dev->platform_data;
+ struct ep93xx_rtc *ep93xx_rtc = dev_get_platdata(dev);
__raw_writel(secs + 1, ep93xx_rtc->mmio_base + EP93XX_RTC_LOAD);
return 0;
@@ -127,7 +127,7 @@ static const struct attribute_group ep93xx_rtc_sysfs_files = {
.attrs = ep93xx_rtc_attrs,
};
-static int __init ep93xx_rtc_probe(struct platform_device *pdev)
+static int ep93xx_rtc_probe(struct platform_device *pdev)
{
struct ep93xx_rtc *ep93xx_rtc;
struct resource *res;
@@ -138,23 +138,15 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENXIO;
-
- if (!devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), pdev->name))
- return -EBUSY;
-
- ep93xx_rtc->mmio_base = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!ep93xx_rtc->mmio_base)
- return -ENXIO;
+ ep93xx_rtc->mmio_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ep93xx_rtc->mmio_base))
+ return PTR_ERR(ep93xx_rtc->mmio_base);
pdev->dev.platform_data = ep93xx_rtc;
platform_set_drvdata(pdev, ep93xx_rtc);
- ep93xx_rtc->rtc = rtc_device_register(pdev->name,
- &pdev->dev, &ep93xx_rtc_ops, THIS_MODULE);
+ ep93xx_rtc->rtc = devm_rtc_device_register(&pdev->dev,
+ pdev->name, &ep93xx_rtc_ops, THIS_MODULE);
if (IS_ERR(ep93xx_rtc->rtc)) {
err = PTR_ERR(ep93xx_rtc->rtc);
goto exit;
@@ -162,55 +154,36 @@ static int __init ep93xx_rtc_probe(struct platform_device *pdev)
err = sysfs_create_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
if (err)
- goto fail;
+ goto exit;
return 0;
-fail:
- rtc_device_unregister(ep93xx_rtc->rtc);
exit:
- platform_set_drvdata(pdev, NULL);
pdev->dev.platform_data = NULL;
return err;
}
-static int __exit ep93xx_rtc_remove(struct platform_device *pdev)
+static int ep93xx_rtc_remove(struct platform_device *pdev)
{
- struct ep93xx_rtc *ep93xx_rtc = platform_get_drvdata(pdev);
-
sysfs_remove_group(&pdev->dev.kobj, &ep93xx_rtc_sysfs_files);
- platform_set_drvdata(pdev, NULL);
- rtc_device_unregister(ep93xx_rtc->rtc);
pdev->dev.platform_data = NULL;
return 0;
}
-/* work with hotplug and coldplug */
-MODULE_ALIAS("platform:ep93xx-rtc");
-
static struct platform_driver ep93xx_rtc_driver = {
.driver = {
.name = "ep93xx-rtc",
.owner = THIS_MODULE,
},
- .remove = __exit_p(ep93xx_rtc_remove),
+ .probe = ep93xx_rtc_probe,
+ .remove = ep93xx_rtc_remove,
};
-static int __init ep93xx_rtc_init(void)
-{
- return platform_driver_probe(&ep93xx_rtc_driver, ep93xx_rtc_probe);
-}
-
-static void __exit ep93xx_rtc_exit(void)
-{
- platform_driver_unregister(&ep93xx_rtc_driver);
-}
+module_platform_driver(ep93xx_rtc_driver);
MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
MODULE_DESCRIPTION("EP93XX RTC driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(DRV_VERSION);
-
-module_init(ep93xx_rtc_init);
-module_exit(ep93xx_rtc_exit);
+MODULE_ALIAS("platform:ep93xx-rtc");
diff --git a/drivers/rtc/rtc-fm3130.c b/drivers/rtc/rtc-fm3130.c
index 4cf2e70c507..83c3b3029fa 100644
--- a/drivers/rtc/rtc-fm3130.c
+++ b/drivers/rtc/rtc-fm3130.c
@@ -47,7 +47,7 @@
struct fm3130 {
u8 reg_addr_time;
- u8 reg_addr_alarm;
+ u8 reg_addr_alarm;
u8 regs[15];
struct i2c_msg msg[4];
struct i2c_client *client;
@@ -116,17 +116,7 @@ static int fm3130_get_time(struct device *dev, struct rtc_time *t)
fm3130_rtc_mode(dev, FM3130_MODE_NORMAL);
- dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x %02x"
- "%02x %02x %02x %02x %02x %02x %02x\n",
- "read",
- fm3130->regs[0], fm3130->regs[1],
- fm3130->regs[2], fm3130->regs[3],
- fm3130->regs[4], fm3130->regs[5],
- fm3130->regs[6], fm3130->regs[7],
- fm3130->regs[8], fm3130->regs[9],
- fm3130->regs[0xa], fm3130->regs[0xb],
- fm3130->regs[0xc], fm3130->regs[0xd],
- fm3130->regs[0xe]);
+ dev_dbg(dev, "%s: %15ph\n", "read", fm3130->regs);
t->tm_sec = bcd2bin(fm3130->regs[FM3130_RTC_SECONDS] & 0x7f);
t->tm_min = bcd2bin(fm3130->regs[FM3130_RTC_MINUTES] & 0x7f);
@@ -175,12 +165,7 @@ static int fm3130_set_time(struct device *dev, struct rtc_time *t)
tmp = t->tm_year - 100;
buf[FM3130_RTC_YEARS] = bin2bcd(tmp);
- dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x"
- "%02x %02x %02x %02x %02x %02x %02x %02x\n",
- "write", buf[0], buf[1], buf[2], buf[3],
- buf[4], buf[5], buf[6], buf[7],
- buf[8], buf[9], buf[0xa], buf[0xb],
- buf[0xc], buf[0xd], buf[0xe]);
+ dev_dbg(dev, "%s: %15ph\n", "write", buf);
fm3130_rtc_mode(dev, FM3130_MODE_WRITE);
@@ -361,8 +346,8 @@ static const struct rtc_class_ops fm3130_rtc_ops = {
static struct i2c_driver fm3130_driver;
-static int __devinit fm3130_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+static int fm3130_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
struct fm3130 *fm3130;
int err = -ENODEV;
@@ -373,7 +358,7 @@ static int __devinit fm3130_probe(struct i2c_client *client,
I2C_FUNC_I2C | I2C_FUNC_SMBUS_WRITE_BYTE_DATA))
return -EIO;
- fm3130 = kzalloc(sizeof(struct fm3130), GFP_KERNEL);
+ fm3130 = devm_kzalloc(&client->dev, sizeof(struct fm3130), GFP_KERNEL);
if (!fm3130)
return -ENOMEM;
@@ -410,7 +395,7 @@ static int __devinit fm3130_probe(struct i2c_client *client,
tmp = i2c_transfer(adapter, fm3130->msg, 4);
if (tmp != 4) {
- pr_debug("read error %d\n", tmp);
+ dev_dbg(&client->dev, "read error %d\n", tmp);
err = -EIO;
goto exit_free;
}
@@ -517,22 +502,12 @@ bad_alarm:
bad_clock:
if (!fm3130->data_valid || !fm3130->alarm_valid)
- dev_dbg(&client->dev,
- "%s: %02x %02x %02x %02x %02x %02x %02x %02x"
- "%02x %02x %02x %02x %02x %02x %02x\n",
- "bogus registers",
- fm3130->regs[0], fm3130->regs[1],
- fm3130->regs[2], fm3130->regs[3],
- fm3130->regs[4], fm3130->regs[5],
- fm3130->regs[6], fm3130->regs[7],
- fm3130->regs[8], fm3130->regs[9],
- fm3130->regs[0xa], fm3130->regs[0xb],
- fm3130->regs[0xc], fm3130->regs[0xd],
- fm3130->regs[0xe]);
+ dev_dbg(&client->dev, "%s: %15ph\n", "bogus registers",
+ fm3130->regs);
/* We won't bail out here because we just got invalid data.
Time setting from u-boot doesn't work anyway */
- fm3130->rtc = rtc_device_register(client->name, &client->dev,
+ fm3130->rtc = devm_rtc_device_register(&client->dev, client->name,
&fm3130_rtc_ops, THIS_MODULE);
if (IS_ERR(fm3130->rtc)) {
err = PTR_ERR(fm3130->rtc);
@@ -542,40 +517,19 @@ bad_clock:
}
return 0;
exit_free:
- kfree(fm3130);
return err;
}
-static int __devexit fm3130_remove(struct i2c_client *client)
-{
- struct fm3130 *fm3130 = i2c_get_clientdata(client);
-
- rtc_device_unregister(fm3130->rtc);
- kfree(fm3130);
- return 0;
-}
-
static struct i2c_driver fm3130_driver = {
.driver = {
.name = "rtc-fm3130",
.owner = THIS_MODULE,
},
.probe = fm3130_probe,
- .remove = __devexit_p(fm3130_remove),
.id_table = fm3130_id,
};
-static int __init fm3130_init(void)
-{
- return i2c_add_driver(&fm3130_driver);
-}
-module_init(fm3130_init);
-
-static void __exit fm3130_exit(void)
-{
- i2c_del_driver(&fm3130_driver);
-}
-module_exit(fm3130_exit);
+module_i2c_driver(fm3130_driver);
MODULE_DESCRIPTION("RTC driver for FM3130");
MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>");
diff --git a/drivers/rtc/rtc-generic.c b/drivers/rtc/rtc-generic.c