Skip to content
This repository has been archived by the owner on Aug 27, 2022. It is now read-only.

Commit

Permalink
MIPS: RB532: Provide functions for gpio configuration
Browse files Browse the repository at this point in the history
As gpiolib doesn't support pin multiplexing, it provides no way to
access the GPIOFUNC register. Also there is no support for setting
interrupt status and level. These functions provide access to them and
are needed by the CompactFlash driver.

Signed-off-by: Phil Sutter <n0-1@freewrt.org>
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
  • Loading branch information
Phil Sutter authored and ralfbaechle committed Nov 20, 2008
1 parent f43909d commit 2e37395
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 120 deletions.
2 changes: 2 additions & 0 deletions arch/mips/include/asm/mach-rc32434/gpio.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,5 +84,7 @@ extern void set_434_reg(unsigned reg_offs, unsigned bit, unsigned len, unsigned
extern unsigned get_434_reg(unsigned reg_offs);
extern void set_latch_u5(unsigned char or_mask, unsigned char nand_mask);
extern unsigned char get_latch_u5(void);
extern void rb532_gpio_set_ilevel(int bit, unsigned gpio);
extern void rb532_gpio_set_istat(int bit, unsigned gpio);

#endif /* _RC32434_GPIO_H_ */
193 changes: 73 additions & 120 deletions arch/mips/rb532/gpio.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@
struct rb532_gpio_chip {
struct gpio_chip chip;
void __iomem *regbase;
void (*set_int_level)(struct gpio_chip *chip, unsigned offset, int value);
int (*get_int_level)(struct gpio_chip *chip, unsigned offset);
void (*set_int_status)(struct gpio_chip *chip, unsigned offset, int value);
int (*get_int_status)(struct gpio_chip *chip, unsigned offset);
};

struct mpmc_device dev3;
Expand Down Expand Up @@ -111,15 +107,47 @@ unsigned char get_latch_u5(void)
}
EXPORT_SYMBOL(get_latch_u5);

/* rb532_set_bit - sanely set a bit
*
* bitval: new value for the bit
* offset: bit index in the 4 byte address range
* ioaddr: 4 byte aligned address being altered
*/
static inline void rb532_set_bit(unsigned bitval,
unsigned offset, void __iomem *ioaddr)
{
unsigned long flags;
u32 val;

bitval = !!bitval; /* map parameter to {0,1} */

local_irq_save(flags);

val = readl(ioaddr);
val &= ~( ~bitval << offset ); /* unset bit if bitval == 0 */
val |= ( bitval << offset ); /* set bit if bitval == 1 */
writel(val, ioaddr);

local_irq_restore(flags);
}

/* rb532_get_bit - read a bit
*
* returns the boolean state of the bit, which may be > 1
*/
static inline int rb532_get_bit(unsigned offset, void __iomem *ioaddr)
{
return (readl(ioaddr) & (1 << offset));
}

/*
* Return GPIO level */
static int rb532_gpio_get(struct gpio_chip *chip, unsigned offset)
{
u32 mask = 1 << offset;
struct rb532_gpio_chip *gpch;

gpch = container_of(chip, struct rb532_gpio_chip, chip);
return readl(gpch->regbase + GPIOD) & mask;
return rb532_get_bit(offset, gpch->regbase + GPIOD);
}

/*
Expand All @@ -128,45 +156,25 @@ static int rb532_gpio_get(struct gpio_chip *chip, unsigned offset)
static void rb532_gpio_set(struct gpio_chip *chip,
unsigned offset, int value)
{
unsigned long flags;
u32 mask = 1 << offset;
u32 tmp;
struct rb532_gpio_chip *gpch;
void __iomem *gpvr;

gpch = container_of(chip, struct rb532_gpio_chip, chip);
gpvr = gpch->regbase + GPIOD;

local_irq_save(flags);
tmp = readl(gpvr);
if (value)
tmp |= mask;
else
tmp &= ~mask;
writel(tmp, gpvr);
local_irq_restore(flags);
rb532_set_bit(value, offset, gpch->regbase + GPIOD);
}

/*
* Set GPIO direction to input
*/
static int rb532_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
{
unsigned long flags;
u32 mask = 1 << offset;
u32 value;
struct rb532_gpio_chip *gpch;
void __iomem *gpdr;

gpch = container_of(chip, struct rb532_gpio_chip, chip);
gpdr = gpch->regbase + GPIOCFG;

local_irq_save(flags);
value = readl(gpdr);
value &= ~mask;
writel(value, gpdr);
local_irq_restore(flags);
if (rb532_get_bit(offset, gpch->regbase + GPIOFUNC))
return 1; /* alternate function, GPIOCFG is ignored */

rb532_set_bit(0, offset, gpch->regbase + GPIOCFG);
return 0;
}

Expand All @@ -176,117 +184,60 @@ static int rb532_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
static int rb532_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
unsigned long flags;
u32 mask = 1 << offset;
u32 tmp;
struct rb532_gpio_chip *gpch;
void __iomem *gpdr;

gpch = container_of(chip, struct rb532_gpio_chip, chip);
writel(mask, gpch->regbase + GPIOD);
gpdr = gpch->regbase + GPIOCFG;

