Blame view

drivers/mfd/tps65910.c 13.4 KB
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  /*
   * tps65910.c  --  TI TPS6591x
   *
   * Copyright 2010 Texas Instruments Inc.
   *
   * Author: Graeme Gregory <gg@slimlogic.co.uk>
   * Author: Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>
   *
   *  This program is free software; you can redistribute it and/or modify it
   *  under  the terms of the GNU General  Public License as published by the
   *  Free Software Foundation;  either version 2 of the License, or (at your
   *  option) any later version.
   *
   */
  
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/init.h>
dc9913a05   Laxman Dewangan   mfd: Use regmap f...
19
  #include <linux/err.h>
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
20
21
  #include <linux/slab.h>
  #include <linux/i2c.h>
4aab3fada   Laxman Dewangan   mfd: tps65910: Mo...
22
23
24
  #include <linux/interrupt.h>
  #include <linux/irq.h>
  #include <linux/irqdomain.h>
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
25
  #include <linux/mfd/core.h>
dc9913a05   Laxman Dewangan   mfd: Use regmap f...
26
  #include <linux/regmap.h>
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
27
  #include <linux/mfd/tps65910.h>
1fead3f39   Sachin Kamat   mfd: tps65910: In...
28
  #include <linux/of.h>
cd4209ced   Rhyland Klein   mfd: Add tps65910...
29
  #include <linux/of_device.h>
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
30

5863eabb2   Venu Byravarasu   mfd: tps65910: Ad...
31
32
33
34
35
36
37
  static struct resource rtc_resources[] = {
  	{
  		.start  = TPS65910_IRQ_RTC_ALARM,
  		.end    = TPS65910_IRQ_RTC_ALARM,
  		.flags  = IORESOURCE_IRQ,
  	}
  };
30fe2b5bd   Geert Uytterhoeven   mfd: ti: Constify...
38
  static const struct mfd_cell tps65910s[] = {
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
39
  	{
32df986e9   Laxman Dewangan   mfd: Register tps...
40
41
42
  		.name = "tps65910-gpio",
  	},
  	{
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
43
44
45
46
  		.name = "tps65910-pmic",
  	},
  	{
  		.name = "tps65910-rtc",
5863eabb2   Venu Byravarasu   mfd: tps65910: Ad...
47
48
  		.num_resources = ARRAY_SIZE(rtc_resources),
  		.resources = &rtc_resources[0],
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
49
50
51
52
53
  	},
  	{
  		.name = "tps65910-power",
  	},
  };
