Blame view

drivers/mfd/ab8500-core.c 23 KB
62579266c   Rabin Vincent   mfd: New AB8500 d...
1
2
3
4
5
6
  /*
   * Copyright (C) ST-Ericsson SA 2010
   *
   * License Terms: GNU General Public License v2
   * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
   * Author: Rabin Vincent <rabin.vincent@stericsson.com>
adceed626   Mattias Wallin   mfd: ab8500 chip ...
7
   * Author: Mattias Wallin <mattias.wallin@stericsson.com>
62579266c   Rabin Vincent   mfd: New AB8500 d...
8
9
10
11
12
13
14
15
16
17
18
   */
  
  #include <linux/kernel.h>
  #include <linux/slab.h>
  #include <linux/init.h>
  #include <linux/irq.h>
  #include <linux/delay.h>
  #include <linux/interrupt.h>
  #include <linux/module.h>
  #include <linux/platform_device.h>
  #include <linux/mfd/core.h>
47c169750   Mattias Wallin   mfd: Align ab8500...
19
  #include <linux/mfd/abx500.h>
ee66e653c   Linus Walleij   mfd: Unify abx500...
20
  #include <linux/mfd/abx500/ab8500.h>
549931f99   Sundar R Iyer   ab8500-mfd: add r...
21
  #include <linux/regulator/ab8500.h>
62579266c   Rabin Vincent   mfd: New AB8500 d...
22
23
24
25
26
  
  /*
   * Interrupt register offsets
   * Bank : 0x0E
   */
47c169750   Mattias Wallin   mfd: Align ab8500...
27
28
29
30
31
32
33
34
35
36
37
38
39
40
  #define AB8500_IT_SOURCE1_REG		0x00
  #define AB8500_IT_SOURCE2_REG		0x01
  #define AB8500_IT_SOURCE3_REG		0x02
  #define AB8500_IT_SOURCE4_REG		0x03
  #define AB8500_IT_SOURCE5_REG		0x04
  #define AB8500_IT_SOURCE6_REG		0x05
  #define AB8500_IT_SOURCE7_REG		0x06
  #define AB8500_IT_SOURCE8_REG		0x07
  #define AB8500_IT_SOURCE19_REG		0x12
  #define AB8500_IT_SOURCE20_REG		0x13
  #define AB8500_IT_SOURCE21_REG		0x14
  #define AB8500_IT_SOURCE22_REG		0x15
  #define AB8500_IT_SOURCE23_REG		0x16
  #define AB8500_IT_SOURCE24_REG		0x17
62579266c   Rabin Vincent   mfd: New AB8500 d...
41
42
43
44
  
  /*
   * latch registers
   */
47c169750   Mattias Wallin   mfd: Align ab8500...
45
46
47
48
49
50
51
52
53
54
  #define AB8500_IT_LATCH1_REG		0x20
  #define AB8500_IT_LATCH2_REG		0x21
  #define AB8500_IT_LATCH3_REG		0x22
  #define AB8500_IT_LATCH4_REG		0x23
  #define AB8500_IT_LATCH5_REG		0x24
  #define AB8500_IT_LATCH6_REG		0x25
  #define AB8500_IT_LATCH7_REG		0x26
  #define AB8500_IT_LATCH8_REG		0x27
  #define AB8500_IT_LATCH9_REG		0x28
  #define AB8500_IT_LATCH10_REG		0x29
92d50a413   Mattias Wallin   mfd: ab8500-core ...
55
  #define AB8500_IT_LATCH12_REG		0x2B
47c169750   Mattias Wallin   mfd: Align ab8500...
56
57
58
59
60
61
  #define AB8500_IT_LATCH19_REG		0x32
  #define AB8500_IT_LATCH20_REG		0x33
  #define AB8500_IT_LATCH21_REG		0x34
  #define AB8500_IT_LATCH22_REG		0x35
  #define AB8500_IT_LATCH23_REG		0x36
  #define AB8500_IT_LATCH24_REG		0x37
62579266c   Rabin Vincent   mfd: New AB8500 d...
62
63
64
65
  
  /*
   * mask registers
   */
47c169750   Mattias Wallin   mfd: Align ab8500...
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  #define AB8500_IT_MASK1_REG		0x40
  #define AB8500_IT_MASK2_REG		0x41
  #define AB8500_IT_MASK3_REG		0x42
  #define AB8500_IT_MASK4_REG		0x43
  #define AB8500_IT_MASK5_REG		0x44
  #define AB8500_IT_MASK6_REG		0x45
  #define AB8500_IT_MASK7_REG		0x46
  #define AB8500_IT_MASK8_REG		0x47
  #define AB8500_IT_MASK9_REG		0x48
  #define AB8500_IT_MASK10_REG		0x49
  #define AB8500_IT_MASK11_REG		0x4A
  #define AB8500_IT_MASK12_REG		0x4B
  #define AB8500_IT_MASK13_REG		0x4C
  #define AB8500_IT_MASK14_REG		0x4D
  #define AB8500_IT_MASK15_REG		0x4E
  #define AB8500_IT_MASK16_REG		0x4F
  #define AB8500_IT_MASK17_REG		0x50
  #define AB8500_IT_MASK18_REG		0x51
  #define AB8500_IT_MASK19_REG		0x52
  #define AB8500_IT_MASK20_REG		0x53
  #define AB8500_IT_MASK21_REG		0x54
  #define AB8500_IT_MASK22_REG		0x55
  #define AB8500_IT_MASK23_REG		0x56
  #define AB8500_IT_MASK24_REG		0x57
  
  #define AB8500_REV_REG			0x80
e5c238c3f   Mattias Wallin   mfd: ab8500-core ...
92
  #define AB8500_SWITCH_OFF_STATUS	0x00
62579266c   Rabin Vincent   mfd: New AB8500 d...
93

b4a310373   Andrew Lynn   mfd: Expose TurnO...
94
  #define AB8500_TURN_ON_STATUS		0x00
62579266c   Rabin Vincent   mfd: New AB8500 d...
95
96
97
98
99
100
101
102
  /*
   * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
   * numbers are indexed into this array with (num / 8).
   *
   * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
   * offset 0.
   */
  static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
92d50a413   Mattias Wallin   mfd: ab8500-core ...
103
  	0, 1, 2, 3, 4, 6, 7, 8, 9, 11, 18, 19, 20, 21,
62579266c   Rabin Vincent   mfd: New AB8500 d...
104
  };
