162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * GPIO controller in LSI ZEVIO SoCs.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Author: Fabian Vogt <fabian@ritter-vogt.de>
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/bitops.h>
962306a36Sopenharmony_ci#include <linux/errno.h>
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/io.h>
1262306a36Sopenharmony_ci#include <linux/mod_devicetable.h>
1362306a36Sopenharmony_ci#include <linux/platform_device.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/spinlock.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/gpio/driver.h>
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci/*
2062306a36Sopenharmony_ci * Memory layout:
2162306a36Sopenharmony_ci * This chip has four gpio sections, each controls 8 GPIOs.
2262306a36Sopenharmony_ci * Bit 0 in section 0 is GPIO 0, bit 2 in section 1 is GPIO 10.
2362306a36Sopenharmony_ci * Disclaimer: Reverse engineered!
2462306a36Sopenharmony_ci * For more information refer to:
2562306a36Sopenharmony_ci * http://hackspire.unsads.com/wiki/index.php/Memory-mapped_I/O_ports#90000000_-_General_Purpose_I.2FO_.28GPIO.29
2662306a36Sopenharmony_ci *
2762306a36Sopenharmony_ci * 0x00-0x3F: Section 0
2862306a36Sopenharmony_ci *     +0x00: Masked interrupt status (read-only)
2962306a36Sopenharmony_ci *     +0x04: R: Interrupt status W: Reset interrupt status
3062306a36Sopenharmony_ci *     +0x08: R: Interrupt mask W: Mask interrupt
3162306a36Sopenharmony_ci *     +0x0C: W: Unmask interrupt (write-only)
3262306a36Sopenharmony_ci *     +0x10: Direction: I/O=1/0
3362306a36Sopenharmony_ci *     +0x14: Output
3462306a36Sopenharmony_ci *     +0x18: Input (read-only)
3562306a36Sopenharmony_ci *     +0x20: R: Level interrupt W: Set as level interrupt
3662306a36Sopenharmony_ci * 0x40-0x7F: Section 1
3762306a36Sopenharmony_ci * 0x80-0xBF: Section 2
3862306a36Sopenharmony_ci * 0xC0-0xFF: Section 3
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define ZEVIO_GPIO_SECTION_SIZE			0x40
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci/* Offsets to various registers */
4462306a36Sopenharmony_ci#define ZEVIO_GPIO_INT_MASKED_STATUS	0x00
4562306a36Sopenharmony_ci#define ZEVIO_GPIO_INT_STATUS		0x04
4662306a36Sopenharmony_ci#define ZEVIO_GPIO_INT_UNMASK		0x08
4762306a36Sopenharmony_ci#define ZEVIO_GPIO_INT_MASK		0x0C
4862306a36Sopenharmony_ci#define ZEVIO_GPIO_DIRECTION		0x10
4962306a36Sopenharmony_ci#define ZEVIO_GPIO_OUTPUT		0x14
5062306a36Sopenharmony_ci#define ZEVIO_GPIO_INPUT			0x18
5162306a36Sopenharmony_ci#define ZEVIO_GPIO_INT_STICKY		0x20
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci/* Bit number of GPIO in its section */
5462306a36Sopenharmony_ci#define ZEVIO_GPIO_BIT(gpio) (gpio&7)
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistruct zevio_gpio {
5762306a36Sopenharmony_ci	struct gpio_chip        chip;
5862306a36Sopenharmony_ci	spinlock_t		lock;
5962306a36Sopenharmony_ci	void __iomem		*regs;
6062306a36Sopenharmony_ci};
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic inline u32 zevio_gpio_port_get(struct zevio_gpio *c, unsigned pin,
6362306a36Sopenharmony_ci					unsigned port_offset)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
6662306a36Sopenharmony_ci	return readl(IOMEM(c->regs + section_offset + port_offset));
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_cistatic inline void zevio_gpio_port_set(struct zevio_gpio *c, unsigned pin,
7062306a36Sopenharmony_ci					unsigned port_offset, u32 val)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	unsigned section_offset = ((pin >> 3) & 3)*ZEVIO_GPIO_SECTION_SIZE;
7362306a36Sopenharmony_ci	writel(val, IOMEM(c->regs + section_offset + port_offset));
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci/* Functions for struct gpio_chip */
7762306a36Sopenharmony_cistatic int zevio_gpio_get(struct gpio_chip *chip, unsigned pin)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	struct zevio_gpio *controller = gpiochip_get_data(chip);
8062306a36Sopenharmony_ci	u32 val, dir;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	spin_lock(&controller->lock);
8362306a36Sopenharmony_ci	dir = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION);
8462306a36Sopenharmony_ci	if (dir & BIT(ZEVIO_GPIO_BIT(pin)))
8562306a36Sopenharmony_ci		val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_INPUT);
8662306a36Sopenharmony_ci	else
8762306a36Sopenharmony_ci		val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT);
8862306a36Sopenharmony_ci	spin_unlock(&controller->lock);
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return (val >> ZEVIO_GPIO_BIT(pin)) & 0x1;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_cistatic void zevio_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	struct zevio_gpio *controller = gpiochip_get_data(chip);
9662306a36Sopenharmony_ci	u32 val;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	spin_lock(&controller->lock);
9962306a36Sopenharmony_ci	val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT);
10062306a36Sopenharmony_ci	if (value)
10162306a36Sopenharmony_ci		val |= BIT(ZEVIO_GPIO_BIT(pin));
10262306a36Sopenharmony_ci	else
10362306a36Sopenharmony_ci		val &= ~BIT(ZEVIO_GPIO_BIT(pin));
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val);
10662306a36Sopenharmony_ci	spin_unlock(&controller->lock);
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_cistatic int zevio_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
11062306a36Sopenharmony_ci{
11162306a36Sopenharmony_ci	struct zevio_gpio *controller = gpiochip_get_data(chip);
11262306a36Sopenharmony_ci	u32 val;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	spin_lock(&controller->lock);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION);
11762306a36Sopenharmony_ci	val |= BIT(ZEVIO_GPIO_BIT(pin));
11862306a36Sopenharmony_ci	zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val);
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	spin_unlock(&controller->lock);
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	return 0;
12362306a36Sopenharmony_ci}
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_cistatic int zevio_gpio_direction_output(struct gpio_chip *chip,
12662306a36Sopenharmony_ci				       unsigned pin, int value)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	struct zevio_gpio *controller = gpiochip_get_data(chip);
12962306a36Sopenharmony_ci	u32 val;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	spin_lock(&controller->lock);
13262306a36Sopenharmony_ci	val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_OUTPUT);
13362306a36Sopenharmony_ci	if (value)
13462306a36Sopenharmony_ci		val |= BIT(ZEVIO_GPIO_BIT(pin));
13562306a36Sopenharmony_ci	else
13662306a36Sopenharmony_ci		val &= ~BIT(ZEVIO_GPIO_BIT(pin));
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_OUTPUT, val);
13962306a36Sopenharmony_ci	val = zevio_gpio_port_get(controller, pin, ZEVIO_GPIO_DIRECTION);
14062306a36Sopenharmony_ci	val &= ~BIT(ZEVIO_GPIO_BIT(pin));
14162306a36Sopenharmony_ci	zevio_gpio_port_set(controller, pin, ZEVIO_GPIO_DIRECTION, val);
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	spin_unlock(&controller->lock);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	return 0;
14662306a36Sopenharmony_ci}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_cistatic int zevio_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	/*
15162306a36Sopenharmony_ci	 * TODO: Implement IRQs.
15262306a36Sopenharmony_ci	 * Not implemented yet due to weird lockups
15362306a36Sopenharmony_ci	 */
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	return -ENXIO;
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_cistatic const struct gpio_chip zevio_gpio_chip = {
15962306a36Sopenharmony_ci	.direction_input	= zevio_gpio_direction_input,
16062306a36Sopenharmony_ci	.direction_output	= zevio_gpio_direction_output,
16162306a36Sopenharmony_ci	.set			= zevio_gpio_set,
16262306a36Sopenharmony_ci	.get			= zevio_gpio_get,
16362306a36Sopenharmony_ci	.to_irq			= zevio_gpio_to_irq,
16462306a36Sopenharmony_ci	.base			= 0,
16562306a36Sopenharmony_ci	.owner			= THIS_MODULE,
16662306a36Sopenharmony_ci	.ngpio			= 32,
16762306a36Sopenharmony_ci};
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci/* Initialization */
17062306a36Sopenharmony_cistatic int zevio_gpio_probe(struct platform_device *pdev)
17162306a36Sopenharmony_ci{
17262306a36Sopenharmony_ci	struct zevio_gpio *controller;
17362306a36Sopenharmony_ci	int status, i;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	controller = devm_kzalloc(&pdev->dev, sizeof(*controller), GFP_KERNEL);
17662306a36Sopenharmony_ci	if (!controller)
17762306a36Sopenharmony_ci		return -ENOMEM;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/* Copy our reference */
18062306a36Sopenharmony_ci	controller->chip = zevio_gpio_chip;
18162306a36Sopenharmony_ci	controller->chip.parent = &pdev->dev;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	controller->regs = devm_platform_ioremap_resource(pdev, 0);
18462306a36Sopenharmony_ci	if (IS_ERR(controller->regs))
18562306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(controller->regs),
18662306a36Sopenharmony_ci				     "failed to ioremap memory resource\n");
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	status = devm_gpiochip_add_data(&pdev->dev, &controller->chip, controller);
18962306a36Sopenharmony_ci	if (status) {
19062306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to add gpiochip: %d\n", status);
19162306a36Sopenharmony_ci		return status;
19262306a36Sopenharmony_ci	}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_ci	spin_lock_init(&controller->lock);
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	/* Disable interrupts, they only cause errors */
19762306a36Sopenharmony_ci	for (i = 0; i < controller->chip.ngpio; i += 8)
19862306a36Sopenharmony_ci		zevio_gpio_port_set(controller, i, ZEVIO_GPIO_INT_MASK, 0xFF);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	dev_dbg(controller->chip.parent, "ZEVIO GPIO controller set up!\n");
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	return 0;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic const struct of_device_id zevio_gpio_of_match[] = {
20662306a36Sopenharmony_ci	{ .compatible = "lsi,zevio-gpio", },
20762306a36Sopenharmony_ci	{ },
20862306a36Sopenharmony_ci};
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_cistatic struct platform_driver zevio_gpio_driver = {
21162306a36Sopenharmony_ci	.driver		= {
21262306a36Sopenharmony_ci		.name	= "gpio-zevio",
21362306a36Sopenharmony_ci		.of_match_table = zevio_gpio_of_match,
21462306a36Sopenharmony_ci		.suppress_bind_attrs = true,
21562306a36Sopenharmony_ci	},
21662306a36Sopenharmony_ci	.probe		= zevio_gpio_probe,
21762306a36Sopenharmony_ci};
21862306a36Sopenharmony_cibuiltin_platform_driver(zevio_gpio_driver);
219