1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2015 Samsung Electronics 4 * Przemyslaw Marczak <p.marczak@samsung.com> 5 */ 6 7#include <common.h> 8#include <fdtdec.h> 9#include <errno.h> 10#include <dm.h> 11#include <linux/printk.h> 12#include <power/pmic.h> 13#include <power/regulator.h> 14#include <power/sandbox_pmic.h> 15 16#define MODE(_id, _val, _name) [_id] = { \ 17 .id = _id, \ 18 .register_value = _val, \ 19 .name = _name, \ 20} 21 22#define RANGE(_min, _max, _step) { \ 23 .min = _min, \ 24 .max = _max, \ 25 .step = _step, \ 26} 27 28/* 29 * struct output_range - helper structure type to define the range of output 30 * operating values (current/voltage), limited by the PMIC IC design. 31 * 32 * @min - minimum value 33 * @max - maximum value 34 * @step - step value 35*/ 36struct output_range { 37 int min; 38 int max; 39 int step; 40}; 41 42/* BUCK: 1,2 - voltage range */ 43static struct output_range buck_voltage_range[] = { 44 RANGE(OUT_BUCK1_UV_MIN, OUT_BUCK1_UV_MAX, OUT_BUCK1_UV_STEP), 45 RANGE(OUT_BUCK2_UV_MIN, OUT_BUCK2_UV_MAX, OUT_BUCK2_UV_STEP), 46}; 47 48/* BUCK: 1 - current range */ 49static struct output_range buck_current_range[] = { 50 RANGE(OUT_BUCK1_UA_MIN, OUT_BUCK1_UA_MAX, OUT_BUCK1_UA_STEP), 51}; 52 53/* BUCK operating modes */ 54static struct dm_regulator_mode sandbox_buck_modes[] = { 55 MODE(BUCK_OM_OFF, OM2REG(BUCK_OM_OFF), "OFF"), 56 MODE(BUCK_OM_ON, OM2REG(BUCK_OM_ON), "ON"), 57 MODE(BUCK_OM_PWM, OM2REG(BUCK_OM_PWM), "PWM"), 58}; 59 60/* LDO: 1,2 - voltage range */ 61static struct output_range ldo_voltage_range[] = { 62 RANGE(OUT_LDO1_UV_MIN, OUT_LDO1_UV_MAX, OUT_LDO1_UV_STEP), 63 RANGE(OUT_LDO2_UV_MIN, OUT_LDO2_UV_MAX, OUT_LDO2_UV_STEP), 64}; 65 66/* LDO: 1 - current range */ 67static struct output_range ldo_current_range[] = { 68 RANGE(OUT_LDO1_UA_MIN, OUT_LDO1_UA_MAX, OUT_LDO1_UA_STEP), 69}; 70 71/* LDO operating modes */ 72static struct dm_regulator_mode sandbox_ldo_modes[] = { 73 MODE(LDO_OM_OFF, OM2REG(LDO_OM_OFF), "OFF"), 74 MODE(LDO_OM_ON, OM2REG(LDO_OM_ON), "ON"), 75 MODE(LDO_OM_SLEEP, OM2REG(LDO_OM_SLEEP), "SLEEP"), 76 MODE(LDO_OM_STANDBY, OM2REG(LDO_OM_STANDBY), "STANDBY"), 77}; 78 79int out_get_value(struct udevice *dev, int output_count, int reg_type, 80 struct output_range *range) 81{ 82 uint8_t reg_val; 83 uint reg; 84 int ret; 85 86 if (dev->driver_data > output_count) { 87 pr_err("Unknown regulator number: %lu for PMIC %s!", 88 dev->driver_data, dev->name); 89 return -EINVAL; 90 } 91 92 reg = (dev->driver_data - 1) * OUT_REG_COUNT + reg_type; 93 ret = pmic_read(dev->parent, reg, ®_val, 1); 94 if (ret) { 95 pr_err("PMIC read failed: %d\n", ret); 96 return ret; 97 } 98 99 ret = REG2VAL(range[dev->driver_data - 1].min, 100 range[dev->driver_data - 1].step, 101 reg_val); 102 103 return ret; 104} 105 106static int out_set_value(struct udevice *dev, int output_count, int reg_type, 107 struct output_range *range, int value) 108{ 109 uint8_t reg_val; 110 uint reg; 111 int ret; 112 int max_value; 113 114 if (dev->driver_data > output_count) { 115 pr_err("Unknown regulator number: %lu for PMIC %s!", 116 dev->driver_data, dev->name); 117 return -EINVAL; 118 } 119 120 max_value = range[dev->driver_data - 1].max; 121 if (value > max_value) { 122 pr_err("Wrong value for %s: %lu. Max is: %d.", 123 dev->name, dev->driver_data, max_value); 124 return -EINVAL; 125 } 126 127 reg_val = VAL2REG(range[dev->driver_data - 1].min, 128 range[dev->driver_data - 1].step, 129 value); 130 131 reg = (dev->driver_data - 1) * OUT_REG_COUNT + reg_type; 132 ret = pmic_write(dev->parent, reg, ®_val, 1); 133 if (ret) { 134 pr_err("PMIC write failed: %d\n", ret); 135 return ret; 136 } 137 138 return 0; 139} 140 141static int out_get_mode(struct udevice *dev) 142{ 143 struct dm_regulator_uclass_plat *uc_pdata; 144 uint8_t reg_val; 145 uint reg; 146 int ret; 147 int i; 148 149 uc_pdata = dev_get_uclass_plat(dev); 150 151 reg = (dev->driver_data - 1) * OUT_REG_COUNT + OUT_REG_OM; 152 ret = pmic_read(dev->parent, reg, ®_val, 1); 153 if (ret) { 154 pr_err("PMIC read failed: %d\n", ret); 155 return ret; 156 } 157 158 for (i = 0; i < uc_pdata->mode_count; i++) { 159 if (reg_val == uc_pdata->mode[i].register_value) 160 return uc_pdata->mode[i].id; 161 } 162 163 pr_err("Unknown operation mode for %s!", dev->name); 164 return -EINVAL; 165} 166 167static int out_set_mode(struct udevice *dev, int mode) 168{ 169 struct dm_regulator_uclass_plat *uc_pdata; 170 int reg_val = -1; 171 uint reg; 172 int ret; 173 int i; 174 175 uc_pdata = dev_get_uclass_plat(dev); 176 177 if (mode >= uc_pdata->mode_count) 178 return -EINVAL; 179 180 for (i = 0; i < uc_pdata->mode_count; i++) { 181 if (mode == uc_pdata->mode[i].id) { 182 reg_val = uc_pdata->mode[i].register_value; 183 break; 184 } 185 } 186 187 if (reg_val == -1) { 188 pr_err("Unknown operation mode for %s!", dev->name); 189 return -EINVAL; 190 } 191 192 reg = (dev->driver_data - 1) * OUT_REG_COUNT + OUT_REG_OM; 193 ret = pmic_write(dev->parent, reg, (uint8_t *)®_val, 1); 194 if (ret) { 195 pr_err("PMIC write failed: %d\n", ret); 196 return ret; 197 } 198 199 return 0; 200} 201 202static int buck_get_voltage(struct udevice *dev) 203{ 204 return out_get_value(dev, SANDBOX_BUCK_COUNT, OUT_REG_UV, 205 buck_voltage_range); 206} 207 208static int buck_set_voltage(struct udevice *dev, int uV) 209{ 210 return out_set_value(dev, SANDBOX_BUCK_COUNT, OUT_REG_UV, 211 buck_voltage_range, uV); 212} 213 214static int buck_get_current(struct udevice *dev) 215{ 216 /* BUCK2 - unsupported */ 217 if (dev->driver_data == 2) 218 return -ENOSYS; 219 220 return out_get_value(dev, SANDBOX_BUCK_COUNT, OUT_REG_UA, 221 buck_current_range); 222} 223 224static int buck_set_current(struct udevice *dev, int uA) 225{ 226 /* BUCK2 - unsupported */ 227 if (dev->driver_data == 2) 228 return -ENOSYS; 229 230 return out_set_value(dev, SANDBOX_BUCK_COUNT, OUT_REG_UA, 231 buck_current_range, uA); 232} 233 234static int buck_get_enable(struct udevice *dev) 235{ 236 if (out_get_mode(dev) == BUCK_OM_OFF) 237 return false; 238 239 return true; 240} 241 242static int buck_set_enable(struct udevice *dev, bool enable) 243{ 244 return out_set_mode(dev, enable ? BUCK_OM_ON : BUCK_OM_OFF); 245} 246 247static int sandbox_buck_probe(struct udevice *dev) 248{ 249 struct dm_regulator_uclass_plat *uc_pdata; 250 251 uc_pdata = dev_get_uclass_plat(dev); 252 253 uc_pdata->type = REGULATOR_TYPE_BUCK; 254 uc_pdata->mode = sandbox_buck_modes; 255 uc_pdata->mode_count = ARRAY_SIZE(sandbox_buck_modes); 256 257 return 0; 258} 259 260static const struct dm_regulator_ops sandbox_buck_ops = { 261 .get_value = buck_get_voltage, 262 .set_value = buck_set_voltage, 263 .get_current = buck_get_current, 264 .set_current = buck_set_current, 265 .get_enable = buck_get_enable, 266 .set_enable = buck_set_enable, 267 .get_mode = out_get_mode, 268 .set_mode = out_set_mode, 269}; 270 271U_BOOT_DRIVER(sandbox_buck) = { 272 .name = SANDBOX_BUCK_DRIVER, 273 .id = UCLASS_REGULATOR, 274 .ops = &sandbox_buck_ops, 275 .probe = sandbox_buck_probe, 276}; 277 278static int ldo_get_voltage(struct udevice *dev) 279{ 280 return out_get_value(dev, SANDBOX_LDO_COUNT, OUT_REG_UV, 281 ldo_voltage_range); 282} 283 284static int ldo_set_voltage(struct udevice *dev, int uV) 285{ 286 return out_set_value(dev, SANDBOX_LDO_COUNT, OUT_REG_UV, 287 ldo_voltage_range, uV); 288} 289 290static int ldo_get_current(struct udevice *dev) 291{ 292 /* LDO2 - unsupported */ 293 if (dev->driver_data == 2) 294 return -ENOSYS; 295 296 return out_get_value(dev, SANDBOX_LDO_COUNT, OUT_REG_UA, 297 ldo_current_range); 298} 299 300static int ldo_set_current(struct udevice *dev, int uA) 301{ 302 /* LDO2 - unsupported */ 303 if (dev->driver_data == 2) 304 return -ENOSYS; 305 306 return out_set_value(dev, SANDBOX_LDO_COUNT, OUT_REG_UA, 307 ldo_current_range, uA); 308} 309 310static int ldo_get_enable(struct udevice *dev) 311{ 312 if (out_get_mode(dev) == LDO_OM_OFF) 313 return false; 314 315 return true; 316} 317 318static int ldo_set_enable(struct udevice *dev, bool enable) 319{ 320 return out_set_mode(dev, enable ? LDO_OM_ON : LDO_OM_OFF); 321} 322 323static int sandbox_ldo_probe(struct udevice *dev) 324{ 325 struct dm_regulator_uclass_plat *uc_pdata; 326 327 uc_pdata = dev_get_uclass_plat(dev); 328 329 uc_pdata->type = REGULATOR_TYPE_LDO; 330 uc_pdata->mode = sandbox_ldo_modes; 331 uc_pdata->mode_count = ARRAY_SIZE(sandbox_ldo_modes); 332 333 return 0; 334} 335 336static const struct dm_regulator_ops sandbox_ldo_ops = { 337 .get_value = ldo_get_voltage, 338 .set_value = ldo_set_voltage, 339 .get_current = ldo_get_current, 340 .set_current = ldo_set_current, 341 .get_enable = ldo_get_enable, 342 .set_enable = ldo_set_enable, 343 .get_mode = out_get_mode, 344 .set_mode = out_set_mode, 345}; 346 347U_BOOT_DRIVER(sandbox_ldo) = { 348 .name = SANDBOX_LDO_DRIVER, 349 .id = UCLASS_REGULATOR, 350 .ops = &sandbox_ldo_ops, 351 .probe = sandbox_ldo_probe, 352}; 353