47c169750   Mattias Wallin   mfd: Align ab8500...
105
106
  static int ab8500_get_chip_id(struct device *dev)
  {
6bce7bf1a   Mattias Wallin   mfd: ab8500-core ...
107
108
109
110
111
112
  	struct ab8500 *ab8500;
  
  	if (!dev)
  		return -EINVAL;
  	ab8500 = dev_get_drvdata(dev->parent);
  	return ab8500 ? (int)ab8500->chip_id : -EINVAL;
47c169750   Mattias Wallin   mfd: Align ab8500...
113
114
115
116
  }
  
  static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
  	u8 reg, u8 data)
62579266c   Rabin Vincent   mfd: New AB8500 d...
117
118
  {
  	int ret;
47c169750   Mattias Wallin   mfd: Align ab8500...
119
120
121
122
123
  	/*
  	 * Put the u8 bank and u8 register together into a an u16.
  	 * The bank on higher 8 bits and register in lower 8 bits.
  	 * */
  	u16 addr = ((u16)bank) << 8 | reg;
62579266c   Rabin Vincent   mfd: New AB8500 d...
124
125
126
  
  	dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x
  ", addr, data);
47c169750   Mattias Wallin   mfd: Align ab8500...
127
128
129
  	ret = mutex_lock_interruptible(&ab8500->lock);
  	if (ret)
  		return ret;
62579266c   Rabin Vincent   mfd: New AB8500 d...
130
131
132
133
134
  	ret = ab8500->write(ab8500, addr, data);
  	if (ret < 0)
  		dev_err(ab8500->dev, "failed to write reg %#x: %d
  ",
  			addr, ret);
47c169750   Mattias Wallin   mfd: Align ab8500...
135
  	mutex_unlock(&ab8500->lock);
62579266c   Rabin Vincent   mfd: New AB8500 d...
136
137
138
  
  	return ret;
  }
47c169750   Mattias Wallin   mfd: Align ab8500...
139
140
  static int ab8500_set_register(struct device *dev, u8 bank,
  	u8 reg, u8 value)
62579266c   Rabin Vincent   mfd: New AB8500 d...
141
  {
47c169750   Mattias Wallin   mfd: Align ab8500...
142
  	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
62579266c   Rabin Vincent   mfd: New AB8500 d...
143

47c169750   Mattias Wallin   mfd: Align ab8500...
144
  	return set_register_interruptible(ab8500, bank, reg, value);
62579266c   Rabin Vincent   mfd: New AB8500 d...
145
  }
62579266c   Rabin Vincent   mfd: New AB8500 d...
146

47c169750   Mattias Wallin   mfd: Align ab8500...
147
148
  static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
  	u8 reg, u8 *value)
62579266c   Rabin Vincent   mfd: New AB8500 d...
149
150
  {
  	int ret;
47c169750   Mattias Wallin   mfd: Align ab8500...
151
152
153
154
155
156
157
  	/* put the u8 bank and u8 reg together into a an u16.
  	 * bank on higher 8 bits and reg in lower */
  	u16 addr = ((u16)bank) << 8 | reg;
  
  	ret = mutex_lock_interruptible(&ab8500->lock);
  	if (ret)
  		return ret;
62579266c   Rabin Vincent   mfd: New AB8500 d...
158
159
160
161
162
163
  
  	ret = ab8500->read(ab8500, addr);
  	if (ret < 0)
  		dev_err(ab8500->dev, "failed to read reg %#x: %d
  ",
  			addr, ret);
47c169750   Mattias Wallin   mfd: Align ab8500...
164
165
  	else
  		*value = ret;
62579266c   Rabin Vincent   mfd: New AB8500 d...
166

47c169750   Mattias Wallin   mfd: Align ab8500...
167
  	mutex_unlock(&ab8500->lock);
62579266c   Rabin Vincent   mfd: New AB8500 d...
168
169
170
171
172
  	dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x
  ", addr, ret);
  
  	return ret;
  }
47c169750   Mattias Wallin   mfd: Align ab8500...
173
174
  static int ab8500_get_register(struct device *dev, u8 bank,
  	u8 reg, u8 *value)
62579266c   Rabin Vincent   mfd: New AB8500 d...
175
  {
47c169750   Mattias Wallin   mfd: Align ab8500...
176
  	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
62579266c   Rabin Vincent   mfd: New AB8500 d...
177

47c169750   Mattias Wallin   mfd: Align ab8500...
178
  	return get_register_interruptible(ab8500, bank, reg, value);
62579266c   Rabin Vincent   mfd: New AB8500 d...
179
  }
47c169750   Mattias Wallin   mfd: Align ab8500...
180
181
182
  
  static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
  	u8 reg, u8 bitmask, u8 bitvalues)
62579266c   Rabin Vincent   mfd: New AB8500 d...
183
184
  {
  	int ret;
47c169750   Mattias Wallin   mfd: Align ab8500...
185
186
187
188
  	u8 data;
  	/* put the u8 bank and u8 reg together into a an u16.
  	 * bank on higher 8 bits and reg in lower */
  	u16 addr = ((u16)bank) << 8 | reg;
62579266c   Rabin Vincent   mfd: New AB8500 d...
189

47c169750   Mattias Wallin   mfd: Align ab8500...
190
191
192
  	ret = mutex_lock_interruptible(&ab8500->lock);
  	if (ret)
  		return ret;
62579266c   Rabin Vincent   mfd: New AB8500 d...
193

47c169750   Mattias Wallin   mfd: Align ab8500...
194
195
196
197
198
  	ret = ab8500->read(ab8500, addr);
  	if (ret < 0) {
  		dev_err(ab8500->dev, "failed to read reg %#x: %d
  ",
  			addr, ret);
62579266c   Rabin Vincent   mfd: New AB8500 d...
199
  		goto out;
47c169750   Mattias Wallin   mfd: Align ab8500...
200
  	}
62579266c   Rabin Vincent   mfd: New AB8500 d...
201

47c169750   Mattias Wallin   mfd: Align ab8500...
202
203
  	data = (u8)ret;
  	data = (~bitmask & data) | (bitmask & bitvalues);
62579266c   Rabin Vincent   mfd: New AB8500 d...
204

47c169750   Mattias Wallin   mfd: Align ab8500...
205
206
207
208
209
  	ret = ab8500->write(ab8500, addr, data);
  	if (ret < 0)
  		dev_err(ab8500->dev, "failed to write reg %#x: %d
  ",
  			addr, ret);
62579266c   Rabin Vincent   mfd: New AB8500 d...
210

47c169750   Mattias Wallin   mfd: Align ab8500...
211
212
  	dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x
  ", addr, data);
62579266c   Rabin Vincent   mfd: New AB8500 d...
213
214
215
216
  out:
  	mutex_unlock(&ab8500->lock);
  	return ret;
  }
