1 /* 2 * Driver for Altera's PIO ip core 3 * 4 * Copyright (C) 2011 Missing Link Electronics 5 * Joachim Foerster <joachim@missinglinkelectronics.com> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License as 9 * published by the Free Software Foundation; either version 2 of 10 * the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, 20 * MA 02111-1307 USA 21 * 22 * To use this driver, in your board's config. header: 23 * #define CONFIG_ALTERA_PIO 24 * #define CONFIG_SYS_ALTERA_PIO_NUM <number-of-pio-cores> 25 * #define CONFIG_SYS_ALTERA_PIO_GPIO_NUM <total-number-of-gpios> 26 * And in your board's early setup routine: 27 * altera_pio_init(<baseaddr>, <width>, 'i'|'o'|'t', 28 * <reset-value>, <neg-mask>, "label"); 29 * - 'i'|'o'|'t': PIO is input-only/output-only/tri-state 30 * - <reset-value>: for correct initial status display, output-only 31 * - <neg-mask> is meant to be used to in cases of active-low 32 * GPIOs, such as LEDs and buttons (on/pressed == 0). Each bit 33 * which is 1 in <neg-mask> inverts the corresponding GPIO's value 34 * before set/after get. So: gpio_set_value(gpio, 1) => LED on . 35 * 36 * Do NOT define CONFIG_SYS_GPIO_BASE ! 37 * 38 * Optionally, in your board's config. header: 39 * - To force a GPIO numbering scheme like in Linux ... 40 * #define CONFIG_GPIO_DOWNTO_NUMBERING 41 * ... starting with 255 (default) 42 * #define CONFIG_GPIO_DOWNTO_MAX 255 43 */ 44 #include <common.h> 45 #include <asm/io.h> 46 #include <asm/gpio.h> 47 48 #ifdef CONFIG_GPIO_DOWNTO_NUMBERING 49 #ifndef CONFIG_GPIO_DOWNTO_MAX 50 #define CONFIG_GPIO_DOWNTO_MAX 255 51 #endif 52 #endif 53 54 #define ALTERA_PIO_DATA 0x0 55 #define ALTERA_PIO_DIR 0x4 56 57 #define GPIO_LABEL_SIZE 9 58 59 60 static struct altera_pio { 61 u32 base; 62 u8 width; 63 char iot; 64 u32 negmask; 65 u32 sh_data; 66 u32 sh_dir; 67 int gidx; 68 char label[GPIO_LABEL_SIZE]; 69 } pios[CONFIG_SYS_ALTERA_PIO_NUM]; 70 71 static int pio_num; 72 73 static struct altera_pio_gpio { 74 unsigned num; 75 struct altera_pio *pio; 76 char reqlabel[GPIO_LABEL_SIZE]; 77 } gpios[CONFIG_SYS_ALTERA_PIO_GPIO_NUM]; 78 79 static int pio_gpio_num; 80 81 82 static int altera_pio_gidx(unsigned gpio) 83 { 84 int i; 85 86 for (i = 0; i < pio_gpio_num; ++i) { 87 if (gpio == gpios[i].num) 88 break; 89 } 90 if (i >= pio_gpio_num) 91 return -1; 92 return i; 93 } 94 95 static struct altera_pio *altera_pio_get_and_mask(unsigned gpio, u32 *mask) 96 { 97 int gidx = altera_pio_gidx(gpio); 98 if (gidx < 0) 99 return NULL; 100 if (mask) 101 *mask = 1 << (gidx - gpios[gidx].pio->gidx); 102 return gpios[gidx].pio; 103 } 104 105 #define altera_pio_use_gidx(_gidx, _reqlabel) \ 106 { strncpy(gpios[_gidx].reqlabel, _reqlabel, GPIO_LABEL_SIZE); } 107 #define altera_pio_unuse_gidx(_gidx) { gpios[_gidx].reqlabel[0] = '\0'; } 108 #define altera_pio_is_gidx_used(_gidx) (gpios[_gidx].reqlabel[0] != '\0') 109 110 static int altera_pio_gpio_init(struct altera_pio *pio, u8 width) 111 { 112 u8 gidx = pio_gpio_num; 113 int i; 114 115 if (!width) 116 return -1; 117 if ((pio_gpio_num + width) > CONFIG_SYS_ALTERA_PIO_GPIO_NUM) 118 return -1; 119 120 for (i = 0; i < width; ++i) { 121 #ifdef CONFIG_GPIO_DOWNTO_NUMBERING 122 gpios[pio_gpio_num + i].num = \ 123 CONFIG_GPIO_DOWNTO_MAX + 1 - gidx - width + i; 124 #else 125 gpios[pio_gpio_num + i].num = pio_gpio_num + i; 126 #endif 127 gpios[pio_gpio_num + i].pio = pio; 128 altera_pio_unuse_gidx(pio_gpio_num + i); 129 } 130 pio_gpio_num += width; 131 return gidx; 132 } 133 134 int altera_pio_init(u32 base, u8 width, char iot, u32 rstval, u32 negmask, 135 const char *label) 136 { 137 if (pio_num >= CONFIG_SYS_ALTERA_PIO_NUM) 138 return -1; 139 140 pios[pio_num].base = base; 141 pios[pio_num].width = width; 142 pios[pio_num].iot = iot; 143 switch (iot) { 144 case 'i': 145 /* input only */ 146 pios[pio_num].sh_dir = 0; 147 pios[pio_num].sh_data = readl(base + ALTERA_PIO_DATA); 148 break; 149 case 'o': 150 /* output only */ 151 pios[pio_num].sh_dir = 0xffffffff & ((1 << width) - 1); 152 pios[pio_num].sh_data = rstval; 153 break; 154 case 't': 155 /* bidir, tri-state */ 156 pios[pio_num].sh_dir = readl(base + ALTERA_PIO_DIR); 157 pios[pio_num].sh_data = readl(base + ALTERA_PIO_DATA); 158 break; 159 default: 160 return -1; 161 } 162 pios[pio_num].negmask = negmask & ((1 << width) - 1); 163 pios[pio_num].gidx = altera_pio_gpio_init(&pios[pio_num], width); 164 if (pios[pio_num].gidx < 0) 165 return -1; 166 strncpy(pios[pio_num].label, label, GPIO_LABEL_SIZE); 167 return pio_num++; 168 } 169 170 void altera_pio_info(void) 171 { 172 int i; 173 int j; 174 int gidx; 175 u32 mask; 176 177 for (i = 0; i < pio_num; ++i) { 178 printf("Altera PIO % 2d, @0x%08x, " 179 "width: %u, label: %s\n", 180 i, pios[i].base, pios[i].width, pios[i].label); 181 gidx = pios[i].gidx; 182 for (j = gidx; j < (gidx + pios[i].width); ++j) { 183 mask = 1 << (j - gidx); 184 printf("\tGPIO % 4d: %s %s [%c] %s\n", 185 gpios[j].num, 186 gpios[j].pio->sh_dir & mask ? "out" : " in", 187 gpio_get_value(gpios[j].num) ? "set" : "clr", 188 altera_pio_is_gidx_used(j) ? 'x' : ' ', 189 gpios[j].reqlabel); 190 } 191 } 192 } 193 194 195 int gpio_request(unsigned gpio, const char *label) 196 { 197 int gidx = altera_pio_gidx(gpio); 198 if (gidx < 0) 199 return gidx; 200 if (altera_pio_is_gidx_used(gidx)) 201 return -1; 202 203 altera_pio_use_gidx(gidx, label); 204 return 0; 205 } 206 207 int gpio_free(unsigned gpio) 208 { 209 int gidx = altera_pio_gidx(gpio); 210 if (gidx < 0) 211 return gidx; 212 if (!altera_pio_is_gidx_used(gidx)) 213 return -1; 214 215 altera_pio_unuse_gidx(gidx); 216 return 0; 217 } 218 219 int gpio_direction_input(unsigned gpio) 220 { 221 u32 mask; 222 struct altera_pio *pio; 223 224 pio = altera_pio_get_and_mask(gpio, &mask); 225 if (!pio) 226 return -1; 227 if (pio->iot == 'o') 228 return -1; 229 230 writel(pio->sh_dir &= ~mask, pio->base + ALTERA_PIO_DIR); 231 return 0; 232 } 233 234 int gpio_direction_output(unsigned gpio, int value) 235 { 236 u32 mask; 237 struct altera_pio *pio; 238 239 pio = altera_pio_get_and_mask(gpio, &mask); 240 if (!pio) 241 return -1; 242 if (pio->iot == 'i') 243 return -1; 244 245 value = (pio->negmask & mask) ? !value : value; 246 if (value) 247 pio->sh_data |= mask; 248 else 249 pio->sh_data &= ~mask; 250 writel(pio->sh_data, pio->base + ALTERA_PIO_DATA); 251 writel(pio->sh_dir |= mask, pio->base + ALTERA_PIO_DIR); 252 return 0; 253 } 254 255 int gpio_get_value(unsigned gpio) 256 { 257 u32 mask; 258 struct altera_pio *pio; 259 u32 val; 260 261 pio = altera_pio_get_and_mask(gpio, &mask); 262 if (!pio) 263 return -1; 264 265 if ((pio->sh_dir & mask) || (pio->iot == 'o')) 266 val = pio->sh_data & mask; 267 else 268 val = readl(pio->base + ALTERA_PIO_DATA) & mask; 269 return (pio->negmask & mask) ? !val : val; 270 } 271 272 void gpio_set_value(unsigned gpio, int value) 273 { 274 u32 mask; 275 struct altera_pio *pio; 276 277 pio = altera_pio_get_and_mask(gpio, &mask); 278 if (!pio) 279 return; 280 if (pio->iot == 'i') 281 return; 282 283 value = (pio->negmask & mask) ? !value : value; 284 if (value) 285 pio->sh_data |= mask; 286 else 287 pio->sh_data &= ~mask; 288 writel(pio->sh_data, pio->base + ALTERA_PIO_DATA); 289 return; 290 } 291 292 int gpio_is_valid(int number) 293 { 294 int gidx = altera_pio_gidx(number); 295 296 if (gidx < 0) 297 return 1; 298 return 0; 299 } 300