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 MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2408)); 26 27 28 #define W1_F29_RETRIES 3 29 30 #define W1_F29_REG_LOGIG_STATE 0x88 /* R */ 31 #define W1_F29_REG_OUTPUT_LATCH_STATE 0x89 /* R */ 32 #define W1_F29_REG_ACTIVITY_LATCH_STATE 0x8A /* R */ 33 #define W1_F29_REG_COND_SEARCH_SELECT_MASK 0x8B /* RW */ 34 #define W1_F29_REG_COND_SEARCH_POL_SELECT 0x8C /* RW */ 35 #define W1_F29_REG_CONTROL_AND_STATUS 0x8D /* RW */ 36 37 #define W1_F29_FUNC_READ_PIO_REGS 0xF0 38 #define W1_F29_FUNC_CHANN_ACCESS_READ 0xF5 39 #define W1_F29_FUNC_CHANN_ACCESS_WRITE 0x5A 40 /* also used to write the control/status reg (0x8D): */ 41 #define W1_F29_FUNC_WRITE_COND_SEARCH_REG 0xCC 42 #define W1_F29_FUNC_RESET_ACTIVITY_LATCHES 0xC3 43 44 #define W1_F29_SUCCESS_CONFIRM_BYTE 0xAA 45 46 static int _read_reg(struct w1_slave *sl, u8 address, unsigned char* buf) 47 { 48 u8 wrbuf[3]; 49 dev_dbg(&sl->dev, 50 "Reading with slave: %p, reg addr: %0#4x, buff addr: %p", 51 sl, (unsigned int)address, buf); 52 53 if (!buf) 54 return -EINVAL; 55 56 mutex_lock(&sl->master->bus_mutex); 57 dev_dbg(&sl->dev, "mutex locked"); 58 59 if (w1_reset_select_slave(sl)) { 60 mutex_unlock(&sl->master->bus_mutex); 61 return -EIO; 62 } 63 64 wrbuf[0] = W1_F29_FUNC_READ_PIO_REGS; 65 wrbuf[1] = address; 66 wrbuf[2] = 0; 67 w1_write_block(sl->master, wrbuf, 3); 68 *buf = w1_read_8(sl->master); 69 70 mutex_unlock(&sl->master->bus_mutex); 71 dev_dbg(&sl->dev, "mutex unlocked"); 72 return 1; 73 } 74 75 static ssize_t state_read(struct file *filp, struct kobject *kobj, 76 struct bin_attribute *bin_attr, char *buf, loff_t off, 77 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 output_read(struct file *filp, struct kobject *kobj, 88 struct bin_attribute *bin_attr, char *buf, 89 loff_t off, size_t count) 90 { 91 dev_dbg(&kobj_to_w1_slave(kobj)->dev, 92 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p", 93 bin_attr->attr.name, kobj, (unsigned int)off, count, buf); 94 if (count != 1 || off != 0) 95 return -EFAULT; 96 return _read_reg(kobj_to_w1_slave(kobj), 97 W1_F29_REG_OUTPUT_LATCH_STATE, buf); 98 } 99 100 static ssize_t activity_read(struct file *filp, struct kobject *kobj, 101 struct bin_attribute *bin_attr, char *buf, 102 loff_t off, size_t count) 103 { 104 dev_dbg(&kobj_to_w1_slave(kobj)->dev, 105 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p", 106 bin_attr->attr.name, kobj, (unsigned int)off, count, buf); 107 if (count != 1 || off != 0) 108 return -EFAULT; 109 return _read_reg(kobj_to_w1_slave(kobj), 110 W1_F29_REG_ACTIVITY_LATCH_STATE, buf); 111 } 112 113 static ssize_t cond_search_mask_read(struct file *filp, struct kobject *kobj, 114 struct bin_attribute *bin_attr, char *buf, 115 loff_t off, size_t count) 116 { 117 dev_dbg(&kobj_to_w1_slave(kobj)->dev, 118 "Reading %s kobj: %p, off: %0#10x, count: %zu, buff addr: %p", 119 bin_attr->attr.name, kobj, (unsigned int)off, count, buf); 120 if (count != 1 || off != 0) 121 return -EFAULT; 122 return _read_reg(kobj_to_w1_slave(kobj), 123 W1_F29_REG_COND_SEARCH_SELECT_MASK, buf); 124 } 125 126 static ssize_t cond_search_polarity_read(struct file *filp, 127 struct kobject *kobj, 128 struct bin_attribute *bin_attr, 129 char *buf, loff_t off, size_t count) 130 { 131 if (count != 1 || off != 0) 132 return -EFAULT; 133 return _read_reg(kobj_to_w1_slave(kobj), 134 W1_F29_REG_COND_SEARCH_POL_SELECT, buf); 135 } 136 137 static ssize_t status_control_read(struct file *filp, struct kobject *kobj, 138 struct bin_attribute *bin_attr, char *buf, 139 loff_t off, size_t count) 140 { 141 if (count != 1 || off != 0) 142 return -EFAULT; 143 return _read_reg(kobj_to_w1_slave(kobj), 144 W1_F29_REG_CONTROL_AND_STATUS, buf); 145 } 146 147 static ssize_t output_write(struct file *filp, struct kobject *kobj, 148 struct bin_attribute *bin_attr, char *buf, 149 loff_t off, size_t count) 150 { 151 struct w1_slave *sl = kobj_to_w1_slave(kobj); 152 u8 w1_buf[3]; 153 u8 readBack; 154 unsigned int retries = W1_F29_RETRIES; 155 156 if (count != 1 || off != 0) 157 return -EFAULT; 158 159 dev_dbg(&sl->dev, "locking mutex for write_output"); 160 mutex_lock(&sl->master->bus_mutex); 161 dev_dbg(&sl->dev, "mutex locked"); 162 163 if (w1_reset_select_slave(sl)) 164 goto error; 165 166 while (retries--) { 167 w1_buf[0] = W1_F29_FUNC_CHANN_ACCESS_WRITE; 168 w1_buf[1] = *buf; 169 w1_buf[2] = ~(*buf); 170 w1_write_block(sl->master, w1_buf, 3); 171 172 readBack = w1_read_8(sl->master); 173 174 if (readBack != W1_F29_SUCCESS_CONFIRM_BYTE) { 175 if (w1_reset_resume_command(sl->master)) 176 goto error; 177 /* try again, the slave is ready for a command */ 178 continue; 179 } 180 181 #ifdef CONFIG_W1_SLAVE_DS2408_READBACK 182 /* here the master could read another byte which 183 would be the PIO reg (the actual pin logic state) 184 since in this driver we don't know which pins are 185 in and outs, there's no value to read the state and 186 compare. with (*buf) so end this command abruptly: */ 187 if (w1_reset_resume_command(sl->master)) 188 goto error; 189 190 /* go read back the output latches */ 191 /* (the direct effect of the write above) */ 192 w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS; 193 w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE; 194 w1_buf[2] = 0; 195 w1_write_block(sl->master, w1_buf, 3); 196 /* read the result of the READ_PIO_REGS command */ 197 if (w1_read_8(sl->master) == *buf) 198 #endif 199 { 200 /* success! */ 201 mutex_unlock(&sl->master->bus_mutex); 202 dev_dbg(&sl->dev, 203 "mutex unlocked, retries:%d", retries); 204 return 1; 205 } 206 } 207 error: 208 mutex_unlock(&sl->master->bus_mutex); 209 dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries); 210 211 return -EIO; 212 } 213 214 215 /** 216 * Writing to the activity file resets the activity latches. 217 */ 218 static ssize_t activity_write(struct file *filp, struct kobject *kobj, 219 struct bin_attribute *bin_attr, char *buf, 220 loff_t off, size_t count) 221 { 222 struct w1_slave *sl = kobj_to_w1_slave(kobj); 223 unsigned int retries = W1_F29_RETRIES; 224 225 if (count != 1 || off != 0) 226 return -EFAULT; 227 228 mutex_lock(&sl->master->bus_mutex); 229 230 if (w1_reset_select_slave(sl)) 231 goto error; 232 233 while (retries--) { 234 w1_write_8(sl->master, W1_F29_FUNC_RESET_ACTIVITY_LATCHES); 235 if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE) { 236 mutex_unlock(&sl->master->bus_mutex); 237 return 1; 238 } 239 if (w1_reset_resume_command(sl->master)) 240 goto error; 241 } 242 243 error: 244 mutex_unlock(&sl->master->bus_mutex); 245 return -EIO; 246 } 247 248 static ssize_t status_control_write(struct file *filp, struct kobject *kobj, 249 struct bin_attribute *bin_attr, char *buf, 250 loff_t off, size_t count) 251 { 252 struct w1_slave *sl = kobj_to_w1_slave(kobj); 253 u8 w1_buf[4]; 254 unsigned int retries = W1_F29_RETRIES; 255 256 if (count != 1 || off != 0) 257 return -EFAULT; 258 259 mutex_lock(&sl->master->bus_mutex); 260 261 if (w1_reset_select_slave(sl)) 262 goto error; 263 264 while (retries--) { 265 w1_buf[0] = W1_F29_FUNC_WRITE_COND_SEARCH_REG; 266 w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS; 267 w1_buf[2] = 0; 268 w1_buf[3] = *buf; 269 270 w1_write_block(sl->master, w1_buf, 4); 271 if (w1_reset_resume_command(sl->master)) 272 goto error; 273 274 w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS; 275 w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS; 276 w1_buf[2] = 0; 277 278 w1_write_block(sl->master, w1_buf, 3); 279 if (w1_read_8(sl->master) == *buf) { 280 /* success! */ 281 mutex_unlock(&sl->master->bus_mutex); 282 return 1; 283 } 284 } 285 error: 286 mutex_unlock(&sl->master->bus_mutex); 287 288 return -EIO; 289 } 290 291 /* 292 * This is a special sequence we must do to ensure the P0 output is not stuck 293 * in test mode. This is described in rev 2 of the ds2408's datasheet 294 * (http://datasheets.maximintegrated.com/en/ds/DS2408.pdf) under 295 * "APPLICATION INFORMATION/Power-up timing". 296 */ 297 static int w1_f29_disable_test_mode(struct w1_slave *sl) 298 { 299 int res; 300 u8 magic[10] = {0x96, }; 301 u64 rn = le64_to_cpu(*((u64*)&sl->reg_num)); 302 303 memcpy(&magic[1], &rn, 8); 304 magic[9] = 0x3C; 305 306 mutex_lock(&sl->master->bus_mutex); 307 308 res = w1_reset_bus(sl->master); 309 if (res) 310 goto out; 311 w1_write_block(sl->master, magic, ARRAY_SIZE(magic)); 312 313 res = w1_reset_bus(sl->master); 314 out: 315 mutex_unlock(&sl->master->bus_mutex); 316 return res; 317 } 318 319 static BIN_ATTR_RO(state, 1); 320 static BIN_ATTR_RW(output, 1); 321 static BIN_ATTR_RW(activity, 1); 322 static BIN_ATTR_RO(cond_search_mask, 1); 323 static BIN_ATTR_RO(cond_search_polarity, 1); 324 static BIN_ATTR_RW(status_control, 1); 325 326 static struct bin_attribute *w1_f29_bin_attrs[] = { 327 &bin_attr_state, 328 &bin_attr_output, 329 &bin_attr_activity, 330 &bin_attr_cond_search_mask, 331 &bin_attr_cond_search_polarity, 332 &bin_attr_status_control, 333 NULL, 334 }; 335 336 static const struct attribute_group w1_f29_group = { 337 .bin_attrs = w1_f29_bin_attrs, 338 }; 339 340 static const struct attribute_group *w1_f29_groups[] = { 341 &w1_f29_group, 342 NULL, 343 }; 344 345 static struct w1_family_ops w1_f29_fops = { 346 .add_slave = w1_f29_disable_test_mode, 347 .groups = w1_f29_groups, 348 }; 349 350 static struct w1_family w1_family_29 = { 351 .fid = W1_FAMILY_DS2408, 352 .fops = &w1_f29_fops, 353 }; 354 module_w1_family(w1_family_29); 355