1 // SPDX-License-Identifier: GPL-2.0+
3 * Copyright (C) 2020-2021 Linaro Limited
6 #define LOG_CATEGORY UCLASS_REGULATOR
11 #include <scmi_agent.h>
12 #include <scmi_protocols.h>
13 #include <asm/types.h>
14 #include <dm/device.h>
15 #include <dm/device_compat.h>
16 #include <dm/device-internal.h>
17 #include <linux/kernel.h>
18 #include <power/regulator.h>
21 * struct scmi_regulator_platdata - Platform data for a scmi voltage domain regulator
22 * @domain_id: ID representing the regulator for the related SCMI agent
24 struct scmi_regulator_platdata {
28 static int scmi_voltd_set_enable(struct udevice *dev, bool enable)
30 struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
31 struct scmi_voltd_config_set_in in = {
32 .domain_id = pdata->domain_id,
33 .config = enable ? SCMI_VOLTD_CONFIG_ON : SCMI_VOLTD_CONFIG_OFF,
35 struct scmi_voltd_config_set_out out;
36 struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
37 SCMI_VOLTAGE_DOMAIN_CONFIG_SET,
41 ret = devm_scmi_process_msg(dev, &msg);
45 ret = scmi_to_linux_errno(out.status);
52 static int scmi_voltd_get_enable(struct udevice *dev)
54 struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
55 struct scmi_voltd_config_get_in in = {
56 .domain_id = pdata->domain_id,
58 struct scmi_voltd_config_get_out out;
59 struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
60 SCMI_VOLTAGE_DOMAIN_CONFIG_GET,
64 ret = devm_scmi_process_msg(dev, &msg);
68 ret = scmi_to_linux_errno(out.status);
72 return out.config == SCMI_VOLTD_CONFIG_ON;
75 static int scmi_voltd_set_voltage_level(struct udevice *dev, int uV)
77 struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
78 struct scmi_voltd_level_set_in in = {
79 .domain_id = pdata->domain_id,
82 struct scmi_voltd_level_set_out out;
83 struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
84 SCMI_VOLTAGE_DOMAIN_LEVEL_SET,
88 ret = devm_scmi_process_msg(dev, &msg);
92 return scmi_to_linux_errno(out.status);
95 static int scmi_voltd_get_voltage_level(struct udevice *dev)
97 struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
98 struct scmi_voltd_level_get_in in = {
99 .domain_id = pdata->domain_id,
101 struct scmi_voltd_level_get_out out;
102 struct scmi_msg msg = SCMI_MSG_IN(SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
103 SCMI_VOLTAGE_DOMAIN_LEVEL_GET,
107 ret = devm_scmi_process_msg(dev, &msg);
111 ret = scmi_to_linux_errno(out.status);
115 return out.voltage_level;
118 static int scmi_regulator_of_to_plat(struct udevice *dev)
120 struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
123 reg = dev_read_addr(dev);
124 if (reg == FDT_ADDR_T_NONE)
127 pdata->domain_id = (u32)reg;
132 static int scmi_regulator_probe(struct udevice *dev)
134 struct scmi_regulator_platdata *pdata = dev_get_plat(dev);
135 struct scmi_voltd_attr_in in = { 0 };
136 struct scmi_voltd_attr_out out = { 0 };
137 struct scmi_msg scmi_msg = {
138 .protocol_id = SCMI_PROTOCOL_ID_VOLTAGE_DOMAIN,
139 .message_id = SCMI_VOLTAGE_DOMAIN_ATTRIBUTES,
141 .in_msg_sz = sizeof(in),
142 .out_msg = (u8 *)&out,
143 .out_msg_sz = sizeof(out),
147 /* Check voltage domain is known from SCMI server */
148 in.domain_id = pdata->domain_id;
150 ret = devm_scmi_process_msg(dev, &scmi_msg);
152 dev_err(dev, "Failed to query voltage domain %u: %d\n",
153 pdata->domain_id, ret);
160 static const struct dm_regulator_ops scmi_voltd_ops = {
161 .get_value = scmi_voltd_get_voltage_level,
162 .set_value = scmi_voltd_set_voltage_level,
163 .get_enable = scmi_voltd_get_enable,
164 .set_enable = scmi_voltd_set_enable,
167 U_BOOT_DRIVER(scmi_regulator) = {
168 .name = "scmi_regulator",
169 .id = UCLASS_REGULATOR,
170 .ops = &scmi_voltd_ops,
171 .probe = scmi_regulator_probe,
172 .of_to_plat = scmi_regulator_of_to_plat,
173 .plat_auto = sizeof(struct scmi_regulator_platdata),
176 static int scmi_regulator_bind(struct udevice *dev)
182 drv = DM_DRIVER_GET(scmi_regulator);
184 ofnode_for_each_subnode(node, dev_ofnode(dev)) {
185 ret = device_bind(dev, drv, ofnode_get_name(node),
194 U_BOOT_DRIVER(scmi_voltage_domain) = {
195 .name = "scmi_voltage_domain",
197 .bind = scmi_regulator_bind,