1 // SPDX-License-Identifier: GPL-2.0-only
3 // Copyright 2020 Google LLC.
5 #include <linux/module.h>
7 #include <linux/platform_data/cros_ec_proto.h>
8 #include <linux/platform_device.h>
9 #include <linux/regulator/driver.h>
10 #include <linux/regulator/machine.h>
11 #include <linux/regulator/of_regulator.h>
12 #include <linux/slab.h>
14 struct cros_ec_regulator_data
{
15 struct regulator_desc desc
;
16 struct regulator_dev
*dev
;
17 struct cros_ec_device
*ec_dev
;
25 static int cros_ec_cmd(struct cros_ec_device
*ec
, u32 version
, u32 command
,
26 void *outdata
, u32 outsize
, void *indata
, u32 insize
)
28 struct cros_ec_command
*msg
;
31 msg
= kzalloc(sizeof(*msg
) + max(outsize
, insize
), GFP_KERNEL
);
35 msg
->version
= version
;
36 msg
->command
= command
;
37 msg
->outsize
= outsize
;
40 if (outdata
&& outsize
> 0)
41 memcpy(msg
->data
, outdata
, outsize
);
43 ret
= cros_ec_cmd_xfer_status(ec
, msg
);
48 memcpy(indata
, msg
->data
, insize
);
55 static int cros_ec_regulator_enable(struct regulator_dev
*dev
)
57 struct cros_ec_regulator_data
*data
= rdev_get_drvdata(dev
);
58 struct ec_params_regulator_enable cmd
= {
63 return cros_ec_cmd(data
->ec_dev
, 0, EC_CMD_REGULATOR_ENABLE
, &cmd
,
64 sizeof(cmd
), NULL
, 0);
67 static int cros_ec_regulator_disable(struct regulator_dev
*dev
)
69 struct cros_ec_regulator_data
*data
= rdev_get_drvdata(dev
);
70 struct ec_params_regulator_enable cmd
= {
75 return cros_ec_cmd(data
->ec_dev
, 0, EC_CMD_REGULATOR_ENABLE
, &cmd
,
76 sizeof(cmd
), NULL
, 0);
79 static int cros_ec_regulator_is_enabled(struct regulator_dev
*dev
)
81 struct cros_ec_regulator_data
*data
= rdev_get_drvdata(dev
);
82 struct ec_params_regulator_is_enabled cmd
= {
85 struct ec_response_regulator_is_enabled resp
;
88 ret
= cros_ec_cmd(data
->ec_dev
, 0, EC_CMD_REGULATOR_IS_ENABLED
, &cmd
,
89 sizeof(cmd
), &resp
, sizeof(resp
));
95 static int cros_ec_regulator_list_voltage(struct regulator_dev
*dev
,
96 unsigned int selector
)
98 struct cros_ec_regulator_data
*data
= rdev_get_drvdata(dev
);
100 if (selector
>= data
->num_voltages
)
103 return data
->voltages_mV
[selector
] * 1000;
106 static int cros_ec_regulator_get_voltage(struct regulator_dev
*dev
)
108 struct cros_ec_regulator_data
*data
= rdev_get_drvdata(dev
);
109 struct ec_params_regulator_get_voltage cmd
= {
110 .index
= data
->index
,
112 struct ec_response_regulator_get_voltage resp
;
115 ret
= cros_ec_cmd(data
->ec_dev
, 0, EC_CMD_REGULATOR_GET_VOLTAGE
, &cmd
,
116 sizeof(cmd
), &resp
, sizeof(resp
));
119 return resp
.voltage_mv
* 1000;
122 static int cros_ec_regulator_set_voltage(struct regulator_dev
*dev
, int min_uV
,
123 int max_uV
, unsigned int *selector
)
125 struct cros_ec_regulator_data
*data
= rdev_get_drvdata(dev
);
126 int min_mV
= DIV_ROUND_UP(min_uV
, 1000);
127 int max_mV
= max_uV
/ 1000;
128 struct ec_params_regulator_set_voltage cmd
= {
129 .index
= data
->index
,
135 * This can happen when the given range [min_uV, max_uV] doesn't
136 * contain any voltage that can be represented exactly in mV.
141 return cros_ec_cmd(data
->ec_dev
, 0, EC_CMD_REGULATOR_SET_VOLTAGE
, &cmd
,
142 sizeof(cmd
), NULL
, 0);
145 static const struct regulator_ops cros_ec_regulator_voltage_ops
= {
146 .enable
= cros_ec_regulator_enable
,
147 .disable
= cros_ec_regulator_disable
,
148 .is_enabled
= cros_ec_regulator_is_enabled
,
149 .list_voltage
= cros_ec_regulator_list_voltage
,
150 .get_voltage
= cros_ec_regulator_get_voltage
,
151 .set_voltage
= cros_ec_regulator_set_voltage
,
154 static int cros_ec_regulator_init_info(struct device
*dev
,
155 struct cros_ec_regulator_data
*data
)
157 struct ec_params_regulator_get_info cmd
= {
158 .index
= data
->index
,
160 struct ec_response_regulator_get_info resp
;
163 ret
= cros_ec_cmd(data
->ec_dev
, 0, EC_CMD_REGULATOR_GET_INFO
, &cmd
,
164 sizeof(cmd
), &resp
, sizeof(resp
));
169 min_t(u16
, ARRAY_SIZE(resp
.voltages_mv
), resp
.num_voltages
);
171 devm_kmemdup(dev
, resp
.voltages_mv
,
172 sizeof(u16
) * data
->num_voltages
, GFP_KERNEL
);
173 if (!data
->voltages_mV
)
176 data
->desc
.n_voltages
= data
->num_voltages
;
178 /* Make sure the returned name is always a valid string */
179 resp
.name
[ARRAY_SIZE(resp
.name
) - 1] = '\0';
180 data
->desc
.name
= devm_kstrdup(dev
, resp
.name
, GFP_KERNEL
);
181 if (!data
->desc
.name
)
187 static int cros_ec_regulator_probe(struct platform_device
*pdev
)
189 struct device
*dev
= &pdev
->dev
;
190 struct device_node
*np
= dev
->of_node
;
191 struct cros_ec_regulator_data
*drvdata
;
192 struct regulator_init_data
*init_data
;
193 struct regulator_config cfg
= {};
194 struct regulator_desc
*desc
;
197 drvdata
= devm_kzalloc(
198 &pdev
->dev
, sizeof(struct cros_ec_regulator_data
), GFP_KERNEL
);
202 drvdata
->ec_dev
= dev_get_drvdata(dev
->parent
);
203 desc
= &drvdata
->desc
;
205 init_data
= of_get_regulator_init_data(dev
, np
, desc
);
209 ret
= of_property_read_u32(np
, "reg", &drvdata
->index
);
213 desc
->owner
= THIS_MODULE
;
214 desc
->type
= REGULATOR_VOLTAGE
;
215 desc
->ops
= &cros_ec_regulator_voltage_ops
;
217 ret
= cros_ec_regulator_init_info(dev
, drvdata
);
221 cfg
.dev
= &pdev
->dev
;
222 cfg
.init_data
= init_data
;
223 cfg
.driver_data
= drvdata
;
226 drvdata
->dev
= devm_regulator_register(dev
, &drvdata
->desc
, &cfg
);
227 if (IS_ERR(drvdata
->dev
)) {
228 dev_err(&pdev
->dev
, "Failed to register regulator: %d\n", ret
);
229 return PTR_ERR(drvdata
->dev
);
232 platform_set_drvdata(pdev
, drvdata
);
237 static const struct of_device_id regulator_cros_ec_of_match
[] = {
238 { .compatible
= "google,cros-ec-regulator", },
241 MODULE_DEVICE_TABLE(of
, regulator_cros_ec_of_match
);
243 static struct platform_driver cros_ec_regulator_driver
= {
244 .probe
= cros_ec_regulator_probe
,
246 .name
= "cros-ec-regulator",
247 .of_match_table
= regulator_cros_ec_of_match
,
251 module_platform_driver(cros_ec_regulator_driver
);
253 MODULE_LICENSE("GPL v2");
254 MODULE_DESCRIPTION("ChromeOS EC controlled regulator");
255 MODULE_AUTHOR("Pi-Hsun Shih <pihsun@chromium.org>");