162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Intel pinctrl/GPIO core driver.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2015, Intel Corporation
662306a36Sopenharmony_ci * Authors: Mathias Nyman <mathias.nyman@linux.intel.com>
762306a36Sopenharmony_ci *          Mika Westerberg <mika.westerberg@linux.intel.com>
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/acpi.h>
1162306a36Sopenharmony_ci#include <linux/gpio/driver.h>
1262306a36Sopenharmony_ci#include <linux/interrupt.h>
1362306a36Sopenharmony_ci#include <linux/log2.h>
1462306a36Sopenharmony_ci#include <linux/module.h>
1562306a36Sopenharmony_ci#include <linux/platform_device.h>
1662306a36Sopenharmony_ci#include <linux/property.h>
1762306a36Sopenharmony_ci#include <linux/seq_file.h>
1862306a36Sopenharmony_ci#include <linux/string_helpers.h>
1962306a36Sopenharmony_ci#include <linux/time.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h>
2262306a36Sopenharmony_ci#include <linux/pinctrl/pinconf.h>
2362306a36Sopenharmony_ci#include <linux/pinctrl/pinconf-generic.h>
2462306a36Sopenharmony_ci#include <linux/pinctrl/pinctrl.h>
2562306a36Sopenharmony_ci#include <linux/pinctrl/pinmux.h>
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci#include <linux/platform_data/x86/pwm-lpss.h>
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci#include "../core.h"
3062306a36Sopenharmony_ci#include "pinctrl-intel.h"
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* Offset from regs */
3362306a36Sopenharmony_ci#define REVID				0x000
3462306a36Sopenharmony_ci#define REVID_SHIFT			16
3562306a36Sopenharmony_ci#define REVID_MASK			GENMASK(31, 16)
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define CAPLIST				0x004
3862306a36Sopenharmony_ci#define CAPLIST_ID_SHIFT		16
3962306a36Sopenharmony_ci#define CAPLIST_ID_MASK			GENMASK(23, 16)
4062306a36Sopenharmony_ci#define CAPLIST_ID_GPIO_HW_INFO		1
4162306a36Sopenharmony_ci#define CAPLIST_ID_PWM			2
4262306a36Sopenharmony_ci#define CAPLIST_ID_BLINK		3
4362306a36Sopenharmony_ci#define CAPLIST_ID_EXP			4
4462306a36Sopenharmony_ci#define CAPLIST_NEXT_SHIFT		0
4562306a36Sopenharmony_ci#define CAPLIST_NEXT_MASK		GENMASK(15, 0)
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#define PADBAR				0x00c
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci#define PADOWN_BITS			4
5062306a36Sopenharmony_ci#define PADOWN_SHIFT(p)			((p) % 8 * PADOWN_BITS)
5162306a36Sopenharmony_ci#define PADOWN_MASK(p)			(GENMASK(3, 0) << PADOWN_SHIFT(p))
5262306a36Sopenharmony_ci#define PADOWN_GPP(p)			((p) / 8)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci#define PWMC				0x204
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci/* Offset from pad_regs */
5762306a36Sopenharmony_ci#define PADCFG0				0x000
5862306a36Sopenharmony_ci#define PADCFG0_RXEVCFG_MASK		GENMASK(26, 25)
5962306a36Sopenharmony_ci#define PADCFG0_RXEVCFG_LEVEL		(0 << 25)
6062306a36Sopenharmony_ci#define PADCFG0_RXEVCFG_EDGE		(1 << 25)
6162306a36Sopenharmony_ci#define PADCFG0_RXEVCFG_DISABLED	(2 << 25)
6262306a36Sopenharmony_ci#define PADCFG0_RXEVCFG_EDGE_BOTH	(3 << 25)
6362306a36Sopenharmony_ci#define PADCFG0_PREGFRXSEL		BIT(24)
6462306a36Sopenharmony_ci#define PADCFG0_RXINV			BIT(23)
6562306a36Sopenharmony_ci#define PADCFG0_GPIROUTIOXAPIC		BIT(20)
6662306a36Sopenharmony_ci#define PADCFG0_GPIROUTSCI		BIT(19)
6762306a36Sopenharmony_ci#define PADCFG0_GPIROUTSMI		BIT(18)
6862306a36Sopenharmony_ci#define PADCFG0_GPIROUTNMI		BIT(17)
6962306a36Sopenharmony_ci#define PADCFG0_PMODE_SHIFT		10
7062306a36Sopenharmony_ci#define PADCFG0_PMODE_MASK		GENMASK(13, 10)
7162306a36Sopenharmony_ci#define PADCFG0_PMODE_GPIO		0
7262306a36Sopenharmony_ci#define PADCFG0_GPIORXDIS		BIT(9)
7362306a36Sopenharmony_ci#define PADCFG0_GPIOTXDIS		BIT(8)
7462306a36Sopenharmony_ci#define PADCFG0_GPIORXSTATE		BIT(1)
7562306a36Sopenharmony_ci#define PADCFG0_GPIOTXSTATE		BIT(0)
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci#define PADCFG1				0x004
7862306a36Sopenharmony_ci#define PADCFG1_TERM_UP			BIT(13)
7962306a36Sopenharmony_ci#define PADCFG1_TERM_SHIFT		10
8062306a36Sopenharmony_ci#define PADCFG1_TERM_MASK		GENMASK(12, 10)
8162306a36Sopenharmony_ci#define PADCFG1_TERM_20K		BIT(2)
8262306a36Sopenharmony_ci#define PADCFG1_TERM_5K			BIT(1)
8362306a36Sopenharmony_ci#define PADCFG1_TERM_4K			(BIT(2) | BIT(1))
8462306a36Sopenharmony_ci#define PADCFG1_TERM_1K			BIT(0)
8562306a36Sopenharmony_ci#define PADCFG1_TERM_952		(BIT(2) | BIT(0))
8662306a36Sopenharmony_ci#define PADCFG1_TERM_833		(BIT(1) | BIT(0))
8762306a36Sopenharmony_ci#define PADCFG1_TERM_800		(BIT(2) | BIT(1) | BIT(0))
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#define PADCFG2				0x008
9062306a36Sopenharmony_ci#define PADCFG2_DEBOUNCE_SHIFT		1
9162306a36Sopenharmony_ci#define PADCFG2_DEBOUNCE_MASK		GENMASK(4, 1)
9262306a36Sopenharmony_ci#define PADCFG2_DEBEN			BIT(0)
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#define DEBOUNCE_PERIOD_NSEC		31250
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistruct intel_pad_context {
9762306a36Sopenharmony_ci	u32 padcfg0;
9862306a36Sopenharmony_ci	u32 padcfg1;
9962306a36Sopenharmony_ci	u32 padcfg2;
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistruct intel_community_context {
10362306a36Sopenharmony_ci	u32 *intmask;
10462306a36Sopenharmony_ci	u32 *hostown;
10562306a36Sopenharmony_ci};
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci#define pin_to_padno(c, p)	((p) - (c)->pin_base)
10862306a36Sopenharmony_ci#define padgroup_offset(g, p)	((p) - (g)->base)
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistruct intel_community *intel_get_community(struct intel_pinctrl *pctrl, unsigned int pin)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	struct intel_community *community;
11362306a36Sopenharmony_ci	int i;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	for (i = 0; i < pctrl->ncommunities; i++) {
11662306a36Sopenharmony_ci		community = &pctrl->communities[i];
11762306a36Sopenharmony_ci		if (pin >= community->pin_base &&
11862306a36Sopenharmony_ci		    pin < community->pin_base + community->npins)
11962306a36Sopenharmony_ci			return community;
12062306a36Sopenharmony_ci	}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	dev_warn(pctrl->dev, "failed to find community for pin %u\n", pin);
12362306a36Sopenharmony_ci	return NULL;
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(intel_get_community, PINCTRL_INTEL);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic const struct intel_padgroup *
12862306a36Sopenharmony_ciintel_community_get_padgroup(const struct intel_community *community,
12962306a36Sopenharmony_ci			     unsigned int pin)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	int i;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	for (i = 0; i < community->ngpps; i++) {
13462306a36Sopenharmony_ci		const struct intel_padgroup *padgrp = &community->gpps[i];
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci		if (pin >= padgrp->base && pin < padgrp->base + padgrp->size)
13762306a36Sopenharmony_ci			return padgrp;
13862306a36Sopenharmony_ci	}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	return NULL;
14162306a36Sopenharmony_ci}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic void __iomem *intel_get_padcfg(struct intel_pinctrl *pctrl,
14462306a36Sopenharmony_ci				      unsigned int pin, unsigned int reg)
14562306a36Sopenharmony_ci{
14662306a36Sopenharmony_ci	const struct intel_community *community;
14762306a36Sopenharmony_ci	unsigned int padno;
14862306a36Sopenharmony_ci	size_t nregs;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	community = intel_get_community(pctrl, pin);
15162306a36Sopenharmony_ci	if (!community)
15262306a36Sopenharmony_ci		return NULL;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	padno = pin_to_padno(community, pin);
15562306a36Sopenharmony_ci	nregs = (community->features & PINCTRL_FEATURE_DEBOUNCE) ? 4 : 2;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	if (reg >= nregs * 4)
15862306a36Sopenharmony_ci		return NULL;
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_ci	return community->pad_regs + reg + padno * nregs * 4;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic bool intel_pad_owned_by_host(struct intel_pinctrl *pctrl, unsigned int pin)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	const struct intel_community *community;
16662306a36Sopenharmony_ci	const struct intel_padgroup *padgrp;
16762306a36Sopenharmony_ci	unsigned int gpp, offset, gpp_offset;
16862306a36Sopenharmony_ci	void __iomem *padown;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	community = intel_get_community(pctrl, pin);
17162306a36Sopenharmony_ci	if (!community)
17262306a36Sopenharmony_ci		return false;
17362306a36Sopenharmony_ci	if (!community->padown_offset)
17462306a36Sopenharmony_ci		return true;
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_ci	padgrp = intel_community_get_padgroup(community, pin);
17762306a36Sopenharmony_ci	if (!padgrp)
17862306a36Sopenharmony_ci		return false;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	gpp_offset = padgroup_offset(padgrp, pin);
18162306a36Sopenharmony_ci	gpp = PADOWN_GPP(gpp_offset);
18262306a36Sopenharmony_ci	offset = community->padown_offset + padgrp->padown_num * 4 + gpp * 4;
18362306a36Sopenharmony_ci	padown = community->regs + offset;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	return !(readl(padown) & PADOWN_MASK(gpp_offset));
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_cistatic bool intel_pad_acpi_mode(struct intel_pinctrl *pctrl, unsigned int pin)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	const struct intel_community *community;
19162306a36Sopenharmony_ci	const struct intel_padgroup *padgrp;
19262306a36Sopenharmony_ci	unsigned int offset, gpp_offset;
19362306a36Sopenharmony_ci	void __iomem *hostown;
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	community = intel_get_community(pctrl, pin);
19662306a36Sopenharmony_ci	if (!community)
19762306a36Sopenharmony_ci		return true;
19862306a36Sopenharmony_ci	if (!community->hostown_offset)
19962306a36Sopenharmony_ci		return false;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	padgrp = intel_community_get_padgroup(community, pin);
20262306a36Sopenharmony_ci	if (!padgrp)
20362306a36Sopenharmony_ci		return true;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	gpp_offset = padgroup_offset(padgrp, pin);
20662306a36Sopenharmony_ci	offset = community->hostown_offset + padgrp->reg_num * 4;
20762306a36Sopenharmony_ci	hostown = community->regs + offset;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	return !(readl(hostown) & BIT(gpp_offset));
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci/**
21362306a36Sopenharmony_ci * enum - Locking variants of the pad configuration
21462306a36Sopenharmony_ci *
21562306a36Sopenharmony_ci * @PAD_UNLOCKED:	pad is fully controlled by the configuration registers
21662306a36Sopenharmony_ci * @PAD_LOCKED:		pad configuration registers, except TX state, are locked
21762306a36Sopenharmony_ci * @PAD_LOCKED_TX:	pad configuration TX state is locked
21862306a36Sopenharmony_ci * @PAD_LOCKED_FULL:	pad configuration registers are locked completely
21962306a36Sopenharmony_ci *
22062306a36Sopenharmony_ci * Locking is considered as read-only mode for corresponding registers and
22162306a36Sopenharmony_ci * their respective fields. That said, TX state bit is locked separately from
22262306a36Sopenharmony_ci * the main locking scheme.
22362306a36Sopenharmony_ci */
22462306a36Sopenharmony_cienum {
22562306a36Sopenharmony_ci	PAD_UNLOCKED	= 0,
22662306a36Sopenharmony_ci	PAD_LOCKED	= 1,
22762306a36Sopenharmony_ci	PAD_LOCKED_TX	= 2,
22862306a36Sopenharmony_ci	PAD_LOCKED_FULL	= PAD_LOCKED | PAD_LOCKED_TX,
22962306a36Sopenharmony_ci};
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cistatic int intel_pad_locked(struct intel_pinctrl *pctrl, unsigned int pin)
23262306a36Sopenharmony_ci{
23362306a36Sopenharmony_ci	struct intel_community *community;
23462306a36Sopenharmony_ci	const struct intel_padgroup *padgrp;
23562306a36Sopenharmony_ci	unsigned int offset, gpp_offset;
23662306a36Sopenharmony_ci	u32 value;
23762306a36Sopenharmony_ci	int ret = PAD_UNLOCKED;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	community = intel_get_community(pctrl, pin);
24062306a36Sopenharmony_ci	if (!community)
24162306a36Sopenharmony_ci		return PAD_LOCKED_FULL;
24262306a36Sopenharmony_ci	if (!community->padcfglock_offset)
24362306a36Sopenharmony_ci		return PAD_UNLOCKED;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	padgrp = intel_community_get_padgroup(community, pin);
24662306a36Sopenharmony_ci	if (!padgrp)
24762306a36Sopenharmony_ci		return PAD_LOCKED_FULL;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	gpp_offset = padgroup_offset(padgrp, pin);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/*
25262306a36Sopenharmony_ci	 * If PADCFGLOCK and PADCFGLOCKTX bits are both clear for this pad,
25362306a36Sopenharmony_ci	 * the pad is considered unlocked. Any other case means that it is
25462306a36Sopenharmony_ci	 * either fully or partially locked.
25562306a36Sopenharmony_ci	 */
25662306a36Sopenharmony_ci	offset = community->padcfglock_offset + 0 + padgrp->reg_num * 8;
25762306a36Sopenharmony_ci	value = readl(community->regs + offset);
25862306a36Sopenharmony_ci	if (value & BIT(gpp_offset))
25962306a36Sopenharmony_ci		ret |= PAD_LOCKED;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	offset = community->padcfglock_offset + 4 + padgrp->reg_num * 8;
26262306a36Sopenharmony_ci	value = readl(community->regs + offset);
26362306a36Sopenharmony_ci	if (value & BIT(gpp_offset))
26462306a36Sopenharmony_ci		ret |= PAD_LOCKED_TX;
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	return ret;
26762306a36Sopenharmony_ci}
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_cistatic bool intel_pad_is_unlocked(struct intel_pinctrl *pctrl, unsigned int pin)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	return (intel_pad_locked(pctrl, pin) & PAD_LOCKED) == PAD_UNLOCKED;
27262306a36Sopenharmony_ci}
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic bool intel_pad_usable(struct intel_pinctrl *pctrl, unsigned int pin)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	return intel_pad_owned_by_host(pctrl, pin) && intel_pad_is_unlocked(pctrl, pin);
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ciint intel_get_groups_count(struct pinctrl_dev *pctldev)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	return pctrl->soc->ngroups;
28462306a36Sopenharmony_ci}
28562306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(intel_get_groups_count, PINCTRL_INTEL);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ciconst char *intel_get_group_name(struct pinctrl_dev *pctldev, unsigned int group)
28862306a36Sopenharmony_ci{
28962306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ci	return pctrl->soc->groups[group].grp.name;
29262306a36Sopenharmony_ci}
29362306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(intel_get_group_name, PINCTRL_INTEL);
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ciint intel_get_group_pins(struct pinctrl_dev *pctldev, unsigned int group,
29662306a36Sopenharmony_ci			 const unsigned int **pins, unsigned int *npins)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	*pins = pctrl->soc->groups[group].grp.pins;
30162306a36Sopenharmony_ci	*npins = pctrl->soc->groups[group].grp.npins;
30262306a36Sopenharmony_ci	return 0;
30362306a36Sopenharmony_ci}
30462306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(intel_get_group_pins, PINCTRL_INTEL);
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_cistatic void intel_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
30762306a36Sopenharmony_ci			       unsigned int pin)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
31062306a36Sopenharmony_ci	void __iomem *padcfg;
31162306a36Sopenharmony_ci	u32 cfg0, cfg1, mode;
31262306a36Sopenharmony_ci	int locked;
31362306a36Sopenharmony_ci	bool acpi;
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci	if (!intel_pad_owned_by_host(pctrl, pin)) {
31662306a36Sopenharmony_ci		seq_puts(s, "not available");
31762306a36Sopenharmony_ci		return;
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	cfg0 = readl(intel_get_padcfg(pctrl, pin, PADCFG0));
32162306a36Sopenharmony_ci	cfg1 = readl(intel_get_padcfg(pctrl, pin, PADCFG1));
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	mode = (cfg0 & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT;
32462306a36Sopenharmony_ci	if (mode == PADCFG0_PMODE_GPIO)
32562306a36Sopenharmony_ci		seq_puts(s, "GPIO ");
32662306a36Sopenharmony_ci	else
32762306a36Sopenharmony_ci		seq_printf(s, "mode %d ", mode);
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	seq_printf(s, "0x%08x 0x%08x", cfg0, cfg1);
33062306a36Sopenharmony_ci
33162306a36Sopenharmony_ci	/* Dump the additional PADCFG registers if available */
33262306a36Sopenharmony_ci	padcfg = intel_get_padcfg(pctrl, pin, PADCFG2);
33362306a36Sopenharmony_ci	if (padcfg)
33462306a36Sopenharmony_ci		seq_printf(s, " 0x%08x", readl(padcfg));
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci	locked = intel_pad_locked(pctrl, pin);
33762306a36Sopenharmony_ci	acpi = intel_pad_acpi_mode(pctrl, pin);
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	if (locked || acpi) {
34062306a36Sopenharmony_ci		seq_puts(s, " [");
34162306a36Sopenharmony_ci		if (locked)
34262306a36Sopenharmony_ci			seq_puts(s, "LOCKED");
34362306a36Sopenharmony_ci		if ((locked & PAD_LOCKED_FULL) == PAD_LOCKED_TX)
34462306a36Sopenharmony_ci			seq_puts(s, " tx");
34562306a36Sopenharmony_ci		else if ((locked & PAD_LOCKED_FULL) == PAD_LOCKED_FULL)
34662306a36Sopenharmony_ci			seq_puts(s, " full");
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci		if (locked && acpi)
34962306a36Sopenharmony_ci			seq_puts(s, ", ");
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci		if (acpi)
35262306a36Sopenharmony_ci			seq_puts(s, "ACPI");
35362306a36Sopenharmony_ci		seq_puts(s, "]");
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_cistatic const struct pinctrl_ops intel_pinctrl_ops = {
35862306a36Sopenharmony_ci	.get_groups_count = intel_get_groups_count,
35962306a36Sopenharmony_ci	.get_group_name = intel_get_group_name,
36062306a36Sopenharmony_ci	.get_group_pins = intel_get_group_pins,
36162306a36Sopenharmony_ci	.pin_dbg_show = intel_pin_dbg_show,
36262306a36Sopenharmony_ci};
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ciint intel_get_functions_count(struct pinctrl_dev *pctldev)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	return pctrl->soc->nfunctions;
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(intel_get_functions_count, PINCTRL_INTEL);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ciconst char *intel_get_function_name(struct pinctrl_dev *pctldev, unsigned int function)
37362306a36Sopenharmony_ci{
37462306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	return pctrl->soc->functions[function].func.name;
37762306a36Sopenharmony_ci}
37862306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(intel_get_function_name, PINCTRL_INTEL);
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ciint intel_get_function_groups(struct pinctrl_dev *pctldev, unsigned int function,
38162306a36Sopenharmony_ci			      const char * const **groups, unsigned int * const ngroups)
38262306a36Sopenharmony_ci{
38362306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	*groups = pctrl->soc->functions[function].func.groups;
38662306a36Sopenharmony_ci	*ngroups = pctrl->soc->functions[function].func.ngroups;
38762306a36Sopenharmony_ci	return 0;
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(intel_get_function_groups, PINCTRL_INTEL);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_cistatic int intel_pinmux_set_mux(struct pinctrl_dev *pctldev,
39262306a36Sopenharmony_ci				unsigned int function, unsigned int group)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
39562306a36Sopenharmony_ci	const struct intel_pingroup *grp = &pctrl->soc->groups[group];
39662306a36Sopenharmony_ci	unsigned long flags;
39762306a36Sopenharmony_ci	int i;
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	/*
40262306a36Sopenharmony_ci	 * All pins in the groups needs to be accessible and writable
40362306a36Sopenharmony_ci	 * before we can enable the mux for this group.
40462306a36Sopenharmony_ci	 */
40562306a36Sopenharmony_ci	for (i = 0; i < grp->grp.npins; i++) {
40662306a36Sopenharmony_ci		if (!intel_pad_usable(pctrl, grp->grp.pins[i])) {
40762306a36Sopenharmony_ci			raw_spin_unlock_irqrestore(&pctrl->lock, flags);
40862306a36Sopenharmony_ci			return -EBUSY;
40962306a36Sopenharmony_ci		}
41062306a36Sopenharmony_ci	}
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci	/* Now enable the mux setting for each pin in the group */
41362306a36Sopenharmony_ci	for (i = 0; i < grp->grp.npins; i++) {
41462306a36Sopenharmony_ci		void __iomem *padcfg0;
41562306a36Sopenharmony_ci		u32 value, pmode;
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci		padcfg0 = intel_get_padcfg(pctrl, grp->grp.pins[i], PADCFG0);
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci		value = readl(padcfg0);
42062306a36Sopenharmony_ci		value &= ~PADCFG0_PMODE_MASK;
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_ci		if (grp->modes)
42362306a36Sopenharmony_ci			pmode = grp->modes[i];
42462306a36Sopenharmony_ci		else
42562306a36Sopenharmony_ci			pmode = grp->mode;
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci		value |= pmode << PADCFG0_PMODE_SHIFT;
42862306a36Sopenharmony_ci		writel(value, padcfg0);
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return 0;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cistatic void __intel_gpio_set_direction(void __iomem *padcfg0, bool input)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	u32 value;
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	value = readl(padcfg0);
44162306a36Sopenharmony_ci	if (input) {
44262306a36Sopenharmony_ci		value &= ~PADCFG0_GPIORXDIS;
44362306a36Sopenharmony_ci		value |= PADCFG0_GPIOTXDIS;
44462306a36Sopenharmony_ci	} else {
44562306a36Sopenharmony_ci		value &= ~PADCFG0_GPIOTXDIS;
44662306a36Sopenharmony_ci		value |= PADCFG0_GPIORXDIS;
44762306a36Sopenharmony_ci	}
44862306a36Sopenharmony_ci	writel(value, padcfg0);
44962306a36Sopenharmony_ci}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_cistatic int __intel_gpio_get_gpio_mode(u32 value)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	return (value & PADCFG0_PMODE_MASK) >> PADCFG0_PMODE_SHIFT;
45462306a36Sopenharmony_ci}
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_cistatic int intel_gpio_get_gpio_mode(void __iomem *padcfg0)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	return __intel_gpio_get_gpio_mode(readl(padcfg0));
45962306a36Sopenharmony_ci}
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_cistatic void intel_gpio_set_gpio_mode(void __iomem *padcfg0)
46262306a36Sopenharmony_ci{
46362306a36Sopenharmony_ci	u32 value;
46462306a36Sopenharmony_ci
46562306a36Sopenharmony_ci	value = readl(padcfg0);
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci	/* Put the pad into GPIO mode */
46862306a36Sopenharmony_ci	value &= ~PADCFG0_PMODE_MASK;
46962306a36Sopenharmony_ci	value |= PADCFG0_PMODE_GPIO;
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	/* Disable TX buffer and enable RX (this will be input) */
47262306a36Sopenharmony_ci	value &= ~PADCFG0_GPIORXDIS;
47362306a36Sopenharmony_ci	value |= PADCFG0_GPIOTXDIS;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	/* Disable SCI/SMI/NMI generation */
47662306a36Sopenharmony_ci	value &= ~(PADCFG0_GPIROUTIOXAPIC | PADCFG0_GPIROUTSCI);
47762306a36Sopenharmony_ci	value &= ~(PADCFG0_GPIROUTSMI | PADCFG0_GPIROUTNMI);
47862306a36Sopenharmony_ci
47962306a36Sopenharmony_ci	writel(value, padcfg0);
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_cistatic int intel_gpio_request_enable(struct pinctrl_dev *pctldev,
48362306a36Sopenharmony_ci				     struct pinctrl_gpio_range *range,
48462306a36Sopenharmony_ci				     unsigned int pin)
48562306a36Sopenharmony_ci{
48662306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
48762306a36Sopenharmony_ci	void __iomem *padcfg0;
48862306a36Sopenharmony_ci	unsigned long flags;
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci	if (!intel_pad_owned_by_host(pctrl, pin)) {
49562306a36Sopenharmony_ci		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
49662306a36Sopenharmony_ci		return -EBUSY;
49762306a36Sopenharmony_ci	}
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	if (!intel_pad_is_unlocked(pctrl, pin)) {
50062306a36Sopenharmony_ci		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
50162306a36Sopenharmony_ci		return 0;
50262306a36Sopenharmony_ci	}
50362306a36Sopenharmony_ci
50462306a36Sopenharmony_ci	/*
50562306a36Sopenharmony_ci	 * If pin is already configured in GPIO mode, we assume that
50662306a36Sopenharmony_ci	 * firmware provides correct settings. In such case we avoid
50762306a36Sopenharmony_ci	 * potential glitches on the pin. Otherwise, for the pin in
50862306a36Sopenharmony_ci	 * alternative mode, consumer has to supply respective flags.
50962306a36Sopenharmony_ci	 */
51062306a36Sopenharmony_ci	if (intel_gpio_get_gpio_mode(padcfg0) == PADCFG0_PMODE_GPIO) {
51162306a36Sopenharmony_ci		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
51262306a36Sopenharmony_ci		return 0;
51362306a36Sopenharmony_ci	}
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	intel_gpio_set_gpio_mode(padcfg0);
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	return 0;
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic int intel_gpio_set_direction(struct pinctrl_dev *pctldev,
52362306a36Sopenharmony_ci				    struct pinctrl_gpio_range *range,
52462306a36Sopenharmony_ci				    unsigned int pin, bool input)
52562306a36Sopenharmony_ci{
52662306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
52762306a36Sopenharmony_ci	void __iomem *padcfg0;
52862306a36Sopenharmony_ci	unsigned long flags;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
53362306a36Sopenharmony_ci	__intel_gpio_set_direction(padcfg0, input);
53462306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	return 0;
53762306a36Sopenharmony_ci}
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistatic const struct pinmux_ops intel_pinmux_ops = {
54062306a36Sopenharmony_ci	.get_functions_count = intel_get_functions_count,
54162306a36Sopenharmony_ci	.get_function_name = intel_get_function_name,
54262306a36Sopenharmony_ci	.get_function_groups = intel_get_function_groups,
54362306a36Sopenharmony_ci	.set_mux = intel_pinmux_set_mux,
54462306a36Sopenharmony_ci	.gpio_request_enable = intel_gpio_request_enable,
54562306a36Sopenharmony_ci	.gpio_set_direction = intel_gpio_set_direction,
54662306a36Sopenharmony_ci};
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_cistatic int intel_config_get_pull(struct intel_pinctrl *pctrl, unsigned int pin,
54962306a36Sopenharmony_ci				 enum pin_config_param param, u32 *arg)
55062306a36Sopenharmony_ci{
55162306a36Sopenharmony_ci	const struct intel_community *community;
55262306a36Sopenharmony_ci	void __iomem *padcfg1;
55362306a36Sopenharmony_ci	unsigned long flags;
55462306a36Sopenharmony_ci	u32 value, term;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	community = intel_get_community(pctrl, pin);
55762306a36Sopenharmony_ci	padcfg1 = intel_get_padcfg(pctrl, pin, PADCFG1);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
56062306a36Sopenharmony_ci	value = readl(padcfg1);
56162306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci	term = (value & PADCFG1_TERM_MASK) >> PADCFG1_TERM_SHIFT;
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	switch (param) {
56662306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_DISABLE:
56762306a36Sopenharmony_ci		if (term)
56862306a36Sopenharmony_ci			return -EINVAL;
56962306a36Sopenharmony_ci		break;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_PULL_UP:
57262306a36Sopenharmony_ci		if (!term || !(value & PADCFG1_TERM_UP))
57362306a36Sopenharmony_ci			return -EINVAL;
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci		switch (term) {
57662306a36Sopenharmony_ci		case PADCFG1_TERM_833:
57762306a36Sopenharmony_ci			*arg = 833;
57862306a36Sopenharmony_ci			break;
57962306a36Sopenharmony_ci		case PADCFG1_TERM_1K:
58062306a36Sopenharmony_ci			*arg = 1000;
58162306a36Sopenharmony_ci			break;
58262306a36Sopenharmony_ci		case PADCFG1_TERM_4K:
58362306a36Sopenharmony_ci			*arg = 4000;
58462306a36Sopenharmony_ci			break;
58562306a36Sopenharmony_ci		case PADCFG1_TERM_5K:
58662306a36Sopenharmony_ci			*arg = 5000;
58762306a36Sopenharmony_ci			break;
58862306a36Sopenharmony_ci		case PADCFG1_TERM_20K:
58962306a36Sopenharmony_ci			*arg = 20000;
59062306a36Sopenharmony_ci			break;
59162306a36Sopenharmony_ci		}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci		break;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_PULL_DOWN:
59662306a36Sopenharmony_ci		if (!term || value & PADCFG1_TERM_UP)
59762306a36Sopenharmony_ci			return -EINVAL;
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ci		switch (term) {
60062306a36Sopenharmony_ci		case PADCFG1_TERM_833:
60162306a36Sopenharmony_ci			if (!(community->features & PINCTRL_FEATURE_1K_PD))
60262306a36Sopenharmony_ci				return -EINVAL;
60362306a36Sopenharmony_ci			*arg = 833;
60462306a36Sopenharmony_ci			break;
60562306a36Sopenharmony_ci		case PADCFG1_TERM_1K:
60662306a36Sopenharmony_ci			if (!(community->features & PINCTRL_FEATURE_1K_PD))
60762306a36Sopenharmony_ci				return -EINVAL;
60862306a36Sopenharmony_ci			*arg = 1000;
60962306a36Sopenharmony_ci			break;
61062306a36Sopenharmony_ci		case PADCFG1_TERM_4K:
61162306a36Sopenharmony_ci			*arg = 4000;
61262306a36Sopenharmony_ci			break;
61362306a36Sopenharmony_ci		case PADCFG1_TERM_5K:
61462306a36Sopenharmony_ci			*arg = 5000;
61562306a36Sopenharmony_ci			break;
61662306a36Sopenharmony_ci		case PADCFG1_TERM_20K:
61762306a36Sopenharmony_ci			*arg = 20000;
61862306a36Sopenharmony_ci			break;
61962306a36Sopenharmony_ci		}
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci		break;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	default:
62462306a36Sopenharmony_ci		return -EINVAL;
62562306a36Sopenharmony_ci	}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_ci	return 0;
62862306a36Sopenharmony_ci}
62962306a36Sopenharmony_ci
63062306a36Sopenharmony_cistatic int intel_config_get_debounce(struct intel_pinctrl *pctrl, unsigned int pin,
63162306a36Sopenharmony_ci				     enum pin_config_param param, u32 *arg)
63262306a36Sopenharmony_ci{
63362306a36Sopenharmony_ci	void __iomem *padcfg2;
63462306a36Sopenharmony_ci	unsigned long flags;
63562306a36Sopenharmony_ci	unsigned long v;
63662306a36Sopenharmony_ci	u32 value2;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	padcfg2 = intel_get_padcfg(pctrl, pin, PADCFG2);
63962306a36Sopenharmony_ci	if (!padcfg2)
64062306a36Sopenharmony_ci		return -ENOTSUPP;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
64362306a36Sopenharmony_ci	value2 = readl(padcfg2);
64462306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
64562306a36Sopenharmony_ci	if (!(value2 & PADCFG2_DEBEN))
64662306a36Sopenharmony_ci		return -EINVAL;
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	v = (value2 & PADCFG2_DEBOUNCE_MASK) >> PADCFG2_DEBOUNCE_SHIFT;
64962306a36Sopenharmony_ci	*arg = BIT(v) * DEBOUNCE_PERIOD_NSEC / NSEC_PER_USEC;
65062306a36Sopenharmony_ci
65162306a36Sopenharmony_ci	return 0;
65262306a36Sopenharmony_ci}
65362306a36Sopenharmony_ci
65462306a36Sopenharmony_cistatic int intel_config_get(struct pinctrl_dev *pctldev, unsigned int pin,
65562306a36Sopenharmony_ci			    unsigned long *config)
65662306a36Sopenharmony_ci{
65762306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
65862306a36Sopenharmony_ci	enum pin_config_param param = pinconf_to_config_param(*config);
65962306a36Sopenharmony_ci	u32 arg = 0;
66062306a36Sopenharmony_ci	int ret;
66162306a36Sopenharmony_ci
66262306a36Sopenharmony_ci	if (!intel_pad_owned_by_host(pctrl, pin))
66362306a36Sopenharmony_ci		return -ENOTSUPP;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	switch (param) {
66662306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_DISABLE:
66762306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_PULL_UP:
66862306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_PULL_DOWN:
66962306a36Sopenharmony_ci		ret = intel_config_get_pull(pctrl, pin, param, &arg);
67062306a36Sopenharmony_ci		if (ret)
67162306a36Sopenharmony_ci			return ret;
67262306a36Sopenharmony_ci		break;
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_ci	case PIN_CONFIG_INPUT_DEBOUNCE:
67562306a36Sopenharmony_ci		ret = intel_config_get_debounce(pctrl, pin, param, &arg);
67662306a36Sopenharmony_ci		if (ret)
67762306a36Sopenharmony_ci			return ret;
67862306a36Sopenharmony_ci		break;
67962306a36Sopenharmony_ci
68062306a36Sopenharmony_ci	default:
68162306a36Sopenharmony_ci		return -ENOTSUPP;
68262306a36Sopenharmony_ci	}
68362306a36Sopenharmony_ci
68462306a36Sopenharmony_ci	*config = pinconf_to_config_packed(param, arg);
68562306a36Sopenharmony_ci	return 0;
68662306a36Sopenharmony_ci}
68762306a36Sopenharmony_ci
68862306a36Sopenharmony_cistatic int intel_config_set_pull(struct intel_pinctrl *pctrl, unsigned int pin,
68962306a36Sopenharmony_ci				 unsigned long config)
69062306a36Sopenharmony_ci{
69162306a36Sopenharmony_ci	unsigned int param = pinconf_to_config_param(config);
69262306a36Sopenharmony_ci	unsigned int arg = pinconf_to_config_argument(config);
69362306a36Sopenharmony_ci	const struct intel_community *community;
69462306a36Sopenharmony_ci	void __iomem *padcfg1;
69562306a36Sopenharmony_ci	unsigned long flags;
69662306a36Sopenharmony_ci	int ret = 0;
69762306a36Sopenharmony_ci	u32 value;
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	community = intel_get_community(pctrl, pin);
70062306a36Sopenharmony_ci	padcfg1 = intel_get_padcfg(pctrl, pin, PADCFG1);
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	value = readl(padcfg1);
70562306a36Sopenharmony_ci	value &= ~(PADCFG1_TERM_MASK | PADCFG1_TERM_UP);
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	/* Set default strength value in case none is given */
70862306a36Sopenharmony_ci	if (arg == 1)
70962306a36Sopenharmony_ci		arg = 5000;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	switch (param) {
71262306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_DISABLE:
71362306a36Sopenharmony_ci		break;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_PULL_UP:
71662306a36Sopenharmony_ci		switch (arg) {
71762306a36Sopenharmony_ci		case 20000:
71862306a36Sopenharmony_ci			value |= PADCFG1_TERM_20K << PADCFG1_TERM_SHIFT;
71962306a36Sopenharmony_ci			break;
72062306a36Sopenharmony_ci		case 5000:
72162306a36Sopenharmony_ci			value |= PADCFG1_TERM_5K << PADCFG1_TERM_SHIFT;
72262306a36Sopenharmony_ci			break;
72362306a36Sopenharmony_ci		case 4000:
72462306a36Sopenharmony_ci			value |= PADCFG1_TERM_4K << PADCFG1_TERM_SHIFT;
72562306a36Sopenharmony_ci			break;
72662306a36Sopenharmony_ci		case 1000:
72762306a36Sopenharmony_ci			value |= PADCFG1_TERM_1K << PADCFG1_TERM_SHIFT;
72862306a36Sopenharmony_ci			break;
72962306a36Sopenharmony_ci		case 833:
73062306a36Sopenharmony_ci			value |= PADCFG1_TERM_833 << PADCFG1_TERM_SHIFT;
73162306a36Sopenharmony_ci			break;
73262306a36Sopenharmony_ci		default:
73362306a36Sopenharmony_ci			ret = -EINVAL;
73462306a36Sopenharmony_ci			break;
73562306a36Sopenharmony_ci		}
73662306a36Sopenharmony_ci
73762306a36Sopenharmony_ci		value |= PADCFG1_TERM_UP;
73862306a36Sopenharmony_ci		break;
73962306a36Sopenharmony_ci
74062306a36Sopenharmony_ci	case PIN_CONFIG_BIAS_PULL_DOWN:
74162306a36Sopenharmony_ci		switch (arg) {
74262306a36Sopenharmony_ci		case 20000:
74362306a36Sopenharmony_ci			value |= PADCFG1_TERM_20K << PADCFG1_TERM_SHIFT;
74462306a36Sopenharmony_ci			break;
74562306a36Sopenharmony_ci		case 5000:
74662306a36Sopenharmony_ci			value |= PADCFG1_TERM_5K << PADCFG1_TERM_SHIFT;
74762306a36Sopenharmony_ci			break;
74862306a36Sopenharmony_ci		case 4000:
74962306a36Sopenharmony_ci			value |= PADCFG1_TERM_4K << PADCFG1_TERM_SHIFT;
75062306a36Sopenharmony_ci			break;
75162306a36Sopenharmony_ci		case 1000:
75262306a36Sopenharmony_ci			if (!(community->features & PINCTRL_FEATURE_1K_PD)) {
75362306a36Sopenharmony_ci				ret = -EINVAL;
75462306a36Sopenharmony_ci				break;
75562306a36Sopenharmony_ci			}
75662306a36Sopenharmony_ci			value |= PADCFG1_TERM_1K << PADCFG1_TERM_SHIFT;
75762306a36Sopenharmony_ci			break;
75862306a36Sopenharmony_ci		case 833:
75962306a36Sopenharmony_ci			if (!(community->features & PINCTRL_FEATURE_1K_PD)) {
76062306a36Sopenharmony_ci				ret = -EINVAL;
76162306a36Sopenharmony_ci				break;
76262306a36Sopenharmony_ci			}
76362306a36Sopenharmony_ci			value |= PADCFG1_TERM_833 << PADCFG1_TERM_SHIFT;
76462306a36Sopenharmony_ci			break;
76562306a36Sopenharmony_ci		default:
76662306a36Sopenharmony_ci			ret = -EINVAL;
76762306a36Sopenharmony_ci			break;
76862306a36Sopenharmony_ci		}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci		break;
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	default:
77362306a36Sopenharmony_ci		ret = -EINVAL;
77462306a36Sopenharmony_ci		break;
77562306a36Sopenharmony_ci	}
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	if (!ret)
77862306a36Sopenharmony_ci		writel(value, padcfg1);
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	return ret;
78362306a36Sopenharmony_ci}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_cistatic int intel_config_set_debounce(struct intel_pinctrl *pctrl,
78662306a36Sopenharmony_ci				     unsigned int pin, unsigned int debounce)
78762306a36Sopenharmony_ci{
78862306a36Sopenharmony_ci	void __iomem *padcfg0, *padcfg2;
78962306a36Sopenharmony_ci	unsigned long flags;
79062306a36Sopenharmony_ci	u32 value0, value2;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	padcfg2 = intel_get_padcfg(pctrl, pin, PADCFG2);
79362306a36Sopenharmony_ci	if (!padcfg2)
79462306a36Sopenharmony_ci		return -ENOTSUPP;
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	padcfg0 = intel_get_padcfg(pctrl, pin, PADCFG0);
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_ci	value0 = readl(padcfg0);
80162306a36Sopenharmony_ci	value2 = readl(padcfg2);
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	/* Disable glitch filter and debouncer */
80462306a36Sopenharmony_ci	value0 &= ~PADCFG0_PREGFRXSEL;
80562306a36Sopenharmony_ci	value2 &= ~(PADCFG2_DEBEN | PADCFG2_DEBOUNCE_MASK);
80662306a36Sopenharmony_ci
80762306a36Sopenharmony_ci	if (debounce) {
80862306a36Sopenharmony_ci		unsigned long v;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci		v = order_base_2(debounce * NSEC_PER_USEC / DEBOUNCE_PERIOD_NSEC);
81162306a36Sopenharmony_ci		if (v < 3 || v > 15) {
81262306a36Sopenharmony_ci			raw_spin_unlock_irqrestore(&pctrl->lock, flags);
81362306a36Sopenharmony_ci			return -EINVAL;
81462306a36Sopenharmony_ci		}
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci		/* Enable glitch filter and debouncer */
81762306a36Sopenharmony_ci		value0 |= PADCFG0_PREGFRXSEL;
81862306a36Sopenharmony_ci		value2 |= v << PADCFG2_DEBOUNCE_SHIFT;
81962306a36Sopenharmony_ci		value2 |= PADCFG2_DEBEN;
82062306a36Sopenharmony_ci	}
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	writel(value0, padcfg0);
82362306a36Sopenharmony_ci	writel(value2, padcfg2);
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	return 0;
82862306a36Sopenharmony_ci}
82962306a36Sopenharmony_ci
83062306a36Sopenharmony_cistatic int intel_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
83162306a36Sopenharmony_ci			  unsigned long *configs, unsigned int nconfigs)
83262306a36Sopenharmony_ci{
83362306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
83462306a36Sopenharmony_ci	int i, ret;
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci	if (!intel_pad_usable(pctrl, pin))
83762306a36Sopenharmony_ci		return -ENOTSUPP;
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	for (i = 0; i < nconfigs; i++) {
84062306a36Sopenharmony_ci		switch (pinconf_to_config_param(configs[i])) {
84162306a36Sopenharmony_ci		case PIN_CONFIG_BIAS_DISABLE:
84262306a36Sopenharmony_ci		case PIN_CONFIG_BIAS_PULL_UP:
84362306a36Sopenharmony_ci		case PIN_CONFIG_BIAS_PULL_DOWN:
84462306a36Sopenharmony_ci			ret = intel_config_set_pull(pctrl, pin, configs[i]);
84562306a36Sopenharmony_ci			if (ret)
84662306a36Sopenharmony_ci				return ret;
84762306a36Sopenharmony_ci			break;
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_ci		case PIN_CONFIG_INPUT_DEBOUNCE:
85062306a36Sopenharmony_ci			ret = intel_config_set_debounce(pctrl, pin,
85162306a36Sopenharmony_ci				pinconf_to_config_argument(configs[i]));
85262306a36Sopenharmony_ci			if (ret)
85362306a36Sopenharmony_ci				return ret;
85462306a36Sopenharmony_ci			break;
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci		default:
85762306a36Sopenharmony_ci			return -ENOTSUPP;
85862306a36Sopenharmony_ci		}
85962306a36Sopenharmony_ci	}
86062306a36Sopenharmony_ci
86162306a36Sopenharmony_ci	return 0;
86262306a36Sopenharmony_ci}
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_cistatic const struct pinconf_ops intel_pinconf_ops = {
86562306a36Sopenharmony_ci	.is_generic = true,
86662306a36Sopenharmony_ci	.pin_config_get = intel_config_get,
86762306a36Sopenharmony_ci	.pin_config_set = intel_config_set,
86862306a36Sopenharmony_ci};
86962306a36Sopenharmony_ci
87062306a36Sopenharmony_cistatic const struct pinctrl_desc intel_pinctrl_desc = {
87162306a36Sopenharmony_ci	.pctlops = &intel_pinctrl_ops,
87262306a36Sopenharmony_ci	.pmxops = &intel_pinmux_ops,
87362306a36Sopenharmony_ci	.confops = &intel_pinconf_ops,
87462306a36Sopenharmony_ci	.owner = THIS_MODULE,
87562306a36Sopenharmony_ci};
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci/**
87862306a36Sopenharmony_ci * intel_gpio_to_pin() - Translate from GPIO offset to pin number
87962306a36Sopenharmony_ci * @pctrl: Pinctrl structure
88062306a36Sopenharmony_ci * @offset: GPIO offset from gpiolib
88162306a36Sopenharmony_ci * @community: Community is filled here if not %NULL
88262306a36Sopenharmony_ci * @padgrp: Pad group is filled here if not %NULL
88362306a36Sopenharmony_ci *
88462306a36Sopenharmony_ci * When coming through gpiolib irqchip, the GPIO offset is not
88562306a36Sopenharmony_ci * automatically translated to pinctrl pin number. This function can be
88662306a36Sopenharmony_ci * used to find out the corresponding pinctrl pin.
88762306a36Sopenharmony_ci *
88862306a36Sopenharmony_ci * Return: a pin number and pointers to the community and pad group, which
88962306a36Sopenharmony_ci * the pin belongs to, or negative error code if translation can't be done.
89062306a36Sopenharmony_ci */
89162306a36Sopenharmony_cistatic int intel_gpio_to_pin(struct intel_pinctrl *pctrl, unsigned int offset,
89262306a36Sopenharmony_ci			     const struct intel_community **community,
89362306a36Sopenharmony_ci			     const struct intel_padgroup **padgrp)
89462306a36Sopenharmony_ci{
89562306a36Sopenharmony_ci	int i;
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	for (i = 0; i < pctrl->ncommunities; i++) {
89862306a36Sopenharmony_ci		const struct intel_community *comm = &pctrl->communities[i];
89962306a36Sopenharmony_ci		int j;
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci		for (j = 0; j < comm->ngpps; j++) {
90262306a36Sopenharmony_ci			const struct intel_padgroup *pgrp = &comm->gpps[j];
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci			if (pgrp->gpio_base == INTEL_GPIO_BASE_NOMAP)
90562306a36Sopenharmony_ci				continue;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci			if (offset >= pgrp->gpio_base &&
90862306a36Sopenharmony_ci			    offset < pgrp->gpio_base + pgrp->size) {
90962306a36Sopenharmony_ci				int pin;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci				pin = pgrp->base + offset - pgrp->gpio_base;
91262306a36Sopenharmony_ci				if (community)
91362306a36Sopenharmony_ci					*community = comm;
91462306a36Sopenharmony_ci				if (padgrp)
91562306a36Sopenharmony_ci					*padgrp = pgrp;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci				return pin;
91862306a36Sopenharmony_ci			}
91962306a36Sopenharmony_ci		}
92062306a36Sopenharmony_ci	}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_ci	return -EINVAL;
92362306a36Sopenharmony_ci}
92462306a36Sopenharmony_ci
92562306a36Sopenharmony_ci/**
92662306a36Sopenharmony_ci * intel_pin_to_gpio() - Translate from pin number to GPIO offset
92762306a36Sopenharmony_ci * @pctrl: Pinctrl structure
92862306a36Sopenharmony_ci * @pin: pin number
92962306a36Sopenharmony_ci *
93062306a36Sopenharmony_ci * Translate the pin number of pinctrl to GPIO offset
93162306a36Sopenharmony_ci *
93262306a36Sopenharmony_ci * Return: a GPIO offset, or negative error code if translation can't be done.
93362306a36Sopenharmony_ci */
93462306a36Sopenharmony_cistatic __maybe_unused int intel_pin_to_gpio(struct intel_pinctrl *pctrl, int pin)
93562306a36Sopenharmony_ci{
93662306a36Sopenharmony_ci	const struct intel_community *community;
93762306a36Sopenharmony_ci	const struct intel_padgroup *padgrp;
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_ci	community = intel_get_community(pctrl, pin);
94062306a36Sopenharmony_ci	if (!community)
94162306a36Sopenharmony_ci		return -EINVAL;
94262306a36Sopenharmony_ci
94362306a36Sopenharmony_ci	padgrp = intel_community_get_padgroup(community, pin);
94462306a36Sopenharmony_ci	if (!padgrp)
94562306a36Sopenharmony_ci		return -EINVAL;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	return pin - padgrp->base + padgrp->gpio_base;
94862306a36Sopenharmony_ci}
94962306a36Sopenharmony_ci
95062306a36Sopenharmony_cistatic int intel_gpio_get(struct gpio_chip *chip, unsigned int offset)
95162306a36Sopenharmony_ci{
95262306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
95362306a36Sopenharmony_ci	void __iomem *reg;
95462306a36Sopenharmony_ci	u32 padcfg0;
95562306a36Sopenharmony_ci	int pin;
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci	pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL);
95862306a36Sopenharmony_ci	if (pin < 0)
95962306a36Sopenharmony_ci		return -EINVAL;
96062306a36Sopenharmony_ci
96162306a36Sopenharmony_ci	reg = intel_get_padcfg(pctrl, pin, PADCFG0);
96262306a36Sopenharmony_ci	if (!reg)
96362306a36Sopenharmony_ci		return -EINVAL;
96462306a36Sopenharmony_ci
96562306a36Sopenharmony_ci	padcfg0 = readl(reg);
96662306a36Sopenharmony_ci	if (!(padcfg0 & PADCFG0_GPIOTXDIS))
96762306a36Sopenharmony_ci		return !!(padcfg0 & PADCFG0_GPIOTXSTATE);
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	return !!(padcfg0 & PADCFG0_GPIORXSTATE);
97062306a36Sopenharmony_ci}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_cistatic void intel_gpio_set(struct gpio_chip *chip, unsigned int offset,
97362306a36Sopenharmony_ci			   int value)
97462306a36Sopenharmony_ci{
97562306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
97662306a36Sopenharmony_ci	unsigned long flags;
97762306a36Sopenharmony_ci	void __iomem *reg;
97862306a36Sopenharmony_ci	u32 padcfg0;
97962306a36Sopenharmony_ci	int pin;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL);
98262306a36Sopenharmony_ci	if (pin < 0)
98362306a36Sopenharmony_ci		return;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	reg = intel_get_padcfg(pctrl, pin, PADCFG0);
98662306a36Sopenharmony_ci	if (!reg)
98762306a36Sopenharmony_ci		return;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
99062306a36Sopenharmony_ci	padcfg0 = readl(reg);
99162306a36Sopenharmony_ci	if (value)
99262306a36Sopenharmony_ci		padcfg0 |= PADCFG0_GPIOTXSTATE;
99362306a36Sopenharmony_ci	else
99462306a36Sopenharmony_ci		padcfg0 &= ~PADCFG0_GPIOTXSTATE;
99562306a36Sopenharmony_ci	writel(padcfg0, reg);
99662306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
99762306a36Sopenharmony_ci}
99862306a36Sopenharmony_ci
99962306a36Sopenharmony_cistatic int intel_gpio_get_direction(struct gpio_chip *chip, unsigned int offset)
100062306a36Sopenharmony_ci{
100162306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = gpiochip_get_data(chip);
100262306a36Sopenharmony_ci	unsigned long flags;
100362306a36Sopenharmony_ci	void __iomem *reg;
100462306a36Sopenharmony_ci	u32 padcfg0;
100562306a36Sopenharmony_ci	int pin;
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	pin = intel_gpio_to_pin(pctrl, offset, NULL, NULL);
100862306a36Sopenharmony_ci	if (pin < 0)
100962306a36Sopenharmony_ci		return -EINVAL;
101062306a36Sopenharmony_ci
101162306a36Sopenharmony_ci	reg = intel_get_padcfg(pctrl, pin, PADCFG0);
101262306a36Sopenharmony_ci	if (!reg)
101362306a36Sopenharmony_ci		return -EINVAL;
101462306a36Sopenharmony_ci
101562306a36Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
101662306a36Sopenharmony_ci	padcfg0 = readl(reg);
101762306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
101862306a36Sopenharmony_ci	if (padcfg0 & PADCFG0_PMODE_MASK)
101962306a36Sopenharmony_ci		return -EINVAL;
102062306a36Sopenharmony_ci
102162306a36Sopenharmony_ci	if (padcfg0 & PADCFG0_GPIOTXDIS)
102262306a36Sopenharmony_ci		return GPIO_LINE_DIRECTION_IN;
102362306a36Sopenharmony_ci
102462306a36Sopenharmony_ci	return GPIO_LINE_DIRECTION_OUT;
102562306a36Sopenharmony_ci}
102662306a36Sopenharmony_ci
102762306a36Sopenharmony_cistatic int intel_gpio_direction_input(struct gpio_chip *chip, unsigned int offset)
102862306a36Sopenharmony_ci{
102962306a36Sopenharmony_ci	return pinctrl_gpio_direction_input(chip->base + offset);
103062306a36Sopenharmony_ci}
103162306a36Sopenharmony_ci
103262306a36Sopenharmony_cistatic int intel_gpio_direction_output(struct gpio_chip *chip, unsigned int offset,
103362306a36Sopenharmony_ci				       int value)
103462306a36Sopenharmony_ci{
103562306a36Sopenharmony_ci	intel_gpio_set(chip, offset, value);
103662306a36Sopenharmony_ci	return pinctrl_gpio_direction_output(chip->base + offset);
103762306a36Sopenharmony_ci}
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_cistatic const struct gpio_chip intel_gpio_chip = {
104062306a36Sopenharmony_ci	.owner = THIS_MODULE,
104162306a36Sopenharmony_ci	.request = gpiochip_generic_request,
104262306a36Sopenharmony_ci	.free = gpiochip_generic_free,
104362306a36Sopenharmony_ci	.get_direction = intel_gpio_get_direction,
104462306a36Sopenharmony_ci	.direction_input = intel_gpio_direction_input,
104562306a36Sopenharmony_ci	.direction_output = intel_gpio_direction_output,
104662306a36Sopenharmony_ci	.get = intel_gpio_get,
104762306a36Sopenharmony_ci	.set = intel_gpio_set,
104862306a36Sopenharmony_ci	.set_config = gpiochip_generic_config,
104962306a36Sopenharmony_ci};
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_cistatic void intel_gpio_irq_ack(struct irq_data *d)
105262306a36Sopenharmony_ci{
105362306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
105462306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
105562306a36Sopenharmony_ci	const struct intel_community *community;
105662306a36Sopenharmony_ci	const struct intel_padgroup *padgrp;
105762306a36Sopenharmony_ci	int pin;
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), &community, &padgrp);
106062306a36Sopenharmony_ci	if (pin >= 0) {
106162306a36Sopenharmony_ci		unsigned int gpp, gpp_offset, is_offset;
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci		gpp = padgrp->reg_num;
106462306a36Sopenharmony_ci		gpp_offset = padgroup_offset(padgrp, pin);
106562306a36Sopenharmony_ci		is_offset = community->is_offset + gpp * 4;
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci		raw_spin_lock(&pctrl->lock);
106862306a36Sopenharmony_ci		writel(BIT(gpp_offset), community->regs + is_offset);
106962306a36Sopenharmony_ci		raw_spin_unlock(&pctrl->lock);
107062306a36Sopenharmony_ci	}
107162306a36Sopenharmony_ci}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_cistatic void intel_gpio_irq_mask_unmask(struct gpio_chip *gc, irq_hw_number_t hwirq, bool mask)
107462306a36Sopenharmony_ci{
107562306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
107662306a36Sopenharmony_ci	const struct intel_community *community;
107762306a36Sopenharmony_ci	const struct intel_padgroup *padgrp;
107862306a36Sopenharmony_ci	int pin;
107962306a36Sopenharmony_ci
108062306a36Sopenharmony_ci	pin = intel_gpio_to_pin(pctrl, hwirq, &community, &padgrp);
108162306a36Sopenharmony_ci	if (pin >= 0) {
108262306a36Sopenharmony_ci		unsigned int gpp, gpp_offset;
108362306a36Sopenharmony_ci		unsigned long flags;
108462306a36Sopenharmony_ci		void __iomem *reg, *is;
108562306a36Sopenharmony_ci		u32 value;
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_ci		gpp = padgrp->reg_num;
108862306a36Sopenharmony_ci		gpp_offset = padgroup_offset(padgrp, pin);
108962306a36Sopenharmony_ci
109062306a36Sopenharmony_ci		reg = community->regs + community->ie_offset + gpp * 4;
109162306a36Sopenharmony_ci		is = community->regs + community->is_offset + gpp * 4;
109262306a36Sopenharmony_ci
109362306a36Sopenharmony_ci		raw_spin_lock_irqsave(&pctrl->lock, flags);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci		/* Clear interrupt status first to avoid unexpected interrupt */
109662306a36Sopenharmony_ci		writel(BIT(gpp_offset), is);
109762306a36Sopenharmony_ci
109862306a36Sopenharmony_ci		value = readl(reg);
109962306a36Sopenharmony_ci		if (mask)
110062306a36Sopenharmony_ci			value &= ~BIT(gpp_offset);
110162306a36Sopenharmony_ci		else
110262306a36Sopenharmony_ci			value |= BIT(gpp_offset);
110362306a36Sopenharmony_ci		writel(value, reg);
110462306a36Sopenharmony_ci		raw_spin_unlock_irqrestore(&pctrl->lock, flags);
110562306a36Sopenharmony_ci	}
110662306a36Sopenharmony_ci}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_cistatic void intel_gpio_irq_mask(struct irq_data *d)
110962306a36Sopenharmony_ci{
111062306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
111162306a36Sopenharmony_ci	irq_hw_number_t hwirq = irqd_to_hwirq(d);
111262306a36Sopenharmony_ci
111362306a36Sopenharmony_ci	intel_gpio_irq_mask_unmask(gc, hwirq, true);
111462306a36Sopenharmony_ci	gpiochip_disable_irq(gc, hwirq);
111562306a36Sopenharmony_ci}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_cistatic void intel_gpio_irq_unmask(struct irq_data *d)
111862306a36Sopenharmony_ci{
111962306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
112062306a36Sopenharmony_ci	irq_hw_number_t hwirq = irqd_to_hwirq(d);
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci	gpiochip_enable_irq(gc, hwirq);
112362306a36Sopenharmony_ci	intel_gpio_irq_mask_unmask(gc, hwirq, false);
112462306a36Sopenharmony_ci}
112562306a36Sopenharmony_ci
112662306a36Sopenharmony_cistatic int intel_gpio_irq_type(struct irq_data *d, unsigned int type)
112762306a36Sopenharmony_ci{
112862306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
112962306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
113062306a36Sopenharmony_ci	unsigned int pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL);
113162306a36Sopenharmony_ci	u32 rxevcfg, rxinv, value;
113262306a36Sopenharmony_ci	unsigned long flags;
113362306a36Sopenharmony_ci	void __iomem *reg;
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	reg = intel_get_padcfg(pctrl, pin, PADCFG0);
113662306a36Sopenharmony_ci	if (!reg)
113762306a36Sopenharmony_ci		return -EINVAL;
113862306a36Sopenharmony_ci
113962306a36Sopenharmony_ci	/*
114062306a36Sopenharmony_ci	 * If the pin is in ACPI mode it is still usable as a GPIO but it
114162306a36Sopenharmony_ci	 * cannot be used as IRQ because GPI_IS status bit will not be
114262306a36Sopenharmony_ci	 * updated by the host controller hardware.
114362306a36Sopenharmony_ci	 */
114462306a36Sopenharmony_ci	if (intel_pad_acpi_mode(pctrl, pin)) {
114562306a36Sopenharmony_ci		dev_warn(pctrl->dev, "pin %u cannot be used as IRQ\n", pin);
114662306a36Sopenharmony_ci		return -EPERM;
114762306a36Sopenharmony_ci	}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_ci	if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH) {
115062306a36Sopenharmony_ci		rxevcfg = PADCFG0_RXEVCFG_EDGE_BOTH;
115162306a36Sopenharmony_ci	} else if (type & IRQ_TYPE_EDGE_FALLING) {
115262306a36Sopenharmony_ci		rxevcfg = PADCFG0_RXEVCFG_EDGE;
115362306a36Sopenharmony_ci	} else if (type & IRQ_TYPE_EDGE_RISING) {
115462306a36Sopenharmony_ci		rxevcfg = PADCFG0_RXEVCFG_EDGE;
115562306a36Sopenharmony_ci	} else if (type & IRQ_TYPE_LEVEL_MASK) {
115662306a36Sopenharmony_ci		rxevcfg = PADCFG0_RXEVCFG_LEVEL;
115762306a36Sopenharmony_ci	} else {
115862306a36Sopenharmony_ci		rxevcfg = PADCFG0_RXEVCFG_DISABLED;
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	if (type == IRQ_TYPE_EDGE_FALLING || type == IRQ_TYPE_LEVEL_LOW)
116262306a36Sopenharmony_ci		rxinv = PADCFG0_RXINV;
116362306a36Sopenharmony_ci	else
116462306a36Sopenharmony_ci		rxinv = 0;
116562306a36Sopenharmony_ci
116662306a36Sopenharmony_ci	raw_spin_lock_irqsave(&pctrl->lock, flags);
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci	intel_gpio_set_gpio_mode(reg);
116962306a36Sopenharmony_ci
117062306a36Sopenharmony_ci	value = readl(reg);
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci	value = (value & ~PADCFG0_RXEVCFG_MASK) | rxevcfg;
117362306a36Sopenharmony_ci	value = (value & ~PADCFG0_RXINV) | rxinv;
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	writel(value, reg);
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ci	if (type & IRQ_TYPE_EDGE_BOTH)
117862306a36Sopenharmony_ci		irq_set_handler_locked(d, handle_edge_irq);
117962306a36Sopenharmony_ci	else if (type & IRQ_TYPE_LEVEL_MASK)
118062306a36Sopenharmony_ci		irq_set_handler_locked(d, handle_level_irq);
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&pctrl->lock, flags);
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	return 0;
118562306a36Sopenharmony_ci}
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_cistatic int intel_gpio_irq_wake(struct irq_data *d, unsigned int on)
118862306a36Sopenharmony_ci{
118962306a36Sopenharmony_ci	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
119062306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
119162306a36Sopenharmony_ci	unsigned int pin = intel_gpio_to_pin(pctrl, irqd_to_hwirq(d), NULL, NULL);
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	if (on)
119462306a36Sopenharmony_ci		enable_irq_wake(pctrl->irq);
119562306a36Sopenharmony_ci	else
119662306a36Sopenharmony_ci		disable_irq_wake(pctrl->irq);
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	dev_dbg(pctrl->dev, "%s wake for pin %u\n", str_enable_disable(on), pin);
119962306a36Sopenharmony_ci	return 0;
120062306a36Sopenharmony_ci}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_cistatic const struct irq_chip intel_gpio_irq_chip = {
120362306a36Sopenharmony_ci	.name = "intel-gpio",
120462306a36Sopenharmony_ci	.irq_ack = intel_gpio_irq_ack,
120562306a36Sopenharmony_ci	.irq_mask = intel_gpio_irq_mask,
120662306a36Sopenharmony_ci	.irq_unmask = intel_gpio_irq_unmask,
120762306a36Sopenharmony_ci	.irq_set_type = intel_gpio_irq_type,
120862306a36Sopenharmony_ci	.irq_set_wake = intel_gpio_irq_wake,
120962306a36Sopenharmony_ci	.flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE,
121062306a36Sopenharmony_ci	GPIOCHIP_IRQ_RESOURCE_HELPERS,
121162306a36Sopenharmony_ci};
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_cistatic int intel_gpio_community_irq_handler(struct intel_pinctrl *pctrl,
121462306a36Sopenharmony_ci					    const struct intel_community *community)
121562306a36Sopenharmony_ci{
121662306a36Sopenharmony_ci	struct gpio_chip *gc = &pctrl->chip;
121762306a36Sopenharmony_ci	unsigned int gpp;
121862306a36Sopenharmony_ci	int ret = 0;
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	for (gpp = 0; gpp < community->ngpps; gpp++) {
122162306a36Sopenharmony_ci		const struct intel_padgroup *padgrp = &community->gpps[gpp];
122262306a36Sopenharmony_ci		unsigned long pending, enabled, gpp_offset;
122362306a36Sopenharmony_ci
122462306a36Sopenharmony_ci		raw_spin_lock(&pctrl->lock);
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci		pending = readl(community->regs + community->is_offset +
122762306a36Sopenharmony_ci				padgrp->reg_num * 4);
122862306a36Sopenharmony_ci		enabled = readl(community->regs + community->ie_offset +
122962306a36Sopenharmony_ci				padgrp->reg_num * 4);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci		raw_spin_unlock(&pctrl->lock);
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci		/* Only interrupts that are enabled */
123462306a36Sopenharmony_ci		pending &= enabled;
123562306a36Sopenharmony_ci
123662306a36Sopenharmony_ci		for_each_set_bit(gpp_offset, &pending, padgrp->size)
123762306a36Sopenharmony_ci			generic_handle_domain_irq(gc->irq.domain, padgrp->gpio_base + gpp_offset);
123862306a36Sopenharmony_ci
123962306a36Sopenharmony_ci		ret += pending ? 1 : 0;
124062306a36Sopenharmony_ci	}
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	return ret;
124362306a36Sopenharmony_ci}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_cistatic irqreturn_t intel_gpio_irq(int irq, void *data)
124662306a36Sopenharmony_ci{
124762306a36Sopenharmony_ci	const struct intel_community *community;
124862306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = data;
124962306a36Sopenharmony_ci	unsigned int i;
125062306a36Sopenharmony_ci	int ret = 0;
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	/* Need to check all communities for pending interrupts */
125362306a36Sopenharmony_ci	for (i = 0; i < pctrl->ncommunities; i++) {
125462306a36Sopenharmony_ci		community = &pctrl->communities[i];
125562306a36Sopenharmony_ci		ret += intel_gpio_community_irq_handler(pctrl, community);
125662306a36Sopenharmony_ci	}
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci	return IRQ_RETVAL(ret);
125962306a36Sopenharmony_ci}
126062306a36Sopenharmony_ci
126162306a36Sopenharmony_cistatic void intel_gpio_irq_init(struct intel_pinctrl *pctrl)
126262306a36Sopenharmony_ci{
126362306a36Sopenharmony_ci	int i;
126462306a36Sopenharmony_ci
126562306a36Sopenharmony_ci	for (i = 0; i < pctrl->ncommunities; i++) {
126662306a36Sopenharmony_ci		const struct intel_community *community;
126762306a36Sopenharmony_ci		void __iomem *base;
126862306a36Sopenharmony_ci		unsigned int gpp;
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ci		community = &pctrl->communities[i];
127162306a36Sopenharmony_ci		base = community->regs;
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci		for (gpp = 0; gpp < community->ngpps; gpp++) {
127462306a36Sopenharmony_ci			/* Mask and clear all interrupts */
127562306a36Sopenharmony_ci			writel(0, base + community->ie_offset + gpp * 4);
127662306a36Sopenharmony_ci			writel(0xffff, base + community->is_offset + gpp * 4);
127762306a36Sopenharmony_ci		}
127862306a36Sopenharmony_ci	}
127962306a36Sopenharmony_ci}
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_cistatic int intel_gpio_irq_init_hw(struct gpio_chip *gc)
128262306a36Sopenharmony_ci{
128362306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
128462306a36Sopenharmony_ci
128562306a36Sopenharmony_ci	/*
128662306a36Sopenharmony_ci	 * Make sure the interrupt lines are in a proper state before
128762306a36Sopenharmony_ci	 * further configuration.
128862306a36Sopenharmony_ci	 */
128962306a36Sopenharmony_ci	intel_gpio_irq_init(pctrl);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci	return 0;
129262306a36Sopenharmony_ci}
129362306a36Sopenharmony_ci
129462306a36Sopenharmony_cistatic int intel_gpio_add_community_ranges(struct intel_pinctrl *pctrl,
129562306a36Sopenharmony_ci				const struct intel_community *community)
129662306a36Sopenharmony_ci{
129762306a36Sopenharmony_ci	int ret = 0, i;
129862306a36Sopenharmony_ci
129962306a36Sopenharmony_ci	for (i = 0; i < community->ngpps; i++) {
130062306a36Sopenharmony_ci		const struct intel_padgroup *gpp = &community->gpps[i];
130162306a36Sopenharmony_ci
130262306a36Sopenharmony_ci		if (gpp->gpio_base == INTEL_GPIO_BASE_NOMAP)
130362306a36Sopenharmony_ci			continue;
130462306a36Sopenharmony_ci
130562306a36Sopenharmony_ci		ret = gpiochip_add_pin_range(&pctrl->chip, dev_name(pctrl->dev),
130662306a36Sopenharmony_ci					     gpp->gpio_base, gpp->base,
130762306a36Sopenharmony_ci					     gpp->size);
130862306a36Sopenharmony_ci		if (ret)
130962306a36Sopenharmony_ci			return ret;
131062306a36Sopenharmony_ci	}
131162306a36Sopenharmony_ci
131262306a36Sopenharmony_ci	return ret;
131362306a36Sopenharmony_ci}
131462306a36Sopenharmony_ci
131562306a36Sopenharmony_cistatic int intel_gpio_add_pin_ranges(struct gpio_chip *gc)
131662306a36Sopenharmony_ci{
131762306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = gpiochip_get_data(gc);
131862306a36Sopenharmony_ci	int ret, i;
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	for (i = 0; i < pctrl->ncommunities; i++) {
132162306a36Sopenharmony_ci		struct intel_community *community = &pctrl->communities[i];
132262306a36Sopenharmony_ci
132362306a36Sopenharmony_ci		ret = intel_gpio_add_community_ranges(pctrl, community);
132462306a36Sopenharmony_ci		if (ret) {
132562306a36Sopenharmony_ci			dev_err(pctrl->dev, "failed to add GPIO pin range\n");
132662306a36Sopenharmony_ci			return ret;
132762306a36Sopenharmony_ci		}
132862306a36Sopenharmony_ci	}
132962306a36Sopenharmony_ci
133062306a36Sopenharmony_ci	return 0;
133162306a36Sopenharmony_ci}
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_cistatic unsigned int intel_gpio_ngpio(const struct intel_pinctrl *pctrl)
133462306a36Sopenharmony_ci{
133562306a36Sopenharmony_ci	const struct intel_community *community;
133662306a36Sopenharmony_ci	unsigned int ngpio = 0;
133762306a36Sopenharmony_ci	int i, j;
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ci	for (i = 0; i < pctrl->ncommunities; i++) {
134062306a36Sopenharmony_ci		community = &pctrl->communities[i];
134162306a36Sopenharmony_ci		for (j = 0; j < community->ngpps; j++) {
134262306a36Sopenharmony_ci			const struct intel_padgroup *gpp = &community->gpps[j];
134362306a36Sopenharmony_ci
134462306a36Sopenharmony_ci			if (gpp->gpio_base == INTEL_GPIO_BASE_NOMAP)
134562306a36Sopenharmony_ci				continue;
134662306a36Sopenharmony_ci
134762306a36Sopenharmony_ci			if (gpp->gpio_base + gpp->size > ngpio)
134862306a36Sopenharmony_ci				ngpio = gpp->gpio_base + gpp->size;
134962306a36Sopenharmony_ci		}
135062306a36Sopenharmony_ci	}
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	return ngpio;
135362306a36Sopenharmony_ci}
135462306a36Sopenharmony_ci
135562306a36Sopenharmony_cistatic int intel_gpio_probe(struct intel_pinctrl *pctrl, int irq)
135662306a36Sopenharmony_ci{
135762306a36Sopenharmony_ci	int ret;
135862306a36Sopenharmony_ci	struct gpio_irq_chip *girq;
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	pctrl->chip = intel_gpio_chip;
136162306a36Sopenharmony_ci
136262306a36Sopenharmony_ci	/* Setup GPIO chip */
136362306a36Sopenharmony_ci	pctrl->chip.ngpio = intel_gpio_ngpio(pctrl);
136462306a36Sopenharmony_ci	pctrl->chip.label = dev_name(pctrl->dev);
136562306a36Sopenharmony_ci	pctrl->chip.parent = pctrl->dev;
136662306a36Sopenharmony_ci	pctrl->chip.base = -1;
136762306a36Sopenharmony_ci	pctrl->chip.add_pin_ranges = intel_gpio_add_pin_ranges;
136862306a36Sopenharmony_ci	pctrl->irq = irq;
136962306a36Sopenharmony_ci
137062306a36Sopenharmony_ci	/*
137162306a36Sopenharmony_ci	 * On some platforms several GPIO controllers share the same interrupt
137262306a36Sopenharmony_ci	 * line.
137362306a36Sopenharmony_ci	 */
137462306a36Sopenharmony_ci	ret = devm_request_irq(pctrl->dev, irq, intel_gpio_irq,
137562306a36Sopenharmony_ci			       IRQF_SHARED | IRQF_NO_THREAD,
137662306a36Sopenharmony_ci			       dev_name(pctrl->dev), pctrl);
137762306a36Sopenharmony_ci	if (ret) {
137862306a36Sopenharmony_ci		dev_err(pctrl->dev, "failed to request interrupt\n");
137962306a36Sopenharmony_ci		return ret;
138062306a36Sopenharmony_ci	}
138162306a36Sopenharmony_ci
138262306a36Sopenharmony_ci	/* Setup IRQ chip */
138362306a36Sopenharmony_ci	girq = &pctrl->chip.irq;
138462306a36Sopenharmony_ci	gpio_irq_chip_set_chip(girq, &intel_gpio_irq_chip);
138562306a36Sopenharmony_ci	/* This will let us handle the IRQ in the driver */
138662306a36Sopenharmony_ci	girq->parent_handler = NULL;
138762306a36Sopenharmony_ci	girq->num_parents = 0;
138862306a36Sopenharmony_ci	girq->default_type = IRQ_TYPE_NONE;
138962306a36Sopenharmony_ci	girq->handler = handle_bad_irq;
139062306a36Sopenharmony_ci	girq->init_hw = intel_gpio_irq_init_hw;
139162306a36Sopenharmony_ci
139262306a36Sopenharmony_ci	ret = devm_gpiochip_add_data(pctrl->dev, &pctrl->chip, pctrl);
139362306a36Sopenharmony_ci	if (ret) {
139462306a36Sopenharmony_ci		dev_err(pctrl->dev, "failed to register gpiochip\n");
139562306a36Sopenharmony_ci		return ret;
139662306a36Sopenharmony_ci	}
139762306a36Sopenharmony_ci
139862306a36Sopenharmony_ci	return 0;
139962306a36Sopenharmony_ci}
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_cistatic int intel_pinctrl_add_padgroups_by_gpps(struct intel_pinctrl *pctrl,
140262306a36Sopenharmony_ci					       struct intel_community *community)
140362306a36Sopenharmony_ci{
140462306a36Sopenharmony_ci	struct intel_padgroup *gpps;
140562306a36Sopenharmony_ci	unsigned int padown_num = 0;
140662306a36Sopenharmony_ci	size_t i, ngpps = community->ngpps;
140762306a36Sopenharmony_ci
140862306a36Sopenharmony_ci	gpps = devm_kcalloc(pctrl->dev, ngpps, sizeof(*gpps), GFP_KERNEL);
140962306a36Sopenharmony_ci	if (!gpps)
141062306a36Sopenharmony_ci		return -ENOMEM;
141162306a36Sopenharmony_ci
141262306a36Sopenharmony_ci	for (i = 0; i < ngpps; i++) {
141362306a36Sopenharmony_ci		gpps[i] = community->gpps[i];
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci		if (gpps[i].size > INTEL_PINCTRL_MAX_GPP_SIZE)
141662306a36Sopenharmony_ci			return -EINVAL;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci		/* Special treatment for GPIO base */
141962306a36Sopenharmony_ci		switch (gpps[i].gpio_base) {
142062306a36Sopenharmony_ci			case INTEL_GPIO_BASE_MATCH:
142162306a36Sopenharmony_ci				gpps[i].gpio_base = gpps[i].base;
142262306a36Sopenharmony_ci				break;
142362306a36Sopenharmony_ci			case INTEL_GPIO_BASE_ZERO:
142462306a36Sopenharmony_ci				gpps[i].gpio_base = 0;
142562306a36Sopenharmony_ci				break;
142662306a36Sopenharmony_ci			case INTEL_GPIO_BASE_NOMAP:
142762306a36Sopenharmony_ci				break;
142862306a36Sopenharmony_ci			default:
142962306a36Sopenharmony_ci				break;
143062306a36Sopenharmony_ci		}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci		gpps[i].padown_num = padown_num;
143362306a36Sopenharmony_ci		padown_num += DIV_ROUND_UP(gpps[i].size * 4, INTEL_PINCTRL_MAX_GPP_SIZE);
143462306a36Sopenharmony_ci	}
143562306a36Sopenharmony_ci
143662306a36Sopenharmony_ci	community->gpps = gpps;
143762306a36Sopenharmony_ci
143862306a36Sopenharmony_ci	return 0;
143962306a36Sopenharmony_ci}
144062306a36Sopenharmony_ci
144162306a36Sopenharmony_cistatic int intel_pinctrl_add_padgroups_by_size(struct intel_pinctrl *pctrl,
144262306a36Sopenharmony_ci					       struct intel_community *community)
144362306a36Sopenharmony_ci{
144462306a36Sopenharmony_ci	struct intel_padgroup *gpps;
144562306a36Sopenharmony_ci	unsigned int npins = community->npins;
144662306a36Sopenharmony_ci	unsigned int padown_num = 0;
144762306a36Sopenharmony_ci	size_t i, ngpps = DIV_ROUND_UP(npins, community->gpp_size);
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	if (community->gpp_size > INTEL_PINCTRL_MAX_GPP_SIZE)
145062306a36Sopenharmony_ci		return -EINVAL;
145162306a36Sopenharmony_ci
145262306a36Sopenharmony_ci	gpps = devm_kcalloc(pctrl->dev, ngpps, sizeof(*gpps), GFP_KERNEL);
145362306a36Sopenharmony_ci	if (!gpps)
145462306a36Sopenharmony_ci		return -ENOMEM;
145562306a36Sopenharmony_ci
145662306a36Sopenharmony_ci	for (i = 0; i < ngpps; i++) {
145762306a36Sopenharmony_ci		unsigned int gpp_size = community->gpp_size;
145862306a36Sopenharmony_ci
145962306a36Sopenharmony_ci		gpps[i].reg_num = i;
146062306a36Sopenharmony_ci		gpps[i].base = community->pin_base + i * gpp_size;
146162306a36Sopenharmony_ci		gpps[i].size = min(gpp_size, npins);
146262306a36Sopenharmony_ci		npins -= gpps[i].size;
146362306a36Sopenharmony_ci
146462306a36Sopenharmony_ci		gpps[i].gpio_base = gpps[i].base;
146562306a36Sopenharmony_ci		gpps[i].padown_num = padown_num;
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci		padown_num += community->gpp_num_padown_regs;
146862306a36Sopenharmony_ci	}
146962306a36Sopenharmony_ci
147062306a36Sopenharmony_ci	community->ngpps = ngpps;
147162306a36Sopenharmony_ci	community->gpps = gpps;
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	return 0;
147462306a36Sopenharmony_ci}
147562306a36Sopenharmony_ci
147662306a36Sopenharmony_cistatic int intel_pinctrl_pm_init(struct intel_pinctrl *pctrl)
147762306a36Sopenharmony_ci{
147862306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
147962306a36Sopenharmony_ci	const struct intel_pinctrl_soc_data *soc = pctrl->soc;
148062306a36Sopenharmony_ci	struct intel_community_context *communities;
148162306a36Sopenharmony_ci	struct intel_pad_context *pads;
148262306a36Sopenharmony_ci	int i;
148362306a36Sopenharmony_ci
148462306a36Sopenharmony_ci	pads = devm_kcalloc(pctrl->dev, soc->npins, sizeof(*pads), GFP_KERNEL);
148562306a36Sopenharmony_ci	if (!pads)
148662306a36Sopenharmony_ci		return -ENOMEM;
148762306a36Sopenharmony_ci
148862306a36Sopenharmony_ci	communities = devm_kcalloc(pctrl->dev, pctrl->ncommunities,
148962306a36Sopenharmony_ci				   sizeof(*communities), GFP_KERNEL);
149062306a36Sopenharmony_ci	if (!communities)
149162306a36Sopenharmony_ci		return -ENOMEM;
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	for (i = 0; i < pctrl->ncommunities; i++) {
149562306a36Sopenharmony_ci		struct intel_community *community = &pctrl->communities[i];
149662306a36Sopenharmony_ci		u32 *intmask, *hostown;
149762306a36Sopenharmony_ci
149862306a36Sopenharmony_ci		intmask = devm_kcalloc(pctrl->dev, community->ngpps,
149962306a36Sopenharmony_ci				       sizeof(*intmask), GFP_KERNEL);
150062306a36Sopenharmony_ci		if (!intmask)
150162306a36Sopenharmony_ci			return -ENOMEM;
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci		communities[i].intmask = intmask;
150462306a36Sopenharmony_ci
150562306a36Sopenharmony_ci		hostown = devm_kcalloc(pctrl->dev, community->ngpps,
150662306a36Sopenharmony_ci				       sizeof(*hostown), GFP_KERNEL);
150762306a36Sopenharmony_ci		if (!hostown)
150862306a36Sopenharmony_ci			return -ENOMEM;
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_ci		communities[i].hostown = hostown;
151162306a36Sopenharmony_ci	}
151262306a36Sopenharmony_ci
151362306a36Sopenharmony_ci	pctrl->context.pads = pads;
151462306a36Sopenharmony_ci	pctrl->context.communities = communities;
151562306a36Sopenharmony_ci#endif
151662306a36Sopenharmony_ci
151762306a36Sopenharmony_ci	return 0;
151862306a36Sopenharmony_ci}
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_cistatic int intel_pinctrl_probe_pwm(struct intel_pinctrl *pctrl,
152162306a36Sopenharmony_ci				   struct intel_community *community)
152262306a36Sopenharmony_ci{
152362306a36Sopenharmony_ci	static const struct pwm_lpss_boardinfo info = {
152462306a36Sopenharmony_ci		.clk_rate = 19200000,
152562306a36Sopenharmony_ci		.npwm = 1,
152662306a36Sopenharmony_ci		.base_unit_bits = 22,
152762306a36Sopenharmony_ci		.bypass = true,
152862306a36Sopenharmony_ci	};
152962306a36Sopenharmony_ci	struct pwm_lpss_chip *pwm;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	if (!(community->features & PINCTRL_FEATURE_PWM))
153262306a36Sopenharmony_ci		return 0;
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	if (!IS_REACHABLE(CONFIG_PWM_LPSS))
153562306a36Sopenharmony_ci		return 0;
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	pwm = devm_pwm_lpss_probe(pctrl->dev, community->regs + PWMC, &info);
153862306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(pwm);
153962306a36Sopenharmony_ci}
154062306a36Sopenharmony_ci
154162306a36Sopenharmony_cistatic int intel_pinctrl_probe(struct platform_device *pdev,
154262306a36Sopenharmony_ci			       const struct intel_pinctrl_soc_data *soc_data)
154362306a36Sopenharmony_ci{
154462306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
154562306a36Sopenharmony_ci	struct intel_pinctrl *pctrl;
154662306a36Sopenharmony_ci	int i, ret, irq;
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	pctrl = devm_kzalloc(dev, sizeof(*pctrl), GFP_KERNEL);
154962306a36Sopenharmony_ci	if (!pctrl)
155062306a36Sopenharmony_ci		return -ENOMEM;
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_ci	pctrl->dev = dev;
155362306a36Sopenharmony_ci	pctrl->soc = soc_data;
155462306a36Sopenharmony_ci	raw_spin_lock_init(&pctrl->lock);
155562306a36Sopenharmony_ci
155662306a36Sopenharmony_ci	/*
155762306a36Sopenharmony_ci	 * Make a copy of the communities which we can use to hold pointers
155862306a36Sopenharmony_ci	 * to the registers.
155962306a36Sopenharmony_ci	 */
156062306a36Sopenharmony_ci	pctrl->ncommunities = pctrl->soc->ncommunities;
156162306a36Sopenharmony_ci	pctrl->communities = devm_kcalloc(dev, pctrl->ncommunities,
156262306a36Sopenharmony_ci					  sizeof(*pctrl->communities), GFP_KERNEL);
156362306a36Sopenharmony_ci	if (!pctrl->communities)
156462306a36Sopenharmony_ci		return -ENOMEM;
156562306a36Sopenharmony_ci
156662306a36Sopenharmony_ci	for (i = 0; i < pctrl->ncommunities; i++) {
156762306a36Sopenharmony_ci		struct intel_community *community = &pctrl->communities[i];
156862306a36Sopenharmony_ci		void __iomem *regs;
156962306a36Sopenharmony_ci		u32 offset;
157062306a36Sopenharmony_ci		u32 value;
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci		*community = pctrl->soc->communities[i];
157362306a36Sopenharmony_ci
157462306a36Sopenharmony_ci		regs = devm_platform_ioremap_resource(pdev, community->barno);
157562306a36Sopenharmony_ci		if (IS_ERR(regs))
157662306a36Sopenharmony_ci			return PTR_ERR(regs);
157762306a36Sopenharmony_ci
157862306a36Sopenharmony_ci		/*
157962306a36Sopenharmony_ci		 * Determine community features based on the revision.
158062306a36Sopenharmony_ci		 * A value of all ones means the device is not present.
158162306a36Sopenharmony_ci		 */
158262306a36Sopenharmony_ci		value = readl(regs + REVID);
158362306a36Sopenharmony_ci		if (value == ~0u)
158462306a36Sopenharmony_ci			return -ENODEV;
158562306a36Sopenharmony_ci		if (((value & REVID_MASK) >> REVID_SHIFT) >= 0x94) {
158662306a36Sopenharmony_ci			community->features |= PINCTRL_FEATURE_DEBOUNCE;
158762306a36Sopenharmony_ci			community->features |= PINCTRL_FEATURE_1K_PD;
158862306a36Sopenharmony_ci		}
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci		/* Determine community features based on the capabilities */
159162306a36Sopenharmony_ci		offset = CAPLIST;
159262306a36Sopenharmony_ci		do {
159362306a36Sopenharmony_ci			value = readl(regs + offset);
159462306a36Sopenharmony_ci			switch ((value & CAPLIST_ID_MASK) >> CAPLIST_ID_SHIFT) {
159562306a36Sopenharmony_ci			case CAPLIST_ID_GPIO_HW_INFO:
159662306a36Sopenharmony_ci				community->features |= PINCTRL_FEATURE_GPIO_HW_INFO;
159762306a36Sopenharmony_ci				break;
159862306a36Sopenharmony_ci			case CAPLIST_ID_PWM:
159962306a36Sopenharmony_ci				community->features |= PINCTRL_FEATURE_PWM;
160062306a36Sopenharmony_ci				break;
160162306a36Sopenharmony_ci			case CAPLIST_ID_BLINK:
160262306a36Sopenharmony_ci				community->features |= PINCTRL_FEATURE_BLINK;
160362306a36Sopenharmony_ci				break;
160462306a36Sopenharmony_ci			case CAPLIST_ID_EXP:
160562306a36Sopenharmony_ci				community->features |= PINCTRL_FEATURE_EXP;
160662306a36Sopenharmony_ci				break;
160762306a36Sopenharmony_ci			default:
160862306a36Sopenharmony_ci				break;
160962306a36Sopenharmony_ci			}
161062306a36Sopenharmony_ci			offset = (value & CAPLIST_NEXT_MASK) >> CAPLIST_NEXT_SHIFT;
161162306a36Sopenharmony_ci		} while (offset);
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci		dev_dbg(dev, "Community%d features: %#08x\n", i, community->features);
161462306a36Sopenharmony_ci
161562306a36Sopenharmony_ci		/* Read offset of the pad configuration registers */
161662306a36Sopenharmony_ci		offset = readl(regs + PADBAR);
161762306a36Sopenharmony_ci
161862306a36Sopenharmony_ci		community->regs = regs;
161962306a36Sopenharmony_ci		community->pad_regs = regs + offset;
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci		if (community->gpps)
162262306a36Sopenharmony_ci			ret = intel_pinctrl_add_padgroups_by_gpps(pctrl, community);
162362306a36Sopenharmony_ci		else
162462306a36Sopenharmony_ci			ret = intel_pinctrl_add_padgroups_by_size(pctrl, community);
162562306a36Sopenharmony_ci		if (ret)
162662306a36Sopenharmony_ci			return ret;
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci		ret = intel_pinctrl_probe_pwm(pctrl, community);
162962306a36Sopenharmony_ci		if (ret)
163062306a36Sopenharmony_ci			return ret;
163162306a36Sopenharmony_ci	}
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	irq = platform_get_irq(pdev, 0);
163462306a36Sopenharmony_ci	if (irq < 0)
163562306a36Sopenharmony_ci		return irq;
163662306a36Sopenharmony_ci
163762306a36Sopenharmony_ci	ret = intel_pinctrl_pm_init(pctrl);
163862306a36Sopenharmony_ci	if (ret)
163962306a36Sopenharmony_ci		return ret;
164062306a36Sopenharmony_ci
164162306a36Sopenharmony_ci	pctrl->pctldesc = intel_pinctrl_desc;
164262306a36Sopenharmony_ci	pctrl->pctldesc.name = dev_name(dev);
164362306a36Sopenharmony_ci	pctrl->pctldesc.pins = pctrl->soc->pins;
164462306a36Sopenharmony_ci	pctrl->pctldesc.npins = pctrl->soc->npins;
164562306a36Sopenharmony_ci
164662306a36Sopenharmony_ci	pctrl->pctldev = devm_pinctrl_register(dev, &pctrl->pctldesc, pctrl);
164762306a36Sopenharmony_ci	if (IS_ERR(pctrl->pctldev)) {
164862306a36Sopenharmony_ci		dev_err(dev, "failed to register pinctrl driver\n");
164962306a36Sopenharmony_ci		return PTR_ERR(pctrl->pctldev);
165062306a36Sopenharmony_ci	}
165162306a36Sopenharmony_ci
165262306a36Sopenharmony_ci	ret = intel_gpio_probe(pctrl, irq);
165362306a36Sopenharmony_ci	if (ret)
165462306a36Sopenharmony_ci		return ret;
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	platform_set_drvdata(pdev, pctrl);
165762306a36Sopenharmony_ci
165862306a36Sopenharmony_ci	return 0;
165962306a36Sopenharmony_ci}
166062306a36Sopenharmony_ci
166162306a36Sopenharmony_ciint intel_pinctrl_probe_by_hid(struct platform_device *pdev)
166262306a36Sopenharmony_ci{
166362306a36Sopenharmony_ci	const struct intel_pinctrl_soc_data *data;
166462306a36Sopenharmony_ci
166562306a36Sopenharmony_ci	data = device_get_match_data(&pdev->dev);
166662306a36Sopenharmony_ci	if (!data)
166762306a36Sopenharmony_ci		return -ENODATA;
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	return intel_pinctrl_probe(pdev, data);
167062306a36Sopenharmony_ci}
167162306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(intel_pinctrl_probe_by_hid, PINCTRL_INTEL);
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ciint intel_pinctrl_probe_by_uid(struct platform_device *pdev)
167462306a36Sopenharmony_ci{
167562306a36Sopenharmony_ci	const struct intel_pinctrl_soc_data *data;
167662306a36Sopenharmony_ci
167762306a36Sopenharmony_ci	data = intel_pinctrl_get_soc_data(pdev);
167862306a36Sopenharmony_ci	if (IS_ERR(data))
167962306a36Sopenharmony_ci		return PTR_ERR(data);
168062306a36Sopenharmony_ci
168162306a36Sopenharmony_ci	return intel_pinctrl_probe(pdev, data);
168262306a36Sopenharmony_ci}
168362306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(intel_pinctrl_probe_by_uid, PINCTRL_INTEL);
168462306a36Sopenharmony_ci
168562306a36Sopenharmony_ciconst struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_device *pdev)
168662306a36Sopenharmony_ci{
168762306a36Sopenharmony_ci	const struct intel_pinctrl_soc_data * const *table;
168862306a36Sopenharmony_ci	const struct intel_pinctrl_soc_data *data = NULL;
168962306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
169062306a36Sopenharmony_ci
169162306a36Sopenharmony_ci	table = device_get_match_data(dev);
169262306a36Sopenharmony_ci	if (table) {
169362306a36Sopenharmony_ci		struct acpi_device *adev = ACPI_COMPANION(dev);
169462306a36Sopenharmony_ci		unsigned int i;
169562306a36Sopenharmony_ci
169662306a36Sopenharmony_ci		for (i = 0; table[i]; i++) {
169762306a36Sopenharmony_ci			if (!strcmp(adev->pnp.unique_id, table[i]->uid)) {
169862306a36Sopenharmony_ci				data = table[i];
169962306a36Sopenharmony_ci				break;
170062306a36Sopenharmony_ci			}
170162306a36Sopenharmony_ci		}
170262306a36Sopenharmony_ci	} else {
170362306a36Sopenharmony_ci		const struct platform_device_id *id;
170462306a36Sopenharmony_ci
170562306a36Sopenharmony_ci		id = platform_get_device_id(pdev);
170662306a36Sopenharmony_ci		if (!id)
170762306a36Sopenharmony_ci			return ERR_PTR(-ENODEV);
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci		table = (const struct intel_pinctrl_soc_data * const *)id->driver_data;
171062306a36Sopenharmony_ci		data = table[pdev->id];
171162306a36Sopenharmony_ci	}
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci	return data ?: ERR_PTR(-ENODATA);
171462306a36Sopenharmony_ci}
171562306a36Sopenharmony_ciEXPORT_SYMBOL_NS_GPL(intel_pinctrl_get_soc_data, PINCTRL_INTEL);
171662306a36Sopenharmony_ci
171762306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP
171862306a36Sopenharmony_cistatic bool __intel_gpio_is_direct_irq(u32 value)
171962306a36Sopenharmony_ci{
172062306a36Sopenharmony_ci	return (value & PADCFG0_GPIROUTIOXAPIC) && (value & PADCFG0_GPIOTXDIS) &&
172162306a36Sopenharmony_ci	       (__intel_gpio_get_gpio_mode(value) == PADCFG0_PMODE_GPIO);
172262306a36Sopenharmony_ci}
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_cistatic bool intel_pinctrl_should_save(struct intel_pinctrl *pctrl, unsigned int pin)
172562306a36Sopenharmony_ci{
172662306a36Sopenharmony_ci	const struct pin_desc *pd = pin_desc_get(pctrl->pctldev, pin);
172762306a36Sopenharmony_ci	u32 value;
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_ci	if (!pd || !intel_pad_usable(pctrl, pin))
173062306a36Sopenharmony_ci		return false;
173162306a36Sopenharmony_ci
173262306a36Sopenharmony_ci	/*
173362306a36Sopenharmony_ci	 * Only restore the pin if it is actually in use by the kernel (or
173462306a36Sopenharmony_ci	 * by userspace). It is possible that some pins are used by the
173562306a36Sopenharmony_ci	 * BIOS during resume and those are not always locked down so leave
173662306a36Sopenharmony_ci	 * them alone.
173762306a36Sopenharmony_ci	 */
173862306a36Sopenharmony_ci	if (pd->mux_owner || pd->gpio_owner ||
173962306a36Sopenharmony_ci	    gpiochip_line_is_irq(&pctrl->chip, intel_pin_to_gpio(pctrl, pin)))
174062306a36Sopenharmony_ci		return true;
174162306a36Sopenharmony_ci
174262306a36Sopenharmony_ci	/*
174362306a36Sopenharmony_ci	 * The firmware on some systems may configure GPIO pins to be
174462306a36Sopenharmony_ci	 * an interrupt source in so called "direct IRQ" mode. In such
174562306a36Sopenharmony_ci	 * cases the GPIO controller driver has no idea if those pins
174662306a36Sopenharmony_ci	 * are being used or not. At the same time, there is a known bug
174762306a36Sopenharmony_ci	 * in the firmwares that don't restore the pin settings correctly
174862306a36Sopenharmony_ci	 * after suspend, i.e. by an unknown reason the Rx value becomes
174962306a36Sopenharmony_ci	 * inverted.
175062306a36Sopenharmony_ci	 *
175162306a36Sopenharmony_ci	 * Hence, let's save and restore the pins that are configured
175262306a36Sopenharmony_ci	 * as GPIOs in the input mode with GPIROUTIOXAPIC bit set.
175362306a36Sopenharmony_ci	 *
175462306a36Sopenharmony_ci	 * See https://bugzilla.kernel.org/show_bug.cgi?id=214749.
175562306a36Sopenharmony_ci	 */
175662306a36Sopenharmony_ci	value = readl(intel_get_padcfg(pctrl, pin, PADCFG0));
175762306a36Sopenharmony_ci	if (__intel_gpio_is_direct_irq(value))
175862306a36Sopenharmony_ci		return true;
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	return false;
176162306a36Sopenharmony_ci}
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ciint intel_pinctrl_suspend_noirq(struct device *dev)
176462306a36Sopenharmony_ci{
176562306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = dev_get_drvdata(dev);
176662306a36Sopenharmony_ci	struct intel_community_context *communities;
176762306a36Sopenharmony_ci	struct intel_pad_context *pads;
176862306a36Sopenharmony_ci	int i;
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	pads = pctrl->context.pads;
177162306a36Sopenharmony_ci	for (i = 0; i < pctrl->soc->npins; i++) {
177262306a36Sopenharmony_ci		const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i];
177362306a36Sopenharmony_ci		void __iomem *padcfg;
177462306a36Sopenharmony_ci		u32 val;
177562306a36Sopenharmony_ci
177662306a36Sopenharmony_ci		if (!intel_pinctrl_should_save(pctrl, desc->number))
177762306a36Sopenharmony_ci			continue;
177862306a36Sopenharmony_ci
177962306a36Sopenharmony_ci		val = readl(intel_get_padcfg(pctrl, desc->number, PADCFG0));
178062306a36Sopenharmony_ci		pads[i].padcfg0 = val & ~PADCFG0_GPIORXSTATE;
178162306a36Sopenharmony_ci		val = readl(intel_get_padcfg(pctrl, desc->number, PADCFG1));
178262306a36Sopenharmony_ci		pads[i].padcfg1 = val;
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci		padcfg = intel_get_padcfg(pctrl, desc->number, PADCFG2);
178562306a36Sopenharmony_ci		if (padcfg)
178662306a36Sopenharmony_ci			pads[i].padcfg2 = readl(padcfg);
178762306a36Sopenharmony_ci	}
178862306a36Sopenharmony_ci
178962306a36Sopenharmony_ci	communities = pctrl->context.communities;
179062306a36Sopenharmony_ci	for (i = 0; i < pctrl->ncommunities; i++) {
179162306a36Sopenharmony_ci		struct intel_community *community = &pctrl->communities[i];
179262306a36Sopenharmony_ci		void __iomem *base;
179362306a36Sopenharmony_ci		unsigned int gpp;
179462306a36Sopenharmony_ci
179562306a36Sopenharmony_ci		base = community->regs + community->ie_offset;
179662306a36Sopenharmony_ci		for (gpp = 0; gpp < community->ngpps; gpp++)
179762306a36Sopenharmony_ci			communities[i].intmask[gpp] = readl(base + gpp * 4);
179862306a36Sopenharmony_ci
179962306a36Sopenharmony_ci		base = community->regs + community->hostown_offset;
180062306a36Sopenharmony_ci		for (gpp = 0; gpp < community->ngpps; gpp++)
180162306a36Sopenharmony_ci			communities[i].hostown[gpp] = readl(base + gpp * 4);
180262306a36Sopenharmony_ci	}
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	return 0;
180562306a36Sopenharmony_ci}
180662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_pinctrl_suspend_noirq);
180762306a36Sopenharmony_ci
180862306a36Sopenharmony_cistatic bool intel_gpio_update_reg(void __iomem *reg, u32 mask, u32 value)
180962306a36Sopenharmony_ci{
181062306a36Sopenharmony_ci	u32 curr, updated;
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_ci	curr = readl(reg);
181362306a36Sopenharmony_ci
181462306a36Sopenharmony_ci	updated = (curr & ~mask) | (value & mask);
181562306a36Sopenharmony_ci	if (curr == updated)
181662306a36Sopenharmony_ci		return false;
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	writel(updated, reg);
181962306a36Sopenharmony_ci	return true;
182062306a36Sopenharmony_ci}
182162306a36Sopenharmony_ci
182262306a36Sopenharmony_cistatic void intel_restore_hostown(struct intel_pinctrl *pctrl, unsigned int c,
182362306a36Sopenharmony_ci				  void __iomem *base, unsigned int gpp, u32 saved)
182462306a36Sopenharmony_ci{
182562306a36Sopenharmony_ci	const struct intel_community *community = &pctrl->communities[c];
182662306a36Sopenharmony_ci	const struct intel_padgroup *padgrp = &community->gpps[gpp];
182762306a36Sopenharmony_ci	struct device *dev = pctrl->dev;
182862306a36Sopenharmony_ci	const char *dummy;
182962306a36Sopenharmony_ci	u32 requested = 0;
183062306a36Sopenharmony_ci	unsigned int i;
183162306a36Sopenharmony_ci
183262306a36Sopenharmony_ci	if (padgrp->gpio_base == INTEL_GPIO_BASE_NOMAP)
183362306a36Sopenharmony_ci		return;
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci	for_each_requested_gpio_in_range(&pctrl->chip, i, padgrp->gpio_base, padgrp->size, dummy)
183662306a36Sopenharmony_ci		requested |= BIT(i);
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	if (!intel_gpio_update_reg(base + gpp * 4, requested, saved))
183962306a36Sopenharmony_ci		return;
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	dev_dbg(dev, "restored hostown %u/%u %#08x\n", c, gpp, readl(base + gpp * 4));
184262306a36Sopenharmony_ci}
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_cistatic void intel_restore_intmask(struct intel_pinctrl *pctrl, unsigned int c,
184562306a36Sopenharmony_ci				  void __iomem *base, unsigned int gpp, u32 saved)
184662306a36Sopenharmony_ci{
184762306a36Sopenharmony_ci	struct device *dev = pctrl->dev;
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	if (!intel_gpio_update_reg(base + gpp * 4, ~0U, saved))
185062306a36Sopenharmony_ci		return;
185162306a36Sopenharmony_ci
185262306a36Sopenharmony_ci	dev_dbg(dev, "restored mask %u/%u %#08x\n", c, gpp, readl(base + gpp * 4));
185362306a36Sopenharmony_ci}
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_cistatic void intel_restore_padcfg(struct intel_pinctrl *pctrl, unsigned int pin,
185662306a36Sopenharmony_ci				 unsigned int reg, u32 saved)
185762306a36Sopenharmony_ci{
185862306a36Sopenharmony_ci	u32 mask = (reg == PADCFG0) ? PADCFG0_GPIORXSTATE : 0;
185962306a36Sopenharmony_ci	unsigned int n = reg / sizeof(u32);
186062306a36Sopenharmony_ci	struct device *dev = pctrl->dev;
186162306a36Sopenharmony_ci	void __iomem *padcfg;
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_ci	padcfg = intel_get_padcfg(pctrl, pin, reg);
186462306a36Sopenharmony_ci	if (!padcfg)
186562306a36Sopenharmony_ci		return;
186662306a36Sopenharmony_ci
186762306a36Sopenharmony_ci	if (!intel_gpio_update_reg(padcfg, ~mask, saved))
186862306a36Sopenharmony_ci		return;
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	dev_dbg(dev, "restored pin %u padcfg%u %#08x\n", pin, n, readl(padcfg));
187162306a36Sopenharmony_ci}
187262306a36Sopenharmony_ci
187362306a36Sopenharmony_ciint intel_pinctrl_resume_noirq(struct device *dev)
187462306a36Sopenharmony_ci{
187562306a36Sopenharmony_ci	struct intel_pinctrl *pctrl = dev_get_drvdata(dev);
187662306a36Sopenharmony_ci	const struct intel_community_context *communities;
187762306a36Sopenharmony_ci	const struct intel_pad_context *pads;
187862306a36Sopenharmony_ci	int i;
187962306a36Sopenharmony_ci
188062306a36Sopenharmony_ci	/* Mask all interrupts */
188162306a36Sopenharmony_ci	intel_gpio_irq_init(pctrl);
188262306a36Sopenharmony_ci
188362306a36Sopenharmony_ci	pads = pctrl->context.pads;
188462306a36Sopenharmony_ci	for (i = 0; i < pctrl->soc->npins; i++) {
188562306a36Sopenharmony_ci		const struct pinctrl_pin_desc *desc = &pctrl->soc->pins[i];
188662306a36Sopenharmony_ci
188762306a36Sopenharmony_ci		if (!(intel_pinctrl_should_save(pctrl, desc->number) ||
188862306a36Sopenharmony_ci		      /*
188962306a36Sopenharmony_ci		       * If the firmware mangled the register contents too much,
189062306a36Sopenharmony_ci		       * check the saved value for the Direct IRQ mode.
189162306a36Sopenharmony_ci		       */
189262306a36Sopenharmony_ci		      __intel_gpio_is_direct_irq(pads[i].padcfg0)))
189362306a36Sopenharmony_ci			continue;
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci		intel_restore_padcfg(pctrl, desc->number, PADCFG0, pads[i].padcfg0);
189662306a36Sopenharmony_ci		intel_restore_padcfg(pctrl, desc->number, PADCFG1, pads[i].padcfg1);
189762306a36Sopenharmony_ci		intel_restore_padcfg(pctrl, desc->number, PADCFG2, pads[i].padcfg2);
189862306a36Sopenharmony_ci	}
189962306a36Sopenharmony_ci
190062306a36Sopenharmony_ci	communities = pctrl->context.communities;
190162306a36Sopenharmony_ci	for (i = 0; i < pctrl->ncommunities; i++) {
190262306a36Sopenharmony_ci		struct intel_community *community = &pctrl->communities[i];
190362306a36Sopenharmony_ci		void __iomem *base;
190462306a36Sopenharmony_ci		unsigned int gpp;
190562306a36Sopenharmony_ci
190662306a36Sopenharmony_ci		base = community->regs + community->ie_offset;
190762306a36Sopenharmony_ci		for (gpp = 0; gpp < community->ngpps; gpp++)
190862306a36Sopenharmony_ci			intel_restore_intmask(pctrl, i, base, gpp, communities[i].intmask[gpp]);
190962306a36Sopenharmony_ci
191062306a36Sopenharmony_ci		base = community->regs + community->hostown_offset;
191162306a36Sopenharmony_ci		for (gpp = 0; gpp < community->ngpps; gpp++)
191262306a36Sopenharmony_ci			intel_restore_hostown(pctrl, i, base, gpp, communities[i].hostown[gpp]);
191362306a36Sopenharmony_ci	}
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci	return 0;
191662306a36Sopenharmony_ci}
191762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(intel_pinctrl_resume_noirq);
191862306a36Sopenharmony_ci#endif
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ciMODULE_AUTHOR("Mathias Nyman <mathias.nyman@linux.intel.com>");
192162306a36Sopenharmony_ciMODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
192262306a36Sopenharmony_ciMODULE_DESCRIPTION("Intel pinctrl/GPIO core driver");
192362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
1924