Commit 7064d7d8 authored by Tan Jui Nee's avatar Tan Jui Nee Committed by Lee Jones
Browse files

mfd: lpc_ich: Add support for pinctrl in non-ACPI system



Add support for non-ACPI systems, such as system that uses
Advanced Boot Loader (ABL) whereby a platform device has to be created
in order to bind with pin control and GPIO.

At the moment, Intel Apollo Lake In-Vehicle Infotainment (IVI) system
requires a driver to hide and unhide P2SB to lookup P2SB BAR and pass
the PCI BAR address to GPIO.

Signed-off-by: default avatarTan Jui Nee <jui.nee.tan@intel.com>
Co-developed-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: default avatarAndy Shevchenko <andriy.shevchenko@linux.intel.com>
Tested-by: default avatarHenning Schild <henning.schild@siemens.com>
Acked-by: default avatarHans de Goede <hdegoede@redhat.com>
Acked-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Signed-off-by: default avatarLee Jones <lee@kernel.org>
parent 55979319
Loading
Loading
Loading
Loading
+104 −1
Original line number Diff line number Diff line
@@ -8,7 +8,8 @@
 *  Configuration Registers.
 *
 *  This driver is derived from lpc_sch.

 *
 *  Copyright (c) 2017, 2021-2022 Intel Corporation
 *  Copyright (c) 2011 Extreme Engineering Solution, Inc.
 *  Author: Aaron Sierra <asierra@xes-inc.com>
 *
@@ -42,6 +43,7 @@
#include <linux/errno.h>
#include <linux/acpi.h>
#include <linux/pci.h>
#include <linux/pinctrl/pinctrl.h>
#include <linux/mfd/core.h>
#include <linux/mfd/lpc_ich.h>
#include <linux/platform_data/itco_wdt.h>
@@ -142,6 +144,73 @@ static struct mfd_cell lpc_ich_gpio_cell = {
	.ignore_resource_conflicts = true,
};

#define APL_GPIO_NORTH		0
#define APL_GPIO_NORTHWEST	1
#define APL_GPIO_WEST		2
#define APL_GPIO_SOUTHWEST	3
#define APL_GPIO_NR_DEVICES	4

/* Offset data for Apollo Lake GPIO controllers */
static resource_size_t apl_gpio_offsets[APL_GPIO_NR_DEVICES] = {
	[APL_GPIO_NORTH]	= 0xc50000,
	[APL_GPIO_NORTHWEST]	= 0xc40000,
	[APL_GPIO_WEST]		= 0xc70000,
	[APL_GPIO_SOUTHWEST]	= 0xc00000,
};

#define APL_GPIO_RESOURCE_SIZE		0x1000

#define APL_GPIO_IRQ			14

static struct resource apl_gpio_resources[APL_GPIO_NR_DEVICES][2] = {
	[APL_GPIO_NORTH] = {
		DEFINE_RES_MEM(0, 0),
		DEFINE_RES_IRQ(APL_GPIO_IRQ),
	},
	[APL_GPIO_NORTHWEST] = {
		DEFINE_RES_MEM(0, 0),
		DEFINE_RES_IRQ(APL_GPIO_IRQ),
	},
	[APL_GPIO_WEST] = {
		DEFINE_RES_MEM(0, 0),
		DEFINE_RES_IRQ(APL_GPIO_IRQ),
	},
	[APL_GPIO_SOUTHWEST] = {
		DEFINE_RES_MEM(0, 0),
		DEFINE_RES_IRQ(APL_GPIO_IRQ),
	},
};

static const struct mfd_cell apl_gpio_devices[APL_GPIO_NR_DEVICES] = {
	[APL_GPIO_NORTH] = {
		.name = "apollolake-pinctrl",
		.id = APL_GPIO_NORTH,
		.num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_NORTH]),
		.resources = apl_gpio_resources[APL_GPIO_NORTH],
		.ignore_resource_conflicts = true,
	},
	[APL_GPIO_NORTHWEST] = {
		.name = "apollolake-pinctrl",
		.id = APL_GPIO_NORTHWEST,
		.num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_NORTHWEST]),
		.resources = apl_gpio_resources[APL_GPIO_NORTHWEST],
		.ignore_resource_conflicts = true,
	},
	[APL_GPIO_WEST] = {
		.name = "apollolake-pinctrl",
		.id = APL_GPIO_WEST,
		.num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_WEST]),
		.resources = apl_gpio_resources[APL_GPIO_WEST],
		.ignore_resource_conflicts = true,
	},
	[APL_GPIO_SOUTHWEST] = {
		.name = "apollolake-pinctrl",
		.id = APL_GPIO_SOUTHWEST,
		.num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_SOUTHWEST]),
		.resources = apl_gpio_resources[APL_GPIO_SOUTHWEST],
		.ignore_resource_conflicts = true,
	},
};

static struct mfd_cell lpc_ich_spi_cell = {
	.name = "intel-spi",
@@ -1085,6 +1154,34 @@ static int lpc_ich_init_wdt(struct pci_dev *dev)
	return ret;
}

static int lpc_ich_init_pinctrl(struct pci_dev *dev)
{
	struct resource base;
	unsigned int i;
	int ret;

	/* Check, if GPIO has been exported as an ACPI device */
	if (acpi_dev_present("INT3452", NULL, -1))
		return -EEXIST;

	ret = p2sb_bar(dev->bus, 0, &base);
	if (ret)
		return ret;

	for (i = 0; i < ARRAY_SIZE(apl_gpio_devices); i++) {
		struct resource *mem = &apl_gpio_resources[i][0];
		resource_size_t offset = apl_gpio_offsets[i];

		/* Fill MEM resource */
		mem->start = base.start + offset;
		mem->end = base.start + offset + APL_GPIO_RESOURCE_SIZE - 1;
		mem->flags = base.flags;
	}

	return mfd_add_devices(&dev->dev, 0, apl_gpio_devices,
			       ARRAY_SIZE(apl_gpio_devices), NULL, 0, NULL);
}

static bool lpc_ich_byt_set_writeable(void __iomem *base, void *data)
{
	u32 val;
@@ -1235,6 +1332,12 @@ static int lpc_ich_probe(struct pci_dev *dev,
			cell_added = true;
	}

	if (priv->chipset == LPC_APL) {
		ret = lpc_ich_init_pinctrl(dev);
		if (!ret)
			cell_added = true;
	}

	if (lpc_chipset_info[priv->chipset].spi_type) {
		ret = lpc_ich_init_spi(dev);
		if (!ret)