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:
@@ -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)
|
||||
{
|
||||
|
Reference in New Issue
Block a user