mirror of
https://github.com/u-boot/u-boot.git
synced 2024-12-19 01:33:27 +08:00
Merge branch '2021-03-03-gpio-improvements' into next
- GPIO uclass improvements
This commit is contained in:
commit
19a33a7b56
@ -23,6 +23,15 @@
|
||||
*/
|
||||
#include <asm-generic/gpio.h>
|
||||
|
||||
/* Our own private GPIO flags, which musn't conflict with GPIOD_... */
|
||||
#define GPIOD_EXT_HIGH BIT(31) /* external source is high (else low) */
|
||||
#define GPIOD_EXT_DRIVEN BIT(30) /* external source is driven */
|
||||
#define GPIOD_EXT_PULL_UP BIT(29) /* GPIO has external pull-up */
|
||||
#define GPIOD_EXT_PULL_DOWN BIT(28) /* GPIO has external pull-down */
|
||||
|
||||
#define GPIOD_EXT_PULL (BIT(28) | BIT(29))
|
||||
#define GPIOD_SANDBOX_MASK GENMASK(31, 28)
|
||||
|
||||
/**
|
||||
* Return the simulated value of a GPIO (used only in sandbox test code)
|
||||
*
|
||||
@ -69,17 +78,17 @@ int sandbox_gpio_set_direction(struct udevice *dev, unsigned int offset,
|
||||
* @param offset GPIO offset within bank
|
||||
* @return dir_flags: bitfield accesses by GPIOD_ defines
|
||||
*/
|
||||
ulong sandbox_gpio_get_dir_flags(struct udevice *dev, unsigned int offset);
|
||||
ulong sandbox_gpio_get_flags(struct udevice *dev, unsigned int offset);
|
||||
|
||||
/**
|
||||
* Set the simulated flags of a GPIO (used only in sandbox test code)
|
||||
*
|
||||
* @param dev device to use
|
||||
* @param offset GPIO offset within bank
|
||||
* @param flags dir_flags: bitfield accesses by GPIOD_ defines
|
||||
* @param flags bitfield accesses by GPIOD_ defines
|
||||
* @return -1 on error, 0 if ok
|
||||
*/
|
||||
int sandbox_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
|
||||
ulong flags);
|
||||
int sandbox_gpio_set_flags(struct udevice *dev, unsigned int offset,
|
||||
ulong flags);
|
||||
|
||||
#endif
|
||||
|
@ -11,6 +11,11 @@
|
||||
|
||||
/* This file is included by device trees, so avoid BIT() macros */
|
||||
|
||||
#define GPIO_DW_SIZE(x) (sizeof(u32) * (x))
|
||||
#define PAD_CFG_OFFSET(x, dw_num) ((x) + GPIO_DW_SIZE(dw_num))
|
||||
#define PAD_CFG0_OFFSET(x) PAD_CFG_OFFSET(x, 0)
|
||||
#define PAD_CFG1_OFFSET(x) PAD_CFG_OFFSET(x, 1)
|
||||
|
||||
#define PAD_CFG0_TX_STATE_BIT 0
|
||||
#define PAD_CFG0_TX_STATE (1 << PAD_CFG0_TX_STATE_BIT)
|
||||
#define PAD_CFG0_RX_STATE_BIT 1
|
||||
|
@ -3,6 +3,8 @@
|
||||
* Copyright (c) 2013 Google, Inc
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY UCLASS_GPIO
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <log.h>
|
||||
@ -21,6 +23,7 @@
|
||||
#include <dm/device_compat.h>
|
||||
#include <linux/bug.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
DECLARE_GLOBAL_DATA_PTR;
|
||||
|
||||
@ -220,7 +223,7 @@ int gpio_xlate_offs_flags(struct udevice *dev, struct gpio_desc *desc,
|
||||
static int gpio_find_and_xlate(struct gpio_desc *desc,
|
||||
struct ofnode_phandle_args *args)
|
||||
{
|
||||
struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
|
||||
const struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
|
||||
|
||||
if (ops->xlate)
|
||||
return ops->xlate(desc->dev, desc, args);
|
||||
@ -353,6 +356,7 @@ int gpio_hog_lookup_name(const char *name, struct gpio_desc **desc)
|
||||
|
||||
int dm_gpio_request(struct gpio_desc *desc, const char *label)
|
||||
{
|
||||
const struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
|
||||
struct udevice *dev = desc->dev;
|
||||
struct gpio_dev_priv *uc_priv;
|
||||
char *str;
|
||||
@ -364,8 +368,8 @@ int dm_gpio_request(struct gpio_desc *desc, const char *label)
|
||||
str = strdup(label);
|
||||
if (!str)
|
||||
return -ENOMEM;
|
||||
if (gpio_get_ops(dev)->request) {
|
||||
ret = gpio_get_ops(dev)->request(dev, desc->offset, label);
|
||||
if (ops->request) {
|
||||
ret = ops->request(dev, desc->offset, label);
|
||||
if (ret) {
|
||||
free(str);
|
||||
return ret;
|
||||
@ -442,14 +446,15 @@ int gpio_requestf(unsigned gpio, const char *fmt, ...)
|
||||
|
||||
int _dm_gpio_free(struct udevice *dev, uint offset)
|
||||
{
|
||||
const struct dm_gpio_ops *ops = gpio_get_ops(dev);
|
||||
struct gpio_dev_priv *uc_priv;
|
||||
int ret;
|
||||
|
||||
uc_priv = dev_get_uclass_priv(dev);
|
||||
if (!uc_priv->name[offset])
|
||||
return -ENXIO;
|
||||
if (gpio_get_ops(dev)->rfree) {
|
||||
ret = gpio_get_ops(dev)->rfree(dev, offset);
|
||||
if (ops->rfree) {
|
||||
ret = ops->rfree(dev, offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@ -513,13 +518,10 @@ int gpio_direction_input(unsigned gpio)
|
||||
int ret;
|
||||
|
||||
ret = gpio_to_device(gpio, &desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = check_reserved(&desc, "dir_input");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return gpio_get_ops(desc.dev)->direction_input(desc.dev, desc.offset);
|
||||
return dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, GPIOD_IS_IN);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -534,24 +536,25 @@ int gpio_direction_input(unsigned gpio)
|
||||
int gpio_direction_output(unsigned gpio, int value)
|
||||
{
|
||||
struct gpio_desc desc;
|
||||
ulong flags;
|
||||
int ret;
|
||||
|
||||
ret = gpio_to_device(gpio, &desc);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = check_reserved(&desc, "dir_output");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return gpio_get_ops(desc.dev)->direction_output(desc.dev,
|
||||
desc.offset, value);
|
||||
flags = GPIOD_IS_OUT;
|
||||
if (value)
|
||||
flags |= GPIOD_IS_OUT_ACTIVE;
|
||||
return dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, flags);
|
||||
}
|
||||
|
||||
static int _gpio_get_value(const struct gpio_desc *desc)
|
||||
{
|
||||
const struct dm_gpio_ops *ops = gpio_get_ops(desc->dev);
|
||||
int value;
|
||||
|
||||
value = gpio_get_ops(desc->dev)->get_value(desc->dev, desc->offset);
|
||||
value = ops->get_value(desc->dev, desc->offset);
|
||||
|
||||
return desc->flags & GPIOD_ACTIVE_LOW ? !value : value;
|
||||
}
|
||||
@ -569,6 +572,7 @@ int dm_gpio_get_value(const struct gpio_desc *desc)
|
||||
|
||||
int dm_gpio_set_value(const struct gpio_desc *desc, int value)
|
||||
{
|
||||
const struct dm_gpio_ops *ops;
|
||||
int ret;
|
||||
|
||||
ret = check_reserved(desc, "set_value");
|
||||
@ -578,21 +582,33 @@ int dm_gpio_set_value(const struct gpio_desc *desc, int value)
|
||||
if (desc->flags & GPIOD_ACTIVE_LOW)
|
||||
value = !value;
|
||||
|
||||
/* GPIOD_ are directly managed by driver in set_flags */
|
||||
ops = gpio_get_ops(desc->dev);
|
||||
if (ops->set_flags) {
|
||||
ulong flags = desc->flags;
|
||||
|
||||
if (value)
|
||||
flags |= GPIOD_IS_OUT_ACTIVE;
|
||||
else
|
||||
flags &= ~GPIOD_IS_OUT_ACTIVE;
|
||||
return ops->set_flags(desc->dev, desc->offset, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
* Emulate open drain by not actively driving the line high or
|
||||
* Emulate open source by not actively driving the line low
|
||||
*/
|
||||
if ((desc->flags & GPIOD_OPEN_DRAIN && value) ||
|
||||
(desc->flags & GPIOD_OPEN_SOURCE && !value))
|
||||
return gpio_get_ops(desc->dev)->direction_input(desc->dev,
|
||||
desc->offset);
|
||||
return ops->direction_input(desc->dev, desc->offset);
|
||||
else if (desc->flags & GPIOD_OPEN_DRAIN ||
|
||||
desc->flags & GPIOD_OPEN_SOURCE)
|
||||
return gpio_get_ops(desc->dev)->direction_output(desc->dev,
|
||||
desc->offset,
|
||||
value);
|
||||
return ops->direction_output(desc->dev, desc->offset, value);
|
||||
|
||||
ret = ops->set_value(desc->dev, desc->offset, value);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
gpio_get_ops(desc->dev)->set_value(desc->dev, desc->offset, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -620,10 +636,21 @@ static int check_dir_flags(ulong flags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int _dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
|
||||
/**
|
||||
* _dm_gpio_set_flags() - Send flags to the driver
|
||||
*
|
||||
* This uses the best available method to send the given flags to the driver.
|
||||
* Note that if flags & GPIOD_ACTIVE_LOW, the driver sees the opposite value
|
||||
* of GPIOD_IS_OUT_ACTIVE.
|
||||
*
|
||||
* @desc: GPIO description
|
||||
* @flags: flags value to set
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
static int _dm_gpio_set_flags(struct gpio_desc *desc, ulong flags)
|
||||
{
|
||||
struct udevice *dev = desc->dev;
|
||||
struct dm_gpio_ops *ops = gpio_get_ops(dev);
|
||||
const struct dm_gpio_ops *ops = gpio_get_ops(dev);
|
||||
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
int ret = 0;
|
||||
|
||||
@ -638,38 +665,52 @@ static int _dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* GPIOD_ are directly managed by driver in set_dir_flags*/
|
||||
if (ops->set_dir_flags) {
|
||||
ret = ops->set_dir_flags(dev, desc->offset, flags);
|
||||
/* If active low, invert the output state */
|
||||
if ((flags & (GPIOD_IS_OUT | GPIOD_ACTIVE_LOW)) ==
|
||||
(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW))
|
||||
flags ^= GPIOD_IS_OUT_ACTIVE;
|
||||
|
||||
/* GPIOD_ are directly managed by driver in set_flags */
|
||||
if (ops->set_flags) {
|
||||
ret = ops->set_flags(dev, desc->offset, flags);
|
||||
} else {
|
||||
if (flags & GPIOD_IS_OUT) {
|
||||
ret = ops->direction_output(dev, desc->offset,
|
||||
GPIOD_FLAGS_OUTPUT(flags));
|
||||
bool value = flags & GPIOD_IS_OUT_ACTIVE;
|
||||
|
||||
ret = ops->direction_output(dev, desc->offset, value);
|
||||
} else if (flags & GPIOD_IS_IN) {
|
||||
ret = ops->direction_input(dev, desc->offset);
|
||||
}
|
||||
}
|
||||
|
||||
/* save the flags also in descriptor */
|
||||
if (!ret)
|
||||
desc->flags = flags;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
|
||||
int dm_gpio_clrset_flags(struct gpio_desc *desc, ulong clr, ulong set)
|
||||
{
|
||||
ulong flags;
|
||||
int ret;
|
||||
|
||||
ret = check_reserved(desc, "set_dir_flags");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* combine the requested flags (for IN/OUT) and the descriptor flags */
|
||||
flags |= desc->flags;
|
||||
ret = _dm_gpio_set_dir_flags(desc, flags);
|
||||
flags = (desc->flags & ~clr) | set;
|
||||
|
||||
return ret;
|
||||
ret = _dm_gpio_set_flags(desc, flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* save the flags also in descriptor */
|
||||
desc->flags = flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags)
|
||||
{
|
||||
/* combine the requested flags (for IN/OUT) and the descriptor flags */
|
||||
return dm_gpio_clrset_flags(desc, GPIOD_MASK_DIR, flags);
|
||||
}
|
||||
|
||||
int dm_gpio_set_dir(struct gpio_desc *desc)
|
||||
@ -680,42 +721,57 @@ int dm_gpio_set_dir(struct gpio_desc *desc)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return _dm_gpio_set_dir_flags(desc, desc->flags);
|
||||
return _dm_gpio_set_flags(desc, desc->flags);
|
||||
}
|
||||
|
||||
int dm_gpio_get_dir_flags(struct gpio_desc *desc, ulong *flags)
|
||||
int dm_gpios_clrset_flags(struct gpio_desc *desc, int count, ulong clr,
|
||||
ulong set)
|
||||
{
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
ret = dm_gpio_clrset_flags(&desc[i], clr, set);
|
||||
if (ret)
|
||||
return log_ret(ret);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dm_gpio_get_flags(struct gpio_desc *desc, ulong *flagsp)
|
||||
{
|
||||
struct udevice *dev = desc->dev;
|
||||
int ret, value;
|
||||
struct dm_gpio_ops *ops = gpio_get_ops(dev);
|
||||
ulong dir_flags;
|
||||
const struct dm_gpio_ops *ops = gpio_get_ops(dev);
|
||||
ulong flags;
|
||||
|
||||
ret = check_reserved(desc, "get_dir_flags");
|
||||
ret = check_reserved(desc, "get_flags");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* GPIOD_ are directly provided by driver except GPIOD_ACTIVE_LOW */
|
||||
if (ops->get_dir_flags) {
|
||||
ret = ops->get_dir_flags(dev, desc->offset, &dir_flags);
|
||||
if (ops->get_flags) {
|
||||
ret = ops->get_flags(dev, desc->offset, &flags);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* GPIOD_ACTIVE_LOW is saved in desc->flags */
|
||||
value = dir_flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0;
|
||||
value = flags & GPIOD_IS_OUT_ACTIVE ? 1 : 0;
|
||||
if (desc->flags & GPIOD_ACTIVE_LOW)
|
||||
value = !value;
|
||||
dir_flags &= ~(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE);
|
||||
dir_flags |= (desc->flags & GPIOD_ACTIVE_LOW);
|
||||
flags &= ~(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE);
|
||||
flags |= (desc->flags & GPIOD_ACTIVE_LOW);
|
||||
if (value)
|
||||
dir_flags |= GPIOD_IS_OUT_ACTIVE;
|
||||
flags |= GPIOD_IS_OUT_ACTIVE;
|
||||
} else {
|
||||
dir_flags = desc->flags;
|
||||
flags = desc->flags;
|
||||
/* only GPIOD_IS_OUT_ACTIVE is provided by uclass */
|
||||
dir_flags &= ~GPIOD_IS_OUT_ACTIVE;
|
||||
flags &= ~GPIOD_IS_OUT_ACTIVE;
|
||||
if ((desc->flags & GPIOD_IS_OUT) && _gpio_get_value(desc))
|
||||
dir_flags |= GPIOD_IS_OUT_ACTIVE;
|
||||
flags |= GPIOD_IS_OUT_ACTIVE;
|
||||
}
|
||||
*flags = dir_flags;
|
||||
*flagsp = flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -785,7 +841,7 @@ static int get_function(struct udevice *dev, int offset, bool skip_unused,
|
||||
const char **namep)
|
||||
{
|
||||
struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
|
||||
struct dm_gpio_ops *ops = gpio_get_ops(dev);
|
||||
const struct dm_gpio_ops *ops = gpio_get_ops(dev);
|
||||
|
||||
BUILD_BUG_ON(GPIOF_COUNT != ARRAY_SIZE(gpio_function));
|
||||
if (!device_active(dev))
|
||||
@ -822,7 +878,7 @@ int gpio_get_raw_function(struct udevice *dev, int offset, const char **namep)
|
||||
|
||||
int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize)
|
||||
{
|
||||
struct dm_gpio_ops *ops = gpio_get_ops(dev);
|
||||
const struct dm_gpio_ops *ops = gpio_get_ops(dev);
|
||||
struct gpio_dev_priv *priv;
|
||||
char *str = buf;
|
||||
int func;
|
||||
@ -862,7 +918,7 @@ int gpio_get_status(struct udevice *dev, int offset, char *buf, int buffsize)
|
||||
#if CONFIG_IS_ENABLED(ACPIGEN)
|
||||
int gpio_get_acpi(const struct gpio_desc *desc, struct acpi_gpio *gpio)
|
||||
{
|
||||
struct dm_gpio_ops *ops;
|
||||
const struct dm_gpio_ops *ops;
|
||||
|
||||
memset(gpio, '\0', sizeof(*gpio));
|
||||
if (!dm_gpio_is_valid(desc)) {
|
||||
@ -949,6 +1005,71 @@ int dm_gpio_get_values_as_int(const struct gpio_desc *desc_list, int count)
|
||||
return vector;
|
||||
}
|
||||
|
||||
int dm_gpio_get_values_as_int_base3(struct gpio_desc *desc_list,
|
||||
int count)
|
||||
{
|
||||
static const char tristate[] = "01z";
|
||||
enum {
|
||||
PULLUP,
|
||||
PULLDOWN,
|
||||
|
||||
NUM_OPTIONS,
|
||||
};
|
||||
int vals[NUM_OPTIONS];
|
||||
uint mask;
|
||||
uint vector = 0;
|
||||
int ret, i;
|
||||
|
||||
/*
|
||||
* Limit to 19 digits which should be plenty. This avoids overflow of a
|
||||
* 32-bit int
|
||||
*/
|
||||
assert(count < 20);
|
||||
|
||||
for (i = 0; i < NUM_OPTIONS; i++) {
|
||||
uint flags = GPIOD_IS_IN;
|
||||
|
||||
flags |= (i == PULLDOWN) ? GPIOD_PULL_DOWN : GPIOD_PULL_UP;
|
||||
ret = dm_gpios_clrset_flags(desc_list, count, GPIOD_MASK_PULL,
|
||||
flags);
|
||||
if (ret)
|
||||
return log_msg_ret("pu", ret);
|
||||
|
||||
/* Give the lines time to settle */
|
||||
udelay(10);
|
||||
|
||||
ret = dm_gpio_get_values_as_int(desc_list, count);
|
||||
if (ret < 0)
|
||||
return log_msg_ret("get1", ret);
|
||||
vals[i] = ret;
|
||||
}
|
||||
|
||||
log_debug("values: %x %x, count = %d\n", vals[0], vals[1], count);
|
||||
for (i = count - 1, mask = 1 << i; i >= 0; i--, mask >>= 1) {
|
||||
uint pd = vals[PULLDOWN] & mask ? 1 : 0;
|
||||
uint pu = vals[PULLUP] & mask ? 1 : 0;
|
||||
uint digit;
|
||||
|
||||
/*
|
||||
* Get value with internal pulldown active. If this is 1 then
|
||||
* there is a stronger external pullup, which we call 1. If not
|
||||
* then call it 0.
|
||||
*
|
||||
* If the values differ then the pin is floating so we call
|
||||
* this a 2.
|
||||
*/
|
||||
if (pu == pd)
|
||||
digit = pd;
|
||||
else
|
||||
digit = 2;
|
||||
log_debug("%c ", tristate[digit]);
|
||||
vector = 3 * vector + digit;
|
||||
}
|
||||
log_debug("vector=%d\n", vector);
|
||||
|
||||
return vector;
|
||||
}
|
||||
|
||||
/**
|
||||
* gpio_request_tail: common work for requesting a gpio.
|
||||
*
|
||||
@ -1011,7 +1132,10 @@ static int gpio_request_tail(int ret, const char *nodename,
|
||||
debug("%s: dm_gpio_requestf failed\n", __func__);
|
||||
goto err;
|
||||
}
|
||||
ret = dm_gpio_set_dir_flags(desc, flags);
|
||||
|
||||
/* Keep any direction flags provided by the devicetree */
|
||||
ret = dm_gpio_set_dir_flags(desc,
|
||||
flags | (desc->flags & GPIOD_MASK_DIR));
|
||||
if (ret) {
|
||||
debug("%s: dm_gpio_set_dir failed\n", __func__);
|
||||
goto err;
|
||||
@ -1024,6 +1148,7 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if !CONFIG_IS_ENABLED(OF_PLATDATA)
|
||||
static int _gpio_request_by_name_nodev(ofnode node, const char *list_name,
|
||||
int index, struct gpio_desc *desc,
|
||||
int flags, bool add_index)
|
||||
@ -1110,6 +1235,7 @@ int gpio_get_list_count(struct udevice *dev, const char *list_name)
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* OF_PLATDATA */
|
||||
|
||||
int dm_gpio_free(struct udevice *dev, struct gpio_desc *desc)
|
||||
{
|
||||
@ -1306,10 +1432,10 @@ static int gpio_post_bind(struct udevice *dev)
|
||||
ops->get_function += gd->reloc_off;
|
||||
if (ops->xlate)
|
||||
ops->xlate += gd->reloc_off;
|
||||
if (ops->set_dir_flags)
|
||||
ops->set_dir_flags += gd->reloc_off;
|
||||
if (ops->get_dir_flags)
|
||||
ops->get_dir_flags += gd->reloc_off;
|
||||
if (ops->set_flags)
|
||||
ops->set_flags += gd->reloc_off;
|
||||
if (ops->get_flags)
|
||||
ops->get_flags += gd->reloc_off;
|
||||
|
||||
reloc_done++;
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
* Copyright 2019 Google LLC
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY UCLASS_GPIO
|
||||
|
||||
#include <common.h>
|
||||
#include <dm.h>
|
||||
#include <errno.h>
|
||||
@ -23,38 +25,6 @@
|
||||
#include <dm/acpi.h>
|
||||
#include <dt-bindings/gpio/x86-gpio.h>
|
||||
|
||||
static int intel_gpio_direction_input(struct udevice *dev, uint offset)
|
||||
{
|
||||
struct udevice *pinctrl = dev_get_parent(dev);
|
||||
uint config_offset;
|
||||
|
||||
config_offset = intel_pinctrl_get_config_reg_offset(pinctrl, offset);
|
||||
|
||||
pcr_clrsetbits32(pinctrl, config_offset,
|
||||
PAD_CFG0_MODE_MASK | PAD_CFG0_TX_STATE |
|
||||
PAD_CFG0_RX_DISABLE,
|
||||
PAD_CFG0_MODE_GPIO | PAD_CFG0_TX_DISABLE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_gpio_direction_output(struct udevice *dev, uint offset,
|
||||
int value)
|
||||
{
|
||||
struct udevice *pinctrl = dev_get_parent(dev);
|
||||
uint config_offset;
|
||||
|
||||
config_offset = intel_pinctrl_get_config_reg_offset(pinctrl, offset);
|
||||
|
||||
pcr_clrsetbits32(pinctrl, config_offset,
|
||||
PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE |
|
||||
PAD_CFG0_TX_DISABLE | PAD_CFG0_TX_STATE,
|
||||
PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE |
|
||||
(value ? PAD_CFG0_TX_STATE : 0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_gpio_get_value(struct udevice *dev, uint offset)
|
||||
{
|
||||
struct udevice *pinctrl = dev_get_parent(dev);
|
||||
@ -130,6 +100,41 @@ static int intel_gpio_xlate(struct udevice *orig_dev, struct gpio_desc *desc,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intel_gpio_set_flags(struct udevice *dev, unsigned int offset,
|
||||
ulong flags)
|
||||
{
|
||||
struct udevice *pinctrl = dev_get_parent(dev);
|
||||
u32 bic0 = 0, bic1 = 0;
|
||||
u32 or0, or1;
|
||||
uint config_offset;
|
||||
|
||||
config_offset = intel_pinctrl_get_config_reg_offset(pinctrl, offset);
|
||||
|
||||
if (flags & GPIOD_IS_OUT) {
|
||||
bic0 |= PAD_CFG0_MODE_MASK | PAD_CFG0_RX_STATE |
|
||||
PAD_CFG0_TX_DISABLE;
|
||||
or0 |= PAD_CFG0_MODE_GPIO | PAD_CFG0_RX_DISABLE;
|
||||
} else if (flags & GPIOD_IS_IN) {
|
||||
bic0 |= PAD_CFG0_MODE_MASK | PAD_CFG0_TX_STATE |
|
||||
PAD_CFG0_RX_DISABLE;
|
||||
or0 |= PAD_CFG0_MODE_GPIO | PAD_CFG0_TX_DISABLE;
|
||||
}
|
||||
if (flags & GPIOD_PULL_UP) {
|
||||
bic1 |= PAD_CFG1_PULL_MASK;
|
||||
or1 |= PAD_CFG1_PULL_UP_20K;
|
||||
} else if (flags & GPIOD_PULL_DOWN) {
|
||||
bic1 |= PAD_CFG1_PULL_MASK;
|
||||
or1 |= PAD_CFG1_PULL_DN_20K;
|
||||
}
|
||||
|
||||
pcr_clrsetbits32(pinctrl, PAD_CFG0_OFFSET(config_offset), bic0, or0);
|
||||
pcr_clrsetbits32(pinctrl, PAD_CFG1_OFFSET(config_offset), bic1, or1);
|
||||
log_debug("%s: flags=%lx, offset=%x, config_offset=%x, %x/%x %x/%x\n",
|
||||
dev->name, flags, offset, config_offset, bic0, or0, bic1, or1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if CONFIG_IS_ENABLED(ACPIGEN)
|
||||
static int intel_gpio_get_acpi(const struct gpio_desc *desc,
|
||||
struct acpi_gpio *gpio)
|
||||
@ -177,12 +182,11 @@ static int intel_gpio_of_to_plat(struct udevice *dev)
|
||||
}
|
||||
|
||||
static const struct dm_gpio_ops gpio_intel_ops = {
|
||||
.direction_input = intel_gpio_direction_input,
|
||||
.direction_output = intel_gpio_direction_output,
|
||||
.get_value = intel_gpio_get_value,
|
||||
.set_value = intel_gpio_set_value,
|
||||
.get_function = intel_gpio_get_function,
|
||||
.xlate = intel_gpio_xlate,
|
||||
.set_flags = intel_gpio_set_flags,
|
||||
#if CONFIG_IS_ENABLED(ACPIGEN)
|
||||
.get_acpi = intel_gpio_get_acpi,
|
||||
#endif
|
||||
|
@ -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, flags = %lx\n", __func__, offset, flags);
|
||||
struct gpio_state *state = get_gpio_state(dev, offset);
|
||||
|
||||
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;
|
||||
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;
|
||||
|
@ -191,8 +191,8 @@ static int stm32_gpio_get_function(struct udevice *dev, unsigned int offset)
|
||||
return GPIOF_FUNC;
|
||||
}
|
||||
|
||||
static int stm32_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
|
||||
ulong flags)
|
||||
static int stm32_gpio_set_flags(struct udevice *dev, unsigned int offset,
|
||||
ulong flags)
|
||||
{
|
||||
struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
||||
struct stm32_gpio_regs *regs = priv->regs;
|
||||
@ -203,12 +203,13 @@ static int stm32_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
|
||||
return idx;
|
||||
|
||||
if (flags & GPIOD_IS_OUT) {
|
||||
int value = GPIOD_FLAGS_OUTPUT(flags);
|
||||
bool value = flags & GPIOD_IS_OUT_ACTIVE;
|
||||
|
||||
if (flags & GPIOD_OPEN_DRAIN)
|
||||
stm32_gpio_set_otype(regs, idx, STM32_GPIO_OTYPE_OD);
|
||||
else
|
||||
stm32_gpio_set_otype(regs, idx, STM32_GPIO_OTYPE_PP);
|
||||
|
||||
stm32_gpio_set_moder(regs, idx, STM32_GPIO_MODE_OUT);
|
||||
writel(BSRR_BIT(idx, value), ®s->bsrr);
|
||||
|
||||
@ -223,8 +224,8 @@ static int stm32_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int stm32_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
|
||||
ulong *flags)
|
||||
static int stm32_gpio_get_flags(struct udevice *dev, unsigned int offset,
|
||||
ulong *flagsp)
|
||||
{
|
||||
struct stm32_gpio_priv *priv = dev_get_priv(dev);
|
||||
struct stm32_gpio_regs *regs = priv->regs;
|
||||
@ -259,7 +260,7 @@ static int stm32_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
|
||||
default:
|
||||
break;
|
||||
}
|
||||
*flags = dir_flags;
|
||||
*flagsp = dir_flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -270,8 +271,8 @@ static const struct dm_gpio_ops gpio_stm32_ops = {
|
||||
.get_value = stm32_gpio_get_value,
|
||||
.set_value = stm32_gpio_set_value,
|
||||
.get_function = stm32_gpio_get_function,
|
||||
.set_dir_flags = stm32_gpio_set_dir_flags,
|
||||
.get_dir_flags = stm32_gpio_get_dir_flags,
|
||||
.set_flags = stm32_gpio_set_flags,
|
||||
.get_flags = stm32_gpio_get_flags,
|
||||
};
|
||||
|
||||
static int gpio_stm32_probe(struct udevice *dev)
|
||||
|
@ -163,12 +163,14 @@ static int stmfx_gpio_direction_output(struct udevice *dev,
|
||||
return stmfx_write_reg(dev, STMFX_REG_GPIO_DIR, offset, 1);
|
||||
}
|
||||
|
||||
static int stmfx_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
|
||||
ulong flags)
|
||||
static int stmfx_gpio_set_flags(struct udevice *dev, unsigned int offset,
|
||||
ulong flags)
|
||||
{
|
||||
int ret = -ENOTSUPP;
|
||||
|
||||
if (flags & GPIOD_IS_OUT) {
|
||||
bool value = flags & GPIOD_IS_OUT_ACTIVE;
|
||||
|
||||
if (flags & GPIOD_OPEN_SOURCE)
|
||||
return -ENOTSUPP;
|
||||
if (flags & GPIOD_OPEN_DRAIN)
|
||||
@ -177,8 +179,7 @@ static int stmfx_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
|
||||
ret = stmfx_conf_set_type(dev, offset, 1);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = stmfx_gpio_direction_output(dev, offset,
|
||||
GPIOD_FLAGS_OUTPUT(flags));
|
||||
ret = stmfx_gpio_direction_output(dev, offset, value);
|
||||
} else if (flags & GPIOD_IS_IN) {
|
||||
ret = stmfx_gpio_direction_input(dev, offset);
|
||||
if (ret)
|
||||
@ -199,8 +200,8 @@ static int stmfx_gpio_set_dir_flags(struct udevice *dev, unsigned int offset,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stmfx_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
|
||||
ulong *flags)
|
||||
static int stmfx_gpio_get_flags(struct udevice *dev, unsigned int offset,
|
||||
ulong *flagsp)
|
||||
{
|
||||
ulong dir_flags = 0;
|
||||
int ret;
|
||||
@ -233,7 +234,7 @@ static int stmfx_gpio_get_dir_flags(struct udevice *dev, unsigned int offset,
|
||||
dir_flags |= GPIOD_PULL_DOWN;
|
||||
}
|
||||
}
|
||||
*flags = dir_flags;
|
||||
*flagsp = dir_flags;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -266,8 +267,8 @@ static const struct dm_gpio_ops stmfx_gpio_ops = {
|
||||
.get_function = stmfx_gpio_get_function,
|
||||
.direction_input = stmfx_gpio_direction_input,
|
||||
.direction_output = stmfx_gpio_direction_output,
|
||||
.set_dir_flags = stmfx_gpio_set_dir_flags,
|
||||
.get_dir_flags = stmfx_gpio_get_dir_flags,
|
||||
.set_flags = stmfx_gpio_set_flags,
|
||||
.get_flags = stmfx_gpio_get_flags,
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(stmfx_gpio) = {
|
||||
|
@ -128,6 +128,12 @@ struct gpio_desc {
|
||||
#define GPIOD_PULL_UP BIT(7) /* GPIO has pull-up enabled */
|
||||
#define GPIOD_PULL_DOWN BIT(8) /* GPIO has pull-down enabled */
|
||||
|
||||
/* Flags for updating the above */
|
||||
#define GPIOD_MASK_DIR (GPIOD_IS_OUT | GPIOD_IS_IN | \
|
||||
GPIOD_IS_OUT_ACTIVE)
|
||||
#define GPIOD_MASK_DSTYPE (GPIOD_OPEN_DRAIN | GPIOD_OPEN_SOURCE)
|
||||
#define GPIOD_MASK_PULL (GPIOD_PULL_UP | GPIOD_PULL_DOWN)
|
||||
|
||||
uint offset; /* GPIO offset within the device */
|
||||
/*
|
||||
* We could consider adding the GPIO label in here. Possibly we could
|
||||
@ -135,12 +141,6 @@ struct gpio_desc {
|
||||
*/
|
||||
};
|
||||
|
||||
/* helper to compute the value of the gpio output */
|
||||
#define GPIOD_FLAGS_OUTPUT_MASK (GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE)
|
||||
#define GPIOD_FLAGS_OUTPUT(flags) \
|
||||
(((((flags) & GPIOD_FLAGS_OUTPUT_MASK) == GPIOD_IS_OUT_ACTIVE) || \
|
||||
(((flags) & GPIOD_FLAGS_OUTPUT_MASK) == GPIOD_ACTIVE_LOW)))
|
||||
|
||||
/**
|
||||
* dm_gpio_is_valid() - Check if a GPIO is valid
|
||||
*
|
||||
@ -260,10 +260,32 @@ int gpio_xlate_offs_flags(struct udevice *dev, struct gpio_desc *desc,
|
||||
struct dm_gpio_ops {
|
||||
int (*request)(struct udevice *dev, unsigned offset, const char *label);
|
||||
int (*rfree)(struct udevice *dev, unsigned int offset);
|
||||
|
||||
/**
|
||||
* direction_input() - deprecated
|
||||
*
|
||||
* Equivalent to set_flags(...GPIOD_IS_IN)
|
||||
*/
|
||||
int (*direction_input)(struct udevice *dev, unsigned offset);
|
||||
|
||||
/**
|
||||
* direction_output() - deprecated
|
||||
*
|
||||
* Equivalent to set_flags(...GPIOD_IS_OUT) with GPIOD_IS_OUT_ACTIVE
|
||||
* also set if @value
|
||||
*/
|
||||
int (*direction_output)(struct udevice *dev, unsigned offset,
|
||||
int value);
|
||||
|
||||
int (*get_value)(struct udevice *dev, unsigned offset);
|
||||
|
||||
/**
|
||||
* set_value() - Sets the GPIO value of an output
|
||||
*
|
||||
* If the driver provides an @set_flags() method then that is used
|
||||
* in preference to this, with GPIOD_IS_OUT_ACTIVE set according to
|
||||
* @value.
|
||||
*/
|
||||
int (*set_value)(struct udevice *dev, unsigned offset, int value);
|
||||
/**
|
||||
* get_function() Get the GPIO function
|
||||
@ -301,35 +323,54 @@ struct dm_gpio_ops {
|
||||
struct ofnode_phandle_args *args);
|
||||
|
||||
/**
|
||||
* set_dir_flags() - Set GPIO dir flags
|
||||
* set_flags() - Adjust GPIO flags
|
||||
*
|
||||
* This function should set up the GPIO configuration according to the
|
||||
* information provide by the direction flags bitfield.
|
||||
* information provided by @flags.
|
||||
*
|
||||
* This method is optional.
|
||||
* If any flags cannot be set (e.g. the driver or hardware does not
|
||||
* support them or this particular GPIO does not have the requested
|
||||
* feature), the driver should return -EINVAL.
|
||||
*
|
||||
* The uclass checks that flags do not obviously conflict (e.g. input
|
||||
* and output). If the driver finds other conflicts it should return
|
||||
* -ERECALLCONFLICT
|
||||
*
|
||||
* Note that GPIOD_ACTIVE_LOW should be ignored, since the uclass
|
||||
* adjusts for it automatically. For example, for an output GPIO,
|
||||
* GPIOD_ACTIVE_LOW causes GPIOD_IS_OUT_ACTIVE to be inverted by the
|
||||
* uclass, so the driver always sees the value that should be set at the
|
||||
* pin (1=high, 0=low).
|
||||
*
|
||||
* This method is required and should be implemented by new drivers. At
|
||||
* some point, it will supersede direction_input() and
|
||||
* direction_output(), which wil be removed.
|
||||
*
|
||||
* @dev: GPIO device
|
||||
* @offset: GPIO offset within that device
|
||||
* @flags: GPIO configuration to use
|
||||
* @return 0 if OK, -ve on error
|
||||
* @flags: New flags value (GPIOD_...)
|
||||
*
|
||||
* @return 0 if OK, -EINVAL if unsupported, -ERECALLCONFLICT if flags
|
||||
* conflict in some * non-obvious way and were not applied,
|
||||
* other -ve on error
|
||||
*/
|
||||
int (*set_dir_flags)(struct udevice *dev, unsigned int offset,
|
||||
ulong flags);
|
||||
int (*set_flags)(struct udevice *dev, unsigned int offset, ulong flags);
|
||||
|
||||
/**
|
||||
* get_dir_flags() - Get GPIO dir flags
|
||||
* get_flags() - Get GPIO flags
|
||||
*
|
||||
* This function return the GPIO direction flags used.
|
||||
* This function return the GPIO flags used. It should read this from
|
||||
* the hardware directly.
|
||||
*
|
||||
* This method is optional.
|
||||
*
|
||||
* @dev: GPIO device
|
||||
* @offset: GPIO offset within that device
|
||||
* @flags: place to put the used direction flags by GPIO
|
||||
* @flagsp: place to put the current flags value
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int (*get_dir_flags)(struct udevice *dev, unsigned int offset,
|
||||
ulong *flags);
|
||||
int (*get_flags)(struct udevice *dev, unsigned int offset,
|
||||
ulong *flagsp);
|
||||
|
||||
#if CONFIG_IS_ENABLED(ACPIGEN)
|
||||
/**
|
||||
@ -456,6 +497,31 @@ int gpio_get_values_as_int(const int *gpio_list);
|
||||
*/
|
||||
int dm_gpio_get_values_as_int(const struct gpio_desc *desc_list, int count);
|
||||
|
||||
/**
|
||||
* dm_gpio_get_values_as_int_base3() - Create a base-3 int from a list of GPIOs
|
||||
*
|
||||
* This uses pull-ups/pull-downs to figure out whether a GPIO line is externally
|
||||
* pulled down, pulled up or floating. This allows three different strap values
|
||||
* for each pin:
|
||||
* 0 : external pull-down
|
||||
* 1 : external pull-up
|
||||
* 2 : floating
|
||||
*
|
||||
* With this it is possible to obtain more combinations from the same number of
|
||||
* strapping pins, when compared to dm_gpio_get_values_as_int(). The external
|
||||
* pull resistors should be made stronger that the internal SoC pull resistors,
|
||||
* for this to work.
|
||||
*
|
||||
* With 2 pins, 6 combinations are possible, compared with 4
|
||||
* With 3 pins, 27 are possible, compared with 8
|
||||
*
|
||||
* @desc_list: List of GPIOs to collect
|
||||
* @count: Number of GPIOs
|
||||
* @return resulting integer value, or -ve on error
|
||||
*/
|
||||
int dm_gpio_get_values_as_int_base3(struct gpio_desc *desc_list,
|
||||
int count);
|
||||
|
||||
/**
|
||||
* gpio_claim_vector() - claim a number of GPIOs for input
|
||||
*
|
||||
@ -651,6 +717,25 @@ int dm_gpio_set_value(const struct gpio_desc *desc, int value);
|
||||
*/
|
||||
int dm_gpio_set_dir(struct gpio_desc *desc);
|
||||
|
||||
/**
|
||||
* dm_gpio_clrset_flags() - Update flags
|
||||
*
|
||||
* This updates the flags as directled. Note that desc->flags is updated by this
|
||||
* function on success. If any changes cannot be made, best efforts are made.
|
||||
*
|
||||
* By use of @clr and @set any of flags can be individually updated, or left
|
||||
* alone
|
||||
*
|
||||
* @desc: GPIO description containing device, offset and flags,
|
||||
* previously returned by gpio_request_by_name()
|
||||
* @clr: Flags to clear (GPIOD_...)
|
||||
* @set: Flags to set (GPIOD_...)
|
||||
* @return 0 if OK, -EINVAL if the flags had obvious conflicts,
|
||||
* -ERECALLCONFLICT if there was a non-obvious hardware conflict when attempting
|
||||
* to set the flags
|
||||
*/
|
||||
int dm_gpio_clrset_flags(struct gpio_desc *desc, ulong clr, ulong set);
|
||||
|
||||
/**
|
||||
* dm_gpio_set_dir_flags() - Set direction using description and added flags
|
||||
*
|
||||
@ -666,16 +751,31 @@ int dm_gpio_set_dir(struct gpio_desc *desc);
|
||||
int dm_gpio_set_dir_flags(struct gpio_desc *desc, ulong flags);
|
||||
|
||||
/**
|
||||
* dm_gpio_get_dir_flags() - Get direction flags
|
||||
* dm_gpios_clrset_flags() - Sets flags for a set of GPIOs
|
||||
*
|
||||
* read the current direction flags
|
||||
* This clears and sets flags individually for each GPIO.
|
||||
*
|
||||
* @desc: List of GPIOs to update
|
||||
* @count: Number of GPIOs in the list
|
||||
* @clr: Flags to clear (GPIOD_...), e.g. GPIOD_MASK_DIR if you are
|
||||
* changing the direction
|
||||
* @set: Flags to set (GPIOD_...)
|
||||
* @return 0 if OK, -ve on error
|
||||
*/
|
||||
int dm_gpios_clrset_flags(struct gpio_desc *desc, int count, ulong clr,
|
||||
ulong set);
|
||||
|
||||
/**
|
||||
* dm_gpio_get_flags() - Get flags
|
||||
*
|
||||
* Read the current flags
|
||||
*
|
||||
* @desc: GPIO description containing device, offset and flags,
|
||||
* previously returned by gpio_request_by_name()
|
||||
* @flags: place to put the used flags
|
||||
* @return 0 if OK, -ve on error, in which case desc->flags is not updated
|
||||
*/
|
||||
int dm_gpio_get_dir_flags(struct gpio_desc *desc, ulong *flags);
|
||||
int dm_gpio_get_flags(struct gpio_desc *desc, ulong *flags);
|
||||
|
||||
/**
|
||||
* gpio_get_number() - Get the global GPIO number of a GPIO
|
||||
|
270
test/dm/gpio.c
270
test/dm/gpio.c
@ -80,15 +80,15 @@ static int dm_test_gpio(struct unit_test_state *uts)
|
||||
|
||||
/* Make it an open drain output, and reset it */
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE,
|
||||
sandbox_gpio_get_dir_flags(dev, offset));
|
||||
ut_assertok(ops->set_dir_flags(dev, offset,
|
||||
GPIOD_IS_OUT | GPIOD_OPEN_DRAIN));
|
||||
sandbox_gpio_get_flags(dev, offset));
|
||||
ut_assertok(ops->set_flags(dev, offset,
|
||||
GPIOD_IS_OUT | GPIOD_OPEN_DRAIN));
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN,
|
||||
sandbox_gpio_get_dir_flags(dev, offset));
|
||||
ut_assertok(ops->set_dir_flags(dev, offset,
|
||||
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE));
|
||||
sandbox_gpio_get_flags(dev, offset));
|
||||
ut_assertok(ops->set_flags(dev, offset,
|
||||
GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE));
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE,
|
||||
sandbox_gpio_get_dir_flags(dev, offset));
|
||||
sandbox_gpio_get_flags(dev, offset));
|
||||
|
||||
/* Make it an input */
|
||||
ut_assertok(ops->direction_input(dev, offset));
|
||||
@ -176,54 +176,64 @@ static int dm_test_gpio_opendrain_opensource(struct unit_test_state *uts)
|
||||
|
||||
/* GPIO 0 is (GPIO_OUT|GPIO_OPEN_DRAIN) */
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN,
|
||||
sandbox_gpio_get_dir_flags(gpio_c, 0));
|
||||
sandbox_gpio_get_flags(gpio_c, 0));
|
||||
|
||||
/* Set it as output high, should become an input */
|
||||
/* Set it as output high */
|
||||
ut_assertok(dm_gpio_set_value(&desc_list[0], 1));
|
||||
ut_assertok(gpio_get_status(gpio_c, 0, buf, sizeof(buf)));
|
||||
ut_asserteq_str("c0: input: 0 [x] a-test.test3-gpios0", buf);
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN | GPIOD_IS_OUT_ACTIVE,
|
||||
sandbox_gpio_get_flags(gpio_c, 0));
|
||||
|
||||
/* Set it as output low, should become output low */
|
||||
/* Set it as output low */
|
||||
ut_assertok(dm_gpio_set_value(&desc_list[0], 0));
|
||||
ut_assertok(gpio_get_status(gpio_c, 0, buf, sizeof(buf)));
|
||||
ut_asserteq_str("c0: output: 0 [x] a-test.test3-gpios0", buf);
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN,
|
||||
sandbox_gpio_get_flags(gpio_c, 0));
|
||||
|
||||
/* GPIO 1 is (GPIO_OUT|GPIO_OPEN_SOURCE) */
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_SOURCE,
|
||||
sandbox_gpio_get_dir_flags(gpio_c, 1));
|
||||
sandbox_gpio_get_flags(gpio_c, 1));
|
||||
|
||||
/* Set it as output high, should become output high */
|
||||
ut_assertok(dm_gpio_set_value(&desc_list[1], 1));
|
||||
ut_assertok(gpio_get_status(gpio_c, 1, buf, sizeof(buf)));
|
||||
ut_asserteq_str("c1: output: 1 [x] a-test.test3-gpios1", buf);
|
||||
|
||||
/* Set it as output low, should become an input */
|
||||
/* Set it as output low */
|
||||
ut_assertok(dm_gpio_set_value(&desc_list[1], 0));
|
||||
ut_assertok(gpio_get_status(gpio_c, 1, buf, sizeof(buf)));
|
||||
ut_asserteq_str("c1: input: 1 [x] a-test.test3-gpios1", buf);
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_SOURCE,
|
||||
sandbox_gpio_get_flags(gpio_c, 1));
|
||||
|
||||
/* GPIO 6 is (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_DRAIN) */
|
||||
ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_DRAIN,
|
||||
sandbox_gpio_get_dir_flags(gpio_c, 6));
|
||||
ut_assertok(gpio_get_status(gpio_c, 1, buf, sizeof(buf)));
|
||||
ut_asserteq_str("c1: output: 0 [x] a-test.test3-gpios1", buf);
|
||||
|
||||
/*
|
||||
* GPIO 6 is (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_DRAIN). Looking at it
|
||||
* directlt from the driver, we get GPIOD_IS_OUT_ACTIVE also, since it
|
||||
* is active low
|
||||
*/
|
||||
ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_DRAIN |
|
||||
GPIOD_IS_OUT_ACTIVE,
|
||||
sandbox_gpio_get_flags(gpio_c, 6));
|
||||
|
||||
/* Set it as output high, should become output low */
|
||||
ut_assertok(dm_gpio_set_value(&desc_list[6], 1));
|
||||
ut_assertok(gpio_get_status(gpio_c, 6, buf, sizeof(buf)));
|
||||
ut_asserteq_str("c6: output: 0 [x] a-test.test3-gpios6", buf);
|
||||
|
||||
/* Set it as output low, should become an input */
|
||||
/* Set it as output low */
|
||||
ut_assertok(dm_gpio_set_value(&desc_list[6], 0));
|
||||
ut_assertok(gpio_get_status(gpio_c, 6, buf, sizeof(buf)));
|
||||
ut_asserteq_str("c6: input: 0 [x] a-test.test3-gpios6", buf);
|
||||
ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_DRAIN |
|
||||
GPIOD_IS_OUT_ACTIVE,
|
||||
sandbox_gpio_get_flags(gpio_c, 6));
|
||||
|
||||
/* GPIO 7 is (GPIO_ACTIVE_LOW|GPIO_OUT|GPIO_OPEN_SOURCE) */
|
||||
ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_SOURCE,
|
||||
sandbox_gpio_get_dir_flags(gpio_c, 7));
|
||||
ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_SOURCE |
|
||||
GPIOD_IS_OUT_ACTIVE,
|
||||
sandbox_gpio_get_flags(gpio_c, 7));
|
||||
|
||||
/* Set it as output high, should become an input */
|
||||
/* Set it as output high */
|
||||
ut_assertok(dm_gpio_set_value(&desc_list[7], 1));
|
||||
ut_assertok(gpio_get_status(gpio_c, 7, buf, sizeof(buf)));
|
||||
ut_asserteq_str("c7: input: 0 [x] a-test.test3-gpios7", buf);
|
||||
ut_asserteq(GPIOD_ACTIVE_LOW | GPIOD_IS_OUT | GPIOD_OPEN_SOURCE,
|
||||
sandbox_gpio_get_flags(gpio_c, 7));
|
||||
|
||||
/* Set it as output low, should become output high */
|
||||
ut_assertok(dm_gpio_set_value(&desc_list[7], 0));
|
||||
@ -363,12 +373,12 @@ static int dm_test_gpio_phandles(struct unit_test_state *uts)
|
||||
ut_assertok(gpio_free_list(dev, desc_list, 3));
|
||||
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE,
|
||||
sandbox_gpio_get_dir_flags(gpio_a, 1));
|
||||
sandbox_gpio_get_flags(gpio_a, 1));
|
||||
ut_asserteq(6, gpio_request_list_by_name(dev, "test2-gpios", desc_list,
|
||||
ARRAY_SIZE(desc_list), 0));
|
||||
|
||||
/* This was set to output previously but flags resetted to 0 = INPUT */
|
||||
ut_asserteq(0, sandbox_gpio_get_dir_flags(gpio_a, 1));
|
||||
ut_asserteq(0, sandbox_gpio_get_flags(gpio_a, 1));
|
||||
ut_asserteq(GPIOF_INPUT, gpio_get_function(gpio_a, 1, NULL));
|
||||
|
||||
/* Active low should invert the input value */
|
||||
@ -397,22 +407,22 @@ static int dm_test_gpio_get_dir_flags(struct unit_test_state *uts)
|
||||
ut_asserteq(6, gpio_request_list_by_name(dev, "test3-gpios", desc_list,
|
||||
ARRAY_SIZE(desc_list), 0));
|
||||
|
||||
ut_assertok(dm_gpio_get_dir_flags(&desc_list[0], &flags));
|
||||
ut_assertok(dm_gpio_get_flags(&desc_list[0], &flags));
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_DRAIN, flags);
|
||||
|
||||
ut_assertok(dm_gpio_get_dir_flags(&desc_list[1], &flags));
|
||||
ut_assertok(dm_gpio_get_flags(&desc_list[1], &flags));
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_OPEN_SOURCE, flags);
|
||||
|
||||
ut_assertok(dm_gpio_get_dir_flags(&desc_list[2], &flags));
|
||||
ut_assertok(dm_gpio_get_flags(&desc_list[2], &flags));
|
||||
ut_asserteq(GPIOD_IS_OUT, flags);
|
||||
|
||||
ut_assertok(dm_gpio_get_dir_flags(&desc_list[3], &flags));
|
||||
ut_assertok(dm_gpio_get_flags(&desc_list[3], &flags));
|
||||
ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_UP, flags);
|
||||
|
||||
ut_assertok(dm_gpio_get_dir_flags(&desc_list[4], &flags));
|
||||
ut_assertok(dm_gpio_get_flags(&desc_list[4], &flags));
|
||||
ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_DOWN, flags);
|
||||
|
||||
ut_assertok(dm_gpio_get_dir_flags(&desc_list[5], &flags));
|
||||
ut_assertok(dm_gpio_get_flags(&desc_list[5], &flags));
|
||||
ut_asserteq(GPIOD_IS_IN, flags);
|
||||
|
||||
ut_assertok(gpio_free_list(dev, desc_list, 6));
|
||||
@ -582,3 +592,189 @@ static int dm_test_gpio_devm(struct unit_test_state *uts)
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_gpio_devm, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
|
||||
|
||||
static int dm_test_clrset_flags(struct unit_test_state *uts)
|
||||
{
|
||||
struct gpio_desc desc;
|
||||
struct udevice *dev;
|
||||
ulong flags;
|
||||
|
||||
ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
|
||||
ut_asserteq_str("a-test", dev->name);
|
||||
ut_assertok(gpio_request_by_name(dev, "test-gpios", 1, &desc, 0));
|
||||
|
||||
ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, GPIOD_IS_OUT));
|
||||
ut_assertok(dm_gpio_get_flags(&desc, &flags));
|
||||
ut_asserteq(GPIOD_IS_OUT, flags);
|
||||
ut_asserteq(GPIOD_IS_OUT, desc.flags);
|
||||
ut_asserteq(0, sandbox_gpio_get_value(desc.dev, desc.offset));
|
||||
|
||||
ut_assertok(dm_gpio_clrset_flags(&desc, 0, GPIOD_IS_OUT_ACTIVE));
|
||||
ut_assertok(dm_gpio_get_flags(&desc, &flags));
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE, flags);
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_IS_OUT_ACTIVE, desc.flags);
|
||||
ut_asserteq(1, sandbox_gpio_get_value(desc.dev, desc.offset));
|
||||
ut_asserteq(1, dm_gpio_get_value(&desc));
|
||||
|
||||
ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_MASK_DIR, GPIOD_IS_IN));
|
||||
ut_assertok(dm_gpio_get_flags(&desc, &flags));
|
||||
ut_asserteq(GPIOD_IS_IN, flags & GPIOD_MASK_DIR);
|
||||
ut_asserteq(GPIOD_IS_IN, desc.flags & GPIOD_MASK_DIR);
|
||||
|
||||
ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_MASK_PULL,
|
||||
GPIOD_PULL_UP));
|
||||
ut_assertok(dm_gpio_get_flags(&desc, &flags));
|
||||
ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_UP, flags);
|
||||
ut_asserteq(GPIOD_IS_IN | GPIOD_PULL_UP, desc.flags);
|
||||
|
||||
/* Check we cannot set both PULL_UP and PULL_DOWN */
|
||||
ut_asserteq(-EINVAL, dm_gpio_clrset_flags(&desc, 0, GPIOD_PULL_DOWN));
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_clrset_flags, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
|
||||
|
||||
/* Check that an active-low GPIO works as expected */
|
||||
static int dm_test_clrset_flags_invert(struct unit_test_state *uts)
|
||||
{
|
||||
struct gpio_desc desc;
|
||||
struct udevice *dev;
|
||||
ulong flags;
|
||||
|
||||
ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
|
||||
ut_asserteq_str("a-test", dev->name);
|
||||
ut_assertok(gpio_request_by_name(dev, "test-gpios", 1, &desc,
|
||||
GPIOD_IS_OUT | GPIOD_ACTIVE_LOW));
|
||||
|
||||
/*
|
||||
* From this size we see it as 0 (active low), but the sandbox driver
|
||||
* sees the pin value high
|
||||
*/
|
||||
ut_asserteq(0, dm_gpio_get_value(&desc));
|
||||
ut_asserteq(1, sandbox_gpio_get_value(desc.dev, desc.offset));
|
||||
|
||||
ut_assertok(dm_gpio_set_value(&desc, 1));
|
||||
ut_asserteq(1, dm_gpio_get_value(&desc));
|
||||
ut_asserteq(0, sandbox_gpio_get_value(desc.dev, desc.offset));
|
||||
|
||||
/* Do the same with dm_gpio_clrset_flags() */
|
||||
ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_IS_OUT_ACTIVE, 0));
|
||||
ut_asserteq(0, dm_gpio_get_value(&desc));
|
||||
ut_asserteq(1, sandbox_gpio_get_value(desc.dev, desc.offset));
|
||||
|
||||
ut_assertok(dm_gpio_clrset_flags(&desc, 0, GPIOD_IS_OUT_ACTIVE));
|
||||
ut_asserteq(1, dm_gpio_get_value(&desc));
|
||||
ut_asserteq(0, sandbox_gpio_get_value(desc.dev, desc.offset));
|
||||
|
||||
ut_assertok(dm_gpio_get_flags(&desc, &flags));
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE,
|
||||
flags);
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW | GPIOD_IS_OUT_ACTIVE,
|
||||
desc.flags);
|
||||
|
||||
ut_assertok(dm_gpio_clrset_flags(&desc, GPIOD_IS_OUT_ACTIVE, 0));
|
||||
ut_assertok(dm_gpio_get_flags(&desc, &flags));
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW, flags);
|
||||
ut_asserteq(GPIOD_IS_OUT | GPIOD_ACTIVE_LOW, desc.flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_clrset_flags_invert, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
|
||||
|
||||
static int set_gpios(struct unit_test_state *uts, struct gpio_desc *desc,
|
||||
int count, uint value)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
const uint mask = 1 << i;
|
||||
|
||||
ut_assertok(sandbox_gpio_set_value(desc[i].dev, desc[i].offset,
|
||||
value & mask));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Check that an active-low GPIO works as expected */
|
||||
static int dm_test_gpio_get_values_as_int(struct unit_test_state *uts)
|
||||
{
|
||||
const int gpio_count = 3;
|
||||
struct gpio_desc desc[gpio_count];
|
||||
struct udevice *dev;
|
||||
|
||||
ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
|
||||
ut_asserteq_str("a-test", dev->name);
|
||||
|
||||
ut_asserteq(3, gpio_request_list_by_name(dev, "test-gpios", desc,
|
||||
gpio_count, GPIOD_IS_IN));
|
||||
ut_assertok(set_gpios(uts, desc, gpio_count, 0));
|
||||
ut_asserteq(0, dm_gpio_get_values_as_int(desc, gpio_count));
|
||||
|
||||
ut_assertok(set_gpios(uts, desc, gpio_count, 5));
|
||||
ut_asserteq(5, dm_gpio_get_values_as_int(desc, gpio_count));
|
||||
|
||||
ut_assertok(set_gpios(uts, desc, gpio_count, 7));
|
||||
ut_asserteq(7, dm_gpio_get_values_as_int(desc, gpio_count));
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_gpio_get_values_as_int,
|
||||
UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
|
||||
|
||||
/* Check that an active-low GPIO works as expected */
|
||||
static int dm_test_gpio_get_values_as_int_base3(struct unit_test_state *uts)
|
||||
{
|
||||
const int gpio_count = 3;
|
||||
struct gpio_desc desc[gpio_count];
|
||||
struct udevice *dev;
|
||||
|
||||
ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
|
||||
ut_asserteq_str("a-test", dev->name);
|
||||
|
||||
ut_asserteq(3, gpio_request_list_by_name(dev, "test-gpios", desc,
|
||||
gpio_count, GPIOD_IS_IN));
|
||||
|
||||
/*
|
||||
* First test the sandbox GPIO driver works as expected. The external
|
||||
* pull resistor should be stronger than the internal one.
|
||||
*/
|
||||
sandbox_gpio_set_flags(desc[0].dev, desc[0].offset,
|
||||
GPIOD_IS_IN | GPIOD_EXT_PULL_UP | GPIOD_PULL_UP);
|
||||
ut_asserteq(1, dm_gpio_get_value(desc));
|
||||
|
||||
sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, GPIOD_IS_IN |
|
||||
GPIOD_EXT_PULL_DOWN | GPIOD_PULL_UP);
|
||||
ut_asserteq(0, dm_gpio_get_value(desc));
|
||||
|
||||
sandbox_gpio_set_flags(desc[0].dev, desc[0].offset,
|
||||
GPIOD_IS_IN | GPIOD_PULL_UP);
|
||||
ut_asserteq(1, dm_gpio_get_value(desc));
|
||||
|
||||
sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, GPIOD_PULL_DOWN);
|
||||
ut_asserteq(0, dm_gpio_get_value(desc));
|
||||
|
||||
/*
|
||||
* Set up pins: pull-up (1), pull-down (0) and floating (2). This should
|
||||
* result in digits 2 0 1, i.e. 2 * 9 + 1 * 3 = 19
|
||||
*/
|
||||
sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, GPIOD_EXT_PULL_UP);
|
||||
sandbox_gpio_set_flags(desc[1].dev, desc[1].offset,
|
||||
GPIOD_EXT_PULL_DOWN);
|
||||
sandbox_gpio_set_flags(desc[2].dev, desc[2].offset, 0);
|
||||
ut_asserteq(19, dm_gpio_get_values_as_int_base3(desc, gpio_count));
|
||||
|
||||
/*
|
||||
* Set up pins: floating (2), pull-up (1) and pull-down (0). This should
|
||||
* result in digits 0 1 2, i.e. 1 * 3 + 2 = 5
|
||||
*/
|
||||
sandbox_gpio_set_flags(desc[0].dev, desc[0].offset, 0);
|
||||
sandbox_gpio_set_flags(desc[1].dev, desc[1].offset, GPIOD_EXT_PULL_UP);
|
||||
sandbox_gpio_set_flags(desc[2].dev, desc[2].offset,
|
||||
GPIOD_EXT_PULL_DOWN);
|
||||
ut_asserteq(5, dm_gpio_get_values_as_int_base3(desc, gpio_count));
|
||||
|
||||
return 0;
|
||||
}
|
||||
DM_TEST(dm_test_gpio_get_values_as_int_base3,
|
||||
UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
|
||||
|
Loading…
Reference in New Issue
Block a user