Blame view

drivers/rtc/rtc-s5m.c 20.6 KB
26dcc12c0   Krzysztof Kozlowski   rtc: s5m: Add SPD...
1
2
3
4
5
6
  // SPDX-License-Identifier: GPL-2.0+
  //
  // Copyright (c) 2013-2014 Samsung Electronics Co., Ltd
  //	http://www.samsung.com
  //
  //  Copyright (C) 2013 Google, Inc
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
7

a737e835e   Joe Perches   rtc: use more sta...
8
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
9
10
  #include <linux/module.h>
  #include <linux/i2c.h>
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
11
  #include <linux/bcd.h>
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
12
13
  #include <linux/regmap.h>
  #include <linux/rtc.h>
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
14
15
16
17
  #include <linux/platform_device.h>
  #include <linux/mfd/samsung/core.h>
  #include <linux/mfd/samsung/irq.h>
  #include <linux/mfd/samsung/rtc.h>
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
18
  #include <linux/mfd/samsung/s2mps14.h>
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
19

d73238d4a   Krzysztof Kozlowski   rtc: s5m: limit e...
20
21
  /*
   * Maximum number of retries for checking changes in UDR field
602cb5bba   Krzysztof Kozlowski   mfd/rtc: sec/s5m:...
22
   * of S5M_RTC_UDR_CON register (to limit possible endless loop).
d73238d4a   Krzysztof Kozlowski   rtc: s5m: limit e...
23
24
   *
   * After writing to RTC registers (setting time or alarm) read the UDR field
602cb5bba   Krzysztof Kozlowski   mfd/rtc: sec/s5m:...
25
   * in S5M_RTC_UDR_CON register. UDR is auto-cleared when data have
d73238d4a   Krzysztof Kozlowski   rtc: s5m: limit e...
26
27
28
   * been transferred.
   */
  #define UDR_READ_RETRY_CNT	5
4a681243c   Gustavo A. R. Silva   rtc: s5m: Move en...
29
30
31
32
33
34
35
36
37
  enum {
  	RTC_SEC = 0,
  	RTC_MIN,
  	RTC_HOUR,
  	RTC_WEEKDAY,
  	RTC_DATE,
  	RTC_MONTH,
  	RTC_YEAR1,
  	RTC_YEAR2,
756d5282b   Gustavo A. R. Silva   rtc: s5m: Remove ...
38
39
  	/* Make sure this is always the last enum name. */
  	RTC_MAX_NUM_TIME_REGS
4a681243c   Gustavo A. R. Silva   rtc: s5m: Move en...
40
  };
8ae83b6f7   Krzysztof Kozlowski   rtc: s5m: Make re...
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  /*
   * Registers used by the driver which are different between chipsets.
   *
   * Operations like read time and write alarm/time require updating
   * specific fields in UDR register. These fields usually are auto-cleared
   * (with some exceptions).
   *
   * Table of operations per device:
   *
   * Device     | Write time | Read time | Write alarm
   * =================================================
   * S5M8767    | UDR + TIME |           | UDR
   * S2MPS11/14 | WUDR       | RUDR      | WUDR + RUDR
   * S2MPS13    | WUDR       | RUDR      | WUDR + AUDR
   * S2MPS15    | WUDR       | RUDR      | AUDR
   */
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
57
58
59
60
61
62
63
64
65
66
67
  struct s5m_rtc_reg_config {
  	/* Number of registers used for setting time/alarm0/alarm1 */
  	unsigned int regs_count;
  	/* First register for time, seconds */
  	unsigned int time;
  	/* RTC control register */
  	unsigned int ctrl;
  	/* First register for alarm 0, seconds */
  	unsigned int alarm0;
  	/* First register for alarm 1, seconds */
  	unsigned int alarm1;
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
68
69
70
71
72
  	/*
  	 * Register for update flag (UDR). Typically setting UDR field to 1
  	 * will enable update of time or alarm register. Then it will be
  	 * auto-cleared after successful update.
  	 */
a83a793ad   Krzysztof Kozlowski   rtc: s5m: Cleanup...
73
  	unsigned int udr_update;
67a6025a7   Krzysztof Kozlowski   rtc: s5m: Add sep...
74
75
  	/* Auto-cleared mask in UDR field for writing time and alarm */
  	unsigned int autoclear_udr_mask;
8ae83b6f7   Krzysztof Kozlowski   rtc: s5m: Make re...
76
77
78
79
80
81
82
  	/*
  	 * Masks in UDR field for time and alarm operations.
  	 * The read time mask can be 0. Rest should not.
  	 */
  	unsigned int read_time_udr_mask;
  	unsigned int write_time_udr_mask;
  	unsigned int write_alarm_udr_mask;
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
83
84
85
86
87
88
89
90
91
  };
  
  /* Register map for S5M8763 and S5M8767 */
  static const struct s5m_rtc_reg_config s5m_rtc_regs = {
  	.regs_count		= 8,
  	.time			= S5M_RTC_SEC,
  	.ctrl			= S5M_ALARM1_CONF,
  	.alarm0			= S5M_ALARM0_SEC,
  	.alarm1			= S5M_ALARM1_SEC,
a83a793ad   Krzysztof Kozlowski   rtc: s5m: Cleanup...
92
  	.udr_update		= S5M_RTC_UDR_CON,
67a6025a7   Krzysztof Kozlowski   rtc: s5m: Add sep...
93
  	.autoclear_udr_mask	= S5M_RTC_UDR_MASK,
8ae83b6f7   Krzysztof Kozlowski   rtc: s5m: Make re...
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
  	.read_time_udr_mask	= 0, /* Not needed */
  	.write_time_udr_mask	= S5M_RTC_UDR_MASK | S5M_RTC_TIME_EN_MASK,
  	.write_alarm_udr_mask	= S5M_RTC_UDR_MASK,
  };
  
  /* Register map for S2MPS13 */
  static const struct s5m_rtc_reg_config s2mps13_rtc_regs = {
  	.regs_count		= 7,
  	.time			= S2MPS_RTC_SEC,
  	.ctrl			= S2MPS_RTC_CTRL,
  	.alarm0			= S2MPS_ALARM0_SEC,
  	.alarm1			= S2MPS_ALARM1_SEC,
  	.udr_update		= S2MPS_RTC_UDR_CON,
  	.autoclear_udr_mask	= S2MPS_RTC_WUDR_MASK,
  	.read_time_udr_mask	= S2MPS_RTC_RUDR_MASK,
  	.write_time_udr_mask	= S2MPS_RTC_WUDR_MASK,
  	.write_alarm_udr_mask	= S2MPS_RTC_WUDR_MASK | S2MPS13_RTC_AUDR_MASK,
  };
  
  /* Register map for S2MPS11/14 */
  static const struct s5m_rtc_reg_config s2mps14_rtc_regs = {
  	.regs_count		= 7,
  	.time			= S2MPS_RTC_SEC,
  	.ctrl			= S2MPS_RTC_CTRL,
  	.alarm0			= S2MPS_ALARM0_SEC,
  	.alarm1			= S2MPS_ALARM1_SEC,
  	.udr_update		= S2MPS_RTC_UDR_CON,
  	.autoclear_udr_mask	= S2MPS_RTC_WUDR_MASK,
  	.read_time_udr_mask	= S2MPS_RTC_RUDR_MASK,
  	.write_time_udr_mask	= S2MPS_RTC_WUDR_MASK,
  	.write_alarm_udr_mask	= S2MPS_RTC_WUDR_MASK | S2MPS_RTC_RUDR_MASK,
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
125
  };
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
126
  /*
8ae83b6f7   Krzysztof Kozlowski   rtc: s5m: Make re...
127
128
   * Register map for S2MPS15 - in comparison to S2MPS14 the WUDR and AUDR bits
   * are swapped.
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
129
   */
