On Thu, Nov 10, 2016 at 02:35:46PM +0100, Michal Simek wrote: > On 8.11.2016 11:19, Maxime Ripard wrote: > > 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), > > +}; > > > > Has someone test this on different HW?
I didn't, but it looks pretty generic. The only thing you have to make sure is that you can respect the rather tight timing constraints of the bus. That rules out a GPIO on an I2C expander for example. > As I went through the series will be good to have cmd/w1.c to be > able to test that devices. Ack. Maxime -- Maxime Ripard, Free Electrons Embedded Linux and Kernel engineering http://free-electrons.com
signature.asc
Description: PGP signature
_______________________________________________ U-Boot mailing list U-Boot@lists.denx.de http://lists.denx.de/mailman/listinfo/u-boot