18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci#include <linux/bits.h> 68c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h> 78c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 88c2ecf20Sopenharmony_ci#include <linux/irq.h> 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/pci.h> 128c2ecf20Sopenharmony_ci#include <linux/slab.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#define PCH_EDGE_FALLING 0 158c2ecf20Sopenharmony_ci#define PCH_EDGE_RISING 1 168c2ecf20Sopenharmony_ci#define PCH_LEVEL_L 2 178c2ecf20Sopenharmony_ci#define PCH_LEVEL_H 3 188c2ecf20Sopenharmony_ci#define PCH_EDGE_BOTH 4 198c2ecf20Sopenharmony_ci#define PCH_IM_MASK GENMASK(2, 0) 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define PCH_IRQ_BASE 24 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_cistruct pch_regs { 248c2ecf20Sopenharmony_ci u32 ien; 258c2ecf20Sopenharmony_ci u32 istatus; 268c2ecf20Sopenharmony_ci u32 idisp; 278c2ecf20Sopenharmony_ci u32 iclr; 288c2ecf20Sopenharmony_ci u32 imask; 298c2ecf20Sopenharmony_ci u32 imaskclr; 308c2ecf20Sopenharmony_ci u32 po; 318c2ecf20Sopenharmony_ci u32 pi; 328c2ecf20Sopenharmony_ci u32 pm; 338c2ecf20Sopenharmony_ci u32 im0; 348c2ecf20Sopenharmony_ci u32 im1; 358c2ecf20Sopenharmony_ci u32 reserved[3]; 368c2ecf20Sopenharmony_ci u32 gpio_use_sel; 378c2ecf20Sopenharmony_ci u32 reset; 388c2ecf20Sopenharmony_ci}; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cienum pch_type_t { 418c2ecf20Sopenharmony_ci INTEL_EG20T_PCH, 428c2ecf20Sopenharmony_ci OKISEMI_ML7223m_IOH, /* LAPIS Semiconductor ML7223 IOH PCIe Bus-m */ 438c2ecf20Sopenharmony_ci OKISEMI_ML7223n_IOH /* LAPIS Semiconductor ML7223 IOH PCIe Bus-n */ 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci/* Specifies number of GPIO PINS */ 478c2ecf20Sopenharmony_cistatic int gpio_pins[] = { 488c2ecf20Sopenharmony_ci [INTEL_EG20T_PCH] = 12, 498c2ecf20Sopenharmony_ci [OKISEMI_ML7223m_IOH] = 8, 508c2ecf20Sopenharmony_ci [OKISEMI_ML7223n_IOH] = 8, 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci/** 548c2ecf20Sopenharmony_ci * struct pch_gpio_reg_data - The register store data. 558c2ecf20Sopenharmony_ci * @ien_reg: To store contents of IEN register. 568c2ecf20Sopenharmony_ci * @imask_reg: To store contents of IMASK register. 578c2ecf20Sopenharmony_ci * @po_reg: To store contents of PO register. 588c2ecf20Sopenharmony_ci * @pm_reg: To store contents of PM register. 598c2ecf20Sopenharmony_ci * @im0_reg: To store contents of IM0 register. 608c2ecf20Sopenharmony_ci * @im1_reg: To store contents of IM1 register. 618c2ecf20Sopenharmony_ci * @gpio_use_sel_reg : To store contents of GPIO_USE_SEL register. 628c2ecf20Sopenharmony_ci * (Only ML7223 Bus-n) 638c2ecf20Sopenharmony_ci */ 648c2ecf20Sopenharmony_cistruct pch_gpio_reg_data { 658c2ecf20Sopenharmony_ci u32 ien_reg; 668c2ecf20Sopenharmony_ci u32 imask_reg; 678c2ecf20Sopenharmony_ci u32 po_reg; 688c2ecf20Sopenharmony_ci u32 pm_reg; 698c2ecf20Sopenharmony_ci u32 im0_reg; 708c2ecf20Sopenharmony_ci u32 im1_reg; 718c2ecf20Sopenharmony_ci u32 gpio_use_sel_reg; 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/** 758c2ecf20Sopenharmony_ci * struct pch_gpio - GPIO private data structure. 768c2ecf20Sopenharmony_ci * @base: PCI base address of Memory mapped I/O register. 778c2ecf20Sopenharmony_ci * @reg: Memory mapped PCH GPIO register list. 788c2ecf20Sopenharmony_ci * @dev: Pointer to device structure. 798c2ecf20Sopenharmony_ci * @gpio: Data for GPIO infrastructure. 808c2ecf20Sopenharmony_ci * @pch_gpio_reg: Memory mapped Register data is saved here 818c2ecf20Sopenharmony_ci * when suspend. 828c2ecf20Sopenharmony_ci * @lock: Used for register access protection 838c2ecf20Sopenharmony_ci * @irq_base: Save base of IRQ number for interrupt 848c2ecf20Sopenharmony_ci * @ioh: IOH ID 858c2ecf20Sopenharmony_ci * @spinlock: Used for register access protection 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_cistruct pch_gpio { 888c2ecf20Sopenharmony_ci void __iomem *base; 898c2ecf20Sopenharmony_ci struct pch_regs __iomem *reg; 908c2ecf20Sopenharmony_ci struct device *dev; 918c2ecf20Sopenharmony_ci struct gpio_chip gpio; 928c2ecf20Sopenharmony_ci struct pch_gpio_reg_data pch_gpio_reg; 938c2ecf20Sopenharmony_ci int irq_base; 948c2ecf20Sopenharmony_ci enum pch_type_t ioh; 958c2ecf20Sopenharmony_ci spinlock_t spinlock; 968c2ecf20Sopenharmony_ci}; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_cistatic void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val) 998c2ecf20Sopenharmony_ci{ 1008c2ecf20Sopenharmony_ci u32 reg_val; 1018c2ecf20Sopenharmony_ci struct pch_gpio *chip = gpiochip_get_data(gpio); 1028c2ecf20Sopenharmony_ci unsigned long flags; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci spin_lock_irqsave(&chip->spinlock, flags); 1058c2ecf20Sopenharmony_ci reg_val = ioread32(&chip->reg->po); 1068c2ecf20Sopenharmony_ci if (val) 1078c2ecf20Sopenharmony_ci reg_val |= BIT(nr); 1088c2ecf20Sopenharmony_ci else 1098c2ecf20Sopenharmony_ci reg_val &= ~BIT(nr); 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci iowrite32(reg_val, &chip->reg->po); 1128c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chip->spinlock, flags); 1138c2ecf20Sopenharmony_ci} 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_cistatic int pch_gpio_get(struct gpio_chip *gpio, unsigned int nr) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci struct pch_gpio *chip = gpiochip_get_data(gpio); 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci return !!(ioread32(&chip->reg->pi) & BIT(nr)); 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr, 1238c2ecf20Sopenharmony_ci int val) 1248c2ecf20Sopenharmony_ci{ 1258c2ecf20Sopenharmony_ci struct pch_gpio *chip = gpiochip_get_data(gpio); 1268c2ecf20Sopenharmony_ci u32 pm; 1278c2ecf20Sopenharmony_ci u32 reg_val; 1288c2ecf20Sopenharmony_ci unsigned long flags; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci spin_lock_irqsave(&chip->spinlock, flags); 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci reg_val = ioread32(&chip->reg->po); 1338c2ecf20Sopenharmony_ci if (val) 1348c2ecf20Sopenharmony_ci reg_val |= BIT(nr); 1358c2ecf20Sopenharmony_ci else 1368c2ecf20Sopenharmony_ci reg_val &= ~BIT(nr); 1378c2ecf20Sopenharmony_ci iowrite32(reg_val, &chip->reg->po); 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci pm = ioread32(&chip->reg->pm); 1408c2ecf20Sopenharmony_ci pm &= BIT(gpio_pins[chip->ioh]) - 1; 1418c2ecf20Sopenharmony_ci pm |= BIT(nr); 1428c2ecf20Sopenharmony_ci iowrite32(pm, &chip->reg->pm); 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chip->spinlock, flags); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci return 0; 1478c2ecf20Sopenharmony_ci} 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_cistatic int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr) 1508c2ecf20Sopenharmony_ci{ 1518c2ecf20Sopenharmony_ci struct pch_gpio *chip = gpiochip_get_data(gpio); 1528c2ecf20Sopenharmony_ci u32 pm; 1538c2ecf20Sopenharmony_ci unsigned long flags; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci spin_lock_irqsave(&chip->spinlock, flags); 1568c2ecf20Sopenharmony_ci pm = ioread32(&chip->reg->pm); 1578c2ecf20Sopenharmony_ci pm &= BIT(gpio_pins[chip->ioh]) - 1; 1588c2ecf20Sopenharmony_ci pm &= ~BIT(nr); 1598c2ecf20Sopenharmony_ci iowrite32(pm, &chip->reg->pm); 1608c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chip->spinlock, flags); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/* 1668c2ecf20Sopenharmony_ci * Save register configuration and disable interrupts. 1678c2ecf20Sopenharmony_ci */ 1688c2ecf20Sopenharmony_cistatic void __maybe_unused pch_gpio_save_reg_conf(struct pch_gpio *chip) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci chip->pch_gpio_reg.ien_reg = ioread32(&chip->reg->ien); 1718c2ecf20Sopenharmony_ci chip->pch_gpio_reg.imask_reg = ioread32(&chip->reg->imask); 1728c2ecf20Sopenharmony_ci chip->pch_gpio_reg.po_reg = ioread32(&chip->reg->po); 1738c2ecf20Sopenharmony_ci chip->pch_gpio_reg.pm_reg = ioread32(&chip->reg->pm); 1748c2ecf20Sopenharmony_ci chip->pch_gpio_reg.im0_reg = ioread32(&chip->reg->im0); 1758c2ecf20Sopenharmony_ci if (chip->ioh == INTEL_EG20T_PCH) 1768c2ecf20Sopenharmony_ci chip->pch_gpio_reg.im1_reg = ioread32(&chip->reg->im1); 1778c2ecf20Sopenharmony_ci if (chip->ioh == OKISEMI_ML7223n_IOH) 1788c2ecf20Sopenharmony_ci chip->pch_gpio_reg.gpio_use_sel_reg = ioread32(&chip->reg->gpio_use_sel); 1798c2ecf20Sopenharmony_ci} 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci/* 1828c2ecf20Sopenharmony_ci * This function restores the register configuration of the GPIO device. 1838c2ecf20Sopenharmony_ci */ 1848c2ecf20Sopenharmony_cistatic void __maybe_unused pch_gpio_restore_reg_conf(struct pch_gpio *chip) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci iowrite32(chip->pch_gpio_reg.ien_reg, &chip->reg->ien); 1878c2ecf20Sopenharmony_ci iowrite32(chip->pch_gpio_reg.imask_reg, &chip->reg->imask); 1888c2ecf20Sopenharmony_ci /* to store contents of PO register */ 1898c2ecf20Sopenharmony_ci iowrite32(chip->pch_gpio_reg.po_reg, &chip->reg->po); 1908c2ecf20Sopenharmony_ci /* to store contents of PM register */ 1918c2ecf20Sopenharmony_ci iowrite32(chip->pch_gpio_reg.pm_reg, &chip->reg->pm); 1928c2ecf20Sopenharmony_ci iowrite32(chip->pch_gpio_reg.im0_reg, &chip->reg->im0); 1938c2ecf20Sopenharmony_ci if (chip->ioh == INTEL_EG20T_PCH) 1948c2ecf20Sopenharmony_ci iowrite32(chip->pch_gpio_reg.im1_reg, &chip->reg->im1); 1958c2ecf20Sopenharmony_ci if (chip->ioh == OKISEMI_ML7223n_IOH) 1968c2ecf20Sopenharmony_ci iowrite32(chip->pch_gpio_reg.gpio_use_sel_reg, &chip->reg->gpio_use_sel); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_cistatic int pch_gpio_to_irq(struct gpio_chip *gpio, unsigned int offset) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci struct pch_gpio *chip = gpiochip_get_data(gpio); 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return chip->irq_base + offset; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistatic void pch_gpio_setup(struct pch_gpio *chip) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct gpio_chip *gpio = &chip->gpio; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci gpio->label = dev_name(chip->dev); 2118c2ecf20Sopenharmony_ci gpio->parent = chip->dev; 2128c2ecf20Sopenharmony_ci gpio->owner = THIS_MODULE; 2138c2ecf20Sopenharmony_ci gpio->direction_input = pch_gpio_direction_input; 2148c2ecf20Sopenharmony_ci gpio->get = pch_gpio_get; 2158c2ecf20Sopenharmony_ci gpio->direction_output = pch_gpio_direction_output; 2168c2ecf20Sopenharmony_ci gpio->set = pch_gpio_set; 2178c2ecf20Sopenharmony_ci gpio->base = -1; 2188c2ecf20Sopenharmony_ci gpio->ngpio = gpio_pins[chip->ioh]; 2198c2ecf20Sopenharmony_ci gpio->can_sleep = false; 2208c2ecf20Sopenharmony_ci gpio->to_irq = pch_gpio_to_irq; 2218c2ecf20Sopenharmony_ci} 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_cistatic int pch_irq_type(struct irq_data *d, unsigned int type) 2248c2ecf20Sopenharmony_ci{ 2258c2ecf20Sopenharmony_ci struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 2268c2ecf20Sopenharmony_ci struct pch_gpio *chip = gc->private; 2278c2ecf20Sopenharmony_ci u32 im, im_pos, val; 2288c2ecf20Sopenharmony_ci u32 __iomem *im_reg; 2298c2ecf20Sopenharmony_ci unsigned long flags; 2308c2ecf20Sopenharmony_ci int ch, irq = d->irq; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci ch = irq - chip->irq_base; 2338c2ecf20Sopenharmony_ci if (irq < chip->irq_base + 8) { 2348c2ecf20Sopenharmony_ci im_reg = &chip->reg->im0; 2358c2ecf20Sopenharmony_ci im_pos = ch - 0; 2368c2ecf20Sopenharmony_ci } else { 2378c2ecf20Sopenharmony_ci im_reg = &chip->reg->im1; 2388c2ecf20Sopenharmony_ci im_pos = ch - 8; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci dev_dbg(chip->dev, "irq=%d type=%d ch=%d pos=%d\n", irq, type, ch, im_pos); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci switch (type) { 2438c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 2448c2ecf20Sopenharmony_ci val = PCH_EDGE_RISING; 2458c2ecf20Sopenharmony_ci break; 2468c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 2478c2ecf20Sopenharmony_ci val = PCH_EDGE_FALLING; 2488c2ecf20Sopenharmony_ci break; 2498c2ecf20Sopenharmony_ci case IRQ_TYPE_EDGE_BOTH: 2508c2ecf20Sopenharmony_ci val = PCH_EDGE_BOTH; 2518c2ecf20Sopenharmony_ci break; 2528c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 2538c2ecf20Sopenharmony_ci val = PCH_LEVEL_H; 2548c2ecf20Sopenharmony_ci break; 2558c2ecf20Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 2568c2ecf20Sopenharmony_ci val = PCH_LEVEL_L; 2578c2ecf20Sopenharmony_ci break; 2588c2ecf20Sopenharmony_ci default: 2598c2ecf20Sopenharmony_ci return 0; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci spin_lock_irqsave(&chip->spinlock, flags); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci /* Set interrupt mode */ 2658c2ecf20Sopenharmony_ci im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4)); 2668c2ecf20Sopenharmony_ci iowrite32(im | (val << (im_pos * 4)), im_reg); 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci /* And the handler */ 2698c2ecf20Sopenharmony_ci if (type & IRQ_TYPE_LEVEL_MASK) 2708c2ecf20Sopenharmony_ci irq_set_handler_locked(d, handle_level_irq); 2718c2ecf20Sopenharmony_ci else if (type & IRQ_TYPE_EDGE_BOTH) 2728c2ecf20Sopenharmony_ci irq_set_handler_locked(d, handle_edge_irq); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chip->spinlock, flags); 2758c2ecf20Sopenharmony_ci return 0; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic void pch_irq_unmask(struct irq_data *d) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 2818c2ecf20Sopenharmony_ci struct pch_gpio *chip = gc->private; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci iowrite32(BIT(d->irq - chip->irq_base), &chip->reg->imaskclr); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic void pch_irq_mask(struct irq_data *d) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 2898c2ecf20Sopenharmony_ci struct pch_gpio *chip = gc->private; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci iowrite32(BIT(d->irq - chip->irq_base), &chip->reg->imask); 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_cistatic void pch_irq_ack(struct irq_data *d) 2958c2ecf20Sopenharmony_ci{ 2968c2ecf20Sopenharmony_ci struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 2978c2ecf20Sopenharmony_ci struct pch_gpio *chip = gc->private; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci iowrite32(BIT(d->irq - chip->irq_base), &chip->reg->iclr); 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic irqreturn_t pch_gpio_handler(int irq, void *dev_id) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct pch_gpio *chip = dev_id; 3058c2ecf20Sopenharmony_ci unsigned long reg_val = ioread32(&chip->reg->istatus); 3068c2ecf20Sopenharmony_ci int i; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci dev_vdbg(chip->dev, "irq=%d status=0x%lx\n", irq, reg_val); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci reg_val &= BIT(gpio_pins[chip->ioh]) - 1; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci for_each_set_bit(i, ®_val, gpio_pins[chip->ioh]) 3138c2ecf20Sopenharmony_ci generic_handle_irq(chip->irq_base + i); 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci return IRQ_RETVAL(reg_val); 3168c2ecf20Sopenharmony_ci} 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_cistatic int pch_gpio_alloc_generic_chip(struct pch_gpio *chip, 3198c2ecf20Sopenharmony_ci unsigned int irq_start, 3208c2ecf20Sopenharmony_ci unsigned int num) 3218c2ecf20Sopenharmony_ci{ 3228c2ecf20Sopenharmony_ci struct irq_chip_generic *gc; 3238c2ecf20Sopenharmony_ci struct irq_chip_type *ct; 3248c2ecf20Sopenharmony_ci int rv; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci gc = devm_irq_alloc_generic_chip(chip->dev, "pch_gpio", 1, irq_start, 3278c2ecf20Sopenharmony_ci chip->base, handle_simple_irq); 3288c2ecf20Sopenharmony_ci if (!gc) 3298c2ecf20Sopenharmony_ci return -ENOMEM; 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci gc->private = chip; 3328c2ecf20Sopenharmony_ci ct = gc->chip_types; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci ct->chip.irq_ack = pch_irq_ack; 3358c2ecf20Sopenharmony_ci ct->chip.irq_mask = pch_irq_mask; 3368c2ecf20Sopenharmony_ci ct->chip.irq_unmask = pch_irq_unmask; 3378c2ecf20Sopenharmony_ci ct->chip.irq_set_type = pch_irq_type; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci rv = devm_irq_setup_generic_chip(chip->dev, gc, IRQ_MSK(num), 3408c2ecf20Sopenharmony_ci IRQ_GC_INIT_MASK_CACHE, 3418c2ecf20Sopenharmony_ci IRQ_NOREQUEST | IRQ_NOPROBE, 0); 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return rv; 3448c2ecf20Sopenharmony_ci} 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_cistatic int pch_gpio_probe(struct pci_dev *pdev, 3478c2ecf20Sopenharmony_ci const struct pci_device_id *id) 3488c2ecf20Sopenharmony_ci{ 3498c2ecf20Sopenharmony_ci s32 ret; 3508c2ecf20Sopenharmony_ci struct pch_gpio *chip; 3518c2ecf20Sopenharmony_ci int irq_base; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL); 3548c2ecf20Sopenharmony_ci if (chip == NULL) 3558c2ecf20Sopenharmony_ci return -ENOMEM; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci chip->dev = &pdev->dev; 3588c2ecf20Sopenharmony_ci ret = pcim_enable_device(pdev); 3598c2ecf20Sopenharmony_ci if (ret) { 3608c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "pci_enable_device FAILED"); 3618c2ecf20Sopenharmony_ci return ret; 3628c2ecf20Sopenharmony_ci } 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci ret = pcim_iomap_regions(pdev, BIT(1), KBUILD_MODNAME); 3658c2ecf20Sopenharmony_ci if (ret) { 3668c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "pci_request_regions FAILED-%d", ret); 3678c2ecf20Sopenharmony_ci return ret; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci chip->base = pcim_iomap_table(pdev)[1]; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (pdev->device == 0x8803) 3738c2ecf20Sopenharmony_ci chip->ioh = INTEL_EG20T_PCH; 3748c2ecf20Sopenharmony_ci else if (pdev->device == 0x8014) 3758c2ecf20Sopenharmony_ci chip->ioh = OKISEMI_ML7223m_IOH; 3768c2ecf20Sopenharmony_ci else if (pdev->device == 0x8043) 3778c2ecf20Sopenharmony_ci chip->ioh = OKISEMI_ML7223n_IOH; 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci chip->reg = chip->base; 3808c2ecf20Sopenharmony_ci pci_set_drvdata(pdev, chip); 3818c2ecf20Sopenharmony_ci spin_lock_init(&chip->spinlock); 3828c2ecf20Sopenharmony_ci pch_gpio_setup(chip); 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci ret = devm_gpiochip_add_data(&pdev->dev, &chip->gpio, chip); 3858c2ecf20Sopenharmony_ci if (ret) { 3868c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "PCH gpio: Failed to register GPIO\n"); 3878c2ecf20Sopenharmony_ci return ret; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci irq_base = devm_irq_alloc_descs(&pdev->dev, -1, 0, 3918c2ecf20Sopenharmony_ci gpio_pins[chip->ioh], NUMA_NO_NODE); 3928c2ecf20Sopenharmony_ci if (irq_base < 0) { 3938c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "PCH gpio: Failed to get IRQ base num\n"); 3948c2ecf20Sopenharmony_ci chip->irq_base = -1; 3958c2ecf20Sopenharmony_ci return 0; 3968c2ecf20Sopenharmony_ci } 3978c2ecf20Sopenharmony_ci chip->irq_base = irq_base; 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_ci /* Mask all interrupts, but enable them */ 4008c2ecf20Sopenharmony_ci iowrite32(BIT(gpio_pins[chip->ioh]) - 1, &chip->reg->imask); 4018c2ecf20Sopenharmony_ci iowrite32(BIT(gpio_pins[chip->ioh]) - 1, &chip->reg->ien); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, pdev->irq, pch_gpio_handler, 4048c2ecf20Sopenharmony_ci IRQF_SHARED, KBUILD_MODNAME, chip); 4058c2ecf20Sopenharmony_ci if (ret) { 4068c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "request_irq failed\n"); 4078c2ecf20Sopenharmony_ci return ret; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci return pch_gpio_alloc_generic_chip(chip, irq_base, gpio_pins[chip->ioh]); 4118c2ecf20Sopenharmony_ci} 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_cistatic int __maybe_unused pch_gpio_suspend(struct device *dev) 4148c2ecf20Sopenharmony_ci{ 4158c2ecf20Sopenharmony_ci struct pch_gpio *chip = dev_get_drvdata(dev); 4168c2ecf20Sopenharmony_ci unsigned long flags; 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci spin_lock_irqsave(&chip->spinlock, flags); 4198c2ecf20Sopenharmony_ci pch_gpio_save_reg_conf(chip); 4208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chip->spinlock, flags); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci return 0; 4238c2ecf20Sopenharmony_ci} 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_cistatic int __maybe_unused pch_gpio_resume(struct device *dev) 4268c2ecf20Sopenharmony_ci{ 4278c2ecf20Sopenharmony_ci struct pch_gpio *chip = dev_get_drvdata(dev); 4288c2ecf20Sopenharmony_ci unsigned long flags; 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci spin_lock_irqsave(&chip->spinlock, flags); 4318c2ecf20Sopenharmony_ci iowrite32(0x01, &chip->reg->reset); 4328c2ecf20Sopenharmony_ci iowrite32(0x00, &chip->reg->reset); 4338c2ecf20Sopenharmony_ci pch_gpio_restore_reg_conf(chip); 4348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&chip->spinlock, flags); 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci return 0; 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(pch_gpio_pm_ops, pch_gpio_suspend, pch_gpio_resume); 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic const struct pci_device_id pch_gpio_pcidev_id[] = { 4428c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x8803) }, 4438c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8014) }, 4448c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8043) }, 4458c2ecf20Sopenharmony_ci { PCI_DEVICE(PCI_VENDOR_ID_ROHM, 0x8803) }, 4468c2ecf20Sopenharmony_ci { 0, } 4478c2ecf20Sopenharmony_ci}; 4488c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pch_gpio_pcidev_id); 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_cistatic struct pci_driver pch_gpio_driver = { 4518c2ecf20Sopenharmony_ci .name = "pch_gpio", 4528c2ecf20Sopenharmony_ci .id_table = pch_gpio_pcidev_id, 4538c2ecf20Sopenharmony_ci .probe = pch_gpio_probe, 4548c2ecf20Sopenharmony_ci .driver = { 4558c2ecf20Sopenharmony_ci .pm = &pch_gpio_pm_ops, 4568c2ecf20Sopenharmony_ci }, 4578c2ecf20Sopenharmony_ci}; 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_cimodule_pci_driver(pch_gpio_driver); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("PCH GPIO PCI Driver"); 4628c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 463