forked from hyperion-project/hyperion.ng
-
Notifications
You must be signed in to change notification settings - Fork 0
/
switchPinCtrl.c
177 lines (138 loc) · 5.43 KB
/
switchPinCtrl.c
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
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//
// Simple byte wise SPI driver
// Demo how to set up memmap and access SPI registers.
// Code seems to be working but has not been much tested.
// G.J. van Loo 15-Jan-2012
//
// Access from ARM Running Linux
#define BCM2708_PERI_BASE 0x20000000
#define UART0_BASE (BCM2708_PERI_BASE + 0x201000) /* Uart 0 */
#define UART1_BASE (BCM2708_PERI_BASE + 0x215000) /* Uart 1 */
#define MCORE_BASE (BCM2708_PERI_BASE + 0x0000) /* Fake frame buffer device */
#define GPIO_BASE (BCM2708_PERI_BASE + 0x200000) /* GPIO controller */
#define SPI0_BASE (BCM2708_PERI_BASE + 0x204000) /* SPI0 controller */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <dirent.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#define PAGE_SIZE (4*1024)
#define BLOCK_SIZE (4*1024)
int mem_fd;
char *gpio_mem, *gpio_map;
char *spi0_mem, *spi0_map;
// I/O access
volatile unsigned *gpio;
volatile unsigned *spi0;
// SPI operation
// GPIO setup macros. Always use INP_GPIO(x) before using OUT_GPIO(x) or SET_GPIO_ALT(x,y)
#define INP_GPIO(g) *(gpio+((g)/10)) &= ~(7<<(((g)%10)*3))
#define OUT_GPIO(g) *(gpio+((g)/10)) |= (1<<(((g)%10)*3))
#define SET_GPIO_ALT(g,a) *(gpio+(((g)/10))) |= (((a)<=3?(a)+4:(a)==4?3:2)<<(((g)%10)*3))
//
#define SPI0_CNTLSTAT *(spi0 + 0)
#define SPI0_FIFO *(spi0 + 1)
#define SPI0_CLKSPEED *(spi0 + 2)
// SPI0_CNTLSTAT register bits
#define SPI0_CS_CS2ACTHIGH 0x00800000 // CS2 active high
#define SPI0_CS_CS1ACTHIGH 0x00400000 // CS1 active high
#define SPI0_CS_CS0ACTHIGH 0x00200000 // CS0 active high
#define SPI0_CS_RXFIFOFULL 0x00100000 // Receive FIFO full
#define SPI0_CS_RXFIFO3_4 0x00080000 // Receive FIFO 3/4 full
#define SPI0_CS_TXFIFOSPCE 0x00040000 // Transmit FIFO has space
#define SPI0_CS_RXFIFODATA 0x00020000 // Receive FIFO has data
#define SPI0_CS_DONE 0x00010000 // SPI transfer done. WRT to CLR!
#define SPI0_CS_MOSI_INPUT 0x00001000 // MOSI is input, read from MOSI (BI-dir mode)
#define SPI0_CS_DEASRT_CS 0x00000800 // De-assert CS at end
#define SPI0_CS_RX_IRQ 0x00000400 // Receive irq enable
#define SPI0_CS_DONE_IRQ 0x00000200 // irq when done
#define SPI0_CS_DMA_ENABLE 0x00000100 // Run in DMA mode
#define SPI0_CS_ACTIVATE 0x00000080 // Activate: be high before starting
#define SPI0_CS_CS_POLARIT 0x00000040 // Chip selects active high
#define SPI0_CS_CLRTXFIFO 0x00000020 // Clear TX FIFO (auto clear bit)
#define SPI0_CS_CLRRXFIFO 0x00000010 // Clear RX FIFO (auto clear bit)
#define SPI0_CS_CLRFIFOS 0x00000030 // Clear BOTH FIFOs (auto clear bit)
#define SPI0_CS_CLK_IDLHI 0x00000008 // Clock pin is high when idle
#define SPI0_CS_CLKTRANS 0x00000004 // 0=first clock in middle of data bit
// 1=first clock at begin of data bit
#define SPI0_CS_CHIPSEL0 0x00000000 // Use chip select 0
#define SPI0_CS_CHIPSEL1 0x00000001 // Use chip select 1
#define SPI0_CS_CHIPSEL2 0x00000002 // Use chip select 2
#define SPI0_CS_CHIPSELN 0x00000003 // No chip select (e.g. use GPIO pin)
#define SPI0_CS_CLRALL (SPI0_CS_CLRFIFOS|SPI0_CS_DONE)
#define ISASC(x) ((x)>=0x20 && (x)<=0x7F)
void setup_io();
int main(int argc, char **argv)
{ int g;
setup_io(); // Set up direct access to I/O for GPIO and SPI
// Switch GPIO 7..11 to SPI mode (ALT function 0)
/************************************************************************\
* You are about to change the GPIO settings of your computer. *
* Mess this up and it will stop working! *
* It might be a good idea to 'sync' before running this program *
* so at least you still have your code changes written to the SD-card! *
\************************************************************************/
for (g=7; g<=11; g++)
{
INP_GPIO(g); // clear bits (= input)
SET_GPIO_ALT(g,0); // set function 0
}
return 0;
} // main
//
// Set up a memory regions to access GPIO and SPI0
//
void setup_io()
{
/* open /dev/mem */
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
printf("can't open /dev/mem \n");
exit (-1);
}
/* mmap GPIO */
if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
printf("allocation error \n");
exit (-1);
}
if ((unsigned long)gpio_mem % PAGE_SIZE)
gpio_mem += PAGE_SIZE - ((unsigned long)gpio_mem % PAGE_SIZE);
gpio_map = (unsigned char *)mmap(
(caddr_t)gpio_mem,
BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
GPIO_BASE
);
if ((long)gpio_map < 0) {
printf("mmap error %ld\n", (long)gpio_map);
exit (-1);
}
gpio = (volatile unsigned *)gpio_map;
/* mmap SPI0 */
if ((spi0_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) {
printf("allocation error \n");
exit (-1);
}
if ((unsigned long)spi0_mem % PAGE_SIZE)
spi0_mem += PAGE_SIZE - ((unsigned long)spi0_mem % PAGE_SIZE);
spi0_map = (unsigned char *)mmap(
(caddr_t)spi0_mem,
BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
SPI0_BASE
);
printf("SPI mapped from 0x%d to 0x%p\n",SPI0_BASE,spi0_map);
if ((long)spi0_map < 0) {
printf("mmap error %ld\n", (long)spi0_map);
exit (-1);
}
spi0 = (volatile unsigned *)spi0_map;
} // setup_io