1 /* 2 * (C) Copyright 2009 Samsung Electronics 3 * Minkyu Kang <mk7.kang@samsung.com> 4 * 5 * SPDX-License-Identifier: GPL-2.0+ 6 */ 7 8 #include <common.h> 9 #include <asm/io.h> 10 #include <asm/gpio.h> 11 #include <asm/arch/gpio.h> 12 13 #define S5P_GPIO_GET_PIN(x) (x % GPIO_PER_BANK) 14 15 #define CON_MASK(x) (0xf << ((x) << 2)) 16 #define CON_SFR(x, v) ((v) << ((x) << 2)) 17 18 #define DAT_MASK(x) (0x1 << (x)) 19 #define DAT_SET(x) (0x1 << (x)) 20 21 #define PULL_MASK(x) (0x3 << ((x) << 1)) 22 #define PULL_MODE(x, v) ((v) << ((x) << 1)) 23 24 #define DRV_MASK(x) (0x3 << ((x) << 1)) 25 #define DRV_SET(x, m) ((m) << ((x) << 1)) 26 #define RATE_MASK(x) (0x1 << (x + 16)) 27 #define RATE_SET(x) (0x1 << (x + 16)) 28 29 #define name_to_gpio(n) s5p_name_to_gpio(n) 30 static inline int s5p_name_to_gpio(const char *name) 31 { 32 unsigned num, irregular_set_number, irregular_bank_base; 33 const struct gpio_name_num_table *tabp; 34 char this_bank, bank_name, irregular_bank_name; 35 char *endp; 36 37 /* 38 * The gpio name starts with either 'g' or 'gp' followed by the bank 39 * name character. Skip one or two characters depending on the prefix. 40 */ 41 if (name[0] == 'g' && name[1] == 'p') 42 name += 2; 43 else if (name[0] == 'g') 44 name++; 45 else 46 return -1; /* Name must start with 'g' */ 47 48 bank_name = *name++; 49 if (!*name) 50 return -1; /* At least one digit is required/expected. */ 51 52 /* 53 * On both exynos5 and exynos5420 architectures there is a bank of 54 * GPIOs which does not fall into the regular address pattern. Those 55 * banks are c4 on Exynos5 and y7 on Exynos5420. The rest of the below 56 * assignments help to handle these irregularities. 57 */ 58 #if defined(CONFIG_EXYNOS4) || defined(CONFIG_EXYNOS5) 59 if (cpu_is_exynos5()) { 60 if (proid_is_exynos5420()) { 61 tabp = exynos5420_gpio_table; 62 irregular_bank_name = 'y'; 63 irregular_set_number = '7'; 64 irregular_bank_base = EXYNOS5420_GPIO_Y70; 65 } else { 66 tabp = exynos5_gpio_table; 67 irregular_bank_name = 'c'; 68 irregular_set_number = '4'; 69 irregular_bank_base = EXYNOS5_GPIO_C40; 70 } 71 } else { 72 if (proid_is_exynos4412()) 73 tabp = exynos4x12_gpio_table; 74 else 75 tabp = exynos4_gpio_table; 76 irregular_bank_name = 0; 77 irregular_set_number = 0; 78 irregular_bank_base = 0; 79 } 80 #else 81 if (cpu_is_s5pc110()) 82 tabp = s5pc110_gpio_table; 83 else 84 tabp = s5pc100_gpio_table; 85 irregular_bank_name = 0; 86 irregular_set_number = 0; 87 irregular_bank_base = 0; 88 #endif 89 90 this_bank = tabp->bank; 91 do { 92 if (bank_name == this_bank) { 93 unsigned pin_index; /* pin number within the bank */ 94 if ((bank_name == irregular_bank_name) && 95 (name[0] == irregular_set_number)) { 96 pin_index = name[1] - '0'; 97 /* Irregular sets have 8 pins. */ 98 if (pin_index >= GPIO_PER_BANK) 99 return -1; 100 num = irregular_bank_base + pin_index; 101 } else { 102 pin_index = simple_strtoul(name, &endp, 8); 103 pin_index -= tabp->bank_offset; 104 /* 105 * Sanity check: bunk 'z' has no set number, 106 * for all other banks there must be exactly 107 * two octal digits, and the resulting number 108 * should not exceed the number of pins in the 109 * bank. 110 */ 111 if (((bank_name != 'z') && !name[1]) || 112 *endp || 113 (pin_index >= tabp->bank_size)) 114 return -1; 115 num = tabp->base + pin_index; 116 } 117 return num; 118 } 119 this_bank = (++tabp)->bank; 120 } while (this_bank); 121 122 return -1; 123 } 124 125 static void s5p_gpio_cfg_pin(struct s5p_gpio_bank *bank, int gpio, int cfg) 126 { 127 unsigned int value; 128 129 value = readl(&bank->con); 130 value &= ~CON_MASK(gpio); 131 value |= CON_SFR(gpio, cfg); 132 writel(value, &bank->con); 133 } 134 135 static void s5p_gpio_set_value(struct s5p_gpio_bank *bank, int gpio, int en) 136 { 137 unsigned int value; 138 139 value = readl(&bank->dat); 140 value &= ~DAT_MASK(gpio); 141 if (en) 142 value |= DAT_SET(gpio); 143 writel(value, &bank->dat); 144 } 145 146 static void s5p_gpio_direction_output(struct s5p_gpio_bank *bank, 147 int gpio, int en) 148 { 149 s5p_gpio_cfg_pin(bank, gpio, S5P_GPIO_OUTPUT); 150 s5p_gpio_set_value(bank, gpio, en); 151 } 152 153 static void s5p_gpio_direction_input(struct s5p_gpio_bank *bank, int gpio) 154 { 155 s5p_gpio_cfg_pin(bank, gpio, S5P_GPIO_INPUT); 156 } 157 158 static unsigned int s5p_gpio_get_value(struct s5p_gpio_bank *bank, int gpio) 159 { 160 unsigned int value; 161 162 value = readl(&bank->dat); 163 return !!(value & DAT_MASK(gpio)); 164 } 165 166 static void s5p_gpio_set_pull(struct s5p_gpio_bank *bank, int gpio, int mode) 167 { 168 unsigned int value; 169 170 value = readl(&bank->pull); 171 value &= ~PULL_MASK(gpio); 172 173 switch (mode) { 174 case S5P_GPIO_PULL_DOWN: 175 case S5P_GPIO_PULL_UP: 176 value |= PULL_MODE(gpio, mode); 177 break; 178 default: 179 break; 180 } 181 182 writel(value, &bank->pull); 183 } 184 185 static void s5p_gpio_set_drv(struct s5p_gpio_bank *bank, int gpio, int mode) 186 { 187 unsigned int value; 188 189 value = readl(&bank->drv); 190 value &= ~DRV_MASK(gpio); 191 192 switch (mode) { 193 case S5P_GPIO_DRV_1X: 194 case S5P_GPIO_DRV_2X: 195 case S5P_GPIO_DRV_3X: 196 case S5P_GPIO_DRV_4X: 197 value |= DRV_SET(gpio, mode); 198 break; 199 default: 200 return; 201 } 202 203 writel(value, &bank->drv); 204 } 205 206 static void s5p_gpio_set_rate(struct s5p_gpio_bank *bank, int gpio, int mode) 207 { 208 unsigned int value; 209 210 value = readl(&bank->drv); 211 value &= ~RATE_MASK(gpio); 212 213 switch (mode) { 214 case S5P_GPIO_DRV_FAST: 215 case S5P_GPIO_DRV_SLOW: 216 value |= RATE_SET(gpio); 217 break; 218 default: 219 return; 220 } 221 222 writel(value, &bank->drv); 223 } 224 225 struct s5p_gpio_bank *s5p_gpio_get_bank(unsigned int gpio) 226 { 227 const struct gpio_info *data; 228 unsigned int upto; 229 int i, count; 230 231 data = get_gpio_data(); 232 count = get_bank_num(); 233 upto = 0; 234 235 for (i = 0; i < count; i++) { 236 debug("i=%d, upto=%d\n", i, upto); 237 if (gpio < data->max_gpio) { 238 struct s5p_gpio_bank *bank; 239 bank = (struct s5p_gpio_bank *)data->reg_addr; 240 bank += (gpio - upto) / GPIO_PER_BANK; 241 debug("gpio=%d, bank=%p\n", gpio, bank); 242 return bank; 243 } 244 245 upto = data->max_gpio; 246 data++; 247 } 248 249 return NULL; 250 } 251 252 int s5p_gpio_get_pin(unsigned gpio) 253 { 254 return S5P_GPIO_GET_PIN(gpio); 255 } 256 257 /* Common GPIO API */ 258 259 int gpio_request(unsigned gpio, const char *label) 260 { 261 return 0; 262 } 263 264 int gpio_free(unsigned gpio) 265 { 266 return 0; 267 } 268 269 int gpio_direction_input(unsigned gpio) 270 { 271 s5p_gpio_direction_input(s5p_gpio_get_bank(gpio), 272 s5p_gpio_get_pin(gpio)); 273 return 0; 274 } 275 276 int gpio_direction_output(unsigned gpio, int value) 277 { 278 s5p_gpio_direction_output(s5p_gpio_get_bank(gpio), 279 s5p_gpio_get_pin(gpio), value); 280 return 0; 281 } 282 283 int gpio_get_value(unsigned gpio) 284 { 285 return (int) s5p_gpio_get_value(s5p_gpio_get_bank(gpio), 286 s5p_gpio_get_pin(gpio)); 287 } 288 289 int gpio_set_value(unsigned gpio, int value) 290 { 291 s5p_gpio_set_value(s5p_gpio_get_bank(gpio), 292 s5p_gpio_get_pin(gpio), value); 293 294 return 0; 295 } 296 297 void gpio_set_pull(int gpio, int mode) 298 { 299 s5p_gpio_set_pull(s5p_gpio_get_bank(gpio), 300 s5p_gpio_get_pin(gpio), mode); 301 } 302 303 void gpio_set_drv(int gpio, int mode) 304 { 305 s5p_gpio_set_drv(s5p_gpio_get_bank(gpio), 306 s5p_gpio_get_pin(gpio), mode); 307 } 308 309 void gpio_cfg_pin(int gpio, int cfg) 310 { 311 s5p_gpio_cfg_pin(s5p_gpio_get_bank(gpio), 312 s5p_gpio_get_pin(gpio), cfg); 313 } 314 315 void gpio_set_rate(int gpio, int mode) 316 { 317 s5p_gpio_set_rate(s5p_gpio_get_bank(gpio), 318 s5p_gpio_get_pin(gpio), mode); 319 } 320