Blame view

drivers/mfd/twl-core.c 32.5 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
  #include <linux/platform_device.h>
2473d25a2   Peter Ujfalusi   mfd: twl-core: Co...
34
  #include <linux/regmap.h>
a603a7fa8   David Brownell   mfd: TWL4030 core...
35
  #include <linux/clk.h>
a30d46c04   David Brownell   mfd: twl4030 IRQ ...
36
  #include <linux/err.h>
aeb5032b3   Benoit Cousson   mfd: twl-core: Ad...
37
38
39
40
  #include <linux/device.h>
  #include <linux/of.h>
  #include <linux/of_irq.h>
  #include <linux/of_platform.h>
e7cc3aca0   Grant Likely   dt: fix twl4030 f...
41
  #include <linux/irq.h>
aeb5032b3   Benoit Cousson   mfd: twl-core: Ad...
42
  #include <linux/irqdomain.h>
a603a7fa8   David Brownell   mfd: TWL4030 core...
43

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

914607008   Peter Ujfalusi   mfd: twl-core: En...
48
49
  /* Register descriptions for audio */
  #include <linux/mfd/twl4030-audio.h>
1b8f333ff   Benoit Cousson   mfd: Remove refer...
50
  #include "twl-core.h"
a603a7fa8   David Brownell   mfd: TWL4030 core...
51
52
53
54
55
56
57
58
59
60
61
62
63
  
  /*
   * 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...
64
  #define DRIVER_NAME			"twl"
a603a7fa8   David Brownell   mfd: TWL4030 core...
65

a603a7fa8   David Brownell   mfd: TWL4030 core...
66
  /* Triton Core internal information (BEGIN) */
a603a7fa8   David Brownell   mfd: TWL4030 core...
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  /* 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
5d4e9bd79   Peter Ujfalusi   mfd: twl-core: Cl...
85
  #define TWL4030_BASEADD_PWM		0x00F8
a603a7fa8   David Brownell   mfd: TWL4030 core...
86
  #define TWL4030_BASEADD_KEYPAD		0x00D2
1920a61e2   Ilkka Koskinen   mfd: Initial supp...
87
88
89
  #define TWL5031_BASEADD_ACCESSORY	0x0074 /* Replaces Main Charge */
  #define TWL5031_BASEADD_INTERRUPTS	0x00B9 /* Different than TWL4030's
  						  one */
a603a7fa8   David Brownell   mfd: TWL4030 core...
90
91
92
93
  /* subchip/slave 3 - POWER ID */
  #define TWL4030_BASEADD_BACKUP		0x0014
  #define TWL4030_BASEADD_INT		0x002E
  #define TWL4030_BASEADD_PM_MASTER	0x0036
a613b739b   Tony Lindgren   mfd: twl-core: Fi...
94

a603a7fa8   David Brownell   mfd: TWL4030 core...
95
  #define TWL4030_BASEADD_PM_RECEIVER	0x005B
a613b739b   Tony Lindgren   mfd: twl-core: Fi...
96
97
  #define TWL4030_DCDC_GLOBAL_CFG		0x06
  #define SMARTREFLEX_ENABLE		BIT(3)
a603a7fa8   David Brownell   mfd: TWL4030 core...
98
99
100
101
  #define TWL4030_BASEADD_RTC		0x001C
  #define TWL4030_BASEADD_SECURED_REG	0x0000
  
  /* Triton Core internal information (END) */
e8deb28ca   Balaji T K   mfd: Add support ...
102
103
  /* subchip/slave 0 0x48 - POWER */
  #define TWL6030_BASEADD_RTC		0x0000
5d4e9bd79   Peter Ujfalusi   mfd: twl-core: Cl...
104
  #define TWL6030_BASEADD_SECURED_REG	0x0017
e8deb28ca   Balaji T K   mfd: Add support ...
105
106
107
108
109
110
111
112
113
114
115
116
117
  #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
89ce43fbb   Graeme Gregory   mfd: twl-core: Ch...
118
  #define TWL6032_BASEADD_CHARGER		0x00DA
5d4e9bd79   Peter Ujfalusi   mfd: twl-core: Cl...
119
  #define TWL6030_BASEADD_LED		0x00F4
e8deb28ca   Balaji T K   mfd: Add support ...
120
121
122
123
124
125
126
  
  /* 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 ...
127
  #define TWL6030_BASEADD_ZERO		0x0000
e8deb28ca   Balaji T K   mfd: Add support ...
128

a603a7fa8   David Brownell   mfd: TWL4030 core...
129
130
  /* Few power values */
  #define R_CFG_BOOT			0x05
a603a7fa8   David Brownell   mfd: TWL4030 core...
131
132
133
134
135
136
  
  /* 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...
137
  #define CK32K_LOWPWR_EN			(1 << 7)
a603a7fa8   David Brownell   mfd: TWL4030 core...
138

a603a7fa8   David Brownell   mfd: TWL4030 core...
139
  /*----------------------------------------------------------------------*/
e8deb28ca   Balaji T K   mfd: Add support ...
140
  /* Structure for each TWL4030/TWL6030 Slave */
fc7b92fca   Balaji T K   mfd: Rename all t...
141
  struct twl_client {
a603a7fa8   David Brownell   mfd: TWL4030 core...
142
  	struct i2c_client *client;
2473d25a2   Peter Ujfalusi   mfd: twl-core: Co...
143
  	struct regmap *regmap;
a603a7fa8   David Brownell   mfd: TWL4030 core...
144
  };
a603a7fa8   David Brownell   mfd: TWL4030 core...
145
  /* mapping the module id to slave id and base address */
fc7b92fca   Balaji T K   mfd: Rename all t...
146
  struct twl_mapping {
a603a7fa8   David Brownell   mfd: TWL4030 core...
147
148
149
  	unsigned char sid;	/* Slave ID */
  	unsigned char base;	/* base address */
  };
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
150
151
152
153
154
155
156
157
158
159
160
  
  struct twl_private {
  	bool ready; /* The core driver is ready to be used */
  	u32 twl_idcode; /* TWL IDCODE Register value */
  	unsigned int twl_id;
  
  	struct twl_mapping *twl_map;
  	struct twl_client *twl_modules;
  };
  
  static struct twl_private *twl_priv;
a603a7fa8   David Brownell   mfd: TWL4030 core...
161

da059ecfc   Peter Ujfalusi   mfd: twl: Convert...
162
  static struct twl_mapping twl4030_map[] = {
a603a7fa8   David Brownell   mfd: TWL4030 core...
163
164
  	/*
  	 * NOTE:  don't change this table without updating the
e8deb28ca   Balaji T K   mfd: Add support ...
165
  	 * <linux/i2c/twl.h> defines for TWL4030_MODULE_*
a603a7fa8   David Brownell   mfd: TWL4030 core...
166
167
  	 * so they continue to match the order in this table.
  	 */
5d4e9bd79   Peter Ujfalusi   mfd: twl-core: Cl...
168
  	/* Common IPs */
a603a7fa8   David Brownell   mfd: TWL4030 core...
169
  	{ 0, TWL4030_BASEADD_USB },
5d4e9bd79   Peter Ujfalusi   mfd: twl-core: Cl...
170
171
172
173
174
175
176
177
178
179
180
  	{ 1, TWL4030_BASEADD_PIH },
  	{ 2, TWL4030_BASEADD_MAIN_CHARGE },
  	{ 3, TWL4030_BASEADD_PM_MASTER },
  	{ 3, TWL4030_BASEADD_PM_RECEIVER },
  
  	{ 3, TWL4030_BASEADD_RTC },
  	{ 2, TWL4030_BASEADD_PWM },
  	{ 2, TWL4030_BASEADD_LED },
  	{ 3, TWL4030_BASEADD_SECURED_REG },
  
  	/* TWL4030 specific IPs */
a603a7fa8   David Brownell   mfd: TWL4030 core...
181
182
183
  	{ 1, TWL4030_BASEADD_AUDIO_VOICE },
  	{ 1, TWL4030_BASEADD_GPIO },
  	{ 1, TWL4030_BASEADD_INTBR },
6691ccd05   Peter Ujfalusi   mfd: twl-core: re...
184
  	{ 1, TWL4030_BASEADD_TEST },
a603a7fa8   David Brownell   mfd: TWL4030 core...
185
  	{ 2, TWL4030_BASEADD_KEYPAD },
5d4e9bd79   Peter Ujfalusi   mfd: twl-core: Cl...
186

a603a7fa8   David Brownell   mfd: TWL4030 core...
187
188
  	{ 2, TWL4030_BASEADD_MADC },
  	{ 2, TWL4030_BASEADD_INTERRUPTS },
a603a7fa8   David Brownell   mfd: TWL4030 core...
189
  	{ 2, TWL4030_BASEADD_PRECHARGE },
a603a7fa8   David Brownell   mfd: TWL4030 core...
190
191
  	{ 3, TWL4030_BASEADD_BACKUP },
  	{ 3, TWL4030_BASEADD_INT },
6691ccd05   Peter Ujfalusi   mfd: twl-core: re...
192

5d4e9bd79   Peter Ujfalusi   mfd: twl-core: Cl...
193
194
  	{ 2, TWL5031_BASEADD_ACCESSORY },
  	{ 2, TWL5031_BASEADD_INTERRUPTS },
a603a7fa8   David Brownell   mfd: TWL4030 core...
195
  };
