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