summaryrefslogtreecommitdiff
path: root/drivers/pinctrl/pinctrl-as3722.c
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2013-11-10 19:44:51 +0530
committerLaxman Dewangan <ldewangan@nvidia.com>2013-11-11 22:17:42 -0800
commit8d9ee8b4d6d410d2a955f1b3fb74f42d46a617f8 (patch)
tree34b384ce38c23cc35b1886c3bb4340b664c1414e /drivers/pinctrl/pinctrl-as3722.c
parent97c6d9bcc27d5776de5589c08b052bfbd8ba2809 (diff)
pinctrl: as3722: add non-dt support
Add non-dt support for AS3722 pincontrol driver so that default pin configuration can be passed through platform data during registering of driver from board files. Change-Id: Ia14c709f84f45f7a994435c980386f4ed11e0ad4 Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> Reviewed-on: http://git-master/r/328686
Diffstat (limited to 'drivers/pinctrl/pinctrl-as3722.c')
-rw-r--r--drivers/pinctrl/pinctrl-as3722.c224
1 files changed, 198 insertions, 26 deletions
diff --git a/drivers/pinctrl/pinctrl-as3722.c b/drivers/pinctrl/pinctrl-as3722.c
index 929e5a363615..483a4c8f444a 100644
--- a/drivers/pinctrl/pinctrl-as3722.c
+++ b/drivers/pinctrl/pinctrl-as3722.c
@@ -300,10 +300,8 @@ static int as3722_pinctrl_gpio_set_direction(struct pinctrl_dev *pctldev,
return mode;
}
- if (as_pci->gpio_control[offset].enable_gpio_invert)
- mode |= AS3722_GPIO_INV;
-
- return as3722_write(as3722, AS3722_GPIOn_CONTROL_REG(offset), mode);
+ return as3722_update_bits(as3722, AS3722_GPIOn_CONTROL_REG(offset),
+ AS3722_GPIO_MODE_MASK, mode);
}
static const struct pinmux_ops as3722_pinmux_ops = {
@@ -368,32 +366,32 @@ static int as3722_pinconf_set(struct pinctrl_dev *pctldev,
int mode_prop = as_pci->gpio_control[pin].mode_prop;
switch (param) {
- case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
- break;
+ case PIN_CONFIG_BIAS_PULL_PIN_DEFAULT:
+ break;
- case PIN_CONFIG_BIAS_DISABLE:
- mode_prop &= ~(AS3722_GPIO_MODE_PULL_UP |
- AS3722_GPIO_MODE_PULL_DOWN);
- break;
- case PIN_CONFIG_BIAS_PULL_UP:
- mode_prop |= AS3722_GPIO_MODE_PULL_UP;
- break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ mode_prop &= ~(AS3722_GPIO_MODE_PULL_UP |
+ AS3722_GPIO_MODE_PULL_DOWN);
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ mode_prop |= AS3722_GPIO_MODE_PULL_UP;
+ break;
- case PIN_CONFIG_BIAS_PULL_DOWN:
- mode_prop |= AS3722_GPIO_MODE_PULL_DOWN;
- break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ mode_prop |= AS3722_GPIO_MODE_PULL_DOWN;
+ break;
- case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
- mode_prop |= AS3722_GPIO_MODE_HIGH_IMPED;
- break;
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ mode_prop |= AS3722_GPIO_MODE_HIGH_IMPED;
+ break;
- case PIN_CONFIG_DRIVE_OPEN_DRAIN:
- mode_prop |= AS3722_GPIO_MODE_OPEN_DRAIN;
- break;
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ mode_prop |= AS3722_GPIO_MODE_OPEN_DRAIN;
+ break;
- default:
- dev_err(as_pci->dev, "Properties not supported\n");
- return -ENOTSUPP;
+ default:
+ dev_err(as_pci->dev, "Properties not supported\n");
+ return -ENOTSUPP;
}
as_pci->gpio_control[pin].mode_prop = mode_prop;
@@ -529,11 +527,159 @@ static const struct gpio_chip as3722_gpio_chip = {
.base = -1,
};
+static int as3722_pinctrl_set_single_pin_config(
+ struct as3722_pctrl_info *as_pci,
+ struct as3722_pinctrl_platform_data *as_pdata)
+{
+ int pin_id;
+ int group_nr;
+ int param_val;
+ int param;
+ int ret = 0;
+ int mux_opt;
+ int i;
+ unsigned long config;
+
+ if (!as_pdata->pin) {
+ dev_err(as_pci->dev, "No pin name\n");
+ return -EINVAL;
+ }
+
+ pin_id = pin_get_from_name(as_pci->pctl, as_pdata->pin);
+ if (pin_id < 0) {
+ dev_err(as_pci->dev, " Pin %s not found\n", as_pdata->pin);
+ return ret;
+ }
+
+ /* Configure bias pull */
+ if (!as_pdata->prop_bias_pull)
+ goto skip_bias_pull;
+
+ if (!strcmp(as_pdata->prop_bias_pull, "pull-up"))
+ param = PIN_CONFIG_BIAS_PULL_UP;
+ else if (!strcmp(as_pdata->prop_bias_pull, "pull-down"))
+ param = PIN_CONFIG_BIAS_PULL_DOWN;
+ else if (!strcmp(as_pdata->prop_bias_pull, "normal"))
+ param = PIN_CONFIG_BIAS_DISABLE;
+ else {
+ dev_err(as_pci->dev, "Unknown bias-pull setting %s\n",
+ as_pdata->prop_bias_pull);
+ goto skip_bias_pull;
+ }
+ config = pinconf_to_config_packed(param, 0);
+ ret = as3722_pinconf_set(as_pci->pctl, pin_id, config);
+ if (ret < 0) {
+ dev_err(as_pci->dev, "bias-pull setting failed: %d\n", ret);
+ return ret;
+ }
+
+skip_bias_pull:
+ /* Configure open drain */
+ if (!as_pdata->prop_open_drain)
+ goto skip_open_drain;
+
+ param = PIN_CONFIG_DRIVE_OPEN_DRAIN;
+ if (!strcmp(as_pdata->prop_bias_pull, "enable"))
+ param_val = 1;
+ else
+ param_val = 0;
+ config = pinconf_to_config_packed(param, param_val);
+ ret = as3722_pinconf_set(as_pci->pctl, pin_id, config);
+ if (ret < 0) {
+ dev_err(as_pci->dev, "Opendrain setting failed: %d\n", ret);
+ return ret;
+ }
+
+skip_open_drain:
+ /* Configure high impedance */
+ if (!as_pdata->prop_high_impedance)
+ goto skip_high_impedance;
+
+ param = PIN_CONFIG_BIAS_HIGH_IMPEDANCE;
+ if (!strcmp(as_pdata->prop_high_impedance, "enable"))
+ param_val = 1;
+ else
+ param_val = 0;
+ config = pinconf_to_config_packed(param, param_val);
+ ret = as3722_pinconf_set(as_pci->pctl, pin_id, config);
+ if (ret < 0) {
+ dev_err(as_pci->dev, "hi-impedance setting failed: %d\n", ret);
+ return ret;
+ }
+
+skip_high_impedance:
+ /* Configure function */
+ if (!as_pdata->function)
+ goto skip_function;
+
+ for (group_nr = 0; group_nr < as_pci->num_pin_groups; ++group_nr) {
+ if (as_pci->pin_groups[group_nr].pins[0] == pin_id)
+ break;
+ }
+
+ if (group_nr == as_pci->num_pin_groups) {
+ dev_err(as_pci->dev,
+ "Pinconf is not supported for pin-id %d\n", pin_id);
+ return -ENOTSUPP;
+ }
+
+ mux_opt = -1;
+ for (i = 0; i < as_pci->num_functions; ++i) {
+ if (!strcmp(as_pdata->function, as_pci->functions[i].name)) {
+ mux_opt = i;
+ break;
+ }
+ }
+ if (mux_opt < 0) {
+ dev_err(as_pci->dev, "Pinmux function %s not supported\n",
+ as_pdata->function);
+ return -EINVAL;
+ }
+
+
+ if (!strcmp(as_pdata->function, "gpio") && as_pdata->prop_gpio_mode) {
+ bool gpio_input = false;
+ int gpio_val = 0;
+
+ if (!strcmp(as_pdata->prop_gpio_mode, "input"))
+ gpio_input = true;
+ else if (!strcmp(as_pdata->prop_gpio_mode, "output-low"))
+ gpio_val = 0;
+ else if (!strcmp(as_pdata->prop_gpio_mode, "output-high"))
+ gpio_val = 1;
+ else {
+ dev_err(as_pci->dev, "Invalid gpio mode %s\n",
+ as_pdata->prop_gpio_mode);
+ goto skip_gpio_config;
+ }
+ if (gpio_input)
+ as3722_gpio_direction_input(&as_pci->gpio_chip, pin_id);
+ else
+ as3722_gpio_direction_output(&as_pci->gpio_chip, pin_id,
+ gpio_val);
+ }
+
+skip_gpio_config:
+ ret = as3722_pinctrl_enable(as_pci->pctl, mux_opt, group_nr);
+ if (ret < 0) {
+ dev_err(as_pci->dev,
+ "Pinconf config for pin %s failed %d\n",
+ as_pdata->pin, ret);
+ return ret;
+ }
+
+skip_function:
+ return ret;
+}
+
static int as3722_pinctrl_probe(struct platform_device *pdev)
{
struct as3722_pctrl_info *as_pci;
+ struct as3722 *as3722 = dev_get_drvdata(pdev->dev.parent);
+ struct as3722_platform_data *pdata = as3722->dev->platform_data;
int ret;
int tret;
+ int i;
as_pci = devm_kzalloc(&pdev->dev, sizeof(*as_pci), GFP_KERNEL);
if (!as_pci)
@@ -541,9 +687,19 @@ static int as3722_pinctrl_probe(struct platform_device *pdev)
as_pci->dev = &pdev->dev;
as_pci->dev->of_node = pdev->dev.parent->of_node;
- as_pci->as3722 = dev_get_drvdata(pdev->dev.parent);
+ as_pci->as3722 = as3722;
platform_set_drvdata(pdev, as_pci);
+ for (i = 0; i < ARRAY_SIZE(as3722_pingroups); ++i) {
+ int gpio_cntr_reg = AS3722_GPIOn_CONTROL_REG(i);
+ u32 val;
+
+ ret = as3722_read(as3722, gpio_cntr_reg, &val);
+ if (!ret)
+ as_pci->gpio_control[i].enable_gpio_invert =
+ !!(val & AS3722_GPIO_INV);
+ }
+
as_pci->pins = as3722_pins_desc;
as_pci->num_pins = ARRAY_SIZE(as3722_pins_desc);
as_pci->functions = as3722_pin_function;
@@ -561,6 +717,8 @@ static int as3722_pinctrl_probe(struct platform_device *pdev)
}
as_pci->gpio_chip = as3722_gpio_chip;
+ if (pdata && pdata->gpio_base)
+ as_pci->gpio_chip.base = pdata->gpio_base;
as_pci->gpio_chip.dev = &pdev->dev;
as_pci->gpio_chip.of_node = pdev->dev.parent->of_node;
ret = gpiochip_add(&as_pci->gpio_chip);
@@ -576,6 +734,20 @@ static int as3722_pinctrl_probe(struct platform_device *pdev)
goto fail_range_add;
}
+ if (pdata) {
+ struct as3722_pinctrl_platform_data *as_pdata;
+
+ for (i = 0; i < pdata->num_pinctrl; ++i) {
+ as_pdata = &pdata->pinctrl_pdata[i];
+ ret = as3722_pinctrl_set_single_pin_config(as_pci,
+ as_pdata);
+ if (ret < 0)
+ dev_warn(&pdev->dev,
+ "Pin config of pin %s failed %d\n",
+ as_pdata->pin, ret);
+ }
+ }
+
return 0;
fail_range_add: