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

From: Linus Walleij
Date: Thu Nov 27 2014 - 04:15:05 EST


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

> From: Hongzhou Yang <hongzhou.yang@xxxxxxxxxxxx>
>
> 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@xxxxxxxxxxxx>
(...)
> 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
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/