Blame view

drivers/rtc/rtc-ds3232.c 17.1 KB
2874c5fd2   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
c03675f05   Roy Zang   rtc: add support ...
2
  /*
080481f54   Akinobu Mita   rtc: merge ds3232...
3
   * RTC client/driver for the Maxim/Dallas DS3232/DS3234 Real-Time Clock
c03675f05   Roy Zang   rtc: add support ...
4
   *
a2d6d2fa9   Lei Xu   drivers/rtc/rtc-d...
5
   * Copyright (C) 2009-2011 Freescale Semiconductor.
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
6
   * Author: Jack Lan <jack.lan@freescale.com>
080481f54   Akinobu Mita   rtc: merge ds3232...
7
   * Copyright (C) 2008 MIMOMax Wireless Ltd.
c03675f05   Roy Zang   rtc: add support ...
8
   */
c03675f05   Roy Zang   rtc: add support ...
9

a737e835e   Joe Perches   rtc: use more sta...
10
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
c03675f05   Roy Zang   rtc: add support ...
11
12
13
14
  #include <linux/kernel.h>
  #include <linux/module.h>
  #include <linux/interrupt.h>
  #include <linux/i2c.h>
080481f54   Akinobu Mita   rtc: merge ds3232...
15
  #include <linux/spi/spi.h>
c03675f05   Roy Zang   rtc: add support ...
16
17
  #include <linux/rtc.h>
  #include <linux/bcd.h>
c03675f05   Roy Zang   rtc: add support ...
18
  #include <linux/slab.h>
370927c4b   Akinobu Mita   rtc: ds3232: conv...
19
  #include <linux/regmap.h>
c35c4195f   Kirill Esipov   rtc: ds3232: add ...
20
  #include <linux/hwmon.h>
c03675f05   Roy Zang   rtc: add support ...
21

ca4b0a6de   Phil Reid   rtc: ds3232: Clea...
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
  #define DS3232_REG_SECONDS      0x00
  #define DS3232_REG_MINUTES      0x01
  #define DS3232_REG_HOURS        0x02
  #define DS3232_REG_AMPM         0x02
  #define DS3232_REG_DAY          0x03
  #define DS3232_REG_DATE         0x04
  #define DS3232_REG_MONTH        0x05
  #define DS3232_REG_CENTURY      0x05
  #define DS3232_REG_YEAR         0x06
  #define DS3232_REG_ALARM1       0x07       /* Alarm 1 BASE */
  #define DS3232_REG_ALARM2       0x0B       /* Alarm 2 BASE */
  #define DS3232_REG_CR           0x0E       /* Control register */
  #       define DS3232_REG_CR_nEOSC   0x80
  #       define DS3232_REG_CR_INTCN   0x04
  #       define DS3232_REG_CR_A2IE    0x02
  #       define DS3232_REG_CR_A1IE    0x01
c03675f05   Roy Zang   rtc: add support ...
38

ca4b0a6de   Phil Reid   rtc: ds3232: Clea...
39
40
41
42
43
  #define DS3232_REG_SR           0x0F       /* control/status register */
  #       define DS3232_REG_SR_OSF     0x80
  #       define DS3232_REG_SR_BSY     0x04
  #       define DS3232_REG_SR_A2F     0x02
  #       define DS3232_REG_SR_A1F     0x01
c03675f05   Roy Zang   rtc: add support ...
44

c35c4195f   Kirill Esipov   rtc: ds3232: add ...
45
  #define DS3232_REG_TEMPERATURE	0x11
9eec31f31   Han Nandor   rtc: ds3232: get ...
46
47
48
49
  #define DS3232_REG_SRAM_START   0x14
  #define DS3232_REG_SRAM_END     0xFF
  
  #define DS3232_REG_SRAM_SIZE    236
c35c4195f   Kirill Esipov   rtc: ds3232: add ...
50

c03675f05   Roy Zang   rtc: add support ...
51
  struct ds3232 {
370927c4b   Akinobu Mita   rtc: ds3232: conv...
52
53
54
  	struct device *dev;
  	struct regmap *regmap;
  	int irq;
c03675f05   Roy Zang   rtc: add support ...
55
  	struct rtc_device *rtc;
c03675f05   Roy Zang   rtc: add support ...
56

c93a3ae2d   Wang Dongsheng   drivers/rtc/rtc-d...
57
  	bool suspended;
c03675f05   Roy Zang   rtc: add support ...
58
  };
370927c4b   Akinobu Mita   rtc: ds3232: conv...
59
  static int ds3232_check_rtc_status(struct device *dev)
