diff options
author | Tom Rini <trini@konsulko.com> | 2022-04-10 11:19:14 -0400 |
---|---|---|
committer | Tom Rini <trini@konsulko.com> | 2022-04-10 11:19:14 -0400 |
commit | 22b7d140fa17a15e85b87cd7258fa4ff190a11a3 (patch) | |
tree | c8eb4bb3e20292dc879416ff5b9a5108b8730d04 | |
parent | d46e86d25c2a504b3e2e4ab17d70b2f0be440f34 (diff) | |
parent | c170fe0a77738df1344a805acfe53133e5d15e43 (diff) |
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'
-rw-r--r-- | common/spl/spl.c | 4 | ||||
-rw-r--r-- | drivers/gpio/Kconfig | 9 | ||||
-rw-r--r-- | drivers/gpio/gpio-uclass.c | 34 | ||||
-rw-r--r-- | drivers/gpio/pca953x_gpio.c | 50 | ||||
-rw-r--r-- | include/asm-generic/gpio.h | 19 | ||||
-rw-r--r-- | test/py/tests/test_gpio.py | 175 |
6 files changed, 276 insertions, 15 deletions
diff --git a/common/spl/spl.c b/common/spl/spl.c index b452d4feeb..c9750ee163 100644 --- a/common/spl/spl.c +++ b/common/spl/spl.c @@ -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 diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index a55e368693..89068c7800 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -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 diff --git a/drivers/gpio/gpio-uclass.c b/drivers/gpio/gpio-uclass.c index 125ae53d61..0ed32b7217 100644 --- a/drivers/gpio/gpio-uclass.c +++ b/drivers/gpio/gpio-uclass.c @@ -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); diff --git a/drivers/gpio/pca953x_gpio.c b/drivers/gpio/pca953x_gpio.c index dc8911a8eb..e98e1e56db 100644 --- a/drivers/gpio/pca953x_gpio.c +++ b/drivers/gpio/pca953x_gpio.c @@ -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; diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h index adc19e9765..81f63f06f1 100644 --- a/include/asm-generic/gpio.h +++ b/include/asm-generic/gpio.h @@ -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 * diff --git a/test/py/tests/test_gpio.py b/test/py/tests/test_gpio.py index 8c64f686b0..109649e2c7 100644 --- a/test/py/tests/test_gpio.py +++ b/test/py/tests/test_gpio.py @@ -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 |