uboot/drivers/w1/w1-gpio.c
<<
>>
Prefs
   1/* SPDX-License-Identifier:     GPL-2.0+
   2 *
   3 * Copyright (c) 2015 Free Electrons
   4 * Copyright (c) 2015 NextThing Co
   5 *
   6 * Maxime Ripard <maxime.ripard@free-electrons.com>
   7 *
   8 */
   9
  10#include <common.h>
  11#include <dm.h>
  12#include <log.h>
  13#include <w1.h>
  14#include <linux/delay.h>
  15
  16#include <asm/gpio.h>
  17
  18#define W1_TIMING_A     6
  19#define W1_TIMING_B     64
  20#define W1_TIMING_C     60
  21#define W1_TIMING_D     10
  22#define W1_TIMING_E     9
  23#define W1_TIMING_F     55
  24#define W1_TIMING_G     0
  25#define W1_TIMING_H     480
  26#define W1_TIMING_I     70
  27#define W1_TIMING_J     410
  28
  29struct w1_gpio_pdata {
  30        struct gpio_desc        gpio;
  31        u64                     search_id;
  32};
  33
  34static bool w1_gpio_read_bit(struct udevice *dev)
  35{
  36        struct w1_gpio_pdata *pdata = dev_get_platdata(dev);
  37        int val;
  38
  39        dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_OUT);
  40        udelay(W1_TIMING_A);
  41
  42        dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_IN);
  43        udelay(W1_TIMING_E);
  44
  45        val = dm_gpio_get_value(&pdata->gpio);
  46        if (val < 0)
  47                debug("error in retrieving GPIO value");
  48        udelay(W1_TIMING_F);
  49
  50        return val;
  51}
  52
  53static u8 w1_gpio_read_byte(struct udevice *dev)
  54{
  55        int i;
  56        u8 ret = 0;
  57
  58        for (i = 0; i < 8; ++i)
  59                ret |= (w1_gpio_read_bit(dev) ? 1 : 0) << i;
  60
  61        return ret;
  62}
  63
  64static void w1_gpio_write_bit(struct udevice *dev, bool bit)
  65{
  66        struct w1_gpio_pdata *pdata = dev_get_platdata(dev);
  67
  68        dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_OUT);
  69
  70        bit ? udelay(W1_TIMING_A) : udelay(W1_TIMING_C);
  71
  72        dm_gpio_set_value(&pdata->gpio, 1);
  73
  74        bit ? udelay(W1_TIMING_B) : udelay(W1_TIMING_D);
  75}
  76
  77static void w1_gpio_write_byte(struct udevice *dev, u8 byte)
  78{
  79        int i;
  80
  81        for (i = 0; i < 8; ++i)
  82                w1_gpio_write_bit(dev, (byte >> i) & 0x1);
  83}
  84
  85static bool w1_gpio_reset(struct udevice *dev)
  86{
  87        struct w1_gpio_pdata *pdata = dev_get_platdata(dev);
  88        int val;
  89
  90        /* initiate the reset pulse. first we must pull the bus to low */
  91        dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
  92        udelay(W1_TIMING_G);
  93
  94        dm_gpio_set_value(&pdata->gpio, 0);
  95        /* wait for the specified time with the bus kept low */
  96        udelay(W1_TIMING_H);
  97
  98        /* now we must read the presence pulse */
  99        dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_IN);
 100        udelay(W1_TIMING_I);
 101
 102        val = dm_gpio_get_value(&pdata->gpio);
 103        if (val < 0)
 104                debug("error in retrieving GPIO value");
 105
 106        /* if nobody pulled the bus down , it means nobody is on the bus */
 107        if (val != 0)
 108                return 1;
 109        /* we have the bus pulled down, let's wait for the specified presence time */
 110        udelay(W1_TIMING_J);
 111
 112        /* read again, the other end should leave the bus free */
 113        val = dm_gpio_get_value(&pdata->gpio);
 114        if (val < 0)
 115                debug("error in retrieving GPIO value");
 116
 117        /* bus is not going up again, so we have an error */
 118        if (val != 1)
 119                return 1;
 120
 121        /* all good, presence detected */
 122        return 0;
 123}
 124
 125static u8 w1_gpio_triplet(struct udevice *dev, bool bdir)
 126{
 127        u8 id_bit   = w1_gpio_read_bit(dev);
 128        u8 comp_bit = w1_gpio_read_bit(dev);
 129        u8 retval;
 130
 131        if (id_bit && comp_bit)
 132                return 0x03;  /* error */
 133
 134        if (!id_bit && !comp_bit) {
 135                /* Both bits are valid, take the direction given */
 136                retval = bdir ? 0x04 : 0;
 137        } else {
 138                /* Only one bit is valid, take that direction */
 139                bdir = id_bit;
 140                retval = id_bit ? 0x05 : 0x02;
 141        }
 142
 143        w1_gpio_write_bit(dev, bdir);
 144        return retval;
 145}
 146
 147static const struct w1_ops w1_gpio_ops = {
 148        .read_byte      = w1_gpio_read_byte,
 149        .reset          = w1_gpio_reset,
 150        .triplet        = w1_gpio_triplet,
 151        .write_byte     = w1_gpio_write_byte,
 152};
 153
 154static int w1_gpio_ofdata_to_platdata(struct udevice *dev)
 155{
 156        struct w1_gpio_pdata *pdata = dev_get_platdata(dev);
 157        int ret;
 158
 159        ret = gpio_request_by_name(dev, "gpios", 0, &pdata->gpio, 0);
 160        if (ret < 0)
 161                printf("Error claiming GPIO %d\n", ret);
 162
 163        return ret;
 164};
 165
 166static const struct udevice_id w1_gpio_id[] = {
 167        { "w1-gpio", 0 },
 168        { },
 169};
 170
 171U_BOOT_DRIVER(w1_gpio_drv) = {
 172        .id                             = UCLASS_W1,
 173        .name                           = "w1_gpio_drv",
 174        .of_match                       = w1_gpio_id,
 175        .ofdata_to_platdata             = w1_gpio_ofdata_to_platdata,
 176        .ops                            = &w1_gpio_ops,
 177        .platdata_auto_alloc_size       = sizeof(struct w1_gpio_pdata),
 178};
 179