8ae83b6f7   Krzysztof Kozlowski   rtc: s5m: Make re...
130
  static const struct s5m_rtc_reg_config s2mps15_rtc_regs = {
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
131
132
133
134
135
  	.regs_count		= 7,
  	.time			= S2MPS_RTC_SEC,
  	.ctrl			= S2MPS_RTC_CTRL,
  	.alarm0			= S2MPS_ALARM0_SEC,
  	.alarm1			= S2MPS_ALARM1_SEC,
a83a793ad   Krzysztof Kozlowski   rtc: s5m: Cleanup...
136
  	.udr_update		= S2MPS_RTC_UDR_CON,
67a6025a7   Krzysztof Kozlowski   rtc: s5m: Add sep...
137
  	.autoclear_udr_mask	= S2MPS_RTC_WUDR_MASK,
8ae83b6f7   Krzysztof Kozlowski   rtc: s5m: Make re...
138
139
140
  	.read_time_udr_mask	= S2MPS_RTC_RUDR_MASK,
  	.write_time_udr_mask	= S2MPS15_RTC_WUDR_MASK,
  	.write_alarm_udr_mask	= S2MPS15_RTC_AUDR_MASK,
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
141
  };
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
142
143
  struct s5m_rtc_info {
  	struct device *dev;
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
144
  	struct i2c_client *i2c;
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
145
  	struct sec_pmic_dev *s5m87xx;
5ccb7d718   Geert Uytterhoeven   drivers/rtc/rtc-s...
146
  	struct regmap *regmap;
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
147
148
  	struct rtc_device *rtc_dev;
  	int irq;
94f919225   Krzysztof Kozlowski   drivers/rtc/rtc-s...
149
  	enum sec_device_type device_type;
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
150
  	int rtc_24hr_mode;
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
151
  	const struct s5m_rtc_reg_config	*regs;
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
152
  };
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
153
154
155
  static const struct regmap_config s5m_rtc_regmap_config = {
  	.reg_bits = 8,
  	.val_bits = 8,
602cb5bba   Krzysztof Kozlowski   mfd/rtc: sec/s5m:...
156
  	.max_register = S5M_RTC_REG_MAX,
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
157
158
159
160
161
162
163
164
  };
  
  static const struct regmap_config s2mps14_rtc_regmap_config = {
  	.reg_bits = 8,
  	.val_bits = 8,
  
  	.max_register = S2MPS_RTC_REG_MAX,
  };
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
  static void s5m8767_data_to_tm(u8 *data, struct rtc_time *tm,
  			       int rtc_24hr_mode)
  {
  	tm->tm_sec = data[RTC_SEC] & 0x7f;
  	tm->tm_min = data[RTC_MIN] & 0x7f;
  	if (rtc_24hr_mode) {
  		tm->tm_hour = data[RTC_HOUR] & 0x1f;
  	} else {
  		tm->tm_hour = data[RTC_HOUR] & 0x0f;
  		if (data[RTC_HOUR] & HOUR_PM_MASK)
  			tm->tm_hour += 12;
  	}
  
  	tm->tm_wday = ffs(data[RTC_WEEKDAY] & 0x7f);
  	tm->tm_mday = data[RTC_DATE] & 0x1f;
  	tm->tm_mon = (data[RTC_MONTH] & 0x0f) - 1;
  	tm->tm_year = (data[RTC_YEAR1] & 0x7f) + 100;
  	tm->tm_yday = 0;
  	tm->tm_isdst = 0;
  }
  
  static int s5m8767_tm_to_data(struct rtc_time *tm, u8 *data)
  {
  	data[RTC_SEC] = tm->tm_sec;
  	data[RTC_MIN] = tm->tm_min;
  
  	if (tm->tm_hour >= 12)
  		data[RTC_HOUR] = tm->tm_hour | HOUR_PM_MASK;
  	else
  		data[RTC_HOUR] = tm->tm_hour & ~HOUR_PM_MASK;
  
  	data[RTC_WEEKDAY] = 1 << tm->tm_wday;
  	data[RTC_DATE] = tm->tm_mday;
  	data[RTC_MONTH] = tm->tm_mon + 1;
  	data[RTC_YEAR1] = tm->tm_year > 100 ? (tm->tm_year - 100) : 0;
  
  	if (tm->tm_year < 100) {
a737e835e   Joe Perches   rtc: use more sta...
202
203
  		pr_err("RTC cannot handle the year %d
  ",
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
204
205
206
207
208
209
  		       1900 + tm->tm_year);
  		return -EINVAL;
  	} else {
  		return 0;
  	}
  }
