18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Intel ICH6-10, Series 5 and 6, Atom C2000 (Avoton/Rangeley) GPIO driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2010 Extreme Engineering Solutions. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/bitops.h> 108c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 118c2ecf20Sopenharmony_ci#include <linux/ioport.h> 128c2ecf20Sopenharmony_ci#include <linux/mfd/lpc_ich.h> 138c2ecf20Sopenharmony_ci#include <linux/module.h> 148c2ecf20Sopenharmony_ci#include <linux/pci.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define DRV_NAME "gpio_ich" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/* 208c2ecf20Sopenharmony_ci * GPIO register offsets in GPIO I/O space. 218c2ecf20Sopenharmony_ci * Each chunk of 32 GPIOs is manipulated via its own USE_SELx, IO_SELx, and 228c2ecf20Sopenharmony_ci * LVLx registers. Logic in the read/write functions takes a register and 238c2ecf20Sopenharmony_ci * an absolute bit number and determines the proper register offset and bit 248c2ecf20Sopenharmony_ci * number in that register. For example, to read the value of GPIO bit 50 258c2ecf20Sopenharmony_ci * the code would access offset ichx_regs[2(=GPIO_LVL)][1(=50/32)], 268c2ecf20Sopenharmony_ci * bit 18 (50%32). 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_cienum GPIO_REG { 298c2ecf20Sopenharmony_ci GPIO_USE_SEL = 0, 308c2ecf20Sopenharmony_ci GPIO_IO_SEL, 318c2ecf20Sopenharmony_ci GPIO_LVL, 328c2ecf20Sopenharmony_ci GPO_BLINK 338c2ecf20Sopenharmony_ci}; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic const u8 ichx_regs[4][3] = { 368c2ecf20Sopenharmony_ci {0x00, 0x30, 0x40}, /* USE_SEL[1-3] offsets */ 378c2ecf20Sopenharmony_ci {0x04, 0x34, 0x44}, /* IO_SEL[1-3] offsets */ 388c2ecf20Sopenharmony_ci {0x0c, 0x38, 0x48}, /* LVL[1-3] offsets */ 398c2ecf20Sopenharmony_ci {0x18, 0x18, 0x18}, /* BLINK offset */ 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_cistatic const u8 ichx_reglen[3] = { 438c2ecf20Sopenharmony_ci 0x30, 0x10, 0x10, 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic const u8 avoton_regs[4][3] = { 478c2ecf20Sopenharmony_ci {0x00, 0x80, 0x00}, 488c2ecf20Sopenharmony_ci {0x04, 0x84, 0x00}, 498c2ecf20Sopenharmony_ci {0x08, 0x88, 0x00}, 508c2ecf20Sopenharmony_ci}; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_cistatic const u8 avoton_reglen[3] = { 538c2ecf20Sopenharmony_ci 0x10, 0x10, 0x00, 548c2ecf20Sopenharmony_ci}; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci#define ICHX_WRITE(val, reg, base_res) outl(val, (reg) + (base_res)->start) 578c2ecf20Sopenharmony_ci#define ICHX_READ(reg, base_res) inl((reg) + (base_res)->start) 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistruct ichx_desc { 608c2ecf20Sopenharmony_ci /* Max GPIO pins the chipset can have */ 618c2ecf20Sopenharmony_ci uint ngpio; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci /* chipset registers */ 648c2ecf20Sopenharmony_ci const u8 (*regs)[3]; 658c2ecf20Sopenharmony_ci const u8 *reglen; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* GPO_BLINK is available on this chipset */ 688c2ecf20Sopenharmony_ci bool have_blink; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci /* Whether the chipset has GPIO in GPE0_STS in the PM IO region */ 718c2ecf20Sopenharmony_ci bool uses_gpe0; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci /* USE_SEL is bogus on some chipsets, eg 3100 */ 748c2ecf20Sopenharmony_ci u32 use_sel_ignore[3]; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* Some chipsets have quirks, let these use their own request/get */ 778c2ecf20Sopenharmony_ci int (*request)(struct gpio_chip *chip, unsigned int offset); 788c2ecf20Sopenharmony_ci int (*get)(struct gpio_chip *chip, unsigned int offset); 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci /* 818c2ecf20Sopenharmony_ci * Some chipsets don't let reading output values on GPIO_LVL register 828c2ecf20Sopenharmony_ci * this option allows driver caching written output values 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_ci bool use_outlvl_cache; 858c2ecf20Sopenharmony_ci}; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic struct { 888c2ecf20Sopenharmony_ci spinlock_t lock; 898c2ecf20Sopenharmony_ci struct device *dev; 908c2ecf20Sopenharmony_ci struct gpio_chip chip; 918c2ecf20Sopenharmony_ci struct resource *gpio_base; /* GPIO IO base */ 928c2ecf20Sopenharmony_ci struct resource *pm_base; /* Power Management IO base */ 938c2ecf20Sopenharmony_ci struct ichx_desc *desc; /* Pointer to chipset-specific description */ 948c2ecf20Sopenharmony_ci u32 orig_gpio_ctrl; /* Orig CTRL value, used to restore on exit */ 958c2ecf20Sopenharmony_ci u8 use_gpio; /* Which GPIO groups are usable */ 968c2ecf20Sopenharmony_ci int outlvl_cache[3]; /* cached output values */ 978c2ecf20Sopenharmony_ci} ichx_priv; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_cistatic int modparam_gpiobase = -1; /* dynamic */ 1008c2ecf20Sopenharmony_cimodule_param_named(gpiobase, modparam_gpiobase, int, 0444); 1018c2ecf20Sopenharmony_ciMODULE_PARM_DESC(gpiobase, "The GPIO number base. -1 means dynamic, which is the default."); 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cistatic int ichx_write_bit(int reg, unsigned int nr, int val, int verify) 1048c2ecf20Sopenharmony_ci{ 1058c2ecf20Sopenharmony_ci unsigned long flags; 1068c2ecf20Sopenharmony_ci u32 data, tmp; 1078c2ecf20Sopenharmony_ci int reg_nr = nr / 32; 1088c2ecf20Sopenharmony_ci int bit = nr & 0x1f; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci spin_lock_irqsave(&ichx_priv.lock, flags); 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache) 1138c2ecf20Sopenharmony_ci data = ichx_priv.outlvl_cache[reg_nr]; 1148c2ecf20Sopenharmony_ci else 1158c2ecf20Sopenharmony_ci data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], 1168c2ecf20Sopenharmony_ci ichx_priv.gpio_base); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci if (val) 1198c2ecf20Sopenharmony_ci data |= BIT(bit); 1208c2ecf20Sopenharmony_ci else 1218c2ecf20Sopenharmony_ci data &= ~BIT(bit); 1228c2ecf20Sopenharmony_ci ICHX_WRITE(data, ichx_priv.desc->regs[reg][reg_nr], 1238c2ecf20Sopenharmony_ci ichx_priv.gpio_base); 1248c2ecf20Sopenharmony_ci if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache) 1258c2ecf20Sopenharmony_ci ichx_priv.outlvl_cache[reg_nr] = data; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci tmp = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], 1288c2ecf20Sopenharmony_ci ichx_priv.gpio_base); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ichx_priv.lock, flags); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci return (verify && data != tmp) ? -EPERM : 0; 1338c2ecf20Sopenharmony_ci} 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_cistatic int ichx_read_bit(int reg, unsigned int nr) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci unsigned long flags; 1388c2ecf20Sopenharmony_ci u32 data; 1398c2ecf20Sopenharmony_ci int reg_nr = nr / 32; 1408c2ecf20Sopenharmony_ci int bit = nr & 0x1f; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci spin_lock_irqsave(&ichx_priv.lock, flags); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci data = ICHX_READ(ichx_priv.desc->regs[reg][reg_nr], 1458c2ecf20Sopenharmony_ci ichx_priv.gpio_base); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (reg == GPIO_LVL && ichx_priv.desc->use_outlvl_cache) 1488c2ecf20Sopenharmony_ci data = ichx_priv.outlvl_cache[reg_nr] | data; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ichx_priv.lock, flags); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return !!(data & BIT(bit)); 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic bool ichx_gpio_check_available(struct gpio_chip *gpio, unsigned int nr) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci return !!(ichx_priv.use_gpio & BIT(nr / 32)); 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_cistatic int ichx_gpio_get_direction(struct gpio_chip *gpio, unsigned int nr) 1618c2ecf20Sopenharmony_ci{ 1628c2ecf20Sopenharmony_ci if (ichx_read_bit(GPIO_IO_SEL, nr)) 1638c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_IN; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return GPIO_LINE_DIRECTION_OUT; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int ichx_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci /* 1718c2ecf20Sopenharmony_ci * Try setting pin as an input and verify it worked since many pins 1728c2ecf20Sopenharmony_ci * are output-only. 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_ci return ichx_write_bit(GPIO_IO_SEL, nr, 1, 1); 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic int ichx_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr, 1788c2ecf20Sopenharmony_ci int val) 1798c2ecf20Sopenharmony_ci{ 1808c2ecf20Sopenharmony_ci /* Disable blink hardware which is available for GPIOs from 0 to 31. */ 1818c2ecf20Sopenharmony_ci if (nr < 32 && ichx_priv.desc->have_blink) 1828c2ecf20Sopenharmony_ci ichx_write_bit(GPO_BLINK, nr, 0, 0); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci /* Set GPIO output value. */ 1858c2ecf20Sopenharmony_ci ichx_write_bit(GPIO_LVL, nr, val, 0); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci /* 1888c2ecf20Sopenharmony_ci * Try setting pin as an output and verify it worked since many pins 1898c2ecf20Sopenharmony_ci * are input-only. 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_ci return ichx_write_bit(GPIO_IO_SEL, nr, 0, 1); 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic int ichx_gpio_get(struct gpio_chip *chip, unsigned int nr) 1958c2ecf20Sopenharmony_ci{ 1968c2ecf20Sopenharmony_ci return ichx_read_bit(GPIO_LVL, nr); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic int ich6_gpio_get(struct gpio_chip *chip, unsigned int nr) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci unsigned long flags; 2028c2ecf20Sopenharmony_ci u32 data; 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci /* 2058c2ecf20Sopenharmony_ci * GPI 0 - 15 need to be read from the power management registers on 2068c2ecf20Sopenharmony_ci * a ICH6/3100 bridge. 2078c2ecf20Sopenharmony_ci */ 2088c2ecf20Sopenharmony_ci if (nr < 16) { 2098c2ecf20Sopenharmony_ci if (!ichx_priv.pm_base) 2108c2ecf20Sopenharmony_ci return -ENXIO; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci spin_lock_irqsave(&ichx_priv.lock, flags); 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* GPI 0 - 15 are latched, write 1 to clear*/ 2158c2ecf20Sopenharmony_ci ICHX_WRITE(BIT(16 + nr), 0, ichx_priv.pm_base); 2168c2ecf20Sopenharmony_ci data = ICHX_READ(0, ichx_priv.pm_base); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&ichx_priv.lock, flags); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci return !!((data >> 16) & BIT(nr)); 2218c2ecf20Sopenharmony_ci } else { 2228c2ecf20Sopenharmony_ci return ichx_gpio_get(chip, nr); 2238c2ecf20Sopenharmony_ci } 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic int ichx_gpio_request(struct gpio_chip *chip, unsigned int nr) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci if (!ichx_gpio_check_available(chip, nr)) 2298c2ecf20Sopenharmony_ci return -ENXIO; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci /* 2328c2ecf20Sopenharmony_ci * Note we assume the BIOS properly set a bridge's USE value. Some 2338c2ecf20Sopenharmony_ci * chips (eg Intel 3100) have bogus USE values though, so first see if 2348c2ecf20Sopenharmony_ci * the chipset's USE value can be trusted for this specific bit. 2358c2ecf20Sopenharmony_ci * If it can't be trusted, assume that the pin can be used as a GPIO. 2368c2ecf20Sopenharmony_ci */ 2378c2ecf20Sopenharmony_ci if (ichx_priv.desc->use_sel_ignore[nr / 32] & BIT(nr & 0x1f)) 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci return ichx_read_bit(GPIO_USE_SEL, nr) ? 0 : -ENODEV; 2418c2ecf20Sopenharmony_ci} 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_cistatic int ich6_gpio_request(struct gpio_chip *chip, unsigned int nr) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci /* 2468c2ecf20Sopenharmony_ci * Fixups for bits 16 and 17 are necessary on the Intel ICH6/3100 2478c2ecf20Sopenharmony_ci * bridge as they are controlled by USE register bits 0 and 1. See 2488c2ecf20Sopenharmony_ci * "Table 704 GPIO_USE_SEL1 register" in the i3100 datasheet for 2498c2ecf20Sopenharmony_ci * additional info. 2508c2ecf20Sopenharmony_ci */ 2518c2ecf20Sopenharmony_ci if (nr == 16 || nr == 17) 2528c2ecf20Sopenharmony_ci nr -= 16; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return ichx_gpio_request(chip, nr); 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic void ichx_gpio_set(struct gpio_chip *chip, unsigned int nr, int val) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci ichx_write_bit(GPIO_LVL, nr, val, 0); 2608c2ecf20Sopenharmony_ci} 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_cistatic void ichx_gpiolib_setup(struct gpio_chip *chip) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci chip->owner = THIS_MODULE; 2658c2ecf20Sopenharmony_ci chip->label = DRV_NAME; 2668c2ecf20Sopenharmony_ci chip->parent = ichx_priv.dev; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* Allow chip-specific overrides of request()/get() */ 2698c2ecf20Sopenharmony_ci chip->request = ichx_priv.desc->request ? 2708c2ecf20Sopenharmony_ci ichx_priv.desc->request : ichx_gpio_request; 2718c2ecf20Sopenharmony_ci chip->get = ichx_priv.desc->get ? 2728c2ecf20Sopenharmony_ci ichx_priv.desc->get : ichx_gpio_get; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci chip->set = ichx_gpio_set; 2758c2ecf20Sopenharmony_ci chip->get_direction = ichx_gpio_get_direction; 2768c2ecf20Sopenharmony_ci chip->direction_input = ichx_gpio_direction_input; 2778c2ecf20Sopenharmony_ci chip->direction_output = ichx_gpio_direction_output; 2788c2ecf20Sopenharmony_ci chip->base = modparam_gpiobase; 2798c2ecf20Sopenharmony_ci chip->ngpio = ichx_priv.desc->ngpio; 2808c2ecf20Sopenharmony_ci chip->can_sleep = false; 2818c2ecf20Sopenharmony_ci chip->dbg_show = NULL; 2828c2ecf20Sopenharmony_ci} 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci/* ICH6-based, 631xesb-based */ 2858c2ecf20Sopenharmony_cistatic struct ichx_desc ich6_desc = { 2868c2ecf20Sopenharmony_ci /* Bridges using the ICH6 controller need fixups for GPIO 0 - 17 */ 2878c2ecf20Sopenharmony_ci .request = ich6_gpio_request, 2888c2ecf20Sopenharmony_ci .get = ich6_gpio_get, 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* GPIO 0-15 are read in the GPE0_STS PM register */ 2918c2ecf20Sopenharmony_ci .uses_gpe0 = true, 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci .ngpio = 50, 2948c2ecf20Sopenharmony_ci .have_blink = true, 2958c2ecf20Sopenharmony_ci .regs = ichx_regs, 2968c2ecf20Sopenharmony_ci .reglen = ichx_reglen, 2978c2ecf20Sopenharmony_ci}; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci/* Intel 3100 */ 3008c2ecf20Sopenharmony_cistatic struct ichx_desc i3100_desc = { 3018c2ecf20Sopenharmony_ci /* 3028c2ecf20Sopenharmony_ci * Bits 16,17, 20 of USE_SEL and bit 16 of USE_SEL2 always read 0 on 3038c2ecf20Sopenharmony_ci * the Intel 3100. See "Table 712. GPIO Summary Table" of 3100 3048c2ecf20Sopenharmony_ci * Datasheet for more info. 3058c2ecf20Sopenharmony_ci */ 3068c2ecf20Sopenharmony_ci .use_sel_ignore = {0x00130000, 0x00010000, 0x0}, 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* The 3100 needs fixups for GPIO 0 - 17 */ 3098c2ecf20Sopenharmony_ci .request = ich6_gpio_request, 3108c2ecf20Sopenharmony_ci .get = ich6_gpio_get, 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci /* GPIO 0-15 are read in the GPE0_STS PM register */ 3138c2ecf20Sopenharmony_ci .uses_gpe0 = true, 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci .ngpio = 50, 3168c2ecf20Sopenharmony_ci .regs = ichx_regs, 3178c2ecf20Sopenharmony_ci .reglen = ichx_reglen, 3188c2ecf20Sopenharmony_ci}; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci/* ICH7 and ICH8-based */ 3218c2ecf20Sopenharmony_cistatic struct ichx_desc ich7_desc = { 3228c2ecf20Sopenharmony_ci .ngpio = 50, 3238c2ecf20Sopenharmony_ci .have_blink = true, 3248c2ecf20Sopenharmony_ci .regs = ichx_regs, 3258c2ecf20Sopenharmony_ci .reglen = ichx_reglen, 3268c2ecf20Sopenharmony_ci}; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci/* ICH9-based */ 3298c2ecf20Sopenharmony_cistatic struct ichx_desc ich9_desc = { 3308c2ecf20Sopenharmony_ci .ngpio = 61, 3318c2ecf20Sopenharmony_ci .have_blink = true, 3328c2ecf20Sopenharmony_ci .regs = ichx_regs, 3338c2ecf20Sopenharmony_ci .reglen = ichx_reglen, 3348c2ecf20Sopenharmony_ci}; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci/* ICH10-based - Consumer/corporate versions have different amount of GPIO */ 3378c2ecf20Sopenharmony_cistatic struct ichx_desc ich10_cons_desc = { 3388c2ecf20Sopenharmony_ci .ngpio = 61, 3398c2ecf20Sopenharmony_ci .have_blink = true, 3408c2ecf20Sopenharmony_ci .regs = ichx_regs, 3418c2ecf20Sopenharmony_ci .reglen = ichx_reglen, 3428c2ecf20Sopenharmony_ci}; 3438c2ecf20Sopenharmony_cistatic struct ichx_desc ich10_corp_desc = { 3448c2ecf20Sopenharmony_ci .ngpio = 72, 3458c2ecf20Sopenharmony_ci .have_blink = true, 3468c2ecf20Sopenharmony_ci .regs = ichx_regs, 3478c2ecf20Sopenharmony_ci .reglen = ichx_reglen, 3488c2ecf20Sopenharmony_ci}; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci/* Intel 5 series, 6 series, 3400 series, and C200 series */ 3518c2ecf20Sopenharmony_cistatic struct ichx_desc intel5_desc = { 3528c2ecf20Sopenharmony_ci .ngpio = 76, 3538c2ecf20Sopenharmony_ci .regs = ichx_regs, 3548c2ecf20Sopenharmony_ci .reglen = ichx_reglen, 3558c2ecf20Sopenharmony_ci}; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci/* Avoton */ 3588c2ecf20Sopenharmony_cistatic struct ichx_desc avoton_desc = { 3598c2ecf20Sopenharmony_ci /* Avoton has only 59 GPIOs, but we assume the first set of register 3608c2ecf20Sopenharmony_ci * (Core) has 32 instead of 31 to keep gpio-ich compliance 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci .ngpio = 60, 3638c2ecf20Sopenharmony_ci .regs = avoton_regs, 3648c2ecf20Sopenharmony_ci .reglen = avoton_reglen, 3658c2ecf20Sopenharmony_ci .use_outlvl_cache = true, 3668c2ecf20Sopenharmony_ci}; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_cistatic int ichx_gpio_request_regions(struct device *dev, 3698c2ecf20Sopenharmony_ci struct resource *res_base, const char *name, u8 use_gpio) 3708c2ecf20Sopenharmony_ci{ 3718c2ecf20Sopenharmony_ci int i; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (!res_base || !res_base->start || !res_base->end) 3748c2ecf20Sopenharmony_ci return -ENODEV; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(ichx_priv.desc->regs[0]); i++) { 3778c2ecf20Sopenharmony_ci if (!(use_gpio & BIT(i))) 3788c2ecf20Sopenharmony_ci continue; 3798c2ecf20Sopenharmony_ci if (!devm_request_region(dev, 3808c2ecf20Sopenharmony_ci res_base->start + ichx_priv.desc->regs[0][i], 3818c2ecf20Sopenharmony_ci ichx_priv.desc->reglen[i], name)) 3828c2ecf20Sopenharmony_ci return -EBUSY; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci return 0; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_cistatic int ichx_gpio_probe(struct platform_device *pdev) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 3908c2ecf20Sopenharmony_ci struct lpc_ich_info *ich_info = dev_get_platdata(dev); 3918c2ecf20Sopenharmony_ci struct resource *res_base, *res_pm; 3928c2ecf20Sopenharmony_ci int err; 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci if (!ich_info) 3958c2ecf20Sopenharmony_ci return -ENODEV; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci switch (ich_info->gpio_version) { 3988c2ecf20Sopenharmony_ci case ICH_I3100_GPIO: 3998c2ecf20Sopenharmony_ci ichx_priv.desc = &i3100_desc; 4008c2ecf20Sopenharmony_ci break; 4018c2ecf20Sopenharmony_ci case ICH_V5_GPIO: 4028c2ecf20Sopenharmony_ci ichx_priv.desc = &intel5_desc; 4038c2ecf20Sopenharmony_ci break; 4048c2ecf20Sopenharmony_ci case ICH_V6_GPIO: 4058c2ecf20Sopenharmony_ci ichx_priv.desc = &ich6_desc; 4068c2ecf20Sopenharmony_ci break; 4078c2ecf20Sopenharmony_ci case ICH_V7_GPIO: 4088c2ecf20Sopenharmony_ci ichx_priv.desc = &ich7_desc; 4098c2ecf20Sopenharmony_ci break; 4108c2ecf20Sopenharmony_ci case ICH_V9_GPIO: 4118c2ecf20Sopenharmony_ci ichx_priv.desc = &ich9_desc; 4128c2ecf20Sopenharmony_ci break; 4138c2ecf20Sopenharmony_ci case ICH_V10CORP_GPIO: 4148c2ecf20Sopenharmony_ci ichx_priv.desc = &ich10_corp_desc; 4158c2ecf20Sopenharmony_ci break; 4168c2ecf20Sopenharmony_ci case ICH_V10CONS_GPIO: 4178c2ecf20Sopenharmony_ci ichx_priv.desc = &ich10_cons_desc; 4188c2ecf20Sopenharmony_ci break; 4198c2ecf20Sopenharmony_ci case AVOTON_GPIO: 4208c2ecf20Sopenharmony_ci ichx_priv.desc = &avoton_desc; 4218c2ecf20Sopenharmony_ci break; 4228c2ecf20Sopenharmony_ci default: 4238c2ecf20Sopenharmony_ci return -ENODEV; 4248c2ecf20Sopenharmony_ci } 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci ichx_priv.dev = dev; 4278c2ecf20Sopenharmony_ci spin_lock_init(&ichx_priv.lock); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci res_base = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPIO); 4308c2ecf20Sopenharmony_ci err = ichx_gpio_request_regions(dev, res_base, pdev->name, 4318c2ecf20Sopenharmony_ci ich_info->use_gpio); 4328c2ecf20Sopenharmony_ci if (err) 4338c2ecf20Sopenharmony_ci return err; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci ichx_priv.gpio_base = res_base; 4368c2ecf20Sopenharmony_ci ichx_priv.use_gpio = ich_info->use_gpio; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci /* 4398c2ecf20Sopenharmony_ci * If necessary, determine the I/O address of ACPI/power management 4408c2ecf20Sopenharmony_ci * registers which are needed to read the GPE0 register for GPI pins 4418c2ecf20Sopenharmony_ci * 0 - 15 on some chipsets. 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_ci if (!ichx_priv.desc->uses_gpe0) 4448c2ecf20Sopenharmony_ci goto init; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci res_pm = platform_get_resource(pdev, IORESOURCE_IO, ICH_RES_GPE0); 4478c2ecf20Sopenharmony_ci if (!res_pm) { 4488c2ecf20Sopenharmony_ci dev_warn(dev, "ACPI BAR is unavailable, GPI 0 - 15 unavailable\n"); 4498c2ecf20Sopenharmony_ci goto init; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci if (!devm_request_region(dev, res_pm->start, resource_size(res_pm), 4538c2ecf20Sopenharmony_ci pdev->name)) { 4548c2ecf20Sopenharmony_ci dev_warn(dev, "ACPI BAR is busy, GPI 0 - 15 unavailable\n"); 4558c2ecf20Sopenharmony_ci goto init; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci ichx_priv.pm_base = res_pm; 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ciinit: 4618c2ecf20Sopenharmony_ci ichx_gpiolib_setup(&ichx_priv.chip); 4628c2ecf20Sopenharmony_ci err = gpiochip_add_data(&ichx_priv.chip, NULL); 4638c2ecf20Sopenharmony_ci if (err) { 4648c2ecf20Sopenharmony_ci dev_err(dev, "Failed to register GPIOs\n"); 4658c2ecf20Sopenharmony_ci return err; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci dev_info(dev, "GPIO from %d to %d\n", ichx_priv.chip.base, 4698c2ecf20Sopenharmony_ci ichx_priv.chip.base + ichx_priv.chip.ngpio - 1); 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci return 0; 4728c2ecf20Sopenharmony_ci} 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_cistatic int ichx_gpio_remove(struct platform_device *pdev) 4758c2ecf20Sopenharmony_ci{ 4768c2ecf20Sopenharmony_ci gpiochip_remove(&ichx_priv.chip); 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci return 0; 4798c2ecf20Sopenharmony_ci} 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_cistatic struct platform_driver ichx_gpio_driver = { 4828c2ecf20Sopenharmony_ci .driver = { 4838c2ecf20Sopenharmony_ci .name = DRV_NAME, 4848c2ecf20Sopenharmony_ci }, 4858c2ecf20Sopenharmony_ci .probe = ichx_gpio_probe, 4868c2ecf20Sopenharmony_ci .remove = ichx_gpio_remove, 4878c2ecf20Sopenharmony_ci}; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_cimodule_platform_driver(ichx_gpio_driver); 4908c2ecf20Sopenharmony_ci 4918c2ecf20Sopenharmony_ciMODULE_AUTHOR("Peter Tyser <ptyser@xes-inc.com>"); 4928c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("GPIO interface for Intel ICH series"); 4938c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 4948c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:"DRV_NAME); 495