Blame view

drivers/mfd/twl-core.c 35.1 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>
4e36dd331   Paul Gortmaker   mfd: Add module.h...
32
  #include <linux/module.h>
a603a7fa8   David Brownell   mfd: TWL4030 core...
33
34
  #include <linux/platform_device.h>
  #include <linux/clk.h>
a30d46c04   David Brownell   mfd: twl4030 IRQ ...
35
  #include <linux/err.h>
aeb5032b3   Benoit Cousson   mfd: twl-core: Ad...
36
37
38
39
40
  #include <linux/device.h>
  #include <linux/of.h>
  #include <linux/of_irq.h>
  #include <linux/of_platform.h>
  #include <linux/irqdomain.h>
a603a7fa8   David Brownell   mfd: TWL4030 core...
41

dad759ff8   David Brownell   mfd: twl4030: cre...
42
  #include <linux/regulator/machine.h>
a603a7fa8   David Brownell   mfd: TWL4030 core...
43
  #include <linux/i2c.h>
b07682b60   Santosh Shilimkar   mfd: Rename twl40...
44
  #include <linux/i2c/twl.h>
a603a7fa8   David Brownell   mfd: TWL4030 core...
45

a313d758c   Mark Brown   mfd: Fix TWL4030 ...
46
  #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
ce491cf85   Tony Lindgren   omap: headers: Mo...
47
  #include <plat/cpu.h>
b29c06ae9   Samuel Ortiz   mfd: Fix twl4030-...
48
  #endif
a603a7fa8   David Brownell   mfd: TWL4030 core...
49
50
51
52
53
54
55
56
57
58
59
60
61
  
  /*
   * 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...
62
  #define DRIVER_NAME			"twl"
a603a7fa8   David Brownell   mfd: TWL4030 core...
63

a603a7fa8   David Brownell   mfd: TWL4030 core...
64
65
66
67
68
69
70
71
72
73
74
  #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...
75
76
77
78
79
80
  #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...
81
82
83
84
85
  #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 ...
86
87
88
89
90
  #ifdef CONFIG_TWL4030_POWER
  #define twl_has_power()        true
  #else
  #define twl_has_power()        false
  #endif
a603a7fa8   David Brownell   mfd: TWL4030 core...
91
92
93
94
95
  #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...
96
97
  #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...
98
99
100
101
  #define twl_has_usb()	true
  #else
  #define twl_has_usb()	false
  #endif
80e45b1e9   Timo Kokkonen   [WATCHDOG] twl403...
102
103
104
105
106
107
  #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...
108

f09ee0451   Thomas Weber   mfd: Fix twl4030 ...
109
  #if defined(CONFIG_MFD_TWL4030_AUDIO) || defined(CONFIG_MFD_TWL4030_AUDIO_MODULE) ||\
f19b2823f   Misael Lopez Cruz   mfd: twl6040: Add...
110
  	defined(CONFIG_TWL6040_CORE) || defined(CONFIG_TWL6040_CORE_MODULE)
0b83ddebc   Peter Ujfalusi   MFD: twl4030: add...
111
112
113
114
  #define twl_has_codec()	true
  #else
  #define twl_has_codec()	false
  #endif
11c39c4bd   Grazvydas Ignotas   mfd: Add twl4030_...
115
116
117
118
119
  #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...
120
121
122
123
  /* 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...
124
  #define TWL_NUM_SLAVES		4
a603a7fa8   David Brownell   mfd: TWL4030 core...
125

9c3664ddc   Felipe Balbi   mfd: Add twl4030-...
126
  #if defined(CONFIG_INPUT_TWL4030_PWRBUTTON) \
14e5c82ca   Eduardo Valentin   mfd: Fix twl_has_...
127
  	|| defined(CONFIG_INPUT_TWL4030_PWRBUTTON_MODULE)
9c3664ddc   Felipe Balbi   mfd: Add twl4030-...
128
129
130
131
  #define twl_has_pwrbutton()	true
  #else
  #define twl_has_pwrbutton()	false
  #endif
a603a7fa8   David Brownell   mfd: TWL4030 core...
132

fc7b92fca   Balaji T K   mfd: Rename all t...
133
134
135
136
137
138
  #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
aeb5032b3   Benoit Cousson   mfd: twl-core: Ad...
139
140
  #define TWL4030_NR_IRQS    8
  #define TWL6030_NR_IRQS    20
a603a7fa8   David Brownell   mfd: TWL4030 core...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
  /* 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...
164
165
166
  #define TWL5031_BASEADD_ACCESSORY	0x0074 /* Replaces Main Charge */
  #define TWL5031_BASEADD_INTERRUPTS	0x00B9 /* Different than TWL4030's
  						  one */
