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

gpio: of: support gpio-ranges for multiple gpiochip devices

Some drivers (e.g. gpio-mt7621 and gpio-brcmstb) have multiple
gpiochip banks within a single device. Unfortunately, the
gpio-ranges property of the device node was being applied to
every gpiochip of the device with device relative GPIO offset
values rather than gpiochip relative GPIO offset values.

This commit makes use of the gpio_chip offset value which can be
non-zero for such devices to split the device node gpio-ranges
property into GPIO offset ranges that can be applied to each
of the relevant gpiochips of the device.

Signed-off-by: Doug Berger <opendmb@gmail.com>
Acked-by: Florian Fainelli <florian.fainelli@broadcom.com>
Link: https://lore.kernel.org/r/20240424185039.1707812-3-opendmb@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>

authored by

Doug Berger and committed by
Bartosz Golaszewski
e818cd3c 7c66f817

+21 -2
+21 -2
drivers/gpio/gpiolib-of.c
··· 1037 1037 struct of_phandle_args pinspec; 1038 1038 struct pinctrl_dev *pctldev; 1039 1039 struct device_node *np; 1040 - int index = 0, ret; 1040 + int index = 0, ret, trim; 1041 1041 const char *name; 1042 1042 static const char group_names_propname[] = "gpio-ranges-group-names"; 1043 1043 struct property *group_names; ··· 1059 1059 if (!pctldev) 1060 1060 return -EPROBE_DEFER; 1061 1061 1062 + /* Ignore ranges outside of this GPIO chip */ 1063 + if (pinspec.args[0] >= (chip->offset + chip->ngpio)) 1064 + continue; 1065 + if (pinspec.args[0] + pinspec.args[2] <= chip->offset) 1066 + continue; 1067 + 1062 1068 if (pinspec.args[2]) { 1069 + /* npins != 0: linear range */ 1063 1070 if (group_names) { 1064 1071 of_property_read_string_index(np, 1065 1072 group_names_propname, ··· 1077 1070 break; 1078 1071 } 1079 1072 } 1080 - /* npins != 0: linear range */ 1073 + 1074 + /* Trim the range to fit this GPIO chip */ 1075 + if (chip->offset > pinspec.args[0]) { 1076 + trim = chip->offset - pinspec.args[0]; 1077 + pinspec.args[2] -= trim; 1078 + pinspec.args[1] += trim; 1079 + pinspec.args[0] = 0; 1080 + } else { 1081 + pinspec.args[0] -= chip->offset; 1082 + } 1083 + if ((pinspec.args[0] + pinspec.args[2]) > chip->ngpio) 1084 + pinspec.args[2] = chip->ngpio - pinspec.args[0]; 1085 + 1081 1086 ret = gpiochip_add_pin_range(chip, 1082 1087 pinctrl_dev_get_devname(pctldev), 1083 1088 pinspec.args[0],