47c169750   Mattias Wallin   mfd: Align ab8500...
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
  
  static int ab8500_mask_and_set_register(struct device *dev,
  	u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
  {
  	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
  
  	return mask_and_set_register_interruptible(ab8500, bank, reg,
  		bitmask, bitvalues);
  
  }
  
  static struct abx500_ops ab8500_ops = {
  	.get_chip_id = ab8500_get_chip_id,
  	.get_register = ab8500_get_register,
  	.set_register = ab8500_set_register,
  	.get_register_page = NULL,
  	.set_register_page = NULL,
  	.mask_and_set_register = ab8500_mask_and_set_register,
  	.event_registers_startup_state_get = NULL,
  	.startup_irq_enabled = NULL,
  };
62579266c   Rabin Vincent   mfd: New AB8500 d...
238

9505a0a0a   Mark Brown   mfd: Convert AB85...
239
  static void ab8500_irq_lock(struct irq_data *data)
62579266c   Rabin Vincent   mfd: New AB8500 d...
240
  {
9505a0a0a   Mark Brown   mfd: Convert AB85...
241
  	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
62579266c   Rabin Vincent   mfd: New AB8500 d...
242
243
244
  
  	mutex_lock(&ab8500->irq_lock);
  }
9505a0a0a   Mark Brown   mfd: Convert AB85...
245
  static void ab8500_irq_sync_unlock(struct irq_data *data)
62579266c   Rabin Vincent   mfd: New AB8500 d...
246
  {
9505a0a0a   Mark Brown   mfd: Convert AB85...
247
  	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
62579266c   Rabin Vincent   mfd: New AB8500 d...
248
249
250
251
252
253
254
255
256
  	int i;
  
  	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
  		u8 old = ab8500->oldmask[i];
  		u8 new = ab8500->mask[i];
  		int reg;
  
  		if (new == old)
  			continue;
863dde5bf   Linus Walleij   mfd: Provide ab85...
257
258
259
  		/* Interrupt register 12 doesn't exist prior to version 2.0 */
  		if (ab8500_irq_regoffset[i] == 11 &&
  			ab8500->chip_id < AB8500_CUT2P0)
92d50a413   Mattias Wallin   mfd: ab8500-core ...
260
  			continue;
62579266c   Rabin Vincent   mfd: New AB8500 d...
261
262
263
  		ab8500->oldmask[i] = new;
  
  		reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
47c169750   Mattias Wallin   mfd: Align ab8500...
264
  		set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
62579266c   Rabin Vincent   mfd: New AB8500 d...
265
266
267
268
  	}
  
  	mutex_unlock(&ab8500->irq_lock);
  }
9505a0a0a   Mark Brown   mfd: Convert AB85...
269
  static void ab8500_irq_mask(struct irq_data *data)
62579266c   Rabin Vincent   mfd: New AB8500 d...
270
  {
9505a0a0a   Mark Brown   mfd: Convert AB85...
271
272
  	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
  	int offset = data->irq - ab8500->irq_base;
62579266c   Rabin Vincent   mfd: New AB8500 d...
273
274
275
276
277
  	int index = offset / 8;
  	int mask = 1 << (offset % 8);
  
  	ab8500->mask[index] |= mask;
  }
9505a0a0a   Mark Brown   mfd: Convert AB85...
278
  static void ab8500_irq_unmask(struct irq_data *data)
62579266c   Rabin Vincent   mfd: New AB8500 d...
279
  {
9505a0a0a   Mark Brown   mfd: Convert AB85...
280
281
  	struct ab8500 *ab8500 = irq_data_get_irq_chip_data(data);
  	int offset = data->irq - ab8500->irq_base;
62579266c   Rabin Vincent   mfd: New AB8500 d...
282
283
284
285
286
287
288
289
  	int index = offset / 8;
  	int mask = 1 << (offset % 8);
  
  	ab8500->mask[index] &= ~mask;
  }
  
  static struct irq_chip ab8500_irq_chip = {
  	.name			= "ab8500",
9505a0a0a   Mark Brown   mfd: Convert AB85...
290
291
292
  	.irq_bus_lock		= ab8500_irq_lock,
  	.irq_bus_sync_unlock	= ab8500_irq_sync_unlock,
  	.irq_mask		= ab8500_irq_mask,
e6f9306e2   Virupax Sadashivpetimath   mfd: Add ab8500 i...
293
  	.irq_disable		= ab8500_irq_mask,
9505a0a0a   Mark Brown   mfd: Convert AB85...
294
  	.irq_unmask		= ab8500_irq_unmask,
62579266c   Rabin Vincent   mfd: New AB8500 d...
295
296
297
298
299
300
301
302
303
304
305
306
307
  };
  
  static irqreturn_t ab8500_irq(int irq, void *dev)
  {
  	struct ab8500 *ab8500 = dev;
  	int i;
  
  	dev_vdbg(ab8500->dev, "interrupt
  ");
  
  	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
  		int regoffset = ab8500_irq_regoffset[i];
  		int status;
47c169750   Mattias Wallin   mfd: Align ab8500...
308
  		u8 value;
62579266c   Rabin Vincent   mfd: New AB8500 d...
309

863dde5bf   Linus Walleij   mfd: Provide ab85...
310
311
  		/* Interrupt register 12 doesn't exist prior to version 2.0 */
  		if (regoffset == 11 && ab8500->chip_id < AB8500_CUT2P0)
92d50a413   Mattias Wallin   mfd: ab8500-core ...
312
  			continue;
47c169750   Mattias Wallin   mfd: Align ab8500...
313
314
315
  		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
  			AB8500_IT_LATCH1_REG + regoffset, &value);
  		if (status < 0 || value == 0)
62579266c   Rabin Vincent   mfd: New AB8500 d...
316
317
318
  			continue;
  
  		do {
88aec4f7b   Mattias Wallin   mfd: Fix ab8500-c...
319
  			int bit = __ffs(value);
62579266c   Rabin Vincent   mfd: New AB8500 d...
320
321
322
  			int line = i * 8 + bit;
  
  			handle_nested_irq(ab8500->irq_base + line);
47c169750   Mattias Wallin   mfd: Align ab8500...
323
324
  			value &= ~(1 << bit);
  		} while (value);
62579266c   Rabin Vincent   mfd: New AB8500 d...
325
326
327
328
329
330
331
332
333
334
335
  	}
  
  	return IRQ_HANDLED;
  }
  
  static int ab8500_irq_init(struct ab8500 *ab8500)
  {
  	int base = ab8500->irq_base;
  	int irq;
  
  	for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
d5bb12216   Thomas Gleixner   mfd: Cleanup irq ...
336
337
  		irq_set_chip_data(irq, ab8500);
  		irq_set_chip_and_handler(irq, &ab8500_irq_chip,
62579266c   Rabin Vincent   mfd: New AB8500 d...
338
  					 handle_simple_irq);
d5bb12216   Thomas Gleixner   mfd: Cleanup irq ...
339
  		irq_set_nested_thread(irq, 1);
62579266c   Rabin Vincent   mfd: New AB8500 d...
340
341
342
  #ifdef CONFIG_ARM
  		set_irq_flags(irq, IRQF_VALID);
  #else
d5bb12216   Thomas Gleixner   mfd: Cleanup irq ...
343
  		irq_set_noprobe(irq);
62579266c   Rabin Vincent   mfd: New AB8500 d...
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
  #endif
  	}
  
  	return 0;
  }
  
  static void ab8500_irq_remove(struct ab8500 *ab8500)
  {
  	int base = ab8500->irq_base;
  	int irq;
  
  	for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
  #ifdef CONFIG_ARM
  		set_irq_flags(irq, 0);
  #endif
d5bb12216   Thomas Gleixner   mfd: Cleanup irq ...
359
360
  		irq_set_chip_and_handler(irq, NULL, NULL);
  		irq_set_chip_data(irq, NULL);
62579266c   Rabin Vincent   mfd: New AB8500 d...
361
362
  	}
  }
