1 /* 2 * w1_ds2408.c - w1 family 29 (DS2408) driver 3 * 4 * Copyright (c) 2010 Jean-Francois Dagenais <dagenaisj@sonatest.com> 5 * 6 * This source code is licensed under the GNU General Public License, 7 * Version 2. See the file COPYING for more details. 8 */ 9 10 #include <linux/kernel.h> 11 #include <linux/module.h> 12 #include <linux/moduleparam.h> 13 #include <linux/device.h> 14 #include <linux/types.h> 15 #include <linux/delay.h> 16 #include <linux/slab.h> 17 18 #include "../w1.h" 19 #include "../w1_int.h" 20 #include "../w1_family.h" 21 22 MODULE_LICENSE("GPL"); 23 MODULE_AUTHOR("Jean-Francois Dagenais <dagenaisj@sonatest.com>"); 24 MODULE_DESCRIPTION("w1 family 29 driver for DS2408 8 Pin IO"); 25 26 27 #define W1_F29_RETRIES 3 28 29 #define W1_F29_REG_LOGIG_STATE 0x88 /* R */ 30 #define W1_F29_REG_OUTPUT_LATCH_STATE 0x89 /* R */ 31 #define W1_F29_REG_ACTIVITY_LATCH_STATE 0x8A /* R */ 32 #define W1_F29_REG_COND_SEARCH_SELECT_MASK 0x8B /* RW */ 33 #define W1_F29_REG_COND_SEARCH_POL_SELECT 0x8C /* RW */ 34 #define W1_F29_REG_CONTROL_AND_STATUS 0x8D /* RW */ 35 36 #define W1_F29_FUNC_READ_PIO_REGS 0xF0 37 #define W1_F29_FUNC_CHANN_ACCESS_READ 0xF5 38 #define W1_F29_FUNC_CHANN_ACCESS_WRITE 0x5A 39 /* also used to write the control/status reg (0x8D): */ 40 #define W1_F29_FUNC_WRITE_COND_SEARCH_REG 0xCC 41 #define W1_F29_FUNC_RESET_ACTIVITY_LATCHES 0xC3 42 43 #define W1_F29_SUCCESS_CONFIRM_BYTE 0xAA 44 45 static int _read_reg(struct w1_slave *sl, u8 address, unsigned char* buf) 46 { 47 u8 wrbuf[3]; 48 dev_dbg(&sl->dev, 49 "Reading with slave: %p, reg addr: %0#4x, buff addr: %p", 50 sl, (unsigned int)address, buf); 51 52 if (!buf) 53 return -EINVAL; 54 55 mutex_lock(&sl->master->bus_mutex); 56 dev_dbg(&sl->dev, "mutex locked"); 57 58 if (w1_reset_select_slave(sl)) { 59 mutex_unlock(&sl->master->bus_mutex); 60 return -EIO; 61 } 62 63 wrbuf[0] = W1_F29_FUNC_READ_PIO_REGS; 64 wrbuf[1] = address; 65 wrbuf[2] = 0; 66 w1_write_block(sl->master, wrbuf, 3); 67 *buf = w1_read_8(sl->master); 68 69 mutex_unlock(&sl->master->bus_mutex); 70 dev_dbg(&sl->dev, "mutex unlocked"); 71 return 1; 72 } 73 74 static ssize_t w1_f29_read_state( 75 struct file *filp, struct kobject *kobj, 76 struct bin_attribute *bin_attr, 77 char *buf, loff_t off, size_t count) 78 { 79 dev_dbg(&kobj_to_w1_slave(kobj)->dev, 80 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p", 81 bin_attr->attr.name, kobj, (unsigned int)off, count, buf); 82 if (count != 1 || off != 0) 83 return -EFAULT; 84 return _read_reg(kobj_to_w1_slave(kobj), W1_F29_REG_LOGIG_STATE, buf); 85 } 86 87 static ssize_t w1_f29_read_output( 88 struct file *filp, struct kobject *kobj, 89 struct bin_attribute *bin_attr, 90 char *buf, loff_t off, size_t count) 91 { 92 dev_dbg(&kobj_to_w1_slave(kobj)->dev, 93 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p", 94 bin_attr->attr.name, kobj, (unsigned int)off, count, buf); 95 if (count != 1 || off != 0) 96 return -EFAULT; 97 return _read_reg(kobj_to_w1_slave(kobj), 98 W1_F29_REG_OUTPUT_LATCH_STATE, buf); 99 } 100 101 static ssize_t w1_f29_read_activity( 102 struct file *filp, struct kobject *kobj, 103 struct bin_attribute *bin_attr, 104 char *buf, loff_t off, size_t count) 105 { 106 dev_dbg(&kobj_to_w1_slave(kobj)->dev, 107 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p", 108 bin_attr->attr.name, kobj, (unsigned int)off, count, buf); 109 if (count != 1 || off != 0) 110 return -EFAULT; 111 return _read_reg(kobj_to_w1_slave(kobj), 112 W1_F29_REG_ACTIVITY_LATCH_STATE, buf); 113 } 114 115 static ssize_t w1_f29_read_cond_search_mask( 116 struct file *filp, struct kobject *kobj, 117 struct bin_attribute *bin_attr, 118 char *buf, loff_t off, size_t count) 119 { 120 dev_dbg(&kobj_to_w1_slave(kobj)->dev, 121 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p", 122 bin_attr->attr.name, kobj, (unsigned int)off, count, buf); 123 if (count != 1 || off != 0) 124 return -EFAULT; 125 return _read_reg(kobj_to_w1_slave(kobj), 126 W1_F29_REG_COND_SEARCH_SELECT_MASK, buf); 127 } 128 129 static ssize_t w1_f29_read_cond_search_polarity( 130 struct file *filp, struct kobject *kobj, 131 struct bin_attribute *bin_attr, 132 char *buf, loff_t off, size_t count) 133 { 134 if (count != 1 || off != 0) 135 return -EFAULT; 136 return _read_reg(kobj_to_w1_slave(kobj), 137 W1_F29_REG_COND_SEARCH_POL_SELECT, buf); 138 } 139 140 static ssize_t w1_f29_read_status_control( 141 struct file *filp, struct kobject *kobj, 142 struct bin_attribute *bin_attr, 143 char *buf, loff_t off, size_t count) 144 { 145 if (count != 1 || off != 0) 146 return -EFAULT; 147 return _read_reg(kobj_to_w1_slave(kobj), 148 W1_F29_REG_CONTROL_AND_STATUS, buf); 149 } 150 151 152 153 154 static ssize_t w1_f29_write_output( 155 struct file *filp, struct kobject *kobj, 156 struct bin_attribute *bin_attr, 157 char *buf, loff_t off, size_t count) 158 { 159 struct w1_slave *sl = kobj_to_w1_slave(kobj); 160 u8 w1_buf[3]; 161 u8 readBack; 162 unsigned int retries = W1_F29_RETRIES; 163 164 if (count != 1 || off != 0) 165 return -EFAULT; 166 167 dev_dbg(&sl->dev, "locking mutex for write_output"); 168 mutex_lock(&sl->master->bus_mutex); 169 dev_dbg(&sl->dev, "mutex locked"); 170 171 if (w1_reset_select_slave(sl)) 172 goto error; 173 174 while (retries--) { 175 w1_buf[0] = W1_F29_FUNC_CHANN_ACCESS_WRITE; 176 w1_buf[1] = *buf; 177 w1_buf[2] = ~(*buf); 178 w1_write_block(sl->master, w1_buf, 3); 179 180 readBack = w1_read_8(sl->master); 181 182 if (readBack != W1_F29_SUCCESS_CONFIRM_BYTE) { 183 if (w1_reset_resume_command(sl->master)) 184 goto error; 185 /* try again, the slave is ready for a command */ 186 continue; 187 } 188 189 #ifdef CONFIG_W1_SLAVE_DS2408_READBACK 190 /* here the master could read another byte which 191 would be the PIO reg (the actual pin logic state) 192 since in this driver we don't know which pins are 193 in and outs, there's no value to read the state and 194 compare. with (*buf) so end this command abruptly: */ 195 if (w1_reset_resume_command(sl->master)) 196 goto error; 197 198 /* go read back the output latches */ 199 /* (the direct effect of the write above) */ 200 w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS; 201 w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE; 202 w1_buf[2] = 0; 203 w1_write_block(sl->master, w1_buf, 3); 204 /* read the result of the READ_PIO_REGS command */ 205 if (w1_read_8(sl->master) == *buf) 206 #endif 207 { 208 /* success! */ 209 mutex_unlock(&sl->master->bus_mutex); 210 dev_dbg(&sl->dev, 211 "mutex unlocked, retries:%d", retries); 212 return 1; 213 } 214 } 215 error: 216 mutex_unlock(&sl->master->bus_mutex); 217 dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries); 218 219 return -EIO; 220 } 221 222 223 /** 224 * Writing to the activity file resets the activity latches. 225 */ 226 static ssize_t w1_f29_write_activity( 227 struct file *filp, struct kobject *kobj, 228 struct bin_attribute *bin_attr, 229 char *buf, loff_t off, size_t count) 230 { 231 struct w1_slave *sl = kobj_to_w1_slave(kobj); 232 unsigned int retries = W1_F29_RETRIES; 233 234 if (count != 1 || off != 0) 235 return -EFAULT; 236 237 mutex_lock(&sl->master->bus_mutex); 238 239 if (w1_reset_select_slave(sl)) 240 goto error; 241 242 while (retries--) { 243 w1_write_8(sl->master, W1_F29_FUNC_RESET_ACTIVITY_LATCHES); 244 if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE) { 245 mutex_unlock(&sl->master->bus_mutex); 246 return 1; 247 } 248 if (w1_reset_resume_command(sl->master)) 249 goto error; 250 } 251 252 error: 253 mutex_unlock(&sl->master->bus_mutex); 254 return -EIO; 255 } 256 257 static ssize_t w1_f29_write_status_control( 258 struct file *filp, 259 struct kobject *kobj, 260 struct bin_attribute *bin_attr, 261 char *buf, 262 loff_t off, 263 size_t count) 264 { 265 struct w1_slave *sl = kobj_to_w1_slave(kobj); 266 u8 w1_buf[4]; 267 unsigned int retries = W1_F29_RETRIES; 268 269 if (count != 1 || off != 0) 270 return -EFAULT; 271 272 mutex_lock(&sl->master->bus_mutex); 273 274 if (w1_reset_select_slave(sl)) 275 goto error; 276 277 while (retries--) { 278 w1_buf[0] = W1_F29_FUNC_WRITE_COND_SEARCH_REG; 279 w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS; 280 w1_buf[2] = 0; 281 w1_buf[3] = *buf; 282 283 w1_write_block(sl->master, w1_buf, 4); 284 if (w1_reset_resume_command(sl->master)) 285 goto error; 286 287 w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS; 288 w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS; 289 w1_buf[2] = 0; 290 291 w1_write_block(sl->master, w1_buf, 3); 292 if (w1_read_8(sl->master) == *buf) { 293 /* success! */ 294 mutex_unlock(&sl->master->bus_mutex); 295 return 1; 296 } 297 } 298 error: 299 mutex_unlock(&sl->master->bus_mutex); 300 301 return -EIO; 302 } 303 304 305 306 static struct bin_attribute w1_f29_sysfs_bin_files[] = { 307 { 308 .attr = { 309 .name = "state", 310 .mode = S_IRUGO, 311 }, 312 .size = 1, 313 .read = w1_f29_read_state, 314 }, 315 { 316 .attr = { 317 .name = "output", 318 .mode = S_IRUGO | S_IWUSR | S_IWGRP, 319 }, 320 .size = 1, 321 .read = w1_f29_read_output, 322 .write = w1_f29_write_output, 323 }, 324 { 325 .attr = { 326 .name = "activity", 327 .mode = S_IRUGO, 328 }, 329 .size = 1, 330 .read = w1_f29_read_activity, 331 .write = w1_f29_write_activity, 332 }, 333 { 334 .attr = { 335 .name = "cond_search_mask", 336 .mode = S_IRUGO, 337 }, 338 .size = 1, 339 .read = w1_f29_read_cond_search_mask, 340 }, 341 { 342 .attr = { 343 .name = "cond_search_polarity", 344 .mode = S_IRUGO, 345 }, 346 .size = 1, 347 .read = w1_f29_read_cond_search_polarity, 348 }, 349 { 350 .attr = { 351 .name = "status_control", 352 .mode = S_IRUGO | S_IWUSR | S_IWGRP, 353 }, 354 .size = 1, 355 .read = w1_f29_read_status_control, 356 .write = w1_f29_write_status_control, 357 } 358 }; 359 360 static int w1_f29_add_slave(struct w1_slave *sl) 361 { 362 int err = 0; 363 int i; 364 365 for (i = 0; i < ARRAY_SIZE(w1_f29_sysfs_bin_files) && !err; ++i) 366 err = sysfs_create_bin_file( 367 &sl->dev.kobj, 368 &(w1_f29_sysfs_bin_files[i])); 369 if (err) 370 while (--i >= 0) 371 sysfs_remove_bin_file(&sl->dev.kobj, 372 &(w1_f29_sysfs_bin_files[i])); 373 return err; 374 } 375 376 static void w1_f29_remove_slave(struct w1_slave *sl) 377 { 378 int i; 379 for (i = ARRAY_SIZE(w1_f29_sysfs_bin_files) - 1; i >= 0; --i) 380 sysfs_remove_bin_file(&sl->dev.kobj, 381 &(w1_f29_sysfs_bin_files[i])); 382 } 383 384 static struct w1_family_ops w1_f29_fops = { 385 .add_slave = w1_f29_add_slave, 386 .remove_slave = w1_f29_remove_slave, 387 }; 388 389 static struct w1_family w1_family_29 = { 390 .fid = W1_FAMILY_DS2408, 391 .fops = &w1_f29_fops, 392 }; 393 394 static int __init w1_f29_init(void) 395 { 396 return w1_register_family(&w1_family_29); 397 } 398 399 static void __exit w1_f29_exit(void) 400 { 401 w1_unregister_family(&w1_family_29); 402 } 403 404 module_init(w1_f29_init); 405 module_exit(w1_f29_exit); 406