a603a7fa8   David Brownell   mfd: TWL4030 core...
167
168
169
170
171
172
173
174
175
  /* 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 ...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
  /* 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 ...
192
  #define TWL6025_BASEADD_CHARGER		0x00DA
e8deb28ca   Balaji T K   mfd: Add support ...
193
194
195
196
197
198
199
  
  /* 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 ...
200
  #define TWL6030_BASEADD_ZERO		0x0000
e8deb28ca   Balaji T K   mfd: Add support ...
201

a603a7fa8   David Brownell   mfd: TWL4030 core...
202
203
  /* Few power values */
  #define R_CFG_BOOT			0x05
a603a7fa8   David Brownell   mfd: TWL4030 core...
204
205
206
207
208
209
  
  /* 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...
210
  #define CK32K_LOWPWR_EN			(1 << 7)
a603a7fa8   David Brownell   mfd: TWL4030 core...
211

dad759ff8   David Brownell   mfd: twl4030: cre...
212
213
214
  /* 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...
215
  #define TWL5031			BIT(2)  /* twl5031 has different registers */
e8deb28ca   Balaji T K   mfd: Add support ...
216
  #define TWL6030_CLASS		BIT(3)	/* TWL6030 class */
dad759ff8   David Brownell   mfd: twl4030: cre...
217

a603a7fa8   David Brownell   mfd: TWL4030 core...
218
  /*----------------------------------------------------------------------*/
a603a7fa8   David Brownell   mfd: TWL4030 core...
219
220
  /* is driver active, bound to a chip? */
  static bool inuse;
ca972d133   Lesly A M   mfd: TWL5030 vers...
221
222
  /* TWL IDCODE Register value */
  static u32 twl_idcode;
e8deb28ca   Balaji T K   mfd: Add support ...
223
224
225
226
227
228
229
230
  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...