c03675f05   Roy Zang   rtc: add support ...
60
  {
370927c4b   Akinobu Mita   rtc: ds3232: conv...
61
  	struct ds3232 *ds3232 = dev_get_drvdata(dev);
c03675f05   Roy Zang   rtc: add support ...
62
63
  	int ret = 0;
  	int control, stat;
370927c4b   Akinobu Mita   rtc: ds3232: conv...
64
65
66
  	ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
  	if (ret)
  		return ret;
c03675f05   Roy Zang   rtc: add support ...
67
68
  
  	if (stat & DS3232_REG_SR_OSF)
370927c4b   Akinobu Mita   rtc: ds3232: conv...
69
  		dev_warn(dev,
c03675f05   Roy Zang   rtc: add support ...
70
71
72
73
74
  				"oscillator discontinuity flagged, "
  				"time unreliable
  ");
  
  	stat &= ~(DS3232_REG_SR_OSF | DS3232_REG_SR_A1F | DS3232_REG_SR_A2F);
370927c4b   Akinobu Mita   rtc: ds3232: conv...
75
76
  	ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat);
  	if (ret)
c03675f05   Roy Zang   rtc: add support ...
77
78
79
80
81
82
  		return ret;
  
  	/* If the alarm is pending, clear it before requesting
  	 * the interrupt, so an interrupt event isn't reported
  	 * before everything is initialized.
  	 */
370927c4b   Akinobu Mita   rtc: ds3232: conv...
83
84
85
  	ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
  	if (ret)
  		return ret;
c03675f05   Roy Zang   rtc: add support ...
86
87
88
  
  	control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE);
  	control |= DS3232_REG_CR_INTCN;
370927c4b   Akinobu Mita   rtc: ds3232: conv...
89
  	return regmap_write(ds3232->regmap, DS3232_REG_CR, control);
c03675f05   Roy Zang   rtc: add support ...
90
91
92
93
  }
  
  static int ds3232_read_time(struct device *dev, struct rtc_time *time)
  {
370927c4b   Akinobu Mita   rtc: ds3232: conv...
94
  	struct ds3232 *ds3232 = dev_get_drvdata(dev);
c03675f05   Roy Zang   rtc: add support ...
95
96
97
98
99
  	int ret;
  	u8 buf[7];
  	unsigned int year, month, day, hour, minute, second;
  	unsigned int week, twelve_hr, am_pm;
  	unsigned int century, add_century = 0;
370927c4b   Akinobu Mita   rtc: ds3232: conv...
100
101
  	ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_SECONDS, buf, 7);
  	if (ret)
c03675f05   Roy Zang   rtc: add support ...
102
  		return ret;
c03675f05   Roy Zang   rtc: add support ...
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
  
  	second = buf[0];
  	minute = buf[1];
  	hour = buf[2];
  	week = buf[3];
  	day = buf[4];
  	month = buf[5];
  	year = buf[6];
  
  	/* Extract additional information for AM/PM and century */
  
  	twelve_hr = hour & 0x40;
  	am_pm = hour & 0x20;
  	century = month & 0x80;
  
  	/* Write to rtc_time structure */
  
  	time->tm_sec = bcd2bin(second);
  	time->tm_min = bcd2bin(minute);
  	if (twelve_hr) {
  		/* Convert to 24 hr */
  		if (am_pm)
  			time->tm_hour = bcd2bin(hour & 0x1F) + 12;
  		else
  			time->tm_hour = bcd2bin(hour & 0x1F);
  	} else {
  		time->tm_hour = bcd2bin(hour);
  	}
a2d6d2fa9   Lei Xu   drivers/rtc/rtc-d...
131
132
  	/* Day of the week in linux range is 0~6 while 1~7 in RTC chip */
  	time->tm_wday = bcd2bin(week) - 1;
c03675f05   Roy Zang   rtc: add support ...
133
  	time->tm_mday = bcd2bin(day);
a2d6d2fa9   Lei Xu   drivers/rtc/rtc-d...
134
135
  	/* linux tm_mon range:0~11, while month range is 1~12 in RTC chip */
  	time->tm_mon = bcd2bin(month & 0x7F) - 1;
c03675f05   Roy Zang   rtc: add support ...
136
137
138
139
  	if (century)
  		add_century = 100;
  
  	time->tm_year = bcd2bin(year) + add_century;
22652ba72   Alexandre Belloni   rtc: stop validat...
140
  	return 0;
