diff options
Diffstat (limited to 'drivers/gpio/gpio-sim.c')
| -rw-r--r-- | drivers/gpio/gpio-sim.c | 87 | 
1 files changed, 83 insertions, 4 deletions
diff --git a/drivers/gpio/gpio-sim.c b/drivers/gpio/gpio-sim.c index f638219a7c4f..050092583f79 100644 --- a/drivers/gpio/gpio-sim.c +++ b/drivers/gpio/gpio-sim.c @@ -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); @@ -486,9 +486,9 @@ static int gpio_sim_add_bank(struct fwnode_handle *swnode, struct device *dev)  	gc->parent = dev;  	gc->fwnode = swnode;  	gc->get = gpio_sim_get; -	gc->set_rv = gpio_sim_set; +	gc->set = gpio_sim_set;  	gc->get_multiple = gpio_sim_get_multiple; -	gc->set_multiple_rv = gpio_sim_set_multiple; +	gc->set_multiple = gpio_sim_set_multiple;  	gc->direction_output = gpio_sim_direction_output;  	gc->direction_input = gpio_sim_direction_input;  	gc->get_direction = gpio_sim_get_direction; @@ -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;  | 
