Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rtc: add rtc-m41t80 driver

This is a new-style i2c driver for ST M41T80 series RTC chip, derived from
works by Alexander Bigga <ab@mycable.de> who wrote the original
rtc-m41txx.c based on drivers/i2c/chips/m41t00.c driver.

This driver supports M41T8[0-4] and M41ST8[457]. The old m41t00 driver
supports M41T00, M41T81 and M41T85(M41ST85). While the M41T00 chip is now
supported by rtc-ds1307 driver, this driver does not include support for
the chip.

[akpm@linux-foundation.org: remove bogus `static']
Signed-off-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Signed-off-by: Alexander Bigga <ab@mycable.de>
Acked-by: Mark A. Greer <mgreer@mvista.com>
Cc: David Brownell <david-b@pacbell.net>
Acked-by: Alessandro Zummo <a.zummo@towertech.it>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Atsushi Nemoto and committed by
Linus Torvalds
caaff562 5663c14b

+642
+12
drivers/rtc/Kconfig
··· 212 212 This driver can also be built as a module. If so, the module 213 213 will be called rtc-pcf8583. 214 214 215 + config RTC_DRV_M41T80 216 + tristate "ST M41T80 series RTC" 217 + depends on RTC_CLASS && I2C 218 + help 219 + If you say Y here you will get support for the 220 + ST M41T80 RTC chips series. Currently following chips are 221 + supported: M41T80, M41T81, M41T82, M41T83, M41ST84, M41ST85 222 + and M41ST87. 223 + 224 + This driver can also be built as a module. If so, the module 225 + will be called rtc-m41t80. 226 + 215 227 comment "SPI RTC drivers" 216 228 depends on RTC_CLASS && SPI_MASTER 217 229
+1
drivers/rtc/Makefile
··· 29 29 obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o 30 30 obj-$(CONFIG_RTC_DRV_S3C) += rtc-s3c.o 31 31 obj-$(CONFIG_RTC_DRV_RS5C348) += rtc-rs5c348.o 32 + obj-$(CONFIG_RTC_DRV_M41T80) += rtc-m41t80.o 32 33 obj-$(CONFIG_RTC_DRV_M48T86) += rtc-m48t86.o 33 34 obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o 34 35 obj-$(CONFIG_RTC_DRV_RS5C313) += rtc-rs5c313.o
+629
drivers/rtc/rtc-m41t80.c
··· 1 + /* 2 + * I2C client/driver for the ST M41T80 family of i2c rtc chips. 3 + * 4 + * Author: Alexander Bigga <ab@mycable.de> 5 + * 6 + * Based on m41t00.c by Mark A. Greer <mgreer@mvista.com> 7 + * 8 + * 2006 (c) mycable GmbH 9 + * 10 + * This program is free software; you can redistribute it and/or modify 11 + * it under the terms of the GNU General Public License version 2 as 12 + * published by the Free Software Foundation. 13 + * 14 + */ 15 + 16 + #include <linux/module.h> 17 + #include <linux/init.h> 18 + #include <linux/slab.h> 19 + #include <linux/string.h> 20 + #include <linux/i2c.h> 21 + #include <linux/rtc.h> 22 + #include <linux/bcd.h> 23 + 24 + #define M41T80_REG_SSEC 0 25 + #define M41T80_REG_SEC 1 26 + #define M41T80_REG_MIN 2 27 + #define M41T80_REG_HOUR 3 28 + #define M41T80_REG_WDAY 4 29 + #define M41T80_REG_DAY 5 30 + #define M41T80_REG_MON 6 31 + #define M41T80_REG_YEAR 7 32 + #define M41T80_REG_ALARM_MON 0xa 33 + #define M41T80_REG_ALARM_DAY 0xb 34 + #define M41T80_REG_ALARM_HOUR 0xc 35 + #define M41T80_REG_ALARM_MIN 0xd 36 + #define M41T80_REG_ALARM_SEC 0xe 37 + #define M41T80_REG_FLAGS 0xf 38 + #define M41T80_REG_SQW 0x13 39 + 40 + #define M41T80_DATETIME_REG_SIZE (M41T80_REG_YEAR + 1) 41 + #define M41T80_ALARM_REG_SIZE \ 42 + (M41T80_REG_ALARM_SEC + 1 - M41T80_REG_ALARM_MON) 43 + 44 + #define M41T80_SEC_ST (1 << 7) /* ST: Stop Bit */ 45 + #define M41T80_ALMON_AFE (1 << 7) /* AFE: AF Enable Bit */ 46 + #define M41T80_ALMON_SQWE (1 << 6) /* SQWE: SQW Enable Bit */ 47 + #define M41T80_ALHOUR_HT (1 << 6) /* HT: Halt Update Bit */ 48 + #define M41T80_FLAGS_AF (1 << 6) /* AF: Alarm Flag Bit */ 49 + #define M41T80_FLAGS_BATT_LOW (1 << 4) /* BL: Battery Low Bit */ 50 + 51 + #define M41T80_FEATURE_HT (1 << 0) 52 + #define M41T80_FEATURE_BL (1 << 1) 53 + 54 + #define DRV_VERSION "0.05" 55 + 56 + struct m41t80_chip_info { 57 + const char *name; 58 + u8 features; 59 + }; 60 + 61 + static const struct m41t80_chip_info m41t80_chip_info_tbl[] = { 62 + { 63 + .name = "m41t80", 64 + .features = 0, 65 + }, 66 + { 67 + .name = "m41t81", 68 + .features = M41T80_FEATURE_HT, 69 + }, 70 + { 71 + .name = "m41t81s", 72 + .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, 73 + }, 74 + { 75 + .name = "m41t82", 76 + .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, 77 + }, 78 + { 79 + .name = "m41t83", 80 + .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, 81 + }, 82 + { 83 + .name = "m41st84", 84 + .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, 85 + }, 86 + { 87 + .name = "m41st85", 88 + .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, 89 + }, 90 + { 91 + .name = "m41st87", 92 + .features = M41T80_FEATURE_HT | M41T80_FEATURE_BL, 93 + }, 94 + }; 95 + 96 + struct m41t80_data { 97 + const struct m41t80_chip_info *chip; 98 + struct rtc_device *rtc; 99 + }; 100 + 101 + static int m41t80_get_datetime(struct i2c_client *client, 102 + struct rtc_time *tm) 103 + { 104 + u8 buf[M41T80_DATETIME_REG_SIZE], dt_addr[1] = { M41T80_REG_SEC }; 105 + struct i2c_msg msgs[] = { 106 + { 107 + .addr = client->addr, 108 + .flags = 0, 109 + .len = 1, 110 + .buf = dt_addr, 111 + }, 112 + { 113 + .addr = client->addr, 114 + .flags = I2C_M_RD, 115 + .len = M41T80_DATETIME_REG_SIZE - M41T80_REG_SEC, 116 + .buf = buf + M41T80_REG_SEC, 117 + }, 118 + }; 119 + 120 + if (i2c_transfer(client->adapter, msgs, 2) < 0) { 121 + dev_err(&client->dev, "read error\n"); 122 + return -EIO; 123 + } 124 + 125 + tm->tm_sec = BCD2BIN(buf[M41T80_REG_SEC] & 0x7f); 126 + tm->tm_min = BCD2BIN(buf[M41T80_REG_MIN] & 0x7f); 127 + tm->tm_hour = BCD2BIN(buf[M41T80_REG_HOUR] & 0x3f); 128 + tm->tm_mday = BCD2BIN(buf[M41T80_REG_DAY] & 0x3f); 129 + tm->tm_wday = buf[M41T80_REG_WDAY] & 0x07; 130 + tm->tm_mon = BCD2BIN(buf[M41T80_REG_MON] & 0x1f) - 1; 131 + 132 + /* assume 20YY not 19YY, and ignore the Century Bit */ 133 + tm->tm_year = BCD2BIN(buf[M41T80_REG_YEAR]) + 100; 134 + return 0; 135 + } 136 + 137 + /* Sets the given date and time to the real time clock. */ 138 + static int m41t80_set_datetime(struct i2c_client *client, struct rtc_time *tm) 139 + { 140 + u8 wbuf[1 + M41T80_DATETIME_REG_SIZE]; 141 + u8 *buf = &wbuf[1]; 142 + u8 dt_addr[1] = { M41T80_REG_SEC }; 143 + struct i2c_msg msgs_in[] = { 144 + { 145 + .addr = client->addr, 146 + .flags = 0, 147 + .len = 1, 148 + .buf = dt_addr, 149 + }, 150 + { 151 + .addr = client->addr, 152 + .flags = I2C_M_RD, 153 + .len = M41T80_DATETIME_REG_SIZE - M41T80_REG_SEC, 154 + .buf = buf + M41T80_REG_SEC, 155 + }, 156 + }; 157 + struct i2c_msg msgs[] = { 158 + { 159 + .addr = client->addr, 160 + .flags = 0, 161 + .len = 1 + M41T80_DATETIME_REG_SIZE, 162 + .buf = wbuf, 163 + }, 164 + }; 165 + 166 + /* Read current reg values into buf[1..7] */ 167 + if (i2c_transfer(client->adapter, msgs_in, 2) < 0) { 168 + dev_err(&client->dev, "read error\n"); 169 + return -EIO; 170 + } 171 + 172 + wbuf[0] = 0; /* offset into rtc's regs */ 173 + /* Merge time-data and register flags into buf[0..7] */ 174 + buf[M41T80_REG_SSEC] = 0; 175 + buf[M41T80_REG_SEC] = 176 + BIN2BCD(tm->tm_sec) | (buf[M41T80_REG_SEC] & ~0x7f); 177 + buf[M41T80_REG_MIN] = 178 + BIN2BCD(tm->tm_min) | (buf[M41T80_REG_MIN] & ~0x7f); 179 + buf[M41T80_REG_HOUR] = 180 + BIN2BCD(tm->tm_hour) | (buf[M41T80_REG_HOUR] & ~0x3f) ; 181 + buf[M41T80_REG_WDAY] = 182 + (tm->tm_wday & 0x07) | (buf[M41T80_REG_WDAY] & ~0x07); 183 + buf[M41T80_REG_DAY] = 184 + BIN2BCD(tm->tm_mday) | (buf[M41T80_REG_DAY] & ~0x3f); 185 + buf[M41T80_REG_MON] = 186 + BIN2BCD(tm->tm_mon + 1) | (buf[M41T80_REG_MON] & ~0x1f); 187 + /* assume 20YY not 19YY */ 188 + buf[M41T80_REG_YEAR] = BIN2BCD(tm->tm_year % 100); 189 + 190 + if (i2c_transfer(client->adapter, msgs, 1) != 1) { 191 + dev_err(&client->dev, "write error\n"); 192 + return -EIO; 193 + } 194 + return 0; 195 + } 196 + 197 + #if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE) 198 + static int m41t80_rtc_proc(struct device *dev, struct seq_file *seq) 199 + { 200 + struct i2c_client *client = to_i2c_client(dev); 201 + struct m41t80_data *clientdata = i2c_get_clientdata(client); 202 + u8 reg; 203 + 204 + if (clientdata->chip->features & M41T80_FEATURE_BL) { 205 + reg = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS); 206 + seq_printf(seq, "battery\t\t: %s\n", 207 + (reg & M41T80_FLAGS_BATT_LOW) ? "exhausted" : "ok"); 208 + } 209 + return 0; 210 + } 211 + #else 212 + #define m41t80_rtc_proc NULL 213 + #endif 214 + 215 + static int m41t80_rtc_read_time(struct device *dev, struct rtc_time *tm) 216 + { 217 + return m41t80_get_datetime(to_i2c_client(dev), tm); 218 + } 219 + 220 + static int m41t80_rtc_set_time(struct device *dev, struct rtc_time *tm) 221 + { 222 + return m41t80_set_datetime(to_i2c_client(dev), tm); 223 + } 224 + 225 + #if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE) 226 + static int 227 + m41t80_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) 228 + { 229 + struct i2c_client *client = to_i2c_client(dev); 230 + int rc; 231 + 232 + switch (cmd) { 233 + case RTC_AIE_OFF: 234 + case RTC_AIE_ON: 235 + break; 236 + default: 237 + return -ENOIOCTLCMD; 238 + } 239 + 240 + rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); 241 + if (rc < 0) 242 + goto err; 243 + switch (cmd) { 244 + case RTC_AIE_OFF: 245 + rc &= ~M41T80_ALMON_AFE; 246 + break; 247 + case RTC_AIE_ON: 248 + rc |= M41T80_ALMON_AFE; 249 + break; 250 + } 251 + if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, rc) < 0) 252 + goto err; 253 + return 0; 254 + err: 255 + return -EIO; 256 + } 257 + #else 258 + #define m41t80_rtc_ioctl NULL 259 + #endif 260 + 261 + static int m41t80_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *t) 262 + { 263 + struct i2c_client *client = to_i2c_client(dev); 264 + u8 wbuf[1 + M41T80_ALARM_REG_SIZE]; 265 + u8 *buf = &wbuf[1]; 266 + u8 *reg = buf - M41T80_REG_ALARM_MON; 267 + u8 dt_addr[1] = { M41T80_REG_ALARM_MON }; 268 + struct i2c_msg msgs_in[] = { 269 + { 270 + .addr = client->addr, 271 + .flags = 0, 272 + .len = 1, 273 + .buf = dt_addr, 274 + }, 275 + { 276 + .addr = client->addr, 277 + .flags = I2C_M_RD, 278 + .len = M41T80_ALARM_REG_SIZE, 279 + .buf = buf, 280 + }, 281 + }; 282 + struct i2c_msg msgs[] = { 283 + { 284 + .addr = client->addr, 285 + .flags = 0, 286 + .len = 1 + M41T80_ALARM_REG_SIZE, 287 + .buf = wbuf, 288 + }, 289 + }; 290 + 291 + if (i2c_transfer(client->adapter, msgs_in, 2) < 0) { 292 + dev_err(&client->dev, "read error\n"); 293 + return -EIO; 294 + } 295 + reg[M41T80_REG_ALARM_MON] &= ~(0x1f | M41T80_ALMON_AFE); 296 + reg[M41T80_REG_ALARM_DAY] = 0; 297 + reg[M41T80_REG_ALARM_HOUR] &= ~(0x3f | 0x80); 298 + reg[M41T80_REG_ALARM_MIN] = 0; 299 + reg[M41T80_REG_ALARM_SEC] = 0; 300 + 301 + wbuf[0] = M41T80_REG_ALARM_MON; /* offset into rtc's regs */ 302 + reg[M41T80_REG_ALARM_SEC] |= t->time.tm_sec >= 0 ? 303 + BIN2BCD(t->time.tm_sec) : 0x80; 304 + reg[M41T80_REG_ALARM_MIN] |= t->time.tm_min >= 0 ? 305 + BIN2BCD(t->time.tm_min) : 0x80; 306 + reg[M41T80_REG_ALARM_HOUR] |= t->time.tm_hour >= 0 ? 307 + BIN2BCD(t->time.tm_hour) : 0x80; 308 + reg[M41T80_REG_ALARM_DAY] |= t->time.tm_mday >= 0 ? 309 + BIN2BCD(t->time.tm_mday) : 0x80; 310 + if (t->time.tm_mon >= 0) 311 + reg[M41T80_REG_ALARM_MON] |= BIN2BCD(t->time.tm_mon + 1); 312 + else 313 + reg[M41T80_REG_ALARM_DAY] |= 0x40; 314 + 315 + if (i2c_transfer(client->adapter, msgs, 1) != 1) { 316 + dev_err(&client->dev, "write error\n"); 317 + return -EIO; 318 + } 319 + 320 + if (t->enabled) { 321 + reg[M41T80_REG_ALARM_MON] |= M41T80_ALMON_AFE; 322 + if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, 323 + reg[M41T80_REG_ALARM_MON]) < 0) { 324 + dev_err(&client->dev, "write error\n"); 325 + return -EIO; 326 + } 327 + } 328 + return 0; 329 + } 330 + 331 + static int m41t80_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *t) 332 + { 333 + struct i2c_client *client = to_i2c_client(dev); 334 + u8 buf[M41T80_ALARM_REG_SIZE + 1]; /* all alarm regs and flags */ 335 + u8 dt_addr[1] = { M41T80_REG_ALARM_MON }; 336 + u8 *reg = buf - M41T80_REG_ALARM_MON; 337 + struct i2c_msg msgs[] = { 338 + { 339 + .addr = client->addr, 340 + .flags = 0, 341 + .len = 1, 342 + .buf = dt_addr, 343 + }, 344 + { 345 + .addr = client->addr, 346 + .flags = I2C_M_RD, 347 + .len = M41T80_ALARM_REG_SIZE + 1, 348 + .buf = buf, 349 + }, 350 + }; 351 + 352 + if (i2c_transfer(client->adapter, msgs, 2) < 0) { 353 + dev_err(&client->dev, "read error\n"); 354 + return -EIO; 355 + } 356 + t->time.tm_sec = -1; 357 + t->time.tm_min = -1; 358 + t->time.tm_hour = -1; 359 + t->time.tm_mday = -1; 360 + t->time.tm_mon = -1; 361 + if (!(reg[M41T80_REG_ALARM_SEC] & 0x80)) 362 + t->time.tm_sec = BCD2BIN(reg[M41T80_REG_ALARM_SEC] & 0x7f); 363 + if (!(reg[M41T80_REG_ALARM_MIN] & 0x80)) 364 + t->time.tm_min = BCD2BIN(reg[M41T80_REG_ALARM_MIN] & 0x7f); 365 + if (!(reg[M41T80_REG_ALARM_HOUR] & 0x80)) 366 + t->time.tm_hour = BCD2BIN(reg[M41T80_REG_ALARM_HOUR] & 0x3f); 367 + if (!(reg[M41T80_REG_ALARM_DAY] & 0x80)) 368 + t->time.tm_mday = BCD2BIN(reg[M41T80_REG_ALARM_DAY] & 0x3f); 369 + if (!(reg[M41T80_REG_ALARM_DAY] & 0x40)) 370 + t->time.tm_mon = BCD2BIN(reg[M41T80_REG_ALARM_MON] & 0x1f) - 1; 371 + t->time.tm_year = -1; 372 + t->time.tm_wday = -1; 373 + t->time.tm_yday = -1; 374 + t->time.tm_isdst = -1; 375 + t->enabled = !!(reg[M41T80_REG_ALARM_MON] & M41T80_ALMON_AFE); 376 + t->pending = !!(reg[M41T80_REG_FLAGS] & M41T80_FLAGS_AF); 377 + return 0; 378 + } 379 + 380 + static struct rtc_class_ops m41t80_rtc_ops = { 381 + .read_time = m41t80_rtc_read_time, 382 + .set_time = m41t80_rtc_set_time, 383 + .read_alarm = m41t80_rtc_read_alarm, 384 + .set_alarm = m41t80_rtc_set_alarm, 385 + .proc = m41t80_rtc_proc, 386 + .ioctl = m41t80_rtc_ioctl, 387 + }; 388 + 389 + #if defined(CONFIG_RTC_INTF_SYSFS) || defined(CONFIG_RTC_INTF_SYSFS_MODULE) 390 + static ssize_t m41t80_sysfs_show_flags(struct device *dev, 391 + struct device_attribute *attr, char *buf) 392 + { 393 + struct i2c_client *client = to_i2c_client(dev); 394 + int val; 395 + 396 + val = i2c_smbus_read_byte_data(client, M41T80_REG_FLAGS); 397 + if (val < 0) 398 + return -EIO; 399 + return sprintf(buf, "%#x\n", val); 400 + } 401 + static DEVICE_ATTR(flags, S_IRUGO, m41t80_sysfs_show_flags, NULL); 402 + 403 + static ssize_t m41t80_sysfs_show_sqwfreq(struct device *dev, 404 + struct device_attribute *attr, char *buf) 405 + { 406 + struct i2c_client *client = to_i2c_client(dev); 407 + int val; 408 + 409 + val = i2c_smbus_read_byte_data(client, M41T80_REG_SQW); 410 + if (val < 0) 411 + return -EIO; 412 + val = (val >> 4) & 0xf; 413 + switch (val) { 414 + case 0: 415 + break; 416 + case 1: 417 + val = 32768; 418 + break; 419 + default: 420 + val = 32768 >> val; 421 + } 422 + return sprintf(buf, "%d\n", val); 423 + } 424 + static ssize_t m41t80_sysfs_set_sqwfreq(struct device *dev, 425 + struct device_attribute *attr, 426 + const char *buf, size_t count) 427 + { 428 + struct i2c_client *client = to_i2c_client(dev); 429 + int almon, sqw; 430 + int val = simple_strtoul(buf, NULL, 0); 431 + 432 + if (val) { 433 + if (!is_power_of_2(val)) 434 + return -EINVAL; 435 + val = ilog2(val); 436 + if (val == 15) 437 + val = 1; 438 + else if (val < 14) 439 + val = 15 - val; 440 + else 441 + return -EINVAL; 442 + } 443 + /* disable SQW, set SQW frequency & re-enable */ 444 + almon = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_MON); 445 + if (almon < 0) 446 + return -EIO; 447 + sqw = i2c_smbus_read_byte_data(client, M41T80_REG_SQW); 448 + if (sqw < 0) 449 + return -EIO; 450 + sqw = (sqw & 0x0f) | (val << 4); 451 + if (i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, 452 + almon & ~M41T80_ALMON_SQWE) < 0 || 453 + i2c_smbus_write_byte_data(client, M41T80_REG_SQW, sqw) < 0) 454 + return -EIO; 455 + if (val && i2c_smbus_write_byte_data(client, M41T80_REG_ALARM_MON, 456 + almon | M41T80_ALMON_SQWE) < 0) 457 + return -EIO; 458 + return count; 459 + } 460 + static DEVICE_ATTR(sqwfreq, S_IRUGO | S_IWUSR, 461 + m41t80_sysfs_show_sqwfreq, m41t80_sysfs_set_sqwfreq); 462 + 463 + static struct attribute *attrs[] = { 464 + &dev_attr_flags.attr, 465 + &dev_attr_sqwfreq.attr, 466 + NULL, 467 + }; 468 + static struct attribute_group attr_group = { 469 + .attrs = attrs, 470 + }; 471 + 472 + static int m41t80_sysfs_register(struct device *dev) 473 + { 474 + return sysfs_create_group(&dev->kobj, &attr_group); 475 + } 476 + #else 477 + static int m41t80_sysfs_register(struct device *dev) 478 + { 479 + return 0; 480 + } 481 + #endif 482 + 483 + /* 484 + ***************************************************************************** 485 + * 486 + * Driver Interface 487 + * 488 + ***************************************************************************** 489 + */ 490 + static int m41t80_probe(struct i2c_client *client) 491 + { 492 + int i, rc = 0; 493 + struct rtc_device *rtc = NULL; 494 + struct rtc_time tm; 495 + const struct m41t80_chip_info *chip; 496 + struct m41t80_data *clientdata = NULL; 497 + 498 + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C 499 + | I2C_FUNC_SMBUS_BYTE_DATA)) { 500 + rc = -ENODEV; 501 + goto exit; 502 + } 503 + 504 + dev_info(&client->dev, 505 + "chip found, driver version " DRV_VERSION "\n"); 506 + 507 + chip = NULL; 508 + for (i = 0; i < ARRAY_SIZE(m41t80_chip_info_tbl); i++) { 509 + if (!strcmp(m41t80_chip_info_tbl[i].name, client->name)) { 510 + chip = &m41t80_chip_info_tbl[i]; 511 + break; 512 + } 513 + } 514 + if (!chip) { 515 + dev_err(&client->dev, "%s is not supported\n", client->name); 516 + rc = -ENODEV; 517 + goto exit; 518 + } 519 + 520 + clientdata = kzalloc(sizeof(*clientdata), GFP_KERNEL); 521 + if (!clientdata) { 522 + rc = -ENOMEM; 523 + goto exit; 524 + } 525 + 526 + rtc = rtc_device_register(client->name, &client->dev, 527 + &m41t80_rtc_ops, THIS_MODULE); 528 + if (IS_ERR(rtc)) { 529 + rc = PTR_ERR(rtc); 530 + rtc = NULL; 531 + goto exit; 532 + } 533 + 534 + clientdata->rtc = rtc; 535 + clientdata->chip = chip; 536 + i2c_set_clientdata(client, clientdata); 537 + 538 + /* Make sure HT (Halt Update) bit is cleared */ 539 + rc = i2c_smbus_read_byte_data(client, M41T80_REG_ALARM_HOUR); 540 + if (rc < 0) 541 + goto ht_err; 542 + 543 + if (rc & M41T80_ALHOUR_HT) { 544 + if (chip->features & M41T80_FEATURE_HT) { 545 + m41t80_get_datetime(client, &tm); 546 + dev_info(&client->dev, "HT bit was set!\n"); 547 + dev_info(&client->dev, 548 + "Power Down at " 549 + "%04i-%02i-%02i %02i:%02i:%02i\n", 550 + tm.tm_year + 1900, 551 + tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, 552 + tm.tm_min, tm.tm_sec); 553 + } 554 + if (i2c_smbus_write_byte_data(client, 555 + M41T80_REG_ALARM_HOUR, 556 + rc & ~M41T80_ALHOUR_HT) < 0) 557 + goto ht_err; 558 + } 559 + 560 + /* Make sure ST (stop) bit is cleared */ 561 + rc = i2c_smbus_read_byte_data(client, M41T80_REG_SEC); 562 + if (rc < 0) 563 + goto st_err; 564 + 565 + if (rc & M41T80_SEC_ST) { 566 + if (i2c_smbus_write_byte_data(client, M41T80_REG_SEC, 567 + rc & ~M41T80_SEC_ST) < 0) 568 + goto st_err; 569 + } 570 + 571 + rc = m41t80_sysfs_register(&client->dev); 572 + if (rc) 573 + goto exit; 574 + 575 + return 0; 576 + 577 + st_err: 578 + rc = -EIO; 579 + dev_err(&client->dev, "Can't clear ST bit\n"); 580 + goto exit; 581 + ht_err: 582 + rc = -EIO; 583 + dev_err(&client->dev, "Can't clear HT bit\n"); 584 + goto exit; 585 + 586 + exit: 587 + if (rtc) 588 + rtc_device_unregister(rtc); 589 + kfree(clientdata); 590 + return rc; 591 + } 592 + 593 + static int m41t80_remove(struct i2c_client *client) 594 + { 595 + struct m41t80_data *clientdata = i2c_get_clientdata(client); 596 + struct rtc_device *rtc = clientdata->rtc; 597 + 598 + if (rtc) 599 + rtc_device_unregister(rtc); 600 + kfree(clientdata); 601 + 602 + return 0; 603 + } 604 + 605 + static struct i2c_driver m41t80_driver = { 606 + .driver = { 607 + .name = "m41t80", 608 + }, 609 + .probe = m41t80_probe, 610 + .remove = m41t80_remove, 611 + }; 612 + 613 + static int __init m41t80_rtc_init(void) 614 + { 615 + return i2c_add_driver(&m41t80_driver); 616 + } 617 + 618 + static void __exit m41t80_rtc_exit(void) 619 + { 620 + i2c_del_driver(&m41t80_driver); 621 + } 622 + 623 + MODULE_AUTHOR("Alexander Bigga <ab@mycable.de>"); 624 + MODULE_DESCRIPTION("ST Microelectronics M41T80 series RTC I2C Client Driver"); 625 + MODULE_LICENSE("GPL"); 626 + MODULE_VERSION(DRV_VERSION); 627 + 628 + module_init(m41t80_rtc_init); 629 + module_exit(m41t80_rtc_exit);