gpio: sim: allow to mark simulated lines as invalid

Add a new line-level, boolean property to the gpio-sim configfs
interface called 'valid'. It's set by default and the user can unset it
to make the line be included in the standard `gpio-reserved-ranges`
property when the chip is registered with GPIO core. This allows users
to specify which lines should not be available for requesting as GPIOs.

Link: https://lore.kernel.org/r/20250630130358.40352-1-brgl@bgdev.pl
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
pull/1309/head
Bartosz Golaszewski 2025-06-30 15:03:57 +02:00
parent 6c99a046ed
commit 0cf6d425d3
2 changed files with 86 additions and 4 deletions

View File

@ -50,8 +50,11 @@ the number of lines exposed by this bank.
**Attribute:** ``/config/gpio-sim/gpio-device/gpio-bankX/lineY/name``
This group represents a single line at the offset Y. The 'name' attribute
allows to set the line name as represented by the 'gpio-line-names' property.
**Attribute:** ``/config/gpio-sim/gpio-device/gpio-bankX/lineY/valid``
This group represents a single line at the offset Y. The ``valid`` attribute
indicates whether the line can be used as GPIO. The ``name`` attribute allows
to set the line name as represented by the 'gpio-line-names' property.
**Item:** ``/config/gpio-sim/gpio-device/gpio-bankX/lineY/hog``

View File

@ -39,7 +39,7 @@
#include "dev-sync-probe.h"
#define GPIO_SIM_NGPIO_MAX 1024
#define GPIO_SIM_PROP_MAX 4 /* Max 3 properties + sentinel. */
#define GPIO_SIM_PROP_MAX 5 /* Max 4 properties + sentinel. */
#define GPIO_SIM_NUM_ATTRS 3 /* value, pull and sentinel */
static DEFINE_IDA(gpio_sim_ida);
@ -629,6 +629,7 @@ struct gpio_sim_line {
unsigned int offset;
char *name;
bool valid;
/* There can only be one hog per line. */
struct gpio_sim_hog *hog;
@ -744,6 +745,36 @@ gpio_sim_set_line_names(struct gpio_sim_bank *bank, char **line_names)
}
}
static unsigned int gpio_sim_get_reserved_ranges_size(struct gpio_sim_bank *bank)
{
struct gpio_sim_line *line;
unsigned int size = 0;
list_for_each_entry(line, &bank->line_list, siblings) {
if (line->valid)
continue;
size += 2;
}
return size;
}
static void gpio_sim_set_reserved_ranges(struct gpio_sim_bank *bank,
u32 *ranges)
{
struct gpio_sim_line *line;
int i = 0;
list_for_each_entry(line, &bank->line_list, siblings) {
if (line->valid)
continue;
ranges[i++] = line->offset;
ranges[i++] = 1;
}
}
static void gpio_sim_remove_hogs(struct gpio_sim_device *dev)
{
struct gpiod_hog *hog;
@ -844,9 +875,10 @@ static struct fwnode_handle *
gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank,
struct fwnode_handle *parent)
{
unsigned int prop_idx = 0, line_names_size, ranges_size;
struct property_entry properties[GPIO_SIM_PROP_MAX];
unsigned int prop_idx = 0, line_names_size;
char **line_names __free(kfree) = NULL;
u32 *ranges __free(kfree) = NULL;
memset(properties, 0, sizeof(properties));
@ -870,6 +902,19 @@ gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank,
line_names, line_names_size);
}
ranges_size = gpio_sim_get_reserved_ranges_size(bank);
if (ranges_size) {
ranges = kcalloc(ranges_size, sizeof(u32), GFP_KERNEL);
if (!ranges)
return ERR_PTR(-ENOMEM);
gpio_sim_set_reserved_ranges(bank, ranges);
properties[prop_idx++] = PROPERTY_ENTRY_U32_ARRAY_LEN(
"gpio-reserved-ranges",
ranges, ranges_size);
}
return fwnode_create_software_node(properties, parent);
}
@ -1189,8 +1234,41 @@ static ssize_t gpio_sim_line_config_name_store(struct config_item *item,
CONFIGFS_ATTR(gpio_sim_line_config_, name);
static ssize_t
gpio_sim_line_config_valid_show(struct config_item *item, char *page)
{
struct gpio_sim_line *line = to_gpio_sim_line(item);
struct gpio_sim_device *dev = gpio_sim_line_get_device(line);
guard(mutex)(&dev->lock);
return sprintf(page, "%c\n", line->valid ? '1' : '0');
}
static ssize_t gpio_sim_line_config_valid_store(struct config_item *item,
const char *page, size_t count)
{
struct gpio_sim_line *line = to_gpio_sim_line(item);
struct gpio_sim_device *dev = gpio_sim_line_get_device(line);
bool valid;
int ret;
ret = kstrtobool(page, &valid);
if (ret)
return ret;
guard(mutex)(&dev->lock);
line->valid = valid;
return count;
}
CONFIGFS_ATTR(gpio_sim_line_config_, valid);
static struct configfs_attribute *gpio_sim_line_config_attrs[] = {
&gpio_sim_line_config_attr_name,
&gpio_sim_line_config_attr_valid,
NULL
};
@ -1399,6 +1477,7 @@ gpio_sim_bank_config_make_line_group(struct config_group *group,
line->parent = bank;
line->offset = offset;
line->valid = true;
list_add_tail(&line->siblings, &bank->line_list);
return &line->group;