231
  struct twl_client {
a603a7fa8   David Brownell   mfd: TWL4030 core...
232
233
234
235
236
237
238
239
240
  	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...
241
  static struct twl_client twl_modules[TWL_NUM_SLAVES];
a603a7fa8   David Brownell   mfd: TWL4030 core...
242

aeb5032b3   Benoit Cousson   mfd: twl-core: Ad...
243
  static struct irq_domain domain;
a603a7fa8   David Brownell   mfd: TWL4030 core...
244
245
  
  /* mapping the module id to slave id and base address */
fc7b92fca   Balaji T K   mfd: Rename all t...
246
  struct twl_mapping {
a603a7fa8   David Brownell   mfd: TWL4030 core...
247
248
249
  	unsigned char sid;	/* Slave ID */
  	unsigned char base;	/* base address */
  };
2cfcce18b   G, Manjunath Kondaiah   mfd: Fix twl-core...
250
  static struct twl_mapping *twl_map;
a603a7fa8   David Brownell   mfd: TWL4030 core...
251

fc7b92fca   Balaji T K   mfd: Rename all t...
252
  static struct twl_mapping twl4030_map[TWL4030_MODULE_LAST + 1] = {
a603a7fa8   David Brownell   mfd: TWL4030 core...
253
254
  	/*
  	 * NOTE:  don't change this table without updating the
e8deb28ca   Balaji T K   mfd: Add support ...
255
  	 * <linux/i2c/twl.h> defines for TWL4030_MODULE_*
a603a7fa8   David Brownell   mfd: TWL4030 core...
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  	 * 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...
277
278
  	{ 2, TWL5031_BASEADD_ACCESSORY },
  	{ 2, TWL5031_BASEADD_INTERRUPTS },
a603a7fa8   David Brownell   mfd: TWL4030 core...
279
280
281
282
283
284
285
286
  
  	{ 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 ...
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
  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 ...
308
309
  	{ SUB_CHIP_ID0, TWL6030_BASEADD_ZERO },
  	{ SUB_CHIP_ID1, TWL6030_BASEADD_ZERO },
e8deb28ca   Balaji T K   mfd: Add support ...
310

fa0d97629   Balaji T K   mfd: Add twl6030 ...
311
312
  	{ SUB_CHIP_ID2, TWL6030_BASEADD_ZERO },
  	{ SUB_CHIP_ID2, TWL6030_BASEADD_ZERO },
e8deb28ca   Balaji T K   mfd: Add support ...
313
314
315
316
317
318
319
320
  	{ 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 ...
321
  	{ SUB_CHIP_ID1, TWL6025_BASEADD_CHARGER },
e8deb28ca   Balaji T K   mfd: Add support ...
322
  };
a603a7fa8   David Brownell   mfd: TWL4030 core...
323
  /*----------------------------------------------------------------------*/
a603a7fa8   David Brownell   mfd: TWL4030 core...
324
325
326
  /* Exported Functions */
  
  /**
fc7b92fca   Balaji T K   mfd: Rename all t...
327
   * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
a603a7fa8   David Brownell   mfd: TWL4030 core...
328
329
330
331
332
333
334
335
336
337
   * @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...
338
  int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
a603a7fa8   David Brownell   mfd: TWL4030 core...
339
340
341
  {
  	int ret;
  	int sid;
fc7b92fca   Balaji T K   mfd: Rename all t...
342
  	struct twl_client *twl;
a603a7fa8   David Brownell   mfd: TWL4030 core...
343
  	struct i2c_msg *msg;
fc7b92fca   Balaji T K   mfd: Rename all t...
344
  	if (unlikely(mod_no > TWL_MODULE_LAST)) {
a603a7fa8   David Brownell   mfd: TWL4030 core...
345
346
347
348
  		pr_err("%s: invalid module number %d
  ", DRIVER_NAME, mod_no);
  		return -EPERM;
  	}
a603a7fa8   David Brownell   mfd: TWL4030 core...
349
  	if (unlikely(!inuse)) {
8653be1af   Ilya Yanok   mfd: Fix twl-core...
350
351
  		pr_err("%s: not initialized
  ", DRIVER_NAME);
a603a7fa8   David Brownell   mfd: TWL4030 core...
352
353
  		return -EPERM;
  	}
8653be1af   Ilya Yanok   mfd: Fix twl-core...
354
355
  	sid = twl_map[mod_no].sid;
  	twl = &twl_modules[sid];
a603a7fa8   David Brownell   mfd: TWL4030 core...
356
357
358
359
360
361
362
363
364
365
366
  	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 ...
367
  	*value = twl_map[mod_no].base + reg;
a603a7fa8   David Brownell   mfd: TWL4030 core...
368
369
  	ret = i2c_transfer(twl->client->adapter, twl->xfer_msg, 1);
  	mutex_unlock(&twl->xfer_lock);
147e08479   Amit Kucheria   mfd: Clarify twl4...
370
371
372
373
374
375
376
377
378
379
380
381
  	/* 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...
382
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
383
  EXPORT_SYMBOL(twl_i2c_write);
a603a7fa8   David Brownell   mfd: TWL4030 core...
384
385
  
  /**
fc7b92fca   Balaji T K   mfd: Rename all t...
386
   * twl_i2c_read - Reads a n bit register in TWL4030/TWL5030/TWL60X0
a603a7fa8   David Brownell   mfd: TWL4030 core...
387
388
389
390
391
392
393
   * @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...
394
  int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
a603a7fa8   David Brownell   mfd: TWL4030 core...
395
396
397
398
  {
  	int ret;
  	u8 val;
  	int sid;
fc7b92fca   Balaji T K   mfd: Rename all t...
399
  	struct twl_client *twl;
a603a7fa8   David Brownell   mfd: TWL4030 core...
400
  	struct i2c_msg *msg;
fc7b92fca   Balaji T K   mfd: Rename all t...
401
  	if (unlikely(mod_no > TWL_MODULE_LAST)) {
a603a7fa8   David Brownell   mfd: TWL4030 core...
402
403
404
405
  		pr_err("%s: invalid module number %d
  ", DRIVER_NAME, mod_no);
  		return -EPERM;
  	}
a603a7fa8   David Brownell   mfd: TWL4030 core...
406
  	if (unlikely(!inuse)) {
8653be1af   Ilya Yanok   mfd: Fix twl-core...
407
408
  		pr_err("%s: not initialized
  ", DRIVER_NAME);
a603a7fa8   David Brownell   mfd: TWL4030 core...
409
410
  		return -EPERM;
  	}
8653be1af   Ilya Yanok   mfd: Fix twl-core...
411
412
  	sid = twl_map[mod_no].sid;
  	twl = &twl_modules[sid];
a603a7fa8   David Brownell   mfd: TWL4030 core...
413
414
415
416
417
418
  	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 ...
419
  	val = twl_map[mod_no].base + reg;
a603a7fa8   David Brownell   mfd: TWL4030 core...
420
421
422
423
424
425
426
427
428
  	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...
429
430
431
432
433
434
435
436
437
438
439
440
  	/* 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...
441
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
442
  EXPORT_SYMBOL(twl_i2c_read);
a603a7fa8   David Brownell   mfd: TWL4030 core...
443
444
  
  /**
fc7b92fca   Balaji T K   mfd: Rename all t...
445
   * twl_i2c_write_u8 - Writes a 8 bit register in TWL4030/TWL5030/TWL60X0
a603a7fa8   David Brownell   mfd: TWL4030 core...
446
447
448
449
450
451
   * @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...
452
  int twl_i2c_write_u8(u8 mod_no, u8 value, u8 reg)
a603a7fa8   David Brownell   mfd: TWL4030 core...
453
454
455
456
457
458
  {
  
  	/* 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...
459
  	return twl_i2c_write(mod_no, temp_buffer, reg, 1);
a603a7fa8   David Brownell   mfd: TWL4030 core...
460
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
461
  EXPORT_SYMBOL(twl_i2c_write_u8);
a603a7fa8   David Brownell   mfd: TWL4030 core...
462
463
  
  /**
fc7b92fca   Balaji T K   mfd: Rename all t...
464
   * twl_i2c_read_u8 - Reads a 8 bit register from TWL4030/TWL5030/TWL60X0
a603a7fa8   David Brownell   mfd: TWL4030 core...
465
466
467
468
469
470
   * @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...
471
  int twl_i2c_read_u8(u8 mod_no, u8 *value, u8 reg)
a603a7fa8   David Brownell   mfd: TWL4030 core...
472
  {
fc7b92fca   Balaji T K   mfd: Rename all t...
473
  	return twl_i2c_read(mod_no, value, reg, 1);
a603a7fa8   David Brownell   mfd: TWL4030 core...
474
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
475
  EXPORT_SYMBOL(twl_i2c_read_u8);
a603a7fa8   David Brownell   mfd: TWL4030 core...
476
477
  
  /*----------------------------------------------------------------------*/
ca972d133   Lesly A M   mfd: TWL5030 vers...
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
525
526
527
528
529
530
531
  /**
   * 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...
532
533
  static struct device *
  add_numbered_child(unsigned chip, const char *name, int num,
5725d66b9   David Brownell   mfd: twl4030: sim...
534
535
  		void *pdata, unsigned pdata_len,
  		bool can_wakeup, int irq0, int irq1)
a603a7fa8   David Brownell   mfd: TWL4030 core...
536
  {
5725d66b9   David Brownell   mfd: twl4030: sim...
537
  	struct platform_device	*pdev;
fc7b92fca   Balaji T K   mfd: Rename all t...
538
  	struct twl_client	*twl = &twl_modules[chip];
5725d66b9   David Brownell   mfd: twl4030: sim...
539
  	int			status;
dad759ff8   David Brownell   mfd: twl4030: cre...
540
  	pdev = platform_device_alloc(name, num);
5725d66b9   David Brownell   mfd: twl4030: sim...
541
542
543
544
545
546
  	if (!pdev) {
  		dev_dbg(&twl->client->dev, "can't alloc dev
  ");
  		status = -ENOMEM;
  		goto err;
  	}
a603a7fa8   David Brownell   mfd: TWL4030 core...
547

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

5725d66b9   David Brownell   mfd: twl4030: sim...
551
552
553
554
555
  	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...
556
557
  			goto err;
  		}
5725d66b9   David Brownell   mfd: twl4030: sim...
558
  	}
a603a7fa8   David Brownell   mfd: TWL4030 core...
559

5725d66b9   David Brownell   mfd: twl4030: sim...
560
561
562
563
564
  	if (irq0) {
  		struct resource r[2] = {
  			{ .start = irq0, .flags = IORESOURCE_IRQ, },
  			{ .start = irq1, .flags = IORESOURCE_IRQ, },
  		};
a603a7fa8   David Brownell   mfd: TWL4030 core...
565

5725d66b9   David Brownell   mfd: twl4030: sim...
566
  		status = platform_device_add_resources(pdev, r, irq1 ? 2 : 1);
a603a7fa8   David Brownell   mfd: TWL4030 core...
567
  		if (status < 0) {
5725d66b9   David Brownell   mfd: twl4030: sim...
568
569
  			dev_dbg(&pdev->dev, "can't add irqs
  ");
a603a7fa8   David Brownell   mfd: TWL4030 core...
570
571
572
  			goto err;
  		}
  	}
5725d66b9   David Brownell   mfd: twl4030: sim...
573
  	status = platform_device_add(pdev);
a603a7fa8   David Brownell   mfd: TWL4030 core...
574

5725d66b9   David Brownell   mfd: twl4030: sim...
575
576
577
578
579
580
581
582
583
  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...
584

dad759ff8   David Brownell   mfd: twl4030: cre...
585
586
587
588
589
590
591
592
593
594
595
  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 ...
596
  		unsigned num_consumers, unsigned long features)
dad759ff8   David Brownell   mfd: twl4030: cre...
597
  {
e8deb28ca   Balaji T K   mfd: Add support ...
598
  	unsigned sub_chip_id;
dad759ff8   David Brownell   mfd: twl4030: cre...
599
600
601
  	/* regulator framework demands init_data ... */
  	if (!pdata)
  		return NULL;
b73eac787   David Brownell   mfd: twl4030 regu...
602
  	if (consumers) {
dad759ff8   David Brownell   mfd: twl4030: cre...
603
604
605
  		pdata->consumer_supplies = consumers;
  		pdata->num_consumer_supplies = num_consumers;
  	}
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
606
  	pdata->driver_data = (void *)features;
dad759ff8   David Brownell   mfd: twl4030: cre...
607
  	/* NOTE:  we currently ignore regulator IRQs, e.g. for short circuits */
e8deb28ca   Balaji T K   mfd: Add support ...
608
609
  	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...
610
611
612
613
  		pdata, sizeof(*pdata), false, 0, 0);
  }
  
  static struct device *
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
614
615
  add_regulator(int num, struct regulator_init_data *pdata,
  		unsigned long features)
