xref: /openbmc/linux/drivers/mfd/ab8500-core.c (revision 47c1697508f2ec9f6b31ce6c825fe1017871dea6)
162579266SRabin Vincent /*
262579266SRabin Vincent  * Copyright (C) ST-Ericsson SA 2010
362579266SRabin Vincent  *
462579266SRabin Vincent  * License Terms: GNU General Public License v2
562579266SRabin Vincent  * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com>
662579266SRabin Vincent  * Author: Rabin Vincent <rabin.vincent@stericsson.com>
7*47c16975SMattias Wallin  * Changes: Mattias Wallin <mattias.wallin@stericsson.com>
862579266SRabin Vincent  */
962579266SRabin Vincent 
1062579266SRabin Vincent #include <linux/kernel.h>
1162579266SRabin Vincent #include <linux/slab.h>
1262579266SRabin Vincent #include <linux/init.h>
1362579266SRabin Vincent #include <linux/irq.h>
1462579266SRabin Vincent #include <linux/delay.h>
1562579266SRabin Vincent #include <linux/interrupt.h>
1662579266SRabin Vincent #include <linux/module.h>
1762579266SRabin Vincent #include <linux/platform_device.h>
1862579266SRabin Vincent #include <linux/mfd/core.h>
19*47c16975SMattias Wallin #include <linux/mfd/abx500.h>
2062579266SRabin Vincent #include <linux/mfd/ab8500.h>
21549931f9SSundar R Iyer #include <linux/regulator/ab8500.h>
2262579266SRabin Vincent 
2362579266SRabin Vincent /*
2462579266SRabin Vincent  * Interrupt register offsets
2562579266SRabin Vincent  * Bank : 0x0E
2662579266SRabin Vincent  */
27*47c16975SMattias Wallin #define AB8500_IT_SOURCE1_REG		0x00
28*47c16975SMattias Wallin #define AB8500_IT_SOURCE2_REG		0x01
29*47c16975SMattias Wallin #define AB8500_IT_SOURCE3_REG		0x02
30*47c16975SMattias Wallin #define AB8500_IT_SOURCE4_REG		0x03
31*47c16975SMattias Wallin #define AB8500_IT_SOURCE5_REG		0x04
32*47c16975SMattias Wallin #define AB8500_IT_SOURCE6_REG		0x05
33*47c16975SMattias Wallin #define AB8500_IT_SOURCE7_REG		0x06
34*47c16975SMattias Wallin #define AB8500_IT_SOURCE8_REG		0x07
35*47c16975SMattias Wallin #define AB8500_IT_SOURCE19_REG		0x12
36*47c16975SMattias Wallin #define AB8500_IT_SOURCE20_REG		0x13
37*47c16975SMattias Wallin #define AB8500_IT_SOURCE21_REG		0x14
38*47c16975SMattias Wallin #define AB8500_IT_SOURCE22_REG		0x15
39*47c16975SMattias Wallin #define AB8500_IT_SOURCE23_REG		0x16
40*47c16975SMattias Wallin #define AB8500_IT_SOURCE24_REG		0x17
4162579266SRabin Vincent 
4262579266SRabin Vincent /*
4362579266SRabin Vincent  * latch registers
4462579266SRabin Vincent  */
45*47c16975SMattias Wallin #define AB8500_IT_LATCH1_REG		0x20
46*47c16975SMattias Wallin #define AB8500_IT_LATCH2_REG		0x21
47*47c16975SMattias Wallin #define AB8500_IT_LATCH3_REG		0x22
48*47c16975SMattias Wallin #define AB8500_IT_LATCH4_REG		0x23
49*47c16975SMattias Wallin #define AB8500_IT_LATCH5_REG		0x24
50*47c16975SMattias Wallin #define AB8500_IT_LATCH6_REG		0x25
51*47c16975SMattias Wallin #define AB8500_IT_LATCH7_REG		0x26
52*47c16975SMattias Wallin #define AB8500_IT_LATCH8_REG		0x27
53*47c16975SMattias Wallin #define AB8500_IT_LATCH9_REG		0x28
54*47c16975SMattias Wallin #define AB8500_IT_LATCH10_REG		0x29
55*47c16975SMattias Wallin #define AB8500_IT_LATCH19_REG		0x32
56*47c16975SMattias Wallin #define AB8500_IT_LATCH20_REG		0x33
57*47c16975SMattias Wallin #define AB8500_IT_LATCH21_REG		0x34
58*47c16975SMattias Wallin #define AB8500_IT_LATCH22_REG		0x35
59*47c16975SMattias Wallin #define AB8500_IT_LATCH23_REG		0x36
60*47c16975SMattias Wallin #define AB8500_IT_LATCH24_REG		0x37
6162579266SRabin Vincent 
6262579266SRabin Vincent /*
6362579266SRabin Vincent  * mask registers
6462579266SRabin Vincent  */
6562579266SRabin Vincent 
66*47c16975SMattias Wallin #define AB8500_IT_MASK1_REG		0x40
67*47c16975SMattias Wallin #define AB8500_IT_MASK2_REG		0x41
68*47c16975SMattias Wallin #define AB8500_IT_MASK3_REG		0x42
69*47c16975SMattias Wallin #define AB8500_IT_MASK4_REG		0x43
70*47c16975SMattias Wallin #define AB8500_IT_MASK5_REG		0x44
71*47c16975SMattias Wallin #define AB8500_IT_MASK6_REG		0x45
72*47c16975SMattias Wallin #define AB8500_IT_MASK7_REG		0x46
73*47c16975SMattias Wallin #define AB8500_IT_MASK8_REG		0x47
74*47c16975SMattias Wallin #define AB8500_IT_MASK9_REG		0x48
75*47c16975SMattias Wallin #define AB8500_IT_MASK10_REG		0x49
76*47c16975SMattias Wallin #define AB8500_IT_MASK11_REG		0x4A
77*47c16975SMattias Wallin #define AB8500_IT_MASK12_REG		0x4B
78*47c16975SMattias Wallin #define AB8500_IT_MASK13_REG		0x4C
79*47c16975SMattias Wallin #define AB8500_IT_MASK14_REG		0x4D
80*47c16975SMattias Wallin #define AB8500_IT_MASK15_REG		0x4E
81*47c16975SMattias Wallin #define AB8500_IT_MASK16_REG		0x4F
82*47c16975SMattias Wallin #define AB8500_IT_MASK17_REG		0x50
83*47c16975SMattias Wallin #define AB8500_IT_MASK18_REG		0x51
84*47c16975SMattias Wallin #define AB8500_IT_MASK19_REG		0x52
85*47c16975SMattias Wallin #define AB8500_IT_MASK20_REG		0x53
86*47c16975SMattias Wallin #define AB8500_IT_MASK21_REG		0x54
87*47c16975SMattias Wallin #define AB8500_IT_MASK22_REG		0x55
88*47c16975SMattias Wallin #define AB8500_IT_MASK23_REG		0x56
89*47c16975SMattias Wallin #define AB8500_IT_MASK24_REG		0x57
9062579266SRabin Vincent 
91*47c16975SMattias Wallin #define AB8500_REV_REG			0x80
9262579266SRabin Vincent 
9362579266SRabin Vincent /*
9462579266SRabin Vincent  * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt
9562579266SRabin Vincent  * numbers are indexed into this array with (num / 8).
9662579266SRabin Vincent  *
9762579266SRabin Vincent  * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at
9862579266SRabin Vincent  * offset 0.
9962579266SRabin Vincent  */
10062579266SRabin Vincent static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = {
10162579266SRabin Vincent 	0, 1, 2, 3, 4, 6, 7, 8, 9, 18, 19, 20, 21,
10262579266SRabin Vincent };
10362579266SRabin Vincent 
104*47c16975SMattias Wallin static int ab8500_get_chip_id(struct device *dev)
105*47c16975SMattias Wallin {
106*47c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
107*47c16975SMattias Wallin 	return (int)ab8500->chip_id;
108*47c16975SMattias Wallin }
109*47c16975SMattias Wallin 
110*47c16975SMattias Wallin static int set_register_interruptible(struct ab8500 *ab8500, u8 bank,
111*47c16975SMattias Wallin 	u8 reg, u8 data)
11262579266SRabin Vincent {
11362579266SRabin Vincent 	int ret;
114*47c16975SMattias Wallin 	/*
115*47c16975SMattias Wallin 	 * Put the u8 bank and u8 register together into a an u16.
116*47c16975SMattias Wallin 	 * The bank on higher 8 bits and register in lower 8 bits.
117*47c16975SMattias Wallin 	 * */
118*47c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
11962579266SRabin Vincent 
12062579266SRabin Vincent 	dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data);
12162579266SRabin Vincent 
122*47c16975SMattias Wallin 	ret = mutex_lock_interruptible(&ab8500->lock);
123*47c16975SMattias Wallin 	if (ret)
124*47c16975SMattias Wallin 		return ret;
125*47c16975SMattias Wallin 
126*47c16975SMattias Wallin 	ret = ab8500->write(ab8500, addr, data);
127*47c16975SMattias Wallin 	if (ret < 0)
128*47c16975SMattias Wallin 		dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
129*47c16975SMattias Wallin 			addr, ret);
130*47c16975SMattias Wallin 	mutex_unlock(&ab8500->lock);
131*47c16975SMattias Wallin 
132*47c16975SMattias Wallin 	return ret;
133*47c16975SMattias Wallin }
134*47c16975SMattias Wallin 
135*47c16975SMattias Wallin static int ab8500_set_register(struct device *dev, u8 bank,
136*47c16975SMattias Wallin 	u8 reg, u8 value)
137*47c16975SMattias Wallin {
138*47c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
139*47c16975SMattias Wallin 
140*47c16975SMattias Wallin 	return set_register_interruptible(ab8500, bank, reg, value);
141*47c16975SMattias Wallin }
142*47c16975SMattias Wallin 
143*47c16975SMattias Wallin static int get_register_interruptible(struct ab8500 *ab8500, u8 bank,
144*47c16975SMattias Wallin 	u8 reg, u8 *value)
145*47c16975SMattias Wallin {
146*47c16975SMattias Wallin 	int ret;
147*47c16975SMattias Wallin 	/* put the u8 bank and u8 reg together into a an u16.
148*47c16975SMattias Wallin 	 * bank on higher 8 bits and reg in lower */
149*47c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
150*47c16975SMattias Wallin 
151*47c16975SMattias Wallin 	ret = mutex_lock_interruptible(&ab8500->lock);
152*47c16975SMattias Wallin 	if (ret)
153*47c16975SMattias Wallin 		return ret;
154*47c16975SMattias Wallin 
155*47c16975SMattias Wallin 	ret = ab8500->read(ab8500, addr);
156*47c16975SMattias Wallin 	if (ret < 0)
157*47c16975SMattias Wallin 		dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
158*47c16975SMattias Wallin 			addr, ret);
159*47c16975SMattias Wallin 	else
160*47c16975SMattias Wallin 		*value = ret;
161*47c16975SMattias Wallin 
162*47c16975SMattias Wallin 	mutex_unlock(&ab8500->lock);
163*47c16975SMattias Wallin 	dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret);
164*47c16975SMattias Wallin 
165*47c16975SMattias Wallin 	return ret;
166*47c16975SMattias Wallin }
167*47c16975SMattias Wallin 
168*47c16975SMattias Wallin static int ab8500_get_register(struct device *dev, u8 bank,
169*47c16975SMattias Wallin 	u8 reg, u8 *value)
170*47c16975SMattias Wallin {
171*47c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
172*47c16975SMattias Wallin 
173*47c16975SMattias Wallin 	return get_register_interruptible(ab8500, bank, reg, value);
174*47c16975SMattias Wallin }
175*47c16975SMattias Wallin 
176*47c16975SMattias Wallin static int mask_and_set_register_interruptible(struct ab8500 *ab8500, u8 bank,
177*47c16975SMattias Wallin 	u8 reg, u8 bitmask, u8 bitvalues)
178*47c16975SMattias Wallin {
179*47c16975SMattias Wallin 	int ret;
180*47c16975SMattias Wallin 	u8 data;
181*47c16975SMattias Wallin 	/* put the u8 bank and u8 reg together into a an u16.
182*47c16975SMattias Wallin 	 * bank on higher 8 bits and reg in lower */
183*47c16975SMattias Wallin 	u16 addr = ((u16)bank) << 8 | reg;
184*47c16975SMattias Wallin 
185*47c16975SMattias Wallin 	ret = mutex_lock_interruptible(&ab8500->lock);
186*47c16975SMattias Wallin 	if (ret)
187*47c16975SMattias Wallin 		return ret;
188*47c16975SMattias Wallin 
189*47c16975SMattias Wallin 	ret = ab8500->read(ab8500, addr);
190*47c16975SMattias Wallin 	if (ret < 0) {
191*47c16975SMattias Wallin 		dev_err(ab8500->dev, "failed to read reg %#x: %d\n",
192*47c16975SMattias Wallin 			addr, ret);
193*47c16975SMattias Wallin 		goto out;
194*47c16975SMattias Wallin 	}
195*47c16975SMattias Wallin 
196*47c16975SMattias Wallin 	data = (u8)ret;
197*47c16975SMattias Wallin 	data = (~bitmask & data) | (bitmask & bitvalues);
198*47c16975SMattias Wallin 
19962579266SRabin Vincent 	ret = ab8500->write(ab8500, addr, data);
20062579266SRabin Vincent 	if (ret < 0)
20162579266SRabin Vincent 		dev_err(ab8500->dev, "failed to write reg %#x: %d\n",
20262579266SRabin Vincent 			addr, ret);
20362579266SRabin Vincent 
204*47c16975SMattias Wallin 	dev_vdbg(ab8500->dev, "mask: addr %#x => data %#x\n", addr, data);
20562579266SRabin Vincent out:
20662579266SRabin Vincent 	mutex_unlock(&ab8500->lock);
20762579266SRabin Vincent 	return ret;
20862579266SRabin Vincent }
209*47c16975SMattias Wallin 
210*47c16975SMattias Wallin static int ab8500_mask_and_set_register(struct device *dev,
211*47c16975SMattias Wallin 	u8 bank, u8 reg, u8 bitmask, u8 bitvalues)
212*47c16975SMattias Wallin {
213*47c16975SMattias Wallin 	struct ab8500 *ab8500 = dev_get_drvdata(dev->parent);
214*47c16975SMattias Wallin 
215*47c16975SMattias Wallin 	return mask_and_set_register_interruptible(ab8500, bank, reg,
216*47c16975SMattias Wallin 		bitmask, bitvalues);
217*47c16975SMattias Wallin 
218*47c16975SMattias Wallin }
219*47c16975SMattias Wallin 
220*47c16975SMattias Wallin static struct abx500_ops ab8500_ops = {
221*47c16975SMattias Wallin 	.get_chip_id = ab8500_get_chip_id,
222*47c16975SMattias Wallin 	.get_register = ab8500_get_register,
223*47c16975SMattias Wallin 	.set_register = ab8500_set_register,
224*47c16975SMattias Wallin 	.get_register_page = NULL,
225*47c16975SMattias Wallin 	.set_register_page = NULL,
226*47c16975SMattias Wallin 	.mask_and_set_register = ab8500_mask_and_set_register,
227*47c16975SMattias Wallin 	.event_registers_startup_state_get = NULL,
228*47c16975SMattias Wallin 	.startup_irq_enabled = NULL,
229*47c16975SMattias Wallin };
23062579266SRabin Vincent 
23162579266SRabin Vincent static void ab8500_irq_lock(unsigned int irq)
23262579266SRabin Vincent {
23362579266SRabin Vincent 	struct ab8500 *ab8500 = get_irq_chip_data(irq);
23462579266SRabin Vincent 
23562579266SRabin Vincent 	mutex_lock(&ab8500->irq_lock);
23662579266SRabin Vincent }
23762579266SRabin Vincent 
23862579266SRabin Vincent static void ab8500_irq_sync_unlock(unsigned int irq)
23962579266SRabin Vincent {
24062579266SRabin Vincent 	struct ab8500 *ab8500 = get_irq_chip_data(irq);
24162579266SRabin Vincent 	int i;
24262579266SRabin Vincent 
24362579266SRabin Vincent 	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
24462579266SRabin Vincent 		u8 old = ab8500->oldmask[i];
24562579266SRabin Vincent 		u8 new = ab8500->mask[i];
24662579266SRabin Vincent 		int reg;
24762579266SRabin Vincent 
24862579266SRabin Vincent 		if (new == old)
24962579266SRabin Vincent 			continue;
25062579266SRabin Vincent 
25162579266SRabin Vincent 		ab8500->oldmask[i] = new;
25262579266SRabin Vincent 
25362579266SRabin Vincent 		reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i];
254*47c16975SMattias Wallin 		set_register_interruptible(ab8500, AB8500_INTERRUPT, reg, new);
25562579266SRabin Vincent 	}
25662579266SRabin Vincent 
25762579266SRabin Vincent 	mutex_unlock(&ab8500->irq_lock);
25862579266SRabin Vincent }
25962579266SRabin Vincent 
26062579266SRabin Vincent static void ab8500_irq_mask(unsigned int irq)
26162579266SRabin Vincent {
26262579266SRabin Vincent 	struct ab8500 *ab8500 = get_irq_chip_data(irq);
26362579266SRabin Vincent 	int offset = irq - ab8500->irq_base;
26462579266SRabin Vincent 	int index = offset / 8;
26562579266SRabin Vincent 	int mask = 1 << (offset % 8);
26662579266SRabin Vincent 
26762579266SRabin Vincent 	ab8500->mask[index] |= mask;
26862579266SRabin Vincent }
26962579266SRabin Vincent 
27062579266SRabin Vincent static void ab8500_irq_unmask(unsigned int irq)
27162579266SRabin Vincent {
27262579266SRabin Vincent 	struct ab8500 *ab8500 = get_irq_chip_data(irq);
27362579266SRabin Vincent 	int offset = irq - ab8500->irq_base;
27462579266SRabin Vincent 	int index = offset / 8;
27562579266SRabin Vincent 	int mask = 1 << (offset % 8);
27662579266SRabin Vincent 
27762579266SRabin Vincent 	ab8500->mask[index] &= ~mask;
27862579266SRabin Vincent }
27962579266SRabin Vincent 
28062579266SRabin Vincent static struct irq_chip ab8500_irq_chip = {
28162579266SRabin Vincent 	.name			= "ab8500",
28262579266SRabin Vincent 	.bus_lock		= ab8500_irq_lock,
28362579266SRabin Vincent 	.bus_sync_unlock	= ab8500_irq_sync_unlock,
28462579266SRabin Vincent 	.mask			= ab8500_irq_mask,
28562579266SRabin Vincent 	.unmask			= ab8500_irq_unmask,
28662579266SRabin Vincent };
28762579266SRabin Vincent 
28862579266SRabin Vincent static irqreturn_t ab8500_irq(int irq, void *dev)
28962579266SRabin Vincent {
29062579266SRabin Vincent 	struct ab8500 *ab8500 = dev;
29162579266SRabin Vincent 	int i;
29262579266SRabin Vincent 
29362579266SRabin Vincent 	dev_vdbg(ab8500->dev, "interrupt\n");
29462579266SRabin Vincent 
29562579266SRabin Vincent 	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) {
29662579266SRabin Vincent 		int regoffset = ab8500_irq_regoffset[i];
29762579266SRabin Vincent 		int status;
298*47c16975SMattias Wallin 		u8 value;
29962579266SRabin Vincent 
300*47c16975SMattias Wallin 		status = get_register_interruptible(ab8500, AB8500_INTERRUPT,
301*47c16975SMattias Wallin 			AB8500_IT_LATCH1_REG + regoffset, &value);
302*47c16975SMattias Wallin 		if (status < 0 || value == 0)
30362579266SRabin Vincent 			continue;
30462579266SRabin Vincent 
30562579266SRabin Vincent 		do {
30662579266SRabin Vincent 			int bit = __ffs(status);
30762579266SRabin Vincent 			int line = i * 8 + bit;
30862579266SRabin Vincent 
30962579266SRabin Vincent 			handle_nested_irq(ab8500->irq_base + line);
310*47c16975SMattias Wallin 			value &= ~(1 << bit);
311*47c16975SMattias Wallin 		} while (value);
31262579266SRabin Vincent 	}
31362579266SRabin Vincent 
31462579266SRabin Vincent 	return IRQ_HANDLED;
31562579266SRabin Vincent }
31662579266SRabin Vincent 
31762579266SRabin Vincent static int ab8500_irq_init(struct ab8500 *ab8500)
31862579266SRabin Vincent {
31962579266SRabin Vincent 	int base = ab8500->irq_base;
32062579266SRabin Vincent 	int irq;
32162579266SRabin Vincent 
32262579266SRabin Vincent 	for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
32362579266SRabin Vincent 		set_irq_chip_data(irq, ab8500);
32462579266SRabin Vincent 		set_irq_chip_and_handler(irq, &ab8500_irq_chip,
32562579266SRabin Vincent 					 handle_simple_irq);
32662579266SRabin Vincent 		set_irq_nested_thread(irq, 1);
32762579266SRabin Vincent #ifdef CONFIG_ARM
32862579266SRabin Vincent 		set_irq_flags(irq, IRQF_VALID);
32962579266SRabin Vincent #else
33062579266SRabin Vincent 		set_irq_noprobe(irq);
33162579266SRabin Vincent #endif
33262579266SRabin Vincent 	}
33362579266SRabin Vincent 
33462579266SRabin Vincent 	return 0;
33562579266SRabin Vincent }
33662579266SRabin Vincent 
33762579266SRabin Vincent static void ab8500_irq_remove(struct ab8500 *ab8500)
33862579266SRabin Vincent {
33962579266SRabin Vincent 	int base = ab8500->irq_base;
34062579266SRabin Vincent 	int irq;
34162579266SRabin Vincent 
34262579266SRabin Vincent 	for (irq = base; irq < base + AB8500_NR_IRQS; irq++) {
34362579266SRabin Vincent #ifdef CONFIG_ARM
34462579266SRabin Vincent 		set_irq_flags(irq, 0);
34562579266SRabin Vincent #endif
34662579266SRabin Vincent 		set_irq_chip_and_handler(irq, NULL, NULL);
34762579266SRabin Vincent 		set_irq_chip_data(irq, NULL);
34862579266SRabin Vincent 	}
34962579266SRabin Vincent }
35062579266SRabin Vincent 
35162579266SRabin Vincent static struct resource ab8500_gpadc_resources[] = {
35262579266SRabin Vincent 	{
35362579266SRabin Vincent 		.name	= "HW_CONV_END",
35462579266SRabin Vincent 		.start	= AB8500_INT_GP_HW_ADC_CONV_END,
35562579266SRabin Vincent 		.end	= AB8500_INT_GP_HW_ADC_CONV_END,
35662579266SRabin Vincent 		.flags	= IORESOURCE_IRQ,
35762579266SRabin Vincent 	},
35862579266SRabin Vincent 	{
35962579266SRabin Vincent 		.name	= "SW_CONV_END",
36062579266SRabin Vincent 		.start	= AB8500_INT_GP_SW_ADC_CONV_END,
36162579266SRabin Vincent 		.end	= AB8500_INT_GP_SW_ADC_CONV_END,
36262579266SRabin Vincent 		.flags	= IORESOURCE_IRQ,
36362579266SRabin Vincent 	},
36462579266SRabin Vincent };
36562579266SRabin Vincent 
36662579266SRabin Vincent static struct resource ab8500_rtc_resources[] = {
36762579266SRabin Vincent 	{
36862579266SRabin Vincent 		.name	= "60S",
36962579266SRabin Vincent 		.start	= AB8500_INT_RTC_60S,
37062579266SRabin Vincent 		.end	= AB8500_INT_RTC_60S,
37162579266SRabin Vincent 		.flags	= IORESOURCE_IRQ,
37262579266SRabin Vincent 	},
37362579266SRabin Vincent 	{
37462579266SRabin Vincent 		.name	= "ALARM",
37562579266SRabin Vincent 		.start	= AB8500_INT_RTC_ALARM,
37662579266SRabin Vincent 		.end	= AB8500_INT_RTC_ALARM,
37762579266SRabin Vincent 		.flags	= IORESOURCE_IRQ,
37862579266SRabin Vincent 	},
37962579266SRabin Vincent };
38062579266SRabin Vincent 
38177686517SSundar R Iyer static struct resource ab8500_poweronkey_db_resources[] = {
38277686517SSundar R Iyer 	{
38377686517SSundar R Iyer 		.name	= "ONKEY_DBF",
38477686517SSundar R Iyer 		.start	= AB8500_INT_PON_KEY1DB_F,
38577686517SSundar R Iyer 		.end	= AB8500_INT_PON_KEY1DB_F,
38677686517SSundar R Iyer 		.flags	= IORESOURCE_IRQ,
38777686517SSundar R Iyer 	},
38877686517SSundar R Iyer 	{
38977686517SSundar R Iyer 		.name	= "ONKEY_DBR",
39077686517SSundar R Iyer 		.start	= AB8500_INT_PON_KEY1DB_R,
39177686517SSundar R Iyer 		.end	= AB8500_INT_PON_KEY1DB_R,
39277686517SSundar R Iyer 		.flags	= IORESOURCE_IRQ,
39377686517SSundar R Iyer 	},
39477686517SSundar R Iyer };
39577686517SSundar R Iyer 
39662579266SRabin Vincent static struct mfd_cell ab8500_devs[] = {
39762579266SRabin Vincent 	{
39862579266SRabin Vincent 		.name = "ab8500-gpadc",
39962579266SRabin Vincent 		.num_resources = ARRAY_SIZE(ab8500_gpadc_resources),
40062579266SRabin Vincent 		.resources = ab8500_gpadc_resources,
40162579266SRabin Vincent 	},
40262579266SRabin Vincent 	{
40362579266SRabin Vincent 		.name = "ab8500-rtc",
40462579266SRabin Vincent 		.num_resources = ARRAY_SIZE(ab8500_rtc_resources),
40562579266SRabin Vincent 		.resources = ab8500_rtc_resources,
40662579266SRabin Vincent 	},
40762579266SRabin Vincent 	{ .name = "ab8500-charger", },
40862579266SRabin Vincent 	{ .name = "ab8500-audio", },
40962579266SRabin Vincent 	{ .name = "ab8500-usb", },
41062579266SRabin Vincent 	{ .name = "ab8500-pwm", },
411549931f9SSundar R Iyer 	{ .name = "ab8500-regulator", },
41277686517SSundar R Iyer 	{
41377686517SSundar R Iyer 		.name = "ab8500-poweron-key",
41477686517SSundar R Iyer 		.num_resources = ARRAY_SIZE(ab8500_poweronkey_db_resources),
41577686517SSundar R Iyer 		.resources = ab8500_poweronkey_db_resources,
41677686517SSundar R Iyer 	},
41762579266SRabin Vincent };
41862579266SRabin Vincent 
41962579266SRabin Vincent int __devinit ab8500_init(struct ab8500 *ab8500)
42062579266SRabin Vincent {
42162579266SRabin Vincent 	struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev);
42262579266SRabin Vincent 	int ret;
42362579266SRabin Vincent 	int i;
424*47c16975SMattias Wallin 	u8 value;
42562579266SRabin Vincent 
42662579266SRabin Vincent 	if (plat)
42762579266SRabin Vincent 		ab8500->irq_base = plat->irq_base;
42862579266SRabin Vincent 
42962579266SRabin Vincent 	mutex_init(&ab8500->lock);
43062579266SRabin Vincent 	mutex_init(&ab8500->irq_lock);
43162579266SRabin Vincent 
432*47c16975SMattias Wallin 	ret = get_register_interruptible(ab8500, AB8500_MISC,
433*47c16975SMattias Wallin 		AB8500_REV_REG, &value);
43462579266SRabin Vincent 	if (ret < 0)
43562579266SRabin Vincent 		return ret;
43662579266SRabin Vincent 
43762579266SRabin Vincent 	/*
43862579266SRabin Vincent 	 * 0x0 - Early Drop
43962579266SRabin Vincent 	 * 0x10 - Cut 1.0
44062579266SRabin Vincent 	 * 0x11 - Cut 1.1
44162579266SRabin Vincent 	 */
442*47c16975SMattias Wallin 	if (value == 0x0 || value == 0x10 || value == 0x11) {
443*47c16975SMattias Wallin 		ab8500->revision = value;
444*47c16975SMattias Wallin 		dev_info(ab8500->dev, "detected chip, revision: %#x\n", value);
44562579266SRabin Vincent 	} else {
446*47c16975SMattias Wallin 		dev_err(ab8500->dev, "unknown chip, revision: %#x\n", value);
44762579266SRabin Vincent 		return -EINVAL;
44862579266SRabin Vincent 	}
449*47c16975SMattias Wallin 	ab8500->chip_id = value;
45062579266SRabin Vincent 
45162579266SRabin Vincent 	if (plat && plat->init)
45262579266SRabin Vincent 		plat->init(ab8500);
45362579266SRabin Vincent 
45462579266SRabin Vincent 	/* Clear and mask all interrupts */
45562579266SRabin Vincent 	for (i = 0; i < 10; i++) {
456*47c16975SMattias Wallin 		get_register_interruptible(ab8500, AB8500_INTERRUPT,
457*47c16975SMattias Wallin 			AB8500_IT_LATCH1_REG + i, &value);
458*47c16975SMattias Wallin 		set_register_interruptible(ab8500, AB8500_INTERRUPT,
459*47c16975SMattias Wallin 			AB8500_IT_MASK1_REG + i, 0xff);
46062579266SRabin Vincent 	}
46162579266SRabin Vincent 
46262579266SRabin Vincent 	for (i = 18; i < 24; i++) {
463*47c16975SMattias Wallin 		get_register_interruptible(ab8500, AB8500_INTERRUPT,
464*47c16975SMattias Wallin 			AB8500_IT_LATCH1_REG + i, &value);
465*47c16975SMattias Wallin 		set_register_interruptible(ab8500, AB8500_INTERRUPT,
466*47c16975SMattias Wallin 			AB8500_IT_MASK1_REG + i, 0xff);
46762579266SRabin Vincent 	}
46862579266SRabin Vincent 
469*47c16975SMattias Wallin 	ret = abx500_register_ops(ab8500->dev, &ab8500_ops);
470*47c16975SMattias Wallin 	if (ret)
471*47c16975SMattias Wallin 		return ret;
472*47c16975SMattias Wallin 
47362579266SRabin Vincent 	for (i = 0; i < AB8500_NUM_IRQ_REGS; i++)
47462579266SRabin Vincent 		ab8500->mask[i] = ab8500->oldmask[i] = 0xff;
47562579266SRabin Vincent 
47662579266SRabin Vincent 	if (ab8500->irq_base) {
47762579266SRabin Vincent 		ret = ab8500_irq_init(ab8500);
47862579266SRabin Vincent 		if (ret)
47962579266SRabin Vincent 			return ret;
48062579266SRabin Vincent 
48162579266SRabin Vincent 		ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq,
48262579266SRabin Vincent 					   IRQF_ONESHOT, "ab8500", ab8500);
48362579266SRabin Vincent 		if (ret)
48462579266SRabin Vincent 			goto out_removeirq;
48562579266SRabin Vincent 	}
48662579266SRabin Vincent 
487549931f9SSundar R Iyer 	ret = mfd_add_devices(ab8500->dev, 0, ab8500_devs,
48862579266SRabin Vincent 			      ARRAY_SIZE(ab8500_devs), NULL,
48962579266SRabin Vincent 			      ab8500->irq_base);
49062579266SRabin Vincent 	if (ret)
49162579266SRabin Vincent 		goto out_freeirq;
49262579266SRabin Vincent 
49362579266SRabin Vincent 	return ret;
49462579266SRabin Vincent 
49562579266SRabin Vincent out_freeirq:
49662579266SRabin Vincent 	if (ab8500->irq_base) {
49762579266SRabin Vincent 		free_irq(ab8500->irq, ab8500);
49862579266SRabin Vincent out_removeirq:
49962579266SRabin Vincent 		ab8500_irq_remove(ab8500);
50062579266SRabin Vincent 	}
50162579266SRabin Vincent 	return ret;
50262579266SRabin Vincent }
50362579266SRabin Vincent 
50462579266SRabin Vincent int __devexit ab8500_exit(struct ab8500 *ab8500)
50562579266SRabin Vincent {
50662579266SRabin Vincent 	mfd_remove_devices(ab8500->dev);
50762579266SRabin Vincent 	if (ab8500->irq_base) {
50862579266SRabin Vincent 		free_irq(ab8500->irq, ab8500);
50962579266SRabin Vincent 		ab8500_irq_remove(ab8500);
51062579266SRabin Vincent 	}
51162579266SRabin Vincent 
51262579266SRabin Vincent 	return 0;
51362579266SRabin Vincent }
51462579266SRabin Vincent 
51562579266SRabin Vincent MODULE_AUTHOR("Srinidhi Kasagar, Rabin Vincent");
51662579266SRabin Vincent MODULE_DESCRIPTION("AB8500 MFD core");
51762579266SRabin Vincent MODULE_LICENSE("GPL v2");
518