linux/drivers/w1/slaves/w1_ds2408.c
<<
>>
Prefs
   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
  22MODULE_LICENSE("GPL");
  23MODULE_AUTHOR("Jean-Francois Dagenais <dagenaisj@sonatest.com>");
  24MODULE_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
  45static 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->mutex);
  56        dev_dbg(&sl->dev, "mutex locked");
  57
  58        if (w1_reset_select_slave(sl)) {
  59                mutex_unlock(&sl->master->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->mutex);
  70        dev_dbg(&sl->dev, "mutex unlocked");
  71        return 1;
  72}
  73
  74static 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
  87static 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
 101static 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
 115static 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
 129static 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
 140static 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
 154static 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->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                /* here the master could read another byte which
 182                   would be the PIO reg (the actual pin logic state)
 183                   since in this driver we don't know which pins are
 184                   in and outs, there's no value to read the state and
 185                   compare. with (*buf) so end this command abruptly: */
 186                if (w1_reset_resume_command(sl->master))
 187                        goto error;
 188
 189                if (readBack != 0xAA) {
 190                        /* try again, the slave is ready for a command */
 191                        continue;
 192                }
 193
 194                /* go read back the output latches */
 195                /* (the direct effect of the write above) */
 196                w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
 197                w1_buf[1] = W1_F29_REG_OUTPUT_LATCH_STATE;
 198                w1_buf[2] = 0;
 199                w1_write_block(sl->master, w1_buf, 3);
 200                /* read the result of the READ_PIO_REGS command */
 201                if (w1_read_8(sl->master) == *buf) {
 202                        /* success! */
 203                        mutex_unlock(&sl->master->mutex);
 204                        dev_dbg(&sl->dev,
 205                                "mutex unlocked, retries:%d", retries);
 206                        return 1;
 207                }
 208        }
 209error:
 210        mutex_unlock(&sl->master->mutex);
 211        dev_dbg(&sl->dev, "mutex unlocked in error, retries:%d", retries);
 212
 213        return -EIO;
 214}
 215
 216
 217/**
 218 * Writing to the activity file resets the activity latches.
 219 */
 220static ssize_t w1_f29_write_activity(
 221        struct file *filp, struct kobject *kobj,
 222        struct bin_attribute *bin_attr,
 223        char *buf, loff_t off, size_t count)
 224{
 225        struct w1_slave *sl = kobj_to_w1_slave(kobj);
 226        unsigned int retries = W1_F29_RETRIES;
 227
 228        if (count != 1 || off != 0)
 229                return -EFAULT;
 230
 231        mutex_lock(&sl->master->mutex);
 232
 233        if (w1_reset_select_slave(sl))
 234                goto error;
 235
 236        while (retries--) {
 237                w1_write_8(sl->master, W1_F29_FUNC_RESET_ACTIVITY_LATCHES);
 238                if (w1_read_8(sl->master) == W1_F29_SUCCESS_CONFIRM_BYTE) {
 239                        mutex_unlock(&sl->master->mutex);
 240                        return 1;
 241                }
 242                if (w1_reset_resume_command(sl->master))
 243                        goto error;
 244        }
 245
 246error:
 247        mutex_unlock(&sl->master->mutex);
 248        return -EIO;
 249}
 250
 251static ssize_t w1_f29_write_status_control(
 252        struct file *filp,
 253        struct kobject *kobj,
 254        struct bin_attribute *bin_attr,
 255        char *buf,
 256        loff_t off,
 257        size_t count)
 258{
 259        struct w1_slave *sl = kobj_to_w1_slave(kobj);
 260        u8 w1_buf[4];
 261        unsigned int retries = W1_F29_RETRIES;
 262
 263        if (count != 1 || off != 0)
 264                return -EFAULT;
 265
 266        mutex_lock(&sl->master->mutex);
 267
 268        if (w1_reset_select_slave(sl))
 269                goto error;
 270
 271        while (retries--) {
 272                w1_buf[0] = W1_F29_FUNC_WRITE_COND_SEARCH_REG;
 273                w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
 274                w1_buf[2] = 0;
 275                w1_buf[3] = *buf;
 276
 277                w1_write_block(sl->master, w1_buf, 4);
 278                if (w1_reset_resume_command(sl->master))
 279                        goto error;
 280
 281                w1_buf[0] = W1_F29_FUNC_READ_PIO_REGS;
 282                w1_buf[1] = W1_F29_REG_CONTROL_AND_STATUS;
 283                w1_buf[2] = 0;
 284
 285                w1_write_block(sl->master, w1_buf, 3);
 286                if (w1_read_8(sl->master) == *buf) {
 287                        /* success! */
 288                        mutex_unlock(&sl->master->mutex);
 289                        return 1;
 290                }
 291        }
 292error:
 293        mutex_unlock(&sl->master->mutex);
 294
 295        return -EIO;
 296}
 297
 298
 299
 300#define NB_SYSFS_BIN_FILES 6
 301static struct bin_attribute w1_f29_sysfs_bin_files[NB_SYSFS_BIN_FILES] = {
 302        {
 303                .attr = {
 304                        .name = "state",
 305                        .mode = S_IRUGO,
 306                },
 307                .size = 1,
 308                .read = w1_f29_read_state,
 309        },
 310        {
 311                .attr = {
 312                        .name = "output",
 313                        .mode = S_IRUGO | S_IWUSR | S_IWGRP,
 314                },
 315                .size = 1,
 316                .read = w1_f29_read_output,
 317                .write = w1_f29_write_output,
 318        },
 319        {
 320                .attr = {
 321                        .name = "activity",
 322                        .mode = S_IRUGO,
 323                },
 324                .size = 1,
 325                .read = w1_f29_read_activity,
 326                .write = w1_f29_write_activity,
 327        },
 328        {
 329                .attr = {
 330                        .name = "cond_search_mask",
 331                        .mode = S_IRUGO,
 332                },
 333                .size = 1,
 334                .read = w1_f29_read_cond_search_mask,
 335                .write = 0,
 336        },
 337        {
 338                .attr = {
 339                        .name = "cond_search_polarity",
 340                        .mode = S_IRUGO,
 341                },
 342                .size = 1,
 343                .read = w1_f29_read_cond_search_polarity,
 344                .write = 0,
 345        },
 346        {
 347                .attr = {
 348                        .name = "status_control",
 349                        .mode = S_IRUGO | S_IWUSR | S_IWGRP,
 350                },
 351                .size = 1,
 352                .read = w1_f29_read_status_control,
 353                .write = w1_f29_write_status_control,
 354        }
 355};
 356
 357static int w1_f29_add_slave(struct w1_slave *sl)
 358{
 359        int err = 0;
 360        int i;
 361
 362        for (i = 0; i < NB_SYSFS_BIN_FILES && !err; ++i)
 363                err = sysfs_create_bin_file(
 364                        &sl->dev.kobj,
 365                        &(w1_f29_sysfs_bin_files[i]));
 366        if (err)
 367                while (--i >= 0)
 368                        sysfs_remove_bin_file(&sl->dev.kobj,
 369                                &(w1_f29_sysfs_bin_files[i]));
 370        return err;
 371}
 372
 373static void w1_f29_remove_slave(struct w1_slave *sl)
 374{
 375        int i;
 376        for (i = NB_SYSFS_BIN_FILES - 1; i >= 0; --i)
 377                sysfs_remove_bin_file(&sl->dev.kobj,
 378                        &(w1_f29_sysfs_bin_files[i]));
 379}
 380
 381static struct w1_family_ops w1_f29_fops = {
 382        .add_slave      = w1_f29_add_slave,
 383        .remove_slave   = w1_f29_remove_slave,
 384};
 385
 386static struct w1_family w1_family_29 = {
 387        .fid = W1_FAMILY_DS2408,
 388        .fops = &w1_f29_fops,
 389};
 390
 391static int __init w1_f29_init(void)
 392{
 393        return w1_register_family(&w1_family_29);
 394}
 395
 396static void __exit w1_f29_exit(void)
 397{
 398        w1_unregister_family(&w1_family_29);
 399}
 400
 401module_init(w1_f29_init);
 402module_exit(w1_f29_exit);
 403