5cef8df5e   Robert Rosengren   mfd: ab8500-core ...
363
  static struct resource __devinitdata ab8500_gpio_resources[] = {
0cb3fcd72   Bibek Basu   gpio: driver for ...
364
365
366
367
368
369
370
  	{
  		.name	= "GPIO_INT6",
  		.start	= AB8500_INT_GPIO6R,
  		.end	= AB8500_INT_GPIO41F,
  		.flags	= IORESOURCE_IRQ,
  	}
  };
5cef8df5e   Robert Rosengren   mfd: ab8500-core ...
371
  static struct resource __devinitdata ab8500_gpadc_resources[] = {
62579266c   Rabin Vincent   mfd: New AB8500 d...
372
373
374
375
376
377
378
379
380
381
382
383
384
  	{
  		.name	= "HW_CONV_END",
  		.start	= AB8500_INT_GP_HW_ADC_CONV_END,
  		.end	= AB8500_INT_GP_HW_ADC_CONV_END,
  		.flags	= IORESOURCE_IRQ,
  	},
  	{
  		.name	= "SW_CONV_END",
  		.start	= AB8500_INT_GP_SW_ADC_CONV_END,
  		.end	= AB8500_INT_GP_SW_ADC_CONV_END,
  		.flags	= IORESOURCE_IRQ,
  	},
  };
5cef8df5e   Robert Rosengren   mfd: ab8500-core ...
385
  static struct resource __devinitdata ab8500_rtc_resources[] = {
62579266c   Rabin Vincent   mfd: New AB8500 d...
386
387
388
389
390
391
392
393
394
395
396
397
398
  	{
  		.name	= "60S",
  		.start	= AB8500_INT_RTC_60S,
  		.end	= AB8500_INT_RTC_60S,
  		.flags	= IORESOURCE_IRQ,
  	},
  	{
  		.name	= "ALARM",
  		.start	= AB8500_INT_RTC_ALARM,
  		.end	= AB8500_INT_RTC_ALARM,
  		.flags	= IORESOURCE_IRQ,
  	},
  };
5cef8df5e   Robert Rosengren   mfd: ab8500-core ...
399
  static struct resource __devinitdata ab8500_poweronkey_db_resources[] = {
776865179   Sundar R Iyer   Input: add suppor...
400
401
402
403
404
405
406
407
408
409
410
411
412
  	{
  		.name	= "ONKEY_DBF",
  		.start	= AB8500_INT_PON_KEY1DB_F,
  		.end	= AB8500_INT_PON_KEY1DB_F,
  		.flags	= IORESOURCE_IRQ,
  	},
  	{
  		.name	= "ONKEY_DBR",
  		.start	= AB8500_INT_PON_KEY1DB_R,
  		.end	= AB8500_INT_PON_KEY1DB_R,
  		.flags	= IORESOURCE_IRQ,
  	},
  };
