Add pin output disable support for RZ/G2L alike SoCs by registering with pincontrol core and provide callback mechanism for configuring pin output disable device by matching with device registered with callback against the device found by the core framework for a given function name and device name. Signed-off-by: Biju Das <biju.das.jz@xxxxxxxxxxxxxx> --- v6: * New patch Ref: https://lore.kernel.org/linux-renesas-soc/OS0PR01MB5922F5494D3C0862E15F3F8486B39@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx/T/#t --- drivers/pinctrl/renesas/pinctrl-rzg2l.c | 44 +++++++++++++++++++++++++ include/linux/pinctrl/pinctrl-rzg2l.h | 26 +++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 include/linux/pinctrl/pinctrl-rzg2l.h diff --git a/drivers/pinctrl/renesas/pinctrl-rzg2l.c b/drivers/pinctrl/renesas/pinctrl-rzg2l.c index 04b31f0c6b34..137d085077d8 100644 --- a/drivers/pinctrl/renesas/pinctrl-rzg2l.c +++ b/drivers/pinctrl/renesas/pinctrl-rzg2l.c @@ -17,9 +17,11 @@ #include <linux/spinlock.h> #include <linux/pinctrl/consumer.h> +#include <linux/pinctrl/output-disable.h> #include <linux/pinctrl/pinconf-generic.h> #include <linux/pinctrl/pinconf.h> #include <linux/pinctrl/pinctrl.h> +#include <linux/pinctrl/pinctrl-rzg2l.h> #include <linux/pinctrl/pinmux.h> #include <dt-bindings/pinctrl/rzg2l-pinctrl.h> @@ -136,6 +138,10 @@ struct rzg2l_pinctrl_data { unsigned int n_dedicated_pins; }; +static struct device *rzg2l_poeg_dev; +static output_disable_cb rzg2l_poeg_cb; +static void *rzg2l_poeg_context; + struct rzg2l_pinctrl { struct pinctrl_dev *pctl; struct pinctrl_desc desc; @@ -747,6 +753,28 @@ static int rzg2l_pinctrl_pinconf_group_get(struct pinctrl_dev *pctldev, return 0; }; +static int rzg2l_pinctrl_output_disable_set(struct pinctrl_dev *pctldev, + struct device *dev, + const char *fname, + const char *gname, + enum pin_output_disable_conf conf, + unsigned int conf_val) +{ + struct rzg2l_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev); + + if (!rzg2l_poeg_cb || !rzg2l_poeg_context) { + dev_err(pctrl->dev, "No callback function registered\n"); + return -EINVAL; + } + + if (!rzg2l_poeg_dev || rzg2l_poeg_dev != dev) { + dev_err(pctrl->dev, "Device match failed\n"); + return -EINVAL; + } + + return rzg2l_poeg_cb(rzg2l_poeg_context, fname, gname, conf, conf_val); +} + static const struct pinctrl_ops rzg2l_pinctrl_pctlops = { .get_groups_count = pinctrl_generic_get_group_count, .get_group_name = pinctrl_generic_get_group_name, @@ -772,6 +800,10 @@ static const struct pinconf_ops rzg2l_pinctrl_confops = { .pin_config_config_dbg_show = pinconf_generic_dump_config, }; +static const struct pin_output_disable_ops rzg2l_pinctrl_output_disable_fops = { + .pin_output_disable_config_set = rzg2l_pinctrl_output_disable_set, +}; + static int rzg2l_gpio_request(struct gpio_chip *chip, unsigned int offset) { struct rzg2l_pinctrl *pctrl = gpiochip_get_data(chip); @@ -1320,6 +1352,17 @@ static void rzg2l_init_irq_valid_mask(struct gpio_chip *gc, } } +int rzg2l_output_disable_cb_register(struct device *dev, output_disable_cb cb, + void *cb_context) +{ + rzg2l_poeg_dev = dev; + rzg2l_poeg_cb = cb; + rzg2l_poeg_context = cb_context; + + return 0; +} +EXPORT_SYMBOL_GPL(rzg2l_output_disable_cb_register); + static int rzg2l_gpio_register(struct rzg2l_pinctrl *pctrl) { struct device_node *np = pctrl->dev->of_node; @@ -1404,6 +1447,7 @@ static int rzg2l_pinctrl_register(struct rzg2l_pinctrl *pctrl) pctrl->desc.pctlops = &rzg2l_pinctrl_pctlops; pctrl->desc.pmxops = &rzg2l_pinctrl_pmxops; pctrl->desc.confops = &rzg2l_pinctrl_confops; + pctrl->desc.poutdisops = &rzg2l_pinctrl_output_disable_fops; pctrl->desc.owner = THIS_MODULE; pins = devm_kcalloc(pctrl->dev, pctrl->desc.npins, sizeof(*pins), GFP_KERNEL); diff --git a/include/linux/pinctrl/pinctrl-rzg2l.h b/include/linux/pinctrl/pinctrl-rzg2l.h new file mode 100644 index 000000000000..a49b4c5f8908 --- /dev/null +++ b/include/linux/pinctrl/pinctrl-rzg2l.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __LINUX_PINCTRL_RZG2L_H__ +#define __LINUX_PINCTRL_RZG2L_H__ + +#include <linux/pinctrl/output-disable.h> + +typedef int (*output_disable_cb) (void *context, + const char *fname, + const char *gname, + enum pin_output_disable_conf conf, + unsigned int conf_val); + +#if IS_ENABLED(CONFIG_PINCTRL_RZG2L) +int rzg2l_output_disable_cb_register(struct device *dev, + output_disable_cb cb, + void *cb_context); +#else +static inline int rzg2l_output_disable_cb_register(struct device *dev, + output_disable_cb cb, + void *cb_context) +{ + return -EINVAL; +} +#endif + +#endif /* __LINUX_PINCTRL_RZG2L_H__ */ -- 2.25.1