Blame view

drivers/rtc/rtc-m41t80.c 25.5 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
2
3
4
5
6
7
8
9
  /*
   * I2C client/driver for the ST M41T80 family of i2c rtc chips.
   *
   * Author: Alexander Bigga <ab@mycable.de>
   *
   * Based on m41t00.c by Mark A. Greer <mgreer@mvista.com>
   *
   * 2006 (c) mycable GmbH
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
10
   */
a737e835e   Joe Perches   rtc: use more sta...
11
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
35aa64f3a   Maciej W. Rozycki   rtc: m41t80: sort...
12
  #include <linux/bcd.h>
1373e77b4   Gary Bisson   rtc: m41t80: add ...
13
  #include <linux/clk-provider.h>
35aa64f3a   Maciej W. Rozycki   rtc: m41t80: sort...
14
  #include <linux/i2c.h>
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
15
  #include <linux/init.h>
9fb1f68d4   Maciej W. Rozycki   rtc: m41t80: incl...
16
  #include <linux/kernel.h>
35aa64f3a   Maciej W. Rozycki   rtc: m41t80: sort...
17
  #include <linux/module.h>
eb235c561   Javier Martinez Canillas   rtc: m41t80: Add ...
18
  #include <linux/of_device.h>
35aa64f3a   Maciej W. Rozycki   rtc: m41t80: sort...
19
  #include <linux/rtc.h>
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
20
  #include <linux/slab.h>
613655fa3   Arnd Bergmann   drivers: autoconv...
21
  #include <linux/mutex.h>
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
22
  #include <linux/string.h>
617780d29   Atsushi Nemoto   rtc: watchdog sup...
23
  #ifdef CONFIG_RTC_DRV_M41T80_WDT
617780d29   Atsushi Nemoto   rtc: watchdog sup...
24
25
  #include <linux/fs.h>
  #include <linux/ioctl.h>
35aa64f3a   Maciej W. Rozycki   rtc: m41t80: sort...
26
27
28
  #include <linux/miscdevice.h>
  #include <linux/reboot.h>
  #include <linux/watchdog.h>
617780d29   Atsushi Nemoto   rtc: watchdog sup...
29
  #endif
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
30

f2b84ee88   Mylène Josserand   rtc: m41t80: repl...
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  #define M41T80_REG_SSEC		0x00
  #define M41T80_REG_SEC		0x01
  #define M41T80_REG_MIN		0x02
  #define M41T80_REG_HOUR		0x03
  #define M41T80_REG_WDAY		0x04
  #define M41T80_REG_DAY		0x05
  #define M41T80_REG_MON		0x06
  #define M41T80_REG_YEAR		0x07
  #define M41T80_REG_ALARM_MON	0x0a
  #define M41T80_REG_ALARM_DAY	0x0b
  #define M41T80_REG_ALARM_HOUR	0x0c
  #define M41T80_REG_ALARM_MIN	0x0d
  #define M41T80_REG_ALARM_SEC	0x0e
  #define M41T80_REG_FLAGS	0x0f
  #define M41T80_REG_SQW		0x13
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
46
47
48
49
  
  #define M41T80_DATETIME_REG_SIZE	(M41T80_REG_YEAR + 1)
  #define M41T80_ALARM_REG_SIZE	\
  	(M41T80_REG_ALARM_SEC + 1 - M41T80_REG_ALARM_MON)
1373e77b4   Gary Bisson   rtc: m41t80: add ...
50
  #define M41T80_SQW_MAX_FREQ	32768
54339f3b3   Mylène Josserand   rtc: m41t80: add ...
51
52
53
54
  #define M41T80_SEC_ST		BIT(7)	/* ST: Stop Bit */
  #define M41T80_ALMON_AFE	BIT(7)	/* AFE: AF Enable Bit */
  #define M41T80_ALMON_SQWE	BIT(6)	/* SQWE: SQW Enable Bit */
  #define M41T80_ALHOUR_HT	BIT(6)	/* HT: Halt Update Bit */
05a7f27a8   Mylène Josserand   rtc: m41t80: hand...
55
  #define M41T80_FLAGS_OF		BIT(2)	/* OF: Oscillator Failure Bit */
54339f3b3   Mylène Josserand   rtc: m41t80: add ...
56
57
58
59
60
  #define M41T80_FLAGS_AF		BIT(6)	/* AF: Alarm Flag Bit */
  #define M41T80_FLAGS_BATT_LOW	BIT(4)	/* BL: Battery Low Bit */
  #define M41T80_WATCHDOG_RB2	BIT(7)	/* RB: Watchdog resolution */
  #define M41T80_WATCHDOG_RB1	BIT(1)	/* RB: Watchdog resolution */
  #define M41T80_WATCHDOG_RB0	BIT(0)	/* RB: Watchdog resolution */
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
61

54339f3b3   Mylène Josserand   rtc: m41t80: add ...
62
63
64
65
66
  #define M41T80_FEATURE_HT	BIT(0)	/* Halt feature */
  #define M41T80_FEATURE_BL	BIT(1)	/* Battery low indicator */
  #define M41T80_FEATURE_SQ	BIT(2)	/* Squarewave feature */
  #define M41T80_FEATURE_WD	BIT(3)	/* Extra watchdog resolution */
  #define M41T80_FEATURE_SQ_ALT	BIT(4)	/* RSx bits are in reg 4 */
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
67