6af75ecd5   Linus Walleij   mfd: Update ab850...
413
  static struct resource __devinitdata ab8500_av_acc_detect_resources[] = {
e098aded7   Mattias Wallin   mfd: ab8500-core ...
414
  	{
6af75ecd5   Linus Walleij   mfd: Update ab850...
415
416
417
418
  	       .name = "ACC_DETECT_1DB_F",
  	       .start = AB8500_INT_ACC_DETECT_1DB_F,
  	       .end = AB8500_INT_ACC_DETECT_1DB_F,
  	       .flags = IORESOURCE_IRQ,
e098aded7   Mattias Wallin   mfd: ab8500-core ...
419
420
  	},
  	{
6af75ecd5   Linus Walleij   mfd: Update ab850...
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
  	       .name = "ACC_DETECT_1DB_R",
  	       .start = AB8500_INT_ACC_DETECT_1DB_R,
  	       .end = AB8500_INT_ACC_DETECT_1DB_R,
  	       .flags = IORESOURCE_IRQ,
  	},
  	{
  	       .name = "ACC_DETECT_21DB_F",
  	       .start = AB8500_INT_ACC_DETECT_21DB_F,
  	       .end = AB8500_INT_ACC_DETECT_21DB_F,
  	       .flags = IORESOURCE_IRQ,
  	},
  	{
  	       .name = "ACC_DETECT_21DB_R",
  	       .start = AB8500_INT_ACC_DETECT_21DB_R,
  	       .end = AB8500_INT_ACC_DETECT_21DB_R,
  	       .flags = IORESOURCE_IRQ,
  	},
  	{
  	       .name = "ACC_DETECT_22DB_F",
  	       .start = AB8500_INT_ACC_DETECT_22DB_F,
  	       .end = AB8500_INT_ACC_DETECT_22DB_F,
  	       .flags = IORESOURCE_IRQ,
e098aded7   Mattias Wallin   mfd: ab8500-core ...
443
444
  	},
  	{
6af75ecd5   Linus Walleij   mfd: Update ab850...
445
446
447
448
449
450
451
452
453
  	       .name = "ACC_DETECT_22DB_R",
  	       .start = AB8500_INT_ACC_DETECT_22DB_R,
  	       .end = AB8500_INT_ACC_DETECT_22DB_R,
  	       .flags = IORESOURCE_IRQ,
  	},
  };
  
  static struct resource __devinitdata ab8500_charger_resources[] = {
  	{
e098aded7   Mattias Wallin   mfd: ab8500-core ...
454
455
456
457
458
459
460
461
462
463
464
465
  		.name = "MAIN_CH_UNPLUG_DET",
  		.start = AB8500_INT_MAIN_CH_UNPLUG_DET,
  		.end = AB8500_INT_MAIN_CH_UNPLUG_DET,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
  		.name = "MAIN_CHARGE_PLUG_DET",
  		.start = AB8500_INT_MAIN_CH_PLUG_DET,
  		.end = AB8500_INT_MAIN_CH_PLUG_DET,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
e098aded7   Mattias Wallin   mfd: ab8500-core ...
466
467
468
469
470
471
  		.name = "VBUS_DET_R",
  		.start = AB8500_INT_VBUS_DET_R,
  		.end = AB8500_INT_VBUS_DET_R,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
6af75ecd5   Linus Walleij   mfd: Update ab850...
472
473
474
  		.name = "VBUS_DET_F",
  		.start = AB8500_INT_VBUS_DET_F,
  		.end = AB8500_INT_VBUS_DET_F,
e098aded7   Mattias Wallin   mfd: ab8500-core ...
475
476
477
  		.flags = IORESOURCE_IRQ,
  	},
  	{
6af75ecd5   Linus Walleij   mfd: Update ab850...
478
479
480
481
482
483
484
485
486
  		.name = "USB_LINK_STATUS",
  		.start = AB8500_INT_USB_LINK_STATUS,
  		.end = AB8500_INT_USB_LINK_STATUS,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
  		.name = "USB_CHARGE_DET_DONE",
  		.start = AB8500_INT_USB_CHG_DET_DONE,
  		.end = AB8500_INT_USB_CHG_DET_DONE,
e098aded7   Mattias Wallin   mfd: ab8500-core ...
487
488
489
490
491
492
493
494
495
  		.flags = IORESOURCE_IRQ,
  	},
  	{
  		.name = "VBUS_OVV",
  		.start = AB8500_INT_VBUS_OVV,
  		.end = AB8500_INT_VBUS_OVV,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
6af75ecd5   Linus Walleij   mfd: Update ab850...
496
497
498
  		.name = "USB_CH_TH_PROT_R",
  		.start = AB8500_INT_USB_CH_TH_PROT_R,
  		.end = AB8500_INT_USB_CH_TH_PROT_R,
e098aded7   Mattias Wallin   mfd: ab8500-core ...
499
500
501
  		.flags = IORESOURCE_IRQ,
  	},
  	{
6af75ecd5   Linus Walleij   mfd: Update ab850...
502
503
504
  		.name = "USB_CH_TH_PROT_F",
  		.start = AB8500_INT_USB_CH_TH_PROT_F,
  		.end = AB8500_INT_USB_CH_TH_PROT_F,
e098aded7   Mattias Wallin   mfd: ab8500-core ...
505
506
507
  		.flags = IORESOURCE_IRQ,
  	},
  	{
6af75ecd5   Linus Walleij   mfd: Update ab850...
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
  		.name = "MAIN_EXT_CH_NOT_OK",
  		.start = AB8500_INT_MAIN_EXT_CH_NOT_OK,
  		.end = AB8500_INT_MAIN_EXT_CH_NOT_OK,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
  		.name = "MAIN_CH_TH_PROT_R",
  		.start = AB8500_INT_MAIN_CH_TH_PROT_R,
  		.end = AB8500_INT_MAIN_CH_TH_PROT_R,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
  		.name = "MAIN_CH_TH_PROT_F",
  		.start = AB8500_INT_MAIN_CH_TH_PROT_F,
  		.end = AB8500_INT_MAIN_CH_TH_PROT_F,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
  		.name = "USB_CHARGER_NOT_OKR",
  		.start = AB8500_INT_USB_CHARGER_NOT_OK,
  		.end = AB8500_INT_USB_CHARGER_NOT_OK,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
  		.name = "USB_CHARGER_NOT_OKF",
  		.start = AB8500_INT_USB_CHARGER_NOT_OKF,
  		.end = AB8500_INT_USB_CHARGER_NOT_OKF,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
  		.name = "CH_WD_EXP",
  		.start = AB8500_INT_CH_WD_EXP,
  		.end = AB8500_INT_CH_WD_EXP,
  		.flags = IORESOURCE_IRQ,
  	},
  };
  
  static struct resource __devinitdata ab8500_btemp_resources[] = {
  	{
  		.name = "BAT_CTRL_INDB",
  		.start = AB8500_INT_BAT_CTRL_INDB,
  		.end = AB8500_INT_BAT_CTRL_INDB,
e098aded7   Mattias Wallin   mfd: ab8500-core ...
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
  		.flags = IORESOURCE_IRQ,
  	},
  	{
  		.name = "BTEMP_LOW",
  		.start = AB8500_INT_BTEMP_LOW,
  		.end = AB8500_INT_BTEMP_LOW,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
  		.name = "BTEMP_HIGH",
  		.start = AB8500_INT_BTEMP_HIGH,
  		.end = AB8500_INT_BTEMP_HIGH,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
6af75ecd5   Linus Walleij   mfd: Update ab850...
565
566
567
  		.name = "BTEMP_LOW_MEDIUM",
  		.start = AB8500_INT_BTEMP_LOW_MEDIUM,
  		.end = AB8500_INT_BTEMP_LOW_MEDIUM,
e098aded7   Mattias Wallin   mfd: ab8500-core ...
568
569
570
  		.flags = IORESOURCE_IRQ,
  	},
  	{
6af75ecd5   Linus Walleij   mfd: Update ab850...
571
572
573
  		.name = "BTEMP_MEDIUM_HIGH",
  		.start = AB8500_INT_BTEMP_MEDIUM_HIGH,
  		.end = AB8500_INT_BTEMP_MEDIUM_HIGH,
e098aded7   Mattias Wallin   mfd: ab8500-core ...
574
575
  		.flags = IORESOURCE_IRQ,
  	},
6af75ecd5   Linus Walleij   mfd: Update ab850...
576
577
578
  };
  
  static struct resource __devinitdata ab8500_fg_resources[] = {
e098aded7   Mattias Wallin   mfd: ab8500-core ...
579
  	{
6af75ecd5   Linus Walleij   mfd: Update ab850...
580
581
582
  		.name = "NCONV_ACCU",
  		.start = AB8500_INT_CCN_CONV_ACC,
  		.end = AB8500_INT_CCN_CONV_ACC,
e098aded7   Mattias Wallin   mfd: ab8500-core ...
583
584
585
  		.flags = IORESOURCE_IRQ,
  	},
  	{
6af75ecd5   Linus Walleij   mfd: Update ab850...
586
587
588
  		.name = "BATT_OVV",
  		.start = AB8500_INT_BATT_OVV,
  		.end = AB8500_INT_BATT_OVV,
e098aded7   Mattias Wallin   mfd: ab8500-core ...
589
590
591
  		.flags = IORESOURCE_IRQ,
  	},
  	{
6af75ecd5   Linus Walleij   mfd: Update ab850...
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
  		.name = "LOW_BAT_F",
  		.start = AB8500_INT_LOW_BAT_F,
  		.end = AB8500_INT_LOW_BAT_F,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
  		.name = "LOW_BAT_R",
  		.start = AB8500_INT_LOW_BAT_R,
  		.end = AB8500_INT_LOW_BAT_R,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
  		.name = "CC_INT_CALIB",
  		.start = AB8500_INT_CC_INT_CALIB,
  		.end = AB8500_INT_CC_INT_CALIB,
e098aded7   Mattias Wallin   mfd: ab8500-core ...
607
608
609
  		.flags = IORESOURCE_IRQ,
  	},
  };
