18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright 2019 American Megatrends International LLC.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Author: Karthikeyan Mani <karthikeyanm@amiindia.co.in>
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include <linux/bitfield.h>
98c2ecf20Sopenharmony_ci#include <linux/clk.h>
108c2ecf20Sopenharmony_ci#include <linux/gpio/driver.h>
118c2ecf20Sopenharmony_ci#include <linux/hashtable.h>
128c2ecf20Sopenharmony_ci#include <linux/init.h>
138c2ecf20Sopenharmony_ci#include <linux/io.h>
148c2ecf20Sopenharmony_ci#include <linux/kernel.h>
158c2ecf20Sopenharmony_ci#include <linux/module.h>
168c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
178c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
188c2ecf20Sopenharmony_ci#include <linux/string.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci/*
218c2ecf20Sopenharmony_ci * MAX_NR_HW_GPIO represents the number of actual hardware-supported GPIOs (ie,
228c2ecf20Sopenharmony_ci * slots within the clocked serial GPIO data). Since each HW GPIO is both an
238c2ecf20Sopenharmony_ci * input and an output, we provide MAX_NR_HW_GPIO * 2 lines on our gpiochip
248c2ecf20Sopenharmony_ci * device.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * We use SGPIO_OUTPUT_OFFSET to define the split between the inputs and
278c2ecf20Sopenharmony_ci * outputs; the inputs start at line 0, the outputs start at OUTPUT_OFFSET.
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_ci#define MAX_NR_HW_SGPIO			80
308c2ecf20Sopenharmony_ci#define SGPIO_OUTPUT_OFFSET		MAX_NR_HW_SGPIO
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define ASPEED_SGPIO_CTRL		0x54
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci#define ASPEED_SGPIO_PINS_MASK		GENMASK(9, 6)
358c2ecf20Sopenharmony_ci#define ASPEED_SGPIO_CLK_DIV_MASK	GENMASK(31, 16)
368c2ecf20Sopenharmony_ci#define ASPEED_SGPIO_ENABLE		BIT(0)
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistruct aspeed_sgpio {
398c2ecf20Sopenharmony_ci	struct gpio_chip chip;
408c2ecf20Sopenharmony_ci	struct clk *pclk;
418c2ecf20Sopenharmony_ci	spinlock_t lock;
428c2ecf20Sopenharmony_ci	void __iomem *base;
438c2ecf20Sopenharmony_ci	int irq;
448c2ecf20Sopenharmony_ci	int n_sgpio;
458c2ecf20Sopenharmony_ci};
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistruct aspeed_sgpio_bank {
488c2ecf20Sopenharmony_ci	uint16_t    val_regs;
498c2ecf20Sopenharmony_ci	uint16_t    rdata_reg;
508c2ecf20Sopenharmony_ci	uint16_t    irq_regs;
518c2ecf20Sopenharmony_ci	const char  names[4][3];
528c2ecf20Sopenharmony_ci};
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci/*
558c2ecf20Sopenharmony_ci * Note: The "value" register returns the input value when the GPIO is
568c2ecf20Sopenharmony_ci *	 configured as an input.
578c2ecf20Sopenharmony_ci *
588c2ecf20Sopenharmony_ci *	 The "rdata" register returns the output value when the GPIO is
598c2ecf20Sopenharmony_ci *	 configured as an output.
608c2ecf20Sopenharmony_ci */
618c2ecf20Sopenharmony_cistatic const struct aspeed_sgpio_bank aspeed_sgpio_banks[] = {
628c2ecf20Sopenharmony_ci	{
638c2ecf20Sopenharmony_ci		.val_regs = 0x0000,
648c2ecf20Sopenharmony_ci		.rdata_reg = 0x0070,
658c2ecf20Sopenharmony_ci		.irq_regs = 0x0004,
668c2ecf20Sopenharmony_ci		.names = { "A", "B", "C", "D" },
678c2ecf20Sopenharmony_ci	},
688c2ecf20Sopenharmony_ci	{
698c2ecf20Sopenharmony_ci		.val_regs = 0x001C,
708c2ecf20Sopenharmony_ci		.rdata_reg = 0x0074,
718c2ecf20Sopenharmony_ci		.irq_regs = 0x0020,
728c2ecf20Sopenharmony_ci		.names = { "E", "F", "G", "H" },
738c2ecf20Sopenharmony_ci	},
748c2ecf20Sopenharmony_ci	{
758c2ecf20Sopenharmony_ci		.val_regs = 0x0038,
768c2ecf20Sopenharmony_ci		.rdata_reg = 0x0078,
778c2ecf20Sopenharmony_ci		.irq_regs = 0x003C,
788c2ecf20Sopenharmony_ci		.names = { "I", "J" },
798c2ecf20Sopenharmony_ci	},
808c2ecf20Sopenharmony_ci};
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_cienum aspeed_sgpio_reg {
838c2ecf20Sopenharmony_ci	reg_val,
848c2ecf20Sopenharmony_ci	reg_rdata,
858c2ecf20Sopenharmony_ci	reg_irq_enable,
868c2ecf20Sopenharmony_ci	reg_irq_type0,
878c2ecf20Sopenharmony_ci	reg_irq_type1,
888c2ecf20Sopenharmony_ci	reg_irq_type2,
898c2ecf20Sopenharmony_ci	reg_irq_status,
908c2ecf20Sopenharmony_ci};
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci#define GPIO_VAL_VALUE      0x00
938c2ecf20Sopenharmony_ci#define GPIO_IRQ_ENABLE     0x00
948c2ecf20Sopenharmony_ci#define GPIO_IRQ_TYPE0      0x04
958c2ecf20Sopenharmony_ci#define GPIO_IRQ_TYPE1      0x08
968c2ecf20Sopenharmony_ci#define GPIO_IRQ_TYPE2      0x0C
978c2ecf20Sopenharmony_ci#define GPIO_IRQ_STATUS     0x10
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic void __iomem *bank_reg(struct aspeed_sgpio *gpio,
1008c2ecf20Sopenharmony_ci				     const struct aspeed_sgpio_bank *bank,
1018c2ecf20Sopenharmony_ci				     const enum aspeed_sgpio_reg reg)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	switch (reg) {
1048c2ecf20Sopenharmony_ci	case reg_val:
1058c2ecf20Sopenharmony_ci		return gpio->base + bank->val_regs + GPIO_VAL_VALUE;
1068c2ecf20Sopenharmony_ci	case reg_rdata:
1078c2ecf20Sopenharmony_ci		return gpio->base + bank->rdata_reg;
1088c2ecf20Sopenharmony_ci	case reg_irq_enable:
1098c2ecf20Sopenharmony_ci		return gpio->base + bank->irq_regs + GPIO_IRQ_ENABLE;
1108c2ecf20Sopenharmony_ci	case reg_irq_type0:
1118c2ecf20Sopenharmony_ci		return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE0;
1128c2ecf20Sopenharmony_ci	case reg_irq_type1:
1138c2ecf20Sopenharmony_ci		return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE1;
1148c2ecf20Sopenharmony_ci	case reg_irq_type2:
1158c2ecf20Sopenharmony_ci		return gpio->base + bank->irq_regs + GPIO_IRQ_TYPE2;
1168c2ecf20Sopenharmony_ci	case reg_irq_status:
1178c2ecf20Sopenharmony_ci		return gpio->base + bank->irq_regs + GPIO_IRQ_STATUS;
1188c2ecf20Sopenharmony_ci	default:
1198c2ecf20Sopenharmony_ci		/* acturally if code runs to here, it's an error case */
1208c2ecf20Sopenharmony_ci		BUG();
1218c2ecf20Sopenharmony_ci	}
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci#define GPIO_BANK(x)    ((x % SGPIO_OUTPUT_OFFSET) >> 5)
1258c2ecf20Sopenharmony_ci#define GPIO_OFFSET(x)  ((x % SGPIO_OUTPUT_OFFSET) & 0x1f)
1268c2ecf20Sopenharmony_ci#define GPIO_BIT(x)     BIT(GPIO_OFFSET(x))
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistatic const struct aspeed_sgpio_bank *to_bank(unsigned int offset)
1298c2ecf20Sopenharmony_ci{
1308c2ecf20Sopenharmony_ci	unsigned int bank;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	bank = GPIO_BANK(offset);
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	WARN_ON(bank >= ARRAY_SIZE(aspeed_sgpio_banks));
1358c2ecf20Sopenharmony_ci	return &aspeed_sgpio_banks[bank];
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_cistatic int aspeed_sgpio_init_valid_mask(struct gpio_chip *gc,
1398c2ecf20Sopenharmony_ci		unsigned long *valid_mask, unsigned int ngpios)
1408c2ecf20Sopenharmony_ci{
1418c2ecf20Sopenharmony_ci	struct aspeed_sgpio *sgpio = gpiochip_get_data(gc);
1428c2ecf20Sopenharmony_ci	int n = sgpio->n_sgpio;
1438c2ecf20Sopenharmony_ci	int c = SGPIO_OUTPUT_OFFSET - n;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	/* input GPIOs in the lower range */
1488c2ecf20Sopenharmony_ci	bitmap_set(valid_mask, 0, n);
1498c2ecf20Sopenharmony_ci	bitmap_clear(valid_mask, n, c);
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	/* output GPIOS above SGPIO_OUTPUT_OFFSET */
1528c2ecf20Sopenharmony_ci	bitmap_set(valid_mask, SGPIO_OUTPUT_OFFSET, n);
1538c2ecf20Sopenharmony_ci	bitmap_clear(valid_mask, SGPIO_OUTPUT_OFFSET + n, c);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	return 0;
1568c2ecf20Sopenharmony_ci}
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic void aspeed_sgpio_irq_init_valid_mask(struct gpio_chip *gc,
1598c2ecf20Sopenharmony_ci		unsigned long *valid_mask, unsigned int ngpios)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	struct aspeed_sgpio *sgpio = gpiochip_get_data(gc);
1628c2ecf20Sopenharmony_ci	int n = sgpio->n_sgpio;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	WARN_ON(ngpios < MAX_NR_HW_SGPIO * 2);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	/* input GPIOs in the lower range */
1678c2ecf20Sopenharmony_ci	bitmap_set(valid_mask, 0, n);
1688c2ecf20Sopenharmony_ci	bitmap_clear(valid_mask, n, ngpios - n);
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_cistatic bool aspeed_sgpio_is_input(unsigned int offset)
1728c2ecf20Sopenharmony_ci{
1738c2ecf20Sopenharmony_ci	return offset < SGPIO_OUTPUT_OFFSET;
1748c2ecf20Sopenharmony_ci}
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_cistatic int aspeed_sgpio_get(struct gpio_chip *gc, unsigned int offset)
1778c2ecf20Sopenharmony_ci{
1788c2ecf20Sopenharmony_ci	struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
1798c2ecf20Sopenharmony_ci	const struct aspeed_sgpio_bank *bank = to_bank(offset);
1808c2ecf20Sopenharmony_ci	unsigned long flags;
1818c2ecf20Sopenharmony_ci	enum aspeed_sgpio_reg reg;
1828c2ecf20Sopenharmony_ci	int rc = 0;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gpio->lock, flags);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	reg = aspeed_sgpio_is_input(offset) ? reg_val : reg_rdata;
1878c2ecf20Sopenharmony_ci	rc = !!(ioread32(bank_reg(gpio, bank, reg)) & GPIO_BIT(offset));
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gpio->lock, flags);
1908c2ecf20Sopenharmony_ci
1918c2ecf20Sopenharmony_ci	return rc;
1928c2ecf20Sopenharmony_ci}
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic int sgpio_set_value(struct gpio_chip *gc, unsigned int offset, int val)
1958c2ecf20Sopenharmony_ci{
1968c2ecf20Sopenharmony_ci	struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
1978c2ecf20Sopenharmony_ci	const struct aspeed_sgpio_bank *bank = to_bank(offset);
1988c2ecf20Sopenharmony_ci	void __iomem *addr_r, *addr_w;
1998c2ecf20Sopenharmony_ci	u32 reg = 0;
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	if (aspeed_sgpio_is_input(offset))
2028c2ecf20Sopenharmony_ci		return -EINVAL;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	/* Since this is an output, read the cached value from rdata, then
2058c2ecf20Sopenharmony_ci	 * update val. */
2068c2ecf20Sopenharmony_ci	addr_r = bank_reg(gpio, bank, reg_rdata);
2078c2ecf20Sopenharmony_ci	addr_w = bank_reg(gpio, bank, reg_val);
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	reg = ioread32(addr_r);
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	if (val)
2128c2ecf20Sopenharmony_ci		reg |= GPIO_BIT(offset);
2138c2ecf20Sopenharmony_ci	else
2148c2ecf20Sopenharmony_ci		reg &= ~GPIO_BIT(offset);
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci	iowrite32(reg, addr_w);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	return 0;
2198c2ecf20Sopenharmony_ci}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_cistatic void aspeed_sgpio_set(struct gpio_chip *gc, unsigned int offset, int val)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
2248c2ecf20Sopenharmony_ci	unsigned long flags;
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gpio->lock, flags);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	sgpio_set_value(gc, offset, val);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gpio->lock, flags);
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistatic int aspeed_sgpio_dir_in(struct gpio_chip *gc, unsigned int offset)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	return aspeed_sgpio_is_input(offset) ? 0 : -EINVAL;
2368c2ecf20Sopenharmony_ci}
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic int aspeed_sgpio_dir_out(struct gpio_chip *gc, unsigned int offset, int val)
2398c2ecf20Sopenharmony_ci{
2408c2ecf20Sopenharmony_ci	struct aspeed_sgpio *gpio = gpiochip_get_data(gc);
2418c2ecf20Sopenharmony_ci	unsigned long flags;
2428c2ecf20Sopenharmony_ci	int rc;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	/* No special action is required for setting the direction; we'll
2458c2ecf20Sopenharmony_ci	 * error-out in sgpio_set_value if this isn't an output GPIO */
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gpio->lock, flags);
2488c2ecf20Sopenharmony_ci	rc = sgpio_set_value(gc, offset, val);
2498c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gpio->lock, flags);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	return rc;
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic int aspeed_sgpio_get_direction(struct gpio_chip *gc, unsigned int offset)
2558c2ecf20Sopenharmony_ci{
2568c2ecf20Sopenharmony_ci	return !!aspeed_sgpio_is_input(offset);
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic void irqd_to_aspeed_sgpio_data(struct irq_data *d,
2608c2ecf20Sopenharmony_ci					struct aspeed_sgpio **gpio,
2618c2ecf20Sopenharmony_ci					const struct aspeed_sgpio_bank **bank,
2628c2ecf20Sopenharmony_ci					u32 *bit, int *offset)
2638c2ecf20Sopenharmony_ci{
2648c2ecf20Sopenharmony_ci	struct aspeed_sgpio *internal;
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci	*offset = irqd_to_hwirq(d);
2678c2ecf20Sopenharmony_ci	internal = irq_data_get_irq_chip_data(d);
2688c2ecf20Sopenharmony_ci	WARN_ON(!internal);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci	*gpio = internal;
2718c2ecf20Sopenharmony_ci	*bank = to_bank(*offset);
2728c2ecf20Sopenharmony_ci	*bit = GPIO_BIT(*offset);
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic void aspeed_sgpio_irq_ack(struct irq_data *d)
2768c2ecf20Sopenharmony_ci{
2778c2ecf20Sopenharmony_ci	const struct aspeed_sgpio_bank *bank;
2788c2ecf20Sopenharmony_ci	struct aspeed_sgpio *gpio;
2798c2ecf20Sopenharmony_ci	unsigned long flags;
2808c2ecf20Sopenharmony_ci	void __iomem *status_addr;
2818c2ecf20Sopenharmony_ci	int offset;
2828c2ecf20Sopenharmony_ci	u32 bit;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	status_addr = bank_reg(gpio, bank, reg_irq_status);
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gpio->lock, flags);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	iowrite32(bit, status_addr);
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gpio->lock, flags);
2938c2ecf20Sopenharmony_ci}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_cistatic void aspeed_sgpio_irq_set_mask(struct irq_data *d, bool set)
2968c2ecf20Sopenharmony_ci{
2978c2ecf20Sopenharmony_ci	const struct aspeed_sgpio_bank *bank;
2988c2ecf20Sopenharmony_ci	struct aspeed_sgpio *gpio;
2998c2ecf20Sopenharmony_ci	unsigned long flags;
3008c2ecf20Sopenharmony_ci	u32 reg, bit;
3018c2ecf20Sopenharmony_ci	void __iomem *addr;
3028c2ecf20Sopenharmony_ci	int offset;
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
3058c2ecf20Sopenharmony_ci	addr = bank_reg(gpio, bank, reg_irq_enable);
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gpio->lock, flags);
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	reg = ioread32(addr);
3108c2ecf20Sopenharmony_ci	if (set)
3118c2ecf20Sopenharmony_ci		reg |= bit;
3128c2ecf20Sopenharmony_ci	else
3138c2ecf20Sopenharmony_ci		reg &= ~bit;
3148c2ecf20Sopenharmony_ci
3158c2ecf20Sopenharmony_ci	iowrite32(reg, addr);
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gpio->lock, flags);
3188c2ecf20Sopenharmony_ci}
3198c2ecf20Sopenharmony_ci
3208c2ecf20Sopenharmony_cistatic void aspeed_sgpio_irq_mask(struct irq_data *d)
3218c2ecf20Sopenharmony_ci{
3228c2ecf20Sopenharmony_ci	aspeed_sgpio_irq_set_mask(d, false);
3238c2ecf20Sopenharmony_ci}
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_cistatic void aspeed_sgpio_irq_unmask(struct irq_data *d)
3268c2ecf20Sopenharmony_ci{
3278c2ecf20Sopenharmony_ci	aspeed_sgpio_irq_set_mask(d, true);
3288c2ecf20Sopenharmony_ci}
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_cistatic int aspeed_sgpio_set_type(struct irq_data *d, unsigned int type)
3318c2ecf20Sopenharmony_ci{
3328c2ecf20Sopenharmony_ci	u32 type0 = 0;
3338c2ecf20Sopenharmony_ci	u32 type1 = 0;
3348c2ecf20Sopenharmony_ci	u32 type2 = 0;
3358c2ecf20Sopenharmony_ci	u32 bit, reg;
3368c2ecf20Sopenharmony_ci	const struct aspeed_sgpio_bank *bank;
3378c2ecf20Sopenharmony_ci	irq_flow_handler_t handler;
3388c2ecf20Sopenharmony_ci	struct aspeed_sgpio *gpio;
3398c2ecf20Sopenharmony_ci	unsigned long flags;
3408c2ecf20Sopenharmony_ci	void __iomem *addr;
3418c2ecf20Sopenharmony_ci	int offset;
3428c2ecf20Sopenharmony_ci
3438c2ecf20Sopenharmony_ci	irqd_to_aspeed_sgpio_data(d, &gpio, &bank, &bit, &offset);
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	switch (type & IRQ_TYPE_SENSE_MASK) {
3468c2ecf20Sopenharmony_ci	case IRQ_TYPE_EDGE_BOTH:
3478c2ecf20Sopenharmony_ci		type2 |= bit;
3488c2ecf20Sopenharmony_ci		fallthrough;
3498c2ecf20Sopenharmony_ci	case IRQ_TYPE_EDGE_RISING:
3508c2ecf20Sopenharmony_ci		type0 |= bit;
3518c2ecf20Sopenharmony_ci		fallthrough;
3528c2ecf20Sopenharmony_ci	case IRQ_TYPE_EDGE_FALLING:
3538c2ecf20Sopenharmony_ci		handler = handle_edge_irq;
3548c2ecf20Sopenharmony_ci		break;
3558c2ecf20Sopenharmony_ci	case IRQ_TYPE_LEVEL_HIGH:
3568c2ecf20Sopenharmony_ci		type0 |= bit;
3578c2ecf20Sopenharmony_ci		fallthrough;
3588c2ecf20Sopenharmony_ci	case IRQ_TYPE_LEVEL_LOW:
3598c2ecf20Sopenharmony_ci		type1 |= bit;
3608c2ecf20Sopenharmony_ci		handler = handle_level_irq;
3618c2ecf20Sopenharmony_ci		break;
3628c2ecf20Sopenharmony_ci	default:
3638c2ecf20Sopenharmony_ci		return -EINVAL;
3648c2ecf20Sopenharmony_ci	}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	spin_lock_irqsave(&gpio->lock, flags);
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci	addr = bank_reg(gpio, bank, reg_irq_type0);
3698c2ecf20Sopenharmony_ci	reg = ioread32(addr);
3708c2ecf20Sopenharmony_ci	reg = (reg & ~bit) | type0;
3718c2ecf20Sopenharmony_ci	iowrite32(reg, addr);
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	addr = bank_reg(gpio, bank, reg_irq_type1);
3748c2ecf20Sopenharmony_ci	reg = ioread32(addr);
3758c2ecf20Sopenharmony_ci	reg = (reg & ~bit) | type1;
3768c2ecf20Sopenharmony_ci	iowrite32(reg, addr);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_ci	addr = bank_reg(gpio, bank, reg_irq_type2);
3798c2ecf20Sopenharmony_ci	reg = ioread32(addr);
3808c2ecf20Sopenharmony_ci	reg = (reg & ~bit) | type2;
3818c2ecf20Sopenharmony_ci	iowrite32(reg, addr);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&gpio->lock, flags);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	irq_set_handler_locked(d, handler);
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_ci	return 0;
3888c2ecf20Sopenharmony_ci}
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cistatic void aspeed_sgpio_irq_handler(struct irq_desc *desc)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	struct gpio_chip *gc = irq_desc_get_handler_data(desc);
3938c2ecf20Sopenharmony_ci	struct irq_chip *ic = irq_desc_get_chip(desc);
3948c2ecf20Sopenharmony_ci	struct aspeed_sgpio *data = gpiochip_get_data(gc);
3958c2ecf20Sopenharmony_ci	unsigned int i, p, girq;
3968c2ecf20Sopenharmony_ci	unsigned long reg;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	chained_irq_enter(ic, desc);
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
4018c2ecf20Sopenharmony_ci		const struct aspeed_sgpio_bank *bank = &aspeed_sgpio_banks[i];
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci		reg = ioread32(bank_reg(data, bank, reg_irq_status));
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci		for_each_set_bit(p, &reg, 32) {
4068c2ecf20Sopenharmony_ci			girq = irq_find_mapping(gc->irq.domain, i * 32 + p);
4078c2ecf20Sopenharmony_ci			generic_handle_irq(girq);
4088c2ecf20Sopenharmony_ci		}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	}
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	chained_irq_exit(ic, desc);
4138c2ecf20Sopenharmony_ci}
4148c2ecf20Sopenharmony_ci
4158c2ecf20Sopenharmony_cistatic struct irq_chip aspeed_sgpio_irqchip = {
4168c2ecf20Sopenharmony_ci	.name       = "aspeed-sgpio",
4178c2ecf20Sopenharmony_ci	.irq_ack    = aspeed_sgpio_irq_ack,
4188c2ecf20Sopenharmony_ci	.irq_mask   = aspeed_sgpio_irq_mask,
4198c2ecf20Sopenharmony_ci	.irq_unmask = aspeed_sgpio_irq_unmask,
4208c2ecf20Sopenharmony_ci	.irq_set_type   = aspeed_sgpio_set_type,
4218c2ecf20Sopenharmony_ci};
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_cistatic int aspeed_sgpio_setup_irqs(struct aspeed_sgpio *gpio,
4248c2ecf20Sopenharmony_ci				   struct platform_device *pdev)
4258c2ecf20Sopenharmony_ci{
4268c2ecf20Sopenharmony_ci	int rc, i;
4278c2ecf20Sopenharmony_ci	const struct aspeed_sgpio_bank *bank;
4288c2ecf20Sopenharmony_ci	struct gpio_irq_chip *irq;
4298c2ecf20Sopenharmony_ci
4308c2ecf20Sopenharmony_ci	rc = platform_get_irq(pdev, 0);
4318c2ecf20Sopenharmony_ci	if (rc < 0)
4328c2ecf20Sopenharmony_ci		return rc;
4338c2ecf20Sopenharmony_ci
4348c2ecf20Sopenharmony_ci	gpio->irq = rc;
4358c2ecf20Sopenharmony_ci
4368c2ecf20Sopenharmony_ci	/* Disable IRQ and clear Interrupt status registers for all SGPIO Pins. */
4378c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
4388c2ecf20Sopenharmony_ci		bank =  &aspeed_sgpio_banks[i];
4398c2ecf20Sopenharmony_ci		/* disable irq enable bits */
4408c2ecf20Sopenharmony_ci		iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_enable));
4418c2ecf20Sopenharmony_ci		/* clear status bits */
4428c2ecf20Sopenharmony_ci		iowrite32(0xffffffff, bank_reg(gpio, bank, reg_irq_status));
4438c2ecf20Sopenharmony_ci	}
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci	irq = &gpio->chip.irq;
4468c2ecf20Sopenharmony_ci	irq->chip = &aspeed_sgpio_irqchip;
4478c2ecf20Sopenharmony_ci	irq->init_valid_mask = aspeed_sgpio_irq_init_valid_mask;
4488c2ecf20Sopenharmony_ci	irq->handler = handle_bad_irq;
4498c2ecf20Sopenharmony_ci	irq->default_type = IRQ_TYPE_NONE;
4508c2ecf20Sopenharmony_ci	irq->parent_handler = aspeed_sgpio_irq_handler;
4518c2ecf20Sopenharmony_ci	irq->parent_handler_data = gpio;
4528c2ecf20Sopenharmony_ci	irq->parents = &gpio->irq;
4538c2ecf20Sopenharmony_ci	irq->num_parents = 1;
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	/* Apply default IRQ settings */
4568c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(aspeed_sgpio_banks); i++) {
4578c2ecf20Sopenharmony_ci		bank = &aspeed_sgpio_banks[i];
4588c2ecf20Sopenharmony_ci		/* set falling or level-low irq */
4598c2ecf20Sopenharmony_ci		iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type0));
4608c2ecf20Sopenharmony_ci		/* trigger type is edge */
4618c2ecf20Sopenharmony_ci		iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type1));
4628c2ecf20Sopenharmony_ci		/* single edge trigger */
4638c2ecf20Sopenharmony_ci		iowrite32(0x00000000, bank_reg(gpio, bank, reg_irq_type2));
4648c2ecf20Sopenharmony_ci	}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	return 0;
4678c2ecf20Sopenharmony_ci}
4688c2ecf20Sopenharmony_ci
4698c2ecf20Sopenharmony_cistatic const struct of_device_id aspeed_sgpio_of_table[] = {
4708c2ecf20Sopenharmony_ci	{ .compatible = "aspeed,ast2400-sgpio" },
4718c2ecf20Sopenharmony_ci	{ .compatible = "aspeed,ast2500-sgpio" },
4728c2ecf20Sopenharmony_ci	{}
4738c2ecf20Sopenharmony_ci};
4748c2ecf20Sopenharmony_ci
4758c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, aspeed_sgpio_of_table);
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_cistatic int __init aspeed_sgpio_probe(struct platform_device *pdev)
4788c2ecf20Sopenharmony_ci{
4798c2ecf20Sopenharmony_ci	struct aspeed_sgpio *gpio;
4808c2ecf20Sopenharmony_ci	u32 nr_gpios, sgpio_freq, sgpio_clk_div;
4818c2ecf20Sopenharmony_ci	int rc;
4828c2ecf20Sopenharmony_ci	unsigned long apb_freq;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
4858c2ecf20Sopenharmony_ci	if (!gpio)
4868c2ecf20Sopenharmony_ci		return -ENOMEM;
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_ci	gpio->base = devm_platform_ioremap_resource(pdev, 0);
4898c2ecf20Sopenharmony_ci	if (IS_ERR(gpio->base))
4908c2ecf20Sopenharmony_ci		return PTR_ERR(gpio->base);
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci	rc = of_property_read_u32(pdev->dev.of_node, "ngpios", &nr_gpios);
4938c2ecf20Sopenharmony_ci	if (rc < 0) {
4948c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Could not read ngpios property\n");
4958c2ecf20Sopenharmony_ci		return -EINVAL;
4968c2ecf20Sopenharmony_ci	} else if (nr_gpios > MAX_NR_HW_SGPIO) {
4978c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Number of GPIOs exceeds the maximum of %d: %d\n",
4988c2ecf20Sopenharmony_ci			MAX_NR_HW_SGPIO, nr_gpios);
4998c2ecf20Sopenharmony_ci		return -EINVAL;
5008c2ecf20Sopenharmony_ci	}
5018c2ecf20Sopenharmony_ci	gpio->n_sgpio = nr_gpios;
5028c2ecf20Sopenharmony_ci
5038c2ecf20Sopenharmony_ci	rc = of_property_read_u32(pdev->dev.of_node, "bus-frequency", &sgpio_freq);
5048c2ecf20Sopenharmony_ci	if (rc < 0) {
5058c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "Could not read bus-frequency property\n");
5068c2ecf20Sopenharmony_ci		return -EINVAL;
5078c2ecf20Sopenharmony_ci	}
5088c2ecf20Sopenharmony_ci
5098c2ecf20Sopenharmony_ci	gpio->pclk = devm_clk_get(&pdev->dev, NULL);
5108c2ecf20Sopenharmony_ci	if (IS_ERR(gpio->pclk)) {
5118c2ecf20Sopenharmony_ci		dev_err(&pdev->dev, "devm_clk_get failed\n");
5128c2ecf20Sopenharmony_ci		return PTR_ERR(gpio->pclk);
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	apb_freq = clk_get_rate(gpio->pclk);
5168c2ecf20Sopenharmony_ci
5178c2ecf20Sopenharmony_ci	/*
5188c2ecf20Sopenharmony_ci	 * From the datasheet,
5198c2ecf20Sopenharmony_ci	 *	SGPIO period = 1/PCLK * 2 * (GPIO254[31:16] + 1)
5208c2ecf20Sopenharmony_ci	 *	period = 2 * (GPIO254[31:16] + 1) / PCLK
5218c2ecf20Sopenharmony_ci	 *	frequency = 1 / (2 * (GPIO254[31:16] + 1) / PCLK)
5228c2ecf20Sopenharmony_ci	 *	frequency = PCLK / (2 * (GPIO254[31:16] + 1))
5238c2ecf20Sopenharmony_ci	 *	frequency * 2 * (GPIO254[31:16] + 1) = PCLK
5248c2ecf20Sopenharmony_ci	 *	GPIO254[31:16] = PCLK / (frequency * 2) - 1
5258c2ecf20Sopenharmony_ci	 */
5268c2ecf20Sopenharmony_ci	if (sgpio_freq == 0)
5278c2ecf20Sopenharmony_ci		return -EINVAL;
5288c2ecf20Sopenharmony_ci
5298c2ecf20Sopenharmony_ci	sgpio_clk_div = (apb_freq / (sgpio_freq * 2)) - 1;
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	if (sgpio_clk_div > (1 << 16) - 1)
5328c2ecf20Sopenharmony_ci		return -EINVAL;
5338c2ecf20Sopenharmony_ci
5348c2ecf20Sopenharmony_ci	iowrite32(FIELD_PREP(ASPEED_SGPIO_CLK_DIV_MASK, sgpio_clk_div) |
5358c2ecf20Sopenharmony_ci		  FIELD_PREP(ASPEED_SGPIO_PINS_MASK, (nr_gpios / 8)) |
5368c2ecf20Sopenharmony_ci		  ASPEED_SGPIO_ENABLE,
5378c2ecf20Sopenharmony_ci		  gpio->base + ASPEED_SGPIO_CTRL);
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_ci	spin_lock_init(&gpio->lock);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	gpio->chip.parent = &pdev->dev;
5428c2ecf20Sopenharmony_ci	gpio->chip.ngpio = MAX_NR_HW_SGPIO * 2;
5438c2ecf20Sopenharmony_ci	gpio->chip.init_valid_mask = aspeed_sgpio_init_valid_mask;
5448c2ecf20Sopenharmony_ci	gpio->chip.direction_input = aspeed_sgpio_dir_in;
5458c2ecf20Sopenharmony_ci	gpio->chip.direction_output = aspeed_sgpio_dir_out;
5468c2ecf20Sopenharmony_ci	gpio->chip.get_direction = aspeed_sgpio_get_direction;
5478c2ecf20Sopenharmony_ci	gpio->chip.request = NULL;
5488c2ecf20Sopenharmony_ci	gpio->chip.free = NULL;
5498c2ecf20Sopenharmony_ci	gpio->chip.get = aspeed_sgpio_get;
5508c2ecf20Sopenharmony_ci	gpio->chip.set = aspeed_sgpio_set;
5518c2ecf20Sopenharmony_ci	gpio->chip.set_config = NULL;
5528c2ecf20Sopenharmony_ci	gpio->chip.label = dev_name(&pdev->dev);
5538c2ecf20Sopenharmony_ci	gpio->chip.base = -1;
5548c2ecf20Sopenharmony_ci
5558c2ecf20Sopenharmony_ci	aspeed_sgpio_setup_irqs(gpio, pdev);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	rc = devm_gpiochip_add_data(&pdev->dev, &gpio->chip, gpio);
5588c2ecf20Sopenharmony_ci	if (rc < 0)
5598c2ecf20Sopenharmony_ci		return rc;
5608c2ecf20Sopenharmony_ci
5618c2ecf20Sopenharmony_ci	return 0;
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_cistatic struct platform_driver aspeed_sgpio_driver = {
5658c2ecf20Sopenharmony_ci	.driver = {
5668c2ecf20Sopenharmony_ci		.name = KBUILD_MODNAME,
5678c2ecf20Sopenharmony_ci		.of_match_table = aspeed_sgpio_of_table,
5688c2ecf20Sopenharmony_ci	},
5698c2ecf20Sopenharmony_ci};
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_cimodule_platform_driver_probe(aspeed_sgpio_driver, aspeed_sgpio_probe);
5728c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Aspeed Serial GPIO Driver");
5738c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
574