3760f7367   Jean Delvare   i2c: Convert most...
68
  static const struct i2c_device_id m41t80_id[] = {
f30281f4f   Daniel Glockner   rtc: add m41t62 s...
69
  	{ "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT },
d3a126fcf   Steven A. Falco   rtc: rtc-m41t80.c...
70
71
72
73
74
75
76
77
78
  	{ "m41t65", M41T80_FEATURE_HT | M41T80_FEATURE_WD },
  	{ "m41t80", M41T80_FEATURE_SQ },
  	{ "m41t81", M41T80_FEATURE_HT | M41T80_FEATURE_SQ},
  	{ "m41t81s", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
  	{ "m41t82", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
  	{ "m41t83", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
  	{ "m41st84", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
  	{ "m41st85", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
  	{ "m41st87", M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ },
6b1a52354   Wolfram Sang   drivers/rtc/rtc-m...
79
  	{ "rv4162", M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT },
3760f7367   Jean Delvare   i2c: Convert most...
80
  	{ }
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
81
  };
3760f7367   Jean Delvare   i2c: Convert most...
82
  MODULE_DEVICE_TABLE(i2c, m41t80_id);
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
83

eb235c561   Javier Martinez Canillas   rtc: m41t80: Add ...
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
  static const struct of_device_id m41t80_of_match[] = {
  	{
  		.compatible = "st,m41t62",
  		.data = (void *)(M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT)
  	},
  	{
  		.compatible = "st,m41t65",
  		.data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_WD)
  	},
  	{
  		.compatible = "st,m41t80",
  		.data = (void *)(M41T80_FEATURE_SQ)
  	},
  	{
  		.compatible = "st,m41t81",
  		.data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_SQ)
  	},
  	{
  		.compatible = "st,m41t81s",
  		.data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
  	},
  	{
  		.compatible = "st,m41t82",
  		.data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
  	},
  	{
  		.compatible = "st,m41t83",
  		.data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
  	},
  	{
  		.compatible = "st,m41t84",
  		.data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
  	},
  	{
  		.compatible = "st,m41t85",
  		.data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
  	},
  	{
  		.compatible = "st,m41t87",
  		.data = (void *)(M41T80_FEATURE_HT | M41T80_FEATURE_BL | M41T80_FEATURE_SQ)
  	},
  	{
a897bf138   Alexandre Belloni   rtc: m41t80: Add ...
126
127
128
129
130
  		.compatible = "microcrystal,rv4162",
  		.data = (void *)(M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT)
  	},
  	/* DT compatibility only, do not use compatibles below: */
  	{
eb235c561   Javier Martinez Canillas   rtc: m41t80: Add ...
131
132
133
134
135
136
137
138
139
140
  		.compatible = "st,rv4162",
  		.data = (void *)(M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT)
  	},
  	{
  		.compatible = "rv4162",
  		.data = (void *)(M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT)
  	},
  	{ }
  };
  MODULE_DEVICE_TABLE(of, m41t80_of_match);
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
141
  struct m41t80_data {
eb235c561   Javier Martinez Canillas   rtc: m41t80: Add ...
142
  	unsigned long features;
1373e77b4   Gary Bisson   rtc: m41t80: add ...
143
  	struct i2c_client *client;
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
144
  	struct rtc_device *rtc;
1373e77b4   Gary Bisson   rtc: m41t80: add ...
145
146
  #ifdef CONFIG_COMMON_CLK
  	struct clk_hw sqw;
2cb90ed3d   Troy Kisky   rtc: m41t80: avoi...
147
  	unsigned long freq;
13bb1d78f   Troy Kisky   rtc: m41t80: avoi...
148
  	unsigned int sqwe;
1373e77b4   Gary Bisson   rtc: m41t80: add ...
149
  #endif
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
150
  };
9c6dfed92   Mylène Josserand   rtc: m41t80: add ...
151
152
153
154
155
156
157
158
159
160
161
162
163
164
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
  static irqreturn_t m41t80_handle_irq(int irq, void *dev_id)
  {
  	struct i2c_client *client = dev_id;
  	struct m41t80_data *m41t80 = i2c_get_clientdata(client);
  	struct mutex *lock = &m41t80->rtc->ops_lock;
  	unsigned long events = 0;
  	int flags, flags_afe;
  
  	mutex_lock(lock);
  
  	flags_afe = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
  	if (flags_afe < 0) {
  		mutex_unlock(lock);
  		return IRQ_NONE;
  	}
  
  	flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
  	if (flags <= 0) {
  		mutex_unlock(lock);
  		return IRQ_NONE;
  	}
  
  	if (flags & M41T80_FLAGS_AF) {
  		flags &= ~M41T80_FLAGS_AF;
  		flags_afe &= ~M41T80_ALMON_AFE;
  		events |= RTC_AF;
  	}
  
  	if (events) {
  		rtc_update_irq(m41t80->rtc, 1, events);
  		i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS, flags);
  		i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
  					  flags_afe);
  	}
  
  	mutex_unlock(lock);
  
  	return IRQ_HANDLED;
  }
e2c8e1a9f   Alexandre Belloni   rtc: m41t80: remo...
190
  static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm)
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
191
  {
e2c8e1a9f   Alexandre Belloni   rtc: m41t80: remo...
192
  	struct i2c_client *client = to_i2c_client(dev);
f2b84ee88   Mylène Josserand   rtc: m41t80: repl...
193
  	unsigned char buf[8];
05a7f27a8   Mylène Josserand   rtc: m41t80: hand...
194
195
196
197
198
199
200
201
202
203
204
  	int err, flags;
  
  	flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
  	if (flags < 0)
  		return flags;
  
  	if (flags & M41T80_FLAGS_OF) {
  		dev_err(&client->dev, "Oscillator failure, data is invalid.
  ");
  		return -EINVAL;
  	}
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
205

f2b84ee88   Mylène Josserand   rtc: m41t80: repl...
206
207
208
209
210
  	err = i2c_smbus_read_i2c_block_data(client, M41T80_REG_SSEC,
  					    sizeof(buf), buf);
  	if (err < 0) {
  		dev_err(&client->dev, "Unable to read date
  ");
f1bd154d8   Maciej W. Rozycki   rtc: m41t80: Comp...
211
  		return err;
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
212
  	}
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
213
214
215
216
  	tm->tm_sec = bcd2bin(buf[M41T80_REG_SEC] & 0x7f);
  	tm->tm_min = bcd2bin(buf[M41T80_REG_MIN] & 0x7f);
  	tm->tm_hour = bcd2bin(buf[M41T80_REG_HOUR] & 0x3f);
  	tm->tm_mday = bcd2bin(buf[M41T80_REG_DAY] & 0x3f);
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
217
  	tm->tm_wday = buf[M41T80_REG_WDAY] & 0x07;
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
218
  	tm->tm_mon = bcd2bin(buf[M41T80_REG_MON] & 0x1f) - 1;
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
219
220
  
  	/* assume 20YY not 19YY, and ignore the Century Bit */
fe20ba70a   Adrian Bunk   drivers/rtc/: use...
221
  	tm->tm_year = bcd2bin(buf[M41T80_REG_YEAR]) + 100;
22652ba72   Alexandre Belloni   rtc: stop validat...
222
  	return 0;
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
223
  }
e2c8e1a9f   Alexandre Belloni   rtc: m41t80: remo...
224
  static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm)
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
225
  {
e2c8e1a9f   Alexandre Belloni   rtc: m41t80: remo...
226
  	struct i2c_client *client = to_i2c_client(dev);
0f546b058   Gary Bisson   rtc: m41t80: fix ...
227
  	struct m41t80_data *clientdata = i2c_get_clientdata(client);
f2b84ee88   Mylène Josserand   rtc: m41t80: repl...
228
  	unsigned char buf[8];
05a7f27a8   Mylène Josserand   rtc: m41t80: hand...
229
  	int err, flags;
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
230

caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
231
  	buf[M41T80_REG_SSEC] = 0;
f2b84ee88   Mylène Josserand   rtc: m41t80: repl...
232
233
234
235
236
237
238
  	buf[M41T80_REG_SEC] = bin2bcd(tm->tm_sec);
  	buf[M41T80_REG_MIN] = bin2bcd(tm->tm_min);
  	buf[M41T80_REG_HOUR] = bin2bcd(tm->tm_hour);
  	buf[M41T80_REG_DAY] = bin2bcd(tm->tm_mday);
  	buf[M41T80_REG_MON] = bin2bcd(tm->tm_mon + 1);
  	buf[M41T80_REG_YEAR] = bin2bcd(tm->tm_year - 100);
  	buf[M41T80_REG_WDAY] = tm->tm_wday;
0f546b058   Gary Bisson   rtc: m41t80: fix ...
239
240
241
242
243
244
245
246
247
248
  	/* If the square wave output is controlled in the weekday register */
  	if (clientdata->features & M41T80_FEATURE_SQ_ALT) {
  		int val;
  
  		val = i2c_smbus_read_byte_data(client, M41T80_REG_WDAY);
  		if (val < 0)
  			return val;
  
  		buf[M41T80_REG_WDAY] |= (val & 0xf0);
  	}
f2b84ee88   Mylène Josserand   rtc: m41t80: repl...
249
250
251
252
253
254
  	err = i2c_smbus_write_i2c_block_data(client, M41T80_REG_SSEC,
  					     sizeof(buf), buf);
  	if (err < 0) {
  		dev_err(&client->dev, "Unable to write to date registers
  ");
  		return err;
bcebd81d0   Stefan Christ   rtc: m41t80: avoi...
255
  	}
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
256

05a7f27a8   Mylène Josserand   rtc: m41t80: hand...
257
258
259
260
  	/* Clear the OF bit of Flags Register */
  	flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
  	if (flags < 0)
  		return flags;
f1bd154d8   Maciej W. Rozycki   rtc: m41t80: Comp...
261
262
263
  	err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS,
  					flags & ~M41T80_FLAGS_OF);
  	if (err < 0) {
05a7f27a8   Mylène Josserand   rtc: m41t80: hand...
264
265
  		dev_err(&client->dev, "Unable to write flags register
  ");
f1bd154d8   Maciej W. Rozycki   rtc: m41t80: Comp...
266
  		return err;
05a7f27a8   Mylène Josserand   rtc: m41t80: hand...
267
  	}
f2b84ee88   Mylène Josserand   rtc: m41t80: repl...
268
  	return err;
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
269
  }
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
270
271
272
273
  static int m41t80_rtc_proc(struct device *dev, struct seq_file *seq)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	struct m41t80_data *clientdata = i2c_get_clientdata(client);
f1bd154d8   Maciej W. Rozycki   rtc: m41t80: Comp...
274
  	int reg;
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
275

3760f7367   Jean Delvare   i2c: Convert most...
276
  	if (clientdata->features & M41T80_FEATURE_BL) {
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
277
  		reg = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
f1bd154d8   Maciej W. Rozycki   rtc: m41t80: Comp...
278
279
  		if (reg < 0)
  			return reg;
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
280
281
282
283
284
285
  		seq_printf(seq, "battery\t\t: %s
  ",
  			   (reg & M41T80_FLAGS_BATT_LOW) ? "exhausted" : "ok");
  	}
  	return 0;
  }
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
286

9c6dfed92   Mylène Josserand   rtc: m41t80: add ...
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  static int m41t80_alarm_irq_enable(struct device *dev, unsigned int enabled)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	int flags, retval;
  
  	flags = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
  	if (flags < 0)
  		return flags;
  
  	if (enabled)
  		flags |= M41T80_ALMON_AFE;
  	else
  		flags &= ~M41T80_ALMON_AFE;
  
  	retval = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, flags);
  	if (retval < 0) {
e89487fef   Stefan Christ   rtc: m41t80: make...
303
304
  		dev_err(dev, "Unable to enable alarm IRQ %d
  ", retval);
9c6dfed92   Mylène Josserand   rtc: m41t80: add ...
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
  		return retval;
  	}
  	return 0;
  }
  
  static int m41t80_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	u8 alarmvals[5];
  	int ret, err;
  
  	alarmvals[0] = bin2bcd(alrm->time.tm_mon + 1);
  	alarmvals[1] = bin2bcd(alrm->time.tm_mday);
  	alarmvals[2] = bin2bcd(alrm->time.tm_hour);
  	alarmvals[3] = bin2bcd(alrm->time.tm_min);
  	alarmvals[4] = bin2bcd(alrm->time.tm_sec);
  
  	/* Clear AF and AFE flags */
  	ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
  	if (ret < 0)
  		return ret;
  	err = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
  					ret & ~(M41T80_ALMON_AFE));
  	if (err < 0) {
  		dev_err(dev, "Unable to clear AFE bit
  ");
  		return err;
  	}
2de9261c1   Gary Bisson   rtc: m41t80: fix ...
333
334
  	/* Keep SQWE bit value */
  	alarmvals[0] |= (ret & M41T80_ALMON_SQWE);
9c6dfed92   Mylène Josserand   rtc: m41t80: add ...
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
378
379
380
381
382
  	ret = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
  	if (ret < 0)
  		return ret;
  
  	err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS,
  					ret & ~(M41T80_FLAGS_AF));
  	if (err < 0) {
  		dev_err(dev, "Unable to clear AF bit
  ");
  		return err;
  	}
  
  	/* Write the alarm */
  	err = i2c_smbus_write_i2c_block_data(client, M41T80_REG_ALARM_MON,
  					     5, alarmvals);
  	if (err)
  		return err;
  
  	/* Enable the alarm interrupt */
  	if (alrm->enabled) {
  		alarmvals[0] |= M41T80_ALMON_AFE;
  		err = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
  						alarmvals[0]);
  		if (err)
  			return err;
  	}
  
  	return 0;
  }
  
  static int m41t80_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  	u8 alarmvals[5];
  	int flags, ret;
  
  	ret = i2c_smbus_read_i2c_block_data(client, M41T80_REG_ALARM_MON,
  					    5, alarmvals);
  	if (ret != 5)
  		return ret < 0 ? ret : -EIO;
  
  	flags = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS);
  	if (flags < 0)
  		return flags;
  
  	alrm->time.tm_sec  = bcd2bin(alarmvals[4] & 0x7f);
  	alrm->time.tm_min  = bcd2bin(alarmvals[3] & 0x7f);
  	alrm->time.tm_hour = bcd2bin(alarmvals[2] & 0x3f);