6af75ecd5   Linus Walleij   mfd: Update ab850...
610
  static struct resource __devinitdata ab8500_chargalg_resources[] = {};
df7206477   Axel Lin   mfd: add #ifdef C...
611
  #ifdef CONFIG_DEBUG_FS
5cef8df5e   Robert Rosengren   mfd: ab8500-core ...
612
  static struct resource __devinitdata ab8500_debug_resources[] = {
e098aded7   Mattias Wallin   mfd: ab8500-core ...
613
614
615
616
617
618
619
620
621
622
623
624
625
  	{
  		.name	= "IRQ_FIRST",
  		.start	= AB8500_INT_MAIN_EXT_CH_NOT_OK,
  		.end	= AB8500_INT_MAIN_EXT_CH_NOT_OK,
  		.flags	= IORESOURCE_IRQ,
  	},
  	{
  		.name	= "IRQ_LAST",
  		.start	= AB8500_INT_USB_CHARGER_NOT_OKF,
  		.end	= AB8500_INT_USB_CHARGER_NOT_OKF,
  		.flags	= IORESOURCE_IRQ,
  	},
  };
df7206477   Axel Lin   mfd: add #ifdef C...
626
  #endif
e098aded7   Mattias Wallin   mfd: ab8500-core ...
627

5cef8df5e   Robert Rosengren   mfd: ab8500-core ...
628
  static struct resource __devinitdata ab8500_usb_resources[] = {
e098aded7   Mattias Wallin   mfd: ab8500-core ...
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
  	{
  		.name = "ID_WAKEUP_R",
  		.start = AB8500_INT_ID_WAKEUP_R,
  		.end = AB8500_INT_ID_WAKEUP_R,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
  		.name = "ID_WAKEUP_F",
  		.start = AB8500_INT_ID_WAKEUP_F,
  		.end = AB8500_INT_ID_WAKEUP_F,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
  		.name = "VBUS_DET_F",
  		.start = AB8500_INT_VBUS_DET_F,
  		.end = AB8500_INT_VBUS_DET_F,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
  		.name = "VBUS_DET_R",
  		.start = AB8500_INT_VBUS_DET_R,
  		.end = AB8500_INT_VBUS_DET_R,
  		.flags = IORESOURCE_IRQ,
  	},
92d50a413   Mattias Wallin   mfd: ab8500-core ...
653
654
655
656
657
658
  	{
  		.name = "USB_LINK_STATUS",
  		.start = AB8500_INT_USB_LINK_STATUS,
  		.end = AB8500_INT_USB_LINK_STATUS,
  		.flags = IORESOURCE_IRQ,
  	},
6af75ecd5   Linus Walleij   mfd: Update ab850...
659
660
661
662
663
664
665
666
667
668
669
670
  	{
  		.name = "USB_ADP_PROBE_PLUG",
  		.start = AB8500_INT_ADP_PROBE_PLUG,
  		.end = AB8500_INT_ADP_PROBE_PLUG,
  		.flags = IORESOURCE_IRQ,
  	},
  	{
  		.name = "USB_ADP_PROBE_UNPLUG",
  		.start = AB8500_INT_ADP_PROBE_UNPLUG,
  		.end = AB8500_INT_ADP_PROBE_UNPLUG,
  		.flags = IORESOURCE_IRQ,
  	},
e098aded7   Mattias Wallin   mfd: ab8500-core ...
671
  };
5cef8df5e   Robert Rosengren   mfd: ab8500-core ...
672
  static struct resource __devinitdata ab8500_temp_resources[] = {
e098aded7   Mattias Wallin   mfd: ab8500-core ...
673
674
675
676
677
678
679
  	{
  		.name  = "AB8500_TEMP_WARM",
  		.start = AB8500_INT_TEMP_WARM,
  		.end   = AB8500_INT_TEMP_WARM,
  		.flags = IORESOURCE_IRQ,
  	},
  };
