Blame view

drivers/mfd/twl-core.c 33.9 KB
a603a7fa8   David Brownell   mfd: TWL4030 core...
1
  /*
fc7b92fca   Balaji T K   mfd: Rename all t...
2
3
   * twl_core.c - driver for TWL4030/TWL5030/TWL60X0/TPS659x0 PM
   * and audio CODEC devices
a603a7fa8   David Brownell   mfd: TWL4030 core...
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
   *
   * Copyright (C) 2005-2006 Texas Instruments, Inc.
   *
   * Modifications to defer interrupt handling to a kernel thread:
   * Copyright (C) 2006 MontaVista Software, Inc.
   *
   * Based on tlv320aic23.c:
   * Copyright (c) by Kai Svahn <kai.svahn@nokia.com>
   *
   * Code cleanup and modifications to IRQ handler.
   * by syed khasim <x0khasim@ti.com>
   *
   * 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.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   */
a603a7fa8   David Brownell   mfd: TWL4030 core...
30
31
  #include <linux/init.h>
  #include <linux/mutex.h>
a603a7fa8   David Brownell   mfd: TWL4030 core...
32
33
  #include <linux/platform_device.h>
  #include <linux/clk.h>
a30d46c04   David Brownell   mfd: twl4030 IRQ ...
34
  #include <linux/err.h>
a603a7fa8   David Brownell   mfd: TWL4030 core...
35

dad759ff8   David Brownell   mfd: twl4030: cre...
36
  #include <linux/regulator/machine.h>
a603a7fa8   David Brownell   mfd: TWL4030 core...
37
  #include <linux/i2c.h>
b07682b60   Santosh Shilimkar   mfd: Rename twl40...
38
  #include <linux/i2c/twl.h>
a603a7fa8   David Brownell   mfd: TWL4030 core...
39

a313d758c   Mark Brown   mfd: Fix TWL4030 ...
40
  #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
ce491cf85   Tony Lindgren   omap: headers: Mo...
41
  #include <plat/cpu.h>
b29c06ae9   Samuel Ortiz   mfd: Fix twl4030-...
42
  #endif
a603a7fa8   David Brownell   mfd: TWL4030 core...
43
44
45
46
47
48
49
50
51
52
53
54
55
  
  /*
   * The TWL4030 "Triton 2" is one of a family of a multi-function "Power
   * Management and System Companion Device" chips originally designed for
   * use in OMAP2 and OMAP 3 based systems.  Its control interfaces use I2C,
   * often at around 3 Mbit/sec, including for interrupt handling.
   *
   * This driver core provides genirq support for the interrupts emitted,
   * by the various modules, and exports register access primitives.
   *
   * FIXME this driver currently requires use of the first interrupt line
   * (and associated registers).
   */
fc7b92fca   Balaji T K   mfd: Rename all t...
56
  #define DRIVER_NAME			"twl"
a603a7fa8   David Brownell   mfd: TWL4030 core...
57

a603a7fa8   David Brownell   mfd: TWL4030 core...
58
59
60
61
62
63
64
65
66
67
68
  #if defined(CONFIG_KEYBOARD_TWL4030) || defined(CONFIG_KEYBOARD_TWL4030_MODULE)
  #define twl_has_keypad()	true
  #else
  #define twl_has_keypad()	false
  #endif
  
  #if defined(CONFIG_GPIO_TWL4030) || defined(CONFIG_GPIO_TWL4030_MODULE)
  #define twl_has_gpio()	true
  #else
  #define twl_has_gpio()	false
  #endif
dad759ff8   David Brownell   mfd: twl4030: cre...
69
70
71
72
73
74
  #if defined(CONFIG_REGULATOR_TWL4030) \
  	|| defined(CONFIG_REGULATOR_TWL4030_MODULE)
  #define twl_has_regulator()	true
  #else
  #define twl_has_regulator()	false
  #endif
a603a7fa8   David Brownell   mfd: TWL4030 core...
75
76
77
78
79
  #if defined(CONFIG_TWL4030_MADC) || defined(CONFIG_TWL4030_MADC_MODULE)
  #define twl_has_madc()	true
  #else
  #define twl_has_madc()	false
  #endif
ebf0bd366   Amit Kucheria   mfd: Add support ...
80
81
82
83
84
  #ifdef CONFIG_TWL4030_POWER
  #define twl_has_power()        true
  #else
  #define twl_has_power()        false
  #endif
a603a7fa8   David Brownell   mfd: TWL4030 core...
85
86
87
88
89
  #if defined(CONFIG_RTC_DRV_TWL4030) || defined(CONFIG_RTC_DRV_TWL4030_MODULE)
  #define twl_has_rtc()	true
  #else
  #define twl_has_rtc()	false
  #endif
e70357e35   Hema HK   mfd: TWL6030: OMA...
90
91
  #if defined(CONFIG_TWL4030_USB) || defined(CONFIG_TWL4030_USB_MODULE) ||\
  	defined(CONFIG_TWL6030_USB) || defined(CONFIG_TWL6030_USB_MODULE)
a603a7fa8   David Brownell   mfd: TWL4030 core...
92
93
94
95
  #define twl_has_usb()	true
  #else
  #define twl_has_usb()	false
  #endif
80e45b1e9   Timo Kokkonen   [WATCHDOG] twl403...
96
97
98
99
100
101
  #if defined(CONFIG_TWL4030_WATCHDOG) || \
  	defined(CONFIG_TWL4030_WATCHDOG_MODULE)
  #define twl_has_watchdog()        true
  #else
  #define twl_has_watchdog()        false
  #endif
a603a7fa8   David Brownell   mfd: TWL4030 core...
102

d62abe563   Misael Lopez Cruz   OMAP4: PMIC: Add ...
103
  #if defined(CONFIG_TWL4030_CODEC) || defined(CONFIG_TWL4030_CODEC_MODULE) ||\
f19b2823f   Misael Lopez Cruz   mfd: twl6040: Add...
104
  	defined(CONFIG_TWL6040_CORE) || defined(CONFIG_TWL6040_CORE_MODULE)
0b83ddebc   Peter Ujfalusi   MFD: twl4030: add...
105
106
107
108
  #define twl_has_codec()	true
  #else
  #define twl_has_codec()	false
  #endif
11c39c4bd   Grazvydas Ignotas   mfd: Add twl4030_...
109
110
111
112
113
  #if defined(CONFIG_CHARGER_TWL4030) || defined(CONFIG_CHARGER_TWL4030_MODULE)
  #define twl_has_bci()	true
  #else
  #define twl_has_bci()	false
  #endif
a603a7fa8   David Brownell   mfd: TWL4030 core...
114
115
116
117
  /* Triton Core internal information (BEGIN) */
  
  /* Last - for index max*/
  #define TWL4030_MODULE_LAST		TWL4030_MODULE_SECURED_REG
fc7b92fca   Balaji T K   mfd: Rename all t...
118
  #define TWL_NUM_SLAVES		4
a603a7fa8   David Brownell   mfd: TWL4030 core...
119

9c3664ddc   Felipe Balbi   mfd: Add twl4030-...
120
  #if defined(CONFIG_INPUT_TWL4030_PWRBUTTON) \
14e5c82ca   Eduardo Valentin   mfd: Fix twl_has_...
121
  	|| defined(CONFIG_INPUT_TWL4030_PWRBUTTON_MODULE)
9c3664ddc   Felipe Balbi   mfd: Add twl4030-...
122
123
124
125
  #define twl_has_pwrbutton()	true
  #else
  #define twl_has_pwrbutton()	false
  #endif
a603a7fa8   David Brownell   mfd: TWL4030 core...
126

fc7b92fca   Balaji T K   mfd: Rename all t...
127
128
129
130
131
132
  #define SUB_CHIP_ID0 0
  #define SUB_CHIP_ID1 1
  #define SUB_CHIP_ID2 2
  #define SUB_CHIP_ID3 3
  
  #define TWL_MODULE_LAST TWL4030_MODULE_LAST
a603a7fa8   David Brownell   mfd: TWL4030 core...
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
  /* Base Address defns for twl4030_map[] */
  
  /* subchip/slave 0 - USB ID */
  #define TWL4030_BASEADD_USB		0x0000
  
  /* subchip/slave 1 - AUD ID */
  #define TWL4030_BASEADD_AUDIO_VOICE	0x0000
  #define TWL4030_BASEADD_GPIO		0x0098
  #define TWL4030_BASEADD_INTBR		0x0085
  #define TWL4030_BASEADD_PIH		0x0080
  #define TWL4030_BASEADD_TEST		0x004C
  
  /* subchip/slave 2 - AUX ID */
  #define TWL4030_BASEADD_INTERRUPTS	0x00B9
  #define TWL4030_BASEADD_LED		0x00EE
  #define TWL4030_BASEADD_MADC		0x0000
  #define TWL4030_BASEADD_MAIN_CHARGE	0x0074
  #define TWL4030_BASEADD_PRECHARGE	0x00AA
  #define TWL4030_BASEADD_PWM0		0x00F8
  #define TWL4030_BASEADD_PWM1		0x00FB
  #define TWL4030_BASEADD_PWMA		0x00EF
  #define TWL4030_BASEADD_PWMB		0x00F1
  #define TWL4030_BASEADD_KEYPAD		0x00D2
