summaryrefslogtreecommitdiff
path: root/sys/src/9/imx8/gpio.c
blob: 0fdb3aefd87bf99a057551d9c697821145079a34 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
#include "u.h"
#include "../port/lib.h"
#include "../port/error.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"

/* gpio registers */
enum {
	GPIO_DR = 0x00/4,
	GPIO_GDIR = 0x04/4,
	GPIO_PSR = 0x08/4,
	GPIO_ICR1 = 0x0C/4,
	GPIO_ICR2 = 0x10/4,
	GPIO_IMR = 0x14/4,
	GPIO_ISR = 0x18/4,
	GPIO_EDGE_SEL = 0x1C/4,
};

typedef struct Ctlr Ctlr;
struct Ctlr
{
	u32int	*reg;
	char	*clk;
	u32int	dir;
	int	enabled;
};

static Ctlr ctlrs[5] = {
	{(u32int*)(VIRTIO + 0x200000),	"gpio1.ipg_clk_s" },
	{(u32int*)(VIRTIO + 0x210000),	"gpio2.ipg_clk_s" },
	{(u32int*)(VIRTIO + 0x220000),	"gpio3.ipg_clk_s" },
	{(u32int*)(VIRTIO + 0x230000),	"gpio4.ipg_clk_s" },
	{(u32int*)(VIRTIO + 0x240000),	"gpio5.ipg_clk_s" },
};

static Ctlr*
enable(uint pin)
{
	Ctlr *ctlr;

	pin /= 32;
	if(pin < 1 || pin > nelem(ctlrs))
		return nil;

	ctlr = &ctlrs[pin-1];
	if(!ctlr->enabled){
		setclkgate(ctlr->clk, 1);
		ctlr->reg[GPIO_IMR] = 0;
		ctlr->dir = ctlr->reg[GPIO_GDIR];
		ctlr->enabled = 1;
	}
	return ctlr;
}

void
gpioout(uint pin, int set)
{
	u32int bit = 1 << (pin % 32);
	Ctlr *ctlr = enable(pin);
	if(ctlr == nil)
		return;
	if((ctlr->dir & bit) == 0)
		ctlr->reg[GPIO_GDIR] = ctlr->dir |= bit;
	if(set)
		ctlr->reg[GPIO_DR] |= bit;
	else
		ctlr->reg[GPIO_DR] &= ~bit;
}

int
gpioin(uint pin)
{
	u32int bit = 1 << (pin % 32);
	Ctlr *ctlr = enable(pin);
	if(ctlr == nil)
		return -1;
	if(ctlr->dir & bit)
		ctlr->reg[GPIO_GDIR] = ctlr->dir &= ~bit;
	return (ctlr->reg[GPIO_DR] & bit) != 0;
}