5cef8df5e   Robert Rosengren   mfd: ab8500-core ...
680
  static struct mfd_cell __devinitdata ab8500_devs[] = {
5814fc35e   Mattias Wallin   mfd: AB8500 debugfs
681
682
683
  #ifdef CONFIG_DEBUG_FS
  	{
  		.name = "ab8500-debug",
e098aded7   Mattias Wallin   mfd: ab8500-core ...
684
685
  		.num_resources = ARRAY_SIZE(ab8500_debug_resources),
  		.resources = ab8500_debug_resources,
5814fc35e   Mattias Wallin   mfd: AB8500 debugfs
686
687
  	},
  #endif
62579266c   Rabin Vincent   mfd: New AB8500 d...
688
  	{
e098aded7   Mattias Wallin   mfd: ab8500-core ...
689
690
691
692
693
694
  		.name = "ab8500-sysctrl",
  	},
  	{
  		.name = "ab8500-regulator",
  	},
  	{
0cb3fcd72   Bibek Basu   gpio: driver for ...
695
696
697
698
699
  		.name = "ab8500-gpio",
  		.num_resources = ARRAY_SIZE(ab8500_gpio_resources),
  		.resources = ab8500_gpio_resources,
  	},
  	{
62579266c   Rabin Vincent   mfd: New AB8500 d...
700
701
702
703
704
705
706
707
708
  		.name = "ab8500-gpadc",
  		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
  		.resources = ab8500_gpadc_resources,
  	},
  	{
  		.name = "ab8500-rtc",
  		.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
  		.resources = ab8500_rtc_resources,
  	},
f0f05b1c7   Arun Murthy   misc: Add ab8500 ...
709
  	{
6af75ecd5   Linus Walleij   mfd: Update ab850...
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
  		.name = "ab8500-charger",
  		.num_resources = ARRAY_SIZE(ab8500_charger_resources),
  		.resources = ab8500_charger_resources,
  	},
  	{
  		.name = "ab8500-btemp",
  		.num_resources = ARRAY_SIZE(ab8500_btemp_resources),
  		.resources = ab8500_btemp_resources,
  	},
  	{
  		.name = "ab8500-fg",
  		.num_resources = ARRAY_SIZE(ab8500_fg_resources),
  		.resources = ab8500_fg_resources,
  	},
  	{
  		.name = "ab8500-chargalg",
  		.num_resources = ARRAY_SIZE(ab8500_chargalg_resources),
  		.resources = ab8500_chargalg_resources,
  	},
  	{
  		.name = "ab8500-acc-det",
  		.num_resources = ARRAY_SIZE(ab8500_av_acc_detect_resources),
  		.resources = ab8500_av_acc_detect_resources,
  	},
  	{
  		.name = "ab8500-codec",
e098aded7   Mattias Wallin   mfd: ab8500-core ...
736
  	},
e098aded7   Mattias Wallin   mfd: ab8500-core ...
737
738
739
740
741
742
743
744
745
746
747
  	{
  		.name = "ab8500-usb",
  		.num_resources = ARRAY_SIZE(ab8500_usb_resources),
  		.resources = ab8500_usb_resources,
  	},
  	{
  		.name = "ab8500-poweron-key",
  		.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
  		.resources = ab8500_poweronkey_db_resources,
  	},
  	{
f0f05b1c7   Arun Murthy   misc: Add ab8500 ...
748
749
750
751
752
753
754
755
756
757
758
  		.name = "ab8500-pwm",
  		.id = 1,
  	},
  	{
  		.name = "ab8500-pwm",
  		.id = 2,
  	},
  	{
  		.name = "ab8500-pwm",
  		.id = 3,
  	},
e098aded7   Mattias Wallin   mfd: ab8500-core ...
759
  	{ .name = "ab8500-leds", },
776865179   Sundar R Iyer   Input: add suppor...
760
  	{
e098aded7   Mattias Wallin   mfd: ab8500-core ...
761
762
763
764
765
766
  		.name = "ab8500-denc",
  	},
  	{
  		.name = "ab8500-temp",
  		.num_resources = ARRAY_SIZE(ab8500_temp_resources),
  		.resources = ab8500_temp_resources,
776865179   Sundar R Iyer   Input: add suppor...
767
  	},
62579266c   Rabin Vincent   mfd: New AB8500 d...
768
  };
