mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-11 15:37:23 +00:00
Merge branch '2022-04-08-gpio-updates'
- Add PCA957X GPIO support, enable GPIO hogging in SPL, add gpio_request_by_line_name() for later use and add some pytests for 'gpio'
This commit is contained in:
commit
22b7d140fa
6 changed files with 276 additions and 15 deletions
|
@ -20,6 +20,7 @@
|
|||
#include <serial.h>
|
||||
#include <spl.h>
|
||||
#include <asm/global_data.h>
|
||||
#include <asm-generic/gpio.h>
|
||||
#include <asm/u-boot.h>
|
||||
#include <nand.h>
|
||||
#include <fat.h>
|
||||
|
@ -743,6 +744,9 @@ void board_init_r(gd_t *dummy1, ulong dummy2)
|
|||
}
|
||||
}
|
||||
|
||||
if (CONFIG_IS_ENABLED(GPIO_HOG))
|
||||
gpio_hog_probe_all();
|
||||
|
||||
#if CONFIG_IS_ENABLED(BOARD_INIT)
|
||||
spl_board_init();
|
||||
#endif
|
||||
|
|
|
@ -57,6 +57,15 @@ config GPIO_HOG
|
|||
is a mechanism providing automatic GPIO request and config-
|
||||
uration as part of the gpio-controller's driver probe function.
|
||||
|
||||
config SPL_GPIO_HOG
|
||||
bool "Enable GPIO hog support in SPL"
|
||||
depends on SPL_GPIO_SUPPORT
|
||||
help
|
||||
Enable gpio hog support in SPL
|
||||
The GPIO chip may contain GPIO hog definitions. GPIO hogging
|
||||
is a mechanism providing automatic GPIO request and config-
|
||||
uration as part of the gpio-controller's driver probe function.
|
||||
|
||||
config DM_GPIO_LOOKUP_LABEL
|
||||
bool "Enable searching for gpio labelnames"
|
||||
depends on DM_GPIO
|
||||
|
|
|
@ -1187,6 +1187,32 @@ int gpio_request_by_name(struct udevice *dev, const char *list_name, int index,
|
|||
index, desc, flags, index > 0, NULL);
|
||||
}
|
||||
|
||||
int gpio_request_by_line_name(struct udevice *dev, const char *line_name,
|
||||
struct gpio_desc *desc, int flags)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = dev_read_stringlist_search(dev, "gpio-line-names", line_name);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
desc->dev = dev;
|
||||
desc->offset = ret;
|
||||
desc->flags = 0;
|
||||
|
||||
ret = dm_gpio_request(desc, line_name);
|
||||
if (ret) {
|
||||
debug("%s: dm_gpio_requestf failed\n", __func__);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dm_gpio_set_dir_flags(desc, flags | desc->flags);
|
||||
if (ret)
|
||||
debug("%s: dm_gpio_set_dir failed\n", __func__);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int gpio_request_list_by_name_nodev(ofnode node, const char *list_name,
|
||||
struct gpio_desc *desc, int max_count,
|
||||
int flags)
|
||||
|
@ -1432,9 +1458,6 @@ void devm_gpiod_put(struct udevice *dev, struct gpio_desc *desc)
|
|||
|
||||
static int gpio_post_bind(struct udevice *dev)
|
||||
{
|
||||
struct udevice *child;
|
||||
ofnode node;
|
||||
|
||||
#if defined(CONFIG_NEEDS_MANUAL_RELOC)
|
||||
struct dm_gpio_ops *ops = (struct dm_gpio_ops *)device_get_ops(dev);
|
||||
static int reloc_done;
|
||||
|
@ -1465,7 +1488,10 @@ static int gpio_post_bind(struct udevice *dev)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (CONFIG_IS_ENABLED(OF_REAL) && IS_ENABLED(CONFIG_GPIO_HOG)) {
|
||||
if (CONFIG_IS_ENABLED(GPIO_HOG)) {
|
||||
struct udevice *child;
|
||||
ofnode node;
|
||||
|
||||
dev_for_each_subnode(node, dev) {
|
||||
if (ofnode_read_bool(node, "gpio-hog")) {
|
||||
const char *name = ofnode_get_name(node);
|
||||
|
|
|
@ -35,6 +35,12 @@
|
|||
#define PCA953X_INVERT 2
|
||||
#define PCA953X_DIRECTION 3
|
||||
|
||||
#define PCA957X_INPUT 0
|
||||
#define PCA957X_OUTPUT 5
|
||||
#define PCA957X_INVERT 1
|
||||
#define PCA957X_DIRECTION 4
|
||||
|
||||
|
||||
#define PCA_GPIO_MASK 0x00FF
|
||||
#define PCA_INT 0x0100
|
||||
#define PCA953X_TYPE 0x1000
|
||||
|
@ -50,8 +56,29 @@ enum {
|
|||
#define MAX_BANK 5
|
||||
#define BANK_SZ 8
|
||||
|
||||
struct pca95xx_reg {
|
||||
int input;
|
||||
int output;
|
||||
int invert;
|
||||
int direction;
|
||||
};
|
||||
|
||||
static const struct pca95xx_reg pca953x_regs = {
|
||||
.direction = PCA953X_DIRECTION,
|
||||
.output = PCA953X_OUTPUT,
|
||||
.input = PCA953X_INPUT,
|
||||
.invert = PCA953X_INVERT,
|
||||
};
|
||||
|
||||
static const struct pca95xx_reg pca957x_regs = {
|
||||
.direction = PCA957X_DIRECTION,
|
||||
.output = PCA957X_OUTPUT,
|
||||
.input = PCA957X_INPUT,
|
||||
.invert = PCA957X_INVERT,
|
||||
};
|
||||
|
||||
/*
|
||||
* struct pca953x_info - Data for pca953x
|
||||
* struct pca953x_info - Data for pca953x/pca957x
|
||||
*
|
||||
* @dev: udevice structure for the device
|
||||
* @addr: i2c slave address
|
||||
|
@ -61,6 +88,7 @@ enum {
|
|||
* @bank_count: the number of banks that the device supports
|
||||
* @reg_output: array to hold the value of output registers
|
||||
* @reg_direction: array to hold the value of direction registers
|
||||
* @regs: struct to hold the registers addresses
|
||||
*/
|
||||
struct pca953x_info {
|
||||
struct udevice *dev;
|
||||
|
@ -71,6 +99,7 @@ struct pca953x_info {
|
|||
int bank_count;
|
||||
u8 reg_output[MAX_BANK];
|
||||
u8 reg_direction[MAX_BANK];
|
||||
const struct pca95xx_reg *regs;
|
||||
};
|
||||
|
||||
static int pca953x_write_single(struct udevice *dev, int reg, u8 val,
|
||||
|
@ -171,12 +200,13 @@ static int pca953x_is_output(struct udevice *dev, int offset)
|
|||
|
||||
static int pca953x_get_value(struct udevice *dev, uint offset)
|
||||
{
|
||||
struct pca953x_info *info = dev_get_plat(dev);
|
||||
int ret;
|
||||
u8 val = 0;
|
||||
|
||||
int off = offset % BANK_SZ;
|
||||
|
||||
ret = pca953x_read_single(dev, PCA953X_INPUT, &val, offset);
|
||||
ret = pca953x_read_single(dev, info->regs->input, &val, offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -196,7 +226,7 @@ static int pca953x_set_value(struct udevice *dev, uint offset, int value)
|
|||
else
|
||||
val = info->reg_output[bank] & ~(1 << off);
|
||||
|
||||
ret = pca953x_write_single(dev, PCA953X_OUTPUT, val, offset);
|
||||
ret = pca953x_write_single(dev, info->regs->output, val, offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -218,7 +248,7 @@ static int pca953x_set_direction(struct udevice *dev, uint offset, int dir)
|
|||
else
|
||||
val = info->reg_direction[bank] & ~(1 << off);
|
||||
|
||||
ret = pca953x_write_single(dev, PCA953X_DIRECTION, val, offset);
|
||||
ret = pca953x_write_single(dev, info->regs->direction, val, offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -296,14 +326,14 @@ static int pca953x_probe(struct udevice *dev)
|
|||
}
|
||||
|
||||
info->chip_type = PCA_CHIP_TYPE(driver_data);
|
||||
if (info->chip_type != PCA953X_TYPE) {
|
||||
dev_err(dev, "Only support PCA953X chip type now.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (info->chip_type == PCA953X_TYPE)
|
||||
info->regs = &pca953x_regs;
|
||||
else
|
||||
info->regs = &pca957x_regs;
|
||||
|
||||
info->bank_count = DIV_ROUND_UP(info->gpio_count, BANK_SZ);
|
||||
|
||||
ret = pca953x_read_regs(dev, PCA953X_OUTPUT, info->reg_output);
|
||||
ret = pca953x_read_regs(dev, info->regs->output, info->reg_output);
|
||||
if (ret) {
|
||||
dev_err(dev, "Error reading output register\n");
|
||||
return ret;
|
||||
|
@ -327,7 +357,7 @@ static int pca953x_probe(struct udevice *dev)
|
|||
|
||||
/* Clear the polarity registers to no invert */
|
||||
memset(val, 0, MAX_BANK);
|
||||
ret = pca953x_write_regs(dev, PCA953X_INVERT, val);
|
||||
ret = pca953x_write_regs(dev, info->regs->invert, val);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Error writing invert register\n");
|
||||
return ret;
|
||||
|
|
|
@ -579,6 +579,25 @@ int gpio_claim_vector(const int *gpio_num_array, const char *fmt);
|
|||
int gpio_request_by_name(struct udevice *dev, const char *list_name,
|
||||
int index, struct gpio_desc *desc, int flags);
|
||||
|
||||
/* gpio_request_by_line_name - Locate and request a GPIO by line name
|
||||
*
|
||||
* Request a GPIO using the offset of the provided line name in the
|
||||
* gpio-line-names property found in the OF node of the GPIO udevice.
|
||||
*
|
||||
* This allows boards to implement common behaviours using GPIOs while not
|
||||
* requiring specific GPIO offsets be used.
|
||||
*
|
||||
* @dev: An instance of a GPIO controller udevice
|
||||
* @line_name: The name of the GPIO (e.g. "bmc-secure-boot")
|
||||
* @desc: A GPIO descriptor that is populated with the requested GPIO
|
||||
* upon return
|
||||
* @flags: The GPIO settings apply to the request
|
||||
* @return 0 if the named line was found and requested successfully, or a
|
||||
* negative error code if the GPIO cannot be found or the request failed.
|
||||
*/
|
||||
int gpio_request_by_line_name(struct udevice *dev, const char *line_name,
|
||||
struct gpio_desc *desc, int flags);
|
||||
|
||||
/**
|
||||
* gpio_request_list_by_name() - Request a list of GPIOs
|
||||
*
|
||||
|
|
|
@ -1,6 +1,16 @@
|
|||
# SPDX-License-Identifier: GPL-2.0+
|
||||
# SPDX-License-Identifier: GPL-2.0+
|
||||
#
|
||||
# Copyright (c) 2021 Adarsh Babu Kalepalli <opensource.kab@gmail.com>
|
||||
# Copyright (c) 2020 Alex Kiernan <alex.kiernan@gmail.com>
|
||||
|
||||
import pytest
|
||||
import time
|
||||
import u_boot_utils
|
||||
|
||||
"""
|
||||
test_gpio_input is intended to test the fix 4dbc107f4683.
|
||||
4dbc107f4683:"cmd: gpio: Correct do_gpio() return value"
|
||||
"""
|
||||
|
||||
@pytest.mark.boardspec('sandbox')
|
||||
@pytest.mark.buildconfigspec('cmd_gpio')
|
||||
|
@ -35,3 +45,166 @@ def test_gpio_exit_statuses(u_boot_console):
|
|||
assert(expected_response in response)
|
||||
response = u_boot_console.run_command('gpio input 200; echo rc:$?')
|
||||
assert(expected_response in response)
|
||||
|
||||
|
||||
"""
|
||||
Generic Tests for 'gpio' command on sandbox and real hardware.
|
||||
The below sequence of tests rely on env__gpio_dev_config for configuration values of gpio pins.
|
||||
|
||||
Configuration data for gpio command.
|
||||
The set,clear,toggle ,input and status options of 'gpio' command are verified.
|
||||
For sake of verification,A LED/buzzer could be connected to GPIO pins configured as O/P.
|
||||
Logic level '1'/'0' can be applied onto GPIO pins configured as I/P
|
||||
|
||||
|
||||
env__gpio_dev_config = {
|
||||
#the number of 'gpio_str_x' strings should equal to
|
||||
#'gpio_str_count' value
|
||||
'gpio_str_count':4 ,
|
||||
'gpio_str_1': '0',
|
||||
'gpio_str_2': '31',
|
||||
'gpio_str_3': '63',
|
||||
'gpio_str_4': '127',
|
||||
'gpio_op_pin': '64',
|
||||
'gpio_ip_pin_set':'65',
|
||||
'gpio_ip_pin_clear':'66',
|
||||
'gpio_clear_value': 'value is 0',
|
||||
'gpio_set_value': 'value is 1',
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
@pytest.mark.buildconfigspec('cmd_gpio')
|
||||
def test_gpio_status_all_generic(u_boot_console):
|
||||
"""Test the 'gpio status' command.
|
||||
|
||||
Displays all gpio pins available on the Board.
|
||||
To verify if the status of pins is displayed or not,
|
||||
the user can configure (gpio_str_count) and verify existence of certain
|
||||
pins.The details of these can be configured in 'gpio_str_n'.
|
||||
of boardenv_* (example above).User can configure any
|
||||
number of such pins and mention that count in 'gpio_str_count'.
|
||||
"""
|
||||
|
||||
f = u_boot_console.config.env.get('env__gpio_dev_config',False)
|
||||
if not f:
|
||||
pytest.skip("gpio not configured")
|
||||
|
||||
gpio_str_count = f['gpio_str_count']
|
||||
|
||||
#Display all the GPIO ports
|
||||
cmd = 'gpio status -a'
|
||||
response = u_boot_console.run_command(cmd)
|
||||
|
||||
for str_value in range(1,gpio_str_count + 1):
|
||||
assert f["gpio_str_%d" %(str_value)] in response
|
||||
|
||||
|
||||
@pytest.mark.buildconfigspec('cmd_gpio')
|
||||
def test_gpio_set_generic(u_boot_console):
|
||||
"""Test the 'gpio set' command.
|
||||
|
||||
A specific gpio pin configured by user as output
|
||||
(mentioned in gpio_op_pin) is verified for
|
||||
'set' option
|
||||
|
||||
"""
|
||||
|
||||
f = u_boot_console.config.env.get('env__gpio_dev_config',False)
|
||||
if not f:
|
||||
pytest.skip("gpio not configured")
|
||||
|
||||
gpio_pin_adr = f['gpio_op_pin'];
|
||||
gpio_set_value = f['gpio_set_value'];
|
||||
|
||||
|
||||
cmd = 'gpio set ' + gpio_pin_adr
|
||||
response = u_boot_console.run_command(cmd)
|
||||
good_response = gpio_set_value
|
||||
assert good_response in response
|
||||
|
||||
|
||||
|
||||
@pytest.mark.buildconfigspec('cmd_gpio')
|
||||
def test_gpio_clear_generic(u_boot_console):
|
||||
"""Test the 'gpio clear' command.
|
||||
|
||||
A specific gpio pin configured by user as output
|
||||
(mentioned in gpio_op_pin) is verified for
|
||||
'clear' option
|
||||
"""
|
||||
|
||||
f = u_boot_console.config.env.get('env__gpio_dev_config',False)
|
||||
if not f:
|
||||
pytest.skip("gpio not configured")
|
||||
|
||||
gpio_pin_adr = f['gpio_op_pin'];
|
||||
gpio_clear_value = f['gpio_clear_value'];
|
||||
|
||||
|
||||
cmd = 'gpio clear ' + gpio_pin_adr
|
||||
response = u_boot_console.run_command(cmd)
|
||||
good_response = gpio_clear_value
|
||||
assert good_response in response
|
||||
|
||||
|
||||
@pytest.mark.buildconfigspec('cmd_gpio')
|
||||
def test_gpio_toggle_generic(u_boot_console):
|
||||
"""Test the 'gpio toggle' command.
|
||||
|
||||
A specific gpio pin configured by user as output
|
||||
(mentioned in gpio_op_pin) is verified for
|
||||
'toggle' option
|
||||
"""
|
||||
|
||||
|
||||
f = u_boot_console.config.env.get('env__gpio_dev_config',False)
|
||||
if not f:
|
||||
pytest.skip("gpio not configured")
|
||||
|
||||
gpio_pin_adr = f['gpio_op_pin'];
|
||||
gpio_set_value = f['gpio_set_value'];
|
||||
gpio_clear_value = f['gpio_clear_value'];
|
||||
|
||||
cmd = 'gpio set ' + gpio_pin_adr
|
||||
response = u_boot_console.run_command(cmd)
|
||||
good_response = gpio_set_value
|
||||
assert good_response in response
|
||||
|
||||
cmd = 'gpio toggle ' + gpio_pin_adr
|
||||
response = u_boot_console.run_command(cmd)
|
||||
good_response = gpio_clear_value
|
||||
assert good_response in response
|
||||
|
||||
|
||||
@pytest.mark.buildconfigspec('cmd_gpio')
|
||||
def test_gpio_input_generic(u_boot_console):
|
||||
"""Test the 'gpio input' command.
|
||||
|
||||
Specific gpio pins configured by user as input
|
||||
(mentioned in gpio_ip_pin_set and gpio_ip_pin_clear)
|
||||
is verified for logic '1' and logic '0' states
|
||||
"""
|
||||
|
||||
f = u_boot_console.config.env.get('env__gpio_dev_config',False)
|
||||
if not f:
|
||||
pytest.skip("gpio not configured")
|
||||
|
||||
gpio_pin_adr = f['gpio_ip_pin_clear'];
|
||||
gpio_clear_value = f['gpio_clear_value'];
|
||||
|
||||
|
||||
cmd = 'gpio input ' + gpio_pin_adr
|
||||
response = u_boot_console.run_command(cmd)
|
||||
good_response = gpio_clear_value
|
||||
assert good_response in response
|
||||
|
||||
|
||||
gpio_pin_adr = f['gpio_ip_pin_set'];
|
||||
gpio_set_value = f['gpio_set_value'];
|
||||
|
||||
|
||||
cmd = 'gpio input ' + gpio_pin_adr
|
||||
response = u_boot_console.run_command(cmd)
|
||||
good_response = gpio_set_value
|
||||
assert good_response in response
|
||||
|
|
Loading…
Reference in a new issue