1bf4994d7SScott Wood /* 2bf4994d7SScott Wood * RTC client/driver for the Maxim/Dallas DS1374 Real-Time Clock over I2C 3bf4994d7SScott Wood * 4bf4994d7SScott Wood * Based on code by Randy Vinson <rvinson@mvista.com>, 5bf4994d7SScott Wood * which was based on the m41t00.c by Mark Greer <mgreer@mvista.com>. 6bf4994d7SScott Wood * 7bf4994d7SScott Wood * Copyright (C) 2006-2007 Freescale Semiconductor 8bf4994d7SScott Wood * 9bf4994d7SScott Wood * 2005 (c) MontaVista Software, Inc. This file is licensed under 10bf4994d7SScott Wood * the terms of the GNU General Public License version 2. This program 11bf4994d7SScott Wood * is licensed "as is" without any warranty of any kind, whether express 12bf4994d7SScott Wood * or implied. 13bf4994d7SScott Wood */ 14bf4994d7SScott Wood /* 15bf4994d7SScott Wood * It would be more efficient to use i2c msgs/i2c_transfer directly but, as 16bf4994d7SScott Wood * recommened in .../Documentation/i2c/writing-clients section 17bf4994d7SScott Wood * "Sending and receiving", using SMBus level communication is preferred. 18bf4994d7SScott Wood */ 19bf4994d7SScott Wood 20bf4994d7SScott Wood #include <linux/kernel.h> 21bf4994d7SScott Wood #include <linux/module.h> 22bf4994d7SScott Wood #include <linux/interrupt.h> 23bf4994d7SScott Wood #include <linux/i2c.h> 24bf4994d7SScott Wood #include <linux/rtc.h> 25bf4994d7SScott Wood #include <linux/bcd.h> 26bf4994d7SScott Wood #include <linux/workqueue.h> 27bf4994d7SScott Wood 28bf4994d7SScott Wood #define DS1374_REG_TOD0 0x00 /* Time of Day */ 29bf4994d7SScott Wood #define DS1374_REG_TOD1 0x01 30bf4994d7SScott Wood #define DS1374_REG_TOD2 0x02 31bf4994d7SScott Wood #define DS1374_REG_TOD3 0x03 32bf4994d7SScott Wood #define DS1374_REG_WDALM0 0x04 /* Watchdog/Alarm */ 33bf4994d7SScott Wood #define DS1374_REG_WDALM1 0x05 34bf4994d7SScott Wood #define DS1374_REG_WDALM2 0x06 35bf4994d7SScott Wood #define DS1374_REG_CR 0x07 /* Control */ 36bf4994d7SScott Wood #define DS1374_REG_CR_AIE 0x01 /* Alarm Int. Enable */ 37bf4994d7SScott Wood #define DS1374_REG_CR_WDALM 0x20 /* 1=Watchdog, 0=Alarm */ 38bf4994d7SScott Wood #define DS1374_REG_CR_WACE 0x40 /* WD/Alarm counter enable */ 39bf4994d7SScott Wood #define DS1374_REG_SR 0x08 /* Status */ 40bf4994d7SScott Wood #define DS1374_REG_SR_OSF 0x80 /* Oscillator Stop Flag */ 41bf4994d7SScott Wood #define DS1374_REG_SR_AF 0x01 /* Alarm Flag */ 42bf4994d7SScott Wood #define DS1374_REG_TCR 0x09 /* Trickle Charge */ 43bf4994d7SScott Wood 443760f736SJean Delvare static const struct i2c_device_id ds1374_id[] = { 45f2eb4327SJean Delvare { "ds1374", 0 }, 463760f736SJean Delvare { } 473760f736SJean Delvare }; 483760f736SJean Delvare MODULE_DEVICE_TABLE(i2c, ds1374_id); 493760f736SJean Delvare 50bf4994d7SScott Wood struct ds1374 { 51bf4994d7SScott Wood struct i2c_client *client; 52bf4994d7SScott Wood struct rtc_device *rtc; 53bf4994d7SScott Wood struct work_struct work; 54bf4994d7SScott Wood 55bf4994d7SScott Wood /* The mutex protects alarm operations, and prevents a race 56bf4994d7SScott Wood * between the enable_irq() in the workqueue and the free_irq() 57bf4994d7SScott Wood * in the remove function. 58bf4994d7SScott Wood */ 59bf4994d7SScott Wood struct mutex mutex; 60bf4994d7SScott Wood int exiting; 61bf4994d7SScott Wood }; 62bf4994d7SScott Wood 63bf4994d7SScott Wood static struct i2c_driver ds1374_driver; 64bf4994d7SScott Wood 65bf4994d7SScott Wood static int ds1374_read_rtc(struct i2c_client *client, u32 *time, 66bf4994d7SScott Wood int reg, int nbytes) 67bf4994d7SScott Wood { 68bf4994d7SScott Wood u8 buf[4]; 69bf4994d7SScott Wood int ret; 70bf4994d7SScott Wood int i; 71bf4994d7SScott Wood 72bf4994d7SScott Wood if (nbytes > 4) { 73bf4994d7SScott Wood WARN_ON(1); 74bf4994d7SScott Wood return -EINVAL; 75bf4994d7SScott Wood } 76bf4994d7SScott Wood 77bf4994d7SScott Wood ret = i2c_smbus_read_i2c_block_data(client, reg, nbytes, buf); 78bf4994d7SScott Wood 79bf4994d7SScott Wood if (ret < 0) 80bf4994d7SScott Wood return ret; 81bf4994d7SScott Wood if (ret < nbytes) 82bf4994d7SScott Wood return -EIO; 83bf4994d7SScott Wood 84bf4994d7SScott Wood for (i = nbytes - 1, *time = 0; i >= 0; i--) 85bf4994d7SScott Wood *time = (*time << 8) | buf[i]; 86bf4994d7SScott Wood 87bf4994d7SScott Wood return 0; 88bf4994d7SScott Wood } 89bf4994d7SScott Wood 90bf4994d7SScott Wood static int ds1374_write_rtc(struct i2c_client *client, u32 time, 91bf4994d7SScott Wood int reg, int nbytes) 92bf4994d7SScott Wood { 93bf4994d7SScott Wood u8 buf[4]; 94bf4994d7SScott Wood int i; 95bf4994d7SScott Wood 96bf4994d7SScott Wood if (nbytes > 4) { 97bf4994d7SScott Wood WARN_ON(1); 98bf4994d7SScott Wood return -EINVAL; 99bf4994d7SScott Wood } 100bf4994d7SScott Wood 101bf4994d7SScott Wood for (i = 0; i < nbytes; i++) { 102bf4994d7SScott Wood buf[i] = time & 0xff; 103bf4994d7SScott Wood time >>= 8; 104bf4994d7SScott Wood } 105bf4994d7SScott Wood 106bf4994d7SScott Wood return i2c_smbus_write_i2c_block_data(client, reg, nbytes, buf); 107bf4994d7SScott Wood } 108bf4994d7SScott Wood 109bf4994d7SScott Wood static int ds1374_check_rtc_status(struct i2c_client *client) 110bf4994d7SScott Wood { 111bf4994d7SScott Wood int ret = 0; 112bf4994d7SScott Wood int control, stat; 113bf4994d7SScott Wood 114bf4994d7SScott Wood stat = i2c_smbus_read_byte_data(client, DS1374_REG_SR); 115bf4994d7SScott Wood if (stat < 0) 116bf4994d7SScott Wood return stat; 117bf4994d7SScott Wood 118bf4994d7SScott Wood if (stat & DS1374_REG_SR_OSF) 119bf4994d7SScott Wood dev_warn(&client->dev, 120bf4994d7SScott Wood "oscillator discontinuity flagged, " 121bf4994d7SScott Wood "time unreliable\n"); 122bf4994d7SScott Wood 123bf4994d7SScott Wood stat &= ~(DS1374_REG_SR_OSF | DS1374_REG_SR_AF); 124bf4994d7SScott Wood 125bf4994d7SScott Wood ret = i2c_smbus_write_byte_data(client, DS1374_REG_SR, stat); 126bf4994d7SScott Wood if (ret < 0) 127bf4994d7SScott Wood return ret; 128bf4994d7SScott Wood 129bf4994d7SScott Wood /* If the alarm is pending, clear it before requesting 130bf4994d7SScott Wood * the interrupt, so an interrupt event isn't reported 131bf4994d7SScott Wood * before everything is initialized. 132bf4994d7SScott Wood */ 133bf4994d7SScott Wood 134bf4994d7SScott Wood control = i2c_smbus_read_byte_data(client, DS1374_REG_CR); 135bf4994d7SScott Wood if (control < 0) 136bf4994d7SScott Wood return control; 137bf4994d7SScott Wood 138bf4994d7SScott Wood control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE); 139bf4994d7SScott Wood return i2c_smbus_write_byte_data(client, DS1374_REG_CR, control); 140bf4994d7SScott Wood } 141bf4994d7SScott Wood 142bf4994d7SScott Wood static int ds1374_read_time(struct device *dev, struct rtc_time *time) 143bf4994d7SScott Wood { 144bf4994d7SScott Wood struct i2c_client *client = to_i2c_client(dev); 145bf4994d7SScott Wood u32 itime; 146bf4994d7SScott Wood int ret; 147bf4994d7SScott Wood 148bf4994d7SScott Wood ret = ds1374_read_rtc(client, &itime, DS1374_REG_TOD0, 4); 149bf4994d7SScott Wood if (!ret) 150bf4994d7SScott Wood rtc_time_to_tm(itime, time); 151bf4994d7SScott Wood 152bf4994d7SScott Wood return ret; 153bf4994d7SScott Wood } 154bf4994d7SScott Wood 155bf4994d7SScott Wood static int ds1374_set_time(struct device *dev, struct rtc_time *time) 156bf4994d7SScott Wood { 157bf4994d7SScott Wood struct i2c_client *client = to_i2c_client(dev); 158bf4994d7SScott Wood unsigned long itime; 159bf4994d7SScott Wood 160bf4994d7SScott Wood rtc_tm_to_time(time, &itime); 161bf4994d7SScott Wood return ds1374_write_rtc(client, itime, DS1374_REG_TOD0, 4); 162bf4994d7SScott Wood } 163bf4994d7SScott Wood 164bf4994d7SScott Wood /* The ds1374 has a decrementer for an alarm, rather than a comparator. 165bf4994d7SScott Wood * If the time of day is changed, then the alarm will need to be 166bf4994d7SScott Wood * reset. 167bf4994d7SScott Wood */ 168bf4994d7SScott Wood static int ds1374_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) 169bf4994d7SScott Wood { 170bf4994d7SScott Wood struct i2c_client *client = to_i2c_client(dev); 171bf4994d7SScott Wood struct ds1374 *ds1374 = i2c_get_clientdata(client); 172bf4994d7SScott Wood u32 now, cur_alarm; 173bf4994d7SScott Wood int cr, sr; 174bf4994d7SScott Wood int ret = 0; 175bf4994d7SScott Wood 176b42f9317SAnton Vorontsov if (client->irq <= 0) 177bf4994d7SScott Wood return -EINVAL; 178bf4994d7SScott Wood 179bf4994d7SScott Wood mutex_lock(&ds1374->mutex); 180bf4994d7SScott Wood 181bf4994d7SScott Wood cr = ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); 182bf4994d7SScott Wood if (ret < 0) 183bf4994d7SScott Wood goto out; 184bf4994d7SScott Wood 185bf4994d7SScott Wood sr = ret = i2c_smbus_read_byte_data(client, DS1374_REG_SR); 186bf4994d7SScott Wood if (ret < 0) 187bf4994d7SScott Wood goto out; 188bf4994d7SScott Wood 189bf4994d7SScott Wood ret = ds1374_read_rtc(client, &now, DS1374_REG_TOD0, 4); 190bf4994d7SScott Wood if (ret) 191bf4994d7SScott Wood goto out; 192bf4994d7SScott Wood 193bf4994d7SScott Wood ret = ds1374_read_rtc(client, &cur_alarm, DS1374_REG_WDALM0, 3); 194bf4994d7SScott Wood if (ret) 195bf4994d7SScott Wood goto out; 196bf4994d7SScott Wood 197bf4994d7SScott Wood rtc_time_to_tm(now + cur_alarm, &alarm->time); 198bf4994d7SScott Wood alarm->enabled = !!(cr & DS1374_REG_CR_WACE); 199bf4994d7SScott Wood alarm->pending = !!(sr & DS1374_REG_SR_AF); 200bf4994d7SScott Wood 201bf4994d7SScott Wood out: 202bf4994d7SScott Wood mutex_unlock(&ds1374->mutex); 203bf4994d7SScott Wood return ret; 204bf4994d7SScott Wood } 205bf4994d7SScott Wood 206bf4994d7SScott Wood static int ds1374_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) 207bf4994d7SScott Wood { 208bf4994d7SScott Wood struct i2c_client *client = to_i2c_client(dev); 209bf4994d7SScott Wood struct ds1374 *ds1374 = i2c_get_clientdata(client); 210bf4994d7SScott Wood struct rtc_time now; 211bf4994d7SScott Wood unsigned long new_alarm, itime; 212bf4994d7SScott Wood int cr; 213bf4994d7SScott Wood int ret = 0; 214bf4994d7SScott Wood 215b42f9317SAnton Vorontsov if (client->irq <= 0) 216bf4994d7SScott Wood return -EINVAL; 217bf4994d7SScott Wood 218bf4994d7SScott Wood ret = ds1374_read_time(dev, &now); 219bf4994d7SScott Wood if (ret < 0) 220bf4994d7SScott Wood return ret; 221bf4994d7SScott Wood 222bf4994d7SScott Wood rtc_tm_to_time(&alarm->time, &new_alarm); 223bf4994d7SScott Wood rtc_tm_to_time(&now, &itime); 224bf4994d7SScott Wood 225bf4994d7SScott Wood /* This can happen due to races, in addition to dates that are 226bf4994d7SScott Wood * truly in the past. To avoid requiring the caller to check for 227bf4994d7SScott Wood * races, dates in the past are assumed to be in the recent past 228bf4994d7SScott Wood * (i.e. not something that we'd rather the caller know about via 229bf4994d7SScott Wood * an error), and the alarm is set to go off as soon as possible. 230bf4994d7SScott Wood */ 231fa7af8b1SRoel Kluin if (time_before_eq(new_alarm, itime)) 232bf4994d7SScott Wood new_alarm = 1; 233fa7af8b1SRoel Kluin else 234fa7af8b1SRoel Kluin new_alarm -= itime; 235bf4994d7SScott Wood 236bf4994d7SScott Wood mutex_lock(&ds1374->mutex); 237bf4994d7SScott Wood 238bf4994d7SScott Wood ret = cr = i2c_smbus_read_byte_data(client, DS1374_REG_CR); 239bf4994d7SScott Wood if (ret < 0) 240bf4994d7SScott Wood goto out; 241bf4994d7SScott Wood 242bf4994d7SScott Wood /* Disable any existing alarm before setting the new one 243bf4994d7SScott Wood * (or lack thereof). */ 244bf4994d7SScott Wood cr &= ~DS1374_REG_CR_WACE; 245bf4994d7SScott Wood 246bf4994d7SScott Wood ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr); 247bf4994d7SScott Wood if (ret < 0) 248bf4994d7SScott Wood goto out; 249bf4994d7SScott Wood 250bf4994d7SScott Wood ret = ds1374_write_rtc(client, new_alarm, DS1374_REG_WDALM0, 3); 251bf4994d7SScott Wood if (ret) 252bf4994d7SScott Wood goto out; 253bf4994d7SScott Wood 254bf4994d7SScott Wood if (alarm->enabled) { 255bf4994d7SScott Wood cr |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE; 256bf4994d7SScott Wood cr &= ~DS1374_REG_CR_WDALM; 257bf4994d7SScott Wood 258bf4994d7SScott Wood ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr); 259bf4994d7SScott Wood } 260bf4994d7SScott Wood 261bf4994d7SScott Wood out: 262bf4994d7SScott Wood mutex_unlock(&ds1374->mutex); 263bf4994d7SScott Wood return ret; 264bf4994d7SScott Wood } 265bf4994d7SScott Wood 266bf4994d7SScott Wood static irqreturn_t ds1374_irq(int irq, void *dev_id) 267bf4994d7SScott Wood { 268bf4994d7SScott Wood struct i2c_client *client = dev_id; 269bf4994d7SScott Wood struct ds1374 *ds1374 = i2c_get_clientdata(client); 270bf4994d7SScott Wood 271bf4994d7SScott Wood disable_irq_nosync(irq); 272bf4994d7SScott Wood schedule_work(&ds1374->work); 273bf4994d7SScott Wood return IRQ_HANDLED; 274bf4994d7SScott Wood } 275bf4994d7SScott Wood 276bf4994d7SScott Wood static void ds1374_work(struct work_struct *work) 277bf4994d7SScott Wood { 278bf4994d7SScott Wood struct ds1374 *ds1374 = container_of(work, struct ds1374, work); 279bf4994d7SScott Wood struct i2c_client *client = ds1374->client; 280bf4994d7SScott Wood int stat, control; 281bf4994d7SScott Wood 282bf4994d7SScott Wood mutex_lock(&ds1374->mutex); 283bf4994d7SScott Wood 284bf4994d7SScott Wood stat = i2c_smbus_read_byte_data(client, DS1374_REG_SR); 285bf4994d7SScott Wood if (stat < 0) 286*28df30e6SJiri Slaby goto unlock; 287bf4994d7SScott Wood 288bf4994d7SScott Wood if (stat & DS1374_REG_SR_AF) { 289bf4994d7SScott Wood stat &= ~DS1374_REG_SR_AF; 290bf4994d7SScott Wood i2c_smbus_write_byte_data(client, DS1374_REG_SR, stat); 291bf4994d7SScott Wood 292bf4994d7SScott Wood control = i2c_smbus_read_byte_data(client, DS1374_REG_CR); 293bf4994d7SScott Wood if (control < 0) 294bf4994d7SScott Wood goto out; 295bf4994d7SScott Wood 296bf4994d7SScott Wood control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE); 297bf4994d7SScott Wood i2c_smbus_write_byte_data(client, DS1374_REG_CR, control); 298bf4994d7SScott Wood 299bf4994d7SScott Wood rtc_update_irq(ds1374->rtc, 1, RTC_AF | RTC_IRQF); 300bf4994d7SScott Wood } 301bf4994d7SScott Wood 302bf4994d7SScott Wood out: 303bf4994d7SScott Wood if (!ds1374->exiting) 304bf4994d7SScott Wood enable_irq(client->irq); 305*28df30e6SJiri Slaby unlock: 306bf4994d7SScott Wood mutex_unlock(&ds1374->mutex); 307bf4994d7SScott Wood } 308bf4994d7SScott Wood 309bf4994d7SScott Wood static int ds1374_ioctl(struct device *dev, unsigned int cmd, unsigned long arg) 310bf4994d7SScott Wood { 311bf4994d7SScott Wood struct i2c_client *client = to_i2c_client(dev); 312bf4994d7SScott Wood struct ds1374 *ds1374 = i2c_get_clientdata(client); 313bf4994d7SScott Wood int ret = -ENOIOCTLCMD; 314bf4994d7SScott Wood 315bf4994d7SScott Wood mutex_lock(&ds1374->mutex); 316bf4994d7SScott Wood 317bf4994d7SScott Wood switch (cmd) { 318bf4994d7SScott Wood case RTC_AIE_OFF: 319bf4994d7SScott Wood ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); 320bf4994d7SScott Wood if (ret < 0) 321bf4994d7SScott Wood goto out; 322bf4994d7SScott Wood 323bf4994d7SScott Wood ret &= ~DS1374_REG_CR_WACE; 324bf4994d7SScott Wood 325bf4994d7SScott Wood ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret); 326bf4994d7SScott Wood if (ret < 0) 327bf4994d7SScott Wood goto out; 328bf4994d7SScott Wood 329bf4994d7SScott Wood break; 330bf4994d7SScott Wood 331bf4994d7SScott Wood case RTC_AIE_ON: 332bf4994d7SScott Wood ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); 333bf4994d7SScott Wood if (ret < 0) 334bf4994d7SScott Wood goto out; 335bf4994d7SScott Wood 336bf4994d7SScott Wood ret |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE; 337bf4994d7SScott Wood ret &= ~DS1374_REG_CR_WDALM; 338bf4994d7SScott Wood 339bf4994d7SScott Wood ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret); 340bf4994d7SScott Wood if (ret < 0) 341bf4994d7SScott Wood goto out; 342bf4994d7SScott Wood 343bf4994d7SScott Wood break; 344bf4994d7SScott Wood } 345bf4994d7SScott Wood 346bf4994d7SScott Wood out: 347bf4994d7SScott Wood mutex_unlock(&ds1374->mutex); 348bf4994d7SScott Wood return ret; 349bf4994d7SScott Wood } 350bf4994d7SScott Wood 351bf4994d7SScott Wood static const struct rtc_class_ops ds1374_rtc_ops = { 352bf4994d7SScott Wood .read_time = ds1374_read_time, 353bf4994d7SScott Wood .set_time = ds1374_set_time, 354bf4994d7SScott Wood .read_alarm = ds1374_read_alarm, 355bf4994d7SScott Wood .set_alarm = ds1374_set_alarm, 356bf4994d7SScott Wood .ioctl = ds1374_ioctl, 357bf4994d7SScott Wood }; 358bf4994d7SScott Wood 359d2653e92SJean Delvare static int ds1374_probe(struct i2c_client *client, 360d2653e92SJean Delvare const struct i2c_device_id *id) 361bf4994d7SScott Wood { 362bf4994d7SScott Wood struct ds1374 *ds1374; 363bf4994d7SScott Wood int ret; 364bf4994d7SScott Wood 365bf4994d7SScott Wood ds1374 = kzalloc(sizeof(struct ds1374), GFP_KERNEL); 366bf4994d7SScott Wood if (!ds1374) 367bf4994d7SScott Wood return -ENOMEM; 368bf4994d7SScott Wood 369bf4994d7SScott Wood ds1374->client = client; 370bf4994d7SScott Wood i2c_set_clientdata(client, ds1374); 371bf4994d7SScott Wood 372bf4994d7SScott Wood INIT_WORK(&ds1374->work, ds1374_work); 373bf4994d7SScott Wood mutex_init(&ds1374->mutex); 374bf4994d7SScott Wood 375bf4994d7SScott Wood ret = ds1374_check_rtc_status(client); 376bf4994d7SScott Wood if (ret) 377bf4994d7SScott Wood goto out_free; 378bf4994d7SScott Wood 379b42f9317SAnton Vorontsov if (client->irq > 0) { 380bf4994d7SScott Wood ret = request_irq(client->irq, ds1374_irq, 0, 381bf4994d7SScott Wood "ds1374", client); 382bf4994d7SScott Wood if (ret) { 383bf4994d7SScott Wood dev_err(&client->dev, "unable to request IRQ\n"); 384bf4994d7SScott Wood goto out_free; 385bf4994d7SScott Wood } 386bf4994d7SScott Wood } 387bf4994d7SScott Wood 388bf4994d7SScott Wood ds1374->rtc = rtc_device_register(client->name, &client->dev, 389bf4994d7SScott Wood &ds1374_rtc_ops, THIS_MODULE); 390bf4994d7SScott Wood if (IS_ERR(ds1374->rtc)) { 391bf4994d7SScott Wood ret = PTR_ERR(ds1374->rtc); 392bf4994d7SScott Wood dev_err(&client->dev, "unable to register the class device\n"); 393bf4994d7SScott Wood goto out_irq; 394bf4994d7SScott Wood } 395bf4994d7SScott Wood 396bf4994d7SScott Wood return 0; 397bf4994d7SScott Wood 398bf4994d7SScott Wood out_irq: 399b42f9317SAnton Vorontsov if (client->irq > 0) 400bf4994d7SScott Wood free_irq(client->irq, client); 401bf4994d7SScott Wood 402bf4994d7SScott Wood out_free: 403bf4994d7SScott Wood i2c_set_clientdata(client, NULL); 404bf4994d7SScott Wood kfree(ds1374); 405bf4994d7SScott Wood return ret; 406bf4994d7SScott Wood } 407bf4994d7SScott Wood 408bf4994d7SScott Wood static int __devexit ds1374_remove(struct i2c_client *client) 409bf4994d7SScott Wood { 410bf4994d7SScott Wood struct ds1374 *ds1374 = i2c_get_clientdata(client); 411bf4994d7SScott Wood 412b42f9317SAnton Vorontsov if (client->irq > 0) { 413bf4994d7SScott Wood mutex_lock(&ds1374->mutex); 414bf4994d7SScott Wood ds1374->exiting = 1; 415bf4994d7SScott Wood mutex_unlock(&ds1374->mutex); 416bf4994d7SScott Wood 417bf4994d7SScott Wood free_irq(client->irq, client); 418bf4994d7SScott Wood flush_scheduled_work(); 419bf4994d7SScott Wood } 420bf4994d7SScott Wood 421bf4994d7SScott Wood rtc_device_unregister(ds1374->rtc); 422bf4994d7SScott Wood i2c_set_clientdata(client, NULL); 423bf4994d7SScott Wood kfree(ds1374); 424bf4994d7SScott Wood return 0; 425bf4994d7SScott Wood } 426bf4994d7SScott Wood 427986e36a5SMarc Pignat #ifdef CONFIG_PM 428986e36a5SMarc Pignat static int ds1374_suspend(struct i2c_client *client, pm_message_t state) 429986e36a5SMarc Pignat { 430986e36a5SMarc Pignat if (client->irq >= 0 && device_may_wakeup(&client->dev)) 431986e36a5SMarc Pignat enable_irq_wake(client->irq); 432986e36a5SMarc Pignat return 0; 433986e36a5SMarc Pignat } 434986e36a5SMarc Pignat 435986e36a5SMarc Pignat static int ds1374_resume(struct i2c_client *client) 436986e36a5SMarc Pignat { 437986e36a5SMarc Pignat if (client->irq >= 0 && device_may_wakeup(&client->dev)) 438986e36a5SMarc Pignat disable_irq_wake(client->irq); 439986e36a5SMarc Pignat return 0; 440986e36a5SMarc Pignat } 441986e36a5SMarc Pignat #else 442986e36a5SMarc Pignat #define ds1374_suspend NULL 443986e36a5SMarc Pignat #define ds1374_resume NULL 444986e36a5SMarc Pignat #endif 445986e36a5SMarc Pignat 446bf4994d7SScott Wood static struct i2c_driver ds1374_driver = { 447bf4994d7SScott Wood .driver = { 448bf4994d7SScott Wood .name = "rtc-ds1374", 449bf4994d7SScott Wood .owner = THIS_MODULE, 450bf4994d7SScott Wood }, 451bf4994d7SScott Wood .probe = ds1374_probe, 452986e36a5SMarc Pignat .suspend = ds1374_suspend, 453986e36a5SMarc Pignat .resume = ds1374_resume, 454bf4994d7SScott Wood .remove = __devexit_p(ds1374_remove), 4553760f736SJean Delvare .id_table = ds1374_id, 456bf4994d7SScott Wood }; 457bf4994d7SScott Wood 458bf4994d7SScott Wood static int __init ds1374_init(void) 459bf4994d7SScott Wood { 460bf4994d7SScott Wood return i2c_add_driver(&ds1374_driver); 461bf4994d7SScott Wood } 462bf4994d7SScott Wood 463bf4994d7SScott Wood static void __exit ds1374_exit(void) 464bf4994d7SScott Wood { 465bf4994d7SScott Wood i2c_del_driver(&ds1374_driver); 466bf4994d7SScott Wood } 467bf4994d7SScott Wood 468bf4994d7SScott Wood module_init(ds1374_init); 469bf4994d7SScott Wood module_exit(ds1374_exit); 470bf4994d7SScott Wood 471bf4994d7SScott Wood MODULE_AUTHOR("Scott Wood <scottwood@freescale.com>"); 472bf4994d7SScott Wood MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC Driver"); 473bf4994d7SScott Wood MODULE_LICENSE("GPL"); 474