1 /* $OpenBSD: ofw_regulator.c,v 1.15 2020/12/23 11:58:36 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2016 Mark Kettenis 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/systm.h> 20 #include <sys/malloc.h> 21 22 #include <dev/ofw/openfirm.h> 23 #include <dev/ofw/ofw_gpio.h> 24 #include <dev/ofw/ofw_pinctrl.h> 25 #include <dev/ofw/ofw_regulator.h> 26 27 #define REGULATOR_VOLTAGE 0 28 #define REGULATOR_CURRENT 1 29 30 LIST_HEAD(, regulator_device) regulator_devices = 31 LIST_HEAD_INITIALIZER(regulator_devices); 32 33 int regulator_type(int); 34 uint32_t regulator_gpio_get(int); 35 int regulator_gpio_set(int, uint32_t); 36 37 void 38 regulator_register(struct regulator_device *rd) 39 { 40 rd->rd_volt_min = OF_getpropint(rd->rd_node, 41 "regulator-min-microvolt", 0); 42 rd->rd_volt_max = OF_getpropint(rd->rd_node, 43 "regulator-max-microvolt", ~0); 44 KASSERT(rd->rd_volt_min <= rd->rd_volt_max); 45 46 rd->rd_amp_min = OF_getpropint(rd->rd_node, 47 "regulator-min-microamp", 0); 48 rd->rd_amp_max = OF_getpropint(rd->rd_node, 49 "regulator-max-microamp", ~0); 50 KASSERT(rd->rd_amp_min <= rd->rd_amp_max); 51 52 rd->rd_ramp_delay = 53 OF_getpropint(rd->rd_node, "regulator-ramp-delay", 0); 54 55 if (rd->rd_get_voltage && rd->rd_set_voltage) { 56 uint32_t voltage = rd->rd_get_voltage(rd->rd_cookie); 57 if (voltage < rd->rd_volt_min) 58 rd->rd_set_voltage(rd->rd_cookie, rd->rd_volt_min); 59 if (voltage > rd->rd_volt_max) 60 rd->rd_set_voltage(rd->rd_cookie, rd->rd_volt_max); 61 } 62 63 if (rd->rd_get_current && rd->rd_set_current) { 64 uint32_t current = rd->rd_get_current(rd->rd_cookie); 65 if (current < rd->rd_amp_min) 66 rd->rd_set_current(rd->rd_cookie, rd->rd_amp_min); 67 if (current > rd->rd_amp_max) 68 rd->rd_set_current(rd->rd_cookie, rd->rd_amp_max); 69 } 70 71 rd->rd_phandle = OF_getpropint(rd->rd_node, "phandle", 0); 72 if (rd->rd_phandle == 0) 73 return; 74 75 LIST_INSERT_HEAD(®ulator_devices, rd, rd_list); 76 } 77 78 int 79 regulator_type(int node) 80 { 81 char type[16] = { 0 }; 82 83 OF_getprop(node, "regulator-type", type, sizeof(type)); 84 if (strcmp(type, "current") == 0) 85 return REGULATOR_CURRENT; 86 87 return REGULATOR_VOLTAGE; 88 } 89 90 int 91 regulator_fixed_set(int node, int enable) 92 { 93 uint32_t *gpio; 94 uint32_t startup_delay; 95 int len; 96 97 pinctrl_byname(node, "default"); 98 99 /* The "gpio" property is optional. */ 100 len = OF_getproplen(node, "gpio"); 101 if (len < 0) 102 return 0; 103 104 /* 105 * We deliberately ignore the "enable-active-high" property 106 * here. Its presence (or absence) is used to override the 107 * polarity encoded by the GPIO flags in the device tree. But 108 * supporting this behaviour is awkward since it would require 109 * interpreting the GPIO flags here which would be a layer 110 * violation since those flags may be driver-specific. In 111 * practice the presence of "enable-active-high" is always 112 * aligned with the polarity encoded by the GPIO flags and any 113 * discrepancy is considered to be a bug by the Linux device 114 * tree maintainers. 115 */ 116 117 gpio = malloc(len, M_TEMP, M_WAITOK); 118 OF_getpropintarray(node, "gpio", gpio, len); 119 gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT); 120 if (enable) 121 gpio_controller_set_pin(gpio, 1); 122 else 123 gpio_controller_set_pin(gpio, 0); 124 free(gpio, M_TEMP, len); 125 126 startup_delay = OF_getpropint(node, "startup-delay-us", 0); 127 if (enable && startup_delay > 0) 128 delay(startup_delay); 129 130 return 0; 131 } 132 133 int 134 regulator_set(uint32_t phandle, int enable) 135 { 136 struct regulator_device *rd; 137 int node; 138 139 if (phandle == 0) 140 return ENODEV; 141 142 node = OF_getnodebyphandle(phandle); 143 if (node == 0) 144 return ENODEV; 145 146 /* Never turn off regulators that should always be on. */ 147 if (OF_getproplen(node, "regulator-always-on") == 0 && !enable) 148 return 0; 149 150 LIST_FOREACH(rd, ®ulator_devices, rd_list) { 151 if (rd->rd_phandle == phandle) 152 break; 153 } 154 155 if (rd && rd->rd_enable) 156 return rd->rd_enable(rd->rd_cookie, enable); 157 158 if (OF_is_compatible(node, "regulator-fixed")) 159 return regulator_fixed_set(node, enable); 160 161 return ENODEV; 162 } 163 164 int 165 regulator_enable(uint32_t phandle) 166 { 167 return regulator_set(phandle, 1); 168 } 169 170 int 171 regulator_disable(uint32_t phandle) 172 { 173 return regulator_set(phandle, 0); 174 } 175 176 uint32_t 177 regulator_get_voltage(uint32_t phandle) 178 { 179 struct regulator_device *rd; 180 int node; 181 182 if (phandle == 0) 183 return 0; 184 185 LIST_FOREACH(rd, ®ulator_devices, rd_list) { 186 if (rd->rd_phandle == phandle) 187 break; 188 } 189 190 if (rd && rd->rd_get_voltage) 191 return rd->rd_get_voltage(rd->rd_cookie); 192 193 node = OF_getnodebyphandle(phandle); 194 if (node == 0) 195 return 0; 196 197 if (OF_is_compatible(node, "regulator-fixed")) 198 return OF_getpropint(node, "regulator-min-microvolt", 0); 199 200 if (OF_is_compatible(node, "regulator-gpio") && 201 regulator_type(node) == REGULATOR_VOLTAGE) 202 return regulator_gpio_get(node); 203 204 return 0; 205 } 206 207 int 208 regulator_set_voltage(uint32_t phandle, uint32_t voltage) 209 { 210 struct regulator_device *rd; 211 uint32_t old, delta; 212 int error, node; 213 214 if (phandle == 0) 215 return ENODEV; 216 217 LIST_FOREACH(rd, ®ulator_devices, rd_list) { 218 if (rd->rd_phandle == phandle) 219 break; 220 } 221 222 /* Check limits. */ 223 if (rd && (voltage < rd->rd_volt_min || voltage > rd->rd_volt_max)) 224 return EINVAL; 225 226 if (rd && rd->rd_set_voltage) { 227 old = rd->rd_get_voltage(rd->rd_cookie); 228 error = rd->rd_set_voltage(rd->rd_cookie, voltage); 229 if (voltage > old && rd->rd_ramp_delay > 0) { 230 delta = voltage - old; 231 delay(howmany(delta, rd->rd_ramp_delay)); 232 } 233 return error; 234 } 235 236 node = OF_getnodebyphandle(phandle); 237 if (node == 0) 238 return ENODEV; 239 240 if (OF_is_compatible(node, "regulator-fixed") && 241 OF_getpropint(node, "regulator-min-microvolt", 0) == voltage) 242 return 0; 243 244 if (OF_is_compatible(node, "regulator-gpio") && 245 regulator_type(node) == REGULATOR_VOLTAGE) 246 return regulator_gpio_set(node, voltage); 247 248 return ENODEV; 249 } 250 251 uint32_t 252 regulator_get_current(uint32_t phandle) 253 { 254 struct regulator_device *rd; 255 int node; 256 257 if (phandle == 0) 258 return 0; 259 260 LIST_FOREACH(rd, ®ulator_devices, rd_list) { 261 if (rd->rd_phandle == phandle) 262 break; 263 } 264 265 if (rd && rd->rd_get_current) 266 return rd->rd_get_current(rd->rd_cookie); 267 268 node = OF_getnodebyphandle(phandle); 269 if (node == 0) 270 return 0; 271 272 if (OF_is_compatible(node, "regulator-fixed")) 273 return OF_getpropint(node, "regulator-min-microamp", 0); 274 275 if (OF_is_compatible(node, "regulator-gpio") && 276 regulator_type(node) == REGULATOR_CURRENT) 277 return regulator_gpio_get(node); 278 279 return 0; 280 } 281 282 int 283 regulator_set_current(uint32_t phandle, uint32_t current) 284 { 285 struct regulator_device *rd; 286 uint32_t old, delta; 287 int error, node; 288 289 if (phandle == 0) 290 return ENODEV; 291 292 LIST_FOREACH(rd, ®ulator_devices, rd_list) { 293 if (rd->rd_phandle == phandle) 294 break; 295 } 296 297 /* Check limits. */ 298 if (rd && (current < rd->rd_amp_min || current > rd->rd_amp_max)) 299 return EINVAL; 300 301 if (rd && rd->rd_set_current) { 302 old = rd->rd_get_current(rd->rd_cookie); 303 error = rd->rd_set_current(rd->rd_cookie, current); 304 if (current > old && rd->rd_ramp_delay > 0) { 305 delta = current - old; 306 delay(howmany(delta, rd->rd_ramp_delay)); 307 } 308 return error; 309 } 310 311 node = OF_getnodebyphandle(phandle); 312 if (node == 0) 313 return ENODEV; 314 315 if (OF_is_compatible(node, "regulator-fixed") && 316 OF_getpropint(node, "regulator-min-microamp", 0) == current) 317 return 0; 318 319 if (OF_is_compatible(node, "regulator-gpio") && 320 regulator_type(node) == REGULATOR_CURRENT) 321 return regulator_gpio_set(node, current); 322 323 return ENODEV; 324 } 325 326 uint32_t 327 regulator_gpio_get(int node) 328 { 329 uint32_t *gpio, *gpios, *states; 330 uint32_t idx, value; 331 size_t glen, slen; 332 int i; 333 334 pinctrl_byname(node, "default"); 335 336 if ((glen = OF_getproplen(node, "gpios")) <= 0) 337 return EINVAL; 338 if ((slen = OF_getproplen(node, "states")) <= 0) 339 return EINVAL; 340 341 if (slen % (2 * sizeof(uint32_t)) != 0) 342 return EINVAL; 343 344 gpios = malloc(glen, M_TEMP, M_WAITOK); 345 states = malloc(slen, M_TEMP, M_WAITOK); 346 347 OF_getpropintarray(node, "gpios", gpios, glen); 348 OF_getpropintarray(node, "states", states, slen); 349 350 i = 0; 351 idx = 0; 352 gpio = gpios; 353 while (gpio && gpio < gpios + (glen / sizeof(uint32_t))) { 354 if (gpio_controller_get_pin(gpio)) 355 idx |= (1 << i); 356 gpio = gpio_controller_next_pin(gpio); 357 i++; 358 } 359 360 value = 0; 361 for (i = 0; i < slen / (2 * sizeof(uint32_t)); i++) { 362 if (states[2 * i + 1] == idx) { 363 value = states[2 * i]; 364 break; 365 } 366 } 367 if (i >= slen / (2 * sizeof(uint32_t))) 368 return 0; 369 370 free(gpios, M_TEMP, glen); 371 free(states, M_TEMP, slen); 372 373 return value; 374 } 375 376 int 377 regulator_gpio_set(int node, uint32_t value) 378 { 379 uint32_t *gpio, *gpios, *states; 380 size_t glen, slen; 381 uint32_t min, max; 382 uint32_t idx; 383 int i; 384 385 pinctrl_byname(node, "default"); 386 387 if (regulator_type(node) == REGULATOR_VOLTAGE) { 388 min = OF_getpropint(node, "regulator-min-microvolt", 0); 389 max = OF_getpropint(node, "regulator-max-microvolt", 0); 390 } 391 392 if (regulator_type(node) == REGULATOR_CURRENT) { 393 min = OF_getpropint(node, "regulator-min-microamp", 0); 394 max = OF_getpropint(node, "regulator-max-microamp", 0); 395 } 396 397 /* Check limits. */ 398 if (value < min || value > max) 399 return EINVAL; 400 401 if ((glen = OF_getproplen(node, "gpios")) <= 0) 402 return EINVAL; 403 if ((slen = OF_getproplen(node, "states")) <= 0) 404 return EINVAL; 405 406 if (slen % (2 * sizeof(uint32_t)) != 0) 407 return EINVAL; 408 409 gpios = malloc(glen, M_TEMP, M_WAITOK); 410 states = malloc(slen, M_TEMP, M_WAITOK); 411 412 OF_getpropintarray(node, "gpios", gpios, glen); 413 OF_getpropintarray(node, "states", states, slen); 414 415 idx = 0; 416 for (i = 0; i < slen / (2 * sizeof(uint32_t)); i++) { 417 if (states[2 * i] < min || states[2 * i] > max) 418 continue; 419 if (states[2 * i] == value) { 420 idx = states[2 * i + 1]; 421 break; 422 } 423 } 424 if (i >= slen / (2 * sizeof(uint32_t))) 425 return EINVAL; 426 427 i = 0; 428 gpio = gpios; 429 while (gpio && gpio < gpios + (glen / sizeof(uint32_t))) { 430 gpio_controller_set_pin(gpio, !!(idx & (1 << i))); 431 gpio = gpio_controller_next_pin(gpio); 432 i++; 433 } 434 435 free(gpios, M_TEMP, glen); 436 free(states, M_TEMP, slen); 437 438 return 0; 439 } 440