Add a bus driver for bitbanging a 1-Wire bus over a GPIO. Signed-off-by: Maxime Ripard <maxime.ripard@bootlin.com> [eugen.hristev@microchip.com: fixed some issues] Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>lime2-spi
parent
d3e19cf919
commit
73aea285e3
@ -1 +1,3 @@ |
|||||||
obj-$(CONFIG_W1) += w1-uclass.o
|
obj-$(CONFIG_W1) += w1-uclass.o
|
||||||
|
|
||||||
|
obj-$(CONFIG_W1_GPIO) += w1-gpio.o
|
||||||
|
@ -0,0 +1,176 @@ |
|||||||
|
/* SPDX-License-Identifier: GPL-2.0+
|
||||||
|
* |
||||||
|
* Copyright (c) 2015 Free Electrons |
||||||
|
* Copyright (c) 2015 NextThing Co |
||||||
|
* |
||||||
|
* Maxime Ripard <maxime.ripard@free-electrons.com> |
||||||
|
* |
||||||
|
*/ |
||||||
|
|
||||||
|
#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); |
||||||
|
if (val < 0) |
||||||
|
debug("error in retrieving GPIO value"); |
||||||
|
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; |
||||||
|
|
||||||
|
/* initiate the reset pulse. first we must pull the bus to low */ |
||||||
|
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); |
||||||
|
/* wait for the specified time with the bus kept low */ |
||||||
|
udelay(W1_TIMING_H); |
||||||
|
|
||||||
|
/* now we must read the presence pulse */ |
||||||
|
dm_gpio_set_dir_flags(&pdata->gpio, GPIOD_IS_IN); |
||||||
|
udelay(W1_TIMING_I); |
||||||
|
|
||||||
|
val = dm_gpio_get_value(&pdata->gpio); |
||||||
|
if (val < 0) |
||||||
|
debug("error in retrieving GPIO value"); |
||||||
|
|
||||||
|
/* if nobody pulled the bus down , it means nobody is on the bus */ |
||||||
|
if (val != 0) |
||||||
|
return 1; |
||||||
|
/* we have the bus pulled down, let's wait for the specified presence time */ |
||||||
|
udelay(W1_TIMING_J); |
||||||
|
|
||||||
|
/* read again, the other end should leave the bus free */ |
||||||
|
val = dm_gpio_get_value(&pdata->gpio); |
||||||
|
if (val < 0) |
||||||
|
debug("error in retrieving GPIO value"); |
||||||
|
|
||||||
|
/* bus is not going up again, so we have an error */ |
||||||
|
if (val != 1) |
||||||
|
return 1; |
||||||
|
|
||||||
|
/* all good, presence detected */ |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
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) |
||||||
|
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), |
||||||
|
}; |
Loading…
Reference in new issue