summaryrefslogtreecommitdiff
path: root/drivers/gpio/sandbox.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpio/sandbox.c')
-rw-r--r--drivers/gpio/sandbox.c138
1 files changed, 90 insertions, 48 deletions
diff --git a/drivers/gpio/sandbox.c b/drivers/gpio/sandbox.c
index dc8d506e8d..d008fdd222 100644
--- a/drivers/gpio/sandbox.c
+++ b/drivers/gpio/sandbox.c
@@ -19,42 +19,51 @@
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/gpio/sandbox-gpio.h>
-
struct gpio_state {
const char *label; /* label given by requester */
- ulong dir_flags; /* dir_flags (GPIOD_...) */
+ ulong flags; /* flags (GPIOD_...) */
};
-/* Access routines for GPIO dir flags */
-static ulong *get_gpio_dir_flags(struct udevice *dev, unsigned int offset)
+/* Access routines for GPIO info */
+static struct gpio_state *get_gpio_state(struct udevice *dev, uint offset)
{
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
struct gpio_state *state = dev_get_priv(dev);
if (offset >= uc_priv->gpio_count) {
- static ulong invalid_dir_flags;
printf("sandbox_gpio: error: invalid gpio %u\n", offset);
- return &invalid_dir_flags;
+ return NULL;
}
- return &state[offset].dir_flags;
+ return &state[offset];
+}
+
+/* Access routines for GPIO flags */
+static ulong *get_gpio_flags(struct udevice *dev, unsigned int offset)
+{
+ struct gpio_state *state = get_gpio_state(dev, offset);
+
+ if (!state)
+ return NULL;
+
+ return &state->flags;
}
static int get_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag)
{
- return (*get_gpio_dir_flags(dev, offset) & flag) != 0;
+ return (*get_gpio_flags(dev, offset) & flag) != 0;
}
static int set_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag,
int value)
{
- ulong *gpio = get_gpio_dir_flags(dev, offset);
+ struct gpio_state *state = get_gpio_state(dev, offset);
if (value)
- *gpio |= flag;
+ state->flags |= flag;
else
- *gpio &= ~flag;
+ state->flags &= ~flag;
return 0;
}
@@ -65,14 +74,31 @@ static int set_gpio_flag(struct udevice *dev, unsigned int offset, ulong flag,
int sandbox_gpio_get_value(struct udevice *dev, unsigned offset)
{
+ struct gpio_state *state = get_gpio_state(dev, offset);
+ bool val;
+
if (get_gpio_flag(dev, offset, GPIOD_IS_OUT))
debug("sandbox_gpio: get_value on output gpio %u\n", offset);
- return get_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE);
+
+ if (state->flags & GPIOD_EXT_DRIVEN) {
+ val = state->flags & GPIOD_EXT_HIGH;
+ } else {
+ if (state->flags & GPIOD_EXT_PULL_UP)
+ val = true;
+ else if (state->flags & GPIOD_EXT_PULL_DOWN)
+ val = false;
+ else
+ val = state->flags & GPIOD_PULL_UP;
+ }
+
+ return val;
}
int sandbox_gpio_set_value(struct udevice *dev, unsigned offset, int value)
{
- return set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE, value);
+ set_gpio_flag(dev, offset, GPIOD_EXT_DRIVEN | GPIOD_EXT_HIGH, value);
+
+ return 0;
}
int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
@@ -83,20 +109,23 @@ int sandbox_gpio_get_direction(struct udevice *dev, unsigned offset)
int sandbox_gpio_set_direction(struct udevice *dev, unsigned offset, int output)
{
set_gpio_flag(dev, offset, GPIOD_IS_OUT, output);
- set_gpio_flag(dev, offset, GPIOD_IS_IN, !(output));
+ set_gpio_flag(dev, offset, GPIOD_IS_IN, !output);
return 0;
}
-ulong sandbox_gpio_get_dir_flags(struct udevice *dev, unsigned int offset)
+ulong sandbox_gpio_get_flags(struct udevice *dev, uint offset)
{
- return *get_gpio_dir_flags(dev, offset);
+ ulong flags = *get_gpio_flags(dev, offset);
+
+ return flags & ~GPIOD_SANDBOX_MASK;
}
-int sandbox_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
- ulong flags)
+int sandbox_gpio_set_flags(struct udevice *dev, uint offset, ulong flags)
{
- *get_gpio_dir_flags(dev, offset) = flags;
+ struct gpio_state *state = get_gpio_state(dev, offset);
+
+ state->flags = flags;
return 0;
}
@@ -117,10 +146,19 @@ static int sb_gpio_direction_input(struct udevice *dev, unsigned offset)
static int sb_gpio_direction_output(struct udevice *dev, unsigned offset,
int value)
{
+ int ret;
+
debug("%s: offset:%u, value = %d\n", __func__, offset, value);
- return sandbox_gpio_set_direction(dev, offset, 1) |
- sandbox_gpio_set_value(dev, offset, value);
+ ret = sandbox_gpio_set_direction(dev, offset, 1);
+ if (ret)
+ return ret;
+ ret = set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE |
+ GPIOD_EXT_DRIVEN | GPIOD_EXT_HIGH, value);
+ if (ret)
+ return ret;
+
+ return 0;
}
/* read GPIO IN value of port 'offset' */
@@ -134,6 +172,8 @@ static int sb_gpio_get_value(struct udevice *dev, unsigned offset)
/* write GPIO OUT value to port 'offset' */
static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value)
{
+ int ret;
+
debug("%s: offset:%u, value = %d\n", __func__, offset, value);
if (!sandbox_gpio_get_direction(dev, offset)) {
@@ -142,7 +182,12 @@ static int sb_gpio_set_value(struct udevice *dev, unsigned offset, int value)
return -1;
}
- return sandbox_gpio_set_value(dev, offset, value);
+ ret = set_gpio_flag(dev, offset, GPIOD_IS_OUT_ACTIVE |
+ GPIOD_EXT_DRIVEN | GPIOD_EXT_HIGH, value);
+ if (ret)
+ return ret;
+
+ return 0;
}
static int sb_gpio_get_function(struct udevice *dev, unsigned offset)
@@ -177,33 +222,30 @@ static int sb_gpio_xlate(struct udevice *dev, struct gpio_desc *desc,
return 0;
}
-static int sb_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
- ulong flags)
+static int sb_gpio_set_flags(struct udevice *dev, unsigned int offset,
+ ulong flags)
{
- ulong *dir_flags;
-
- debug("%s: offset:%u, dir_flags = %lx\n", __func__, offset, flags);
-
- dir_flags = get_gpio_dir_flags(dev, offset);
-
- /*
- * For testing purposes keep the output value when switching to input.
- * This allows us to manipulate the input value via the gpio command.
- */
- if (flags & GPIOD_IS_IN)
- *dir_flags = (flags & ~GPIOD_IS_OUT_ACTIVE) |
- (*dir_flags & GPIOD_IS_OUT_ACTIVE);
- else
- *dir_flags = flags;
+ debug("%s: offset:%u, flags = %lx\n", __func__, offset, flags);
+ struct gpio_state *state = get_gpio_state(dev, offset);
+
+ if (flags & GPIOD_IS_OUT) {
+ flags |= GPIOD_EXT_DRIVEN;
+ if (flags & GPIOD_IS_OUT_ACTIVE)
+ flags |= GPIOD_EXT_HIGH;
+ else
+ flags &= ~GPIOD_EXT_HIGH;
+ } else {
+ flags |= state->flags & GPIOD_SANDBOX_MASK;
+ }
+ state->flags = flags;
return 0;
}
-static int sb_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
- ulong *flags)
+static int sb_gpio_get_flags(struct udevice *dev, uint offset, ulong *flagsp)
{
debug("%s: offset:%u\n", __func__, offset);
- *flags = *get_gpio_dir_flags(dev, offset);
+ *flagsp = *get_gpio_flags(dev, offset) & ~GPIOD_SANDBOX_MASK;
return 0;
}
@@ -272,8 +314,8 @@ static const struct dm_gpio_ops gpio_sandbox_ops = {
.set_value = sb_gpio_set_value,
.get_function = sb_gpio_get_function,
.xlate = sb_gpio_xlate,
- .set_dir_flags = sb_gpio_set_dir_flags,
- .get_dir_flags = sb_gpio_get_dir_flags,
+ .set_flags = sb_gpio_set_flags,
+ .get_flags = sb_gpio_get_flags,
#if CONFIG_IS_ENABLED(ACPIGEN)
.get_acpi = sb_gpio_get_acpi,
#endif
@@ -456,7 +498,7 @@ static const char *sb_pinctrl_get_pin_name(struct udevice *dev,
return pin_name;
}
-static char *get_dir_flags_string(ulong flags)
+static char *get_flags_string(ulong flags)
{
if (flags & GPIOD_OPEN_DRAIN)
return "drive-open-drain";
@@ -475,7 +517,7 @@ static int sb_pinctrl_get_pin_muxing(struct udevice *dev,
{
struct udevice *gpio_dev;
unsigned int gpio_idx;
- ulong dir_flags;
+ ulong flags;
int function;
/* look up for the bank which owns the requested pin */
@@ -484,11 +526,11 @@ static int sb_pinctrl_get_pin_muxing(struct udevice *dev,
snprintf(buf, size, "Error");
} else {
function = sb_gpio_get_function(gpio_dev, gpio_idx);
- dir_flags = *get_gpio_dir_flags(gpio_dev, gpio_idx);
+ flags = *get_gpio_flags(gpio_dev, gpio_idx);
snprintf(buf, size, "gpio %s %s",
function == GPIOF_OUTPUT ? "output" : "input",
- get_dir_flags_string(dir_flags));
+ get_flags_string(flags));
}
return 0;