Message ID | 20241226-amlogic-pinctrl-v2-2-cdae42a67b76@amlogic.com |
---|---|
State | Superseded |
Headers | show |
Series | Pinctrl: Add Amlogic pinctrl driver | expand |
Hi Xianwei, kernel test robot noticed the following build warnings: [auto build test WARNING on 4de5110762b94b9978fb8182a568572fb2194f8b] url: https://github.com/intel-lab-lkp/linux/commits/Xianwei-Zhao-via-B4-Relay/dt-bindings-pinctrl-Add-support-for-Amlogic-SoCs/20241226-155844 base: 4de5110762b94b9978fb8182a568572fb2194f8b patch link: https://lore.kernel.org/r/20241226-amlogic-pinctrl-v2-2-cdae42a67b76%40amlogic.com patch subject: [PATCH v2 2/5] pinctrl: pinconf-generic: Add API for pinmux propertity in DTS file config: arc-randconfig-001-20241226 (https://download.01.org/0day-ci/archive/20241226/202412261752.6HK0iJXu-lkp@intel.com/config) compiler: arceb-elf-gcc (GCC) 13.2.0 reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20241226/202412261752.6HK0iJXu-lkp@intel.com/reproduce) If you fix the issue in a separate patch/commit (i.e. not just a new version of the same patch/commit), kindly add following tags | Reported-by: kernel test robot <lkp@intel.com> | Closes: https://lore.kernel.org/oe-kbuild-all/202412261752.6HK0iJXu-lkp@intel.com/ All warnings (new ones prefixed by >>): >> drivers/pinctrl/pinconf-generic.c:250: warning: Function parameter or struct member 'dev' not described in 'pinconf_generic_parse_dt_pinmux' >> drivers/pinctrl/pinconf-generic.c:250: warning: Excess function parameter 'pctldev' description in 'pinconf_generic_parse_dt_pinmux' vim +250 drivers/pinctrl/pinconf-generic.c 235 236 /** 237 * pinconf_generic_parse_dt_pinmux() 238 * parse the pinmux properties into generic pin mux values. 239 * @np: node containing the pinmux properties 240 * @pctldev: pincontrol device 241 * @pid: array with pin identity entries 242 * @pmux: array with pin mux value entries 243 * @npins: number of pins 244 * 245 * pinmux propertity: mux value [0,7]bits and pin identity [8,31]bits. 246 */ 247 int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev, 248 unsigned int **pid, unsigned int **pmux, 249 unsigned int *npins) > 250 { 251 unsigned int *pid_t; 252 unsigned int *pmux_t; 253 struct property *prop; 254 unsigned int npins_t, i; 255 u32 value; 256 int ret; 257 258 prop = of_find_property(np, "pinmux", NULL); 259 if (!prop) { 260 dev_info(dev, "Missing pinmux property\n"); 261 return -ENOENT; 262 } 263 264 if (!pid || !pmux || !npins) { 265 dev_err(dev, "paramers error\n"); 266 return -EINVAL; 267 } 268 269 npins_t = prop->length / sizeof(u32); 270 pid_t = devm_kcalloc(dev, npins_t, sizeof(*pid_t), GFP_KERNEL); 271 pmux_t = devm_kcalloc(dev, npins_t, sizeof(*pmux_t), GFP_KERNEL); 272 if (!pid_t || !pmux_t) { 273 dev_err(dev, "kalloc memory fail\n"); 274 return -ENOMEM; 275 } 276 for (i = 0; i < npins_t; i++) { 277 ret = of_property_read_u32_index(np, "pinmux", i, &value); 278 if (ret) { 279 dev_err(dev, "get pinmux value fail\n"); 280 goto exit; 281 } 282 pmux_t[i] = value & 0xff; 283 pid_t[i] = (value >> 8) & 0xffffff; 284 } 285 *pid = pid_t; 286 *pmux = pmux_t; 287 *npins = npins_t; 288 289 return 0; 290 exit: 291 devm_kfree(dev, pid_t); 292 devm_kfree(dev, pmux_t); 293 return ret; 294 } 295 EXPORT_SYMBOL_GPL(pinconf_generic_parse_dt_pinmux); 296
On Thu, Dec 26, 2024 at 8:57 AM Xianwei Zhao via B4 Relay <devnull+xianwei.zhao.amlogic.com@kernel.org> wrote: > From: Xianwei Zhao <xianwei.zhao@amlogic.com> > > When describing pin mux func through pinmux propertity, > a standard API is added for support. The pinmux contains pin > identification and mux values, which can include multiple > pins. And groups configuration use other word. DTS such as: > > func-name { > group_alias: group-name{ > pinmux= <pin_id << 8 | mux_value)>, > <pin_id << 8 | mux_value)>; > bias-pull-up; > drive-strength-microamp = <4000>; > }; > }; > > Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com> There are some build errors, but I really like the path taken with the utility function here! Yours, Linus Walleij
On Thu 26 Dec 2024 at 15:57, Xianwei Zhao via B4 Relay <devnull+xianwei.zhao.amlogic.com@kernel.org> wrote: > From: Xianwei Zhao <xianwei.zhao@amlogic.com> > > When describing pin mux func through pinmux propertity, > a standard API is added for support. The pinmux contains pin > identification and mux values, which can include multiple > pins. And groups configuration use other word. DTS such as: > > func-name { > group_alias: group-name{ > pinmux= <pin_id << 8 | mux_value)>, > <pin_id << 8 | mux_value)>; This representation does not seem very generic but more tailored to your use-case. > bias-pull-up; > drive-strength-microamp = <4000>; If you want to add pinmux (aka alternate function) selection as a pinconf prop then I think there should be a single pinmux setting per group, and as many groups as you need per function defined. something like func-foo { group-a { groups = "pin_a", "pin_b"; bias-pull-up; alternate-function = <2>; }; group-b { groups = "pin_c""; bias-disable; alternate-function = <5>; }; }; Something similar is already done to handle different pin bias requirement on single function on amlogic platforms: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/amlogic/meson-axg.dtsi?h=v6.13-rc6#n421 > }; > }; > > Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com> > --- > drivers/pinctrl/pinconf-generic.c | 130 ++++++++++++++++++++++++++++++++ > drivers/pinctrl/pinconf.h | 4 + > include/linux/pinctrl/pinconf-generic.h | 4 + > 3 files changed, 138 insertions(+) > > diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c > index 0b13d7f17b32..a4d3c12a80c4 100644 > --- a/drivers/pinctrl/pinconf-generic.c > +++ b/drivers/pinctrl/pinconf-generic.c > @@ -233,6 +233,67 @@ static void parse_dt_cfg(struct device_node *np, > } > } > > +/** > + * pinconf_generic_parse_dt_pinmux() > + * parse the pinmux properties into generic pin mux values. > + * @np: node containing the pinmux properties > + * @pctldev: pincontrol device > + * @pid: array with pin identity entries > + * @pmux: array with pin mux value entries > + * @npins: number of pins > + * > + * pinmux propertity: mux value [0,7]bits and pin identity [8,31]bits. > + */ > +int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev, > + unsigned int **pid, unsigned int **pmux, > + unsigned int *npins) > +{ > + unsigned int *pid_t; > + unsigned int *pmux_t; > + struct property *prop; > + unsigned int npins_t, i; > + u32 value; > + int ret; > + > + prop = of_find_property(np, "pinmux", NULL); > + if (!prop) { > + dev_info(dev, "Missing pinmux property\n"); > + return -ENOENT; > + } > + > + if (!pid || !pmux || !npins) { > + dev_err(dev, "paramers error\n"); > + return -EINVAL; > + } > + > + npins_t = prop->length / sizeof(u32); > + pid_t = devm_kcalloc(dev, npins_t, sizeof(*pid_t), GFP_KERNEL); > + pmux_t = devm_kcalloc(dev, npins_t, sizeof(*pmux_t), GFP_KERNEL); > + if (!pid_t || !pmux_t) { > + dev_err(dev, "kalloc memory fail\n"); > + return -ENOMEM; > + } > + for (i = 0; i < npins_t; i++) { > + ret = of_property_read_u32_index(np, "pinmux", i, &value); > + if (ret) { > + dev_err(dev, "get pinmux value fail\n"); > + goto exit; > + } > + pmux_t[i] = value & 0xff; > + pid_t[i] = (value >> 8) & 0xffffff; > + } > + *pid = pid_t; > + *pmux = pmux_t; > + *npins = npins_t; > + > + return 0; > +exit: > + devm_kfree(dev, pid_t); > + devm_kfree(dev, pmux_t); > + return ret; > +} > +EXPORT_SYMBOL_GPL(pinconf_generic_parse_dt_pinmux); > + > /** > * pinconf_generic_parse_dt_config() > * parse the config properties into generic pinconfig values. > @@ -295,6 +356,75 @@ int pinconf_generic_parse_dt_config(struct device_node *np, > } > EXPORT_SYMBOL_GPL(pinconf_generic_parse_dt_config); > > +int pinconf_generic_dt_node_to_map_pinmux(struct pinctrl_dev *pctldev, > + struct device_node *np, > + struct pinctrl_map **map, > + unsigned int *num_maps) > +{ > + struct device *dev = pctldev->dev; > + struct device_node *pnode; > + unsigned long *configs = NULL; > + unsigned int num_configs = 0; > + struct property *prop; > + unsigned int reserved_maps; > + int reserve; > + int ret; > + > + prop = of_find_property(np, "pinmux", NULL); > + if (!prop) { > + dev_info(dev, "Missing pinmux property\n"); > + return -ENOENT; > + } > + > + pnode = of_get_parent(np); > + if (!pnode) { > + dev_info(dev, "Missing function node\n"); > + return -EINVAL; > + } > + > + reserved_maps = 0; > + *map = NULL; > + *num_maps = 0; > + > + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, > + &num_configs); > + if (ret < 0) { > + dev_err(dev, "%pOF: could not parse node property\n", np); > + return ret; > + } > + > + reserve = 1; > + if (num_configs) > + reserve++; > + > + ret = pinctrl_utils_reserve_map(pctldev, map, &reserved_maps, > + num_maps, reserve); > + if (ret < 0) > + goto exit; > + > + ret = pinctrl_utils_add_map_mux(pctldev, map, > + &reserved_maps, num_maps, np->name, > + pnode->name); > + if (ret < 0) > + goto exit; > + > + if (num_configs) { > + ret = pinctrl_utils_add_map_configs(pctldev, map, &reserved_maps, > + num_maps, np->name, configs, > + num_configs, PIN_MAP_TYPE_CONFIGS_GROUP); > + if (ret < 0) > + goto exit; > + } > + > +exit: > + kfree(configs); > + if (ret) > + pinctrl_utils_free_map(pctldev, *map, *num_maps); > + > + return ret; > +} > +EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map_pinmux); > + > int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, > struct device_node *np, struct pinctrl_map **map, > unsigned int *reserved_maps, unsigned int *num_maps, > diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h > index a14c950bc700..a171195b3615 100644 > --- a/drivers/pinctrl/pinconf.h > +++ b/drivers/pinctrl/pinconf.h > @@ -138,4 +138,8 @@ int pinconf_generic_parse_dt_config(struct device_node *np, > struct pinctrl_dev *pctldev, > unsigned long **configs, > unsigned int *nconfigs); > + > +int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev, > + unsigned int **pid, unsigned int **pmux, > + unsigned int *npins); > #endif > diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h > index 53cfde98433d..1bcf071b860e 100644 > --- a/include/linux/pinctrl/pinconf-generic.h > +++ b/include/linux/pinctrl/pinconf-generic.h > @@ -232,4 +232,8 @@ static inline int pinconf_generic_dt_node_to_map_all(struct pinctrl_dev *pctldev > PIN_MAP_TYPE_INVALID); > } > > +int pinconf_generic_dt_node_to_map_pinmux(struct pinctrl_dev *pctldev, > + struct device_node *np, > + struct pinctrl_map **map, > + unsigned int *num_maps); > #endif /* __LINUX_PINCTRL_PINCONF_GENERIC_H */
Hi Linus, Thanks for your reply. On 2025/1/7 23:18, Linus Walleij wrote: > [ EXTERNAL EMAIL ] > > On Thu, Dec 26, 2024 at 8:57 AM Xianwei Zhao via B4 Relay > <devnull+xianwei.zhao.amlogic.com@kernel.org> wrote: > >> From: Xianwei Zhao <xianwei.zhao@amlogic.com> >> >> When describing pin mux func through pinmux propertity, >> a standard API is added for support. The pinmux contains pin >> identification and mux values, which can include multiple >> pins. And groups configuration use other word. DTS such as: >> >> func-name { >> group_alias: group-name{ >> pinmux= <pin_id << 8 | mux_value)>, >> <pin_id << 8 | mux_value)>; >> bias-pull-up; >> drive-strength-microamp = <4000>; >> }; >> }; >> >> Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com> > > There are some build errors, but I really like the path taken with > the utility function here! > I will fix the issue Reported by kernel test robot next version. > Yours, > Linus Walleij
Hi Jerome, Thanks for your reply. On 2025/1/8 00:47, Jerome Brunet wrote: > [ EXTERNAL EMAIL ] > > On Thu 26 Dec 2024 at 15:57, Xianwei Zhao via B4 Relay <devnull+xianwei.zhao.amlogic.com@kernel.org> wrote: > >> From: Xianwei Zhao <xianwei.zhao@amlogic.com> >> >> When describing pin mux func through pinmux propertity, >> a standard API is added for support. The pinmux contains pin >> identification and mux values, which can include multiple >> pins. And groups configuration use other word. DTS such as: >> >> func-name { >> group_alias: group-name{ >> pinmux= <pin_id << 8 | mux_value)>, >> <pin_id << 8 | mux_value)>; > > This representation does not seem very generic but more tailored to > your use-case https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/Documentation/devicetree/bindings/pinctrl/pinmux-node.yaml?h=next-20250113 The document above includes a description of the pinmux property. This is not my personal usage but rather a common practice, as other manufacturers' drivers also use it in a similar way. However, the specific definitions within pinmux may vary between manufacturers. > >> bias-pull-up; >> drive-strength-microamp = <4000>; > > If you want to add pinmux (aka alternate function) selection as a > pinconf prop then I think there should be a single pinmux setting per > group, and as many groups as you need per function defined. > > something like > > func-foo { > group-a { > groups = "pin_a", "pin_b"; > bias-pull-up; > alternate-function = <2>; > }; > > group-b { > groups = "pin_c""; > bias-disable; > alternate-function = <5>; > }; > }; > > Something similar is already done to handle different pin bias requirement > on single function on amlogic platforms: > > https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/arm64/boot/dts/amlogic/meson-axg.dtsi?h=v6.13-rc6#n421 > > >> }; >> }; >> >> Signed-off-by: Xianwei Zhao <xianwei.zhao@amlogic.com> >> --- >> drivers/pinctrl/pinconf-generic.c | 130 ++++++++++++++++++++++++++++++++ >> drivers/pinctrl/pinconf.h | 4 + >> include/linux/pinctrl/pinconf-generic.h | 4 + >> 3 files changed, 138 insertions(+) >> >> diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c >> index 0b13d7f17b32..a4d3c12a80c4 100644 >> --- a/drivers/pinctrl/pinconf-generic.c >> +++ b/drivers/pinctrl/pinconf-generic.c >> @@ -233,6 +233,67 @@ static void parse_dt_cfg(struct device_node *np, >> } >> } >> >> +/** >> + * pinconf_generic_parse_dt_pinmux() >> + * parse the pinmux properties into generic pin mux values. >> + * @np: node containing the pinmux properties >> + * @pctldev: pincontrol device >> + * @pid: array with pin identity entries >> + * @pmux: array with pin mux value entries >> + * @npins: number of pins >> + * >> + * pinmux propertity: mux value [0,7]bits and pin identity [8,31]bits. >> + */ >> +int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev, >> + unsigned int **pid, unsigned int **pmux, >> + unsigned int *npins) >> +{ >> + unsigned int *pid_t; >> + unsigned int *pmux_t; >> + struct property *prop; >> + unsigned int npins_t, i; >> + u32 value; >> + int ret; >> + >> + prop = of_find_property(np, "pinmux", NULL); >> + if (!prop) { >> + dev_info(dev, "Missing pinmux property\n"); >> + return -ENOENT; >> + } >> + >> + if (!pid || !pmux || !npins) { >> + dev_err(dev, "paramers error\n"); >> + return -EINVAL; >> + } >> + >> + npins_t = prop->length / sizeof(u32); >> + pid_t = devm_kcalloc(dev, npins_t, sizeof(*pid_t), GFP_KERNEL); >> + pmux_t = devm_kcalloc(dev, npins_t, sizeof(*pmux_t), GFP_KERNEL); >> + if (!pid_t || !pmux_t) { >> + dev_err(dev, "kalloc memory fail\n"); >> + return -ENOMEM; >> + } >> + for (i = 0; i < npins_t; i++) { >> + ret = of_property_read_u32_index(np, "pinmux", i, &value); >> + if (ret) { >> + dev_err(dev, "get pinmux value fail\n"); >> + goto exit; >> + } >> + pmux_t[i] = value & 0xff; >> + pid_t[i] = (value >> 8) & 0xffffff; >> + } >> + *pid = pid_t; >> + *pmux = pmux_t; >> + *npins = npins_t; >> + >> + return 0; >> +exit: >> + devm_kfree(dev, pid_t); >> + devm_kfree(dev, pmux_t); >> + return ret; >> +} >> +EXPORT_SYMBOL_GPL(pinconf_generic_parse_dt_pinmux); >> + >> /** >> * pinconf_generic_parse_dt_config() >> * parse the config properties into generic pinconfig values. >> @@ -295,6 +356,75 @@ int pinconf_generic_parse_dt_config(struct device_node *np, >> } >> EXPORT_SYMBOL_GPL(pinconf_generic_parse_dt_config); >> >> +int pinconf_generic_dt_node_to_map_pinmux(struct pinctrl_dev *pctldev, >> + struct device_node *np, >> + struct pinctrl_map **map, >> + unsigned int *num_maps) >> +{ >> + struct device *dev = pctldev->dev; >> + struct device_node *pnode; >> + unsigned long *configs = NULL; >> + unsigned int num_configs = 0; >> + struct property *prop; >> + unsigned int reserved_maps; >> + int reserve; >> + int ret; >> + >> + prop = of_find_property(np, "pinmux", NULL); >> + if (!prop) { >> + dev_info(dev, "Missing pinmux property\n"); >> + return -ENOENT; >> + } >> + >> + pnode = of_get_parent(np); >> + if (!pnode) { >> + dev_info(dev, "Missing function node\n"); >> + return -EINVAL; >> + } >> + >> + reserved_maps = 0; >> + *map = NULL; >> + *num_maps = 0; >> + >> + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, >> + &num_configs); >> + if (ret < 0) { >> + dev_err(dev, "%pOF: could not parse node property\n", np); >> + return ret; >> + } >> + >> + reserve = 1; >> + if (num_configs) >> + reserve++; >> + >> + ret = pinctrl_utils_reserve_map(pctldev, map, &reserved_maps, >> + num_maps, reserve); >> + if (ret < 0) >> + goto exit; >> + >> + ret = pinctrl_utils_add_map_mux(pctldev, map, >> + &reserved_maps, num_maps, np->name, >> + pnode->name); >> + if (ret < 0) >> + goto exit; >> + >> + if (num_configs) { >> + ret = pinctrl_utils_add_map_configs(pctldev, map, &reserved_maps, >> + num_maps, np->name, configs, >> + num_configs, PIN_MAP_TYPE_CONFIGS_GROUP); >> + if (ret < 0) >> + goto exit; >> + } >> + >> +exit: >> + kfree(configs); >> + if (ret) >> + pinctrl_utils_free_map(pctldev, *map, *num_maps); >> + >> + return ret; >> +} >> +EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map_pinmux); >> + >> int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, >> struct device_node *np, struct pinctrl_map **map, >> unsigned int *reserved_maps, unsigned int *num_maps, >> diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h >> index a14c950bc700..a171195b3615 100644 >> --- a/drivers/pinctrl/pinconf.h >> +++ b/drivers/pinctrl/pinconf.h >> @@ -138,4 +138,8 @@ int pinconf_generic_parse_dt_config(struct device_node *np, >> struct pinctrl_dev *pctldev, >> unsigned long **configs, >> unsigned int *nconfigs); >> + >> +int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev, >> + unsigned int **pid, unsigned int **pmux, >> + unsigned int *npins); >> #endif >> diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h >> index 53cfde98433d..1bcf071b860e 100644 >> --- a/include/linux/pinctrl/pinconf-generic.h >> +++ b/include/linux/pinctrl/pinconf-generic.h >> @@ -232,4 +232,8 @@ static inline int pinconf_generic_dt_node_to_map_all(struct pinctrl_dev *pctldev >> PIN_MAP_TYPE_INVALID); >> } >> >> +int pinconf_generic_dt_node_to_map_pinmux(struct pinctrl_dev *pctldev, >> + struct device_node *np, >> + struct pinctrl_map **map, >> + unsigned int *num_maps); >> #endif /* __LINUX_PINCTRL_PINCONF_GENERIC_H */ > > -- > Jerome
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c index 0b13d7f17b32..a4d3c12a80c4 100644 --- a/drivers/pinctrl/pinconf-generic.c +++ b/drivers/pinctrl/pinconf-generic.c @@ -233,6 +233,67 @@ static void parse_dt_cfg(struct device_node *np, } } +/** + * pinconf_generic_parse_dt_pinmux() + * parse the pinmux properties into generic pin mux values. + * @np: node containing the pinmux properties + * @pctldev: pincontrol device + * @pid: array with pin identity entries + * @pmux: array with pin mux value entries + * @npins: number of pins + * + * pinmux propertity: mux value [0,7]bits and pin identity [8,31]bits. + */ +int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev, + unsigned int **pid, unsigned int **pmux, + unsigned int *npins) +{ + unsigned int *pid_t; + unsigned int *pmux_t; + struct property *prop; + unsigned int npins_t, i; + u32 value; + int ret; + + prop = of_find_property(np, "pinmux", NULL); + if (!prop) { + dev_info(dev, "Missing pinmux property\n"); + return -ENOENT; + } + + if (!pid || !pmux || !npins) { + dev_err(dev, "paramers error\n"); + return -EINVAL; + } + + npins_t = prop->length / sizeof(u32); + pid_t = devm_kcalloc(dev, npins_t, sizeof(*pid_t), GFP_KERNEL); + pmux_t = devm_kcalloc(dev, npins_t, sizeof(*pmux_t), GFP_KERNEL); + if (!pid_t || !pmux_t) { + dev_err(dev, "kalloc memory fail\n"); + return -ENOMEM; + } + for (i = 0; i < npins_t; i++) { + ret = of_property_read_u32_index(np, "pinmux", i, &value); + if (ret) { + dev_err(dev, "get pinmux value fail\n"); + goto exit; + } + pmux_t[i] = value & 0xff; + pid_t[i] = (value >> 8) & 0xffffff; + } + *pid = pid_t; + *pmux = pmux_t; + *npins = npins_t; + + return 0; +exit: + devm_kfree(dev, pid_t); + devm_kfree(dev, pmux_t); + return ret; +} +EXPORT_SYMBOL_GPL(pinconf_generic_parse_dt_pinmux); + /** * pinconf_generic_parse_dt_config() * parse the config properties into generic pinconfig values. @@ -295,6 +356,75 @@ int pinconf_generic_parse_dt_config(struct device_node *np, } EXPORT_SYMBOL_GPL(pinconf_generic_parse_dt_config); +int pinconf_generic_dt_node_to_map_pinmux(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *num_maps) +{ + struct device *dev = pctldev->dev; + struct device_node *pnode; + unsigned long *configs = NULL; + unsigned int num_configs = 0; + struct property *prop; + unsigned int reserved_maps; + int reserve; + int ret; + + prop = of_find_property(np, "pinmux", NULL); + if (!prop) { + dev_info(dev, "Missing pinmux property\n"); + return -ENOENT; + } + + pnode = of_get_parent(np); + if (!pnode) { + dev_info(dev, "Missing function node\n"); + return -EINVAL; + } + + reserved_maps = 0; + *map = NULL; + *num_maps = 0; + + ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, + &num_configs); + if (ret < 0) { + dev_err(dev, "%pOF: could not parse node property\n", np); + return ret; + } + + reserve = 1; + if (num_configs) + reserve++; + + ret = pinctrl_utils_reserve_map(pctldev, map, &reserved_maps, + num_maps, reserve); + if (ret < 0) + goto exit; + + ret = pinctrl_utils_add_map_mux(pctldev, map, + &reserved_maps, num_maps, np->name, + pnode->name); + if (ret < 0) + goto exit; + + if (num_configs) { + ret = pinctrl_utils_add_map_configs(pctldev, map, &reserved_maps, + num_maps, np->name, configs, + num_configs, PIN_MAP_TYPE_CONFIGS_GROUP); + if (ret < 0) + goto exit; + } + +exit: + kfree(configs); + if (ret) + pinctrl_utils_free_map(pctldev, *map, *num_maps); + + return ret; +} +EXPORT_SYMBOL_GPL(pinconf_generic_dt_node_to_map_pinmux); + int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev, struct device_node *np, struct pinctrl_map **map, unsigned int *reserved_maps, unsigned int *num_maps, diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h index a14c950bc700..a171195b3615 100644 --- a/drivers/pinctrl/pinconf.h +++ b/drivers/pinctrl/pinconf.h @@ -138,4 +138,8 @@ int pinconf_generic_parse_dt_config(struct device_node *np, struct pinctrl_dev *pctldev, unsigned long **configs, unsigned int *nconfigs); + +int pinconf_generic_parse_dt_pinmux(struct device_node *np, struct device *dev, + unsigned int **pid, unsigned int **pmux, + unsigned int *npins); #endif diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h index 53cfde98433d..1bcf071b860e 100644 --- a/include/linux/pinctrl/pinconf-generic.h +++ b/include/linux/pinctrl/pinconf-generic.h @@ -232,4 +232,8 @@ static inline int pinconf_generic_dt_node_to_map_all(struct pinctrl_dev *pctldev PIN_MAP_TYPE_INVALID); } +int pinconf_generic_dt_node_to_map_pinmux(struct pinctrl_dev *pctldev, + struct device_node *np, + struct pinctrl_map **map, + unsigned int *num_maps); #endif /* __LINUX_PINCTRL_PINCONF_GENERIC_H */