1
0
mirror of https://xff.cz/git/u-boot/ synced 2025-09-01 08:42:12 +02:00

dm: gpio: Add better functions to request GPIOs

At present U-Boot sort-of supports the standard way of reading GPIOs from
device tree nodes, but the support is incomplete, a bit clunky and only
works for GPIO bindings where #gpio-cells is 2.

Add new functions to request GPIOs, taking full account of the device
tree binding. These permit requesting a GPIO with a simple call like:

   gpio_request_by_name(dev, "cd-gpios", 0, &desc, GPIOD_IS_IN);

This will request the GPIO, looking at the device's node which might be
this, for example:

   cd-gpios = <&gpio TEGRA_GPIO(B, 3) GPIO_ACTIVE_LOW>;

The GPIO will be set to input mode in this case and polarity will be
honoured by the GPIO calls.

It is also possible to request and free a list of GPIOs.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass
2015-01-05 20:05:29 -07:00
parent 0dac4d51f5
commit 3669e0e759
5 changed files with 461 additions and 4 deletions

View File

@@ -12,6 +12,8 @@
#include <asm/gpio.h>
#include <linux/ctype.h>
DECLARE_GLOBAL_DATA_PTR;
/**
* gpio_to_device() - Convert global GPIO number to device, number
*
@@ -92,8 +94,8 @@ int gpio_lookup_name(const char *name, struct udevice **devp,
return 0;
}
int gpio_find_and_xlate(struct gpio_desc *desc,
struct fdtdec_phandle_args *args)
static int gpio_find_and_xlate(struct gpio_desc *desc,
struct fdtdec_phandle_args *args)
{
struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
@@ -132,6 +134,17 @@ static int dm_gpio_request(struct gpio_desc *desc, const char *label)
return 0;
}
static int dm_gpio_requestf(struct gpio_desc *desc, const char *fmt, ...)
{
va_list args;
char buf[40];
va_start(args, fmt);
vscnprintf(buf, sizeof(buf), fmt, args);
va_end(args);
return dm_gpio_request(desc, buf);
}
/**
* gpio_request() - [COMPAT] Request GPIO
* gpio: GPIO number
@@ -501,6 +514,155 @@ unsigned gpio_get_values_as_int(const int *gpio_num_array)
return vector;
}
static int _gpio_request_by_name_nodev(const void *blob, int node,
const char *list_name, int index,
struct gpio_desc *desc, int flags,
bool add_index)
{
struct fdtdec_phandle_args args;
int ret;
desc->dev = NULL;
desc->offset = 0;
ret = fdtdec_parse_phandle_with_args(blob, node, list_name,
"#gpio-cells", 0, index, &args);
if (ret) {
debug("%s: fdtdec_parse_phandle_with_args failed\n", __func__);
goto err;
}
ret = uclass_get_device_by_of_offset(UCLASS_GPIO, args.node,
&desc->dev);
if (ret) {
debug("%s: uclass_get_device_by_of_offset failed\n", __func__);
goto err;
}
ret = gpio_find_and_xlate(desc, &args);
if (ret) {
debug("%s: gpio_find_and_xlate failed\n", __func__);
goto err;
}
ret = dm_gpio_requestf(desc, add_index ? "%s.%s%d" : "%s.%s",
fdt_get_name(blob, node, NULL),
list_name, index);
if (ret) {
debug("%s: dm_gpio_requestf failed\n", __func__);
goto err;
}
ret = dm_gpio_set_dir_flags(desc, flags | desc->flags);
if (ret) {
debug("%s: dm_gpio_set_dir failed\n", __func__);
goto err;
}
return 0;
err:
debug("%s: Node '%s', property '%s', failed to request GPIO index %d: %d\n",
__func__, fdt_get_name(blob, node, NULL), list_name, index, ret);
return ret;
}
int gpio_request_by_name_nodev(const void *blob, int node,
const char *list_name, int index,
struct gpio_desc *desc, int flags)
{
return _gpio_request_by_name_nodev(blob, node, list_name, index, desc,
flags, index > 0);
}
int gpio_request_by_name(struct udevice *dev, const char *list_name, int index,
struct gpio_desc *desc, int flags)
{
/*
* This isn't ideal since we don't use dev->name in the debug()
* calls in gpio_request_by_name(), but we can do this until
* gpio_request_by_name_nodev() can be dropped.
*/
return gpio_request_by_name_nodev(gd->fdt_blob, dev->of_offset,
list_name, index, desc, flags);
}
int gpio_request_list_by_name_nodev(const void *blob, int node,
const char *list_name,
struct gpio_desc *desc, int max_count,
int flags)
{
int count;
int ret;
for (count = 0; ; count++) {
if (count >= max_count) {
ret = -ENOSPC;
goto err;
}
ret = _gpio_request_by_name_nodev(blob, node, list_name, count,
&desc[count], flags, true);
if (ret == -ENOENT)
break;
else if (ret)
goto err;
}
/* We ran out of GPIOs in the list */
return count;
err:
gpio_free_list_nodev(desc, count - 1);
return ret;
}
int gpio_request_list_by_name(struct udevice *dev, const char *list_name,
struct gpio_desc *desc, int max_count,
int flags)
{
/*
* This isn't ideal since we don't use dev->name in the debug()
* calls in gpio_request_by_name(), but we can do this until
* gpio_request_list_by_name_nodev() can be dropped.
*/
return gpio_request_list_by_name_nodev(gd->fdt_blob, dev->of_offset,
list_name, desc, max_count,
flags);
}
int gpio_get_list_count(struct udevice *dev, const char *list_name)
{
int ret;
ret = fdtdec_parse_phandle_with_args(gd->fdt_blob, dev->of_offset,
list_name, "#gpio-cells", 0, -1,
NULL);
if (ret) {
debug("%s: Node '%s', property '%s', GPIO count failed: %d\n",
__func__, dev->name, list_name, ret);
}
return ret;
}
int dm_gpio_free(struct udevice *dev, struct gpio_desc *desc)
{
/* For now, we don't do any checking of dev */
return _dm_gpio_free(desc->dev, desc->offset);
}
int gpio_free_list(struct udevice *dev, struct gpio_desc *desc, int count)
{
int i;
/* For now, we don't do any checking of dev */
for (i = 0; i < count; i++)
dm_gpio_free(dev, &desc[i]);
return 0;
}
int gpio_free_list_nodev(struct gpio_desc *desc, int count)
{
return gpio_free_list(NULL, desc, count);
}
/* We need to renumber the GPIOs when any driver is probed/removed */
static int gpio_renumber(struct udevice *removed_dev)
{