162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2011 LAPIS Semiconductor Co., Ltd. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#include <linux/bits.h> 662306a36Sopenharmony_ci#include <linux/gpio/driver.h> 762306a36Sopenharmony_ci#include <linux/interrupt.h> 862306a36Sopenharmony_ci#include <linux/irq.h> 962306a36Sopenharmony_ci#include <linux/kernel.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/pci.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define PCH_EDGE_FALLING 0 1562306a36Sopenharmony_ci#define PCH_EDGE_RISING 1 1662306a36Sopenharmony_ci#define PCH_LEVEL_L 2 1762306a36Sopenharmony_ci#define PCH_LEVEL_H 3 1862306a36Sopenharmony_ci#define PCH_EDGE_BOTH 4 1962306a36Sopenharmony_ci#define PCH_IM_MASK GENMASK(2, 0) 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define PCH_IRQ_BASE 24 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct pch_regs { 2462306a36Sopenharmony_ci u32 ien; 2562306a36Sopenharmony_ci u32 istatus; 2662306a36Sopenharmony_ci u32 idisp; 2762306a36Sopenharmony_ci u32 iclr; 2862306a36Sopenharmony_ci u32 imask; 2962306a36Sopenharmony_ci u32 imaskclr; 3062306a36Sopenharmony_ci u32 po; 3162306a36Sopenharmony_ci u32 pi; 3262306a36Sopenharmony_ci u32 pm; 3362306a36Sopenharmony_ci u32 im0; 3462306a36Sopenharmony_ci u32 im1; 3562306a36Sopenharmony_ci u32 reserved[3]; 3662306a36Sopenharmony_ci u32 gpio_use_sel; 3762306a36Sopenharmony_ci u32 reset; 3862306a36Sopenharmony_ci}; 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define PCI_DEVICE_ID_INTEL_EG20T_PCH 0x8803 4162306a36Sopenharmony_ci#define PCI_DEVICE_ID_ROHM_ML7223m_IOH 0x8014 4262306a36Sopenharmony_ci#define PCI_DEVICE_ID_ROHM_ML7223n_IOH 0x8043 4362306a36Sopenharmony_ci#define PCI_DEVICE_ID_ROHM_EG20T_PCH 0x8803 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cienum pch_type_t { 4662306a36Sopenharmony_ci INTEL_EG20T_PCH, 4762306a36Sopenharmony_ci OKISEMI_ML7223m_IOH, /* LAPIS Semiconductor ML7223 IOH PCIe Bus-m */ 4862306a36Sopenharmony_ci OKISEMI_ML7223n_IOH /* LAPIS Semiconductor ML7223 IOH PCIe Bus-n */ 4962306a36Sopenharmony_ci}; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/* Specifies number of GPIO PINS */ 5262306a36Sopenharmony_cistatic int gpio_pins[] = { 5362306a36Sopenharmony_ci [INTEL_EG20T_PCH] = 12, 5462306a36Sopenharmony_ci [OKISEMI_ML7223m_IOH] = 8, 5562306a36Sopenharmony_ci [OKISEMI_ML7223n_IOH] = 8, 5662306a36Sopenharmony_ci}; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci/** 5962306a36Sopenharmony_ci * struct pch_gpio_reg_data - The register store data. 6062306a36Sopenharmony_ci * @ien_reg: To store contents of IEN register. 6162306a36Sopenharmony_ci * @imask_reg: To store contents of IMASK register. 6262306a36Sopenharmony_ci * @po_reg: To store contents of PO register. 6362306a36Sopenharmony_ci * @pm_reg: To store contents of PM register. 6462306a36Sopenharmony_ci * @im0_reg: To store contents of IM0 register. 6562306a36Sopenharmony_ci * @im1_reg: To store contents of IM1 register. 6662306a36Sopenharmony_ci * @gpio_use_sel_reg : To store contents of GPIO_USE_SEL register. 6762306a36Sopenharmony_ci * (Only ML7223 Bus-n) 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_cistruct pch_gpio_reg_data { 7062306a36Sopenharmony_ci u32 ien_reg; 7162306a36Sopenharmony_ci u32 imask_reg; 7262306a36Sopenharmony_ci u32 po_reg; 7362306a36Sopenharmony_ci u32 pm_reg; 7462306a36Sopenharmony_ci u32 im0_reg; 7562306a36Sopenharmony_ci u32 im1_reg; 7662306a36Sopenharmony_ci u32 gpio_use_sel_reg; 7762306a36Sopenharmony_ci}; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/** 8062306a36Sopenharmony_ci * struct pch_gpio - GPIO private data structure. 8162306a36Sopenharmony_ci * @base: PCI base address of Memory mapped I/O register. 8262306a36Sopenharmony_ci * @reg: Memory mapped PCH GPIO register list. 8362306a36Sopenharmony_ci * @dev: Pointer to device structure. 8462306a36Sopenharmony_ci * @gpio: Data for GPIO infrastructure. 8562306a36Sopenharmony_ci * @pch_gpio_reg: Memory mapped Register data is saved here 8662306a36Sopenharmony_ci * when suspend. 8762306a36Sopenharmony_ci * @lock: Used for register access protection 8862306a36Sopenharmony_ci * @irq_base: Save base of IRQ number for interrupt 8962306a36Sopenharmony_ci * @ioh: IOH ID 9062306a36Sopenharmony_ci * @spinlock: Used for register access protection 9162306a36Sopenharmony_ci */ 9262306a36Sopenharmony_cistruct pch_gpio { 9362306a36Sopenharmony_ci void __iomem *base; 9462306a36Sopenharmony_ci struct pch_regs __iomem *reg; 9562306a36Sopenharmony_ci struct device *dev; 9662306a36Sopenharmony_ci struct gpio_chip gpio; 9762306a36Sopenharmony_ci struct pch_gpio_reg_data pch_gpio_reg; 9862306a36Sopenharmony_ci int irq_base; 9962306a36Sopenharmony_ci enum pch_type_t ioh; 10062306a36Sopenharmony_ci spinlock_t spinlock; 10162306a36Sopenharmony_ci}; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic void pch_gpio_set(struct gpio_chip *gpio, unsigned int nr, int val) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci u32 reg_val; 10662306a36Sopenharmony_ci struct pch_gpio *chip = gpiochip_get_data(gpio); 10762306a36Sopenharmony_ci unsigned long flags; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci spin_lock_irqsave(&chip->spinlock, flags); 11062306a36Sopenharmony_ci reg_val = ioread32(&chip->reg->po); 11162306a36Sopenharmony_ci if (val) 11262306a36Sopenharmony_ci reg_val |= BIT(nr); 11362306a36Sopenharmony_ci else 11462306a36Sopenharmony_ci reg_val &= ~BIT(nr); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci iowrite32(reg_val, &chip->reg->po); 11762306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->spinlock, flags); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic int pch_gpio_get(struct gpio_chip *gpio, unsigned int nr) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci struct pch_gpio *chip = gpiochip_get_data(gpio); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return !!(ioread32(&chip->reg->pi) & BIT(nr)); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic int pch_gpio_direction_output(struct gpio_chip *gpio, unsigned int nr, 12862306a36Sopenharmony_ci int val) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct pch_gpio *chip = gpiochip_get_data(gpio); 13162306a36Sopenharmony_ci u32 pm; 13262306a36Sopenharmony_ci u32 reg_val; 13362306a36Sopenharmony_ci unsigned long flags; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci spin_lock_irqsave(&chip->spinlock, flags); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci reg_val = ioread32(&chip->reg->po); 13862306a36Sopenharmony_ci if (val) 13962306a36Sopenharmony_ci reg_val |= BIT(nr); 14062306a36Sopenharmony_ci else 14162306a36Sopenharmony_ci reg_val &= ~BIT(nr); 14262306a36Sopenharmony_ci iowrite32(reg_val, &chip->reg->po); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci pm = ioread32(&chip->reg->pm); 14562306a36Sopenharmony_ci pm &= BIT(gpio_pins[chip->ioh]) - 1; 14662306a36Sopenharmony_ci pm |= BIT(nr); 14762306a36Sopenharmony_ci iowrite32(pm, &chip->reg->pm); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->spinlock, flags); 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci return 0; 15262306a36Sopenharmony_ci} 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_cistatic int pch_gpio_direction_input(struct gpio_chip *gpio, unsigned int nr) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct pch_gpio *chip = gpiochip_get_data(gpio); 15762306a36Sopenharmony_ci u32 pm; 15862306a36Sopenharmony_ci unsigned long flags; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci spin_lock_irqsave(&chip->spinlock, flags); 16162306a36Sopenharmony_ci pm = ioread32(&chip->reg->pm); 16262306a36Sopenharmony_ci pm &= BIT(gpio_pins[chip->ioh]) - 1; 16362306a36Sopenharmony_ci pm &= ~BIT(nr); 16462306a36Sopenharmony_ci iowrite32(pm, &chip->reg->pm); 16562306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->spinlock, flags); 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci return 0; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* 17162306a36Sopenharmony_ci * Save register configuration and disable interrupts. 17262306a36Sopenharmony_ci */ 17362306a36Sopenharmony_cistatic void __maybe_unused pch_gpio_save_reg_conf(struct pch_gpio *chip) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci chip->pch_gpio_reg.ien_reg = ioread32(&chip->reg->ien); 17662306a36Sopenharmony_ci chip->pch_gpio_reg.imask_reg = ioread32(&chip->reg->imask); 17762306a36Sopenharmony_ci chip->pch_gpio_reg.po_reg = ioread32(&chip->reg->po); 17862306a36Sopenharmony_ci chip->pch_gpio_reg.pm_reg = ioread32(&chip->reg->pm); 17962306a36Sopenharmony_ci chip->pch_gpio_reg.im0_reg = ioread32(&chip->reg->im0); 18062306a36Sopenharmony_ci if (chip->ioh == INTEL_EG20T_PCH) 18162306a36Sopenharmony_ci chip->pch_gpio_reg.im1_reg = ioread32(&chip->reg->im1); 18262306a36Sopenharmony_ci if (chip->ioh == OKISEMI_ML7223n_IOH) 18362306a36Sopenharmony_ci chip->pch_gpio_reg.gpio_use_sel_reg = ioread32(&chip->reg->gpio_use_sel); 18462306a36Sopenharmony_ci} 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_ci/* 18762306a36Sopenharmony_ci * This function restores the register configuration of the GPIO device. 18862306a36Sopenharmony_ci */ 18962306a36Sopenharmony_cistatic void __maybe_unused pch_gpio_restore_reg_conf(struct pch_gpio *chip) 19062306a36Sopenharmony_ci{ 19162306a36Sopenharmony_ci iowrite32(chip->pch_gpio_reg.ien_reg, &chip->reg->ien); 19262306a36Sopenharmony_ci iowrite32(chip->pch_gpio_reg.imask_reg, &chip->reg->imask); 19362306a36Sopenharmony_ci /* to store contents of PO register */ 19462306a36Sopenharmony_ci iowrite32(chip->pch_gpio_reg.po_reg, &chip->reg->po); 19562306a36Sopenharmony_ci /* to store contents of PM register */ 19662306a36Sopenharmony_ci iowrite32(chip->pch_gpio_reg.pm_reg, &chip->reg->pm); 19762306a36Sopenharmony_ci iowrite32(chip->pch_gpio_reg.im0_reg, &chip->reg->im0); 19862306a36Sopenharmony_ci if (chip->ioh == INTEL_EG20T_PCH) 19962306a36Sopenharmony_ci iowrite32(chip->pch_gpio_reg.im1_reg, &chip->reg->im1); 20062306a36Sopenharmony_ci if (chip->ioh == OKISEMI_ML7223n_IOH) 20162306a36Sopenharmony_ci iowrite32(chip->pch_gpio_reg.gpio_use_sel_reg, &chip->reg->gpio_use_sel); 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic int pch_gpio_to_irq(struct gpio_chip *gpio, unsigned int offset) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct pch_gpio *chip = gpiochip_get_data(gpio); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci return chip->irq_base + offset; 20962306a36Sopenharmony_ci} 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_cistatic void pch_gpio_setup(struct pch_gpio *chip) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci struct gpio_chip *gpio = &chip->gpio; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci gpio->label = dev_name(chip->dev); 21662306a36Sopenharmony_ci gpio->parent = chip->dev; 21762306a36Sopenharmony_ci gpio->owner = THIS_MODULE; 21862306a36Sopenharmony_ci gpio->direction_input = pch_gpio_direction_input; 21962306a36Sopenharmony_ci gpio->get = pch_gpio_get; 22062306a36Sopenharmony_ci gpio->direction_output = pch_gpio_direction_output; 22162306a36Sopenharmony_ci gpio->set = pch_gpio_set; 22262306a36Sopenharmony_ci gpio->base = -1; 22362306a36Sopenharmony_ci gpio->ngpio = gpio_pins[chip->ioh]; 22462306a36Sopenharmony_ci gpio->can_sleep = false; 22562306a36Sopenharmony_ci gpio->to_irq = pch_gpio_to_irq; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic int pch_irq_type(struct irq_data *d, unsigned int type) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 23162306a36Sopenharmony_ci struct pch_gpio *chip = gc->private; 23262306a36Sopenharmony_ci u32 im, im_pos, val; 23362306a36Sopenharmony_ci u32 __iomem *im_reg; 23462306a36Sopenharmony_ci unsigned long flags; 23562306a36Sopenharmony_ci int ch, irq = d->irq; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci ch = irq - chip->irq_base; 23862306a36Sopenharmony_ci if (irq < chip->irq_base + 8) { 23962306a36Sopenharmony_ci im_reg = &chip->reg->im0; 24062306a36Sopenharmony_ci im_pos = ch - 0; 24162306a36Sopenharmony_ci } else { 24262306a36Sopenharmony_ci im_reg = &chip->reg->im1; 24362306a36Sopenharmony_ci im_pos = ch - 8; 24462306a36Sopenharmony_ci } 24562306a36Sopenharmony_ci dev_dbg(chip->dev, "irq=%d type=%d ch=%d pos=%d\n", irq, type, ch, im_pos); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci switch (type) { 24862306a36Sopenharmony_ci case IRQ_TYPE_EDGE_RISING: 24962306a36Sopenharmony_ci val = PCH_EDGE_RISING; 25062306a36Sopenharmony_ci break; 25162306a36Sopenharmony_ci case IRQ_TYPE_EDGE_FALLING: 25262306a36Sopenharmony_ci val = PCH_EDGE_FALLING; 25362306a36Sopenharmony_ci break; 25462306a36Sopenharmony_ci case IRQ_TYPE_EDGE_BOTH: 25562306a36Sopenharmony_ci val = PCH_EDGE_BOTH; 25662306a36Sopenharmony_ci break; 25762306a36Sopenharmony_ci case IRQ_TYPE_LEVEL_HIGH: 25862306a36Sopenharmony_ci val = PCH_LEVEL_H; 25962306a36Sopenharmony_ci break; 26062306a36Sopenharmony_ci case IRQ_TYPE_LEVEL_LOW: 26162306a36Sopenharmony_ci val = PCH_LEVEL_L; 26262306a36Sopenharmony_ci break; 26362306a36Sopenharmony_ci default: 26462306a36Sopenharmony_ci return 0; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci spin_lock_irqsave(&chip->spinlock, flags); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* Set interrupt mode */ 27062306a36Sopenharmony_ci im = ioread32(im_reg) & ~(PCH_IM_MASK << (im_pos * 4)); 27162306a36Sopenharmony_ci iowrite32(im | (val << (im_pos * 4)), im_reg); 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci /* And the handler */ 27462306a36Sopenharmony_ci if (type & IRQ_TYPE_LEVEL_MASK) 27562306a36Sopenharmony_ci irq_set_handler_locked(d, handle_level_irq); 27662306a36Sopenharmony_ci else if (type & IRQ_TYPE_EDGE_BOTH) 27762306a36Sopenharmony_ci irq_set_handler_locked(d, handle_edge_irq); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->spinlock, flags); 28062306a36Sopenharmony_ci return 0; 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic void pch_irq_unmask(struct irq_data *d) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 28662306a36Sopenharmony_ci struct pch_gpio *chip = gc->private; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci iowrite32(BIT(d->irq - chip->irq_base), &chip->reg->imaskclr); 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic void pch_irq_mask(struct irq_data *d) 29262306a36Sopenharmony_ci{ 29362306a36Sopenharmony_ci struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 29462306a36Sopenharmony_ci struct pch_gpio *chip = gc->private; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci iowrite32(BIT(d->irq - chip->irq_base), &chip->reg->imask); 29762306a36Sopenharmony_ci} 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_cistatic void pch_irq_ack(struct irq_data *d) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 30262306a36Sopenharmony_ci struct pch_gpio *chip = gc->private; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci iowrite32(BIT(d->irq - chip->irq_base), &chip->reg->iclr); 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_cistatic irqreturn_t pch_gpio_handler(int irq, void *dev_id) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct pch_gpio *chip = dev_id; 31062306a36Sopenharmony_ci unsigned long reg_val = ioread32(&chip->reg->istatus); 31162306a36Sopenharmony_ci int i; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci dev_vdbg(chip->dev, "irq=%d status=0x%lx\n", irq, reg_val); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci reg_val &= BIT(gpio_pins[chip->ioh]) - 1; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci for_each_set_bit(i, ®_val, gpio_pins[chip->ioh]) 31862306a36Sopenharmony_ci generic_handle_irq(chip->irq_base + i); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return IRQ_RETVAL(reg_val); 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_cistatic int pch_gpio_alloc_generic_chip(struct pch_gpio *chip, 32462306a36Sopenharmony_ci unsigned int irq_start, 32562306a36Sopenharmony_ci unsigned int num) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci struct irq_chip_generic *gc; 32862306a36Sopenharmony_ci struct irq_chip_type *ct; 32962306a36Sopenharmony_ci int rv; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci gc = devm_irq_alloc_generic_chip(chip->dev, "pch_gpio", 1, irq_start, 33262306a36Sopenharmony_ci chip->base, handle_simple_irq); 33362306a36Sopenharmony_ci if (!gc) 33462306a36Sopenharmony_ci return -ENOMEM; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci gc->private = chip; 33762306a36Sopenharmony_ci ct = gc->chip_types; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci ct->chip.irq_ack = pch_irq_ack; 34062306a36Sopenharmony_ci ct->chip.irq_mask = pch_irq_mask; 34162306a36Sopenharmony_ci ct->chip.irq_unmask = pch_irq_unmask; 34262306a36Sopenharmony_ci ct->chip.irq_set_type = pch_irq_type; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci rv = devm_irq_setup_generic_chip(chip->dev, gc, IRQ_MSK(num), 34562306a36Sopenharmony_ci IRQ_GC_INIT_MASK_CACHE, 34662306a36Sopenharmony_ci IRQ_NOREQUEST | IRQ_NOPROBE, 0); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci return rv; 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic int pch_gpio_probe(struct pci_dev *pdev, 35262306a36Sopenharmony_ci const struct pci_device_id *id) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci struct device *dev = &pdev->dev; 35562306a36Sopenharmony_ci s32 ret; 35662306a36Sopenharmony_ci struct pch_gpio *chip; 35762306a36Sopenharmony_ci int irq_base; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); 36062306a36Sopenharmony_ci if (chip == NULL) 36162306a36Sopenharmony_ci return -ENOMEM; 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_ci chip->dev = dev; 36462306a36Sopenharmony_ci ret = pcim_enable_device(pdev); 36562306a36Sopenharmony_ci if (ret) 36662306a36Sopenharmony_ci return dev_err_probe(dev, ret, "Failed to enable PCI device\n"); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci ret = pcim_iomap_regions(pdev, BIT(1), KBUILD_MODNAME); 36962306a36Sopenharmony_ci if (ret) 37062306a36Sopenharmony_ci return dev_err_probe(dev, ret, "Failed to request and map PCI regions\n"); 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ci chip->base = pcim_iomap_table(pdev)[1]; 37362306a36Sopenharmony_ci chip->ioh = id->driver_data; 37462306a36Sopenharmony_ci chip->reg = chip->base; 37562306a36Sopenharmony_ci pci_set_drvdata(pdev, chip); 37662306a36Sopenharmony_ci spin_lock_init(&chip->spinlock); 37762306a36Sopenharmony_ci pch_gpio_setup(chip); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci ret = devm_gpiochip_add_data(dev, &chip->gpio, chip); 38062306a36Sopenharmony_ci if (ret) 38162306a36Sopenharmony_ci return dev_err_probe(dev, ret, "Failed to register GPIO\n"); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci irq_base = devm_irq_alloc_descs(dev, -1, 0, 38462306a36Sopenharmony_ci gpio_pins[chip->ioh], NUMA_NO_NODE); 38562306a36Sopenharmony_ci if (irq_base < 0) { 38662306a36Sopenharmony_ci dev_warn(dev, "PCH gpio: Failed to get IRQ base num\n"); 38762306a36Sopenharmony_ci chip->irq_base = -1; 38862306a36Sopenharmony_ci return 0; 38962306a36Sopenharmony_ci } 39062306a36Sopenharmony_ci chip->irq_base = irq_base; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci /* Mask all interrupts, but enable them */ 39362306a36Sopenharmony_ci iowrite32(BIT(gpio_pins[chip->ioh]) - 1, &chip->reg->imask); 39462306a36Sopenharmony_ci iowrite32(BIT(gpio_pins[chip->ioh]) - 1, &chip->reg->ien); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci ret = devm_request_irq(dev, pdev->irq, pch_gpio_handler, 39762306a36Sopenharmony_ci IRQF_SHARED, KBUILD_MODNAME, chip); 39862306a36Sopenharmony_ci if (ret) 39962306a36Sopenharmony_ci return dev_err_probe(dev, ret, "Failed to request IRQ\n"); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci return pch_gpio_alloc_generic_chip(chip, irq_base, gpio_pins[chip->ioh]); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic int __maybe_unused pch_gpio_suspend(struct device *dev) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci struct pch_gpio *chip = dev_get_drvdata(dev); 40762306a36Sopenharmony_ci unsigned long flags; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci spin_lock_irqsave(&chip->spinlock, flags); 41062306a36Sopenharmony_ci pch_gpio_save_reg_conf(chip); 41162306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->spinlock, flags); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci return 0; 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_cistatic int __maybe_unused pch_gpio_resume(struct device *dev) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct pch_gpio *chip = dev_get_drvdata(dev); 41962306a36Sopenharmony_ci unsigned long flags; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci spin_lock_irqsave(&chip->spinlock, flags); 42262306a36Sopenharmony_ci iowrite32(0x01, &chip->reg->reset); 42362306a36Sopenharmony_ci iowrite32(0x00, &chip->reg->reset); 42462306a36Sopenharmony_ci pch_gpio_restore_reg_conf(chip); 42562306a36Sopenharmony_ci spin_unlock_irqrestore(&chip->spinlock, flags); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci return 0; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(pch_gpio_pm_ops, pch_gpio_suspend, pch_gpio_resume); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_cistatic const struct pci_device_id pch_gpio_pcidev_id[] = { 43362306a36Sopenharmony_ci { PCI_DEVICE_DATA(INTEL, EG20T_PCH, INTEL_EG20T_PCH) }, 43462306a36Sopenharmony_ci { PCI_DEVICE_DATA(ROHM, ML7223m_IOH, OKISEMI_ML7223m_IOH) }, 43562306a36Sopenharmony_ci { PCI_DEVICE_DATA(ROHM, ML7223n_IOH, OKISEMI_ML7223n_IOH) }, 43662306a36Sopenharmony_ci { PCI_DEVICE_DATA(ROHM, EG20T_PCH, INTEL_EG20T_PCH) }, 43762306a36Sopenharmony_ci { } 43862306a36Sopenharmony_ci}; 43962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, pch_gpio_pcidev_id); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_cistatic struct pci_driver pch_gpio_driver = { 44262306a36Sopenharmony_ci .name = "pch_gpio", 44362306a36Sopenharmony_ci .id_table = pch_gpio_pcidev_id, 44462306a36Sopenharmony_ci .probe = pch_gpio_probe, 44562306a36Sopenharmony_ci .driver = { 44662306a36Sopenharmony_ci .pm = &pch_gpio_pm_ops, 44762306a36Sopenharmony_ci }, 44862306a36Sopenharmony_ci}; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cimodule_pci_driver(pch_gpio_driver); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ciMODULE_DESCRIPTION("PCH GPIO PCI Driver"); 45362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 454