Icarus Chau | 9855895 | 2015-03-03 19:36:03 -0800 | [diff] [blame^] | 1 | /* |
| 2 | * Copyright (C) 2015 Broadcom Corporation |
| 3 | * |
| 4 | * This program is free software; you can redistribute it and/or |
| 5 | * modify it under the terms of the GNU General Public License as |
| 6 | * published by the Free Software Foundation version 2. |
| 7 | * |
| 8 | * This program is distributed "as is" WITHOUT ANY WARRANTY of any |
| 9 | * kind, whether express or implied; without even the implied warranty |
| 10 | * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | * GNU General Public License for more details. |
| 12 | */ |
| 13 | |
| 14 | #include <arch/io.h> |
| 15 | #include <console/console.h> |
| 16 | #include <gpio.h> |
| 17 | #include <stdlib.h> |
| 18 | #include <delay.h> |
| 19 | |
| 20 | #define dev_dbg(chip, fmt, args...) printk(BIOS_DEBUG, "[%s] " fmt, \ |
| 21 | chip->label, args) |
| 22 | |
| 23 | #define CYGNUS_GPIO_DATA_IN_OFFSET 0x00 |
| 24 | #define CYGNUS_GPIO_DATA_OUT_OFFSET 0x04 |
| 25 | #define CYGNUS_GPIO_OUT_EN_OFFSET 0x08 |
| 26 | #define CYGNUS_GPIO_IN_TYPE_OFFSET 0x0c |
| 27 | #define CYGNUS_GPIO_INT_DE_OFFSET 0x10 |
| 28 | #define CYGNUS_GPIO_INT_EDGE_OFFSET 0x14 |
| 29 | #define CYGNUS_GPIO_INT_MSK_OFFSET 0x18 |
| 30 | #define CYGNUS_GPIO_INT_STAT_OFFSET 0x1c |
| 31 | #define CYGNUS_GPIO_INT_MSTAT_OFFSET 0x20 |
| 32 | #define CYGNUS_GPIO_INT_CLR_OFFSET 0x24 |
| 33 | #define CYGNUS_GPIO_PAD_RES_OFFSET 0x34 |
| 34 | #define CYGNUS_GPIO_RES_EN_OFFSET 0x38 |
| 35 | |
| 36 | /* drive strength control for ASIU GPIO */ |
| 37 | #define CYGNUS_GPIO_ASIU_DRV0_CTRL_OFFSET 0x58 |
| 38 | |
| 39 | /* drive strength control for CCM/CRMU (AON) GPIO */ |
| 40 | #define CYGNUS_GPIO_DRV0_CTRL_OFFSET 0x00 |
| 41 | |
| 42 | #define GPIO_BANK_SIZE 0x200 |
| 43 | #define NGPIOS_PER_BANK 32 |
| 44 | #define GPIO_BANK(pin) ((pin) / NGPIOS_PER_BANK) |
| 45 | |
| 46 | #define CYGNUS_GPIO_REG(pin, reg) (GPIO_BANK(pin) * GPIO_BANK_SIZE + (reg)) |
| 47 | #define CYGNUS_GPIO_SHIFT(pin) ((pin) % NGPIOS_PER_BANK) |
| 48 | |
| 49 | #define GPIO_DRV_STRENGTH_BIT_SHIFT 20 |
| 50 | #define GPIO_DRV_STRENGTH_BITS 3 |
| 51 | #define GPIO_DRV_STRENGTH_BIT_MASK ((1 << GPIO_DRV_STRENGTH_BITS) - 1) |
| 52 | |
| 53 | /* |
| 54 | * Cygnus GPIO core |
| 55 | * |
| 56 | * @base: I/O register base for Cygnus GPIO controller |
| 57 | * @io_ctrl: I/O register base for certain type of Cygnus GPIO controller that |
| 58 | * has the PINCONF support implemented outside of the GPIO block |
| 59 | * @num_banks: number of GPIO banks, each bank supports up to 32 GPIOs |
| 60 | * @pinmux_is_supported: flag to indicate this GPIO controller contains pins |
| 61 | * that can be individually muxed to GPIO |
| 62 | * @pctl_priv: pointer to pinctrl handle |
| 63 | */ |
| 64 | struct cygnus_gpio { |
| 65 | void *base; |
| 66 | void *io_ctrl; |
| 67 | const char *label; |
| 68 | int gpio_base; |
| 69 | u16 ngpio; |
| 70 | unsigned num_banks; |
| 71 | int pinmux_is_supported; |
| 72 | void *pctl_priv; |
| 73 | }; |
| 74 | |
| 75 | /* |
| 76 | * GPIO cores table |
| 77 | * |
| 78 | * Cygnus has 3 gpio cores. The tables contains descriptors of those cores. |
| 79 | */ |
| 80 | struct cygnus_gpio cygnus_gpio_table[] = { |
| 81 | { |
| 82 | .base = (void *)0x03024800, |
| 83 | .io_ctrl = (void *)0x03024008, |
| 84 | .label = "gpio_crmu", |
| 85 | .gpio_base = 170, |
| 86 | .ngpio = 6, |
| 87 | }, |
| 88 | { |
| 89 | .base = (void *)0x1800a000, |
| 90 | .io_ctrl = (void *)0x0301d164, |
| 91 | .label = "gpio_ccm", |
| 92 | .gpio_base = 0, |
| 93 | .ngpio = 24, |
| 94 | }, |
| 95 | { |
| 96 | .base = (void *)0x180a5000, |
| 97 | .label = "gpio_asiu", |
| 98 | .gpio_base = 24, |
| 99 | .ngpio = 146, |
| 100 | .pinmux_is_supported = 1 |
| 101 | } |
| 102 | }; |
| 103 | |
| 104 | /* |
| 105 | * Map a GPIO in the local gpio_chip pin space to a pin in the Cygnus IOMUX |
| 106 | * pinctrl pin space |
| 107 | */ |
| 108 | struct cygnus_gpio_pin_range { |
| 109 | unsigned offset; |
| 110 | unsigned pin_base; |
| 111 | unsigned num_pins; |
| 112 | }; |
| 113 | |
| 114 | #define CYGNUS_PINRANGE(o, p, n) { .offset = o, .pin_base = p, .num_pins = n } |
| 115 | |
| 116 | /* |
| 117 | * Pin mapping table for mapping local GPIO pins to Cygnus IOMUX pinctrl pins. |
| 118 | * This is for ASIU gpio. The offset is based on ASIU gpios. |
| 119 | */ |
| 120 | static const struct cygnus_gpio_pin_range cygnus_gpio_pintable[] = { |
| 121 | CYGNUS_PINRANGE(0, 42, 1), |
| 122 | CYGNUS_PINRANGE(1, 44, 3), |
| 123 | CYGNUS_PINRANGE(4, 48, 1), |
| 124 | CYGNUS_PINRANGE(5, 50, 3), |
| 125 | CYGNUS_PINRANGE(8, 126, 1), |
| 126 | CYGNUS_PINRANGE(9, 155, 1), |
| 127 | CYGNUS_PINRANGE(10, 152, 1), |
| 128 | CYGNUS_PINRANGE(11, 154, 1), |
| 129 | CYGNUS_PINRANGE(12, 153, 1), |
| 130 | CYGNUS_PINRANGE(13, 127, 3), |
| 131 | CYGNUS_PINRANGE(16, 140, 1), |
| 132 | CYGNUS_PINRANGE(17, 145, 7), |
| 133 | CYGNUS_PINRANGE(24, 130, 10), |
| 134 | CYGNUS_PINRANGE(34, 141, 4), |
| 135 | CYGNUS_PINRANGE(38, 54, 1), |
| 136 | CYGNUS_PINRANGE(39, 56, 3), |
| 137 | CYGNUS_PINRANGE(42, 60, 3), |
| 138 | CYGNUS_PINRANGE(45, 64, 3), |
| 139 | CYGNUS_PINRANGE(48, 68, 2), |
| 140 | CYGNUS_PINRANGE(50, 84, 6), |
| 141 | CYGNUS_PINRANGE(56, 94, 6), |
| 142 | CYGNUS_PINRANGE(62, 72, 1), |
| 143 | CYGNUS_PINRANGE(63, 70, 1), |
| 144 | CYGNUS_PINRANGE(64, 80, 1), |
| 145 | CYGNUS_PINRANGE(65, 74, 3), |
| 146 | CYGNUS_PINRANGE(68, 78, 1), |
| 147 | CYGNUS_PINRANGE(69, 82, 1), |
| 148 | CYGNUS_PINRANGE(70, 156, 17), |
| 149 | CYGNUS_PINRANGE(87, 104, 12), |
| 150 | CYGNUS_PINRANGE(99, 102, 2), |
| 151 | CYGNUS_PINRANGE(101, 90, 4), |
| 152 | CYGNUS_PINRANGE(105, 116, 10), |
| 153 | CYGNUS_PINRANGE(123, 11, 1), |
| 154 | CYGNUS_PINRANGE(124, 38, 4), |
| 155 | CYGNUS_PINRANGE(128, 43, 1), |
| 156 | CYGNUS_PINRANGE(129, 47, 1), |
| 157 | CYGNUS_PINRANGE(130, 49, 1), |
| 158 | CYGNUS_PINRANGE(131, 53, 1), |
| 159 | CYGNUS_PINRANGE(132, 55, 1), |
| 160 | CYGNUS_PINRANGE(133, 59, 1), |
| 161 | CYGNUS_PINRANGE(134, 63, 1), |
| 162 | CYGNUS_PINRANGE(135, 67, 1), |
| 163 | CYGNUS_PINRANGE(136, 71, 1), |
| 164 | CYGNUS_PINRANGE(137, 73, 1), |
| 165 | CYGNUS_PINRANGE(138, 77, 1), |
| 166 | CYGNUS_PINRANGE(139, 79, 1), |
| 167 | CYGNUS_PINRANGE(140, 81, 1), |
| 168 | CYGNUS_PINRANGE(141, 83, 1), |
| 169 | CYGNUS_PINRANGE(142, 10, 1) |
| 170 | }; |
| 171 | |
| 172 | static unsigned cygnus_gpio_to_pin(unsigned gpio) |
| 173 | { |
| 174 | int i; |
| 175 | |
| 176 | for (i = 0; i < ARRAY_SIZE(cygnus_gpio_pintable); i++) { |
| 177 | const struct cygnus_gpio_pin_range *range = cygnus_gpio_pintable |
| 178 | + i; |
| 179 | |
| 180 | if ((gpio < range->offset) || |
| 181 | (gpio >= (range->offset + range->num_pins))) |
| 182 | continue; |
| 183 | |
| 184 | return range->pin_base + (gpio - range->offset); |
| 185 | } |
| 186 | return -1; |
| 187 | } |
| 188 | |
| 189 | static struct cygnus_gpio *cygnus_get_gpio_core(unsigned gpio, |
| 190 | unsigned *gpio_offset) |
| 191 | { |
| 192 | int i; |
| 193 | |
| 194 | for (i = 0; i < ARRAY_SIZE(cygnus_gpio_table); i++) { |
| 195 | struct cygnus_gpio *chip = cygnus_gpio_table + i; |
| 196 | |
| 197 | if ((gpio < chip->gpio_base) || |
| 198 | (gpio >= (chip->gpio_base + chip->ngpio))) |
| 199 | continue; |
| 200 | |
| 201 | *gpio_offset = gpio - chip->gpio_base; |
| 202 | return chip; |
| 203 | } |
| 204 | |
| 205 | return NULL; |
| 206 | } |
| 207 | |
| 208 | static u32 cygnus_readl(struct cygnus_gpio *chip, unsigned int offset) |
| 209 | { |
| 210 | return read32(chip->base + offset); |
| 211 | } |
| 212 | |
| 213 | static void cygnus_writel(struct cygnus_gpio *chip, unsigned int offset, |
| 214 | u32 val) |
| 215 | { |
| 216 | write32(chip->base + offset, val); |
| 217 | } |
| 218 | |
| 219 | /** |
| 220 | * cygnus_set_bit - set or clear one bit (corresponding to the GPIO pin) in a |
| 221 | * Cygnus GPIO register |
| 222 | * |
| 223 | * @cygnus_gpio: Cygnus GPIO device |
| 224 | * @reg: register offset |
| 225 | * @gpio: GPIO pin |
| 226 | * @set: set or clear. 1 - set; 0 -clear |
| 227 | */ |
| 228 | static void cygnus_set_bit(struct cygnus_gpio *chip, unsigned int reg, |
| 229 | unsigned gpio, int set) |
| 230 | { |
| 231 | unsigned int offset = CYGNUS_GPIO_REG(gpio, reg); |
| 232 | unsigned int shift = CYGNUS_GPIO_SHIFT(gpio); |
| 233 | u32 val; |
| 234 | |
| 235 | val = cygnus_readl(chip, offset); |
| 236 | if (set) |
| 237 | val |= BIT(shift); |
| 238 | else |
| 239 | val &= ~BIT(shift); |
| 240 | cygnus_writel(chip, offset, val); |
| 241 | } |
| 242 | |
| 243 | static int cygnus_get_bit(struct cygnus_gpio *chip, unsigned int reg, |
| 244 | unsigned gpio) |
| 245 | { |
| 246 | unsigned int offset = CYGNUS_GPIO_REG(gpio, reg); |
| 247 | unsigned int shift = CYGNUS_GPIO_SHIFT(gpio); |
| 248 | u32 val; |
| 249 | |
| 250 | val = cygnus_readl(chip, offset) & BIT(shift); |
| 251 | if (val) |
| 252 | return 1; |
| 253 | else |
| 254 | return 0; |
| 255 | } |
| 256 | |
| 257 | /* |
| 258 | * Request the Cygnus IOMUX pinmux controller to mux individual pins to GPIO |
| 259 | */ |
| 260 | static int cygnus_gpio_request(struct cygnus_gpio *chip, unsigned offset) |
| 261 | { |
| 262 | /* not all Cygnus GPIO pins can be muxed individually */ |
| 263 | if (!chip->pinmux_is_supported || (chip->pctl_priv == NULL)) |
| 264 | return 0; |
| 265 | |
| 266 | return cygnus_gpio_request_enable(chip->pctl_priv, |
| 267 | cygnus_gpio_to_pin(offset)); |
| 268 | } |
| 269 | |
| 270 | static void cygnus_gpio_free(struct cygnus_gpio *chip, unsigned offset) |
| 271 | { |
| 272 | if (!chip->pinmux_is_supported || (chip->pctl_priv == NULL)) |
| 273 | return; |
| 274 | |
| 275 | cygnus_gpio_disable_free(chip->pctl_priv, cygnus_gpio_to_pin(offset)); |
| 276 | } |
| 277 | |
| 278 | static int cygnus_gpio_direction_input(struct cygnus_gpio *chip, unsigned gpio) |
| 279 | { |
| 280 | cygnus_set_bit(chip, CYGNUS_GPIO_OUT_EN_OFFSET, gpio, 0); |
| 281 | |
| 282 | dev_dbg(chip, "gpio:%u set input\n", gpio); |
| 283 | |
| 284 | return 0; |
| 285 | } |
| 286 | |
| 287 | static int cygnus_gpio_direction_output(struct cygnus_gpio *chip, unsigned gpio, |
| 288 | int value) |
| 289 | { |
| 290 | cygnus_set_bit(chip, CYGNUS_GPIO_OUT_EN_OFFSET, gpio, 1); |
| 291 | cygnus_set_bit(chip, CYGNUS_GPIO_DATA_OUT_OFFSET, gpio, value); |
| 292 | |
| 293 | dev_dbg(chip, "gpio:%u set output, value:%d\n", gpio, value); |
| 294 | |
| 295 | return 0; |
| 296 | } |
| 297 | |
| 298 | static void cygnus_gpio_set(struct cygnus_gpio *chip, unsigned gpio, int value) |
| 299 | { |
| 300 | cygnus_set_bit(chip, CYGNUS_GPIO_DATA_OUT_OFFSET, gpio, value); |
| 301 | |
| 302 | dev_dbg(chip, "gpio:%u set, value:%d\n", gpio, value); |
| 303 | } |
| 304 | |
| 305 | static int cygnus_gpio_get(struct cygnus_gpio *chip, unsigned gpio) |
| 306 | { |
| 307 | return cygnus_get_bit(chip, CYGNUS_GPIO_DATA_IN_OFFSET, gpio); |
| 308 | } |
| 309 | |
| 310 | static int cygnus_gpio_set_pull(struct cygnus_gpio *chip, unsigned gpio, |
| 311 | int disable, int pull_up) |
| 312 | { |
| 313 | if (disable) { |
| 314 | cygnus_set_bit(chip, CYGNUS_GPIO_RES_EN_OFFSET, gpio, 0); |
| 315 | } else { |
| 316 | cygnus_set_bit(chip, CYGNUS_GPIO_PAD_RES_OFFSET, gpio, pull_up); |
| 317 | cygnus_set_bit(chip, CYGNUS_GPIO_RES_EN_OFFSET, gpio, 1); |
| 318 | } |
| 319 | |
| 320 | dev_dbg(chip, "gpio:%u set pullup:%d\n", gpio, pull_up); |
| 321 | |
| 322 | return 0; |
| 323 | } |
| 324 | |
| 325 | #define CYGNUS_GPIO_TEST_AON_GPIO0 170 |
| 326 | #define CYGNUS_GPIO_TEST_SPI2_MISO 69 |
| 327 | #define CYGNUS_GPIO_TEST_DELAY_S 3 |
| 328 | |
| 329 | static void cygnus_gpio_test(void) |
| 330 | { |
| 331 | gpio_t gpio_in; |
| 332 | gpio_t gpio_out; |
| 333 | unsigned val; |
| 334 | |
| 335 | printk(BIOS_INFO, "Start gpio test...\n"); |
| 336 | |
| 337 | gpio_in = CYGNUS_GPIO_TEST_AON_GPIO0; /* AON_GPIO0 */ |
| 338 | gpio_input(gpio_in); |
| 339 | gpio_input_pulldown(gpio_in); |
| 340 | printk(BIOS_INFO, "GPIO get %d=%d\n", gpio_in, gpio_get(gpio_in)); |
| 341 | |
| 342 | gpio_in = CYGNUS_GPIO_TEST_SPI2_MISO; /* SPI2_MISO */ |
| 343 | gpio_input(gpio_in); |
| 344 | gpio_input_pullup(gpio_in); |
| 345 | printk(BIOS_INFO, "GPIO get %d=%d\n", gpio_in, gpio_get(gpio_in)); |
| 346 | val = 0; |
| 347 | gpio_out = CYGNUS_GPIO_TEST_SPI2_MISO; |
| 348 | |
| 349 | gpio_output(gpio_out, val); |
| 350 | printk(BIOS_INFO, "GPIO set %d=%d\n", gpio_out, val); |
| 351 | delay(CYGNUS_GPIO_TEST_DELAY_S); |
| 352 | |
| 353 | val = 1; |
| 354 | gpio_set(gpio_out, val); |
| 355 | printk(BIOS_INFO, "GPIO set %d=%d\n", gpio_out, val); |
| 356 | delay(CYGNUS_GPIO_TEST_DELAY_S); |
| 357 | |
| 358 | val = 0; |
| 359 | gpio_set(gpio_out, val); |
| 360 | printk(BIOS_INFO, "GPIO set %d=%d\n", gpio_out, val); |
| 361 | delay(CYGNUS_GPIO_TEST_DELAY_S); |
| 362 | |
| 363 | val = 1; |
| 364 | gpio_set(gpio_out, val); |
| 365 | printk(BIOS_INFO, "GPIO set %d=%d\n", gpio_out, val); |
| 366 | delay(CYGNUS_GPIO_TEST_DELAY_S); |
| 367 | |
| 368 | val = 0; |
| 369 | gpio_set(gpio_out, val); |
| 370 | printk(BIOS_INFO, "GPIO set %d=%d\n", gpio_out, val); |
| 371 | delay(CYGNUS_GPIO_TEST_DELAY_S); |
| 372 | |
| 373 | gpio_free(CYGNUS_GPIO_TEST_AON_GPIO0); |
| 374 | gpio_free(CYGNUS_GPIO_TEST_SPI2_MISO); |
| 375 | printk(BIOS_INFO, "Gpio test completed...\n"); |
| 376 | } |
| 377 | |
| 378 | void gpio_init(void) |
| 379 | { |
| 380 | int i; |
| 381 | |
| 382 | printk(BIOS_INFO, "Setting up the gpio...\n"); |
| 383 | |
| 384 | for (i = 0; i < ARRAY_SIZE(cygnus_gpio_table); i++) { |
| 385 | struct cygnus_gpio *chip = cygnus_gpio_table + i; |
| 386 | |
| 387 | chip->num_banks = (chip->ngpio+NGPIOS_PER_BANK - 1) |
| 388 | / NGPIOS_PER_BANK; |
| 389 | if (chip->pinmux_is_supported) |
| 390 | chip->pctl_priv = cygnus_pinmux_init(); |
| 391 | } |
| 392 | |
| 393 | if (IS_ENABLED(CONFIG_CYGNUS_GPIO_TEST)) |
| 394 | cygnus_gpio_test(); |
| 395 | } |
| 396 | |
| 397 | void gpio_free(gpio_t gpio) |
| 398 | { |
| 399 | struct cygnus_gpio *chip; |
| 400 | unsigned gpio_num; |
| 401 | |
| 402 | chip = cygnus_get_gpio_core(gpio, &gpio_num); |
| 403 | if (chip == NULL) { |
| 404 | dev_dbg(chip, "unable to find chip for gpio %d", gpio); |
| 405 | return; |
| 406 | } |
| 407 | |
| 408 | cygnus_gpio_free(chip, gpio_num); |
| 409 | } |
| 410 | |
| 411 | void gpio_input(gpio_t gpio) |
| 412 | { |
| 413 | struct cygnus_gpio *chip; |
| 414 | unsigned gpio_num; |
| 415 | |
| 416 | chip = cygnus_get_gpio_core(gpio, &gpio_num); |
| 417 | if (chip == NULL) { |
| 418 | dev_dbg(chip, "unable to find chip for gpio %d", gpio); |
| 419 | return; |
| 420 | } |
| 421 | |
| 422 | if (cygnus_gpio_request(chip, gpio_num) != 0) { |
| 423 | printk(BIOS_ERR, "Cannot mux GPIO %d\n", gpio); |
| 424 | return; |
| 425 | } |
| 426 | cygnus_gpio_direction_input(chip, gpio_num); |
| 427 | } |
| 428 | |
| 429 | void gpio_input_pulldown(gpio_t gpio) |
| 430 | { |
| 431 | struct cygnus_gpio *chip; |
| 432 | unsigned gpio_num; |
| 433 | |
| 434 | chip = cygnus_get_gpio_core(gpio, &gpio_num); |
| 435 | if (chip == NULL) { |
| 436 | dev_dbg(chip, "unable to find chip for gpio %d", gpio); |
| 437 | return; |
| 438 | } |
| 439 | |
| 440 | cygnus_gpio_set_pull(chip, gpio_num, 0, 0); |
| 441 | } |
| 442 | |
| 443 | void gpio_input_pullup(gpio_t gpio) |
| 444 | { |
| 445 | struct cygnus_gpio *chip; |
| 446 | unsigned gpio_num; |
| 447 | |
| 448 | chip = cygnus_get_gpio_core(gpio, &gpio_num); |
| 449 | if (chip == NULL) { |
| 450 | dev_dbg(chip, "unable to find chip for gpio %d", gpio); |
| 451 | return; |
| 452 | } |
| 453 | |
| 454 | cygnus_gpio_set_pull(chip, gpio_num, 0, 1); |
| 455 | } |
| 456 | |
| 457 | int gpio_get(gpio_t gpio) |
| 458 | { |
| 459 | struct cygnus_gpio *chip; |
| 460 | unsigned gpio_num; |
| 461 | |
| 462 | chip = cygnus_get_gpio_core(gpio, &gpio_num); |
| 463 | if (chip == NULL) { |
| 464 | dev_dbg(chip, "unable to find chip for gpio %d", gpio); |
| 465 | return -1; |
| 466 | } |
| 467 | |
| 468 | return cygnus_gpio_get(chip, gpio_num); |
| 469 | } |
| 470 | |
| 471 | void gpio_set(gpio_t gpio, int value) |
| 472 | { |
| 473 | struct cygnus_gpio *chip; |
| 474 | unsigned gpio_num; |
| 475 | |
| 476 | chip = cygnus_get_gpio_core(gpio, &gpio_num); |
| 477 | if (chip == NULL) { |
| 478 | dev_dbg(chip, "unable to find chip for gpio %d", gpio); |
| 479 | return; |
| 480 | } |
| 481 | |
| 482 | cygnus_gpio_set(chip, gpio_num, value); |
| 483 | } |
| 484 | |
| 485 | void gpio_output(gpio_t gpio, int value) |
| 486 | { |
| 487 | struct cygnus_gpio *chip; |
| 488 | unsigned gpio_num; |
| 489 | |
| 490 | chip = cygnus_get_gpio_core(gpio, &gpio_num); |
| 491 | if (chip == NULL) { |
| 492 | dev_dbg(chip, "unable to find chip for gpio %d", gpio); |
| 493 | return; |
| 494 | } |
| 495 | |
| 496 | if (cygnus_gpio_request(chip, gpio_num) != 0) { |
| 497 | printk(BIOS_ERR, "Cannot mux GPIO %d\n", gpio); |
| 498 | return; |
| 499 | } |
| 500 | cygnus_gpio_direction_output(chip, gpio_num, value); |
| 501 | } |