blob: debf434212da5c7bd660080e4068ade7333cfe4a [file] [log] [blame]
Greg Malysad7e90d62025-02-26 12:30:23 -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 * dm pinctrl implementation for ADI ADSP SoCs
11 *
12 */
13
14#include <dm.h>
15#include <dm/pinctrl.h>
16#include <dm/device_compat.h>
17#include <linux/bitops.h>
18#include <linux/io.h>
19
20#define ADSP_PORT_MMIO_SIZE 0x80
21#define ADSP_PORT_PIN_SIZE 16
22
23#define ADSP_PORT_PORT_MUX_BITS 2
24#define ADSP_PORT_PORT_MUX_MASK 0x03
25#define ADSP_PINCTRL_FUNCTION_COUNT 4
26
27#define ADSP_PORT_REG_FER 0x00
28#define ADSP_PORT_REG_FER_SET 0x04
29#define ADSP_PORT_REG_FER_CLEAR 0x08
30#define ADSP_PORT_REG_DATA 0x0c
31#define ADSP_PORT_REG_DATA_SET 0x10
32#define ADSP_PORT_REG_DATA_CLEAR 0x14
33#define ADSP_PORT_REG_DIR 0x18
34#define ADSP_PORT_REG_DIR_SET 0x1c
35#define ADSP_PORT_REG_DIR_CLEAR 0x20
36#define ADSP_PORT_REG_INEN 0x24
37#define ADSP_PORT_REG_INEN_SET 0x28
38#define ADSP_PORT_REG_INEN_CLEAR 0x2c
39#define ADSP_PORT_REG_PORT_MUX 0x30
40#define ADSP_PORT_REG_DATA_TGL 0x34
41#define ADSP_PORT_REG_POLAR 0x38
42#define ADSP_PORT_REG_POLAR_SET 0x3c
43#define ADSP_PORT_REG_POLAR_CLEAR 0x40
44#define ADSP_PORT_REG_LOCK 0x44
45#define ADSP_PORT_REG_TRIG_TGL 0x48
46
47struct adsp_pinctrl_priv {
48 void __iomem *base;
49 int npins;
50 char pinbuf[16];
51};
52
53static u32 get_port(unsigned int pin)
54{
55 return pin / ADSP_PORT_PIN_SIZE;
56}
57
58static u32 get_offset(unsigned int pin)
59{
60 return pin % ADSP_PORT_PIN_SIZE;
61}
62
63static int adsp_pinctrl_pinmux_set(struct udevice *udev, unsigned int pin, unsigned int func)
64{
65 struct adsp_pinctrl_priv *priv = dev_get_priv(udev);
66 void __iomem *portbase;
67 u32 port, offset;
68 u32 val;
69
70 if (pin >= priv->npins)
71 return -ENODEV;
72
73 if (func >= ADSP_PINCTRL_FUNCTION_COUNT)
74 return -EINVAL;
75
76 port = get_port(pin);
77 offset = get_offset(pin);
78 portbase = priv->base + port * ADSP_PORT_MMIO_SIZE;
79
80 val = ioread32(portbase + ADSP_PORT_REG_PORT_MUX);
81 val &= ~(ADSP_PORT_PORT_MUX_MASK << (ADSP_PORT_PORT_MUX_BITS * offset));
82 val |= func << (ADSP_PORT_PORT_MUX_BITS * offset);
83 iowrite32(val, portbase + ADSP_PORT_REG_PORT_MUX);
84
85 iowrite32(BIT(offset), portbase + ADSP_PORT_REG_FER_SET);
86 return 0;
87}
88
89static int adsp_pinctrl_set_state(struct udevice *udev, struct udevice *config)
90{
91 const struct fdt_property *pinlist;
92 int length = 0;
93 int ret, i;
94 u32 pin, function;
95
96 pinlist = dev_read_prop(config, "adi,pins", &length);
97 if (!pinlist) {
98 dev_err(udev, "missing adi,pins property in pinctrl config node\n");
99 return -EINVAL;
100 }
101
102 if (length % (sizeof(uint32_t) * 2)) {
103 dev_err(udev, "adi,pins property must be a multiple of two uint32_ts\n");
104 return -EINVAL;
105 }
106
107 for (i = 0; i < length / sizeof(uint32_t); i += 2) {
108 ret = dev_read_u32_index(config, "adi,pins", i, &pin);
109 if (ret)
110 return ret;
111
112 ret = dev_read_u32_index(config, "adi,pins", i + 1, &function);
113 if (ret)
114 return ret;
115
116 ret = adsp_pinctrl_pinmux_set(udev, pin, function);
117 if (ret)
118 return ret;
119 }
120
121 return 0;
122}
123
124const struct pinctrl_ops adsp_pinctrl_ops = {
125 .set_state = adsp_pinctrl_set_state,
126};
127
128static int adsp_pinctrl_probe(struct udevice *udev)
129{
130 struct adsp_pinctrl_priv *priv = dev_get_priv(udev);
131
132 priv->base = dev_read_addr_ptr(udev);
133 priv->npins = dev_read_u32_default(udev, "adi,npins", 0);
134
135 if (!priv->base) {
136 dev_err(udev, "Missing or invalid pinctrl base address\n");
137 return -ENOENT;
138 }
139
140 if (!priv->npins) {
141 dev_err(udev, "Missing adi,npins property!\n");
142 return -ENOENT;
143 }
144
145 return 0;
146}
147
148static const struct udevice_id adsp_pinctrl_match[] = {
149 { .compatible = "adi,adsp-pinctrl" },
150 { },
151};
152
153U_BOOT_DRIVER(adi_adsp_pinctrl) = {
154 .name = "adi_adsp_pinctrl",
155 .id = UCLASS_PINCTRL,
156 .of_match = adsp_pinctrl_match,
157 .probe = adsp_pinctrl_probe,
158 .priv_auto = sizeof(struct adsp_pinctrl_priv),
159 .ops = &adsp_pinctrl_ops,
160 .flags = DM_FLAG_PRE_RELOC,
161};