From 13e754b5fff5be1930e2b8fe534a52b608c9e479 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 3 Dec 2012 19:27:28 +0100 Subject: [PATCH] PINCTRL: lantiq: fixes --- drivers/pinctrl/pinctrl-lantiq.c | 54 ++++++++++++++++++----------- drivers/pinctrl/pinctrl-lantiq.h | 1 + drivers/pinctrl/pinctrl-xway.c | 70 ++++++++++++++++++++++++++++++++++---- 3 files changed, 99 insertions(+), 26 deletions(-) Index: linux-3.7-rc8/drivers/pinctrl/pinctrl-lantiq.c =================================================================== --- linux-3.7-rc8.orig/drivers/pinctrl/pinctrl-lantiq.c 2012-12-03 20:22:37.000000000 +0100 +++ linux-3.7-rc8/drivers/pinctrl/pinctrl-lantiq.c 2012-12-14 22:59:40.687563565 +0100 @@ -64,11 +64,13 @@ seq_printf(s, " %s", dev_name(pctldev->dev)); } -static int ltq_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, +static void ltq_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev, struct device_node *np, struct pinctrl_map **map) { struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev); + struct property *pins = of_find_property(np, "lantiq,pins", NULL); + struct property *groups = of_find_property(np, "lantiq,groups", NULL); unsigned long configs[3]; unsigned num_configs = 0; struct property *prop; @@ -76,8 +78,20 @@ const char *function; int ret, i; + if (!pins && !groups) { + dev_err(pctldev->dev, "%s defines neither pins nor groups\n", + np->name); + return; + } + + if (pins && groups) { + dev_err(pctldev->dev, "%s defines both pins and groups\n", + np->name); + return; + } + ret = of_property_read_string(np, "lantiq,function", &function); - if (!ret) { + if (groups && !ret) { of_property_for_each_string(np, "lantiq,groups", prop, group) { (*map)->type = PIN_MAP_TYPE_MUX_GROUP; (*map)->name = function; @@ -85,11 +99,6 @@ (*map)->data.mux.function = function; (*map)++; } - if (of_find_property(np, "lantiq,pins", NULL)) - dev_err(pctldev->dev, - "%s mixes pins and groups settings\n", - np->name); - return 0; } for (i = 0; i < info->num_params; i++) { @@ -103,7 +112,7 @@ } if (!num_configs) - return -EINVAL; + return; of_property_for_each_string(np, "lantiq,pins", prop, pin) { (*map)->data.configs.configs = kmemdup(configs, @@ -115,7 +124,16 @@ (*map)->data.configs.num_configs = num_configs; (*map)++; } - return 0; + of_property_for_each_string(np, "lantiq,groups", prop, group) { + (*map)->data.configs.configs = kmemdup(configs, + num_configs * sizeof(unsigned long), + GFP_KERNEL); + (*map)->type = PIN_MAP_TYPE_CONFIGS_GROUP; + (*map)->name = group; + (*map)->data.configs.group_or_pin = group; + (*map)->data.configs.num_configs = num_configs; + (*map)++; + } } static int ltq_pinctrl_dt_subnode_size(struct device_node *np) @@ -135,23 +153,19 @@ { struct pinctrl_map *tmp; struct device_node *np; - int ret; + int max_maps = 0; - *num_maps = 0; for_each_child_of_node(np_config, np) - *num_maps += ltq_pinctrl_dt_subnode_size(np); - *map = kzalloc(*num_maps * sizeof(struct pinctrl_map), GFP_KERNEL); + max_maps += ltq_pinctrl_dt_subnode_size(np); + *map = kzalloc(max_maps * sizeof(struct pinctrl_map) * 2, GFP_KERNEL); if (!*map) return -ENOMEM; tmp = *map; - for_each_child_of_node(np_config, np) { - ret = ltq_pinctrl_dt_subnode_to_map(pctldev, np, &tmp); - if (ret < 0) { - ltq_pinctrl_dt_free_map(pctldev, *map, *num_maps); - return ret; - } - } + for_each_child_of_node(np_config, np) + ltq_pinctrl_dt_subnode_to_map(pctldev, np, &tmp); + *num_maps = ((int)(tmp - *map)); + return 0; } Index: linux-3.7-rc8/drivers/pinctrl/pinctrl-lantiq.h =================================================================== --- linux-3.7-rc8.orig/drivers/pinctrl/pinctrl-lantiq.h 2012-12-03 20:22:37.000000000 +0100 +++ linux-3.7-rc8/drivers/pinctrl/pinctrl-lantiq.h 2012-12-14 22:55:26.591557194 +0100 @@ -34,6 +34,7 @@ LTQ_PINCONF_PARAM_OPEN_DRAIN, LTQ_PINCONF_PARAM_DRIVE_CURRENT, LTQ_PINCONF_PARAM_SLEW_RATE, + LTQ_PINCONF_PARAM_OUTPUT, }; struct ltq_cfg_param { Index: linux-3.7-rc8/drivers/pinctrl/pinctrl-xway.c =================================================================== --- linux-3.7-rc8.orig/drivers/pinctrl/pinctrl-xway.c 2012-12-14 22:55:26.567557195 +0100 +++ linux-3.7-rc8/drivers/pinctrl/pinctrl-xway.c 2012-12-14 22:55:26.595557195 +0100 @@ -443,7 +443,7 @@ else reg = GPIO_OD(pin); *config = LTQ_PINCONF_PACK(param, - !!gpio_getbit(info->membase[0], reg, PORT_PIN(pin))); + !gpio_getbit(info->membase[0], reg, PORT_PIN(pin))); break; case LTQ_PINCONF_PARAM_PULL: @@ -466,6 +466,11 @@ *config = LTQ_PINCONF_PACK(param, 1); break; + case LTQ_PINCONF_PARAM_OUTPUT: + reg = GPIO_DIR(pin); + *config = LTQ_PINCONF_PACK(param, + gpio_getbit(info->membase[0], reg, PORT_PIN(pin))); + break; default: dev_err(pctldev->dev, "Invalid config param %04x\n", param); return -ENOTSUPP; @@ -489,7 +494,10 @@ reg = GPIO3_OD; else reg = GPIO_OD(pin); - gpio_setbit(info->membase[0], reg, PORT_PIN(pin)); + if (arg == 0) + gpio_setbit(info->membase[0], reg, PORT_PIN(pin)); + else + gpio_clearbit(info->membase[0], reg, PORT_PIN(pin)); break; case LTQ_PINCONF_PARAM_PULL: @@ -515,6 +523,14 @@ dev_err(pctldev->dev, "Invalid pull value %d\n", arg); break; + case LTQ_PINCONF_PARAM_OUTPUT: + reg = GPIO_DIR(pin); + if (arg == 0) + gpio_clearbit(info->membase[0], reg, PORT_PIN(pin)); + else + gpio_setbit(info->membase[0], reg, PORT_PIN(pin)); + break; + default: dev_err(pctldev->dev, "Invalid config param %04x\n", param); return -ENOTSUPP; @@ -522,9 +538,25 @@ return 0; } +int xway_pinconf_group_set(struct pinctrl_dev *pctldev, + unsigned selector, + unsigned long config) +{ + struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctldev); + int i, ret = 0; + + for (i = 0; i < info->grps[selector].npins && !ret; i++) + ret = xway_pinconf_set(pctldev, + info->grps[selector].pins[i], config); + + return ret; +} + + struct pinconf_ops xway_pinconf_ops = { .pin_config_get = xway_pinconf_get, .pin_config_set = xway_pinconf_set, + .pin_config_group_set = xway_pinconf_group_set, }; static struct pinctrl_desc xway_pctrl_desc = { @@ -532,10 +564,9 @@ .confops = &xway_pinconf_ops, }; -static inline int xway_mux_apply(struct pinctrl_dev *pctrldev, +static int mux_apply(struct ltq_pinmux_info *info, int pin, int mux) { - struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); int port = PORT(pin); u32 alt1_reg = GPIO_ALT1(pin); @@ -555,9 +586,18 @@ return 0; } +static inline int xway_mux_apply(struct pinctrl_dev *pctrldev, + int pin, int mux) +{ + struct ltq_pinmux_info *info = pinctrl_dev_get_drvdata(pctrldev); + + return mux_apply(info, pin, mux); +} + static const struct ltq_cfg_param xway_cfg_params[] = { {"lantiq,pull", LTQ_PINCONF_PARAM_PULL}, {"lantiq,open-drain", LTQ_PINCONF_PARAM_OPEN_DRAIN}, + {"lantiq,output", LTQ_PINCONF_PARAM_OUTPUT}, }; static struct ltq_pinmux_info xway_info = { @@ -598,6 +638,10 @@ { struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev); + if (PORT(pin) == PORT3) + gpio_setbit(info->membase[0], GPIO3_OD, PORT_PIN(pin)); + else + gpio_setbit(info->membase[0], GPIO_OD(pin), PORT_PIN(pin)); gpio_setbit(info->membase[0], GPIO_DIR(pin), PORT_PIN(pin)); xway_gpio_set(chip, pin, val); @@ -618,6 +662,18 @@ pinctrl_free_gpio(gpio); } +static int xway_gpio_to_irq(struct gpio_chip *chip, unsigned offset) +{ + struct ltq_pinmux_info *info = dev_get_drvdata(chip->dev); + int i; + + for (i = 0; i < info->num_exin; i++) + if (info->exin[i] == offset) + return ltq_eiu_get_irq(i); + + return -1; +} + static struct gpio_chip xway_chip = { .label = "gpio-xway", .direction_input = xway_gpio_dir_in, @@ -626,6 +682,7 @@ .set = xway_gpio_set, .request = xway_gpio_req, .free = xway_gpio_free, + .to_irq = xway_gpio_to_irq, .base = -1, };