diff options
author | Haojian Zhuang <haojian.zhuang@linaro.org> | 2013-03-13 16:45:26 +0800 |
---|---|---|
committer | Haojian Zhuang <haojian.zhuang@linaro.org> | 2013-03-13 16:45:26 +0800 |
commit | 85996424ef208605a20dc6cb20200bc7b2ec7fa7 (patch) | |
tree | 404c38d0d77d96699caab3311b24147d7eebfcb8 | |
parent | 6d452a2406274fa2684df2c5248654db60e70377 (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.c | 211 |
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) |