1e9034789SMichal Meloun /*- 2e9034789SMichal Meloun * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3e9034789SMichal Meloun * 4e9034789SMichal Meloun * Copyright 2020 Michal Meloun <mmel@FreeBSD.org> 5e9034789SMichal Meloun * 6e9034789SMichal Meloun * Redistribution and use in source and binary forms, with or without 7e9034789SMichal Meloun * modification, are permitted provided that the following conditions 8e9034789SMichal Meloun * are met: 9e9034789SMichal Meloun * 1. Redistributions of source code must retain the above copyright 10e9034789SMichal Meloun * notice, this list of conditions and the following disclaimer. 11e9034789SMichal Meloun * 2. Redistributions in binary form must reproduce the above copyright 12e9034789SMichal Meloun * notice, this list of conditions and the following disclaimer in the 13e9034789SMichal Meloun * documentation and/or other materials provided with the distribution. 14e9034789SMichal Meloun * 15e9034789SMichal Meloun * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16e9034789SMichal Meloun * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17e9034789SMichal Meloun * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18e9034789SMichal Meloun * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19e9034789SMichal Meloun * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20e9034789SMichal Meloun * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21e9034789SMichal Meloun * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22e9034789SMichal Meloun * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23e9034789SMichal Meloun * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24e9034789SMichal Meloun * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25e9034789SMichal Meloun * SUCH DAMAGE. 26e9034789SMichal Meloun */ 27e9034789SMichal Meloun 28e9034789SMichal Meloun #include <sys/cdefs.h> 29e9034789SMichal Meloun __FBSDID("$FreeBSD$"); 30e9034789SMichal Meloun 31e9034789SMichal Meloun #include <sys/param.h> 32e9034789SMichal Meloun #include <sys/systm.h> 33e9034789SMichal Meloun #include <sys/bus.h> 34e9034789SMichal Meloun #include <sys/gpio.h> 35e9034789SMichal Meloun #include <sys/kernel.h> 36e9034789SMichal Meloun #include <sys/module.h> 37e9034789SMichal Meloun #include <sys/malloc.h> 38e9034789SMichal Meloun #include <sys/rman.h> 39e9034789SMichal Meloun #include <sys/sx.h> 40e9034789SMichal Meloun 41e9034789SMichal Meloun #include <machine/bus.h> 42e9034789SMichal Meloun 43e9034789SMichal Meloun #include <dev/extres/regulator/regulator.h> 44e9034789SMichal Meloun #include <dev/gpio/gpiobusvar.h> 45e9034789SMichal Meloun 46e9034789SMichal Meloun #include <gnu/dts/include/dt-bindings/mfd/max77620.h> 47e9034789SMichal Meloun 48e9034789SMichal Meloun #include "max77620.h" 49e9034789SMichal Meloun 50e9034789SMichal Meloun MALLOC_DEFINE(M_MAX77620_REG, "MAX77620 regulator", "MAX77620 power regulator"); 51e9034789SMichal Meloun 52e9034789SMichal Meloun #define DIV_ROUND_UP(n,d) howmany(n, d) 53e9034789SMichal Meloun 54e9034789SMichal Meloun enum max77620_reg_id { 55e9034789SMichal Meloun MAX77620_REG_ID_SD0, 56e9034789SMichal Meloun MAX77620_REG_ID_SD1, 57e9034789SMichal Meloun MAX77620_REG_ID_SD2, 58e9034789SMichal Meloun MAX77620_REG_ID_SD3, 59e9034789SMichal Meloun MAX77620_REG_ID_LDO0, 60e9034789SMichal Meloun MAX77620_REG_ID_LDO1, 61e9034789SMichal Meloun MAX77620_REG_ID_LDO2, 62e9034789SMichal Meloun MAX77620_REG_ID_LDO3, 63e9034789SMichal Meloun MAX77620_REG_ID_LDO4, 64e9034789SMichal Meloun MAX77620_REG_ID_LDO5, 65e9034789SMichal Meloun MAX77620_REG_ID_LDO6, 66e9034789SMichal Meloun MAX77620_REG_ID_LDO7, 67e9034789SMichal Meloun MAX77620_REG_ID_LDO8, 68e9034789SMichal Meloun }; 69e9034789SMichal Meloun 70e9034789SMichal Meloun /* Initial configuration. */ 71e9034789SMichal Meloun struct max77620_regnode_init_def { 72e9034789SMichal Meloun struct regnode_init_def reg_init_def; 73e9034789SMichal Meloun int active_fps_src; 74e9034789SMichal Meloun int active_fps_pu_slot; 75e9034789SMichal Meloun int active_fps_pd_slot; 76e9034789SMichal Meloun int suspend_fps_src; 77e9034789SMichal Meloun int suspend_fps_pu_slot; 78e9034789SMichal Meloun int suspend_fps_pd_slot; 79e9034789SMichal Meloun int ramp_rate_setting; 80e9034789SMichal Meloun }; 81e9034789SMichal Meloun 82e9034789SMichal Meloun /* Regulator HW definition. */ 83e9034789SMichal Meloun struct reg_def { 84e9034789SMichal Meloun intptr_t id; /* ID */ 85e9034789SMichal Meloun char *name; /* Regulator name */ 86e9034789SMichal Meloun char *supply_name; /* Source property name */ 87e9034789SMichal Meloun bool is_sd_reg; /* SD or LDO regulator? */ 88e9034789SMichal Meloun uint8_t volt_reg; 89e9034789SMichal Meloun uint8_t volt_vsel_mask; 90e9034789SMichal Meloun uint8_t cfg_reg; 91e9034789SMichal Meloun uint8_t fps_reg; 92e9034789SMichal Meloun uint8_t pwr_mode_reg; 93e9034789SMichal Meloun uint8_t pwr_mode_mask; 94e9034789SMichal Meloun uint8_t pwr_mode_shift; 95e9034789SMichal Meloun struct regulator_range *ranges; 96e9034789SMichal Meloun int nranges; 97e9034789SMichal Meloun }; 98e9034789SMichal Meloun 99e9034789SMichal Meloun struct max77620_reg_sc { 100e9034789SMichal Meloun struct regnode *regnode; 101e9034789SMichal Meloun struct max77620_softc *base_sc; 102e9034789SMichal Meloun struct reg_def *def; 103e9034789SMichal Meloun phandle_t xref; 104e9034789SMichal Meloun 105e9034789SMichal Meloun struct regnode_std_param *param; 106e9034789SMichal Meloun /* Configured values */ 107e9034789SMichal Meloun int active_fps_src; 108e9034789SMichal Meloun int active_fps_pu_slot; 109e9034789SMichal Meloun int active_fps_pd_slot; 110e9034789SMichal Meloun int suspend_fps_src; 111e9034789SMichal Meloun int suspend_fps_pu_slot; 112e9034789SMichal Meloun int suspend_fps_pd_slot; 113e9034789SMichal Meloun int ramp_rate_setting; 114e9034789SMichal Meloun int enable_usec; 115e9034789SMichal Meloun uint8_t enable_pwr_mode; 116e9034789SMichal Meloun 117e9034789SMichal Meloun /* Cached values */ 118e9034789SMichal Meloun uint8_t fps_src; 119e9034789SMichal Meloun uint8_t pwr_mode; 120e9034789SMichal Meloun int pwr_ramp_delay; 121e9034789SMichal Meloun }; 122e9034789SMichal Meloun 123e9034789SMichal Meloun static struct regulator_range max77620_sd0_ranges[] = { 124e9034789SMichal Meloun REG_RANGE_INIT(0, 64, 600000, 12500), /* 0.6V - 1.4V / 12.5mV */ 125e9034789SMichal Meloun }; 126e9034789SMichal Meloun 127e9034789SMichal Meloun static struct regulator_range max77620_sd1_ranges[] = { 128e9034789SMichal Meloun REG_RANGE_INIT(0, 76, 600000, 12500), /* 0.6V - 1.55V / 12.5mV */ 129e9034789SMichal Meloun }; 130e9034789SMichal Meloun 131e9034789SMichal Meloun static struct regulator_range max77620_sdx_ranges[] = { 132e9034789SMichal Meloun REG_RANGE_INIT(0, 255, 600000, 12500), /* 0.6V - 3.7875V / 12.5mV */ 133e9034789SMichal Meloun }; 134e9034789SMichal Meloun 135e9034789SMichal Meloun static struct regulator_range max77620_ldo0_1_ranges[] = { 136e9034789SMichal Meloun REG_RANGE_INIT(0, 63, 800000, 25000), /* 0.8V - 2.375V / 25mV */ 137e9034789SMichal Meloun }; 138e9034789SMichal Meloun 139e9034789SMichal Meloun static struct regulator_range max77620_ldo4_ranges[] = { 140e9034789SMichal Meloun REG_RANGE_INIT(0, 63, 800000, 12500), /* 0.8V - 1.5875V / 12.5mV */ 141e9034789SMichal Meloun }; 142e9034789SMichal Meloun 143e9034789SMichal Meloun static struct regulator_range max77620_ldox_ranges[] = { 144e9034789SMichal Meloun REG_RANGE_INIT(0, 63, 800000, 50000), /* 0.8V - 3.95V / 50mV */ 145e9034789SMichal Meloun }; 146e9034789SMichal Meloun 147e9034789SMichal Meloun static struct reg_def max77620s_def[] = { 148e9034789SMichal Meloun { 149e9034789SMichal Meloun .id = MAX77620_REG_ID_SD0, 150e9034789SMichal Meloun .name = "sd0", 151e9034789SMichal Meloun .supply_name = "in-sd0", 152e9034789SMichal Meloun .is_sd_reg = true, 153e9034789SMichal Meloun .volt_reg = MAX77620_REG_SD0, 154e9034789SMichal Meloun .volt_vsel_mask = MAX77620_SD0_VSEL_MASK, 155e9034789SMichal Meloun .cfg_reg = MAX77620_REG_CFG_SD0, 156e9034789SMichal Meloun .fps_reg = MAX77620_REG_FPS_SD0, 157e9034789SMichal Meloun .pwr_mode_reg = MAX77620_REG_CFG_SD0, 158e9034789SMichal Meloun .pwr_mode_mask = MAX77620_SD_POWER_MODE_MASK, 159e9034789SMichal Meloun .pwr_mode_shift = MAX77620_SD_POWER_MODE_SHIFT, 160e9034789SMichal Meloun .ranges = max77620_sd0_ranges, 161e9034789SMichal Meloun .nranges = nitems(max77620_sd0_ranges), 162e9034789SMichal Meloun }, 163e9034789SMichal Meloun { 164e9034789SMichal Meloun .id = MAX77620_REG_ID_SD1, 165e9034789SMichal Meloun .name = "sd1", 166e9034789SMichal Meloun .supply_name = "in-sd1", 167e9034789SMichal Meloun .is_sd_reg = true, 168e9034789SMichal Meloun .volt_reg = MAX77620_REG_SD1, 169e9034789SMichal Meloun .volt_vsel_mask = MAX77620_SD1_VSEL_MASK, 170e9034789SMichal Meloun .cfg_reg = MAX77620_REG_CFG_SD1, 171e9034789SMichal Meloun .fps_reg = MAX77620_REG_FPS_SD1, 172e9034789SMichal Meloun .pwr_mode_reg = MAX77620_REG_CFG_SD1, 173e9034789SMichal Meloun .pwr_mode_mask = MAX77620_SD_POWER_MODE_MASK, 174e9034789SMichal Meloun .pwr_mode_shift = MAX77620_SD_POWER_MODE_SHIFT, 175e9034789SMichal Meloun .ranges = max77620_sd1_ranges, 176e9034789SMichal Meloun .nranges = nitems(max77620_sd1_ranges), 177e9034789SMichal Meloun }, 178e9034789SMichal Meloun { 179e9034789SMichal Meloun .id = MAX77620_REG_ID_SD2, 180e9034789SMichal Meloun .name = "sd2", 181e9034789SMichal Meloun .supply_name = "in-sd2", 182e9034789SMichal Meloun .is_sd_reg = true, 183e9034789SMichal Meloun .volt_reg = MAX77620_REG_SD2, 184e9034789SMichal Meloun .volt_vsel_mask = MAX77620_SDX_VSEL_MASK, 185e9034789SMichal Meloun .cfg_reg = MAX77620_REG_CFG_SD2, 186e9034789SMichal Meloun .fps_reg = MAX77620_REG_FPS_SD2, 187e9034789SMichal Meloun .pwr_mode_reg = MAX77620_REG_CFG_SD2, 188e9034789SMichal Meloun .pwr_mode_mask = MAX77620_SD_POWER_MODE_MASK, 189e9034789SMichal Meloun .pwr_mode_shift = MAX77620_SD_POWER_MODE_SHIFT, 190e9034789SMichal Meloun .ranges = max77620_sdx_ranges, 191e9034789SMichal Meloun .nranges = nitems(max77620_sdx_ranges), 192e9034789SMichal Meloun }, 193e9034789SMichal Meloun { 194e9034789SMichal Meloun .id = MAX77620_REG_ID_SD3, 195e9034789SMichal Meloun .name = "sd3", 196e9034789SMichal Meloun .supply_name = "in-sd3", 197e9034789SMichal Meloun .is_sd_reg = true, 198e9034789SMichal Meloun .volt_reg = MAX77620_REG_SD3, 199e9034789SMichal Meloun .volt_vsel_mask = MAX77620_SDX_VSEL_MASK, 200e9034789SMichal Meloun .cfg_reg = MAX77620_REG_CFG_SD3, 201e9034789SMichal Meloun .fps_reg = MAX77620_REG_FPS_SD3, 202e9034789SMichal Meloun .pwr_mode_reg = MAX77620_REG_CFG_SD3, 203e9034789SMichal Meloun .pwr_mode_mask = MAX77620_SD_POWER_MODE_MASK, 204e9034789SMichal Meloun .pwr_mode_shift = MAX77620_SD_POWER_MODE_SHIFT, 205e9034789SMichal Meloun .ranges = max77620_sdx_ranges, 206e9034789SMichal Meloun .nranges = nitems(max77620_sdx_ranges), 207e9034789SMichal Meloun }, 208e9034789SMichal Meloun { 209e9034789SMichal Meloun .id = MAX77620_REG_ID_LDO0, 210e9034789SMichal Meloun .name = "ldo0", 211e9034789SMichal Meloun .supply_name = "vin-ldo0-1", 212e9034789SMichal Meloun .volt_reg = MAX77620_REG_CFG_LDO0, 213e9034789SMichal Meloun .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, 214e9034789SMichal Meloun .is_sd_reg = false, 215e9034789SMichal Meloun .cfg_reg = MAX77620_REG_CFG2_LDO0, 216e9034789SMichal Meloun .fps_reg = MAX77620_REG_FPS_LDO0, 217e9034789SMichal Meloun .pwr_mode_reg = MAX77620_REG_CFG_LDO0, 218e9034789SMichal Meloun .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, 219e9034789SMichal Meloun .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, 220e9034789SMichal Meloun .ranges = max77620_ldo0_1_ranges, 221e9034789SMichal Meloun .nranges = nitems(max77620_ldo0_1_ranges), 222e9034789SMichal Meloun }, 223e9034789SMichal Meloun { 224e9034789SMichal Meloun .id = MAX77620_REG_ID_LDO1, 225e9034789SMichal Meloun .name = "ldo1", 226e9034789SMichal Meloun .supply_name = "in-ldo0-1", 227e9034789SMichal Meloun .is_sd_reg = false, 228e9034789SMichal Meloun .volt_reg = MAX77620_REG_CFG_LDO1, 229e9034789SMichal Meloun .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, 230e9034789SMichal Meloun .cfg_reg = MAX77620_REG_CFG2_LDO1, 231e9034789SMichal Meloun .fps_reg = MAX77620_REG_FPS_LDO1, 232e9034789SMichal Meloun .pwr_mode_reg = MAX77620_REG_CFG_LDO1, 233e9034789SMichal Meloun .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, 234e9034789SMichal Meloun .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, 235e9034789SMichal Meloun .ranges = max77620_ldo0_1_ranges, 236e9034789SMichal Meloun .nranges = nitems(max77620_ldo0_1_ranges), 237e9034789SMichal Meloun }, 238e9034789SMichal Meloun { 239e9034789SMichal Meloun .id = MAX77620_REG_ID_LDO2, 240e9034789SMichal Meloun .name = "ldo2", 241e9034789SMichal Meloun .supply_name = "in-ldo2", 242e9034789SMichal Meloun .is_sd_reg = false, 243e9034789SMichal Meloun .volt_reg = MAX77620_REG_CFG_LDO2, 244e9034789SMichal Meloun .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, 245e9034789SMichal Meloun .cfg_reg = MAX77620_REG_CFG2_LDO2, 246e9034789SMichal Meloun .fps_reg = MAX77620_REG_FPS_LDO2, 247e9034789SMichal Meloun .pwr_mode_reg = MAX77620_REG_CFG_LDO2, 248e9034789SMichal Meloun .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, 249e9034789SMichal Meloun .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, 250e9034789SMichal Meloun .ranges = max77620_ldox_ranges, 251e9034789SMichal Meloun .nranges = nitems(max77620_ldox_ranges), 252e9034789SMichal Meloun }, 253e9034789SMichal Meloun { 254e9034789SMichal Meloun .id = MAX77620_REG_ID_LDO3, 255e9034789SMichal Meloun .name = "ldo3", 256e9034789SMichal Meloun .supply_name = "in-ldo3-5", 257e9034789SMichal Meloun .is_sd_reg = false, 258e9034789SMichal Meloun .volt_reg = MAX77620_REG_CFG_LDO3, 259e9034789SMichal Meloun .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, 260e9034789SMichal Meloun .cfg_reg = MAX77620_REG_CFG2_LDO3, 261e9034789SMichal Meloun .fps_reg = MAX77620_REG_FPS_LDO3, 262e9034789SMichal Meloun .pwr_mode_reg = MAX77620_REG_CFG_LDO3, 263e9034789SMichal Meloun .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, 264e9034789SMichal Meloun .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, 265e9034789SMichal Meloun .ranges = max77620_ldox_ranges, 266e9034789SMichal Meloun .nranges = nitems(max77620_ldox_ranges), 267e9034789SMichal Meloun }, 268e9034789SMichal Meloun { 269e9034789SMichal Meloun .id = MAX77620_REG_ID_LDO4, 270e9034789SMichal Meloun .name = "ldo4", 271e9034789SMichal Meloun .supply_name = "in-ldo4-6", 272e9034789SMichal Meloun .is_sd_reg = false, 273e9034789SMichal Meloun .volt_reg = MAX77620_REG_CFG_LDO4, 274e9034789SMichal Meloun .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, 275e9034789SMichal Meloun .cfg_reg = MAX77620_REG_CFG2_LDO4, 276e9034789SMichal Meloun .fps_reg = MAX77620_REG_FPS_LDO4, 277e9034789SMichal Meloun .pwr_mode_reg = MAX77620_REG_CFG_LDO4, 278e9034789SMichal Meloun .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, 279e9034789SMichal Meloun .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, 280e9034789SMichal Meloun .ranges = max77620_ldo4_ranges, 281e9034789SMichal Meloun .nranges = nitems(max77620_ldo4_ranges), 282e9034789SMichal Meloun }, 283e9034789SMichal Meloun { 284e9034789SMichal Meloun .id = MAX77620_REG_ID_LDO5, 285e9034789SMichal Meloun .name = "ldo5", 286e9034789SMichal Meloun .supply_name = "in-ldo3-5", 287e9034789SMichal Meloun .is_sd_reg = false, 288e9034789SMichal Meloun .volt_reg = MAX77620_REG_CFG_LDO5, 289e9034789SMichal Meloun .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, 290e9034789SMichal Meloun .cfg_reg = MAX77620_REG_CFG2_LDO5, 291e9034789SMichal Meloun .fps_reg = MAX77620_REG_FPS_LDO5, 292e9034789SMichal Meloun .pwr_mode_reg = MAX77620_REG_CFG_LDO5, 293e9034789SMichal Meloun .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, 294e9034789SMichal Meloun .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, 295e9034789SMichal Meloun .ranges = max77620_ldox_ranges, 296e9034789SMichal Meloun .nranges = nitems(max77620_ldox_ranges), 297e9034789SMichal Meloun }, 298e9034789SMichal Meloun { 299e9034789SMichal Meloun .id = MAX77620_REG_ID_LDO6, 300e9034789SMichal Meloun .name = "ldo6", 301e9034789SMichal Meloun .supply_name = "in-ldo4-6", 302e9034789SMichal Meloun .is_sd_reg = false, 303e9034789SMichal Meloun .volt_reg = MAX77620_REG_CFG_LDO6, 304e9034789SMichal Meloun .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, 305e9034789SMichal Meloun .cfg_reg = MAX77620_REG_CFG2_LDO6, 306e9034789SMichal Meloun .fps_reg = MAX77620_REG_FPS_LDO6, 307e9034789SMichal Meloun .pwr_mode_reg = MAX77620_REG_CFG_LDO6, 308e9034789SMichal Meloun .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, 309e9034789SMichal Meloun .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, 310e9034789SMichal Meloun .ranges = max77620_ldox_ranges, 311e9034789SMichal Meloun .nranges = nitems(max77620_ldox_ranges), 312e9034789SMichal Meloun }, 313e9034789SMichal Meloun { 314e9034789SMichal Meloun .id = MAX77620_REG_ID_LDO7, 315e9034789SMichal Meloun .name = "ldo7", 316e9034789SMichal Meloun .supply_name = "in-ldo7-8", 317e9034789SMichal Meloun .is_sd_reg = false, 318e9034789SMichal Meloun .volt_reg = MAX77620_REG_CFG_LDO7, 319e9034789SMichal Meloun .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, 320e9034789SMichal Meloun .cfg_reg = MAX77620_REG_CFG2_LDO7, 321e9034789SMichal Meloun .fps_reg = MAX77620_REG_FPS_LDO7, 322e9034789SMichal Meloun .pwr_mode_reg = MAX77620_REG_CFG_LDO7, 323e9034789SMichal Meloun .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, 324e9034789SMichal Meloun .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, 325e9034789SMichal Meloun .ranges = max77620_ldox_ranges, 326e9034789SMichal Meloun .nranges = nitems(max77620_ldox_ranges), 327e9034789SMichal Meloun }, 328e9034789SMichal Meloun { 329e9034789SMichal Meloun .id = MAX77620_REG_ID_LDO8, 330e9034789SMichal Meloun .name = "ldo8", 331e9034789SMichal Meloun .supply_name = "in-ldo7-8", 332e9034789SMichal Meloun .is_sd_reg = false, 333e9034789SMichal Meloun .volt_reg = MAX77620_REG_CFG_LDO8, 334e9034789SMichal Meloun .volt_vsel_mask = MAX77620_LDO_VSEL_MASK, 335e9034789SMichal Meloun .cfg_reg = MAX77620_REG_CFG2_LDO8, 336e9034789SMichal Meloun .fps_reg = MAX77620_REG_FPS_LDO8, 337e9034789SMichal Meloun .pwr_mode_reg = MAX77620_REG_CFG_LDO8, 338e9034789SMichal Meloun .pwr_mode_mask = MAX77620_LDO_POWER_MODE_MASK, 339e9034789SMichal Meloun .pwr_mode_shift = MAX77620_LDO_POWER_MODE_SHIFT, 340e9034789SMichal Meloun .ranges = max77620_ldox_ranges, 341e9034789SMichal Meloun .nranges = nitems(max77620_ldox_ranges), 342e9034789SMichal Meloun }, 343e9034789SMichal Meloun }; 344e9034789SMichal Meloun 345e9034789SMichal Meloun 346e9034789SMichal Meloun static int max77620_regnode_init(struct regnode *regnode); 347e9034789SMichal Meloun static int max77620_regnode_enable(struct regnode *regnode, bool enable, 348e9034789SMichal Meloun int *udelay); 349e9034789SMichal Meloun static int max77620_regnode_set_volt(struct regnode *regnode, int min_uvolt, 350e9034789SMichal Meloun int max_uvolt, int *udelay); 351e9034789SMichal Meloun static int max77620_regnode_get_volt(struct regnode *regnode, int *uvolt); 352e9034789SMichal Meloun static regnode_method_t max77620_regnode_methods[] = { 353e9034789SMichal Meloun /* Regulator interface */ 354e9034789SMichal Meloun REGNODEMETHOD(regnode_init, max77620_regnode_init), 355e9034789SMichal Meloun REGNODEMETHOD(regnode_enable, max77620_regnode_enable), 356e9034789SMichal Meloun REGNODEMETHOD(regnode_set_voltage, max77620_regnode_set_volt), 357e9034789SMichal Meloun REGNODEMETHOD(regnode_get_voltage, max77620_regnode_get_volt), 358e9034789SMichal Meloun REGNODEMETHOD_END 359e9034789SMichal Meloun }; 360e9034789SMichal Meloun DEFINE_CLASS_1(max77620_regnode, max77620_regnode_class, max77620_regnode_methods, 361e9034789SMichal Meloun sizeof(struct max77620_reg_sc), regnode_class); 362e9034789SMichal Meloun 363e9034789SMichal Meloun static int 364e9034789SMichal Meloun max77620_get_sel(struct max77620_reg_sc *sc, uint8_t *sel) 365e9034789SMichal Meloun { 366e9034789SMichal Meloun int rv; 367e9034789SMichal Meloun 368e9034789SMichal Meloun rv = RD1(sc->base_sc, sc->def->volt_reg, sel); 369e9034789SMichal Meloun if (rv != 0) { 370e9034789SMichal Meloun printf("%s: cannot read volatge selector: %d\n", 371e9034789SMichal Meloun regnode_get_name(sc->regnode), rv); 372e9034789SMichal Meloun return (rv); 373e9034789SMichal Meloun } 374e9034789SMichal Meloun *sel &= sc->def->volt_vsel_mask; 375e9034789SMichal Meloun *sel >>= ffs(sc->def->volt_vsel_mask) - 1; 376e9034789SMichal Meloun return (0); 377e9034789SMichal Meloun } 378e9034789SMichal Meloun 379e9034789SMichal Meloun static int 380e9034789SMichal Meloun max77620_set_sel(struct max77620_reg_sc *sc, uint8_t sel) 381e9034789SMichal Meloun { 382e9034789SMichal Meloun int rv; 383e9034789SMichal Meloun 384e9034789SMichal Meloun sel <<= ffs(sc->def->volt_vsel_mask) - 1; 385e9034789SMichal Meloun sel &= sc->def->volt_vsel_mask; 386e9034789SMichal Meloun 387e9034789SMichal Meloun rv = RM1(sc->base_sc, sc->def->volt_reg, 388e9034789SMichal Meloun sc->def->volt_vsel_mask, sel); 389e9034789SMichal Meloun if (rv != 0) { 390e9034789SMichal Meloun printf("%s: cannot set volatge selector: %d\n", 391e9034789SMichal Meloun regnode_get_name(sc->regnode), rv); 392e9034789SMichal Meloun return (rv); 393e9034789SMichal Meloun } 394e9034789SMichal Meloun return (rv); 395e9034789SMichal Meloun } 396e9034789SMichal Meloun 397e9034789SMichal Meloun static int 398e9034789SMichal Meloun max77620_get_fps_src(struct max77620_reg_sc *sc, uint8_t *fps_src) 399e9034789SMichal Meloun { 400e9034789SMichal Meloun uint8_t val; 401e9034789SMichal Meloun int rv; 402e9034789SMichal Meloun 403e9034789SMichal Meloun rv = RD1(sc->base_sc, sc->def->fps_reg, &val); 404e9034789SMichal Meloun if (rv != 0) 405e9034789SMichal Meloun return (rv); 406e9034789SMichal Meloun 407e9034789SMichal Meloun *fps_src = (val & MAX77620_FPS_SRC_MASK) >> MAX77620_FPS_SRC_SHIFT; 408e9034789SMichal Meloun return (0); 409e9034789SMichal Meloun } 410e9034789SMichal Meloun 411e9034789SMichal Meloun static int 412e9034789SMichal Meloun max77620_set_fps_src(struct max77620_reg_sc *sc, uint8_t fps_src) 413e9034789SMichal Meloun { 414e9034789SMichal Meloun int rv; 415e9034789SMichal Meloun 416e9034789SMichal Meloun rv = RM1(sc->base_sc, sc->def->fps_reg, MAX77620_FPS_SRC_MASK, 417e9034789SMichal Meloun fps_src << MAX77620_FPS_SRC_SHIFT); 418e9034789SMichal Meloun if (rv != 0) 419e9034789SMichal Meloun return (rv); 420e9034789SMichal Meloun sc->fps_src = fps_src; 421e9034789SMichal Meloun return (0); 422e9034789SMichal Meloun } 423e9034789SMichal Meloun 424e9034789SMichal Meloun static int 425e9034789SMichal Meloun max77620_set_fps_slots(struct max77620_reg_sc *sc, bool suspend) 426e9034789SMichal Meloun { 427e9034789SMichal Meloun uint8_t mask, val; 428e9034789SMichal Meloun int pu_slot, pd_slot, rv; 429e9034789SMichal Meloun 430e9034789SMichal Meloun if (suspend) { 431e9034789SMichal Meloun pu_slot = sc->suspend_fps_pu_slot; 432e9034789SMichal Meloun pd_slot = sc->suspend_fps_pd_slot; 433e9034789SMichal Meloun } else { 434e9034789SMichal Meloun pu_slot = sc->active_fps_pu_slot; 435e9034789SMichal Meloun pd_slot = sc->active_fps_pd_slot; 436e9034789SMichal Meloun } 437e9034789SMichal Meloun 438e9034789SMichal Meloun mask = 0; 439e9034789SMichal Meloun val = 0; 440e9034789SMichal Meloun if (pu_slot >= 0) { 441e9034789SMichal Meloun mask |= MAX77620_FPS_PU_PERIOD_MASK; 442e9034789SMichal Meloun val |= ((uint8_t)pu_slot << MAX77620_FPS_PU_PERIOD_SHIFT) & 443e9034789SMichal Meloun MAX77620_FPS_PU_PERIOD_MASK; 444e9034789SMichal Meloun } 445e9034789SMichal Meloun if (pd_slot >= 0) { 446e9034789SMichal Meloun mask |= MAX77620_FPS_PD_PERIOD_MASK; 447e9034789SMichal Meloun val |= ((uint8_t)pd_slot << MAX77620_FPS_PD_PERIOD_SHIFT) & 448e9034789SMichal Meloun MAX77620_FPS_PD_PERIOD_MASK; 449e9034789SMichal Meloun } 450e9034789SMichal Meloun 451e9034789SMichal Meloun rv = RM1(sc->base_sc, sc->def->fps_reg, mask, val); 452e9034789SMichal Meloun if (rv != 0) 453e9034789SMichal Meloun return (rv); 454e9034789SMichal Meloun return (0); 455e9034789SMichal Meloun } 456e9034789SMichal Meloun 457e9034789SMichal Meloun static int 458e9034789SMichal Meloun max77620_get_pwr_mode(struct max77620_reg_sc *sc, uint8_t *pwr_mode) 459e9034789SMichal Meloun { 460e9034789SMichal Meloun uint8_t val; 461e9034789SMichal Meloun int rv; 462e9034789SMichal Meloun 463e9034789SMichal Meloun rv = RD1(sc->base_sc, sc->def->pwr_mode_reg, &val); 464e9034789SMichal Meloun if (rv != 0) 465e9034789SMichal Meloun return (rv); 466e9034789SMichal Meloun 467e9034789SMichal Meloun *pwr_mode = (val & sc->def->pwr_mode_mask) >> sc->def->pwr_mode_shift; 468e9034789SMichal Meloun return (0); 469e9034789SMichal Meloun } 470e9034789SMichal Meloun 471e9034789SMichal Meloun static int 472e9034789SMichal Meloun max77620_set_pwr_mode(struct max77620_reg_sc *sc, uint8_t pwr_mode) 473e9034789SMichal Meloun { 474e9034789SMichal Meloun int rv; 475e9034789SMichal Meloun 476e9034789SMichal Meloun rv = RM1(sc->base_sc, sc->def->pwr_mode_reg, sc->def->pwr_mode_shift, 477e9034789SMichal Meloun pwr_mode << sc->def->pwr_mode_shift); 478e9034789SMichal Meloun if (rv != 0) 479e9034789SMichal Meloun return (rv); 480e9034789SMichal Meloun sc->pwr_mode = pwr_mode; 481e9034789SMichal Meloun return (0); 482e9034789SMichal Meloun } 483e9034789SMichal Meloun 484e9034789SMichal Meloun static int 485e9034789SMichal Meloun max77620_get_pwr_ramp_delay(struct max77620_reg_sc *sc, int *rate) 486e9034789SMichal Meloun { 487e9034789SMichal Meloun uint8_t val; 488e9034789SMichal Meloun int rv; 489e9034789SMichal Meloun 490e9034789SMichal Meloun rv = RD1(sc->base_sc, sc->def->cfg_reg, &val); 491e9034789SMichal Meloun if (rv != 0) 492e9034789SMichal Meloun return (rv); 493e9034789SMichal Meloun 494e9034789SMichal Meloun if (sc->def->is_sd_reg) { 495e9034789SMichal Meloun val = (val & MAX77620_SD_SR_MASK) >> MAX77620_SD_SR_SHIFT; 496e9034789SMichal Meloun if (val == 0) 497e9034789SMichal Meloun *rate = 13750; 498e9034789SMichal Meloun else if (val == 1) 499e9034789SMichal Meloun *rate = 27500; 500e9034789SMichal Meloun else if (val == 2) 501e9034789SMichal Meloun *rate = 55000; 502e9034789SMichal Meloun else 503e9034789SMichal Meloun *rate = 100000; 504e9034789SMichal Meloun } else { 505e9034789SMichal Meloun val = (val & MAX77620_LDO_SLEW_RATE_MASK) >> 506e9034789SMichal Meloun MAX77620_LDO_SLEW_RATE_SHIFT; 507e9034789SMichal Meloun if (val == 0) 508e9034789SMichal Meloun *rate = 100000; 509e9034789SMichal Meloun else 510e9034789SMichal Meloun *rate = 5000; 511e9034789SMichal Meloun } 512e9034789SMichal Meloun sc->pwr_ramp_delay = *rate; 513e9034789SMichal Meloun return (0); 514e9034789SMichal Meloun } 515e9034789SMichal Meloun 516e9034789SMichal Meloun static int 517e9034789SMichal Meloun max77620_set_pwr_ramp_delay(struct max77620_reg_sc *sc, int rate) 518e9034789SMichal Meloun { 519e9034789SMichal Meloun uint8_t val, mask; 520e9034789SMichal Meloun int rv; 521e9034789SMichal Meloun 522e9034789SMichal Meloun if (sc->def->is_sd_reg) { 523e9034789SMichal Meloun if (rate <= 13750) 524e9034789SMichal Meloun val = 0; 525e9034789SMichal Meloun else if (rate <= 27500) 526e9034789SMichal Meloun val = 1; 527e9034789SMichal Meloun else if (rate <= 55000) 528e9034789SMichal Meloun val = 2; 529e9034789SMichal Meloun else 530e9034789SMichal Meloun val = 3; 531e9034789SMichal Meloun val <<= MAX77620_SD_SR_SHIFT; 532e9034789SMichal Meloun mask = MAX77620_SD_SR_MASK; 533e9034789SMichal Meloun } else { 534e9034789SMichal Meloun if (rate <= 5000) 535e9034789SMichal Meloun val = 1; 536e9034789SMichal Meloun else 537e9034789SMichal Meloun val = 0; 538e9034789SMichal Meloun val <<= MAX77620_LDO_SLEW_RATE_SHIFT; 539e9034789SMichal Meloun mask = MAX77620_LDO_SLEW_RATE_MASK; 540e9034789SMichal Meloun } 541e9034789SMichal Meloun rv = RM1(sc->base_sc, sc->def->cfg_reg, mask, val); 542e9034789SMichal Meloun if (rv != 0) 543e9034789SMichal Meloun return (rv); 544e9034789SMichal Meloun return (0); 545e9034789SMichal Meloun } 546e9034789SMichal Meloun 547e9034789SMichal Meloun static int 548e9034789SMichal Meloun max77620_regnode_init(struct regnode *regnode) 549e9034789SMichal Meloun { 550e9034789SMichal Meloun struct max77620_reg_sc *sc; 551e9034789SMichal Meloun uint8_t val; 552e9034789SMichal Meloun int intval, rv; 553e9034789SMichal Meloun 554e9034789SMichal Meloun sc = regnode_get_softc(regnode); 555e9034789SMichal Meloun sc->enable_usec = 500; 556e9034789SMichal Meloun sc->enable_pwr_mode = MAX77620_POWER_MODE_NORMAL; 557e9034789SMichal Meloun #if 0 558e9034789SMichal Meloun { 559e9034789SMichal Meloun uint8_t val1, val2, val3; 560e9034789SMichal Meloun RD1(sc->base_sc, sc->def->volt_reg, &val1); 561e9034789SMichal Meloun RD1(sc->base_sc, sc->def->cfg_reg, &val2); 562e9034789SMichal Meloun RD1(sc->base_sc, sc->def->fps_reg, &val3); 563e9034789SMichal Meloun printf("%s: Volt: 0x%02X, CFG: 0x%02X, FPS: 0x%02X\n", regnode_get_name(sc->regnode), val1, val2, val3); 564e9034789SMichal Meloun } 565e9034789SMichal Meloun #endif 566e9034789SMichal Meloun /* Get current power mode */ 567e9034789SMichal Meloun rv = max77620_get_pwr_mode(sc, &val); 568e9034789SMichal Meloun if (rv != 0) { 569e9034789SMichal Meloun printf("%s: cannot read current power mode: %d\n", 570e9034789SMichal Meloun regnode_get_name(sc->regnode), rv); 571e9034789SMichal Meloun return (rv); 572e9034789SMichal Meloun } 573e9034789SMichal Meloun sc->pwr_mode = val; 574e9034789SMichal Meloun 575e9034789SMichal Meloun /* Get current power ramp delay */ 576e9034789SMichal Meloun rv = max77620_get_pwr_ramp_delay(sc, &intval); 577e9034789SMichal Meloun if (rv != 0) { 578e9034789SMichal Meloun printf("%s: cannot read current power mode: %d\n", 579e9034789SMichal Meloun regnode_get_name(sc->regnode), rv); 580e9034789SMichal Meloun return (rv); 581e9034789SMichal Meloun } 582e9034789SMichal Meloun sc->pwr_ramp_delay = intval; 583e9034789SMichal Meloun 584e9034789SMichal Meloun /* Get FPS source if is not specified. */ 585e9034789SMichal Meloun if (sc->active_fps_src == -1) { 586e9034789SMichal Meloun rv = max77620_get_fps_src(sc, &val); 587e9034789SMichal Meloun if (rv != 0) { 588e9034789SMichal Meloun printf("%s: cannot read current FPS source: %d\n", 589e9034789SMichal Meloun regnode_get_name(sc->regnode), rv); 590e9034789SMichal Meloun return (rv); 591e9034789SMichal Meloun } 592e9034789SMichal Meloun sc->active_fps_src = val; 593e9034789SMichal Meloun } 594e9034789SMichal Meloun 595e9034789SMichal Meloun /* Configure power mode non-FPS controlled regulators. */ 596e9034789SMichal Meloun if (sc->active_fps_src != MAX77620_FPS_SRC_NONE || 597e9034789SMichal Meloun (sc->pwr_mode != MAX77620_POWER_MODE_DISABLE && 598e9034789SMichal Meloun sc->pwr_mode != sc->enable_pwr_mode)) { 599e9034789SMichal Meloun rv = max77620_set_pwr_mode(sc, (uint8_t)sc->enable_pwr_mode); 600e9034789SMichal Meloun if (rv != 0) { 601e9034789SMichal Meloun printf("%s: cannot set power mode: %d\n", 602e9034789SMichal Meloun regnode_get_name(sc->regnode), rv); 603e9034789SMichal Meloun return (rv); 604e9034789SMichal Meloun } 605e9034789SMichal Meloun } 606e9034789SMichal Meloun 607e9034789SMichal Meloun /* Set FPS source. */ 608e9034789SMichal Meloun rv = max77620_set_fps_src(sc, sc->active_fps_src); 609e9034789SMichal Meloun if (rv != 0) { 610e9034789SMichal Meloun printf("%s: cannot setup FPS source: %d\n", 611e9034789SMichal Meloun regnode_get_name(sc->regnode), rv); 612e9034789SMichal Meloun return (rv); 613e9034789SMichal Meloun } 614e9034789SMichal Meloun /* Set FPS slots. */ 615e9034789SMichal Meloun rv = max77620_set_fps_slots(sc, false); 616e9034789SMichal Meloun if (rv != 0) { 617e9034789SMichal Meloun printf("%s: cannot setup power slots: %d\n", 618e9034789SMichal Meloun regnode_get_name(sc->regnode), rv); 619e9034789SMichal Meloun return (rv); 620e9034789SMichal Meloun } 621e9034789SMichal Meloun /* Setup power ramp . */ 622e9034789SMichal Meloun if (sc->ramp_rate_setting != -1) { 623e9034789SMichal Meloun rv = max77620_set_pwr_ramp_delay(sc, sc->pwr_ramp_delay); 624e9034789SMichal Meloun if (rv != 0) { 625e9034789SMichal Meloun printf("%s: cannot set power ramp delay: %d\n", 626e9034789SMichal Meloun regnode_get_name(sc->regnode), rv); 627e9034789SMichal Meloun return (rv); 628e9034789SMichal Meloun } 629e9034789SMichal Meloun } 630e9034789SMichal Meloun 631e9034789SMichal Meloun return (0); 632e9034789SMichal Meloun } 633e9034789SMichal Meloun 634e9034789SMichal Meloun static void 635e9034789SMichal Meloun max77620_fdt_parse(struct max77620_softc *sc, phandle_t node, struct reg_def *def, 636e9034789SMichal Meloun struct max77620_regnode_init_def *init_def) 637e9034789SMichal Meloun { 638e9034789SMichal Meloun int rv; 639e9034789SMichal Meloun phandle_t parent, supply_node; 640e9034789SMichal Meloun char prop_name[64]; /* Maximum OFW property name length. */ 641e9034789SMichal Meloun 642e9034789SMichal Meloun rv = regulator_parse_ofw_stdparam(sc->dev, node, 643e9034789SMichal Meloun &init_def->reg_init_def); 644e9034789SMichal Meloun 645e9034789SMichal Meloun rv = OF_getencprop(node, "maxim,active-fps-source", 646e9034789SMichal Meloun &init_def->active_fps_src, sizeof(init_def->active_fps_src)); 647e9034789SMichal Meloun if (rv <= 0) 648e9034789SMichal Meloun init_def->active_fps_src = MAX77620_FPS_SRC_DEF; 649e9034789SMichal Meloun 650e9034789SMichal Meloun rv = OF_getencprop(node, "maxim,active-fps-power-up-slot", 651e9034789SMichal Meloun &init_def->active_fps_pu_slot, sizeof(init_def->active_fps_pu_slot)); 652e9034789SMichal Meloun if (rv <= 0) 653e9034789SMichal Meloun init_def->active_fps_pu_slot = -1; 654e9034789SMichal Meloun 655e9034789SMichal Meloun rv = OF_getencprop(node, "maxim,active-fps-power-down-slot", 656e9034789SMichal Meloun &init_def->active_fps_pd_slot, sizeof(init_def->active_fps_pd_slot)); 657e9034789SMichal Meloun if (rv <= 0) 658e9034789SMichal Meloun init_def->active_fps_pd_slot = -1; 659e9034789SMichal Meloun 660e9034789SMichal Meloun rv = OF_getencprop(node, "maxim,suspend-fps-source", 661e9034789SMichal Meloun &init_def->suspend_fps_src, sizeof(init_def->suspend_fps_src)); 662e9034789SMichal Meloun if (rv <= 0) 663e9034789SMichal Meloun init_def->suspend_fps_src = -1; 664e9034789SMichal Meloun 665e9034789SMichal Meloun rv = OF_getencprop(node, "maxim,suspend-fps-power-up-slot", 666e9034789SMichal Meloun &init_def->suspend_fps_pu_slot, sizeof(init_def->suspend_fps_pu_slot)); 667e9034789SMichal Meloun if (rv <= 0) 668e9034789SMichal Meloun init_def->suspend_fps_pu_slot = -1; 669e9034789SMichal Meloun 670e9034789SMichal Meloun rv = OF_getencprop(node, "maxim,suspend-fps-power-down-slot", 671e9034789SMichal Meloun &init_def->suspend_fps_pd_slot, sizeof(init_def->suspend_fps_pd_slot)); 672e9034789SMichal Meloun if (rv <= 0) 673e9034789SMichal Meloun init_def->suspend_fps_pd_slot = -1; 674e9034789SMichal Meloun 675e9034789SMichal Meloun rv = OF_getencprop(node, "maxim,ramp-rate-setting", 676e9034789SMichal Meloun &init_def->ramp_rate_setting, sizeof(init_def->ramp_rate_setting)); 677e9034789SMichal Meloun if (rv <= 0) 678e9034789SMichal Meloun init_def->ramp_rate_setting = -1; 679e9034789SMichal Meloun 680e9034789SMichal Meloun /* Get parent supply. */ 681e9034789SMichal Meloun if (def->supply_name == NULL) 682e9034789SMichal Meloun return; 683e9034789SMichal Meloun 684e9034789SMichal Meloun parent = OF_parent(node); 685e9034789SMichal Meloun snprintf(prop_name, sizeof(prop_name), "%s-supply", 686e9034789SMichal Meloun def->supply_name); 687e9034789SMichal Meloun rv = OF_getencprop(parent, prop_name, &supply_node, 688e9034789SMichal Meloun sizeof(supply_node)); 689e9034789SMichal Meloun if (rv <= 0) 690e9034789SMichal Meloun return; 691e9034789SMichal Meloun supply_node = OF_node_from_xref(supply_node); 692e9034789SMichal Meloun rv = OF_getprop_alloc(supply_node, "regulator-name", 693e9034789SMichal Meloun (void **)&init_def->reg_init_def.parent_name); 694e9034789SMichal Meloun if (rv <= 0) 695e9034789SMichal Meloun init_def->reg_init_def.parent_name = NULL; 696e9034789SMichal Meloun } 697e9034789SMichal Meloun 698e9034789SMichal Meloun static struct max77620_reg_sc * 699e9034789SMichal Meloun max77620_attach(struct max77620_softc *sc, phandle_t node, struct reg_def *def) 700e9034789SMichal Meloun { 701e9034789SMichal Meloun struct max77620_reg_sc *reg_sc; 702e9034789SMichal Meloun struct max77620_regnode_init_def init_def; 703e9034789SMichal Meloun struct regnode *regnode; 704e9034789SMichal Meloun 705e9034789SMichal Meloun bzero(&init_def, sizeof(init_def)); 706e9034789SMichal Meloun 707e9034789SMichal Meloun max77620_fdt_parse(sc, node, def, &init_def); 708e9034789SMichal Meloun init_def.reg_init_def.id = def->id; 709e9034789SMichal Meloun init_def.reg_init_def.ofw_node = node; 710e9034789SMichal Meloun regnode = regnode_create(sc->dev, &max77620_regnode_class, 711e9034789SMichal Meloun &init_def.reg_init_def); 712e9034789SMichal Meloun if (regnode == NULL) { 713e9034789SMichal Meloun device_printf(sc->dev, "Cannot create regulator.\n"); 714e9034789SMichal Meloun return (NULL); 715e9034789SMichal Meloun } 716e9034789SMichal Meloun reg_sc = regnode_get_softc(regnode); 717e9034789SMichal Meloun 718e9034789SMichal Meloun /* Init regulator softc. */ 719e9034789SMichal Meloun reg_sc->regnode = regnode; 720e9034789SMichal Meloun reg_sc->base_sc = sc; 721e9034789SMichal Meloun reg_sc->def = def; 722e9034789SMichal Meloun reg_sc->xref = OF_xref_from_node(node); 723e9034789SMichal Meloun reg_sc->param = regnode_get_stdparam(regnode); 724e9034789SMichal Meloun reg_sc->active_fps_src = init_def.active_fps_src; 725e9034789SMichal Meloun reg_sc->active_fps_pu_slot = init_def.active_fps_pu_slot; 726e9034789SMichal Meloun reg_sc->active_fps_pd_slot = init_def.active_fps_pd_slot; 727e9034789SMichal Meloun reg_sc->suspend_fps_src = init_def.suspend_fps_src; 728e9034789SMichal Meloun reg_sc->suspend_fps_pu_slot = init_def.suspend_fps_pu_slot; 729e9034789SMichal Meloun reg_sc->suspend_fps_pd_slot = init_def.suspend_fps_pd_slot; 730e9034789SMichal Meloun reg_sc->ramp_rate_setting = init_def.ramp_rate_setting; 731e9034789SMichal Meloun 732e9034789SMichal Meloun regnode_register(regnode); 733e9034789SMichal Meloun if (bootverbose) { 734e9034789SMichal Meloun int volt, rv; 735e9034789SMichal Meloun regnode_topo_slock(); 736e9034789SMichal Meloun rv = regnode_get_voltage(regnode, &volt); 737e9034789SMichal Meloun if (rv == ENODEV) { 738e9034789SMichal Meloun device_printf(sc->dev, 739e9034789SMichal Meloun " Regulator %s: parent doesn't exist yet.\n", 740e9034789SMichal Meloun regnode_get_name(regnode)); 741e9034789SMichal Meloun } else if (rv != 0) { 742e9034789SMichal Meloun device_printf(sc->dev, 743e9034789SMichal Meloun " Regulator %s: voltage: INVALID!!!\n", 744e9034789SMichal Meloun regnode_get_name(regnode)); 745e9034789SMichal Meloun } else { 746e9034789SMichal Meloun device_printf(sc->dev, 747e9034789SMichal Meloun " Regulator %s: voltage: %d uV\n", 748e9034789SMichal Meloun regnode_get_name(regnode), volt); 749e9034789SMichal Meloun device_printf(sc->dev, 750e9034789SMichal Meloun " FPS source: %d, mode: %d, ramp delay: %d\n", 751e9034789SMichal Meloun reg_sc->fps_src, reg_sc->pwr_mode, 752e9034789SMichal Meloun reg_sc->pwr_ramp_delay); 753e9034789SMichal Meloun } 754e9034789SMichal Meloun regnode_topo_unlock(); 755e9034789SMichal Meloun } 756e9034789SMichal Meloun 757e9034789SMichal Meloun return (reg_sc); 758e9034789SMichal Meloun } 759e9034789SMichal Meloun 760e9034789SMichal Meloun int 761e9034789SMichal Meloun max77620_regulator_attach(struct max77620_softc *sc, phandle_t node) 762e9034789SMichal Meloun { 763e9034789SMichal Meloun struct max77620_reg_sc *reg; 764e9034789SMichal Meloun phandle_t child, rnode; 765e9034789SMichal Meloun int i; 766e9034789SMichal Meloun 767e9034789SMichal Meloun rnode = ofw_bus_find_child(node, "regulators"); 768e9034789SMichal Meloun if (rnode <= 0) { 769e9034789SMichal Meloun device_printf(sc->dev, " Cannot find regulators subnode\n"); 770e9034789SMichal Meloun return (ENXIO); 771e9034789SMichal Meloun } 772e9034789SMichal Meloun 773e9034789SMichal Meloun sc->nregs = nitems(max77620s_def); 774e9034789SMichal Meloun sc->regs = malloc(sizeof(struct max77620_reg_sc *) * sc->nregs, 775e9034789SMichal Meloun M_MAX77620_REG, M_WAITOK | M_ZERO); 776e9034789SMichal Meloun 777e9034789SMichal Meloun 778e9034789SMichal Meloun /* Attach all known regulators if exist in DT. */ 779e9034789SMichal Meloun for (i = 0; i < sc->nregs; i++) { 780e9034789SMichal Meloun child = ofw_bus_find_child(rnode, max77620s_def[i].name); 781e9034789SMichal Meloun if (child == 0) { 782e9034789SMichal Meloun if (bootverbose) 783e9034789SMichal Meloun device_printf(sc->dev, 784e9034789SMichal Meloun "Regulator %s missing in DT\n", 785e9034789SMichal Meloun max77620s_def[i].name); 786e9034789SMichal Meloun continue; 787e9034789SMichal Meloun } 788e9034789SMichal Meloun if (ofw_bus_node_status_okay(child) == 0) 789e9034789SMichal Meloun continue; 790e9034789SMichal Meloun reg = max77620_attach(sc, child, max77620s_def + i); 791e9034789SMichal Meloun if (reg == NULL) { 792e9034789SMichal Meloun device_printf(sc->dev, "Cannot attach regulator: %s\n", 793e9034789SMichal Meloun max77620s_def[i].name); 794e9034789SMichal Meloun return (ENXIO); 795e9034789SMichal Meloun } 796e9034789SMichal Meloun sc->regs[i] = reg; 797e9034789SMichal Meloun } 798e9034789SMichal Meloun return (0); 799e9034789SMichal Meloun } 800e9034789SMichal Meloun 801e9034789SMichal Meloun int 802e9034789SMichal Meloun max77620_regulator_map(device_t dev, phandle_t xref, int ncells, 803e9034789SMichal Meloun pcell_t *cells, intptr_t *num) 804e9034789SMichal Meloun { 805e9034789SMichal Meloun struct max77620_softc *sc; 806e9034789SMichal Meloun int i; 807e9034789SMichal Meloun 808e9034789SMichal Meloun sc = device_get_softc(dev); 809e9034789SMichal Meloun for (i = 0; i < sc->nregs; i++) { 810e9034789SMichal Meloun if (sc->regs[i] == NULL) 811e9034789SMichal Meloun continue; 812e9034789SMichal Meloun if (sc->regs[i]->xref == xref) { 813e9034789SMichal Meloun *num = sc->regs[i]->def->id; 814e9034789SMichal Meloun return (0); 815e9034789SMichal Meloun } 816e9034789SMichal Meloun } 817e9034789SMichal Meloun 818e9034789SMichal Meloun return (ENXIO); 819e9034789SMichal Meloun } 820e9034789SMichal Meloun 821e9034789SMichal Meloun static int 822e9034789SMichal Meloun max77620_regnode_enable(struct regnode *regnode, bool val, int *udelay) 823e9034789SMichal Meloun { 824e9034789SMichal Meloun 825e9034789SMichal Meloun struct max77620_reg_sc *sc; 826e9034789SMichal Meloun uint8_t mode; 827e9034789SMichal Meloun int rv; 828e9034789SMichal Meloun 829e9034789SMichal Meloun sc = regnode_get_softc(regnode); 830e9034789SMichal Meloun 831e9034789SMichal Meloun if (sc->active_fps_src != MAX77620_FPS_SRC_NONE) { 832e9034789SMichal Meloun *udelay = 0; 833e9034789SMichal Meloun return (0); 834e9034789SMichal Meloun } 835e9034789SMichal Meloun 836e9034789SMichal Meloun if (val) 837e9034789SMichal Meloun mode = sc->enable_pwr_mode; 838e9034789SMichal Meloun else 839e9034789SMichal Meloun mode = MAX77620_POWER_MODE_DISABLE; 840e9034789SMichal Meloun 841e9034789SMichal Meloun rv = max77620_set_pwr_mode(sc, mode); 842e9034789SMichal Meloun if (rv != 0) { 843e9034789SMichal Meloun printf("%s: cannot set power mode: %d\n", 844e9034789SMichal Meloun regnode_get_name(sc->regnode), rv); 845e9034789SMichal Meloun return (rv); 846e9034789SMichal Meloun } 847e9034789SMichal Meloun 848e9034789SMichal Meloun *udelay = sc->enable_usec; 849e9034789SMichal Meloun return (0); 850e9034789SMichal Meloun } 851e9034789SMichal Meloun 852e9034789SMichal Meloun static int 853e9034789SMichal Meloun max77620_regnode_set_volt(struct regnode *regnode, int min_uvolt, int max_uvolt, 854e9034789SMichal Meloun int *udelay) 855e9034789SMichal Meloun { 856e9034789SMichal Meloun struct max77620_reg_sc *sc; 857e9034789SMichal Meloun uint8_t sel; 858e9034789SMichal Meloun int rv; 859e9034789SMichal Meloun 860e9034789SMichal Meloun sc = regnode_get_softc(regnode); 861e9034789SMichal Meloun 862e9034789SMichal Meloun *udelay = 0; 863e9034789SMichal Meloun rv = regulator_range_volt_to_sel8(sc->def->ranges, sc->def->nranges, 864e9034789SMichal Meloun min_uvolt, max_uvolt, &sel); 865e9034789SMichal Meloun if (rv != 0) 866e9034789SMichal Meloun return (rv); 867e9034789SMichal Meloun rv = max77620_set_sel(sc, sel); 868e9034789SMichal Meloun return (rv); 869e9034789SMichal Meloun } 870e9034789SMichal Meloun 871e9034789SMichal Meloun static int 872e9034789SMichal Meloun max77620_regnode_get_volt(struct regnode *regnode, int *uvolt) 873e9034789SMichal Meloun { 874e9034789SMichal Meloun 875e9034789SMichal Meloun struct max77620_reg_sc *sc; 876e9034789SMichal Meloun uint8_t sel; 877e9034789SMichal Meloun int rv; 878e9034789SMichal Meloun 879e9034789SMichal Meloun sc = regnode_get_softc(regnode); 880e9034789SMichal Meloun rv = max77620_get_sel(sc, &sel); 881e9034789SMichal Meloun if (rv != 0) 882e9034789SMichal Meloun return (rv); 883e9034789SMichal Meloun 884e9034789SMichal Meloun rv = regulator_range_sel8_to_volt(sc->def->ranges, sc->def->nranges, 885e9034789SMichal Meloun sel, uvolt); 886e9034789SMichal Meloun return (rv); 887e9034789SMichal Meloun return(0); 888e9034789SMichal Meloun } 889