blob: 4c6ab86203c253a6e6302f5cbca6a5925db5b7f8 [file] [log] [blame]
Billy Tsaief123392024-08-20 15:27:36 +08001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (C) ASPEED Technology Inc.
4 * Billy Tsai <billy_tsai@aspeedtech.com>
5 */
6#include <asm/io.h>
7#include <asm/gpio.h>
8
9#include <config.h>
10#include <clk.h>
11#include <dm.h>
12#include <asm/io.h>
13#include <linux/bug.h>
14#include <linux/sizes.h>
15
16struct aspeed_gpio_priv {
17 void *regs;
18};
19
20#define GPIO_G7_IRQ_STS_BASE 0x100
21#define GPIO_G7_IRQ_STS_OFFSET(x) (GPIO_G7_IRQ_STS_BASE + (x) * 0x4)
22#define GPIO_G7_CTRL_REG_BASE 0x180
23#define GPIO_G7_CTRL_REG_OFFSET(x) (GPIO_G7_CTRL_REG_BASE + (x) * 0x4)
24#define GPIO_G7_OUT_DATA BIT(0)
25#define GPIO_G7_DIR BIT(1)
26#define GPIO_G7_IRQ_EN BIT(2)
27#define GPIO_G7_IRQ_TYPE0 BIT(3)
28#define GPIO_G7_IRQ_TYPE1 BIT(4)
29#define GPIO_G7_IRQ_TYPE2 BIT(5)
30#define GPIO_G7_RST_TOLERANCE BIT(6)
31#define GPIO_G7_DEBOUNCE_SEL GENMASK(8, 7)
32#define GPIO_G7_INPUT_MASK BIT(9)
33#define GPIO_G7_IRQ_STS BIT(12)
34#define GPIO_G7_IN_DATA BIT(13)
35/*
36 * The configuration of the following registers should be determined
37 * outside of the GPIO driver.
38 */
39#define GPIO_G7_PRIVILEGE_W_REG_BASE 0x810
40#define GPIO_G7_PRIVILEGE_W_REG_OFFSET(x) (GPIO_G7_PRIVILEGE_W_REG_BASE + ((x) >> 2) * 0x4)
41#define GPIO_G7_PRIVILEGE_R_REG_BASE 0x910
42#define GPIO_G7_PRIVILEGE_R_REG_OFFSET(x) (GPIO_G7_PRIVILEGE_R_REG_BASE + ((x) >> 2) * 0x4)
43#define GPIO_G7_IRQ_TARGET_REG_BASE 0xA10
44#define GPIO_G7_IRQ_TARGET_REG_OFFSET(x) (GPIO_G7_IRQ_TARGET_REG_BASE + ((x) >> 2) * 0x4)
45#define GPIO_G7_IRQ_TO_INTC2_18 BIT(0)
46#define GPIO_G7_IRQ_TO_INTC2_19 BIT(1)
47#define GPIO_G7_IRQ_TO_INTC2_20 BIT(2)
48#define GPIO_G7_IRQ_TO_SIO BIT(3)
49#define GPIO_G7_IRQ_TARGET_RESET_TOLERANCE BIT(6)
50#define GPIO_G7_IRQ_TARGET_W_PROTECT BIT(7)
51
52static int
53aspeed_gpio_direction_input(struct udevice *dev, unsigned int offset)
54{
55 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
56 void __iomem *addr = priv->regs + GPIO_G7_CTRL_REG_OFFSET(offset);
57 u32 dir = readl(addr);
58
59 dir &= ~GPIO_G7_DIR;
60 writel(dir, addr);
61
62 return 0;
63}
64
65static int aspeed_gpio_direction_output(struct udevice *dev, unsigned int offset,
66 int value)
67{
68 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
69 void __iomem *addr = priv->regs + GPIO_G7_CTRL_REG_OFFSET(offset);
70 u32 data = readl(addr);
71
72 if (value)
73 data |= GPIO_G7_OUT_DATA;
74 else
75 data &= ~GPIO_G7_OUT_DATA;
76 writel(data, addr);
77 data |= GPIO_G7_DIR;
78 writel(data, addr);
79
80 return 0;
81}
82
83static int aspeed_gpio_get_value(struct udevice *dev, unsigned int offset)
84{
85 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
86 void __iomem *addr = priv->regs + GPIO_G7_CTRL_REG_OFFSET(offset);
87
88 return !!(readl(addr) & GPIO_G7_IN_DATA);
89}
90
91static int
92aspeed_gpio_set_value(struct udevice *dev, unsigned int offset, int value)
93{
94 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
95 void __iomem *addr = priv->regs + GPIO_G7_CTRL_REG_OFFSET(offset);
96 u32 data = readl(addr);
97
98 if (value)
99 data |= GPIO_G7_OUT_DATA;
100 else
101 data &= ~GPIO_G7_OUT_DATA;
102
103 writel(data, addr);
104
105 return 0;
106}
107
108static int aspeed_gpio_get_function(struct udevice *dev, unsigned int offset)
109{
110 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
111 void __iomem *addr = priv->regs + GPIO_G7_CTRL_REG_OFFSET(offset);
112
113 if (readl(addr) & GPIO_G7_DIR)
114 return GPIOF_OUTPUT;
115
116 return GPIOF_INPUT;
117}
118
119static const struct dm_gpio_ops aspeed_gpio_ops = {
120 .direction_input = aspeed_gpio_direction_input,
121 .direction_output = aspeed_gpio_direction_output,
122 .get_value = aspeed_gpio_get_value,
123 .set_value = aspeed_gpio_set_value,
124 .get_function = aspeed_gpio_get_function,
125};
126
127static int aspeed_gpio_probe(struct udevice *dev)
128{
129 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev);
130 struct aspeed_gpio_priv *priv = dev_get_priv(dev);
131
132 uc_priv->bank_name = dev->name;
133 ofnode_read_u32(dev_ofnode(dev), "ngpios", &uc_priv->gpio_count);
134 priv->regs = devfdt_get_addr_ptr(dev);
135
136 return 0;
137}
138
139static const struct udevice_id aspeed_gpio_ids[] = {
140 { .compatible = "aspeed,ast2700-gpio", },
141 { }
142};
143
144U_BOOT_DRIVER(gpio_aspeed) = {
145 .name = "gpio-aspeed",
146 .id = UCLASS_GPIO,
147 .of_match = aspeed_gpio_ids,
148 .ops = &aspeed_gpio_ops,
149 .probe = aspeed_gpio_probe,
150 .priv_auto = sizeof(struct aspeed_gpio_priv),
151};