18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Intel MID GPIO driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2008-2014,2016 Intel Corporation. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci/* Supports: 98c2ecf20Sopenharmony_ci * Moorestown platform Langwell chip. 108c2ecf20Sopenharmony_ci * Medfield platform Penwell chip. 118c2ecf20Sopenharmony_ci * Clovertrail platform Cloverview chip. 128c2ecf20Sopenharmony_ci */ 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include <linux/delay.h> 158c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 168c2ecf20Sopenharmony_ci#include <linux/init.h> 178c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 188c2ecf20Sopenharmony_ci#include <linux/io.h> 198c2ecf20Sopenharmony_ci#include <linux/kernel.h> 208c2ecf20Sopenharmony_ci#include <linux/pci.h> 218c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 228c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 238c2ecf20Sopenharmony_ci#include <linux/slab.h> 248c2ecf20Sopenharmony_ci#include <linux/stddef.h> 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define INTEL_MID_IRQ_TYPE_EDGE (1 << 0) 278c2ecf20Sopenharmony_ci#define INTEL_MID_IRQ_TYPE_LEVEL (1 << 1) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* 308c2ecf20Sopenharmony_ci * Langwell chip has 64 pins and thus there are 2 32bit registers to control 318c2ecf20Sopenharmony_ci * each feature, while Penwell chip has 96 pins for each block, and need 3 32bit 328c2ecf20Sopenharmony_ci * registers to control them, so we only define the order here instead of a 338c2ecf20Sopenharmony_ci * structure, to get a bit offset for a pin (use GPDR as an example): 348c2ecf20Sopenharmony_ci * 358c2ecf20Sopenharmony_ci * nreg = ngpio / 32; 368c2ecf20Sopenharmony_ci * reg = offset / 32; 378c2ecf20Sopenharmony_ci * bit = offset % 32; 388c2ecf20Sopenharmony_ci * reg_addr = reg_base + GPDR * nreg * 4 + reg * 4; 398c2ecf20Sopenharmony_ci * 408c2ecf20Sopenharmony_ci * so the bit of reg_addr is to control pin offset's GPDR feature 418c2ecf20Sopenharmony_ci*/ 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cienum GPIO_REG { 448c2ecf20Sopenharmony_ci GPLR = 0, /* pin level read-only */ 458c2ecf20Sopenharmony_ci GPDR, /* pin direction */ 468c2ecf20Sopenharmony_ci GPSR, /* pin set */ 478c2ecf20Sopenharmony_ci GPCR, /* pin clear */ 488c2ecf20Sopenharmony_ci GRER, /* rising edge detect */ 498c2ecf20Sopenharmony_ci GFER, /* falling edge detect */ 508c2ecf20Sopenharmony_ci GEDR, /* edge detect result */ 518c2ecf20Sopenharmony_ci GAFR, /* alt function */ 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* intel_mid gpio driver data */ 558c2ecf20Sopenharmony_cistruct intel_mid_gpio_ddata { 568c2ecf20Sopenharmony_ci u16 ngpio; /* number of gpio pins */ 578c2ecf20Sopenharmony_ci u32 chip_irq_type; /* chip interrupt type */ 588c2ecf20Sopenharmony_ci}; 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct intel_mid_gpio { 618c2ecf20Sopenharmony_ci struct gpio_chip chip; 628c2ecf20Sopenharmony_ci void __iomem *reg_base; 638c2ecf20Sopenharmony_ci spinlock_t lock; 648c2ecf20Sopenharmony_ci struct pci_dev *pdev; 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic void __iomem *gpio_reg(struct gpio_chip *chip, unsigned offset, 688c2ecf20Sopenharmony_ci enum GPIO_REG reg_type) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct intel_mid_gpio *priv = gpiochip_get_data(chip); 718c2ecf20Sopenharmony_ci unsigned nreg = chip->ngpio / 32; 728c2ecf20Sopenharmony_ci u8 reg = offset / 32; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci return priv->reg_base + reg_type * nreg * 4 + reg * 4; 758c2ecf20Sopenharmony_ci} 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_cistatic void __iomem *gpio_reg_2bit(struct gpio_chip *chip, unsigned offset, 788c2ecf20Sopenharmony_ci enum GPIO_REG reg_type) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci struct intel_mid_gpio *priv = gpiochip_get_data(chip); 818c2ecf20Sopenharmony_ci unsigned nreg = chip->ngpio / 32; 828c2ecf20Sopenharmony_ci u8 reg = offset / 16; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci return priv->reg_base + reg_type * nreg * 4 + reg * 4; 858c2ecf20Sopenharmony_ci} 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_cistatic int intel_gpio_request(struct gpio_chip *chip, unsigned offset) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci void __iomem *gafr = gpio_reg_2bit(chip, offset, GAFR); 908c2ecf20Sopenharmony_ci u32 value = readl(gafr); 918c2ecf20Sopenharmony_ci int shift = (offset % 16) << 1, af = (value >> shift) & 3; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (af) { 948c2ecf20Sopenharmony_ci value &= ~(3 << shift); 958c2ecf20Sopenharmony_ci writel(value, gafr); 968c2ecf20Sopenharmony_ci } 978c2ecf20Sopenharmony_ci return 0; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int intel_gpio_get(struct gpio_chip *chip, unsigned offset) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci void __iomem *gplr = gpio_reg(chip, offset, GPLR); 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci return !!(readl(gplr) & BIT(offset % 32)); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic void intel_gpio_set(struct gpio_chip *chip, unsigned offset, int value) 1088c2ecf20Sopenharmony_ci{ 1098c2ecf20Sopenharmony_ci void __iomem *gpsr, *gpcr; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (value) { 1128c2ecf20Sopenharmony_ci gpsr = gpio_reg(chip, offset, GPSR); 1138c2ecf20Sopenharmony_ci writel(BIT(offset % 32), gpsr); 1148c2ecf20Sopenharmony_ci } else { 1158c2ecf20Sopenharmony_ci gpcr = gpio_reg(chip, offset, GPCR); 1168c2ecf20Sopenharmony_ci writel(BIT(offset % 32), gpcr); 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic int intel_gpio_direction_input(struct gpio_chip *chip, unsigned offset) 1218c2ecf20Sopenharmony_ci{ 1228c2ecf20Sopenharmony_ci struct intel_mid_gpio *priv = gpiochip_get_data(chip); 1238c2ecf20Sopenharmony_ci void __iomem *gpdr = gpio_reg(chip, offset, GPDR); 1248c2ecf20Sopenharmony_ci u32 value; 1258c2ecf20Sopenharmony_ci unsigned long flags; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci if (priv->pdev) 1288c2ecf20Sopenharmony_ci pm_runtime_get(&priv->pdev->dev); 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 1318c2ecf20Sopenharmony_ci value = readl(gpdr); 1328c2ecf20Sopenharmony_ci value &= ~BIT(offset % 32); 1338c2ecf20Sopenharmony_ci writel(value, gpdr); 1348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (priv->pdev) 1378c2ecf20Sopenharmony_ci pm_runtime_put(&priv->pdev->dev); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci return 0; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int intel_gpio_direction_output(struct gpio_chip *chip, 1438c2ecf20Sopenharmony_ci unsigned offset, int value) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct intel_mid_gpio *priv = gpiochip_get_data(chip); 1468c2ecf20Sopenharmony_ci void __iomem *gpdr = gpio_reg(chip, offset, GPDR); 1478c2ecf20Sopenharmony_ci unsigned long flags; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci intel_gpio_set(chip, offset, value); 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci if (priv->pdev) 1528c2ecf20Sopenharmony_ci pm_runtime_get(&priv->pdev->dev); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 1558c2ecf20Sopenharmony_ci value = readl(gpdr); 1568c2ecf20Sopenharmony_ci value |= BIT(offset % 32); 1578c2ecf20Sopenharmony_ci writel(value, gpdr); 1588c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci if (priv->pdev) 1618c2ecf20Sopenharmony_ci pm_runtime_put(&priv->pdev->dev); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci return 0; 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic int intel_mid_irq_type(struct irq_data *d, unsigned type) 1678c2ecf20Sopenharmony_ci{ 1688c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_data_get_irq_chip_data(d); 1698c2ecf20Sopenharmony_ci struct intel_mid_gpio *priv = gpiochip_get_data(gc); 1708c2ecf20Sopenharmony_ci u32 gpio = irqd_to_hwirq(d); 1718c2ecf20Sopenharmony_ci unsigned long flags; 1728c2ecf20Sopenharmony_ci u32 value; 1738c2ecf20Sopenharmony_ci void __iomem *grer = gpio_reg(&priv->chip, gpio, GRER); 1748c2ecf20Sopenharmony_ci void __iomem *gfer = gpio_reg(&priv->chip, gpio, GFER); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci if (gpio >= priv->chip.ngpio) 1778c2ecf20Sopenharmony_ci return -EINVAL; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci if (priv->pdev) 1808c2ecf20Sopenharmony_ci pm_runtime_get(&priv->pdev->dev); 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci spin_lock_irqsave(&priv->lock, flags); 1838c2ecf20Sopenharmony_ci if (type & IRQ_TYPE_EDGE_RISING) 1848c2ecf20Sopenharmony_ci value = readl(grer) | BIT(gpio % 32); 1858c2ecf20Sopenharmony_ci else 1868c2ecf20Sopenharmony_ci value = readl(grer) & (~BIT(gpio % 32)); 1878c2ecf20Sopenharmony_ci writel(value, grer); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (type & IRQ_TYPE_EDGE_FALLING) 1908c2ecf20Sopenharmony_ci value = readl(gfer) | BIT(gpio % 32); 1918c2ecf20Sopenharmony_ci else 1928c2ecf20Sopenharmony_ci value = readl(gfer) & (~BIT(gpio % 32)); 1938c2ecf20Sopenharmony_ci writel(value, gfer); 1948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&priv->lock, flags); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci if (priv->pdev) 1978c2ecf20Sopenharmony_ci pm_runtime_put(&priv->pdev->dev); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci return 0; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic void intel_mid_irq_unmask(struct irq_data *d) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic void intel_mid_irq_mask(struct irq_data *d) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic struct irq_chip intel_mid_irqchip = { 2118c2ecf20Sopenharmony_ci .name = "INTEL_MID-GPIO", 2128c2ecf20Sopenharmony_ci .irq_mask = intel_mid_irq_mask, 2138c2ecf20Sopenharmony_ci .irq_unmask = intel_mid_irq_unmask, 2148c2ecf20Sopenharmony_ci .irq_set_type = intel_mid_irq_type, 2158c2ecf20Sopenharmony_ci}; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_cistatic const struct intel_mid_gpio_ddata gpio_lincroft = { 2188c2ecf20Sopenharmony_ci .ngpio = 64, 2198c2ecf20Sopenharmony_ci}; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic const struct intel_mid_gpio_ddata gpio_penwell_aon = { 2228c2ecf20Sopenharmony_ci .ngpio = 96, 2238c2ecf20Sopenharmony_ci .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, 2248c2ecf20Sopenharmony_ci}; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic const struct intel_mid_gpio_ddata gpio_penwell_core = { 2278c2ecf20Sopenharmony_ci .ngpio = 96, 2288c2ecf20Sopenharmony_ci .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, 2298c2ecf20Sopenharmony_ci}; 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic const struct intel_mid_gpio_ddata gpio_cloverview_aon = { 2328c2ecf20Sopenharmony_ci .ngpio = 96, 2338c2ecf20Sopenharmony_ci .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE | INTEL_MID_IRQ_TYPE_LEVEL, 2348c2ecf20Sopenharmony_ci}; 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic const struct intel_mid_gpio_ddata gpio_cloverview_core = { 2378c2ecf20Sopenharmony_ci .ngpio = 96, 2388c2ecf20Sopenharmony_ci .chip_irq_type = INTEL_MID_IRQ_TYPE_EDGE, 2398c2ecf20Sopenharmony_ci}; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic const struct pci_device_id intel_gpio_ids[] = { 2428c2ecf20Sopenharmony_ci { 2438c2ecf20Sopenharmony_ci /* Lincroft */ 2448c2ecf20Sopenharmony_ci PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x080f), 2458c2ecf20Sopenharmony_ci .driver_data = (kernel_ulong_t)&gpio_lincroft, 2468c2ecf20Sopenharmony_ci }, 2478c2ecf20Sopenharmony_ci { 2488c2ecf20Sopenharmony_ci /* Penwell AON */ 2498c2ecf20Sopenharmony_ci PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081f), 2508c2ecf20Sopenharmony_ci .driver_data = (kernel_ulong_t)&gpio_penwell_aon, 2518c2ecf20Sopenharmony_ci }, 2528c2ecf20Sopenharmony_ci { 2538c2ecf20Sopenharmony_ci /* Penwell Core */ 2548c2ecf20Sopenharmony_ci PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x081a), 2558c2ecf20Sopenharmony_ci .driver_data = (kernel_ulong_t)&gpio_penwell_core, 2568c2ecf20Sopenharmony_ci }, 2578c2ecf20Sopenharmony_ci { 2588c2ecf20Sopenharmony_ci /* Cloverview Aon */ 2598c2ecf20Sopenharmony_ci PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08eb), 2608c2ecf20Sopenharmony_ci .driver_data = (kernel_ulong_t)&gpio_cloverview_aon, 2618c2ecf20Sopenharmony_ci }, 2628c2ecf20Sopenharmony_ci { 2638c2ecf20Sopenharmony_ci /* Cloverview Core */ 2648c2ecf20Sopenharmony_ci PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x08f7), 2658c2ecf20Sopenharmony_ci .driver_data = (kernel_ulong_t)&gpio_cloverview_core, 2668c2ecf20Sopenharmony_ci }, 2678c2ecf20Sopenharmony_ci { } 2688c2ecf20Sopenharmony_ci}; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_cistatic void intel_mid_irq_handler(struct irq_desc *desc) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci struct gpio_chip *gc = irq_desc_get_handler_data(desc); 2738c2ecf20Sopenharmony_ci struct intel_mid_gpio *priv = gpiochip_get_data(gc); 2748c2ecf20Sopenharmony_ci struct irq_data *data = irq_desc_get_irq_data(desc); 2758c2ecf20Sopenharmony_ci struct irq_chip *chip = irq_data_get_irq_chip(data); 2768c2ecf20Sopenharmony_ci u32 base, gpio, mask; 2778c2ecf20Sopenharmony_ci unsigned long pending; 2788c2ecf20Sopenharmony_ci void __iomem *gedr; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* check GPIO controller to check which pin triggered the interrupt */ 2818c2ecf20Sopenharmony_ci for (base = 0; base < priv->chip.ngpio; base += 32) { 2828c2ecf20Sopenharmony_ci gedr = gpio_reg(&priv->chip, base, GEDR); 2838c2ecf20Sopenharmony_ci while ((pending = readl(gedr))) { 2848c2ecf20Sopenharmony_ci gpio = __ffs(pending); 2858c2ecf20Sopenharmony_ci mask = BIT(gpio); 2868c2ecf20Sopenharmony_ci /* Clear before handling so we can't lose an edge */ 2878c2ecf20Sopenharmony_ci writel(mask, gedr); 2888c2ecf20Sopenharmony_ci generic_handle_irq(irq_find_mapping(gc->irq.domain, 2898c2ecf20Sopenharmony_ci base + gpio)); 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci chip->irq_eoi(data); 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic int intel_mid_irq_init_hw(struct gpio_chip *chip) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct intel_mid_gpio *priv = gpiochip_get_data(chip); 2998c2ecf20Sopenharmony_ci void __iomem *reg; 3008c2ecf20Sopenharmony_ci unsigned base; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci for (base = 0; base < priv->chip.ngpio; base += 32) { 3038c2ecf20Sopenharmony_ci /* Clear the rising-edge detect register */ 3048c2ecf20Sopenharmony_ci reg = gpio_reg(&priv->chip, base, GRER); 3058c2ecf20Sopenharmony_ci writel(0, reg); 3068c2ecf20Sopenharmony_ci /* Clear the falling-edge detect register */ 3078c2ecf20Sopenharmony_ci reg = gpio_reg(&priv->chip, base, GFER); 3088c2ecf20Sopenharmony_ci writel(0, reg); 3098c2ecf20Sopenharmony_ci /* Clear the edge detect status register */ 3108c2ecf20Sopenharmony_ci reg = gpio_reg(&priv->chip, base, GEDR); 3118c2ecf20Sopenharmony_ci writel(~0, reg); 3128c2ecf20Sopenharmony_ci } 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci return 0; 3158c2ecf20Sopenharmony_ci} 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic int __maybe_unused intel_gpio_runtime_idle(struct device *dev) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci int err = pm_schedule_suspend(dev, 500); 3208c2ecf20Sopenharmony_ci return err ?: -EBUSY; 3218c2ecf20Sopenharmony_ci} 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic const struct dev_pm_ops intel_gpio_pm_ops = { 3248c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(NULL, NULL, intel_gpio_runtime_idle) 3258c2ecf20Sopenharmony_ci}; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic int intel_gpio_probe(struct pci_dev *pdev, 3288c2ecf20Sopenharmony_ci const struct pci_device_id *id) 3298c2ecf20Sopenharmony_ci{ 3308c2ecf20Sopenharmony_ci void __iomem *base; 3318c2ecf20Sopenharmony_ci struct intel_mid_gpio *priv; 3328c2ecf20Sopenharmony_ci u32 gpio_base; 3338c2ecf20Sopenharmony_ci u32 irq_base; 3348c2ecf20Sopenharmony_ci int retval; 3358c2ecf20Sopenharmony_ci struct gpio_irq_chip *girq; 3368c2ecf20Sopenharmony_ci struct intel_mid_gpio_ddata *ddata = 3378c2ecf20Sopenharmony_ci (struct intel_mid_gpio_ddata *)id->driver_data; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci retval = pcim_enable_device(pdev); 3408c2ecf20Sopenharmony_ci if (retval) 3418c2ecf20Sopenharmony_ci return retval; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci retval = pcim_iomap_regions(pdev, 1 << 0 | 1 << 1, pci_name(pdev)); 3448c2ecf20Sopenharmony_ci if (retval) { 3458c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "I/O memory mapping error\n"); 3468c2ecf20Sopenharmony_ci return retval; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci base = pcim_iomap_table(pdev)[1]; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci irq_base = readl(base); 3528c2ecf20Sopenharmony_ci gpio_base = readl(sizeof(u32) + base); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci /* release the IO mapping, since we already get the info from bar1 */ 3558c2ecf20Sopenharmony_ci pcim_iounmap_regions(pdev, 1 << 1); 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); 3588c2ecf20Sopenharmony_ci if (!priv) 3598c2ecf20Sopenharmony_ci return -ENOMEM; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci priv->reg_base = pcim_iomap_table(pdev)[0]; 3628c2ecf20Sopenharmony_ci priv->chip.label = dev_name(&pdev->dev); 3638c2ecf20Sopenharmony_ci priv->chip.parent = &pdev->dev; 3648c2ecf20Sopenharmony_ci priv->chip.request = intel_gpio_request; 3658c2ecf20Sopenharmony_ci priv->chip.direction_input = intel_gpio_direction_input; 3668c2ecf20Sopenharmony_ci priv->chip.direction_output = intel_gpio_direction_output; 3678c2ecf20Sopenharmony_ci priv->chip.get = intel_gpio_get; 3688c2ecf20Sopenharmony_ci priv->chip.set = intel_gpio_set; 3698c2ecf20Sopenharmony_ci priv->chip.base = gpio_base; 3708c2ecf20Sopenharmony_ci priv->chip.ngpio = ddata->ngpio; 3718c2ecf20Sopenharmony_ci priv->chip.can_sleep = false; 3728c2ecf20Sopenharmony_ci priv->pdev = pdev; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci spin_lock_init(&priv->lock); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci girq = &priv->chip.irq; 3778c2ecf20Sopenharmony_ci girq->chip = &intel_mid_irqchip; 3788c2ecf20Sopenharmony_ci girq->init_hw = intel_mid_irq_init_hw; 3798c2ecf20Sopenharmony_ci girq->parent_handler = intel_mid_irq_handler; 3808c2ecf20Sopenharmony_ci girq->num_parents = 1; 3818c2ecf20Sopenharmony_ci girq->parents = devm_kcalloc(&pdev->dev, girq->num_parents, 3828c2ecf20Sopenharmony_ci sizeof(*girq->parents), 3838c2ecf20Sopenharmony_ci GFP_KERNEL); 3848c2ecf20Sopenharmony_ci if (!girq->parents) 3858c2ecf20Sopenharmony_ci return -ENOMEM; 3868c2ecf20Sopenharmony_ci girq->parents[0] = pdev->irq; 3878c2ecf20Sopenharmony_ci girq->first = irq_base; 3888c2ecf20Sopenharmony_ci girq->default_type = IRQ_TYPE_NONE; 3898c2ecf20Sopenharmony_ci girq->handler = handle_simple_irq; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, priv); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci retval = devm_gpiochip_add_data(&pdev->dev, &priv->chip, priv); 3948c2ecf20Sopenharmony_ci if (retval) { 3958c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "gpiochip_add error %d\n", retval); 3968c2ecf20Sopenharmony_ci return retval; 3978c2ecf20Sopenharmony_ci } 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci pm_runtime_put_noidle(&pdev->dev); 4008c2ecf20Sopenharmony_ci pm_runtime_allow(&pdev->dev); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci return 0; 4038c2ecf20Sopenharmony_ci} 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_cistatic struct pci_driver intel_gpio_driver = { 4068c2ecf20Sopenharmony_ci .name = "intel_mid_gpio", 4078c2ecf20Sopenharmony_ci .id_table = intel_gpio_ids, 4088c2ecf20Sopenharmony_ci .probe = intel_gpio_probe, 4098c2ecf20Sopenharmony_ci .driver = { 4108c2ecf20Sopenharmony_ci .pm = &intel_gpio_pm_ops, 4118c2ecf20Sopenharmony_ci }, 4128c2ecf20Sopenharmony_ci}; 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_cibuiltin_pci_driver(intel_gpio_driver); 415