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> 275a0e3ad6STejun Heo #include <linux/slab.h> 28*bc96ba74SMark Brown #include <linux/pm.h> 29bf4994d7SScott Wood 30bf4994d7SScott Wood #define DS1374_REG_TOD0 0x00 /* Time of Day */ 31bf4994d7SScott Wood #define DS1374_REG_TOD1 0x01 32bf4994d7SScott Wood #define DS1374_REG_TOD2 0x02 33bf4994d7SScott Wood #define DS1374_REG_TOD3 0x03 34bf4994d7SScott Wood #define DS1374_REG_WDALM0 0x04 /* Watchdog/Alarm */ 35bf4994d7SScott Wood #define DS1374_REG_WDALM1 0x05 36bf4994d7SScott Wood #define DS1374_REG_WDALM2 0x06 37bf4994d7SScott Wood #define DS1374_REG_CR 0x07 /* Control */ 38bf4994d7SScott Wood #define DS1374_REG_CR_AIE 0x01 /* Alarm Int. Enable */ 39bf4994d7SScott Wood #define DS1374_REG_CR_WDALM 0x20 /* 1=Watchdog, 0=Alarm */ 40bf4994d7SScott Wood #define DS1374_REG_CR_WACE 0x40 /* WD/Alarm counter enable */ 41bf4994d7SScott Wood #define DS1374_REG_SR 0x08 /* Status */ 42bf4994d7SScott Wood #define DS1374_REG_SR_OSF 0x80 /* Oscillator Stop Flag */ 43bf4994d7SScott Wood #define DS1374_REG_SR_AF 0x01 /* Alarm Flag */ 44bf4994d7SScott Wood #define DS1374_REG_TCR 0x09 /* Trickle Charge */ 45bf4994d7SScott Wood 463760f736SJean Delvare static const struct i2c_device_id ds1374_id[] = { 47f2eb4327SJean Delvare { "ds1374", 0 }, 483760f736SJean Delvare { } 493760f736SJean Delvare }; 503760f736SJean Delvare MODULE_DEVICE_TABLE(i2c, ds1374_id); 513760f736SJean Delvare 52bf4994d7SScott Wood struct ds1374 { 53bf4994d7SScott Wood struct i2c_client *client; 54bf4994d7SScott Wood struct rtc_device *rtc; 55bf4994d7SScott Wood struct work_struct work; 56bf4994d7SScott Wood 57bf4994d7SScott Wood /* The mutex protects alarm operations, and prevents a race 58bf4994d7SScott Wood * between the enable_irq() in the workqueue and the free_irq() 59bf4994d7SScott Wood * in the remove function. 60bf4994d7SScott Wood */ 61bf4994d7SScott Wood struct mutex mutex; 62bf4994d7SScott Wood int exiting; 63bf4994d7SScott Wood }; 64bf4994d7SScott Wood 65bf4994d7SScott Wood static struct i2c_driver ds1374_driver; 66bf4994d7SScott Wood 67bf4994d7SScott Wood static int ds1374_read_rtc(struct i2c_client *client, u32 *time, 68bf4994d7SScott Wood int reg, int nbytes) 69bf4994d7SScott Wood { 70bf4994d7SScott Wood u8 buf[4]; 71bf4994d7SScott Wood int ret; 72bf4994d7SScott Wood int i; 73bf4994d7SScott Wood 74bf4994d7SScott Wood if (nbytes > 4) { 75bf4994d7SScott Wood WARN_ON(1); 76bf4994d7SScott Wood return -EINVAL; 77bf4994d7SScott Wood } 78bf4994d7SScott Wood 79bf4994d7SScott Wood ret = i2c_smbus_read_i2c_block_data(client, reg, nbytes, buf); 80bf4994d7SScott Wood 81bf4994d7SScott Wood if (ret < 0) 82bf4994d7SScott Wood return ret; 83bf4994d7SScott Wood if (ret < nbytes) 84bf4994d7SScott Wood return -EIO; 85bf4994d7SScott Wood 86bf4994d7SScott Wood for (i = nbytes - 1, *time = 0; i >= 0; i--) 87bf4994d7SScott Wood *time = (*time << 8) | buf[i]; 88bf4994d7SScott Wood 89bf4994d7SScott Wood return 0; 90bf4994d7SScott Wood } 91bf4994d7SScott Wood 92bf4994d7SScott Wood static int ds1374_write_rtc(struct i2c_client *client, u32 time, 93bf4994d7SScott Wood int reg, int nbytes) 94bf4994d7SScott Wood { 95bf4994d7SScott Wood u8 buf[4]; 96bf4994d7SScott Wood int i; 97bf4994d7SScott Wood 98bf4994d7SScott Wood if (nbytes > 4) { 99bf4994d7SScott Wood WARN_ON(1); 100bf4994d7SScott Wood return -EINVAL; 101bf4994d7SScott Wood } 102bf4994d7SScott Wood 103bf4994d7SScott Wood for (i = 0; i < nbytes; i++) { 104bf4994d7SScott Wood buf[i] = time & 0xff; 105bf4994d7SScott Wood time >>= 8; 106bf4994d7SScott Wood } 107bf4994d7SScott Wood 108bf4994d7SScott Wood return i2c_smbus_write_i2c_block_data(client, reg, nbytes, buf); 109bf4994d7SScott Wood } 110bf4994d7SScott Wood 111bf4994d7SScott Wood static int ds1374_check_rtc_status(struct i2c_client *client) 112bf4994d7SScott Wood { 113bf4994d7SScott Wood int ret = 0; 114bf4994d7SScott Wood int control, stat; 115bf4994d7SScott Wood 116bf4994d7SScott Wood stat = i2c_smbus_read_byte_data(client, DS1374_REG_SR); 117bf4994d7SScott Wood if (stat < 0) 118bf4994d7SScott Wood return stat; 119bf4994d7SScott Wood 120bf4994d7SScott Wood if (stat & DS1374_REG_SR_OSF) 121bf4994d7SScott Wood dev_warn(&client->dev, 122bf4994d7SScott Wood "oscillator discontinuity flagged, " 123bf4994d7SScott Wood "time unreliable\n"); 124bf4994d7SScott Wood 125bf4994d7SScott Wood stat &= ~(DS1374_REG_SR_OSF | DS1374_REG_SR_AF); 126bf4994d7SScott Wood 127bf4994d7SScott Wood ret = i2c_smbus_write_byte_data(client, DS1374_REG_SR, stat); 128bf4994d7SScott Wood if (ret < 0) 129bf4994d7SScott Wood return ret; 130bf4994d7SScott Wood 131bf4994d7SScott Wood /* If the alarm is pending, clear it before requesting 132bf4994d7SScott Wood * the interrupt, so an interrupt event isn't reported 133bf4994d7SScott Wood * before everything is initialized. 134bf4994d7SScott Wood */ 135bf4994d7SScott Wood 136bf4994d7SScott Wood control = i2c_smbus_read_byte_data(client, DS1374_REG_CR); 137bf4994d7SScott Wood if (control < 0) 138bf4994d7SScott Wood return control; 139bf4994d7SScott Wood 140bf4994d7SScott Wood control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE); 141bf4994d7SScott Wood return i2c_smbus_write_byte_data(client, DS1374_REG_CR, control); 142bf4994d7SScott Wood } 143bf4994d7SScott Wood 144bf4994d7SScott Wood static int ds1374_read_time(struct device *dev, struct rtc_time *time) 145bf4994d7SScott Wood { 146bf4994d7SScott Wood struct i2c_client *client = to_i2c_client(dev); 147bf4994d7SScott Wood u32 itime; 148bf4994d7SScott Wood int ret; 149bf4994d7SScott Wood 150bf4994d7SScott Wood ret = ds1374_read_rtc(client, &itime, DS1374_REG_TOD0, 4); 151bf4994d7SScott Wood if (!ret) 152bf4994d7SScott Wood rtc_time_to_tm(itime, time); 153bf4994d7SScott Wood 154bf4994d7SScott Wood return ret; 155bf4994d7SScott Wood } 156bf4994d7SScott Wood 157bf4994d7SScott Wood static int ds1374_set_time(struct device *dev, struct rtc_time *time) 158bf4994d7SScott Wood { 159bf4994d7SScott Wood struct i2c_client *client = to_i2c_client(dev); 160bf4994d7SScott Wood unsigned long itime; 161bf4994d7SScott Wood 162bf4994d7SScott Wood rtc_tm_to_time(time, &itime); 163bf4994d7SScott Wood return ds1374_write_rtc(client, itime, DS1374_REG_TOD0, 4); 164bf4994d7SScott Wood } 165bf4994d7SScott Wood 166bf4994d7SScott Wood /* The ds1374 has a decrementer for an alarm, rather than a comparator. 167bf4994d7SScott Wood * If the time of day is changed, then the alarm will need to be 168bf4994d7SScott Wood * reset. 169bf4994d7SScott Wood */ 170bf4994d7SScott Wood static int ds1374_read_alarm(struct device *dev, struct rtc_wkalrm *alarm) 171bf4994d7SScott Wood { 172bf4994d7SScott Wood struct i2c_client *client = to_i2c_client(dev); 173bf4994d7SScott Wood struct ds1374 *ds1374 = i2c_get_clientdata(client); 174bf4994d7SScott Wood u32 now, cur_alarm; 175bf4994d7SScott Wood int cr, sr; 176bf4994d7SScott Wood int ret = 0; 177bf4994d7SScott Wood 178b42f9317SAnton Vorontsov if (client->irq <= 0) 179bf4994d7SScott Wood return -EINVAL; 180bf4994d7SScott Wood 181bf4994d7SScott Wood mutex_lock(&ds1374->mutex); 182bf4994d7SScott Wood 183bf4994d7SScott Wood cr = ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); 184bf4994d7SScott Wood if (ret < 0) 185bf4994d7SScott Wood goto out; 186bf4994d7SScott Wood 187bf4994d7SScott Wood sr = ret = i2c_smbus_read_byte_data(client, DS1374_REG_SR); 188bf4994d7SScott Wood if (ret < 0) 189bf4994d7SScott Wood goto out; 190bf4994d7SScott Wood 191bf4994d7SScott Wood ret = ds1374_read_rtc(client, &now, DS1374_REG_TOD0, 4); 192bf4994d7SScott Wood if (ret) 193bf4994d7SScott Wood goto out; 194bf4994d7SScott Wood 195bf4994d7SScott Wood ret = ds1374_read_rtc(client, &cur_alarm, DS1374_REG_WDALM0, 3); 196bf4994d7SScott Wood if (ret) 197bf4994d7SScott Wood goto out; 198bf4994d7SScott Wood 199bf4994d7SScott Wood rtc_time_to_tm(now + cur_alarm, &alarm->time); 200bf4994d7SScott Wood alarm->enabled = !!(cr & DS1374_REG_CR_WACE); 201bf4994d7SScott Wood alarm->pending = !!(sr & DS1374_REG_SR_AF); 202bf4994d7SScott Wood 203bf4994d7SScott Wood out: 204bf4994d7SScott Wood mutex_unlock(&ds1374->mutex); 205bf4994d7SScott Wood return ret; 206bf4994d7SScott Wood } 207bf4994d7SScott Wood 208bf4994d7SScott Wood static int ds1374_set_alarm(struct device *dev, struct rtc_wkalrm *alarm) 209bf4994d7SScott Wood { 210bf4994d7SScott Wood struct i2c_client *client = to_i2c_client(dev); 211bf4994d7SScott Wood struct ds1374 *ds1374 = i2c_get_clientdata(client); 212bf4994d7SScott Wood struct rtc_time now; 213bf4994d7SScott Wood unsigned long new_alarm, itime; 214bf4994d7SScott Wood int cr; 215bf4994d7SScott Wood int ret = 0; 216bf4994d7SScott Wood 217b42f9317SAnton Vorontsov if (client->irq <= 0) 218bf4994d7SScott Wood return -EINVAL; 219bf4994d7SScott Wood 220bf4994d7SScott Wood ret = ds1374_read_time(dev, &now); 221bf4994d7SScott Wood if (ret < 0) 222bf4994d7SScott Wood return ret; 223bf4994d7SScott Wood 224bf4994d7SScott Wood rtc_tm_to_time(&alarm->time, &new_alarm); 225bf4994d7SScott Wood rtc_tm_to_time(&now, &itime); 226bf4994d7SScott Wood 227bf4994d7SScott Wood /* This can happen due to races, in addition to dates that are 228bf4994d7SScott Wood * truly in the past. To avoid requiring the caller to check for 229bf4994d7SScott Wood * races, dates in the past are assumed to be in the recent past 230bf4994d7SScott Wood * (i.e. not something that we'd rather the caller know about via 231bf4994d7SScott Wood * an error), and the alarm is set to go off as soon as possible. 232bf4994d7SScott Wood */ 233fa7af8b1SRoel Kluin if (time_before_eq(new_alarm, itime)) 234bf4994d7SScott Wood new_alarm = 1; 235fa7af8b1SRoel Kluin else 236fa7af8b1SRoel Kluin new_alarm -= itime; 237bf4994d7SScott Wood 238bf4994d7SScott Wood mutex_lock(&ds1374->mutex); 239bf4994d7SScott Wood 240bf4994d7SScott Wood ret = cr = i2c_smbus_read_byte_data(client, DS1374_REG_CR); 241bf4994d7SScott Wood if (ret < 0) 242bf4994d7SScott Wood goto out; 243bf4994d7SScott Wood 244bf4994d7SScott Wood /* Disable any existing alarm before setting the new one 245bf4994d7SScott Wood * (or lack thereof). */ 246bf4994d7SScott Wood cr &= ~DS1374_REG_CR_WACE; 247bf4994d7SScott Wood 248bf4994d7SScott Wood ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr); 249bf4994d7SScott Wood if (ret < 0) 250bf4994d7SScott Wood goto out; 251bf4994d7SScott Wood 252bf4994d7SScott Wood ret = ds1374_write_rtc(client, new_alarm, DS1374_REG_WDALM0, 3); 253bf4994d7SScott Wood if (ret) 254bf4994d7SScott Wood goto out; 255bf4994d7SScott Wood 256bf4994d7SScott Wood if (alarm->enabled) { 257bf4994d7SScott Wood cr |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE; 258bf4994d7SScott Wood cr &= ~DS1374_REG_CR_WDALM; 259bf4994d7SScott Wood 260bf4994d7SScott Wood ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, cr); 261bf4994d7SScott Wood } 262bf4994d7SScott Wood 263bf4994d7SScott Wood out: 264bf4994d7SScott Wood mutex_unlock(&ds1374->mutex); 265bf4994d7SScott Wood return ret; 266bf4994d7SScott Wood } 267bf4994d7SScott Wood 268bf4994d7SScott Wood static irqreturn_t ds1374_irq(int irq, void *dev_id) 269bf4994d7SScott Wood { 270bf4994d7SScott Wood struct i2c_client *client = dev_id; 271bf4994d7SScott Wood struct ds1374 *ds1374 = i2c_get_clientdata(client); 272bf4994d7SScott Wood 273bf4994d7SScott Wood disable_irq_nosync(irq); 274bf4994d7SScott Wood schedule_work(&ds1374->work); 275bf4994d7SScott Wood return IRQ_HANDLED; 276bf4994d7SScott Wood } 277bf4994d7SScott Wood 278bf4994d7SScott Wood static void ds1374_work(struct work_struct *work) 279bf4994d7SScott Wood { 280bf4994d7SScott Wood struct ds1374 *ds1374 = container_of(work, struct ds1374, work); 281bf4994d7SScott Wood struct i2c_client *client = ds1374->client; 282bf4994d7SScott Wood int stat, control; 283bf4994d7SScott Wood 284bf4994d7SScott Wood mutex_lock(&ds1374->mutex); 285bf4994d7SScott Wood 286bf4994d7SScott Wood stat = i2c_smbus_read_byte_data(client, DS1374_REG_SR); 287bf4994d7SScott Wood if (stat < 0) 28828df30e6SJiri Slaby goto unlock; 289bf4994d7SScott Wood 290bf4994d7SScott Wood if (stat & DS1374_REG_SR_AF) { 291bf4994d7SScott Wood stat &= ~DS1374_REG_SR_AF; 292bf4994d7SScott Wood i2c_smbus_write_byte_data(client, DS1374_REG_SR, stat); 293bf4994d7SScott Wood 294bf4994d7SScott Wood control = i2c_smbus_read_byte_data(client, DS1374_REG_CR); 295bf4994d7SScott Wood if (control < 0) 296bf4994d7SScott Wood goto out; 297bf4994d7SScott Wood 298bf4994d7SScott Wood control &= ~(DS1374_REG_CR_WACE | DS1374_REG_CR_AIE); 299bf4994d7SScott Wood i2c_smbus_write_byte_data(client, DS1374_REG_CR, control); 300bf4994d7SScott Wood 301bf4994d7SScott Wood rtc_update_irq(ds1374->rtc, 1, RTC_AF | RTC_IRQF); 302bf4994d7SScott Wood } 303bf4994d7SScott Wood 304bf4994d7SScott Wood out: 305bf4994d7SScott Wood if (!ds1374->exiting) 306bf4994d7SScott Wood enable_irq(client->irq); 30728df30e6SJiri Slaby unlock: 308bf4994d7SScott Wood mutex_unlock(&ds1374->mutex); 309bf4994d7SScott Wood } 310bf4994d7SScott Wood 31116380c15SJohn Stultz static int ds1374_alarm_irq_enable(struct device *dev, unsigned int enabled) 312bf4994d7SScott Wood { 313bf4994d7SScott Wood struct i2c_client *client = to_i2c_client(dev); 314bf4994d7SScott Wood struct ds1374 *ds1374 = i2c_get_clientdata(client); 31516380c15SJohn Stultz int ret; 316bf4994d7SScott Wood 317bf4994d7SScott Wood mutex_lock(&ds1374->mutex); 318bf4994d7SScott Wood 319bf4994d7SScott Wood ret = i2c_smbus_read_byte_data(client, DS1374_REG_CR); 320bf4994d7SScott Wood if (ret < 0) 321bf4994d7SScott Wood goto out; 322bf4994d7SScott Wood 32316380c15SJohn Stultz if (enabled) { 324bf4994d7SScott Wood ret |= DS1374_REG_CR_WACE | DS1374_REG_CR_AIE; 325bf4994d7SScott Wood ret &= ~DS1374_REG_CR_WDALM; 32616380c15SJohn Stultz } else { 32716380c15SJohn Stultz ret &= ~DS1374_REG_CR_WACE; 328bf4994d7SScott Wood } 32916380c15SJohn Stultz ret = i2c_smbus_write_byte_data(client, DS1374_REG_CR, ret); 330bf4994d7SScott Wood 331bf4994d7SScott Wood out: 332bf4994d7SScott Wood mutex_unlock(&ds1374->mutex); 333bf4994d7SScott Wood return ret; 334bf4994d7SScott Wood } 335bf4994d7SScott Wood 336bf4994d7SScott Wood static const struct rtc_class_ops ds1374_rtc_ops = { 337bf4994d7SScott Wood .read_time = ds1374_read_time, 338bf4994d7SScott Wood .set_time = ds1374_set_time, 339bf4994d7SScott Wood .read_alarm = ds1374_read_alarm, 340bf4994d7SScott Wood .set_alarm = ds1374_set_alarm, 34116380c15SJohn Stultz .alarm_irq_enable = ds1374_alarm_irq_enable, 342bf4994d7SScott Wood }; 343bf4994d7SScott Wood 344d2653e92SJean Delvare static int ds1374_probe(struct i2c_client *client, 345d2653e92SJean Delvare const struct i2c_device_id *id) 346bf4994d7SScott Wood { 347bf4994d7SScott Wood struct ds1374 *ds1374; 348bf4994d7SScott Wood int ret; 349bf4994d7SScott Wood 350bf4994d7SScott Wood ds1374 = kzalloc(sizeof(struct ds1374), GFP_KERNEL); 351bf4994d7SScott Wood if (!ds1374) 352bf4994d7SScott Wood return -ENOMEM; 353bf4994d7SScott Wood 354bf4994d7SScott Wood ds1374->client = client; 355bf4994d7SScott Wood i2c_set_clientdata(client, ds1374); 356bf4994d7SScott Wood 357bf4994d7SScott Wood INIT_WORK(&ds1374->work, ds1374_work); 358bf4994d7SScott Wood mutex_init(&ds1374->mutex); 359bf4994d7SScott Wood 360bf4994d7SScott Wood ret = ds1374_check_rtc_status(client); 361bf4994d7SScott Wood if (ret) 362bf4994d7SScott Wood goto out_free; 363bf4994d7SScott Wood 364b42f9317SAnton Vorontsov if (client->irq > 0) { 365bf4994d7SScott Wood ret = request_irq(client->irq, ds1374_irq, 0, 366bf4994d7SScott Wood "ds1374", client); 367bf4994d7SScott Wood if (ret) { 368bf4994d7SScott Wood dev_err(&client->dev, "unable to request IRQ\n"); 369bf4994d7SScott Wood goto out_free; 370bf4994d7SScott Wood } 37126b3c01fSAnton Vorontsov 37226b3c01fSAnton Vorontsov device_set_wakeup_capable(&client->dev, 1); 373bf4994d7SScott Wood } 374bf4994d7SScott Wood 375bf4994d7SScott Wood ds1374->rtc = rtc_device_register(client->name, &client->dev, 376bf4994d7SScott Wood &ds1374_rtc_ops, THIS_MODULE); 377bf4994d7SScott Wood if (IS_ERR(ds1374->rtc)) { 378bf4994d7SScott Wood ret = PTR_ERR(ds1374->rtc); 379bf4994d7SScott Wood dev_err(&client->dev, "unable to register the class device\n"); 380bf4994d7SScott Wood goto out_irq; 381bf4994d7SScott Wood } 382bf4994d7SScott Wood 383bf4994d7SScott Wood return 0; 384bf4994d7SScott Wood 385bf4994d7SScott Wood out_irq: 386b42f9317SAnton Vorontsov if (client->irq > 0) 387bf4994d7SScott Wood free_irq(client->irq, client); 388bf4994d7SScott Wood 389bf4994d7SScott Wood out_free: 390bf4994d7SScott Wood kfree(ds1374); 391bf4994d7SScott Wood return ret; 392bf4994d7SScott Wood } 393bf4994d7SScott Wood 394bf4994d7SScott Wood static int __devexit ds1374_remove(struct i2c_client *client) 395bf4994d7SScott Wood { 396bf4994d7SScott Wood struct ds1374 *ds1374 = i2c_get_clientdata(client); 397bf4994d7SScott Wood 398b42f9317SAnton Vorontsov if (client->irq > 0) { 399bf4994d7SScott Wood mutex_lock(&ds1374->mutex); 400bf4994d7SScott Wood ds1374->exiting = 1; 401bf4994d7SScott Wood mutex_unlock(&ds1374->mutex); 402bf4994d7SScott Wood 403bf4994d7SScott Wood free_irq(client->irq, client); 4049db8995bSTejun Heo cancel_work_sync(&ds1374->work); 405bf4994d7SScott Wood } 406bf4994d7SScott Wood 407bf4994d7SScott Wood rtc_device_unregister(ds1374->rtc); 408bf4994d7SScott Wood kfree(ds1374); 409bf4994d7SScott Wood return 0; 410bf4994d7SScott Wood } 411bf4994d7SScott Wood 412986e36a5SMarc Pignat #ifdef CONFIG_PM 413*bc96ba74SMark Brown static int ds1374_suspend(struct device *dev) 414986e36a5SMarc Pignat { 415*bc96ba74SMark Brown struct i2c_client *client = to_i2c_client(dev); 416*bc96ba74SMark Brown 417986e36a5SMarc Pignat if (client->irq >= 0 && device_may_wakeup(&client->dev)) 418986e36a5SMarc Pignat enable_irq_wake(client->irq); 419986e36a5SMarc Pignat return 0; 420986e36a5SMarc Pignat } 421986e36a5SMarc Pignat 422*bc96ba74SMark Brown static int ds1374_resume(struct device *dev) 423986e36a5SMarc Pignat { 424*bc96ba74SMark Brown struct i2c_client *client = to_i2c_client(dev); 425*bc96ba74SMark Brown 426986e36a5SMarc Pignat if (client->irq >= 0 && device_may_wakeup(&client->dev)) 427986e36a5SMarc Pignat disable_irq_wake(client->irq); 428986e36a5SMarc Pignat return 0; 429986e36a5SMarc Pignat } 430*bc96ba74SMark Brown 431*bc96ba74SMark Brown static SIMPLE_DEV_PM_OPS(ds1374_pm, ds1374_suspend, ds1374_resume); 432*bc96ba74SMark Brown 433*bc96ba74SMark Brown #define DS1374_PM (&ds1374_pm) 434986e36a5SMarc Pignat #else 435*bc96ba74SMark Brown #define DS1374_PM NULL 436986e36a5SMarc Pignat #endif 437986e36a5SMarc Pignat 438bf4994d7SScott Wood static struct i2c_driver ds1374_driver = { 439bf4994d7SScott Wood .driver = { 440bf4994d7SScott Wood .name = "rtc-ds1374", 441bf4994d7SScott Wood .owner = THIS_MODULE, 442*bc96ba74SMark Brown .pm = DS1374_PM, 443bf4994d7SScott Wood }, 444bf4994d7SScott Wood .probe = ds1374_probe, 445bf4994d7SScott Wood .remove = __devexit_p(ds1374_remove), 4463760f736SJean Delvare .id_table = ds1374_id, 447bf4994d7SScott Wood }; 448bf4994d7SScott Wood 449bf4994d7SScott Wood static int __init ds1374_init(void) 450bf4994d7SScott Wood { 451bf4994d7SScott Wood return i2c_add_driver(&ds1374_driver); 452bf4994d7SScott Wood } 453bf4994d7SScott Wood 454bf4994d7SScott Wood static void __exit ds1374_exit(void) 455bf4994d7SScott Wood { 456bf4994d7SScott Wood i2c_del_driver(&ds1374_driver); 457bf4994d7SScott Wood } 458bf4994d7SScott Wood 459bf4994d7SScott Wood module_init(ds1374_init); 460bf4994d7SScott Wood module_exit(ds1374_exit); 461bf4994d7SScott Wood 462bf4994d7SScott Wood MODULE_AUTHOR("Scott Wood <scottwood@freescale.com>"); 463bf4994d7SScott Wood MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC Driver"); 464bf4994d7SScott Wood MODULE_LICENSE("GPL"); 465