ofw_regulator.c revision 1.4
1/* $OpenBSD: ofw_regulator.c,v 1.4 2017/12/18 09:13:47 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 27LIST_HEAD(, regulator_device) regulator_devices = 28 LIST_HEAD_INITIALIZER(regulator_devices); 29 30void 31regulator_register(struct regulator_device *rd) 32{ 33 rd->rd_min = OF_getpropint(rd->rd_node, "regulator-min-microvolt", 0); 34 rd->rd_max = OF_getpropint(rd->rd_node, "regulator-max-microvolt", ~0); 35 KASSERT(rd->rd_min <= rd->rd_max); 36 37 if (rd->rd_get_voltage && rd->rd_set_voltage) { 38 uint32_t voltage = rd->rd_get_voltage(rd->rd_cookie); 39 if (voltage < rd->rd_min) 40 rd->rd_set_voltage(rd->rd_cookie, rd->rd_min); 41 if (voltage > rd->rd_max) 42 rd->rd_set_voltage(rd->rd_cookie, rd->rd_max); 43 } 44 45 rd->rd_phandle = OF_getpropint(rd->rd_node, "phandle", 0); 46 if (rd->rd_phandle == 0) 47 return; 48 49 LIST_INSERT_HEAD(®ulator_devices, rd, rd_list); 50} 51 52int 53regulator_fixed_set(int node, int enable) 54{ 55 uint32_t *gpio; 56 uint32_t startup_delay; 57 int active; 58 int len; 59 60 pinctrl_byname(node, "default"); 61 62 if (OF_getproplen(node, "enable-active-high") == 0) 63 active = 1; 64 else 65 active = 0; 66 67 /* The "gpio" property is optional. */ 68 len = OF_getproplen(node, "gpio"); 69 if (len < 0) 70 return 0; 71 72 gpio = malloc(len, M_TEMP, M_WAITOK); 73 OF_getpropintarray(node, "gpio", gpio, len); 74 gpio_controller_config_pin(gpio, GPIO_CONFIG_OUTPUT); 75 if (enable) 76 gpio_controller_set_pin(gpio, active); 77 else 78 gpio_controller_set_pin(gpio, !active); 79 free(gpio, M_TEMP, len); 80 81 startup_delay = OF_getpropint(node, "startup-delay-us", 0); 82 if (enable && startup_delay > 0) 83 delay(startup_delay); 84 85 return 0; 86} 87 88int 89regulator_set(uint32_t phandle, int enable) 90{ 91 struct regulator_device *rd; 92 int node; 93 94 node = OF_getnodebyphandle(phandle); 95 if (node == 0) 96 return ENODEV; 97 98 /* Don't mess around with regulators that are always on. */ 99 if (OF_getproplen(node, "regulator-always-on") == 0) 100 return 0; 101 102 LIST_FOREACH(rd, ®ulator_devices, rd_list) { 103 if (rd->rd_phandle == phandle) 104 break; 105 } 106 107 if (rd && rd->rd_enable) 108 return rd->rd_enable(rd->rd_cookie, enable); 109 110 if (OF_is_compatible(node, "regulator-fixed")) 111 return regulator_fixed_set(node, enable); 112 113 return ENODEV; 114} 115 116int 117regulator_enable(uint32_t phandle) 118{ 119 return regulator_set(phandle, 1); 120} 121 122int 123regulator_disable(uint32_t phandle) 124{ 125 return regulator_set(phandle, 0); 126} 127 128uint32_t 129regulator_get_voltage(uint32_t phandle) 130{ 131 struct regulator_device *rd; 132 int node; 133 134 LIST_FOREACH(rd, ®ulator_devices, rd_list) { 135 if (rd->rd_phandle == phandle) 136 break; 137 } 138 139 if (rd && rd->rd_get_voltage) 140 return rd->rd_get_voltage(rd->rd_cookie); 141 142 node = OF_getnodebyphandle(phandle); 143 if (node == 0) 144 return 0; 145 146 if (OF_is_compatible(node, "regulator-fixed")) 147 return OF_getpropint(node, "regulator-min-voltage", 0); 148 149 return 0; 150} 151 152int 153regulator_set_voltage(uint32_t phandle, uint32_t voltage) 154{ 155 struct regulator_device *rd; 156 157 LIST_FOREACH(rd, ®ulator_devices, rd_list) { 158 if (rd->rd_phandle == phandle) 159 break; 160 } 161 162 /* Check limits. */ 163 if (rd && (voltage < rd->rd_min || voltage > rd->rd_max)) 164 return EINVAL; 165 166 if (rd && rd->rd_set_voltage) 167 return rd->rd_set_voltage(rd->rd_cookie, voltage); 168 169 return ENODEV; 170} 171