c03675f05   Roy Zang   rtc: add support ...
141
142
143
144
  }
  
  static int ds3232_set_time(struct device *dev, struct rtc_time *time)
  {
370927c4b   Akinobu Mita   rtc: ds3232: conv...
145
  	struct ds3232 *ds3232 = dev_get_drvdata(dev);
c03675f05   Roy Zang   rtc: add support ...
146
147
148
149
150
151
152
  	u8 buf[7];
  
  	/* Extract time from rtc_time and load into ds3232*/
  
  	buf[0] = bin2bcd(time->tm_sec);
  	buf[1] = bin2bcd(time->tm_min);
  	buf[2] = bin2bcd(time->tm_hour);
a2d6d2fa9   Lei Xu   drivers/rtc/rtc-d...
153
154
  	/* Day of the week in linux range is 0~6 while 1~7 in RTC chip */
  	buf[3] = bin2bcd(time->tm_wday + 1);
c03675f05   Roy Zang   rtc: add support ...
155
  	buf[4] = bin2bcd(time->tm_mday); /* Date */
a2d6d2fa9   Lei Xu   drivers/rtc/rtc-d...
156
157
  	/* linux tm_mon range:0~11, while month range is 1~12 in RTC chip */
  	buf[5] = bin2bcd(time->tm_mon + 1);
c03675f05   Roy Zang   rtc: add support ...
158
159
160
161
162
163
  	if (time->tm_year >= 100) {
  		buf[5] |= 0x80;
  		buf[6] = bin2bcd(time->tm_year - 100);
  	} else {
  		buf[6] = bin2bcd(time->tm_year);
  	}
370927c4b   Akinobu Mita   rtc: ds3232: conv...
164
  	return regmap_bulk_write(ds3232->regmap, DS3232_REG_SECONDS, buf, 7);
c03675f05   Roy Zang   rtc: add support ...
165
  }
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
166
167
168
169
170
171
172
  /*
   * DS3232 has two alarm, we only use alarm1
   * According to linux specification, only support one-shot alarm
   * no periodic alarm mode
   */
  static int ds3232_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
  {
370927c4b   Akinobu Mita   rtc: ds3232: conv...
173
  	struct ds3232 *ds3232 = dev_get_drvdata(dev);
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
174
175
176
  	int control, stat;
  	int ret;
  	u8 buf[4];
370927c4b   Akinobu Mita   rtc: ds3232: conv...
177
178
  	ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
  	if (ret)
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
179
  		goto out;
370927c4b   Akinobu Mita   rtc: ds3232: conv...
180
181
  	ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
  	if (ret)
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
182
  		goto out;
370927c4b   Akinobu Mita   rtc: ds3232: conv...
183
184
  	ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_ALARM1, buf, 4);
  	if (ret)
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
185
186
187
188
189
190
  		goto out;
  
  	alarm->time.tm_sec = bcd2bin(buf[0] & 0x7F);
  	alarm->time.tm_min = bcd2bin(buf[1] & 0x7F);
  	alarm->time.tm_hour = bcd2bin(buf[2] & 0x7F);
  	alarm->time.tm_mday = bcd2bin(buf[3] & 0x7F);
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
191
192
193
194
195
  	alarm->enabled = !!(control & DS3232_REG_CR_A1IE);
  	alarm->pending = !!(stat & DS3232_REG_SR_A1F);
  
  	ret = 0;
  out:
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
196
197
198
199
200
201
202
203
204
  	return ret;
  }
  
  /*
   * linux rtc-module does not support wday alarm
   * and only 24h time mode supported indeed
   */
  static int ds3232_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
  {
370927c4b   Akinobu Mita   rtc: ds3232: conv...
205
  	struct ds3232 *ds3232 = dev_get_drvdata(dev);
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
206
207
208
  	int control, stat;
  	int ret;
  	u8 buf[4];
370927c4b   Akinobu Mita   rtc: ds3232: conv...
209
  	if (ds3232->irq <= 0)
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
210
  		return -EINVAL;
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
211
212
213
214
215
216
  	buf[0] = bin2bcd(alarm->time.tm_sec);
  	buf[1] = bin2bcd(alarm->time.tm_min);
  	buf[2] = bin2bcd(alarm->time.tm_hour);
  	buf[3] = bin2bcd(alarm->time.tm_mday);
  
  	/* clear alarm interrupt enable bit */
370927c4b   Akinobu Mita   rtc: ds3232: conv...
217
218
  	ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
  	if (ret)
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
219
  		goto out;
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
220
  	control &= ~(DS3232_REG_CR_A1IE | DS3232_REG_CR_A2IE);
370927c4b   Akinobu Mita   rtc: ds3232: conv...
221
222
  	ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control);
  	if (ret)
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
223
224
225
  		goto out;
  
  	/* clear any pending alarm flag */
370927c4b   Akinobu Mita   rtc: ds3232: conv...
226
227
  	ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
  	if (ret)
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
228
  		goto out;
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
229
  	stat &= ~(DS3232_REG_SR_A1F | DS3232_REG_SR_A2F);
370927c4b   Akinobu Mita   rtc: ds3232: conv...
230
231
  	ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat);
  	if (ret)
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
232
  		goto out;
370927c4b   Akinobu Mita   rtc: ds3232: conv...
233
  	ret = regmap_bulk_write(ds3232->regmap, DS3232_REG_ALARM1, buf, 4);
