Blame view

drivers/rtc/rtc-twl.c 17 KB
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
1
  /*
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
2
   * rtc-twl.c -- TWL Real Time Clock interface
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
   *
   * Copyright (C) 2007 MontaVista Software, Inc
   * Author: Alexandre Rusev <source@mvista.com>
   *
   * Based on original TI driver twl4030-rtc.c
   *   Copyright (C) 2006 Texas Instruments, Inc.
   *
   * Based on rtc-omap.c
   *   Copyright (C) 2003 MontaVista Software, Inc.
   *   Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
   *   Copyright (C) 2006 David Brownell
   *
   * 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.
   */
a737e835e   Joe Perches   rtc: use more sta...
20
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
21
  #include <linux/kernel.h>
2fac6674d   Anton Vorontsov   rtc: bunch of dri...
22
  #include <linux/errno.h>
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
23
24
25
26
27
28
29
  #include <linux/init.h>
  #include <linux/module.h>
  #include <linux/types.h>
  #include <linux/rtc.h>
  #include <linux/bcd.h>
  #include <linux/platform_device.h>
  #include <linux/interrupt.h>
c8a6046e1   Sachin Kamat   drivers/rtc: use ...
30
  #include <linux/of.h>
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
31

a20542565   Wolfram Sang   mfd: twl: Move he...
32
  #include <linux/mfd/twl.h>
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
33

e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
34
35
36
37
  enum twl_class {
  	TWL_4030 = 0,
  	TWL_6030,
  };
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
38
39
40
41
  
  /*
   * RTC block register offsets (use TWL_MODULE_RTC)
   */
a6b49ffd2   Balaji T K   rtc: Add twl6030 ...
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
  enum {
  	REG_SECONDS_REG = 0,
  	REG_MINUTES_REG,
  	REG_HOURS_REG,
  	REG_DAYS_REG,
  	REG_MONTHS_REG,
  	REG_YEARS_REG,
  	REG_WEEKS_REG,
  
  	REG_ALARM_SECONDS_REG,
  	REG_ALARM_MINUTES_REG,
  	REG_ALARM_HOURS_REG,
  	REG_ALARM_DAYS_REG,
  	REG_ALARM_MONTHS_REG,
  	REG_ALARM_YEARS_REG,
  
  	REG_RTC_CTRL_REG,
  	REG_RTC_STATUS_REG,
  	REG_RTC_INTERRUPTS_REG,
  
  	REG_RTC_COMP_LSB_REG,
  	REG_RTC_COMP_MSB_REG,
  };
2e84067b6   Tobias Klauser   rtc-twl: Storage ...
65
  static const u8 twl4030_rtc_reg_map[] = {
a6b49ffd2   Balaji T K   rtc: Add twl6030 ...
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
  	[REG_SECONDS_REG] = 0x00,
  	[REG_MINUTES_REG] = 0x01,
  	[REG_HOURS_REG] = 0x02,
  	[REG_DAYS_REG] = 0x03,
  	[REG_MONTHS_REG] = 0x04,
  	[REG_YEARS_REG] = 0x05,
  	[REG_WEEKS_REG] = 0x06,
  
  	[REG_ALARM_SECONDS_REG] = 0x07,
  	[REG_ALARM_MINUTES_REG] = 0x08,
  	[REG_ALARM_HOURS_REG] = 0x09,
  	[REG_ALARM_DAYS_REG] = 0x0A,
  	[REG_ALARM_MONTHS_REG] = 0x0B,
  	[REG_ALARM_YEARS_REG] = 0x0C,
  
  	[REG_RTC_CTRL_REG] = 0x0D,
  	[REG_RTC_STATUS_REG] = 0x0E,
  	[REG_RTC_INTERRUPTS_REG] = 0x0F,
  
  	[REG_RTC_COMP_LSB_REG] = 0x10,
  	[REG_RTC_COMP_MSB_REG] = 0x11,
  };
