linux/drivers/w1/slaves/w1_ds2408.c
<<
>>
Prefs
   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));
 354