root/drivers/w1/slaves/w1_ds2405.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. w1_ds2405_select
  2. w1_ds2405_read_pio
  3. state_show
  4. output_show
  5. output_store

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *      w1_ds2405.c
   4  *
   5  * Copyright (c) 2017 Maciej S. Szmigiero <mail@maciej.szmigiero.name>
   6  * Based on w1_therm.c copyright (c) 2004 Evgeniy Polyakov <zbr@ioremap.net>
   7  */
   8 
   9 #include <linux/device.h>
  10 #include <linux/kernel.h>
  11 #include <linux/module.h>
  12 #include <linux/moduleparam.h>
  13 #include <linux/mutex.h>
  14 #include <linux/string.h>
  15 #include <linux/types.h>
  16 
  17 #include <linux/w1.h>
  18 
  19 #define W1_FAMILY_DS2405        0x05
  20 
  21 MODULE_LICENSE("GPL");
  22 MODULE_AUTHOR("Maciej S. Szmigiero <mail@maciej.szmigiero.name>");
  23 MODULE_DESCRIPTION("Driver for 1-wire Dallas DS2405 PIO.");
  24 MODULE_ALIAS("w1-family-" __stringify(W1_FAMILY_DS2405));
  25 
  26 static int w1_ds2405_select(struct w1_slave *sl, bool only_active)
  27 {
  28         struct w1_master *dev = sl->master;
  29 
  30         u64 dev_addr = le64_to_cpu(*(u64 *)&sl->reg_num);
  31         unsigned int bit_ctr;
  32 
  33         if (w1_reset_bus(dev) != 0)
  34                 return 0;
  35 
  36         /*
  37          * We cannot use a normal Match ROM command
  38          * since doing so would toggle PIO state
  39          */
  40         w1_write_8(dev, only_active ? W1_ALARM_SEARCH : W1_SEARCH);
  41 
  42         for (bit_ctr = 0; bit_ctr < 64; bit_ctr++) {
  43                 int bit2send = !!(dev_addr & BIT(bit_ctr));
  44                 u8 ret;
  45 
  46                 ret = w1_triplet(dev, bit2send);
  47 
  48                 if ((ret & (BIT(0) | BIT(1))) ==
  49                     (BIT(0) | BIT(1))) /* no devices found */
  50                         return 0;
  51 
  52                 if (!!(ret & BIT(2)) != bit2send)
  53                         /* wrong direction taken - no such device */
  54                         return 0;
  55         }
  56 
  57         return 1;
  58 }
  59 
  60 static int w1_ds2405_read_pio(struct w1_slave *sl)
  61 {
  62         if (w1_ds2405_select(sl, true))
  63                 return 0; /* "active" means PIO is low */
  64 
  65         if (w1_ds2405_select(sl, false))
  66                 return 1;
  67 
  68         return -ENODEV;
  69 }
  70 
  71 static ssize_t state_show(struct device *device,
  72                           struct device_attribute *attr, char *buf)
  73 {
  74         struct w1_slave *sl = dev_to_w1_slave(device);
  75         struct w1_master *dev = sl->master;
  76 
  77         int ret;
  78         ssize_t f_retval;
  79         u8 state;
  80 
  81         ret = mutex_lock_interruptible(&dev->bus_mutex);
  82         if (ret)
  83                 return ret;
  84 
  85         if (!w1_ds2405_select(sl, false)) {
  86                 f_retval = -ENODEV;
  87                 goto out_unlock;
  88         }
  89 
  90         state = w1_read_8(dev);
  91         if (state != 0 &&
  92             state != 0xff) {
  93                 dev_err(device, "non-consistent state %x\n", state);
  94                 f_retval = -EIO;
  95                 goto out_unlock;
  96         }
  97 
  98         *buf = state ? '1' : '0';
  99         f_retval = 1;
 100 
 101 out_unlock:
 102         w1_reset_bus(dev);
 103         mutex_unlock(&dev->bus_mutex);
 104 
 105         return f_retval;
 106 }
 107 
 108 static ssize_t output_show(struct device *device,
 109                            struct device_attribute *attr, char *buf)
 110 {
 111         struct w1_slave *sl = dev_to_w1_slave(device);
 112         struct w1_master *dev = sl->master;
 113 
 114         int ret;
 115         ssize_t f_retval;
 116 
 117         ret = mutex_lock_interruptible(&dev->bus_mutex);
 118         if (ret)
 119                 return ret;
 120 
 121         ret = w1_ds2405_read_pio(sl);
 122         if (ret < 0) {
 123                 f_retval = ret;
 124                 goto out_unlock;
 125         }
 126 
 127         *buf = ret ? '1' : '0';
 128         f_retval = 1;
 129 
 130 out_unlock:
 131         w1_reset_bus(dev);
 132         mutex_unlock(&dev->bus_mutex);
 133 
 134         return f_retval;
 135 }
 136 
 137 static ssize_t output_store(struct device *device,
 138                             struct device_attribute *attr,
 139                             const char *buf, size_t count)
 140 {
 141         struct w1_slave *sl = dev_to_w1_slave(device);
 142         struct w1_master *dev = sl->master;
 143 
 144         int ret, current_pio;
 145         unsigned int val;
 146         ssize_t f_retval;
 147 
 148         if (count < 1)
 149                 return -EINVAL;
 150 
 151         if (sscanf(buf, " %u%n", &val, &ret) < 1)
 152                 return -EINVAL;
 153 
 154         if (val != 0 && val != 1)
 155                 return -EINVAL;
 156 
 157         f_retval = ret;
 158 
 159         ret = mutex_lock_interruptible(&dev->bus_mutex);
 160         if (ret)
 161                 return ret;
 162 
 163         current_pio = w1_ds2405_read_pio(sl);
 164         if (current_pio < 0) {
 165                 f_retval = current_pio;
 166                 goto out_unlock;
 167         }
 168 
 169         if (current_pio == val)
 170                 goto out_unlock;
 171 
 172         if (w1_reset_bus(dev) != 0) {
 173                 f_retval = -ENODEV;
 174                 goto out_unlock;
 175         }
 176 
 177         /*
 178          * can't use w1_reset_select_slave() here since it uses Skip ROM if
 179          * there is only one device on bus
 180          */
 181         do {
 182                 u64 dev_addr = le64_to_cpu(*(u64 *)&sl->reg_num);
 183                 u8 cmd[9];
 184 
 185                 cmd[0] = W1_MATCH_ROM;
 186                 memcpy(&cmd[1], &dev_addr, sizeof(dev_addr));
 187 
 188                 w1_write_block(dev, cmd, sizeof(cmd));
 189         } while (0);
 190 
 191 out_unlock:
 192         w1_reset_bus(dev);
 193         mutex_unlock(&dev->bus_mutex);
 194 
 195         return f_retval;
 196 }
 197 
 198 static DEVICE_ATTR_RO(state);
 199 static DEVICE_ATTR_RW(output);
 200 
 201 static struct attribute *w1_ds2405_attrs[] = {
 202         &dev_attr_state.attr,
 203         &dev_attr_output.attr,
 204         NULL
 205 };
 206 
 207 ATTRIBUTE_GROUPS(w1_ds2405);
 208 
 209 static struct w1_family_ops w1_ds2405_fops = {
 210         .groups = w1_ds2405_groups
 211 };
 212 
 213 static struct w1_family w1_family_ds2405 = {
 214         .fid = W1_FAMILY_DS2405,
 215         .fops = &w1_ds2405_fops
 216 };
 217 
 218 module_w1_family(w1_family_ds2405);

/* [<][>][^][v][top][bottom][index][help] */