7b4393a62   Akinobu Mita   rtc: ds3232: add ...
234
235
  	if (ret)
  		goto out;
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
236
237
238
  
  	if (alarm->enabled) {
  		control |= DS3232_REG_CR_A1IE;
370927c4b   Akinobu Mita   rtc: ds3232: conv...
239
  		ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control);
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
240
241
  	}
  out:
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
242
243
  	return ret;
  }
7b4393a62   Akinobu Mita   rtc: ds3232: add ...
244
  static int ds3232_update_alarm(struct device *dev, unsigned int enabled)
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
245
  {
370927c4b   Akinobu Mita   rtc: ds3232: conv...
246
  	struct ds3232 *ds3232 = dev_get_drvdata(dev);
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
247
248
  	int control;
  	int ret;
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
249

370927c4b   Akinobu Mita   rtc: ds3232: conv...
250
251
  	ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
  	if (ret)
fc1dcb0b3   Akinobu Mita   rtc: ds3232: use ...
252
  		return ret;
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
253

7522297e1   Akinobu Mita   rtc: ds3232: remo...
254
  	if (enabled)
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
255
256
257
258
259
  		/* enable alarm1 interrupt */
  		control |= DS3232_REG_CR_A1IE;
  	else
  		/* disable alarm1 interrupt */
  		control &= ~(DS3232_REG_CR_A1IE);
7b4393a62   Akinobu Mita   rtc: ds3232: add ...
260
  	ret = regmap_write(ds3232->regmap, DS3232_REG_CR, control);
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
261

7b4393a62   Akinobu Mita   rtc: ds3232: add ...
262
  	return ret;
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
263
  }
c35c4195f   Kirill Esipov   rtc: ds3232: add ...
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
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
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
  /*
   * Temperature sensor support for ds3232/ds3234 devices.
   * A user-initiated temperature conversion is not started by this function,
   * so the temperature is updated once every 64 seconds.
   */
  static int ds3232_hwmon_read_temp(struct device *dev, long int *mC)
  {
  	struct ds3232 *ds3232 = dev_get_drvdata(dev);
  	u8 temp_buf[2];
  	s16 temp;
  	int ret;
  
  	ret = regmap_bulk_read(ds3232->regmap, DS3232_REG_TEMPERATURE, temp_buf,
  			       sizeof(temp_buf));
  	if (ret < 0)
  		return ret;
  
  	/*
  	 * Temperature is represented as a 10-bit code with a resolution of
  	 * 0.25 degree celsius and encoded in two's complement format.
  	 */
  	temp = (temp_buf[0] << 8) | temp_buf[1];
  	temp >>= 6;
  	*mC = temp * 250;
  
  	return 0;
  }
  
  static umode_t ds3232_hwmon_is_visible(const void *data,
  				       enum hwmon_sensor_types type,
  				       u32 attr, int channel)
  {
  	if (type != hwmon_temp)
  		return 0;
  
  	switch (attr) {
  	case hwmon_temp_input:
  		return 0444;
  	default:
  		return 0;
  	}
  }
  
  static int ds3232_hwmon_read(struct device *dev,
  			     enum hwmon_sensor_types type,
  			     u32 attr, int channel, long *temp)
  {
  	int err;
  
  	switch (attr) {
  	case hwmon_temp_input:
  		err = ds3232_hwmon_read_temp(dev, temp);
  		break;
  	default:
  		err = -EOPNOTSUPP;
  		break;
  	}
  
  	return err;
  }
  
  static u32 ds3232_hwmon_chip_config[] = {
  	HWMON_C_REGISTER_TZ,
  	0
  };
  
  static const struct hwmon_channel_info ds3232_hwmon_chip = {
  	.type = hwmon_chip,
  	.config = ds3232_hwmon_chip_config,
  };
  
  static u32 ds3232_hwmon_temp_config[] = {
  	HWMON_T_INPUT,
  	0
  };
  
  static const struct hwmon_channel_info ds3232_hwmon_temp = {
  	.type = hwmon_temp,
  	.config = ds3232_hwmon_temp_config,
  };
  
  static const struct hwmon_channel_info *ds3232_hwmon_info[] = {
  	&ds3232_hwmon_chip,
  	&ds3232_hwmon_temp,
  	NULL
  };
  
  static const struct hwmon_ops ds3232_hwmon_hwmon_ops = {
  	.is_visible = ds3232_hwmon_is_visible,
  	.read = ds3232_hwmon_read,
  };
  
  static const struct hwmon_chip_info ds3232_hwmon_chip_info = {
  	.ops = &ds3232_hwmon_hwmon_ops,
  	.info = ds3232_hwmon_info,
  };
  
  static void ds3232_hwmon_register(struct device *dev, const char *name)
  {
  	struct ds3232 *ds3232 = dev_get_drvdata(dev);
  	struct device *hwmon_dev;
  
  	if (!IS_ENABLED(CONFIG_RTC_DRV_DS3232_HWMON))
  		return;
  
  	hwmon_dev = devm_hwmon_device_register_with_info(dev, name, ds3232,
  							&ds3232_hwmon_chip_info,
  							NULL);
  	if (IS_ERR(hwmon_dev)) {
  		dev_err(dev, "unable to register hwmon device %ld
  ",
  			PTR_ERR(hwmon_dev));
  	}
  }
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
378
379
  static int ds3232_alarm_irq_enable(struct device *dev, unsigned int enabled)
  {
370927c4b   Akinobu Mita   rtc: ds3232: conv...
380
  	struct ds3232 *ds3232 = dev_get_drvdata(dev);
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
381

370927c4b   Akinobu Mita   rtc: ds3232: conv...
382
  	if (ds3232->irq <= 0)
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
383
  		return -EINVAL;
7b4393a62   Akinobu Mita   rtc: ds3232: add ...
384
  	return ds3232_update_alarm(dev, enabled);
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
385
  }