d842b61ba   Krzysztof Kozlowski   mfd: twl-core: Co...
196
  static const struct reg_default twl4030_49_defaults[] = {
914607008   Peter Ujfalusi   mfd: twl-core: En...
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
  	/* Audio Registers */
  	{ 0x01, 0x00}, /* CODEC_MODE	*/
  	{ 0x02, 0x00}, /* OPTION	*/
  	/* 0x03  Unused	*/
  	{ 0x04, 0x00}, /* MICBIAS_CTL	*/
  	{ 0x05, 0x00}, /* ANAMICL	*/
  	{ 0x06, 0x00}, /* ANAMICR	*/
  	{ 0x07, 0x00}, /* AVADC_CTL	*/
  	{ 0x08, 0x00}, /* ADCMICSEL	*/
  	{ 0x09, 0x00}, /* DIGMIXING	*/
  	{ 0x0a, 0x0f}, /* ATXL1PGA	*/
  	{ 0x0b, 0x0f}, /* ATXR1PGA	*/
  	{ 0x0c, 0x0f}, /* AVTXL2PGA	*/
  	{ 0x0d, 0x0f}, /* AVTXR2PGA	*/
  	{ 0x0e, 0x00}, /* AUDIO_IF	*/
  	{ 0x0f, 0x00}, /* VOICE_IF	*/
  	{ 0x10, 0x3f}, /* ARXR1PGA	*/
  	{ 0x11, 0x3f}, /* ARXL1PGA	*/
  	{ 0x12, 0x3f}, /* ARXR2PGA	*/
  	{ 0x13, 0x3f}, /* ARXL2PGA	*/
  	{ 0x14, 0x25}, /* VRXPGA	*/
  	{ 0x15, 0x00}, /* VSTPGA	*/
  	{ 0x16, 0x00}, /* VRX2ARXPGA	*/
  	{ 0x17, 0x00}, /* AVDAC_CTL	*/
  	{ 0x18, 0x00}, /* ARX2VTXPGA	*/
  	{ 0x19, 0x32}, /* ARXL1_APGA_CTL*/
  	{ 0x1a, 0x32}, /* ARXR1_APGA_CTL*/
  	{ 0x1b, 0x32}, /* ARXL2_APGA_CTL*/
  	{ 0x1c, 0x32}, /* ARXR2_APGA_CTL*/
  	{ 0x1d, 0x00}, /* ATX2ARXPGA	*/
  	{ 0x1e, 0x00}, /* BT_IF		*/
  	{ 0x1f, 0x55}, /* BTPGA		*/
  	{ 0x20, 0x00}, /* BTSTPGA	*/
  	{ 0x21, 0x00}, /* EAR_CTL	*/
  	{ 0x22, 0x00}, /* HS_SEL	*/
  	{ 0x23, 0x00}, /* HS_GAIN_SET	*/
  	{ 0x24, 0x00}, /* HS_POPN_SET	*/
  	{ 0x25, 0x00}, /* PREDL_CTL	*/
  	{ 0x26, 0x00}, /* PREDR_CTL	*/
  	{ 0x27, 0x00}, /* PRECKL_CTL	*/
  	{ 0x28, 0x00}, /* PRECKR_CTL	*/
  	{ 0x29, 0x00}, /* HFL_CTL	*/
  	{ 0x2a, 0x00}, /* HFR_CTL	*/
  	{ 0x2b, 0x05}, /* ALC_CTL	*/
  	{ 0x2c, 0x00}, /* ALC_SET1	*/
  	{ 0x2d, 0x00}, /* ALC_SET2	*/
  	{ 0x2e, 0x00}, /* BOOST_CTL	*/
  	{ 0x2f, 0x00}, /* SOFTVOL_CTL	*/
  	{ 0x30, 0x13}, /* DTMF_FREQSEL	*/
  	{ 0x31, 0x00}, /* DTMF_TONEXT1H	*/
  	{ 0x32, 0x00}, /* DTMF_TONEXT1L	*/
  	{ 0x33, 0x00}, /* DTMF_TONEXT2H	*/
  	{ 0x34, 0x00}, /* DTMF_TONEXT2L	*/
  	{ 0x35, 0x79}, /* DTMF_TONOFF	*/
  	{ 0x36, 0x11}, /* DTMF_WANONOFF	*/
  	{ 0x37, 0x00}, /* I2S_RX_SCRAMBLE_H */
  	{ 0x38, 0x00}, /* I2S_RX_SCRAMBLE_M */
  	{ 0x39, 0x00}, /* I2S_RX_SCRAMBLE_L */
  	{ 0x3a, 0x06}, /* APLL_CTL */
  	{ 0x3b, 0x00}, /* DTMF_CTL */
  	{ 0x3c, 0x44}, /* DTMF_PGA_CTL2	(0x3C) */
  	{ 0x3d, 0x69}, /* DTMF_PGA_CTL1	(0x3D) */
  	{ 0x3e, 0x00}, /* MISC_SET_1 */
  	{ 0x3f, 0x00}, /* PCMBTMUX */
  	/* 0x40 - 0x42  Unused */
  	{ 0x43, 0x00}, /* RX_PATH_SEL */
  	{ 0x44, 0x32}, /* VDL_APGA_CTL */
  	{ 0x45, 0x00}, /* VIBRA_CTL */
  	{ 0x46, 0x00}, /* VIBRA_SET */
  	{ 0x47, 0x00}, /* VIBRA_PWM_SET	*/
  	{ 0x48, 0x00}, /* ANAMIC_GAIN	*/
  	{ 0x49, 0x00}, /* MISC_SET_2	*/
  	/* End of Audio Registers */
  };
  
  static bool twl4030_49_nop_reg(struct device *dev, unsigned int reg)
  {
  	switch (reg) {
56816b700   Tomas Novotny   mfd: twl-core: Fi...
275
276
277
278
279
  	case 0x00:
  	case 0x03:
  	case 0x40:
  	case 0x41:
  	case 0x42:
914607008   Peter Ujfalusi   mfd: twl-core: En...
280
281
282
283
284
285
286
287
288
289
290
291
292
293
  		return false;
  	default:
  		return true;
  	}
  }
  
  static const struct regmap_range twl4030_49_volatile_ranges[] = {
  	regmap_reg_range(TWL4030_BASEADD_TEST, 0xff),
  };
  
  static const struct regmap_access_table twl4030_49_volatile_table = {
  	.yes_ranges = twl4030_49_volatile_ranges,
  	.n_yes_ranges = ARRAY_SIZE(twl4030_49_volatile_ranges),
  };
d842b61ba   Krzysztof Kozlowski   mfd: twl-core: Co...
294
  static const struct regmap_config twl4030_regmap_config[4] = {
2473d25a2   Peter Ujfalusi   mfd: twl-core: Co...
295
296
297
298
299
300
301
302
303
304
305
  	{
  		/* Address 0x48 */
  		.reg_bits = 8,
  		.val_bits = 8,
  		.max_register = 0xff,
  	},
  	{
  		/* Address 0x49 */
  		.reg_bits = 8,
  		.val_bits = 8,
  		.max_register = 0xff,
914607008   Peter Ujfalusi   mfd: twl-core: En...
306
307
308
309
310
311
312
313
314
  
  		.readable_reg = twl4030_49_nop_reg,
  		.writeable_reg = twl4030_49_nop_reg,
  
  		.volatile_table = &twl4030_49_volatile_table,
  
  		.reg_defaults = twl4030_49_defaults,
  		.num_reg_defaults = ARRAY_SIZE(twl4030_49_defaults),
  		.cache_type = REGCACHE_RBTREE,
2473d25a2   Peter Ujfalusi   mfd: twl-core: Co...
315
316
317
318
319
320
321
322
323
324
325
326
327
328
  	},
  	{
  		/* Address 0x4a */
  		.reg_bits = 8,
  		.val_bits = 8,
  		.max_register = 0xff,
  	},
  	{
  		/* Address 0x4b */
  		.reg_bits = 8,
  		.val_bits = 8,
  		.max_register = 0xff,
  	},
  };
e8deb28ca   Balaji T K   mfd: Add support ...
329
330
331
332
333
334
  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.
  	 */
