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