[PATCH v3 1/3] ARM: mediatek: Add Pinctrl/GPIO driver for mt8135.

Linus Walleij linus.walleij at linaro.org
Thu Nov 27 01:14:49 PST 2014


()On Tue, Nov 11, 2014 at 1:38 PM, Hongzhou Yang
<hongzhou.yang at mediatek.com> wrote:

> From: Hongzhou Yang <hongzhou.yang at mediatek.com>
>
> The mediatek SoCs have GPIO controller that handle both the muxing and GPIOs.
>
> The GPIO controller have pinmux, pull enable, pull select, direction and output high/low control.
>
> This driver include common driver and mt8135 part.
> The common driver include the pinctrl driver and GPIO driver.
> The mt8135 part contain its special device data.
>
> Signed-off-by: Hongzhou Yang <hongzhou.yang at mediatek.com>
(...)
>  menuconfig ARCH_MEDIATEK
>         bool "Mediatek MT65xx & MT81xx SoC" if ARCH_MULTI_V7
>         select ARM_GIC
> +       select PINCTRL

Should it not also select PINCTRL_MTK8135 for the right SoC?

(...)
> +++ b/drivers/pinctrl/mediatek/Kconfig
> @@ -0,0 +1,12 @@
> +if ARCH_MEDIATEK
> +
> +config PINCTRL_MTK_COMMON
> +       bool
> +       select PINMUX
> +       select GENERIC_PINCONF

This is also a GPIO driver but it fails to select GPIOLIB,
OF_GPIO and also possibly GPIOLIB_IRQCHIP.

(...)
> +static int mtk_pctrl_dt_node_to_map_config(struct mtk_pinctrl *pctl, u32 pin,
> +               unsigned long *configs, unsigned num_configs,
> +               struct pinctrl_map **map, unsigned *cnt_maps,
> +               unsigned *num_maps)
> +{
> +       struct mtk_pinctrl_group *grp;
> +       unsigned long *cfgs;
> +
> +       if (*num_maps == *cnt_maps)
> +               return -ENOSPC;
> +
> +       cfgs = kmemdup(configs, num_configs * sizeof(*cfgs),
> +                      GFP_KERNEL);
> +       if (cfgs == NULL)
> +               return -ENOMEM;
> +
> +       grp = mtk_pctrl_find_group_by_pin(pctl, pin);
> +       if (!grp) {
> +               dev_err(pctl->dev, "unable to match pin %d to group\n", pin);
> +               return -EINVAL;
> +       }
> +
> +       (*map)[*num_maps].type = PIN_MAP_TYPE_CONFIGS_GROUP;
> +       (*map)[*num_maps].data.configs.group_or_pin = grp->name;
> +       (*map)[*num_maps].data.configs.configs = cfgs;
> +       (*map)[*num_maps].data.configs.num_configs = num_configs;
> +       (*num_maps)++;
> +
> +       return 0;
> +}

Can't this use pinctrl_utils_add_map_configs()?

> +static void mtk_pctrl_dt_free_map(struct pinctrl_dev *pctldev,
> +                                   struct pinctrl_map *map,
> +                                   unsigned num_maps)
> +{
> +       int i;
> +
> +       for (i = 0; i < num_maps; i++) {
> +               if (map[i].type == PIN_MAP_TYPE_CONFIGS_GROUP)
> +                       kfree(map[i].data.configs.configs);
> +       }
> +
> +       kfree(map);
> +}

Use pinctrl_utils_dt_free_map() instead.

> +static int mtk_dt_cnt_map(struct pinctrl_map **map, unsigned *cnt_maps,
> +               unsigned *num_maps, unsigned cnt)
> +{
> +       unsigned old_num = *cnt_maps;
> +       unsigned new_num = *num_maps + cnt;
> +       struct pinctrl_map *new_map;
> +
> +       if (old_num >= new_num)
> +               return 0;
> +
> +       new_map = krealloc(*map, sizeof(*new_map) * new_num, GFP_KERNEL);
> +       if (!new_map)
> +               return -ENOMEM;
> +
> +       memset(new_map + old_num, 0, (new_num - old_num) * sizeof(*new_map));
> +
> +       *map = new_map;
> +       *cnt_maps = new_num;
> +
> +       return 0;
> +}

Use pinctrl_utils_reserve_map() instead.

> +static int mtk_pctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
> +                                     struct device_node *node,
> +                                     struct pinctrl_map **map,
> +                                     unsigned *num_maps, unsigned *cnt_maps)
> +{
> +       struct property *pins;
> +       u32 pinfunc, pin, func;
> +       int num_pins, num_funcs, maps_per_pin;
> +       unsigned long *configs;
> +       unsigned int num_configs;
> +       bool has_config = 0;
> +       int i, err;
> +       unsigned cnt = 0;
> +       struct mtk_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev);
> +
> +       pins = of_find_property(node, "mediatek,pins", NULL);
> +       if (!pins) {
> +               dev_err(pctl->dev, "missing mediatek,pins property in node %s .\n",
> +                               node->name);
> +               return -EINVAL;
> +       }
> +
> +       err = pinconf_generic_parse_dt_config(node, &configs, &num_configs);
> +       if (num_configs)
> +               has_config = 1;

I'd prefer we first identify if it's a config or mux subnode, then go on to
parse it as mux or config. See comments on patch 2/3.

> +
> +       num_pins = pins->length / sizeof(u32);
> +       num_funcs = num_pins;
> +       maps_per_pin = 0;
> +       if (num_funcs)
> +               maps_per_pin++;
> +       if (has_config && num_pins >= 1)
> +               maps_per_pin++;
> +
> +       if (!num_pins || !maps_per_pin)
> +               return -EINVAL;
> +
> +       cnt = num_pins * maps_per_pin;
> +
> +       err = mtk_dt_cnt_map(map, cnt_maps, num_maps, cnt);
> +       if (err < 0)
> +               goto fail;
> +
> +       for (i = 0; i < num_pins; i++) {
> +               err = of_property_read_u32_index(node, "mediatek,pins",
> +                               i, &pinfunc);

As mentioned use just "pins" and let's figure out how to handle
this in a generic way.

> +static int mtk_gpio_request(struct gpio_chip *chip, unsigned offset)
> +{
> +       return pinctrl_request_gpio(chip->base + offset);
> +}
> +
> +static void mtk_gpio_free(struct gpio_chip *chip, unsigned offset)
> +{
> +       pinctrl_free_gpio(chip->base + offset);
> +}
> +
> +static int mtk_gpio_direction_input(struct gpio_chip *chip,
> +                                       unsigned offset)
> +{
> +       return pinctrl_gpio_direction_input(chip->base + offset);
> +}
> +
> +static int mtk_gpio_direction_output(struct gpio_chip *chip,
> +                                       unsigned offset, int value)
> +{
> +       mtk_gpio_set(chip, offset, value);
> +       return pinctrl_gpio_direction_output(chip->base + offset);
> +}

This is kinda nice!

> +static int mtk_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
> +{
> +       struct mtk_pinctrl *pctl = dev_get_drvdata(chip->dev);
> +       struct mtk_pinctrl_group *g = pctl->groups + offset;
> +       struct mtk_desc_function *desc =
> +                       mtk_pctrl_desc_find_irq_function_from_name(
> +                                       pctl, g->name);
> +       if (!desc)
> +               return -EINVAL;
> +
> +       return desc->irqnum;
> +}

I don't quite get this still. Does this mean every single GPIO line
potentially has it's own unique IRQ line?

Yours,
Linus Walleij



More information about the linux-arm-kernel mailing list