9c6dfed92   Mylène Josserand   rtc: m41t80: add ...
383
  	alrm->time.tm_mday = bcd2bin(alarmvals[1] & 0x3f);
3cc9ffbb1   Maciej W. Rozycki   rtc: m41t80: Corr...
384
  	alrm->time.tm_mon  = bcd2bin(alarmvals[0] & 0x3f) - 1;
9c6dfed92   Mylène Josserand   rtc: m41t80: add ...
385
386
387
388
389
390
  
  	alrm->enabled = !!(alarmvals[0] & M41T80_ALMON_AFE);
  	alrm->pending = (flags & M41T80_FLAGS_AF) && alrm->enabled;
  
  	return 0;
  }
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
391
392
393
  static struct rtc_class_ops m41t80_rtc_ops = {
  	.read_time = m41t80_rtc_read_time,
  	.set_time = m41t80_rtc_set_time,
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
394
  	.proc = m41t80_rtc_proc,
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
395
  };
ae036af89   Stefan Christ   rtc: m41t80: add ...
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
  #ifdef CONFIG_PM_SLEEP
  static int m41t80_suspend(struct device *dev)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  
  	if (client->irq >= 0 && device_may_wakeup(dev))
  		enable_irq_wake(client->irq);
  
  	return 0;
  }
  
  static int m41t80_resume(struct device *dev)
  {
  	struct i2c_client *client = to_i2c_client(dev);
  
  	if (client->irq >= 0 && device_may_wakeup(dev))
  		disable_irq_wake(client->irq);
  
  	return 0;
  }
  #endif
  
  static SIMPLE_DEV_PM_OPS(m41t80_pm, m41t80_suspend, m41t80_resume);