local_irq_save(flags);
tmp = readl(gpdr);
tmp |= mask;
writel(tmp, gpdr);
local_irq_restore(flags);
if (rb532_get_bit(offset, gpch->regbase + GPIOFUNC))
return 1; /* alternate function, GPIOCFG is ignored */

/* set the initial output value */
rb532_set_bit(value, offset, gpch->regbase + GPIOD);

rb532_set_bit(1, offset, gpch->regbase + GPIOCFG);
return 0;
}

/*
* Set the GPIO interrupt level
*/
static void rb532_gpio_set_int_level(struct gpio_chip *chip,
unsigned offset, int value)
{
unsigned long flags;
u32 mask = 1 << offset;
u32 tmp;
struct rb532_gpio_chip *gpch;
void __iomem *gpil;

gpch = container_of(chip, struct rb532_gpio_chip, chip);
gpil = gpch->regbase + GPIOILEVEL;

local_irq_save(flags);
tmp = readl(gpil);
if (value)
tmp |= mask;
else
tmp &= ~mask;
writel(tmp, gpil);
local_irq_restore(flags);
}
static struct rb532_gpio_chip rb532_gpio_chip[] = {
[0] = {
.chip = {
.label = "gpio0",
.direction_input = rb532_gpio_direction_input,
.direction_output = rb532_gpio_direction_output,
.get = rb532_gpio_get,
.set = rb532_gpio_set,
.base = 0,
.ngpio = 32,
},
},
};

/*
* Get the GPIO interrupt level
* Set GPIO interrupt level
*/
static int rb532_gpio_get_int_level(struct gpio_chip *chip, unsigned offset)
void rb532_gpio_set_ilevel(int bit, unsigned gpio)
{
u32 mask = 1 << offset;
struct rb532_gpio_chip *gpch;

gpch = container_of(chip, struct rb532_gpio_chip, chip);
return readl(gpch->regbase + GPIOILEVEL) & mask;
rb532_set_bit(bit, gpio, rb532_gpio_chip->regbase + GPIOILEVEL);
}
EXPORT_SYMBOL(rb532_gpio_set_ilevel);

/*
* Set the GPIO interrupt status
* Set GPIO interrupt status
*/
static void rb532_gpio_set_int_status(struct gpio_chip *chip,
unsigned offset, int value)
void rb532_gpio_set_istat(int bit, unsigned gpio)
{
unsigned long flags;
u32 mask = 1 << offset;
u32 tmp;
struct rb532_gpio_chip *gpch;
void __iomem *gpis;

gpch = container_of(chip, struct rb532_gpio_chip, chip);
gpis = gpch->regbase + GPIOISTAT;

local_irq_save(flags);
tmp = readl(gpis);
if (value)
tmp |= mask;
else
tmp &= ~mask;
writel(tmp, gpis);
local_irq_restore(flags);
rb532_set_bit(bit, gpio, rb532_gpio_chip->regbase + GPIOISTAT);
}
EXPORT_SYMBOL(rb532_gpio_set_istat);

/*
* Get the GPIO interrupt status
* Configure GPIO alternate function
*/
static int rb532_gpio_get_int_status(struct gpio_chip *chip, unsigned offset)
static void rb532_gpio_set_func(int bit, unsigned gpio)
{
u32 mask = 1 << offset;
struct rb532_gpio_chip *gpch;

gpch = container_of(chip, struct rb532_gpio_chip, chip);
return readl(gpch->regbase + GPIOISTAT) & mask;
rb532_set_bit(bit, gpio, rb532_gpio_chip->regbase + GPIOFUNC);
}

static struct rb532_gpio_chip rb532_gpio_chip[] = {
[0] = {
.chip = {
.label = "gpio0",
.direction_input = rb532_gpio_direction_input,
.direction_output = rb532_gpio_direction_output,
.get = rb532_gpio_get,
.set = rb532_gpio_set,
.base = 0,
.ngpio = 32,
},
.get_int_level = rb532_gpio_get_int_level,
.set_int_level = rb532_gpio_set_int_level,
.get_int_status = rb532_gpio_get_int_status,
.set_int_status = rb532_gpio_set_int_status,
},
};

int __init rb532_gpio_init(void)
{
struct resource *r;
Expand All @@ -310,9 +261,11 @@ int __init rb532_gpio_init(void)
return -ENXIO;
}

/* Set the interrupt status and level for the CF pin */
rb532_gpio_set_int_level(&rb532_gpio_chip->chip, CF_GPIO_NUM, 1);
rb532_gpio_set_int_status(&rb532_gpio_chip->chip, CF_GPIO_NUM, 0);
/* configure CF_GPIO_NUM as CFRDY IRQ source */
rb532_gpio_set_func(0, CF_GPIO_NUM);
rb532_gpio_direction_input(&rb532_gpio_chip->chip, CF_GPIO_NUM);
rb532_gpio_set_ilevel(1, CF_GPIO_NUM);
rb532_gpio_set_istat(0, CF_GPIO_NUM);

return 0;
}
Expand Down

0 comments on commit 2e37395

Please sign in to comment.