|
| 1 | +/* |
| 2 | +Copyright (c) 2012-2015 Ben Croston |
| 3 | +
|
| 4 | +Permission is hereby granted, free of charge, to any person obtaining a copy of |
| 5 | +this software and associated documentation files (the "Software"), to deal in |
| 6 | +the Software without restriction, including without limitation the rights to |
| 7 | +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies |
| 8 | +of the Software, and to permit persons to whom the Software is furnished to do |
| 9 | +so, subject to the following conditions: |
| 10 | +
|
| 11 | +The above copyright notice and this permission notice shall be included in all |
| 12 | +copies or substantial portions of the Software. |
| 13 | +
|
| 14 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| 15 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| 16 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| 17 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| 18 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 19 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
| 20 | +SOFTWARE. |
| 21 | +*/ |
| 22 | + |
| 23 | +#include <stdint.h> |
| 24 | +#include <stdlib.h> |
| 25 | +#include <stdio.h> |
| 26 | +#include <fcntl.h> |
| 27 | +#include <sys/mman.h> |
| 28 | +#include "c_gpio.h" |
| 29 | + |
| 30 | +static volatile uint32_t *gpio_map; |
| 31 | + |
| 32 | +uint32_t readl(uint32_t addr) |
| 33 | +{ |
| 34 | + uint32_t val = 0; |
| 35 | + uint32_t mmap_base = (addr & ~MAP_MASK); |
| 36 | + uint32_t mmap_seek = ((addr - mmap_base) >> 2); |
| 37 | + val = *(gpio_map + mmap_seek); |
| 38 | + if(OPiGPIODebug) |
| 39 | + printf("mmap_base = 0x%x\t mmap_seek = 0x%x\t gpio_map = 0x%x\t total = 0x%x\n",mmap_base,mmap_seek,gpio_map,(gpio_map + mmap_seek)); |
| 40 | + |
| 41 | + return val; |
| 42 | +} |
| 43 | + |
| 44 | +void writel(uint32_t val, uint32_t addr) |
| 45 | +{ |
| 46 | + uint32_t mmap_base = (addr & ~MAP_MASK); |
| 47 | + uint32_t mmap_seek = ((addr - mmap_base) >> 2); |
| 48 | + *(gpio_map + mmap_seek) = val; |
| 49 | +} |
| 50 | + |
| 51 | +int setup(void) |
| 52 | +{ |
| 53 | + int mem_fd; |
| 54 | + uint8_t *gpio_mem; |
| 55 | + |
| 56 | + if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) |
| 57 | + { |
| 58 | + return SETUP_DEVMEM_FAIL; |
| 59 | + } |
| 60 | + |
| 61 | + if ((gpio_mem = malloc(BLOCK_SIZE + (PAGE_SIZE-1))) == NULL) |
| 62 | + return SETUP_MALLOC_FAIL; |
| 63 | + |
| 64 | + if ((uint32_t)gpio_mem % PAGE_SIZE) |
| 65 | + gpio_mem += PAGE_SIZE - ((uint32_t)gpio_mem % PAGE_SIZE); |
| 66 | + |
| 67 | + gpio_map = (uint32_t *)mmap( (caddr_t)gpio_mem, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, mem_fd, GPIO_BASE_OPI); |
| 68 | + |
| 69 | + if(OPiGPIODebug) |
| 70 | + printf("gpio_mem = 0x%x\t gpio_map = 0x%x\n",gpio_mem,gpio_map); |
| 71 | + |
| 72 | + if ((uint32_t)gpio_map < 0) |
| 73 | + return SETUP_MMAP_FAIL; |
| 74 | + |
| 75 | + return SETUP_OK; |
| 76 | +} |
| 77 | + |
| 78 | +int gpio_function(int gpio) |
| 79 | +{ |
| 80 | + uint32_t regval = 0; |
| 81 | + int bank = gpio >> 5; |
| 82 | + int index = gpio - (bank << 5); |
| 83 | + int offset = ((index - ((index >> 3) << 3)) << 2); |
| 84 | + uint32_t phyaddr = SUNXI_GPIO_BASE + (bank * 36) + ((index >> 3) << 2); |
| 85 | + |
| 86 | + regval = readl(phyaddr); |
| 87 | + if (OPiGPIODebug) |
| 88 | + printf("read reg val: 0x%x offset:%d\n",regval,offset); |
| 89 | + |
| 90 | + regval >>= offset; |
| 91 | + regval &= 7; |
| 92 | + if (OPiGPIODebug) |
| 93 | + printf("read reg val: 0x%x\n",regval); |
| 94 | + |
| 95 | + return regval; // 1=input, 0=output, 4=alt0 |
| 96 | +} |
| 97 | + |
| 98 | +void set_pullupdn(int gpio, int pud)//void sunxi_pullUpDnControl (int pin, int pud) |
| 99 | +{ |
| 100 | + uint32_t regval = 0; |
| 101 | + int bank = gpio >> 5; |
| 102 | + int index = gpio - (bank << 5); |
| 103 | + int sub = index >> 4; |
| 104 | + int sub_index = index - 16*sub; |
| 105 | + uint32_t phyaddr = SUNXI_GPIO_BASE + (bank * 36) + 0x1C + 4*sub; // +0x1c -> pullUpDn reg |
| 106 | + |
| 107 | + if (OPiGPIODebug) |
| 108 | + printf("func:%s pin:%d,bank:%d index:%d sub:%d phyaddr:0x%x\n",__func__, gpio,bank,index,sub,phyaddr); |
| 109 | + |
| 110 | + regval = readl(phyaddr); |
| 111 | + if (OPiGPIODebug) |
| 112 | + printf("pullUpDn reg:0x%x, pud:0x%x sub_index:%d\n", regval, pud, sub_index); |
| 113 | + regval &= ~(3 << (sub_index << 1)); |
| 114 | + regval |= (pud << (sub_index << 1)); |
| 115 | + if (OPiGPIODebug) |
| 116 | + printf("pullUpDn val ready to set:0x%x\n", regval); |
| 117 | + writel(regval, phyaddr); |
| 118 | + regval = readl(phyaddr); |
| 119 | + if (OPiGPIODebug) |
| 120 | + printf("pullUpDn reg after set:0x%x addr:0x%x\n", regval, phyaddr); |
| 121 | +} |
| 122 | + |
| 123 | +void setup_gpio(int gpio, int direction, int pud)//void sunxi_set_gpio_mode(int pin,int mode) |
| 124 | +{ |
| 125 | + uint32_t regval = 0; |
| 126 | + int bank = gpio >> 5; |
| 127 | + int index = gpio - (bank << 5); |
| 128 | + int offset = ((index - ((index >> 3) << 3)) << 2); |
| 129 | + uint32_t phyaddr = SUNXI_GPIO_BASE + (bank * 36) + ((index >> 3) << 2); |
| 130 | + if (OPiGPIODebug) |
| 131 | + printf("func:%s pin:%d, direction:%d bank:%d index:%d phyaddr:0x%x\n",__func__, gpio , direction,bank,index,phyaddr); |
| 132 | + |
| 133 | + regval = readl(phyaddr); |
| 134 | + if (OPiGPIODebug) |
| 135 | + printf("read reg val: 0x%x offset:%d\n",regval,offset); |
| 136 | + |
| 137 | + set_pullupdn(gpio, pud); |
| 138 | + |
| 139 | + if(INPUT == direction) |
| 140 | + { |
| 141 | + regval &= ~(7 << offset); |
| 142 | + writel(regval, phyaddr); |
| 143 | + regval = readl(phyaddr); |
| 144 | + if (OPiGPIODebug) |
| 145 | + printf("Input mode set over reg val: 0x%x\n",regval); |
| 146 | + } |
| 147 | + else if(OUTPUT == direction) |
| 148 | + { |
| 149 | + regval &= ~(7 << offset); |
| 150 | + regval |= (1 << offset); |
| 151 | + if (OPiGPIODebug) |
| 152 | + printf("Out mode ready set val: 0x%x\n",regval); |
| 153 | + writel(regval, phyaddr); |
| 154 | + regval = readl(phyaddr); |
| 155 | + if (OPiGPIODebug) |
| 156 | + printf("Out mode set over reg val: 0x%x\n",regval); |
| 157 | + } |
| 158 | + else |
| 159 | + { |
| 160 | + printf("line:%dpin number error\n",__LINE__); |
| 161 | + } |
| 162 | +} |
| 163 | + |
| 164 | +void output_gpio(int gpio, int value) //void sunxi_digitalWrite(int pin, int value) |
| 165 | +{ |
| 166 | + uint32_t regval = 0; |
| 167 | + int bank = gpio >> 5; |
| 168 | + int index = gpio - (bank << 5); |
| 169 | + uint32_t phyaddr = SUNXI_GPIO_BASE + (bank * 36) + 0x10; // +0x10 -> data reg |
| 170 | + if (OPiGPIODebug) |
| 171 | + printf("func:%s pin:%d, value:%d bank:%d index:%d phyaddr:0x%x\n",__func__, gpio , value,bank,index,phyaddr); |
| 172 | + |
| 173 | + regval = readl(phyaddr); |
| 174 | + if (OPiGPIODebug) |
| 175 | + printf("before write reg val: 0x%x,index:%d\n",regval,index); |
| 176 | + if(0 == value) |
| 177 | + { |
| 178 | + regval &= ~(1 << index); |
| 179 | + writel(regval, phyaddr); |
| 180 | + regval = readl(phyaddr); |
| 181 | + if (OPiGPIODebug) |
| 182 | + printf("LOW val set over reg val: 0x%x\n",regval); |
| 183 | + } |
| 184 | + else |
| 185 | + { |
| 186 | + regval |= (1 << index); |
| 187 | + writel(regval, phyaddr); |
| 188 | + regval = readl(phyaddr); |
| 189 | + if (OPiGPIODebug) |
| 190 | + printf("HIGH val set over reg val: 0x%x\n",regval); |
| 191 | + } |
| 192 | +} |
| 193 | + |
| 194 | +int input_gpio(int gpio)//int sunxi_digitalRead(int pin) |
| 195 | +{ |
| 196 | + uint32_t regval = 0; |
| 197 | + int bank = gpio >> 5; |
| 198 | + int index = gpio - (bank << 5); |
| 199 | + uint32_t phyaddr = SUNXI_GPIO_BASE + (bank * 36) + 0x10; // +0x10 -> data reg |
| 200 | + if (OPiGPIODebug) |
| 201 | + printf("func:%s pin:%d,bank:%d index:%d phyaddr:0x%x\n",__func__, gpio,bank,index,phyaddr); |
| 202 | + |
| 203 | + regval = readl(phyaddr); |
| 204 | + regval = regval >> index; |
| 205 | + regval &= 1; |
| 206 | + if (OPiGPIODebug) |
| 207 | + printf("***** read reg val: 0x%x,bank:%d,index:%d,line:%d\n",regval,bank,index,__LINE__); |
| 208 | + |
| 209 | + return regval; |
| 210 | +} |
| 211 | + |
| 212 | +void clear_event_detect(int gpio) |
| 213 | +{ |
| 214 | + return; |
| 215 | +} |
| 216 | + |
| 217 | +int eventdetected(int gpio) |
| 218 | +{ |
| 219 | + return 0; |
| 220 | +} |
| 221 | + |
| 222 | +void set_rising_event(int gpio, int enable) |
| 223 | +{ |
| 224 | + return; |
| 225 | +} |
| 226 | + |
| 227 | +void set_falling_event(int gpio, int enable) |
| 228 | +{ |
| 229 | + return; |
| 230 | +} |
| 231 | + |
| 232 | +void set_high_event(int gpio, int enable) |
| 233 | +{ |
| 234 | + return; |
| 235 | +} |
| 236 | + |
| 237 | +void set_low_event(int gpio, int enable) |
| 238 | +{ |
| 239 | + return; |
| 240 | +} |
| 241 | + |
| 242 | +void cleanup(void) |
| 243 | +{ |
| 244 | + munmap((caddr_t)gpio_map, BLOCK_SIZE); |
| 245 | +} |
0 commit comments