1/* 2 * drivers/i2c/chips/ds1374.c 3 * 4 * I2C client/driver for the Maxim/Dallas DS1374 Real-Time Clock 5 * 6 * Author: Randy Vinson <rvinson@mvista.com> 7 * 8 * Based on the m41t00.c by Mark Greer <mgreer@mvista.com> 9 * 10 * 2005 (c) MontaVista Software, Inc. This file is licensed under 11 * the terms of the GNU General Public License version 2. This program 12 * is licensed "as is" without any warranty of any kind, whether express 13 * or implied. 14 */ 15/* 16 * This i2c client/driver wedges between the drivers/char/genrtc.c RTC 17 * interface and the SMBus interface of the i2c subsystem. 18 * It would be more efficient to use i2c msgs/i2c_transfer directly but, as 19 * recommened in .../Documentation/i2c/writing-clients section 20 * "Sending and receiving", using SMBus level communication is preferred. 21 */ 22 23#include <linux/kernel.h> 24#include <linux/module.h> 25#include <linux/interrupt.h> 26#include <linux/i2c.h> 27#include <linux/rtc.h> 28#include <linux/bcd.h> 29#include <linux/mutex.h> 30#include <linux/workqueue.h> 31 32#define DS1374_REG_TOD0 0x00 33#define DS1374_REG_TOD1 0x01 34#define DS1374_REG_TOD2 0x02 35#define DS1374_REG_TOD3 0x03 36#define DS1374_REG_WDALM0 0x04 37#define DS1374_REG_WDALM1 0x05 38#define DS1374_REG_WDALM2 0x06 39#define DS1374_REG_CR 0x07 40#define DS1374_REG_SR 0x08 41#define DS1374_REG_SR_OSF 0x80 42#define DS1374_REG_TCR 0x09 43 44#define DS1374_DRV_NAME "ds1374" 45 46static DEFINE_MUTEX(ds1374_mutex); 47 48static struct i2c_driver ds1374_driver; 49static struct i2c_client *save_client; 50 51static unsigned short ignore[] = { I2C_CLIENT_END }; 52static unsigned short normal_addr[] = { 0x68, I2C_CLIENT_END }; 53 54static struct i2c_client_address_data addr_data = { 55 .normal_i2c = normal_addr, 56 .probe = ignore, 57 .ignore = ignore, 58}; 59 60static ulong ds1374_read_rtc(void) 61{ 62 ulong time = 0; 63 int reg = DS1374_REG_WDALM0; 64 65 while (reg--) { 66 s32 tmp; 67 if ((tmp = i2c_smbus_read_byte_data(save_client, reg)) < 0) { 68 dev_warn(&save_client->dev, 69 "can't read from rtc chip\n"); 70 return 0; 71 } 72 time = (time << 8) | (tmp & 0xff); 73 } 74 return time; 75} 76 77static void ds1374_write_rtc(ulong time) 78{ 79 int reg; 80 81 for (reg = DS1374_REG_TOD0; reg < DS1374_REG_WDALM0; reg++) { 82 if (i2c_smbus_write_byte_data(save_client, reg, time & 0xff) 83 < 0) { 84 dev_warn(&save_client->dev, 85 "can't write to rtc chip\n"); 86 break; 87 } 88 time = time >> 8; 89 } 90} 91 92static void ds1374_check_rtc_status(void) 93{ 94 s32 tmp; 95 96 tmp = i2c_smbus_read_byte_data(save_client, DS1374_REG_SR); 97 if (tmp < 0) { 98 dev_warn(&save_client->dev, 99 "can't read status from rtc chip\n"); 100 return; 101 } 102 if (tmp & DS1374_REG_SR_OSF) { 103 dev_warn(&save_client->dev, 104 "oscillator discontinuity flagged, time unreliable\n"); 105 tmp &= ~DS1374_REG_SR_OSF; 106 tmp = i2c_smbus_write_byte_data(save_client, DS1374_REG_SR, 107 tmp & 0xff); 108 if (tmp < 0) 109 dev_warn(&save_client->dev, 110 "can't clear discontinuity notification\n"); 111 } 112} 113 114ulong ds1374_get_rtc_time(void) 115{ 116 ulong t1, t2; 117 int limit = 10; /* arbitrary retry limit */ 118 119 mutex_lock(&ds1374_mutex); 120 121 /* 122 * Since the reads are being performed one byte at a time using 123 * the SMBus vs a 4-byte i2c transfer, there is a chance that a 124 * carry will occur during the read. To detect this, 2 reads are 125 * performed and compared. 126 */ 127 do { 128 t1 = ds1374_read_rtc(); 129 t2 = ds1374_read_rtc(); 130 } while (t1 != t2 && limit--); 131 132 mutex_unlock(&ds1374_mutex); 133 134 if (t1 != t2) { 135 dev_warn(&save_client->dev, 136 "can't get consistent time from rtc chip\n"); 137 t1 = 0; 138 } 139 140 return t1; 141} 142 143static ulong new_time; 144 145static void ds1374_set_work(struct work_struct *work) 146{ 147 ulong t1, t2; 148 int limit = 10; /* arbitrary retry limit */ 149 150 t1 = new_time; 151 152 mutex_lock(&ds1374_mutex); 153 154 /* 155 * Since the writes are being performed one byte at a time using 156 * the SMBus vs a 4-byte i2c transfer, there is a chance that a 157 * carry will occur during the write. To detect this, the write 158 * value is read back and compared. 159 */ 160 do { 161 ds1374_write_rtc(t1); 162 t2 = ds1374_read_rtc(); 163 } while (t1 != t2 && limit--); 164 165 mutex_unlock(&ds1374_mutex); 166 167 if (t1 != t2) 168 dev_warn(&save_client->dev, 169 "can't confirm time set from rtc chip\n"); 170} 171 172static struct workqueue_struct *ds1374_workqueue; 173 174static DECLARE_WORK(ds1374_work, ds1374_set_work); 175 176int ds1374_set_rtc_time(ulong nowtime) 177{ 178 new_time = nowtime; 179 180 if (in_interrupt()) 181 queue_work(ds1374_workqueue, &ds1374_work); 182 else 183 ds1374_set_work(NULL); 184 185 return 0; 186} 187 188/* 189 ***************************************************************************** 190 * 191 * Driver Interface 192 * 193 ***************************************************************************** 194 */ 195static int ds1374_probe(struct i2c_adapter *adap, int addr, int kind) 196{ 197 struct i2c_client *client; 198 int rc; 199 200 client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL); 201 if (!client) 202 return -ENOMEM; 203 204 strncpy(client->name, DS1374_DRV_NAME, I2C_NAME_SIZE); 205 client->addr = addr; 206 client->adapter = adap; 207 client->driver = &ds1374_driver; 208 209 ds1374_workqueue = create_singlethread_workqueue("ds1374"); 210 if (!ds1374_workqueue) { 211 kfree(client); 212 return -ENOMEM; /* most expected reason */ 213 } 214 215 if ((rc = i2c_attach_client(client)) != 0) { 216 kfree(client); 217 return rc; 218 } 219 220 save_client = client; 221 222 ds1374_check_rtc_status(); 223 224 return 0; 225} 226 227static int ds1374_attach(struct i2c_adapter *adap) 228{ 229 return i2c_probe(adap, &addr_data, ds1374_probe); 230} 231 232static int ds1374_detach(struct i2c_client *client) 233{ 234 int rc; 235 236 if ((rc = i2c_detach_client(client)) == 0) { 237 kfree(i2c_get_clientdata(client)); 238 destroy_workqueue(ds1374_workqueue); 239 } 240 return rc; 241} 242 243static struct i2c_driver ds1374_driver = { 244 .driver = { 245 .name = DS1374_DRV_NAME, 246 }, 247 .id = I2C_DRIVERID_DS1374, 248 .attach_adapter = ds1374_attach, 249 .detach_client = ds1374_detach, 250}; 251 252static int __init ds1374_init(void) 253{ 254 return i2c_add_driver(&ds1374_driver); 255} 256 257static void __exit ds1374_exit(void) 258{ 259 i2c_del_driver(&ds1374_driver); 260} 261 262module_init(ds1374_init); 263module_exit(ds1374_exit); 264 265MODULE_AUTHOR("Randy Vinson <rvinson@mvista.com>"); 266MODULE_DESCRIPTION("Maxim/Dallas DS1374 RTC I2C Client Driver"); 267MODULE_LICENSE("GPL"); 268