Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+86 -4
+5 -2
Documentation/admin-guide/gpio/gpio-sim.rst
··· 50 50 51 51 **Attribute:** ``/config/gpio-sim/gpio-device/gpio-bankX/lineY/name`` 52 52 53 - This group represents a single line at the offset Y. The 'name' attribute 54 - allows to set the line name as represented by the 'gpio-line-names' property. 53 + **Attribute:** ``/config/gpio-sim/gpio-device/gpio-bankX/lineY/valid`` 54 + 55 + This group represents a single line at the offset Y. The ``valid`` attribute 56 + indicates whether the line can be used as GPIO. The ``name`` attribute allows 57 + to set the line name as represented by the 'gpio-line-names' property. 55 58 56 59 **Item:** ``/config/gpio-sim/gpio-device/gpio-bankX/lineY/hog`` 57 60
+81 -2
drivers/gpio/gpio-sim.c
··· 39 39 #include "dev-sync-probe.h" 40 40 41 41 #define GPIO_SIM_NGPIO_MAX 1024 42 - #define GPIO_SIM_PROP_MAX 4 /* Max 3 properties + sentinel. */ 42 + #define GPIO_SIM_PROP_MAX 5 /* Max 4 properties + sentinel. */ 43 43 #define GPIO_SIM_NUM_ATTRS 3 /* value, pull and sentinel */ 44 44 45 45 static DEFINE_IDA(gpio_sim_ida); ··· 629 629 630 630 unsigned int offset; 631 631 char *name; 632 + bool valid; 632 633 633 634 /* There can only be one hog per line. */ 634 635 struct gpio_sim_hog *hog; ··· 745 744 } 746 745 } 747 746 747 + static unsigned int gpio_sim_get_reserved_ranges_size(struct gpio_sim_bank *bank) 748 + { 749 + struct gpio_sim_line *line; 750 + unsigned int size = 0; 751 + 752 + list_for_each_entry(line, &bank->line_list, siblings) { 753 + if (line->valid) 754 + continue; 755 + 756 + size += 2; 757 + } 758 + 759 + return size; 760 + } 761 + 762 + static void gpio_sim_set_reserved_ranges(struct gpio_sim_bank *bank, 763 + u32 *ranges) 764 + { 765 + struct gpio_sim_line *line; 766 + int i = 0; 767 + 768 + list_for_each_entry(line, &bank->line_list, siblings) { 769 + if (line->valid) 770 + continue; 771 + 772 + ranges[i++] = line->offset; 773 + ranges[i++] = 1; 774 + } 775 + } 776 + 748 777 static void gpio_sim_remove_hogs(struct gpio_sim_device *dev) 749 778 { 750 779 struct gpiod_hog *hog; ··· 875 844 gpio_sim_make_bank_swnode(struct gpio_sim_bank *bank, 876 845 struct fwnode_handle *parent) 877 846 { 847 + unsigned int prop_idx = 0, line_names_size, ranges_size; 878 848 struct property_entry properties[GPIO_SIM_PROP_MAX]; 879 - unsigned int prop_idx = 0, line_names_size; 880 849 char **line_names __free(kfree) = NULL; 850 + u32 *ranges __free(kfree) = NULL; 881 851 882 852 memset(properties, 0, sizeof(properties)); 883 853 ··· 900 868 properties[prop_idx++] = PROPERTY_ENTRY_STRING_ARRAY_LEN( 901 869 "gpio-line-names", 902 870 line_names, line_names_size); 871 + } 872 + 873 + ranges_size = gpio_sim_get_reserved_ranges_size(bank); 874 + if (ranges_size) { 875 + ranges = kcalloc(ranges_size, sizeof(u32), GFP_KERNEL); 876 + if (!ranges) 877 + return ERR_PTR(-ENOMEM); 878 + 879 + gpio_sim_set_reserved_ranges(bank, ranges); 880 + 881 + properties[prop_idx++] = PROPERTY_ENTRY_U32_ARRAY_LEN( 882 + "gpio-reserved-ranges", 883 + ranges, ranges_size); 903 884 } 904 885 905 886 return fwnode_create_software_node(properties, parent); ··· 1234 1189 1235 1190 CONFIGFS_ATTR(gpio_sim_line_config_, name); 1236 1191 1192 + static ssize_t 1193 + gpio_sim_line_config_valid_show(struct config_item *item, char *page) 1194 + { 1195 + struct gpio_sim_line *line = to_gpio_sim_line(item); 1196 + struct gpio_sim_device *dev = gpio_sim_line_get_device(line); 1197 + 1198 + guard(mutex)(&dev->lock); 1199 + 1200 + return sprintf(page, "%c\n", line->valid ? '1' : '0'); 1201 + } 1202 + 1203 + static ssize_t gpio_sim_line_config_valid_store(struct config_item *item, 1204 + const char *page, size_t count) 1205 + { 1206 + struct gpio_sim_line *line = to_gpio_sim_line(item); 1207 + struct gpio_sim_device *dev = gpio_sim_line_get_device(line); 1208 + bool valid; 1209 + int ret; 1210 + 1211 + ret = kstrtobool(page, &valid); 1212 + if (ret) 1213 + return ret; 1214 + 1215 + guard(mutex)(&dev->lock); 1216 + 1217 + line->valid = valid; 1218 + 1219 + return count; 1220 + } 1221 + 1222 + CONFIGFS_ATTR(gpio_sim_line_config_, valid); 1223 + 1237 1224 static struct configfs_attribute *gpio_sim_line_config_attrs[] = { 1238 1225 &gpio_sim_line_config_attr_name, 1226 + &gpio_sim_line_config_attr_valid, 1239 1227 NULL 1240 1228 }; 1241 1229 ··· 1477 1399 1478 1400 line->parent = bank; 1479 1401 line->offset = offset; 1402 + line->valid = true; 1480 1403 list_add_tail(&line->siblings, &bank->line_list); 1481 1404 1482 1405 return &line->group;