Padmanabhan Komanduru | dbd2fb0 | 2016-12-02 15:18:49 +0530 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (c) 2016-2017, The Linux Foundation. All rights reserved. |
| 3 | * |
| 4 | * This program is free software; you can redistribute it and/or modify |
| 5 | * it under the terms of the GNU General Public License version 2 and |
| 6 | * only version 2 as published by the Free Software Foundation. |
| 7 | * |
| 8 | * This program is distributed in the hope that it will be useful, |
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | * GNU General Public License for more details. |
| 12 | * |
| 13 | */ |
| 14 | |
| 15 | #include <linux/of.h> |
| 16 | #include <linux/delay.h> |
| 17 | #include <linux/slab.h> |
| 18 | |
| 19 | #include "dsi_pwr.h" |
| 20 | |
| 21 | /* |
| 22 | * dsi_pwr_parse_supply_node() - parse power supply node from root device node |
| 23 | */ |
| 24 | static int dsi_pwr_parse_supply_node(struct device_node *root, |
| 25 | struct dsi_regulator_info *regs) |
| 26 | { |
| 27 | int rc = 0; |
| 28 | int i = 0; |
| 29 | u32 tmp = 0; |
| 30 | struct device_node *node = NULL; |
| 31 | |
| 32 | for_each_child_of_node(root, node) { |
| 33 | const char *st = NULL; |
| 34 | |
| 35 | rc = of_property_read_string(node, "qcom,supply-name", &st); |
| 36 | if (rc) { |
| 37 | pr_err("failed to read name, rc = %d\n", rc); |
| 38 | goto error; |
| 39 | } |
| 40 | |
| 41 | snprintf(regs->vregs[i].vreg_name, |
| 42 | ARRAY_SIZE(regs->vregs[i].vreg_name), |
| 43 | "%s", st); |
| 44 | |
| 45 | rc = of_property_read_u32(node, "qcom,supply-min-voltage", |
| 46 | &tmp); |
| 47 | if (rc) { |
| 48 | pr_err("failed to read min voltage, rc = %d\n", rc); |
| 49 | goto error; |
| 50 | } |
| 51 | regs->vregs[i].min_voltage = tmp; |
| 52 | |
| 53 | rc = of_property_read_u32(node, "qcom,supply-max-voltage", |
| 54 | &tmp); |
| 55 | if (rc) { |
| 56 | pr_err("failed to read max voltage, rc = %d\n", rc); |
| 57 | goto error; |
| 58 | } |
| 59 | regs->vregs[i].max_voltage = tmp; |
| 60 | |
| 61 | rc = of_property_read_u32(node, "qcom,supply-enable-load", |
| 62 | &tmp); |
| 63 | if (rc) { |
| 64 | pr_err("failed to read enable load, rc = %d\n", rc); |
| 65 | goto error; |
| 66 | } |
| 67 | regs->vregs[i].enable_load = tmp; |
| 68 | |
| 69 | rc = of_property_read_u32(node, "qcom,supply-disable-load", |
| 70 | &tmp); |
| 71 | if (rc) { |
| 72 | pr_err("failed to read disable load, rc = %d\n", rc); |
| 73 | goto error; |
| 74 | } |
| 75 | regs->vregs[i].disable_load = tmp; |
| 76 | |
| 77 | /* Optional values */ |
| 78 | rc = of_property_read_u32(node, "qcom,supply-pre-on-sleep", |
| 79 | &tmp); |
| 80 | if (rc) { |
| 81 | pr_debug("pre-on-sleep not specified\n"); |
| 82 | rc = 0; |
| 83 | } else { |
| 84 | regs->vregs[i].pre_on_sleep = tmp; |
| 85 | } |
| 86 | |
| 87 | rc = of_property_read_u32(node, "qcom,supply-pre-off-sleep", |
| 88 | &tmp); |
| 89 | if (rc) { |
| 90 | pr_debug("pre-off-sleep not specified\n"); |
| 91 | rc = 0; |
| 92 | } else { |
| 93 | regs->vregs[i].pre_off_sleep = tmp; |
| 94 | } |
| 95 | |
| 96 | rc = of_property_read_u32(node, "qcom,supply-post-on-sleep", |
| 97 | &tmp); |
| 98 | if (rc) { |
| 99 | pr_debug("post-on-sleep not specified\n"); |
| 100 | rc = 0; |
| 101 | } else { |
| 102 | regs->vregs[i].post_on_sleep = tmp; |
| 103 | } |
| 104 | |
| 105 | rc = of_property_read_u32(node, "qcom,supply-post-off-sleep", |
| 106 | &tmp); |
| 107 | if (rc) { |
| 108 | pr_debug("post-off-sleep not specified\n"); |
| 109 | rc = 0; |
| 110 | } else { |
| 111 | regs->vregs[i].post_off_sleep = tmp; |
| 112 | } |
| 113 | |
| 114 | ++i; |
| 115 | pr_debug("[%s] minv=%d maxv=%d, en_load=%d, dis_load=%d\n", |
| 116 | regs->vregs[i].vreg_name, |
| 117 | regs->vregs[i].min_voltage, |
| 118 | regs->vregs[i].max_voltage, |
| 119 | regs->vregs[i].enable_load, |
| 120 | regs->vregs[i].disable_load); |
| 121 | } |
| 122 | |
| 123 | error: |
| 124 | return rc; |
| 125 | } |
| 126 | |
| 127 | /** |
| 128 | * dsi_pwr_enable_vregs() - enable/disable regulators |
| 129 | */ |
| 130 | static int dsi_pwr_enable_vregs(struct dsi_regulator_info *regs, bool enable) |
| 131 | { |
| 132 | int rc = 0, i = 0; |
| 133 | struct dsi_vreg *vreg; |
| 134 | int num_of_v = 0; |
| 135 | |
| 136 | if (enable) { |
| 137 | for (i = 0; i < regs->count; i++) { |
| 138 | vreg = ®s->vregs[i]; |
| 139 | if (vreg->pre_on_sleep) |
| 140 | msleep(vreg->pre_on_sleep); |
| 141 | |
| 142 | rc = regulator_set_load(vreg->vreg, |
| 143 | vreg->enable_load); |
| 144 | if (rc < 0) { |
| 145 | pr_err("Setting optimum mode failed for %s\n", |
| 146 | vreg->vreg_name); |
| 147 | goto error; |
| 148 | } |
| 149 | num_of_v = regulator_count_voltages(vreg->vreg); |
| 150 | if (num_of_v > 0) { |
| 151 | rc = regulator_set_voltage(vreg->vreg, |
| 152 | vreg->min_voltage, |
| 153 | vreg->max_voltage); |
| 154 | if (rc) { |
| 155 | pr_err("Set voltage(%s) fail, rc=%d\n", |
| 156 | vreg->vreg_name, rc); |
| 157 | goto error_disable_opt_mode; |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | rc = regulator_enable(vreg->vreg); |
| 162 | if (rc) { |
| 163 | pr_err("enable failed for %s, rc=%d\n", |
| 164 | vreg->vreg_name, rc); |
| 165 | goto error_disable_voltage; |
| 166 | } |
| 167 | |
| 168 | if (vreg->post_on_sleep) |
| 169 | msleep(vreg->post_on_sleep); |
| 170 | } |
| 171 | } else { |
| 172 | for (i = (regs->count - 1); i >= 0; i--) { |
| 173 | if (regs->vregs[i].pre_off_sleep) |
| 174 | msleep(regs->vregs[i].pre_off_sleep); |
| 175 | |
| 176 | (void)regulator_set_load(regs->vregs[i].vreg, |
| 177 | regs->vregs[i].disable_load); |
| 178 | (void)regulator_disable(regs->vregs[i].vreg); |
| 179 | |
| 180 | if (regs->vregs[i].post_off_sleep) |
| 181 | msleep(regs->vregs[i].post_off_sleep); |
| 182 | } |
| 183 | } |
| 184 | |
| 185 | return 0; |
| 186 | error_disable_opt_mode: |
| 187 | (void)regulator_set_load(regs->vregs[i].vreg, |
| 188 | regs->vregs[i].disable_load); |
| 189 | |
| 190 | error_disable_voltage: |
| 191 | if (num_of_v > 0) |
| 192 | (void)regulator_set_voltage(regs->vregs[i].vreg, |
| 193 | 0, regs->vregs[i].max_voltage); |
| 194 | error: |
| 195 | for (i--; i >= 0; i--) { |
| 196 | if (regs->vregs[i].pre_off_sleep) |
| 197 | msleep(regs->vregs[i].pre_off_sleep); |
| 198 | |
| 199 | (void)regulator_set_load(regs->vregs[i].vreg, |
| 200 | regs->vregs[i].disable_load); |
| 201 | |
| 202 | num_of_v = regulator_count_voltages(regs->vregs[i].vreg); |
| 203 | if (num_of_v > 0) |
| 204 | (void)regulator_set_voltage(regs->vregs[i].vreg, |
| 205 | 0, regs->vregs[i].max_voltage); |
| 206 | |
| 207 | (void)regulator_disable(regs->vregs[i].vreg); |
| 208 | |
| 209 | if (regs->vregs[i].post_off_sleep) |
| 210 | msleep(regs->vregs[i].post_off_sleep); |
| 211 | } |
| 212 | |
| 213 | return rc; |
| 214 | } |
| 215 | |
| 216 | /** |
| 217 | * dsi_pwr_of_get_vreg_data - Parse regulator supply information |
| 218 | * @of_node: Device of node to parse for supply information. |
| 219 | * @regs: Pointer where regulator information will be copied to. |
| 220 | * @supply_name: Name of the supply node. |
| 221 | * |
| 222 | * return: error code in case of failure or 0 for success. |
| 223 | */ |
| 224 | int dsi_pwr_of_get_vreg_data(struct device_node *of_node, |
| 225 | struct dsi_regulator_info *regs, |
| 226 | char *supply_name) |
| 227 | { |
| 228 | int rc = 0; |
| 229 | struct device_node *supply_root_node = NULL; |
| 230 | |
| 231 | if (!of_node || !regs) { |
| 232 | pr_err("Bad params\n"); |
| 233 | return -EINVAL; |
| 234 | } |
| 235 | |
| 236 | regs->count = 0; |
| 237 | supply_root_node = of_get_child_by_name(of_node, supply_name); |
| 238 | if (!supply_root_node) { |
| 239 | supply_root_node = of_parse_phandle(of_node, supply_name, 0); |
| 240 | if (!supply_root_node) { |
Shashank Babu Chinta Venkata | cf41133 | 2017-05-10 17:30:08 -0700 | [diff] [blame] | 241 | pr_debug("No supply entry present for %s\n", |
| 242 | supply_name); |
Padmanabhan Komanduru | dbd2fb0 | 2016-12-02 15:18:49 +0530 | [diff] [blame] | 243 | return -EINVAL; |
| 244 | } |
| 245 | } |
| 246 | |
| 247 | regs->count = of_get_available_child_count(supply_root_node); |
| 248 | if (regs->count == 0) { |
| 249 | pr_err("No vregs defined for %s\n", supply_name); |
| 250 | return -EINVAL; |
| 251 | } |
| 252 | |
| 253 | regs->vregs = kcalloc(regs->count, sizeof(*regs->vregs), GFP_KERNEL); |
| 254 | if (!regs->vregs) { |
| 255 | regs->count = 0; |
| 256 | return -ENOMEM; |
| 257 | } |
| 258 | |
| 259 | rc = dsi_pwr_parse_supply_node(supply_root_node, regs); |
| 260 | if (rc) { |
| 261 | pr_err("failed to parse supply node for %s, rc = %d\n", |
| 262 | supply_name, rc); |
| 263 | |
| 264 | kfree(regs->vregs); |
| 265 | regs->vregs = NULL; |
| 266 | regs->count = 0; |
| 267 | } |
| 268 | |
| 269 | return rc; |
| 270 | } |
| 271 | |
| 272 | /** |
| 273 | * dsi_pwr_get_dt_vreg_data - parse regulator supply information |
| 274 | * @dev: Device whose of_node needs to be parsed. |
| 275 | * @regs: Pointer where regulator information will be copied to. |
| 276 | * @supply_name: Name of the supply node. |
| 277 | * |
| 278 | * return: error code in case of failure or 0 for success. |
| 279 | */ |
| 280 | int dsi_pwr_get_dt_vreg_data(struct device *dev, |
| 281 | struct dsi_regulator_info *regs, |
| 282 | char *supply_name) |
| 283 | { |
| 284 | int rc = 0; |
| 285 | struct device_node *of_node = NULL; |
| 286 | struct device_node *supply_node = NULL; |
| 287 | struct device_node *supply_root_node = NULL; |
| 288 | |
| 289 | if (!dev || !regs) { |
| 290 | pr_err("Bad params\n"); |
| 291 | return -EINVAL; |
| 292 | } |
| 293 | |
| 294 | of_node = dev->of_node; |
| 295 | regs->count = 0; |
| 296 | supply_root_node = of_get_child_by_name(of_node, supply_name); |
| 297 | if (!supply_root_node) { |
| 298 | supply_root_node = of_parse_phandle(of_node, supply_name, 0); |
| 299 | if (!supply_root_node) { |
Shashank Babu Chinta Venkata | cf41133 | 2017-05-10 17:30:08 -0700 | [diff] [blame] | 300 | pr_debug("No supply entry present for %s\n", |
| 301 | supply_name); |
Padmanabhan Komanduru | dbd2fb0 | 2016-12-02 15:18:49 +0530 | [diff] [blame] | 302 | return -EINVAL; |
| 303 | } |
| 304 | } |
| 305 | |
| 306 | for_each_child_of_node(supply_root_node, supply_node) |
| 307 | regs->count++; |
| 308 | |
| 309 | if (regs->count == 0) { |
| 310 | pr_err("No vregs defined for %s\n", supply_name); |
| 311 | return -EINVAL; |
| 312 | } |
| 313 | |
| 314 | regs->vregs = devm_kcalloc(dev, regs->count, sizeof(*regs->vregs), |
| 315 | GFP_KERNEL); |
| 316 | if (!regs->vregs) { |
| 317 | regs->count = 0; |
| 318 | return -ENOMEM; |
| 319 | } |
| 320 | |
| 321 | rc = dsi_pwr_parse_supply_node(supply_root_node, regs); |
| 322 | if (rc) { |
| 323 | pr_err("failed to parse supply node for %s, rc = %d\n", |
| 324 | supply_name, rc); |
| 325 | devm_kfree(dev, regs->vregs); |
| 326 | regs->vregs = NULL; |
| 327 | regs->count = 0; |
| 328 | } |
| 329 | |
| 330 | return rc; |
| 331 | } |
| 332 | |
| 333 | /** |
| 334 | * dsi_pwr_enable_regulator() - enable a set of regulators |
| 335 | * @regs: Pointer to set of regulators to enable or disable. |
| 336 | * @enable: Enable/Disable regulators. |
| 337 | * |
| 338 | * return: error code in case of failure or 0 for success. |
| 339 | */ |
| 340 | int dsi_pwr_enable_regulator(struct dsi_regulator_info *regs, bool enable) |
| 341 | { |
| 342 | int rc = 0; |
| 343 | |
| 344 | if (enable) { |
| 345 | if (regs->refcount == 0) { |
| 346 | rc = dsi_pwr_enable_vregs(regs, true); |
| 347 | if (rc) |
| 348 | pr_err("failed to enable regulators\n"); |
| 349 | } |
| 350 | regs->refcount++; |
| 351 | } else { |
| 352 | if (regs->refcount == 0) { |
| 353 | pr_err("Unbalanced regulator off\n"); |
| 354 | } else { |
| 355 | regs->refcount--; |
| 356 | if (regs->refcount == 0) { |
| 357 | rc = dsi_pwr_enable_vregs(regs, false); |
| 358 | if (rc) |
| 359 | pr_err("failed to disable vregs\n"); |
| 360 | } |
| 361 | } |
| 362 | } |
| 363 | |
| 364 | return rc; |
| 365 | } |