18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2007 Felix Fietkau <nbd@openwrt.org> 48c2ecf20Sopenharmony_ci * Copyright (C) 2007 Eugene Konev <ejka@openwrt.org> 58c2ecf20Sopenharmony_ci * Copyright (C) 2009-2010 Florian Fainelli <florian@openwrt.org> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/init.h> 98c2ecf20Sopenharmony_ci#include <linux/export.h> 108c2ecf20Sopenharmony_ci#include <linux/gpio.h> 118c2ecf20Sopenharmony_ci 128c2ecf20Sopenharmony_ci#include <asm/mach-ar7/ar7.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define AR7_GPIO_MAX 32 158c2ecf20Sopenharmony_ci#define TITAN_GPIO_MAX 51 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistruct ar7_gpio_chip { 188c2ecf20Sopenharmony_ci void __iomem *regs; 198c2ecf20Sopenharmony_ci struct gpio_chip chip; 208c2ecf20Sopenharmony_ci}; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic int ar7_gpio_get_value(struct gpio_chip *chip, unsigned gpio) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); 258c2ecf20Sopenharmony_ci void __iomem *gpio_in = gpch->regs + AR7_GPIO_INPUT; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci return !!(readl(gpio_in) & (1 << gpio)); 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_cistatic int titan_gpio_get_value(struct gpio_chip *chip, unsigned gpio) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); 338c2ecf20Sopenharmony_ci void __iomem *gpio_in0 = gpch->regs + TITAN_GPIO_INPUT_0; 348c2ecf20Sopenharmony_ci void __iomem *gpio_in1 = gpch->regs + TITAN_GPIO_INPUT_1; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci return readl(gpio >> 5 ? gpio_in1 : gpio_in0) & (1 << (gpio & 0x1f)); 378c2ecf20Sopenharmony_ci} 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_cistatic void ar7_gpio_set_value(struct gpio_chip *chip, 408c2ecf20Sopenharmony_ci unsigned gpio, int value) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); 438c2ecf20Sopenharmony_ci void __iomem *gpio_out = gpch->regs + AR7_GPIO_OUTPUT; 448c2ecf20Sopenharmony_ci unsigned tmp; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci tmp = readl(gpio_out) & ~(1 << gpio); 478c2ecf20Sopenharmony_ci if (value) 488c2ecf20Sopenharmony_ci tmp |= 1 << gpio; 498c2ecf20Sopenharmony_ci writel(tmp, gpio_out); 508c2ecf20Sopenharmony_ci} 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic void titan_gpio_set_value(struct gpio_chip *chip, 538c2ecf20Sopenharmony_ci unsigned gpio, int value) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); 568c2ecf20Sopenharmony_ci void __iomem *gpio_out0 = gpch->regs + TITAN_GPIO_OUTPUT_0; 578c2ecf20Sopenharmony_ci void __iomem *gpio_out1 = gpch->regs + TITAN_GPIO_OUTPUT_1; 588c2ecf20Sopenharmony_ci unsigned tmp; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_ci tmp = readl(gpio >> 5 ? gpio_out1 : gpio_out0) & ~(1 << (gpio & 0x1f)); 618c2ecf20Sopenharmony_ci if (value) 628c2ecf20Sopenharmony_ci tmp |= 1 << (gpio & 0x1f); 638c2ecf20Sopenharmony_ci writel(tmp, gpio >> 5 ? gpio_out1 : gpio_out0); 648c2ecf20Sopenharmony_ci} 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_cistatic int ar7_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); 698c2ecf20Sopenharmony_ci void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci writel(readl(gpio_dir) | (1 << gpio), gpio_dir); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic int titan_gpio_direction_input(struct gpio_chip *chip, unsigned gpio) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); 798c2ecf20Sopenharmony_ci void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0; 808c2ecf20Sopenharmony_ci void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (gpio >= TITAN_GPIO_MAX) 838c2ecf20Sopenharmony_ci return -EINVAL; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci writel(readl(gpio >> 5 ? gpio_dir1 : gpio_dir0) | (1 << (gpio & 0x1f)), 868c2ecf20Sopenharmony_ci gpio >> 5 ? gpio_dir1 : gpio_dir0); 878c2ecf20Sopenharmony_ci return 0; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistatic int ar7_gpio_direction_output(struct gpio_chip *chip, 918c2ecf20Sopenharmony_ci unsigned gpio, int value) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); 948c2ecf20Sopenharmony_ci void __iomem *gpio_dir = gpch->regs + AR7_GPIO_DIR; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci ar7_gpio_set_value(chip, gpio, value); 978c2ecf20Sopenharmony_ci writel(readl(gpio_dir) & ~(1 << gpio), gpio_dir); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci return 0; 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_cistatic int titan_gpio_direction_output(struct gpio_chip *chip, 1038c2ecf20Sopenharmony_ci unsigned gpio, int value) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci struct ar7_gpio_chip *gpch = gpiochip_get_data(chip); 1068c2ecf20Sopenharmony_ci void __iomem *gpio_dir0 = gpch->regs + TITAN_GPIO_DIR_0; 1078c2ecf20Sopenharmony_ci void __iomem *gpio_dir1 = gpch->regs + TITAN_GPIO_DIR_1; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (gpio >= TITAN_GPIO_MAX) 1108c2ecf20Sopenharmony_ci return -EINVAL; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci titan_gpio_set_value(chip, gpio, value); 1138c2ecf20Sopenharmony_ci writel(readl(gpio >> 5 ? gpio_dir1 : gpio_dir0) & ~(1 << 1148c2ecf20Sopenharmony_ci (gpio & 0x1f)), gpio >> 5 ? gpio_dir1 : gpio_dir0); 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci return 0; 1178c2ecf20Sopenharmony_ci} 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_cistatic struct ar7_gpio_chip ar7_gpio_chip = { 1208c2ecf20Sopenharmony_ci .chip = { 1218c2ecf20Sopenharmony_ci .label = "ar7-gpio", 1228c2ecf20Sopenharmony_ci .direction_input = ar7_gpio_direction_input, 1238c2ecf20Sopenharmony_ci .direction_output = ar7_gpio_direction_output, 1248c2ecf20Sopenharmony_ci .set = ar7_gpio_set_value, 1258c2ecf20Sopenharmony_ci .get = ar7_gpio_get_value, 1268c2ecf20Sopenharmony_ci .base = 0, 1278c2ecf20Sopenharmony_ci .ngpio = AR7_GPIO_MAX, 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci}; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic struct ar7_gpio_chip titan_gpio_chip = { 1328c2ecf20Sopenharmony_ci .chip = { 1338c2ecf20Sopenharmony_ci .label = "titan-gpio", 1348c2ecf20Sopenharmony_ci .direction_input = titan_gpio_direction_input, 1358c2ecf20Sopenharmony_ci .direction_output = titan_gpio_direction_output, 1368c2ecf20Sopenharmony_ci .set = titan_gpio_set_value, 1378c2ecf20Sopenharmony_ci .get = titan_gpio_get_value, 1388c2ecf20Sopenharmony_ci .base = 0, 1398c2ecf20Sopenharmony_ci .ngpio = TITAN_GPIO_MAX, 1408c2ecf20Sopenharmony_ci } 1418c2ecf20Sopenharmony_ci}; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic inline int ar7_gpio_enable_ar7(unsigned gpio) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci void __iomem *gpio_en = ar7_gpio_chip.regs + AR7_GPIO_ENABLE; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci writel(readl(gpio_en) | (1 << gpio), gpio_en); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci return 0; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_cistatic inline int ar7_gpio_enable_titan(unsigned gpio) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci void __iomem *gpio_en0 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_0; 1558c2ecf20Sopenharmony_ci void __iomem *gpio_en1 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_1; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci writel(readl(gpio >> 5 ? gpio_en1 : gpio_en0) | (1 << (gpio & 0x1f)), 1588c2ecf20Sopenharmony_ci gpio >> 5 ? gpio_en1 : gpio_en0); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci return 0; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ciint ar7_gpio_enable(unsigned gpio) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci return ar7_is_titan() ? ar7_gpio_enable_titan(gpio) : 1668c2ecf20Sopenharmony_ci ar7_gpio_enable_ar7(gpio); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ar7_gpio_enable); 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_cistatic inline int ar7_gpio_disable_ar7(unsigned gpio) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci void __iomem *gpio_en = ar7_gpio_chip.regs + AR7_GPIO_ENABLE; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci writel(readl(gpio_en) & ~(1 << gpio), gpio_en); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci return 0; 1778c2ecf20Sopenharmony_ci} 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_cistatic inline int ar7_gpio_disable_titan(unsigned gpio) 1808c2ecf20Sopenharmony_ci{ 1818c2ecf20Sopenharmony_ci void __iomem *gpio_en0 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_0; 1828c2ecf20Sopenharmony_ci void __iomem *gpio_en1 = titan_gpio_chip.regs + TITAN_GPIO_ENBL_1; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci writel(readl(gpio >> 5 ? gpio_en1 : gpio_en0) & ~(1 << (gpio & 0x1f)), 1858c2ecf20Sopenharmony_ci gpio >> 5 ? gpio_en1 : gpio_en0); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci return 0; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ciint ar7_gpio_disable(unsigned gpio) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci return ar7_is_titan() ? ar7_gpio_disable_titan(gpio) : 1938c2ecf20Sopenharmony_ci ar7_gpio_disable_ar7(gpio); 1948c2ecf20Sopenharmony_ci} 1958c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ar7_gpio_disable); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistruct titan_gpio_cfg { 1988c2ecf20Sopenharmony_ci u32 reg; 1998c2ecf20Sopenharmony_ci u32 shift; 2008c2ecf20Sopenharmony_ci u32 func; 2018c2ecf20Sopenharmony_ci}; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic const struct titan_gpio_cfg titan_gpio_table[] = { 2048c2ecf20Sopenharmony_ci /* reg, start bit, mux value */ 2058c2ecf20Sopenharmony_ci {4, 24, 1}, 2068c2ecf20Sopenharmony_ci {4, 26, 1}, 2078c2ecf20Sopenharmony_ci {4, 28, 1}, 2088c2ecf20Sopenharmony_ci {4, 30, 1}, 2098c2ecf20Sopenharmony_ci {5, 6, 1}, 2108c2ecf20Sopenharmony_ci {5, 8, 1}, 2118c2ecf20Sopenharmony_ci {5, 10, 1}, 2128c2ecf20Sopenharmony_ci {5, 12, 1}, 2138c2ecf20Sopenharmony_ci {7, 14, 3}, 2148c2ecf20Sopenharmony_ci {7, 16, 3}, 2158c2ecf20Sopenharmony_ci {7, 18, 3}, 2168c2ecf20Sopenharmony_ci {7, 20, 3}, 2178c2ecf20Sopenharmony_ci {7, 22, 3}, 2188c2ecf20Sopenharmony_ci {7, 26, 3}, 2198c2ecf20Sopenharmony_ci {7, 28, 3}, 2208c2ecf20Sopenharmony_ci {7, 30, 3}, 2218c2ecf20Sopenharmony_ci {8, 0, 3}, 2228c2ecf20Sopenharmony_ci {8, 2, 3}, 2238c2ecf20Sopenharmony_ci {8, 4, 3}, 2248c2ecf20Sopenharmony_ci {8, 10, 3}, 2258c2ecf20Sopenharmony_ci {8, 14, 3}, 2268c2ecf20Sopenharmony_ci {8, 16, 3}, 2278c2ecf20Sopenharmony_ci {8, 18, 3}, 2288c2ecf20Sopenharmony_ci {8, 20, 3}, 2298c2ecf20Sopenharmony_ci {9, 8, 3}, 2308c2ecf20Sopenharmony_ci {9, 10, 3}, 2318c2ecf20Sopenharmony_ci {9, 12, 3}, 2328c2ecf20Sopenharmony_ci {9, 14, 3}, 2338c2ecf20Sopenharmony_ci {9, 18, 3}, 2348c2ecf20Sopenharmony_ci {9, 20, 3}, 2358c2ecf20Sopenharmony_ci {9, 24, 3}, 2368c2ecf20Sopenharmony_ci {9, 26, 3}, 2378c2ecf20Sopenharmony_ci {9, 28, 3}, 2388c2ecf20Sopenharmony_ci {9, 30, 3}, 2398c2ecf20Sopenharmony_ci {10, 0, 3}, 2408c2ecf20Sopenharmony_ci {10, 2, 3}, 2418c2ecf20Sopenharmony_ci {10, 8, 3}, 2428c2ecf20Sopenharmony_ci {10, 10, 3}, 2438c2ecf20Sopenharmony_ci {10, 12, 3}, 2448c2ecf20Sopenharmony_ci {10, 14, 3}, 2458c2ecf20Sopenharmony_ci {13, 12, 3}, 2468c2ecf20Sopenharmony_ci {13, 14, 3}, 2478c2ecf20Sopenharmony_ci {13, 16, 3}, 2488c2ecf20Sopenharmony_ci {13, 18, 3}, 2498c2ecf20Sopenharmony_ci {13, 24, 3}, 2508c2ecf20Sopenharmony_ci {13, 26, 3}, 2518c2ecf20Sopenharmony_ci {13, 28, 3}, 2528c2ecf20Sopenharmony_ci {13, 30, 3}, 2538c2ecf20Sopenharmony_ci {14, 2, 3}, 2548c2ecf20Sopenharmony_ci {14, 6, 3}, 2558c2ecf20Sopenharmony_ci {14, 8, 3}, 2568c2ecf20Sopenharmony_ci {14, 12, 3} 2578c2ecf20Sopenharmony_ci}; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_cistatic int titan_gpio_pinsel(unsigned gpio) 2608c2ecf20Sopenharmony_ci{ 2618c2ecf20Sopenharmony_ci struct titan_gpio_cfg gpio_cfg; 2628c2ecf20Sopenharmony_ci u32 mux_status, pin_sel_reg, tmp; 2638c2ecf20Sopenharmony_ci void __iomem *pin_sel = (void __iomem *)KSEG1ADDR(AR7_REGS_PINSEL); 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_ci if (gpio >= ARRAY_SIZE(titan_gpio_table)) 2668c2ecf20Sopenharmony_ci return -EINVAL; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci gpio_cfg = titan_gpio_table[gpio]; 2698c2ecf20Sopenharmony_ci pin_sel_reg = gpio_cfg.reg - 1; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci mux_status = (readl(pin_sel + pin_sel_reg) >> gpio_cfg.shift) & 0x3; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* Check the mux status */ 2748c2ecf20Sopenharmony_ci if (!((mux_status == 0) || (mux_status == gpio_cfg.func))) 2758c2ecf20Sopenharmony_ci return 0; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* Set the pin sel value */ 2788c2ecf20Sopenharmony_ci tmp = readl(pin_sel + pin_sel_reg); 2798c2ecf20Sopenharmony_ci tmp |= ((gpio_cfg.func & 0x3) << gpio_cfg.shift); 2808c2ecf20Sopenharmony_ci writel(tmp, pin_sel + pin_sel_reg); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci return 0; 2838c2ecf20Sopenharmony_ci} 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci/* Perform minimal Titan GPIO configuration */ 2868c2ecf20Sopenharmony_cistatic void titan_gpio_init(void) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci unsigned i; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci for (i = 44; i < 48; i++) { 2918c2ecf20Sopenharmony_ci titan_gpio_pinsel(i); 2928c2ecf20Sopenharmony_ci ar7_gpio_enable_titan(i); 2938c2ecf20Sopenharmony_ci titan_gpio_direction_input(&titan_gpio_chip.chip, i); 2948c2ecf20Sopenharmony_ci } 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ciint __init ar7_gpio_init(void) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci int ret; 3008c2ecf20Sopenharmony_ci struct ar7_gpio_chip *gpch; 3018c2ecf20Sopenharmony_ci unsigned size; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (!ar7_is_titan()) { 3048c2ecf20Sopenharmony_ci gpch = &ar7_gpio_chip; 3058c2ecf20Sopenharmony_ci size = 0x10; 3068c2ecf20Sopenharmony_ci } else { 3078c2ecf20Sopenharmony_ci gpch = &titan_gpio_chip; 3088c2ecf20Sopenharmony_ci size = 0x1f; 3098c2ecf20Sopenharmony_ci } 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci gpch->regs = ioremap(AR7_REGS_GPIO, size); 3128c2ecf20Sopenharmony_ci if (!gpch->regs) { 3138c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: failed to ioremap regs\n", 3148c2ecf20Sopenharmony_ci gpch->chip.label); 3158c2ecf20Sopenharmony_ci return -ENOMEM; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci ret = gpiochip_add_data(&gpch->chip, gpch); 3198c2ecf20Sopenharmony_ci if (ret) { 3208c2ecf20Sopenharmony_ci printk(KERN_ERR "%s: failed to add gpiochip\n", 3218c2ecf20Sopenharmony_ci gpch->chip.label); 3228c2ecf20Sopenharmony_ci return ret; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci printk(KERN_INFO "%s: registered %d GPIOs\n", 3258c2ecf20Sopenharmony_ci gpch->chip.label, gpch->chip.ngpio); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (ar7_is_titan()) 3288c2ecf20Sopenharmony_ci titan_gpio_init(); 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci return ret; 3318c2ecf20Sopenharmony_ci} 332