1a9b7ce28SMatti Vaittinen // SPDX-License-Identifier: GPL-2.0 2a9b7ce28SMatti Vaittinen // Copyright (C) 2024 ROHM Semiconductors 3a9b7ce28SMatti Vaittinen // bd96801-regulator.c ROHM BD96801 regulator driver 4a9b7ce28SMatti Vaittinen 5a9b7ce28SMatti Vaittinen /* 6a9b7ce28SMatti Vaittinen * This version of the "BD86801 scalable PMIC"'s driver supports only very 7a9b7ce28SMatti Vaittinen * basic set of the PMIC features. Most notably, there is no support for 8a8d77166SMatti Vaittinen * the configurations which should be done when the PMIC is in STBY mode. 9a9b7ce28SMatti Vaittinen * 10a9b7ce28SMatti Vaittinen * Being able to reliably do the configurations like changing the 11a9b7ce28SMatti Vaittinen * regulator safety limits (like limits for the over/under -voltages, over 12a9b7ce28SMatti Vaittinen * current, thermal protection) would require the configuring driver to be 13a9b7ce28SMatti Vaittinen * synchronized with entity causing the PMIC state transitions. Eg, one 14a9b7ce28SMatti Vaittinen * should be able to ensure the PMIC is in STBY state when the 15a9b7ce28SMatti Vaittinen * configurations are applied to the hardware. How and when the PMIC state 16a9b7ce28SMatti Vaittinen * transitions are to be done is likely to be very system specific, as will 17a9b7ce28SMatti Vaittinen * be the need to configure these safety limits. Hence it's not simple to 18a9b7ce28SMatti Vaittinen * come up with a generic solution. 19a9b7ce28SMatti Vaittinen * 20a8d77166SMatti Vaittinen * Users who require the STBY state configurations can have a look at the 21a8d77166SMatti Vaittinen * original RFC: 22a9b7ce28SMatti Vaittinen * https://lore.kernel.org/all/cover.1712920132.git.mazziesaccount@gmail.com/ 23a8d77166SMatti Vaittinen * which implements some of the safety limit configurations - but leaves the 24a8d77166SMatti Vaittinen * state change handling and synchronization to be implemented. 25a9b7ce28SMatti Vaittinen * 26a9b7ce28SMatti Vaittinen * It would be great to hear (and receive a patch!) if you implement the 27a8d77166SMatti Vaittinen * STBY configuration support in your downstream driver ;) 28a9b7ce28SMatti Vaittinen */ 29a9b7ce28SMatti Vaittinen 30f372c262SKrzysztof Kozlowski #include <linux/cleanup.h> 31a9b7ce28SMatti Vaittinen #include <linux/delay.h> 32a9b7ce28SMatti Vaittinen #include <linux/err.h> 33a9b7ce28SMatti Vaittinen #include <linux/interrupt.h> 34a9b7ce28SMatti Vaittinen #include <linux/kernel.h> 35a9b7ce28SMatti Vaittinen #include <linux/linear_range.h> 36a9b7ce28SMatti Vaittinen #include <linux/mfd/rohm-generic.h> 37a9b7ce28SMatti Vaittinen #include <linux/mfd/rohm-bd96801.h> 38a9b7ce28SMatti Vaittinen #include <linux/module.h> 39a9b7ce28SMatti Vaittinen #include <linux/of.h> 40a9b7ce28SMatti Vaittinen #include <linux/platform_device.h> 41a9b7ce28SMatti Vaittinen #include <linux/regmap.h> 42a9b7ce28SMatti Vaittinen #include <linux/regulator/coupler.h> 43a9b7ce28SMatti Vaittinen #include <linux/regulator/driver.h> 44a9b7ce28SMatti Vaittinen #include <linux/regulator/machine.h> 45a9b7ce28SMatti Vaittinen #include <linux/regulator/of_regulator.h> 46a9b7ce28SMatti Vaittinen #include <linux/slab.h> 47a9b7ce28SMatti Vaittinen #include <linux/timer.h> 48a9b7ce28SMatti Vaittinen 49a9b7ce28SMatti Vaittinen enum { 50a9b7ce28SMatti Vaittinen BD96801_BUCK1, 51a9b7ce28SMatti Vaittinen BD96801_BUCK2, 52a9b7ce28SMatti Vaittinen BD96801_BUCK3, 53a9b7ce28SMatti Vaittinen BD96801_BUCK4, 54a9b7ce28SMatti Vaittinen BD96801_LDO5, 55a9b7ce28SMatti Vaittinen BD96801_LDO6, 56a9b7ce28SMatti Vaittinen BD96801_LDO7, 57a9b7ce28SMatti Vaittinen BD96801_REGULATOR_AMOUNT, 58a9b7ce28SMatti Vaittinen }; 59a9b7ce28SMatti Vaittinen 60a9b7ce28SMatti Vaittinen enum { 61a9b7ce28SMatti Vaittinen BD96801_PROT_OVP, 62a9b7ce28SMatti Vaittinen BD96801_PROT_UVP, 63a9b7ce28SMatti Vaittinen BD96801_PROT_OCP, 64a9b7ce28SMatti Vaittinen BD96801_PROT_TEMP, 65a9b7ce28SMatti Vaittinen BD96801_NUM_PROT, 66a9b7ce28SMatti Vaittinen }; 67a9b7ce28SMatti Vaittinen 68a9b7ce28SMatti Vaittinen #define BD96801_ALWAYS_ON_REG 0x3c 69a9b7ce28SMatti Vaittinen #define BD96801_REG_ENABLE 0x0b 70a9b7ce28SMatti Vaittinen #define BD96801_BUCK1_EN_MASK BIT(0) 71a9b7ce28SMatti Vaittinen #define BD96801_BUCK2_EN_MASK BIT(1) 72a9b7ce28SMatti Vaittinen #define BD96801_BUCK3_EN_MASK BIT(2) 73a9b7ce28SMatti Vaittinen #define BD96801_BUCK4_EN_MASK BIT(3) 74a9b7ce28SMatti Vaittinen #define BD96801_LDO5_EN_MASK BIT(4) 75a9b7ce28SMatti Vaittinen #define BD96801_LDO6_EN_MASK BIT(5) 76a9b7ce28SMatti Vaittinen #define BD96801_LDO7_EN_MASK BIT(6) 77a9b7ce28SMatti Vaittinen 78a9b7ce28SMatti Vaittinen #define BD96801_BUCK1_VSEL_REG 0x28 79a9b7ce28SMatti Vaittinen #define BD96801_BUCK2_VSEL_REG 0x29 80a9b7ce28SMatti Vaittinen #define BD96801_BUCK3_VSEL_REG 0x2a 81a9b7ce28SMatti Vaittinen #define BD96801_BUCK4_VSEL_REG 0x2b 82a9b7ce28SMatti Vaittinen #define BD96801_LDO5_VSEL_REG 0x25 83a9b7ce28SMatti Vaittinen #define BD96801_LDO6_VSEL_REG 0x26 84a9b7ce28SMatti Vaittinen #define BD96801_LDO7_VSEL_REG 0x27 85a9b7ce28SMatti Vaittinen #define BD96801_BUCK_VSEL_MASK 0x1F 86a9b7ce28SMatti Vaittinen #define BD96801_LDO_VSEL_MASK 0xff 87a9b7ce28SMatti Vaittinen 88a9b7ce28SMatti Vaittinen #define BD96801_MASK_RAMP_DELAY 0xc0 89a9b7ce28SMatti Vaittinen #define BD96801_INT_VOUT_BASE_REG 0x21 90a9b7ce28SMatti Vaittinen #define BD96801_BUCK_INT_VOUT_MASK 0xff 91a9b7ce28SMatti Vaittinen 92a9b7ce28SMatti Vaittinen #define BD96801_BUCK_VOLTS 256 93a9b7ce28SMatti Vaittinen #define BD96801_LDO_VOLTS 256 94a9b7ce28SMatti Vaittinen 95a9b7ce28SMatti Vaittinen #define BD96801_OVP_MASK 0x03 96a9b7ce28SMatti Vaittinen #define BD96801_MASK_BUCK1_OVP_SHIFT 0x00 97a9b7ce28SMatti Vaittinen #define BD96801_MASK_BUCK2_OVP_SHIFT 0x02 98a9b7ce28SMatti Vaittinen #define BD96801_MASK_BUCK3_OVP_SHIFT 0x04 99a9b7ce28SMatti Vaittinen #define BD96801_MASK_BUCK4_OVP_SHIFT 0x06 100a9b7ce28SMatti Vaittinen #define BD96801_MASK_LDO5_OVP_SHIFT 0x00 101a9b7ce28SMatti Vaittinen #define BD96801_MASK_LDO6_OVP_SHIFT 0x02 102a9b7ce28SMatti Vaittinen #define BD96801_MASK_LDO7_OVP_SHIFT 0x04 103a9b7ce28SMatti Vaittinen 104a9b7ce28SMatti Vaittinen #define BD96801_PROT_LIMIT_OCP_MIN 0x00 105a9b7ce28SMatti Vaittinen #define BD96801_PROT_LIMIT_LOW 0x01 106a9b7ce28SMatti Vaittinen #define BD96801_PROT_LIMIT_MID 0x02 107a9b7ce28SMatti Vaittinen #define BD96801_PROT_LIMIT_HI 0x03 108a9b7ce28SMatti Vaittinen 109a9b7ce28SMatti Vaittinen #define BD96801_REG_BUCK1_OCP 0x32 110a9b7ce28SMatti Vaittinen #define BD96801_REG_BUCK2_OCP 0x32 111a9b7ce28SMatti Vaittinen #define BD96801_REG_BUCK3_OCP 0x33 112a9b7ce28SMatti Vaittinen #define BD96801_REG_BUCK4_OCP 0x33 113a9b7ce28SMatti Vaittinen 114a9b7ce28SMatti Vaittinen #define BD96801_MASK_BUCK1_OCP_SHIFT 0x00 115a9b7ce28SMatti Vaittinen #define BD96801_MASK_BUCK2_OCP_SHIFT 0x04 116a9b7ce28SMatti Vaittinen #define BD96801_MASK_BUCK3_OCP_SHIFT 0x00 117a9b7ce28SMatti Vaittinen #define BD96801_MASK_BUCK4_OCP_SHIFT 0x04 118a9b7ce28SMatti Vaittinen 119a9b7ce28SMatti Vaittinen #define BD96801_REG_LDO5_OCP 0x34 120a9b7ce28SMatti Vaittinen #define BD96801_REG_LDO6_OCP 0x34 121a9b7ce28SMatti Vaittinen #define BD96801_REG_LDO7_OCP 0x34 122a9b7ce28SMatti Vaittinen 123a9b7ce28SMatti Vaittinen #define BD96801_MASK_LDO5_OCP_SHIFT 0x00 124a9b7ce28SMatti Vaittinen #define BD96801_MASK_LDO6_OCP_SHIFT 0x02 125a9b7ce28SMatti Vaittinen #define BD96801_MASK_LDO7_OCP_SHIFT 0x04 126a9b7ce28SMatti Vaittinen 127a9b7ce28SMatti Vaittinen #define BD96801_MASK_SHD_INTB BIT(7) 128a9b7ce28SMatti Vaittinen #define BD96801_INTB_FATAL BIT(7) 129a9b7ce28SMatti Vaittinen 130a9b7ce28SMatti Vaittinen #define BD96801_NUM_REGULATORS 7 131a9b7ce28SMatti Vaittinen #define BD96801_NUM_LDOS 4 132a9b7ce28SMatti Vaittinen 133a9b7ce28SMatti Vaittinen /* 134a9b7ce28SMatti Vaittinen * Ramp rates for bucks are controlled by bits [7:6] as follows: 135a9b7ce28SMatti Vaittinen * 00 => 1 mV/uS 136a9b7ce28SMatti Vaittinen * 01 => 5 mV/uS 137a9b7ce28SMatti Vaittinen * 10 => 10 mV/uS 138a9b7ce28SMatti Vaittinen * 11 => 20 mV/uS 139a9b7ce28SMatti Vaittinen */ 140a9b7ce28SMatti Vaittinen static const unsigned int buck_ramp_table[] = { 1000, 5000, 10000, 20000 }; 141a9b7ce28SMatti Vaittinen 142a9b7ce28SMatti Vaittinen /* 143a9b7ce28SMatti Vaittinen * This is a voltage range that get's appended to selected 144a9b7ce28SMatti Vaittinen * bd96801_buck_init_volts value. The range from 0x0 to 0xF is actually 145a9b7ce28SMatti Vaittinen * bd96801_buck_init_volts + 0 ... bd96801_buck_init_volts + 150mV 146a9b7ce28SMatti Vaittinen * and the range from 0x10 to 0x1f is bd96801_buck_init_volts - 150mV ... 147a9b7ce28SMatti Vaittinen * bd96801_buck_init_volts - 0. But as the members of linear_range 148a9b7ce28SMatti Vaittinen * are all unsigned I will apply offset of -150 mV to value in 149a9b7ce28SMatti Vaittinen * linear_range - which should increase these ranges with 150a9b7ce28SMatti Vaittinen * 150 mV getting all the values to >= 0. 151a9b7ce28SMatti Vaittinen */ 152a9b7ce28SMatti Vaittinen static const struct linear_range bd96801_tune_volts[] = { 153a9b7ce28SMatti Vaittinen REGULATOR_LINEAR_RANGE(150000, 0x00, 0xF, 10000), 154a9b7ce28SMatti Vaittinen REGULATOR_LINEAR_RANGE(0, 0x10, 0x1F, 10000), 155a9b7ce28SMatti Vaittinen }; 156a9b7ce28SMatti Vaittinen 157a9b7ce28SMatti Vaittinen static const struct linear_range bd96801_buck_init_volts[] = { 158a9b7ce28SMatti Vaittinen REGULATOR_LINEAR_RANGE(500000 - 150000, 0x00, 0xc8, 5000), 159a9b7ce28SMatti Vaittinen REGULATOR_LINEAR_RANGE(1550000 - 150000, 0xc9, 0xec, 50000), 160a9b7ce28SMatti Vaittinen REGULATOR_LINEAR_RANGE(3300000 - 150000, 0xed, 0xff, 0), 161a9b7ce28SMatti Vaittinen }; 162a9b7ce28SMatti Vaittinen 163a9b7ce28SMatti Vaittinen static const struct linear_range bd96801_ldo_int_volts[] = { 164a9b7ce28SMatti Vaittinen REGULATOR_LINEAR_RANGE(300000, 0x00, 0x78, 25000), 165a9b7ce28SMatti Vaittinen REGULATOR_LINEAR_RANGE(3300000, 0x79, 0xff, 0), 166a9b7ce28SMatti Vaittinen }; 167a9b7ce28SMatti Vaittinen 168a9b7ce28SMatti Vaittinen #define BD96801_LDO_SD_VOLT_MASK 0x1 169a9b7ce28SMatti Vaittinen #define BD96801_LDO_MODE_MASK 0x6 170a9b7ce28SMatti Vaittinen #define BD96801_LDO_MODE_INT 0x0 171a9b7ce28SMatti Vaittinen #define BD96801_LDO_MODE_SD 0x2 172a9b7ce28SMatti Vaittinen #define BD96801_LDO_MODE_DDR 0x4 173a9b7ce28SMatti Vaittinen 174a9b7ce28SMatti Vaittinen static int ldo_ddr_volt_table[] = {500000, 300000}; 175a9b7ce28SMatti Vaittinen static int ldo_sd_volt_table[] = {3300000, 1800000}; 176a9b7ce28SMatti Vaittinen 177a9b7ce28SMatti Vaittinen /* Constant IRQ initialization data (templates) */ 178a9b7ce28SMatti Vaittinen struct bd96801_irqinfo { 179a9b7ce28SMatti Vaittinen int type; 180a9b7ce28SMatti Vaittinen struct regulator_irq_desc irq_desc; 181a9b7ce28SMatti Vaittinen int err_cfg; 182a9b7ce28SMatti Vaittinen int wrn_cfg; 183a9b7ce28SMatti Vaittinen const char *irq_name; 184a9b7ce28SMatti Vaittinen }; 185a9b7ce28SMatti Vaittinen 186a9b7ce28SMatti Vaittinen #define BD96801_IRQINFO(_type, _name, _irqoff_ms, _irqname) \ 187a9b7ce28SMatti Vaittinen { \ 188a9b7ce28SMatti Vaittinen .type = (_type), \ 189a9b7ce28SMatti Vaittinen .err_cfg = -1, \ 190a9b7ce28SMatti Vaittinen .wrn_cfg = -1, \ 191a9b7ce28SMatti Vaittinen .irq_name = (_irqname), \ 192a9b7ce28SMatti Vaittinen .irq_desc = { \ 193a9b7ce28SMatti Vaittinen .name = (_name), \ 194a9b7ce28SMatti Vaittinen .irq_off_ms = (_irqoff_ms), \ 195a9b7ce28SMatti Vaittinen .map_event = regulator_irq_map_event_simple, \ 196a9b7ce28SMatti Vaittinen }, \ 197a9b7ce28SMatti Vaittinen } 198a9b7ce28SMatti Vaittinen 199a9b7ce28SMatti Vaittinen static const struct bd96801_irqinfo buck1_irqinfo[] = { 200a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-h", 500, 201*9cc95754SMatti Vaittinen "buck1-overcurr-h"), 202a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-l", 500, 203*9cc95754SMatti Vaittinen "buck1-overcurr-l"), 204a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OCP, "buck1-over-curr-n", 500, 205*9cc95754SMatti Vaittinen "buck1-overcurr-n"), 206a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OVP, "buck1-over-voltage", 500, 207*9cc95754SMatti Vaittinen "buck1-overvolt"), 208a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_UVP, "buck1-under-voltage", 500, 209*9cc95754SMatti Vaittinen "buck1-undervolt"), 210a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_TEMP, "buck1-over-temp", 500, 211*9cc95754SMatti Vaittinen "buck1-thermal") 212a9b7ce28SMatti Vaittinen }; 213a9b7ce28SMatti Vaittinen 214a9b7ce28SMatti Vaittinen static const struct bd96801_irqinfo buck2_irqinfo[] = { 215a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-h", 500, 216*9cc95754SMatti Vaittinen "buck2-overcurr-h"), 217a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-l", 500, 218*9cc95754SMatti Vaittinen "buck2-overcurr-l"), 219a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OCP, "buck2-over-curr-n", 500, 220*9cc95754SMatti Vaittinen "buck2-overcurr-n"), 221a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OVP, "buck2-over-voltage", 500, 222*9cc95754SMatti Vaittinen "buck2-overvolt"), 223a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_UVP, "buck2-under-voltage", 500, 224*9cc95754SMatti Vaittinen "buck2-undervolt"), 225a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_TEMP, "buck2-over-temp", 500, 226*9cc95754SMatti Vaittinen "buck2-thermal") 227a9b7ce28SMatti Vaittinen }; 228a9b7ce28SMatti Vaittinen 229a9b7ce28SMatti Vaittinen static const struct bd96801_irqinfo buck3_irqinfo[] = { 230a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-h", 500, 231*9cc95754SMatti Vaittinen "buck3-overcurr-h"), 232a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-l", 500, 233*9cc95754SMatti Vaittinen "buck3-overcurr-l"), 234a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OCP, "buck3-over-curr-n", 500, 235*9cc95754SMatti Vaittinen "buck3-overcurr-n"), 236a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OVP, "buck3-over-voltage", 500, 237*9cc95754SMatti Vaittinen "buck3-overvolt"), 238a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_UVP, "buck3-under-voltage", 500, 239*9cc95754SMatti Vaittinen "buck3-undervolt"), 240a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_TEMP, "buck3-over-temp", 500, 241*9cc95754SMatti Vaittinen "buck3-thermal") 242a9b7ce28SMatti Vaittinen }; 243a9b7ce28SMatti Vaittinen 244a9b7ce28SMatti Vaittinen static const struct bd96801_irqinfo buck4_irqinfo[] = { 245a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-h", 500, 246*9cc95754SMatti Vaittinen "buck4-overcurr-h"), 247a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-l", 500, 248*9cc95754SMatti Vaittinen "buck4-overcurr-l"), 249a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OCP, "buck4-over-curr-n", 500, 250*9cc95754SMatti Vaittinen "buck4-overcurr-n"), 251a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OVP, "buck4-over-voltage", 500, 252*9cc95754SMatti Vaittinen "buck4-overvolt"), 253a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_UVP, "buck4-under-voltage", 500, 254*9cc95754SMatti Vaittinen "buck4-undervolt"), 255a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_TEMP, "buck4-over-temp", 500, 256*9cc95754SMatti Vaittinen "buck4-thermal") 257a9b7ce28SMatti Vaittinen }; 258a9b7ce28SMatti Vaittinen 259a9b7ce28SMatti Vaittinen static const struct bd96801_irqinfo ldo5_irqinfo[] = { 260a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OCP, "ldo5-overcurr", 500, 261*9cc95754SMatti Vaittinen "ldo5-overcurr"), 262a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OVP, "ldo5-over-voltage", 500, 263*9cc95754SMatti Vaittinen "ldo5-overvolt"), 264a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_UVP, "ldo5-under-voltage", 500, 265*9cc95754SMatti Vaittinen "ldo5-undervolt"), 266a9b7ce28SMatti Vaittinen }; 267a9b7ce28SMatti Vaittinen 268a9b7ce28SMatti Vaittinen static const struct bd96801_irqinfo ldo6_irqinfo[] = { 269a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OCP, "ldo6-overcurr", 500, 270*9cc95754SMatti Vaittinen "ldo6-overcurr"), 271a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OVP, "ldo6-over-voltage", 500, 272*9cc95754SMatti Vaittinen "ldo6-overvolt"), 273a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_UVP, "ldo6-under-voltage", 500, 274*9cc95754SMatti Vaittinen "ldo6-undervolt"), 275a9b7ce28SMatti Vaittinen }; 276a9b7ce28SMatti Vaittinen 277a9b7ce28SMatti Vaittinen static const struct bd96801_irqinfo ldo7_irqinfo[] = { 278a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OCP, "ldo7-overcurr", 500, 279*9cc95754SMatti Vaittinen "ldo7-overcurr"), 280a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_OVP, "ldo7-over-voltage", 500, 281*9cc95754SMatti Vaittinen "ldo7-overvolt"), 282a9b7ce28SMatti Vaittinen BD96801_IRQINFO(BD96801_PROT_UVP, "ldo7-under-voltage", 500, 283*9cc95754SMatti Vaittinen "ldo7-undervolt"), 284a9b7ce28SMatti Vaittinen }; 285a9b7ce28SMatti Vaittinen 286a9b7ce28SMatti Vaittinen struct bd96801_irq_desc { 287a9b7ce28SMatti Vaittinen struct bd96801_irqinfo *irqinfo; 288a9b7ce28SMatti Vaittinen int num_irqs; 289a9b7ce28SMatti Vaittinen }; 290a9b7ce28SMatti Vaittinen 291a9b7ce28SMatti Vaittinen struct bd96801_regulator_data { 292a9b7ce28SMatti Vaittinen struct regulator_desc desc; 293a9b7ce28SMatti Vaittinen const struct linear_range *init_ranges; 294a9b7ce28SMatti Vaittinen int num_ranges; 295a9b7ce28SMatti Vaittinen struct bd96801_irq_desc irq_desc; 296a9b7ce28SMatti Vaittinen int initial_voltage; 297a9b7ce28SMatti Vaittinen int ldo_vol_lvl; 298a9b7ce28SMatti Vaittinen int ldo_errs; 299a9b7ce28SMatti Vaittinen }; 300a9b7ce28SMatti Vaittinen 301a9b7ce28SMatti Vaittinen struct bd96801_pmic_data { 302a9b7ce28SMatti Vaittinen struct bd96801_regulator_data regulator_data[BD96801_NUM_REGULATORS]; 303a9b7ce28SMatti Vaittinen struct regmap *regmap; 304a9b7ce28SMatti Vaittinen int fatal_ind; 305a9b7ce28SMatti Vaittinen }; 306a9b7ce28SMatti Vaittinen 307a9b7ce28SMatti Vaittinen static int ldo_map_notif(int irq, struct regulator_irq_data *rid, 308a9b7ce28SMatti Vaittinen unsigned long *dev_mask) 309a9b7ce28SMatti Vaittinen { 310a9b7ce28SMatti Vaittinen int i; 311a9b7ce28SMatti Vaittinen 312a9b7ce28SMatti Vaittinen for (i = 0; i < rid->num_states; i++) { 313a9b7ce28SMatti Vaittinen struct bd96801_regulator_data *rdata; 314a9b7ce28SMatti Vaittinen struct regulator_dev *rdev; 315a9b7ce28SMatti Vaittinen 316a9b7ce28SMatti Vaittinen rdev = rid->states[i].rdev; 317a9b7ce28SMatti Vaittinen rdata = container_of(rdev->desc, struct bd96801_regulator_data, 318a9b7ce28SMatti Vaittinen desc); 319a9b7ce28SMatti Vaittinen rid->states[i].notifs = regulator_err2notif(rdata->ldo_errs); 320a9b7ce28SMatti Vaittinen rid->states[i].errors = rdata->ldo_errs; 321a9b7ce28SMatti Vaittinen *dev_mask |= BIT(i); 322a9b7ce28SMatti Vaittinen } 323a9b7ce28SMatti Vaittinen return 0; 324a9b7ce28SMatti Vaittinen } 325a9b7ce28SMatti Vaittinen 326a9b7ce28SMatti Vaittinen static int bd96801_list_voltage_lr(struct regulator_dev *rdev, 327a9b7ce28SMatti Vaittinen unsigned int selector) 328a9b7ce28SMatti Vaittinen { 329a9b7ce28SMatti Vaittinen int voltage; 330a9b7ce28SMatti Vaittinen struct bd96801_regulator_data *data; 331a9b7ce28SMatti Vaittinen 332a9b7ce28SMatti Vaittinen data = container_of(rdev->desc, struct bd96801_regulator_data, desc); 333a9b7ce28SMatti Vaittinen 334a9b7ce28SMatti Vaittinen /* 335a9b7ce28SMatti Vaittinen * The BD096801 has voltage setting in two registers. One giving the 336a9b7ce28SMatti Vaittinen * "initial voltage" (can be changed only when regulator is disabled. 337a9b7ce28SMatti Vaittinen * This driver caches the value and sets it only at startup. The other 338a9b7ce28SMatti Vaittinen * register is voltage tuning value which applies -150 mV ... +150 mV 339a9b7ce28SMatti Vaittinen * offset to the voltage. 340a9b7ce28SMatti Vaittinen * 341a9b7ce28SMatti Vaittinen * Note that the cached initial voltage stored in regulator data is 342a9b7ce28SMatti Vaittinen * 'scaled down' by the 150 mV so that all of our tuning values are 343a9b7ce28SMatti Vaittinen * >= 0. This is done because the linear_ranges uses unsigned values. 344a9b7ce28SMatti Vaittinen * 345a9b7ce28SMatti Vaittinen * As a result, we increase the tuning voltage which we get based on 346a9b7ce28SMatti Vaittinen * the selector by the stored initial_voltage. 347a9b7ce28SMatti Vaittinen */ 348a9b7ce28SMatti Vaittinen voltage = regulator_list_voltage_linear_range(rdev, selector); 349a9b7ce28SMatti Vaittinen if (voltage < 0) 350a9b7ce28SMatti Vaittinen return voltage; 351a9b7ce28SMatti Vaittinen 352a9b7ce28SMatti Vaittinen return voltage + data->initial_voltage; 353a9b7ce28SMatti Vaittinen } 354a9b7ce28SMatti Vaittinen 355a9b7ce28SMatti Vaittinen 356a9b7ce28SMatti Vaittinen static const struct regulator_ops bd96801_ldo_table_ops = { 357a9b7ce28SMatti Vaittinen .is_enabled = regulator_is_enabled_regmap, 358a9b7ce28SMatti Vaittinen .list_voltage = regulator_list_voltage_table, 359a9b7ce28SMatti Vaittinen .get_voltage_sel = regulator_get_voltage_sel_regmap, 360a9b7ce28SMatti Vaittinen }; 361a9b7ce28SMatti Vaittinen 362a9b7ce28SMatti Vaittinen static const struct regulator_ops bd96801_buck_ops = { 363a9b7ce28SMatti Vaittinen .is_enabled = regulator_is_enabled_regmap, 364a9b7ce28SMatti Vaittinen .list_voltage = bd96801_list_voltage_lr, 365a9b7ce28SMatti Vaittinen .set_voltage_sel = regulator_set_voltage_sel_regmap, 366a9b7ce28SMatti Vaittinen .get_voltage_sel = regulator_get_voltage_sel_regmap, 367a9b7ce28SMatti Vaittinen .set_voltage_time_sel = regulator_set_voltage_time_sel, 368a9b7ce28SMatti Vaittinen .set_ramp_delay = regulator_set_ramp_delay_regmap, 369a9b7ce28SMatti Vaittinen }; 370a9b7ce28SMatti Vaittinen 371a9b7ce28SMatti Vaittinen static const struct regulator_ops bd96801_ldo_ops = { 372a9b7ce28SMatti Vaittinen .is_enabled = regulator_is_enabled_regmap, 373a9b7ce28SMatti Vaittinen .list_voltage = regulator_list_voltage_linear_range, 374a9b7ce28SMatti Vaittinen .get_voltage_sel = regulator_get_voltage_sel_regmap, 375a9b7ce28SMatti Vaittinen }; 376a9b7ce28SMatti Vaittinen 377a9b7ce28SMatti Vaittinen static int buck_get_initial_voltage(struct regmap *regmap, struct device *dev, 378a9b7ce28SMatti Vaittinen struct bd96801_regulator_data *data) 379a9b7ce28SMatti Vaittinen { 380a9b7ce28SMatti Vaittinen int ret = 0, sel, initial_uv; 381a9b7ce28SMatti Vaittinen int reg = BD96801_INT_VOUT_BASE_REG + data->desc.id; 382a9b7ce28SMatti Vaittinen 383a9b7ce28SMatti Vaittinen if (data->num_ranges) { 384a9b7ce28SMatti Vaittinen ret = regmap_read(regmap, reg, &sel); 385a9b7ce28SMatti Vaittinen sel &= BD96801_BUCK_INT_VOUT_MASK; 386a9b7ce28SMatti Vaittinen 387a9b7ce28SMatti Vaittinen ret = linear_range_get_value_array(data->init_ranges, 388a9b7ce28SMatti Vaittinen data->num_ranges, sel, 389a9b7ce28SMatti Vaittinen &initial_uv); 390a9b7ce28SMatti Vaittinen if (ret) 391a9b7ce28SMatti Vaittinen return ret; 392a9b7ce28SMatti Vaittinen 393a9b7ce28SMatti Vaittinen data->initial_voltage = initial_uv; 394a9b7ce28SMatti Vaittinen dev_dbg(dev, "Tune-scaled initial voltage %u\n", 395a9b7ce28SMatti Vaittinen data->initial_voltage); 396a9b7ce28SMatti Vaittinen } 397a9b7ce28SMatti Vaittinen 398a9b7ce28SMatti Vaittinen return 0; 399a9b7ce28SMatti Vaittinen } 400a9b7ce28SMatti Vaittinen 401a9b7ce28SMatti Vaittinen static int get_ldo_initial_voltage(struct regmap *regmap, 402a9b7ce28SMatti Vaittinen struct device *dev, 403a9b7ce28SMatti Vaittinen struct bd96801_regulator_data *data) 404a9b7ce28SMatti Vaittinen { 405a9b7ce28SMatti Vaittinen int ret; 406a9b7ce28SMatti Vaittinen int cfgreg; 407a9b7ce28SMatti Vaittinen 408a9b7ce28SMatti Vaittinen ret = regmap_read(regmap, data->ldo_vol_lvl, &cfgreg); 409a9b7ce28SMatti Vaittinen if (ret) 410a9b7ce28SMatti Vaittinen return ret; 411a9b7ce28SMatti Vaittinen 412a9b7ce28SMatti Vaittinen switch (cfgreg & BD96801_LDO_MODE_MASK) { 413a9b7ce28SMatti Vaittinen case BD96801_LDO_MODE_DDR: 414a9b7ce28SMatti Vaittinen data->desc.volt_table = ldo_ddr_volt_table; 415a9b7ce28SMatti Vaittinen data->desc.n_voltages = ARRAY_SIZE(ldo_ddr_volt_table); 416a9b7ce28SMatti Vaittinen break; 417a9b7ce28SMatti Vaittinen case BD96801_LDO_MODE_SD: 418a9b7ce28SMatti Vaittinen data->desc.volt_table = ldo_sd_volt_table; 419a9b7ce28SMatti Vaittinen data->desc.n_voltages = ARRAY_SIZE(ldo_sd_volt_table); 420a9b7ce28SMatti Vaittinen break; 421a9b7ce28SMatti Vaittinen default: 422a9b7ce28SMatti Vaittinen dev_info(dev, "Leaving LDO to normal mode"); 423a9b7ce28SMatti Vaittinen return 0; 424a9b7ce28SMatti Vaittinen } 425a9b7ce28SMatti Vaittinen 426a9b7ce28SMatti Vaittinen /* SD or DDR mode => override default ops */ 427a9b7ce28SMatti Vaittinen data->desc.ops = &bd96801_ldo_table_ops, 428a9b7ce28SMatti Vaittinen data->desc.vsel_mask = 1; 429a9b7ce28SMatti Vaittinen data->desc.vsel_reg = data->ldo_vol_lvl; 430a9b7ce28SMatti Vaittinen 431a9b7ce28SMatti Vaittinen return 0; 432a9b7ce28SMatti Vaittinen } 433a9b7ce28SMatti Vaittinen 434a9b7ce28SMatti Vaittinen static int get_initial_voltage(struct device *dev, struct regmap *regmap, 435a9b7ce28SMatti Vaittinen struct bd96801_regulator_data *data) 436a9b7ce28SMatti Vaittinen { 437a9b7ce28SMatti Vaittinen /* BUCK */ 438a9b7ce28SMatti Vaittinen if (data->desc.id <= BD96801_BUCK4) 439a9b7ce28SMatti Vaittinen return buck_get_initial_voltage(regmap, dev, data); 440a9b7ce28SMatti Vaittinen 441a9b7ce28SMatti Vaittinen /* LDO */ 442a9b7ce28SMatti Vaittinen return get_ldo_initial_voltage(regmap, dev, data); 443a9b7ce28SMatti Vaittinen } 444a9b7ce28SMatti Vaittinen 445a9b7ce28SMatti Vaittinen static int bd96801_walk_regulator_dt(struct device *dev, struct regmap *regmap, 446a9b7ce28SMatti Vaittinen struct bd96801_regulator_data *data, 447a9b7ce28SMatti Vaittinen int num) 448a9b7ce28SMatti Vaittinen { 449a9b7ce28SMatti Vaittinen int i, ret; 450a9b7ce28SMatti Vaittinen 451f372c262SKrzysztof Kozlowski struct device_node *nproot __free(device_node) = 452f372c262SKrzysztof Kozlowski of_get_child_by_name(dev->parent->of_node, "regulators"); 453a9b7ce28SMatti Vaittinen if (!nproot) { 454a9b7ce28SMatti Vaittinen dev_err(dev, "failed to find regulators node\n"); 455a9b7ce28SMatti Vaittinen return -ENODEV; 456a9b7ce28SMatti Vaittinen } 457f372c262SKrzysztof Kozlowski for_each_child_of_node_scoped(nproot, np) { 458a9b7ce28SMatti Vaittinen for (i = 0; i < num; i++) { 459a9b7ce28SMatti Vaittinen if (!of_node_name_eq(np, data[i].desc.of_match)) 460a9b7ce28SMatti Vaittinen continue; 461a9b7ce28SMatti Vaittinen /* 462a9b7ce28SMatti Vaittinen * If STBY configs are supported, we must pass node 463a9b7ce28SMatti Vaittinen * here to extract the initial voltages from the DT. 464a9b7ce28SMatti Vaittinen * Thus we do the initial voltage getting in this 465a9b7ce28SMatti Vaittinen * loop. 466a9b7ce28SMatti Vaittinen */ 467a9b7ce28SMatti Vaittinen ret = get_initial_voltage(dev, regmap, &data[i]); 468a9b7ce28SMatti Vaittinen if (ret) { 469a9b7ce28SMatti Vaittinen dev_err(dev, 470a9b7ce28SMatti Vaittinen "Initializing voltages for %s failed\n", 471a9b7ce28SMatti Vaittinen data[i].desc.name); 472a9b7ce28SMatti Vaittinen return ret; 473a9b7ce28SMatti Vaittinen } 474f372c262SKrzysztof Kozlowski 475a9b7ce28SMatti Vaittinen if (of_property_read_bool(np, "rohm,keep-on-stby")) { 476a9b7ce28SMatti Vaittinen ret = regmap_set_bits(regmap, 477a9b7ce28SMatti Vaittinen BD96801_ALWAYS_ON_REG, 478a9b7ce28SMatti Vaittinen 1 << data[i].desc.id); 479a9b7ce28SMatti Vaittinen if (ret) { 480a9b7ce28SMatti Vaittinen dev_err(dev, 481a9b7ce28SMatti Vaittinen "failed to set %s on-at-stby\n", 482a9b7ce28SMatti Vaittinen data[i].desc.name); 483a9b7ce28SMatti Vaittinen return ret; 484a9b7ce28SMatti Vaittinen } 485a9b7ce28SMatti Vaittinen } 486a9b7ce28SMatti Vaittinen } 487f372c262SKrzysztof Kozlowski } 488a9b7ce28SMatti Vaittinen 489a9b7ce28SMatti Vaittinen return 0; 490a9b7ce28SMatti Vaittinen } 491a9b7ce28SMatti Vaittinen 492a9b7ce28SMatti Vaittinen /* 493a9b7ce28SMatti Vaittinen * Template for regulator data. Probe will allocate dynamic / driver instance 494a9b7ce28SMatti Vaittinen * struct so we should be on a safe side even if there were multiple PMICs to 495a9b7ce28SMatti Vaittinen * control. Note that there is a plan to allow multiple PMICs to be used so 496a9b7ce28SMatti Vaittinen * systems can scale better. I am however still slightly unsure how the 497a9b7ce28SMatti Vaittinen * multi-PMIC case will be handled. I don't know if the processor will have I2C 498a9b7ce28SMatti Vaittinen * acces to all of the PMICs or only the first one. I'd guess there will be 499a9b7ce28SMatti Vaittinen * access provided to all PMICs for voltage scaling - but the errors will only 500a9b7ce28SMatti Vaittinen * be informed via the master PMIC. Eg, we should prepare to support multiple 501a9b7ce28SMatti Vaittinen * driver instances - either with or without the IRQs... Well, let's first 502a9b7ce28SMatti Vaittinen * just support the simple and clear single-PMIC setup and ponder the multi PMIC 503a9b7ce28SMatti Vaittinen * case later. What we can easly do for preparing is to not use static global 504a9b7ce28SMatti Vaittinen * data for regulators though. 505a9b7ce28SMatti Vaittinen */ 506a9b7ce28SMatti Vaittinen static const struct bd96801_pmic_data bd96801_data = { 507a9b7ce28SMatti Vaittinen .regulator_data = { 508a9b7ce28SMatti Vaittinen { 509a9b7ce28SMatti Vaittinen .desc = { 510a9b7ce28SMatti Vaittinen .name = "buck1", 511a9b7ce28SMatti Vaittinen .of_match = of_match_ptr("buck1"), 512a9b7ce28SMatti Vaittinen .regulators_node = of_match_ptr("regulators"), 513a9b7ce28SMatti Vaittinen .id = BD96801_BUCK1, 514a9b7ce28SMatti Vaittinen .ops = &bd96801_buck_ops, 515a9b7ce28SMatti Vaittinen .type = REGULATOR_VOLTAGE, 516a9b7ce28SMatti Vaittinen .linear_ranges = bd96801_tune_volts, 517a9b7ce28SMatti Vaittinen .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), 518a9b7ce28SMatti Vaittinen .n_voltages = BD96801_BUCK_VOLTS, 519a9b7ce28SMatti Vaittinen .enable_reg = BD96801_REG_ENABLE, 520a9b7ce28SMatti Vaittinen .enable_mask = BD96801_BUCK1_EN_MASK, 521a9b7ce28SMatti Vaittinen .enable_is_inverted = true, 522a9b7ce28SMatti Vaittinen .vsel_reg = BD96801_BUCK1_VSEL_REG, 523a9b7ce28SMatti Vaittinen .vsel_mask = BD96801_BUCK_VSEL_MASK, 524a9b7ce28SMatti Vaittinen .ramp_reg = BD96801_BUCK1_VSEL_REG, 525a9b7ce28SMatti Vaittinen .ramp_mask = BD96801_MASK_RAMP_DELAY, 526a9b7ce28SMatti Vaittinen .ramp_delay_table = &buck_ramp_table[0], 527a9b7ce28SMatti Vaittinen .n_ramp_values = ARRAY_SIZE(buck_ramp_table), 528a9b7ce28SMatti Vaittinen .owner = THIS_MODULE, 529a9b7ce28SMatti Vaittinen }, 530a9b7ce28SMatti Vaittinen .init_ranges = bd96801_buck_init_volts, 531a9b7ce28SMatti Vaittinen .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), 532a9b7ce28SMatti Vaittinen .irq_desc = { 533a9b7ce28SMatti Vaittinen .irqinfo = (struct bd96801_irqinfo *)&buck1_irqinfo[0], 534a9b7ce28SMatti Vaittinen .num_irqs = ARRAY_SIZE(buck1_irqinfo), 535a9b7ce28SMatti Vaittinen }, 536a9b7ce28SMatti Vaittinen }, { 537a9b7ce28SMatti Vaittinen .desc = { 538a9b7ce28SMatti Vaittinen .name = "buck2", 539a9b7ce28SMatti Vaittinen .of_match = of_match_ptr("buck2"), 540a9b7ce28SMatti Vaittinen .regulators_node = of_match_ptr("regulators"), 541a9b7ce28SMatti Vaittinen .id = BD96801_BUCK2, 542a9b7ce28SMatti Vaittinen .ops = &bd96801_buck_ops, 543a9b7ce28SMatti Vaittinen .type = REGULATOR_VOLTAGE, 544a9b7ce28SMatti Vaittinen .linear_ranges = bd96801_tune_volts, 545a9b7ce28SMatti Vaittinen .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), 546a9b7ce28SMatti Vaittinen .n_voltages = BD96801_BUCK_VOLTS, 547a9b7ce28SMatti Vaittinen .enable_reg = BD96801_REG_ENABLE, 548a9b7ce28SMatti Vaittinen .enable_mask = BD96801_BUCK2_EN_MASK, 549a9b7ce28SMatti Vaittinen .enable_is_inverted = true, 550a9b7ce28SMatti Vaittinen .vsel_reg = BD96801_BUCK2_VSEL_REG, 551a9b7ce28SMatti Vaittinen .vsel_mask = BD96801_BUCK_VSEL_MASK, 552a9b7ce28SMatti Vaittinen .ramp_reg = BD96801_BUCK2_VSEL_REG, 553a9b7ce28SMatti Vaittinen .ramp_mask = BD96801_MASK_RAMP_DELAY, 554a9b7ce28SMatti Vaittinen .ramp_delay_table = &buck_ramp_table[0], 555a9b7ce28SMatti Vaittinen .n_ramp_values = ARRAY_SIZE(buck_ramp_table), 556a9b7ce28SMatti Vaittinen .owner = THIS_MODULE, 557a9b7ce28SMatti Vaittinen }, 558a9b7ce28SMatti Vaittinen .irq_desc = { 559a9b7ce28SMatti Vaittinen .irqinfo = (struct bd96801_irqinfo *)&buck2_irqinfo[0], 560a9b7ce28SMatti Vaittinen .num_irqs = ARRAY_SIZE(buck2_irqinfo), 561a9b7ce28SMatti Vaittinen }, 562a9b7ce28SMatti Vaittinen .init_ranges = bd96801_buck_init_volts, 563a9b7ce28SMatti Vaittinen .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), 564a9b7ce28SMatti Vaittinen }, { 565a9b7ce28SMatti Vaittinen .desc = { 566a9b7ce28SMatti Vaittinen .name = "buck3", 567a9b7ce28SMatti Vaittinen .of_match = of_match_ptr("buck3"), 568a9b7ce28SMatti Vaittinen .regulators_node = of_match_ptr("regulators"), 569a9b7ce28SMatti Vaittinen .id = BD96801_BUCK3, 570a9b7ce28SMatti Vaittinen .ops = &bd96801_buck_ops, 571a9b7ce28SMatti Vaittinen .type = REGULATOR_VOLTAGE, 572a9b7ce28SMatti Vaittinen .linear_ranges = bd96801_tune_volts, 573a9b7ce28SMatti Vaittinen .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), 574a9b7ce28SMatti Vaittinen .n_voltages = BD96801_BUCK_VOLTS, 575a9b7ce28SMatti Vaittinen .enable_reg = BD96801_REG_ENABLE, 576a9b7ce28SMatti Vaittinen .enable_mask = BD96801_BUCK3_EN_MASK, 577a9b7ce28SMatti Vaittinen .enable_is_inverted = true, 578a9b7ce28SMatti Vaittinen .vsel_reg = BD96801_BUCK3_VSEL_REG, 579a9b7ce28SMatti Vaittinen .vsel_mask = BD96801_BUCK_VSEL_MASK, 580a9b7ce28SMatti Vaittinen .ramp_reg = BD96801_BUCK3_VSEL_REG, 581a9b7ce28SMatti Vaittinen .ramp_mask = BD96801_MASK_RAMP_DELAY, 582a9b7ce28SMatti Vaittinen .ramp_delay_table = &buck_ramp_table[0], 583a9b7ce28SMatti Vaittinen .n_ramp_values = ARRAY_SIZE(buck_ramp_table), 584a9b7ce28SMatti Vaittinen .owner = THIS_MODULE, 585a9b7ce28SMatti Vaittinen }, 586a9b7ce28SMatti Vaittinen .irq_desc = { 587a9b7ce28SMatti Vaittinen .irqinfo = (struct bd96801_irqinfo *)&buck3_irqinfo[0], 588a9b7ce28SMatti Vaittinen .num_irqs = ARRAY_SIZE(buck3_irqinfo), 589a9b7ce28SMatti Vaittinen }, 590a9b7ce28SMatti Vaittinen .init_ranges = bd96801_buck_init_volts, 591a9b7ce28SMatti Vaittinen .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), 592a9b7ce28SMatti Vaittinen }, { 593a9b7ce28SMatti Vaittinen .desc = { 594a9b7ce28SMatti Vaittinen .name = "buck4", 595a9b7ce28SMatti Vaittinen .of_match = of_match_ptr("buck4"), 596a9b7ce28SMatti Vaittinen .regulators_node = of_match_ptr("regulators"), 597a9b7ce28SMatti Vaittinen .id = BD96801_BUCK4, 598a9b7ce28SMatti Vaittinen .ops = &bd96801_buck_ops, 599a9b7ce28SMatti Vaittinen .type = REGULATOR_VOLTAGE, 600a9b7ce28SMatti Vaittinen .linear_ranges = bd96801_tune_volts, 601a9b7ce28SMatti Vaittinen .n_linear_ranges = ARRAY_SIZE(bd96801_tune_volts), 602a9b7ce28SMatti Vaittinen .n_voltages = BD96801_BUCK_VOLTS, 603a9b7ce28SMatti Vaittinen .enable_reg = BD96801_REG_ENABLE, 604a9b7ce28SMatti Vaittinen .enable_mask = BD96801_BUCK4_EN_MASK, 605a9b7ce28SMatti Vaittinen .enable_is_inverted = true, 606a9b7ce28SMatti Vaittinen .vsel_reg = BD96801_BUCK4_VSEL_REG, 607a9b7ce28SMatti Vaittinen .vsel_mask = BD96801_BUCK_VSEL_MASK, 608a9b7ce28SMatti Vaittinen .ramp_reg = BD96801_BUCK4_VSEL_REG, 609a9b7ce28SMatti Vaittinen .ramp_mask = BD96801_MASK_RAMP_DELAY, 610a9b7ce28SMatti Vaittinen .ramp_delay_table = &buck_ramp_table[0], 611a9b7ce28SMatti Vaittinen .n_ramp_values = ARRAY_SIZE(buck_ramp_table), 612a9b7ce28SMatti Vaittinen .owner = THIS_MODULE, 613a9b7ce28SMatti Vaittinen }, 614a9b7ce28SMatti Vaittinen .irq_desc = { 615a9b7ce28SMatti Vaittinen .irqinfo = (struct bd96801_irqinfo *)&buck4_irqinfo[0], 616a9b7ce28SMatti Vaittinen .num_irqs = ARRAY_SIZE(buck4_irqinfo), 617a9b7ce28SMatti Vaittinen }, 618a9b7ce28SMatti Vaittinen .init_ranges = bd96801_buck_init_volts, 619a9b7ce28SMatti Vaittinen .num_ranges = ARRAY_SIZE(bd96801_buck_init_volts), 620a9b7ce28SMatti Vaittinen }, { 621a9b7ce28SMatti Vaittinen .desc = { 622a9b7ce28SMatti Vaittinen .name = "ldo5", 623a9b7ce28SMatti Vaittinen .of_match = of_match_ptr("ldo5"), 624a9b7ce28SMatti Vaittinen .regulators_node = of_match_ptr("regulators"), 625a9b7ce28SMatti Vaittinen .id = BD96801_LDO5, 626a9b7ce28SMatti Vaittinen .ops = &bd96801_ldo_ops, 627a9b7ce28SMatti Vaittinen .type = REGULATOR_VOLTAGE, 628a9b7ce28SMatti Vaittinen .linear_ranges = bd96801_ldo_int_volts, 629a9b7ce28SMatti Vaittinen .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), 630a9b7ce28SMatti Vaittinen .n_voltages = BD96801_LDO_VOLTS, 631a9b7ce28SMatti Vaittinen .enable_reg = BD96801_REG_ENABLE, 632a9b7ce28SMatti Vaittinen .enable_mask = BD96801_LDO5_EN_MASK, 633a9b7ce28SMatti Vaittinen .enable_is_inverted = true, 634a9b7ce28SMatti Vaittinen .vsel_reg = BD96801_LDO5_VSEL_REG, 635a9b7ce28SMatti Vaittinen .vsel_mask = BD96801_LDO_VSEL_MASK, 636a9b7ce28SMatti Vaittinen .owner = THIS_MODULE, 637a9b7ce28SMatti Vaittinen }, 638a9b7ce28SMatti Vaittinen .irq_desc = { 639a9b7ce28SMatti Vaittinen .irqinfo = (struct bd96801_irqinfo *)&ldo5_irqinfo[0], 640a9b7ce28SMatti Vaittinen .num_irqs = ARRAY_SIZE(ldo5_irqinfo), 641a9b7ce28SMatti Vaittinen }, 642a9b7ce28SMatti Vaittinen .ldo_vol_lvl = BD96801_LDO5_VOL_LVL_REG, 643a9b7ce28SMatti Vaittinen }, { 644a9b7ce28SMatti Vaittinen .desc = { 645a9b7ce28SMatti Vaittinen .name = "ldo6", 646a9b7ce28SMatti Vaittinen .of_match = of_match_ptr("ldo6"), 647a9b7ce28SMatti Vaittinen .regulators_node = of_match_ptr("regulators"), 648a9b7ce28SMatti Vaittinen .id = BD96801_LDO6, 649a9b7ce28SMatti Vaittinen .ops = &bd96801_ldo_ops, 650a9b7ce28SMatti Vaittinen .type = REGULATOR_VOLTAGE, 651a9b7ce28SMatti Vaittinen .linear_ranges = bd96801_ldo_int_volts, 652a9b7ce28SMatti Vaittinen .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), 653a9b7ce28SMatti Vaittinen .n_voltages = BD96801_LDO_VOLTS, 654a9b7ce28SMatti Vaittinen .enable_reg = BD96801_REG_ENABLE, 655a9b7ce28SMatti Vaittinen .enable_mask = BD96801_LDO6_EN_MASK, 656a9b7ce28SMatti Vaittinen .enable_is_inverted = true, 657a9b7ce28SMatti Vaittinen .vsel_reg = BD96801_LDO6_VSEL_REG, 658a9b7ce28SMatti Vaittinen .vsel_mask = BD96801_LDO_VSEL_MASK, 659a9b7ce28SMatti Vaittinen .owner = THIS_MODULE, 660a9b7ce28SMatti Vaittinen }, 661a9b7ce28SMatti Vaittinen .irq_desc = { 662a9b7ce28SMatti Vaittinen .irqinfo = (struct bd96801_irqinfo *)&ldo6_irqinfo[0], 663a9b7ce28SMatti Vaittinen .num_irqs = ARRAY_SIZE(ldo6_irqinfo), 664a9b7ce28SMatti Vaittinen }, 665a9b7ce28SMatti Vaittinen .ldo_vol_lvl = BD96801_LDO6_VOL_LVL_REG, 666a9b7ce28SMatti Vaittinen }, { 667a9b7ce28SMatti Vaittinen .desc = { 668a9b7ce28SMatti Vaittinen .name = "ldo7", 669a9b7ce28SMatti Vaittinen .of_match = of_match_ptr("ldo7"), 670a9b7ce28SMatti Vaittinen .regulators_node = of_match_ptr("regulators"), 671a9b7ce28SMatti Vaittinen .id = BD96801_LDO7, 672a9b7ce28SMatti Vaittinen .ops = &bd96801_ldo_ops, 673a9b7ce28SMatti Vaittinen .type = REGULATOR_VOLTAGE, 674a9b7ce28SMatti Vaittinen .linear_ranges = bd96801_ldo_int_volts, 675a9b7ce28SMatti Vaittinen .n_linear_ranges = ARRAY_SIZE(bd96801_ldo_int_volts), 676a9b7ce28SMatti Vaittinen .n_voltages = BD96801_LDO_VOLTS, 677a9b7ce28SMatti Vaittinen .enable_reg = BD96801_REG_ENABLE, 678a9b7ce28SMatti Vaittinen .enable_mask = BD96801_LDO7_EN_MASK, 679a9b7ce28SMatti Vaittinen .enable_is_inverted = true, 680a9b7ce28SMatti Vaittinen .vsel_reg = BD96801_LDO7_VSEL_REG, 681a9b7ce28SMatti Vaittinen .vsel_mask = BD96801_LDO_VSEL_MASK, 682a9b7ce28SMatti Vaittinen .owner = THIS_MODULE, 683a9b7ce28SMatti Vaittinen }, 684a9b7ce28SMatti Vaittinen .irq_desc = { 685a9b7ce28SMatti Vaittinen .irqinfo = (struct bd96801_irqinfo *)&ldo7_irqinfo[0], 686a9b7ce28SMatti Vaittinen .num_irqs = ARRAY_SIZE(ldo7_irqinfo), 687a9b7ce28SMatti Vaittinen }, 688a9b7ce28SMatti Vaittinen .ldo_vol_lvl = BD96801_LDO7_VOL_LVL_REG, 689a9b7ce28SMatti Vaittinen }, 690a9b7ce28SMatti Vaittinen }, 691a9b7ce28SMatti Vaittinen }; 692a9b7ce28SMatti Vaittinen 693a9b7ce28SMatti Vaittinen static int initialize_pmic_data(struct device *dev, 694a9b7ce28SMatti Vaittinen struct bd96801_pmic_data *pdata) 695a9b7ce28SMatti Vaittinen { 696a9b7ce28SMatti Vaittinen int r, i; 697a9b7ce28SMatti Vaittinen 698a9b7ce28SMatti Vaittinen /* 699a9b7ce28SMatti Vaittinen * Allocate and initialize IRQ data for all of the regulators. We 700a9b7ce28SMatti Vaittinen * wish to modify IRQ information independently for each driver 701a9b7ce28SMatti Vaittinen * instance. 702a9b7ce28SMatti Vaittinen */ 703a9b7ce28SMatti Vaittinen for (r = 0; r < BD96801_NUM_REGULATORS; r++) { 704a9b7ce28SMatti Vaittinen const struct bd96801_irqinfo *template; 705a9b7ce28SMatti Vaittinen struct bd96801_irqinfo *new; 706a9b7ce28SMatti Vaittinen int num_infos; 707a9b7ce28SMatti Vaittinen 708a9b7ce28SMatti Vaittinen template = pdata->regulator_data[r].irq_desc.irqinfo; 709a9b7ce28SMatti Vaittinen num_infos = pdata->regulator_data[r].irq_desc.num_irqs; 710a9b7ce28SMatti Vaittinen 711a9b7ce28SMatti Vaittinen new = devm_kcalloc(dev, num_infos, sizeof(*new), GFP_KERNEL); 712a9b7ce28SMatti Vaittinen if (!new) 713a9b7ce28SMatti Vaittinen return -ENOMEM; 714a9b7ce28SMatti Vaittinen 715a9b7ce28SMatti Vaittinen pdata->regulator_data[r].irq_desc.irqinfo = new; 716a9b7ce28SMatti Vaittinen 717a9b7ce28SMatti Vaittinen for (i = 0; i < num_infos; i++) 718a9b7ce28SMatti Vaittinen new[i] = template[i]; 719a9b7ce28SMatti Vaittinen } 720a9b7ce28SMatti Vaittinen 721a9b7ce28SMatti Vaittinen return 0; 722a9b7ce28SMatti Vaittinen } 723a9b7ce28SMatti Vaittinen 724a8d77166SMatti Vaittinen static int bd96801_map_event_all(int irq, struct regulator_irq_data *rid, 725a8d77166SMatti Vaittinen unsigned long *dev_mask) 726a8d77166SMatti Vaittinen { 727a8d77166SMatti Vaittinen int i; 728a8d77166SMatti Vaittinen 729a8d77166SMatti Vaittinen for (i = 0; i < rid->num_states; i++) { 730a8d77166SMatti Vaittinen rid->states[i].notifs = REGULATOR_EVENT_FAIL; 731a8d77166SMatti Vaittinen rid->states[i].errors = REGULATOR_ERROR_FAIL; 732a8d77166SMatti Vaittinen *dev_mask |= BIT(i); 733a8d77166SMatti Vaittinen } 734a8d77166SMatti Vaittinen 735a8d77166SMatti Vaittinen return 0; 736a8d77166SMatti Vaittinen } 737a8d77166SMatti Vaittinen 738a8d77166SMatti Vaittinen static int bd96801_rdev_errb_irqs(struct platform_device *pdev, 739a8d77166SMatti Vaittinen struct regulator_dev *rdev) 740a8d77166SMatti Vaittinen { 741a8d77166SMatti Vaittinen int i; 742a8d77166SMatti Vaittinen void *retp; 743a8d77166SMatti Vaittinen static const char * const single_out_errb_irqs[] = { 744*9cc95754SMatti Vaittinen "%s-pvin-err", "%s-ovp-err", "%s-uvp-err", "%s-shdn-err", 745a8d77166SMatti Vaittinen }; 746a8d77166SMatti Vaittinen 747a8d77166SMatti Vaittinen for (i = 0; i < ARRAY_SIZE(single_out_errb_irqs); i++) { 748a8d77166SMatti Vaittinen struct regulator_irq_desc id = { 749a8d77166SMatti Vaittinen .map_event = bd96801_map_event_all, 750a8d77166SMatti Vaittinen .irq_off_ms = 1000, 751a8d77166SMatti Vaittinen }; 752a8d77166SMatti Vaittinen struct regulator_dev *rdev_arr[1]; 753a8d77166SMatti Vaittinen char tmp[255]; 754a8d77166SMatti Vaittinen int irq; 755a8d77166SMatti Vaittinen 756a8d77166SMatti Vaittinen snprintf(tmp, 255, single_out_errb_irqs[i], rdev->desc->name); 757a8d77166SMatti Vaittinen tmp[254] = 0; 758a8d77166SMatti Vaittinen id.name = tmp; 759a8d77166SMatti Vaittinen 760a8d77166SMatti Vaittinen irq = platform_get_irq_byname(pdev, tmp); 761a8d77166SMatti Vaittinen if (irq < 0) 762a8d77166SMatti Vaittinen continue; 763a8d77166SMatti Vaittinen 764a8d77166SMatti Vaittinen rdev_arr[0] = rdev; 765a8d77166SMatti Vaittinen retp = devm_regulator_irq_helper(&pdev->dev, &id, irq, 0, 766a8d77166SMatti Vaittinen REGULATOR_ERROR_FAIL, NULL, 767a8d77166SMatti Vaittinen rdev_arr, 1); 768a8d77166SMatti Vaittinen if (IS_ERR(retp)) 769a8d77166SMatti Vaittinen return PTR_ERR(retp); 770a8d77166SMatti Vaittinen 771a8d77166SMatti Vaittinen } 772a8d77166SMatti Vaittinen return 0; 773a8d77166SMatti Vaittinen } 774a8d77166SMatti Vaittinen 775a8d77166SMatti Vaittinen static int bd96801_global_errb_irqs(struct platform_device *pdev, 776a8d77166SMatti Vaittinen struct regulator_dev **rdev, int num_rdev) 777a8d77166SMatti Vaittinen { 778a8d77166SMatti Vaittinen int i, num_irqs; 779a8d77166SMatti Vaittinen void *retp; 780a8d77166SMatti Vaittinen static const char * const global_errb_irqs[] = { 781*9cc95754SMatti Vaittinen "otp-err", "dbist-err", "eep-err", "abist-err", "prstb-err", 782*9cc95754SMatti Vaittinen "drmoserr1", "drmoserr2", "slave-err", "vref-err", "tsd", 783*9cc95754SMatti Vaittinen "uvlo-err", "ovlo-err", "osc-err", "pon-err", "poff-err", 784*9cc95754SMatti Vaittinen "cmd-shdn-err", "int-shdn-err" 785a8d77166SMatti Vaittinen }; 786a8d77166SMatti Vaittinen 787a8d77166SMatti Vaittinen num_irqs = ARRAY_SIZE(global_errb_irqs); 788a8d77166SMatti Vaittinen for (i = 0; i < num_irqs; i++) { 789a8d77166SMatti Vaittinen int irq; 790a8d77166SMatti Vaittinen struct regulator_irq_desc id = { 791a8d77166SMatti Vaittinen .name = global_errb_irqs[i], 792a8d77166SMatti Vaittinen .map_event = bd96801_map_event_all, 793a8d77166SMatti Vaittinen .irq_off_ms = 1000, 794a8d77166SMatti Vaittinen }; 795a8d77166SMatti Vaittinen 796a8d77166SMatti Vaittinen irq = platform_get_irq_byname(pdev, global_errb_irqs[i]); 797a8d77166SMatti Vaittinen if (irq < 0) 798a8d77166SMatti Vaittinen continue; 799a8d77166SMatti Vaittinen 800a8d77166SMatti Vaittinen retp = devm_regulator_irq_helper(&pdev->dev, &id, irq, 0, 801a8d77166SMatti Vaittinen REGULATOR_ERROR_FAIL, NULL, 802a8d77166SMatti Vaittinen rdev, num_rdev); 803a8d77166SMatti Vaittinen if (IS_ERR(retp)) 804a8d77166SMatti Vaittinen return PTR_ERR(retp); 805a8d77166SMatti Vaittinen } 806a8d77166SMatti Vaittinen 807a8d77166SMatti Vaittinen return 0; 808a8d77166SMatti Vaittinen } 809a8d77166SMatti Vaittinen 810a9b7ce28SMatti Vaittinen static int bd96801_rdev_intb_irqs(struct platform_device *pdev, 811a9b7ce28SMatti Vaittinen struct bd96801_pmic_data *pdata, 812a9b7ce28SMatti Vaittinen struct bd96801_irqinfo *iinfo, 813a9b7ce28SMatti Vaittinen struct regulator_dev *rdev) 814a9b7ce28SMatti Vaittinen { 815a9b7ce28SMatti Vaittinen struct regulator_dev *rdev_arr[1]; 816a9b7ce28SMatti Vaittinen void *retp; 817a9b7ce28SMatti Vaittinen int err = 0; 818a9b7ce28SMatti Vaittinen int irq; 819a9b7ce28SMatti Vaittinen int err_flags[] = { 820a9b7ce28SMatti Vaittinen [BD96801_PROT_OVP] = REGULATOR_ERROR_REGULATION_OUT, 821a9b7ce28SMatti Vaittinen [BD96801_PROT_UVP] = REGULATOR_ERROR_UNDER_VOLTAGE, 822a9b7ce28SMatti Vaittinen [BD96801_PROT_OCP] = REGULATOR_ERROR_OVER_CURRENT, 823a9b7ce28SMatti Vaittinen [BD96801_PROT_TEMP] = REGULATOR_ERROR_OVER_TEMP, 824a9b7ce28SMatti Vaittinen 825a9b7ce28SMatti Vaittinen }; 826a9b7ce28SMatti Vaittinen int wrn_flags[] = { 827a9b7ce28SMatti Vaittinen [BD96801_PROT_OVP] = REGULATOR_ERROR_OVER_VOLTAGE_WARN, 828a9b7ce28SMatti Vaittinen [BD96801_PROT_UVP] = REGULATOR_ERROR_UNDER_VOLTAGE_WARN, 829a9b7ce28SMatti Vaittinen [BD96801_PROT_OCP] = REGULATOR_ERROR_OVER_CURRENT_WARN, 830a9b7ce28SMatti Vaittinen [BD96801_PROT_TEMP] = REGULATOR_ERROR_OVER_TEMP_WARN, 831a9b7ce28SMatti Vaittinen }; 832a9b7ce28SMatti Vaittinen 833a9b7ce28SMatti Vaittinen /* 834a9b7ce28SMatti Vaittinen * Don't install IRQ handler if both error and warning 835a9b7ce28SMatti Vaittinen * notifications are explicitly disabled 836a9b7ce28SMatti Vaittinen */ 837a9b7ce28SMatti Vaittinen if (!iinfo->err_cfg && !iinfo->wrn_cfg) 838a9b7ce28SMatti Vaittinen return 0; 839a9b7ce28SMatti Vaittinen 840a9b7ce28SMatti Vaittinen if (WARN_ON(iinfo->type >= BD96801_NUM_PROT)) 841a9b7ce28SMatti Vaittinen return -EINVAL; 842a9b7ce28SMatti Vaittinen 843a9b7ce28SMatti Vaittinen if (iinfo->err_cfg) 844a9b7ce28SMatti Vaittinen err = err_flags[iinfo->type]; 845a9b7ce28SMatti Vaittinen else if (iinfo->wrn_cfg) 846a9b7ce28SMatti Vaittinen err = wrn_flags[iinfo->type]; 847a9b7ce28SMatti Vaittinen 848a9b7ce28SMatti Vaittinen iinfo->irq_desc.data = pdata; 849a9b7ce28SMatti Vaittinen irq = platform_get_irq_byname(pdev, iinfo->irq_name); 850a9b7ce28SMatti Vaittinen if (irq < 0) 851a9b7ce28SMatti Vaittinen return irq; 852a9b7ce28SMatti Vaittinen /* Find notifications for this IRQ (WARN/ERR) */ 853a9b7ce28SMatti Vaittinen 854a9b7ce28SMatti Vaittinen rdev_arr[0] = rdev; 855a9b7ce28SMatti Vaittinen retp = devm_regulator_irq_helper(&pdev->dev, 856a9b7ce28SMatti Vaittinen &iinfo->irq_desc, irq, 857a9b7ce28SMatti Vaittinen 0, err, NULL, rdev_arr, 858a9b7ce28SMatti Vaittinen 1); 859a9b7ce28SMatti Vaittinen if (IS_ERR(retp)) 860a9b7ce28SMatti Vaittinen return PTR_ERR(retp); 861a9b7ce28SMatti Vaittinen 862a9b7ce28SMatti Vaittinen return 0; 863a9b7ce28SMatti Vaittinen } 864a9b7ce28SMatti Vaittinen 865a9b7ce28SMatti Vaittinen static int bd96801_probe(struct platform_device *pdev) 866a9b7ce28SMatti Vaittinen { 867a9b7ce28SMatti Vaittinen struct regulator_dev *ldo_errs_rdev_arr[BD96801_NUM_LDOS]; 868a8d77166SMatti Vaittinen struct regulator_dev *all_rdevs[BD96801_NUM_REGULATORS]; 869a9b7ce28SMatti Vaittinen struct bd96801_regulator_data *rdesc; 870a9b7ce28SMatti Vaittinen struct regulator_config config = {}; 871a9b7ce28SMatti Vaittinen int ldo_errs_arr[BD96801_NUM_LDOS]; 872a9b7ce28SMatti Vaittinen struct bd96801_pmic_data *pdata; 873a9b7ce28SMatti Vaittinen int temp_notif_ldos = 0; 874a9b7ce28SMatti Vaittinen struct device *parent; 875a9b7ce28SMatti Vaittinen int i, ret; 876a8d77166SMatti Vaittinen bool use_errb; 877a9b7ce28SMatti Vaittinen void *retp; 878a9b7ce28SMatti Vaittinen 879a9b7ce28SMatti Vaittinen parent = pdev->dev.parent; 880a9b7ce28SMatti Vaittinen 881a9b7ce28SMatti Vaittinen pdata = devm_kmemdup(&pdev->dev, &bd96801_data, sizeof(bd96801_data), 882a9b7ce28SMatti Vaittinen GFP_KERNEL); 883a9b7ce28SMatti Vaittinen if (!pdata) 884a9b7ce28SMatti Vaittinen return -ENOMEM; 885a9b7ce28SMatti Vaittinen 886a9b7ce28SMatti Vaittinen if (initialize_pmic_data(&pdev->dev, pdata)) 887a9b7ce28SMatti Vaittinen return -ENOMEM; 888a9b7ce28SMatti Vaittinen 889a9b7ce28SMatti Vaittinen pdata->regmap = dev_get_regmap(parent, NULL); 890a9b7ce28SMatti Vaittinen if (!pdata->regmap) { 891a9b7ce28SMatti Vaittinen dev_err(&pdev->dev, "No register map found\n"); 892a9b7ce28SMatti Vaittinen return -ENODEV; 893a9b7ce28SMatti Vaittinen } 894a9b7ce28SMatti Vaittinen 895a9b7ce28SMatti Vaittinen rdesc = &pdata->regulator_data[0]; 896a9b7ce28SMatti Vaittinen 897a9b7ce28SMatti Vaittinen config.driver_data = pdata; 898a9b7ce28SMatti Vaittinen config.regmap = pdata->regmap; 899a9b7ce28SMatti Vaittinen config.dev = parent; 900a9b7ce28SMatti Vaittinen 901a8d77166SMatti Vaittinen ret = of_property_match_string(pdev->dev.parent->of_node, 902a8d77166SMatti Vaittinen "interrupt-names", "errb"); 903a8d77166SMatti Vaittinen if (ret < 0) 904a8d77166SMatti Vaittinen use_errb = false; 905a8d77166SMatti Vaittinen else 906a8d77166SMatti Vaittinen use_errb = true; 907a8d77166SMatti Vaittinen 908a9b7ce28SMatti Vaittinen ret = bd96801_walk_regulator_dt(&pdev->dev, pdata->regmap, rdesc, 909a9b7ce28SMatti Vaittinen BD96801_NUM_REGULATORS); 910a9b7ce28SMatti Vaittinen if (ret) 911a9b7ce28SMatti Vaittinen return ret; 912a9b7ce28SMatti Vaittinen 913a9b7ce28SMatti Vaittinen for (i = 0; i < ARRAY_SIZE(pdata->regulator_data); i++) { 914a9b7ce28SMatti Vaittinen struct regulator_dev *rdev; 915a9b7ce28SMatti Vaittinen struct bd96801_irq_desc *idesc = &rdesc[i].irq_desc; 916a9b7ce28SMatti Vaittinen int j; 917a9b7ce28SMatti Vaittinen 918a9b7ce28SMatti Vaittinen rdev = devm_regulator_register(&pdev->dev, 919a9b7ce28SMatti Vaittinen &rdesc[i].desc, &config); 920a9b7ce28SMatti Vaittinen if (IS_ERR(rdev)) { 921a9b7ce28SMatti Vaittinen dev_err(&pdev->dev, 922a9b7ce28SMatti Vaittinen "failed to register %s regulator\n", 923a9b7ce28SMatti Vaittinen rdesc[i].desc.name); 924a9b7ce28SMatti Vaittinen return PTR_ERR(rdev); 925a9b7ce28SMatti Vaittinen } 926a8d77166SMatti Vaittinen all_rdevs[i] = rdev; 927a9b7ce28SMatti Vaittinen /* 928a9b7ce28SMatti Vaittinen * LDOs don't have own temperature monitoring. If temperature 929a9b7ce28SMatti Vaittinen * notification was requested for this LDO from DT then we will 930a9b7ce28SMatti Vaittinen * add the regulator to be notified if central IC temperature 931a9b7ce28SMatti Vaittinen * exceeds threshold. 932a9b7ce28SMatti Vaittinen */ 933a9b7ce28SMatti Vaittinen if (rdesc[i].ldo_errs) { 934a9b7ce28SMatti Vaittinen ldo_errs_rdev_arr[temp_notif_ldos] = rdev; 935a9b7ce28SMatti Vaittinen ldo_errs_arr[temp_notif_ldos] = rdesc[i].ldo_errs; 936a9b7ce28SMatti Vaittinen temp_notif_ldos++; 937a9b7ce28SMatti Vaittinen } 938a9b7ce28SMatti Vaittinen 939a9b7ce28SMatti Vaittinen /* Register INTB handlers for configured protections */ 940a9b7ce28SMatti Vaittinen for (j = 0; j < idesc->num_irqs; j++) { 941a9b7ce28SMatti Vaittinen ret = bd96801_rdev_intb_irqs(pdev, pdata, 942a9b7ce28SMatti Vaittinen &idesc->irqinfo[j], rdev); 943a9b7ce28SMatti Vaittinen if (ret) 944a9b7ce28SMatti Vaittinen return ret; 945a9b7ce28SMatti Vaittinen } 946a8d77166SMatti Vaittinen /* Register per regulator ERRB notifiers */ 947a8d77166SMatti Vaittinen if (use_errb) { 948a8d77166SMatti Vaittinen ret = bd96801_rdev_errb_irqs(pdev, rdev); 949a8d77166SMatti Vaittinen if (ret) 950a8d77166SMatti Vaittinen return ret; 951a8d77166SMatti Vaittinen } 952a9b7ce28SMatti Vaittinen } 953a9b7ce28SMatti Vaittinen if (temp_notif_ldos) { 954a9b7ce28SMatti Vaittinen int irq; 955a9b7ce28SMatti Vaittinen struct regulator_irq_desc tw_desc = { 956*9cc95754SMatti Vaittinen .name = "core-thermal", 957a9b7ce28SMatti Vaittinen .irq_off_ms = 500, 958a9b7ce28SMatti Vaittinen .map_event = ldo_map_notif, 959a9b7ce28SMatti Vaittinen }; 960a9b7ce28SMatti Vaittinen 961*9cc95754SMatti Vaittinen irq = platform_get_irq_byname(pdev, "core-thermal"); 962a9b7ce28SMatti Vaittinen if (irq < 0) 963a9b7ce28SMatti Vaittinen return irq; 964a9b7ce28SMatti Vaittinen 965a9b7ce28SMatti Vaittinen retp = devm_regulator_irq_helper(&pdev->dev, &tw_desc, irq, 0, 966a9b7ce28SMatti Vaittinen 0, &ldo_errs_arr[0], 967a9b7ce28SMatti Vaittinen &ldo_errs_rdev_arr[0], 968a9b7ce28SMatti Vaittinen temp_notif_ldos); 969a9b7ce28SMatti Vaittinen if (IS_ERR(retp)) 970a9b7ce28SMatti Vaittinen return PTR_ERR(retp); 971a9b7ce28SMatti Vaittinen } 972a9b7ce28SMatti Vaittinen 973a8d77166SMatti Vaittinen if (use_errb) 974a8d77166SMatti Vaittinen return bd96801_global_errb_irqs(pdev, all_rdevs, 975a8d77166SMatti Vaittinen ARRAY_SIZE(all_rdevs)); 976a8d77166SMatti Vaittinen 977a9b7ce28SMatti Vaittinen return 0; 978a9b7ce28SMatti Vaittinen } 979a9b7ce28SMatti Vaittinen 980a9b7ce28SMatti Vaittinen static const struct platform_device_id bd96801_pmic_id[] = { 981a9b7ce28SMatti Vaittinen { "bd96801-regulator", }, 982a9b7ce28SMatti Vaittinen { } 983a9b7ce28SMatti Vaittinen }; 984a9b7ce28SMatti Vaittinen MODULE_DEVICE_TABLE(platform, bd96801_pmic_id); 985a9b7ce28SMatti Vaittinen 986a9b7ce28SMatti Vaittinen static struct platform_driver bd96801_regulator = { 987a9b7ce28SMatti Vaittinen .driver = { 988a9b7ce28SMatti Vaittinen .name = "bd96801-pmic" 989a9b7ce28SMatti Vaittinen }, 990a9b7ce28SMatti Vaittinen .probe = bd96801_probe, 991a9b7ce28SMatti Vaittinen .id_table = bd96801_pmic_id, 992a9b7ce28SMatti Vaittinen }; 993a9b7ce28SMatti Vaittinen 994a9b7ce28SMatti Vaittinen module_platform_driver(bd96801_regulator); 995a9b7ce28SMatti Vaittinen 996a9b7ce28SMatti Vaittinen MODULE_AUTHOR("Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>"); 997a9b7ce28SMatti Vaittinen MODULE_DESCRIPTION("BD96801 voltage regulator driver"); 998a9b7ce28SMatti Vaittinen MODULE_LICENSE("GPL"); 999