Skip to content

Commit

Permalink
pinctrl: support pinconfig on the U300
Browse files Browse the repository at this point in the history
This adds pin configuration support for the U300 driver pair,
we can now read out the biasing and drive mode in debugfs and
configure it using the new configuration API.

ChangeLog v1->v2:
- Migrate to pin config and generic pin config changes.
ChangeLog v2->v3:
- Adjust to generic pin config changes in v7 patch set.

Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
  • Loading branch information
Linus Walleij committed Mar 12, 2012
1 parent a050b3e commit dc0b1aa
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 8 deletions.
1 change: 1 addition & 0 deletions drivers/pinctrl/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ config PINCTRL_U300
bool "U300 pin controller driver"
depends on ARCH_U300
select PINMUX
select GENERIC_PINCONF

config PINCTRL_COH901
bool "ST-Ericsson U300 COH 901 335/571 GPIO"
Expand Down
77 changes: 69 additions & 8 deletions drivers/pinctrl/pinctrl-coh901.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pinctrl/pinconf-generic.h>
#include <mach/gpio-u300.h>
#include "pinctrl-coh901.h"

/*
* Register definitions for COH 901 335 variant
Expand Down Expand Up @@ -418,8 +420,68 @@ 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)
/* Returning -EINVAL means "supported but not available" */
int u300_gpio_config_get(struct gpio_chip *chip,
unsigned offset,
unsigned long *config)
{
struct u300_gpio *gpio = to_u300_gpio(chip);
enum pin_config_param param = (enum pin_config_param) *config;
bool biasmode;
u32 drmode;

/* One bit per pin, clamp to bool range */
biasmode = !!(readl(U300_PIN_REG(offset, per)) & U300_PIN_BIT(offset));

/* Mask out the two bits for this pin and shift to bits 0,1 */
drmode = readl(U300_PIN_REG(offset, pcr));
drmode &= (U300_GPIO_PXPCR_PIN_MODE_MASK << ((offset & 0x07) << 1));
drmode >>= ((offset & 0x07) << 1);

switch(param) {
case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
*config = 0;
if (biasmode)
return 0;
else
return -EINVAL;
break;
case PIN_CONFIG_BIAS_PULL_UP:
*config = 0;
if (!biasmode)
return 0;
else
return -EINVAL;
break;
case PIN_CONFIG_DRIVE_PUSH_PULL:
*config = 0;
if (drmode == U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL)
return 0;
else
return -EINVAL;
break;
case PIN_CONFIG_DRIVE_OPEN_DRAIN:
*config = 0;
if (drmode == U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN)
return 0;
else
return -EINVAL;
break;
case PIN_CONFIG_DRIVE_OPEN_SOURCE:
*config = 0;
if (drmode == U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE)
return 0;
else
return -EINVAL;
break;
default:
break;
}
return -ENOTSUPP;
}

int u300_gpio_config_set(struct gpio_chip *chip, unsigned offset,
enum pin_config_param param)
{
struct u300_gpio *gpio = to_u300_gpio(chip);
unsigned long flags;
Expand Down Expand Up @@ -620,13 +682,12 @@ static void __init u300_gpio_init_pin(struct u300_gpio *gpio,
u300_gpio_direction_output(&gpio->chip, offset, conf->outval);

/* Deactivate bias mode for output */
u300_gpio_config(&gpio->chip, offset,
PIN_CONFIG_BIAS_HIGH_IMPEDANCE,
0);
u300_gpio_config_set(&gpio->chip, offset,
PIN_CONFIG_BIAS_HIGH_IMPEDANCE);

/* Set drive mode for output */
u300_gpio_config(&gpio->chip, offset,
PIN_CONFIG_DRIVE_PUSH_PULL, 0);
u300_gpio_config_set(&gpio->chip, offset,
PIN_CONFIG_DRIVE_PUSH_PULL);

dev_dbg(gpio->dev, "set up pin %d as output, value: %d\n",
offset, conf->outval);
Expand All @@ -637,7 +698,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_set(&gpio->chip, offset, conf->bias_mode);

dev_dbg(gpio->dev, "set up pin %d as input, bias: %04x\n",
offset, conf->bias_mode);
Expand Down
5 changes: 5 additions & 0 deletions drivers/pinctrl/pinctrl-coh901.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
int u300_gpio_config_get(struct gpio_chip *chip,
unsigned offset,
unsigned long *config);
int u300_gpio_config_set(struct gpio_chip *chip, unsigned offset,
enum pin_config_param param);
60 changes: 60 additions & 0 deletions drivers/pinctrl/pinctrl-u300.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#include <linux/err.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/pinctrl/pinmux.h>
#include <linux/pinctrl/pinconf.h>
#include <linux/pinctrl/pinconf-generic.h>
#include "pinctrl-coh901.h"

/*
* Register definitions for the U300 Padmux control registers in the
Expand Down Expand Up @@ -1044,12 +1047,69 @@ 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_config_get(struct pinctrl_dev *pctldev,
unsigned pin,
unsigned long *config)
{
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 -ENOTSUPP;

return u300_gpio_config_get(range->gc,
(pin - range->pin_base + range->base),
config);
}

int u300_pin_config_set(struct pinctrl_dev *pctldev,
unsigned pin,
unsigned long config)
{
struct pinctrl_gpio_range *range = u300_match_gpio_range(pin);
int ret;

if (!range)
return -EINVAL;

/* Note: none of these configurations take any argument */
ret = u300_gpio_config_set(range->gc,
(pin - range->pin_base + range->base),
pinconf_to_config_param(config));
if (ret)
return ret;

return 0;
}

static struct pinconf_ops u300_pconf_ops = {
.is_generic = true,
.pin_config_get = u300_pin_config_get,
.pin_config_set = u300_pin_config_set,
};

static struct pinctrl_desc u300_pmx_desc = {
.name = DRIVER_NAME,
.pins = u300_pads,
.npins = ARRAY_SIZE(u300_pads),
.pctlops = &u300_pctrl_ops,
.pmxops = &u300_pmx_ops,
.confops = &u300_pconf_ops,
.owner = THIS_MODULE,
};

Expand Down

0 comments on commit dc0b1aa

Please sign in to comment.