1373e77b4   Gary Bisson   rtc: m41t80: add ...
419
420
  #ifdef CONFIG_COMMON_CLK
  #define sqw_to_m41t80_data(_hw) container_of(_hw, struct m41t80_data, sqw)
2cb90ed3d   Troy Kisky   rtc: m41t80: avoi...
421
422
423
424
425
426
427
  static unsigned long m41t80_decode_freq(int setting)
  {
  	return (setting == 0) ? 0 : (setting == 1) ? M41T80_SQW_MAX_FREQ :
  		M41T80_SQW_MAX_FREQ >> setting;
  }
  
  static unsigned long m41t80_get_freq(struct m41t80_data *m41t80)
1373e77b4   Gary Bisson   rtc: m41t80: add ...
428
  {
1373e77b4   Gary Bisson   rtc: m41t80: add ...
429
430
431
432
  	struct i2c_client *client = m41t80->client;
  	int reg_sqw = (m41t80->features & M41T80_FEATURE_SQ_ALT) ?
  		M41T80_REG_WDAY : M41T80_REG_SQW;
  	int ret = i2c_smbus_read_byte_data(client, reg_sqw);
1373e77b4   Gary Bisson   rtc: m41t80: add ...
433
434
435
  
  	if (ret < 0)
  		return 0;
2cb90ed3d   Troy Kisky   rtc: m41t80: avoi...
436
437
  	return m41t80_decode_freq(ret >> 4);
  }
1373e77b4   Gary Bisson   rtc: m41t80: add ...
438

2cb90ed3d   Troy Kisky   rtc: m41t80: avoi...
439
440
441
442
  static unsigned long m41t80_sqw_recalc_rate(struct clk_hw *hw,
  					    unsigned long parent_rate)
  {
  	return sqw_to_m41t80_data(hw)->freq;
1373e77b4   Gary Bisson   rtc: m41t80: add ...
443
444
445
446
447
  }
  
  static long m41t80_sqw_round_rate(struct clk_hw *hw, unsigned long rate,
  				  unsigned long *prate)
  {
c8384bb04   Troy Kisky   rtc: m41t80: fix ...
448
449
450
451
452
453
454
  	if (rate >= M41T80_SQW_MAX_FREQ)
  		return M41T80_SQW_MAX_FREQ;
  	if (rate >= M41T80_SQW_MAX_FREQ / 4)
  		return M41T80_SQW_MAX_FREQ / 4;
  	if (!rate)
  		return 0;
  	return 1 << ilog2(rate);
1373e77b4   Gary Bisson   rtc: m41t80: add ...
455
456
457
458
459
460
461
462
463
464
  }
  
  static int m41t80_sqw_set_rate(struct clk_hw *hw, unsigned long rate,
  			       unsigned long parent_rate)
  {
  	struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw);
  	struct i2c_client *client = m41t80->client;
  	int reg_sqw = (m41t80->features & M41T80_FEATURE_SQ_ALT) ?
  		M41T80_REG_WDAY : M41T80_REG_SQW;
  	int reg, ret, val = 0;
05a03bf26   Troy Kisky   rtc: m41t80: remo...
465
466
467
468
469
470
  	if (rate >= M41T80_SQW_MAX_FREQ)
  		val = 1;
  	else if (rate >= M41T80_SQW_MAX_FREQ / 4)
  		val = 2;
  	else if (rate)
  		val = 15 - ilog2(rate);
1373e77b4   Gary Bisson   rtc: m41t80: add ...
471
472
473
474
475
476
477
478
  
  	reg = i2c_smbus_read_byte_data(client, reg_sqw);
  	if (reg < 0)
  		return reg;
  
  	reg = (reg & 0x0f) | (val << 4);
  
  	ret = i2c_smbus_write_byte_data(client, reg_sqw, reg);
2cb90ed3d   Troy Kisky   rtc: m41t80: avoi...
479
480
  	if (!ret)
  		m41t80->freq = m41t80_decode_freq(val);
de6042d2f   Troy Kisky   rtc: m41t80: m41t...
481
  	return ret;
