mirror of
https://github.com/Fishwaldo/u-boot.git
synced 2025-03-21 14:41:31 +00:00
gpio: s3c: Fix the GPIO driver
The GPIO driver didn't correctly compute the bank offset from the GPIO number and caused random writes into the GPIO block address space. Fix the driver so it actually does the writes correctly. While at it, make use of the clrsetbits_le32() mechanisms. Signed-off-by: Marek Vasut <marex@denx.de> Cc: Kyungmin Park <kyungmin.park@samsung.com> Cc: Lukasz Majewski <l.majewski@samsung.com> Cc: Minkyu Kang <mk7.kang@samsung.com> Cc: Vladimir Zapolskiy <vz@mleia.com> Signed-off-by: Minkyu Kang <mk7.kang@samsung.com>
This commit is contained in:
parent
7b0c0f69a4
commit
13cfd101dd
1 changed files with 41 additions and 32 deletions
|
@ -8,53 +8,50 @@
|
||||||
#include <asm/arch/s3c2440.h>
|
#include <asm/arch/s3c2440.h>
|
||||||
#include <asm/gpio.h>
|
#include <asm/gpio.h>
|
||||||
#include <asm/io.h>
|
#include <asm/io.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#define GPIO_INPUT 0x0
|
#define GPIO_INPUT 0x0
|
||||||
#define GPIO_OUTPUT 0x1
|
#define GPIO_OUTPUT 0x1
|
||||||
|
|
||||||
/* 0x4 means that we want DAT and not CON register */
|
#define S3C_GPIO_CON 0x0
|
||||||
#define GPIO_PORT(x) ((((x) >> 5) & 0x3) + 0x4)
|
#define S3C_GPIO_DAT 0x4
|
||||||
#define GPIO_BIT(x) ((x) & 0x3f)
|
|
||||||
|
|
||||||
/*
|
static uint32_t s3c_gpio_get_bank_addr(unsigned gpio)
|
||||||
* It's how we calculate the full port address
|
{
|
||||||
* We have to get the number of the port + 1 (Port A is at 0x56000001 ...)
|
/* There is up to 16 pins per bank, one bank is 0x10 big. */
|
||||||
* We move it at the second digit, and finally we add 0x4 because we want
|
uint32_t addr = gpio & ~0xf;
|
||||||
* to modify GPIO DAT and not CON
|
|
||||||
*/
|
if (addr >= 0x80 && addr != 0xd0) { /* Wrong GPIO bank. */
|
||||||
#define GPIO_FULLPORT(x) (S3C24X0_GPIO_BASE | ((GPIO_PORT(gpio) + 1) << 1))
|
printf("Invalid GPIO bank (bank %02x)\n", addr);
|
||||||
|
return 0xffffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
return addr | S3C24X0_GPIO_BASE;
|
||||||
|
}
|
||||||
|
|
||||||
int gpio_set_value(unsigned gpio, int value)
|
int gpio_set_value(unsigned gpio, int value)
|
||||||
{
|
{
|
||||||
unsigned l = readl(GPIO_FULLPORT(gpio));
|
uint32_t addr = s3c_gpio_get_bank_addr(gpio);
|
||||||
unsigned bit;
|
|
||||||
unsigned port = GPIO_FULLPORT(gpio);
|
|
||||||
|
|
||||||
/*
|
if (addr == 0xffffffff)
|
||||||
* All GPIO Port have a configuration on
|
return -EINVAL;
|
||||||
* 2 bits excepted the first GPIO (A) which
|
|
||||||
* have only 1 bit of configuration.
|
|
||||||
*/
|
|
||||||
if (!GPIO_PORT(gpio))
|
|
||||||
bit = (0x1 << GPIO_BIT(gpio));
|
|
||||||
else
|
|
||||||
bit = (0x3 << GPIO_BIT(gpio));
|
|
||||||
|
|
||||||
if (value)
|
if (value)
|
||||||
l |= bit;
|
setbits_le32(addr | S3C_GPIO_DAT, 1 << (gpio & 0xf));
|
||||||
else
|
else
|
||||||
l &= ~bit;
|
clrbits_le32(addr | S3C_GPIO_DAT, 1 << (gpio & 0xf));
|
||||||
|
|
||||||
return writel(l, port);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpio_get_value(unsigned gpio)
|
int gpio_get_value(unsigned gpio)
|
||||||
{
|
{
|
||||||
unsigned l = readl(GPIO_FULLPORT(gpio));
|
uint32_t addr = s3c_gpio_get_bank_addr(gpio);
|
||||||
|
|
||||||
if (GPIO_PORT(gpio) == 0) /* PORT A */
|
if (addr == 0xffffffff)
|
||||||
return (l >> GPIO_BIT(gpio)) & 0x1;
|
return -EINVAL;
|
||||||
return (l >> GPIO_BIT(gpio)) & 0x3;
|
|
||||||
|
return !!(readl(addr | S3C_GPIO_DAT) & (1 << (gpio & 0xf)));
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpio_request(unsigned gpio, const char *label)
|
int gpio_request(unsigned gpio, const char *label)
|
||||||
|
@ -67,13 +64,25 @@ int gpio_free(unsigned gpio)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int s3c_gpio_direction(unsigned gpio, uint8_t dir)
|
||||||
|
{
|
||||||
|
uint32_t addr = s3c_gpio_get_bank_addr(gpio);
|
||||||
|
const uint32_t mask = 0x3 << ((gpio & 0xf) << 1);
|
||||||
|
const uint32_t dirm = dir << ((gpio & 0xf) << 1);
|
||||||
|
|
||||||
|
if (addr == 0xffffffff)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
clrsetbits_le32(addr | S3C_GPIO_CON, mask, dirm);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int gpio_direction_input(unsigned gpio)
|
int gpio_direction_input(unsigned gpio)
|
||||||
{
|
{
|
||||||
return writel(GPIO_INPUT << GPIO_BIT(gpio), GPIO_FULLPORT(gpio));
|
return s3c_gpio_direction(gpio, GPIO_INPUT);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gpio_direction_output(unsigned gpio, int value)
|
int gpio_direction_output(unsigned gpio, int value)
|
||||||
{
|
{
|
||||||
writel(GPIO_OUTPUT << GPIO_BIT(gpio), GPIO_FULLPORT(gpio));
|
return s3c_gpio_direction(gpio, GPIO_OUTPUT);
|
||||||
return gpio_set_value(gpio, value);
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue