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