cca69b67b   Mattias Wallin   mfd: Export ab850...
769
770
771
772
773
774
775
776
777
  static ssize_t show_chip_id(struct device *dev,
  				struct device_attribute *attr, char *buf)
  {
  	struct ab8500 *ab8500;
  
  	ab8500 = dev_get_drvdata(dev);
  	return sprintf(buf, "%#x
  ", ab8500 ? ab8500->chip_id : -EINVAL);
  }
e5c238c3f   Mattias Wallin   mfd: ab8500-core ...
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
  /*
   * ab8500 has switched off due to (SWITCH_OFF_STATUS):
   * 0x01 Swoff bit programming
   * 0x02 Thermal protection activation
   * 0x04 Vbat lower then BattOk falling threshold
   * 0x08 Watchdog expired
   * 0x10 Non presence of 32kHz clock
   * 0x20 Battery level lower than power on reset threshold
   * 0x40 Power on key 1 pressed longer than 10 seconds
   * 0x80 DB8500 thermal shutdown
   */
  static ssize_t show_switch_off_status(struct device *dev,
  				struct device_attribute *attr, char *buf)
  {
  	int ret;
  	u8 value;
  	struct ab8500 *ab8500;
  
  	ab8500 = dev_get_drvdata(dev);
  	ret = get_register_interruptible(ab8500, AB8500_RTC,
  		AB8500_SWITCH_OFF_STATUS, &value);
  	if (ret < 0)
  		return ret;
  	return sprintf(buf, "%#x
  ", value);
  }
b4a310373   Andrew Lynn   mfd: Expose TurnO...
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
  /*
   * ab8500 has turned on due to (TURN_ON_STATUS):
   * 0x01 PORnVbat
   * 0x02 PonKey1dbF
   * 0x04 PonKey2dbF
   * 0x08 RTCAlarm
   * 0x10 MainChDet
   * 0x20 VbusDet
   * 0x40 UsbIDDetect
   * 0x80 Reserved
   */
  static ssize_t show_turn_on_status(struct device *dev,
  				struct device_attribute *attr, char *buf)
  {
  	int ret;
  	u8 value;
  	struct ab8500 *ab8500;
  
  	ab8500 = dev_get_drvdata(dev);
  	ret = get_register_interruptible(ab8500, AB8500_SYS_CTRL1_BLOCK,
  		AB8500_TURN_ON_STATUS, &value);
  	if (ret < 0)
  		return ret;
  	return sprintf(buf, "%#x
  ", value);
  }
cca69b67b   Mattias Wallin   mfd: Export ab850...
830
  static DEVICE_ATTR(chip_id, S_IRUGO, show_chip_id, NULL);
e5c238c3f   Mattias Wallin   mfd: ab8500-core ...
831
  static DEVICE_ATTR(switch_off_status, S_IRUGO, show_switch_off_status, NULL);
b4a310373   Andrew Lynn   mfd: Expose TurnO...
832
  static DEVICE_ATTR(turn_on_status, S_IRUGO, show_turn_on_status, NULL);
cca69b67b   Mattias Wallin   mfd: Export ab850...
833
834
835
  
  static struct attribute *ab8500_sysfs_entries[] = {
  	&dev_attr_chip_id.attr,
e5c238c3f   Mattias Wallin   mfd: ab8500-core ...
836
  	&dev_attr_switch_off_status.attr,
b4a310373   Andrew Lynn   mfd: Expose TurnO...
837
  	&dev_attr_turn_on_status.attr,
cca69b67b   Mattias Wallin   mfd: Export ab850...
838
839
840
841
842
843
  	NULL,
  };
  
  static struct attribute_group ab8500_attr_group = {
  	.attrs	= ab8500_sysfs_entries,
  };
62579266c   Rabin Vincent   mfd: New AB8500 d...
844
845
846
847
848
  int __devinit ab8500_init(struct ab8500 *ab8500)
  {
  	struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
  	int ret;
  	int i;
47c169750   Mattias Wallin   mfd: Align ab8500...
849
  	u8 value;
62579266c   Rabin Vincent   mfd: New AB8500 d...
850
851
852
853
854
855
  
  	if (plat)
  		ab8500->irq_base = plat->irq_base;
  
  	mutex_init(&ab8500->lock);
  	mutex_init(&ab8500->irq_lock);
47c169750   Mattias Wallin   mfd: Align ab8500...
856
857
  	ret = get_register_interruptible(ab8500, AB8500_MISC,
  		AB8500_REV_REG, &value);
62579266c   Rabin Vincent   mfd: New AB8500 d...
858
859
  	if (ret < 0)
  		return ret;
863dde5bf   Linus Walleij   mfd: Provide ab85...
860
  	switch (value) {
863dde5bf   Linus Walleij   mfd: Provide ab85...
861
862
863
864
  	case AB8500_CUT1P0:
  	case AB8500_CUT1P1:
  	case AB8500_CUT2P0:
  	case AB8500_CUT3P0:
0e9049ecc   Mattias Wallin   mfd: Add support ...
865
  	case AB8500_CUT3P3:
47c169750   Mattias Wallin   mfd: Align ab8500...
866
867
  		dev_info(ab8500->dev, "detected chip, revision: %#x
  ", value);
863dde5bf   Linus Walleij   mfd: Provide ab85...
868
869
  		break;
  	default:
47c169750   Mattias Wallin   mfd: Align ab8500...
870
871
  		dev_err(ab8500->dev, "unknown chip, revision: %#x
  ", value);
62579266c   Rabin Vincent   mfd: New AB8500 d...
872
873
  		return -EINVAL;
  	}
47c169750   Mattias Wallin   mfd: Align ab8500...
874
  	ab8500->chip_id = value;
62579266c   Rabin Vincent   mfd: New AB8500 d...
875

e5c238c3f   Mattias Wallin   mfd: ab8500-core ...
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
  	/*
  	 * ab8500 has switched off due to (SWITCH_OFF_STATUS):
  	 * 0x01 Swoff bit programming
  	 * 0x02 Thermal protection activation
  	 * 0x04 Vbat lower then BattOk falling threshold
  	 * 0x08 Watchdog expired
  	 * 0x10 Non presence of 32kHz clock
  	 * 0x20 Battery level lower than power on reset threshold
  	 * 0x40 Power on key 1 pressed longer than 10 seconds
  	 * 0x80 DB8500 thermal shutdown
  	 */
  
  	ret = get_register_interruptible(ab8500, AB8500_RTC,
  		AB8500_SWITCH_OFF_STATUS, &value);
  	if (ret < 0)
  		return ret;
  	dev_info(ab8500->dev, "switch off status: %#x", value);
62579266c   Rabin Vincent   mfd: New AB8500 d...
893
894
895
896
  	if (plat && plat->init)
  		plat->init(ab8500);
  
  	/* Clear and mask all interrupts */
92d50a413   Mattias Wallin   mfd: ab8500-core ...
897
  	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
863dde5bf   Linus Walleij   mfd: Provide ab85...
898
899
900
  		/* Interrupt register 12 doesn't exist prior to version 2.0 */
  		if (ab8500_irq_regoffset[i] == 11 &&
  			ab8500->chip_id < AB8500_CUT2P0)
92d50a413   Mattias Wallin   mfd: ab8500-core ...
901
  			continue;
62579266c   Rabin Vincent   mfd: New AB8500 d...
902

47c169750   Mattias Wallin   mfd: Align ab8500...
903
  		get_register_interruptible(ab8500, AB8500_INTERRUPT,
92d50a413   Mattias Wallin   mfd: ab8500-core ...
904
905
  			AB8500_IT_LATCH1_REG + ab8500_irq_regoffset[i],
  			&value);
47c169750   Mattias Wallin   mfd: Align ab8500...
906
  		set_register_interruptible(ab8500, AB8500_INTERRUPT,
92d50a413   Mattias Wallin   mfd: ab8500-core ...
907
  			AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i], 0xff);
62579266c   Rabin Vincent   mfd: New AB8500 d...
908
  	}
47c169750   Mattias Wallin   mfd: Align ab8500...
909
910
911
  	ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
  	if (ret)
  		return ret;
62579266c   Rabin Vincent   mfd: New AB8500 d...
912
913
914
915
916
917
918
919
920
  	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++)
  		ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
  
  	if (ab8500->irq_base) {
  		ret = ab8500_irq_init(ab8500);
  		if (ret)
  			return ret;
  
  		ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
4f079985b   Mattias Wallin   mfd: ab8500-core ...
921
922
  					   IRQF_ONESHOT | IRQF_NO_SUSPEND,
  					   "ab8500", ab8500);
62579266c   Rabin Vincent   mfd: New AB8500 d...
923
924
925
  		if (ret)
  			goto out_removeirq;
  	}
549931f99   Sundar R Iyer   ab8500-mfd: add r...
926
  	ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
62579266c   Rabin Vincent   mfd: New AB8500 d...
927
928
929
930
  			      ARRAY_SIZE(ab8500_devs), NULL,
  			      ab8500->irq_base);
  	if (ret)
  		goto out_freeirq;
cca69b67b   Mattias Wallin   mfd: Export ab850...
931
932
933
934
  	ret = sysfs_create_group(&ab8500->dev->kobj, &ab8500_attr_group);
  	if (ret)
  		dev_err(ab8500->dev, "error creating sysfs entries
  ");
62579266c   Rabin Vincent   mfd: New AB8500 d...
935
936
937
938
939
940
941
942
943
944
945
946
947
  	return ret;
  
  out_freeirq:
  	if (ab8500->irq_base) {
  		free_irq(ab8500->irq, ab8500);
  out_removeirq:
  		ab8500_irq_remove(ab8500);
  	}
  	return ret;
  }
  
  int __devexit ab8500_exit(struct ab8500 *ab8500)
  {
cca69b67b   Mattias Wallin   mfd: Export ab850...
948
  	sysfs_remove_group(&ab8500->dev->kobj, &ab8500_attr_group);
62579266c   Rabin Vincent   mfd: New AB8500 d...
949
950
951
952
953
954
955
956
  	mfd_remove_devices(ab8500->dev);
  	if (ab8500->irq_base) {
  		free_irq(ab8500->irq, ab8500);
  		ab8500_irq_remove(ab8500);
  	}
  
  	return 0;
  }
adceed626   Mattias Wallin   mfd: ab8500 chip ...
957
  MODULE_AUTHOR("Mattias Wallin, Srinidhi Kasagar, Rabin Vincent");
62579266c   Rabin Vincent   mfd: New AB8500 d...
958
959
  MODULE_DESCRIPTION("AB8500 MFD core");
  MODULE_LICENSE("GPL v2");