[U-Boot] [PATCH v6 3/4] EXYNOS5: GPIO: Support GPIO Command for EXYNOS5

Przemyslaw Marczak
2014-04-14T15:19:13Z

Hi,

On 04/12/2014 11:43 AM, Akshay Saraswat wrote:
> From: Rajeshwari Shinde <rajeshwari.s@samsung.com>
>
> This patch adds support for name to gpio conversion in s5p_gpio
> to enable gpio command EXYNOS 5250 & 5420.
> Function has been added to asm/gpio.h to decode the
> input gpio name to gpio number.
>
> Example: SMDK5420 # gpio set gpa00
>
> Signed-off-by: Rajeshwari Shinde <rajeshwari.s@samsung.com>
> Signed-off-by: Akshay Saraswat <akshay.s@samsung.com>
> ---
> arch/arm/include/asm/arch-exynos/gpio.h | 28 +++++++++
> drivers/gpio/s5p_gpio.c | 105 ++++++++++++++++++++++++++++++++
> 2 files changed, 133 insertions(+)
>
> diff --git a/arch/arm/include/asm/arch-exynos/gpio.h b/arch/arm/include/asm/arch-exynos/gpio.h
> index 697e6f3..3736a22 100644
> --- a/arch/arm/include/asm/arch-exynos/gpio.h
> +++ b/arch/arm/include/asm/arch-exynos/gpio.h
> @@ -1038,6 +1038,34 @@ static inline unsigned int get_bank_num(void)
> }
> }
>
> +/*
> + * This structure helps mapping symbolic GPIO names into indices from
> + * exynos5_gpio_pin/exynos5420_gpio_pin enums.
> + *
> + * By convention, symbolic GPIO name is defined as follows:
> + *
> + * g[p]<bank><set><bit>, where
> + * p is optional
> + * <bank> - a single character bank name, as defined by the SOC
> + * <set> - a single digit set number
> + * <bit> - bit number within the set (in 0..7 range).
> + *
> + * <set><bit> essentially form an octal number of the GPIO pin within the bank
> + * space. On the 5420 architecture some banks' sets do not start not from zero
> + * ('d' starts from 1 and 'j' starts from 4). To compensate for that and
> + * maintain flat number space withoout holes, those banks use offsets to be
> + * deducted from the pin number.
> + */
> +struct gpio_name_num_table {
> + char bank; /* bank name symbol */
> + u8 bank_size; /* total number of pins in the bank */
> + char bank_offset; /* offset of the first bank's pin */
> + unsigned int base; /* index of the first bank's pin in the enum */
> +};
> +
> +int s5p_name_to_gpio(const char *name);
> +#define name_to_gpio(n) s5p_name_to_gpio(n)
> +
> void gpio_cfg_pin(int gpio, int cfg);
> void gpio_set_pull(int gpio, int mode);
> void gpio_set_drv(int gpio, int mode);
> diff --git a/drivers/gpio/s5p_gpio.c b/drivers/gpio/s5p_gpio.c
> index b1b6fbe..9a80b0c 100644
> --- a/drivers/gpio/s5p_gpio.c
> +++ b/drivers/gpio/s5p_gpio.c
> @@ -28,6 +28,111 @@
> #define RATE_MASK(x) (0x1 << (x + 16))
> #define RATE_SET(x) (0x1 << (x + 16))
>

This driver is common so you can't put here SOC specific code.
This is also the reason of build break for s5pc1xx architecture.

It should be initialized in arch/arm/include/asm/arch-exynos/gpio.h.
The same should be defined for Exynos4 and for s5pc1xx: in
arch/arm/include/asm/arch-s5pc1xx/gpio.h.

This also can require introduce a s5p_gpio.h header with structure
gpio_name_num_table. And maybe better name for this structure type is
gpio_name_to_num ?

