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 if (!data->voltages_mV) 174 return -ENOMEM; 175 176 data->desc.n_voltages = data->num_voltages; 177 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) 182 return -ENOMEM; 183 184 return 0; 185 } 186 187 static int cros_ec_regulator_probe(struct platform_device *pdev) 188 { 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; 195 int ret; 196 197 drvdata = devm_kzalloc( 198 &pdev->dev, sizeof(struct cros_ec_regulator_data), GFP_KERNEL); 199 if (!drvdata) 200 return -ENOMEM; 201 202 drvdata->ec_dev = dev_get_drvdata(dev->parent); 203 desc = &drvdata->desc; 204 205 init_data = of_get_regulator_init_data(dev, np, desc); 206 if (!init_data) 207 return -EINVAL; 208 209 ret = of_property_read_u32(np, "reg", &drvdata->index); 210 if (ret < 0) 211 return ret; 212 213 desc->owner = THIS_MODULE; 214 desc->type = REGULATOR_VOLTAGE; 215 desc->ops = &cros_ec_regulator_voltage_ops; 216 217 ret = cros_ec_regulator_init_info(dev, drvdata); 218 if (ret < 0) 219 return ret; 220 221 cfg.dev = &pdev->dev; 222 cfg.init_data = init_data; 223 cfg.driver_data = drvdata; 224 cfg.of_node = np; 225 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); 230 } 231 232 platform_set_drvdata(pdev, drvdata); 233 234 return 0; 235 } 236 237 static const struct of_device_id regulator_cros_ec_of_match[] = { 238 { .compatible = "google,cros-ec-regulator", }, 239 {} 240 }; 241 MODULE_DEVICE_TABLE(of, regulator_cros_ec_of_match); 242 243 static struct platform_driver cros_ec_regulator_driver = { 244 .probe = cros_ec_regulator_probe, 245 .driver = { 246 .name = "cros-ec-regulator", 247 .of_match_table = regulator_cros_ec_of_match, 248 }, 249 }; 250 251 module_platform_driver(cros_ec_regulator_driver); 252 253 MODULE_LICENSE("GPL v2"); 254 MODULE_DESCRIPTION("ChromeOS EC controlled regulator"); 255 MODULE_AUTHOR("Pi-Hsun Shih <pihsun@chromium.org>"); 256