uboot/drivers/w1/w1-uclass.c
<<
>>
Prefs
   1// SPDX-License-Identifier:     GPL-2.0+
   2/*
   3 *
   4 * Copyright (c) 2015 Free Electrons
   5 * Copyright (c) 2015 NextThing Co.
   6 * Copyright (c) 2018 Microchip Technology, Inc.
   7 *
   8 * Maxime Ripard <maxime.ripard@free-electrons.com>
   9 * Eugen Hristev <eugen.hristev@microchip.com>
  10 *
  11 */
  12
  13#include <common.h>
  14#include <dm.h>
  15#include <w1.h>
  16#include <w1-eeprom.h>
  17
  18#include <dm/device-internal.h>
  19
  20#define W1_MATCH_ROM    0x55
  21#define W1_SKIP_ROM     0xcc
  22#define W1_SEARCH       0xf0
  23
  24struct w1_bus {
  25        u64     search_id;
  26};
  27
  28static int w1_enumerate(struct udevice *bus)
  29{
  30        const struct w1_ops *ops = device_get_ops(bus);
  31        struct w1_bus *w1 = dev_get_uclass_priv(bus);
  32        u64 last_rn, rn = w1->search_id, tmp64;
  33        bool last_device = false;
  34        int search_bit, desc_bit = 64;
  35        int last_zero = -1;
  36        u8 triplet_ret = 0;
  37        int i;
  38
  39        if (!ops->reset || !ops->write_byte || !ops->triplet)
  40                return -ENOSYS;
  41
  42        while (!last_device) {
  43                last_rn = rn;
  44                rn = 0;
  45
  46                /*
  47                 * Reset bus and all 1-wire device state machines
  48                 * so they can respond to our requests.
  49                 *
  50                 * Return 0 - device(s) present, 1 - no devices present.
  51                 */
  52                if (ops->reset(bus)) {
  53                        debug("%s: No devices present on the wire.\n",
  54                              __func__);
  55                        break;
  56                }
  57
  58                /* Start the search */
  59                ops->write_byte(bus, W1_SEARCH);
  60                for (i = 0; i < 64; ++i) {
  61                        /* Determine the direction/search bit */
  62                        if (i == desc_bit)
  63                                /* took the 0 path last time, so take the 1 path */
  64                                search_bit = 1;
  65                        else if (i > desc_bit)
  66                                /* take the 0 path on the next branch */
  67                                search_bit = 0;
  68                        else
  69                                search_bit = ((last_rn >> i) & 0x1);
  70
  71                        /* Read two bits and write one bit */
  72                        triplet_ret = ops->triplet(bus, search_bit);
  73
  74                        /* quit if no device responded */
  75                        if ((triplet_ret & 0x03) == 0x03)
  76                                break;
  77
  78                        /* If both directions were valid, and we took the 0 path... */
  79                        if (triplet_ret == 0)
  80                                last_zero = i;
  81
  82                        /* extract the direction taken & update the device number */
  83                        tmp64 = (triplet_ret >> 2);
  84                        rn |= (tmp64 << i);
  85                }
  86
  87                if ((triplet_ret & 0x03) != 0x03) {
  88                        if (desc_bit == last_zero || last_zero < 0) {
  89                                last_device = 1;
  90                                w1->search_id = 0;
  91                        } else {
  92                                w1->search_id = rn;
  93                        }
  94                        desc_bit = last_zero;
  95
  96                        debug("%s: Detected new device 0x%llx (family 0x%x)\n",
  97                              bus->name, rn, (u8)(rn & 0xff));
  98
  99                        /* attempt to register as w1-eeprom device */
 100                        w1_eeprom_register_new_device(rn);
 101                }
 102        }
 103
 104        return 0;
 105}
 106
 107int w1_get_bus(int busnum, struct udevice **busp)
 108{
 109        int ret, i = 0;
 110
 111        struct udevice *dev;
 112
 113        for (ret = uclass_first_device(UCLASS_W1, &dev);
 114             dev && !ret;
 115             ret = uclass_next_device(&dev), i++) {
 116                if (i == busnum) {
 117                        *busp = dev;
 118                        return 0;
 119                }
 120        }
 121
 122        if (!ret) {
 123                debug("Cannot find w1 bus %d\n", busnum);
 124                ret = -ENODEV;
 125        }
 126
 127        return ret;
 128}
 129
 130u8 w1_get_device_family(struct udevice *dev)
 131{
 132        struct w1_device *w1 = dev_get_parent_platdata(dev);
 133
 134        return w1->id & 0xff;
 135}
 136
 137int w1_reset_select(struct udevice *dev)
 138{
 139        struct w1_device *w1 = dev_get_parent_platdata(dev);
 140        struct udevice *bus = dev_get_parent(dev);
 141        const struct w1_ops *ops = device_get_ops(bus);
 142        int i;
 143
 144        if (!ops->reset || !ops->write_byte)
 145                return -ENOSYS;
 146
 147        ops->reset(bus);
 148
 149        ops->write_byte(bus, W1_MATCH_ROM);
 150
 151        for (i = 0; i < sizeof(w1->id); i++)
 152                ops->write_byte(bus, (w1->id >> (i * 8)) & 0xff);
 153
 154        return 0;
 155}
 156
 157int w1_read_byte(struct udevice *dev)
 158{
 159        struct udevice *bus = dev_get_parent(dev);
 160        const struct w1_ops *ops = device_get_ops(bus);
 161
 162        if (!ops->read_byte)
 163                return -ENOSYS;
 164
 165        return ops->read_byte(bus);
 166}
 167
 168int w1_read_buf(struct udevice *dev, u8 *buf, unsigned int count)
 169{
 170        int i, ret;
 171
 172        for (i = 0; i < count; i++) {
 173                ret = w1_read_byte(dev);
 174                if (ret < 0)
 175                        return ret;
 176
 177                buf[i] = ret & 0xff;
 178        }
 179
 180        return 0;
 181}
 182
 183int w1_write_byte(struct udevice *dev, u8 byte)
 184{
 185        struct udevice *bus = dev_get_parent(dev);
 186        const struct w1_ops *ops = device_get_ops(bus);
 187
 188        if (!ops->write_byte)
 189                return -ENOSYS;
 190
 191        ops->write_byte(bus, byte);
 192
 193        return 0;
 194}
 195
 196static int w1_post_probe(struct udevice *bus)
 197{
 198        w1_enumerate(bus);
 199
 200        return 0;
 201}
 202
 203int w1_init(void)
 204{
 205        struct udevice *bus;
 206        struct uclass *uc;
 207        int ret;
 208
 209        ret = uclass_get(UCLASS_W1, &uc);
 210        if (ret)
 211                return ret;
 212
 213        uclass_foreach_dev(bus, uc) {
 214                ret = device_probe(bus);
 215                if (ret == -ENODEV) {   /* No such device. */
 216                        printf("W1 controller not available.\n");
 217                        continue;
 218                }
 219
 220                if (ret) {              /* Other error. */
 221                        printf("W1 controller probe failed.\n");
 222                        continue;
 223                }
 224        }
 225        return 0;
 226}
 227
 228UCLASS_DRIVER(w1) = {
 229        .name           = "w1",
 230        .id             = UCLASS_W1,
 231        .flags          = DM_UC_FLAG_SEQ_ALIAS,
 232        .per_device_auto_alloc_size     = sizeof(struct w1_bus),
 233        .post_probe     = w1_post_probe,
 234#if CONFIG_IS_ENABLED(OF_CONTROL)
 235        .post_bind      = dm_scan_fdt_dev,
 236#endif
 237        .per_child_platdata_auto_alloc_size     = sizeof(struct w1_device),
 238};
 239