Blame view
drivers/rtc/rtc-m41t80.c
25.5 KB
d2912cb15 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
caaff562e 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 rtc: add rtc-m41t... |
10 |
*/ |
a737e835e rtc: use more sta... |
11 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
35aa64f3a rtc: m41t80: sort... |
12 |
#include <linux/bcd.h> |
1373e77b4 rtc: m41t80: add ... |
13 |
#include <linux/clk-provider.h> |
35aa64f3a rtc: m41t80: sort... |
14 |
#include <linux/i2c.h> |
caaff562e rtc: add rtc-m41t... |
15 |
#include <linux/init.h> |
9fb1f68d4 rtc: m41t80: incl... |
16 |
#include <linux/kernel.h> |
35aa64f3a rtc: m41t80: sort... |
17 |
#include <linux/module.h> |
eb235c561 rtc: m41t80: Add ... |
18 |
#include <linux/of_device.h> |
35aa64f3a rtc: m41t80: sort... |
19 |
#include <linux/rtc.h> |
caaff562e rtc: add rtc-m41t... |
20 |
#include <linux/slab.h> |
613655fa3 drivers: autoconv... |
21 |
#include <linux/mutex.h> |
caaff562e rtc: add rtc-m41t... |
22 |
#include <linux/string.h> |
617780d29 rtc: watchdog sup... |
23 |
#ifdef CONFIG_RTC_DRV_M41T80_WDT |
617780d29 rtc: watchdog sup... |
24 25 |
#include <linux/fs.h> #include <linux/ioctl.h> |
35aa64f3a rtc: m41t80: sort... |
26 27 28 |
#include <linux/miscdevice.h> #include <linux/reboot.h> #include <linux/watchdog.h> |
617780d29 rtc: watchdog sup... |
29 |
#endif |
caaff562e rtc: add rtc-m41t... |
30 |
|
f2b84ee88 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 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 rtc: m41t80: add ... |
50 |
#define M41T80_SQW_MAX_FREQ 32768 |
54339f3b3 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 rtc: m41t80: hand... |
55 |
#define M41T80_FLAGS_OF BIT(2) /* OF: Oscillator Failure Bit */ |
54339f3b3 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 rtc: add rtc-m41t... |
61 |
|
54339f3b3 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 rtc: add rtc-m41t... |
67 |
|
3760f7367 i2c: Convert most... |
68 |
static const struct i2c_device_id m41t80_id[] = { |
f30281f4f rtc: add m41t62 s... |
69 |
{ "m41t62", M41T80_FEATURE_SQ | M41T80_FEATURE_SQ_ALT }, |
d3a126fcf 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 drivers/rtc/rtc-m... |
79 |
{ "rv4162", M41T80_FEATURE_SQ | M41T80_FEATURE_WD | M41T80_FEATURE_SQ_ALT }, |
3760f7367 i2c: Convert most... |
80 |
{ } |
caaff562e rtc: add rtc-m41t... |
81 |
}; |
3760f7367 i2c: Convert most... |
82 |
MODULE_DEVICE_TABLE(i2c, m41t80_id); |
caaff562e rtc: add rtc-m41t... |
83 |
|
eb235c561 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 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 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 rtc: add rtc-m41t... |
141 |
struct m41t80_data { |
eb235c561 rtc: m41t80: Add ... |
142 |
unsigned long features; |
1373e77b4 rtc: m41t80: add ... |
143 |
struct i2c_client *client; |
caaff562e rtc: add rtc-m41t... |
144 |
struct rtc_device *rtc; |
1373e77b4 rtc: m41t80: add ... |
145 146 |
#ifdef CONFIG_COMMON_CLK struct clk_hw sqw; |
2cb90ed3d rtc: m41t80: avoi... |
147 |
unsigned long freq; |
13bb1d78f rtc: m41t80: avoi... |
148 |
unsigned int sqwe; |
1373e77b4 rtc: m41t80: add ... |
149 |
#endif |
caaff562e rtc: add rtc-m41t... |
150 |
}; |
9c6dfed92 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 rtc: m41t80: remo... |
190 |
static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm) |
caaff562e rtc: add rtc-m41t... |
191 |
{ |
e2c8e1a9f rtc: m41t80: remo... |
192 |
struct i2c_client *client = to_i2c_client(dev); |
f2b84ee88 rtc: m41t80: repl... |
193 |
unsigned char buf[8]; |
05a7f27a8 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 rtc: add rtc-m41t... |
205 |
|
f2b84ee88 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 rtc: m41t80: Comp... |
211 |
return err; |
caaff562e rtc: add rtc-m41t... |
212 |
} |
fe20ba70a 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 rtc: add rtc-m41t... |
217 |
tm->tm_wday = buf[M41T80_REG_WDAY] & 0x07; |
fe20ba70a drivers/rtc/: use... |
218 |
tm->tm_mon = bcd2bin(buf[M41T80_REG_MON] & 0x1f) - 1; |
caaff562e rtc: add rtc-m41t... |
219 220 |
/* assume 20YY not 19YY, and ignore the Century Bit */ |
fe20ba70a drivers/rtc/: use... |
221 |
tm->tm_year = bcd2bin(buf[M41T80_REG_YEAR]) + 100; |
22652ba72 rtc: stop validat... |
222 |
return 0; |
caaff562e rtc: add rtc-m41t... |
223 |
} |
e2c8e1a9f rtc: m41t80: remo... |
224 |
static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm) |
caaff562e rtc: add rtc-m41t... |
225 |
{ |
e2c8e1a9f rtc: m41t80: remo... |
226 |
struct i2c_client *client = to_i2c_client(dev); |
0f546b058 rtc: m41t80: fix ... |
227 |
struct m41t80_data *clientdata = i2c_get_clientdata(client); |
f2b84ee88 rtc: m41t80: repl... |
228 |
unsigned char buf[8]; |
05a7f27a8 rtc: m41t80: hand... |
229 |
int err, flags; |
caaff562e rtc: add rtc-m41t... |
230 |
|
caaff562e rtc: add rtc-m41t... |
231 |
buf[M41T80_REG_SSEC] = 0; |
f2b84ee88 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 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 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 rtc: m41t80: avoi... |
255 |
} |
caaff562e rtc: add rtc-m41t... |
256 |
|
05a7f27a8 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 rtc: m41t80: Comp... |
261 262 263 |
err = i2c_smbus_write_byte_data(client, M41T80_REG_FLAGS, flags & ~M41T80_FLAGS_OF); if (err < 0) { |
05a7f27a8 rtc: m41t80: hand... |
264 265 |
dev_err(&client->dev, "Unable to write flags register "); |
f1bd154d8 rtc: m41t80: Comp... |
266 |
return err; |
05a7f27a8 rtc: m41t80: hand... |
267 |
} |
f2b84ee88 rtc: m41t80: repl... |
268 |
return err; |
caaff562e rtc: add rtc-m41t... |
269 |
} |
caaff562e 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 rtc: m41t80: Comp... |
274 |
int reg; |
caaff562e rtc: add rtc-m41t... |
275 |
|
3760f7367 i2c: Convert most... |
276 |
if (clientdata->features & M41T80_FEATURE_BL) { |
caaff562e rtc: add rtc-m41t... |
277 |
reg = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS); |
f1bd154d8 rtc: m41t80: Comp... |
278 279 |
if (reg < 0) return reg; |
caaff562e 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 rtc: add rtc-m41t... |
286 |
|
9c6dfed92 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 rtc: m41t80: make... |
303 304 |
dev_err(dev, "Unable to enable alarm IRQ %d ", retval); |
9c6dfed92 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 rtc: m41t80: fix ... |
333 334 |
/* Keep SQWE bit value */ alarmvals[0] |= (ret & M41T80_ALMON_SQWE); |
9c6dfed92 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 rtc: m41t80: add ... |
383 |
alrm->time.tm_mday = bcd2bin(alarmvals[1] & 0x3f); |
3cc9ffbb1 rtc: m41t80: Corr... |
384 |
alrm->time.tm_mon = bcd2bin(alarmvals[0] & 0x3f) - 1; |
9c6dfed92 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 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 rtc: add rtc-m41t... |
394 |
.proc = m41t80_rtc_proc, |
caaff562e rtc: add rtc-m41t... |
395 |
}; |
ae036af89 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 rtc: m41t80: add ... |
419 420 |
#ifdef CONFIG_COMMON_CLK #define sqw_to_m41t80_data(_hw) container_of(_hw, struct m41t80_data, sqw) |
2cb90ed3d 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 rtc: m41t80: add ... |
428 |
{ |
1373e77b4 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 rtc: m41t80: add ... |
433 434 435 |
if (ret < 0) return 0; |
2cb90ed3d rtc: m41t80: avoi... |
436 437 |
return m41t80_decode_freq(ret >> 4); } |
1373e77b4 rtc: m41t80: add ... |
438 |
|
2cb90ed3d 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 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 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 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 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 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 rtc: m41t80: avoi... |
479 480 |
if (!ret) m41t80->freq = m41t80_decode_freq(val); |
de6042d2f rtc: m41t80: m41t... |
481 |
return ret; |
1373e77b4 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 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 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 rtc: m41t80: avoi... |
515 |
return sqw_to_m41t80_data(hw)->sqwe; |
1373e77b4 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 rtc: m41t80: avoi... |
550 |
m41t80->freq = m41t80_get_freq(m41t80); |
1373e77b4 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 rtc: watchdog sup... |
563 564 565 566 567 568 569 570 |
#ifdef CONFIG_RTC_DRV_M41T80_WDT /* ***************************************************************************** * * Watchdog Driver * ***************************************************************************** */ |
76384f319 rtc: m41t80: move... |
571 |
static DEFINE_MUTEX(m41t80_rtc_mutex); |
617780d29 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 rtc: rtc-m41t80.c... |
601 |
struct m41t80_data *clientdata = i2c_get_clientdata(save_client); |
617780d29 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 rtc: m41t80: remo... |
610 |
i2c_data[1] = wdt_margin << 2 | 0x82; |
617780d29 rtc: watchdog sup... |
611 |
|
d3a126fcf 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 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 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 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 drivers: Push dow... |
696 |
static int wdt_ioctl(struct file *file, unsigned int cmd, |
617780d29 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 treewide: Use fal... |
726 |
fallthrough; |
617780d29 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 rtc: use more sta... |
735 736 |
pr_info("disable watchdog "); |
617780d29 rtc: watchdog sup... |
737 738 739 740 |
wdt_disable(); } if (rv & WDIOS_ENABLECARD) { |
a737e835e rtc: use more sta... |
741 742 |
pr_info("enable watchdog "); |
617780d29 rtc: watchdog sup... |
743 744 745 746 747 748 749 |
wdt_ping(); } return -EINVAL; } return -ENOTTY; } |
55929332c drivers: Push dow... |
750 751 752 753 |
static long wdt_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret; |
613655fa3 drivers: autoconv... |
754 |
mutex_lock(&m41t80_rtc_mutex); |
55929332c drivers: Push dow... |
755 |
ret = wdt_ioctl(file, cmd, arg); |
613655fa3 drivers: autoconv... |
756 |
mutex_unlock(&m41t80_rtc_mutex); |
55929332c drivers: Push dow... |
757 758 759 |
return ret; } |
617780d29 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 drivers: autoconv... |
769 |
mutex_lock(&m41t80_rtc_mutex); |
410127353 rtc-rtc-m41t80: B... |
770 |
if (test_and_set_bit(0, &wdt_is_open)) { |
613655fa3 drivers: autoconv... |
771 |
mutex_unlock(&m41t80_rtc_mutex); |
617780d29 rtc: watchdog sup... |
772 |
return -EBUSY; |
410127353 rtc-rtc-m41t80: B... |
773 |
} |
617780d29 rtc: watchdog sup... |
774 775 776 777 |
/* * Activate */ wdt_is_open = 1; |
613655fa3 drivers: autoconv... |
778 |
mutex_unlock(&m41t80_rtc_mutex); |
c5bf68fe0 *: convert stream... |
779 |
return stream_open(inode, file); |
617780d29 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 drivers: Push dow... |
820 |
.unlocked_ioctl = wdt_unlocked_ioctl, |
b6dfb2477 compat_ioctl: mov... |
821 |
.compat_ioctl = compat_ptr_ioctl, |
617780d29 rtc: watchdog sup... |
822 823 824 |
.write = wdt_write, .open = wdt_open, .release = wdt_release, |
6038f373a llseek: automatic... |
825 |
.llseek = no_llseek, |
617780d29 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 rtc: add rtc-m41t... |
842 843 844 845 846 847 848 |
/* ***************************************************************************** * * Driver Interface * ***************************************************************************** */ |
ef6b3125c rtc: m41t80: upda... |
849 |
|
d2653e927 i2c: Add support ... |
850 851 |
static int m41t80_probe(struct i2c_client *client, const struct i2c_device_id *id) |
caaff562e rtc: add rtc-m41t... |
852 |
{ |
e5108df40 rtc: m41t80: simp... |
853 |
struct i2c_adapter *adapter = client->adapter; |
3760f7367 i2c: Convert most... |
854 |
int rc = 0; |
caaff562e rtc: add rtc-m41t... |
855 |
struct rtc_time tm; |
9c6dfed92 rtc: m41t80: add ... |
856 |
struct m41t80_data *m41t80_data = NULL; |
d4473b9b7 rtc: m41t80: enab... |
857 |
bool wakeup_source = false; |
caaff562e rtc: add rtc-m41t... |
858 |
|
f2b84ee88 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 drivers/rtc/rtc-m... |
863 |
return -ENODEV; |
f2b84ee88 rtc: m41t80: repl... |
864 |
} |
caaff562e rtc: add rtc-m41t... |
865 |
|
9c6dfed92 rtc: m41t80: add ... |
866 867 868 |
m41t80_data = devm_kzalloc(&client->dev, sizeof(*m41t80_data), GFP_KERNEL); if (!m41t80_data) |
c67fedfab drivers/rtc/rtc-m... |
869 |
return -ENOMEM; |
caaff562e rtc: add rtc-m41t... |
870 |
|
1373e77b4 rtc: m41t80: add ... |
871 |
m41t80_data->client = client; |
eb235c561 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 rtc: m41t80: add ... |
877 |
i2c_set_clientdata(client, m41t80_data); |
10d0c768c 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 rtc: m41t80: enab... |
881 882 883 884 |
#ifdef CONFIG_OF wakeup_source = of_property_read_bool(client->dev.of_node, "wakeup-source"); #endif |
9c6dfed92 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 rtc: m41t80: enab... |
894 |
wakeup_source = false; |
9c6dfed92 rtc: m41t80: add ... |
895 896 |
} } |
d4473b9b7 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 rtc: m41t80: Init... |
904 |
|
10d0c768c rtc: m41t80: fix ... |
905 |
m41t80_data->rtc->ops = &m41t80_rtc_ops; |
cf79e7c3c rtc: m41t80: set ... |
906 907 |
m41t80_data->rtc->range_min = RTC_TIMESTAMP_BEGIN_2000; m41t80_data->rtc->range_max = RTC_TIMESTAMP_END_2099; |
caaff562e rtc: add rtc-m41t... |
908 |
|
d4473b9b7 rtc: m41t80: enab... |
909 910 |
if (client->irq <= 0) { /* We cannot support UIE mode if we do not have an IRQ line */ |
10d0c768c rtc: m41t80: fix ... |
911 |
m41t80_data->rtc->uie_unsupported = 1; |
d4473b9b7 rtc: m41t80: enab... |
912 |
} |
caaff562e 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 rtc: add rtc-m41t... |
916 |
|
c67fedfab drivers/rtc/rtc-m... |
917 |
if (rc >= 0 && rc & M41T80_ALHOUR_HT) { |
9c6dfed92 rtc: m41t80: add ... |
918 |
if (m41t80_data->features & M41T80_FEATURE_HT) { |
e2c8e1a9f rtc: m41t80: remo... |
919 |
m41t80_rtc_read_time(&client->dev, &tm); |
caaff562e rtc: add rtc-m41t... |
920 921 |
dev_info(&client->dev, "HT bit was set! "); |
22b844ae3 rtc: m41t80: Swit... |
922 923 |
dev_info(&client->dev, "Power Down at %ptR ", &tm); |
caaff562e rtc: add rtc-m41t... |
924 |
} |
c67fedfab drivers/rtc/rtc-m... |
925 |
rc = i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_HOUR, |
fc99b9015 rtc: m41t80: remo... |
926 |
rc & ~M41T80_ALHOUR_HT); |
c67fedfab drivers/rtc/rtc-m... |
927 928 929 930 931 |
} if (rc < 0) { dev_err(&client->dev, "Can't clear HT bit "); |
85d77047c drivers/rtc/rtc-m... |
932 |
return rc; |
caaff562e 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 rtc: add rtc-m41t... |
937 |
|
c67fedfab drivers/rtc/rtc-m... |
938 939 |
if (rc >= 0 && rc & M41T80_SEC_ST) rc = i2c_smbus_write_byte_data(client, M41T80_REG_SEC, |
fc99b9015 rtc: m41t80: remo... |
940 |
rc & ~M41T80_SEC_ST); |
c67fedfab drivers/rtc/rtc-m... |
941 942 943 |
if (rc < 0) { dev_err(&client->dev, "Can't clear ST bit "); |
85d77047c drivers/rtc/rtc-m... |
944 |
return rc; |
caaff562e rtc: add rtc-m41t... |
945 |
} |
617780d29 rtc: watchdog sup... |
946 |
#ifdef CONFIG_RTC_DRV_M41T80_WDT |
9c6dfed92 rtc: m41t80: add ... |
947 |
if (m41t80_data->features & M41T80_FEATURE_HT) { |
417607d05 RTC/watchdog: M41... |
948 |
save_client = client; |
617780d29 rtc: watchdog sup... |
949 950 |
rc = misc_register(&wdt_dev); if (rc) |
c67fedfab drivers/rtc/rtc-m... |
951 |
return rc; |
617780d29 rtc: watchdog sup... |
952 953 954 |
rc = register_reboot_notifier(&wdt_notifier); if (rc) { misc_deregister(&wdt_dev); |
c67fedfab drivers/rtc/rtc-m... |
955 |
return rc; |
617780d29 rtc: watchdog sup... |
956 |
} |
617780d29 rtc: watchdog sup... |
957 958 |
} #endif |
1373e77b4 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 rtc: m41t80: fix ... |
963 964 965 966 |
rc = rtc_register_device(m41t80_data->rtc); if (rc) return rc; |
caaff562e rtc: add rtc-m41t... |
967 |
return 0; |
caaff562e rtc: add rtc-m41t... |
968 969 970 971 |
} static int m41t80_remove(struct i2c_client *client) { |
4ebabb78e rtc: rtc-m41t80: ... |
972 |
#ifdef CONFIG_RTC_DRV_M41T80_WDT |
caaff562e rtc: add rtc-m41t... |
973 |
struct m41t80_data *clientdata = i2c_get_clientdata(client); |
caaff562e rtc: add rtc-m41t... |
974 |
|
3760f7367 i2c: Convert most... |
975 |
if (clientdata->features & M41T80_FEATURE_HT) { |
617780d29 rtc: watchdog sup... |
976 977 978 979 |
misc_deregister(&wdt_dev); unregister_reboot_notifier(&wdt_notifier); } #endif |
caaff562e rtc: add rtc-m41t... |
980 981 982 983 984 985 |
return 0; } static struct i2c_driver m41t80_driver = { .driver = { |
afe1ab4d5 correct name for ... |
986 |
.name = "rtc-m41t80", |
eb235c561 rtc: m41t80: Add ... |
987 |
.of_match_table = of_match_ptr(m41t80_of_match), |
ae036af89 rtc: m41t80: add ... |
988 |
.pm = &m41t80_pm, |
caaff562e rtc: add rtc-m41t... |
989 990 991 |
}, .probe = m41t80_probe, .remove = m41t80_remove, |
3760f7367 i2c: Convert most... |
992 |
.id_table = m41t80_id, |
caaff562e rtc: add rtc-m41t... |
993 |
}; |
0abc92011 rtc: convert rtc ... |
994 |
module_i2c_driver(m41t80_driver); |
caaff562e 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"); |