1/*
2 * Copyright 2011-2012 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		Alexander von Gluck, kallisti5@unixzen.com
7 *		Gordon Henderson, gordon@drogon.net
8 */
9
10
11#include "gpio.h"
12
13
14//  Define the shift up for the 3 bits per pin in each GPFSEL port
15static uint8_t
16kGPIOToShift[] =
17{
18	0, 3, 6, 9, 12, 15, 18, 21, 24, 27,
19	0, 3, 6, 9, 12, 15, 18, 21, 24, 27,
20	0, 3, 6, 9, 12, 15, 18, 21, 24, 27,
21	0, 3, 6, 9, 12, 15, 18, 21, 24, 27,
22	0, 3, 6, 9, 12, 15, 18, 21, 24, 27,
23};
24
25
26//  Map a BCM_GPIO pin to it's control port. (GPFSEL 0-5)
27static uint8_t
28kGPIOToGPFSEL[] =
29{
30	0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
31	1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
32	2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
33	3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
34	4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
35	5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
36};
37
38
39// (Word) offset to the GPIO Set registers for each GPIO pin
40static uint8_t
41kGPIOToGPSET[] =
42{
43	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
44	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
45	8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
46	8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
47};
48
49// (Word) offset to the GPIO Clear registers for each GPIO pin
50static uint8_t
51kGPIOToGPCLR[] =
52{
53	10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
54	10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
55	11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
56	11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
57};
58
59
60/*!
61 * At GPIO (base) (pin) state set (value)
62 */
63void
64gpio_write(addr_t base, int pin, bool value)
65{
66	volatile addr_t *gpio = (addr_t*)base;
67
68	if (value == 1)
69		*(gpio + kGPIOToGPSET[pin]) = 1 << pin;
70	else
71		*(gpio + kGPIOToGPCLR[pin]) = 1 << pin;
72}
73
74
75/*!
76 * At GPIO (base) (pin) set mode (mode)
77 */
78void
79gpio_mode(addr_t base, int pin, int mode)
80{
81	int sel = kGPIOToGPFSEL[pin];
82	int shift = kGPIOToShift[pin];
83
84	volatile addr_t *gpio = (addr_t*)base + sel;
85
86	if (mode == GPIO_IN)
87		*gpio = (*gpio & ~(7 << shift));
88	else if (mode == GPIO_OUT)
89		*gpio = (*gpio & ~(7 << shift)) | (1 << shift);
90	else
91		*gpio = (*gpio & ~(7 << shift)) | (mode << shift);
92}
93
94
95void
96gpio_init()
97{
98	// ** Take control of ok led, and general use pins
99	int pin = 0;
100	for (pin = 16; pin <= 25; pin++)
101		gpio_mode(GPIO_BASE, pin, GPIO_OUT);
102}
103