[PATCH v2] gpio: rewrite U300 GPIO to use gpiolib
Barry Song
21cnbao at gmail.com
Wed Sep 7 08:55:28 EDT 2011
> -/* GPIO Pull-Up status */
> -#define DISABLE_PULL_UP 0
> -#define ENABLE_PULL_UP 1
> +#define U300_OUTPUT_LOW { \
> + .output = true, \
> + .outval = 0, \
> +}
>
> -#define GPIO_NOT_USED 0
> -#define GPIO_IN 1
> -#define GPIO_OUT 2
> +#define U300_OUTPUT_HIGH { \
> + .output = true, \
> + .outval = 1, \
> +}
>
> -struct u300_gpio_configuration_data {
> - unsigned char pin_usage;
> - unsigned char default_output_value;
> - unsigned char pull_up;
> -};
>
> /* Initial configuration */
> -const struct u300_gpio_configuration_data
> -u300_gpio_config[U300_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
> -#ifdef CONFIG_MACH_U300_BS335
> +static const struct __initdata u300_gpio_confdata
> +bs335_gpio_config[BS335_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
> /* Port 0, pins 0-7 */
> {
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}
> + U300_FLOATING_INPUT,
> + U300_OUTPUT_HIGH,
> + U300_FLOATING_INPUT,
> + U300_OUTPUT_LOW,
> + U300_OUTPUT_LOW,
> + U300_OUTPUT_LOW,
> + U300_OUTPUT_LOW,
> + U300_OUTPUT_LOW,
> },
> /* Port 1, pins 0-7 */
> {
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}
> + U300_OUTPUT_LOW,
> + U300_OUTPUT_LOW,
> + U300_OUTPUT_LOW,
> + U300_PULL_UP_INPUT,
> + U300_FLOATING_INPUT,
> + U300_OUTPUT_HIGH,
> + U300_OUTPUT_LOW,
> + U300_OUTPUT_LOW,
> },
> /* Port 2, pins 0-7 */
> {
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_OUTPUT_LOW,
> + U300_PULL_UP_INPUT,
> + U300_OUTPUT_LOW,
> + U300_PULL_UP_INPUT,
> },
> /* Port 3, pins 0-7 */
> {
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}
> + U300_PULL_UP_INPUT,
> + U300_OUTPUT_LOW,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> },
> /* Port 4, pins 0-7 */
> {
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> },
> /* Port 5, pins 0-7 */
> {
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> },
> /* Port 6, pind 0-7 */
> {
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> }
> -#endif
> +};
>
> -#ifdef CONFIG_MACH_U300_BS365
> +static const struct __initdata u300_gpio_confdata
> +bs365_gpio_config[BS365_GPIO_NUM_PORTS][U300_GPIO_PINS_PER_PORT] = {
> /* Port 0, pins 0-7 */
> {
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}
> + U300_FLOATING_INPUT,
> + U300_OUTPUT_LOW,
> + U300_FLOATING_INPUT,
> + U300_OUTPUT_LOW,
> + U300_OUTPUT_LOW,
> + U300_OUTPUT_LOW,
> + U300_PULL_UP_INPUT,
> + U300_FLOATING_INPUT,
> },
> /* Port 1, pins 0-7 */
> {
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_HIGH, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP}
> + U300_OUTPUT_LOW,
> + U300_FLOATING_INPUT,
> + U300_OUTPUT_LOW,
> + U300_FLOATING_INPUT,
> + U300_FLOATING_INPUT,
> + U300_OUTPUT_HIGH,
> + U300_OUTPUT_LOW,
> + U300_OUTPUT_LOW,
> },
> /* Port 2, pins 0-7 */
> {
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, DISABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}
> + U300_FLOATING_INPUT,
> + U300_PULL_UP_INPUT,
> + U300_OUTPUT_LOW,
> + U300_OUTPUT_LOW,
> + U300_PULL_UP_INPUT,
> + U300_PULL_UP_INPUT,
> + U300_PULL_UP_INPUT,
> + U300_PULL_UP_INPUT,
> },
> /* Port 3, pins 0-7 */
> {
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}
> + U300_PULL_UP_INPUT,
> + U300_PULL_UP_INPUT,
> + U300_PULL_UP_INPUT,
> + U300_PULL_UP_INPUT,
> + U300_PULL_UP_INPUT,
> + U300_PULL_UP_INPUT,
> + U300_PULL_UP_INPUT,
> + U300_PULL_UP_INPUT,
> },
> /* Port 4, pins 0-7 */
> {
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_IN, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> + U300_PULL_UP_INPUT,
> + U300_PULL_UP_INPUT,
> + U300_PULL_UP_INPUT,
> + U300_PULL_UP_INPUT,
> /* These 4 pins doesn't exist on DB3210 */
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP},
> - {GPIO_OUT, DEFAULT_OUTPUT_LOW, ENABLE_PULL_UP}
> + U300_OUTPUT_LOW,
> + U300_OUTPUT_LOW,
> + U300_OUTPUT_LOW,
> + U300_OUTPUT_LOW,
> }
> -#endif
> };
> -#endif
>
> -
> -/* No users == we can power down GPIO */
> -static int gpio_users;
> -
> -struct gpio_struct {
> - int (*callback)(void *);
> - void *data;
> - int users;
> -}
> -/*
> - * Let drivers register callback in order to get notified when there is
> - * an interrupt on the gpio pin
> +static int u300_gpio_config(struct gpio_chip *chip, unsigned offset,
> + u16 param, unsigned long *data)
> +{
> + struct u300_gpio *gpio = to_u300_gpio(chip);
> unsigned long flags;
> u32 val;
>
> - if (gpio > U300_GPIO_MAX)
> - return -EINVAL;
> -
> local_irq_save(flags);
> - val = readl(virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) *
> - U300_GPIO_PORTX_SPACING);
> - /* Mask out this pin*/
> - val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << ((gpio & 0x07) << 1));
> - /* This is not needed since it sets the bits to zero.*/
> - /* val |= (U300_GPIO_PXPCR_PIN_MODE_INPUT << (gpio*2)); */
> - writel(val, virtbase + U300_GPIO_PXPCR + PIN_TO_PORT(gpio) *
> - U300_GPIO_PORTX_SPACING);
> + switch (param) {
> + case GPIO_U300_CONFIG_BIAS_UNKNOWN:
> + case GPIO_U300_CONFIG_BIAS_FLOAT:
> + val = readl(U300_PIN_REG(offset, per));
> + writel(val | U300_PIN_BIT(offset), U300_PIN_REG(offset, per));
> + break;
> + case GPIO_U300_CONFIG_BIAS_PULL_UP:
> + val = readl(U300_PIN_REG(offset, per));
> + writel(val & ~U300_PIN_BIT(offset), U300_PIN_REG(offset, per));
> + break;
> + case GPIO_U300_CONFIG_DRIVE_PUSH_PULL:
> + val = readl(U300_PIN_REG(offset, pcr));
> + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK
> + << ((offset & 0x07) << 1));
> + val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL
> + << ((offset & 0x07) << 1));
> + writel(val, U300_PIN_REG(offset, pcr));
> + break;
> + case GPIO_U300_CONFIG_DRIVE_OPEN_DRAIN:
> + val = readl(U300_PIN_REG(offset, pcr));
> + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK
> + << ((offset & 0x07) << 1));
> + val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_DRAIN
> + << ((offset & 0x07) << 1));
> + writel(val, U300_PIN_REG(offset, pcr));
> + break;
> + case GPIO_U300_CONFIG_DRIVE_OPEN_SOURCE:
> + val = readl(U300_PIN_REG(offset, pcr));
> + val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK
> + << ((offset & 0x07) << 1));
> + val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_OPEN_SOURCE
> + << ((offset & 0x07) << 1));
> + writel(val, U300_PIN_REG(offset, pcr));
> + break;
> + default:
> + local_irq_restore(flags);
> + dev_err(gpio->dev, "illegal configuration requested\n");
> + return -EINVAL;
> + }
> local_irq_restore(flags);
> return 0;
> }
>
> -static void gpio_set_initial_values(void)
> +static void __init u300_gpio_init_pin(struct u300_gpio *gpio,
> + int offset,
> + const struct u300_gpio_confdata *conf)
> {
> -#ifdef U300_COH901571_3
> - int i, j;
> - unsigned long flags;
> - u32 val;
> + /* Set mode: input or output */
> + if (conf->output) {
> + u300_gpio_direction_output(&gpio->chip, offset, conf->outval);
>
> - /* Write default values to all pins */
> - for (i = 0; i < U300_GPIO_NUM_PORTS; i++) {
> - val = 0;
> - for (j = 0; j < 8; j++)
> - val |= (u32) (u300_gpio_config[i][j].default_output_value != DEFAULT_OUTPUT_LOW) << j;
> - local_irq_save(flags);
> - writel(val, virtbase + U300_GPIO_PXPDOR + i * U300_GPIO_PORTX_SPACING);
> - local_irq_restore(flags);
> + /* Deactivate bias mode for output */
> + u300_gpio_config(&gpio->chip, offset,
> + GPIO_U300_CONFIG_BIAS_FLOAT,
> + NULL);
> +
> + /* Set drive mode for output */
> + u300_gpio_config(&gpio->chip, offset,
> + GPIO_U300_CONFIG_DRIVE_PUSH_PULL, NULL);
> +
> + dev_dbg(gpio->dev, "set up pin %d as output, value: %d\n",
> + offset, conf->outval);
> + } else {
> + u300_gpio_direction_input(&gpio->chip, offset);
> +
> + /* Always set output low on input pins */
> + u300_gpio_set(&gpio->chip, offset, 0);
> +
> + /* Set bias mode for input */
> + u300_gpio_config(&gpio->chip, offset, conf->bias_mode, NULL);
> +
> + dev_dbg(gpio->dev, "set up pin %d as input, bias: %04x\n",
> + offset, conf->bias_mode);
> }
> +}
>
> - /*
> - * Put all pins that are set to either 'GPIO_OUT' or 'GPIO_NOT_USED'
> - * to output and 'GPIO_IN' to input for each port. And initialize
> - * default value on outputs.
> - */
> - for (i = 0; i < U300_GPIO_NUM_PORTS; i++) {
> - for (j = 0; j < U300_GPIO_PINS_PER_PORT; j++) {
> - local_irq_save(flags);
> - val = readl(virtbase + U300_GPIO_PXPCR +
> - i * U300_GPIO_PORTX_SPACING);
> - /* Mask out this pin */
> - val &= ~(U300_GPIO_PXPCR_PIN_MODE_MASK << (j << 1));
> -
> - if (u300_gpio_config[i][j].pin_usage != GPIO_IN)
> - val |= (U300_GPIO_PXPCR_PIN_MODE_OUTPUT_PUSH_PULL << (j << 1));
> - writel(val, virtbase + U300_GPIO_PXPCR +
> - i * U300_GPIO_PORTX_SPACING);
> - local_irq_restore(flags);
> +static void __init u300_gpio_init_coh901571(struct u300_gpio *gpio,
> + struct u300_gpio_platform *plat)
> +{
> + int i, j;
> +
> + /* Write default config and values to all pins */
> + for (i = 0; i < plat->ports; i++) {
> + for (j = 0; j < 8; j++) {
> + const struct u300_gpio_confdata *conf;
> + int offset = (i*8) + j;
> +
> + if (plat->variant == U300_GPIO_COH901571_3_BS335)
> + conf = &bs335_gpio_config[i][j];
> + else if (plat->variant == U300_GPIO_COH901571_3_BS365)
> + conf = &bs365_gpio_config[i][j];
> + else
> + break;
> +
> + u300_gpio_init_pin(gpio, offset, conf);
> }
> }
> +}
>
> - /* Enable or disable the internal pull-ups in the GPIO ASIC block */
> - for (i = 0; i < U300_GPIO_MAX; i++) {
> - val = 0;
> - for (j = 0; j < 8; j++)
> - val |= (u32)((u300_gpio_config[i][j].pull_up == DISABLE_PULL_UP) << j);
> - local_irq_save(flags);
> - writel(val, virtbase + U300_GPIO_PXPER + i * U300_GPIO_PORTX_SPACING);
> - local_irq_restore(flags);
this has used array/table to set the pull of gpio. so what's our plan
about api to config GPIO pull dynamically?
-barry
More information about the linux-arm-kernel
mailing list