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, &reg_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