aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaojian Zhuang <haojian.zhuang@linaro.org>2013-03-13 16:45:26 +0800
committerHaojian Zhuang <haojian.zhuang@linaro.org>2013-03-13 16:45:26 +0800
commit85996424ef208605a20dc6cb20200bc7b2ec7fa7 (patch)
tree404c38d0d77d96699caab3311b24147d7eebfcb8
parent6d452a2406274fa2684df2c5248654db60e70377 (diff)
pinctrl: single: sync code with latest next tree
pinctrl-single is updated on 3.10. The interface on pin configurations are changed. So sync latest code into code base. Signed-off-by: Haojian Zhuang <haojian.zhuang@linaro.org>
-rw-r--r--drivers/pinctrl/pinctrl-single.c211
1 files changed, 140 insertions, 71 deletions
diff --git a/drivers/pinctrl/pinctrl-single.c b/drivers/pinctrl/pinctrl-single.c
index dcbbd7cda53e..a62afd055fce 100644
--- a/drivers/pinctrl/pinctrl-single.c
+++ b/drivers/pinctrl/pinctrl-single.c
@@ -62,16 +62,18 @@ struct pcs_func_vals {
/**
* struct pcs_conf_vals - pinconf parameter, pinconf register offset
- * and value, match, mask
+ * and value, enable, disable, mask
* @param: config parameter
- * @val: register value
- * @match: register match value
- * @mask: mask of register value
+ * @val: user input bits in the pinconf register
+ * @enable: enable bits in the pinconf register
+ * @disable: disable bits in the pinconf register
+ * @mask: mask bits in the register value
*/
struct pcs_conf_vals {
enum pin_config_param param;
unsigned val;
- unsigned match;
+ unsigned enable;
+ unsigned disable;
unsigned mask;
};
@@ -202,6 +204,16 @@ struct pcs_device {
void (*write)(unsigned val, void __iomem *reg);
};
+static int pcs_pinconf_get(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *config);
+static int pcs_pinconf_set(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long config);
+
+static enum pin_config_param pcs_bias[] = {
+ PIN_CONFIG_BIAS_PULL_DOWN,
+ PIN_CONFIG_BIAS_PULL_UP,
+};
+
/*
* REVISIT: Reads and writes could eventually use regmap or something
* generic. But at least on omaps, some mux registers are performance
@@ -514,11 +526,42 @@ static struct pinmux_ops pcs_pinmux_ops = {
.gpio_request_enable = pcs_request_gpio,
};
+/* Clear BIAS value */
+static void pcs_pinconf_clear_bias(struct pinctrl_dev *pctldev, unsigned pin)
+{
+ unsigned long config;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(pcs_bias); i++) {
+ config = pinconf_to_config_packed(pcs_bias[i], 0);
+ pcs_pinconf_set(pctldev, pin, config);
+ }
+}
+
+/*
+ * Check whether PIN_CONFIG_BIAS_DISABLE is valid.
+ * It's depend on that PULL_DOWN & PULL_UP configs are all invalid.
+ */
+static bool pcs_pinconf_bias_disable(struct pinctrl_dev *pctldev, unsigned pin)
+{
+ unsigned long config;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pcs_bias); i++) {
+ config = pinconf_to_config_packed(pcs_bias[i], 0);
+ if (!pcs_pinconf_get(pctldev, pin, &config))
+ goto out;
+ }
+ return true;
+out:
+ return false;
+}
+
static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
unsigned pin, unsigned long *config)
{
struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
struct pcs_function *func;
+ enum pin_config_param param;
unsigned offset = 0, data = 0, i, j, ret;
ret = pcs_get_function(pctldev, pin, &func);
@@ -526,26 +569,36 @@ static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
return ret;
for (i = 0; i < func->nconfs; i++) {
- if (pinconf_to_config_param(*config) != func->conf[i].param)
+ param = pinconf_to_config_param(*config);
+ if (param == PIN_CONFIG_BIAS_DISABLE) {
+ if (pcs_pinconf_bias_disable(pctldev, pin)) {
+ *config = 0;
+ return 0;
+ } else {
+ return -ENOTSUPP;
+ }
+ } else if (param != func->conf[i].param) {
continue;
+ }
+
offset = pin * (pcs->width / BITS_PER_BYTE);
data = pcs->read(pcs->base + offset) & func->conf[i].mask;
switch (func->conf[i].param) {
- /* 3 parameters */
- case PIN_CONFIG_BIAS_DISABLE:
+ /* 4 parameters */
case PIN_CONFIG_BIAS_PULL_DOWN:
case PIN_CONFIG_BIAS_PULL_UP:
- case PIN_CONFIG_INPUT_SCHMITT_DISABLE:
- if (data != func->conf[i].match)
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ if ((data != func->conf[i].enable) ||
+ (data == func->conf[i].disable))
return -ENOTSUPP;
- *config = data;
+ *config = 0;
break;
+ /* 2 parameters */
case PIN_CONFIG_INPUT_SCHMITT:
- /* either INPUT_SCHMITT or DISABLE */
for (j = 0; j < func->nconfs; j++) {
switch (func->conf[j].param) {
- case PIN_CONFIG_INPUT_SCHMITT_DISABLE:
- if (data == func->conf[j].match)
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+ if (data != func->conf[j].enable)
return -ENOTSUPP;
break;
default:
@@ -554,7 +607,7 @@ static int pcs_pinconf_get(struct pinctrl_dev *pctldev,
}
*config = data;
break;
- case PIN_CONFIG_POWER_SOURCE:
+ case PIN_CONFIG_DRIVE_STRENGTH:
case PIN_CONFIG_SLEW_RATE:
default:
*config = data;
@@ -570,7 +623,8 @@ static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
{
struct pcs_device *pcs = pinctrl_dev_get_drvdata(pctldev);
struct pcs_function *func;
- unsigned offset = 0, shift = 0, arg = 0, i, data, ret;
+ unsigned offset = 0, shift = 0, i, data, ret;
+ u16 arg;
ret = pcs_get_function(pctldev, pin, &func);
if (ret)
@@ -580,23 +634,31 @@ static int pcs_pinconf_set(struct pinctrl_dev *pctldev,
if (pinconf_to_config_param(config) == func->conf[i].param) {
offset = pin * (pcs->width / BITS_PER_BYTE);
data = pcs->read(pcs->base + offset);
+ arg = pinconf_to_config_argument(config);
switch (func->conf[i].param) {
/* 2 parameters */
case PIN_CONFIG_INPUT_SCHMITT:
- case PIN_CONFIG_POWER_SOURCE:
+ case PIN_CONFIG_DRIVE_STRENGTH:
case PIN_CONFIG_SLEW_RATE:
shift = ffs(func->conf[i].mask) - 1;
- arg = pinconf_to_config_argument(config);
data &= ~func->conf[i].mask;
data |= (arg << shift) & func->conf[i].mask;
break;
- /* 3 parameters */
+ /* 4 parameters */
case PIN_CONFIG_BIAS_DISABLE:
+ pcs_pinconf_clear_bias(pctldev, pin);
+ break;
case PIN_CONFIG_BIAS_PULL_DOWN:
case PIN_CONFIG_BIAS_PULL_UP:
- case PIN_CONFIG_INPUT_SCHMITT_DISABLE:
+ if (arg)
+ pcs_pinconf_clear_bias(pctldev, pin);
+ /* fall through */
+ case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
data &= ~func->conf[i].mask;
- data |= func->conf[i].val;
+ if (arg)
+ data |= func->conf[i].enable;
+ else
+ data |= func->conf[i].disable;
break;
default:
return -ENOTSUPP;
@@ -671,6 +733,7 @@ static struct pinconf_ops pcs_pinconf_ops = {
.pin_config_dbg_show = pcs_pinconf_dbg_show,
.pin_config_group_dbg_show = pcs_pinconf_group_dbg_show,
.pin_config_config_dbg_show = pcs_pinconf_config_dbg_show,
+ .is_generic = true,
};
/**
@@ -861,26 +924,30 @@ static int pcs_get_pin_by_offset(struct pcs_device *pcs, unsigned offset)
return index;
}
-static int pcs_config_match(unsigned data, unsigned match)
+/*
+ * check whether data matches enable bits or disable bits
+ * Return value: 1 for matching enable bits, 0 for matching disable bits,
+ * and negative value for matching failure.
+ */
+static int pcs_config_match(unsigned data, unsigned enable, unsigned disable)
{
- int ret = 0;
+ int ret = -EINVAL;
- if (!match) {
- if (!data)
- ret = 1;
- } else {
- if ((data & match) == match)
- ret = 1;
- }
+ if (data == enable)
+ ret = 1;
+ else if (data == disable)
+ ret = 0;
return ret;
}
static void add_config(struct pcs_conf_vals **conf, enum pin_config_param param,
- unsigned value, unsigned match, unsigned mask)
+ unsigned value, unsigned enable, unsigned disable,
+ unsigned mask)
{
(*conf)->param = param;
(*conf)->val = value;
- (*conf)->match = match;
+ (*conf)->enable = enable;
+ (*conf)->disable = disable;
(*conf)->mask = mask;
(*conf)++;
}
@@ -893,43 +960,47 @@ static void add_setting(unsigned long **setting, enum pin_config_param param,
}
/* add pinconf setting with 2 parameters */
-static void pcs_add_conf2(struct device_node *np, const char *name,
- enum pin_config_param param,
- struct pcs_conf_vals **conf,
- unsigned long **settings)
+static void pcs_add_conf2(struct pcs_device *pcs, struct device_node *np,
+ const char *name, enum pin_config_param param,
+ struct pcs_conf_vals **conf, unsigned long **settings)
{
- unsigned value[2];
+ unsigned value[2], shift;
int ret;
ret = of_property_read_u32_array(np, name, value, 2);
if (ret)
return;
- /* value to set, mask */
+ /* set value & mask */
value[0] &= value[1];
- add_config(conf, param, value[0], 0, value[1]);
- add_setting(settings, param, value[0]);
+ shift = ffs(value[1]) - 1;
+ /* skip enable & disable */
+ add_config(conf, param, value[0], 0, 0, value[1]);
+ add_setting(settings, param, value[0] >> shift);
}
-/* add pinconf setting with 3 parameters */
-static void pcs_add_conf3(struct device_node *np, const char *name,
- enum pin_config_param param,
- struct pcs_conf_vals **conf,
- unsigned long **settings)
+/* add pinconf setting with 4 parameters */
+static void pcs_add_conf4(struct pcs_device *pcs, struct device_node *np,
+ const char *name, enum pin_config_param param,
+ struct pcs_conf_vals **conf, unsigned long **settings)
{
- unsigned value[3];
+ unsigned value[4];
int ret;
- ret = of_property_read_u32_array(np, name, value, 3);
+ /* value to set, enable, disable, mask */
+ ret = of_property_read_u32_array(np, name, value, 4);
if (ret)
return;
- /* value to set, match, mask */
- value[0] &= value[2];
- value[1] &= value[2];
- add_config(conf, param, value[0], value[1], value[2]);
- if (pcs_config_match(value[0], value[1]))
- ret = 1;
- else
- ret = 0;
+ if (!value[3]) {
+ dev_err(pcs->dev, "mask field of the property can't be 0\n");
+ return;
+ }
+ value[0] &= value[3];
+ value[1] &= value[3];
+ value[2] &= value[3];
+ ret = pcs_config_match(value[0], value[1], value[2]);
+ if (ret < 0)
+ dev_dbg(pcs->dev, "failed to match enable or disable bits\n");
+ add_config(conf, param, value[0], value[1], value[2], value[3]);
add_setting(settings, param, ret);
}
@@ -943,16 +1014,15 @@ static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
unsigned long *settings = NULL, *s = NULL;
struct pcs_conf_vals *conf = NULL;
struct pcs_conf_type prop2[] = {
- { "pinctrl-single,power-source", PIN_CONFIG_POWER_SOURCE, },
+ { "pinctrl-single,drive-strength", PIN_CONFIG_DRIVE_STRENGTH, },
{ "pinctrl-single,slew-rate", PIN_CONFIG_SLEW_RATE, },
{ "pinctrl-single,input-schmitt", PIN_CONFIG_INPUT_SCHMITT, },
};
- struct pcs_conf_type prop3[] = {
- { "pinctrl-single,bias-disable", PIN_CONFIG_BIAS_DISABLE, },
+ struct pcs_conf_type prop4[] = {
{ "pinctrl-single,bias-pullup", PIN_CONFIG_BIAS_PULL_UP, },
{ "pinctrl-single,bias-pulldown", PIN_CONFIG_BIAS_PULL_DOWN, },
- { "pinctrl-single,input-schmitt-disable",
- PIN_CONFIG_INPUT_SCHMITT_DISABLE, },
+ { "pinctrl-single,input-schmitt-enable",
+ PIN_CONFIG_INPUT_SCHMITT_ENABLE, },
};
/* If pinconf isn't supported, don't parse properties in below. */
@@ -964,8 +1034,8 @@ static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
if (of_find_property(np, prop2[i].name, NULL))
nconfs++;
}
- for (i = 0; i < ARRAY_SIZE(prop3); i++) {
- if (of_find_property(np, prop3[i].name, NULL))
+ for (i = 0; i < ARRAY_SIZE(prop4); i++) {
+ if (of_find_property(np, prop4[i].name, NULL))
nconfs++;
}
if (!nconfs)
@@ -985,12 +1055,12 @@ static int pcs_parse_pinconf(struct pcs_device *pcs, struct device_node *np,
return -ENOMEM;
s = &settings[0];
- for (i = 0; i < ARRAY_SIZE(prop2); i++) {
- pcs_add_conf2(np, prop2[i].name, prop2[i].param, &conf, &s);
- }
- for (i = 0; i < ARRAY_SIZE(prop3); i++) {
- pcs_add_conf3(np, prop3[i].name, prop3[i].param, &conf, &s);
- }
+ for (i = 0; i < ARRAY_SIZE(prop2); i++)
+ pcs_add_conf2(pcs, np, prop2[i].name, prop2[i].param,
+ &conf, &s);
+ for (i = 0; i < ARRAY_SIZE(prop4); i++)
+ pcs_add_conf4(pcs, np, prop4[i].name, prop4[i].param,
+ &conf, &s);
m->type = PIN_MAP_TYPE_CONFIGS_GROUP;
m->data.configs.group_or_pin = np->name;
m->data.configs.configs = settings;
@@ -1366,10 +1436,9 @@ static int pcs_probe(struct platform_device *pdev)
pcs->desc.name = DRIVER_NAME;
pcs->desc.pctlops = &pcs_pinctrl_ops;
pcs->desc.pmxops = &pcs_pinmux_ops;
- pcs->desc.confops = &pcs_pinconf_ops;
+ if (pcs->is_pinconf)
+ pcs->desc.confops = &pcs_pinconf_ops;
pcs->desc.owner = THIS_MODULE;
- if (match->data)
- pcs_pinconf_ops.is_generic = true;
ret = pcs_allocate_pin_table(pcs);
if (ret < 0)