1 // SPDX-License-Identifier: GPL-2.0-only 2 // 3 // Copyright 2020 Google LLC. 4 5 #include <linux/module.h> 6 #include <linux/of.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> 13 14 struct cros_ec_regulator_data { 15 struct regulator_desc desc; 16 struct regulator_dev *dev; 17 struct cros_ec_device *ec_dev; 18 19 u32 index; 20 21 u16 *voltages_mV; 22 u16 num_voltages; 23 }; 24 25 static int cros_ec_cmd(struct cros_ec_device *ec, u32 version, u32 command, 26 void *outdata, u32 outsize, void *indata, u32 insize) 27 { 28 struct cros_ec_command *msg; 29 int ret; 30 31 msg = kzalloc(sizeof(*msg) + max(outsize, insize), GFP_KERNEL); 32 if (!msg) 33 return -ENOMEM; 34 35 msg->version = version; 36 msg->command = command; 37 msg->outsize = outsize; 38 msg->insize = insize; 39 40 if (outdata && outsize > 0) 41 memcpy(msg->data, outdata, outsize); 42 43 ret = cros_ec_cmd_xfer_status(ec, msg); 44 if (ret < 0) 45 goto cleanup; 46 47 if (insize) 48 memcpy(indata, msg->data, insize); 49 50 cleanup: 51 kfree(msg); 52 return ret; 53 } 54 55 static int cros_ec_regulator_enable(struct regulator_dev *dev) 56 { 57 struct cros_ec_regulator_data *data = rdev_get_drvdata(dev); 58 struct ec_params_regulator_enable cmd = { 59 .index = data->index, 60 .enable = 1, 61 }; 62 63 return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd, 64 sizeof(cmd), NULL, 0); 65 } 66 67 static int cros_ec_regulator_disable(struct regulator_dev *dev) 68 { 69 struct cros_ec_regulator_data *data = rdev_get_drvdata(dev); 70 struct ec_params_regulator_enable cmd = { 71 .index = data->index, 72 .enable = 0, 73 }; 74 75 return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_ENABLE, &cmd, 76 sizeof(cmd), NULL, 0); 77 } 78 79 static int cros_ec_regulator_is_enabled(struct regulator_dev *dev) 80 { 81 struct cros_ec_regulator_data *data = rdev_get_drvdata(dev); 82 struct ec_params_regulator_is_enabled cmd = { 83 .index = data->index, 84 }; 85 struct ec_response_regulator_is_enabled resp; 86 int ret; 87 88 ret = cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_IS_ENABLED, &cmd, 89 sizeof(cmd), &resp, sizeof(resp)); 90 if (ret < 0) 91 return ret; 92 return resp.enabled; 93 } 94 95 static int cros_ec_regulator_list_voltage(struct regulator_dev *dev, 96 unsigned int selector) 97 { 98 struct cros_ec_regulator_data *data = rdev_get_drvdata(dev); 99 100 if (selector >= data->num_voltages) 101 return -EINVAL; 102 103 return data->voltages_mV[selector] * 1000; 104 } 105 106 static int cros_ec_regulator_get_voltage(struct regulator_dev *dev) 107 { 108 struct cros_ec_regulator_data *data = rdev_get_drvdata(dev); 109 struct ec_params_regulator_get_voltage cmd = { 110 .index = data->index, 111 }; 112 struct ec_response_regulator_get_voltage resp; 113 int ret; 114 115 ret = cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_GET_VOLTAGE, &cmd, 116 sizeof(cmd), &resp, sizeof(resp)); 117 if (ret < 0) 118 return ret; 119 return resp.voltage_mv * 1000; 120 } 121 122 static int cros_ec_regulator_set_voltage(struct regulator_dev *dev, int min_uV, 123 int max_uV, unsigned int *selector) 124 { 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, 130 .min_mv = min_mV, 131 .max_mv = max_mV, 132 }; 133 134 /* 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. 137 */ 138 if (min_mV > max_mV) 139 return -EINVAL; 140 141 return cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_SET_VOLTAGE, &cmd, 142 sizeof(cmd), NULL, 0); 143 } 144 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, 152 }; 153 154 static int cros_ec_regulator_init_info(struct device *dev, 155 struct cros_ec_regulator_data *data) 156 { 157 struct ec_params_regulator_get_info cmd = { 158 .index = data->index, 159 }; 160 struct ec_response_regulator_get_info resp; 161 int ret; 162 163 ret = cros_ec_cmd(data->ec_dev, 0, EC_CMD_REGULATOR_GET_INFO, &cmd, 164 sizeof(cmd), &resp, sizeof(resp)); 165 if (ret < 0) 166 return ret; 167 168 data->num_voltages = 169 min_t(u16, ARRAY_SIZE(resp.voltages_mv), resp.num_voltages); 170 data->voltages_mV = 171 devm_kmemdup(dev, resp.voltages_mv, 172 sizeof(u16) * data->num_voltages, GFP_KERNEL); 173 data->desc.n_voltages = data->num_voltages; 174 175 /* Make sure the returned name is always a valid string */ 176 resp.name[ARRAY_SIZE(resp.name) - 1] = '\0'; 177 data->desc.name = devm_kstrdup(dev, resp.name, GFP_KERNEL); 178 if (!data->desc.name) 179 return -ENOMEM; 180 181 return 0; 182 } 183 184 static int cros_ec_regulator_probe(struct platform_device *pdev) 185 { 186 struct device *dev = &pdev->dev; 187 struct device_node *np = dev->of_node; 188 struct cros_ec_regulator_data *drvdata; 189 struct regulator_init_data *init_data; 190 struct regulator_config cfg = {}; 191 struct regulator_desc *desc; 192 int ret; 193 194 drvdata = devm_kzalloc( 195 &pdev->dev, sizeof(struct cros_ec_regulator_data), GFP_KERNEL); 196 if (!drvdata) 197 return -ENOMEM; 198 199 drvdata->ec_dev = dev_get_drvdata(dev->parent); 200 desc = &drvdata->desc; 201 202 init_data = of_get_regulator_init_data(dev, np, desc); 203 if (!init_data) 204 return -EINVAL; 205 206 ret = of_property_read_u32(np, "reg", &drvdata->index); 207 if (ret < 0) 208 return ret; 209 210 desc->owner = THIS_MODULE; 211 desc->type = REGULATOR_VOLTAGE; 212 desc->ops = &cros_ec_regulator_voltage_ops; 213 214 ret = cros_ec_regulator_init_info(dev, drvdata); 215 if (ret < 0) 216 return ret; 217 218 cfg.dev = &pdev->dev; 219 cfg.init_data = init_data; 220 cfg.driver_data = drvdata; 221 cfg.of_node = np; 222 223 drvdata->dev = devm_regulator_register(dev, &drvdata->desc, &cfg); 224 if (IS_ERR(drvdata->dev)) { 225 dev_err(&pdev->dev, "Failed to register regulator: %d\n", ret); 226 return PTR_ERR(drvdata->dev); 227 } 228 229 platform_set_drvdata(pdev, drvdata); 230 231 return 0; 232 } 233 234 static const struct of_device_id regulator_cros_ec_of_match[] = { 235 { .compatible = "google,cros-ec-regulator", }, 236 {} 237 }; 238 MODULE_DEVICE_TABLE(of, regulator_cros_ec_of_match); 239 240 static struct platform_driver cros_ec_regulator_driver = { 241 .probe = cros_ec_regulator_probe, 242 .driver = { 243 .name = "cros-ec-regulator", 244 .of_match_table = regulator_cros_ec_of_match, 245 }, 246 }; 247 248 module_platform_driver(cros_ec_regulator_driver); 249 250 MODULE_LICENSE("GPL v2"); 251 MODULE_DESCRIPTION("ChromeOS EC controlled regulator"); 252 MODULE_AUTHOR("Pi-Hsun Shih <pihsun@chromium.org>"); 253