Blame view

drivers/mfd/88pm860x-core.c 33.4 KB
d2912cb15   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
2
3
4
5
  /*
   * Base driver for Marvell 88PM8607
   *
   * Copyright (C) 2009 Marvell International Ltd.
2e57848fe   Lee Jones   mfd: 88pm860x-cor...
6
7
   *
   * Author: Haojian Zhuang <haojian.zhuang@marvell.com>
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
8
9
10
11
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
12
  #include <linux/err.h>
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
13
  #include <linux/i2c.h>
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
14
  #include <linux/irq.h>
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
15
  #include <linux/interrupt.h>
837c8293b   Haojian Zhuang   mfd: 88pm860x: Us...
16
  #include <linux/irqdomain.h>
2e57d5674   Haojian Zhuang   mfd: 88pm860x: De...
17
18
  #include <linux/of.h>
  #include <linux/of_platform.h>
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
19
  #include <linux/platform_device.h>
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
20
21
  #include <linux/regmap.h>
  #include <linux/slab.h>
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
22
  #include <linux/mfd/core.h>
53dbab7af   Haojian Zhuang   mfd: Support 88pm...
23
  #include <linux/mfd/88pm860x.h>
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
24
  #include <linux/regulator/machine.h>
a830d28b4   Jett.Zhou   power_supply: Ena...
25
  #include <linux/power/charger-manager.h>
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
26

2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
27
  #define INT_STATUS_NUM			3
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
28
  static struct resource bk0_resources[] = {
a6ccdcd98   Haojian Zhuang   mfd: 88pm860x: Us...
29
30
31
32
  	{2, 2, "duty cycle", IORESOURCE_REG, },
  	{3, 3, "always on",  IORESOURCE_REG, },
  	{3, 3, "current",    IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
33
  static struct resource bk1_resources[] = {
a6ccdcd98   Haojian Zhuang   mfd: 88pm860x: Us...
34
35
36
37
  	{4, 4, "duty cycle", IORESOURCE_REG, },
  	{5, 5, "always on",  IORESOURCE_REG, },
  	{5, 5, "current",    IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
38
  static struct resource bk2_resources[] = {
a6ccdcd98   Haojian Zhuang   mfd: 88pm860x: Us...
39
40
41
  	{6, 6, "duty cycle", IORESOURCE_REG, },
  	{7, 7, "always on",  IORESOURCE_REG, },
  	{5, 5, "current",    IORESOURCE_REG, },
a16122bca   Haojian Zhuang   mfd: Append subde...
42
  };
adb70483f   Haojian Zhuang   mfd: Adopt mfd_da...
43

a9e9ce4c4   Bill Pemberton   mfd: remove use o...
44
  static struct resource led0_resources[] = {
894fc8f2c   Haojian Zhuang   mfd: 88pm860x: Us...
45
46
47
48
  	/* RGB1 Red LED */
  	{0xd, 0xd, "control", IORESOURCE_REG, },
  	{0xc, 0xc, "blink",   IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
49
  static struct resource led1_resources[] = {
894fc8f2c   Haojian Zhuang   mfd: 88pm860x: Us...
50
51
52
53
  	/* RGB1 Green LED */
  	{0xe, 0xe, "control", IORESOURCE_REG, },
  	{0xc, 0xc, "blink",   IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
54
  static struct resource led2_resources[] = {
894fc8f2c   Haojian Zhuang   mfd: 88pm860x: Us...
55
56
57
58
  	/* RGB1 Blue LED */
  	{0xf, 0xf, "control", IORESOURCE_REG, },
  	{0xc, 0xc, "blink",   IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
59
  static struct resource led3_resources[] = {
894fc8f2c   Haojian Zhuang   mfd: 88pm860x: Us...
60
61
62
63
  	/* RGB2 Red LED */
  	{0x9, 0x9, "control", IORESOURCE_REG, },
  	{0x8, 0x8, "blink",   IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
64
  static struct resource led4_resources[] = {
894fc8f2c   Haojian Zhuang   mfd: 88pm860x: Us...
65
66
67
68
  	/* RGB2 Green LED */
  	{0xa, 0xa, "control", IORESOURCE_REG, },
  	{0x8, 0x8, "blink",   IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
69
  static struct resource led5_resources[] = {
894fc8f2c   Haojian Zhuang   mfd: 88pm860x: Us...
70
71
72
  	/* RGB2 Blue LED */
  	{0xb, 0xb, "control", IORESOURCE_REG, },
  	{0x8, 0x8, "blink",   IORESOURCE_REG, },
3154c3446   Haojian Zhuang   mfd: Adopt mfd_da...
73
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
74
  static struct resource buck1_resources[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
75
76
  	{0x24, 0x24, "buck set", IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
77
  static struct resource buck2_resources[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
78
79
  	{0x25, 0x25, "buck set", IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
80
  static struct resource buck3_resources[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
81
82
  	{0x26, 0x26, "buck set", IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
83
  static struct resource ldo1_resources[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
84
85
  	{0x10, 0x10, "ldo set", IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
86
  static struct resource ldo2_resources[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
87
88
  	{0x11, 0x11, "ldo set", IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
89
  static struct resource ldo3_resources[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
90
91
  	{0x12, 0x12, "ldo set", IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
92
  static struct resource ldo4_resources[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
93
94
  	{0x13, 0x13, "ldo set", IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
95
  static struct resource ldo5_resources[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
96
97
  	{0x14, 0x14, "ldo set", IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
98
  static struct resource ldo6_resources[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
99
100
  	{0x15, 0x15, "ldo set", IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
101
  static struct resource ldo7_resources[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
102
103
  	{0x16, 0x16, "ldo set", IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
104
  static struct resource ldo8_resources[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
105
106
  	{0x17, 0x17, "ldo set", IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
107
  static struct resource ldo9_resources[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
108
109
  	{0x18, 0x18, "ldo set", IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
110
  static struct resource ldo10_resources[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
111
112
  	{0x19, 0x19, "ldo set", IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
113
  static struct resource ldo12_resources[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
114
115
  	{0x1a, 0x1a, "ldo set", IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
116
  static struct resource ldo_vibrator_resources[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
117
118
  	{0x28, 0x28, "ldo set", IORESOURCE_REG, },
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
119
  static struct resource ldo14_resources[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
120
  	{0x1b, 0x1b, "ldo set", IORESOURCE_REG, },
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
121
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
122
  static struct resource touch_resources[] = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
123
124
  	{PM8607_IRQ_PEN, PM8607_IRQ_PEN, "touch", IORESOURCE_IRQ,},
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
125
  static struct resource onkey_resources[] = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
126
127
  	{PM8607_IRQ_ONKEY, PM8607_IRQ_ONKEY, "onkey", IORESOURCE_IRQ,},
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
128
  static struct resource codec_resources[] = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
129
130
131
132
133
134
135
  	/* Headset microphone insertion or removal */
  	{PM8607_IRQ_MICIN,   PM8607_IRQ_MICIN,   "micin",   IORESOURCE_IRQ,},
  	/* Hook-switch press or release */
  	{PM8607_IRQ_HOOK,    PM8607_IRQ_HOOK,    "hook",    IORESOURCE_IRQ,},
  	/* Headset insertion or removal */
  	{PM8607_IRQ_HEADSET, PM8607_IRQ_HEADSET, "headset", IORESOURCE_IRQ,},
  	/* Audio short */
2e57848fe   Lee Jones   mfd: 88pm860x-cor...
136
137
  	{PM8607_IRQ_AUDIO_SHORT, PM8607_IRQ_AUDIO_SHORT, "audio-short",
  	 IORESOURCE_IRQ,},
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
138
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
139
  static struct resource battery_resources[] = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
140
141
142
  	{PM8607_IRQ_CC,  PM8607_IRQ_CC,  "columb counter", IORESOURCE_IRQ,},
  	{PM8607_IRQ_BAT, PM8607_IRQ_BAT, "battery",        IORESOURCE_IRQ,},
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
143
  static struct resource charger_resources[] = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
144
  	{PM8607_IRQ_CHG,  PM8607_IRQ_CHG,  "charger detect",  IORESOURCE_IRQ,},
2e57848fe   Lee Jones   mfd: 88pm860x-cor...
145
146
147
148
149
150
151
152
  	{PM8607_IRQ_CHG_DONE,  PM8607_IRQ_CHG_DONE,  "charging done",
  	 IORESOURCE_IRQ,},
  	{PM8607_IRQ_CHG_FAIL,  PM8607_IRQ_CHG_FAIL,  "charging timeout",
  	 IORESOURCE_IRQ,},
  	{PM8607_IRQ_CHG_FAULT, PM8607_IRQ_CHG_FAULT, "charging fault",
  	 IORESOURCE_IRQ,},
  	{PM8607_IRQ_GPADC1,    PM8607_IRQ_GPADC1,    "battery temperature",
  	 IORESOURCE_IRQ,},
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
153
154
155
  	{PM8607_IRQ_VBAT, PM8607_IRQ_VBAT, "battery voltage", IORESOURCE_IRQ,},
  	{PM8607_IRQ_VCHG, PM8607_IRQ_VCHG, "vchg voltage",    IORESOURCE_IRQ,},
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
156
  static struct resource rtc_resources[] = {
023670295   Mark Brown   mfd: 88pm860x: Co...
157
  	{PM8607_IRQ_RTC, PM8607_IRQ_RTC, "rtc", IORESOURCE_IRQ,},
008b30408   Haojian Zhuang   mfd: Add rtc supp...
158
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
159
  static struct mfd_cell bk_devs[] = {
a6ccdcd98   Haojian Zhuang   mfd: 88pm860x: Us...
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
  	{
  		.name = "88pm860x-backlight",
  		.id = 0,
  		.num_resources = ARRAY_SIZE(bk0_resources),
  		.resources = bk0_resources,
  	}, {
  		.name = "88pm860x-backlight",
  		.id = 1,
  		.num_resources = ARRAY_SIZE(bk1_resources),
  		.resources = bk1_resources,
  	}, {
  		.name = "88pm860x-backlight",
  		.id = 2,
  		.num_resources = ARRAY_SIZE(bk2_resources),
  		.resources = bk2_resources,
  	},
adb70483f   Haojian Zhuang   mfd: Adopt mfd_da...
176
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
177
  static struct mfd_cell led_devs[] = {
894fc8f2c   Haojian Zhuang   mfd: 88pm860x: Us...
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
  	{
  		.name = "88pm860x-led",
  		.id = 0,
  		.num_resources = ARRAY_SIZE(led0_resources),
  		.resources = led0_resources,
  	}, {
  		.name = "88pm860x-led",
  		.id = 1,
  		.num_resources = ARRAY_SIZE(led1_resources),
  		.resources = led1_resources,
  	}, {
  		.name = "88pm860x-led",
  		.id = 2,
  		.num_resources = ARRAY_SIZE(led2_resources),
  		.resources = led2_resources,
  	}, {
  		.name = "88pm860x-led",
  		.id = 3,
  		.num_resources = ARRAY_SIZE(led3_resources),
  		.resources = led3_resources,
  	}, {
  		.name = "88pm860x-led",
  		.id = 4,
  		.num_resources = ARRAY_SIZE(led4_resources),
  		.resources = led4_resources,
  	}, {
  		.name = "88pm860x-led",
  		.id = 5,
  		.num_resources = ARRAY_SIZE(led5_resources),
  		.resources = led5_resources,
  	},
a16122bca   Haojian Zhuang   mfd: Append subde...
209
  };
a9e9ce4c4   Bill Pemberton   mfd: remove use o...
210
  static struct mfd_cell reg_devs[] = {
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
  	{
  		.name = "88pm860x-regulator",
  		.id = 0,
  		.num_resources = ARRAY_SIZE(buck1_resources),
  		.resources = buck1_resources,
  	}, {
  		.name = "88pm860x-regulator",
  		.id = 1,
  		.num_resources = ARRAY_SIZE(buck2_resources),
  		.resources = buck2_resources,
  	}, {
  		.name = "88pm860x-regulator",
  		.id = 2,
  		.num_resources = ARRAY_SIZE(buck3_resources),
  		.resources = buck3_resources,
  	}, {
  		.name = "88pm860x-regulator",
  		.id = 3,
  		.num_resources = ARRAY_SIZE(ldo1_resources),
  		.resources = ldo1_resources,
  	}, {
  		.name = "88pm860x-regulator",
  		.id = 4,
  		.num_resources = ARRAY_SIZE(ldo2_resources),
  		.resources = ldo2_resources,
  	}, {
  		.name = "88pm860x-regulator",
  		.id = 5,
  		.num_resources = ARRAY_SIZE(ldo3_resources),
  		.resources = ldo3_resources,
  	}, {
  		.name = "88pm860x-regulator",
  		.id = 6,
  		.num_resources = ARRAY_SIZE(ldo4_resources),
  		.resources = ldo4_resources,
  	}, {
  		.name = "88pm860x-regulator",
  		.id = 7,
  		.num_resources = ARRAY_SIZE(ldo5_resources),
  		.resources = ldo5_resources,
  	}, {
  		.name = "88pm860x-regulator",
  		.id = 8,
  		.num_resources = ARRAY_SIZE(ldo6_resources),
  		.resources = ldo6_resources,
  	}, {
  		.name = "88pm860x-regulator",
  		.id = 9,
  		.num_resources = ARRAY_SIZE(ldo7_resources),
  		.resources = ldo7_resources,
  	}, {
  		.name = "88pm860x-regulator",
  		.id = 10,
  		.num_resources = ARRAY_SIZE(ldo8_resources),
  		.resources = ldo8_resources,
  	}, {
  		.name = "88pm860x-regulator",
  		.id = 11,
  		.num_resources = ARRAY_SIZE(ldo9_resources),
  		.resources = ldo9_resources,
  	}, {
  		.name = "88pm860x-regulator",
  		.id = 12,
  		.num_resources = ARRAY_SIZE(ldo10_resources),
  		.resources = ldo10_resources,
  	}, {
  		.name = "88pm860x-regulator",
  		.id = 13,
  		.num_resources = ARRAY_SIZE(ldo12_resources),
  		.resources = ldo12_resources,
  	}, {
  		.name = "88pm860x-regulator",
  		.id = 14,
  		.num_resources = ARRAY_SIZE(ldo_vibrator_resources),
  		.resources = ldo_vibrator_resources,
  	}, {
  		.name = "88pm860x-regulator",
  		.id = 15,
  		.num_resources = ARRAY_SIZE(ldo14_resources),
  		.resources = ldo14_resources,
  	},
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
292
  };
a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
293
  static struct mfd_cell touch_devs[] = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
294
  	{"88pm860x-touch", -1,},
a16122bca   Haojian Zhuang   mfd: Append subde...
295
  };
a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
296
  static struct mfd_cell onkey_devs[] = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
297
  	{"88pm860x-onkey", -1,},
a16122bca   Haojian Zhuang   mfd: Append subde...
298
  };
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
299

a5156f1ad   Haojian Zhuang   mfd: Fix build wa...
300
  static struct mfd_cell codec_devs[] = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
301
  	{"88pm860x-codec", -1,},
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
302
  };
2573f6d36   Jett.Zhou   mfd: Add pre-regu...
303
304
305
306
307
308
309
310
  static struct regulator_consumer_supply preg_supply[] = {
  	REGULATOR_SUPPLY("preg", "charger-manager"),
  };
  
  static struct regulator_init_data preg_init_data = {
  	.num_consumer_supplies	= ARRAY_SIZE(preg_supply),
  	.consumer_supplies	= &preg_supply[0],
  };
f1ade3525   Anton Vorontsov   88pm860x_battery ...
311
312
  static struct charger_regulator chg_desc_regulator_data[] = {
  	{ .regulator_name = "preg", },
a830d28b4   Jett.Zhou   power_supply: Ena...
313
  };
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
314
  static struct mfd_cell power_devs[] = {
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
315
316
  	{"88pm860x-battery", -1,},
  	{"88pm860x-charger", -1,},
2573f6d36   Jett.Zhou   mfd: Add pre-regu...
317
  	{"88pm860x-preg",    -1,},
a830d28b4   Jett.Zhou   power_supply: Ena...
318
  	{"charger-manager", -1,},
2c36af7b5   Haojian Zhuang   mfd: Add codec re...
319
  };
008b30408   Haojian Zhuang   mfd: Add rtc supp...
320
321
322
  static struct mfd_cell rtc_devs[] = {
  	{"88pm860x-rtc", -1,},
  };
2c36af7b5   Haojian Zhuang   mfd: Add codec re...
323

2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
324
325
326
327
328
329
  struct pm860x_irq_data {
  	int	reg;
  	int	mask_reg;
  	int	enable;		/* enable or not */
  	int	offs;		/* bit offset in mask register */
  };
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
330

2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
  static struct pm860x_irq_data pm860x_irqs[] = {
  	[PM8607_IRQ_ONKEY] = {
  		.reg		= PM8607_INT_STATUS1,
  		.mask_reg	= PM8607_INT_MASK_1,
  		.offs		= 1 << 0,
  	},
  	[PM8607_IRQ_EXTON] = {
  		.reg		= PM8607_INT_STATUS1,
  		.mask_reg	= PM8607_INT_MASK_1,
  		.offs		= 1 << 1,
  	},
  	[PM8607_IRQ_CHG] = {
  		.reg		= PM8607_INT_STATUS1,
  		.mask_reg	= PM8607_INT_MASK_1,
  		.offs		= 1 << 2,
  	},
  	[PM8607_IRQ_BAT] = {
  		.reg		= PM8607_INT_STATUS1,
  		.mask_reg	= PM8607_INT_MASK_1,
  		.offs		= 1 << 3,
  	},
  	[PM8607_IRQ_RTC] = {
  		.reg		= PM8607_INT_STATUS1,
  		.mask_reg	= PM8607_INT_MASK_1,
  		.offs		= 1 << 4,
  	},
  	[PM8607_IRQ_CC] = {
  		.reg		= PM8607_INT_STATUS1,
  		.mask_reg	= PM8607_INT_MASK_1,
  		.offs		= 1 << 5,
  	},
  	[PM8607_IRQ_VBAT] = {
  		.reg		= PM8607_INT_STATUS2,
  		.mask_reg	= PM8607_INT_MASK_2,
  		.offs		= 1 << 0,
  	},
  	[PM8607_IRQ_VCHG] = {
  		.reg		= PM8607_INT_STATUS2,
  		.mask_reg	= PM8607_INT_MASK_2,
  		.offs		= 1 << 1,
  	},
  	[PM8607_IRQ_VSYS] = {
  		.reg		= PM8607_INT_STATUS2,
  		.mask_reg	= PM8607_INT_MASK_2,
  		.offs		= 1 << 2,
  	},
  	[PM8607_IRQ_TINT] = {
  		.reg		= PM8607_INT_STATUS2,
  		.mask_reg	= PM8607_INT_MASK_2,
  		.offs		= 1 << 3,
  	},
  	[PM8607_IRQ_GPADC0] = {
  		.reg		= PM8607_INT_STATUS2,
  		.mask_reg	= PM8607_INT_MASK_2,
  		.offs		= 1 << 4,
  	},
  	[PM8607_IRQ_GPADC1] = {
  		.reg		= PM8607_INT_STATUS2,
  		.mask_reg	= PM8607_INT_MASK_2,
  		.offs		= 1 << 5,
  	},
  	[PM8607_IRQ_GPADC2] = {
  		.reg		= PM8607_INT_STATUS2,
  		.mask_reg	= PM8607_INT_MASK_2,
  		.offs		= 1 << 6,
  	},
  	[PM8607_IRQ_GPADC3] = {
  		.reg		= PM8607_INT_STATUS2,
  		.mask_reg	= PM8607_INT_MASK_2,
  		.offs		= 1 << 7,
  	},
  	[PM8607_IRQ_AUDIO_SHORT] = {
  		.reg		= PM8607_INT_STATUS3,
  		.mask_reg	= PM8607_INT_MASK_3,
  		.offs		= 1 << 0,
  	},
  	[PM8607_IRQ_PEN] = {
  		.reg		= PM8607_INT_STATUS3,
  		.mask_reg	= PM8607_INT_MASK_3,
  		.offs		= 1 << 1,
  	},
  	[PM8607_IRQ_HEADSET] = {
  		.reg		= PM8607_INT_STATUS3,
  		.mask_reg	= PM8607_INT_MASK_3,
  		.offs		= 1 << 2,
  	},
  	[PM8607_IRQ_HOOK] = {
  		.reg		= PM8607_INT_STATUS3,
  		.mask_reg	= PM8607_INT_MASK_3,
  		.offs		= 1 << 3,
  	},
  	[PM8607_IRQ_MICIN] = {
  		.reg		= PM8607_INT_STATUS3,
  		.mask_reg	= PM8607_INT_MASK_3,
  		.offs		= 1 << 4,
  	},
  	[PM8607_IRQ_CHG_FAIL] = {
  		.reg		= PM8607_INT_STATUS3,
  		.mask_reg	= PM8607_INT_MASK_3,
  		.offs		= 1 << 5,
  	},
  	[PM8607_IRQ_CHG_DONE] = {
  		.reg		= PM8607_INT_STATUS3,
  		.mask_reg	= PM8607_INT_MASK_3,
  		.offs		= 1 << 6,
  	},
  	[PM8607_IRQ_CHG_FAULT] = {
  		.reg		= PM8607_INT_STATUS3,
  		.mask_reg	= PM8607_INT_MASK_3,
  		.offs		= 1 << 7,
  	},
  };
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
443

2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
444
  static irqreturn_t pm860x_irq(int irq, void *data)
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
445
  {
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
446
  	struct pm860x_chip *chip = data;
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
447
448
449
450
451
452
453
454
455
456
457
  	struct pm860x_irq_data *irq_data;
  	struct i2c_client *i2c;
  	int read_reg = -1, value = 0;
  	int i;
  
  	i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
  	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
  		irq_data = &pm860x_irqs[i];
  		if (read_reg != irq_data->reg) {
  			read_reg = irq_data->reg;
  			value = pm860x_reg_read(i2c, irq_data->reg);
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
458
  		}
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
459
460
  		if (value & irq_data->enable)
  			handle_nested_irq(chip->irq_base + i);
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
461
  	}
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
462
463
  	return IRQ_HANDLED;
  }
49f89d9ac   Mark Brown   mfd: Convert 88PM...
464
  static void pm860x_irq_lock(struct irq_data *data)
53dbab7af   Haojian Zhuang   mfd: Support 88pm...
465
  {
49f89d9ac   Mark Brown   mfd: Convert 88PM...
466
  	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
467
468
  
  	mutex_lock(&chip->irq_lock);
53dbab7af   Haojian Zhuang   mfd: Support 88pm...
469
  }
49f89d9ac   Mark Brown   mfd: Convert 88PM...
470
  static void pm860x_irq_sync_unlock(struct irq_data *data)
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
471
  {
49f89d9ac   Mark Brown   mfd: Convert 88PM...
472
  	struct pm860x_chip *chip = irq_data_get_irq_chip_data(data);
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
  	struct pm860x_irq_data *irq_data;
  	struct i2c_client *i2c;
  	static unsigned char cached[3] = {0x0, 0x0, 0x0};
  	unsigned char mask[3];
  	int i;
  
  	i2c = (chip->id == CHIP_PM8607) ? chip->client : chip->companion;
  	/* Load cached value. In initial, all IRQs are masked */
  	for (i = 0; i < 3; i++)
  		mask[i] = cached[i];
  	for (i = 0; i < ARRAY_SIZE(pm860x_irqs); i++) {
  		irq_data = &pm860x_irqs[i];
  		switch (irq_data->mask_reg) {
  		case PM8607_INT_MASK_1:
  			mask[0] &= ~irq_data->offs;
  			mask[0] |= irq_data->enable;
  			break;
  		case PM8607_INT_MASK_2:
  			mask[1] &= ~irq_data->offs;
  			mask[1] |= irq_data->enable;
  			break;
  		case PM8607_INT_MASK_3:
  			mask[2] &= ~irq_data->offs;
  			mask[2] |= irq_data->enable;
  			break;
  		default:
  			dev_err(chip->dev, "wrong IRQ
  ");
  			break;
  		}
  	}
  	/* update mask into registers */
  	for (i = 0; i < 3; i++) {
  		if (mask[i] != cached[i]) {
  			cached[i] = mask[i];
  			pm860x_reg_write(i2c, PM8607_INT_MASK_1 + i, mask[i]);
  		}
  	}
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
511

5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
512
  	mutex_unlock(&chip->irq_lock);
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
513
  }
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
514

49f89d9ac   Mark Brown   mfd: Convert 88PM...
515
  static void pm860x_irq_enable(struct irq_data *data)
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
516
  {
837c8293b   Haojian Zhuang   mfd: 88pm860x: Us...
517
  	pm860x_irqs[data->hwirq].enable = pm860x_irqs[data->hwirq].offs;
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
518
  }
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
519

49f89d9ac   Mark Brown   mfd: Convert 88PM...
520
  static void pm860x_irq_disable(struct irq_data *data)
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
521
  {
837c8293b   Haojian Zhuang   mfd: 88pm860x: Us...
522
  	pm860x_irqs[data->hwirq].enable = 0;
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
523
524
525
526
  }
  
  static struct irq_chip pm860x_irq_chip = {
  	.name		= "88pm860x",
49f89d9ac   Mark Brown   mfd: Convert 88PM...
527
528
529
530
  	.irq_bus_lock	= pm860x_irq_lock,
  	.irq_bus_sync_unlock = pm860x_irq_sync_unlock,
  	.irq_enable	= pm860x_irq_enable,
  	.irq_disable	= pm860x_irq_disable,
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
531
  };
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
532

837c8293b   Haojian Zhuang   mfd: 88pm860x: Us...
533
534
535
536
537
538
  static int pm860x_irq_domain_map(struct irq_domain *d, unsigned int virq,
  				 irq_hw_number_t hw)
  {
  	irq_set_chip_data(virq, d->host_data);
  	irq_set_chip_and_handler(virq, &pm860x_irq_chip, handle_edge_irq);
  	irq_set_nested_thread(virq, 1);
837c8293b   Haojian Zhuang   mfd: 88pm860x: Us...
539
  	irq_set_noprobe(virq);
837c8293b   Haojian Zhuang   mfd: 88pm860x: Us...
540
541
  	return 0;
  }
7ce7b26f8   Krzysztof Kozlowski   mfd: Constify reg...
542
  static const struct irq_domain_ops pm860x_irq_domain_ops = {
837c8293b   Haojian Zhuang   mfd: 88pm860x: Us...
543
544
545
  	.map	= pm860x_irq_domain_map,
  	.xlate	= irq_domain_xlate_onetwocell,
  };
f791be492   Bill Pemberton   mfd: remove use o...
546
  static int device_irq_init(struct pm860x_chip *chip,
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
547
548
  				     struct pm860x_platform_data *pdata)
  {
2e57848fe   Lee Jones   mfd: 88pm860x-cor...
549
550
  	struct i2c_client *i2c = (chip->id == CHIP_PM8607) ?
  		chip->client : chip->companion;
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
551
  	unsigned char status_buf[INT_STATUS_NUM];
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
552
  	unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
837c8293b   Haojian Zhuang   mfd: 88pm860x: Us...
553
554
555
  	int data, mask, ret = -EINVAL;
  	int nr_irqs, irq_base = -1;
  	struct device_node *node = i2c->dev.of_node;
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
  
  	mask = PM8607_B0_MISC1_INV_INT | PM8607_B0_MISC1_INT_CLEAR
  		| PM8607_B0_MISC1_INT_MASK;
  	data = 0;
  	chip->irq_mode = 0;
  	if (pdata && pdata->irq_mode) {
  		/*
  		 * irq_mode defines the way of clearing interrupt. If it's 1,
  		 * clear IRQ by write. Otherwise, clear it by read.
  		 * This control bit is valid from 88PM8607 B0 steping.
  		 */
  		data |= PM8607_B0_MISC1_INT_CLEAR;
  		chip->irq_mode = 1;
  	}
  	ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, mask, data);
  	if (ret < 0)
  		goto out;
  
  	/* mask all IRQs */
  	memset(status_buf, 0, INT_STATUS_NUM);
  	ret = pm860x_bulk_write(i2c, PM8607_INT_MASK_1,
  				INT_STATUS_NUM, status_buf);
  	if (ret < 0)
  		goto out;
  
  	if (chip->irq_mode) {
  		/* clear interrupt status by write */
  		memset(status_buf, 0xFF, INT_STATUS_NUM);
  		ret = pm860x_bulk_write(i2c, PM8607_INT_STATUS1,
  					INT_STATUS_NUM, status_buf);
  	} else {
  		/* clear interrupt status by read */
  		ret = pm860x_bulk_read(i2c, PM8607_INT_STATUS1,
  					INT_STATUS_NUM, status_buf);
  	}
  	if (ret < 0)
  		goto out;
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
593
  	mutex_init(&chip->irq_lock);
837c8293b   Haojian Zhuang   mfd: 88pm860x: Us...
594
595
596
597
598
599
600
601
602
603
604
605
606
607
  
  	if (pdata && pdata->irq_base)
  		irq_base = pdata->irq_base;
  	nr_irqs = ARRAY_SIZE(pm860x_irqs);
  	chip->irq_base = irq_alloc_descs(irq_base, 0, nr_irqs, 0);
  	if (chip->irq_base < 0) {
  		dev_err(&i2c->dev, "Failed to allocate interrupts, ret:%d
  ",
  			chip->irq_base);
  		ret = -EBUSY;
  		goto out;
  	}
  	irq_domain_add_legacy(node, nr_irqs, chip->irq_base, 0,
  			      &pm860x_irq_domain_ops, chip);
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
608
609
  	chip->core_irq = i2c->irq;
  	if (!chip->core_irq)
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
610
  		goto out;
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
611

2e57848fe   Lee Jones   mfd: 88pm860x-cor...
612
613
  	ret = request_threaded_irq(chip->core_irq, NULL, pm860x_irq,
  				   flags | IRQF_ONESHOT, "88pm860x", chip);
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
614
615
616
617
618
  	if (ret) {
  		dev_err(chip->dev, "Failed to request IRQ: %d
  ", ret);
  		chip->core_irq = 0;
  	}
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
619
620
  	return 0;
  out:
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
621
  	chip->core_irq = 0;
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
622
623
  	return ret;
  }
872c1b14e   Henrik Kretzschmar   mfd: Section clea...
624
  static void device_irq_exit(struct pm860x_chip *chip)
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
625
  {
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
626
627
  	if (chip->core_irq)
  		free_irq(chip->core_irq, chip);
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
628
  }
23de435a5   Jett.Zhou   mfd: Add power co...
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
  int pm8606_osc_enable(struct pm860x_chip *chip, unsigned short client)
  {
  	int ret = -EIO;
  	struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
  		chip->client : chip->companion;
  
  	dev_dbg(chip->dev, "%s(B): client=0x%x
  ", __func__, client);
  	dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d
  ",
  			__func__, chip->osc_vote,
  			chip->osc_status);
  
  	mutex_lock(&chip->osc_lock);
  	/* Update voting status */
  	chip->osc_vote |= client;
  	/* If reference group is off - turn on*/
  	if (chip->osc_status != PM8606_REF_GP_OSC_ON) {
  		chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
  		/* Enable Reference group Vsys */
  		if (pm860x_set_bits(i2c, PM8606_VSYS,
  				PM8606_VSYS_EN, PM8606_VSYS_EN))
  			goto out;
  
  		/*Enable Internal Oscillator */
  		if (pm860x_set_bits(i2c, PM8606_MISC,
  				PM8606_MISC_OSC_EN, PM8606_MISC_OSC_EN))
  			goto out;
  		/* Update status (only if writes succeed) */
  		chip->osc_status = PM8606_REF_GP_OSC_ON;
  	}
  	mutex_unlock(&chip->osc_lock);
  
  	dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d
  ",
  			__func__, chip->osc_vote,
  			chip->osc_status, ret);
  	return 0;
  out:
  	mutex_unlock(&chip->osc_lock);
  	return ret;
  }
2f5f89be6   Samuel Ortiz   mfd: Fix pm8606 b...
671
  EXPORT_SYMBOL(pm8606_osc_enable);
23de435a5   Jett.Zhou   mfd: Add power co...
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
  
  int pm8606_osc_disable(struct pm860x_chip *chip, unsigned short client)
  {
  	int ret = -EIO;
  	struct i2c_client *i2c = (chip->id == CHIP_PM8606) ?
  		chip->client : chip->companion;
  
  	dev_dbg(chip->dev, "%s(B): client=0x%x
  ", __func__, client);
  	dev_dbg(chip->dev, "%s(B): vote=0x%x status=%d
  ",
  			__func__, chip->osc_vote,
  			chip->osc_status);
  
  	mutex_lock(&chip->osc_lock);
f90dff446   Lee Jones   mfd: 88pm860x-cor...
687
  	/* Update voting status */
23de435a5   Jett.Zhou   mfd: Add power co...
688
  	chip->osc_vote &= ~(client);
f90dff446   Lee Jones   mfd: 88pm860x-cor...
689
690
691
692
  	/*
  	 * If reference group is off and this is the last client to release
  	 * - turn off
  	 */
23de435a5   Jett.Zhou   mfd: Add power co...
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
  	if ((chip->osc_status != PM8606_REF_GP_OSC_OFF) &&
  			(chip->osc_vote == REF_GP_NO_CLIENTS)) {
  		chip->osc_status = PM8606_REF_GP_OSC_UNKNOWN;
  		/* Disable Reference group Vsys */
  		if (pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0))
  			goto out;
  		/* Disable Internal Oscillator */
  		if (pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0))
  			goto out;
  		chip->osc_status = PM8606_REF_GP_OSC_OFF;
  	}
  	mutex_unlock(&chip->osc_lock);
  
  	dev_dbg(chip->dev, "%s(A): vote=0x%x status=%d ret=%d
  ",
  			__func__, chip->osc_vote,
  			chip->osc_status, ret);
  	return 0;
  out:
  	mutex_unlock(&chip->osc_lock);
  	return ret;
  }
2f5f89be6   Samuel Ortiz   mfd: Fix pm8606 b...
715
  EXPORT_SYMBOL(pm8606_osc_disable);
23de435a5   Jett.Zhou   mfd: Add power co...
716

f791be492   Bill Pemberton   mfd: remove use o...
717
  static void device_osc_init(struct i2c_client *i2c)
23de435a5   Jett.Zhou   mfd: Add power co...
718
719
720
721
722
723
724
725
726
727
728
729
730
  {
  	struct pm860x_chip *chip = i2c_get_clientdata(i2c);
  
  	mutex_init(&chip->osc_lock);
  	/* init portofino reference group voting and status */
  	/* Disable Reference group Vsys */
  	pm860x_set_bits(i2c, PM8606_VSYS, PM8606_VSYS_EN, 0);
  	/* Disable Internal Oscillator */
  	pm860x_set_bits(i2c, PM8606_MISC, PM8606_MISC_OSC_EN, 0);
  
  	chip->osc_vote = REF_GP_NO_CLIENTS;
  	chip->osc_status = PM8606_REF_GP_OSC_OFF;
  }
f791be492   Bill Pemberton   mfd: remove use o...
731
  static void device_bk_init(struct pm860x_chip *chip,
adb70483f   Haojian Zhuang   mfd: Adopt mfd_da...
732
733
  				     struct pm860x_platform_data *pdata)
  {
a6ccdcd98   Haojian Zhuang   mfd: 88pm860x: Us...
734
735
736
737
738
739
740
741
742
  	int ret, i;
  
  	if (pdata && pdata->backlight) {
  		if (pdata->num_backlights > ARRAY_SIZE(bk_devs))
  			pdata->num_backlights = ARRAY_SIZE(bk_devs);
  		for (i = 0; i < pdata->num_backlights; i++) {
  			bk_devs[i].platform_data = &pdata->backlight[i];
  			bk_devs[i].pdata_size =
  				sizeof(struct pm860x_backlight_pdata);
adb70483f   Haojian Zhuang   mfd: Adopt mfd_da...
743
744
  		}
  	}
a6ccdcd98   Haojian Zhuang   mfd: 88pm860x: Us...
745
  	ret = mfd_add_devices(chip->dev, 0, bk_devs,
55692af5e   Mark Brown   mfd: core: Push i...
746
  			      ARRAY_SIZE(bk_devs), NULL, 0, NULL);
a6ccdcd98   Haojian Zhuang   mfd: 88pm860x: Us...
747
748
749
  	if (ret < 0)
  		dev_err(chip->dev, "Failed to add backlight subdev
  ");
adb70483f   Haojian Zhuang   mfd: Adopt mfd_da...
750
  }
f791be492   Bill Pemberton   mfd: remove use o...
751
  static void device_led_init(struct pm860x_chip *chip,
3154c3446   Haojian Zhuang   mfd: Adopt mfd_da...
752
  				      struct pm860x_platform_data *pdata)
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
753
  {
894fc8f2c   Haojian Zhuang   mfd: 88pm860x: Us...
754
  	int ret, i;
3154c3446   Haojian Zhuang   mfd: Adopt mfd_da...
755

894fc8f2c   Haojian Zhuang   mfd: 88pm860x: Us...
756
757
758
759
760
761
762
  	if (pdata && pdata->led) {
  		if (pdata->num_leds > ARRAY_SIZE(led_devs))
  			pdata->num_leds = ARRAY_SIZE(led_devs);
  		for (i = 0; i < pdata->num_leds; i++) {
  			led_devs[i].platform_data = &pdata->led[i];
  			led_devs[i].pdata_size =
  				sizeof(struct pm860x_led_pdata);
a16122bca   Haojian Zhuang   mfd: Append subde...
763
764
  		}
  	}
894fc8f2c   Haojian Zhuang   mfd: 88pm860x: Us...
765
  	ret = mfd_add_devices(chip->dev, 0, led_devs,
55692af5e   Mark Brown   mfd: core: Push i...
766
  			      ARRAY_SIZE(led_devs), NULL, 0, NULL);
894fc8f2c   Haojian Zhuang   mfd: 88pm860x: Us...
767
768
769
770
771
  	if (ret < 0) {
  		dev_err(chip->dev, "Failed to add led subdev
  ");
  		return;
  	}
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
772
  }
f791be492   Bill Pemberton   mfd: remove use o...
773
  static void device_regulator_init(struct pm860x_chip *chip,
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
774
775
  					    struct pm860x_platform_data *pdata)
  {
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
776
  	int ret;
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
777

a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
  	if (pdata == NULL)
  		return;
  	if (pdata->buck1) {
  		reg_devs[0].platform_data = pdata->buck1;
  		reg_devs[0].pdata_size = sizeof(struct regulator_init_data);
  	}
  	if (pdata->buck2) {
  		reg_devs[1].platform_data = pdata->buck2;
  		reg_devs[1].pdata_size = sizeof(struct regulator_init_data);
  	}
  	if (pdata->buck3) {
  		reg_devs[2].platform_data = pdata->buck3;
  		reg_devs[2].pdata_size = sizeof(struct regulator_init_data);
  	}
  	if (pdata->ldo1) {
  		reg_devs[3].platform_data = pdata->ldo1;
  		reg_devs[3].pdata_size = sizeof(struct regulator_init_data);
  	}
  	if (pdata->ldo2) {
  		reg_devs[4].platform_data = pdata->ldo2;
  		reg_devs[4].pdata_size = sizeof(struct regulator_init_data);
  	}
  	if (pdata->ldo3) {
  		reg_devs[5].platform_data = pdata->ldo3;
  		reg_devs[5].pdata_size = sizeof(struct regulator_init_data);
  	}
  	if (pdata->ldo4) {
  		reg_devs[6].platform_data = pdata->ldo4;
  		reg_devs[6].pdata_size = sizeof(struct regulator_init_data);
  	}
  	if (pdata->ldo5) {
  		reg_devs[7].platform_data = pdata->ldo5;
  		reg_devs[7].pdata_size = sizeof(struct regulator_init_data);
  	}
  	if (pdata->ldo6) {
  		reg_devs[8].platform_data = pdata->ldo6;
  		reg_devs[8].pdata_size = sizeof(struct regulator_init_data);
  	}
  	if (pdata->ldo7) {
  		reg_devs[9].platform_data = pdata->ldo7;
  		reg_devs[9].pdata_size = sizeof(struct regulator_init_data);
  	}
  	if (pdata->ldo8) {
  		reg_devs[10].platform_data = pdata->ldo8;
  		reg_devs[10].pdata_size = sizeof(struct regulator_init_data);
  	}
  	if (pdata->ldo9) {
  		reg_devs[11].platform_data = pdata->ldo9;
  		reg_devs[11].pdata_size = sizeof(struct regulator_init_data);
  	}
  	if (pdata->ldo10) {
  		reg_devs[12].platform_data = pdata->ldo10;
  		reg_devs[12].pdata_size = sizeof(struct regulator_init_data);
  	}
  	if (pdata->ldo12) {
  		reg_devs[13].platform_data = pdata->ldo12;
  		reg_devs[13].pdata_size = sizeof(struct regulator_init_data);
  	}
  	if (pdata->ldo_vibrator) {
  		reg_devs[14].platform_data = pdata->ldo_vibrator;
  		reg_devs[14].pdata_size = sizeof(struct regulator_init_data);
  	}
  	if (pdata->ldo14) {
  		reg_devs[15].platform_data = pdata->ldo14;
  		reg_devs[15].pdata_size = sizeof(struct regulator_init_data);
  	}
  	ret = mfd_add_devices(chip->dev, 0, reg_devs,
55692af5e   Mark Brown   mfd: core: Push i...
845
  			      ARRAY_SIZE(reg_devs), NULL, 0, NULL);
a70abacb0   Haojian Zhuang   mfd: 88pm860x: Us...
846
847
848
  	if (ret < 0) {
  		dev_err(chip->dev, "Failed to add regulator subdev
  ");
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
849
  		return;
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
850
  	}
22aad0011   Haojian Zhuang   mfd: Adopt mfd_da...
851
  }
f791be492   Bill Pemberton   mfd: remove use o...
852
  static void device_rtc_init(struct pm860x_chip *chip,
008b30408   Haojian Zhuang   mfd: Add rtc supp...
853
854
855
  				      struct pm860x_platform_data *pdata)
  {
  	int ret;
2e57848fe   Lee Jones   mfd: 88pm860x-cor...
856
  	if (!pdata)
008b30408   Haojian Zhuang   mfd: Add rtc supp...
857
858
859
860
861
862
863
864
  		return;
  
  	rtc_devs[0].platform_data = pdata->rtc;
  	rtc_devs[0].pdata_size = sizeof(struct pm860x_rtc_pdata);
  	rtc_devs[0].num_resources = ARRAY_SIZE(rtc_resources);
  	rtc_devs[0].resources = &rtc_resources[0];
  	ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
  			      ARRAY_SIZE(rtc_devs), &rtc_resources[0],
55692af5e   Mark Brown   mfd: core: Push i...
865
  			      chip->irq_base, NULL);
008b30408   Haojian Zhuang   mfd: Add rtc supp...
866
867
868
869
  	if (ret < 0)
  		dev_err(chip->dev, "Failed to add rtc subdev
  ");
  }
f791be492   Bill Pemberton   mfd: remove use o...
870
  static void device_touch_init(struct pm860x_chip *chip,
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
871
872
873
  					struct pm860x_platform_data *pdata)
  {
  	int ret;
f5fb758de   Haojian Zhuang   mfd: Avoid to all...
874
  	if (pdata == NULL)
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
875
  		return;
f5fb758de   Haojian Zhuang   mfd: Avoid to all...
876
877
  	touch_devs[0].platform_data = pdata->touch;
  	touch_devs[0].pdata_size = sizeof(struct pm860x_touch_pdata);
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
878
879
880
881
  	touch_devs[0].num_resources = ARRAY_SIZE(touch_resources);
  	touch_devs[0].resources = &touch_resources[0];
  	ret = mfd_add_devices(chip->dev, 0, &touch_devs[0],
  			      ARRAY_SIZE(touch_devs), &touch_resources[0],
55692af5e   Mark Brown   mfd: core: Push i...
882
  			      chip->irq_base, NULL);
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
883
884
885
886
  	if (ret < 0)
  		dev_err(chip->dev, "Failed to add touch subdev
  ");
  }
f791be492   Bill Pemberton   mfd: remove use o...
887
  static void device_power_init(struct pm860x_chip *chip,
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
888
889
890
  					struct pm860x_platform_data *pdata)
  {
  	int ret;
f5fb758de   Haojian Zhuang   mfd: Avoid to all...
891
  	if (pdata == NULL)
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
892
  		return;
f5fb758de   Haojian Zhuang   mfd: Avoid to all...
893
894
  	power_devs[0].platform_data = pdata->power;
  	power_devs[0].pdata_size = sizeof(struct pm860x_power_pdata);
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
895
896
897
  	power_devs[0].num_resources = ARRAY_SIZE(battery_resources);
  	power_devs[0].resources = &battery_resources[0],
  	ret = mfd_add_devices(chip->dev, 0, &power_devs[0], 1,
55692af5e   Mark Brown   mfd: core: Push i...
898
  			      &battery_resources[0], chip->irq_base, NULL);
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
899
900
901
  	if (ret < 0)
  		dev_err(chip->dev, "Failed to add battery subdev
  ");
f5fb758de   Haojian Zhuang   mfd: Avoid to all...
902
903
  	power_devs[1].platform_data = pdata->power;
  	power_devs[1].pdata_size = sizeof(struct pm860x_power_pdata);
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
904
905
906
  	power_devs[1].num_resources = ARRAY_SIZE(charger_resources);
  	power_devs[1].resources = &charger_resources[0],
  	ret = mfd_add_devices(chip->dev, 0, &power_devs[1], 1,
55692af5e   Mark Brown   mfd: core: Push i...
907
  			      &charger_resources[0], chip->irq_base, NULL);
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
908
909
910
  	if (ret < 0)
  		dev_err(chip->dev, "Failed to add charger subdev
  ");
2573f6d36   Jett.Zhou   mfd: Add pre-regu...
911
912
913
  
  	power_devs[2].platform_data = &preg_init_data;
  	power_devs[2].pdata_size = sizeof(struct regulator_init_data);
2573f6d36   Jett.Zhou   mfd: Add pre-regu...
914
  	ret = mfd_add_devices(chip->dev, 0, &power_devs[2], 1,
ff13e9e25   Haojian Zhuang   mfd: 88pm860x: Av...
915
  			      NULL, chip->irq_base, NULL);
2573f6d36   Jett.Zhou   mfd: Add pre-regu...
916
917
918
  	if (ret < 0)
  		dev_err(chip->dev, "Failed to add preg subdev
  ");
a830d28b4   Jett.Zhou   power_supply: Ena...
919
920
921
922
923
924
925
926
927
  
  	if (pdata->chg_desc) {
  		pdata->chg_desc->charger_regulators =
  			&chg_desc_regulator_data[0];
  		pdata->chg_desc->num_charger_regulators	=
  			ARRAY_SIZE(chg_desc_regulator_data),
  		power_devs[3].platform_data = pdata->chg_desc;
  		power_devs[3].pdata_size = sizeof(*pdata->chg_desc);
  		ret = mfd_add_devices(chip->dev, 0, &power_devs[3], 1,
18766f093   Anton Vorontsov   Merge with upstre...
928
  				      NULL, chip->irq_base, NULL);
a830d28b4   Jett.Zhou   power_supply: Ena...
929
930
931
932
  		if (ret < 0)
  			dev_err(chip->dev, "Failed to add chg-manager subdev
  ");
  	}
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
933
  }
f791be492   Bill Pemberton   mfd: remove use o...
934
  static void device_onkey_init(struct pm860x_chip *chip,
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
935
936
937
938
939
940
941
942
  					struct pm860x_platform_data *pdata)
  {
  	int ret;
  
  	onkey_devs[0].num_resources = ARRAY_SIZE(onkey_resources);
  	onkey_devs[0].resources = &onkey_resources[0],
  	ret = mfd_add_devices(chip->dev, 0, &onkey_devs[0],
  			      ARRAY_SIZE(onkey_devs), &onkey_resources[0],
55692af5e   Mark Brown   mfd: core: Push i...
943
  			      chip->irq_base, NULL);
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
944
945
946
947
  	if (ret < 0)
  		dev_err(chip->dev, "Failed to add onkey subdev
  ");
  }
f791be492   Bill Pemberton   mfd: remove use o...
948
  static void device_codec_init(struct pm860x_chip *chip,
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
949
950
951
952
953
954
955
  					struct pm860x_platform_data *pdata)
  {
  	int ret;
  
  	codec_devs[0].num_resources = ARRAY_SIZE(codec_resources);
  	codec_devs[0].resources = &codec_resources[0],
  	ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
55692af5e   Mark Brown   mfd: core: Push i...
956
957
  			      ARRAY_SIZE(codec_devs), &codec_resources[0], 0,
  			      NULL);
c9f560b3d   Haojian Zhuang   mfd: Adopt mfd_da...
958
959
960
961
  	if (ret < 0)
  		dev_err(chip->dev, "Failed to add codec subdev
  ");
  }
f791be492   Bill Pemberton   mfd: remove use o...
962
  static void device_8607_init(struct pm860x_chip *chip,
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
963
964
965
  				       struct i2c_client *i2c,
  				       struct pm860x_platform_data *pdata)
  {
a16122bca   Haojian Zhuang   mfd: Append subde...
966
  	int data, ret;
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
967

53dbab7af   Haojian Zhuang   mfd: Support 88pm...
968
  	ret = pm860x_reg_read(i2c, PM8607_CHIP_ID);
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
969
970
971
972
973
  	if (ret < 0) {
  		dev_err(chip->dev, "Failed to read CHIP ID: %d
  ", ret);
  		goto out;
  	}
38b340527   Haojian Zhuang   mfd: Update chip ...
974
975
976
  	switch (ret & PM8607_VERSION_MASK) {
  	case 0x40:
  	case 0x50:
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
977
978
979
  		dev_info(chip->dev, "Marvell 88PM8607 (ID: %02x) detected
  ",
  			 ret);
38b340527   Haojian Zhuang   mfd: Update chip ...
980
981
  		break;
  	default:
2e57848fe   Lee Jones   mfd: 88pm860x-cor...
982
983
984
985
  		dev_err(chip->dev,
  			"Failed to detect Marvell 88PM8607. Chip ID: %02x
  ",
  			ret);
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
986
987
  		goto out;
  	}
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
988

53dbab7af   Haojian Zhuang   mfd: Support 88pm...
989
  	ret = pm860x_reg_read(i2c, PM8607_BUCK3);
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
990
991
992
993
994
995
996
  	if (ret < 0) {
  		dev_err(chip->dev, "Failed to read BUCK3 register: %d
  ", ret);
  		goto out;
  	}
  	if (ret & PM8607_BUCK3_DOUBLE)
  		chip->buck3_double = 1;
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
997
  	ret = pm860x_reg_read(i2c, PM8607_B0_MISC1);
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
998
999
1000
1001
1002
  	if (ret < 0) {
  		dev_err(chip->dev, "Failed to read MISC1 register: %d
  ", ret);
  		goto out;
  	}
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
1003

5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
  	if (pdata && (pdata->i2c_port == PI2C_PORT))
  		data = PM8607_B0_MISC1_PI2C;
  	else
  		data = 0;
  	ret = pm860x_set_bits(i2c, PM8607_B0_MISC1, PM8607_B0_MISC1_PI2C, data);
  	if (ret < 0) {
  		dev_err(chip->dev, "Failed to access MISC1:%d
  ", ret);
  		goto out;
  	}
  
  	ret = device_irq_init(chip, pdata);
  	if (ret < 0)
  		goto out;
cea438dda   Haojian Zhuang   mfd: Remove unuse...
1018
1019
1020
1021
1022
1023
  	device_regulator_init(chip, pdata);
  	device_rtc_init(chip, pdata);
  	device_onkey_init(chip, pdata);
  	device_touch_init(chip, pdata);
  	device_power_init(chip, pdata);
  	device_codec_init(chip, pdata);
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
1024
  out:
53dbab7af   Haojian Zhuang   mfd: Support 88pm...
1025
1026
  	return;
  }
f791be492   Bill Pemberton   mfd: remove use o...
1027
  static void device_8606_init(struct pm860x_chip *chip,
782580647   Jett.Zhou   mfd: Code cleanup...
1028
1029
1030
1031
1032
1033
1034
  				       struct i2c_client *i2c,
  				       struct pm860x_platform_data *pdata)
  {
  	device_osc_init(i2c);
  	device_bk_init(chip, pdata);
  	device_led_init(chip, pdata);
  }
f791be492   Bill Pemberton   mfd: remove use o...
1035
  static int pm860x_device_init(struct pm860x_chip *chip,
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1036
  					struct pm860x_platform_data *pdata)
53dbab7af   Haojian Zhuang   mfd: Support 88pm...
1037
  {
2afa62ea7   Haojian Zhuang   mfd: Use genirq i...
1038
  	chip->core_irq = 0;
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
1039

53dbab7af   Haojian Zhuang   mfd: Support 88pm...
1040
1041
  	switch (chip->id) {
  	case CHIP_PM8606:
782580647   Jett.Zhou   mfd: Code cleanup...
1042
  		device_8606_init(chip, chip->client, pdata);
53dbab7af   Haojian Zhuang   mfd: Support 88pm...
1043
1044
1045
1046
1047
1048
1049
1050
1051
  		break;
  	case CHIP_PM8607:
  		device_8607_init(chip, chip->client, pdata);
  		break;
  	}
  
  	if (chip->companion) {
  		switch (chip->id) {
  		case CHIP_PM8607:
782580647   Jett.Zhou   mfd: Code cleanup...
1052
  			device_8606_init(chip, chip->companion, pdata);
53dbab7af   Haojian Zhuang   mfd: Support 88pm...
1053
1054
1055
1056
1057
1058
  			break;
  		case CHIP_PM8606:
  			device_8607_init(chip, chip->companion, pdata);
  			break;
  		}
  	}
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
1059

53dbab7af   Haojian Zhuang   mfd: Support 88pm...
1060
  	return 0;
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
1061
  }
4740f73fe   Bill Pemberton   mfd: remove use o...
1062
  static void pm860x_device_exit(struct pm860x_chip *chip)
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
1063
  {
5c42e8c4a   Haojian Zhuang   mfd: Add irq supp...
1064
  	device_irq_exit(chip);
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
1065
1066
  	mfd_remove_devices(chip->dev);
  }
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
  static int verify_addr(struct i2c_client *i2c)
  {
  	unsigned short addr_8607[] = {0x30, 0x34};
  	unsigned short addr_8606[] = {0x10, 0x11};
  	int size, i;
  
  	if (i2c == NULL)
  		return 0;
  	size = ARRAY_SIZE(addr_8606);
  	for (i = 0; i < size; i++) {
  		if (i2c->addr == *(addr_8606 + i))
  			return CHIP_PM8606;
  	}
  	size = ARRAY_SIZE(addr_8607);
  	for (i = 0; i < size; i++) {
  		if (i2c->addr == *(addr_8607 + i))
  			return CHIP_PM8607;
  	}
  	return 0;
  }
8da90cc82   Krzysztof Kozlowski   mfd: 88pm860x-cor...
1087
  static const struct regmap_config pm860x_regmap_config = {
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1088
1089
1090
  	.reg_bits = 8,
  	.val_bits = 8,
  };
f791be492   Bill Pemberton   mfd: remove use o...
1091
  static int pm860x_dt_init(struct device_node *np,
2e57d5674   Haojian Zhuang   mfd: 88pm860x: De...
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
  				    struct device *dev,
  				    struct pm860x_platform_data *pdata)
  {
  	int ret;
  
  	if (of_get_property(np, "marvell,88pm860x-irq-read-clr", NULL))
  		pdata->irq_mode = 1;
  	ret = of_property_read_u32(np, "marvell,88pm860x-slave-addr",
  				   &pdata->companion_addr);
  	if (ret) {
2e57848fe   Lee Jones   mfd: 88pm860x-cor...
1102
1103
1104
  		dev_err(dev,
  			"Not found \"marvell,88pm860x-slave-addr\" property
  ");
2e57d5674   Haojian Zhuang   mfd: 88pm860x: De...
1105
1106
1107
1108
  		pdata->companion_addr = 0;
  	}
  	return 0;
  }
1e98dcd77   Lee Jones   mfd: 88pm860x: Mo...
1109
  static int pm860x_probe(struct i2c_client *client)
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1110
  {
334a41ce9   Jingoo Han   mfd: Use dev_get_...
1111
  	struct pm860x_platform_data *pdata = dev_get_platdata(&client->dev);
2e57d5674   Haojian Zhuang   mfd: 88pm860x: De...
1112
  	struct device_node *node = client->dev.of_node;
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1113
1114
  	struct pm860x_chip *chip;
  	int ret;
2e57d5674   Haojian Zhuang   mfd: 88pm860x: De...
1115
1116
1117
1118
1119
1120
1121
1122
1123
  	if (node && !pdata) {
  		/* parse DT to get platform data */
  		pdata = devm_kzalloc(&client->dev,
  				     sizeof(struct pm860x_platform_data),
  				     GFP_KERNEL);
  		if (!pdata)
  			return -ENOMEM;
  		ret = pm860x_dt_init(node, &client->dev, pdata);
  		if (ret)
85529575b   Jingoo Han   mfd: 88pm860x: Dr...
1124
  			return ret;
2e57d5674   Haojian Zhuang   mfd: 88pm860x: De...
1125
  	} else if (!pdata) {
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1126
1127
1128
1129
  		pr_info("No platform data in %s!
  ", __func__);
  		return -EINVAL;
  	}
a1ace0aac   Lee Jones   mfd: 88pm860x: Co...
1130
1131
  	chip = devm_kzalloc(&client->dev,
  			    sizeof(struct pm860x_chip), GFP_KERNEL);
85529575b   Jingoo Han   mfd: 88pm860x: Dr...
1132
1133
  	if (chip == NULL)
  		return -ENOMEM;
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1134
1135
  
  	chip->id = verify_addr(client);
aaaab4223   Sachin Kamat   mfd: 88pm860x: Us...
1136
  	chip->regmap = devm_regmap_init_i2c(client, &pm860x_regmap_config);
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1137
1138
1139
1140
1141
  	if (IS_ERR(chip->regmap)) {
  		ret = PTR_ERR(chip->regmap);
  		dev_err(&client->dev, "Failed to allocate register map: %d
  ",
  				ret);
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
  		return ret;
  	}
  	chip->client = client;
  	i2c_set_clientdata(client, chip);
  	chip->dev = &client->dev;
  	dev_set_drvdata(chip->dev, chip);
  
  	/*
  	 * Both client and companion client shares same platform driver.
  	 * Driver distinguishes them by pdata->companion_addr.
  	 * pdata->companion_addr is only assigned if companion chip exists.
  	 * At the same time, the companion_addr shouldn't equal to client
  	 * address.
  	 */
  	if (pdata->companion_addr && (pdata->companion_addr != client->addr)) {
  		chip->companion_addr = pdata->companion_addr;
9520b835f   Wolfram Sang   mfd: 88pm860x-cor...
1158
  		chip->companion = i2c_new_dummy_device(chip->client->adapter,
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1159
  						chip->companion_addr);
9520b835f   Wolfram Sang   mfd: 88pm860x-cor...
1160
  		if (IS_ERR(chip->companion)) {
159ce52a6   Krzysztof Kozlowski   mfd: 88pm860x: Fi...
1161
1162
1163
  			dev_err(&client->dev,
  				"Failed to allocate I2C companion device
  ");
9520b835f   Wolfram Sang   mfd: 88pm860x-cor...
1164
  			return PTR_ERR(chip->companion);
159ce52a6   Krzysztof Kozlowski   mfd: 88pm860x: Fi...
1165
  		}
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1166
1167
1168
1169
1170
1171
1172
  		chip->regmap_companion = regmap_init_i2c(chip->companion,
  							&pm860x_regmap_config);
  		if (IS_ERR(chip->regmap_companion)) {
  			ret = PTR_ERR(chip->regmap_companion);
  			dev_err(&chip->companion->dev,
  				"Failed to allocate register map: %d
  ", ret);
a7ab1c8b2   Krzysztof Kozlowski   mfd: 88pm860x: Fi...
1173
  			i2c_unregister_device(chip->companion);
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1174
1175
1176
1177
1178
1179
1180
1181
  			return ret;
  		}
  		i2c_set_clientdata(chip->companion, chip);
  	}
  
  	pm860x_device_init(chip, pdata);
  	return 0;
  }
4740f73fe   Bill Pemberton   mfd: remove use o...
1182
  static int pm860x_remove(struct i2c_client *client)
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1183
1184
1185
1186
1187
1188
1189
1190
  {
  	struct pm860x_chip *chip = i2c_get_clientdata(client);
  
  	pm860x_device_exit(chip);
  	if (chip->companion) {
  		regmap_exit(chip->regmap_companion);
  		i2c_unregister_device(chip->companion);
  	}
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1191
1192
1193
1194
1195
1196
  	return 0;
  }
  
  #ifdef CONFIG_PM_SLEEP
  static int pm860x_suspend(struct device *dev)
  {
1b5420e1f   Geliang Tang   mfd: Use to_i2c_c...
1197
  	struct i2c_client *client = to_i2c_client(dev);
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1198
1199
1200
1201
1202
1203
1204
1205
1206
  	struct pm860x_chip *chip = i2c_get_clientdata(client);
  
  	if (device_may_wakeup(dev) && chip->wakeup_flag)
  		enable_irq_wake(chip->core_irq);
  	return 0;
  }
  
  static int pm860x_resume(struct device *dev)
  {
1b5420e1f   Geliang Tang   mfd: Use to_i2c_c...
1207
  	struct i2c_client *client = to_i2c_client(dev);
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1208
1209
1210
1211
1212
1213
1214
1215
1216
  	struct pm860x_chip *chip = i2c_get_clientdata(client);
  
  	if (device_may_wakeup(dev) && chip->wakeup_flag)
  		disable_irq_wake(chip->core_irq);
  	return 0;
  }
  #endif
  
  static SIMPLE_DEV_PM_OPS(pm860x_pm_ops, pm860x_suspend, pm860x_resume);
2e57d5674   Haojian Zhuang   mfd: 88pm860x: De...
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
  static const struct i2c_device_id pm860x_id_table[] = {
  	{ "88PM860x", 0 },
  	{}
  };
  MODULE_DEVICE_TABLE(i2c, pm860x_id_table);
  
  static const struct of_device_id pm860x_dt_ids[] = {
  	{ .compatible = "marvell,88pm860x", },
  	{},
  };
  MODULE_DEVICE_TABLE(of, pm860x_dt_ids);
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1228
1229
1230
  static struct i2c_driver pm860x_driver = {
  	.driver	= {
  		.name	= "88PM860x",
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1231
  		.pm     = &pm860x_pm_ops,
cd2a55321   Sachin Kamat   mfd: 88pm860x: Re...
1232
  		.of_match_table	= pm860x_dt_ids,
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1233
  	},
1e98dcd77   Lee Jones   mfd: 88pm860x: Mo...
1234
  	.probe_new	= pm860x_probe,
84449216b   Bill Pemberton   mfd: remove use o...
1235
  	.remove		= pm860x_remove,
f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1236
1237
1238
1239
1240
1241
  	.id_table	= pm860x_id_table,
  };
  
  static int __init pm860x_i2c_init(void)
  {
  	int ret;
f90dff446   Lee Jones   mfd: 88pm860x-cor...
1242

f2f218cdc   Haojian Zhuang   mfd: 88pm860x: Mo...
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
  	ret = i2c_add_driver(&pm860x_driver);
  	if (ret != 0)
  		pr_err("Failed to register 88PM860x I2C driver: %d
  ", ret);
  	return ret;
  }
  subsys_initcall(pm860x_i2c_init);
  
  static void __exit pm860x_i2c_exit(void)
  {
  	i2c_del_driver(&pm860x_driver);
  }
  module_exit(pm860x_i2c_exit);
53dbab7af   Haojian Zhuang   mfd: Support 88pm...
1256
  MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM860x");
bbd51b1ff   Haojian Zhuang   mfd: Split 88pm86...
1257
1258
  MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com>");
  MODULE_LICENSE("GPL");