4aab3fada   Laxman Dewangan   mfd: tps65910: Mo...
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
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
209
210
211
  static const struct regmap_irq tps65911_irqs[] = {
  	/* INT_STS */
  	[TPS65911_IRQ_PWRHOLD_F] = {
  		.mask = INT_MSK_PWRHOLD_F_IT_MSK_MASK,
  		.reg_offset = 0,
  	},
  	[TPS65911_IRQ_VBAT_VMHI] = {
  		.mask = INT_MSK_VMBHI_IT_MSK_MASK,
  		.reg_offset = 0,
  	},
  	[TPS65911_IRQ_PWRON] = {
  		.mask = INT_MSK_PWRON_IT_MSK_MASK,
  		.reg_offset = 0,
  	},
  	[TPS65911_IRQ_PWRON_LP] = {
  		.mask = INT_MSK_PWRON_LP_IT_MSK_MASK,
  		.reg_offset = 0,
  	},
  	[TPS65911_IRQ_PWRHOLD_R] = {
  		.mask = INT_MSK_PWRHOLD_R_IT_MSK_MASK,
  		.reg_offset = 0,
  	},
  	[TPS65911_IRQ_HOTDIE] = {
  		.mask = INT_MSK_HOTDIE_IT_MSK_MASK,
  		.reg_offset = 0,
  	},
  	[TPS65911_IRQ_RTC_ALARM] = {
  		.mask = INT_MSK_RTC_ALARM_IT_MSK_MASK,
  		.reg_offset = 0,
  	},
  	[TPS65911_IRQ_RTC_PERIOD] = {
  		.mask = INT_MSK_RTC_PERIOD_IT_MSK_MASK,
  		.reg_offset = 0,
  	},
  
  	/* INT_STS2 */
  	[TPS65911_IRQ_GPIO0_R] = {
  		.mask = INT_MSK2_GPIO0_R_IT_MSK_MASK,
  		.reg_offset = 1,
  	},
  	[TPS65911_IRQ_GPIO0_F] = {
  		.mask = INT_MSK2_GPIO0_F_IT_MSK_MASK,
  		.reg_offset = 1,
  	},
  	[TPS65911_IRQ_GPIO1_R] = {
  		.mask = INT_MSK2_GPIO1_R_IT_MSK_MASK,
  		.reg_offset = 1,
  	},
  	[TPS65911_IRQ_GPIO1_F] = {
  		.mask = INT_MSK2_GPIO1_F_IT_MSK_MASK,
  		.reg_offset = 1,
  	},
  	[TPS65911_IRQ_GPIO2_R] = {
  		.mask = INT_MSK2_GPIO2_R_IT_MSK_MASK,
  		.reg_offset = 1,
  	},
  	[TPS65911_IRQ_GPIO2_F] = {
  		.mask = INT_MSK2_GPIO2_F_IT_MSK_MASK,
  		.reg_offset = 1,
  	},
  	[TPS65911_IRQ_GPIO3_R] = {
  		.mask = INT_MSK2_GPIO3_R_IT_MSK_MASK,
  		.reg_offset = 1,
  	},
  	[TPS65911_IRQ_GPIO3_F] = {
  		.mask = INT_MSK2_GPIO3_F_IT_MSK_MASK,
  		.reg_offset = 1,
  	},
  
  	/* INT_STS2 */
  	[TPS65911_IRQ_GPIO4_R] = {
  		.mask = INT_MSK3_GPIO4_R_IT_MSK_MASK,
  		.reg_offset = 2,
  	},
  	[TPS65911_IRQ_GPIO4_F] = {
  		.mask = INT_MSK3_GPIO4_F_IT_MSK_MASK,
  		.reg_offset = 2,
  	},
  	[TPS65911_IRQ_GPIO5_R] = {
  		.mask = INT_MSK3_GPIO5_R_IT_MSK_MASK,
  		.reg_offset = 2,
  	},
  	[TPS65911_IRQ_GPIO5_F] = {
  		.mask = INT_MSK3_GPIO5_F_IT_MSK_MASK,
  		.reg_offset = 2,
  	},
  	[TPS65911_IRQ_WTCHDG] = {
  		.mask = INT_MSK3_WTCHDG_IT_MSK_MASK,
  		.reg_offset = 2,
  	},
  	[TPS65911_IRQ_VMBCH2_H] = {
  		.mask = INT_MSK3_VMBCH2_H_IT_MSK_MASK,
  		.reg_offset = 2,
  	},
  	[TPS65911_IRQ_VMBCH2_L] = {
  		.mask = INT_MSK3_VMBCH2_L_IT_MSK_MASK,
  		.reg_offset = 2,
  	},
  	[TPS65911_IRQ_PWRDN] = {
  		.mask = INT_MSK3_PWRDN_IT_MSK_MASK,
  		.reg_offset = 2,
  	},
  };
  
  static const struct regmap_irq tps65910_irqs[] = {
  	/* INT_STS */
  	[TPS65910_IRQ_VBAT_VMBDCH] = {
  		.mask = TPS65910_INT_MSK_VMBDCH_IT_MSK_MASK,
  		.reg_offset = 0,
  	},
  	[TPS65910_IRQ_VBAT_VMHI] = {
  		.mask = TPS65910_INT_MSK_VMBHI_IT_MSK_MASK,
  		.reg_offset = 0,
  	},
  	[TPS65910_IRQ_PWRON] = {
  		.mask = TPS65910_INT_MSK_PWRON_IT_MSK_MASK,
  		.reg_offset = 0,
  	},
  	[TPS65910_IRQ_PWRON_LP] = {
  		.mask = TPS65910_INT_MSK_PWRON_LP_IT_MSK_MASK,
  		.reg_offset = 0,
  	},
  	[TPS65910_IRQ_PWRHOLD] = {
  		.mask = TPS65910_INT_MSK_PWRHOLD_IT_MSK_MASK,
  		.reg_offset = 0,
  	},
  	[TPS65910_IRQ_HOTDIE] = {
  		.mask = TPS65910_INT_MSK_HOTDIE_IT_MSK_MASK,
  		.reg_offset = 0,
  	},
  	[TPS65910_IRQ_RTC_ALARM] = {
  		.mask = TPS65910_INT_MSK_RTC_ALARM_IT_MSK_MASK,
  		.reg_offset = 0,
  	},
  	[TPS65910_IRQ_RTC_PERIOD] = {
  		.mask = TPS65910_INT_MSK_RTC_PERIOD_IT_MSK_MASK,
  		.reg_offset = 0,
  	},
  
  	/* INT_STS2 */
  	[TPS65910_IRQ_GPIO_R] = {
  		.mask = TPS65910_INT_MSK2_GPIO0_F_IT_MSK_MASK,
  		.reg_offset = 1,
  	},
  	[TPS65910_IRQ_GPIO_F] = {
  		.mask = TPS65910_INT_MSK2_GPIO0_R_IT_MSK_MASK,
  		.reg_offset = 1,
  	},
  };
  
  static struct regmap_irq_chip tps65911_irq_chip = {
  	.name = "tps65910",
  	.irqs = tps65911_irqs,
  	.num_irqs = ARRAY_SIZE(tps65911_irqs),
  	.num_regs = 3,
  	.irq_reg_stride = 2,
  	.status_base = TPS65910_INT_STS,
  	.mask_base = TPS65910_INT_MSK,
0582c0faf   Kim, Milo   mfd: tps65910: Fi...
212
  	.ack_base = TPS65910_INT_STS,
4aab3fada   Laxman Dewangan   mfd: tps65910: Mo...
213
214
215
216
217
218
219
220
221
222
  };
  
  static struct regmap_irq_chip tps65910_irq_chip = {
  	.name = "tps65910",
  	.irqs = tps65910_irqs,
  	.num_irqs = ARRAY_SIZE(tps65910_irqs),
  	.num_regs = 2,
  	.irq_reg_stride = 2,
  	.status_base = TPS65910_INT_STS,
  	.mask_base = TPS65910_INT_MSK,
0582c0faf   Kim, Milo   mfd: tps65910: Fi...
223
  	.ack_base = TPS65910_INT_STS,
4aab3fada   Laxman Dewangan   mfd: tps65910: Mo...
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
  };
  
  static int tps65910_irq_init(struct tps65910 *tps65910, int irq,
  		    struct tps65910_platform_data *pdata)
  {
  	int ret = 0;
  	static struct regmap_irq_chip *tps6591x_irqs_chip;
  
  	if (!irq) {
  		dev_warn(tps65910->dev, "No interrupt support, no core IRQ
  ");
  		return -EINVAL;
  	}
  
  	if (!pdata) {
  		dev_warn(tps65910->dev, "No interrupt support, no pdata
  ");
  		return -EINVAL;
  	}
  
  	switch (tps65910_chip_id(tps65910)) {
  	case TPS65910:
  		tps6591x_irqs_chip = &tps65910_irq_chip;
  		break;
  	case TPS65911:
  		tps6591x_irqs_chip = &tps65911_irq_chip;
  		break;
  	}
  
  	tps65910->chip_irq = irq;
  	ret = regmap_add_irq_chip(tps65910->regmap, tps65910->chip_irq,
  		IRQF_ONESHOT, pdata->irq_base,
  		tps6591x_irqs_chip, &tps65910->irq_data);
483e2dfdb   Krzysztof Kozlowski   mfd: tps65910: Fi...
257
  	if (ret < 0) {
4aab3fada   Laxman Dewangan   mfd: tps65910: Mo...
258
259
  		dev_warn(tps65910->dev, "Failed to add irq_chip %d
  ", ret);
483e2dfdb   Krzysztof Kozlowski   mfd: tps65910: Fi...
260
261
  		tps65910->chip_irq = 0;
  	}
4aab3fada   Laxman Dewangan   mfd: tps65910: Mo...
262
263
264
265
266
267
268
269
270
  	return ret;
  }
  
  static int tps65910_irq_exit(struct tps65910 *tps65910)
  {
  	if (tps65910->chip_irq > 0)
  		regmap_del_irq_chip(tps65910->chip_irq, tps65910->irq_data);
  	return 0;
  }
dc9913a05   Laxman Dewangan   mfd: Use regmap f...
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
  static bool is_volatile_reg(struct device *dev, unsigned int reg)
  {
  	struct tps65910 *tps65910 = dev_get_drvdata(dev);
  
  	/*
  	 * Caching all regulator registers.
  	 * All regualator register address range is same for
  	 * TPS65910 and TPS65911
  	 */
  	if ((reg >= TPS65910_VIO) && (reg <= TPS65910_VDAC)) {
  		/* Check for non-existing register */
  		if (tps65910_chip_id(tps65910) == TPS65910)
  			if ((reg == TPS65911_VDDCTRL_OP) ||
  				(reg == TPS65911_VDDCTRL_SR))
  				return true;
  		return false;
  	}
  	return true;
  }
39ecb0376   Laxman Dewangan   mfd: Use correct ...
290
  static const struct regmap_config tps65910_regmap_config = {
dc9913a05   Laxman Dewangan   mfd: Use regmap f...
291
292
293
  	.reg_bits = 8,
  	.val_bits = 8,
  	.volatile_reg = is_volatile_reg,
3bf6bf9be   Laxman Dewangan   mfd: Cache tps659...
294
  	.max_register = TPS65910_MAX_REGISTER - 1,
dc9913a05   Laxman Dewangan   mfd: Use regmap f...
295
296
  	.cache_type = REGCACHE_RBTREE,
  };
f791be492   Bill Pemberton   mfd: remove use o...
297
  static int tps65910_ck32k_init(struct tps65910 *tps65910,
712db99df   Johan Hovold   mfd: Add support ...
298
299
  					struct tps65910_board *pmic_pdata)
  {
712db99df   Johan Hovold   mfd: Add support ...
300
  	int ret;
d02e83cbc   Johan Hovold   mfd: Add tps65910...
301
302
303
304
  	if (!pmic_pdata->en_ck32k_xtal)
  		return 0;
  
  	ret = tps65910_reg_clear_bits(tps65910, TPS65910_DEVCTRL,
712db99df   Johan Hovold   mfd: Add support ...
305
  						DEVCTRL_CK32K_CTRL_MASK);
d02e83cbc   Johan Hovold   mfd: Add tps65910...
306
307
308
309
  	if (ret < 0) {
  		dev_err(tps65910->dev, "clear ck32k_ctrl failed: %d
  ", ret);
  		return ret;
712db99df   Johan Hovold   mfd: Add support ...
310
311
312
313
  	}
  
  	return 0;
  }
f791be492   Bill Pemberton   mfd: remove use o...
314
  static int tps65910_sleepinit(struct tps65910 *tps65910,
201cf0528   Laxman Dewangan   mfd: Add support ...
315
316
317
318
319
320
321
322
323
324
325
  		struct tps65910_board *pmic_pdata)
  {
  	struct device *dev = NULL;
  	int ret = 0;
  
  	dev = tps65910->dev;
  
  	if (!pmic_pdata->en_dev_slp)
  		return 0;
  
  	/* enabling SLEEP device state */
3f7e82759   Rhyland Klein   mfd: Commonize tp...
326
  	ret = tps65910_reg_set_bits(tps65910, TPS65910_DEVCTRL,
201cf0528   Laxman Dewangan   mfd: Add support ...
327
328
329
330
331
332
333
334
335
336
337
338
  				DEVCTRL_DEV_SLP_MASK);
  	if (ret < 0) {
  		dev_err(dev, "set dev_slp failed: %d
  ", ret);
  		goto err_sleep_init;
  	}
  
  	/* Return if there is no sleep keepon data. */
  	if (!pmic_pdata->slp_keepon)
  		return 0;
  
  	if (pmic_pdata->slp_keepon->therm_keepon) {
3f7e82759   Rhyland Klein   mfd: Commonize tp...
339
340
  		ret = tps65910_reg_set_bits(tps65910,
  				TPS65910_SLEEP_KEEP_RES_ON,
201cf0528   Laxman Dewangan   mfd: Add support ...
341
342
343
344
345
346
347
348
349
  				SLEEP_KEEP_RES_ON_THERM_KEEPON_MASK);
  		if (ret < 0) {
  			dev_err(dev, "set therm_keepon failed: %d
  ", ret);
  			goto disable_dev_slp;
  		}
  	}
  
  	if (pmic_pdata->slp_keepon->clkout32k_keepon) {
3f7e82759   Rhyland Klein   mfd: Commonize tp...
350
351
  		ret = tps65910_reg_set_bits(tps65910,
  				TPS65910_SLEEP_KEEP_RES_ON,
201cf0528   Laxman Dewangan   mfd: Add support ...
352
353
354
355
356
357
358
359
360
  				SLEEP_KEEP_RES_ON_CLKOUT32K_KEEPON_MASK);
  		if (ret < 0) {
  			dev_err(dev, "set clkout32k_keepon failed: %d
  ", ret);
  			goto disable_dev_slp;
  		}
  	}
  
  	if (pmic_pdata->slp_keepon->i2chs_keepon) {
3f7e82759   Rhyland Klein   mfd: Commonize tp...
361
362
  		ret = tps65910_reg_set_bits(tps65910,
  				TPS65910_SLEEP_KEEP_RES_ON,
201cf0528   Laxman Dewangan   mfd: Add support ...
363
364
365
366
367
368
369
370
371
372
373
  				SLEEP_KEEP_RES_ON_I2CHS_KEEPON_MASK);
  		if (ret < 0) {
  			dev_err(dev, "set i2chs_keepon failed: %d
  ", ret);
  			goto disable_dev_slp;
  		}
  	}
  
  	return 0;
  
  disable_dev_slp:
3f7e82759   Rhyland Klein   mfd: Commonize tp...
374
375
  	tps65910_reg_clear_bits(tps65910, TPS65910_DEVCTRL,
  				DEVCTRL_DEV_SLP_MASK);
201cf0528   Laxman Dewangan   mfd: Add support ...
376
377
378
379
  
  err_sleep_init:
  	return ret;
  }
cd4209ced   Rhyland Klein   mfd: Add tps65910...
380
  #ifdef CONFIG_OF
c0dfbfe2a   Jingoo Han   mfd: tps65910: Ma...
381
  static const struct of_device_id tps65910_of_match[] = {
cd4209ced   Rhyland Klein   mfd: Add tps65910...
382
383
384
385
386
387
388
  	{ .compatible = "ti,tps65910", .data = (void *)TPS65910},
  	{ .compatible = "ti,tps65911", .data = (void *)TPS65911},
  	{ },
  };
  MODULE_DEVICE_TABLE(of, tps65910_of_match);
  
  static struct tps65910_board *tps65910_parse_dt(struct i2c_client *client,
01a0f4aaa   Lee Jones   mfd: tps65910: Ri...
389
  						unsigned long *chip_id)
cd4209ced   Rhyland Klein   mfd: Add tps65910...
390
391
392
393
394
  {
  	struct device_node *np = client->dev.of_node;
  	struct tps65910_board *board_info;
  	unsigned int prop;
  	const struct of_device_id *match;
cd4209ced   Rhyland Klein   mfd: Add tps65910...
395
  	int ret = 0;
cd4209ced   Rhyland Klein   mfd: Add tps65910...
396
397
398
399
400
401
402
  
  	match = of_match_device(tps65910_of_match, &client->dev);
  	if (!match) {
  		dev_err(&client->dev, "Failed to find matching dt id
  ");
  		return NULL;
  	}
01a0f4aaa   Lee Jones   mfd: tps65910: Ri...
403
  	*chip_id  = (unsigned long)match->data;
cd4209ced   Rhyland Klein   mfd: Add tps65910...
404
405
406
407
408
409
410
411
412
413
414
415
  
  	board_info = devm_kzalloc(&client->dev, sizeof(*board_info),
  			GFP_KERNEL);
  	if (!board_info) {
  		dev_err(&client->dev, "Failed to allocate pdata
  ");
  		return NULL;
  	}
  
  	ret = of_property_read_u32(np, "ti,vmbch-threshold", &prop);
  	if (!ret)
  		board_info->vmbch_threshold = prop;
cd4209ced   Rhyland Klein   mfd: Add tps65910...
416
417
418
419
  
  	ret = of_property_read_u32(np, "ti,vmbch2-threshold", &prop);
  	if (!ret)
  		board_info->vmbch2_threshold = prop;
cd4209ced   Rhyland Klein   mfd: Add tps65910...
420

bcc1dd4cd   Johan Hovold   mfd: Add device-t...
421
422
  	prop = of_property_read_bool(np, "ti,en-ck32k-xtal");
  	board_info->en_ck32k_xtal = prop;
cd4209ced   Rhyland Klein   mfd: Add tps65910...
423
424
  	board_info->irq = client->irq;
  	board_info->irq_base = -1;
b079fa720   Bill Huang   mfd: dt: tps65910...
425
426
  	board_info->pm_off = of_property_read_bool(np,
  			"ti,system-power-controller");
cd4209ced   Rhyland Klein   mfd: Add tps65910...
427
428
429
430
  
  	return board_info;
  }
  #else
7f65f74cc   Samuel Ortiz   mfd: Fix tps65910...
431
432
  static inline
  struct tps65910_board *tps65910_parse_dt(struct i2c_client *client,
01a0f4aaa   Lee Jones   mfd: tps65910: Ri...
433
  					 unsigned long *chip_id)
cd4209ced   Rhyland Klein   mfd: Add tps65910...
434
435
436
437
  {
  	return NULL;
  }
  #endif
201cf0528   Laxman Dewangan   mfd: Add support ...
438

b079fa720   Bill Huang   mfd: dt: tps65910...
439
440
441
442
443
444
445
446
447
448
449
450
451
452
  static struct i2c_client *tps65910_i2c_client;
  static void tps65910_power_off(void)
  {
  	struct tps65910 *tps65910;
  
  	tps65910 = dev_get_drvdata(&tps65910_i2c_client->dev);
  
  	if (tps65910_reg_set_bits(tps65910, TPS65910_DEVCTRL,
  			DEVCTRL_PWR_OFF_MASK) < 0)
  		return;
  
  	tps65910_reg_clear_bits(tps65910, TPS65910_DEVCTRL,
  			DEVCTRL_DEV_ON_MASK);
  }
f791be492   Bill Pemberton   mfd: remove use o...
453
  static int tps65910_i2c_probe(struct i2c_client *i2c,
01a0f4aaa   Lee Jones   mfd: tps65910: Ri...
454
  			      const struct i2c_device_id *id)
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
455
456
  {
  	struct tps65910 *tps65910;
2537df722   Graeme Gregory   TPS65910: GPIO: A...
457
  	struct tps65910_board *pmic_plat_data;
cb8d86545   Laxman Dewangan   mfd: Save device ...
458
  	struct tps65910_board *of_pmic_plat_data = NULL;
e3471bdc2   Graeme Gregory   TPS65910: IRQ: Ad...
459
  	struct tps65910_platform_data *init_data;
01a0f4aaa   Lee Jones   mfd: tps65910: Ri...
460
  	unsigned long chip_id = id->driver_data;
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
461
  	int ret = 0;
2537df722   Graeme Gregory   TPS65910: GPIO: A...
462
  	pmic_plat_data = dev_get_platdata(&i2c->dev);
cd4209ced   Rhyland Klein   mfd: Add tps65910...
463

cb8d86545   Laxman Dewangan   mfd: Save device ...
464
  	if (!pmic_plat_data && i2c->dev.of_node) {
cd4209ced   Rhyland Klein   mfd: Add tps65910...
465
  		pmic_plat_data = tps65910_parse_dt(i2c, &chip_id);
cb8d86545   Laxman Dewangan   mfd: Save device ...
466
467
  		of_pmic_plat_data = pmic_plat_data;
  	}
cd4209ced   Rhyland Klein   mfd: Add tps65910...
468

2537df722   Graeme Gregory   TPS65910: GPIO: A...
469
470
  	if (!pmic_plat_data)
  		return -EINVAL;
63fe7dee9   Laxman Dewangan   mfd: Convert all ...
471
  	init_data = devm_kzalloc(&i2c->dev, sizeof(*init_data), GFP_KERNEL);
e3471bdc2   Graeme Gregory   TPS65910: IRQ: Ad...
472
473
  	if (init_data == NULL)
  		return -ENOMEM;
63fe7dee9   Laxman Dewangan   mfd: Convert all ...
474
475
  	tps65910 = devm_kzalloc(&i2c->dev, sizeof(*tps65910), GFP_KERNEL);
  	if (tps65910 == NULL)
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
476
  		return -ENOMEM;
cb8d86545   Laxman Dewangan   mfd: Save device ...
477
  	tps65910->of_plat_data = of_pmic_plat_data;
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
478
479
480
  	i2c_set_clientdata(i2c, tps65910);
  	tps65910->dev = &i2c->dev;
  	tps65910->i2c_client = i2c;
cd4209ced   Rhyland Klein   mfd: Add tps65910...
481
  	tps65910->id = chip_id;
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
482

be1c77002   Arnout Vandecappelle (Essensium/Mind)   mfd: tps65910: Wo...
483
484
485
486
487
  	/* Work around silicon erratum SWCZ010: the tps65910 may miss the
  	 * first I2C transfer. So issue a dummy transfer before the first
  	 * real transfer.
  	 */
  	i2c_master_send(i2c, "", 1);
63fe7dee9   Laxman Dewangan   mfd: Convert all ...
488
  	tps65910->regmap = devm_regmap_init_i2c(i2c, &tps65910_regmap_config);
dc9913a05   Laxman Dewangan   mfd: Use regmap f...
489
490
491
492
  	if (IS_ERR(tps65910->regmap)) {
  		ret = PTR_ERR(tps65910->regmap);
  		dev_err(&i2c->dev, "regmap initialization failed: %d
  ", ret);
63fe7dee9   Laxman Dewangan   mfd: Convert all ...
493
  		return ret;
dc9913a05   Laxman Dewangan   mfd: Use regmap f...
494
  	}
b1224cd11   Jesper Juhl   mfd: Avoid two as...
495
  	init_data->irq = pmic_plat_data->irq;
1773140fe   Laxman Dewangan   mfd: Initialize t...
496
  	init_data->irq_base = pmic_plat_data->irq_base;
b1224cd11   Jesper Juhl   mfd: Avoid two as...
497

1e351a95b   Afzal Mohammed   mfd: Make TPS6591...
498
  	tps65910_irq_init(tps65910, init_data->irq, init_data);
d02e83cbc   Johan Hovold   mfd: Add tps65910...
499
  	tps65910_ck32k_init(tps65910, pmic_plat_data);
201cf0528   Laxman Dewangan   mfd: Add support ...
500
  	tps65910_sleepinit(tps65910, pmic_plat_data);
b079fa720   Bill Huang   mfd: dt: tps65910...
501
502
503
504
  	if (pmic_plat_data->pm_off && !pm_power_off) {
  		tps65910_i2c_client = i2c;
  		pm_power_off = tps65910_power_off;
  	}
10ecb80e8   Laxman Dewangan   mfd: tps65910: In...
505
506
  	ret = mfd_add_devices(tps65910->dev, -1,
  			      tps65910s, ARRAY_SIZE(tps65910s),
17143e38a   Laxman Dewangan   mfd: tps65910: Pa...
507
508
  			      NULL, 0,
  			      regmap_irq_get_domain(tps65910->irq_data));
10ecb80e8   Laxman Dewangan   mfd: tps65910: In...
509
510
511
  	if (ret < 0) {
  		dev_err(&i2c->dev, "mfd_add_devices failed: %d
  ", ret);
742766aac   Krzysztof Kozlowski   mfd: tps65910: Fi...
512
  		tps65910_irq_exit(tps65910);
10ecb80e8   Laxman Dewangan   mfd: tps65910: In...
513
514
  		return ret;
  	}
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
515
516
  	return ret;
  }
4740f73fe   Bill Pemberton   mfd: remove use o...
517
  static int tps65910_i2c_remove(struct i2c_client *i2c)
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
518
519
  {
  	struct tps65910 *tps65910 = i2c_get_clientdata(i2c);
ec2328c30   Mark Brown   mfd: Implement tp...
520
  	tps65910_irq_exit(tps65910);
1e351a95b   Afzal Mohammed   mfd: Make TPS6591...
521
  	mfd_remove_devices(tps65910->dev);
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
522
523
524
525
526
  
  	return 0;
  }
  
  static const struct i2c_device_id tps65910_i2c_id[] = {
795570561   Jorge Eduardo Candelaria   MFD: TPS65910: Ad...
527
528
         { "tps65910", TPS65910 },
         { "tps65911", TPS65911 },
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
529
530
531
532
533
534
535
536
537
         { }
  };
  MODULE_DEVICE_TABLE(i2c, tps65910_i2c_id);
  
  
  static struct i2c_driver tps65910_i2c_driver = {
  	.driver = {
  		   .name = "tps65910",
  		   .owner = THIS_MODULE,
cd4209ced   Rhyland Klein   mfd: Add tps65910...
538
  		   .of_match_table = of_match_ptr(tps65910_of_match),
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
539
540
  	},
  	.probe = tps65910_i2c_probe,
84449216b   Bill Pemberton   mfd: remove use o...
541
  	.remove = tps65910_i2c_remove,
27c6750ec   Graeme Gregory   MFD: TPS65910: Ad...
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
  	.id_table = tps65910_i2c_id,
  };
  
  static int __init tps65910_i2c_init(void)
  {
  	return i2c_add_driver(&tps65910_i2c_driver);
  }
  /* init early so consumer devices can complete system boot */
  subsys_initcall(tps65910_i2c_init);
  
  static void __exit tps65910_i2c_exit(void)
  {
  	i2c_del_driver(&tps65910_i2c_driver);
  }
  module_exit(tps65910_i2c_exit);
  
  MODULE_AUTHOR("Graeme Gregory <gg@slimlogic.co.uk>");
  MODULE_AUTHOR("Jorge Eduardo Candelaria <jedu@slimlogic.co.uk>");
  MODULE_DESCRIPTION("TPS6591x chip family multi-function driver");
  MODULE_LICENSE("GPL");