dad759ff8   David Brownell   mfd: twl4030: cre...
616
  {
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
617
  	return add_regulator_linked(num, pdata, NULL, 0, features);
dad759ff8   David Brownell   mfd: twl4030: cre...
618
  }
5725d66b9   David Brownell   mfd: twl4030: sim...
619
620
621
622
623
  /*
   * 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...
624

dad759ff8   David Brownell   mfd: twl4030: cre...
625
626
  static int
  add_children(struct twl4030_platform_data *pdata, unsigned long features)
5725d66b9   David Brownell   mfd: twl4030: sim...
627
628
  {
  	struct device	*child;
e8deb28ca   Balaji T K   mfd: Add support ...
629
  	unsigned sub_chip_id;
a603a7fa8   David Brownell   mfd: TWL4030 core...
630

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

5725d66b9   David Brownell   mfd: twl4030: sim...
720
721
  		if (IS_ERR(child))
  			return PTR_ERR(child);
dad759ff8   David Brownell   mfd: twl4030: cre...
722
723
  
  		/* we need to connect regulators to this transceiver */
f8ebdff08   Roger Quadros   mfd: Fix twl4030 ...
724
725
726
727
728
  		if (twl_has_regulator() && child) {
  			usb1v5.dev = child;
  			usb1v8.dev = child;
  			usb3v1.dev = child;
  		}
