ref: b5e47e6202d51fb29cdc2b4f7838346d7eb46a2d
dir: /sys/src/9/bcm/gpio.c/
/*
* Raspberry Pi GPIO support
*/
#include "u.h"
#include "../port/lib.h"
#include "../port/error.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#define GPIOREGS (VIRTIO+0x200000)
/* GPIO regs */
enum {
Fsel0 = 0x00>>2,
FuncMask= 0x7,
Set0 = 0x1c>>2,
Clr0 = 0x28>>2,
Lev0 = 0x34>>2,
Evds0 = 0x40>>2,
Redge0 = 0x4C>>2,
Fedge0 = 0x58>>2,
Hpin0 = 0x64>>2,
Lpin0 = 0x70>>2,
ARedge0 = 0x7C>>2,
AFedge0 = 0x88>>2,
PUD = 0x94>>2,
Off = 0x0,
Pulldown= 0x1,
Pullup = 0x2,
PudMask = 0x3,
PUDclk0 = 0x98>>2,
PUDclk1 = 0x9c>>2,
/* BCM2711 only */
PUPPDN0 = 0xe4>>2,
PUPPDN1 = 0xe8>>2,
PUPPDN2 = 0xec>>2,
PUPPDN3 = 0xf0>>2,
};
static u32int *regs = (u32int*)GPIOREGS;
void
gpiosel(uint pin, int func)
{
int shift = (pin % 10) * 3;
u32int *reg = ®s[Fsel0 + pin/10];
func &= FuncMask;
*reg = (*reg & ~(FuncMask<<shift)) | (func<<shift);
}
void
gpiopull(uint pin, int func)
{
u32int *reg;
func &= PudMask;
if(regs[PUPPDN3] == 0x6770696f){
/* BCM2835, BCM2836, BCM2837 */
u32int mask = 1 << (pin % 32);
reg = ®s[PUDclk0 + pin/32];
regs[PUD] = func;
microdelay(1);
*reg = mask;
microdelay(1);
*reg = 0;
} else {
/* BCM2711 */
int shift = 2*(pin % 16);
static u32int map[PudMask+1] = {0x00,0x02,0x01};
reg = ®s[PUPPDN0 + pin/16];
*reg = (*reg & ~(3<<shift)) | (map[func] << shift);
}
}
void
gpiopulloff(uint pin)
{
gpiopull(pin, Off);
}
void
gpiopullup(uint pin)
{
gpiopull(pin, Pullup);
}
void
gpiopulldown(uint pin)
{
gpiopull(pin, Pulldown);
}
void
gpioout(uint pin, int set)
{
regs[(set? Set0: Clr0) + pin/32] = 1 << (pin % 32);
}
int
gpioin(uint pin)
{
return (regs[Lev0 + pin/32] & (1 << (pin % 32))) != 0;
}
void
gpioselevent(uint pin, int falling, int enable)
{
u32int *reg = ®s[(falling? Fedge0: Redge0) + pin/32];
*reg = (*reg & ~(1<<pin)) | ((enable != 0)<<pin);
}
int
gpiogetevent(uint pin)
{
u32int *reg, val;
reg = ®s[Evds0 + pin/32];
val = *reg & (1 << (pin % 32));
*reg |= val;
return val != 0;
}
void
gpiomeminit(void)
{
Physseg seg;
memset(&seg, 0, sizeof seg);
seg.attr = SG_PHYSICAL | SG_DEVICE | SG_NOEXEC;
seg.name = "gpio";
seg.pa = (GPIOREGS - soc.virtio) + soc.physio;
seg.size = BY2PG;
addphysseg(&seg);
}