1 /* 2 * An I2C driver for the Ricoh RS5C372 RTC 3 * 4 * Copyright (C) 2005 Pavel Mironchik <pmironchik@optifacio.net> 5 * Copyright (C) 2006 Tower Technologies 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 */ 11 12 #include <linux/i2c.h> 13 #include <linux/rtc.h> 14 #include <linux/bcd.h> 15 16 #define DRV_VERSION "0.3" 17 18 /* Addresses to scan */ 19 static unsigned short normal_i2c[] = { /* 0x32,*/ I2C_CLIENT_END }; 20 21 /* Insmod parameters */ 22 I2C_CLIENT_INSMOD; 23 24 #define RS5C372_REG_SECS 0 25 #define RS5C372_REG_MINS 1 26 #define RS5C372_REG_HOURS 2 27 #define RS5C372_REG_WDAY 3 28 #define RS5C372_REG_DAY 4 29 #define RS5C372_REG_MONTH 5 30 #define RS5C372_REG_YEAR 6 31 #define RS5C372_REG_TRIM 7 32 33 #define RS5C372_TRIM_XSL 0x80 34 #define RS5C372_TRIM_MASK 0x7F 35 36 #define RS5C372_REG_BASE 0 37 38 static int rs5c372_attach(struct i2c_adapter *adapter); 39 static int rs5c372_detach(struct i2c_client *client); 40 static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind); 41 42 struct rs5c372 { 43 u8 reg_addr; 44 u8 regs[17]; 45 struct i2c_msg msg[1]; 46 struct i2c_client client; 47 struct rtc_device *rtc; 48 }; 49 50 static struct i2c_driver rs5c372_driver = { 51 .driver = { 52 .name = "rs5c372", 53 }, 54 .attach_adapter = &rs5c372_attach, 55 .detach_client = &rs5c372_detach, 56 }; 57 58 static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm) 59 { 60 61 struct rs5c372 *rs5c372 = i2c_get_clientdata(client); 62 u8 *buf = &(rs5c372->regs[1]); 63 64 /* this implements the 3rd reading method, according 65 * to the datasheet. rs5c372 defaults to internal 66 * address 0xF, so 0x0 is in regs[1] 67 */ 68 69 if ((i2c_transfer(client->adapter, rs5c372->msg, 1)) != 1) { 70 dev_err(&client->dev, "%s: read error\n", __FUNCTION__); 71 return -EIO; 72 } 73 74 tm->tm_sec = BCD2BIN(buf[RS5C372_REG_SECS] & 0x7f); 75 tm->tm_min = BCD2BIN(buf[RS5C372_REG_MINS] & 0x7f); 76 tm->tm_hour = BCD2BIN(buf[RS5C372_REG_HOURS] & 0x3f); 77 tm->tm_wday = BCD2BIN(buf[RS5C372_REG_WDAY] & 0x07); 78 tm->tm_mday = BCD2BIN(buf[RS5C372_REG_DAY] & 0x3f); 79 80 /* tm->tm_mon is zero-based */ 81 tm->tm_mon = BCD2BIN(buf[RS5C372_REG_MONTH] & 0x1f) - 1; 82 83 /* year is 1900 + tm->tm_year */ 84 tm->tm_year = BCD2BIN(buf[RS5C372_REG_YEAR]) + 100; 85 86 dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " 87 "mday=%d, mon=%d, year=%d, wday=%d\n", 88 __FUNCTION__, 89 tm->tm_sec, tm->tm_min, tm->tm_hour, 90 tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); 91 92 return 0; 93 } 94 95 static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm) 96 { 97 unsigned char buf[8] = { RS5C372_REG_BASE }; 98 99 dev_dbg(&client->dev, 100 "%s: secs=%d, mins=%d, hours=%d " 101 "mday=%d, mon=%d, year=%d, wday=%d\n", 102 __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour, 103 tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); 104 105 buf[1] = BIN2BCD(tm->tm_sec); 106 buf[2] = BIN2BCD(tm->tm_min); 107 buf[3] = BIN2BCD(tm->tm_hour); 108 buf[4] = BIN2BCD(tm->tm_wday); 109 buf[5] = BIN2BCD(tm->tm_mday); 110 buf[6] = BIN2BCD(tm->tm_mon + 1); 111 buf[7] = BIN2BCD(tm->tm_year - 100); 112 113 if ((i2c_master_send(client, buf, 8)) != 8) { 114 dev_err(&client->dev, "%s: write error\n", __FUNCTION__); 115 return -EIO; 116 } 117 118 return 0; 119 } 120 121 static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim) 122 { 123 struct rs5c372 *rs5c372 = i2c_get_clientdata(client); 124 u8 tmp = rs5c372->regs[RS5C372_REG_TRIM + 1]; 125 126 if (osc) 127 *osc = (tmp & RS5C372_TRIM_XSL) ? 32000 : 32768; 128 129 if (trim) { 130 *trim = tmp & RS5C372_TRIM_MASK; 131 dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, *trim); 132 } 133 134 return 0; 135 } 136 137 static int rs5c372_rtc_read_time(struct device *dev, struct rtc_time *tm) 138 { 139 return rs5c372_get_datetime(to_i2c_client(dev), tm); 140 } 141 142 static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm) 143 { 144 return rs5c372_set_datetime(to_i2c_client(dev), tm); 145 } 146 147 static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq) 148 { 149 int err, osc, trim; 150 151 err = rs5c372_get_trim(to_i2c_client(dev), &osc, &trim); 152 if (err == 0) { 153 seq_printf(seq, "%d.%03d KHz\n", osc / 1000, osc % 1000); 154 seq_printf(seq, "trim\t: %d\n", trim); 155 } 156 157 return 0; 158 } 159 160 static const struct rtc_class_ops rs5c372_rtc_ops = { 161 .proc = rs5c372_rtc_proc, 162 .read_time = rs5c372_rtc_read_time, 163 .set_time = rs5c372_rtc_set_time, 164 }; 165 166 static ssize_t rs5c372_sysfs_show_trim(struct device *dev, 167 struct device_attribute *attr, char *buf) 168 { 169 int err, trim; 170 171 err = rs5c372_get_trim(to_i2c_client(dev), NULL, &trim); 172 if (err) 173 return err; 174 175 return sprintf(buf, "0x%2x\n", trim); 176 } 177 static DEVICE_ATTR(trim, S_IRUGO, rs5c372_sysfs_show_trim, NULL); 178 179 static ssize_t rs5c372_sysfs_show_osc(struct device *dev, 180 struct device_attribute *attr, char *buf) 181 { 182 int err, osc; 183 184 err = rs5c372_get_trim(to_i2c_client(dev), &osc, NULL); 185 if (err) 186 return err; 187 188 return sprintf(buf, "%d.%03d KHz\n", osc / 1000, osc % 1000); 189 } 190 static DEVICE_ATTR(osc, S_IRUGO, rs5c372_sysfs_show_osc, NULL); 191 192 static int rs5c372_attach(struct i2c_adapter *adapter) 193 { 194 return i2c_probe(adapter, &addr_data, rs5c372_probe); 195 } 196 197 static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) 198 { 199 int err = 0; 200 struct i2c_client *client; 201 struct rs5c372 *rs5c372; 202 203 dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); 204 205 if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { 206 err = -ENODEV; 207 goto exit; 208 } 209 210 if (!(rs5c372 = kzalloc(sizeof(struct rs5c372), GFP_KERNEL))) { 211 err = -ENOMEM; 212 goto exit; 213 } 214 client = &rs5c372->client; 215 216 /* I2C client */ 217 client->addr = address; 218 client->driver = &rs5c372_driver; 219 client->adapter = adapter; 220 221 strlcpy(client->name, rs5c372_driver.driver.name, I2C_NAME_SIZE); 222 223 i2c_set_clientdata(client, rs5c372); 224 225 rs5c372->msg[0].addr = address; 226 rs5c372->msg[0].flags = I2C_M_RD; 227 rs5c372->msg[0].len = sizeof(rs5c372->regs); 228 rs5c372->msg[0].buf = rs5c372->regs; 229 230 /* Inform the i2c layer */ 231 if ((err = i2c_attach_client(client))) 232 goto exit_kfree; 233 234 dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); 235 236 rs5c372->rtc = rtc_device_register(rs5c372_driver.driver.name, 237 &client->dev, &rs5c372_rtc_ops, THIS_MODULE); 238 239 if (IS_ERR(rs5c372->rtc)) { 240 err = PTR_ERR(rs5c372->rtc); 241 goto exit_detach; 242 } 243 244 err = device_create_file(&client->dev, &dev_attr_trim); 245 if (err) 246 goto exit_devreg; 247 err = device_create_file(&client->dev, &dev_attr_osc); 248 if (err) 249 goto exit_trim; 250 251 return 0; 252 253 exit_trim: 254 device_remove_file(&client->dev, &dev_attr_trim); 255 256 exit_devreg: 257 rtc_device_unregister(rs5c372->rtc); 258 259 exit_detach: 260 i2c_detach_client(client); 261 262 exit_kfree: 263 kfree(rs5c372); 264 265 exit: 266 return err; 267 } 268 269 static int rs5c372_detach(struct i2c_client *client) 270 { 271 int err; 272 struct rs5c372 *rs5c372 = i2c_get_clientdata(client); 273 274 if (rs5c372->rtc) 275 rtc_device_unregister(rs5c372->rtc); 276 277 if ((err = i2c_detach_client(client))) 278 return err; 279 280 kfree(rs5c372); 281 return 0; 282 } 283 284 static __init int rs5c372_init(void) 285 { 286 return i2c_add_driver(&rs5c372_driver); 287 } 288 289 static __exit void rs5c372_exit(void) 290 { 291 i2c_del_driver(&rs5c372_driver); 292 } 293 294 module_init(rs5c372_init); 295 module_exit(rs5c372_exit); 296 297 MODULE_AUTHOR( 298 "Pavel Mironchik <pmironchik@optifacio.net>, " 299 "Alessandro Zummo <a.zummo@towertech.it>"); 300 MODULE_DESCRIPTION("Ricoh RS5C372 RTC driver"); 301 MODULE_LICENSE("GPL"); 302 MODULE_VERSION(DRV_VERSION); 303