d73238d4a   Krzysztof Kozlowski   rtc: s5m: limit e...
210
211
212
213
  /*
   * Read RTC_UDR_CON register and wait till UDR field is cleared.
   * This indicates that time/alarm update ended.
   */
8124c7117   Krzysztof Kozlowski   rtc: s5m: De-inli...
214
  static int s5m8767_wait_for_udr_update(struct s5m_rtc_info *info)
d73238d4a   Krzysztof Kozlowski   rtc: s5m: limit e...
215
216
217
218
219
  {
  	int ret, retry = UDR_READ_RETRY_CNT;
  	unsigned int data;
  
  	do {
a83a793ad   Krzysztof Kozlowski   rtc: s5m: Cleanup...
220
  		ret = regmap_read(info->regmap, info->regs->udr_update, &data);
67a6025a7   Krzysztof Kozlowski   rtc: s5m: Add sep...
221
  	} while (--retry && (data & info->regs->autoclear_udr_mask) && !ret);
d73238d4a   Krzysztof Kozlowski   rtc: s5m: limit e...
222
223
224
225
226
227
228
  
  	if (!retry)
  		dev_err(info->dev, "waiting for UDR update, reached max number of retries
  ");
  
  	return ret;
  }
8124c7117   Krzysztof Kozlowski   rtc: s5m: De-inli...
229
  static int s5m_check_peding_alarm_interrupt(struct s5m_rtc_info *info,
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
230
231
232
233
234
235
236
237
238
239
240
  		struct rtc_wkalrm *alarm)
  {
  	int ret;
  	unsigned int val;
  
  	switch (info->device_type) {
  	case S5M8767X:
  	case S5M8763X:
  		ret = regmap_read(info->regmap, S5M_RTC_STATUS, &val);
  		val &= S5M_ALARM0_STATUS;
  		break;
a65e5efa7   Alim Akhtar   rtc: s5m.c: Add s...
241
  	case S2MPS15X:
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
242
  	case S2MPS14X:
5281f94ae   Krzysztof Kozlowski   drivers/rtc/rtc-s...
243
  	case S2MPS13X:
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
244
245
246
247
  		ret = regmap_read(info->s5m87xx->regmap_pmic, S2MPS14_REG_ST2,
  				&val);
  		val &= S2MPS_ALARM0_STATUS;
  		break;
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
248
249
250
251
252
253
254
255
256
257
258
259
260
  	default:
  		return -EINVAL;
  	}
  	if (ret < 0)
  		return ret;
  
  	if (val)
  		alarm->pending = 1;
  	else
  		alarm->pending = 0;
  
  	return 0;
  }
8124c7117   Krzysztof Kozlowski   rtc: s5m: De-inli...
261
  static int s5m8767_rtc_set_time_reg(struct s5m_rtc_info *info)
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
262
263
264
  {
  	int ret;
  	unsigned int data;
a83a793ad   Krzysztof Kozlowski   rtc: s5m: Cleanup...
265
  	ret = regmap_read(info->regmap, info->regs->udr_update, &data);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
266
267
268
269
270
  	if (ret < 0) {
  		dev_err(info->dev, "failed to read update reg(%d)
  ", ret);
  		return ret;
  	}
8ae83b6f7   Krzysztof Kozlowski   rtc: s5m: Make re...
271
  	data |= info->regs->write_time_udr_mask;
a65e5efa7   Alim Akhtar   rtc: s5m.c: Add s...
272

a83a793ad   Krzysztof Kozlowski   rtc: s5m: Cleanup...
273
  	ret = regmap_write(info->regmap, info->regs->udr_update, data);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
274
275
276
277
278
  	if (ret < 0) {
  		dev_err(info->dev, "failed to write update reg(%d)
  ", ret);
  		return ret;
  	}
d73238d4a   Krzysztof Kozlowski   rtc: s5m: limit e...
279
  	ret = s5m8767_wait_for_udr_update(info);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
280
281
282
  
  	return ret;
  }
8124c7117   Krzysztof Kozlowski   rtc: s5m: De-inli...
283
  static int s5m8767_rtc_set_alarm_reg(struct s5m_rtc_info *info)
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
284
285
286
  {
  	int ret;
  	unsigned int data;
a83a793ad   Krzysztof Kozlowski   rtc: s5m: Cleanup...
287
  	ret = regmap_read(info->regmap, info->regs->udr_update, &data);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
288
289
290
291
292
293
  	if (ret < 0) {
  		dev_err(info->dev, "%s: fail to read update reg(%d)
  ",
  			__func__, ret);
  		return ret;
  	}
8ae83b6f7   Krzysztof Kozlowski   rtc: s5m: Make re...
294
  	data |= info->regs->write_alarm_udr_mask;
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
295
296
297
298
299
  	switch (info->device_type) {
  	case S5M8763X:
  	case S5M8767X:
  		data &= ~S5M_RTC_TIME_EN_MASK;
  		break;
a65e5efa7   Alim Akhtar   rtc: s5m.c: Add s...
300
  	case S2MPS15X:
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
301
  	case S2MPS14X:
5281f94ae   Krzysztof Kozlowski   drivers/rtc/rtc-s...
302
  	case S2MPS13X:
8ae83b6f7   Krzysztof Kozlowski   rtc: s5m: Make re...
303
  		/* No exceptions needed */
5281f94ae   Krzysztof Kozlowski   drivers/rtc/rtc-s...
304
  		break;
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
305
306
307
  	default:
  		return -EINVAL;
  	}
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
308

a83a793ad   Krzysztof Kozlowski   rtc: s5m: Cleanup...
309
  	ret = regmap_write(info->regmap, info->regs->udr_update, data);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
310
311
312
313
314
315
  	if (ret < 0) {
  		dev_err(info->dev, "%s: fail to write update reg(%d)
  ",
  			__func__, ret);
  		return ret;
  	}
d73238d4a   Krzysztof Kozlowski   rtc: s5m: limit e...
316
  	ret = s5m8767_wait_for_udr_update(info);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
317

5281f94ae   Krzysztof Kozlowski   drivers/rtc/rtc-s...
318
319
  	/* On S2MPS13 the AUDR is not auto-cleared */
  	if (info->device_type == S2MPS13X)
a83a793ad   Krzysztof Kozlowski   rtc: s5m: Cleanup...
320
  		regmap_update_bits(info->regmap, info->regs->udr_update,
5281f94ae   Krzysztof Kozlowski   drivers/rtc/rtc-s...
321
  				   S2MPS13_RTC_AUDR_MASK, 0);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
  	return ret;
  }
  
  static void s5m8763_data_to_tm(u8 *data, struct rtc_time *tm)
  {
  	tm->tm_sec = bcd2bin(data[RTC_SEC]);
  	tm->tm_min = bcd2bin(data[RTC_MIN]);
  
  	if (data[RTC_HOUR] & HOUR_12) {
  		tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x1f);
  		if (data[RTC_HOUR] & HOUR_PM)
  			tm->tm_hour += 12;
  	} else {
  		tm->tm_hour = bcd2bin(data[RTC_HOUR] & 0x3f);
  	}
  
  	tm->tm_wday = data[RTC_WEEKDAY] & 0x07;
  	tm->tm_mday = bcd2bin(data[RTC_DATE]);
  	tm->tm_mon = bcd2bin(data[RTC_MONTH]);
  	tm->tm_year = bcd2bin(data[RTC_YEAR1]) + bcd2bin(data[RTC_YEAR2]) * 100;
  	tm->tm_year -= 1900;
  }
  
  static void s5m8763_tm_to_data(struct rtc_time *tm, u8 *data)
  {
  	data[RTC_SEC] = bin2bcd(tm->tm_sec);
  	data[RTC_MIN] = bin2bcd(tm->tm_min);
  	data[RTC_HOUR] = bin2bcd(tm->tm_hour);
  	data[RTC_WEEKDAY] = tm->tm_wday;
  	data[RTC_DATE] = bin2bcd(tm->tm_mday);
  	data[RTC_MONTH] = bin2bcd(tm->tm_mon);
  	data[RTC_YEAR1] = bin2bcd(tm->tm_year % 100);
  	data[RTC_YEAR2] = bin2bcd((tm->tm_year + 1900) / 100);
  }
  
  static int s5m_rtc_read_time(struct device *dev, struct rtc_time *tm)
  {
  	struct s5m_rtc_info *info = dev_get_drvdata(dev);
756d5282b   Gustavo A. R. Silva   rtc: s5m: Remove ...
360
  	u8 data[RTC_MAX_NUM_TIME_REGS];
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
361
  	int ret;
8ae83b6f7   Krzysztof Kozlowski   rtc: s5m: Make re...
362
  	if (info->regs->read_time_udr_mask) {
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
363
  		ret = regmap_update_bits(info->regmap,
a83a793ad   Krzysztof Kozlowski   rtc: s5m: Cleanup...
364
  				info->regs->udr_update,
8ae83b6f7   Krzysztof Kozlowski   rtc: s5m: Make re...
365
366
  				info->regs->read_time_udr_mask,
  				info->regs->read_time_udr_mask);
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
367
368
369
370
371
372
373
374
  		if (ret) {
  			dev_err(dev,
  				"Failed to prepare registers for time reading: %d
  ",
  				ret);
  			return ret;
  		}
  	}
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
375
376
  	ret = regmap_bulk_read(info->regmap, info->regs->time, data,
  			info->regs->regs_count);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
377
378
379
380
381
382
383
384
385
  	if (ret < 0)
  		return ret;
  
  	switch (info->device_type) {
  	case S5M8763X:
  		s5m8763_data_to_tm(data, tm);
  		break;
  
  	case S5M8767X:
a65e5efa7   Alim Akhtar   rtc: s5m.c: Add s...
386
  	case S2MPS15X:
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
387
  	case S2MPS14X:
5281f94ae   Krzysztof Kozlowski   drivers/rtc/rtc-s...
388
  	case S2MPS13X:
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
389
390
391
392
393
394
  		s5m8767_data_to_tm(data, tm, info->rtc_24hr_mode);
  		break;
  
  	default:
  		return -EINVAL;
  	}
5527842ea   Andy Shevchenko   rtc: s5m: Switch ...
395
396
  	dev_dbg(dev, "%s: %ptR(%d)
  ", __func__, tm, tm->tm_wday);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
397

22652ba72   Alexandre Belloni   rtc: stop validat...
398
  	return 0;
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
399
400
401
402
403
  }
  
  static int s5m_rtc_set_time(struct device *dev, struct rtc_time *tm)
  {
  	struct s5m_rtc_info *info = dev_get_drvdata(dev);
756d5282b   Gustavo A. R. Silva   rtc: s5m: Remove ...
404
  	u8 data[RTC_MAX_NUM_TIME_REGS];
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
405
406
407
408
409
410
411
  	int ret = 0;
  
  	switch (info->device_type) {
  	case S5M8763X:
  		s5m8763_tm_to_data(tm, data);
  		break;
  	case S5M8767X:
a65e5efa7   Alim Akhtar   rtc: s5m.c: Add s...
412
  	case S2MPS15X:
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
413
  	case S2MPS14X:
5281f94ae   Krzysztof Kozlowski   drivers/rtc/rtc-s...
414
  	case S2MPS13X:
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
415
416
417
418
419
420
421
422
  		ret = s5m8767_tm_to_data(tm, data);
  		break;
  	default:
  		return -EINVAL;
  	}
  
  	if (ret < 0)
  		return ret;
5527842ea   Andy Shevchenko   rtc: s5m: Switch ...
423
424
  	dev_dbg(dev, "%s: %ptR(%d)
  ", __func__, tm, tm->tm_wday);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
425

f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
426
427
  	ret = regmap_raw_write(info->regmap, info->regs->time, data,
  			info->regs->regs_count);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
428
429
430
431
432
433
434
435
436
437
438
  	if (ret < 0)
  		return ret;
  
  	ret = s5m8767_rtc_set_time_reg(info);
  
  	return ret;
  }
  
  static int s5m_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  {
  	struct s5m_rtc_info *info = dev_get_drvdata(dev);
756d5282b   Gustavo A. R. Silva   rtc: s5m: Remove ...
439
  	u8 data[RTC_MAX_NUM_TIME_REGS];
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
440
441
  	unsigned int val;
  	int ret, i;
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
442
443
  	ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data,
  			info->regs->regs_count);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
444
445
446
447
448
449
  	if (ret < 0)
  		return ret;
  
  	switch (info->device_type) {
  	case S5M8763X:
  		s5m8763_data_to_tm(data, &alrm->time);
602cb5bba   Krzysztof Kozlowski   mfd/rtc: sec/s5m:...
450
  		ret = regmap_read(info->regmap, S5M_ALARM0_CONF, &val);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
451
452
453
454
  		if (ret < 0)
  			return ret;
  
  		alrm->enabled = !!val;
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
455
456
457
  		break;
  
  	case S5M8767X:
a65e5efa7   Alim Akhtar   rtc: s5m.c: Add s...
458
  	case S2MPS15X:
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
459
  	case S2MPS14X:
5281f94ae   Krzysztof Kozlowski   drivers/rtc/rtc-s...
460
  	case S2MPS13X:
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
461
  		s5m8767_data_to_tm(data, &alrm->time, info->rtc_24hr_mode);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
462
  		alrm->enabled = 0;
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
463
  		for (i = 0; i < info->regs->regs_count; i++) {
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
464
465
466
467
468
  			if (data[i] & ALARM_ENABLE_MASK) {
  				alrm->enabled = 1;
  				break;
  			}
  		}
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
469
470
471
472
473
  		break;
  
  	default:
  		return -EINVAL;
  	}
5527842ea   Andy Shevchenko   rtc: s5m: Switch ...
474
475
  	dev_dbg(dev, "%s: %ptR(%d)
  ", __func__, &alrm->time, alrm->time.tm_wday);
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
476
477
  
  	ret = s5m_check_peding_alarm_interrupt(info, alrm);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
478
479
480
481
482
483
  
  	return 0;
  }
  
  static int s5m_rtc_stop_alarm(struct s5m_rtc_info *info)
  {
756d5282b   Gustavo A. R. Silva   rtc: s5m: Remove ...
484
  	u8 data[RTC_MAX_NUM_TIME_REGS];
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
485
486
  	int ret, i;
  	struct rtc_time tm;
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
487
488
  	ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data,
  			info->regs->regs_count);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
489
490
491
492
  	if (ret < 0)
  		return ret;
  
  	s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode);
5527842ea   Andy Shevchenko   rtc: s5m: Switch ...
493
494
  	dev_dbg(info->dev, "%s: %ptR(%d)
  ", __func__, &tm, tm.tm_wday);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
495
496
497
  
  	switch (info->device_type) {
  	case S5M8763X:
602cb5bba   Krzysztof Kozlowski   mfd/rtc: sec/s5m:...
498
  		ret = regmap_write(info->regmap, S5M_ALARM0_CONF, 0);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
499
500
501
  		break;
  
  	case S5M8767X:
a65e5efa7   Alim Akhtar   rtc: s5m.c: Add s...
502
  	case S2MPS15X:
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
503
  	case S2MPS14X:
5281f94ae   Krzysztof Kozlowski   drivers/rtc/rtc-s...
504
  	case S2MPS13X:
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
505
  		for (i = 0; i < info->regs->regs_count; i++)
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
506
  			data[i] &= ~ALARM_ENABLE_MASK;
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
507
508
  		ret = regmap_raw_write(info->regmap, info->regs->alarm0, data,
  				info->regs->regs_count);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
  		if (ret < 0)
  			return ret;
  
  		ret = s5m8767_rtc_set_alarm_reg(info);
  
  		break;
  
  	default:
  		return -EINVAL;
  	}
  
  	return ret;
  }
  
  static int s5m_rtc_start_alarm(struct s5m_rtc_info *info)
  {
  	int ret;
756d5282b   Gustavo A. R. Silva   rtc: s5m: Remove ...
526
  	u8 data[RTC_MAX_NUM_TIME_REGS];
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
527
528
  	u8 alarm0_conf;
  	struct rtc_time tm;
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
529
530
  	ret = regmap_bulk_read(info->regmap, info->regs->alarm0, data,
  			info->regs->regs_count);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
531
532
533
534
  	if (ret < 0)
  		return ret;
  
  	s5m8767_data_to_tm(data, &tm, info->rtc_24hr_mode);
5527842ea   Andy Shevchenko   rtc: s5m: Switch ...
535
536
  	dev_dbg(info->dev, "%s: %ptR(%d)
  ", __func__, &tm, tm.tm_wday);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
537
538
539
540
  
  	switch (info->device_type) {
  	case S5M8763X:
  		alarm0_conf = 0x77;
602cb5bba   Krzysztof Kozlowski   mfd/rtc: sec/s5m:...
541
  		ret = regmap_write(info->regmap, S5M_ALARM0_CONF, alarm0_conf);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
542
543
544
  		break;
  
  	case S5M8767X:
a65e5efa7   Alim Akhtar   rtc: s5m.c: Add s...
545
  	case S2MPS15X:
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
546
  	case S2MPS14X:
5281f94ae   Krzysztof Kozlowski   drivers/rtc/rtc-s...
547
  	case S2MPS13X:
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
548
549
550
551
552
553
554
555
556
557
  		data[RTC_SEC] |= ALARM_ENABLE_MASK;
  		data[RTC_MIN] |= ALARM_ENABLE_MASK;
  		data[RTC_HOUR] |= ALARM_ENABLE_MASK;
  		data[RTC_WEEKDAY] &= ~ALARM_ENABLE_MASK;
  		if (data[RTC_DATE] & 0x1f)
  			data[RTC_DATE] |= ALARM_ENABLE_MASK;
  		if (data[RTC_MONTH] & 0xf)
  			data[RTC_MONTH] |= ALARM_ENABLE_MASK;
  		if (data[RTC_YEAR1] & 0x7f)
  			data[RTC_YEAR1] |= ALARM_ENABLE_MASK;
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
558
559
  		ret = regmap_raw_write(info->regmap, info->regs->alarm0, data,
  				info->regs->regs_count);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
  		if (ret < 0)
  			return ret;
  		ret = s5m8767_rtc_set_alarm_reg(info);
  
  		break;
  
  	default:
  		return -EINVAL;
  	}
  
  	return ret;
  }
  
  static int s5m_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  {
  	struct s5m_rtc_info *info = dev_get_drvdata(dev);
756d5282b   Gustavo A. R. Silva   rtc: s5m: Remove ...
576
  	u8 data[RTC_MAX_NUM_TIME_REGS];
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
577
578
579
580
581
582
583
584
  	int ret;
  
  	switch (info->device_type) {
  	case S5M8763X:
  		s5m8763_tm_to_data(&alrm->time, data);
  		break;
  
  	case S5M8767X:
a65e5efa7   Alim Akhtar   rtc: s5m.c: Add s...
585
  	case S2MPS15X:
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
586
  	case S2MPS14X:
5281f94ae   Krzysztof Kozlowski   drivers/rtc/rtc-s...
587
  	case S2MPS13X:
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
588
589
590
591
592
593
  		s5m8767_tm_to_data(&alrm->time, data);
  		break;
  
  	default:
  		return -EINVAL;
  	}
5527842ea   Andy Shevchenko   rtc: s5m: Switch ...
594
595
  	dev_dbg(dev, "%s: %ptR(%d)
  ", __func__, &alrm->time, alrm->time.tm_wday);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
596
597
598
599
  
  	ret = s5m_rtc_stop_alarm(info);
  	if (ret < 0)
  		return ret;
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
600
601
  	ret = regmap_raw_write(info->regmap, info->regs->alarm0, data,
  			info->regs->regs_count);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
  	if (ret < 0)
  		return ret;
  
  	ret = s5m8767_rtc_set_alarm_reg(info);
  	if (ret < 0)
  		return ret;
  
  	if (alrm->enabled)
  		ret = s5m_rtc_start_alarm(info);
  
  	return ret;
  }
  
  static int s5m_rtc_alarm_irq_enable(struct device *dev,
  				    unsigned int enabled)
  {
  	struct s5m_rtc_info *info = dev_get_drvdata(dev);
  
  	if (enabled)
  		return s5m_rtc_start_alarm(info);
  	else
  		return s5m_rtc_stop_alarm(info);
  }
  
  static irqreturn_t s5m_rtc_alarm_irq(int irq, void *data)
  {
  	struct s5m_rtc_info *info = data;
  
  	rtc_update_irq(info->rtc_dev, 1, RTC_IRQF | RTC_AF);
  
  	return IRQ_HANDLED;
  }
  
  static const struct rtc_class_ops s5m_rtc_ops = {
  	.read_time = s5m_rtc_read_time,
  	.set_time = s5m_rtc_set_time,
  	.read_alarm = s5m_rtc_read_alarm,
  	.set_alarm = s5m_rtc_set_alarm,
  	.alarm_irq_enable = s5m_rtc_alarm_irq_enable,
  };
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
642
643
644
  static int s5m8767_rtc_init_reg(struct s5m_rtc_info *info)
  {
  	u8 data[2];
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
645
  	int ret;
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
646

0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
647
648
649
650
651
652
653
654
655
656
  	switch (info->device_type) {
  	case S5M8763X:
  	case S5M8767X:
  		/* UDR update time. Default of 7.32 ms is too long. */
  		ret = regmap_update_bits(info->regmap, S5M_RTC_UDR_CON,
  				S5M_RTC_UDR_T_MASK, S5M_RTC_UDR_T_450_US);
  		if (ret < 0)
  			dev_err(info->dev, "%s: fail to change UDR time: %d
  ",
  					__func__, ret);
0c5f5d9af   Krzysztof Kozlowski   rtc: s5m: use sho...
657

0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
658
659
660
661
662
663
  		/* Set RTC control register : Binary mode, 24hour mode */
  		data[0] = (1 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
  		data[1] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
  
  		ret = regmap_raw_write(info->regmap, S5M_ALARM0_CONF, data, 2);
  		break;
a65e5efa7   Alim Akhtar   rtc: s5m.c: Add s...
664
  	case S2MPS15X:
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
665
  	case S2MPS14X:
5281f94ae   Krzysztof Kozlowski   drivers/rtc/rtc-s...
666
  	case S2MPS13X:
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
667
668
  		data[0] = (0 << BCD_EN_SHIFT) | (1 << MODEL24_SHIFT);
  		ret = regmap_write(info->regmap, info->regs->ctrl, data[0]);
ff02c0444   Joonyoung Shim   rtc: s5m: fix to ...
669
670
671
672
673
674
675
676
677
678
  		if (ret < 0)
  			break;
  
  		/*
  		 * Should set WUDR & (RUDR or AUDR) bits to high after writing
  		 * RTC_CTRL register like writing Alarm registers. We can't find
  		 * the description from datasheet but vendor code does that
  		 * really.
  		 */
  		ret = s5m8767_rtc_set_alarm_reg(info);
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
679
680
681
682
683
  		break;
  
  	default:
  		return -EINVAL;
  	}
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
684
685
  
  	info->rtc_24hr_mode = 1;
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
686
687
688
689
690
691
  	if (ret < 0) {
  		dev_err(info->dev, "%s: fail to write controlm reg(%d)
  ",
  			__func__, ret);
  		return ret;
  	}
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
692
693
694
695
696
697
698
699
  	return ret;
  }
  
  static int s5m_rtc_probe(struct platform_device *pdev)
  {
  	struct sec_pmic_dev *s5m87xx = dev_get_drvdata(pdev->dev.parent);
  	struct sec_platform_data *pdata = s5m87xx->pdata;
  	struct s5m_rtc_info *info;
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
700
  	const struct regmap_config *regmap_cfg;
a0347f20a   Krzysztof Kozlowski   rtc: s5m: consoli...
701
  	int ret, alarm_irq;
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
702
703
704
705
706
707
708
709
710
711
  
  	if (!pdata) {
  		dev_err(pdev->dev.parent, "Platform data not supplied
  ");
  		return -ENODEV;
  	}
  
  	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
  	if (!info)
  		return -ENOMEM;
94f919225   Krzysztof Kozlowski   drivers/rtc/rtc-s...
712
  	switch (platform_get_device_id(pdev)->driver_data) {
a65e5efa7   Alim Akhtar   rtc: s5m.c: Add s...
713
  	case S2MPS15X:
8ae83b6f7   Krzysztof Kozlowski   rtc: s5m: Make re...
714
715
716
717
  		regmap_cfg = &s2mps14_rtc_regmap_config;
  		info->regs = &s2mps15_rtc_regs;
  		alarm_irq = S2MPS14_IRQ_RTCA0;
  		break;
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
718
  	case S2MPS14X:
8ae83b6f7   Krzysztof Kozlowski   rtc: s5m: Make re...
719
720
721
722
  		regmap_cfg = &s2mps14_rtc_regmap_config;
  		info->regs = &s2mps14_rtc_regs;
  		alarm_irq = S2MPS14_IRQ_RTCA0;
  		break;
5281f94ae   Krzysztof Kozlowski   drivers/rtc/rtc-s...
723
  	case S2MPS13X:
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
724
  		regmap_cfg = &s2mps14_rtc_regmap_config;
8ae83b6f7   Krzysztof Kozlowski   rtc: s5m: Make re...
725
  		info->regs = &s2mps13_rtc_regs;
a0347f20a   Krzysztof Kozlowski   rtc: s5m: consoli...
726
  		alarm_irq = S2MPS14_IRQ_RTCA0;
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
727
728
729
  		break;
  	case S5M8763X:
  		regmap_cfg = &s5m_rtc_regmap_config;
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
730
  		info->regs = &s5m_rtc_regs;
a0347f20a   Krzysztof Kozlowski   rtc: s5m: consoli...
731
  		alarm_irq = S5M8763_IRQ_ALARM0;
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
732
733
734
  		break;
  	case S5M8767X:
  		regmap_cfg = &s5m_rtc_regmap_config;
f8b23bbda   Krzysztof Kozlowski   rtc: s5m: support...
735
  		info->regs = &s5m_rtc_regs;
a0347f20a   Krzysztof Kozlowski   rtc: s5m: consoli...
736
  		alarm_irq = S5M8767_IRQ_RTCA1;
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
737
738
  		break;
  	default:
94f919225   Krzysztof Kozlowski   drivers/rtc/rtc-s...
739
740
741
742
  		dev_err(&pdev->dev,
  				"Device type %lu is not supported by RTC driver
  ",
  				platform_get_device_id(pdev)->driver_data);
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
743
744
  		return -ENODEV;
  	}
aae364d2a   Wolfram Sang   rtc: s5m: convert...
745
746
  	info->i2c = i2c_new_dummy_device(s5m87xx->i2c->adapter, RTC_I2C_ADDR);
  	if (IS_ERR(info->i2c)) {
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
747
748
  		dev_err(&pdev->dev, "Failed to allocate I2C for RTC
  ");
aae364d2a   Wolfram Sang   rtc: s5m: convert...
749
  		return PTR_ERR(info->i2c);
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
750
751
752
753
754
755
756
757
758
759
  	}
  
  	info->regmap = devm_regmap_init_i2c(info->i2c, regmap_cfg);
  	if (IS_ERR(info->regmap)) {
  		ret = PTR_ERR(info->regmap);
  		dev_err(&pdev->dev, "Failed to allocate RTC register map: %d
  ",
  				ret);
  		goto err;
  	}
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
760
761
  	info->dev = &pdev->dev;
  	info->s5m87xx = s5m87xx;
94f919225   Krzysztof Kozlowski   drivers/rtc/rtc-s...
762
  	info->device_type = platform_get_device_id(pdev)->driver_data;
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
763

b7d5b9a96   Bartlomiej Zolnierkiewicz   drivers/rtc/rtc-s...
764
765
766
767
768
769
  	if (s5m87xx->irq_data) {
  		info->irq = regmap_irq_get_virq(s5m87xx->irq_data, alarm_irq);
  		if (info->irq <= 0) {
  			ret = -EINVAL;
  			dev_err(&pdev->dev, "Failed to get virtual IRQ %d
  ",
a0347f20a   Krzysztof Kozlowski   rtc: s5m: consoli...
770
  				alarm_irq);
b7d5b9a96   Bartlomiej Zolnierkiewicz   drivers/rtc/rtc-s...
771
772
  			goto err;
  		}
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
773
774
775
776
777
  	}
  
  	platform_set_drvdata(pdev, info);
  
  	ret = s5m8767_rtc_init_reg(info);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
778
779
780
781
  	device_init_wakeup(&pdev->dev, 1);
  
  	info->rtc_dev = devm_rtc_device_register(&pdev->dev, "s5m-rtc",
  						 &s5m_rtc_ops, THIS_MODULE);
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
782
783
784
785
  	if (IS_ERR(info->rtc_dev)) {
  		ret = PTR_ERR(info->rtc_dev);
  		goto err;
  	}
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
786

b7d5b9a96   Bartlomiej Zolnierkiewicz   drivers/rtc/rtc-s...
787
788
789
790
791
  	if (!info->irq) {
  		dev_info(&pdev->dev, "Alarm IRQ not available
  ");
  		return 0;
  	}
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
792
793
794
  	ret = devm_request_threaded_irq(&pdev->dev, info->irq, NULL,
  					s5m_rtc_alarm_irq, 0, "rtc-alarm0",
  					info);
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
795
  	if (ret < 0) {
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
796
797
798
  		dev_err(&pdev->dev, "Failed to request alarm IRQ: %d: %d
  ",
  			info->irq, ret);
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
799
800
801
802
803
804
805
  		goto err;
  	}
  
  	return 0;
  
  err:
  	i2c_unregister_device(info->i2c);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
806
807
808
  
  	return ret;
  }
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
809
810
811
  static int s5m_rtc_remove(struct platform_device *pdev)
  {
  	struct s5m_rtc_info *info = platform_get_drvdata(pdev);
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
812
813
814
815
  	i2c_unregister_device(info->i2c);
  
  	return 0;
  }
11ba5a1ee   Geert Uytterhoeven   drivers/rtc/rtc-s...
816
  #ifdef CONFIG_PM_SLEEP
222ead7fd   Krzysztof Kozlowski   rtc: s5m: enable ...
817
818
819
820
  static int s5m_rtc_resume(struct device *dev)
  {
  	struct s5m_rtc_info *info = dev_get_drvdata(dev);
  	int ret = 0;
b7d5b9a96   Bartlomiej Zolnierkiewicz   drivers/rtc/rtc-s...
821
  	if (info->irq && device_may_wakeup(dev))
222ead7fd   Krzysztof Kozlowski   rtc: s5m: enable ...
822
823
824
825
826
827
828
829
830
  		ret = disable_irq_wake(info->irq);
  
  	return ret;
  }
  
  static int s5m_rtc_suspend(struct device *dev)
  {
  	struct s5m_rtc_info *info = dev_get_drvdata(dev);
  	int ret = 0;
b7d5b9a96   Bartlomiej Zolnierkiewicz   drivers/rtc/rtc-s...
831
  	if (info->irq && device_may_wakeup(dev))
222ead7fd   Krzysztof Kozlowski   rtc: s5m: enable ...
832
833
834
835
  		ret = enable_irq_wake(info->irq);
  
  	return ret;
  }
11ba5a1ee   Geert Uytterhoeven   drivers/rtc/rtc-s...
836
  #endif /* CONFIG_PM_SLEEP */
222ead7fd   Krzysztof Kozlowski   rtc: s5m: enable ...
837
838
  
  static SIMPLE_DEV_PM_OPS(s5m_rtc_pm_ops, s5m_rtc_suspend, s5m_rtc_resume);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
839
  static const struct platform_device_id s5m_rtc_id[] = {
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
840
  	{ "s5m-rtc",		S5M8767X },
5281f94ae   Krzysztof Kozlowski   drivers/rtc/rtc-s...
841
  	{ "s2mps13-rtc",	S2MPS13X },
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
842
  	{ "s2mps14-rtc",	S2MPS14X },
a65e5efa7   Alim Akhtar   rtc: s5m.c: Add s...
843
  	{ "s2mps15-rtc",	S2MPS15X },
45cd15e60   Andrey Ryabinin   drivers/rtc/rtc-s...
844
  	{ },
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
845
  };
63074cc3d   Javier Martinez Canillas   rtc: Fix module a...
846
  MODULE_DEVICE_TABLE(platform, s5m_rtc_id);
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
847
848
849
850
  
  static struct platform_driver s5m_rtc_driver = {
  	.driver		= {
  		.name	= "s5m-rtc",
222ead7fd   Krzysztof Kozlowski   rtc: s5m: enable ...
851
  		.pm	= &s5m_rtc_pm_ops,
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
852
853
  	},
  	.probe		= s5m_rtc_probe,
e349c910e   Krzysztof Kozlowski   mfd/rtc: s5m: Do ...
854
  	.remove		= s5m_rtc_remove,
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
855
856
857
858
859
860
861
  	.id_table	= s5m_rtc_id,
  };
  
  module_platform_driver(s5m_rtc_driver);
  
  /* Module information */
  MODULE_AUTHOR("Sangbeom Kim <sbkim73@samsung.com>");
0c5deb1ea   Krzysztof Kozlowski   rtc: s5m: add sup...
862
  MODULE_DESCRIPTION("Samsung S5M/S2MPS14 RTC driver");
5bccae6ec   Sangbeom Kim   rtc: s5m-rtc: add...
863
864
  MODULE_LICENSE("GPL");
  MODULE_ALIAS("platform:s5m-rtc");