dad759ff8   David Brownell   mfd: twl4030: cre...
729
  	}
e70357e35   Hema HK   mfd: TWL6030: OMA...
730
  	if (twl_has_usb() && pdata->usb && twl_class_is_6030()) {
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
731
732
  		static struct regulator_consumer_supply usb3v3;
  		int regulator;
e70357e35   Hema HK   mfd: TWL6030: OMA...
733
734
735
736
737
738
739
740
741
742
743
  
  		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 ...
744
745
746
747
748
749
750
751
752
753
  			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...
754
755
756
  			if (IS_ERR(child))
  				return PTR_ERR(child);
  		}
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
757
  		pdata->usb->features = features;
e70357e35   Hema HK   mfd: TWL6030: OMA...
758
759
760
761
762
763
764
765
766
767
768
769
  		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 ...
770
771
772
773
774
775
776
  	} 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...
777

521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
778
779
  			if (IS_ERR(child))
  					return PTR_ERR(child);
e70357e35   Hema HK   mfd: TWL6030: OMA...
780
  	}
dad759ff8   David Brownell   mfd: twl4030: cre...
781

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

521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
816
817
  		child = add_regulator(TWL4030_REG_VIO, pdata->vio,
  					features);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
818
819
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
820
821
  		child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1,
  					features);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
822
823
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
824
825
  		child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2,
  					features);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
826
827
  		if (IS_ERR(child))
  			return PTR_ERR(child);
dad759ff8   David Brownell   mfd: twl4030: cre...
828

521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
829
830
  		child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
831
832
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
833
834
  		child = add_regulator(TWL4030_REG_VDAC, pdata->vdac,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
835
836
837
838
839
840
  		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 ...
841
  				pdata->vaux2, features);
dad759ff8   David Brownell   mfd: twl4030: cre...
842
843
  		if (IS_ERR(child))
  			return PTR_ERR(child);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
844

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

521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
866
867
  		child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
868
869
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
870
871
  		child = add_regulator(TWL4030_REG_VSIM, pdata->vsim,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
872
873
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
874
875
  		child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
876
877
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
878
879
  		child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
880
881
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
882
883
  		child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
884
885
  		if (IS_ERR(child))
  			return PTR_ERR(child);
a603a7fa8   David Brownell   mfd: TWL4030 core...
886
  	}
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
887
  	/* twl6030 regulators */
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
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
930
931
932
933
934
935
936
  	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 ...