5d4e9bd79   Peter Ujfalusi   mfd: twl-core: Cl...
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
  
  	/* Common IPs */
  	{ 1, TWL6030_BASEADD_USB },
  	{ 1, TWL6030_BASEADD_PIH },
  	{ 1, TWL6030_BASEADD_CHARGER },
  	{ 0, TWL6030_BASEADD_PM_MASTER },
  	{ 0, TWL6030_BASEADD_PM_SLAVE_MISC },
  
  	{ 0, TWL6030_BASEADD_RTC },
  	{ 1, TWL6030_BASEADD_PWM },
  	{ 1, TWL6030_BASEADD_LED },
  	{ 0, TWL6030_BASEADD_SECURED_REG },
  
  	/* TWL6030 specific IPs */
  	{ 0, TWL6030_BASEADD_ZERO },
  	{ 1, TWL6030_BASEADD_ZERO },
  	{ 2, TWL6030_BASEADD_ZERO },
  	{ 1, TWL6030_BASEADD_GPADC_CTRL },
  	{ 1, TWL6030_BASEADD_GASGAUGE },
e8deb28ca   Balaji T K   mfd: Add support ...
354
  };
d842b61ba   Krzysztof Kozlowski   mfd: twl-core: Co...
355
  static const struct regmap_config twl6030_regmap_config[3] = {
2473d25a2   Peter Ujfalusi   mfd: twl-core: Co...
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
  	{
  		/* Address 0x48 */
  		.reg_bits = 8,
  		.val_bits = 8,
  		.max_register = 0xff,
  	},
  	{
  		/* Address 0x49 */
  		.reg_bits = 8,
  		.val_bits = 8,
  		.max_register = 0xff,
  	},
  	{
  		/* Address 0x4a */
  		.reg_bits = 8,
  		.val_bits = 8,
  		.max_register = 0xff,
  	},
  };
a603a7fa8   David Brownell   mfd: TWL4030 core...
375
  /*----------------------------------------------------------------------*/
6dd810b5e   Peter Ujfalusi   mfd: twl-core: Al...
376
377
378
379
380
381
382
  static inline int twl_get_num_slaves(void)
  {
  	if (twl_class_is_4030())
  		return 4; /* TWL4030 class have four slave address */
  	else
  		return 3; /* TWL6030 class have three slave address */
  }
5d4e9bd79   Peter Ujfalusi   mfd: twl-core: Cl...
383
384
385
386
387
388
389
  static inline int twl_get_last_module(void)
  {
  	if (twl_class_is_4030())
  		return TWL4030_MODULE_LAST;
  	else
  		return TWL6030_MODULE_LAST;
  }
a603a7fa8   David Brownell   mfd: TWL4030 core...
390
  /* Exported Functions */
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
391
392
393
394
395
  unsigned int twl_rev(void)
  {
  	return twl_priv ? twl_priv->twl_id : 0;
  }
  EXPORT_SYMBOL(twl_rev);
a603a7fa8   David Brownell   mfd: TWL4030 core...
396
  /**
8daf35406   Peter Ujfalusi   mfd: twl-core: Si...
397
   * twl_get_regmap - Get the regmap associated with the given module
a603a7fa8   David Brownell   mfd: TWL4030 core...
398
   * @mod_no: module number
a603a7fa8   David Brownell   mfd: TWL4030 core...
399
   *
8daf35406   Peter Ujfalusi   mfd: twl-core: Si...
400
   * Returns the regmap pointer or NULL in case of failure.
a603a7fa8   David Brownell   mfd: TWL4030 core...
401
   */
8daf35406   Peter Ujfalusi   mfd: twl-core: Si...
402
  static struct regmap *twl_get_regmap(u8 mod_no)
