Add a bus driver for bitbanging a 1-Wire bus over a GPIO.

Signed-off-by: Maxime Ripard <maxime.rip...@free-electrons.com>
---
 drivers/w1/Kconfig   |   6 ++-
 drivers/w1/Makefile  |   1 +-
 drivers/w1/w1-gpio.c | 160 ++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 167 insertions(+), 0 deletions(-)
 create mode 100644 drivers/w1/w1-gpio.c

diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig
index 0c056b4c06a9..ccc3ae15db86 100644
--- a/drivers/w1/Kconfig
+++ b/drivers/w1/Kconfig
@@ -12,6 +12,12 @@ config W1
 
 if W1
 
+config W1_GPIO
+       bool "Enable 1-Wire GPIO bitbanging"
+       depends on DM_GPIO
+       help
+         Emulate a 1-Wire bus using a GPIO.
+
 endif
 
 endmenu
diff --git a/drivers/w1/Makefile b/drivers/w1/Makefile
index 26820fa209e1..7fd8697f8419 100644
--- a/drivers/w1/Makefile
+++ b/drivers/w1/Makefile
@@ -1,2 +1,3 @@
 obj-$(CONFIG_W1) += w1-uclass.o
 
+obj-$(CONFIG_W1_GPIO) += w1-gpio.o
diff --git a/drivers/w1/w1-gpio.c b/drivers/w1/w1-gpio.c
new file mode 100644
index 000000000000..091849162533
--- /dev/null
+++ b/drivers/w1/w1-gpio.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2015 Free Electrons
+ * Copyright (c) 2015 NextThing Co
+ *
+ * Maxime Ripard <maxime.rip...@free-electrons.com>
+ *
+ * SPDX-License-Identifier:    GPL-2.0+
+ */
+
+#include <common.h>
+#include <dm.h>
+#include <w1.h>
+
+#include <asm/gpio.h>
+
+
+#define W1_TIMING_A    6
+#define W1_TIMING_B    64
+#define W1_TIMING_C    60
+#define W1_TIMING_D    10
+#define W1_TIMING_E    9
+#define W1_TIMING_F    55
+#define W1_TIMING_G    0
+#define W1_TIMING_H    480
+#define W1_TIMING_I    70
+#define W1_TIMING_J    410
+
+struct w1_gpio_pdata {
+       struct gpio_desc        gpio;
+       u64                     search_id;
+};
+
+static bool w1_gpio_read_bit(struct udevice *dev)
+{
+       struct w1_gpio_pdata *pdata = dev_get_platdata(dev);
+       int val;
+
+       dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_OUT);
+       udelay(W1_TIMING_A);
+
+       dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_IN);
+       udelay(W1_TIMING_E);
+
+       val = dm_gpio_get_value(&pdata->gpio);
+       udelay(W1_TIMING_F);
+
+       return val;
+}
+
+static u8 w1_gpio_read_byte(struct udevice *dev)
+{
+       int i;
+       u8 ret = 0;
+
+       for (i = 0; i < 8; ++i)
+               ret |= (w1_gpio_read_bit(dev) ? 1 : 0) << i;
+
+       return ret;
+}
+
+static void w1_gpio_write_bit(struct udevice *dev, bool bit)
+{
+       struct w1_gpio_pdata *pdata = dev_get_platdata(dev);
+
+       dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_OUT);
+
+       bit ? udelay(W1_TIMING_A) : udelay(W1_TIMING_C);
+
+       dm_gpio_set_value(&pdata->gpio, 1);
+
+       bit ? udelay(W1_TIMING_B) : udelay(W1_TIMING_D);
+}
+
+static void w1_gpio_write_byte(struct udevice *dev, u8 byte)
+{
+       int i;
+
+       for (i = 0; i < 8; ++i)
+               w1_gpio_write_bit(dev, (byte >> i) & 0x1);
+}
+
+static bool w1_gpio_reset(struct udevice *dev)
+{
+       struct w1_gpio_pdata *pdata = dev_get_platdata(dev);
+       int val;
+
+       dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE);
+       udelay(W1_TIMING_G);
+
+       dm_gpio_set_value(&pdata->gpio, 0);
+       udelay(W1_TIMING_H);
+
+       dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_IN);
+       udelay(W1_TIMING_I);
+
+       val = dm_gpio_get_value(&pdata->gpio);
+       udelay(W1_TIMING_J);
+
+       return val;
+}
+
+static u8 w1_gpio_triplet(struct udevice *dev, bool bdir)
+{
+       u8 id_bit   = w1_gpio_read_bit(dev);
+       u8 comp_bit = w1_gpio_read_bit(dev);
+       u8 retval;
+
+       if (id_bit && comp_bit)
+               return 0x03;  /* error */
+
+       if (!id_bit && !comp_bit) {
+               /* Both bits are valid, take the direction given */
+               retval = bdir ? 0x04 : 0;
+       } else {
+               /* Only one bit is valid, take that direction */
+               bdir = id_bit;
+               retval = id_bit ? 0x05 : 0x02;
+       }
+
+       w1_gpio_write_bit(dev, bdir);
+       return retval;
+}
+
+
+static const struct w1_ops w1_gpio_ops = {
+       .read_byte      = w1_gpio_read_byte,
+       .reset          = w1_gpio_reset,
+       .triplet        = w1_gpio_triplet,
+       .write_byte     = w1_gpio_write_byte,
+};
+
+static int w1_gpio_ofdata_to_platdata(struct udevice *dev)
+{
+       struct w1_gpio_pdata *pdata = dev_get_platdata(dev);
+       int ret;
+
+       ret = gpio_request_by_name(dev, "gpios", 0, &pdata->gpio, 0);
+       if (ret < 0)
+               goto error;
+
+       return 0;
+
+error:
+       printf("Error claiming GPIO %d\n", ret);
+       return ret;
+};
+
+static const struct udevice_id w1_gpio_id[] = {
+       { "w1-gpio", 0 },
+       { },
+};
+
+U_BOOT_DRIVER(w1_gpio_drv) = {
+       .id                             = UCLASS_W1,
+       .name                           = "w1_gpio_drv",
+       .of_match                       = w1_gpio_id,
+       .ofdata_to_platdata             = w1_gpio_ofdata_to_platdata,
+       .ops                            = &w1_gpio_ops,
+       .platdata_auto_alloc_size       = sizeof(struct w1_gpio_pdata),
+};
-- 
git-series 0.8.11
_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to