162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * GPIO interface for Intel Poulsbo SCH
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci *  Copyright (c) 2010 CompuLab Ltd
662306a36Sopenharmony_ci *  Author: Denis Turischev <denis@compulab.co.il>
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/acpi.h>
1062306a36Sopenharmony_ci#include <linux/bitops.h>
1162306a36Sopenharmony_ci#include <linux/errno.h>
1262306a36Sopenharmony_ci#include <linux/gpio/driver.h>
1362306a36Sopenharmony_ci#include <linux/io.h>
1462306a36Sopenharmony_ci#include <linux/irq.h>
1562306a36Sopenharmony_ci#include <linux/kernel.h>
1662306a36Sopenharmony_ci#include <linux/module.h>
1762306a36Sopenharmony_ci#include <linux/pci_ids.h>
1862306a36Sopenharmony_ci#include <linux/platform_device.h>
1962306a36Sopenharmony_ci#include <linux/types.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define GEN	0x00
2262306a36Sopenharmony_ci#define GIO	0x04
2362306a36Sopenharmony_ci#define GLV	0x08
2462306a36Sopenharmony_ci#define GTPE	0x0c
2562306a36Sopenharmony_ci#define GTNE	0x10
2662306a36Sopenharmony_ci#define GGPE	0x14
2762306a36Sopenharmony_ci#define GSMI	0x18
2862306a36Sopenharmony_ci#define GTS	0x1c
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define CORE_BANK_OFFSET	0x00
3162306a36Sopenharmony_ci#define RESUME_BANK_OFFSET	0x20
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/*
3462306a36Sopenharmony_ci * iLB datasheet describes GPE0BLK registers, in particular GPE0E.GPIO bit.
3562306a36Sopenharmony_ci * Document Number: 328195-001
3662306a36Sopenharmony_ci */
3762306a36Sopenharmony_ci#define GPE0E_GPIO	14
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistruct sch_gpio {
4062306a36Sopenharmony_ci	struct gpio_chip chip;
4162306a36Sopenharmony_ci	spinlock_t lock;
4262306a36Sopenharmony_ci	unsigned short iobase;
4362306a36Sopenharmony_ci	unsigned short resume_base;
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	/* GPE handling */
4662306a36Sopenharmony_ci	u32 gpe;
4762306a36Sopenharmony_ci	acpi_gpe_handler gpe_handler;
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic unsigned int sch_gpio_offset(struct sch_gpio *sch, unsigned int gpio,
5162306a36Sopenharmony_ci				unsigned int reg)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	unsigned int base = CORE_BANK_OFFSET;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	if (gpio >= sch->resume_base) {
5662306a36Sopenharmony_ci		gpio -= sch->resume_base;
5762306a36Sopenharmony_ci		base = RESUME_BANK_OFFSET;
5862306a36Sopenharmony_ci	}
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	return base + reg + gpio / 8;
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_cistatic unsigned int sch_gpio_bit(struct sch_gpio *sch, unsigned int gpio)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	if (gpio >= sch->resume_base)
6662306a36Sopenharmony_ci		gpio -= sch->resume_base;
6762306a36Sopenharmony_ci	return gpio % 8;
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic int sch_gpio_reg_get(struct sch_gpio *sch, unsigned int gpio, unsigned int reg)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	unsigned short offset, bit;
7362306a36Sopenharmony_ci	u8 reg_val;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	offset = sch_gpio_offset(sch, gpio, reg);
7662306a36Sopenharmony_ci	bit = sch_gpio_bit(sch, gpio);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	reg_val = !!(inb(sch->iobase + offset) & BIT(bit));
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	return reg_val;
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_cistatic void sch_gpio_reg_set(struct sch_gpio *sch, unsigned int gpio, unsigned int reg,
8462306a36Sopenharmony_ci			     int val)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	unsigned short offset, bit;
8762306a36Sopenharmony_ci	u8 reg_val;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	offset = sch_gpio_offset(sch, gpio, reg);
9062306a36Sopenharmony_ci	bit = sch_gpio_bit(sch, gpio);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	reg_val = inb(sch->iobase + offset);
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	if (val)
9562306a36Sopenharmony_ci		outb(reg_val | BIT(bit), sch->iobase + offset);
9662306a36Sopenharmony_ci	else
9762306a36Sopenharmony_ci		outb((reg_val & ~BIT(bit)), sch->iobase + offset);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_cistatic int sch_gpio_direction_in(struct gpio_chip *gc, unsigned int gpio_num)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	struct sch_gpio *sch = gpiochip_get_data(gc);
10362306a36Sopenharmony_ci	unsigned long flags;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	spin_lock_irqsave(&sch->lock, flags);
10662306a36Sopenharmony_ci	sch_gpio_reg_set(sch, gpio_num, GIO, 1);
10762306a36Sopenharmony_ci	spin_unlock_irqrestore(&sch->lock, flags);
10862306a36Sopenharmony_ci	return 0;
10962306a36Sopenharmony_ci}
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic int sch_gpio_get(struct gpio_chip *gc, unsigned int gpio_num)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	struct sch_gpio *sch = gpiochip_get_data(gc);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	return sch_gpio_reg_get(sch, gpio_num, GLV);
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic void sch_gpio_set(struct gpio_chip *gc, unsigned int gpio_num, int val)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	struct sch_gpio *sch = gpiochip_get_data(gc);
12162306a36Sopenharmony_ci	unsigned long flags;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	spin_lock_irqsave(&sch->lock, flags);
12462306a36Sopenharmony_ci	sch_gpio_reg_set(sch, gpio_num, GLV, val);
12562306a36Sopenharmony_ci	spin_unlock_irqrestore(&sch->lock, flags);
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic int sch_gpio_direction_out(struct gpio_chip *gc, unsigned int gpio_num,
12962306a36Sopenharmony_ci				  int val)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	struct sch_gpio *sch = gpiochip_get_data(gc);
13262306a36Sopenharmony_ci	unsigned long flags;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	spin_lock_irqsave(&sch->lock, flags);
13562306a36Sopenharmony_ci	sch_gpio_reg_set(sch, gpio_num, GIO, 0);
13662306a36Sopenharmony_ci	spin_unlock_irqrestore(&sch->lock, flags);
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	/*
13962306a36Sopenharmony_ci	 * according to the datasheet, writing to the level register has no
14062306a36Sopenharmony_ci	 * effect when GPIO is programmed as input.
14162306a36Sopenharmony_ci	 * Actually the level register is read-only when configured as input.
14262306a36Sopenharmony_ci	 * Thus presetting the output level before switching to output is _NOT_ possible.
14362306a36Sopenharmony_ci	 * Hence we set the level after configuring the GPIO as output.
14462306a36Sopenharmony_ci	 * But we cannot prevent a short low pulse if direction is set to high
14562306a36Sopenharmony_ci	 * and an external pull-up is connected.
14662306a36Sopenharmony_ci	 */
14762306a36Sopenharmony_ci	sch_gpio_set(gc, gpio_num, val);
14862306a36Sopenharmony_ci	return 0;
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic int sch_gpio_get_direction(struct gpio_chip *gc, unsigned int gpio_num)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	struct sch_gpio *sch = gpiochip_get_data(gc);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	if (sch_gpio_reg_get(sch, gpio_num, GIO))
15662306a36Sopenharmony_ci		return GPIO_LINE_DIRECTION_IN;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	return GPIO_LINE_DIRECTION_OUT;
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic const struct gpio_chip sch_gpio_chip = {
16262306a36Sopenharmony_ci	.label			= "sch_gpio",
16362306a36Sopenharmony_ci	.owner			= THIS_MODULE,
16462306a36Sopenharmony_ci	.direction_input	= sch_gpio_direction_in,
16562306a36Sopenharmony_ci	.get			= sch_gpio_get,
16662306a36Sopenharmony_ci	.direction_output	= sch_gpio_direction_out,
16762306a36Sopenharmony_ci	.set			= sch_gpio_set,
16862306a36Sopenharmony_ci	.get_direction		= sch_gpio_get_direction,
16962306a36Sopenharmony_ci};
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic int sch_irq_type(struct irq_data *d, unsigned int type)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
17462306a36Sopenharmony_ci	struct sch_gpio *sch = gpiochip_get_data(gc);
17562306a36Sopenharmony_ci	irq_hw_number_t gpio_num = irqd_to_hwirq(d);
17662306a36Sopenharmony_ci	unsigned long flags;
17762306a36Sopenharmony_ci	int rising, falling;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	switch (type & IRQ_TYPE_SENSE_MASK) {
18062306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_RISING:
18162306a36Sopenharmony_ci		rising = 1;
18262306a36Sopenharmony_ci		falling = 0;
18362306a36Sopenharmony_ci		break;
18462306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_FALLING:
18562306a36Sopenharmony_ci		rising = 0;
18662306a36Sopenharmony_ci		falling = 1;
18762306a36Sopenharmony_ci		break;
18862306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_BOTH:
18962306a36Sopenharmony_ci		rising = 1;
19062306a36Sopenharmony_ci		falling = 1;
19162306a36Sopenharmony_ci		break;
19262306a36Sopenharmony_ci	default:
19362306a36Sopenharmony_ci		return -EINVAL;
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	spin_lock_irqsave(&sch->lock, flags);
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	sch_gpio_reg_set(sch, gpio_num, GTPE, rising);
19962306a36Sopenharmony_ci	sch_gpio_reg_set(sch, gpio_num, GTNE, falling);
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	irq_set_handler_locked(d, handle_edge_irq);
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ci	spin_unlock_irqrestore(&sch->lock, flags);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	return 0;
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_cistatic void sch_irq_ack(struct irq_data *d)
20962306a36Sopenharmony_ci{
21062306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
21162306a36Sopenharmony_ci	struct sch_gpio *sch = gpiochip_get_data(gc);
21262306a36Sopenharmony_ci	irq_hw_number_t gpio_num = irqd_to_hwirq(d);
21362306a36Sopenharmony_ci	unsigned long flags;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	spin_lock_irqsave(&sch->lock, flags);
21662306a36Sopenharmony_ci	sch_gpio_reg_set(sch, gpio_num, GTS, 1);
21762306a36Sopenharmony_ci	spin_unlock_irqrestore(&sch->lock, flags);
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic void sch_irq_mask_unmask(struct gpio_chip *gc, irq_hw_number_t gpio_num, int val)
22162306a36Sopenharmony_ci{
22262306a36Sopenharmony_ci	struct sch_gpio *sch = gpiochip_get_data(gc);
22362306a36Sopenharmony_ci	unsigned long flags;
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci	spin_lock_irqsave(&sch->lock, flags);
22662306a36Sopenharmony_ci	sch_gpio_reg_set(sch, gpio_num, GGPE, val);
22762306a36Sopenharmony_ci	spin_unlock_irqrestore(&sch->lock, flags);
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_cistatic void sch_irq_mask(struct irq_data *d)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
23362306a36Sopenharmony_ci	irq_hw_number_t gpio_num = irqd_to_hwirq(d);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	sch_irq_mask_unmask(gc, gpio_num, 0);
23662306a36Sopenharmony_ci	gpiochip_disable_irq(gc, gpio_num);
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic void sch_irq_unmask(struct irq_data *d)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
24262306a36Sopenharmony_ci	irq_hw_number_t gpio_num = irqd_to_hwirq(d);
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	gpiochip_enable_irq(gc, gpio_num);
24562306a36Sopenharmony_ci	sch_irq_mask_unmask(gc, gpio_num, 1);
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic const struct irq_chip sch_irqchip = {
24962306a36Sopenharmony_ci	.name = "sch_gpio",
25062306a36Sopenharmony_ci	.irq_ack = sch_irq_ack,
25162306a36Sopenharmony_ci	.irq_mask = sch_irq_mask,
25262306a36Sopenharmony_ci	.irq_unmask = sch_irq_unmask,
25362306a36Sopenharmony_ci	.irq_set_type = sch_irq_type,
25462306a36Sopenharmony_ci	.flags = IRQCHIP_IMMUTABLE,
25562306a36Sopenharmony_ci	GPIOCHIP_IRQ_RESOURCE_HELPERS,
25662306a36Sopenharmony_ci};
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_cistatic u32 sch_gpio_gpe_handler(acpi_handle gpe_device, u32 gpe, void *context)
25962306a36Sopenharmony_ci{
26062306a36Sopenharmony_ci	struct sch_gpio *sch = context;
26162306a36Sopenharmony_ci	struct gpio_chip *gc = &sch->chip;
26262306a36Sopenharmony_ci	unsigned long core_status, resume_status;
26362306a36Sopenharmony_ci	unsigned long pending;
26462306a36Sopenharmony_ci	unsigned long flags;
26562306a36Sopenharmony_ci	int offset;
26662306a36Sopenharmony_ci	u32 ret;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	spin_lock_irqsave(&sch->lock, flags);
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci	core_status = inl(sch->iobase + CORE_BANK_OFFSET + GTS);
27162306a36Sopenharmony_ci	resume_status = inl(sch->iobase + RESUME_BANK_OFFSET + GTS);
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	spin_unlock_irqrestore(&sch->lock, flags);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	pending = (resume_status << sch->resume_base) | core_status;
27662306a36Sopenharmony_ci	for_each_set_bit(offset, &pending, sch->chip.ngpio)
27762306a36Sopenharmony_ci		generic_handle_domain_irq(gc->irq.domain, offset);
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	/* Set returning value depending on whether we handled an interrupt */
28062306a36Sopenharmony_ci	ret = pending ? ACPI_INTERRUPT_HANDLED : ACPI_INTERRUPT_NOT_HANDLED;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	/* Acknowledge GPE to ACPICA */
28362306a36Sopenharmony_ci	ret |= ACPI_REENABLE_GPE;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	return ret;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic void sch_gpio_remove_gpe_handler(void *data)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	struct sch_gpio *sch = data;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	acpi_disable_gpe(NULL, sch->gpe);
29362306a36Sopenharmony_ci	acpi_remove_gpe_handler(NULL, sch->gpe, sch->gpe_handler);
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic int sch_gpio_install_gpe_handler(struct sch_gpio *sch)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct device *dev = sch->chip.parent;
29962306a36Sopenharmony_ci	acpi_status status;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	status = acpi_install_gpe_handler(NULL, sch->gpe, ACPI_GPE_LEVEL_TRIGGERED,
30262306a36Sopenharmony_ci					  sch->gpe_handler, sch);
30362306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
30462306a36Sopenharmony_ci		dev_err(dev, "Failed to install GPE handler for %u: %s\n",
30562306a36Sopenharmony_ci			sch->gpe, acpi_format_exception(status));
30662306a36Sopenharmony_ci		return -ENODEV;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	status = acpi_enable_gpe(NULL, sch->gpe);
31062306a36Sopenharmony_ci	if (ACPI_FAILURE(status)) {
31162306a36Sopenharmony_ci		dev_err(dev, "Failed to enable GPE handler for %u: %s\n",
31262306a36Sopenharmony_ci			sch->gpe, acpi_format_exception(status));
31362306a36Sopenharmony_ci		acpi_remove_gpe_handler(NULL, sch->gpe, sch->gpe_handler);
31462306a36Sopenharmony_ci		return -ENODEV;
31562306a36Sopenharmony_ci	}
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	return devm_add_action_or_reset(dev, sch_gpio_remove_gpe_handler, sch);
31862306a36Sopenharmony_ci}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_cistatic int sch_gpio_probe(struct platform_device *pdev)
32162306a36Sopenharmony_ci{
32262306a36Sopenharmony_ci	struct gpio_irq_chip *girq;
32362306a36Sopenharmony_ci	struct sch_gpio *sch;
32462306a36Sopenharmony_ci	struct resource *res;
32562306a36Sopenharmony_ci	int ret;
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ci	sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL);
32862306a36Sopenharmony_ci	if (!sch)
32962306a36Sopenharmony_ci		return -ENOMEM;
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_IO, 0);
33262306a36Sopenharmony_ci	if (!res)
33362306a36Sopenharmony_ci		return -EBUSY;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	if (!devm_request_region(&pdev->dev, res->start, resource_size(res),
33662306a36Sopenharmony_ci				 pdev->name))
33762306a36Sopenharmony_ci		return -EBUSY;
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	spin_lock_init(&sch->lock);
34062306a36Sopenharmony_ci	sch->iobase = res->start;
34162306a36Sopenharmony_ci	sch->chip = sch_gpio_chip;
34262306a36Sopenharmony_ci	sch->chip.label = dev_name(&pdev->dev);
34362306a36Sopenharmony_ci	sch->chip.parent = &pdev->dev;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	switch (pdev->id) {
34662306a36Sopenharmony_ci	case PCI_DEVICE_ID_INTEL_SCH_LPC:
34762306a36Sopenharmony_ci		sch->resume_base = 10;
34862306a36Sopenharmony_ci		sch->chip.ngpio = 14;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci		/*
35162306a36Sopenharmony_ci		 * GPIO[6:0] enabled by default
35262306a36Sopenharmony_ci		 * GPIO7 is configured by the CMC as SLPIOVR
35362306a36Sopenharmony_ci		 * Enable GPIO[9:8] core powered gpios explicitly
35462306a36Sopenharmony_ci		 */
35562306a36Sopenharmony_ci		sch_gpio_reg_set(sch, 8, GEN, 1);
35662306a36Sopenharmony_ci		sch_gpio_reg_set(sch, 9, GEN, 1);
35762306a36Sopenharmony_ci		/*
35862306a36Sopenharmony_ci		 * SUS_GPIO[2:0] enabled by default
35962306a36Sopenharmony_ci		 * Enable SUS_GPIO3 resume powered gpio explicitly
36062306a36Sopenharmony_ci		 */
36162306a36Sopenharmony_ci		sch_gpio_reg_set(sch, 13, GEN, 1);
36262306a36Sopenharmony_ci		break;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	case PCI_DEVICE_ID_INTEL_ITC_LPC:
36562306a36Sopenharmony_ci		sch->resume_base = 5;
36662306a36Sopenharmony_ci		sch->chip.ngpio = 14;
36762306a36Sopenharmony_ci		break;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	case PCI_DEVICE_ID_INTEL_CENTERTON_ILB:
37062306a36Sopenharmony_ci		sch->resume_base = 21;
37162306a36Sopenharmony_ci		sch->chip.ngpio = 30;
37262306a36Sopenharmony_ci		break;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci	case PCI_DEVICE_ID_INTEL_QUARK_X1000_ILB:
37562306a36Sopenharmony_ci		sch->resume_base = 2;
37662306a36Sopenharmony_ci		sch->chip.ngpio = 8;
37762306a36Sopenharmony_ci		break;
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci	default:
38062306a36Sopenharmony_ci		return -ENODEV;
38162306a36Sopenharmony_ci	}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	girq = &sch->chip.irq;
38462306a36Sopenharmony_ci	gpio_irq_chip_set_chip(girq, &sch_irqchip);
38562306a36Sopenharmony_ci	girq->num_parents = 0;
38662306a36Sopenharmony_ci	girq->parents = NULL;
38762306a36Sopenharmony_ci	girq->parent_handler = NULL;
38862306a36Sopenharmony_ci	girq->default_type = IRQ_TYPE_NONE;
38962306a36Sopenharmony_ci	girq->handler = handle_bad_irq;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/* GPE setup is optional */
39262306a36Sopenharmony_ci	sch->gpe = GPE0E_GPIO;
39362306a36Sopenharmony_ci	sch->gpe_handler = sch_gpio_gpe_handler;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	ret = sch_gpio_install_gpe_handler(sch);
39662306a36Sopenharmony_ci	if (ret)
39762306a36Sopenharmony_ci		dev_warn(&pdev->dev, "Can't setup GPE, no IRQ support\n");
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	return devm_gpiochip_add_data(&pdev->dev, &sch->chip, sch);
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_cistatic struct platform_driver sch_gpio_driver = {
40362306a36Sopenharmony_ci	.driver = {
40462306a36Sopenharmony_ci		.name = "sch_gpio",
40562306a36Sopenharmony_ci	},
40662306a36Sopenharmony_ci	.probe		= sch_gpio_probe,
40762306a36Sopenharmony_ci};
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_cimodule_platform_driver(sch_gpio_driver);
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ciMODULE_AUTHOR("Denis Turischev <denis@compulab.co.il>");
41262306a36Sopenharmony_ciMODULE_DESCRIPTION("GPIO interface for Intel Poulsbo SCH");
41362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
41462306a36Sopenharmony_ciMODULE_ALIAS("platform:sch_gpio");
415