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.2" 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 static struct i2c_driver rs5c372_driver = { 43 .driver = { 44 .name = "rs5c372", 45 }, 46 .attach_adapter = &rs5c372_attach, 47 .detach_client = &rs5c372_detach, 48 }; 49 50 static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm) 51 { 52 unsigned char buf[7] = { RS5C372_REG_BASE }; 53 54 /* this implements the 1st reading method, according 55 * to the datasheet. buf[0] is initialized with 56 * address ptr and transmission format register. 57 */ 58 struct i2c_msg msgs[] = { 59 { client->addr, 0, 1, buf }, 60 { client->addr, I2C_M_RD, 7, buf }, 61 }; 62 63 if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { 64 dev_err(&client->dev, "%s: read error\n", __FUNCTION__); 65 return -EIO; 66 } 67 68 tm->tm_sec = BCD2BIN(buf[RS5C372_REG_SECS] & 0x7f); 69 tm->tm_min = BCD2BIN(buf[RS5C372_REG_MINS] & 0x7f); 70 tm->tm_hour = BCD2BIN(buf[RS5C372_REG_HOURS] & 0x3f); 71 tm->tm_wday = BCD2BIN(buf[RS5C372_REG_WDAY] & 0x07); 72 tm->tm_mday = BCD2BIN(buf[RS5C372_REG_DAY] & 0x3f); 73 74 /* tm->tm_mon is zero-based */ 75 tm->tm_mon = BCD2BIN(buf[RS5C372_REG_MONTH] & 0x1f) - 1; 76 77 /* year is 1900 + tm->tm_year */ 78 tm->tm_year = BCD2BIN(buf[RS5C372_REG_YEAR]) + 100; 79 80 dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, " 81 "mday=%d, mon=%d, year=%d, wday=%d\n", 82 __FUNCTION__, 83 tm->tm_sec, tm->tm_min, tm->tm_hour, 84 tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); 85 86 return 0; 87 } 88 89 static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm) 90 { 91 unsigned char buf[8] = { RS5C372_REG_BASE }; 92 93 dev_dbg(&client->dev, 94 "%s: secs=%d, mins=%d, hours=%d " 95 "mday=%d, mon=%d, year=%d, wday=%d\n", 96 __FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour, 97 tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday); 98 99 buf[1] = BIN2BCD(tm->tm_sec); 100 buf[2] = BIN2BCD(tm->tm_min); 101 buf[3] = BIN2BCD(tm->tm_hour); 102 buf[4] = BIN2BCD(tm->tm_wday); 103 buf[5] = BIN2BCD(tm->tm_mday); 104 buf[6] = BIN2BCD(tm->tm_mon + 1); 105 buf[7] = BIN2BCD(tm->tm_year - 100); 106 107 if ((i2c_master_send(client, buf, 8)) != 8) { 108 dev_err(&client->dev, "%s: write error\n", __FUNCTION__); 109 return -EIO; 110 } 111 112 return 0; 113 } 114 115 static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim) 116 { 117 unsigned char buf = RS5C372_REG_TRIM; 118 119 struct i2c_msg msgs[] = { 120 { client->addr, 0, 1, &buf }, 121 { client->addr, I2C_M_RD, 1, &buf }, 122 }; 123 124 if ((i2c_transfer(client->adapter, msgs, 2)) != 2) { 125 dev_err(&client->dev, "%s: read error\n", __FUNCTION__); 126 return -EIO; 127 } 128 129 dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, *trim); 130 131 if (osc) 132 *osc = (buf & RS5C372_TRIM_XSL) ? 32000 : 32768; 133 134 if (trim) 135 *trim = buf & RS5C372_TRIM_MASK; 136 137 return 0; 138 } 139 140 static int rs5c372_rtc_read_time(struct device *dev, struct rtc_time *tm) 141 { 142 return rs5c372_get_datetime(to_i2c_client(dev), tm); 143 } 144 145 static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm) 146 { 147 return rs5c372_set_datetime(to_i2c_client(dev), tm); 148 } 149 150 static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq) 151 { 152 int err, osc, trim; 153 154 err = rs5c372_get_trim(to_i2c_client(dev), &osc, &trim); 155 if (err == 0) { 156 seq_printf(seq, "%d.%03d KHz\n", osc / 1000, osc % 1000); 157 seq_printf(seq, "trim\t: %d\n", trim); 158 } 159 160 return 0; 161 } 162 163 static const struct rtc_class_ops rs5c372_rtc_ops = { 164 .proc = rs5c372_rtc_proc, 165 .read_time = rs5c372_rtc_read_time, 166 .set_time = rs5c372_rtc_set_time, 167 }; 168 169 static ssize_t rs5c372_sysfs_show_trim(struct device *dev, 170 struct device_attribute *attr, char *buf) 171 { 172 int err, trim; 173 174 err = rs5c372_get_trim(to_i2c_client(dev), NULL, &trim); 175 if (err) 176 return err; 177 178 return sprintf(buf, "0x%2x\n", trim); 179 } 180 static DEVICE_ATTR(trim, S_IRUGO, rs5c372_sysfs_show_trim, NULL); 181 182 static ssize_t rs5c372_sysfs_show_osc(struct device *dev, 183 struct device_attribute *attr, char *buf) 184 { 185 int err, osc; 186 187 err = rs5c372_get_trim(to_i2c_client(dev), &osc, NULL); 188 if (err) 189 return err; 190 191 return sprintf(buf, "%d.%03d KHz\n", osc / 1000, osc % 1000); 192 } 193 static DEVICE_ATTR(osc, S_IRUGO, rs5c372_sysfs_show_osc, NULL); 194 195 static int rs5c372_attach(struct i2c_adapter *adapter) 196 { 197 return i2c_probe(adapter, &addr_data, rs5c372_probe); 198 } 199 200 static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind) 201 { 202 int err = 0; 203 struct i2c_client *client; 204 struct rtc_device *rtc; 205 206 dev_dbg(&adapter->dev, "%s\n", __FUNCTION__); 207 208 if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) { 209 err = -ENODEV; 210 goto exit; 211 } 212 213 if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) { 214 err = -ENOMEM; 215 goto exit; 216 } 217 218 /* I2C client */ 219 client->addr = address; 220 client->driver = &rs5c372_driver; 221 client->adapter = adapter; 222 223 strlcpy(client->name, rs5c372_driver.driver.name, I2C_NAME_SIZE); 224 225 /* Inform the i2c layer */ 226 if ((err = i2c_attach_client(client))) 227 goto exit_kfree; 228 229 dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n"); 230 231 rtc = rtc_device_register(rs5c372_driver.driver.name, &client->dev, 232 &rs5c372_rtc_ops, THIS_MODULE); 233 234 if (IS_ERR(rtc)) { 235 err = PTR_ERR(rtc); 236 goto exit_detach; 237 } 238 239 i2c_set_clientdata(client, rtc); 240 241 device_create_file(&client->dev, &dev_attr_trim); 242 device_create_file(&client->dev, &dev_attr_osc); 243 244 return 0; 245 246 exit_detach: 247 i2c_detach_client(client); 248 249 exit_kfree: 250 kfree(client); 251 252 exit: 253 return err; 254 } 255 256 static int rs5c372_detach(struct i2c_client *client) 257 { 258 int err; 259 struct rtc_device *rtc = i2c_get_clientdata(client); 260 261 if (rtc) 262 rtc_device_unregister(rtc); 263 264 if ((err = i2c_detach_client(client))) 265 return err; 266 267 kfree(client); 268 269 return 0; 270 } 271 272 static __init int rs5c372_init(void) 273 { 274 return i2c_add_driver(&rs5c372_driver); 275 } 276 277 static __exit void rs5c372_exit(void) 278 { 279 i2c_del_driver(&rs5c372_driver); 280 } 281 282 module_init(rs5c372_init); 283 module_exit(rs5c372_exit); 284 285 MODULE_AUTHOR( 286 "Pavel Mironchik <pmironchik@optifacio.net>, " 287 "Alessandro Zummo <a.zummo@towertech.it>"); 288 MODULE_DESCRIPTION("Ricoh RS5C372 RTC driver"); 289 MODULE_LICENSE("GPL"); 290 MODULE_VERSION(DRV_VERSION); 291