From 3cac991e33b1395430c09ae49039702eb6748c7d Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Tue, 5 Dec 2017 15:46:39 +0100 Subject: [PATCH 1/8] gpio: axp209: switch unsigned variables to unsigned int Checkpatch complains with the following message: WARNING: Prefer 'unsigned int' to bare use of 'unsigned' Let's make it happy by switching over to unsigned int. Signed-off-by: Quentin Schulz Signed-off-by: Linus Walleij --- drivers/gpio/gpio-axp209.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-axp209.c b/drivers/gpio/gpio-axp209.c index 4a346b7b4172..6ee7dc1418fa 100644 --- a/drivers/gpio/gpio-axp209.c +++ b/drivers/gpio/gpio-axp209.c @@ -32,7 +32,7 @@ struct axp20x_gpio { struct regmap *regmap; }; -static int axp20x_gpio_get_reg(unsigned offset) +static int axp20x_gpio_get_reg(unsigned int offset) { switch (offset) { case 0: @@ -46,7 +46,7 @@ static int axp20x_gpio_get_reg(unsigned offset) return -EINVAL; } -static int axp20x_gpio_input(struct gpio_chip *chip, unsigned offset) +static int axp20x_gpio_input(struct gpio_chip *chip, unsigned int offset) { struct axp20x_gpio *gpio = gpiochip_get_data(chip); int reg; @@ -60,7 +60,7 @@ static int axp20x_gpio_input(struct gpio_chip *chip, unsigned offset) AXP20X_GPIO_FUNCTION_INPUT); } -static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset) +static int axp20x_gpio_get(struct gpio_chip *chip, unsigned int offset) { struct axp20x_gpio *gpio = gpiochip_get_data(chip); unsigned int val; @@ -73,7 +73,8 @@ static int axp20x_gpio_get(struct gpio_chip *chip, unsigned offset) return !!(val & BIT(offset + 4)); } -static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) +static int axp20x_gpio_get_direction(struct gpio_chip *chip, + unsigned int offset) { struct axp20x_gpio *gpio = gpiochip_get_data(chip); unsigned int val; @@ -102,7 +103,7 @@ static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned offset) return val & 2; } -static int axp20x_gpio_output(struct gpio_chip *chip, unsigned offset, +static int axp20x_gpio_output(struct gpio_chip *chip, unsigned int offset, int value) { struct axp20x_gpio *gpio = gpiochip_get_data(chip); @@ -118,7 +119,7 @@ static int axp20x_gpio_output(struct gpio_chip *chip, unsigned offset, : AXP20X_GPIO_FUNCTION_OUT_LOW); } -static void axp20x_gpio_set(struct gpio_chip *chip, unsigned offset, +static void axp20x_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { axp20x_gpio_output(chip, offset, value); From 449317a8b4c4ed47c2a51f864c4697ae57195b96 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Tue, 5 Dec 2017 15:46:40 +0100 Subject: [PATCH 2/8] pinctrl: move gpio-axp209 to pinctrl To prepare the driver for the upcoming pinctrl features, move the GPIO driver AXP209 from GPIO to pinctrl subsystem. Signed-off-by: Quentin Schulz Acked-by: Maxime Ripard Acked-by: Chen-Yu Tsai Signed-off-by: Linus Walleij --- drivers/gpio/Kconfig | 6 ------ drivers/gpio/Makefile | 1 - drivers/pinctrl/Kconfig | 10 ++++++++++ drivers/pinctrl/Makefile | 1 + .../{gpio/gpio-axp209.c => pinctrl/pinctrl-axp209.c} | 0 5 files changed, 11 insertions(+), 7 deletions(-) rename drivers/{gpio/gpio-axp209.c => pinctrl/pinctrl-axp209.c} (100%) diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index d6a8e851ad13..395669bfcc26 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -122,12 +122,6 @@ config GPIO_ATH79 Select this option to enable GPIO driver for Atheros AR71XX/AR724X/AR913X SoC devices. -config GPIO_AXP209 - tristate "X-Powers AXP209 PMIC GPIO Support" - depends on MFD_AXP20X - help - Say yes to enable GPIO support for the AXP209 PMIC - config GPIO_BCM_KONA bool "Broadcom Kona GPIO" depends on OF_GPIO && (ARCH_BCM_MOBILE || COMPILE_TEST) diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile index 4bc24febb889..bc5dd673fa11 100644 --- a/drivers/gpio/Makefile +++ b/drivers/gpio/Makefile @@ -32,7 +32,6 @@ obj-$(CONFIG_GPIO_AMDPT) += gpio-amdpt.o obj-$(CONFIG_GPIO_ARIZONA) += gpio-arizona.o obj-$(CONFIG_GPIO_ATH79) += gpio-ath79.o obj-$(CONFIG_GPIO_ASPEED) += gpio-aspeed.o -obj-$(CONFIG_GPIO_AXP209) += gpio-axp209.o obj-$(CONFIG_GPIO_BCM_KONA) += gpio-bcm-kona.o obj-$(CONFIG_GPIO_BD9571MWV) += gpio-bd9571mwv.o obj-$(CONFIG_GPIO_BRCMSTB) += gpio-brcmstb.o diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig index 4571cc098b76..ce126955212c 100644 --- a/drivers/pinctrl/Kconfig +++ b/drivers/pinctrl/Kconfig @@ -63,6 +63,16 @@ config PINCTRL_AS3722 open drain configuration for the GPIO pins of AS3722 devices. It also supports the GPIO functionality through gpiolib. +config PINCTRL_AXP209 + tristate "X-Powers AXP209 PMIC pinctrl and GPIO Support" + depends on MFD_AXP20X + help + AXP PMICs provides multiple GPIOs that can be muxed for different + functions. This driver bundles a pinctrl driver to select the function + muxing and a GPIO driver to handle the GPIO when the GPIO function is + selected. + Say yes to enable pinctrl and GPIO support for the AXP209 PMIC + config PINCTRL_BF54x def_bool y if BF54x select PINCTRL_ADI2 diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile index d0d4844f8022..4777f1595ce2 100644 --- a/drivers/pinctrl/Makefile +++ b/drivers/pinctrl/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_GENERIC_PINCONF) += pinconf-generic.o obj-$(CONFIG_PINCTRL_ADI2) += pinctrl-adi2.o obj-$(CONFIG_PINCTRL_ARTPEC6) += pinctrl-artpec6.o obj-$(CONFIG_PINCTRL_AS3722) += pinctrl-as3722.o +obj-$(CONFIG_PINCTRL_AXP209) += pinctrl-axp209.o obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o diff --git a/drivers/gpio/gpio-axp209.c b/drivers/pinctrl/pinctrl-axp209.c similarity index 100% rename from drivers/gpio/gpio-axp209.c rename to drivers/pinctrl/pinctrl-axp209.c From 23f75d7dfa92132e08e31640e0f641dcdea781b9 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Tue, 5 Dec 2017 15:46:41 +0100 Subject: [PATCH 3/8] pinctrl: axp209: add pinctrl features The X-Powers AXP209 has 3 GPIOs. GPIO0/1 can each act either as a GPIO, an ADC or a LDO regulator. GPIO2 can only act as a GPIO. This adds the pinctrl features to the driver so GPIO0/1 can be used as ADC or LDO regulator. Signed-off-by: Quentin Schulz Acked-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-axp209.c | 304 +++++++++++++++++++++++++++++-- 1 file changed, 284 insertions(+), 20 deletions(-) diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c index 6ee7dc1418fa..48cb57dcc575 100644 --- a/drivers/pinctrl/pinctrl-axp209.c +++ b/drivers/pinctrl/pinctrl-axp209.c @@ -1,7 +1,8 @@ /* - * AXP20x GPIO driver + * AXP20x pinctrl and GPIO driver * * Copyright (C) 2016 Maxime Ripard + * Copyright (C) 2017 Quentin Schulz * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the @@ -18,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include #include @@ -27,9 +31,52 @@ #define AXP20X_GPIO_FUNCTION_OUT_HIGH 1 #define AXP20X_GPIO_FUNCTION_INPUT 2 +#define AXP20X_FUNC_GPIO_OUT 0 +#define AXP20X_FUNC_GPIO_IN 1 +#define AXP20X_FUNC_LDO 2 +#define AXP20X_FUNC_ADC 3 +#define AXP20X_FUNCS_NB 4 + +#define AXP20X_MUX_GPIO_OUT 0 +#define AXP20X_MUX_GPIO_IN BIT(1) +#define AXP20X_MUX_ADC BIT(2) + +struct axp20x_pctrl_desc { + const struct pinctrl_pin_desc *pins; + unsigned int npins; + /* Stores the pins supporting LDO function. Bit offset is pin number. */ + u8 ldo_mask; + /* Stores the pins supporting ADC function. Bit offset is pin number. */ + u8 adc_mask; +}; + +struct axp20x_pinctrl_function { + const char *name; + unsigned int muxval; + const char **groups; + unsigned int ngroups; +}; + struct axp20x_gpio { struct gpio_chip chip; struct regmap *regmap; + struct pinctrl_dev *pctl_dev; + struct device *dev; + const struct axp20x_pctrl_desc *desc; + struct axp20x_pinctrl_function funcs[AXP20X_FUNCS_NB]; +}; + +static const struct pinctrl_pin_desc axp209_pins[] = { + PINCTRL_PIN(0, "GPIO0"), + PINCTRL_PIN(1, "GPIO1"), + PINCTRL_PIN(2, "GPIO2"), +}; + +static const struct axp20x_pctrl_desc axp20x_data = { + .pins = axp209_pins, + .npins = ARRAY_SIZE(axp209_pins), + .ldo_mask = BIT(0) | BIT(1), + .adc_mask = BIT(0) | BIT(1), }; static int axp20x_gpio_get_reg(unsigned int offset) @@ -48,16 +95,7 @@ static int axp20x_gpio_get_reg(unsigned int offset) static int axp20x_gpio_input(struct gpio_chip *chip, unsigned int offset) { - struct axp20x_gpio *gpio = gpiochip_get_data(chip); - int reg; - - reg = axp20x_gpio_get_reg(offset); - if (reg < 0) - return reg; - - return regmap_update_bits(gpio->regmap, reg, - AXP20X_GPIO_FUNCTIONS, - AXP20X_GPIO_FUNCTION_INPUT); + return pinctrl_gpio_direction_input(chip->base + offset); } static int axp20x_gpio_get(struct gpio_chip *chip, unsigned int offset) @@ -105,30 +143,221 @@ static int axp20x_gpio_get_direction(struct gpio_chip *chip, static int axp20x_gpio_output(struct gpio_chip *chip, unsigned int offset, int value) +{ + chip->set(chip, offset, value); + + return 0; +} + +static void axp20x_gpio_set(struct gpio_chip *chip, unsigned int offset, + int value) { struct axp20x_gpio *gpio = gpiochip_get_data(chip); int reg; + reg = axp20x_gpio_get_reg(offset); + if (reg < 0) + return; + + regmap_update_bits(gpio->regmap, reg, + AXP20X_GPIO_FUNCTIONS, + value ? AXP20X_GPIO_FUNCTION_OUT_HIGH : + AXP20X_GPIO_FUNCTION_OUT_LOW); +} + +static int axp20x_pmx_set(struct pinctrl_dev *pctldev, unsigned int offset, + u8 config) +{ + struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + int reg; + reg = axp20x_gpio_get_reg(offset); if (reg < 0) return reg; - return regmap_update_bits(gpio->regmap, reg, - AXP20X_GPIO_FUNCTIONS, - value ? AXP20X_GPIO_FUNCTION_OUT_HIGH - : AXP20X_GPIO_FUNCTION_OUT_LOW); + return regmap_update_bits(gpio->regmap, reg, AXP20X_GPIO_FUNCTIONS, + config); } -static void axp20x_gpio_set(struct gpio_chip *chip, unsigned int offset, - int value) +static int axp20x_pmx_func_cnt(struct pinctrl_dev *pctldev) { - axp20x_gpio_output(chip, offset, value); + struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + + return ARRAY_SIZE(gpio->funcs); +} + +static const char *axp20x_pmx_func_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + + return gpio->funcs[selector].name; +} + +static int axp20x_pmx_func_groups(struct pinctrl_dev *pctldev, + unsigned int selector, + const char * const **groups, + unsigned int *num_groups) +{ + struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + + *groups = gpio->funcs[selector].groups; + *num_groups = gpio->funcs[selector].ngroups; + + return 0; +} + +static int axp20x_pmx_set_mux(struct pinctrl_dev *pctldev, + unsigned int function, unsigned int group) +{ + struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + unsigned int mask; + + /* Every pin supports GPIO_OUT and GPIO_IN functions */ + if (function <= AXP20X_FUNC_GPIO_IN) + return axp20x_pmx_set(pctldev, group, + gpio->funcs[function].muxval); + + if (function == AXP20X_FUNC_LDO) + mask = gpio->desc->ldo_mask; + else + mask = gpio->desc->adc_mask; + + if (!(BIT(group) & mask)) + return -EINVAL; + + /* + * We let the regulator framework handle the LDO muxing as muxing bits + * are basically also regulators on/off bits. It's better not to enforce + * any state of the regulator when selecting LDO mux so that we don't + * interfere with the regulator driver. + */ + if (function == AXP20X_FUNC_LDO) + return 0; + + return axp20x_pmx_set(pctldev, group, gpio->funcs[function].muxval); +} + +static int axp20x_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, + struct pinctrl_gpio_range *range, + unsigned int offset, bool input) +{ + struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + + if (input) + return axp20x_pmx_set(pctldev, offset, + gpio->funcs[AXP20X_FUNC_GPIO_IN].muxval); + + return axp20x_pmx_set(pctldev, offset, + gpio->funcs[AXP20X_FUNC_GPIO_OUT].muxval); +} + +static const struct pinmux_ops axp20x_pmx_ops = { + .get_functions_count = axp20x_pmx_func_cnt, + .get_function_name = axp20x_pmx_func_name, + .get_function_groups = axp20x_pmx_func_groups, + .set_mux = axp20x_pmx_set_mux, + .gpio_set_direction = axp20x_pmx_gpio_set_direction, + .strict = true, +}; + +static int axp20x_groups_cnt(struct pinctrl_dev *pctldev) +{ + struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + + return gpio->desc->npins; +} + +static int axp20x_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, + const unsigned int **pins, unsigned int *num_pins) +{ + struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + + *pins = (unsigned int *)&gpio->desc->pins[selector]; + *num_pins = 1; + + return 0; +} + +static const char *axp20x_group_name(struct pinctrl_dev *pctldev, + unsigned int selector) +{ + struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + + return gpio->desc->pins[selector].name; +} + +static const struct pinctrl_ops axp20x_pctrl_ops = { + .dt_node_to_map = pinconf_generic_dt_node_to_map_group, + .dt_free_map = pinconf_generic_dt_free_map, + .get_groups_count = axp20x_groups_cnt, + .get_group_name = axp20x_group_name, + .get_group_pins = axp20x_group_pins, +}; + +static void axp20x_funcs_groups_from_mask(struct device *dev, unsigned int mask, + unsigned int mask_len, + struct axp20x_pinctrl_function *func, + const struct pinctrl_pin_desc *pins) +{ + unsigned long int mask_cpy = mask; + const char **group; + unsigned int ngroups = hweight8(mask); + int bit; + + func->ngroups = ngroups; + if (func->ngroups > 0) { + func->groups = devm_kzalloc(dev, ngroups * sizeof(const char *), + GFP_KERNEL); + group = func->groups; + for_each_set_bit(bit, &mask_cpy, mask_len) { + *group = pins[bit].name; + group++; + } + } +} + +static void axp20x_build_funcs_groups(struct platform_device *pdev) +{ + struct axp20x_gpio *gpio = platform_get_drvdata(pdev); + int i, pin, npins = gpio->desc->npins; + + gpio->funcs[AXP20X_FUNC_GPIO_OUT].name = "gpio_out"; + gpio->funcs[AXP20X_FUNC_GPIO_OUT].muxval = AXP20X_MUX_GPIO_OUT; + gpio->funcs[AXP20X_FUNC_GPIO_IN].name = "gpio_in"; + gpio->funcs[AXP20X_FUNC_GPIO_IN].muxval = AXP20X_MUX_GPIO_IN; + gpio->funcs[AXP20X_FUNC_LDO].name = "ldo"; + /* + * Muxval for LDO is useless as we won't use it. + * See comment in axp20x_pmx_set_mux. + */ + gpio->funcs[AXP20X_FUNC_ADC].name = "adc"; + gpio->funcs[AXP20X_FUNC_ADC].muxval = AXP20X_MUX_ADC; + + /* Every pin supports GPIO_OUT and GPIO_IN functions */ + for (i = 0; i <= AXP20X_FUNC_GPIO_IN; i++) { + gpio->funcs[i].ngroups = npins; + gpio->funcs[i].groups = devm_kzalloc(&pdev->dev, + npins * sizeof(char *), + GFP_KERNEL); + for (pin = 0; pin < npins; pin++) + gpio->funcs[i].groups[pin] = gpio->desc->pins[pin].name; + } + + axp20x_funcs_groups_from_mask(&pdev->dev, gpio->desc->ldo_mask, + npins, &gpio->funcs[AXP20X_FUNC_LDO], + gpio->desc->pins); + + axp20x_funcs_groups_from_mask(&pdev->dev, gpio->desc->adc_mask, + npins, &gpio->funcs[AXP20X_FUNC_ADC], + gpio->desc->pins); } static int axp20x_gpio_probe(struct platform_device *pdev) { struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); struct axp20x_gpio *gpio; + struct pinctrl_desc *pctrl_desc; int ret; if (!of_device_is_available(pdev->dev.of_node)) @@ -145,6 +374,8 @@ static int axp20x_gpio_probe(struct platform_device *pdev) gpio->chip.base = -1; gpio->chip.can_sleep = true; + gpio->chip.request = gpiochip_generic_request; + gpio->chip.free = gpiochip_generic_free; gpio->chip.parent = &pdev->dev; gpio->chip.label = dev_name(&pdev->dev); gpio->chip.owner = THIS_MODULE; @@ -155,7 +386,30 @@ static int axp20x_gpio_probe(struct platform_device *pdev) gpio->chip.direction_output = axp20x_gpio_output; gpio->chip.ngpio = 3; + gpio->desc = &axp20x_data; gpio->regmap = axp20x->regmap; + gpio->dev = &pdev->dev; + + platform_set_drvdata(pdev, gpio); + + axp20x_build_funcs_groups(pdev); + + pctrl_desc = devm_kzalloc(&pdev->dev, sizeof(*pctrl_desc), GFP_KERNEL); + if (!pctrl_desc) + return -ENOMEM; + + pctrl_desc->name = dev_name(&pdev->dev); + pctrl_desc->owner = THIS_MODULE; + pctrl_desc->pins = gpio->desc->pins; + pctrl_desc->npins = gpio->desc->npins; + pctrl_desc->pctlops = &axp20x_pctrl_ops; + pctrl_desc->pmxops = &axp20x_pmx_ops; + + gpio->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, gpio); + if (IS_ERR(gpio->pctl_dev)) { + dev_err(&pdev->dev, "couldn't register pinctrl driver\n"); + return PTR_ERR(gpio->pctl_dev); + } ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); if (ret) { @@ -163,7 +417,16 @@ static int axp20x_gpio_probe(struct platform_device *pdev) return ret; } - dev_info(&pdev->dev, "AXP209 GPIO driver loaded\n"); + ret = gpiochip_add_pin_range(&gpio->chip, dev_name(&pdev->dev), + gpio->desc->pins->number, + gpio->desc->pins->number, + gpio->desc->npins); + if (ret) { + dev_err(&pdev->dev, "failed to add pin range\n"); + return ret; + } + + dev_info(&pdev->dev, "AXP209 pinctrl and GPIO driver loaded\n"); return 0; } @@ -185,5 +448,6 @@ static struct platform_driver axp20x_gpio_driver = { module_platform_driver(axp20x_gpio_driver); MODULE_AUTHOR("Maxime Ripard "); -MODULE_DESCRIPTION("AXP20x PMIC GPIO driver"); +MODULE_AUTHOR("Quentin Schulz "); +MODULE_DESCRIPTION("AXP20x PMIC pinctrl and GPIO driver"); MODULE_LICENSE("GPL"); From f17aea430fff4b95ac94e8625096cd82544e9054 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Tue, 5 Dec 2017 15:46:42 +0100 Subject: [PATCH 4/8] dt-bindings: gpio: gpio-axp209: add pinctrl features The X-Powers AXP209 has 3 GPIOs. GPIO0/1 can each act either as a GPIO, an ADC or a LDO regulator. GPIO2 can only act as a GPIO. This adds the pinctrl features to the driver so GPIO0/1 can be used as ADC or LDO regulator. Signed-off-by: Quentin Schulz Acked-by: Rob Herring Acked-by: Maxime Ripard Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio-axp209.txt | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt index a6611304dd3c..0d77597c3f92 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt @@ -1,8 +1,13 @@ -AXP209 GPIO controller +AXP209 GPIO & pinctrl controller This driver follows the usual GPIO bindings found in Documentation/devicetree/bindings/gpio/gpio.txt +This driver follows the usual pinctrl bindings found in +Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt + +This driver employs the per-pin muxing pattern. + Required properties: - compatible: Should be "x-powers,axp209-gpio" - #gpio-cells: Should be two. The first cell is the pin number and the @@ -28,3 +33,32 @@ axp209: pmic@34 { #gpio-cells = <2>; }; }; + +The GPIOs can be muxed to other functions and therefore, must be a subnode of +axp_gpio. + +Example: + +&axp_gpio { + gpio0_adc: gpio0-adc { + pins = "GPIO0"; + function = "adc"; + }; +}; + +&example_node { + pinctrl-names = "default"; + pinctrl-0 = <&gpio0_adc>; +}; + +GPIOs and their functions +------------------------- + +Each GPIO is independent from the other (i.e. GPIO0 in gpio_in function does +not force GPIO1 and GPIO2 to be in gpio_in function as well). + +GPIO | Functions +------------------------ +GPIO0 | gpio_in, gpio_out, ldo, adc +GPIO1 | gpio_in, gpio_out, ldo, adc +GPIO2 | gpio_in, gpio_out From d242e60c7d59fb95a9349d1487cfb3ddf6eebdde Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Tue, 5 Dec 2017 15:46:43 +0100 Subject: [PATCH 5/8] pinctrl: axp209: rename everything from gpio to pctl This driver used to do only GPIO features of the GPIOs in X-Powers AXP20X. Now that we have migrated everything to the pinctrl subsystem and added pinctrl features, rename everything related to pinctrl from gpio to pctl to ease the understanding of differences between GPIO and pinctrl features. Signed-off-by: Quentin Schulz Acked-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-axp209.c | 170 +++++++++++++++---------------- 1 file changed, 85 insertions(+), 85 deletions(-) diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c index 48cb57dcc575..17eeb0410a5b 100644 --- a/drivers/pinctrl/pinctrl-axp209.c +++ b/drivers/pinctrl/pinctrl-axp209.c @@ -57,7 +57,7 @@ struct axp20x_pinctrl_function { unsigned int ngroups; }; -struct axp20x_gpio { +struct axp20x_pctl { struct gpio_chip chip; struct regmap *regmap; struct pinctrl_dev *pctl_dev; @@ -100,11 +100,11 @@ static int axp20x_gpio_input(struct gpio_chip *chip, unsigned int offset) static int axp20x_gpio_get(struct gpio_chip *chip, unsigned int offset) { - struct axp20x_gpio *gpio = gpiochip_get_data(chip); + struct axp20x_pctl *pctl = gpiochip_get_data(chip); unsigned int val; int ret; - ret = regmap_read(gpio->regmap, AXP20X_GPIO20_SS, &val); + ret = regmap_read(pctl->regmap, AXP20X_GPIO20_SS, &val); if (ret) return ret; @@ -114,7 +114,7 @@ static int axp20x_gpio_get(struct gpio_chip *chip, unsigned int offset) static int axp20x_gpio_get_direction(struct gpio_chip *chip, unsigned int offset) { - struct axp20x_gpio *gpio = gpiochip_get_data(chip); + struct axp20x_pctl *pctl = gpiochip_get_data(chip); unsigned int val; int reg, ret; @@ -122,7 +122,7 @@ static int axp20x_gpio_get_direction(struct gpio_chip *chip, if (reg < 0) return reg; - ret = regmap_read(gpio->regmap, reg, &val); + ret = regmap_read(pctl->regmap, reg, &val); if (ret) return ret; @@ -152,14 +152,14 @@ static int axp20x_gpio_output(struct gpio_chip *chip, unsigned int offset, static void axp20x_gpio_set(struct gpio_chip *chip, unsigned int offset, int value) { - struct axp20x_gpio *gpio = gpiochip_get_data(chip); + struct axp20x_pctl *pctl = gpiochip_get_data(chip); int reg; reg = axp20x_gpio_get_reg(offset); if (reg < 0) return; - regmap_update_bits(gpio->regmap, reg, + regmap_update_bits(pctl->regmap, reg, AXP20X_GPIO_FUNCTIONS, value ? AXP20X_GPIO_FUNCTION_OUT_HIGH : AXP20X_GPIO_FUNCTION_OUT_LOW); @@ -168,30 +168,30 @@ static void axp20x_gpio_set(struct gpio_chip *chip, unsigned int offset, static int axp20x_pmx_set(struct pinctrl_dev *pctldev, unsigned int offset, u8 config) { - struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); int reg; reg = axp20x_gpio_get_reg(offset); if (reg < 0) return reg; - return regmap_update_bits(gpio->regmap, reg, AXP20X_GPIO_FUNCTIONS, + return regmap_update_bits(pctl->regmap, reg, AXP20X_GPIO_FUNCTIONS, config); } static int axp20x_pmx_func_cnt(struct pinctrl_dev *pctldev) { - struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); - return ARRAY_SIZE(gpio->funcs); + return ARRAY_SIZE(pctl->funcs); } static const char *axp20x_pmx_func_name(struct pinctrl_dev *pctldev, unsigned int selector) { - struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); - return gpio->funcs[selector].name; + return pctl->funcs[selector].name; } static int axp20x_pmx_func_groups(struct pinctrl_dev *pctldev, @@ -199,10 +199,10 @@ static int axp20x_pmx_func_groups(struct pinctrl_dev *pctldev, const char * const **groups, unsigned int *num_groups) { - struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); - *groups = gpio->funcs[selector].groups; - *num_groups = gpio->funcs[selector].ngroups; + *groups = pctl->funcs[selector].groups; + *num_groups = pctl->funcs[selector].ngroups; return 0; } @@ -210,18 +210,18 @@ static int axp20x_pmx_func_groups(struct pinctrl_dev *pctldev, static int axp20x_pmx_set_mux(struct pinctrl_dev *pctldev, unsigned int function, unsigned int group) { - struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); unsigned int mask; /* Every pin supports GPIO_OUT and GPIO_IN functions */ if (function <= AXP20X_FUNC_GPIO_IN) return axp20x_pmx_set(pctldev, group, - gpio->funcs[function].muxval); + pctl->funcs[function].muxval); if (function == AXP20X_FUNC_LDO) - mask = gpio->desc->ldo_mask; + mask = pctl->desc->ldo_mask; else - mask = gpio->desc->adc_mask; + mask = pctl->desc->adc_mask; if (!(BIT(group) & mask)) return -EINVAL; @@ -235,21 +235,21 @@ static int axp20x_pmx_set_mux(struct pinctrl_dev *pctldev, if (function == AXP20X_FUNC_LDO) return 0; - return axp20x_pmx_set(pctldev, group, gpio->funcs[function].muxval); + return axp20x_pmx_set(pctldev, group, pctl->funcs[function].muxval); } static int axp20x_pmx_gpio_set_direction(struct pinctrl_dev *pctldev, struct pinctrl_gpio_range *range, unsigned int offset, bool input) { - struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); if (input) return axp20x_pmx_set(pctldev, offset, - gpio->funcs[AXP20X_FUNC_GPIO_IN].muxval); + pctl->funcs[AXP20X_FUNC_GPIO_IN].muxval); return axp20x_pmx_set(pctldev, offset, - gpio->funcs[AXP20X_FUNC_GPIO_OUT].muxval); + pctl->funcs[AXP20X_FUNC_GPIO_OUT].muxval); } static const struct pinmux_ops axp20x_pmx_ops = { @@ -263,17 +263,17 @@ static const struct pinmux_ops axp20x_pmx_ops = { static int axp20x_groups_cnt(struct pinctrl_dev *pctldev) { - struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); - return gpio->desc->npins; + return pctl->desc->npins; } static int axp20x_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, const unsigned int **pins, unsigned int *num_pins) { - struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); - *pins = (unsigned int *)&gpio->desc->pins[selector]; + *pins = (unsigned int *)&pctl->desc->pins[selector]; *num_pins = 1; return 0; @@ -282,9 +282,9 @@ static int axp20x_group_pins(struct pinctrl_dev *pctldev, unsigned int selector, static const char *axp20x_group_name(struct pinctrl_dev *pctldev, unsigned int selector) { - struct axp20x_gpio *gpio = pinctrl_dev_get_drvdata(pctldev); + struct axp20x_pctl *pctl = pinctrl_dev_get_drvdata(pctldev); - return gpio->desc->pins[selector].name; + return pctl->desc->pins[selector].name; } static const struct pinctrl_ops axp20x_pctrl_ops = { @@ -319,44 +319,44 @@ static void axp20x_funcs_groups_from_mask(struct device *dev, unsigned int mask, static void axp20x_build_funcs_groups(struct platform_device *pdev) { - struct axp20x_gpio *gpio = platform_get_drvdata(pdev); - int i, pin, npins = gpio->desc->npins; + struct axp20x_pctl *pctl = platform_get_drvdata(pdev); + int i, pin, npins = pctl->desc->npins; - gpio->funcs[AXP20X_FUNC_GPIO_OUT].name = "gpio_out"; - gpio->funcs[AXP20X_FUNC_GPIO_OUT].muxval = AXP20X_MUX_GPIO_OUT; - gpio->funcs[AXP20X_FUNC_GPIO_IN].name = "gpio_in"; - gpio->funcs[AXP20X_FUNC_GPIO_IN].muxval = AXP20X_MUX_GPIO_IN; - gpio->funcs[AXP20X_FUNC_LDO].name = "ldo"; + pctl->funcs[AXP20X_FUNC_GPIO_OUT].name = "gpio_out"; + pctl->funcs[AXP20X_FUNC_GPIO_OUT].muxval = AXP20X_MUX_GPIO_OUT; + pctl->funcs[AXP20X_FUNC_GPIO_IN].name = "gpio_in"; + pctl->funcs[AXP20X_FUNC_GPIO_IN].muxval = AXP20X_MUX_GPIO_IN; + pctl->funcs[AXP20X_FUNC_LDO].name = "ldo"; /* * Muxval for LDO is useless as we won't use it. * See comment in axp20x_pmx_set_mux. */ - gpio->funcs[AXP20X_FUNC_ADC].name = "adc"; - gpio->funcs[AXP20X_FUNC_ADC].muxval = AXP20X_MUX_ADC; + pctl->funcs[AXP20X_FUNC_ADC].name = "adc"; + pctl->funcs[AXP20X_FUNC_ADC].muxval = AXP20X_MUX_ADC; /* Every pin supports GPIO_OUT and GPIO_IN functions */ for (i = 0; i <= AXP20X_FUNC_GPIO_IN; i++) { - gpio->funcs[i].ngroups = npins; - gpio->funcs[i].groups = devm_kzalloc(&pdev->dev, + pctl->funcs[i].ngroups = npins; + pctl->funcs[i].groups = devm_kzalloc(&pdev->dev, npins * sizeof(char *), GFP_KERNEL); for (pin = 0; pin < npins; pin++) - gpio->funcs[i].groups[pin] = gpio->desc->pins[pin].name; + pctl->funcs[i].groups[pin] = pctl->desc->pins[pin].name; } - axp20x_funcs_groups_from_mask(&pdev->dev, gpio->desc->ldo_mask, - npins, &gpio->funcs[AXP20X_FUNC_LDO], - gpio->desc->pins); + axp20x_funcs_groups_from_mask(&pdev->dev, pctl->desc->ldo_mask, + npins, &pctl->funcs[AXP20X_FUNC_LDO], + pctl->desc->pins); - axp20x_funcs_groups_from_mask(&pdev->dev, gpio->desc->adc_mask, - npins, &gpio->funcs[AXP20X_FUNC_ADC], - gpio->desc->pins); + axp20x_funcs_groups_from_mask(&pdev->dev, pctl->desc->adc_mask, + npins, &pctl->funcs[AXP20X_FUNC_ADC], + pctl->desc->pins); } -static int axp20x_gpio_probe(struct platform_device *pdev) +static int axp20x_pctl_probe(struct platform_device *pdev) { struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); - struct axp20x_gpio *gpio; + struct axp20x_pctl *pctl; struct pinctrl_desc *pctrl_desc; int ret; @@ -368,29 +368,29 @@ static int axp20x_gpio_probe(struct platform_device *pdev) return -EINVAL; } - gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL); - if (!gpio) + pctl = devm_kzalloc(&pdev->dev, sizeof(*pctl), GFP_KERNEL); + if (!pctl) return -ENOMEM; - gpio->chip.base = -1; - gpio->chip.can_sleep = true; - gpio->chip.request = gpiochip_generic_request; - gpio->chip.free = gpiochip_generic_free; - gpio->chip.parent = &pdev->dev; - gpio->chip.label = dev_name(&pdev->dev); - gpio->chip.owner = THIS_MODULE; - gpio->chip.get = axp20x_gpio_get; - gpio->chip.get_direction = axp20x_gpio_get_direction; - gpio->chip.set = axp20x_gpio_set; - gpio->chip.direction_input = axp20x_gpio_input; - gpio->chip.direction_output = axp20x_gpio_output; - gpio->chip.ngpio = 3; + pctl->chip.base = -1; + pctl->chip.can_sleep = true; + pctl->chip.request = gpiochip_generic_request; + pctl->chip.free = gpiochip_generic_free; + pctl->chip.parent = &pdev->dev; + pctl->chip.label = dev_name(&pdev->dev); + pctl->chip.owner = THIS_MODULE; + pctl->chip.get = axp20x_gpio_get; + pctl->chip.get_direction = axp20x_gpio_get_direction; + pctl->chip.set = axp20x_gpio_set; + pctl->chip.direction_input = axp20x_gpio_input; + pctl->chip.direction_output = axp20x_gpio_output; + pctl->chip.ngpio = 3; - gpio->desc = &axp20x_data; - gpio->regmap = axp20x->regmap; - gpio->dev = &pdev->dev; + pctl->desc = &axp20x_data; + pctl->regmap = axp20x->regmap; + pctl->dev = &pdev->dev; - platform_set_drvdata(pdev, gpio); + platform_set_drvdata(pdev, pctl); axp20x_build_funcs_groups(pdev); @@ -400,27 +400,27 @@ static int axp20x_gpio_probe(struct platform_device *pdev) pctrl_desc->name = dev_name(&pdev->dev); pctrl_desc->owner = THIS_MODULE; - pctrl_desc->pins = gpio->desc->pins; - pctrl_desc->npins = gpio->desc->npins; + pctrl_desc->pins = pctl->desc->pins; + pctrl_desc->npins = pctl->desc->npins; pctrl_desc->pctlops = &axp20x_pctrl_ops; pctrl_desc->pmxops = &axp20x_pmx_ops; - gpio->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, gpio); - if (IS_ERR(gpio->pctl_dev)) { + pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, pctrl_desc, pctl); + if (IS_ERR(pctl->pctl_dev)) { dev_err(&pdev->dev, "couldn't register pinctrl driver\n"); - return PTR_ERR(gpio->pctl_dev); + return PTR_ERR(pctl->pctl_dev); } - ret = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio); + ret = devm_gpiochip_add_data(&pdev->dev, &pctl->chip, pctl); if (ret) { dev_err(&pdev->dev, "Failed to register GPIO chip\n"); return ret; } - ret = gpiochip_add_pin_range(&gpio->chip, dev_name(&pdev->dev), - gpio->desc->pins->number, - gpio->desc->pins->number, - gpio->desc->npins); + ret = gpiochip_add_pin_range(&pctl->chip, dev_name(&pdev->dev), + pctl->desc->pins->number, + pctl->desc->pins->number, + pctl->desc->npins); if (ret) { dev_err(&pdev->dev, "failed to add pin range\n"); return ret; @@ -431,21 +431,21 @@ static int axp20x_gpio_probe(struct platform_device *pdev) return 0; } -static const struct of_device_id axp20x_gpio_match[] = { +static const struct of_device_id axp20x_pctl_match[] = { { .compatible = "x-powers,axp209-gpio" }, { } }; -MODULE_DEVICE_TABLE(of, axp20x_gpio_match); +MODULE_DEVICE_TABLE(of, axp20x_pctl_match); -static struct platform_driver axp20x_gpio_driver = { - .probe = axp20x_gpio_probe, +static struct platform_driver axp20x_pctl_driver = { + .probe = axp20x_pctl_probe, .driver = { .name = "axp20x-gpio", - .of_match_table = axp20x_gpio_match, + .of_match_table = axp20x_pctl_match, }, }; -module_platform_driver(axp20x_gpio_driver); +module_platform_driver(axp20x_pctl_driver); MODULE_AUTHOR("Maxime Ripard "); MODULE_AUTHOR("Quentin Schulz "); From 48e706fbc546d63148a762aadf92f412eefe8b8e Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Tue, 5 Dec 2017 15:46:44 +0100 Subject: [PATCH 6/8] pinctrl: axp209: add programmable gpio_status_offset To prepare for patches that will add support for a new PMIC that has a different GPIO input status register, add a gpio_status_offset within axp20x_pctl structure and use it. Signed-off-by: Quentin Schulz Acked-by: Maxime Ripard Acked-by: Chen-Yu Tsai Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-axp209.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c index 17eeb0410a5b..db8e319b6e11 100644 --- a/drivers/pinctrl/pinctrl-axp209.c +++ b/drivers/pinctrl/pinctrl-axp209.c @@ -48,6 +48,7 @@ struct axp20x_pctrl_desc { u8 ldo_mask; /* Stores the pins supporting ADC function. Bit offset is pin number. */ u8 adc_mask; + u8 gpio_status_offset; }; struct axp20x_pinctrl_function { @@ -77,6 +78,7 @@ static const struct axp20x_pctrl_desc axp20x_data = { .npins = ARRAY_SIZE(axp209_pins), .ldo_mask = BIT(0) | BIT(1), .adc_mask = BIT(0) | BIT(1), + .gpio_status_offset = 4, }; static int axp20x_gpio_get_reg(unsigned int offset) @@ -108,7 +110,7 @@ static int axp20x_gpio_get(struct gpio_chip *chip, unsigned int offset) if (ret) return ret; - return !!(val & BIT(offset + 4)); + return !!(val & BIT(offset + pctl->desc->gpio_status_offset)); } static int axp20x_gpio_get_direction(struct gpio_chip *chip, From a0a4b4c2420e0af6171a2be1965bdd983d35953c Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Tue, 5 Dec 2017 15:46:45 +0100 Subject: [PATCH 7/8] pinctrl: axp209: add programmable ADC muxing value To prepare for patches that will add support for a new PMIC that has a different GPIO adc muxing value, add an adc_mux within axp20x_pctl structure and use it. Signed-off-by: Quentin Schulz Acked-by: Maxime Ripard Signed-off-by: Linus Walleij --- drivers/pinctrl/pinctrl-axp209.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c index db8e319b6e11..9bb8722ba90f 100644 --- a/drivers/pinctrl/pinctrl-axp209.c +++ b/drivers/pinctrl/pinctrl-axp209.c @@ -49,6 +49,7 @@ struct axp20x_pctrl_desc { /* Stores the pins supporting ADC function. Bit offset is pin number. */ u8 adc_mask; u8 gpio_status_offset; + u8 adc_mux; }; struct axp20x_pinctrl_function { @@ -79,6 +80,7 @@ static const struct axp20x_pctrl_desc axp20x_data = { .ldo_mask = BIT(0) | BIT(1), .adc_mask = BIT(0) | BIT(1), .gpio_status_offset = 4, + .adc_mux = AXP20X_MUX_ADC, }; static int axp20x_gpio_get_reg(unsigned int offset) @@ -334,7 +336,7 @@ static void axp20x_build_funcs_groups(struct platform_device *pdev) * See comment in axp20x_pmx_set_mux. */ pctl->funcs[AXP20X_FUNC_ADC].name = "adc"; - pctl->funcs[AXP20X_FUNC_ADC].muxval = AXP20X_MUX_ADC; + pctl->funcs[AXP20X_FUNC_ADC].muxval = pctl->desc->adc_mux; /* Every pin supports GPIO_OUT and GPIO_IN functions */ for (i = 0; i <= AXP20X_FUNC_GPIO_IN; i++) { From e1190083b89bd0d53c83b647ff313d9f004c6772 Mon Sep 17 00:00:00 2001 From: Quentin Schulz Date: Tue, 5 Dec 2017 15:46:46 +0100 Subject: [PATCH 8/8] pinctrl: axp209: add support for AXP813 GPIOs The AXP813 has only two GPIOs. GPIO0 can either be used as a GPIO, an LDO regulator or an ADC. GPIO1 can be used either as a GPIO or an LDO regulator. Moreover, the status bit of the GPIOs when in input mode is not offset by 4 unlike the AXP209. Signed-off-by: Quentin Schulz Acked-by: Maxime Ripard Acked-by: Rob Herring Signed-off-by: Linus Walleij --- .../devicetree/bindings/gpio/gpio-axp209.txt | 13 ++++++- drivers/pinctrl/pinctrl-axp209.c | 35 ++++++++++++++----- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt index 0d77597c3f92..fc42b2caa06d 100644 --- a/Documentation/devicetree/bindings/gpio/gpio-axp209.txt +++ b/Documentation/devicetree/bindings/gpio/gpio-axp209.txt @@ -9,7 +9,9 @@ Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt This driver employs the per-pin muxing pattern. Required properties: -- compatible: Should be "x-powers,axp209-gpio" +- compatible: Should be one of: + - "x-powers,axp209-gpio" + - "x-powers,axp813-gpio" - #gpio-cells: Should be two. The first cell is the pin number and the second is the GPIO flags. - gpio-controller: Marks the device node as a GPIO controller. @@ -57,8 +59,17 @@ GPIOs and their functions Each GPIO is independent from the other (i.e. GPIO0 in gpio_in function does not force GPIO1 and GPIO2 to be in gpio_in function as well). +axp209 +------ GPIO | Functions ------------------------ GPIO0 | gpio_in, gpio_out, ldo, adc GPIO1 | gpio_in, gpio_out, ldo, adc GPIO2 | gpio_in, gpio_out + +axp813 +------ +GPIO | Functions +------------------------ +GPIO0 | gpio_in, gpio_out, ldo, adc +GPIO1 | gpio_in, gpio_out, ldo diff --git a/drivers/pinctrl/pinctrl-axp209.c b/drivers/pinctrl/pinctrl-axp209.c index 9bb8722ba90f..22d3bb0bf927 100644 --- a/drivers/pinctrl/pinctrl-axp209.c +++ b/drivers/pinctrl/pinctrl-axp209.c @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -41,6 +42,8 @@ #define AXP20X_MUX_GPIO_IN BIT(1) #define AXP20X_MUX_ADC BIT(2) +#define AXP813_MUX_ADC (BIT(2) | BIT(0)) + struct axp20x_pctrl_desc { const struct pinctrl_pin_desc *pins; unsigned int npins; @@ -74,6 +77,11 @@ static const struct pinctrl_pin_desc axp209_pins[] = { PINCTRL_PIN(2, "GPIO2"), }; +static const struct pinctrl_pin_desc axp813_pins[] = { + PINCTRL_PIN(0, "GPIO0"), + PINCTRL_PIN(1, "GPIO1"), +}; + static const struct axp20x_pctrl_desc axp20x_data = { .pins = axp209_pins, .npins = ARRAY_SIZE(axp209_pins), @@ -83,6 +91,15 @@ static const struct axp20x_pctrl_desc axp20x_data = { .adc_mux = AXP20X_MUX_ADC, }; +static const struct axp20x_pctrl_desc axp813_data = { + .pins = axp813_pins, + .npins = ARRAY_SIZE(axp813_pins), + .ldo_mask = BIT(0) | BIT(1), + .adc_mask = BIT(0), + .gpio_status_offset = 0, + .adc_mux = AXP813_MUX_ADC, +}; + static int axp20x_gpio_get_reg(unsigned int offset) { switch (offset) { @@ -357,10 +374,18 @@ static void axp20x_build_funcs_groups(struct platform_device *pdev) pctl->desc->pins); } +static const struct of_device_id axp20x_pctl_match[] = { + { .compatible = "x-powers,axp209-gpio", .data = &axp20x_data, }, + { .compatible = "x-powers,axp813-gpio", .data = &axp813_data, }, + { } +}; +MODULE_DEVICE_TABLE(of, axp20x_pctl_match); + static int axp20x_pctl_probe(struct platform_device *pdev) { struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent); struct axp20x_pctl *pctl; + struct device *dev = &pdev->dev; struct pinctrl_desc *pctrl_desc; int ret; @@ -388,9 +413,9 @@ static int axp20x_pctl_probe(struct platform_device *pdev) pctl->chip.set = axp20x_gpio_set; pctl->chip.direction_input = axp20x_gpio_input; pctl->chip.direction_output = axp20x_gpio_output; - pctl->chip.ngpio = 3; + pctl->chip.ngpio = pctl->desc->npins; - pctl->desc = &axp20x_data; + pctl->desc = (struct axp20x_pctrl_desc *)of_device_get_match_data(dev); pctl->regmap = axp20x->regmap; pctl->dev = &pdev->dev; @@ -435,12 +460,6 @@ static int axp20x_pctl_probe(struct platform_device *pdev) return 0; } -static const struct of_device_id axp20x_pctl_match[] = { - { .compatible = "x-powers,axp209-gpio" }, - { } -}; -MODULE_DEVICE_TABLE(of, axp20x_pctl_match); - static struct platform_driver axp20x_pctl_driver = { .probe = axp20x_pctl_probe, .driver = {