2e84067b6   Tobias Klauser   rtc-twl: Storage ...
88
  static const u8 twl6030_rtc_reg_map[] = {
a6b49ffd2   Balaji T K   rtc: Add twl6030 ...
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  	[REG_SECONDS_REG] = 0x00,
  	[REG_MINUTES_REG] = 0x01,
  	[REG_HOURS_REG] = 0x02,
  	[REG_DAYS_REG] = 0x03,
  	[REG_MONTHS_REG] = 0x04,
  	[REG_YEARS_REG] = 0x05,
  	[REG_WEEKS_REG] = 0x06,
  
  	[REG_ALARM_SECONDS_REG] = 0x08,
  	[REG_ALARM_MINUTES_REG] = 0x09,
  	[REG_ALARM_HOURS_REG] = 0x0A,
  	[REG_ALARM_DAYS_REG] = 0x0B,
  	[REG_ALARM_MONTHS_REG] = 0x0C,
  	[REG_ALARM_YEARS_REG] = 0x0D,
  
  	[REG_RTC_CTRL_REG] = 0x10,
  	[REG_RTC_STATUS_REG] = 0x11,
  	[REG_RTC_INTERRUPTS_REG] = 0x12,
  
  	[REG_RTC_COMP_LSB_REG] = 0x13,
  	[REG_RTC_COMP_MSB_REG] = 0x14,
  };
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
111
112
113
114
115
116
117
118
119
  
  /* RTC_CTRL_REG bitfields */
  #define BIT_RTC_CTRL_REG_STOP_RTC_M              0x01
  #define BIT_RTC_CTRL_REG_ROUND_30S_M             0x02
  #define BIT_RTC_CTRL_REG_AUTO_COMP_M             0x04
  #define BIT_RTC_CTRL_REG_MODE_12_24_M            0x08
  #define BIT_RTC_CTRL_REG_TEST_MODE_M             0x10
  #define BIT_RTC_CTRL_REG_SET_32_COUNTER_M        0x20
  #define BIT_RTC_CTRL_REG_GET_TIME_M              0x40
f3ec434c6   Konstantin Shlyakhovoy   drivers/rtc/rtc-t...
120
  #define BIT_RTC_CTRL_REG_RTC_V_OPT               0x80
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
  
  /* RTC_STATUS_REG bitfields */
  #define BIT_RTC_STATUS_REG_RUN_M                 0x02
  #define BIT_RTC_STATUS_REG_1S_EVENT_M            0x04
  #define BIT_RTC_STATUS_REG_1M_EVENT_M            0x08
  #define BIT_RTC_STATUS_REG_1H_EVENT_M            0x10
  #define BIT_RTC_STATUS_REG_1D_EVENT_M            0x20
  #define BIT_RTC_STATUS_REG_ALARM_M               0x40
  #define BIT_RTC_STATUS_REG_POWER_UP_M            0x80
  
  /* RTC_INTERRUPTS_REG bitfields */
  #define BIT_RTC_INTERRUPTS_REG_EVERY_M           0x03
  #define BIT_RTC_INTERRUPTS_REG_IT_TIMER_M        0x04
  #define BIT_RTC_INTERRUPTS_REG_IT_ALARM_M        0x08
  
  
  /* REG_SECONDS_REG through REG_YEARS_REG is how many registers? */
  #define ALL_TIME_REGS		6
  
  /*----------------------------------------------------------------------*/
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
  struct twl_rtc {
  	struct device *dev;
  	struct rtc_device *rtc;
  	u8 *reg_map;
  	/*
  	 * Cache the value for timer/alarm interrupts register; this is
  	 * only changed by callers holding rtc ops lock (or resume).
  	 */
  	unsigned char rtc_irq_bits;
  	bool wake_enabled;
  #ifdef CONFIG_PM_SLEEP
  	unsigned char irqstat;
  #endif
  	enum twl_class class;
  };
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
156
157
  
  /*
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
158
   * Supports 1 byte read from TWL RTC register.
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
159
   */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
