[PATCH v2 2/6] lib: utils/gpio: Add generic GPIO configuration library
Atish Patra
atishp at atishpatra.org
Fri Jul 9 11:55:13 PDT 2021
On Fri, Jul 9, 2021 at 6:11 AM Anup Patel <anup.patel at wdc.com> wrote:
>
> We add generic GPIO configuration library which is independent of
> hardware description format (FDT or ACPI). The OpenSBI platform
> support or GPIO drivers can register GPIO chip instances which
> can be discovered and used by different GPIO clients. Each GPIO
> chip instance has a unique ID which can be used by GPIO clients
> to lookup GPIO chip instance.
>
> Signed-off-by: Anup Patel <anup.patel at wdc.com>
> ---
> include/sbi_utils/gpio/gpio.h | 99 +++++++++++++++++++++++++++++
> lib/utils/gpio/gpio.c | 116 ++++++++++++++++++++++++++++++++++
> lib/utils/gpio/objects.mk | 10 +++
> 3 files changed, 225 insertions(+)
> create mode 100644 include/sbi_utils/gpio/gpio.h
> create mode 100644 lib/utils/gpio/gpio.c
> create mode 100644 lib/utils/gpio/objects.mk
>
> diff --git a/include/sbi_utils/gpio/gpio.h b/include/sbi_utils/gpio/gpio.h
> new file mode 100644
> index 0000000..167d11a
> --- /dev/null
> +++ b/include/sbi_utils/gpio/gpio.h
> @@ -0,0 +1,99 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> + *
> + * Authors:
> + * Anup Patel <anup.patel at wdc.com>
> + */
> +
> +#ifndef __GPIO_H__
> +#define __GPIO_H__
> +
> +#include <sbi/sbi_types.h>
> +
> +#define GPIO_LINE_DIRECTION_IN 1
> +#define GPIO_LINE_DIRECTION_OUT 0
> +
> +/** Representation of a GPIO pin */
> +struct gpio_pin {
> + /** Pointer to the GPIO chip */
> + struct gpio_chip *chip;
> + /** Identification of GPIO pin within GPIO chip */
> + unsigned int offset;
> + /**
> + * Additional configuration flags of the GPIO pin desired
> + * by GPIO clients.
> + *
> + * NOTE: GPIO chip can have custom configuration flags.
> + */
> + unsigned int flags;
> +#define GPIO_FLAG_ACTIVE_LOW 0x1
> +#define GPIO_FLAG_SINGLE_ENDED 0x2
> +#define GPIO_FLAG_OPEN_DRAIN 0x4
> +#define GPIO_FLAG_TRANSITORY 0x8
> +#define GPIO_FLAG_PULL_UP 0x10
> +#define GPIO_FLAG_PULL_DOWN 0x20
> +};
> +
> +/** Representation of a GPIO chip */
> +struct gpio_chip {
> + /** Pointer to GPIO driver owning this GPIO chip */
> + void *driver;
> + /** Uniquie ID of the GPIO chip assigned by the driver */
> + unsigned int id;
> + /** Number of GPIOs supported by the GPIO chip */
> + unsigned int ngpio;
> + /**
> + * Get current direction of GPIO pin
> + *
> + * @return 0=output, 1=input, or negative error
> + */
> + int (*get_direction)(struct gpio_pin *gp);
> + /**
> + * Set input direction of GPIO pin
> + *
> + * @return 0 on success and negative error code on failure
> + */
> + int (*direction_input)(struct gpio_pin *gp);
> + /**
> + * Set output direction of GPIO pin with given output value
> + *
> + * @return 0 on success and negative error code on failure
> + */
> + int (*direction_output)(struct gpio_pin *gp, int value);
> + /**
> + * Get current value of GPIO pin
> + *
> + * @return 0=low, 1=high, or negative error
> + */
> + int (*get)(struct gpio_pin *gp);
> + /** Set output value for GPIO pin */
> + void (*set)(struct gpio_pin *gp, int value);
> +};
> +
Is there a reason not to add an "addr" property here ?
We don't have to define sifive_gpio_chip in that case. We can get rid
of the static allocation of sifive_gpio_chip_array as well.
> +/** Find a registered GPIO chip */
> +struct gpio_chip *gpio_chip_find(unsigned int id);
> +
> +/** Register GPIO chip */
> +int gpio_chip_add(struct gpio_chip *gc);
> +
> +/** Un-register GPIO chip */
> +void gpio_chip_remove(struct gpio_chip *gc);
> +
> +/** Get current direction of GPIO pin */
> +int gpio_get_direction(struct gpio_pin *gp);
> +
> +/** Set input direction of GPIO pin */
> +int gpio_direction_input(struct gpio_pin *gp);
> +
> +/** Set output direction of GPIO pin */
> +int gpio_direction_output(struct gpio_pin *gp, int value);
> +
> +/** Get current value of GPIO pin */
> +int gpio_get(struct gpio_pin *gp);
> +
> +/** Set output value of GPIO pin */
> +int gpio_set(struct gpio_pin *gp, int value);
> +
> +#endif
> diff --git a/lib/utils/gpio/gpio.c b/lib/utils/gpio/gpio.c
> new file mode 100644
> index 0000000..fb30c0f
> --- /dev/null
> +++ b/lib/utils/gpio/gpio.c
> @@ -0,0 +1,116 @@
> +/*
> + * SPDX-License-Identifier: BSD-2-Clause
> + *
> + * Copyright (c) 2021 Western Digital Corporation or its affiliates.
> + *
> + * Authors:
> + * Anup Patel <anup.patel at wdc.com>
> + */
> +
> +#include <sbi/sbi_error.h>
> +#include <sbi_utils/gpio/gpio.h>
> +
> +#define GPIO_CHIP_MAX 16
> +
> +static struct gpio_chip *gc_array[GPIO_CHIP_MAX];
> +
> +struct gpio_chip *gpio_chip_find(unsigned int id)
> +{
> + unsigned int i;
> + struct gpio_chip *ret = NULL;
> +
> + for (i = 0; i < GPIO_CHIP_MAX; i++) {
> + if (gc_array[i] && gc_array[i]->id == id) {
> + ret = gc_array[i];
> + break;
> + }
> + }
> +
> + return ret;
> +}
> +
> +int gpio_chip_add(struct gpio_chip *gc)
> +{
> + int i, ret = SBI_ENOSPC;
> +
> + if (!gc)
> + return SBI_EINVAL;
> + if (gpio_chip_find(gc->id))
> + return SBI_EALREADY;
> +
> + for (i = 0; i < GPIO_CHIP_MAX; i++) {
> + if (!gc_array[i]) {
> + gc_array[i] = gc;
> + ret = 0;
> + break;
> + }
> + }
> +
> + return ret;
> +}
> +
> +void gpio_chip_remove(struct gpio_chip *gc)
> +{
> + int i;
> +
> + if (!gc)
> + return;
> +
> + for (i = 0; i < GPIO_CHIP_MAX; i++) {
> + if (gc_array[i] == gc) {
> + gc_array[i] = NULL;
> + break;
> + }
> + }
> +}
> +
> +int gpio_get_direction(struct gpio_pin *gp)
> +{
> + if (!gp || !gp->chip || (gp->chip->ngpio <= gp->offset))
> + return SBI_EINVAL;
> + if (!gp->chip->get_direction)
> + return SBI_ENOSYS;
> +
> + return gp->chip->get_direction(gp);
> +}
> +
> +int gpio_direction_input(struct gpio_pin *gp)
> +{
> + if (!gp || !gp->chip || (gp->chip->ngpio <= gp->offset))
> + return SBI_EINVAL;
> + if (!gp->chip->direction_input)
> + return SBI_ENOSYS;
> +
> + return gp->chip->direction_input(gp);
> +}
> +
> +int gpio_direction_output(struct gpio_pin *gp, int value)
> +{
> + if (!gp || !gp->chip || (gp->chip->ngpio <= gp->offset))
> + return SBI_EINVAL;
> + if (!gp->chip->direction_output)
> + return SBI_ENOSYS;
> +
> + return gp->chip->direction_output(gp, value);
> +}
> +
> +int gpio_get(struct gpio_pin *gp)
> +{
> + if (!gp || !gp->chip || (gp->chip->ngpio <= gp->offset))
> + return SBI_EINVAL;
> + if (!gp->chip->get)
> + return SBI_ENOSYS;
> +
> + return gp->chip->get(gp);
> +}
> +
> +int gpio_set(struct gpio_pin *gp, int value)
> +{
> + if (!gp || !gp->chip || (gp->chip->ngpio <= gp->offset))
> + return SBI_EINVAL;
> + if (!gp->chip->set)
> + return SBI_ENOSYS;
> +
> + gp->chip->set(gp, value);
> + return 0;
> +}
> diff --git a/lib/utils/gpio/objects.mk b/lib/utils/gpio/objects.mk
> new file mode 100644
> index 0000000..e99a895
> --- /dev/null
> +++ b/lib/utils/gpio/objects.mk
> @@ -0,0 +1,10 @@
> +#
> +# SPDX-License-Identifier: BSD-2-Clause
> +#
> +# Copyright (c) 2021 Western Digital Corporation or its affiliates.
> +#
> +# Authors:
> +# Anup Patel <anup.patel at wdc.com>
> +#
> +
> +libsbiutils-objs-y += gpio/gpio.o
> --
> 2.25.1
>
>
> --
> opensbi mailing list
> opensbi at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/opensbi
--
Regards,
Atish
More information about the opensbi
mailing list