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