937
  	if (twl_has_regulator() && twl_class_is_6030()) {
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
938
939
940
941
942
943
944
945
946
947
948
  		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 ...
949
950
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
951
952
  		child = add_regulator(TWL6025_REG_LDO1, pdata->ldo1,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
953
954
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
955
956
  		child = add_regulator(TWL6025_REG_LDO7, pdata->ldo7,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
957
958
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
959
960
  		child = add_regulator(TWL6025_REG_LDO6, pdata->ldo6,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
961
962
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
963
964
  		child = add_regulator(TWL6025_REG_LDOLN, pdata->ldoln,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
965
966
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
967
968
  		child = add_regulator(TWL6025_REG_LDO2, pdata->ldo2,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
969
970
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
971
972
  		child = add_regulator(TWL6025_REG_LDO4, pdata->ldo4,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
973
974
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
975
976
  		child = add_regulator(TWL6025_REG_LDO3, pdata->ldo3,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
977
978
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
979
980
  		child = add_regulator(TWL6025_REG_SMPS3, pdata->smps3,
  					features);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
981
982
  		if (IS_ERR(child))
  			return PTR_ERR(child);
8e6de4a30   Balaji T K   regulator: twl: a...
983

521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
984
985
  		child = add_regulator(TWL6025_REG_SMPS4, pdata->smps4,
  					features);
8e6de4a30   Balaji T K   regulator: twl: a...
986
987
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
988
989
990
991
992
  
  		child = add_regulator(TWL6025_REG_VIO, pdata->vio6025,
  					features);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
993
  	}
11c39c4bd   Grazvydas Ignotas   mfd: Add twl4030_...
994
995
996
997
998
999
1000
1001
1002
1003
  	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...
1004
  	return 0;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
  }
  
  /*----------------------------------------------------------------------*/
  
  /*
   * 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...
1017
1018
  	e = twl_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0,
  			TWL4030_PM_MASTER_PROTECT_KEY);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1019
1020
1021
1022
1023
1024
  	return e;
  }
  
  static inline int __init unprotect_pm_master(void)
  {
  	int e = 0;
49e6f87eb   Felipe Balbi   mfd: Switch twl-c...
1025
1026
1027
1028
1029
1030
  	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...
1031
1032
  	return e;
  }
38a684963   Ilkka Koskinen   mfd: Enable twl40...
1033
1034
  static void clocks_init(struct device *dev,
  			struct twl4030_clock_init_data *clock)
a603a7fa8   David Brownell   mfd: TWL4030 core...
1035
1036
1037
1038
1039
1040
1041
1042
  {
  	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 ...
1043
  		osc = clk_get(dev, "osc_ck");
a603a7fa8   David Brownell   mfd: TWL4030 core...
1044
  	else
e6b50c8d5   Russell King   TWL4030: fix clk ...
1045
  		osc = clk_get(dev, "osc_sys_ck");
6354ab5c6   Samuel Ortiz   mfd: Fix twl4030-...
1046

a603a7fa8   David Brownell   mfd: TWL4030 core...
1047
  	if (IS_ERR(osc)) {
fc7b92fca   Balaji T K   mfd: Rename all t...
1048
  		printk(KERN_WARNING "Skipping twl internal clock init and "
a603a7fa8   David Brownell   mfd: TWL4030 core...
1049
1050
1051
1052
1053
1054
1055
  				"using bootloader value (unknown osc rate)
  ");
  		return;
  	}
  
  	rate = clk_get_rate(osc);
  	clk_put(osc);
6354ab5c6   Samuel Ortiz   mfd: Fix twl4030-...
1056
1057
1058
1059
1060
  #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...
1061
  	printk(KERN_WARNING "Skipping twl internal clock init and "
6354ab5c6   Samuel Ortiz   mfd: Fix twl4030-...
1062
1063
1064
1065
1066
  	       "using bootloader value (unknown osc rate)
  ");
  
  	return;
  #endif
a603a7fa8   David Brownell   mfd: TWL4030 core...
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
  	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...
1080
1081
  	if (clock && clock->ck32k_lowpwr_enable)
  		ctrl |= CK32K_LOWPWR_EN;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1082
1083
  	e |= unprotect_pm_master();
  	/* effect->MADC+USB ck en */
fc7b92fca   Balaji T K   mfd: Rename all t...
1084
  	e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, ctrl, R_CFG_BOOT);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1085
1086
1087
1088
1089
1090
1091
1092
  	e |= protect_pm_master();
  
  	if (e < 0)
  		pr_err("%s: clock init err [%d]
  ", DRIVER_NAME, e);
  }
  
  /*----------------------------------------------------------------------*/
e8deb28ca   Balaji T K   mfd: Add support ...
1093
1094
1095
1096
1097
  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...
1098

fc7b92fca   Balaji T K   mfd: Rename all t...
1099
  static int twl_remove(struct i2c_client *client)
a603a7fa8   David Brownell   mfd: TWL4030 core...
1100
1101
  {
  	unsigned i;
a30d46c04   David Brownell   mfd: twl4030 IRQ ...
1102
  	int status;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1103

e8deb28ca   Balaji T K   mfd: Add support ...
1104
1105
1106
1107
  	if (twl_class_is_4030())
  		status = twl4030_exit_irq();
  	else
  		status = twl6030_exit_irq();
a30d46c04   David Brownell   mfd: twl4030 IRQ ...
1108
1109
  	if (status < 0)
  		return status;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1110

fc7b92fca   Balaji T K   mfd: Rename all t...
1111
1112
  	for (i = 0; i < TWL_NUM_SLAVES; i++) {
  		struct twl_client	*twl = &twl_modules[i];
a603a7fa8   David Brownell   mfd: TWL4030 core...
1113
1114
1115
  
  		if (twl->client && twl->client != client)
  			i2c_unregister_device(twl->client);
fc7b92fca   Balaji T K   mfd: Rename all t...
1116
  		twl_modules[i].client = NULL;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1117
1118
1119
1120
1121
1122
  	}
  	inuse = false;
  	return 0;
  }
  
  /* NOTE:  this driver only handles a single twl4030/tps659x0 chip */
5b9cecd68   Bryan Wu   mfd: Fix twl_prob...
1123
  static int __devinit
fc7b92fca   Balaji T K   mfd: Rename all t...
1124
  twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
a603a7fa8   David Brownell   mfd: TWL4030 core...
1125
1126
1127
1128
  {
  	int				status;
  	unsigned			i;
  	struct twl4030_platform_data	*pdata = client->dev.platform_data;
aeb5032b3   Benoit Cousson   mfd: twl-core: Ad...
1129
  	struct device_node		*node = client->dev.of_node;
a29aaf55c   Moiz Sonasath   mfd: Disable TWL4...
1130
  	u8 temp;
ca972d133   Lesly A M   mfd: TWL5030 vers...
1131
  	int ret = 0;
aeb5032b3   Benoit Cousson   mfd: twl-core: Ad...
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
  	int nr_irqs = TWL4030_NR_IRQS;
  
  	if ((id->driver_data) & TWL6030_CLASS)
  		nr_irqs = TWL6030_NR_IRQS;
  
  	if (node && !pdata) {
  		/*
  		 * XXX: Temporary pdata until the information is correctly
  		 * retrieved by every TWL modules from DT.
  		 */
  		pdata = devm_kzalloc(&client->dev,
  				     sizeof(struct twl4030_platform_data),
  				     GFP_KERNEL);
  		if (!pdata)
  			return -ENOMEM;
  	}
a603a7fa8   David Brownell   mfd: TWL4030 core...
1148
1149
1150
1151
1152
1153
  
  	if (!pdata) {
  		dev_dbg(&client->dev, "no platform data?
  ");
  		return -EINVAL;
  	}
aeb5032b3   Benoit Cousson   mfd: twl-core: Ad...
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
  	status = irq_alloc_descs(-1, pdata->irq_base, nr_irqs, 0);
  	if (IS_ERR_VALUE(status)) {
  		dev_err(&client->dev, "Fail to allocate IRQ descs
  ");
  		return status;
  	}
  
  	pdata->irq_base = status;
  	pdata->irq_end = pdata->irq_base + nr_irqs;
  
  	domain.irq_base = pdata->irq_base;
  	domain.nr_irq = nr_irqs;
  #ifdef CONFIG_OF_IRQ
  	domain.of_node = of_node_get(node);
  	domain.ops = &irq_domain_simple_ops;
  #endif
  	irq_domain_add(&domain);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1171
1172
1173
1174
1175
  	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 ...
1176
  	if (inuse) {
a603a7fa8   David Brownell   mfd: TWL4030 core...
1177
1178
1179
1180
  		dev_dbg(&client->dev, "driver is already in use
  ");
  		return -EBUSY;
  	}
fc7b92fca   Balaji T K   mfd: Rename all t...
1181
1182
  	for (i = 0; i < TWL_NUM_SLAVES; i++) {
  		struct twl_client	*twl = &twl_modules[i];
a603a7fa8   David Brownell   mfd: TWL4030 core...
1183
1184
1185
1186
1187
1188
1189
1190
  
  		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...
1191
  				dev_err(&client->dev,
a603a7fa8   David Brownell   mfd: TWL4030 core...
1192
1193
1194
1195
1196
  					"can't attach client %d
  ", i);
  				status = -ENOMEM;
  				goto fail;
  			}
a603a7fa8   David Brownell   mfd: TWL4030 core...
1197
1198
1199
1200
  		}
  		mutex_init(&twl->xfer_lock);
  	}
  	inuse = true;
e8deb28ca   Balaji T K   mfd: Add support ...
1201
1202
1203
1204
1205
1206
1207
  	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...
1208
1209
  
  	/* setup clock framework */
38a684963   Ilkka Koskinen   mfd: Enable twl40...
1210
  	clocks_init(&client->dev, pdata->clock);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1211

ca972d133   Lesly A M   mfd: TWL5030 vers...
1212
1213
1214
1215
1216
1217
  	/* 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 ...
1218
1219
1220
  	/* load power event scripts */
  	if (twl_has_power() && pdata->power)
  		twl4030_power_init(pdata->power);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1221
1222
1223
1224
  	/* 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 ...
1225
1226
1227
1228
1229
1230
1231
1232
  		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 ...
1233
1234
  		if (status < 0)
  			goto fail;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1235
  	}
a29aaf55c   Moiz Sonasath   mfd: Disable TWL4...
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
  	/* 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);
  	}
aeb5032b3   Benoit Cousson   mfd: twl-core: Ad...
1247
1248
1249
1250
1251
1252
  #ifdef CONFIG_OF_DEVICE
  	if (node)
  		status = of_platform_populate(node, NULL, NULL, &client->dev);
  	else
  #endif
  		status = add_children(pdata, id->driver_data);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1253
1254
  fail:
  	if (status < 0)
fc7b92fca   Balaji T K   mfd: Rename all t...
1255
  		twl_remove(client);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1256
1257
  	return status;
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
1258
  static const struct i2c_device_id twl_ids[] = {
dad759ff8   David Brownell   mfd: twl4030: cre...
1259
1260
  	{ "twl4030", TWL4030_VAUX2 },	/* "Triton 2" */
  	{ "twl5030", 0 },		/* T2 updated */
1920a61e2   Ilkka Koskinen   mfd: Initial supp...
1261
  	{ "twl5031", TWL5031 },		/* TWL5030 updated */
dad759ff8   David Brownell   mfd: twl4030: cre...
1262
1263
1264
  	{ "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...
1265
1266
  	{ "tps65921", TPS_SUBSET },	/* fewer LDOs; no codec, no LED
  					   and vibrator. Charger in USB module*/
e8deb28ca   Balaji T K   mfd: Add support ...
1267
  	{ "twl6030", TWL6030_CLASS },	/* "Phoenix power chip" */
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
1268
  	{ "twl6025", TWL6030_CLASS | TWL6025_SUBCLASS }, /* "Phoenix lite" */
a603a7fa8   David Brownell   mfd: TWL4030 core...
1269
1270
  	{ /* end of list */ },
  };
fc7b92fca   Balaji T K   mfd: Rename all t...
1271
  MODULE_DEVICE_TABLE(i2c, twl_ids);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1272
1273
  
  /* One Client Driver , 4 Clients */
fc7b92fca   Balaji T K   mfd: Rename all t...
1274
  static struct i2c_driver twl_driver = {
a603a7fa8   David Brownell   mfd: TWL4030 core...
1275
  	.driver.name	= DRIVER_NAME,
fc7b92fca   Balaji T K   mfd: Rename all t...
1276
1277
1278
  	.id_table	= twl_ids,
  	.probe		= twl_probe,
  	.remove		= twl_remove,
a603a7fa8   David Brownell   mfd: TWL4030 core...
1279
  };
fc7b92fca   Balaji T K   mfd: Rename all t...
1280
  static int __init twl_init(void)
a603a7fa8   David Brownell   mfd: TWL4030 core...
1281
  {
fc7b92fca   Balaji T K   mfd: Rename all t...
1282
  	return i2c_add_driver(&twl_driver);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1283
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
1284
  subsys_initcall(twl_init);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1285

fc7b92fca   Balaji T K   mfd: Rename all t...
1286
  static void __exit twl_exit(void)
a603a7fa8   David Brownell   mfd: TWL4030 core...
1287
  {
fc7b92fca   Balaji T K   mfd: Rename all t...
1288
  	i2c_del_driver(&twl_driver);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1289
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
1290
  module_exit(twl_exit);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1291
1292
  
  MODULE_AUTHOR("Texas Instruments, Inc.");
fc7b92fca   Balaji T K   mfd: Rename all t...
1293
  MODULE_DESCRIPTION("I2C Core interface for TWL");
a603a7fa8   David Brownell   mfd: TWL4030 core...
1294
  MODULE_LICENSE("GPL");