c03675f05   Roy Zang   rtc: add support ...
386
387
  static irqreturn_t ds3232_irq(int irq, void *dev_id)
  {
370927c4b   Akinobu Mita   rtc: ds3232: conv...
388
389
  	struct device *dev = dev_id;
  	struct ds3232 *ds3232 = dev_get_drvdata(dev);
fc1dcb0b3   Akinobu Mita   rtc: ds3232: use ...
390
  	struct mutex *lock = &ds3232->rtc->ops_lock;
370927c4b   Akinobu Mita   rtc: ds3232: conv...
391
  	int ret;
c03675f05   Roy Zang   rtc: add support ...
392
  	int stat, control;
fc1dcb0b3   Akinobu Mita   rtc: ds3232: use ...
393
  	mutex_lock(lock);
c03675f05   Roy Zang   rtc: add support ...
394

370927c4b   Akinobu Mita   rtc: ds3232: conv...
395
396
  	ret = regmap_read(ds3232->regmap, DS3232_REG_SR, &stat);
  	if (ret)
c03675f05   Roy Zang   rtc: add support ...
397
398
399
  		goto unlock;
  
  	if (stat & DS3232_REG_SR_A1F) {
370927c4b   Akinobu Mita   rtc: ds3232: conv...
400
401
  		ret = regmap_read(ds3232->regmap, DS3232_REG_CR, &control);
  		if (ret) {
95c60c1c8   Akinobu Mita   rtc: ds3232: fix ...
402
403
404
  			dev_warn(ds3232->dev,
  				 "Read Control Register error %d
  ", ret);
c93a3ae2d   Wang Dongsheng   drivers/rtc/rtc-d...
405
406
407
  		} else {
  			/* disable alarm1 interrupt */
  			control &= ~(DS3232_REG_CR_A1IE);
7b4393a62   Akinobu Mita   rtc: ds3232: add ...
408
409
410
411
412
413
414
415
416
  			ret = regmap_write(ds3232->regmap, DS3232_REG_CR,
  					   control);
  			if (ret) {
  				dev_warn(ds3232->dev,
  					 "Write Control Register error %d
  ",
  					 ret);
  				goto unlock;
  			}
c93a3ae2d   Wang Dongsheng   drivers/rtc/rtc-d...
417
418
419
  
  			/* clear the alarm pend flag */
  			stat &= ~DS3232_REG_SR_A1F;
7b4393a62   Akinobu Mita   rtc: ds3232: add ...
420
421
422
423
424
425
426
427
  			ret = regmap_write(ds3232->regmap, DS3232_REG_SR, stat);
  			if (ret) {
  				dev_warn(ds3232->dev,
  					 "Write Status Register error %d
  ",
  					 ret);
  				goto unlock;
  			}
c93a3ae2d   Wang Dongsheng   drivers/rtc/rtc-d...
428
429
  
  			rtc_update_irq(ds3232->rtc, 1, RTC_AF | RTC_IRQF);
c93a3ae2d   Wang Dongsheng   drivers/rtc/rtc-d...
430
  		}
c03675f05   Roy Zang   rtc: add support ...
431
  	}
c03675f05   Roy Zang   rtc: add support ...
432
  unlock:
fc1dcb0b3   Akinobu Mita   rtc: ds3232: use ...
433
  	mutex_unlock(lock);
95c60c1c8   Akinobu Mita   rtc: ds3232: fix ...
434
435
  
  	return IRQ_HANDLED;
c03675f05   Roy Zang   rtc: add support ...
436
437
438
439
440
  }
  
  static const struct rtc_class_ops ds3232_rtc_ops = {
  	.read_time = ds3232_read_time,
  	.set_time = ds3232_set_time,
f46418c5c   Lan Chunhe-B25806   drivers/rtc/rtc-d...
441
442
443
  	.read_alarm = ds3232_read_alarm,
  	.set_alarm = ds3232_set_alarm,
  	.alarm_irq_enable = ds3232_alarm_irq_enable,
c03675f05   Roy Zang   rtc: add support ...
444
  };
9eec31f31   Han Nandor   rtc: ds3232: get ...
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
  static int ds3232_nvmem_read(void *priv, unsigned int offset, void *val,
  			     size_t bytes)
  {
  	struct regmap *ds3232_regmap = (struct regmap *)priv;
  
  	return regmap_bulk_read(ds3232_regmap, DS3232_REG_SRAM_START + offset,
  				val, bytes);
  }
  
  static int ds3232_nvmem_write(void *priv, unsigned int offset, void *val,
  			      size_t bytes)
  {
  	struct regmap *ds3232_regmap = (struct regmap *)priv;
  
  	return regmap_bulk_write(ds3232_regmap, DS3232_REG_SRAM_START + offset,
  				 val, bytes);
  }
370927c4b   Akinobu Mita   rtc: ds3232: conv...
462
463
  static int ds3232_probe(struct device *dev, struct regmap *regmap, int irq,
  			const char *name)
c03675f05   Roy Zang   rtc: add support ...
464
465
466
  {
  	struct ds3232 *ds3232;
  	int ret;
9eec31f31   Han Nandor   rtc: ds3232: get ...
467
468
469
470
471
472
473
474
475
476
  	struct nvmem_config nvmem_cfg = {
  		.name = "ds3232_sram",
  		.stride = 1,
  		.size = DS3232_REG_SRAM_SIZE,
  		.word_size = 1,
  		.reg_read = ds3232_nvmem_read,
  		.reg_write = ds3232_nvmem_write,
  		.priv = regmap,
  		.type = NVMEM_TYPE_BATTERY_BACKED
  	};
c03675f05   Roy Zang   rtc: add support ...
477

370927c4b   Akinobu Mita   rtc: ds3232: conv...
478
  	ds3232 = devm_kzalloc(dev, sizeof(*ds3232), GFP_KERNEL);
c03675f05   Roy Zang   rtc: add support ...
479
480
  	if (!ds3232)
  		return -ENOMEM;
370927c4b   Akinobu Mita   rtc: ds3232: conv...
481
482
483
484
  	ds3232->regmap = regmap;
  	ds3232->irq = irq;
  	ds3232->dev = dev;
  	dev_set_drvdata(dev, ds3232);
c03675f05   Roy Zang   rtc: add support ...
485

370927c4b   Akinobu Mita   rtc: ds3232: conv...
486
  	ret = ds3232_check_rtc_status(dev);
c03675f05   Roy Zang   rtc: add support ...
487
  	if (ret)
667146127   Sachin Kamat   drivers/rtc/rtc-d...
488
  		return ret;
c03675f05   Roy Zang   rtc: add support ...
489

d4f6c6f15   Phil Reid   rtc: ds3232: Call...
490
491
  	if (ds3232->irq > 0)
  		device_init_wakeup(dev, 1);
c35c4195f   Kirill Esipov   rtc: ds3232: add ...
492
  	ds3232_hwmon_register(dev, name);
b4b77f3c2   Qianyu Gong   rtc: ds3232: fix ...
493
494
495
496
  	ds3232->rtc = devm_rtc_device_register(dev, name, &ds3232_rtc_ops,
  						THIS_MODULE);
  	if (IS_ERR(ds3232->rtc))
  		return PTR_ERR(ds3232->rtc);
9eec31f31   Han Nandor   rtc: ds3232: get ...
497
498
499
  	ret = rtc_nvmem_register(ds3232->rtc, &nvmem_cfg);
  	if(ret)
  		return ret;
370927c4b   Akinobu Mita   rtc: ds3232: conv...
500
  	if (ds3232->irq > 0) {
95c60c1c8   Akinobu Mita   rtc: ds3232: fix ...
501
502
503
504
  		ret = devm_request_threaded_irq(dev, ds3232->irq, NULL,
  						ds3232_irq,
  						IRQF_SHARED | IRQF_ONESHOT,
  						name, dev);
c03675f05   Roy Zang   rtc: add support ...
505
  		if (ret) {
d4f6c6f15   Phil Reid   rtc: ds3232: Call...
506
  			device_set_wakeup_capable(dev, 0);
370927c4b   Akinobu Mita   rtc: ds3232: conv...
507
508
509
  			ds3232->irq = 0;
  			dev_err(dev, "unable to request IRQ
  ");
d4f6c6f15   Phil Reid   rtc: ds3232: Call...
510
  		}
c03675f05   Roy Zang   rtc: add support ...
511
  	}
370927c4b   Akinobu Mita   rtc: ds3232: conv...
512

b4b77f3c2   Qianyu Gong   rtc: ds3232: fix ...
513
  	return 0;
c03675f05   Roy Zang   rtc: add support ...
514
  }
c93a3ae2d   Wang Dongsheng   drivers/rtc/rtc-d...
515
516
517
518
  #ifdef CONFIG_PM_SLEEP
  static int ds3232_suspend(struct device *dev)
  {
  	struct ds3232 *ds3232 = dev_get_drvdata(dev);
c93a3ae2d   Wang Dongsheng   drivers/rtc/rtc-d...
519

95c60c1c8   Akinobu Mita   rtc: ds3232: fix ...
520
521
  	if (device_may_wakeup(dev)) {
  		if (enable_irq_wake(ds3232->irq))
dc2280ebf   Wang Dongsheng   rtc: ds3232: fix ...
522
523
  			dev_warn_once(dev, "Cannot set wakeup source
  ");
c93a3ae2d   Wang Dongsheng   drivers/rtc/rtc-d...
524
525
526
527
528
529
530
531
  	}
  
  	return 0;
  }
  
  static int ds3232_resume(struct device *dev)
  {
  	struct ds3232 *ds3232 = dev_get_drvdata(dev);
c93a3ae2d   Wang Dongsheng   drivers/rtc/rtc-d...
532

95c60c1c8   Akinobu Mita   rtc: ds3232: fix ...
533
534
  	if (device_may_wakeup(dev))
  		disable_irq_wake(ds3232->irq);
c93a3ae2d   Wang Dongsheng   drivers/rtc/rtc-d...
535
536
537
538
539
540
541
542
  
  	return 0;
  }
  #endif
  
  static const struct dev_pm_ops ds3232_pm_ops = {
  	SET_SYSTEM_SLEEP_PM_OPS(ds3232_suspend, ds3232_resume)
  };
080481f54   Akinobu Mita   rtc: merge ds3232...
543
  #if IS_ENABLED(CONFIG_I2C)
370927c4b   Akinobu Mita   rtc: ds3232: conv...
544
545
546
547
548
549
550
  static int ds3232_i2c_probe(struct i2c_client *client,
  			    const struct i2c_device_id *id)
  {
  	struct regmap *regmap;
  	static const struct regmap_config config = {
  		.reg_bits = 8,
  		.val_bits = 8,
9eec31f31   Han Nandor   rtc: ds3232: get ...
551
  		.max_register = DS3232_REG_SRAM_END,
370927c4b   Akinobu Mita   rtc: ds3232: conv...
552
553
554
555
556
557
558
559
560
561
562
563
  	};
  
  	regmap = devm_regmap_init_i2c(client, &config);
  	if (IS_ERR(regmap)) {
  		dev_err(&client->dev, "%s: regmap allocation failed: %ld
  ",
  			__func__, PTR_ERR(regmap));
  		return PTR_ERR(regmap);
  	}
  
  	return ds3232_probe(&client->dev, regmap, client->irq, client->name);
  }
c03675f05   Roy Zang   rtc: add support ...
564
565
566
567
568
  static const struct i2c_device_id ds3232_id[] = {
  	{ "ds3232", 0 },
  	{ }
  };
  MODULE_DEVICE_TABLE(i2c, ds3232_id);
4dfbd1378   Javier Martinez Canillas   rtc: ds3232: Add ...
569
570
571
572
573
  static const struct of_device_id ds3232_of_match[] = {
  	{ .compatible = "dallas,ds3232" },
  	{ }
  };
  MODULE_DEVICE_TABLE(of, ds3232_of_match);
c03675f05   Roy Zang   rtc: add support ...
574
575
576
  static struct i2c_driver ds3232_driver = {
  	.driver = {
  		.name = "rtc-ds3232",
4dfbd1378   Javier Martinez Canillas   rtc: ds3232: Add ...
577
  		.of_match_table = of_match_ptr(ds3232_of_match),
c93a3ae2d   Wang Dongsheng   drivers/rtc/rtc-d...
578
  		.pm	= &ds3232_pm_ops,
c03675f05   Roy Zang   rtc: add support ...
579
  	},
370927c4b   Akinobu Mita   rtc: ds3232: conv...
580
  	.probe = ds3232_i2c_probe,
c03675f05   Roy Zang   rtc: add support ...
581
582
  	.id_table = ds3232_id,
  };
080481f54   Akinobu Mita   rtc: merge ds3232...
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
  
  static int ds3232_register_driver(void)
  {
  	return i2c_add_driver(&ds3232_driver);
  }
  
  static void ds3232_unregister_driver(void)
  {
  	i2c_del_driver(&ds3232_driver);
  }
  
  #else
  
  static int ds3232_register_driver(void)
  {
  	return 0;
  }
  
  static void ds3232_unregister_driver(void)
  {
  }
  
  #endif
  
  #if IS_ENABLED(CONFIG_SPI_MASTER)
  
  static int ds3234_probe(struct spi_device *spi)
  {
  	int res;
  	unsigned int tmp;
  	static const struct regmap_config config = {
  		.reg_bits = 8,
  		.val_bits = 8,
9eec31f31   Han Nandor   rtc: ds3232: get ...
616
  		.max_register = DS3232_REG_SRAM_END,
080481f54   Akinobu Mita   rtc: merge ds3232...
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
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
  		.write_flag_mask = 0x80,
  	};
  	struct regmap *regmap;
  
  	regmap = devm_regmap_init_spi(spi, &config);
  	if (IS_ERR(regmap)) {
  		dev_err(&spi->dev, "%s: regmap allocation failed: %ld
  ",
  			__func__, PTR_ERR(regmap));
  		return PTR_ERR(regmap);
  	}
  
  	spi->mode = SPI_MODE_3;
  	spi->bits_per_word = 8;
  	spi_setup(spi);
  
  	res = regmap_read(regmap, DS3232_REG_SECONDS, &tmp);
  	if (res)
  		return res;
  
  	/* Control settings
  	 *
  	 * CONTROL_REG
  	 * BIT 7	6	5	4	3	2	1	0
  	 *     EOSC	BBSQW	CONV	RS2	RS1	INTCN	A2IE	A1IE
  	 *
  	 *     0	0	0	1	1	1	0	0
  	 *
  	 * CONTROL_STAT_REG
  	 * BIT 7	6	5	4	3	2	1	0
  	 *     OSF	BB32kHz	CRATE1	CRATE0	EN32kHz	BSY	A2F	A1F
  	 *
  	 *     1	0	0	0	1	0	0	0
  	 */
  	res = regmap_read(regmap, DS3232_REG_CR, &tmp);
  	if (res)
  		return res;
  	res = regmap_write(regmap, DS3232_REG_CR, tmp & 0x1c);
  	if (res)
  		return res;
  
  	res = regmap_read(regmap, DS3232_REG_SR, &tmp);
  	if (res)
  		return res;
  	res = regmap_write(regmap, DS3232_REG_SR, tmp & 0x88);
  	if (res)
  		return res;
  
  	/* Print our settings */
  	res = regmap_read(regmap, DS3232_REG_CR, &tmp);
  	if (res)
  		return res;
  	dev_info(&spi->dev, "Control Reg: 0x%02x
  ", tmp);
  
  	res = regmap_read(regmap, DS3232_REG_SR, &tmp);
  	if (res)
  		return res;
  	dev_info(&spi->dev, "Ctrl/Stat Reg: 0x%02x
  ", tmp);
  
  	return ds3232_probe(&spi->dev, regmap, spi->irq, "ds3234");
  }
080481f54   Akinobu Mita   rtc: merge ds3232...
680
681
682
683
684
  static struct spi_driver ds3234_driver = {
  	.driver = {
  		.name	 = "ds3234",
  	},
  	.probe	 = ds3234_probe,
080481f54   Akinobu Mita   rtc: merge ds3232...
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
  };
  
  static int ds3234_register_driver(void)
  {
  	return spi_register_driver(&ds3234_driver);
  }
  
  static void ds3234_unregister_driver(void)
  {
  	spi_unregister_driver(&ds3234_driver);
  }
  
  #else
  
  static int ds3234_register_driver(void)
  {
  	return 0;
  }
  
  static void ds3234_unregister_driver(void)
  {
  }
  
  #endif
  
  static int __init ds323x_init(void)
  {
  	int ret;
  
  	ret = ds3232_register_driver();
  	if (ret) {
  		pr_err("Failed to register ds3232 driver: %d
  ", ret);
  		return ret;
  	}
  
  	ret = ds3234_register_driver();
  	if (ret) {
  		pr_err("Failed to register ds3234 driver: %d
  ", ret);
  		ds3232_unregister_driver();
  	}
  
  	return ret;
  }
  module_init(ds323x_init)
  
  static void __exit ds323x_exit(void)
  {
  	ds3234_unregister_driver();
  	ds3232_unregister_driver();
  }
  module_exit(ds323x_exit)
c03675f05   Roy Zang   rtc: add support ...
738
739
  
  MODULE_AUTHOR("Srikanth Srinivasan <srikanth.srinivasan@freescale.com>");
080481f54   Akinobu Mita   rtc: merge ds3232...
740
741
  MODULE_AUTHOR("Dennis Aberilla <denzzzhome@yahoo.com>");
  MODULE_DESCRIPTION("Maxim/Dallas DS3232/DS3234 RTC Driver");
c03675f05   Roy Zang   rtc: add support ...
742
  MODULE_LICENSE("GPL");
080481f54   Akinobu Mita   rtc: merge ds3232...
743
  MODULE_ALIAS("spi:ds3234");