mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-28 02:35:28 +00:00
GPIO console commands currently only show input voltage level, and can only set level on predefined outputs. This change allows GPIOs to be cycled between output, input, and alternate function, as well as displaying the mode and asserted level (if any) in gpioget. This change creates CONFIG_CMD_GPIO_EXTENDED as the internal gpio interface needs to be changed to support this, and I can't test the other architectures. It may be worthwhile to add this for all, or not. This change is also necessary also for servo micro JTAG and PD UART support, as several pins are tied together on the flex and stm32 outputs need to be variously active or in high-z depending on mode. BUG=chromium:571477 TEST=gpioget <0|1|IN|A|ALT>; gpioget; BRANCH=None Change-Id: Iba32992db6244ee1e654db840d1c9c11dd2a0993 Signed-off-by: Nick Sanders <nsanders@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/338885 Reviewed-by: Aseda Aboagye <aaboagye@chromium.org>
149 lines
3.6 KiB
C
149 lines
3.6 KiB
C
/* Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
|
|
/* GPIO common functionality for Chrome EC */
|
|
|
|
#include "common.h"
|
|
#include "gpio.h"
|
|
#include "registers.h"
|
|
#include "util.h"
|
|
|
|
/* GPIO alternate function structure */
|
|
struct gpio_alt_func {
|
|
/* Port base address */
|
|
uint32_t port;
|
|
|
|
/* Bitmask on that port (multiple bits allowed) */
|
|
uint32_t mask;
|
|
|
|
/* Alternate function number */
|
|
uint8_t func;
|
|
|
|
/* Module ID (as uint8_t, since enum would be 32-bit) */
|
|
uint8_t module_id;
|
|
|
|
/* Flags (GPIO_*; see above). */
|
|
uint16_t flags;
|
|
};
|
|
|
|
/*
|
|
* Construct the gpio_alt_funcs array. This array is used by gpio_config_module
|
|
* to enable and disable GPIO alternate functions on a module by module basis.
|
|
*/
|
|
#define ALTERNATE(pinmask, function, module, flags) \
|
|
{GPIO_##pinmask, function, module, flags},
|
|
|
|
static const struct gpio_alt_func gpio_alt_funcs[] = {
|
|
#include "gpio.wrap"
|
|
};
|
|
|
|
/*
|
|
* GPIO_CONFIG_ALL_PORTS signifies a "don't care" for the GPIO port. This is
|
|
* used in gpio_config_pins(). When the port parameter is set to this, the
|
|
* pin_mask parameter is ignored.
|
|
*/
|
|
#define GPIO_CONFIG_ALL_PORTS 0xFFFFFFFF
|
|
|
|
static int gpio_config_pins(enum module_id id,
|
|
uint32_t port,
|
|
uint32_t pin_mask,
|
|
int enable)
|
|
{
|
|
const struct gpio_alt_func *af;
|
|
int rv = EC_ERROR_INVAL;
|
|
|
|
/* Find pins and set to alternate functions */
|
|
for (af = gpio_alt_funcs;
|
|
af < gpio_alt_funcs + ARRAY_SIZE(gpio_alt_funcs);
|
|
af++) {
|
|
if (af->module_id != id)
|
|
continue; /* Pins for some other module */
|
|
|
|
/* Check to see if the requested port matches. */
|
|
if ((port != GPIO_CONFIG_ALL_PORTS) && (port != af->port))
|
|
continue;
|
|
|
|
/* If we don't care which port, enable all applicable pins. */
|
|
if (port == GPIO_CONFIG_ALL_PORTS)
|
|
pin_mask = af->mask;
|
|
|
|
if ((af->mask & pin_mask) == pin_mask) {
|
|
if (!(af->flags & GPIO_DEFAULT))
|
|
gpio_set_flags_by_mask(
|
|
af->port,
|
|
(af->mask & pin_mask),
|
|
enable ? af->flags : GPIO_INPUT);
|
|
gpio_set_alternate_function(
|
|
af->port,
|
|
(af->mask & pin_mask),
|
|
enable ? af->func : -1);
|
|
rv = EC_SUCCESS;
|
|
/* We're done here if we were just setting one port. */
|
|
if (port != GPIO_CONFIG_ALL_PORTS)
|
|
break;
|
|
}
|
|
}
|
|
|
|
return rv;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
/* GPIO API */
|
|
|
|
int gpio_config_module(enum module_id id, int enable)
|
|
{
|
|
/* Set all the alternate functions for this module. */
|
|
return gpio_config_pins(id, GPIO_CONFIG_ALL_PORTS, 0, enable);
|
|
}
|
|
|
|
int gpio_config_pin(enum module_id id, enum gpio_signal signal, int enable)
|
|
{
|
|
return gpio_config_pins(id,
|
|
gpio_list[signal].port,
|
|
gpio_list[signal].mask,
|
|
enable);
|
|
}
|
|
|
|
void gpio_set_flags(enum gpio_signal signal, int flags)
|
|
{
|
|
const struct gpio_info *g = gpio_list + signal;
|
|
|
|
gpio_set_flags_by_mask(g->port, g->mask, flags);
|
|
}
|
|
|
|
#ifdef CONFIG_CMD_GPIO_EXTENDED
|
|
int gpio_get_flags(enum gpio_signal signal)
|
|
{
|
|
const struct gpio_info *g = gpio_list + signal;
|
|
|
|
return gpio_get_flags_by_mask(g->port, g->mask);
|
|
}
|
|
#endif
|
|
|
|
int gpio_get_default_flags(enum gpio_signal signal)
|
|
{
|
|
return gpio_list[signal].flags;
|
|
}
|
|
|
|
void gpio_reset(enum gpio_signal signal)
|
|
{
|
|
const struct gpio_info *g = gpio_list + signal;
|
|
|
|
gpio_set_flags_by_mask(g->port, g->mask, g->flags);
|
|
gpio_set_alternate_function(g->port, g->mask, -1);
|
|
}
|
|
|
|
const char *gpio_get_name(enum gpio_signal signal)
|
|
{
|
|
return gpio_list[signal].name;
|
|
}
|
|
|
|
int gpio_is_implemented(enum gpio_signal signal)
|
|
{
|
|
return !!gpio_list[signal].mask;
|
|
}
|
|
|
|
/*****************************************************************************/
|