1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2025 - 2026, Advanced Micro Devices, Inc.
*
* Michal Simek <michal.simek@amd.com>
*/
#include <dm.h>
#include <dm/device_compat.h>
#include <dm/devres.h>
#include <asm/gpio.h>
#include <linux/delay.h>
struct gpio_delay_desc {
struct gpio_desc real_gpio;
u32 ramp_up_us;
u32 ramp_down_us;
};
struct gpio_delay_priv {
struct gpio_delay_desc *descs;
};
static int gpio_delay_direction_input(struct udevice *dev, unsigned int offset)
{
return -ENOSYS;
}
static int gpio_delay_get_value(struct udevice *dev, unsigned int offset)
{
return -ENOSYS;
}
static int gpio_delay_set_value(struct udevice *dev, unsigned int offset,
int value)
{
struct gpio_delay_priv *priv = dev_get_priv(dev);
struct gpio_delay_desc *desc = &priv->descs[offset];
u32 wait;
int ret;
dev_dbg(dev, "gpio %d set to %d\n", offset, value);
ret = dm_gpio_set_value(&desc->real_gpio, value);
if (ret) {
dev_err(dev, "Failed to set gpio %d, value %d\n", offset, value);
return ret;
}
if (value)
wait = desc->ramp_up_us;
else
wait = desc->ramp_down_us;
udelay(wait);
dev_dbg(dev, "waited for %d us\n", wait);
return 0;
}
static int gpio_delay_direction_output(struct udevice *dev, unsigned int offset,
int value)
{
return gpio_delay_set_value(dev, offset, value);
}
static int gpio_delay_xlate(struct udevice *dev, struct gpio_desc *desc,
struct ofnode_phandle_args *args)
{
struct gpio_delay_priv *priv = dev_get_priv(dev);
if (args->args_count < 3)
return -EINVAL;
if (args->args[0] >= 32)
return -EINVAL;
struct gpio_delay_desc *d = &priv->descs[args->args[0]];
d->ramp_up_us = args->args[1];
d->ramp_down_us = args->args[2];
dev_dbg(dev, "pin: %d, ramp_up_us: %d, ramp_down_us: %d\n",
args->args[0], d->ramp_up_us, d->ramp_down_us);
return 0;
}
static const struct dm_gpio_ops gpio_delay_ops = {
.direction_output = gpio_delay_direction_output,
.direction_input = gpio_delay_direction_input,
.get_value = gpio_delay_get_value,
.set_value = gpio_delay_set_value,
.xlate = gpio_delay_xlate,
};
static int gpio_delay_probe(struct udevice *dev)
{
struct gpio_delay_priv *priv = dev_get_priv(dev);
struct gpio_delay_desc *d;
ofnode node = dev_ofnode(dev);
int i = 0, ret, ngpio;
ngpio = gpio_get_list_count(dev, "gpios");
if (ngpio < 0)
return ngpio;
dev_dbg(dev, "gpios: %d\n", ngpio);
priv->descs = devm_kmalloc_array(dev, ngpio, sizeof(*d), GFP_KERNEL);
if (!priv->descs)
return -ENOMEM;
/* Request all GPIOs described in the controller node */
for (i = 0; i < ngpio; i++) {
d = &priv->descs[i];
ret = gpio_request_by_name_nodev(node, "gpios", i,
&d->real_gpio, 0);
if (ret)
return ret;
}
return 0;
}
static const struct udevice_id gpio_delay_ids[] = {
{ .compatible = "gpio-delay" },
{ }
};
U_BOOT_DRIVER(gpio_delay) = {
.name = "gpio-delay",
.id = UCLASS_GPIO,
.of_match = gpio_delay_ids,
.ops = &gpio_delay_ops,
.priv_auto = sizeof(struct gpio_delay_priv),
.probe = gpio_delay_probe,
};
|