18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2018 Spreadtrum Communications Inc.
48c2ecf20Sopenharmony_ci * Copyright (C) 2018 Linaro Ltd.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/bitops.h>
88c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h>
98c2ecf20Sopenharmony_ci#include <linux/kernel.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/of_device.h>
128c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
138c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
148c2ecf20Sopenharmony_ci
158c2ecf20Sopenharmony_ci/* GPIO registers definition */
168c2ecf20Sopenharmony_ci#define SPRD_GPIO_DATA		0x0
178c2ecf20Sopenharmony_ci#define SPRD_GPIO_DMSK		0x4
188c2ecf20Sopenharmony_ci#define SPRD_GPIO_DIR		0x8
198c2ecf20Sopenharmony_ci#define SPRD_GPIO_IS		0xc
208c2ecf20Sopenharmony_ci#define SPRD_GPIO_IBE		0x10
218c2ecf20Sopenharmony_ci#define SPRD_GPIO_IEV		0x14
228c2ecf20Sopenharmony_ci#define SPRD_GPIO_IE		0x18
238c2ecf20Sopenharmony_ci#define SPRD_GPIO_RIS		0x1c
248c2ecf20Sopenharmony_ci#define SPRD_GPIO_MIS		0x20
258c2ecf20Sopenharmony_ci#define SPRD_GPIO_IC		0x24
268c2ecf20Sopenharmony_ci#define SPRD_GPIO_INEN		0x28
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* We have 16 banks GPIOs and each bank contain 16 GPIOs */
298c2ecf20Sopenharmony_ci#define SPRD_GPIO_BANK_NR	16
308c2ecf20Sopenharmony_ci#define SPRD_GPIO_NR		256
318c2ecf20Sopenharmony_ci#define SPRD_GPIO_BANK_SIZE	0x80
328c2ecf20Sopenharmony_ci#define SPRD_GPIO_BANK_MASK	GENMASK(15, 0)
338c2ecf20Sopenharmony_ci#define SPRD_GPIO_BIT(x)	((x) & (SPRD_GPIO_BANK_NR - 1))
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_cistruct sprd_gpio {
368c2ecf20Sopenharmony_ci	struct gpio_chip chip;
378c2ecf20Sopenharmony_ci	void __iomem *base;
388c2ecf20Sopenharmony_ci	spinlock_t lock;
398c2ecf20Sopenharmony_ci	int irq;
408c2ecf20Sopenharmony_ci};
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic inline void __iomem *sprd_gpio_bank_base(struct sprd_gpio *sprd_gpio,
438c2ecf20Sopenharmony_ci						unsigned int bank)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	return sprd_gpio->base + SPRD_GPIO_BANK_SIZE * bank;
468c2ecf20Sopenharmony_ci}
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_cistatic void sprd_gpio_update(struct gpio_chip *chip, unsigned int offset,
498c2ecf20Sopenharmony_ci			     u16 reg, int val)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	struct sprd_gpio *sprd_gpio = gpiochip_get_data(chip);
528c2ecf20Sopenharmony_ci	void __iomem *base = sprd_gpio_bank_base(sprd_gpio,
538c2ecf20Sopenharmony_ci						 offset / SPRD_GPIO_BANK_NR);
548c2ecf20Sopenharmony_ci	unsigned long flags;
558c2ecf20Sopenharmony_ci	u32 tmp;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	spin_lock_irqsave(&sprd_gpio->lock, flags);
588c2ecf20Sopenharmony_ci	tmp = readl_relaxed(base + reg);
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	if (val)
618c2ecf20Sopenharmony_ci		tmp |= BIT(SPRD_GPIO_BIT(offset));
628c2ecf20Sopenharmony_ci	else
638c2ecf20Sopenharmony_ci		tmp &= ~BIT(SPRD_GPIO_BIT(offset));
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci	writel_relaxed(tmp, base + reg);
668c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&sprd_gpio->lock, flags);
678c2ecf20Sopenharmony_ci}
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_cistatic int sprd_gpio_read(struct gpio_chip *chip, unsigned int offset, u16 reg)
708c2ecf20Sopenharmony_ci{
718c2ecf20Sopenharmony_ci	struct sprd_gpio *sprd_gpio = gpiochip_get_data(chip);
728c2ecf20Sopenharmony_ci	void __iomem *base = sprd_gpio_bank_base(sprd_gpio,
738c2ecf20Sopenharmony_ci						 offset / SPRD_GPIO_BANK_NR);
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci	return !!(readl_relaxed(base + reg) & BIT(SPRD_GPIO_BIT(offset)));
768c2ecf20Sopenharmony_ci}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cistatic int sprd_gpio_request(struct gpio_chip *chip, unsigned int offset)
798c2ecf20Sopenharmony_ci{
808c2ecf20Sopenharmony_ci	sprd_gpio_update(chip, offset, SPRD_GPIO_DMSK, 1);
818c2ecf20Sopenharmony_ci	return 0;
828c2ecf20Sopenharmony_ci}
838c2ecf20Sopenharmony_ci
848c2ecf20Sopenharmony_cistatic void sprd_gpio_free(struct gpio_chip *chip, unsigned int offset)
858c2ecf20Sopenharmony_ci{
868c2ecf20Sopenharmony_ci	sprd_gpio_update(chip, offset, SPRD_GPIO_DMSK, 0);
878c2ecf20Sopenharmony_ci}
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cistatic int sprd_gpio_direction_input(struct gpio_chip *chip,
908c2ecf20Sopenharmony_ci				     unsigned int offset)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	sprd_gpio_update(chip, offset, SPRD_GPIO_DIR, 0);
938c2ecf20Sopenharmony_ci	sprd_gpio_update(chip, offset, SPRD_GPIO_INEN, 1);
948c2ecf20Sopenharmony_ci	return 0;
958c2ecf20Sopenharmony_ci}
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cistatic int sprd_gpio_direction_output(struct gpio_chip *chip,
988c2ecf20Sopenharmony_ci				      unsigned int offset, int value)
998c2ecf20Sopenharmony_ci{
1008c2ecf20Sopenharmony_ci	sprd_gpio_update(chip, offset, SPRD_GPIO_DIR, 1);
1018c2ecf20Sopenharmony_ci	sprd_gpio_update(chip, offset, SPRD_GPIO_INEN, 0);
1028c2ecf20Sopenharmony_ci	sprd_gpio_update(chip, offset, SPRD_GPIO_DATA, value);
1038c2ecf20Sopenharmony_ci	return 0;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic int sprd_gpio_get(struct gpio_chip *chip, unsigned int offset)
1078c2ecf20Sopenharmony_ci{
1088c2ecf20Sopenharmony_ci	return sprd_gpio_read(chip, offset, SPRD_GPIO_DATA);
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic void sprd_gpio_set(struct gpio_chip *chip, unsigned int offset,
1128c2ecf20Sopenharmony_ci			  int value)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	sprd_gpio_update(chip, offset, SPRD_GPIO_DATA, value);
1158c2ecf20Sopenharmony_ci}
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_cistatic void sprd_gpio_irq_mask(struct irq_data *data)
1188c2ecf20Sopenharmony_ci{
1198c2ecf20Sopenharmony_ci	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
1208c2ecf20Sopenharmony_ci	u32 offset = irqd_to_hwirq(data);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	sprd_gpio_update(chip, offset, SPRD_GPIO_IE, 0);
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic void sprd_gpio_irq_ack(struct irq_data *data)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
1288c2ecf20Sopenharmony_ci	u32 offset = irqd_to_hwirq(data);
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	sprd_gpio_update(chip, offset, SPRD_GPIO_IC, 1);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_cistatic void sprd_gpio_irq_unmask(struct irq_data *data)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
1368c2ecf20Sopenharmony_ci	u32 offset = irqd_to_hwirq(data);
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	sprd_gpio_update(chip, offset, SPRD_GPIO_IE, 1);
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic int sprd_gpio_irq_set_type(struct irq_data *data,
1428c2ecf20Sopenharmony_ci				  unsigned int flow_type)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	struct gpio_chip *chip = irq_data_get_irq_chip_data(data);
1458c2ecf20Sopenharmony_ci	u32 offset = irqd_to_hwirq(data);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	switch (flow_type) {
1488c2ecf20Sopenharmony_ci	case IRQ_TYPE_EDGE_RISING:
1498c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0);
1508c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0);
1518c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 1);
1528c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IC, 1);
1538c2ecf20Sopenharmony_ci		irq_set_handler_locked(data, handle_edge_irq);
1548c2ecf20Sopenharmony_ci		break;
1558c2ecf20Sopenharmony_ci	case IRQ_TYPE_EDGE_FALLING:
1568c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0);
1578c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0);
1588c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 0);
1598c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IC, 1);
1608c2ecf20Sopenharmony_ci		irq_set_handler_locked(data, handle_edge_irq);
1618c2ecf20Sopenharmony_ci		break;
1628c2ecf20Sopenharmony_ci	case IRQ_TYPE_EDGE_BOTH:
1638c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 0);
1648c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 1);
1658c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IC, 1);
1668c2ecf20Sopenharmony_ci		irq_set_handler_locked(data, handle_edge_irq);
1678c2ecf20Sopenharmony_ci		break;
1688c2ecf20Sopenharmony_ci	case IRQ_TYPE_LEVEL_HIGH:
1698c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 1);
1708c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0);
1718c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 1);
1728c2ecf20Sopenharmony_ci		irq_set_handler_locked(data, handle_level_irq);
1738c2ecf20Sopenharmony_ci		break;
1748c2ecf20Sopenharmony_ci	case IRQ_TYPE_LEVEL_LOW:
1758c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IS, 1);
1768c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IBE, 0);
1778c2ecf20Sopenharmony_ci		sprd_gpio_update(chip, offset, SPRD_GPIO_IEV, 0);
1788c2ecf20Sopenharmony_ci		irq_set_handler_locked(data, handle_level_irq);
1798c2ecf20Sopenharmony_ci		break;
1808c2ecf20Sopenharmony_ci	default:
1818c2ecf20Sopenharmony_ci		return -EINVAL;
1828c2ecf20Sopenharmony_ci	}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	return 0;
1858c2ecf20Sopenharmony_ci}
1868c2ecf20Sopenharmony_ci
1878c2ecf20Sopenharmony_cistatic void sprd_gpio_irq_handler(struct irq_desc *desc)
1888c2ecf20Sopenharmony_ci{
1898c2ecf20Sopenharmony_ci	struct gpio_chip *chip = irq_desc_get_handler_data(desc);
1908c2ecf20Sopenharmony_ci	struct irq_chip *ic = irq_desc_get_chip(desc);
1918c2ecf20Sopenharmony_ci	struct sprd_gpio *sprd_gpio = gpiochip_get_data(chip);
1928c2ecf20Sopenharmony_ci	u32 bank, n, girq;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	chained_irq_enter(ic, desc);
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	for (bank = 0; bank * SPRD_GPIO_BANK_NR < chip->ngpio; bank++) {
1978c2ecf20Sopenharmony_ci		void __iomem *base = sprd_gpio_bank_base(sprd_gpio, bank);
1988c2ecf20Sopenharmony_ci		unsigned long reg = readl_relaxed(base + SPRD_GPIO_MIS) &
1998c2ecf20Sopenharmony_ci			SPRD_GPIO_BANK_MASK;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci		for_each_set_bit(n, &reg, SPRD_GPIO_BANK_NR) {
2028c2ecf20Sopenharmony_ci			girq = irq_find_mapping(chip->irq.domain,
2038c2ecf20Sopenharmony_ci						bank * SPRD_GPIO_BANK_NR + n);
2048c2ecf20Sopenharmony_ci
2058c2ecf20Sopenharmony_ci			generic_handle_irq(girq);
2068c2ecf20Sopenharmony_ci		}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci	chained_irq_exit(ic, desc);
2108c2ecf20Sopenharmony_ci}
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_cistatic struct irq_chip sprd_gpio_irqchip = {
2138c2ecf20Sopenharmony_ci	.name = "sprd-gpio",
2148c2ecf20Sopenharmony_ci	.irq_ack = sprd_gpio_irq_ack,
2158c2ecf20Sopenharmony_ci	.irq_mask = sprd_gpio_irq_mask,
2168c2ecf20Sopenharmony_ci	.irq_unmask = sprd_gpio_irq_unmask,
2178c2ecf20Sopenharmony_ci	.irq_set_type = sprd_gpio_irq_set_type,
2188c2ecf20Sopenharmony_ci	.flags = IRQCHIP_SKIP_SET_WAKE,
2198c2ecf20Sopenharmony_ci};
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistatic int sprd_gpio_probe(struct platform_device *pdev)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	struct gpio_irq_chip *irq;
2248c2ecf20Sopenharmony_ci	struct sprd_gpio *sprd_gpio;
2258c2ecf20Sopenharmony_ci	int ret;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	sprd_gpio = devm_kzalloc(&pdev->dev, sizeof(*sprd_gpio), GFP_KERNEL);
2288c2ecf20Sopenharmony_ci	if (!sprd_gpio)
2298c2ecf20Sopenharmony_ci		return -ENOMEM;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	sprd_gpio->irq = platform_get_irq(pdev, 0);
2328c2ecf20Sopenharmony_ci	if (sprd_gpio->irq < 0)
2338c2ecf20Sopenharmony_ci		return sprd_gpio->irq;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	sprd_gpio->base = devm_platform_ioremap_resource(pdev, 0);
2368c2ecf20Sopenharmony_ci	if (IS_ERR(sprd_gpio->base))
2378c2ecf20Sopenharmony_ci		return PTR_ERR(sprd_gpio->base);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	spin_lock_init(&sprd_gpio->lock);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	sprd_gpio->chip.label = dev_name(&pdev->dev);
2428c2ecf20Sopenharmony_ci	sprd_gpio->chip.ngpio = SPRD_GPIO_NR;
2438c2ecf20Sopenharmony_ci	sprd_gpio->chip.base = -1;
2448c2ecf20Sopenharmony_ci	sprd_gpio->chip.parent = &pdev->dev;
2458c2ecf20Sopenharmony_ci	sprd_gpio->chip.of_node = pdev->dev.of_node;
2468c2ecf20Sopenharmony_ci	sprd_gpio->chip.request = sprd_gpio_request;
2478c2ecf20Sopenharmony_ci	sprd_gpio->chip.free = sprd_gpio_free;
2488c2ecf20Sopenharmony_ci	sprd_gpio->chip.get = sprd_gpio_get;
2498c2ecf20Sopenharmony_ci	sprd_gpio->chip.set = sprd_gpio_set;
2508c2ecf20Sopenharmony_ci	sprd_gpio->chip.direction_input = sprd_gpio_direction_input;
2518c2ecf20Sopenharmony_ci	sprd_gpio->chip.direction_output = sprd_gpio_direction_output;
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	irq = &sprd_gpio->chip.irq;
2548c2ecf20Sopenharmony_ci	irq->chip = &sprd_gpio_irqchip;
2558c2ecf20Sopenharmony_ci	irq->handler = handle_bad_irq;
2568c2ecf20Sopenharmony_ci	irq->default_type = IRQ_TYPE_NONE;
2578c2ecf20Sopenharmony_ci	irq->parent_handler = sprd_gpio_irq_handler;
2588c2ecf20Sopenharmony_ci	irq->parent_handler_data = sprd_gpio;
2598c2ecf20Sopenharmony_ci	irq->num_parents = 1;
2608c2ecf20Sopenharmony_ci	irq->parents = &sprd_gpio->irq;
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	ret = devm_gpiochip_add_data(&pdev->dev, &sprd_gpio->chip, sprd_gpio);
2638c2ecf20Sopenharmony_ci	if (ret < 0) {
2648c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Could not register gpiochip %d\n", ret);
2658c2ecf20Sopenharmony_ci		return ret;
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, sprd_gpio);
2698c2ecf20Sopenharmony_ci	return 0;
2708c2ecf20Sopenharmony_ci}
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_cistatic const struct of_device_id sprd_gpio_of_match[] = {
2738c2ecf20Sopenharmony_ci	{ .compatible = "sprd,sc9860-gpio", },
2748c2ecf20Sopenharmony_ci	{ /* end of list */ }
2758c2ecf20Sopenharmony_ci};
2768c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, sprd_gpio_of_match);
2778c2ecf20Sopenharmony_ci
2788c2ecf20Sopenharmony_cistatic struct platform_driver sprd_gpio_driver = {
2798c2ecf20Sopenharmony_ci	.probe = sprd_gpio_probe,
2808c2ecf20Sopenharmony_ci	.driver = {
2818c2ecf20Sopenharmony_ci		.name = "sprd-gpio",
2828c2ecf20Sopenharmony_ci		.of_match_table	= sprd_gpio_of_match,
2838c2ecf20Sopenharmony_ci	},
2848c2ecf20Sopenharmony_ci};
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_cimodule_platform_driver_probe(sprd_gpio_driver, sprd_gpio_probe);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Spreadtrum GPIO driver");
2898c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2");
290