160
  static int twl_rtc_read_u8(struct twl_rtc *twl_rtc, u8 *data, u8 reg)
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
161
162
  {
  	int ret;
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
163
  	ret = twl_i2c_read_u8(TWL_MODULE_RTC, data, (twl_rtc->reg_map[reg]));
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
164
  	if (ret < 0)
a737e835e   Joe Perches   rtc: use more sta...
165
166
  		pr_err("Could not read TWL register %X - error %d
  ", reg, ret);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
167
168
169
170
  	return ret;
  }
  
  /*
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
171
   * Supports 1 byte write to TWL RTC registers.
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
172
   */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
173
  static int twl_rtc_write_u8(struct twl_rtc *twl_rtc, u8 data, u8 reg)
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
174
175
  {
  	int ret;
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
176
  	ret = twl_i2c_write_u8(TWL_MODULE_RTC, data, (twl_rtc->reg_map[reg]));
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
177
  	if (ret < 0)
a737e835e   Joe Perches   rtc: use more sta...
178
179
180
  		pr_err("Could not write TWL register %X - error %d
  ",
  		       reg, ret);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
181
182
183
184
  	return ret;
  }
  
  /*
a748384bb   Alessandro Zummo   rtc: tw4030 add a...
185
   * Enable 1/second update and/or alarm interrupts.
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
186
   */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
187
  static int set_rtc_irq_bit(struct twl_rtc *twl_rtc, unsigned char bit)
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
188
189
190
  {
  	unsigned char val;
  	int ret;
ce9f65063   Venu Byravarasu   drivers/rtc/rtc-t...
191
  	/* if the bit is set, return from here */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
192
  	if (twl_rtc->rtc_irq_bits & bit)
ce9f65063   Venu Byravarasu   drivers/rtc/rtc-t...
193
  		return 0;
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
194
  	val = twl_rtc->rtc_irq_bits | bit;
a748384bb   Alessandro Zummo   rtc: tw4030 add a...
195
  	val &= ~BIT_RTC_INTERRUPTS_REG_EVERY_M;
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
196
  	ret = twl_rtc_write_u8(twl_rtc, val, REG_RTC_INTERRUPTS_REG);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
197
  	if (ret == 0)
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
198
  		twl_rtc->rtc_irq_bits = val;
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
199
200
201
202
203
  
  	return ret;
  }
  
  /*
a748384bb   Alessandro Zummo   rtc: tw4030 add a...
204
   * Disable update and/or alarm interrupts.
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
205
   */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
206
  static int mask_rtc_irq_bit(struct twl_rtc *twl_rtc, unsigned char bit)
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
207
208
209
  {
  	unsigned char val;
  	int ret;
ce9f65063   Venu Byravarasu   drivers/rtc/rtc-t...
210
  	/* if the bit is clear, return from here */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
211
  	if (!(twl_rtc->rtc_irq_bits & bit))
ce9f65063   Venu Byravarasu   drivers/rtc/rtc-t...
212
  		return 0;
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
213
214
  	val = twl_rtc->rtc_irq_bits & ~bit;
  	ret = twl_rtc_write_u8(twl_rtc, val, REG_RTC_INTERRUPTS_REG);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
215
  	if (ret == 0)
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
216
  		twl_rtc->rtc_irq_bits = val;
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
217
218
219
  
  	return ret;
  }
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
220
  static int twl_rtc_alarm_irq_enable(struct device *dev, unsigned enabled)
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
221
  {
ae8458949   Kevin Hilman   drivers/rtc/rtc-t...
222
  	struct platform_device *pdev = to_platform_device(dev);
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
223
  	struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
ae8458949   Kevin Hilman   drivers/rtc/rtc-t...
224
  	int irq = platform_get_irq(pdev, 0);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
225
  	int ret;
ae8458949   Kevin Hilman   drivers/rtc/rtc-t...
226
  	if (enabled) {
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
227
228
229
  		ret = set_rtc_irq_bit(twl_rtc,
  				      BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
  		if (device_can_wakeup(dev) && !twl_rtc->wake_enabled) {
ae8458949   Kevin Hilman   drivers/rtc/rtc-t...
230
  			enable_irq_wake(irq);
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
231
  			twl_rtc->wake_enabled = true;
ae8458949   Kevin Hilman   drivers/rtc/rtc-t...
232
233
  		}
  	} else {
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
234
235
236
  		ret = mask_rtc_irq_bit(twl_rtc,
  				       BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
  		if (twl_rtc->wake_enabled) {
ae8458949   Kevin Hilman   drivers/rtc/rtc-t...
237
  			disable_irq_wake(irq);
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
238
  			twl_rtc->wake_enabled = false;
ae8458949   Kevin Hilman   drivers/rtc/rtc-t...
239
240
  		}
  	}
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
241
242
243
  
  	return ret;
  }
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
244
  /*
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
245
   * Gets current TWL RTC time and date parameters.
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
246
247
248
249
250
251
252
   *
   * The RTC's time/alarm representation is not what gmtime(3) requires
   * Linux to use:
   *
   *  - Months are 1..12 vs Linux 0-11
   *  - Years are 0..99 vs Linux 1900..N (we assume 21st century)
   */
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
253
  static int twl_rtc_read_time(struct device *dev, struct rtc_time *tm)
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
254
  {
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
255
  	struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
14591d888   Peter Ujfalusi   mfd/rtc/gpio: twl...
256
  	unsigned char rtc_data[ALL_TIME_REGS];
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
257
258
  	int ret;
  	u8 save_control;
f3ec434c6   Konstantin Shlyakhovoy   drivers/rtc/rtc-t...
259
  	u8 rtc_control;
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
260

e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
261
  	ret = twl_rtc_read_u8(twl_rtc, &save_control, REG_RTC_CTRL_REG);
f3ec434c6   Konstantin Shlyakhovoy   drivers/rtc/rtc-t...
262
263
264
  	if (ret < 0) {
  		dev_err(dev, "%s: reading CTRL_REG, error %d
  ", __func__, ret);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
265
  		return ret;
f3ec434c6   Konstantin Shlyakhovoy   drivers/rtc/rtc-t...
266
267
  	}
  	/* for twl6030/32 make sure BIT_RTC_CTRL_REG_GET_TIME_M is clear */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
268
  	if (twl_rtc->class == TWL_6030) {
f3ec434c6   Konstantin Shlyakhovoy   drivers/rtc/rtc-t...
269
270
  		if (save_control & BIT_RTC_CTRL_REG_GET_TIME_M) {
  			save_control &= ~BIT_RTC_CTRL_REG_GET_TIME_M;
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
271
272
  			ret = twl_rtc_write_u8(twl_rtc, save_control,
  					       REG_RTC_CTRL_REG);
f3ec434c6   Konstantin Shlyakhovoy   drivers/rtc/rtc-t...
273
274
275
276
277
278
279
280
  			if (ret < 0) {
  				dev_err(dev, "%s clr GET_TIME, error %d
  ",
  					__func__, ret);
  				return ret;
  			}
  		}
  	}
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
281

f3ec434c6   Konstantin Shlyakhovoy   drivers/rtc/rtc-t...
282
283
  	/* Copy RTC counting registers to static registers or latches */
  	rtc_control = save_control | BIT_RTC_CTRL_REG_GET_TIME_M;
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
284

f3ec434c6   Konstantin Shlyakhovoy   drivers/rtc/rtc-t...
285
  	/* for twl6030/32 enable read access to static shadowed registers */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
286
  	if (twl_rtc->class == TWL_6030)
f3ec434c6   Konstantin Shlyakhovoy   drivers/rtc/rtc-t...
287
  		rtc_control |= BIT_RTC_CTRL_REG_RTC_V_OPT;
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
288
  	ret = twl_rtc_write_u8(twl_rtc, rtc_control, REG_RTC_CTRL_REG);
f3ec434c6   Konstantin Shlyakhovoy   drivers/rtc/rtc-t...
289
290
291
  	if (ret < 0) {
  		dev_err(dev, "%s: writing CTRL_REG, error %d
  ", __func__, ret);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
292
  		return ret;
f3ec434c6   Konstantin Shlyakhovoy   drivers/rtc/rtc-t...
293
  	}
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
294

ef3b7d0d3   Balaji T K   mfd: Rename twl40...
295
  	ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
296
  			(twl_rtc->reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
297
298
  
  	if (ret < 0) {
f3ec434c6   Konstantin Shlyakhovoy   drivers/rtc/rtc-t...
299
300
  		dev_err(dev, "%s: reading data, error %d
  ", __func__, ret);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
301
302
  		return ret;
  	}
f3ec434c6   Konstantin Shlyakhovoy   drivers/rtc/rtc-t...
303
  	/* for twl6030 restore original state of rtc control register */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
304
305
  	if (twl_rtc->class == TWL_6030) {
  		ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
f3ec434c6   Konstantin Shlyakhovoy   drivers/rtc/rtc-t...
306
307
308
309
310
311
312
  		if (ret < 0) {
  			dev_err(dev, "%s: restore CTRL_REG, error %d
  ",
  				__func__, ret);
  			return ret;
  		}
  	}
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
313
314
315
316
317
318
319
320
321
  	tm->tm_sec = bcd2bin(rtc_data[0]);
  	tm->tm_min = bcd2bin(rtc_data[1]);
  	tm->tm_hour = bcd2bin(rtc_data[2]);
  	tm->tm_mday = bcd2bin(rtc_data[3]);
  	tm->tm_mon = bcd2bin(rtc_data[4]) - 1;
  	tm->tm_year = bcd2bin(rtc_data[5]) + 100;
  
  	return ret;
  }
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
322
  static int twl_rtc_set_time(struct device *dev, struct rtc_time *tm)
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
323
  {
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
324
  	struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
325
  	unsigned char save_control;
14591d888   Peter Ujfalusi   mfd/rtc/gpio: twl...
326
  	unsigned char rtc_data[ALL_TIME_REGS];
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
327
  	int ret;
14591d888   Peter Ujfalusi   mfd/rtc/gpio: twl...
328
329
330
331
332
333
  	rtc_data[0] = bin2bcd(tm->tm_sec);
  	rtc_data[1] = bin2bcd(tm->tm_min);
  	rtc_data[2] = bin2bcd(tm->tm_hour);
  	rtc_data[3] = bin2bcd(tm->tm_mday);
  	rtc_data[4] = bin2bcd(tm->tm_mon + 1);
  	rtc_data[5] = bin2bcd(tm->tm_year - 100);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
334
335
  
  	/* Stop RTC while updating the TC registers */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
336
  	ret = twl_rtc_read_u8(twl_rtc, &save_control, REG_RTC_CTRL_REG);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
337
338
339
340
  	if (ret < 0)
  		goto out;
  
  	save_control &= ~BIT_RTC_CTRL_REG_STOP_RTC_M;
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
341
  	ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
342
343
344
345
  	if (ret < 0)
  		goto out;
  
  	/* update all the time registers in one shot */
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
346
  	ret = twl_i2c_write(TWL_MODULE_RTC, rtc_data,
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
347
  		(twl_rtc->reg_map[REG_SECONDS_REG]), ALL_TIME_REGS);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
348
349
350
351
352
353
354
355
  	if (ret < 0) {
  		dev_err(dev, "rtc_set_time error %d
  ", ret);
  		goto out;
  	}
  
  	/* Start back RTC */
  	save_control |= BIT_RTC_CTRL_REG_STOP_RTC_M;
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
356
  	ret = twl_rtc_write_u8(twl_rtc, save_control, REG_RTC_CTRL_REG);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
357
358
359
360
361
362
  
  out:
  	return ret;
  }
  
  /*
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
363
   * Gets current TWL RTC alarm time.
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
364
   */
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
365
  static int twl_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
366
  {
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
367
  	struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
14591d888   Peter Ujfalusi   mfd/rtc/gpio: twl...
368
  	unsigned char rtc_data[ALL_TIME_REGS];
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
369
  	int ret;
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
370
  	ret = twl_i2c_read(TWL_MODULE_RTC, rtc_data,
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
371
  			twl_rtc->reg_map[REG_ALARM_SECONDS_REG], ALL_TIME_REGS);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
  	if (ret < 0) {
  		dev_err(dev, "rtc_read_alarm error %d
  ", ret);
  		return ret;
  	}
  
  	/* some of these fields may be wildcard/"match all" */
  	alm->time.tm_sec = bcd2bin(rtc_data[0]);
  	alm->time.tm_min = bcd2bin(rtc_data[1]);
  	alm->time.tm_hour = bcd2bin(rtc_data[2]);
  	alm->time.tm_mday = bcd2bin(rtc_data[3]);
  	alm->time.tm_mon = bcd2bin(rtc_data[4]) - 1;
  	alm->time.tm_year = bcd2bin(rtc_data[5]) + 100;
  
  	/* report cached alarm enable state */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
387
  	if (twl_rtc->rtc_irq_bits & BIT_RTC_INTERRUPTS_REG_IT_ALARM_M)
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
388
389
390
391
  		alm->enabled = 1;
  
  	return ret;
  }
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
392
  static int twl_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
393
  {
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
394
  	struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
14591d888   Peter Ujfalusi   mfd/rtc/gpio: twl...
395
  	unsigned char alarm_data[ALL_TIME_REGS];
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
396
  	int ret;
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
397
  	ret = twl_rtc_alarm_irq_enable(dev, 0);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
398
399
  	if (ret)
  		goto out;
14591d888   Peter Ujfalusi   mfd/rtc/gpio: twl...
400
401
402
403
404
405
  	alarm_data[0] = bin2bcd(alm->time.tm_sec);
  	alarm_data[1] = bin2bcd(alm->time.tm_min);
  	alarm_data[2] = bin2bcd(alm->time.tm_hour);
  	alarm_data[3] = bin2bcd(alm->time.tm_mday);
  	alarm_data[4] = bin2bcd(alm->time.tm_mon + 1);
  	alarm_data[5] = bin2bcd(alm->time.tm_year - 100);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
406
407
  
  	/* update all the alarm registers in one shot */
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
408
  	ret = twl_i2c_write(TWL_MODULE_RTC, alarm_data,
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
409
  			twl_rtc->reg_map[REG_ALARM_SECONDS_REG], ALL_TIME_REGS);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
410
411
412
413
414
415
416
  	if (ret) {
  		dev_err(dev, "rtc_set_alarm error %d
  ", ret);
  		goto out;
  	}
  
  	if (alm->enabled)
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
417
  		ret = twl_rtc_alarm_irq_enable(dev, 1);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
418
419
420
  out:
  	return ret;
  }
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
421
  static irqreturn_t twl_rtc_interrupt(int irq, void *data)
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
422
  {
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
423
  	struct twl_rtc *twl_rtc = data;
2778ebcc0   Venu Byravarasu   drivers/rtc/rtc-t...
424
  	unsigned long events;
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
425
426
427
  	int ret = IRQ_NONE;
  	int res;
  	u8 rd_reg;
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
428
  	res = twl_rtc_read_u8(twl_rtc, &rd_reg, REG_RTC_STATUS_REG);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
429
430
431
432
433
434
435
436
437
  	if (res)
  		goto out;
  	/*
  	 * Figure out source of interrupt: ALARM or TIMER in RTC_STATUS_REG.
  	 * only one (ALARM or RTC) interrupt source may be enabled
  	 * at time, we also could check our results
  	 * by reading RTS_INTERRUPTS_REGISTER[IT_TIMER,IT_ALARM]
  	 */
  	if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
2778ebcc0   Venu Byravarasu   drivers/rtc/rtc-t...
438
  		events = RTC_IRQF | RTC_AF;
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
439
  	else
2778ebcc0   Venu Byravarasu   drivers/rtc/rtc-t...
440
  		events = RTC_IRQF | RTC_PF;
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
441

e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
442
443
  	res = twl_rtc_write_u8(twl_rtc, BIT_RTC_STATUS_REG_ALARM_M,
  			       REG_RTC_STATUS_REG);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
444
445
  	if (res)
  		goto out;
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
446
  	if (twl_rtc->class == TWL_4030) {
a6b49ffd2   Balaji T K   rtc: Add twl6030 ...
447
448
449
450
451
452
453
454
455
456
457
458
  		/* Clear on Read enabled. RTC_IT bit of TWL4030_INT_PWR_ISR1
  		 * needs 2 reads to clear the interrupt. One read is done in
  		 * do_twl_pwrirq(). Doing the second read, to clear
  		 * the bit.
  		 *
  		 * FIXME the reason PWR_ISR1 needs an extra read is that
  		 * RTC_IF retriggered until we cleared REG_ALARM_M above.
  		 * But re-reading like this is a bad hack; by doing so we
  		 * risk wrongly clearing status for some other IRQ (losing
  		 * the interrupt).  Be smarter about handling RTC_UF ...
  		 */
  		res = twl_i2c_read_u8(TWL4030_MODULE_INT,
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
459
  			&rd_reg, TWL4030_INT_PWR_ISR1);
a6b49ffd2   Balaji T K   rtc: Add twl6030 ...
460
461
462
  		if (res)
  			goto out;
  	}
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
463
464
  
  	/* Notify RTC core on event */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
465
  	rtc_update_irq(twl_rtc->rtc, 1, events);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
466
467
468
469
470
  
  	ret = IRQ_HANDLED;
  out:
  	return ret;
  }
34c7b3ac4   Julia Lawall   rtc: constify rtc...
471
  static const struct rtc_class_ops twl_rtc_ops = {
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
472
473
474
475
476
  	.read_time	= twl_rtc_read_time,
  	.set_time	= twl_rtc_set_time,
  	.read_alarm	= twl_rtc_read_alarm,
  	.set_alarm	= twl_rtc_set_alarm,
  	.alarm_irq_enable = twl_rtc_alarm_irq_enable,
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
477
478
479
  };
  
  /*----------------------------------------------------------------------*/
5a167f454   Greg Kroah-Hartman   Drivers: rtc: rem...
480
  static int twl_rtc_probe(struct platform_device *pdev)
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
481
  {
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
482
  	struct twl_rtc *twl_rtc;
1c02cbfec   Nicolae Rosia   rtc: twl: make dr...
483
  	struct device_node *np = pdev->dev.of_node;
7e72c6863   Todd Poynor   rtc: twl: Fix reg...
484
  	int ret = -EINVAL;
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
485
486
  	int irq = platform_get_irq(pdev, 0);
  	u8 rd_reg;
1c02cbfec   Nicolae Rosia   rtc: twl: make dr...
487
488
489
490
491
  	if (!np) {
  		dev_err(&pdev->dev, "no DT info
  ");
  		return -EINVAL;
  	}
2fac6674d   Anton Vorontsov   rtc: bunch of dri...
492
  	if (irq <= 0)
f53eeb853   Jingoo Han   drivers/rtc/rtc-t...
493
  		return ret;
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
494

e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
  	twl_rtc = devm_kzalloc(&pdev->dev, sizeof(*twl_rtc), GFP_KERNEL);
  	if (!twl_rtc)
  		return -ENOMEM;
  
  	if (twl_class_is_4030()) {
  		twl_rtc->class = TWL_4030;
  		twl_rtc->reg_map = (u8 *)twl4030_rtc_reg_map;
  	} else if (twl_class_is_6030()) {
  		twl_rtc->class = TWL_6030;
  		twl_rtc->reg_map = (u8 *)twl6030_rtc_reg_map;
  	} else {
  		dev_err(&pdev->dev, "TWL Class not supported.
  ");
  		return -EINVAL;
  	}
d3869ff68   Peter Ujfalusi   drivers/rtc/rtc-t...
510

e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
511
  	ret = twl_rtc_read_u8(twl_rtc, &rd_reg, REG_RTC_STATUS_REG);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
512
  	if (ret < 0)
f53eeb853   Jingoo Han   drivers/rtc/rtc-t...
513
  		return ret;
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
514
515
516
517
518
519
520
521
522
523
  
  	if (rd_reg & BIT_RTC_STATUS_REG_POWER_UP_M)
  		dev_warn(&pdev->dev, "Power up reset detected.
  ");
  
  	if (rd_reg & BIT_RTC_STATUS_REG_ALARM_M)
  		dev_warn(&pdev->dev, "Pending Alarm interrupt detected.
  ");
  
  	/* Clear RTC Power up reset and pending alarm interrupts */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
524
  	ret = twl_rtc_write_u8(twl_rtc, rd_reg, REG_RTC_STATUS_REG);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
525
  	if (ret < 0)
f53eeb853   Jingoo Han   drivers/rtc/rtc-t...
526
  		return ret;
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
527

e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
528
  	if (twl_rtc->class == TWL_6030) {
a6b49ffd2   Balaji T K   rtc: Add twl6030 ...
529
530
531
532
533
  		twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
  			REG_INT_MSK_LINE_A);
  		twl6030_interrupt_unmask(TWL6030_RTC_INT_MASK,
  			REG_INT_MSK_STS_A);
  	}
f7439bcb7   Venu Byravarasu   drivers/rtc/rtc-t...
534
535
  	dev_info(&pdev->dev, "Enabling TWL-RTC
  ");
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
536
537
  	ret = twl_rtc_write_u8(twl_rtc, BIT_RTC_CTRL_REG_STOP_RTC_M,
  			       REG_RTC_CTRL_REG);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
538
  	if (ret < 0)
f53eeb853   Jingoo Han   drivers/rtc/rtc-t...
539
  		return ret;
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
540

8dcebaa9a   Kevin Hilman   drivers/rtc/rtc-t...
541
  	/* ensure interrupts are disabled, bootloaders can be strange */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
542
  	ret = twl_rtc_write_u8(twl_rtc, 0, REG_RTC_INTERRUPTS_REG);
8dcebaa9a   Kevin Hilman   drivers/rtc/rtc-t...
543
544
545
  	if (ret < 0)
  		dev_warn(&pdev->dev, "unable to disable interrupt
  ");
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
546
  	/* init cached IRQ enable bits */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
547
548
  	ret = twl_rtc_read_u8(twl_rtc, &twl_rtc->rtc_irq_bits,
  			      REG_RTC_INTERRUPTS_REG);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
549
  	if (ret < 0)
f53eeb853   Jingoo Han   drivers/rtc/rtc-t...
550
  		return ret;
7e72c6863   Todd Poynor   rtc: twl: Fix reg...
551

e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
552
  	platform_set_drvdata(pdev, twl_rtc);
b99b94b52   Grygorii Strashko   drivers/rtc/rtc-t...
553
  	device_init_wakeup(&pdev->dev, 1);
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
554
  	twl_rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
f53eeb853   Jingoo Han   drivers/rtc/rtc-t...
555
  					&twl_rtc_ops, THIS_MODULE);
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
556
  	if (IS_ERR(twl_rtc->rtc)) {
7e72c6863   Todd Poynor   rtc: twl: Fix reg...
557
558
  		dev_err(&pdev->dev, "can't register RTC device, err %ld
  ",
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
559
560
  			PTR_ERR(twl_rtc->rtc));
  		return PTR_ERR(twl_rtc->rtc);
7e72c6863   Todd Poynor   rtc: twl: Fix reg...
561
  	}
f53eeb853   Jingoo Han   drivers/rtc/rtc-t...
562
563
564
  	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
  					twl_rtc_interrupt,
  					IRQF_TRIGGER_RISING | IRQF_ONESHOT,
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
565
  					dev_name(&twl_rtc->rtc->dev), twl_rtc);
7e72c6863   Todd Poynor   rtc: twl: Fix reg...
566
567
568
  	if (ret < 0) {
  		dev_err(&pdev->dev, "IRQ is not free.
  ");
f53eeb853   Jingoo Han   drivers/rtc/rtc-t...
569
  		return ret;
7e72c6863   Todd Poynor   rtc: twl: Fix reg...
570
  	}
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
571

7e72c6863   Todd Poynor   rtc: twl: Fix reg...
572
  	return 0;
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
573
574
575
  }
  
  /*
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
576
   * Disable all TWL RTC module interrupts.
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
577
578
   * Sets status flag to free.
   */
5a167f454   Greg Kroah-Hartman   Drivers: rtc: rem...
579
  static int twl_rtc_remove(struct platform_device *pdev)
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
580
  {
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
581
  	struct twl_rtc *twl_rtc = platform_get_drvdata(pdev);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
582
  	/* leave rtc running, but disable irqs */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
583
584
585
  	mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
  	mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
  	if (twl_rtc->class == TWL_6030) {
a6b49ffd2   Balaji T K   rtc: Add twl6030 ...
586
587
588
589
590
  		twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
  			REG_INT_MSK_LINE_A);
  		twl6030_interrupt_mask(TWL6030_RTC_INT_MASK,
  			REG_INT_MSK_STS_A);
  	}
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
591
592
  	return 0;
  }
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
593
  static void twl_rtc_shutdown(struct platform_device *pdev)
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
594
  {
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
595
  	struct twl_rtc *twl_rtc = platform_get_drvdata(pdev);
cafa1d8b0   Matti Halme   rtc: rtc-twl4030 ...
596
597
  	/* mask timer interrupts, but leave alarm interrupts on to enable
  	   power-on when alarm is triggered */
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
598
  	mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
599
  }
b9d8c4603   Jingoo Han   rtc: rtc-twl: con...
600
  #ifdef CONFIG_PM_SLEEP
b9d8c4603   Jingoo Han   rtc: rtc-twl: con...
601
  static int twl_rtc_suspend(struct device *dev)
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
602
  {
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
603
  	struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
604

e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
605
606
607
  	twl_rtc->irqstat = twl_rtc->rtc_irq_bits;
  
  	mask_rtc_irq_bit(twl_rtc, BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
608
609
  	return 0;
  }
b9d8c4603   Jingoo Han   rtc: rtc-twl: con...
610
  static int twl_rtc_resume(struct device *dev)
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
611
  {
e3e7f95bc   Nicolae Rosia   rtc: twl: kill st...
612
613
614
  	struct twl_rtc *twl_rtc = dev_get_drvdata(dev);
  
  	set_rtc_irq_bit(twl_rtc, twl_rtc->irqstat);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
615
616
  	return 0;
  }
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
617
  #endif
b9d8c4603   Jingoo Han   rtc: rtc-twl: con...
618
  static SIMPLE_DEV_PM_OPS(twl_rtc_pm_ops, twl_rtc_suspend, twl_rtc_resume);
948170f89   Benoit Cousson   drivers/rtc/rtc-t...
619
620
621
622
623
  static const struct of_device_id twl_rtc_of_match[] = {
  	{.compatible = "ti,twl4030-rtc", },
  	{ },
  };
  MODULE_DEVICE_TABLE(of, twl_rtc_of_match);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
624
625
  
  static struct platform_driver twl4030rtc_driver = {
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
626
  	.probe		= twl_rtc_probe,
5a167f454   Greg Kroah-Hartman   Drivers: rtc: rem...
627
  	.remove		= twl_rtc_remove,
ef3b7d0d3   Balaji T K   mfd: Rename twl40...
628
  	.shutdown	= twl_rtc_shutdown,
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
629
  	.driver		= {
948170f89   Benoit Cousson   drivers/rtc/rtc-t...
630
  		.name		= "twl_rtc",
b9d8c4603   Jingoo Han   rtc: rtc-twl: con...
631
  		.pm		= &twl_rtc_pm_ops,
1c02cbfec   Nicolae Rosia   rtc: twl: make dr...
632
  		.of_match_table = twl_rtc_of_match,
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
633
634
  	},
  };
5ee67484d   Peter Ujfalusi   drivers/rtc/rtc-t...
635
  module_platform_driver(twl4030rtc_driver);
f96411ab7   David Brownell   mfd: rtc-twl4030 ...
636
637
638
  
  MODULE_AUTHOR("Texas Instruments, MontaVista Software");
  MODULE_LICENSE("GPL");