@@ -32,6 +32,7 @@ config PINMUX_U300
bool "U300 pinmux driver"
depends on ARCH_U300
select PINMUX
+ select PINCONF
config PINCTRL_COH901XXX
bool "ST-Ericsson U300 COH 901 335/571 GPIO"
@@ -420,8 +420,37 @@ static int u300_gpio_to_irq(struct gpio_chip *chip, unsigned offset)
return retirq;
}
-static int u300_gpio_config(struct gpio_chip *chip, unsigned offset,
- enum pin_config_param param, unsigned long data)
+int u300_gpio_get_initial_config(struct gpio_chip *chip,
+ struct pin_config *conf,
+ unsigned offset)
+{
+ struct u300_gpio *gpio = to_u300_gpio(chip);
+ u32 val;
+
+ val = readl(U300_PIN_REG(offset, per));
+ if (val & U300_PIN_BIT(offset))
+ conf->bias.param = PIN_CONFIG_BIAS_HIGH_IMPEDANCE;
+ else
+ conf->bias.param = PIN_CONFIG_BIAS_PULL_UP;
+ switch (val &
+ (U300_GPIO_PXPCR_PIN_MODE_MASK << ((offset & 0x07) << 1))) {
+ case U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL:
+ conf->drive.param = PIN_CONFIG_DRIVE_PUSH_PULL;
+ break;
+ case U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN:
+ conf->drive.param = PIN_CONFIG_DRIVE_OPEN_DRAIN;
+ break;
+ case U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE:
+ conf->drive.param = PIN_CONFIG_DRIVE_OPEN_SOURCE;
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+int u300_gpio_config(struct gpio_chip *chip, unsigned offset,
+ enum pin_config_param param)
{
struct u300_gpio *gpio = to_u300_gpio(chip);
unsigned long flags;
@@ -623,12 +652,11 @@ static void __init u300_gpio_init_pin(struct u300_gpio *gpio,
/* Deactivate bias mode for output */
u300_gpio_config(&gpio->chip, offset,
- PIN_CONFIG_BIAS_HIGH_IMPEDANCE,
- 0);
+ PIN_CONFIG_BIAS_HIGH_IMPEDANCE);
/* Set drive mode for output */
u300_gpio_config(&gpio->chip, offset,
- PIN_CONFIG_DRIVE_PUSH_PULL, 0);
+ PIN_CONFIG_DRIVE_PUSH_PULL);
dev_dbg(gpio->dev, "set up pin %d as output, value: %d\n",
offset, conf->outval);
@@ -639,7 +667,7 @@ static void __init u300_gpio_init_pin(struct u300_gpio *gpio,
u300_gpio_set(&gpio->chip, offset, 0);
/* Set bias mode for input */
- u300_gpio_config(&gpio->chip, offset, conf->bias_mode, 0);
+ u300_gpio_config(&gpio->chip, offset, conf->bias_mode);
dev_dbg(gpio->dev, "set up pin %d as input, bias: %04x\n",
offset, conf->bias_mode);
@@ -1,3 +1,8 @@
+int u300_gpio_get_initial_config(struct gpio_chip *chip,
+ struct pin_config *conf,
+ unsigned offset);
+int u300_gpio_config(struct gpio_chip *chip,
+ unsigned offset, enum pin_config_param param);
int u300_gpio_probe(struct platform_device *pdev,
- struct gpio_chip **chip);
+ struct gpio_chip **chip);
int u300_gpio_remove(struct platform_device *pdev);
@@ -19,6 +19,7 @@
#include <linux/err.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
#include "pinctrl-coh901xxx.h"
/*
@@ -1046,6 +1047,66 @@ static struct pinctrl_gpio_range u300_gpio_ranges[] = {
U300_GPIO_RANGE(25, 181, 1),
};
+static struct pinctrl_gpio_range *u300_match_gpio_range(unsigned pin)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++) {
+ struct pinctrl_gpio_range *range;
+
+ range = &u300_gpio_ranges[i];
+ if (pin >= range->pin_base &&
+ pin <= (range->pin_base + range->npins - 1))
+ return range;
+ }
+ return NULL;
+}
+
+int u300_pin_get_initial_config(struct pinctrl_dev *pctldev,
+ struct pin_config *conf,
+ unsigned pin)
+{
+ struct pinctrl_gpio_range *range = u300_match_gpio_range(pin);
+
+ /* We get config for those pins we CAN get it for and that's it */
+ if (!range)
+ return 0;
+
+ return u300_gpio_get_initial_config(range->gc, conf,
+ (pin - range->pin_base + range->base));
+}
+
+int u300_pin_config(struct pinctrl_dev *pctldev,
+ const struct pin_config *conf,
+ unsigned pin,
+ const struct pin_config_tuple *configs,
+ unsigned num_configs)
+{
+ struct pinctrl_gpio_range *range = u300_match_gpio_range(pin);
+ int ret;
+ int i;
+
+ if (!range)
+ return -EINVAL;
+
+ for (i = 0; i < num_configs; i++) {
+ const struct pin_config_tuple *config = &configs[i];
+
+ ret = u300_gpio_config(range->gc,
+ (pin - range->pin_base + range->base),
+ config->param);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct pinconf_ops u300_pconf_ops = {
+ .pin_get_initial_config = u300_pin_get_initial_config,
+ .pin_config = u300_pin_config,
+};
+
static struct pinctrl_desc u300_pmx_desc = {
.name = DRIVER_NAME,
.pins = u300_pads,
@@ -1053,6 +1114,7 @@ static struct pinctrl_desc u300_pmx_desc = {
.maxpin = U300_NUM_PADS-1,
.pctlops = &u300_pctrl_ops,
.pmxops = &u300_pmx_ops,
+ .confops = &u300_pconf_ops,
.owner = THIS_MODULE,
};
@@ -1092,25 +1154,30 @@ static int __init u300_pmx_probe(struct platform_device *pdev)
goto out_no_remap;
}
- upmx->pctl = pinctrl_register(&u300_pmx_desc, &pdev->dev, upmx);
- if (!upmx->pctl) {
- dev_err(&pdev->dev, "could not register U300 pinmux driver\n");
- ret = -EINVAL;
- goto out_no_pmx;
- }
-
/* Now probe the sibling GPIO driver */
ret = u300_gpio_probe(upmx->gpio_pdev, &chip);
if (ret) {
dev_err(&pdev->dev, "could not probe sibling GPIO device\n");
goto out_no_gpio;
}
+ /*
+ * These ranges will be used during pin configuration registration
+ * to call back into the GPIO driver and read out default pin
+ * configuration so set it up here.
+ */
+ for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++)
+ u300_gpio_ranges[i].gc = chip;
+
+ upmx->pctl = pinctrl_register(&u300_pmx_desc, &pdev->dev, upmx);
+ if (!upmx->pctl) {
+ dev_err(&pdev->dev, "could not register U300 pinmux driver\n");
+ ret = -EINVAL;
+ goto out_no_pmx;
+ }
/* We will handle a range of GPIO pins */
- for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++) {
- u300_gpio_ranges[i].gc = chip;
+ for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++)
pinctrl_add_gpio_range(upmx->pctl, &u300_gpio_ranges[i]);
- }
platform_set_drvdata(pdev, upmx);
@@ -1118,9 +1185,9 @@ static int __init u300_pmx_probe(struct platform_device *pdev)
return 0;
-out_no_gpio:
- pinctrl_unregister(upmx->pctl);
out_no_pmx:
+ u300_gpio_remove(upmx->gpio_pdev);
+out_no_gpio:
iounmap(upmx->virtbase);
out_no_remap:
platform_set_drvdata(pdev, NULL);
@@ -1136,10 +1203,10 @@ static int __exit u300_pmx_remove(struct platform_device *pdev)
struct u300_pmx *upmx = platform_get_drvdata(pdev);
int i;
+ pinctrl_unregister(upmx->pctl);
for (i = 0; i < ARRAY_SIZE(u300_gpio_ranges); i++)
pinctrl_remove_gpio_range(upmx->pctl, &u300_gpio_ranges[i]);
u300_gpio_remove(upmx->gpio_pdev);
- pinctrl_unregister(upmx->pctl);
iounmap(upmx->virtbase);
release_mem_region(upmx->phybase, upmx->physize);
platform_set_drvdata(pdev, NULL);