> +#define GPIO_ENTRY(name, base, top, offset) { name, top - base, offset, base }
> +static const struct gpio_name_num_table exynos5_gpio_table[] = {
> + GPIO_ENTRY('a', EXYNOS5_GPIO_A00, EXYNOS5_GPIO_B00, 0),
> + GPIO_ENTRY('b', EXYNOS5_GPIO_B00, EXYNOS5_GPIO_C00, 0),
> + GPIO_ENTRY('c', EXYNOS5_GPIO_C00, EXYNOS5_GPIO_D00, 0),
> + GPIO_ENTRY('d', EXYNOS5_GPIO_D00, EXYNOS5_GPIO_Y00, 0),
> + GPIO_ENTRY('y', EXYNOS5_GPIO_Y00, EXYNOS5_GPIO_C40, 0),
> + GPIO_ENTRY('x', EXYNOS5_GPIO_X00, EXYNOS5_GPIO_E00, 0),
> + GPIO_ENTRY('e', EXYNOS5_GPIO_E00, EXYNOS5_GPIO_F00, 0),
> + GPIO_ENTRY('f', EXYNOS5_GPIO_F00, EXYNOS5_GPIO_G00, 0),
> + GPIO_ENTRY('g', EXYNOS5_GPIO_G00, EXYNOS5_GPIO_H00, 0),
> + GPIO_ENTRY('h', EXYNOS5_GPIO_H00, EXYNOS5_GPIO_V00, 0),
> + GPIO_ENTRY('v', EXYNOS5_GPIO_V00, EXYNOS5_GPIO_Z0, 0),
> + GPIO_ENTRY('z', EXYNOS5_GPIO_Z0, EXYNOS5_GPIO_MAX_PORT, 0),
> + { 0 }
> +};
> +
> +static const struct gpio_name_num_table exynos5420_gpio_table[] = {
> + GPIO_ENTRY('a', EXYNOS5420_GPIO_A00, EXYNOS5420_GPIO_B00, 0),
> + GPIO_ENTRY('b', EXYNOS5420_GPIO_B00, EXYNOS5420_GPIO_H00, 0),
> + GPIO_ENTRY('h', EXYNOS5420_GPIO_H00, EXYNOS5420_GPIO_Y70, 0),
> + GPIO_ENTRY('x', EXYNOS5420_GPIO_X00, EXYNOS5420_GPIO_C00, 0),
> + GPIO_ENTRY('c', EXYNOS5420_GPIO_C00, EXYNOS5420_GPIO_D10, 0),
> + GPIO_ENTRY('d', EXYNOS5420_GPIO_D10, EXYNOS5420_GPIO_Y00, 010),
> + GPIO_ENTRY('y', EXYNOS5420_GPIO_Y00, EXYNOS5420_GPIO_E00, 0),
> + GPIO_ENTRY('e', EXYNOS5420_GPIO_E00, EXYNOS5420_GPIO_F00, 0),
> + GPIO_ENTRY('f', EXYNOS5420_GPIO_F00, EXYNOS5420_GPIO_G00, 0),
> + GPIO_ENTRY('g', EXYNOS5420_GPIO_G00, EXYNOS5420_GPIO_J40, 0),
> + GPIO_ENTRY('j', EXYNOS5420_GPIO_J40, EXYNOS5420_GPIO_Z0, 040),
> + GPIO_ENTRY('z', EXYNOS5420_GPIO_Z0, EXYNOS5420_GPIO_MAX_PORT, 0),
> + { 0 }
> +};
> +
> +int s5p_name_to_gpio(const char *name)
> +{
> + unsigned num, irregular_set_number, irregular_bank_base;
> + const struct gpio_name_num_table *tabp;
> + char this_bank, bank_name, irregular_bank_name;
> + char *endp;
> +
> + /*
> + * The gpio name starts with either 'g' ot 'gp' followed by the bank
> + * name character. Skip one or two characters depending on the prefix.
> + */
> + if (name[1] == 'p')
> + name += 2;
> + else
> + name++;
> + bank_name = *name++;
> + if (!*name)
> + return -1; /* At least one digit is required/expected. */
> +
> + /*
> + * On both exynos5 and exynos5420 architectures there is a bank of
> + * GPIOs which does not fall into the regular address pattern. Those
> + * banks are c4 on Exynos5 and y7 on Exynos5420. The rest of the below
> + * assignments help to handle these irregularities.
> + */

We can't check cpu id for s5pc1xx when exynos is compiled so you
shouldn't check proid in this driver, but you can do this in
arch-XXXX/gpio.h.
So then this is a still s5p common driver.

> + if (proid_is_exynos5420()) {
> + tabp = exynos5420_gpio_table;
> + irregular_bank_name = 'y';
> + irregular_set_number = '7';
> + irregular_bank_base = EXYNOS5420_GPIO_Y70;
> + } else {
> + tabp = exynos5_gpio_table;
> + irregular_bank_name = 'c';
> + irregular_set_number = '4';
> + irregular_bank_base = EXYNOS5_GPIO_C40;
> + }
> +
> + this_bank = tabp->bank;
> + do {
> + if (bank_name == this_bank) {
> + unsigned pin_index; /* pin number within the bank */
> + if ((bank_name == irregular_bank_name) &&
> + (name[0] == irregular_set_number)) {
> + pin_index = name[1] - '0';
> + /* Irregular sets have 8 pins. */
> + if (pin_index >= GPIO_PER_BANK)
> + return -1;
> + num = irregular_bank_base + pin_index;
> + } else {
> + pin_index = simple_strtoul(name, &endp, 8);
> + pin_index -= tabp->bank_offset;
> + /*
> + * Sanity check: bunk 'z' has no set number,
> + * for all other banks there must be exactly
> + * two octal digits, and the resulting number
> + * should not exceed the number of pins in the
> + * bank.
> + */
> + if (((bank_name != 'z') && !name[1]) ||
> + *endp ||
> + (pin_index >= tabp->bank_size))
> + return -1;
> + num = tabp->base + pin_index;
> + }
> + return num;
> + }
> + this_bank = (++tabp)->bank;
> + } while (this_bank);
> +
> + return -1;
> +}
> +
> void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg)
> {
> unsigned int value;
>

You made a lot of good job. Please just make this driver more common,
then I will implement and test this feature for exynos4 and s5pc1xx boards.

Thanks
--
Przemyslaw Marczak
Samsung R&D Institute Poland
Samsung Electronics
p.marczak at samsung.com