1373e77b4   Gary Bisson   rtc: m41t80: add ...
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
  }
  
  static int m41t80_sqw_control(struct clk_hw *hw, bool enable)
  {
  	struct m41t80_data *m41t80 = sqw_to_m41t80_data(hw);
  	struct i2c_client *client = m41t80->client;
  	int ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
  
  	if (ret < 0)
  		return ret;
  
  	if (enable)
  		ret |= M41T80_ALMON_SQWE;
  	else
  		ret &= ~M41T80_ALMON_SQWE;
13bb1d78f   Troy Kisky   rtc: m41t80: avoi...
497
498
499
500
  	ret = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, ret);
  	if (!ret)
  		m41t80->sqwe = enable;
  	return ret;
1373e77b4   Gary Bisson   rtc: m41t80: add ...
501
502
503
504
505
506
507
508
509
510
511
512
513
514
  }
  
  static int m41t80_sqw_prepare(struct clk_hw *hw)
  {
  	return m41t80_sqw_control(hw, 1);
  }
  
  static void m41t80_sqw_unprepare(struct clk_hw *hw)
  {
  	m41t80_sqw_control(hw, 0);
  }
  
  static int m41t80_sqw_is_prepared(struct clk_hw *hw)
  {
13bb1d78f   Troy Kisky   rtc: m41t80: avoi...
515
  	return sqw_to_m41t80_data(hw)->sqwe;
1373e77b4   Gary Bisson   rtc: m41t80: add ...
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
  }
  
  static const struct clk_ops m41t80_sqw_ops = {
  	.prepare = m41t80_sqw_prepare,
  	.unprepare = m41t80_sqw_unprepare,
  	.is_prepared = m41t80_sqw_is_prepared,
  	.recalc_rate = m41t80_sqw_recalc_rate,
  	.round_rate = m41t80_sqw_round_rate,
  	.set_rate = m41t80_sqw_set_rate,
  };
  
  static struct clk *m41t80_sqw_register_clk(struct m41t80_data *m41t80)
  {
  	struct i2c_client *client = m41t80->client;
  	struct device_node *node = client->dev.of_node;
  	struct clk *clk;
  	struct clk_init_data init;
  	int ret;
  
  	/* First disable the clock */
  	ret = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON);
  	if (ret < 0)
  		return ERR_PTR(ret);
  	ret = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON,
  					ret & ~(M41T80_ALMON_SQWE));
  	if (ret < 0)
  		return ERR_PTR(ret);
  
  	init.name = "m41t80-sqw";
  	init.ops = &m41t80_sqw_ops;
  	init.flags = 0;
  	init.parent_names = NULL;
  	init.num_parents = 0;
  	m41t80->sqw.init = &init;
2cb90ed3d   Troy Kisky   rtc: m41t80: avoi...
550
  	m41t80->freq = m41t80_get_freq(m41t80);
1373e77b4   Gary Bisson   rtc: m41t80: add ...
551
552
553
554
555
556
557
558
559
560
561
562
  
  	/* optional override of the clockname */
  	of_property_read_string(node, "clock-output-names", &init.name);
  
  	/* register the clock */
  	clk = clk_register(&client->dev, &m41t80->sqw);
  	if (!IS_ERR(clk))
  		of_clk_add_provider(node, of_clk_src_simple_get, clk);
  
  	return clk;
  }
  #endif
617780d29   Atsushi Nemoto   rtc: watchdog sup...
563
564
565
566
567
568
569
570
  #ifdef CONFIG_RTC_DRV_M41T80_WDT
  /*
   *****************************************************************************
   *
   * Watchdog Driver
   *
   *****************************************************************************
   */
76384f319   Sebastian Andrzej Siewior   rtc: m41t80: move...
571
  static DEFINE_MUTEX(m41t80_rtc_mutex);
617780d29   Atsushi Nemoto   rtc: watchdog sup...
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
  static struct i2c_client *save_client;
  
  /* Default margin */
  #define WD_TIMO 60		/* 1..31 seconds */
  
  static int wdt_margin = WD_TIMO;
  module_param(wdt_margin, int, 0);
  MODULE_PARM_DESC(wdt_margin, "Watchdog timeout in seconds (default 60s)");
  
  static unsigned long wdt_is_open;
  static int boot_flag;
  
  /**
   *	wdt_ping:
   *
   *	Reload counter one with the watchdog timeout. We don't bother reloading
   *	the cascade counter.
   */
  static void wdt_ping(void)
  {
  	unsigned char i2c_data[2];
  	struct i2c_msg msgs1[1] = {
  		{
  			.addr	= save_client->addr,
  			.flags	= 0,
  			.len	= 2,
  			.buf	= i2c_data,
  		},
  	};
d3a126fcf   Steven A. Falco   rtc: rtc-m41t80.c...
601
  	struct m41t80_data *clientdata = i2c_get_clientdata(save_client);
617780d29   Atsushi Nemoto   rtc: watchdog sup...
602
603
604
605
606
607
608
609
  	i2c_data[0] = 0x09;		/* watchdog register */
  
  	if (wdt_margin > 31)
  		i2c_data[1] = (wdt_margin & 0xFC) | 0x83; /* resolution = 4s */
  	else
  		/*
  		 * WDS = 1 (0x80), mulitplier = WD_TIMO, resolution = 1s (0x02)
  		 */
fc99b9015   Mylène Josserand   rtc: m41t80: remo...
610
  		i2c_data[1] = wdt_margin << 2 | 0x82;
617780d29   Atsushi Nemoto   rtc: watchdog sup...
611

d3a126fcf   Steven A. Falco   rtc: rtc-m41t80.c...
612
613
614
615
616
617
  	/*
  	 * M41T65 has three bits for watchdog resolution.  Don't set bit 7, as
  	 * that would be an invalid resolution.
  	 */
  	if (clientdata->features & M41T80_FEATURE_WD)
  		i2c_data[1] &= ~M41T80_WATCHDOG_RB2;
617780d29   Atsushi Nemoto   rtc: watchdog sup...
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
  	i2c_transfer(save_client->adapter, msgs1, 1);
  }
  
  /**
   *	wdt_disable:
   *
   *	disables watchdog.
   */
  static void wdt_disable(void)
  {
  	unsigned char i2c_data[2], i2c_buf[0x10];
  	struct i2c_msg msgs0[2] = {
  		{
  			.addr	= save_client->addr,
  			.flags	= 0,
  			.len	= 1,
  			.buf	= i2c_data,
  		},
  		{
  			.addr	= save_client->addr,
  			.flags	= I2C_M_RD,
  			.len	= 1,
  			.buf	= i2c_buf,
  		},
  	};
  	struct i2c_msg msgs1[1] = {
  		{
  			.addr	= save_client->addr,
  			.flags	= 0,
  			.len	= 2,
  			.buf	= i2c_data,
  		},
  	};
  
  	i2c_data[0] = 0x09;
  	i2c_transfer(save_client->adapter, msgs0, 2);
  
  	i2c_data[0] = 0x09;
  	i2c_data[1] = 0x00;
  	i2c_transfer(save_client->adapter, msgs1, 1);
  }
  
  /**
   *	wdt_write:
   *	@file: file handle to the watchdog
   *	@buf: buffer to write (unused as data does not matter here
   *	@count: count of bytes
   *	@ppos: pointer to the position to write. No seeks allowed
   *
   *	A write to a watchdog device is defined as a keepalive signal. Any
   *	write of data will do, as we we don't define content meaning.
   */
  static ssize_t wdt_write(struct file *file, const char __user *buf,
  			 size_t count, loff_t *ppos)
  {
617780d29   Atsushi Nemoto   rtc: watchdog sup...
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
  	if (count) {
  		wdt_ping();
  		return 1;
  	}
  	return 0;
  }
  
  static ssize_t wdt_read(struct file *file, char __user *buf,
  			size_t count, loff_t *ppos)
  {
  	return 0;
  }
  
  /**
   *	wdt_ioctl:
617780d29   Atsushi Nemoto   rtc: watchdog sup...
688
689
690
691
692
693
694
695
   *	@file: file handle to the device
   *	@cmd: watchdog command
   *	@arg: argument pointer
   *
   *	The watchdog API defines a common set of functions for all watchdogs
   *	according to their available features. We only actually usefully support
   *	querying capabilities and current status.
   */
