summaryrefslogtreecommitdiffstats
path: root/drivers/firmware/scmi/sandbox-scmi_devices.c
blob: 66a67928817f83950795fb3f80efe957b07008be (plain)
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
140
141
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2020-2021, Linaro Limited
 */

#define LOG_CATEGORY UCLASS_MISC

#include <common.h>
#include <clk.h>
#include <dm.h>
#include <log.h>
#include <malloc.h>
#include <reset.h>
#include <asm/io.h>
#include <asm/scmi_test.h>
#include <dm/device_compat.h>
#include <power/regulator.h>

/*
 * Simulate to some extent a SCMI exchange.
 * This drivers gets SCMI resources and offers API function to the
 * SCMI test sequence manipulate the resources, currently clock
 * and reset controllers.
 */

#define SCMI_TEST_DEVICES_CLK_COUNT		3
#define SCMI_TEST_DEVICES_RD_COUNT		1
#define SCMI_TEST_DEVICES_VOLTD_COUNT		2

/*
 * struct sandbox_scmi_device_priv - Storage for device handles used by test
 * @clk:		Array of clock instances used by tests
 * @reset_clt:		Array of the reset controller instances used by tests
 * @regulators:		Array of regulator device references used by the tests
 * @devices:		Resources exposed by sandbox_scmi_devices_ctx()
 */
struct sandbox_scmi_device_priv {
	struct clk clk[SCMI_TEST_DEVICES_CLK_COUNT];
	struct reset_ctl reset_ctl[SCMI_TEST_DEVICES_RD_COUNT];
	struct udevice *regulators[SCMI_TEST_DEVICES_VOLTD_COUNT];
	struct sandbox_scmi_devices devices;
};

struct sandbox_scmi_devices *sandbox_scmi_devices_ctx(struct udevice *dev)
{
	struct sandbox_scmi_device_priv *priv = dev_get_priv(dev);

	if (priv)
		return &priv->devices;

	return NULL;
}

static int sandbox_scmi_devices_remove(struct udevice *dev)
{
	struct sandbox_scmi_devices *devices = sandbox_scmi_devices_ctx(dev);
	int ret = 0;
	size_t n;

	if (!devices)
		return 0;

	for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) {
		int ret2 = reset_free(devices->reset + n);

		if (ret2 && !ret)
			ret = ret2;
	}

	return ret;
}

static int sandbox_scmi_devices_probe(struct udevice *dev)
{
	struct sandbox_scmi_device_priv *priv = dev_get_priv(dev);
	int ret;
	size_t n;

	priv->devices = (struct sandbox_scmi_devices){
		.clk = priv->clk,
		.clk_count = SCMI_TEST_DEVICES_CLK_COUNT,
		.reset = priv->reset_ctl,
		.reset_count = SCMI_TEST_DEVICES_RD_COUNT,
		.regul = priv->regulators,
		.regul_count = SCMI_TEST_DEVICES_VOLTD_COUNT,
	};

	for (n = 0; n < SCMI_TEST_DEVICES_CLK_COUNT; n++) {
		ret = clk_get_by_index(dev, n, priv->devices.clk + n);
		if (ret) {
			dev_err(dev, "%s: Failed on clk %zu\n", __func__, n);
			return ret;
		}
	}

	for (n = 0; n < SCMI_TEST_DEVICES_RD_COUNT; n++) {
		ret = reset_get_by_index(dev, n, priv->devices.reset + n);
		if (ret) {
			dev_err(dev, "%s: Failed on reset %zu\n", __func__, n);
			goto err_reset;
		}
	}

	for (n = 0; n < SCMI_TEST_DEVICES_VOLTD_COUNT; n++) {
		char name[32];

		ret = snprintf(name, sizeof(name), "regul%zu-supply", n);
		assert(ret >= 0 && ret < sizeof(name));

		ret = device_get_supply_regulator(dev, name,
						  priv->devices.regul + n);
		if (ret) {
			dev_err(dev, "%s: Failed on voltd %zu\n", __func__, n);
			goto err_regul;
		}
	}

	return 0;

err_regul:
	n = SCMI_TEST_DEVICES_RD_COUNT;
err_reset:
	for (; n > 0; n--)
		reset_free(priv->devices.reset + n - 1);

	return ret;
}

static const struct udevice_id sandbox_scmi_devices_ids[] = {
	{ .compatible = "sandbox,scmi-devices" },
	{ }
};

U_BOOT_DRIVER(sandbox_scmi_devices) = {
	.name = "sandbox-scmi_devices",
	.id = UCLASS_MISC,
	.of_match = sandbox_scmi_devices_ids,
	.priv_auto	= sizeof(struct sandbox_scmi_device_priv),
	.remove = sandbox_scmi_devices_remove,
	.probe = sandbox_scmi_devices_probe,
};