1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (C) 2020-2021, Linaro Limited
4 */
5
6 #define LOG_CATEGORY UCLASS_MISC
7
8 #include <common.h>
9 #include <clk.h>
10 #include <dm.h>
11 #include <log.h>
12 #include <malloc.h>
13 #include <reset.h>
14 #include <asm/io.h>
15 #include <asm/scmi_test.h>
16 #include <dm/device_compat.h>
17 #include <power/regulator.h>
18
19 /*
20 * Simulate to some extent a SCMI exchange.
21 * This drivers gets SCMI resources and offers API function to the
22 * SCMI test sequence manipulate the resources, currently clock
23 * and reset controllers.
24 */
25
26 #define SCMI_TEST_DEVICES_CLK_COUNT 3
27 #define SCMI_TEST_DEVICES_RD_COUNT 1
28 #define SCMI_TEST_DEVICES_VOLTD_COUNT 2
29
30 /*
31 * struct sandbox_scmi_device_priv - Storage for device handles used by test
32 * @clk: Array of clock instances used by tests
33 * @reset_clt: Array of the reset controller instances used by tests
34 * @regulators: Array of regulator device references used by the tests
35 * @devices: Resources exposed by sandbox_scmi_devices_ctx()
36 */
37 struct sandbox_scmi_device_priv {
38 struct clk clk[SCMI_TEST_DEVICES_CLK_COUNT];
39 struct reset_ctl reset_ctl[SCMI_TEST_DEVICES_RD_COUNT];
40 struct udevice *regulators[SCMI_TEST_DEVICES_VOLTD_COUNT];
41 struct sandbox_scmi_devices devices;
42 };
43
sandbox_scmi_devices_ctx(struct udevice * dev)44 struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(struct udevice *dev)
45 {
46 struct sandbox_scmi_device_priv *priv = dev_get_priv(dev);
47
48 if (priv)
49 return &priv->devices;
50
51 return NULL;
52 }
53
sandbox_scmi_devices_remove(struct udevice * dev)54 static int sandbox_scmi_devices_remove(struct udevice *dev)
55 {
56 struct sandbox_scmi_devices *devices = sandbox_scmi_devices_ctx(dev);
57 int ret = 0;
58 size_t n;
59
60 if (!devices)
61 return 0;
62
63 for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) {
64 int ret2 = reset_free(devices->reset + n);
65
66 if (ret2 && !ret)
67 ret = ret2;
68 }
69
70 return ret;
71 }
72
sandbox_scmi_devices_probe(struct udevice * dev)73 static int sandbox_scmi_devices_probe(struct udevice *dev)
74 {
75 struct sandbox_scmi_device_priv *priv = dev_get_priv(dev);
76 int ret;
77 size_t n;
78
79 priv->devices = (struct sandbox_scmi_devices){
80 .clk = priv->clk,
81 .clk_count = SCMI_TEST_DEVICES_CLK_COUNT,
82 .reset = priv->reset_ctl,
83 .reset_count = SCMI_TEST_DEVICES_RD_COUNT,
84 .regul = priv->regulators,
85 .regul_count = SCMI_TEST_DEVICES_VOLTD_COUNT,
86 };
87
88 for (n = 0; n < SCMI_TEST_DEVICES_CLK_COUNT; n++) {
89 ret = clk_get_by_index(dev, n, priv->devices.clk + n);
90 if (ret) {
91 dev_err(dev, "%s: Failed on clk %zu\n", __func__, n);
92 return ret;
93 }
94 }
95
96 for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) {
97 ret = reset_get_by_index(dev, n, priv->devices.reset + n);
98 if (ret) {
99 dev_err(dev, "%s: Failed on reset %zu\n", __func__, n);
100 goto err_reset;
101 }
102 }
103
104 for (n = 0; n < SCMI_TEST_DEVICES_VOLTD_COUNT; n++) {
105 char name[32];
106
107 ret = snprintf(name, sizeof(name), "regul%zu-supply", n);
108 assert(ret >= 0 && ret < sizeof(name));
109
110 ret = device_get_supply_regulator(dev, name,
111 priv->devices.regul + n);
112 if (ret) {
113 dev_err(dev, "%s: Failed on voltd %zu\n", __func__, n);
114 goto err_regul;
115 }
116 }
117
118 return 0;
119
120 err_regul:
121 n = SCMI_TEST_DEVICES_RD_COUNT;
122 err_reset:
123 for (; n > 0; n--)
124 reset_free(priv->devices.reset + n - 1);
125
126 return ret;
127 }
128
129 static const struct udevice_id sandbox_scmi_devices_ids[] = {
130 { .compatible = "sandbox,scmi-devices" },
131 { }
132 };
133
134 U_BOOT_DRIVER(sandbox_scmi_devices) = {
135 .name = "sandbox-scmi_devices",
136 .id = UCLASS_MISC,
137 .of_match = sandbox_scmi_devices_ids,
138 .priv_auto = sizeof(struct sandbox_scmi_device_priv),
139 .remove = sandbox_scmi_devices_remove,
140 .probe = sandbox_scmi_devices_probe,
141 };
142