1920a61e2   Ilkka Koskinen   mfd: Initial supp...
156
157
158
  #define TWL5031_BASEADD_ACCESSORY	0x0074 /* Replaces Main Charge */
  #define TWL5031_BASEADD_INTERRUPTS	0x00B9 /* Different than TWL4030's
  						  one */
a603a7fa8   David Brownell   mfd: TWL4030 core...
159
160
161
162
163
164
165
166
167
  /* subchip/slave 3 - POWER ID */
  #define TWL4030_BASEADD_BACKUP		0x0014
  #define TWL4030_BASEADD_INT		0x002E
  #define TWL4030_BASEADD_PM_MASTER	0x0036
  #define TWL4030_BASEADD_PM_RECEIVER	0x005B
  #define TWL4030_BASEADD_RTC		0x001C
  #define TWL4030_BASEADD_SECURED_REG	0x0000
  
  /* Triton Core internal information (END) */
e8deb28ca   Balaji T K   mfd: Add support ...
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
  /* subchip/slave 0 0x48 - POWER */
  #define TWL6030_BASEADD_RTC		0x0000
  #define TWL6030_BASEADD_MEM		0x0017
  #define TWL6030_BASEADD_PM_MASTER	0x001F
  #define TWL6030_BASEADD_PM_SLAVE_MISC	0x0030 /* PM_RECEIVER */
  #define TWL6030_BASEADD_PM_MISC		0x00E2
  #define TWL6030_BASEADD_PM_PUPD		0x00F0
  
  /* subchip/slave 1 0x49 - FEATURE */
  #define TWL6030_BASEADD_USB		0x0000
  #define TWL6030_BASEADD_GPADC_CTRL	0x002E
  #define TWL6030_BASEADD_AUX		0x0090
  #define TWL6030_BASEADD_PWM		0x00BA
  #define TWL6030_BASEADD_GASGAUGE	0x00C0
  #define TWL6030_BASEADD_PIH		0x00D0
  #define TWL6030_BASEADD_CHARGER		0x00E0
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
184
  #define TWL6025_BASEADD_CHARGER		0x00DA
e8deb28ca   Balaji T K   mfd: Add support ...
185
186
187
188
189
190
191
  
  /* subchip/slave 2 0x4A - DFT */
  #define TWL6030_BASEADD_DIEID		0x00C0
  
  /* subchip/slave 3 0x4B - AUDIO */
  #define TWL6030_BASEADD_AUDIO		0x0000
  #define TWL6030_BASEADD_RSV		0x0000
fa0d97629   Balaji T K   mfd: Add twl6030 ...
192
  #define TWL6030_BASEADD_ZERO		0x0000
e8deb28ca   Balaji T K   mfd: Add support ...
193

a603a7fa8   David Brownell   mfd: TWL4030 core...
194
195
  /* Few power values */
  #define R_CFG_BOOT			0x05
a603a7fa8   David Brownell   mfd: TWL4030 core...
196
197
198
199
200
201
  
  /* some fields in R_CFG_BOOT */
  #define HFCLK_FREQ_19p2_MHZ		(1 << 0)
  #define HFCLK_FREQ_26_MHZ		(2 << 0)
  #define HFCLK_FREQ_38p4_MHZ		(3 << 0)
  #define HIGH_PERF_SQ			(1 << 3)
38a684963   Ilkka Koskinen   mfd: Enable twl40...
202
  #define CK32K_LOWPWR_EN			(1 << 7)
a603a7fa8   David Brownell   mfd: TWL4030 core...
203

dad759ff8   David Brownell   mfd: twl4030: cre...
204
205
206
  /* chip-specific feature flags, for i2c_device_id.driver_data */
  #define TWL4030_VAUX2		BIT(0)	/* pre-5030 voltage ranges */
  #define TPS_SUBSET		BIT(1)	/* tps659[23]0 have fewer LDOs */
1920a61e2   Ilkka Koskinen   mfd: Initial supp...
207
  #define TWL5031			BIT(2)  /* twl5031 has different registers */
e8deb28ca   Balaji T K   mfd: Add support ...
208
  #define TWL6030_CLASS		BIT(3)	/* TWL6030 class */
dad759ff8   David Brownell   mfd: twl4030: cre...
209

a603a7fa8   David Brownell   mfd: TWL4030 core...
210
  /*----------------------------------------------------------------------*/
a603a7fa8   David Brownell   mfd: TWL4030 core...
211
212
  /* is driver active, bound to a chip? */
  static bool inuse;
ca972d133   Lesly A M   mfd: TWL5030 vers...
213
214
  /* TWL IDCODE Register value */
  static u32 twl_idcode;
e8deb28ca   Balaji T K   mfd: Add support ...
215
216
217
218
219
220
221
222
  static unsigned int twl_id;
  unsigned int twl_rev(void)
  {
  	return twl_id;
  }
  EXPORT_SYMBOL(twl_rev);
  
  /* Structure for each TWL4030/TWL6030 Slave */
fc7b92fca   Balaji T K   mfd: Rename all t...
223
  struct twl_client {
a603a7fa8   David Brownell   mfd: TWL4030 core...
224
225
226
227
228
229
230
231
232
  	struct i2c_client *client;
  	u8 address;
  
  	/* max numb of i2c_msg required is for read =2 */
  	struct i2c_msg xfer_msg[2];
  
  	/* To lock access to xfer_msg */
  	struct mutex xfer_lock;
  };
fc7b92fca   Balaji T K   mfd: Rename all t...
233
  static struct twl_client twl_modules[TWL_NUM_SLAVES];
a603a7fa8   David Brownell   mfd: TWL4030 core...
234
235
236
  
  
  /* mapping the module id to slave id and base address */
fc7b92fca   Balaji T K   mfd: Rename all t...
237
  struct twl_mapping {
a603a7fa8   David Brownell   mfd: TWL4030 core...
238
239
240
  	unsigned char sid;	/* Slave ID */
  	unsigned char base;	/* base address */
  };
2cfcce18b   G, Manjunath Kondaiah   mfd: Fix twl-core...
241
  static struct twl_mapping *twl_map;
a603a7fa8   David Brownell   mfd: TWL4030 core...
242

fc7b92fca   Balaji T K   mfd: Rename all t...
243
  static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {
a603a7fa8   David Brownell   mfd: TWL4030 core...
244
245
  	/*
  	 * NOTE:  don't change this table without updating the
e8deb28ca   Balaji T K   mfd: Add support ...
246
  	 * <linux/i2c/twl.h> defines for TWL4030_MODULE_*
a603a7fa8   David Brownell   mfd: TWL4030 core...
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
  	 * so they continue to match the order in this table.
  	 */
  
  	{ 0, TWL4030_BASEADD_USB },
  
  	{ 1, TWL4030_BASEADD_AUDIO_VOICE },
  	{ 1, TWL4030_BASEADD_GPIO },
  	{ 1, TWL4030_BASEADD_INTBR },
  	{ 1, TWL4030_BASEADD_PIH },
  	{ 1, TWL4030_BASEADD_TEST },
  
  	{ 2, TWL4030_BASEADD_KEYPAD },
  	{ 2, TWL4030_BASEADD_MADC },
  	{ 2, TWL4030_BASEADD_INTERRUPTS },
  	{ 2, TWL4030_BASEADD_LED },
  	{ 2, TWL4030_BASEADD_MAIN_CHARGE },
  	{ 2, TWL4030_BASEADD_PRECHARGE },
  	{ 2, TWL4030_BASEADD_PWM0 },
  	{ 2, TWL4030_BASEADD_PWM1 },
  	{ 2, TWL4030_BASEADD_PWMA },
  	{ 2, TWL4030_BASEADD_PWMB },
1920a61e2   Ilkka Koskinen   mfd: Initial supp...
268
269
  	{ 2, TWL5031_BASEADD_ACCESSORY },
  	{ 2, TWL5031_BASEADD_INTERRUPTS },
a603a7fa8   David Brownell   mfd: TWL4030 core...
270
271
272
273
274
275
276
277
  
  	{ 3, TWL4030_BASEADD_BACKUP },
  	{ 3, TWL4030_BASEADD_INT },
  	{ 3, TWL4030_BASEADD_PM_MASTER },
  	{ 3, TWL4030_BASEADD_PM_RECEIVER },
  	{ 3, TWL4030_BASEADD_RTC },
  	{ 3, TWL4030_BASEADD_SECURED_REG },
  };