55929332c   Arnd Bergmann   drivers: Push dow...
696
  static int wdt_ioctl(struct file *file, unsigned int cmd,
617780d29   Atsushi Nemoto   rtc: watchdog sup...
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
  		     unsigned long arg)
  {
  	int new_margin, rv;
  	static struct watchdog_info ident = {
  		.options = WDIOF_POWERUNDER | WDIOF_KEEPALIVEPING |
  			WDIOF_SETTIMEOUT,
  		.firmware_version = 1,
  		.identity = "M41T80 WTD"
  	};
  
  	switch (cmd) {
  	case WDIOC_GETSUPPORT:
  		return copy_to_user((struct watchdog_info __user *)arg, &ident,
  				    sizeof(ident)) ? -EFAULT : 0;
  
  	case WDIOC_GETSTATUS:
  	case WDIOC_GETBOOTSTATUS:
  		return put_user(boot_flag, (int __user *)arg);
  	case WDIOC_KEEPALIVE:
  		wdt_ping();
  		return 0;
  	case WDIOC_SETTIMEOUT:
  		if (get_user(new_margin, (int __user *)arg))
  			return -EFAULT;
  		/* Arbitrary, can't find the card's limits */
  		if (new_margin < 1 || new_margin > 124)
  			return -EINVAL;
  		wdt_margin = new_margin;
  		wdt_ping();
df561f668   Gustavo A. R. Silva   treewide: Use fal...
726
  		fallthrough;
617780d29   Atsushi Nemoto   rtc: watchdog sup...
727
728
729
730
731
732
733
734
  	case WDIOC_GETTIMEOUT:
  		return put_user(wdt_margin, (int __user *)arg);
  
  	case WDIOC_SETOPTIONS:
  		if (copy_from_user(&rv, (int __user *)arg, sizeof(int)))
  			return -EFAULT;
  
  		if (rv & WDIOS_DISABLECARD) {
a737e835e   Joe Perches   rtc: use more sta...
735
736
  			pr_info("disable watchdog
  ");
617780d29   Atsushi Nemoto   rtc: watchdog sup...
737
738
739
740
  			wdt_disable();
  		}
  
  		if (rv & WDIOS_ENABLECARD) {
a737e835e   Joe Perches   rtc: use more sta...
741
742
  			pr_info("enable watchdog
  ");
617780d29   Atsushi Nemoto   rtc: watchdog sup...
743
744
745
746
747
748
749
  			wdt_ping();
  		}
  
  		return -EINVAL;
  	}
  	return -ENOTTY;
  }
55929332c   Arnd Bergmann   drivers: Push dow...
750
751
752
753
  static long wdt_unlocked_ioctl(struct file *file, unsigned int cmd,
  			       unsigned long arg)
  {
  	int ret;
613655fa3   Arnd Bergmann   drivers: autoconv...
754
  	mutex_lock(&m41t80_rtc_mutex);
55929332c   Arnd Bergmann   drivers: Push dow...
755
  	ret = wdt_ioctl(file, cmd, arg);
613655fa3   Arnd Bergmann   drivers: autoconv...
756
  	mutex_unlock(&m41t80_rtc_mutex);
55929332c   Arnd Bergmann   drivers: Push dow...
757
758
759
  
  	return ret;
  }
617780d29   Atsushi Nemoto   rtc: watchdog sup...
760
761
762
763
764
765
766
767
768
  /**
   *	wdt_open:
   *	@inode: inode of device
   *	@file: file handle to device
   *
   */
  static int wdt_open(struct inode *inode, struct file *file)
  {
  	if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
613655fa3   Arnd Bergmann   drivers: autoconv...
769
  		mutex_lock(&m41t80_rtc_mutex);
410127353   Arnd Bergmann   rtc-rtc-m41t80: B...
770
  		if (test_and_set_bit(0, &wdt_is_open)) {
613655fa3   Arnd Bergmann   drivers: autoconv...
771
  			mutex_unlock(&m41t80_rtc_mutex);
617780d29   Atsushi Nemoto   rtc: watchdog sup...
772
  			return -EBUSY;
410127353   Arnd Bergmann   rtc-rtc-m41t80: B...
773
  		}
617780d29   Atsushi Nemoto   rtc: watchdog sup...
774
775
776
777
  		/*
  		 *	Activate
  		 */
  		wdt_is_open = 1;
613655fa3   Arnd Bergmann   drivers: autoconv...
778
  		mutex_unlock(&m41t80_rtc_mutex);
c5bf68fe0   Kirill Smelkov   *: convert stream...
779
  		return stream_open(inode, file);
617780d29   Atsushi Nemoto   rtc: watchdog sup...
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
  	}
  	return -ENODEV;
  }
  
  /**
   *	wdt_close:
   *	@inode: inode to board
   *	@file: file handle to board
   *
   */
  static int wdt_release(struct inode *inode, struct file *file)
  {
  	if (MINOR(inode->i_rdev) == WATCHDOG_MINOR)
  		clear_bit(0, &wdt_is_open);
  	return 0;
  }
  
  /**
   *	notify_sys:
   *	@this: our notifier block
   *	@code: the event being reported
   *	@unused: unused
   *
   *	Our notifier is called on system shutdowns. We want to turn the card
   *	off at reboot otherwise the machine will reboot again during memory
   *	test or worse yet during the following fsck. This would suck, in fact
   *	trust me - if it happens it does suck.
   */
  static int wdt_notify_sys(struct notifier_block *this, unsigned long code,
  			  void *unused)
  {
  	if (code == SYS_DOWN || code == SYS_HALT)
  		/* Disable Watchdog */
  		wdt_disable();
  	return NOTIFY_DONE;
  }
  
  static const struct file_operations wdt_fops = {
  	.owner	= THIS_MODULE,
  	.read	= wdt_read,
55929332c   Arnd Bergmann   drivers: Push dow...
820
  	.unlocked_ioctl = wdt_unlocked_ioctl,
b6dfb2477   Arnd Bergmann   compat_ioctl: mov...
821
  	.compat_ioctl = compat_ptr_ioctl,
617780d29   Atsushi Nemoto   rtc: watchdog sup...
822
823
824
  	.write	= wdt_write,
  	.open	= wdt_open,
  	.release = wdt_release,
6038f373a   Arnd Bergmann   llseek: automatic...
825
  	.llseek = no_llseek,
617780d29   Atsushi Nemoto   rtc: watchdog sup...
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
  };
  
  static struct miscdevice wdt_dev = {
  	.minor = WATCHDOG_MINOR,
  	.name = "watchdog",
  	.fops = &wdt_fops,
  };
  
  /*
   *	The WDT card needs to learn about soft shutdowns in order to
   *	turn the timebomb registers off.
   */
  static struct notifier_block wdt_notifier = {
  	.notifier_call = wdt_notify_sys,
  };
  #endif /* CONFIG_RTC_DRV_M41T80_WDT */
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
842
843
844
845
846
847
848
  /*
   *****************************************************************************
   *
   *	Driver Interface
   *
   *****************************************************************************
   */
ef6b3125c   Mylène Josserand   rtc: m41t80: upda...
849

d2653e927   Jean Delvare   i2c: Add support ...
850
851
  static int m41t80_probe(struct i2c_client *client,
  			const struct i2c_device_id *id)
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
852
  {
e5108df40   Wolfram Sang   rtc: m41t80: simp...
853
  	struct i2c_adapter *adapter = client->adapter;
3760f7367   Jean Delvare   i2c: Convert most...
854
  	int rc = 0;
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
855
  	struct rtc_time tm;
9c6dfed92   Mylène Josserand   rtc: m41t80: add ...
856
  	struct m41t80_data *m41t80_data = NULL;
d4473b9b7   Eric Cooper   rtc: m41t80: enab...
857
  	bool wakeup_source = false;
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
858

f2b84ee88   Mylène Josserand   rtc: m41t80: repl...
859
860
861
862
  	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_I2C_BLOCK |
  				     I2C_FUNC_SMBUS_BYTE_DATA)) {
  		dev_err(&adapter->dev, "doesn't support I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_I2C_BLOCK
  ");
c67fedfab   Wolfram Sang   drivers/rtc/rtc-m...
863
  		return -ENODEV;
f2b84ee88   Mylène Josserand   rtc: m41t80: repl...
864
  	}
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
865

9c6dfed92   Mylène Josserand   rtc: m41t80: add ...
866
867
868
  	m41t80_data = devm_kzalloc(&client->dev, sizeof(*m41t80_data),
  				   GFP_KERNEL);
  	if (!m41t80_data)
c67fedfab   Wolfram Sang   drivers/rtc/rtc-m...
869
  		return -ENOMEM;
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
870

1373e77b4   Gary Bisson   rtc: m41t80: add ...
871
  	m41t80_data->client = client;
eb235c561   Javier Martinez Canillas   rtc: m41t80: Add ...
872
873
874
875
876
  	if (client->dev.of_node)
  		m41t80_data->features = (unsigned long)
  			of_device_get_match_data(&client->dev);
  	else
  		m41t80_data->features = id->driver_data;
9c6dfed92   Mylène Josserand   rtc: m41t80: add ...
877
  	i2c_set_clientdata(client, m41t80_data);
10d0c768c   Alexandre Belloni   rtc: m41t80: fix ...
878
879
880
  	m41t80_data->rtc =  devm_rtc_allocate_device(&client->dev);
  	if (IS_ERR(m41t80_data->rtc))
  		return PTR_ERR(m41t80_data->rtc);
d4473b9b7   Eric Cooper   rtc: m41t80: enab...
881
882
883
884
  #ifdef CONFIG_OF
  	wakeup_source = of_property_read_bool(client->dev.of_node,
  					      "wakeup-source");
  #endif
9c6dfed92   Mylène Josserand   rtc: m41t80: add ...
885
886
887
888
889
890
891
892
893
  	if (client->irq > 0) {
  		rc = devm_request_threaded_irq(&client->dev, client->irq,
  					       NULL, m41t80_handle_irq,
  					       IRQF_TRIGGER_LOW | IRQF_ONESHOT,
  					       "m41t80", client);
  		if (rc) {
  			dev_warn(&client->dev, "unable to request IRQ, alarms disabled
  ");
  			client->irq = 0;
d4473b9b7   Eric Cooper   rtc: m41t80: enab...
894
  			wakeup_source = false;
9c6dfed92   Mylène Josserand   rtc: m41t80: add ...
895
896
  		}
  	}
d4473b9b7   Eric Cooper   rtc: m41t80: enab...
897
898
899
900
901
902
903
  	if (client->irq > 0 || wakeup_source) {
  		m41t80_rtc_ops.read_alarm = m41t80_read_alarm;
  		m41t80_rtc_ops.set_alarm = m41t80_set_alarm;
  		m41t80_rtc_ops.alarm_irq_enable = m41t80_alarm_irq_enable;
  		/* Enable the wakealarm */
  		device_init_wakeup(&client->dev, true);
  	}
a015dbc11   John Stultz   rtc: m41t80: Init...
904

10d0c768c   Alexandre Belloni   rtc: m41t80: fix ...
905
  	m41t80_data->rtc->ops = &m41t80_rtc_ops;
cf79e7c3c   Alexandre Belloni   rtc: m41t80: set ...
906
907
  	m41t80_data->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000;
  	m41t80_data->rtc->range_max = RTC_TIMESTAMP_END_2099;
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
908

d4473b9b7   Eric Cooper   rtc: m41t80: enab...
909
910
  	if (client->irq <= 0) {
  		/* We cannot support UIE mode if we do not have an IRQ line */
10d0c768c   Alexandre Belloni   rtc: m41t80: fix ...
911
  		m41t80_data->rtc->uie_unsupported = 1;
d4473b9b7   Eric Cooper   rtc: m41t80: enab...
912
  	}
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
913
914
915
  
  	/* Make sure HT (Halt Update) bit is cleared */
  	rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR);
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
916

c67fedfab   Wolfram Sang   drivers/rtc/rtc-m...
917
  	if (rc >= 0 && rc & M41T80_ALHOUR_HT) {
9c6dfed92   Mylène Josserand   rtc: m41t80: add ...
918
  		if (m41t80_data->features & M41T80_FEATURE_HT) {
e2c8e1a9f   Alexandre Belloni   rtc: m41t80: remo...
919
  			m41t80_rtc_read_time(&client->dev, &tm);
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
920
921
  			dev_info(&client->dev, "HT bit was set!
  ");
22b844ae3   Andy Shevchenko   rtc: m41t80: Swit...
922
923
  			dev_info(&client->dev, "Power Down at %ptR
  ", &tm);
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
924
  		}
c67fedfab   Wolfram Sang   drivers/rtc/rtc-m...
925
  		rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_HOUR,
fc99b9015   Mylène Josserand   rtc: m41t80: remo...
926
  					       rc & ~M41T80_ALHOUR_HT);
c67fedfab   Wolfram Sang   drivers/rtc/rtc-m...
927
928
929
930
931
  	}
  
  	if (rc < 0) {
  		dev_err(&client->dev, "Can't clear HT bit
  ");
85d77047c   Wolfram Sang   drivers/rtc/rtc-m...
932
  		return rc;
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
933
934
935
936
  	}
  
  	/* Make sure ST (stop) bit is cleared */
  	rc = i2c_smbus_read_byte_data(client, M41T80_REG_SEC);
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
937

c67fedfab   Wolfram Sang   drivers/rtc/rtc-m...
938
939
  	if (rc >= 0 && rc & M41T80_SEC_ST)
  		rc = i2c_smbus_write_byte_data(client, M41T80_REG_SEC,
fc99b9015   Mylène Josserand   rtc: m41t80: remo...
940
  					       rc & ~M41T80_SEC_ST);
c67fedfab   Wolfram Sang   drivers/rtc/rtc-m...
941
942
943
  	if (rc < 0) {
  		dev_err(&client->dev, "Can't clear ST bit
  ");
85d77047c   Wolfram Sang   drivers/rtc/rtc-m...
944
  		return rc;
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
945
  	}
617780d29   Atsushi Nemoto   rtc: watchdog sup...
946
  #ifdef CONFIG_RTC_DRV_M41T80_WDT
9c6dfed92   Mylène Josserand   rtc: m41t80: add ...
947
  	if (m41t80_data->features & M41T80_FEATURE_HT) {
417607d05   Maciej W. Rozycki   RTC/watchdog: M41...
948
  		save_client = client;
617780d29   Atsushi Nemoto   rtc: watchdog sup...
949
950
  		rc = misc_register(&wdt_dev);
  		if (rc)
c67fedfab   Wolfram Sang   drivers/rtc/rtc-m...
951
  			return rc;
617780d29   Atsushi Nemoto   rtc: watchdog sup...
952
953
954
  		rc = register_reboot_notifier(&wdt_notifier);
  		if (rc) {
  			misc_deregister(&wdt_dev);
c67fedfab   Wolfram Sang   drivers/rtc/rtc-m...
955
  			return rc;
617780d29   Atsushi Nemoto   rtc: watchdog sup...
956
  		}
617780d29   Atsushi Nemoto   rtc: watchdog sup...
957
958
  	}
  #endif
1373e77b4   Gary Bisson   rtc: m41t80: add ...
959
960
961
962
  #ifdef CONFIG_COMMON_CLK
  	if (m41t80_data->features & M41T80_FEATURE_SQ)
  		m41t80_sqw_register_clk(m41t80_data);
  #endif
10d0c768c   Alexandre Belloni   rtc: m41t80: fix ...
963
964
965
966
  
  	rc = rtc_register_device(m41t80_data->rtc);
  	if (rc)
  		return rc;
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
967
  	return 0;
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
968
969
970
971
  }
  
  static int m41t80_remove(struct i2c_client *client)
  {
4ebabb78e   Jingoo Han   rtc: rtc-m41t80: ...
972
  #ifdef CONFIG_RTC_DRV_M41T80_WDT
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
973
  	struct m41t80_data *clientdata = i2c_get_clientdata(client);
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
974

3760f7367   Jean Delvare   i2c: Convert most...
975
  	if (clientdata->features & M41T80_FEATURE_HT) {
617780d29   Atsushi Nemoto   rtc: watchdog sup...
976
977
978
979
  		misc_deregister(&wdt_dev);
  		unregister_reboot_notifier(&wdt_notifier);
  	}
  #endif
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
980
981
982
983
984
985
  
  	return 0;
  }
  
  static struct i2c_driver m41t80_driver = {
  	.driver = {
afe1ab4d5   David Brownell   correct name for ...
986
  		.name = "rtc-m41t80",
eb235c561   Javier Martinez Canillas   rtc: m41t80: Add ...
987
  		.of_match_table = of_match_ptr(m41t80_of_match),
ae036af89   Stefan Christ   rtc: m41t80: add ...
988
  		.pm = &m41t80_pm,
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
989
990
991
  	},
  	.probe = m41t80_probe,
  	.remove = m41t80_remove,
3760f7367   Jean Delvare   i2c: Convert most...
992
  	.id_table = m41t80_id,
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
993
  };
0abc92011   Axel Lin   rtc: convert rtc ...
994
  module_i2c_driver(m41t80_driver);
caaff562e   Atsushi Nemoto   rtc: add rtc-m41t...
995
996
997
998
  
  MODULE_AUTHOR("Alexander Bigga <ab@mycable.de>");
  MODULE_DESCRIPTION("ST Microelectronics M41T80 series RTC I2C Client Driver");
  MODULE_LICENSE("GPL");