2012-12-15 01:59:45 +00:00
|
|
|
From 13e754b5fff5be1930e2b8fe534a52b608c9e479 Mon Sep 17 00:00:00 2001
|
|
|
|
From: John Crispin <blogic@openwrt.org>
|
|
|
|
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(-)
|
|
|
|
|
2013-01-28 17:44:20 +00:00
|
|
|
--- a/drivers/pinctrl/pinctrl-lantiq.c
|
|
|
|
+++ b/drivers/pinctrl/pinctrl-lantiq.c
|
|
|
|
@@ -64,11 +64,13 @@ static void ltq_pinctrl_pin_dbg_show(str
|
2012-12-15 01:59:45 +00:00
|
|
|
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;
|
2013-01-28 17:44:20 +00:00
|
|
|
@@ -76,8 +78,20 @@ static int ltq_pinctrl_dt_subnode_to_map
|
2012-12-15 01:59:45 +00:00
|
|
|
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;
|
2013-01-28 17:44:20 +00:00
|
|
|
@@ -85,11 +99,6 @@ static int ltq_pinctrl_dt_subnode_to_map
|
2012-12-15 01:59:45 +00:00
|
|
|
(*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++) {
|
2013-01-28 17:44:20 +00:00
|
|
|
@@ -103,7 +112,7 @@ static int ltq_pinctrl_dt_subnode_to_map
|
2012-12-15 01:59:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!num_configs)
|
|
|
|
- return -EINVAL;
|
|
|
|
+ return;
|
|
|
|
|
|
|
|
of_property_for_each_string(np, "lantiq,pins", prop, pin) {
|
|
|
|
(*map)->data.configs.configs = kmemdup(configs,
|
2013-01-28 17:44:20 +00:00
|
|
|
@@ -115,7 +124,16 @@ static int ltq_pinctrl_dt_subnode_to_map
|
2012-12-15 01:59:45 +00:00
|
|
|
(*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)
|
2013-01-28 17:44:20 +00:00
|
|
|
@@ -135,23 +153,19 @@ int ltq_pinctrl_dt_node_to_map(struct pi
|
2012-12-15 01:59:45 +00:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2013-01-28 17:44:20 +00:00
|
|
|
--- a/drivers/pinctrl/pinctrl-lantiq.h
|
|
|
|
+++ b/drivers/pinctrl/pinctrl-lantiq.h
|
|
|
|
@@ -34,6 +34,7 @@ enum ltq_pinconf_param {
|
2012-12-15 01:59:45 +00:00
|
|
|
LTQ_PINCONF_PARAM_OPEN_DRAIN,
|
|
|
|
LTQ_PINCONF_PARAM_DRIVE_CURRENT,
|
|
|
|
LTQ_PINCONF_PARAM_SLEW_RATE,
|
|
|
|
+ LTQ_PINCONF_PARAM_OUTPUT,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct ltq_cfg_param {
|
2013-01-28 17:44:20 +00:00
|
|
|
--- a/drivers/pinctrl/pinctrl-xway.c
|
|
|
|
+++ b/drivers/pinctrl/pinctrl-xway.c
|
|
|
|
@@ -443,7 +443,7 @@ static int xway_pinconf_get(struct pinct
|
2012-12-15 01:59:45 +00:00
|
|
|
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:
|
2013-01-28 17:44:20 +00:00
|
|
|
@@ -466,6 +466,11 @@ static int xway_pinconf_get(struct pinct
|
2012-12-15 01:59:45 +00:00
|
|
|
*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;
|
2013-01-28 17:44:20 +00:00
|
|
|
@@ -489,7 +494,10 @@ static int xway_pinconf_set(struct pinct
|
2012-12-15 01:59:45 +00:00
|
|
|
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:
|
2013-01-28 17:44:20 +00:00
|
|
|
@@ -515,6 +523,14 @@ static int xway_pinconf_set(struct pinct
|
2012-12-15 01:59:45 +00:00
|
|
|
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;
|
2013-01-28 17:44:20 +00:00
|
|
|
@@ -522,9 +538,25 @@ static int xway_pinconf_set(struct pinct
|
2012-12-15 01:59:45 +00:00
|
|
|
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 = {
|
2013-01-28 17:44:20 +00:00
|
|
|
@@ -532,10 +564,9 @@ static struct pinctrl_desc xway_pctrl_de
|
2012-12-15 01:59:45 +00:00
|
|
|
.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);
|
|
|
|
|
2013-01-28 17:44:20 +00:00
|
|
|
@@ -555,9 +586,18 @@ static inline int xway_mux_apply(struct
|
2012-12-15 01:59:45 +00:00
|
|
|
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 = {
|
2013-01-28 17:44:20 +00:00
|
|
|
@@ -598,6 +638,10 @@ static int xway_gpio_dir_out(struct gpio
|
2012-12-15 01:59:45 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2013-01-28 17:44:20 +00:00
|
|
|
@@ -618,6 +662,18 @@ static void xway_gpio_free(struct gpio_c
|
2012-12-15 01:59:45 +00:00
|
|
|
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,
|
2013-01-28 17:44:20 +00:00
|
|
|
@@ -626,6 +682,7 @@ static struct gpio_chip xway_chip = {
|
2012-12-15 01:59:45 +00:00
|
|
|
.set = xway_gpio_set,
|
|
|
|
.request = xway_gpio_req,
|
|
|
|
.free = xway_gpio_free,
|
|
|
|
+ .to_irq = xway_gpio_to_irq,
|
|
|
|
.base = -1,
|
|
|
|
};
|
|
|
|
|