e8deb28ca   Balaji T K   mfd: Add support ...
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
  static struct twl_mapping twl6030_map[] = {
  	/*
  	 * NOTE:  don't change this table without updating the
  	 * <linux/i2c/twl.h> defines for TWL4030_MODULE_*
  	 * so they continue to match the order in this table.
  	 */
  	{ SUB_CHIP_ID1, TWL6030_BASEADD_USB },
  	{ SUB_CHIP_ID3, TWL6030_BASEADD_AUDIO },
  	{ SUB_CHIP_ID2, TWL6030_BASEADD_DIEID },
  	{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
  	{ SUB_CHIP_ID1, TWL6030_BASEADD_PIH },
  
  	{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
  	{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
  	{ SUB_CHIP_ID1, TWL6030_BASEADD_GPADC_CTRL },
  	{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
  	{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
  
  	{ SUB_CHIP_ID1, TWL6030_BASEADD_CHARGER },
  	{ SUB_CHIP_ID1, TWL6030_BASEADD_GASGAUGE },
  	{ SUB_CHIP_ID1, TWL6030_BASEADD_PWM },
fa0d97629   Balaji T K   mfd: Add twl6030 ...
299
300
  	{ SUB_CHIP_ID0, TWL6030_BASEADD_ZERO },
  	{ SUB_CHIP_ID1, TWL6030_BASEADD_ZERO },
e8deb28ca   Balaji T K   mfd: Add support ...
301

fa0d97629   Balaji T K   mfd: Add twl6030 ...
302
303
  	{ SUB_CHIP_ID2, TWL6030_BASEADD_ZERO },
  	{ SUB_CHIP_ID2, TWL6030_BASEADD_ZERO },
e8deb28ca   Balaji T K   mfd: Add support ...
304
305
306
307
308
309
310
311
  	{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
  	{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
  	{ SUB_CHIP_ID2, TWL6030_BASEADD_RSV },
  	{ SUB_CHIP_ID0, TWL6030_BASEADD_PM_MASTER },
  	{ SUB_CHIP_ID0, TWL6030_BASEADD_PM_SLAVE_MISC },
  
  	{ SUB_CHIP_ID0, TWL6030_BASEADD_RTC },
  	{ SUB_CHIP_ID0, TWL6030_BASEADD_MEM },
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
312
  	{ SUB_CHIP_ID1, TWL6025_BASEADD_CHARGER },
e8deb28ca   Balaji T K   mfd: Add support ...
313
  };
a603a7fa8   David Brownell   mfd: TWL4030 core...
314
  /*----------------------------------------------------------------------*/
a603a7fa8   David Brownell   mfd: TWL4030 core...
315
316
317
  /* Exported Functions */
  
  /**
fc7b92fca   Balaji T K   mfd: Rename all t...
318
   * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
a603a7fa8   David Brownell   mfd: TWL4030 core...
319
320
321
322
323
324
325
326
327
328
   * @mod_no: module number
   * @value: an array of num_bytes+1 containing data to write
   * @reg: register address (just offset will do)
   * @num_bytes: number of bytes to transfer
   *
   * IMPORTANT: for 'value' parameter: Allocate value num_bytes+1 and
   * valid data starts at Offset 1.
   *
   * Returns the result of operation - 0 is success
   */
fc7b92fca   Balaji T K   mfd: Rename all t...
329
  int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
a603a7fa8   David Brownell   mfd: TWL4030 core...
330
331
332
  {
  	int ret;
  	int sid;
fc7b92fca   Balaji T K   mfd: Rename all t...
333
  	struct twl_client *twl;
a603a7fa8   David Brownell   mfd: TWL4030 core...
334
  	struct i2c_msg *msg;
fc7b92fca   Balaji T K   mfd: Rename all t...
335
  	if (unlikely(mod_no > TWL_MODULE_LAST)) {
a603a7fa8   David Brownell   mfd: TWL4030 core...
336
337
338
339
  		pr_err("%s: invalid module number %d
  ", DRIVER_NAME, mod_no);
  		return -EPERM;
  	}
e8deb28ca   Balaji T K   mfd: Add support ...
340
  	sid = twl_map[mod_no].sid;
fc7b92fca   Balaji T K   mfd: Rename all t...
341
  	twl = &twl_modules[sid];
a603a7fa8   David Brownell   mfd: TWL4030 core...
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
  
  	if (unlikely(!inuse)) {
  		pr_err("%s: client %d is not initialized
  ", DRIVER_NAME, sid);
  		return -EPERM;
  	}
  	mutex_lock(&twl->xfer_lock);
  	/*
  	 * [MSG1]: fill the register address data
  	 * fill the data Tx buffer
  	 */
  	msg = &twl->xfer_msg[0];
  	msg->addr = twl->address;
  	msg->len = num_bytes + 1;
  	msg->flags = 0;
  	msg->buf = value;
  	/* over write the first byte of buffer with the register address */
e8deb28ca   Balaji T K   mfd: Add support ...
359
  	*value = twl_map[mod_no].base + reg;
a603a7fa8   David Brownell   mfd: TWL4030 core...
360
361
  	ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 1);
  	mutex_unlock(&twl->xfer_lock);
147e08479   Amit Kucheria   mfd: Clarify twl4...
362
363
364
365
366
367
368
369
370
371
372
373
  	/* i2c_transfer returns number of messages transferred */
  	if (ret != 1) {
  		pr_err("%s: i2c_write failed to transfer all messages
  ",
  			DRIVER_NAME);
  		if (ret < 0)
  			return ret;
  		else
  			return -EIO;
  	} else {
  		return 0;
  	}
a603a7fa8   David Brownell   mfd: TWL4030 core...
374
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
375
  EXPORT_SYMBOL(twl_i2c_write);
a603a7fa8   David Brownell   mfd: TWL4030 core...
376
377
  
  /**
fc7b92fca   Balaji T K   mfd: Rename all t...
378
   * twl_i2c_read - Reads a n bit register in TWL4030/TWL5030/TWL60X0
a603a7fa8   David Brownell   mfd: TWL4030 core...
379
380
381
382
383
384
385
   * @mod_no: module number
   * @value: an array of num_bytes containing data to be read
   * @reg: register address (just offset will do)
   * @num_bytes: number of bytes to transfer
   *
   * Returns result of operation - num_bytes is success else failure.
   */
fc7b92fca   Balaji T K   mfd: Rename all t...
386
  int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
a603a7fa8   David Brownell   mfd: TWL4030 core...
387
388
389
390
  {
  	int ret;
  	u8 val;
  	int sid;
fc7b92fca   Balaji T K   mfd: Rename all t...
391
  	struct twl_client *twl;
a603a7fa8   David Brownell   mfd: TWL4030 core...
392
  	struct i2c_msg *msg;
fc7b92fca   Balaji T K   mfd: Rename all t...
393
  	if (unlikely(mod_no > TWL_MODULE_LAST)) {
a603a7fa8   David Brownell   mfd: TWL4030 core...
394
395
396
397
  		pr_err("%s: invalid module number %d
  ", DRIVER_NAME, mod_no);
  		return -EPERM;
  	}
e8deb28ca   Balaji T K   mfd: Add support ...
398
  	sid = twl_map[mod_no].sid;
fc7b92fca   Balaji T K   mfd: Rename all t...
399
  	twl = &twl_modules[sid];
a603a7fa8   David Brownell   mfd: TWL4030 core...
400
401
402
403
404
405
406
407
408
409
410
411
  
  	if (unlikely(!inuse)) {
  		pr_err("%s: client %d is not initialized
  ", DRIVER_NAME, sid);
  		return -EPERM;
  	}
  	mutex_lock(&twl->xfer_lock);
  	/* [MSG1] fill the register address data */
  	msg = &twl->xfer_msg[0];
  	msg->addr = twl->address;
  	msg->len = 1;
  	msg->flags = 0;	/* Read the register value */
e8deb28ca   Balaji T K   mfd: Add support ...
412
  	val = twl_map[mod_no].base + reg;
a603a7fa8   David Brownell   mfd: TWL4030 core...
413
414
415
416
417
418
419
420
421
  	msg->buf = &val;
  	/* [MSG2] fill the data rx buffer */
  	msg = &twl->xfer_msg[1];
  	msg->addr = twl->address;
  	msg->flags = I2C_M_RD;	/* Read the register value */
  	msg->len = num_bytes;	/* only n bytes */
  	msg->buf = value;
  	ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 2);
  	mutex_unlock(&twl->xfer_lock);
147e08479   Amit Kucheria   mfd: Clarify twl4...
422
423
424
425
426
427
428
429
430
431
432
433
  	/* i2c_transfer returns number of messages transferred */
  	if (ret != 2) {
  		pr_err("%s: i2c_read failed to transfer all messages
  ",
  			DRIVER_NAME);
  		if (ret < 0)
  			return ret;
  		else
  			return -EIO;
  	} else {
  		return 0;
  	}
a603a7fa8   David Brownell   mfd: TWL4030 core...
434
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
435
  EXPORT_SYMBOL(twl_i2c_read);
a603a7fa8   David Brownell   mfd: TWL4030 core...
436
437
  
  /**
fc7b92fca   Balaji T K   mfd: Rename all t...
438
   * twl_i2c_write_u8 - Writes a 8 bit register in TWL4030/TWL5030/TWL60X0
a603a7fa8   David Brownell   mfd: TWL4030 core...
439
440
441
442
443
444
   * @mod_no: module number
   * @value: the value to be written 8 bit
   * @reg: register address (just offset will do)
   *
   * Returns result of operation - 0 is success
   */
fc7b92fca   Balaji T K   mfd: Rename all t...
445
  int twl_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
a603a7fa8   David Brownell   mfd: TWL4030 core...
446
447
448
449
450
451
  {
  
  	/* 2 bytes offset 1 contains the data offset 0 is used by i2c_write */
  	u8 temp_buffer[2] = { 0 };
  	/* offset 1 contains the data */
  	temp_buffer[1] = value;
fc7b92fca   Balaji T K   mfd: Rename all t...
452
  	return twl_i2c_write(mod_no, temp_buffer, reg, 1);
a603a7fa8   David Brownell   mfd: TWL4030 core...
453
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
454
  EXPORT_SYMBOL(twl_i2c_write_u8);
a603a7fa8   David Brownell   mfd: TWL4030 core...
455
456
  
  /**
fc7b92fca   Balaji T K   mfd: Rename all t...
457
   * twl_i2c_read_u8 - Reads a 8 bit register from TWL4030/TWL5030/TWL60X0
a603a7fa8   David Brownell   mfd: TWL4030 core...
458
459
460
461
462
463
   * @mod_no: module number
   * @value: the value read 8 bit
   * @reg: register address (just offset will do)
   *
   * Returns result of operation - 0 is success
   */
fc7b92fca   Balaji T K   mfd: Rename all t...
464
  int twl_i2c_read_u8(u8 mod_no, u8 *value, u8 reg)
a603a7fa8   David Brownell   mfd: TWL4030 core...
465
  {
fc7b92fca   Balaji T K   mfd: Rename all t...
466
  	return twl_i2c_read(mod_no, value, reg, 1);
a603a7fa8   David Brownell   mfd: TWL4030 core...
467
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
468
  EXPORT_SYMBOL(twl_i2c_read_u8);
a603a7fa8   David Brownell   mfd: TWL4030 core...
469
470
  
  /*----------------------------------------------------------------------*/
ca972d133   Lesly A M   mfd: TWL5030 vers...
471
472
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
511
512
513
514
515
516
517
518
519
520
521
522
523
524
  /**
   * twl_read_idcode_register - API to read the IDCODE register.
   *
   * Unlocks the IDCODE register and read the 32 bit value.
   */
  static int twl_read_idcode_register(void)
  {
  	int err;
  
  	err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, TWL_EEPROM_R_UNLOCK,
  						REG_UNLOCK_TEST_REG);
  	if (err) {
  		pr_err("TWL4030 Unable to unlock IDCODE registers -%d
  ", err);
  		goto fail;
  	}
  
  	err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_idcode),
  						REG_IDCODE_7_0, 4);
  	if (err) {
  		pr_err("TWL4030: unable to read IDCODE -%d
  ", err);
  		goto fail;
  	}
  
  	err = twl_i2c_write_u8(TWL4030_MODULE_INTBR, 0x0, REG_UNLOCK_TEST_REG);
  	if (err)
  		pr_err("TWL4030 Unable to relock IDCODE registers -%d
  ", err);
  fail:
  	return err;
  }
  
  /**
   * twl_get_type - API to get TWL Si type.
   *
   * Api to get the TWL Si type from IDCODE value.
   */
  int twl_get_type(void)
  {
  	return TWL_SIL_TYPE(twl_idcode);
  }
  EXPORT_SYMBOL_GPL(twl_get_type);
  
  /**
   * twl_get_version - API to get TWL Si version.
   *
   * Api to get the TWL Si version from IDCODE value.
   */
  int twl_get_version(void)
  {
  	return TWL_SIL_REV(twl_idcode);
  }
  EXPORT_SYMBOL_GPL(twl_get_version);
dad759ff8   David Brownell   mfd: twl4030: cre...
525
526
  static struct device *
  add_numbered_child(unsigned chip, const char *name, int num,
5725d66b9   David Brownell   mfd: twl4030: sim...
527
528
  		void *pdata, unsigned pdata_len,
  		bool can_wakeup, int irq0, int irq1)
a603a7fa8   David Brownell   mfd: TWL4030 core...
529
  {
5725d66b9   David Brownell   mfd: twl4030: sim...
530
  	struct platform_device	*pdev;
fc7b92fca   Balaji T K   mfd: Rename all t...
531
  	struct twl_client	*twl = &twl_modules[chip];
5725d66b9   David Brownell   mfd: twl4030: sim...
532
  	int			status;
dad759ff8   David Brownell   mfd: twl4030: cre...
533
  	pdev = platform_device_alloc(name, num);
5725d66b9   David Brownell   mfd: twl4030: sim...
534
535
536
537
538
539
  	if (!pdev) {
  		dev_dbg(&twl->client->dev, "can't alloc dev
  ");
  		status = -ENOMEM;
  		goto err;
  	}
a603a7fa8   David Brownell   mfd: TWL4030 core...
540

5725d66b9   David Brownell   mfd: twl4030: sim...
541
542
  	device_init_wakeup(&pdev->dev, can_wakeup);
  	pdev->dev.parent = &twl->client->dev;
a603a7fa8   David Brownell   mfd: TWL4030 core...
543

5725d66b9   David Brownell   mfd: twl4030: sim...
544
545
546
547
548
  	if (pdata) {
  		status = platform_device_add_data(pdev, pdata, pdata_len);
  		if (status < 0) {
  			dev_dbg(&pdev->dev, "can't add platform_data
  ");
a603a7fa8   David Brownell   mfd: TWL4030 core...
549
550
  			goto err;
  		}
5725d66b9   David Brownell   mfd: twl4030: sim...
551
  	}
a603a7fa8   David Brownell   mfd: TWL4030 core...
552

5725d66b9   David Brownell   mfd: twl4030: sim...
553
554
555
556
557
  	if (irq0) {
  		struct resource r[2] = {
  			{ .start = irq0, .flags = IORESOURCE_IRQ, },
  			{ .start = irq1, .flags = IORESOURCE_IRQ, },
  		};
a603a7fa8   David Brownell   mfd: TWL4030 core...
558

5725d66b9   David Brownell   mfd: twl4030: sim...
559
  		status = platform_device_add_resources(pdev, r, irq1 ? 2 : 1);
a603a7fa8   David Brownell   mfd: TWL4030 core...
560
  		if (status < 0) {
5725d66b9   David Brownell   mfd: twl4030: sim...
561
562
  			dev_dbg(&pdev->dev, "can't add irqs
  ");
a603a7fa8   David Brownell   mfd: TWL4030 core...
563
564
565
  			goto err;
  		}
  	}
5725d66b9   David Brownell   mfd: twl4030: sim...
566
  	status = platform_device_add(pdev);
a603a7fa8   David Brownell   mfd: TWL4030 core...
567

5725d66b9   David Brownell   mfd: twl4030: sim...
568
569
570
571
572
573
574
575
576
  err:
  	if (status < 0) {
  		platform_device_put(pdev);
  		dev_err(&twl->client->dev, "can't add %s dev
  ", name);
  		return ERR_PTR(status);
  	}
  	return &pdev->dev;
  }
a603a7fa8   David Brownell   mfd: TWL4030 core...
577

dad759ff8   David Brownell   mfd: twl4030: cre...
578
579
580
581
582
583
584
585
586
587
588
  static inline struct device *add_child(unsigned chip, const char *name,
  		void *pdata, unsigned pdata_len,
  		bool can_wakeup, int irq0, int irq1)
  {
  	return add_numbered_child(chip, name, -1, pdata, pdata_len,
  		can_wakeup, irq0, irq1);
  }
  
  static struct device *
  add_regulator_linked(int num, struct regulator_init_data *pdata,
  		struct regulator_consumer_supply *consumers,
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
589
  		unsigned num_consumers, unsigned long features)
dad759ff8   David Brownell   mfd: twl4030: cre...
590
  {
e8deb28ca   Balaji T K   mfd: Add support ...
591
  	unsigned sub_chip_id;
dad759ff8   David Brownell   mfd: twl4030: cre...
592
593
594
  	/* regulator framework demands init_data ... */
  	if (!pdata)
  		return NULL;
b73eac787   David Brownell   mfd: twl4030 regu...
595
  	if (consumers) {
dad759ff8   David Brownell   mfd: twl4030: cre...
596
597
598
  		pdata->consumer_supplies = consumers;
  		pdata->num_consumer_supplies = num_consumers;
  	}
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
599
  	pdata->driver_data = (void *)features;
dad759ff8   David Brownell   mfd: twl4030: cre...
600
  	/* NOTE:  we currently ignore regulator IRQs, e.g. for short circuits */
e8deb28ca   Balaji T K   mfd: Add support ...
601
602
  	sub_chip_id = twl_map[TWL_MODULE_PM_MASTER].sid;
  	return add_numbered_child(sub_chip_id, "twl_reg", num,
dad759ff8   David Brownell   mfd: twl4030: cre...
603
604
605
606
  		pdata, sizeof(*pdata), false, 0, 0);
  }
  
  static struct device *
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
607
608
  add_regulator(int num, struct regulator_init_data *pdata,
  		unsigned long features)
dad759ff8   David Brownell   mfd: twl4030: cre...
609
  {
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
610
  	return add_regulator_linked(num, pdata, NULL, 0, features);
dad759ff8   David Brownell   mfd: twl4030: cre...
611
  }
5725d66b9   David Brownell   mfd: twl4030: sim...
612
613
614
615
616
  /*
   * NOTE:  We know the first 8 IRQs after pdata->base_irq are
   * for the PIH, and the next are for the PWR_INT SIH, since
   * that's how twl_init_irq() sets things up.
   */
a603a7fa8   David Brownell   mfd: TWL4030 core...
617

dad759ff8   David Brownell   mfd: twl4030: cre...
618
619
  static int
  add_children(struct twl4030_platform_data *pdata, unsigned long features)
5725d66b9   David Brownell   mfd: twl4030: sim...
620
621
  {
  	struct device	*child;
e8deb28ca   Balaji T K   mfd: Add support ...
622
  	unsigned sub_chip_id;
a603a7fa8   David Brownell   mfd: TWL4030 core...
623

5725d66b9   David Brownell   mfd: twl4030: sim...
624
  	if (twl_has_gpio() && pdata->gpio) {
fc7b92fca   Balaji T K   mfd: Rename all t...
625
  		child = add_child(SUB_CHIP_ID1, "twl4030_gpio",
5725d66b9   David Brownell   mfd: twl4030: sim...
626
  				pdata->gpio, sizeof(*pdata->gpio),
fc7b92fca   Balaji T K   mfd: Rename all t...
627
  				false, pdata->irq_base + GPIO_INTR_OFFSET, 0);
5725d66b9   David Brownell   mfd: twl4030: sim...
628
629
  		if (IS_ERR(child))
  			return PTR_ERR(child);
a603a7fa8   David Brownell   mfd: TWL4030 core...
630
631
632
  	}
  
  	if (twl_has_keypad() && pdata->keypad) {
fc7b92fca   Balaji T K   mfd: Rename all t...
633
  		child = add_child(SUB_CHIP_ID2, "twl4030_keypad",
5725d66b9   David Brownell   mfd: twl4030: sim...
634
  				pdata->keypad, sizeof(*pdata->keypad),
fc7b92fca   Balaji T K   mfd: Rename all t...
635
  				true, pdata->irq_base + KEYPAD_INTR_OFFSET, 0);
5725d66b9   David Brownell   mfd: twl4030: sim...
636
637
  		if (IS_ERR(child))
  			return PTR_ERR(child);
a603a7fa8   David Brownell   mfd: TWL4030 core...
638
639
640
  	}
  
  	if (twl_has_madc() && pdata->madc) {
5725d66b9   David Brownell   mfd: twl4030: sim...
641
642
  		child = add_child(2, "twl4030_madc",
  				pdata->madc, sizeof(*pdata->madc),
fc7b92fca   Balaji T K   mfd: Rename all t...
643
  				true, pdata->irq_base + MADC_INTR_OFFSET, 0);
5725d66b9   David Brownell   mfd: twl4030: sim...
644
645
  		if (IS_ERR(child))
  			return PTR_ERR(child);
a603a7fa8   David Brownell   mfd: TWL4030 core...
646
647
648
  	}
  
  	if (twl_has_rtc()) {
a603a7fa8   David Brownell   mfd: TWL4030 core...
649
  		/*
5725d66b9   David Brownell   mfd: twl4030: sim...
650
  		 * REVISIT platform_data here currently might expose the
a603a7fa8   David Brownell   mfd: TWL4030 core...
651
  		 * "msecure" line ... but for now we just expect board
5725d66b9   David Brownell   mfd: twl4030: sim...
652
  		 * setup to tell the chip "it's always ok to SET_TIME".
a603a7fa8   David Brownell   mfd: TWL4030 core...
653
654
655
  		 * Eventually, Linux might become more aware of such
  		 * HW security concerns, and "least privilege".
  		 */
e8deb28ca   Balaji T K   mfd: Add support ...
656
657
  		sub_chip_id = twl_map[TWL_MODULE_RTC].sid;
  		child = add_child(sub_chip_id, "twl_rtc",
5725d66b9   David Brownell   mfd: twl4030: sim...
658
  				NULL, 0,
fc7b92fca   Balaji T K   mfd: Rename all t...
659
  				true, pdata->irq_base + RTC_INTR_OFFSET, 0);
5725d66b9   David Brownell   mfd: twl4030: sim...
660
661
  		if (IS_ERR(child))
  			return PTR_ERR(child);
a603a7fa8   David Brownell   mfd: TWL4030 core...
662
  	}
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
663
  	if (twl_has_usb() && pdata->usb && twl_class_is_4030()) {
f8ebdff08   Roger Quadros   mfd: Fix twl4030 ...
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
  
  		static struct regulator_consumer_supply usb1v5 = {
  			.supply =	"usb1v5",
  		};
  		static struct regulator_consumer_supply usb1v8 = {
  			.supply =	"usb1v8",
  		};
  		static struct regulator_consumer_supply usb3v1 = {
  			.supply =	"usb3v1",
  		};
  
  	/* First add the regulators so that they can be used by transceiver */
  		if (twl_has_regulator()) {
  			/* this is a template that gets copied */
  			struct regulator_init_data usb_fixed = {
  				.constraints.valid_modes_mask =
  					REGULATOR_MODE_NORMAL
  					| REGULATOR_MODE_STANDBY,
  				.constraints.valid_ops_mask =
  					REGULATOR_CHANGE_MODE
  					| REGULATOR_CHANGE_STATUS,
  			};
  
  			child = add_regulator_linked(TWL4030_REG_VUSB1V5,
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
688
689
  						      &usb_fixed, &usb1v5, 1,
  						      features);
f8ebdff08   Roger Quadros   mfd: Fix twl4030 ...
690
691
692
693
  			if (IS_ERR(child))
  				return PTR_ERR(child);
  
  			child = add_regulator_linked(TWL4030_REG_VUSB1V8,
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
694
695
  						      &usb_fixed, &usb1v8, 1,
  						      features);
f8ebdff08   Roger Quadros   mfd: Fix twl4030 ...
696
697
698
699
  			if (IS_ERR(child))
  				return PTR_ERR(child);
  
  			child = add_regulator_linked(TWL4030_REG_VUSB3V1,
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
700
701
  						      &usb_fixed, &usb3v1, 1,
  						      features);
f8ebdff08   Roger Quadros   mfd: Fix twl4030 ...
702
703
704
705
  			if (IS_ERR(child))
  				return PTR_ERR(child);
  
  		}
5725d66b9   David Brownell   mfd: twl4030: sim...
706
707
708
709
  		child = add_child(0, "twl4030_usb",
  				pdata->usb, sizeof(*pdata->usb),
  				true,
  				/* irq0 = USB_PRES, irq1 = USB */
fc7b92fca   Balaji T K   mfd: Rename all t...
710
711
  				pdata->irq_base + USB_PRES_INTR_OFFSET,
  				pdata->irq_base + USB_INTR_OFFSET);
f8ebdff08   Roger Quadros   mfd: Fix twl4030 ...
712

5725d66b9   David Brownell   mfd: twl4030: sim...
713
714
  		if (IS_ERR(child))
  			return PTR_ERR(child);
dad759ff8   David Brownell   mfd: twl4030: cre...
715
716
  
  		/* we need to connect regulators to this transceiver */
f8ebdff08   Roger Quadros   mfd: Fix twl4030 ...
717
718
719
720
721
  		if (twl_has_regulator() && child) {
  			usb1v5.dev = child;
  			usb1v8.dev = child;
  			usb3v1.dev = child;
  		}
dad759ff8   David Brownell   mfd: twl4030: cre...
722
  	}
e70357e35   Hema HK   mfd: TWL6030: OMA...
723
  	if (twl_has_usb() && pdata->usb && twl_class_is_6030()) {
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
724
725
  		static struct regulator_consumer_supply usb3v3;
  		int regulator;
e70357e35   Hema HK   mfd: TWL6030: OMA...
726
727
728
729
730
731
732
733
734
735
736
  
  		if (twl_has_regulator()) {
  			/* this is a template that gets copied */
  			struct regulator_init_data usb_fixed = {
  				.constraints.valid_modes_mask =
  					REGULATOR_MODE_NORMAL
  					| REGULATOR_MODE_STANDBY,
  				.constraints.valid_ops_mask =
  					REGULATOR_CHANGE_MODE
  					| REGULATOR_CHANGE_STATUS,
  			};
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
737
738
739
740
741
742
743
744
745
746
  			if (features & TWL6025_SUBCLASS) {
  				usb3v3.supply =	"ldousb";
  				regulator = TWL6025_REG_LDOUSB;
  			} else {
  				usb3v3.supply = "vusb";
  				regulator = TWL6030_REG_VUSB;
  			}
  			child = add_regulator_linked(regulator, &usb_fixed,
  							&usb3v3, 1,
  							features);
e70357e35   Hema HK   mfd: TWL6030: OMA...
747
748
749
  			if (IS_ERR(child))
  				return PTR_ERR(child);
  		}
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
750
  		pdata->usb->features = features;
e70357e35   Hema HK   mfd: TWL6030: OMA...
751
752
753
754
755
756
757
758
759
760
761
762
  		child = add_child(0, "twl6030_usb",
  			pdata->usb, sizeof(*pdata->usb),
  			true,
  			/* irq1 = VBUS_PRES, irq0 = USB ID */
  			pdata->irq_base + USBOTG_INTR_OFFSET,
  			pdata->irq_base + USB_PRES_INTR_OFFSET);
  
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  		/* we need to connect regulators to this transceiver */
  		if (twl_has_regulator() && child)
  			usb3v3.dev = child;
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
763
764
765
766
767
768
769
  	} else if (twl_has_regulator() && twl_class_is_6030()) {
  		if (features & TWL6025_SUBCLASS)
  			child = add_regulator(TWL6025_REG_LDOUSB,
  						pdata->ldousb, features);
  		else
  			child = add_regulator(TWL6030_REG_VUSB,
  						pdata->vusb, features);
e70357e35   Hema HK   mfd: TWL6030: OMA...
770

521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
771
772
  			if (IS_ERR(child))
  					return PTR_ERR(child);
e70357e35   Hema HK   mfd: TWL6030: OMA...
773
  	}
dad759ff8   David Brownell   mfd: twl4030: cre...
774

153617fdd   Keerthy   mfd: Enabling twl...
775
  	if (twl_has_watchdog() && twl_class_is_4030()) {
80e45b1e9   Timo Kokkonen   [WATCHDOG] twl403...
776
777
  		child = add_child(0, "twl4030_wdt", NULL, 0, false, 0, 0);
  		if (IS_ERR(child))
9c3664ddc   Felipe Balbi   mfd: Add twl4030-...
778
779
  			return PTR_ERR(child);
  	}
153617fdd   Keerthy   mfd: Enabling twl...
780
  	if (twl_has_pwrbutton() && twl_class_is_4030()) {
9c3664ddc   Felipe Balbi   mfd: Add twl4030-...
781
782
783
  		child = add_child(1, "twl4030_pwrbutton",
  				NULL, 0, true, pdata->irq_base + 8 + 0, 0);
  		if (IS_ERR(child))
80e45b1e9   Timo Kokkonen   [WATCHDOG] twl403...
784
785
  			return PTR_ERR(child);
  	}
4ae6df5e1   Peter Ujfalusi   MFD: twl4030-audi...
786
  	if (twl_has_codec() && pdata->audio && twl_class_is_4030()) {
d62abe563   Misael Lopez Cruz   OMAP4: PMIC: Add ...
787
  		sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
f0fba2ad1   Liam Girdwood   ASoC: multi-compo...
788
  		child = add_child(sub_chip_id, "twl4030-audio",
4ae6df5e1   Peter Ujfalusi   MFD: twl4030-audi...
789
  				pdata->audio, sizeof(*pdata->audio),
d62abe563   Misael Lopez Cruz   OMAP4: PMIC: Add ...
790
791
792
793
  				false, 0, 0);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  	}
4ae6df5e1   Peter Ujfalusi   MFD: twl4030-audi...
794
  	if (twl_has_codec() && pdata->audio && twl_class_is_6030()) {
d62abe563   Misael Lopez Cruz   OMAP4: PMIC: Add ...
795
  		sub_chip_id = twl_map[TWL_MODULE_AUDIO_VOICE].sid;
f19b2823f   Misael Lopez Cruz   mfd: twl6040: Add...
796
  		child = add_child(sub_chip_id, "twl6040",
4ae6df5e1   Peter Ujfalusi   MFD: twl4030-audi...
797
  				pdata->audio, sizeof(*pdata->audio),
0b83ddebc   Peter Ujfalusi   MFD: twl4030: add...
798
799
800
801
  				false, 0, 0);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  	}
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
802
803
  	/* twl4030 regulators */
  	if (twl_has_regulator() && twl_class_is_4030()) {
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
804
805
  		child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
806
807
  		if (IS_ERR(child))
  			return PTR_ERR(child);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
808

521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
809
810
  		child = add_regulator(TWL4030_REG_VIO, pdata->vio,
  					features);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
811
812
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
813
814
  		child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1,
  					features);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
815
816
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
817
818
  		child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2,
  					features);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
819
820
  		if (IS_ERR(child))
  			return PTR_ERR(child);
dad759ff8   David Brownell   mfd: twl4030: cre...
821

521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
822
823
  		child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
824
825
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
826
827
  		child = add_regulator(TWL4030_REG_VDAC, pdata->vdac,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
828
829
830
831
832
833
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  
  		child = add_regulator((features & TWL4030_VAUX2)
  					? TWL4030_REG_VAUX2_4030
  					: TWL4030_REG_VAUX2,
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
834
  				pdata->vaux2, features);
dad759ff8   David Brownell   mfd: twl4030: cre...
835
836
  		if (IS_ERR(child))
  			return PTR_ERR(child);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
837

521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
838
839
  		child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1,
  					features);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
840
841
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
842
843
  		child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2,
  					features);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
844
845
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
846
847
  		child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig,
  					features);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
848
849
  		if (IS_ERR(child))
  			return PTR_ERR(child);
dad759ff8   David Brownell   mfd: twl4030: cre...
850
  	}
dad759ff8   David Brownell   mfd: twl4030: cre...
851
  	/* maybe add LDOs that are omitted on cost-reduced parts */
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
852
853
  	if (twl_has_regulator() && !(features & TPS_SUBSET)
  	  && twl_class_is_4030()) {
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
854
855
  		child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
856
857
  		if (IS_ERR(child))
  			return PTR_ERR(child);
dad759ff8   David Brownell   mfd: twl4030: cre...
858

521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
859
860
  		child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
861
862
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
863
864
  		child = add_regulator(TWL4030_REG_VSIM, pdata->vsim,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
865
866
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
867
868
  		child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
869
870
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
871
872
  		child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
873
874
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
875
876
  		child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
877
878
  		if (IS_ERR(child))
  			return PTR_ERR(child);
a603a7fa8   David Brownell   mfd: TWL4030 core...
879
  	}
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
880
  	/* twl6030 regulators */
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
  	if (twl_has_regulator() && twl_class_is_6030() &&
  			!(features & TWL6025_SUBCLASS)) {
  		child = add_regulator(TWL6030_REG_VMMC, pdata->vmmc,
  					features);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  
  		child = add_regulator(TWL6030_REG_VPP, pdata->vpp,
  					features);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  
  		child = add_regulator(TWL6030_REG_VUSIM, pdata->vusim,
  					features);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  
  		child = add_regulator(TWL6030_REG_VCXIO, pdata->vcxio,
  					features);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  
  		child = add_regulator(TWL6030_REG_VDAC, pdata->vdac,
  					features);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  
  		child = add_regulator(TWL6030_REG_VAUX1_6030, pdata->vaux1,
  					features);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  
  		child = add_regulator(TWL6030_REG_VAUX2_6030, pdata->vaux2,
  					features);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  
  		child = add_regulator(TWL6030_REG_VAUX3_6030, pdata->vaux3,
  					features);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  
  		child = add_regulator(TWL6030_REG_CLK32KG, pdata->clk32kg,
  					features);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  	}
  
  	/* 6030 and 6025 share this regulator */
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
930
  	if (twl_has_regulator() && twl_class_is_6030()) {
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
931
932
933
934
935
936
937
938
939
940
941
  		child = add_regulator(TWL6030_REG_VANA, pdata->vana,
  					features);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  	}
  
  	/* twl6025 regulators */
  	if (twl_has_regulator() && twl_class_is_6030() &&
  			(features & TWL6025_SUBCLASS)) {
  		child = add_regulator(TWL6025_REG_LDO5, pdata->ldo5,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
942
943
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
944
945
  		child = add_regulator(TWL6025_REG_LDO1, pdata->ldo1,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
946
947
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
948
949
  		child = add_regulator(TWL6025_REG_LDO7, pdata->ldo7,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
950
951
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
952
953
  		child = add_regulator(TWL6025_REG_LDO6, pdata->ldo6,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
954
955
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
956
957
  		child = add_regulator(TWL6025_REG_LDOLN, pdata->ldoln,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
958
959
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
960
961
  		child = add_regulator(TWL6025_REG_LDO2, pdata->ldo2,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
962
963
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
964
965
  		child = add_regulator(TWL6025_REG_LDO4, pdata->ldo4,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
966
967
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
968
969
  		child = add_regulator(TWL6025_REG_LDO3, pdata->ldo3,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
970
971
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
972
973
  		child = add_regulator(TWL6025_REG_SMPS3, pdata->smps3,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
974
975
  		if (IS_ERR(child))
  			return PTR_ERR(child);
8e6de4a30   Balaji T K   regulator: twl: a...
976

521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
977
978
  		child = add_regulator(TWL6025_REG_SMPS4, pdata->smps4,
  					features);
8e6de4a30   Balaji T K   regulator: twl: a...
979
980
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
981
982
983
984
985
  
  		child = add_regulator(TWL6025_REG_VIO, pdata->vio6025,
  					features);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
986
  	}
11c39c4bd   Grazvydas Ignotas   mfd: Add twl4030_...
987
988
989
990
991
992
993
994
995
996
  	if (twl_has_bci() && pdata->bci &&
  			!(features & (TPS_SUBSET | TWL5031))) {
  		child = add_child(3, "twl4030_bci",
  				pdata->bci, sizeof(*pdata->bci), false,
  				/* irq0 = CHG_PRES, irq1 = BCI */
  				pdata->irq_base + BCI_PRES_INTR_OFFSET,
  				pdata->irq_base + BCI_INTR_OFFSET);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  	}
5725d66b9   David Brownell   mfd: twl4030: sim...
997
  	return 0;
a603a7fa8   David Brownell   mfd: TWL4030 core...
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
  }
  
  /*----------------------------------------------------------------------*/
  
  /*
   * These three functions initialize the on-chip clock framework,
   * letting it generate the right frequencies for USB, MADC, and
   * other purposes.
   */
  static inline int __init protect_pm_master(void)
  {
  	int e = 0;
49e6f87eb   Felipe Balbi   mfd: Switch twl-c...
1010
1011
  	e = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0,
  			TWL4030_PM_MASTER_PROTECT_KEY);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1012
1013
1014
1015
1016
1017
  	return e;
  }
  
  static inline int __init unprotect_pm_master(void)
  {
  	int e = 0;
49e6f87eb   Felipe Balbi   mfd: Switch twl-c...
1018
1019
1020
1021
1022
1023
  	e |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
  			TWL4030_PM_MASTER_KEY_CFG1,
  			TWL4030_PM_MASTER_PROTECT_KEY);
  	e |= twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
  			TWL4030_PM_MASTER_KEY_CFG2,
  			TWL4030_PM_MASTER_PROTECT_KEY);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1024
1025
  	return e;
  }
38a684963   Ilkka Koskinen   mfd: Enable twl40...
1026
1027
  static void clocks_init(struct device *dev,
  			struct twl4030_clock_init_data *clock)
a603a7fa8   David Brownell   mfd: TWL4030 core...
1028
1029
1030
1031
1032
1033
1034
1035
  {
  	int e = 0;
  	struct clk *osc;
  	u32 rate;
  	u8 ctrl = HFCLK_FREQ_26_MHZ;
  
  #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
  	if (cpu_is_omap2430())
e6b50c8d5   Russell King   TWL4030: fix clk ...
1036
  		osc = clk_get(dev, "osc_ck");
a603a7fa8   David Brownell   mfd: TWL4030 core...
1037
  	else
e6b50c8d5   Russell King   TWL4030: fix clk ...
1038
  		osc = clk_get(dev, "osc_sys_ck");
6354ab5c6   Samuel Ortiz   mfd: Fix twl4030-...
1039

a603a7fa8   David Brownell   mfd: TWL4030 core...
1040
  	if (IS_ERR(osc)) {
fc7b92fca   Balaji T K   mfd: Rename all t...
1041
  		printk(KERN_WARNING "Skipping twl internal clock init and "
a603a7fa8   David Brownell   mfd: TWL4030 core...
1042
1043
1044
1045
1046
1047
1048
  				"using bootloader value (unknown osc rate)
  ");
  		return;
  	}
  
  	rate = clk_get_rate(osc);
  	clk_put(osc);
6354ab5c6   Samuel Ortiz   mfd: Fix twl4030-...
1049
1050
1051
1052
1053
  #else
  	/* REVISIT for non-OMAP systems, pass the clock rate from
  	 * board init code, using platform_data.
  	 */
  	osc = ERR_PTR(-EIO);
fc7b92fca   Balaji T K   mfd: Rename all t...
1054
  	printk(KERN_WARNING "Skipping twl internal clock init and "
6354ab5c6   Samuel Ortiz   mfd: Fix twl4030-...
1055
1056
1057
1058
1059
  	       "using bootloader value (unknown osc rate)
  ");
  
  	return;
  #endif
a603a7fa8   David Brownell   mfd: TWL4030 core...
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
  	switch (rate) {
  	case 19200000:
  		ctrl = HFCLK_FREQ_19p2_MHZ;
  		break;
  	case 26000000:
  		ctrl = HFCLK_FREQ_26_MHZ;
  		break;
  	case 38400000:
  		ctrl = HFCLK_FREQ_38p4_MHZ;
  		break;
  	}
  
  	ctrl |= HIGH_PERF_SQ;
38a684963   Ilkka Koskinen   mfd: Enable twl40...
1073
1074
  	if (clock && clock->ck32k_lowpwr_enable)
  		ctrl |= CK32K_LOWPWR_EN;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1075
1076
  	e |= unprotect_pm_master();
  	/* effect->MADC+USB ck en */
fc7b92fca   Balaji T K   mfd: Rename all t...
1077
  	e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, ctrl, R_CFG_BOOT);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1078
1079
1080
1081
1082
1083
1084
1085
  	e |= protect_pm_master();
  
  	if (e < 0)
  		pr_err("%s: clock init err [%d]
  ", DRIVER_NAME, e);
  }
  
  /*----------------------------------------------------------------------*/
e8deb28ca   Balaji T K   mfd: Add support ...
1086
1087
1088
1089
1090
  int twl4030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
  int twl4030_exit_irq(void);
  int twl4030_init_chip_irq(const char *chip);
  int twl6030_init_irq(int irq_num, unsigned irq_base, unsigned irq_end);
  int twl6030_exit_irq(void);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1091

fc7b92fca   Balaji T K   mfd: Rename all t...
1092
  static int twl_remove(struct i2c_client *client)
a603a7fa8   David Brownell   mfd: TWL4030 core...
1093
1094
  {
  	unsigned i;
a30d46c04   David Brownell   mfd: twl4030 IRQ ...
1095
  	int status;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1096

e8deb28ca   Balaji T K   mfd: Add support ...
1097
1098
1099
1100
  	if (twl_class_is_4030())
  		status = twl4030_exit_irq();
  	else
  		status = twl6030_exit_irq();
a30d46c04   David Brownell   mfd: twl4030 IRQ ...
1101
1102
  	if (status < 0)
  		return status;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1103

fc7b92fca   Balaji T K   mfd: Rename all t...
1104
1105
  	for (i = 0; i < TWL_NUM_SLAVES; i++) {
  		struct twl_client	*twl = &twl_modules[i];
a603a7fa8   David Brownell   mfd: TWL4030 core...
1106
1107
1108
  
  		if (twl->client && twl->client != client)
  			i2c_unregister_device(twl->client);
fc7b92fca   Balaji T K   mfd: Rename all t...
1109
  		twl_modules[i].client = NULL;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1110
1111
1112
1113
1114
1115
  	}
  	inuse = false;
  	return 0;
  }
  
  /* NOTE:  this driver only handles a single twl4030/tps659x0 chip */
5b9cecd68   Bryan Wu   mfd: Fix twl_prob...
1116
  static int __devinit
fc7b92fca   Balaji T K   mfd: Rename all t...
1117
  twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
a603a7fa8   David Brownell   mfd: TWL4030 core...
1118
1119
1120
1121
  {
  	int				status;
  	unsigned			i;
  	struct twl4030_platform_data	*pdata = client->dev.platform_data;
a29aaf55c   Moiz Sonasath   mfd: Disable TWL4...
1122
  	u8 temp;
ca972d133   Lesly A M   mfd: TWL5030 vers...
1123
  	int ret = 0;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
  
  	if (!pdata) {
  		dev_dbg(&client->dev, "no platform data?
  ");
  		return -EINVAL;
  	}
  
  	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
  		dev_dbg(&client->dev, "can't talk I2C?
  ");
  		return -EIO;
  	}
a30d46c04   David Brownell   mfd: twl4030 IRQ ...
1136
  	if (inuse) {
a603a7fa8   David Brownell   mfd: TWL4030 core...
1137
1138
1139
1140
  		dev_dbg(&client->dev, "driver is already in use
  ");
  		return -EBUSY;
  	}
fc7b92fca   Balaji T K   mfd: Rename all t...
1141
1142
  	for (i = 0; i < TWL_NUM_SLAVES; i++) {
  		struct twl_client	*twl = &twl_modules[i];
a603a7fa8   David Brownell   mfd: TWL4030 core...
1143
1144
1145
1146
1147
1148
1149
1150
  
  		twl->address = client->addr + i;
  		if (i == 0)
  			twl->client = client;
  		else {
  			twl->client = i2c_new_dummy(client->adapter,
  					twl->address);
  			if (!twl->client) {
a8643430b   Ilkka Koskinen   mfd: Do not deref...
1151
  				dev_err(&client->dev,
a603a7fa8   David Brownell   mfd: TWL4030 core...
1152
1153
1154
1155
1156
  					"can't attach client %d
  ", i);
  				status = -ENOMEM;
  				goto fail;
  			}
a603a7fa8   David Brownell   mfd: TWL4030 core...
1157
1158
1159
1160
  		}
  		mutex_init(&twl->xfer_lock);
  	}
  	inuse = true;
e8deb28ca   Balaji T K   mfd: Add support ...
1161
1162
1163
1164
1165
1166
1167
  	if ((id->driver_data) & TWL6030_CLASS) {
  		twl_id = TWL6030_CLASS_ID;
  		twl_map = &twl6030_map[0];
  	} else {
  		twl_id = TWL4030_CLASS_ID;
  		twl_map = &twl4030_map[0];
  	}
a603a7fa8   David Brownell   mfd: TWL4030 core...
1168
1169
  
  	/* setup clock framework */
38a684963   Ilkka Koskinen   mfd: Enable twl40...
1170
  	clocks_init(&client->dev, pdata->clock);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1171

ca972d133   Lesly A M   mfd: TWL5030 vers...
1172
1173
1174
1175
1176
1177
  	/* read TWL IDCODE Register */
  	if (twl_id == TWL4030_CLASS_ID) {
  		ret = twl_read_idcode_register();
  		WARN(ret < 0, "Error: reading twl_idcode register value
  ");
  	}
ebf0bd366   Amit Kucheria   mfd: Add support ...
1178
1179
1180
  	/* load power event scripts */
  	if (twl_has_power() && pdata->power)
  		twl4030_power_init(pdata->power);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1181
1182
1183
1184
  	/* Maybe init the T2 Interrupt subsystem */
  	if (client->irq
  			&& pdata->irq_base
  			&& pdata->irq_end > pdata->irq_base) {
e8deb28ca   Balaji T K   mfd: Add support ...
1185
1186
1187
1188
1189
1190
1191
1192
  		if (twl_class_is_4030()) {
  			twl4030_init_chip_irq(id->name);
  			status = twl4030_init_irq(client->irq, pdata->irq_base,
  			pdata->irq_end);
  		} else {
  			status = twl6030_init_irq(client->irq, pdata->irq_base,
  			pdata->irq_end);
  		}
a30d46c04   David Brownell   mfd: twl4030 IRQ ...
1193
1194
  		if (status < 0)
  			goto fail;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1195
  	}
a29aaf55c   Moiz Sonasath   mfd: Disable TWL4...
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
  	/* Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
  	 * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
  	 * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
  	 */
  
  	if (twl_class_is_4030()) {
  		twl_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1);
  		temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
  		I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
  		twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
  	}
dad759ff8   David Brownell   mfd: twl4030: cre...
1207
  	status = add_children(pdata, id->driver_data);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1208
1209
  fail:
  	if (status < 0)
fc7b92fca   Balaji T K   mfd: Rename all t...
1210
  		twl_remove(client);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1211
1212
  	return status;
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
1213
  static const struct i2c_device_id twl_ids[] = {
dad759ff8   David Brownell   mfd: twl4030: cre...
1214
1215
  	{ "twl4030", TWL4030_VAUX2 },	/* "Triton 2" */
  	{ "twl5030", 0 },		/* T2 updated */
1920a61e2   Ilkka Koskinen   mfd: Initial supp...
1216
  	{ "twl5031", TWL5031 },		/* TWL5030 updated */
dad759ff8   David Brownell   mfd: twl4030: cre...
1217
1218
1219
  	{ "tps65950", 0 },		/* catalog version of twl5030 */
  	{ "tps65930", TPS_SUBSET },	/* fewer LDOs and DACs; no charger */
  	{ "tps65920", TPS_SUBSET },	/* fewer LDOs; no codec or charger */
59dead5a0   Oleg Drokin   mfd: Add tps65921...
1220
1221
  	{ "tps65921", TPS_SUBSET },	/* fewer LDOs; no codec, no LED
  					   and vibrator. Charger in USB module*/
e8deb28ca   Balaji T K   mfd: Add support ...
1222
  	{ "twl6030", TWL6030_CLASS },	/* "Phoenix power chip" */
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
1223
  	{ "twl6025", TWL6030_CLASS | TWL6025_SUBCLASS }, /* "Phoenix lite" */
a603a7fa8   David Brownell   mfd: TWL4030 core...
1224
1225
  	{ /* end of list */ },
  };
fc7b92fca   Balaji T K   mfd: Rename all t...
1226
  MODULE_DEVICE_TABLE(i2c, twl_ids);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1227
1228
  
  /* One Client Driver , 4 Clients */
fc7b92fca   Balaji T K   mfd: Rename all t...
1229
  static struct i2c_driver twl_driver = {
a603a7fa8   David Brownell   mfd: TWL4030 core...
1230
  	.driver.name	= DRIVER_NAME,
fc7b92fca   Balaji T K   mfd: Rename all t...
1231
1232
1233
  	.id_table	= twl_ids,
  	.probe		= twl_probe,
  	.remove		= twl_remove,
a603a7fa8   David Brownell   mfd: TWL4030 core...
1234
  };
fc7b92fca   Balaji T K   mfd: Rename all t...
1235
  static int __init twl_init(void)
a603a7fa8   David Brownell   mfd: TWL4030 core...
1236
  {
fc7b92fca   Balaji T K   mfd: Rename all t...
1237
  	return i2c_add_driver(&twl_driver);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1238
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
1239
  subsys_initcall(twl_init);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1240

fc7b92fca   Balaji T K   mfd: Rename all t...
1241
  static void __exit twl_exit(void)
a603a7fa8   David Brownell   mfd: TWL4030 core...
1242
  {
fc7b92fca   Balaji T K   mfd: Rename all t...
1243
  	i2c_del_driver(&twl_driver);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1244
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
1245
  module_exit(twl_exit);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1246
1247
  
  MODULE_AUTHOR("Texas Instruments, Inc.");
fc7b92fca   Balaji T K   mfd: Rename all t...
1248
  MODULE_DESCRIPTION("I2C Core interface for TWL");
a603a7fa8   David Brownell   mfd: TWL4030 core...
1249
  MODULE_LICENSE("GPL");