xref: /linux/drivers/regulator/bd96801-regulator.c (revision ed7171ff9fabc49ae6ed42fbd082a576473836fc)
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