a603a7fa8   David Brownell   mfd: TWL4030 core...
403
  {
a603a7fa8   David Brownell   mfd: TWL4030 core...
404
  	int sid;
fc7b92fca   Balaji T K   mfd: Rename all t...
405
  	struct twl_client *twl;
a603a7fa8   David Brownell   mfd: TWL4030 core...
406

1765dbcca   Jon Hunter   mfd: twl-core: Fi...
407
408
409
  	if (unlikely(!twl_priv || !twl_priv->ready)) {
  		pr_err("%s: not initialized
  ", DRIVER_NAME);
8daf35406   Peter Ujfalusi   mfd: twl-core: Si...
410
  		return NULL;
a603a7fa8   David Brownell   mfd: TWL4030 core...
411
  	}
1765dbcca   Jon Hunter   mfd: twl-core: Fi...
412
413
414
  	if (unlikely(mod_no >= twl_get_last_module())) {
  		pr_err("%s: invalid module number %d
  ", DRIVER_NAME, mod_no);
8daf35406   Peter Ujfalusi   mfd: twl-core: Si...
415
  		return NULL;
a603a7fa8   David Brownell   mfd: TWL4030 core...
416
  	}
050cde136   Peter Ujfalusi   mfd: twl-core: No...
417

80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
418
419
  	sid = twl_priv->twl_map[mod_no].sid;
  	twl = &twl_priv->twl_modules[sid];
8653be1af   Ilya Yanok   mfd: Fix twl-core...
420

8daf35406   Peter Ujfalusi   mfd: twl-core: Si...
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
  	return twl->regmap;
  }
  
  /**
   * twl_i2c_write - Writes a n bit register in TWL4030/TWL5030/TWL60X0
   * @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
   *
   * Returns the result of operation - 0 is success
   */
  int twl_i2c_write(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
  {
  	struct regmap *regmap = twl_get_regmap(mod_no);
  	int ret;
  
  	if (!regmap)
  		return -EPERM;
  
  	ret = regmap_bulk_write(regmap, twl_priv->twl_map[mod_no].base + reg,
  				value, num_bytes);
2473d25a2   Peter Ujfalusi   mfd: twl-core: Co...
443
444
445
446
447
448
449
  
  	if (ret)
  		pr_err("%s: Write failed (mod %d, reg 0x%02x count %d)
  ",
  		       DRIVER_NAME, mod_no, reg, num_bytes);
  
  	return ret;
a603a7fa8   David Brownell   mfd: TWL4030 core...
450
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
451
  EXPORT_SYMBOL(twl_i2c_write);
a603a7fa8   David Brownell   mfd: TWL4030 core...
452
453
  
  /**
fc7b92fca   Balaji T K   mfd: Rename all t...
454
   * twl_i2c_read - Reads a n bit register in TWL4030/TWL5030/TWL60X0
a603a7fa8   David Brownell   mfd: TWL4030 core...
455
456
457
458
459
460
461
   * @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...
462
  int twl_i2c_read(u8 mod_no, u8 *value, u8 reg, unsigned num_bytes)
a603a7fa8   David Brownell   mfd: TWL4030 core...
463
  {
8daf35406   Peter Ujfalusi   mfd: twl-core: Si...
464
  	struct regmap *regmap = twl_get_regmap(mod_no);
a603a7fa8   David Brownell   mfd: TWL4030 core...
465
  	int ret;
a603a7fa8   David Brownell   mfd: TWL4030 core...
466

8daf35406   Peter Ujfalusi   mfd: twl-core: Si...
467
  	if (!regmap)
a603a7fa8   David Brownell   mfd: TWL4030 core...
468
  		return -EPERM;
8653be1af   Ilya Yanok   mfd: Fix twl-core...
469

8daf35406   Peter Ujfalusi   mfd: twl-core: Si...
470
471
  	ret = regmap_bulk_read(regmap, twl_priv->twl_map[mod_no].base + reg,
  			       value, num_bytes);
2473d25a2   Peter Ujfalusi   mfd: twl-core: Co...
472
473
474
475
476
477
478
  
  	if (ret)
  		pr_err("%s: Read failed (mod %d, reg 0x%02x count %d)
  ",
  		       DRIVER_NAME, mod_no, reg, num_bytes);
  
  	return ret;
a603a7fa8   David Brownell   mfd: TWL4030 core...
479
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
480
  EXPORT_SYMBOL(twl_i2c_read);
a603a7fa8   David Brownell   mfd: TWL4030 core...
481

3def927ea   Peter Ujfalusi   mfd: twl-core: AP...
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
  /**
   * twl_regcache_bypass - Configure the regcache bypass for the regmap associated
   *			 with the module
   * @mod_no: module number
   * @enable: Regcache bypass state
   *
   * Returns 0 else failure.
   */
  int twl_set_regcache_bypass(u8 mod_no, bool enable)
  {
  	struct regmap *regmap = twl_get_regmap(mod_no);
  
  	if (!regmap)
  		return -EPERM;
  
  	regcache_cache_bypass(regmap, enable);
  
  	return 0;
  }
  EXPORT_SYMBOL(twl_set_regcache_bypass);
a603a7fa8   David Brownell   mfd: TWL4030 core...
502
  /*----------------------------------------------------------------------*/
ca972d133   Lesly A M   mfd: TWL5030 vers...
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
  /**
   * 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;
  	}
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
519
  	err = twl_i2c_read(TWL4030_MODULE_INTBR, (u8 *)(&twl_priv->twl_idcode),
ca972d133   Lesly A M   mfd: TWL5030 vers...
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
  						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)
  {
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
542
  	return TWL_SIL_TYPE(twl_priv->twl_idcode);
ca972d133   Lesly A M   mfd: TWL5030 vers...
543
544
545
546
547
548
549
550
551
552
  }
  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)
  {
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
553
  	return TWL_SIL_REV(twl_priv->twl_idcode);
ca972d133   Lesly A M   mfd: TWL5030 vers...
554
555
  }
  EXPORT_SYMBOL_GPL(twl_get_version);
2275c544c   Peter Ujfalusi   mfd: twl-core: Ad...
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
  /**
   * twl_get_hfclk_rate - API to get TWL external HFCLK clock rate.
   *
   * Api to get the TWL HFCLK rate based on BOOT_CFG register.
   */
  int twl_get_hfclk_rate(void)
  {
  	u8 ctrl;
  	int rate;
  
  	twl_i2c_read_u8(TWL_MODULE_PM_MASTER, &ctrl, R_CFG_BOOT);
  
  	switch (ctrl & 0x3) {
  	case HFCLK_FREQ_19p2_MHZ:
  		rate = 19200000;
  		break;
  	case HFCLK_FREQ_26_MHZ:
  		rate = 26000000;
  		break;
  	case HFCLK_FREQ_38p4_MHZ:
  		rate = 38400000;
  		break;
  	default:
  		pr_err("TWL4030: HFCLK is not configured
  ");
  		rate = -EINVAL;
  		break;
  	}
  
  	return rate;
  }
  EXPORT_SYMBOL_GPL(twl_get_hfclk_rate);
dad759ff8   David Brownell   mfd: twl4030: cre...
588
  static struct device *
3c3302794   Peter Ujfalusi   mfd: twl-core: Us...
589
  add_numbered_child(unsigned mod_no, const char *name, int num,
5725d66b9   David Brownell   mfd: twl4030: sim...
590
591
  		void *pdata, unsigned pdata_len,
  		bool can_wakeup, int irq0, int irq1)
a603a7fa8   David Brownell   mfd: TWL4030 core...
592
  {
5725d66b9   David Brownell   mfd: twl4030: sim...
593
  	struct platform_device	*pdev;
3c3302794   Peter Ujfalusi   mfd: twl-core: Us...
594
595
596
597
598
599
600
601
  	struct twl_client	*twl;
  	int			status, sid;
  
  	if (unlikely(mod_no >= twl_get_last_module())) {
  		pr_err("%s: invalid module number %d
  ", DRIVER_NAME, mod_no);
  		return ERR_PTR(-EPERM);
  	}
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
602
603
  	sid = twl_priv->twl_map[mod_no].sid;
  	twl = &twl_priv->twl_modules[sid];
5725d66b9   David Brownell   mfd: twl4030: sim...
604

dad759ff8   David Brownell   mfd: twl4030: cre...
605
  	pdev = platform_device_alloc(name, num);
a67911d38   Markus Elfring   mfd: twl-core: Re...
606
607
  	if (!pdev)
  		return ERR_PTR(-ENOMEM);
a603a7fa8   David Brownell   mfd: TWL4030 core...
608

5725d66b9   David Brownell   mfd: twl4030: sim...
609
  	pdev->dev.parent = &twl->client->dev;
a603a7fa8   David Brownell   mfd: TWL4030 core...
610

5725d66b9   David Brownell   mfd: twl4030: sim...
611
612
613
614
615
  	if (pdata) {
  		status = platform_device_add_data(pdev, pdata, pdata_len);
  		if (status < 0) {
  			dev_dbg(&pdev->dev, "can't add platform_data
  ");
8175a01c2   Markus Elfring   mfd: twl-core: Re...
616
  			goto put_device;
a603a7fa8   David Brownell   mfd: TWL4030 core...
617
  		}
5725d66b9   David Brownell   mfd: twl4030: sim...
618
  	}
a603a7fa8   David Brownell   mfd: TWL4030 core...
619

5725d66b9   David Brownell   mfd: twl4030: sim...
620
621
622
623
624
  	if (irq0) {
  		struct resource r[2] = {
  			{ .start = irq0, .flags = IORESOURCE_IRQ, },
  			{ .start = irq1, .flags = IORESOURCE_IRQ, },
  		};
a603a7fa8   David Brownell   mfd: TWL4030 core...
625

5725d66b9   David Brownell   mfd: twl4030: sim...
626
  		status = platform_device_add_resources(pdev, r, irq1 ? 2 : 1);
a603a7fa8   David Brownell   mfd: TWL4030 core...
627
  		if (status < 0) {
5725d66b9   David Brownell   mfd: twl4030: sim...
628
629
  			dev_dbg(&pdev->dev, "can't add irqs
  ");
8175a01c2   Markus Elfring   mfd: twl-core: Re...
630
  			goto put_device;
a603a7fa8   David Brownell   mfd: TWL4030 core...
631
632
  		}
  	}
5725d66b9   David Brownell   mfd: twl4030: sim...
633
  	status = platform_device_add(pdev);
8175a01c2   Markus Elfring   mfd: twl-core: Re...
634
635
636
637
  	if (status)
  		goto put_device;
  
  	device_init_wakeup(&pdev->dev, can_wakeup);
5725d66b9   David Brownell   mfd: twl4030: sim...
638
  	return &pdev->dev;
8175a01c2   Markus Elfring   mfd: twl-core: Re...
639
640
641
642
643
644
  
  put_device:
  	platform_device_put(pdev);
  	dev_err(&twl->client->dev, "failed to add device %s
  ", name);
  	return ERR_PTR(status);
5725d66b9   David Brownell   mfd: twl4030: sim...
645
  }
a603a7fa8   David Brownell   mfd: TWL4030 core...
646

3c3302794   Peter Ujfalusi   mfd: twl-core: Us...
647
  static inline struct device *add_child(unsigned mod_no, const char *name,
dad759ff8   David Brownell   mfd: twl4030: cre...
648
649
650
  		void *pdata, unsigned pdata_len,
  		bool can_wakeup, int irq0, int irq1)
  {
3c3302794   Peter Ujfalusi   mfd: twl-core: Us...
651
  	return add_numbered_child(mod_no, name, -1, pdata, pdata_len,
dad759ff8   David Brownell   mfd: twl4030: cre...
652
653
654
655
656
657
  		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 ...
658
  		unsigned num_consumers, unsigned long features)
dad759ff8   David Brownell   mfd: twl4030: cre...
659
  {
63bfff4e2   Tero Kristo   regulator: twl403...
660
  	struct twl_regulator_driver_data drv_data;
dad759ff8   David Brownell   mfd: twl4030: cre...
661
662
663
  	/* regulator framework demands init_data ... */
  	if (!pdata)
  		return NULL;
b73eac787   David Brownell   mfd: twl4030 regu...
664
  	if (consumers) {
dad759ff8   David Brownell   mfd: twl4030: cre...
665
666
667
  		pdata->consumer_supplies = consumers;
  		pdata->num_consumer_supplies = num_consumers;
  	}
63bfff4e2   Tero Kristo   regulator: twl403...
668
669
670
671
672
673
674
675
676
677
678
679
680
  	if (pdata->driver_data) {
  		/* If we have existing drv_data, just add the flags */
  		struct twl_regulator_driver_data *tmp;
  		tmp = pdata->driver_data;
  		tmp->features |= features;
  	} else {
  		/* add new driver data struct, used only during init */
  		drv_data.features = features;
  		drv_data.set_voltage = NULL;
  		drv_data.get_voltage = NULL;
  		drv_data.data = NULL;
  		pdata->driver_data = &drv_data;
  	}
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
681

dad759ff8   David Brownell   mfd: twl4030: cre...
682
  	/* NOTE:  we currently ignore regulator IRQs, e.g. for short circuits */
3c3302794   Peter Ujfalusi   mfd: twl-core: Us...
683
  	return add_numbered_child(TWL_MODULE_PM_MASTER, "twl_reg", num,
dad759ff8   David Brownell   mfd: twl4030: cre...
684
685
686
687
  		pdata, sizeof(*pdata), false, 0, 0);
  }
  
  static struct device *
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
688
689
  add_regulator(int num, struct regulator_init_data *pdata,
  		unsigned long features)
dad759ff8   David Brownell   mfd: twl4030: cre...
690
  {
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
691
  	return add_regulator_linked(num, pdata, NULL, 0, features);
dad759ff8   David Brownell   mfd: twl4030: cre...
692
  }
5725d66b9   David Brownell   mfd: twl4030: sim...
693
694
695
696
697
  /*
   * 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...
698

dad759ff8   David Brownell   mfd: twl4030: cre...
699
  static int
9e1786202   Felipe Balbi   mfd: Make twl-cor...
700
701
  add_children(struct twl4030_platform_data *pdata, unsigned irq_base,
  		unsigned long features)
5725d66b9   David Brownell   mfd: twl4030: sim...
702
703
  {
  	struct device	*child;
a603a7fa8   David Brownell   mfd: TWL4030 core...
704

f78959cfa   Thierry Reding   mfd: twl: Replace...
705
  	if (IS_ENABLED(CONFIG_GPIO_TWL4030) && pdata->gpio) {
3c3302794   Peter Ujfalusi   mfd: twl-core: Us...
706
  		child = add_child(TWL4030_MODULE_GPIO, "twl4030_gpio",
5725d66b9   David Brownell   mfd: twl4030: sim...
707
  				pdata->gpio, sizeof(*pdata->gpio),
9e1786202   Felipe Balbi   mfd: Make twl-cor...
708
  				false, irq_base + GPIO_INTR_OFFSET, 0);
5725d66b9   David Brownell   mfd: twl4030: sim...
709
710
  		if (IS_ERR(child))
  			return PTR_ERR(child);
a603a7fa8   David Brownell   mfd: TWL4030 core...
711
  	}
f78959cfa   Thierry Reding   mfd: twl: Replace...
712
  	if (IS_ENABLED(CONFIG_KEYBOARD_TWL4030) && pdata->keypad) {
3c3302794   Peter Ujfalusi   mfd: twl-core: Us...
713
  		child = add_child(TWL4030_MODULE_KEYPAD, "twl4030_keypad",
5725d66b9   David Brownell   mfd: twl4030: sim...
714
  				pdata->keypad, sizeof(*pdata->keypad),
9e1786202   Felipe Balbi   mfd: Make twl-cor...
715
  				true, irq_base + KEYPAD_INTR_OFFSET, 0);
5725d66b9   David Brownell   mfd: twl4030: sim...
716
717
  		if (IS_ERR(child))
  			return PTR_ERR(child);
a603a7fa8   David Brownell   mfd: TWL4030 core...
718
  	}
24ae36f5c   Peter Ujfalusi   mfd: twl-core: Re...
719
720
  	if (IS_ENABLED(CONFIG_TWL4030_MADC) && pdata->madc &&
  	    twl_class_is_4030()) {
3c3302794   Peter Ujfalusi   mfd: twl-core: Us...
721
  		child = add_child(TWL4030_MODULE_MADC, "twl4030_madc",
5725d66b9   David Brownell   mfd: twl4030: sim...
722
  				pdata->madc, sizeof(*pdata->madc),
9e1786202   Felipe Balbi   mfd: Make twl-cor...
723
  				true, irq_base + MADC_INTR_OFFSET, 0);
5725d66b9   David Brownell   mfd: twl4030: sim...
724
725
  		if (IS_ERR(child))
  			return PTR_ERR(child);
a603a7fa8   David Brownell   mfd: TWL4030 core...
726
  	}
f78959cfa   Thierry Reding   mfd: twl: Replace...
727
  	if (IS_ENABLED(CONFIG_RTC_DRV_TWL4030)) {
a603a7fa8   David Brownell   mfd: TWL4030 core...
728
  		/*
5725d66b9   David Brownell   mfd: twl4030: sim...
729
  		 * REVISIT platform_data here currently might expose the
a603a7fa8   David Brownell   mfd: TWL4030 core...
730
  		 * "msecure" line ... but for now we just expect board
5725d66b9   David Brownell   mfd: twl4030: sim...
731
  		 * setup to tell the chip "it's always ok to SET_TIME".
a603a7fa8   David Brownell   mfd: TWL4030 core...
732
733
734
  		 * Eventually, Linux might become more aware of such
  		 * HW security concerns, and "least privilege".
  		 */
3c3302794   Peter Ujfalusi   mfd: twl-core: Us...
735
  		child = add_child(TWL_MODULE_RTC, "twl_rtc", NULL, 0,
9e1786202   Felipe Balbi   mfd: Make twl-cor...
736
  				true, irq_base + RTC_INTR_OFFSET, 0);
5725d66b9   David Brownell   mfd: twl4030: sim...
737
738
  		if (IS_ERR(child))
  			return PTR_ERR(child);
a603a7fa8   David Brownell   mfd: TWL4030 core...
739
  	}
afc45898f   Peter Ujfalusi   mfd: twl-core: Su...
740
  	if (IS_ENABLED(CONFIG_PWM_TWL)) {
3c3302794   Peter Ujfalusi   mfd: twl-core: Us...
741
  		child = add_child(TWL_MODULE_PWM, "twl-pwm", NULL, 0,
afc45898f   Peter Ujfalusi   mfd: twl-core: Su...
742
743
744
745
746
747
  				  false, 0, 0);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  	}
  
  	if (IS_ENABLED(CONFIG_PWM_TWL_LED)) {
3c3302794   Peter Ujfalusi   mfd: twl-core: Us...
748
  		child = add_child(TWL_MODULE_LED, "twl-pwmled", NULL, 0,
48a364b75   Thierry Reding   pwm: Move TWL6030...
749
750
751
752
  				  false, 0, 0);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  	}
f78959cfa   Thierry Reding   mfd: twl: Replace...
753
754
  	if (IS_ENABLED(CONFIG_TWL4030_USB) && pdata->usb &&
  	    twl_class_is_4030()) {
f8ebdff08   Roger Quadros   mfd: Fix twl4030 ...
755
756
757
758
759
760
761
  
  		static struct regulator_consumer_supply usb1v5 = {
  			.supply =	"usb1v5",
  		};
  		static struct regulator_consumer_supply usb1v8 = {
  			.supply =	"usb1v8",
  		};
e57c4a67d   NeilBrown   twl4030_charger: ...
762
763
  		static struct regulator_consumer_supply usb3v1 = {
  			.supply =	"usb3v1",
f8ebdff08   Roger Quadros   mfd: Fix twl4030 ...
764
765
766
  		};
  
  	/* First add the regulators so that they can be used by transceiver */
f78959cfa   Thierry Reding   mfd: twl: Replace...
767
  		if (IS_ENABLED(CONFIG_REGULATOR_TWL4030)) {
f8ebdff08   Roger Quadros   mfd: Fix twl4030 ...
768
769
770
771
772
773
774
775
776
777
778
  			/* 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 ...
779
780
  						      &usb_fixed, &usb1v5, 1,
  						      features);
f8ebdff08   Roger Quadros   mfd: Fix twl4030 ...
781
782
783
784
  			if (IS_ERR(child))
  				return PTR_ERR(child);
  
  			child = add_regulator_linked(TWL4030_REG_VUSB1V8,
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
785
786
  						      &usb_fixed, &usb1v8, 1,
  						      features);
f8ebdff08   Roger Quadros   mfd: Fix twl4030 ...
787
788
789
790
  			if (IS_ERR(child))
  				return PTR_ERR(child);
  
  			child = add_regulator_linked(TWL4030_REG_VUSB3V1,
e57c4a67d   NeilBrown   twl4030_charger: ...
791
  						      &usb_fixed, &usb3v1, 1,
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
792
  						      features);
f8ebdff08   Roger Quadros   mfd: Fix twl4030 ...
793
794
795
796
  			if (IS_ERR(child))
  				return PTR_ERR(child);
  
  		}
3c3302794   Peter Ujfalusi   mfd: twl-core: Us...
797
  		child = add_child(TWL_MODULE_USB, "twl4030_usb",
2d86ad37e   Peter Ujfalusi   mfd: twl-core: Cl...
798
  				pdata->usb, sizeof(*pdata->usb), true,
5725d66b9   David Brownell   mfd: twl4030: sim...
799
  				/* irq0 = USB_PRES, irq1 = USB */
9e1786202   Felipe Balbi   mfd: Make twl-cor...
800
801
  				irq_base + USB_PRES_INTR_OFFSET,
  				irq_base + USB_INTR_OFFSET);
f8ebdff08   Roger Quadros   mfd: Fix twl4030 ...
802

5725d66b9   David Brownell   mfd: twl4030: sim...
803
804
  		if (IS_ERR(child))
  			return PTR_ERR(child);
dad759ff8   David Brownell   mfd: twl4030: cre...
805
806
  
  		/* we need to connect regulators to this transceiver */
f78959cfa   Thierry Reding   mfd: twl: Replace...
807
  		if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && child) {
1b65fa849   Mark Brown   mfd: twl-core: Do...
808
809
  			usb1v5.dev_name = dev_name(child);
  			usb1v8.dev_name = dev_name(child);
e57c4a67d   NeilBrown   twl4030_charger: ...
810
  			usb3v1.dev_name = dev_name(child);
f8ebdff08   Roger Quadros   mfd: Fix twl4030 ...
811
  		}
dad759ff8   David Brownell   mfd: twl4030: cre...
812
  	}
f78959cfa   Thierry Reding   mfd: twl: Replace...
813
  	if (IS_ENABLED(CONFIG_TWL4030_WATCHDOG) && twl_class_is_4030()) {
3c3302794   Peter Ujfalusi   mfd: twl-core: Us...
814
815
  		child = add_child(TWL_MODULE_PM_RECEIVER, "twl4030_wdt", NULL,
  				  0, false, 0, 0);
80e45b1e9   Timo Kokkonen   [WATCHDOG] twl403...
816
  		if (IS_ERR(child))
9c3664ddc   Felipe Balbi   mfd: Add twl4030-...
817
818
  			return PTR_ERR(child);
  	}
f78959cfa   Thierry Reding   mfd: twl: Replace...
819
  	if (IS_ENABLED(CONFIG_INPUT_TWL4030_PWRBUTTON) && twl_class_is_4030()) {
3c3302794   Peter Ujfalusi   mfd: twl-core: Us...
820
821
  		child = add_child(TWL_MODULE_PM_MASTER, "twl4030_pwrbutton",
  				  NULL, 0, true, irq_base + 8 + 0, 0);
9c3664ddc   Felipe Balbi   mfd: Add twl4030-...
822
  		if (IS_ERR(child))
80e45b1e9   Timo Kokkonen   [WATCHDOG] twl403...
823
824
  			return PTR_ERR(child);
  	}
f78959cfa   Thierry Reding   mfd: twl: Replace...
825
826
  	if (IS_ENABLED(CONFIG_MFD_TWL4030_AUDIO) && pdata->audio &&
  	    twl_class_is_4030()) {
3c3302794   Peter Ujfalusi   mfd: twl-core: Us...
827
  		child = add_child(TWL4030_MODULE_AUDIO_VOICE, "twl4030-audio",
4ae6df5e1   Peter Ujfalusi   MFD: twl4030-audi...
828
  				pdata->audio, sizeof(*pdata->audio),
d62abe563   Misael Lopez Cruz   OMAP4: PMIC: Add ...
829
830
831
832
  				false, 0, 0);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  	}
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
833
  	/* twl4030 regulators */
f78959cfa   Thierry Reding   mfd: twl: Replace...
834
  	if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && twl_class_is_4030()) {
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
835
836
  		child = add_regulator(TWL4030_REG_VPLL1, pdata->vpll1,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
837
838
  		if (IS_ERR(child))
  			return PTR_ERR(child);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
839

521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
840
841
  		child = add_regulator(TWL4030_REG_VIO, pdata->vio,
  					features);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
842
843
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
844
845
  		child = add_regulator(TWL4030_REG_VDD1, pdata->vdd1,
  					features);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
846
847
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
848
849
  		child = add_regulator(TWL4030_REG_VDD2, pdata->vdd2,
  					features);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
850
851
  		if (IS_ERR(child))
  			return PTR_ERR(child);
dad759ff8   David Brownell   mfd: twl4030: cre...
852

521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
853
854
  		child = add_regulator(TWL4030_REG_VMMC1, pdata->vmmc1,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
855
856
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
857
858
  		child = add_regulator(TWL4030_REG_VDAC, pdata->vdac,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
859
860
861
862
863
864
  		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 ...
865
  				pdata->vaux2, features);
dad759ff8   David Brownell   mfd: twl4030: cre...
866
867
  		if (IS_ERR(child))
  			return PTR_ERR(child);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
868

521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
869
870
  		child = add_regulator(TWL4030_REG_VINTANA1, pdata->vintana1,
  					features);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
871
872
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
873
874
  		child = add_regulator(TWL4030_REG_VINTANA2, pdata->vintana2,
  					features);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
875
876
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
877
878
  		child = add_regulator(TWL4030_REG_VINTDIG, pdata->vintdig,
  					features);
ab4abe056   Juha Keski-Saari   mfd: Add all twl4...
879
880
  		if (IS_ERR(child))
  			return PTR_ERR(child);
dad759ff8   David Brownell   mfd: twl4030: cre...
881
  	}
dad759ff8   David Brownell   mfd: twl4030: cre...
882
  	/* maybe add LDOs that are omitted on cost-reduced parts */
f78959cfa   Thierry Reding   mfd: twl: Replace...
883
  	if (IS_ENABLED(CONFIG_REGULATOR_TWL4030) && !(features & TPS_SUBSET)
9da665392   Rajendra Nayak   mfd: Add twl6030 ...
884
  	  && twl_class_is_4030()) {
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
885
886
  		child = add_regulator(TWL4030_REG_VPLL2, pdata->vpll2,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
887
888
  		if (IS_ERR(child))
  			return PTR_ERR(child);
dad759ff8   David Brownell   mfd: twl4030: cre...
889

521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
890
891
  		child = add_regulator(TWL4030_REG_VMMC2, pdata->vmmc2,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
892
893
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
894
895
  		child = add_regulator(TWL4030_REG_VSIM, pdata->vsim,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
896
897
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
898
899
  		child = add_regulator(TWL4030_REG_VAUX1, pdata->vaux1,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
900
901
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
902
903
  		child = add_regulator(TWL4030_REG_VAUX3, pdata->vaux3,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
904
905
  		if (IS_ERR(child))
  			return PTR_ERR(child);
521d8ec3f   Graeme Gregory   mfd: Add phoenix ...
906
907
  		child = add_regulator(TWL4030_REG_VAUX4, pdata->vaux4,
  					features);
dad759ff8   David Brownell   mfd: twl4030: cre...
908
909
  		if (IS_ERR(child))
  			return PTR_ERR(child);
a603a7fa8   David Brownell   mfd: TWL4030 core...
910
  	}
f78959cfa   Thierry Reding   mfd: twl: Replace...
911
  	if (IS_ENABLED(CONFIG_CHARGER_TWL4030) && pdata->bci &&
11c39c4bd   Grazvydas Ignotas   mfd: Add twl4030_...
912
  			!(features & (TPS_SUBSET | TWL5031))) {
3c3302794   Peter Ujfalusi   mfd: twl-core: Us...
913
  		child = add_child(TWL_MODULE_MAIN_CHARGE, "twl4030_bci",
11c39c4bd   Grazvydas Ignotas   mfd: Add twl4030_...
914
915
  				pdata->bci, sizeof(*pdata->bci), false,
  				/* irq0 = CHG_PRES, irq1 = BCI */
9e1786202   Felipe Balbi   mfd: Make twl-cor...
916
917
  				irq_base + BCI_PRES_INTR_OFFSET,
  				irq_base + BCI_INTR_OFFSET);
11c39c4bd   Grazvydas Ignotas   mfd: Add twl4030_...
918
919
920
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  	}
637d6895f   Florian Vaussard   mfd: twl4030-powe...
921
922
923
924
925
926
927
  	if (IS_ENABLED(CONFIG_TWL4030_POWER) && pdata->power) {
  		child = add_child(TWL_MODULE_PM_MASTER, "twl4030_power",
  				  pdata->power, sizeof(*pdata->power), false,
  				  0, 0);
  		if (IS_ERR(child))
  			return PTR_ERR(child);
  	}
5725d66b9   David Brownell   mfd: twl4030: sim...
928
  	return 0;
a603a7fa8   David Brownell   mfd: TWL4030 core...
929
930
931
932
933
934
935
936
937
938
939
940
  }
  
  /*----------------------------------------------------------------------*/
  
  /*
   * 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;
d640e7579   Peter Ujfalusi   mfd: twl-core: Ch...
941
942
  	e = twl_i2c_write_u8(TWL_MODULE_PM_MASTER, 0,
  			     TWL4030_PM_MASTER_PROTECT_KEY);
a603a7fa8   David Brownell   mfd: TWL4030 core...
943
944
945
946
947
948
  	return e;
  }
  
  static inline int __init unprotect_pm_master(void)
  {
  	int e = 0;
d640e7579   Peter Ujfalusi   mfd: twl-core: Ch...
949
950
951
952
  	e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG1,
  			      TWL4030_PM_MASTER_PROTECT_KEY);
  	e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, TWL4030_PM_MASTER_KEY_CFG2,
  			      TWL4030_PM_MASTER_PROTECT_KEY);
49e6f87eb   Felipe Balbi   mfd: Switch twl-c...
953

a603a7fa8   David Brownell   mfd: TWL4030 core...
954
955
  	return e;
  }
38a684963   Ilkka Koskinen   mfd: Enable twl40...
956
957
  static void clocks_init(struct device *dev,
  			struct twl4030_clock_init_data *clock)
a603a7fa8   David Brownell   mfd: TWL4030 core...
958
959
960
961
962
  {
  	int e = 0;
  	struct clk *osc;
  	u32 rate;
  	u8 ctrl = HFCLK_FREQ_26_MHZ;
defa6be1c   Tony Lindgren   mfd: Fix compile ...
963
  	osc = clk_get(dev, "fck");
a603a7fa8   David Brownell   mfd: TWL4030 core...
964
  	if (IS_ERR(osc)) {
fc7b92fca   Balaji T K   mfd: Rename all t...
965
  		printk(KERN_WARNING "Skipping twl internal clock init and "
a603a7fa8   David Brownell   mfd: TWL4030 core...
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
  				"using bootloader value (unknown osc rate)
  ");
  		return;
  	}
  
  	rate = clk_get_rate(osc);
  	clk_put(osc);
  
  	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...
987
988
  	if (clock && clock->ck32k_lowpwr_enable)
  		ctrl |= CK32K_LOWPWR_EN;
a603a7fa8   David Brownell   mfd: TWL4030 core...
989
990
  	e |= unprotect_pm_master();
  	/* effect->MADC+USB ck en */
fc7b92fca   Balaji T K   mfd: Rename all t...
991
  	e |= twl_i2c_write_u8(TWL_MODULE_PM_MASTER, ctrl, R_CFG_BOOT);
a603a7fa8   David Brownell   mfd: TWL4030 core...
992
993
994
995
996
997
998
999
  	e |= protect_pm_master();
  
  	if (e < 0)
  		pr_err("%s: clock init err [%d]
  ", DRIVER_NAME, e);
  }
  
  /*----------------------------------------------------------------------*/
a603a7fa8   David Brownell   mfd: TWL4030 core...
1000

fc7b92fca   Balaji T K   mfd: Rename all t...
1001
  static int twl_remove(struct i2c_client *client)
a603a7fa8   David Brownell   mfd: TWL4030 core...
1002
  {
364cedb2f   Peter Ujfalusi   mfd: Detach twl60...
1003
  	unsigned i, num_slaves;
a30d46c04   David Brownell   mfd: twl4030 IRQ ...
1004
  	int status;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1005

6dd810b5e   Peter Ujfalusi   mfd: twl-core: Al...
1006
  	if (twl_class_is_4030())
e8deb28ca   Balaji T K   mfd: Add support ...
1007
  		status = twl4030_exit_irq();
6dd810b5e   Peter Ujfalusi   mfd: twl-core: Al...
1008
  	else
e8deb28ca   Balaji T K   mfd: Add support ...
1009
  		status = twl6030_exit_irq();
a30d46c04   David Brownell   mfd: twl4030 IRQ ...
1010
1011
  	if (status < 0)
  		return status;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1012

6dd810b5e   Peter Ujfalusi   mfd: twl-core: Al...
1013
  	num_slaves = twl_get_num_slaves();
364cedb2f   Peter Ujfalusi   mfd: Detach twl60...
1014
  	for (i = 0; i < num_slaves; i++) {
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
1015
  		struct twl_client	*twl = &twl_priv->twl_modules[i];
a603a7fa8   David Brownell   mfd: TWL4030 core...
1016
1017
1018
  
  		if (twl->client && twl->client != client)
  			i2c_unregister_device(twl->client);
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
1019
  		twl->client = NULL;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1020
  	}
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
1021
  	twl_priv->ready = false;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1022
1023
  	return 0;
  }
80ec831e8   Tony Lindgren   mfd: twl-core: Fi...
1024
1025
1026
1027
  static struct of_dev_auxdata twl_auxdata_lookup[] = {
  	OF_DEV_AUXDATA("ti,twl4030-gpio", 0, "twl4030-gpio", NULL),
  	{ /* sentinel */ },
  };
ec1a07b34   Benoit Cousson   mfd: Replace twl-...
1028
  /* NOTE: This driver only handles a single twl4030/tps659x0 chip */
f791be492   Bill Pemberton   mfd: remove use o...
1029
  static int
fc7b92fca   Balaji T K   mfd: Rename all t...
1030
  twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
a603a7fa8   David Brownell   mfd: TWL4030 core...
1031
  {
334a41ce9   Jingoo Han   mfd: Use dev_get_...
1032
  	struct twl4030_platform_data	*pdata = dev_get_platdata(&client->dev);
aeb5032b3   Benoit Cousson   mfd: twl-core: Ad...
1033
  	struct device_node		*node = client->dev.of_node;
defa6be1c   Tony Lindgren   mfd: Fix compile ...
1034
  	struct platform_device		*pdev;
d842b61ba   Krzysztof Kozlowski   mfd: twl-core: Co...
1035
  	const struct regmap_config	*twl_regmap_config;
ec1a07b34   Benoit Cousson   mfd: Replace twl-...
1036
1037
  	int				irq_base = 0;
  	int				status;
364cedb2f   Peter Ujfalusi   mfd: Detach twl60...
1038
  	unsigned			i, num_slaves;
aeb5032b3   Benoit Cousson   mfd: twl-core: Ad...
1039

7e2e6c575   Peter Ujfalusi   mfd: twl-core: Do...
1040
1041
1042
1043
1044
  	if (!node && !pdata) {
  		dev_err(&client->dev, "no platform data
  ");
  		return -EINVAL;
  	}
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
1045
  	if (twl_priv) {
6382a0614   Peter Ujfalusi   mfd: twl-core: Mo...
1046
1047
1048
1049
1050
  		dev_dbg(&client->dev, "only one instance of %s allowed
  ",
  			DRIVER_NAME);
  		return -EBUSY;
  	}
defa6be1c   Tony Lindgren   mfd: Fix compile ...
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
  	pdev = platform_device_alloc(DRIVER_NAME, -1);
  	if (!pdev) {
  		dev_err(&client->dev, "can't alloc pdev
  ");
  		return -ENOMEM;
  	}
  
  	status = platform_device_add(pdev);
  	if (status) {
  		platform_device_put(pdev);
  		return status;
  	}
a603a7fa8   David Brownell   mfd: TWL4030 core...
1063
1064
1065
  	if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C) == 0) {
  		dev_dbg(&client->dev, "can't talk I2C?
  ");
defa6be1c   Tony Lindgren   mfd: Fix compile ...
1066
1067
  		status = -EIO;
  		goto free;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1068
  	}
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
1069
1070
1071
1072
1073
1074
  	twl_priv = devm_kzalloc(&client->dev, sizeof(struct twl_private),
  				GFP_KERNEL);
  	if (!twl_priv) {
  		status = -ENOMEM;
  		goto free;
  	}
364cedb2f   Peter Ujfalusi   mfd: Detach twl60...
1075
  	if ((id->driver_data) & TWL6030_CLASS) {
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
1076
1077
  		twl_priv->twl_id = TWL6030_CLASS_ID;
  		twl_priv->twl_map = &twl6030_map[0];
89ce43fbb   Graeme Gregory   mfd: twl-core: Ch...
1078
1079
  		/* The charger base address is different in twl6032 */
  		if ((id->driver_data) & TWL6032_SUBCLASS)
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
1080
  			twl_priv->twl_map[TWL_MODULE_MAIN_CHARGE].base =
89ce43fbb   Graeme Gregory   mfd: twl-core: Ch...
1081
  							TWL6032_BASEADD_CHARGER;
2473d25a2   Peter Ujfalusi   mfd: twl-core: Co...
1082
  		twl_regmap_config = twl6030_regmap_config;
364cedb2f   Peter Ujfalusi   mfd: Detach twl60...
1083
  	} else {
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
1084
1085
  		twl_priv->twl_id = TWL4030_CLASS_ID;
  		twl_priv->twl_map = &twl4030_map[0];
2473d25a2   Peter Ujfalusi   mfd: twl-core: Co...
1086
  		twl_regmap_config = twl4030_regmap_config;
6dd810b5e   Peter Ujfalusi   mfd: twl-core: Al...
1087
1088
1089
  	}
  
  	num_slaves = twl_get_num_slaves();
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
1090
1091
1092
1093
  	twl_priv->twl_modules = devm_kzalloc(&client->dev,
  					 sizeof(struct twl_client) * num_slaves,
  					 GFP_KERNEL);
  	if (!twl_priv->twl_modules) {
6dd810b5e   Peter Ujfalusi   mfd: twl-core: Al...
1094
1095
  		status = -ENOMEM;
  		goto free;
364cedb2f   Peter Ujfalusi   mfd: Detach twl60...
1096
1097
1098
  	}
  
  	for (i = 0; i < num_slaves; i++) {
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
1099
  		struct twl_client *twl = &twl_priv->twl_modules[i];
a603a7fa8   David Brownell   mfd: TWL4030 core...
1100

ec1a07b34   Benoit Cousson   mfd: Replace twl-...
1101
  		if (i == 0) {
a603a7fa8   David Brownell   mfd: TWL4030 core...
1102
  			twl->client = client;
ec1a07b34   Benoit Cousson   mfd: Replace twl-...
1103
  		} else {
a603a7fa8   David Brownell   mfd: TWL4030 core...
1104
  			twl->client = i2c_new_dummy(client->adapter,
2473d25a2   Peter Ujfalusi   mfd: twl-core: Co...
1105
  						    client->addr + i);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1106
  			if (!twl->client) {
a8643430b   Ilkka Koskinen   mfd: Do not deref...
1107
  				dev_err(&client->dev,
a603a7fa8   David Brownell   mfd: TWL4030 core...
1108
1109
1110
1111
1112
  					"can't attach client %d
  ", i);
  				status = -ENOMEM;
  				goto fail;
  			}
a603a7fa8   David Brownell   mfd: TWL4030 core...
1113
  		}
2473d25a2   Peter Ujfalusi   mfd: twl-core: Co...
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
  
  		twl->regmap = devm_regmap_init_i2c(twl->client,
  						   &twl_regmap_config[i]);
  		if (IS_ERR(twl->regmap)) {
  			status = PTR_ERR(twl->regmap);
  			dev_err(&client->dev,
  				"Failed to allocate regmap %d, err: %d
  ", i,
  				status);
  			goto fail;
  		}
a603a7fa8   David Brownell   mfd: TWL4030 core...
1125
  	}
ec1a07b34   Benoit Cousson   mfd: Replace twl-...
1126

80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
1127
  	twl_priv->ready = true;
a603a7fa8   David Brownell   mfd: TWL4030 core...
1128
1129
  
  	/* setup clock framework */
7e2e6c575   Peter Ujfalusi   mfd: twl-core: Do...
1130
  	clocks_init(&pdev->dev, pdata ? pdata->clock : NULL);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1131

ca972d133   Lesly A M   mfd: TWL5030 vers...
1132
  	/* read TWL IDCODE Register */
80a97ccd3   Peter Ujfalusi   mfd: twl-core: Co...
1133
  	if (twl_class_is_4030()) {
ec1a07b34   Benoit Cousson   mfd: Replace twl-...
1134
1135
1136
  		status = twl_read_idcode_register();
  		WARN(status < 0, "Error: reading twl_idcode register value
  ");
ca972d133   Lesly A M   mfd: TWL5030 vers...
1137
  	}
a603a7fa8   David Brownell   mfd: TWL4030 core...
1138
  	/* Maybe init the T2 Interrupt subsystem */
9e1786202   Felipe Balbi   mfd: Make twl-cor...
1139
  	if (client->irq) {
e8deb28ca   Balaji T K   mfd: Add support ...
1140
1141
  		if (twl_class_is_4030()) {
  			twl4030_init_chip_irq(id->name);
78518ffa0   Benoit Cousson   mfd: Move twl-cor...
1142
  			irq_base = twl4030_init_irq(&client->dev, client->irq);
e8deb28ca   Balaji T K   mfd: Add support ...
1143
  		} else {
78518ffa0   Benoit Cousson   mfd: Move twl-cor...
1144
  			irq_base = twl6030_init_irq(&client->dev, client->irq);
e8deb28ca   Balaji T K   mfd: Add support ...
1145
  		}
78518ffa0   Benoit Cousson   mfd: Move twl-cor...
1146
1147
  		if (irq_base < 0) {
  			status = irq_base;
a30d46c04   David Brownell   mfd: twl4030 IRQ ...
1148
  			goto fail;
78518ffa0   Benoit Cousson   mfd: Move twl-cor...
1149
  		}
a603a7fa8   David Brownell   mfd: TWL4030 core...
1150
  	}
ec1a07b34   Benoit Cousson   mfd: Replace twl-...
1151
1152
  	/*
  	 * Disable TWL4030/TWL5030 I2C Pull-up on I2C1 and I2C4(SR) interface.
a29aaf55c   Moiz Sonasath   mfd: Disable TWL4...
1153
1154
  	 * 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.
a613b739b   Tony Lindgren   mfd: twl-core: Fi...
1155
1156
1157
1158
1159
  	 *
  	 * Also, always enable SmartReflex bit as that's needed for omaps to
  	 * to do anything over I2C4 for voltage scaling even if SmartReflex
  	 * is disabled. Without the SmartReflex bit omap sys_clkreq idle
  	 * signal will never trigger for retention idle.
a29aaf55c   Moiz Sonasath   mfd: Disable TWL4...
1160
  	 */
a29aaf55c   Moiz Sonasath   mfd: Disable TWL4...
1161
  	if (twl_class_is_4030()) {
ec1a07b34   Benoit Cousson   mfd: Replace twl-...
1162
  		u8 temp;
a29aaf55c   Moiz Sonasath   mfd: Disable TWL4...
1163
1164
  		twl_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1);
  		temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
ec1a07b34   Benoit Cousson   mfd: Replace twl-...
1165
  			I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
a29aaf55c   Moiz Sonasath   mfd: Disable TWL4...
1166
  		twl_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
a613b739b   Tony Lindgren   mfd: twl-core: Fi...
1167
1168
1169
1170
1171
1172
  
  		twl_i2c_read_u8(TWL_MODULE_PM_RECEIVER, &temp,
  				TWL4030_DCDC_GLOBAL_CFG);
  		temp |= SMARTREFLEX_ENABLE;
  		twl_i2c_write_u8(TWL_MODULE_PM_RECEIVER, temp,
  				 TWL4030_DCDC_GLOBAL_CFG);
a29aaf55c   Moiz Sonasath   mfd: Disable TWL4...
1173
  	}
80ec831e8   Tony Lindgren   mfd: twl-core: Fi...
1174
1175
1176
1177
1178
1179
  	if (node) {
  		if (pdata)
  			twl_auxdata_lookup[0].platform_data = pdata->gpio;
  		status = of_platform_populate(node, NULL, twl_auxdata_lookup,
  					      &client->dev);
  	} else {
9e1786202   Felipe Balbi   mfd: Make twl-cor...
1180
  		status = add_children(pdata, irq_base, id->driver_data);
80ec831e8   Tony Lindgren   mfd: twl-core: Fi...
1181
  	}
aeb5032b3   Benoit Cousson   mfd: twl-core: Ad...
1182

a603a7fa8   David Brownell   mfd: TWL4030 core...
1183
1184
  fail:
  	if (status < 0)
fc7b92fca   Balaji T K   mfd: Rename all t...
1185
  		twl_remove(client);
defa6be1c   Tony Lindgren   mfd: Fix compile ...
1186
1187
1188
  free:
  	if (status < 0)
  		platform_device_unregister(pdev);
ec1a07b34   Benoit Cousson   mfd: Replace twl-...
1189

a603a7fa8   David Brownell   mfd: TWL4030 core...
1190
1191
  	return status;
  }
fc7b92fca   Balaji T K   mfd: Rename all t...
1192
  static const struct i2c_device_id twl_ids[] = {
dad759ff8   David Brownell   mfd: twl4030: cre...
1193
1194
  	{ "twl4030", TWL4030_VAUX2 },	/* "Triton 2" */
  	{ "twl5030", 0 },		/* T2 updated */
1920a61e2   Ilkka Koskinen   mfd: Initial supp...
1195
  	{ "twl5031", TWL5031 },		/* TWL5030 updated */
dad759ff8   David Brownell   mfd: twl4030: cre...
1196
1197
1198
  	{ "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...
1199
1200
  	{ "tps65921", TPS_SUBSET },	/* fewer LDOs; no codec, no LED
  					   and vibrator. Charger in USB module*/
e8deb28ca   Balaji T K   mfd: Add support ...
1201
  	{ "twl6030", TWL6030_CLASS },	/* "Phoenix power chip" */
89ce43fbb   Graeme Gregory   mfd: twl-core: Ch...
1202
  	{ "twl6032", TWL6030_CLASS | TWL6032_SUBCLASS }, /* "Phoenix lite" */
a603a7fa8   David Brownell   mfd: TWL4030 core...
1203
1204
  	{ /* end of list */ },
  };
fc7b92fca   Balaji T K   mfd: Rename all t...
1205
  MODULE_DEVICE_TABLE(i2c, twl_ids);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1206
1207
  
  /* One Client Driver , 4 Clients */
fc7b92fca   Balaji T K   mfd: Rename all t...
1208
  static struct i2c_driver twl_driver = {
a603a7fa8   David Brownell   mfd: TWL4030 core...
1209
  	.driver.name	= DRIVER_NAME,
fc7b92fca   Balaji T K   mfd: Rename all t...
1210
1211
1212
  	.id_table	= twl_ids,
  	.probe		= twl_probe,
  	.remove		= twl_remove,
a603a7fa8   David Brownell   mfd: TWL4030 core...
1213
  };
032fa16d4   Grygorii Strashko   mfd: twl-core: Co...
1214
  module_i2c_driver(twl_driver);
a603a7fa8   David Brownell   mfd: TWL4030 core...
1215
1216
  
  MODULE_AUTHOR("Texas Instruments, Inc.");
fc7b92fca   Balaji T K   mfd: Rename all t...
1217
  MODULE_DESCRIPTION("I2C Core interface for TWL");
a603a7fa8   David Brownell   mfd: TWL4030 core...
1218
  MODULE_LICENSE("GPL");