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

Przemyslaw Marczak p.marczak at samsung.com
Mon Apr 14 17:19:13 CEST 2014


Hi,

On 04/12/2014 11:43 AM, Akshay Saraswat wrote:
> From: Rajeshwari Shinde <rajeshwari.s at 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 at samsung.com>
> Signed-off-by: Akshay Saraswat <akshay.s at 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


More information about the U-Boot mailing list