162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * GPIOs on MPC512x/8349/8572/8610/QorIQ and compatible
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2008 Peter Korsgaard <jacmet@sunsite.dk>
662306a36Sopenharmony_ci * Copyright (C) 2016 Freescale Semiconductor Inc.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/acpi.h>
1062306a36Sopenharmony_ci#include <linux/kernel.h>
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci#include <linux/platform_device.h>
1362306a36Sopenharmony_ci#include <linux/spinlock.h>
1462306a36Sopenharmony_ci#include <linux/io.h>
1562306a36Sopenharmony_ci#include <linux/of.h>
1662306a36Sopenharmony_ci#include <linux/property.h>
1762306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1862306a36Sopenharmony_ci#include <linux/slab.h>
1962306a36Sopenharmony_ci#include <linux/irq.h>
2062306a36Sopenharmony_ci#include <linux/gpio/driver.h>
2162306a36Sopenharmony_ci#include <linux/bitops.h>
2262306a36Sopenharmony_ci#include <linux/interrupt.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define MPC8XXX_GPIO_PINS	32
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci#define GPIO_DIR		0x00
2762306a36Sopenharmony_ci#define GPIO_ODR		0x04
2862306a36Sopenharmony_ci#define GPIO_DAT		0x08
2962306a36Sopenharmony_ci#define GPIO_IER		0x0c
3062306a36Sopenharmony_ci#define GPIO_IMR		0x10
3162306a36Sopenharmony_ci#define GPIO_ICR		0x14
3262306a36Sopenharmony_ci#define GPIO_ICR2		0x18
3362306a36Sopenharmony_ci#define GPIO_IBE		0x18
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistruct mpc8xxx_gpio_chip {
3662306a36Sopenharmony_ci	struct gpio_chip	gc;
3762306a36Sopenharmony_ci	void __iomem *regs;
3862306a36Sopenharmony_ci	raw_spinlock_t lock;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	int (*direction_output)(struct gpio_chip *chip,
4162306a36Sopenharmony_ci				unsigned offset, int value);
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	struct irq_domain *irq;
4462306a36Sopenharmony_ci	int irqn;
4562306a36Sopenharmony_ci};
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci/*
4862306a36Sopenharmony_ci * This hardware has a big endian bit assignment such that GPIO line 0 is
4962306a36Sopenharmony_ci * connected to bit 31, line 1 to bit 30 ... line 31 to bit 0.
5062306a36Sopenharmony_ci * This inline helper give the right bitmask for a certain line.
5162306a36Sopenharmony_ci */
5262306a36Sopenharmony_cistatic inline u32 mpc_pin2mask(unsigned int offset)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	return BIT(31 - offset);
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci/* Workaround GPIO 1 errata on MPC8572/MPC8536. The status of GPIOs
5862306a36Sopenharmony_ci * defined as output cannot be determined by reading GPDAT register,
5962306a36Sopenharmony_ci * so we use shadow data register instead. The status of input pins
6062306a36Sopenharmony_ci * is determined by reading GPDAT register.
6162306a36Sopenharmony_ci */
6262306a36Sopenharmony_cistatic int mpc8572_gpio_get(struct gpio_chip *gc, unsigned int gpio)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	u32 val;
6562306a36Sopenharmony_ci	struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
6662306a36Sopenharmony_ci	u32 out_mask, out_shadow;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci	out_mask = gc->read_reg(mpc8xxx_gc->regs + GPIO_DIR);
6962306a36Sopenharmony_ci	val = gc->read_reg(mpc8xxx_gc->regs + GPIO_DAT) & ~out_mask;
7062306a36Sopenharmony_ci	out_shadow = gc->bgpio_data & out_mask;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	return !!((val | out_shadow) & mpc_pin2mask(gpio));
7362306a36Sopenharmony_ci}
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_cistatic int mpc5121_gpio_dir_out(struct gpio_chip *gc,
7662306a36Sopenharmony_ci				unsigned int gpio, int val)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
7962306a36Sopenharmony_ci	/* GPIO 28..31 are input only on MPC5121 */
8062306a36Sopenharmony_ci	if (gpio >= 28)
8162306a36Sopenharmony_ci		return -EINVAL;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	return mpc8xxx_gc->direction_output(gc, gpio, val);
8462306a36Sopenharmony_ci}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_cistatic int mpc5125_gpio_dir_out(struct gpio_chip *gc,
8762306a36Sopenharmony_ci				unsigned int gpio, int val)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
9062306a36Sopenharmony_ci	/* GPIO 0..3 are input only on MPC5125 */
9162306a36Sopenharmony_ci	if (gpio <= 3)
9262306a36Sopenharmony_ci		return -EINVAL;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	return mpc8xxx_gc->direction_output(gc, gpio, val);
9562306a36Sopenharmony_ci}
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_cistatic int mpc8xxx_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
9862306a36Sopenharmony_ci{
9962306a36Sopenharmony_ci	struct mpc8xxx_gpio_chip *mpc8xxx_gc = gpiochip_get_data(gc);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (mpc8xxx_gc->irq && offset < MPC8XXX_GPIO_PINS)
10262306a36Sopenharmony_ci		return irq_create_mapping(mpc8xxx_gc->irq, offset);
10362306a36Sopenharmony_ci	else
10462306a36Sopenharmony_ci		return -ENXIO;
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic irqreturn_t mpc8xxx_gpio_irq_cascade(int irq, void *data)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	struct mpc8xxx_gpio_chip *mpc8xxx_gc = data;
11062306a36Sopenharmony_ci	struct gpio_chip *gc = &mpc8xxx_gc->gc;
11162306a36Sopenharmony_ci	unsigned long mask;
11262306a36Sopenharmony_ci	int i;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	mask = gc->read_reg(mpc8xxx_gc->regs + GPIO_IER)
11562306a36Sopenharmony_ci		& gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR);
11662306a36Sopenharmony_ci	for_each_set_bit(i, &mask, 32)
11762306a36Sopenharmony_ci		generic_handle_domain_irq(mpc8xxx_gc->irq, 31 - i);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	return IRQ_HANDLED;
12062306a36Sopenharmony_ci}
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_cistatic void mpc8xxx_irq_unmask(struct irq_data *d)
12362306a36Sopenharmony_ci{
12462306a36Sopenharmony_ci	struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
12562306a36Sopenharmony_ci	struct gpio_chip *gc = &mpc8xxx_gc->gc;
12662306a36Sopenharmony_ci	unsigned long flags;
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci	gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR,
13162306a36Sopenharmony_ci		gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR)
13262306a36Sopenharmony_ci		| mpc_pin2mask(irqd_to_hwirq(d)));
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic void mpc8xxx_irq_mask(struct irq_data *d)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
14062306a36Sopenharmony_ci	struct gpio_chip *gc = &mpc8xxx_gc->gc;
14162306a36Sopenharmony_ci	unsigned long flags;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR,
14662306a36Sopenharmony_ci		gc->read_reg(mpc8xxx_gc->regs + GPIO_IMR)
14762306a36Sopenharmony_ci		& ~mpc_pin2mask(irqd_to_hwirq(d)));
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
15062306a36Sopenharmony_ci}
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_cistatic void mpc8xxx_irq_ack(struct irq_data *d)
15362306a36Sopenharmony_ci{
15462306a36Sopenharmony_ci	struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
15562306a36Sopenharmony_ci	struct gpio_chip *gc = &mpc8xxx_gc->gc;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	gc->write_reg(mpc8xxx_gc->regs + GPIO_IER,
15862306a36Sopenharmony_ci		      mpc_pin2mask(irqd_to_hwirq(d)));
15962306a36Sopenharmony_ci}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_cistatic int mpc8xxx_irq_set_type(struct irq_data *d, unsigned int flow_type)
16262306a36Sopenharmony_ci{
16362306a36Sopenharmony_ci	struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
16462306a36Sopenharmony_ci	struct gpio_chip *gc = &mpc8xxx_gc->gc;
16562306a36Sopenharmony_ci	unsigned long flags;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	switch (flow_type) {
16862306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_FALLING:
16962306a36Sopenharmony_ci	case IRQ_TYPE_LEVEL_LOW:
17062306a36Sopenharmony_ci		raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
17162306a36Sopenharmony_ci		gc->write_reg(mpc8xxx_gc->regs + GPIO_ICR,
17262306a36Sopenharmony_ci			gc->read_reg(mpc8xxx_gc->regs + GPIO_ICR)
17362306a36Sopenharmony_ci			| mpc_pin2mask(irqd_to_hwirq(d)));
17462306a36Sopenharmony_ci		raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
17562306a36Sopenharmony_ci		break;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_BOTH:
17862306a36Sopenharmony_ci		raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
17962306a36Sopenharmony_ci		gc->write_reg(mpc8xxx_gc->regs + GPIO_ICR,
18062306a36Sopenharmony_ci			gc->read_reg(mpc8xxx_gc->regs + GPIO_ICR)
18162306a36Sopenharmony_ci			& ~mpc_pin2mask(irqd_to_hwirq(d)));
18262306a36Sopenharmony_ci		raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
18362306a36Sopenharmony_ci		break;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	default:
18662306a36Sopenharmony_ci		return -EINVAL;
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	return 0;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_cistatic int mpc512x_irq_set_type(struct irq_data *d, unsigned int flow_type)
19362306a36Sopenharmony_ci{
19462306a36Sopenharmony_ci	struct mpc8xxx_gpio_chip *mpc8xxx_gc = irq_data_get_irq_chip_data(d);
19562306a36Sopenharmony_ci	struct gpio_chip *gc = &mpc8xxx_gc->gc;
19662306a36Sopenharmony_ci	unsigned long gpio = irqd_to_hwirq(d);
19762306a36Sopenharmony_ci	void __iomem *reg;
19862306a36Sopenharmony_ci	unsigned int shift;
19962306a36Sopenharmony_ci	unsigned long flags;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (gpio < 16) {
20262306a36Sopenharmony_ci		reg = mpc8xxx_gc->regs + GPIO_ICR;
20362306a36Sopenharmony_ci		shift = (15 - gpio) * 2;
20462306a36Sopenharmony_ci	} else {
20562306a36Sopenharmony_ci		reg = mpc8xxx_gc->regs + GPIO_ICR2;
20662306a36Sopenharmony_ci		shift = (15 - (gpio % 16)) * 2;
20762306a36Sopenharmony_ci	}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	switch (flow_type) {
21062306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_FALLING:
21162306a36Sopenharmony_ci	case IRQ_TYPE_LEVEL_LOW:
21262306a36Sopenharmony_ci		raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
21362306a36Sopenharmony_ci		gc->write_reg(reg, (gc->read_reg(reg) & ~(3 << shift))
21462306a36Sopenharmony_ci			| (2 << shift));
21562306a36Sopenharmony_ci		raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
21662306a36Sopenharmony_ci		break;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_RISING:
21962306a36Sopenharmony_ci	case IRQ_TYPE_LEVEL_HIGH:
22062306a36Sopenharmony_ci		raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
22162306a36Sopenharmony_ci		gc->write_reg(reg, (gc->read_reg(reg) & ~(3 << shift))
22262306a36Sopenharmony_ci			| (1 << shift));
22362306a36Sopenharmony_ci		raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
22462306a36Sopenharmony_ci		break;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	case IRQ_TYPE_EDGE_BOTH:
22762306a36Sopenharmony_ci		raw_spin_lock_irqsave(&mpc8xxx_gc->lock, flags);
22862306a36Sopenharmony_ci		gc->write_reg(reg, (gc->read_reg(reg) & ~(3 << shift)));
22962306a36Sopenharmony_ci		raw_spin_unlock_irqrestore(&mpc8xxx_gc->lock, flags);
23062306a36Sopenharmony_ci		break;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	default:
23362306a36Sopenharmony_ci		return -EINVAL;
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	return 0;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_cistatic struct irq_chip mpc8xxx_irq_chip = {
24062306a36Sopenharmony_ci	.name		= "mpc8xxx-gpio",
24162306a36Sopenharmony_ci	.irq_unmask	= mpc8xxx_irq_unmask,
24262306a36Sopenharmony_ci	.irq_mask	= mpc8xxx_irq_mask,
24362306a36Sopenharmony_ci	.irq_ack	= mpc8xxx_irq_ack,
24462306a36Sopenharmony_ci	/* this might get overwritten in mpc8xxx_probe() */
24562306a36Sopenharmony_ci	.irq_set_type	= mpc8xxx_irq_set_type,
24662306a36Sopenharmony_ci};
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic int mpc8xxx_gpio_irq_map(struct irq_domain *h, unsigned int irq,
24962306a36Sopenharmony_ci				irq_hw_number_t hwirq)
25062306a36Sopenharmony_ci{
25162306a36Sopenharmony_ci	irq_set_chip_data(irq, h->host_data);
25262306a36Sopenharmony_ci	irq_set_chip_and_handler(irq, &mpc8xxx_irq_chip, handle_edge_irq);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	return 0;
25562306a36Sopenharmony_ci}
25662306a36Sopenharmony_ci
25762306a36Sopenharmony_cistatic const struct irq_domain_ops mpc8xxx_gpio_irq_ops = {
25862306a36Sopenharmony_ci	.map	= mpc8xxx_gpio_irq_map,
25962306a36Sopenharmony_ci	.xlate	= irq_domain_xlate_twocell,
26062306a36Sopenharmony_ci};
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_cistruct mpc8xxx_gpio_devtype {
26362306a36Sopenharmony_ci	int (*gpio_dir_out)(struct gpio_chip *, unsigned int, int);
26462306a36Sopenharmony_ci	int (*gpio_get)(struct gpio_chip *, unsigned int);
26562306a36Sopenharmony_ci	int (*irq_set_type)(struct irq_data *, unsigned int);
26662306a36Sopenharmony_ci};
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_cistatic const struct mpc8xxx_gpio_devtype mpc512x_gpio_devtype = {
26962306a36Sopenharmony_ci	.gpio_dir_out = mpc5121_gpio_dir_out,
27062306a36Sopenharmony_ci	.irq_set_type = mpc512x_irq_set_type,
27162306a36Sopenharmony_ci};
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistatic const struct mpc8xxx_gpio_devtype mpc5125_gpio_devtype = {
27462306a36Sopenharmony_ci	.gpio_dir_out = mpc5125_gpio_dir_out,
27562306a36Sopenharmony_ci	.irq_set_type = mpc512x_irq_set_type,
27662306a36Sopenharmony_ci};
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_cistatic const struct mpc8xxx_gpio_devtype mpc8572_gpio_devtype = {
27962306a36Sopenharmony_ci	.gpio_get = mpc8572_gpio_get,
28062306a36Sopenharmony_ci};
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_cistatic const struct mpc8xxx_gpio_devtype mpc8xxx_gpio_devtype_default = {
28362306a36Sopenharmony_ci	.irq_set_type = mpc8xxx_irq_set_type,
28462306a36Sopenharmony_ci};
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_cistatic const struct of_device_id mpc8xxx_gpio_ids[] = {
28762306a36Sopenharmony_ci	{ .compatible = "fsl,mpc8349-gpio", },
28862306a36Sopenharmony_ci	{ .compatible = "fsl,mpc8572-gpio", .data = &mpc8572_gpio_devtype, },
28962306a36Sopenharmony_ci	{ .compatible = "fsl,mpc8610-gpio", },
29062306a36Sopenharmony_ci	{ .compatible = "fsl,mpc5121-gpio", .data = &mpc512x_gpio_devtype, },
29162306a36Sopenharmony_ci	{ .compatible = "fsl,mpc5125-gpio", .data = &mpc5125_gpio_devtype, },
29262306a36Sopenharmony_ci	{ .compatible = "fsl,pq3-gpio",     },
29362306a36Sopenharmony_ci	{ .compatible = "fsl,ls1028a-gpio", },
29462306a36Sopenharmony_ci	{ .compatible = "fsl,ls1088a-gpio", },
29562306a36Sopenharmony_ci	{ .compatible = "fsl,qoriq-gpio",   },
29662306a36Sopenharmony_ci	{}
29762306a36Sopenharmony_ci};
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_cistatic int mpc8xxx_probe(struct platform_device *pdev)
30062306a36Sopenharmony_ci{
30162306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
30262306a36Sopenharmony_ci	struct mpc8xxx_gpio_chip *mpc8xxx_gc;
30362306a36Sopenharmony_ci	struct gpio_chip	*gc;
30462306a36Sopenharmony_ci	const struct mpc8xxx_gpio_devtype *devtype = NULL;
30562306a36Sopenharmony_ci	struct fwnode_handle *fwnode;
30662306a36Sopenharmony_ci	int ret;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	mpc8xxx_gc = devm_kzalloc(&pdev->dev, sizeof(*mpc8xxx_gc), GFP_KERNEL);
30962306a36Sopenharmony_ci	if (!mpc8xxx_gc)
31062306a36Sopenharmony_ci		return -ENOMEM;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	platform_set_drvdata(pdev, mpc8xxx_gc);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	raw_spin_lock_init(&mpc8xxx_gc->lock);
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	mpc8xxx_gc->regs = devm_platform_ioremap_resource(pdev, 0);
31762306a36Sopenharmony_ci	if (IS_ERR(mpc8xxx_gc->regs))
31862306a36Sopenharmony_ci		return PTR_ERR(mpc8xxx_gc->regs);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	gc = &mpc8xxx_gc->gc;
32162306a36Sopenharmony_ci	gc->parent = &pdev->dev;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_ci	if (device_property_read_bool(&pdev->dev, "little-endian")) {
32462306a36Sopenharmony_ci		ret = bgpio_init(gc, &pdev->dev, 4,
32562306a36Sopenharmony_ci				 mpc8xxx_gc->regs + GPIO_DAT,
32662306a36Sopenharmony_ci				 NULL, NULL,
32762306a36Sopenharmony_ci				 mpc8xxx_gc->regs + GPIO_DIR, NULL,
32862306a36Sopenharmony_ci				 BGPIOF_BIG_ENDIAN);
32962306a36Sopenharmony_ci		if (ret)
33062306a36Sopenharmony_ci			return ret;
33162306a36Sopenharmony_ci		dev_dbg(&pdev->dev, "GPIO registers are LITTLE endian\n");
33262306a36Sopenharmony_ci	} else {
33362306a36Sopenharmony_ci		ret = bgpio_init(gc, &pdev->dev, 4,
33462306a36Sopenharmony_ci				 mpc8xxx_gc->regs + GPIO_DAT,
33562306a36Sopenharmony_ci				 NULL, NULL,
33662306a36Sopenharmony_ci				 mpc8xxx_gc->regs + GPIO_DIR, NULL,
33762306a36Sopenharmony_ci				 BGPIOF_BIG_ENDIAN
33862306a36Sopenharmony_ci				 | BGPIOF_BIG_ENDIAN_BYTE_ORDER);
33962306a36Sopenharmony_ci		if (ret)
34062306a36Sopenharmony_ci			return ret;
34162306a36Sopenharmony_ci		dev_dbg(&pdev->dev, "GPIO registers are BIG endian\n");
34262306a36Sopenharmony_ci	}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	mpc8xxx_gc->direction_output = gc->direction_output;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	devtype = device_get_match_data(&pdev->dev);
34762306a36Sopenharmony_ci	if (!devtype)
34862306a36Sopenharmony_ci		devtype = &mpc8xxx_gpio_devtype_default;
34962306a36Sopenharmony_ci
35062306a36Sopenharmony_ci	/*
35162306a36Sopenharmony_ci	 * It's assumed that only a single type of gpio controller is available
35262306a36Sopenharmony_ci	 * on the current machine, so overwriting global data is fine.
35362306a36Sopenharmony_ci	 */
35462306a36Sopenharmony_ci	if (devtype->irq_set_type)
35562306a36Sopenharmony_ci		mpc8xxx_irq_chip.irq_set_type = devtype->irq_set_type;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	if (devtype->gpio_dir_out)
35862306a36Sopenharmony_ci		gc->direction_output = devtype->gpio_dir_out;
35962306a36Sopenharmony_ci	if (devtype->gpio_get)
36062306a36Sopenharmony_ci		gc->get = devtype->gpio_get;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	gc->to_irq = mpc8xxx_gpio_to_irq;
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	/*
36562306a36Sopenharmony_ci	 * The GPIO Input Buffer Enable register(GPIO_IBE) is used to control
36662306a36Sopenharmony_ci	 * the input enable of each individual GPIO port.  When an individual
36762306a36Sopenharmony_ci	 * GPIO port’s direction is set to input (GPIO_GPDIR[DRn=0]), the
36862306a36Sopenharmony_ci	 * associated input enable must be set (GPIOxGPIE[IEn]=1) to propagate
36962306a36Sopenharmony_ci	 * the port value to the GPIO Data Register.
37062306a36Sopenharmony_ci	 */
37162306a36Sopenharmony_ci	fwnode = dev_fwnode(&pdev->dev);
37262306a36Sopenharmony_ci	if (of_device_is_compatible(np, "fsl,qoriq-gpio") ||
37362306a36Sopenharmony_ci	    of_device_is_compatible(np, "fsl,ls1028a-gpio") ||
37462306a36Sopenharmony_ci	    of_device_is_compatible(np, "fsl,ls1088a-gpio") ||
37562306a36Sopenharmony_ci	    is_acpi_node(fwnode)) {
37662306a36Sopenharmony_ci		gc->write_reg(mpc8xxx_gc->regs + GPIO_IBE, 0xffffffff);
37762306a36Sopenharmony_ci		/* Also, latch state of GPIOs configured as output by bootloader. */
37862306a36Sopenharmony_ci		gc->bgpio_data = gc->read_reg(mpc8xxx_gc->regs + GPIO_DAT) &
37962306a36Sopenharmony_ci			gc->read_reg(mpc8xxx_gc->regs + GPIO_DIR);
38062306a36Sopenharmony_ci	}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_ci	ret = devm_gpiochip_add_data(&pdev->dev, gc, mpc8xxx_gc);
38362306a36Sopenharmony_ci	if (ret) {
38462306a36Sopenharmony_ci		dev_err(&pdev->dev,
38562306a36Sopenharmony_ci			"GPIO chip registration failed with status %d\n", ret);
38662306a36Sopenharmony_ci		return ret;
38762306a36Sopenharmony_ci	}
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	mpc8xxx_gc->irqn = platform_get_irq(pdev, 0);
39062306a36Sopenharmony_ci	if (mpc8xxx_gc->irqn < 0)
39162306a36Sopenharmony_ci		return mpc8xxx_gc->irqn;
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	mpc8xxx_gc->irq = irq_domain_create_linear(fwnode,
39462306a36Sopenharmony_ci						   MPC8XXX_GPIO_PINS,
39562306a36Sopenharmony_ci						   &mpc8xxx_gpio_irq_ops,
39662306a36Sopenharmony_ci						   mpc8xxx_gc);
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_ci	if (!mpc8xxx_gc->irq)
39962306a36Sopenharmony_ci		return 0;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	/* ack and mask all irqs */
40262306a36Sopenharmony_ci	gc->write_reg(mpc8xxx_gc->regs + GPIO_IER, 0xffffffff);
40362306a36Sopenharmony_ci	gc->write_reg(mpc8xxx_gc->regs + GPIO_IMR, 0);
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	ret = devm_request_irq(&pdev->dev, mpc8xxx_gc->irqn,
40662306a36Sopenharmony_ci			       mpc8xxx_gpio_irq_cascade,
40762306a36Sopenharmony_ci			       IRQF_NO_THREAD | IRQF_SHARED, "gpio-cascade",
40862306a36Sopenharmony_ci			       mpc8xxx_gc);
40962306a36Sopenharmony_ci	if (ret) {
41062306a36Sopenharmony_ci		dev_err(&pdev->dev,
41162306a36Sopenharmony_ci			"failed to devm_request_irq(%d), ret = %d\n",
41262306a36Sopenharmony_ci			mpc8xxx_gc->irqn, ret);
41362306a36Sopenharmony_ci		goto err;
41462306a36Sopenharmony_ci	}
41562306a36Sopenharmony_ci
41662306a36Sopenharmony_ci	return 0;
41762306a36Sopenharmony_cierr:
41862306a36Sopenharmony_ci	irq_domain_remove(mpc8xxx_gc->irq);
41962306a36Sopenharmony_ci	return ret;
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_cistatic int mpc8xxx_remove(struct platform_device *pdev)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	struct mpc8xxx_gpio_chip *mpc8xxx_gc = platform_get_drvdata(pdev);
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (mpc8xxx_gc->irq) {
42762306a36Sopenharmony_ci		irq_set_chained_handler_and_data(mpc8xxx_gc->irqn, NULL, NULL);
42862306a36Sopenharmony_ci		irq_domain_remove(mpc8xxx_gc->irq);
42962306a36Sopenharmony_ci	}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	return 0;
43262306a36Sopenharmony_ci}
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci#ifdef CONFIG_ACPI
43562306a36Sopenharmony_cistatic const struct acpi_device_id gpio_acpi_ids[] = {
43662306a36Sopenharmony_ci	{"NXP0031",},
43762306a36Sopenharmony_ci	{ }
43862306a36Sopenharmony_ci};
43962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, gpio_acpi_ids);
44062306a36Sopenharmony_ci#endif
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_cistatic struct platform_driver mpc8xxx_plat_driver = {
44362306a36Sopenharmony_ci	.probe		= mpc8xxx_probe,
44462306a36Sopenharmony_ci	.remove		= mpc8xxx_remove,
44562306a36Sopenharmony_ci	.driver		= {
44662306a36Sopenharmony_ci		.name = "gpio-mpc8xxx",
44762306a36Sopenharmony_ci		.of_match_table	= mpc8xxx_gpio_ids,
44862306a36Sopenharmony_ci		.acpi_match_table = ACPI_PTR(gpio_acpi_ids),
44962306a36Sopenharmony_ci	},
45062306a36Sopenharmony_ci};
45162306a36Sopenharmony_ci
45262306a36Sopenharmony_cistatic int __init mpc8xxx_init(void)
45362306a36Sopenharmony_ci{
45462306a36Sopenharmony_ci	return platform_driver_register(&mpc8xxx_plat_driver);
45562306a36Sopenharmony_ci}
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ciarch_initcall(mpc8xxx_init);
458