blob: 0ce00572e082003a250ba69a30bde963c654bb2c [file] [log] [blame]
Greg Malysa4dc391e2025-02-26 12:30:25 -05001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * (C) Copyright 2022 - Analog Devices, Inc.
4 *
5 * Written and/or maintained by Timesys Corporation
6 *
7 * Author: Greg Malysa <greg.malysa@timesys.com>
8 * Additional Contact: Nathan Barrett-Morrison <nathan.morrison@timesys.com>
9 */
10
11#include <dm.h>
12#include <asm-generic/gpio.h>
13#include <dm/device_compat.h>
14#include <linux/bitops.h>
15#include <linux/io.h>
16
17#define ADSP_PORT_MMIO_SIZE 0x80
18#define ADSP_PORT_PIN_SIZE 16
19
20#define ADSP_PORT_REG_FER 0x00
21#define ADSP_PORT_REG_FER_SET 0x04
22#define ADSP_PORT_REG_FER_CLEAR 0x08
23#define ADSP_PORT_REG_DATA 0x0c
24#define ADSP_PORT_REG_DATA_SET 0x10
25#define ADSP_PORT_REG_DATA_CLEAR 0x14
26#define ADSP_PORT_REG_DIR 0x18
27#define ADSP_PORT_REG_DIR_SET 0x1c
28#define ADSP_PORT_REG_DIR_CLEAR 0x20
29#define ADSP_PORT_REG_INEN 0x24
30#define ADSP_PORT_REG_INEN_SET 0x28
31#define ADSP_PORT_REG_INEN_CLEAR 0x2c
32#define ADSP_PORT_REG_PORT_MUX 0x30
33#define ADSP_PORT_REG_DATA_TGL 0x34
34#define ADSP_PORT_REG_POLAR 0x38
35#define ADSP_PORT_REG_POLAR_SET 0x3c
36#define ADSP_PORT_REG_POLAR_CLEAR 0x40
37#define ADSP_PORT_REG_LOCK 0x44
38#define ADSP_PORT_REG_TRIG_TGL 0x48
39
40struct adsp_gpio_priv {
41 void __iomem *base;
42 int ngpio;
43};
44
45static u32 get_port(unsigned int pin)
46{
47 return pin / ADSP_PORT_PIN_SIZE;
48}
49
50static u32 get_offset(unsigned int pin)
51{
52 return pin % ADSP_PORT_PIN_SIZE;
53}
54
55static int adsp_gpio_input(struct udevice *udev, unsigned int pin)
56{
57 struct adsp_gpio_priv *priv = dev_get_priv(udev);
58 u32 port, offset;
59 void __iomem *portbase;
60
61 if (pin < priv->ngpio) {
62 port = get_port(pin);
63 offset = get_offset(pin);
64 portbase = priv->base + port * ADSP_PORT_MMIO_SIZE;
65
66 iowrite16(BIT(offset), portbase + ADSP_PORT_REG_FER_CLEAR);
67 iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DIR_CLEAR);
68 iowrite16(BIT(offset), portbase + ADSP_PORT_REG_INEN_SET);
69 return 0;
70 }
71
72 return -EINVAL;
73}
74
75static int adsp_gpio_output(struct udevice *udev, unsigned int pin, int value)
76{
77 struct adsp_gpio_priv *priv = dev_get_priv(udev);
78 u32 port, offset;
79 void __iomem *portbase;
80
81 if (pin < priv->ngpio) {
82 port = get_port(pin);
83 offset = get_offset(pin);
84 portbase = priv->base + port * ADSP_PORT_MMIO_SIZE;
85
86 iowrite16(BIT(offset), portbase + ADSP_PORT_REG_FER_CLEAR);
87
88 if (value)
89 iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DATA_SET);
90 else
91 iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DATA_CLEAR);
92
93 iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DIR_SET);
94 iowrite16(BIT(offset), portbase + ADSP_PORT_REG_INEN_CLEAR);
95 return 0;
96 }
97
98 return -EINVAL;
99}
100
101static int adsp_gpio_get_value(struct udevice *udev, unsigned int pin)
102{
103 struct adsp_gpio_priv *priv = dev_get_priv(udev);
104 u32 port, offset;
105 u16 val;
106 void __iomem *portbase;
107
108 if (pin < priv->ngpio) {
109 port = get_port(pin);
110 offset = get_offset(pin);
111 portbase = priv->base + port * ADSP_PORT_MMIO_SIZE;
112
113 val = ioread16(portbase + ADSP_PORT_REG_DATA);
114 return !!(val & BIT(offset));
115 }
116
117 return 0;
118}
119
120static int adsp_gpio_set_value(struct udevice *udev, unsigned int pin, int value)
121{
122 struct adsp_gpio_priv *priv = dev_get_priv(udev);
123 u32 port, offset;
124 void __iomem *portbase;
125
126 if (pin < priv->ngpio) {
127 port = get_port(pin);
128 offset = get_offset(pin);
129 portbase = priv->base + port * ADSP_PORT_MMIO_SIZE;
130
131 if (value)
132 iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DATA_SET);
133 else
134 iowrite16(BIT(offset), portbase + ADSP_PORT_REG_DATA_CLEAR);
135 }
136
137 return 0;
138}
139
140static const struct dm_gpio_ops adsp_gpio_ops = {
141 .direction_input = adsp_gpio_input,
142 .direction_output = adsp_gpio_output,
143 .get_value = adsp_gpio_get_value,
144 .set_value = adsp_gpio_set_value,
145};
146
147static int adsp_gpio_probe(struct udevice *udev)
148{
149 struct adsp_gpio_priv *priv = dev_get_priv(udev);
150 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(udev);
151
152 uc_priv->bank_name = "adsp gpio";
153 uc_priv->gpio_count = dev_read_u32_default(udev, "adi,ngpios", 0);
154
155 if (!uc_priv->gpio_count) {
156 dev_err(udev, "Missing adi,ngpios property!\n");
157 return -ENOENT;
158 }
159
160 priv->base = dev_read_addr_ptr(udev);
161 priv->ngpio = uc_priv->gpio_count;
162
163 return 0;
164}
165
166static const struct udevice_id adsp_gpio_match[] = {
167 { .compatible = "adi,adsp-gpio" },
168 { },
169};
170
171U_BOOT_DRIVER(adi_adsp_gpio) = {
172 .name = "adi_adsp_gpio",
173 .id = UCLASS_GPIO,
174 .ops = &adsp_gpio_ops,
175 .probe = adsp_gpio_probe,
176 .priv_auto = sizeof(struct adsp_gpio_priv),
177 .of_match = adsp_gpio_match,
178 .flags = DM_FLAG_PRE_RELOC,
179};