Commit 62579266cf9caca5b999560be2b5ceee42fc4d4d
Committed by
Samuel Ortiz
1 parent
75907a1153
Exists in
master
and in
7 other branches
mfd: New AB8500 driver
Add a new driver to support the AB8500 Power Management chip, replacing the current AB4500. The new driver replaces the old one, instead of an incremental modification, because this is a substantial overhaul including: - Split of the driver into -core and -spi portions, to allow another interface layer to be added - Addition of interrupt support - Switch to MFD core API for handling subdevices - Simplification of the APIs to remove a redundant block parameter - Rename of the APIs and macros from ab4500_* to ab8500_* - Rename of the files from ab4500* to ab8500* - Change of the driver name from ab4500 to ab8500 Acked-by: Linus Walleij <linus.walleij@stericsson.com> Acked-by: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> Signed-off-by: Rabin Vincent <rabin.vincent@stericsson.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Showing 8 changed files with 712 additions and 477 deletions Side-by-side Diff
arch/arm/mach-ux500/board-mop500.c
drivers/mfd/Kconfig
... | ... | @@ -420,11 +420,12 @@ |
420 | 420 | This enables the PCAP ASIC present on EZX Phones. This is |
421 | 421 | needed for MMC, TouchScreen, Sound, USB, etc.. |
422 | 422 | |
423 | -config AB4500_CORE | |
424 | - tristate "ST-Ericsson's AB4500 Mixed Signal Power management chip" | |
425 | - depends on SPI | |
423 | +config AB8500_CORE | |
424 | + bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" | |
425 | + depends on SPI=y && GENERIC_HARDIRQS | |
426 | + select MFD_CORE | |
426 | 427 | help |
427 | - Select this option to enable access to AB4500 power management | |
428 | + Select this option to enable access to AB8500 power management | |
428 | 429 | chip. This connects to U8500 on the SSP/SPI bus and exports |
429 | 430 | read/write functions for the devices to get access to this chip. |
430 | 431 | This chip embeds various other multimedia funtionalities as well. |
drivers/mfd/Makefile
... | ... | @@ -64,8 +64,8 @@ |
64 | 64 | obj-$(CONFIG_ABX500_CORE) += abx500-core.o |
65 | 65 | obj-$(CONFIG_AB3100_CORE) += ab3100-core.o |
66 | 66 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o |
67 | -obj-$(CONFIG_AB4500_CORE) += ab4500-core.o | |
68 | 67 | obj-$(CONFIG_AB3550_CORE) += ab3550-core.o |
68 | +obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-spi.o | |
69 | 69 | obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o |
70 | 70 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o |
71 | 71 | obj-$(CONFIG_LPC_SCH) += lpc_sch.o |
drivers/mfd/ab4500-core.c
1 | -/* | |
2 | - * Copyright (C) 2009 ST-Ericsson | |
3 | - * | |
4 | - * Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com> | |
5 | - * | |
6 | - * This program is free software; you can redistribute it | |
7 | - * and/or modify it under the terms of the GNU General Public | |
8 | - * License version 2, as published by the Free Software Foundation. | |
9 | - * | |
10 | - * AB4500 is a companion power management chip used with U8500. | |
11 | - * On this platform, this is interfaced with SSP0 controller | |
12 | - * which is a ARM primecell pl022. | |
13 | - * | |
14 | - * At the moment the module just exports read/write features. | |
15 | - * Interrupt management to be added - TODO. | |
16 | - */ | |
17 | -#include <linux/kernel.h> | |
18 | -#include <linux/slab.h> | |
19 | -#include <linux/init.h> | |
20 | -#include <linux/module.h> | |
21 | -#include <linux/platform_device.h> | |
22 | -#include <linux/spi/spi.h> | |
23 | -#include <linux/mfd/ab4500.h> | |
24 | - | |
25 | -/* just required if probe fails, we need to | |
26 | - * unregister the device | |
27 | - */ | |
28 | -static struct spi_driver ab4500_driver; | |
29 | - | |
30 | -/* | |
31 | - * This funtion writes to any AB4500 registers using | |
32 | - * SPI protocol & before it writes it packs the data | |
33 | - * in the below 24 bit frame format | |
34 | - * | |
35 | - * *|------------------------------------| | |
36 | - * *| 23|22...18|17.......10|9|8|7......0| | |
37 | - * *| r/w bank adr data | | |
38 | - * * ------------------------------------ | |
39 | - * | |
40 | - * This function shouldn't be called from interrupt | |
41 | - * context | |
42 | - */ | |
43 | -int ab4500_write(struct ab4500 *ab4500, unsigned char block, | |
44 | - unsigned long addr, unsigned char data) | |
45 | -{ | |
46 | - struct spi_transfer xfer; | |
47 | - struct spi_message msg; | |
48 | - int err; | |
49 | - unsigned long spi_data = | |
50 | - block << 18 | addr << 10 | data; | |
51 | - | |
52 | - mutex_lock(&ab4500->lock); | |
53 | - ab4500->tx_buf[0] = spi_data; | |
54 | - ab4500->rx_buf[0] = 0; | |
55 | - | |
56 | - xfer.tx_buf = ab4500->tx_buf; | |
57 | - xfer.rx_buf = NULL; | |
58 | - xfer.len = sizeof(unsigned long); | |
59 | - | |
60 | - spi_message_init(&msg); | |
61 | - spi_message_add_tail(&xfer, &msg); | |
62 | - | |
63 | - err = spi_sync(ab4500->spi, &msg); | |
64 | - mutex_unlock(&ab4500->lock); | |
65 | - | |
66 | - return err; | |
67 | -} | |
68 | -EXPORT_SYMBOL(ab4500_write); | |
69 | - | |
70 | -int ab4500_read(struct ab4500 *ab4500, unsigned char block, | |
71 | - unsigned long addr) | |
72 | -{ | |
73 | - struct spi_transfer xfer; | |
74 | - struct spi_message msg; | |
75 | - unsigned long spi_data = | |
76 | - 1 << 23 | block << 18 | addr << 10; | |
77 | - | |
78 | - mutex_lock(&ab4500->lock); | |
79 | - ab4500->tx_buf[0] = spi_data; | |
80 | - ab4500->rx_buf[0] = 0; | |
81 | - | |
82 | - xfer.tx_buf = ab4500->tx_buf; | |
83 | - xfer.rx_buf = ab4500->rx_buf; | |
84 | - xfer.len = sizeof(unsigned long); | |
85 | - | |
86 | - spi_message_init(&msg); | |
87 | - spi_message_add_tail(&xfer, &msg); | |
88 | - | |
89 | - spi_sync(ab4500->spi, &msg); | |
90 | - mutex_unlock(&ab4500->lock); | |
91 | - | |
92 | - return ab4500->rx_buf[0]; | |
93 | -} | |
94 | -EXPORT_SYMBOL(ab4500_read); | |
95 | - | |
96 | -/* ref: ab3100 core */ | |
97 | -#define AB4500_DEVICE(devname, devid) \ | |
98 | -static struct platform_device ab4500_##devname##_device = { \ | |
99 | - .name = devid, \ | |
100 | - .id = -1, \ | |
101 | -} | |
102 | - | |
103 | -/* list of childern devices of ab4500 - all are | |
104 | - * not populated here - TODO | |
105 | - */ | |
106 | -AB4500_DEVICE(charger, "ab4500-charger"); | |
107 | -AB4500_DEVICE(audio, "ab4500-audio"); | |
108 | -AB4500_DEVICE(usb, "ab4500-usb"); | |
109 | -AB4500_DEVICE(tvout, "ab4500-tvout"); | |
110 | -AB4500_DEVICE(sim, "ab4500-sim"); | |
111 | -AB4500_DEVICE(gpadc, "ab4500-gpadc"); | |
112 | -AB4500_DEVICE(clkmgt, "ab4500-clkmgt"); | |
113 | -AB4500_DEVICE(misc, "ab4500-misc"); | |
114 | - | |
115 | -static struct platform_device *ab4500_platform_devs[] = { | |
116 | - &ab4500_charger_device, | |
117 | - &ab4500_audio_device, | |
118 | - &ab4500_usb_device, | |
119 | - &ab4500_tvout_device, | |
120 | - &ab4500_sim_device, | |
121 | - &ab4500_gpadc_device, | |
122 | - &ab4500_clkmgt_device, | |
123 | - &ab4500_misc_device, | |
124 | -}; | |
125 | - | |
126 | -static int __init ab4500_probe(struct spi_device *spi) | |
127 | -{ | |
128 | - struct ab4500 *ab4500; | |
129 | - unsigned char revision; | |
130 | - int err = 0; | |
131 | - int i; | |
132 | - | |
133 | - ab4500 = kzalloc(sizeof *ab4500, GFP_KERNEL); | |
134 | - if (!ab4500) { | |
135 | - dev_err(&spi->dev, "could not allocate AB4500\n"); | |
136 | - err = -ENOMEM; | |
137 | - goto not_detect; | |
138 | - } | |
139 | - | |
140 | - ab4500->spi = spi; | |
141 | - spi_set_drvdata(spi, ab4500); | |
142 | - | |
143 | - mutex_init(&ab4500->lock); | |
144 | - | |
145 | - /* read the revision register */ | |
146 | - revision = ab4500_read(ab4500, AB4500_MISC, AB4500_REV_REG); | |
147 | - | |
148 | - /* revision id 0x0 is for early drop, 0x10 is for cut1.0 */ | |
149 | - if (revision == 0x0 || revision == 0x10) | |
150 | - dev_info(&spi->dev, "Detected chip: %s, revision = %x\n", | |
151 | - ab4500_driver.driver.name, revision); | |
152 | - else { | |
153 | - dev_err(&spi->dev, "unknown chip: 0x%x\n", revision); | |
154 | - goto not_detect; | |
155 | - } | |
156 | - | |
157 | - for (i = 0; i < ARRAY_SIZE(ab4500_platform_devs); i++) { | |
158 | - ab4500_platform_devs[i]->dev.parent = | |
159 | - &spi->dev; | |
160 | - platform_set_drvdata(ab4500_platform_devs[i], ab4500); | |
161 | - } | |
162 | - | |
163 | - /* register the ab4500 platform devices */ | |
164 | - platform_add_devices(ab4500_platform_devs, | |
165 | - ARRAY_SIZE(ab4500_platform_devs)); | |
166 | - | |
167 | - return err; | |
168 | - | |
169 | - not_detect: | |
170 | - spi_unregister_driver(&ab4500_driver); | |
171 | - kfree(ab4500); | |
172 | - return err; | |
173 | -} | |
174 | - | |
175 | -static int __devexit ab4500_remove(struct spi_device *spi) | |
176 | -{ | |
177 | - struct ab4500 *ab4500 = | |
178 | - spi_get_drvdata(spi); | |
179 | - | |
180 | - kfree(ab4500); | |
181 | - | |
182 | - return 0; | |
183 | -} | |
184 | - | |
185 | -static struct spi_driver ab4500_driver = { | |
186 | - .driver = { | |
187 | - .name = "ab4500", | |
188 | - .owner = THIS_MODULE, | |
189 | - }, | |
190 | - .probe = ab4500_probe, | |
191 | - .remove = __devexit_p(ab4500_remove) | |
192 | -}; | |
193 | - | |
194 | -static int __devinit ab4500_init(void) | |
195 | -{ | |
196 | - return spi_register_driver(&ab4500_driver); | |
197 | -} | |
198 | - | |
199 | -static void __exit ab4500_exit(void) | |
200 | -{ | |
201 | - spi_unregister_driver(&ab4500_driver); | |
202 | -} | |
203 | - | |
204 | -subsys_initcall(ab4500_init); | |
205 | -module_exit(ab4500_exit); | |
206 | - | |
207 | -MODULE_AUTHOR("Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com"); | |
208 | -MODULE_DESCRIPTION("AB4500 core driver"); | |
209 | -MODULE_LICENSE("GPL"); |
drivers/mfd/ab8500-core.c
1 | +/* | |
2 | + * Copyright (C) ST-Ericsson SA 2010 | |
3 | + * | |
4 | + * License Terms: GNU General Public License v2 | |
5 | + * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> | |
6 | + * Author: Rabin Vincent <rabin.vincent@stericsson.com> | |
7 | + */ | |
8 | + | |
9 | +#include <linux/kernel.h> | |
10 | +#include <linux/slab.h> | |
11 | +#include <linux/init.h> | |
12 | +#include <linux/irq.h> | |
13 | +#include <linux/delay.h> | |
14 | +#include <linux/interrupt.h> | |
15 | +#include <linux/module.h> | |
16 | +#include <linux/platform_device.h> | |
17 | +#include <linux/mfd/core.h> | |
18 | +#include <linux/mfd/ab8500.h> | |
19 | + | |
20 | +/* | |
21 | + * Interrupt register offsets | |
22 | + * Bank : 0x0E | |
23 | + */ | |
24 | +#define AB8500_IT_SOURCE1_REG 0x0E00 | |
25 | +#define AB8500_IT_SOURCE2_REG 0x0E01 | |
26 | +#define AB8500_IT_SOURCE3_REG 0x0E02 | |
27 | +#define AB8500_IT_SOURCE4_REG 0x0E03 | |
28 | +#define AB8500_IT_SOURCE5_REG 0x0E04 | |
29 | +#define AB8500_IT_SOURCE6_REG 0x0E05 | |
30 | +#define AB8500_IT_SOURCE7_REG 0x0E06 | |
31 | +#define AB8500_IT_SOURCE8_REG 0x0E07 | |
32 | +#define AB8500_IT_SOURCE19_REG 0x0E12 | |
33 | +#define AB8500_IT_SOURCE20_REG 0x0E13 | |
34 | +#define AB8500_IT_SOURCE21_REG 0x0E14 | |
35 | +#define AB8500_IT_SOURCE22_REG 0x0E15 | |
36 | +#define AB8500_IT_SOURCE23_REG 0x0E16 | |
37 | +#define AB8500_IT_SOURCE24_REG 0x0E17 | |
38 | + | |
39 | +/* | |
40 | + * latch registers | |
41 | + */ | |
42 | +#define AB8500_IT_LATCH1_REG 0x0E20 | |
43 | +#define AB8500_IT_LATCH2_REG 0x0E21 | |
44 | +#define AB8500_IT_LATCH3_REG 0x0E22 | |
45 | +#define AB8500_IT_LATCH4_REG 0x0E23 | |
46 | +#define AB8500_IT_LATCH5_REG 0x0E24 | |
47 | +#define AB8500_IT_LATCH6_REG 0x0E25 | |
48 | +#define AB8500_IT_LATCH7_REG 0x0E26 | |
49 | +#define AB8500_IT_LATCH8_REG 0x0E27 | |
50 | +#define AB8500_IT_LATCH9_REG 0x0E28 | |
51 | +#define AB8500_IT_LATCH10_REG 0x0E29 | |
52 | +#define AB8500_IT_LATCH19_REG 0x0E32 | |
53 | +#define AB8500_IT_LATCH20_REG 0x0E33 | |
54 | +#define AB8500_IT_LATCH21_REG 0x0E34 | |
55 | +#define AB8500_IT_LATCH22_REG 0x0E35 | |
56 | +#define AB8500_IT_LATCH23_REG 0x0E36 | |
57 | +#define AB8500_IT_LATCH24_REG 0x0E37 | |
58 | + | |
59 | +/* | |
60 | + * mask registers | |
61 | + */ | |
62 | + | |
63 | +#define AB8500_IT_MASK1_REG 0x0E40 | |
64 | +#define AB8500_IT_MASK2_REG 0x0E41 | |
65 | +#define AB8500_IT_MASK3_REG 0x0E42 | |
66 | +#define AB8500_IT_MASK4_REG 0x0E43 | |
67 | +#define AB8500_IT_MASK5_REG 0x0E44 | |
68 | +#define AB8500_IT_MASK6_REG 0x0E45 | |
69 | +#define AB8500_IT_MASK7_REG 0x0E46 | |
70 | +#define AB8500_IT_MASK8_REG 0x0E47 | |
71 | +#define AB8500_IT_MASK9_REG 0x0E48 | |
72 | +#define AB8500_IT_MASK10_REG 0x0E49 | |
73 | +#define AB8500_IT_MASK11_REG 0x0E4A | |
74 | +#define AB8500_IT_MASK12_REG 0x0E4B | |
75 | +#define AB8500_IT_MASK13_REG 0x0E4C | |
76 | +#define AB8500_IT_MASK14_REG 0x0E4D | |
77 | +#define AB8500_IT_MASK15_REG 0x0E4E | |
78 | +#define AB8500_IT_MASK16_REG 0x0E4F | |
79 | +#define AB8500_IT_MASK17_REG 0x0E50 | |
80 | +#define AB8500_IT_MASK18_REG 0x0E51 | |
81 | +#define AB8500_IT_MASK19_REG 0x0E52 | |
82 | +#define AB8500_IT_MASK20_REG 0x0E53 | |
83 | +#define AB8500_IT_MASK21_REG 0x0E54 | |
84 | +#define AB8500_IT_MASK22_REG 0x0E55 | |
85 | +#define AB8500_IT_MASK23_REG 0x0E56 | |
86 | +#define AB8500_IT_MASK24_REG 0x0E57 | |
87 | + | |
88 | +#define AB8500_REV_REG 0x1080 | |
89 | + | |
90 | +/* | |
91 | + * Map interrupt numbers to the LATCH and MASK register offsets, Interrupt | |
92 | + * numbers are indexed into this array with (num / 8). | |
93 | + * | |
94 | + * This is one off from the register names, i.e. AB8500_IT_MASK1_REG is at | |
95 | + * offset 0. | |
96 | + */ | |
97 | +static const int ab8500_irq_regoffset[AB8500_NUM_IRQ_REGS] = { | |
98 | + 0, 1, 2, 3, 4, 6, 7, 8, 9, 18, 19, 20, 21, | |
99 | +}; | |
100 | + | |
101 | +static int __ab8500_write(struct ab8500 *ab8500, u16 addr, u8 data) | |
102 | +{ | |
103 | + int ret; | |
104 | + | |
105 | + dev_vdbg(ab8500->dev, "wr: addr %#x <= %#x\n", addr, data); | |
106 | + | |
107 | + ret = ab8500->write(ab8500, addr, data); | |
108 | + if (ret < 0) | |
109 | + dev_err(ab8500->dev, "failed to write reg %#x: %d\n", | |
110 | + addr, ret); | |
111 | + | |
112 | + return ret; | |
113 | +} | |
114 | + | |
115 | +/** | |
116 | + * ab8500_write() - write an AB8500 register | |
117 | + * @ab8500: device to write to | |
118 | + * @addr: address of the register | |
119 | + * @data: value to write | |
120 | + */ | |
121 | +int ab8500_write(struct ab8500 *ab8500, u16 addr, u8 data) | |
122 | +{ | |
123 | + int ret; | |
124 | + | |
125 | + mutex_lock(&ab8500->lock); | |
126 | + ret = __ab8500_write(ab8500, addr, data); | |
127 | + mutex_unlock(&ab8500->lock); | |
128 | + | |
129 | + return ret; | |
130 | +} | |
131 | +EXPORT_SYMBOL_GPL(ab8500_write); | |
132 | + | |
133 | +static int __ab8500_read(struct ab8500 *ab8500, u16 addr) | |
134 | +{ | |
135 | + int ret; | |
136 | + | |
137 | + ret = ab8500->read(ab8500, addr); | |
138 | + if (ret < 0) | |
139 | + dev_err(ab8500->dev, "failed to read reg %#x: %d\n", | |
140 | + addr, ret); | |
141 | + | |
142 | + dev_vdbg(ab8500->dev, "rd: addr %#x => data %#x\n", addr, ret); | |
143 | + | |
144 | + return ret; | |
145 | +} | |
146 | + | |
147 | +/** | |
148 | + * ab8500_read() - read an AB8500 register | |
149 | + * @ab8500: device to read from | |
150 | + * @addr: address of the register | |
151 | + */ | |
152 | +int ab8500_read(struct ab8500 *ab8500, u16 addr) | |
153 | +{ | |
154 | + int ret; | |
155 | + | |
156 | + mutex_lock(&ab8500->lock); | |
157 | + ret = __ab8500_read(ab8500, addr); | |
158 | + mutex_unlock(&ab8500->lock); | |
159 | + | |
160 | + return ret; | |
161 | +} | |
162 | +EXPORT_SYMBOL_GPL(ab8500_read); | |
163 | + | |
164 | +/** | |
165 | + * ab8500_set_bits() - set a bitfield in an AB8500 register | |
166 | + * @ab8500: device to read from | |
167 | + * @addr: address of the register | |
168 | + * @mask: mask of the bitfield to modify | |
169 | + * @data: value to set to the bitfield | |
170 | + */ | |
171 | +int ab8500_set_bits(struct ab8500 *ab8500, u16 addr, u8 mask, u8 data) | |
172 | +{ | |
173 | + int ret; | |
174 | + | |
175 | + mutex_lock(&ab8500->lock); | |
176 | + | |
177 | + ret = __ab8500_read(ab8500, addr); | |
178 | + if (ret < 0) | |
179 | + goto out; | |
180 | + | |
181 | + ret &= ~mask; | |
182 | + ret |= data; | |
183 | + | |
184 | + ret = __ab8500_write(ab8500, addr, ret); | |
185 | + | |
186 | +out: | |
187 | + mutex_unlock(&ab8500->lock); | |
188 | + return ret; | |
189 | +} | |
190 | +EXPORT_SYMBOL_GPL(ab8500_set_bits); | |
191 | + | |
192 | +static void ab8500_irq_lock(unsigned int irq) | |
193 | +{ | |
194 | + struct ab8500 *ab8500 = get_irq_chip_data(irq); | |
195 | + | |
196 | + mutex_lock(&ab8500->irq_lock); | |
197 | +} | |
198 | + | |
199 | +static void ab8500_irq_sync_unlock(unsigned int irq) | |
200 | +{ | |
201 | + struct ab8500 *ab8500 = get_irq_chip_data(irq); | |
202 | + int i; | |
203 | + | |
204 | + for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) { | |
205 | + u8 old = ab8500->oldmask[i]; | |
206 | + u8 new = ab8500->mask[i]; | |
207 | + int reg; | |
208 | + | |
209 | + if (new == old) | |
210 | + continue; | |
211 | + | |
212 | + ab8500->oldmask[i] = new; | |
213 | + | |
214 | + reg = AB8500_IT_MASK1_REG + ab8500_irq_regoffset[i]; | |
215 | + ab8500_write(ab8500, reg, new); | |
216 | + } | |
217 | + | |
218 | + mutex_unlock(&ab8500->irq_lock); | |
219 | +} | |
220 | + | |
221 | +static void ab8500_irq_mask(unsigned int irq) | |
222 | +{ | |
223 | + struct ab8500 *ab8500 = get_irq_chip_data(irq); | |
224 | + int offset = irq - ab8500->irq_base; | |
225 | + int index = offset / 8; | |
226 | + int mask = 1 << (offset % 8); | |
227 | + | |
228 | + ab8500->mask[index] |= mask; | |
229 | +} | |
230 | + | |
231 | +static void ab8500_irq_unmask(unsigned int irq) | |
232 | +{ | |
233 | + struct ab8500 *ab8500 = get_irq_chip_data(irq); | |
234 | + int offset = irq - ab8500->irq_base; | |
235 | + int index = offset / 8; | |
236 | + int mask = 1 << (offset % 8); | |
237 | + | |
238 | + ab8500->mask[index] &= ~mask; | |
239 | +} | |
240 | + | |
241 | +static struct irq_chip ab8500_irq_chip = { | |
242 | + .name = "ab8500", | |
243 | + .bus_lock = ab8500_irq_lock, | |
244 | + .bus_sync_unlock = ab8500_irq_sync_unlock, | |
245 | + .mask = ab8500_irq_mask, | |
246 | + .unmask = ab8500_irq_unmask, | |
247 | +}; | |
248 | + | |
249 | +static irqreturn_t ab8500_irq(int irq, void *dev) | |
250 | +{ | |
251 | + struct ab8500 *ab8500 = dev; | |
252 | + int i; | |
253 | + | |
254 | + dev_vdbg(ab8500->dev, "interrupt\n"); | |
255 | + | |
256 | + for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) { | |
257 | + int regoffset = ab8500_irq_regoffset[i]; | |
258 | + int status; | |
259 | + | |
260 | + status = ab8500_read(ab8500, AB8500_IT_LATCH1_REG + regoffset); | |
261 | + if (status <= 0) | |
262 | + continue; | |
263 | + | |
264 | + do { | |
265 | + int bit = __ffs(status); | |
266 | + int line = i * 8 + bit; | |
267 | + | |
268 | + handle_nested_irq(ab8500->irq_base + line); | |
269 | + status &= ~(1 << bit); | |
270 | + } while (status); | |
271 | + } | |
272 | + | |
273 | + return IRQ_HANDLED; | |
274 | +} | |
275 | + | |
276 | +static int ab8500_irq_init(struct ab8500 *ab8500) | |
277 | +{ | |
278 | + int base = ab8500->irq_base; | |
279 | + int irq; | |
280 | + | |
281 | + for (irq = base; irq < base + AB8500_NR_IRQS; irq++) { | |
282 | + set_irq_chip_data(irq, ab8500); | |
283 | + set_irq_chip_and_handler(irq, &ab8500_irq_chip, | |
284 | + handle_simple_irq); | |
285 | + set_irq_nested_thread(irq, 1); | |
286 | +#ifdef CONFIG_ARM | |
287 | + set_irq_flags(irq, IRQF_VALID); | |
288 | +#else | |
289 | + set_irq_noprobe(irq); | |
290 | +#endif | |
291 | + } | |
292 | + | |
293 | + return 0; | |
294 | +} | |
295 | + | |
296 | +static void ab8500_irq_remove(struct ab8500 *ab8500) | |
297 | +{ | |
298 | + int base = ab8500->irq_base; | |
299 | + int irq; | |
300 | + | |
301 | + for (irq = base; irq < base + AB8500_NR_IRQS; irq++) { | |
302 | +#ifdef CONFIG_ARM | |
303 | + set_irq_flags(irq, 0); | |
304 | +#endif | |
305 | + set_irq_chip_and_handler(irq, NULL, NULL); | |
306 | + set_irq_chip_data(irq, NULL); | |
307 | + } | |
308 | +} | |
309 | + | |
310 | +static struct resource ab8500_gpadc_resources[] = { | |
311 | + { | |
312 | + .name = "HW_CONV_END", | |
313 | + .start = AB8500_INT_GP_HW_ADC_CONV_END, | |
314 | + .end = AB8500_INT_GP_HW_ADC_CONV_END, | |
315 | + .flags = IORESOURCE_IRQ, | |
316 | + }, | |
317 | + { | |
318 | + .name = "SW_CONV_END", | |
319 | + .start = AB8500_INT_GP_SW_ADC_CONV_END, | |
320 | + .end = AB8500_INT_GP_SW_ADC_CONV_END, | |
321 | + .flags = IORESOURCE_IRQ, | |
322 | + }, | |
323 | +}; | |
324 | + | |
325 | +static struct resource ab8500_rtc_resources[] = { | |
326 | + { | |
327 | + .name = "60S", | |
328 | + .start = AB8500_INT_RTC_60S, | |
329 | + .end = AB8500_INT_RTC_60S, | |
330 | + .flags = IORESOURCE_IRQ, | |
331 | + }, | |
332 | + { | |
333 | + .name = "ALARM", | |
334 | + .start = AB8500_INT_RTC_ALARM, | |
335 | + .end = AB8500_INT_RTC_ALARM, | |
336 | + .flags = IORESOURCE_IRQ, | |
337 | + }, | |
338 | +}; | |
339 | + | |
340 | +static struct mfd_cell ab8500_devs[] = { | |
341 | + { | |
342 | + .name = "ab8500-gpadc", | |
343 | + .num_resources = ARRAY_SIZE(ab8500_gpadc_resources), | |
344 | + .resources = ab8500_gpadc_resources, | |
345 | + }, | |
346 | + { | |
347 | + .name = "ab8500-rtc", | |
348 | + .num_resources = ARRAY_SIZE(ab8500_rtc_resources), | |
349 | + .resources = ab8500_rtc_resources, | |
350 | + }, | |
351 | + { .name = "ab8500-charger", }, | |
352 | + { .name = "ab8500-audio", }, | |
353 | + { .name = "ab8500-usb", }, | |
354 | + { .name = "ab8500-pwm", }, | |
355 | +}; | |
356 | + | |
357 | +int __devinit ab8500_init(struct ab8500 *ab8500) | |
358 | +{ | |
359 | + struct ab8500_platform_data *plat = dev_get_platdata(ab8500->dev); | |
360 | + int ret; | |
361 | + int i; | |
362 | + | |
363 | + if (plat) | |
364 | + ab8500->irq_base = plat->irq_base; | |
365 | + | |
366 | + mutex_init(&ab8500->lock); | |
367 | + mutex_init(&ab8500->irq_lock); | |
368 | + | |
369 | + ret = ab8500_read(ab8500, AB8500_REV_REG); | |
370 | + if (ret < 0) | |
371 | + return ret; | |
372 | + | |
373 | + /* | |
374 | + * 0x0 - Early Drop | |
375 | + * 0x10 - Cut 1.0 | |
376 | + * 0x11 - Cut 1.1 | |
377 | + */ | |
378 | + if (ret == 0x0 || ret == 0x10 || ret == 0x11) { | |
379 | + ab8500->revision = ret; | |
380 | + dev_info(ab8500->dev, "detected chip, revision: %#x\n", ret); | |
381 | + } else { | |
382 | + dev_err(ab8500->dev, "unknown chip, revision: %#x\n", ret); | |
383 | + return -EINVAL; | |
384 | + } | |
385 | + | |
386 | + if (plat && plat->init) | |
387 | + plat->init(ab8500); | |
388 | + | |
389 | + /* Clear and mask all interrupts */ | |
390 | + for (i = 0; i < 10; i++) { | |
391 | + ab8500_read(ab8500, AB8500_IT_LATCH1_REG + i); | |
392 | + ab8500_write(ab8500, AB8500_IT_MASK1_REG + i, 0xff); | |
393 | + } | |
394 | + | |
395 | + for (i = 18; i < 24; i++) { | |
396 | + ab8500_read(ab8500, AB8500_IT_LATCH1_REG + i); | |
397 | + ab8500_write(ab8500, AB8500_IT_MASK1_REG + i, 0xff); | |
398 | + } | |
399 | + | |
400 | + for (i = 0; i < AB8500_NUM_IRQ_REGS; i++) | |
401 | + ab8500->mask[i] = ab8500->oldmask[i] = 0xff; | |
402 | + | |
403 | + if (ab8500->irq_base) { | |
404 | + ret = ab8500_irq_init(ab8500); | |
405 | + if (ret) | |
406 | + return ret; | |
407 | + | |
408 | + ret = request_threaded_irq(ab8500->irq, NULL, ab8500_irq, | |
409 | + IRQF_ONESHOT, "ab8500", ab8500); | |
410 | + if (ret) | |
411 | + goto out_removeirq; | |
412 | + } | |
413 | + | |
414 | + ret = mfd_add_devices(ab8500->dev, -1, ab8500_devs, | |
415 | + ARRAY_SIZE(ab8500_devs), NULL, | |
416 | + ab8500->irq_base); | |
417 | + if (ret) | |
418 | + goto out_freeirq; | |
419 | + | |
420 | + return ret; | |
421 | + | |
422 | +out_freeirq: | |
423 | + if (ab8500->irq_base) { | |
424 | + free_irq(ab8500->irq, ab8500); | |
425 | +out_removeirq: | |
426 | + ab8500_irq_remove(ab8500); | |
427 | + } | |
428 | + return ret; | |
429 | +} | |
430 | + | |
431 | +int __devexit ab8500_exit(struct ab8500 *ab8500) | |
432 | +{ | |
433 | + mfd_remove_devices(ab8500->dev); | |
434 | + if (ab8500->irq_base) { | |
435 | + free_irq(ab8500->irq, ab8500); | |
436 | + ab8500_irq_remove(ab8500); | |
437 | + } | |
438 | + | |
439 | + return 0; | |
440 | +} | |
441 | + | |
442 | +MODULE_AUTHOR("Srinidhi Kasagar, Rabin Vincent"); | |
443 | +MODULE_DESCRIPTION("AB8500 MFD core"); | |
444 | +MODULE_LICENSE("GPL v2"); |
drivers/mfd/ab8500-spi.c
1 | +/* | |
2 | + * Copyright (C) ST-Ericsson SA 2010 | |
3 | + * | |
4 | + * License Terms: GNU General Public License v2 | |
5 | + * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> | |
6 | + */ | |
7 | + | |
8 | +#include <linux/kernel.h> | |
9 | +#include <linux/slab.h> | |
10 | +#include <linux/init.h> | |
11 | +#include <linux/module.h> | |
12 | +#include <linux/platform_device.h> | |
13 | +#include <linux/spi/spi.h> | |
14 | +#include <linux/mfd/ab8500.h> | |
15 | + | |
16 | +/* | |
17 | + * This funtion writes to any AB8500 registers using | |
18 | + * SPI protocol & before it writes it packs the data | |
19 | + * in the below 24 bit frame format | |
20 | + * | |
21 | + * *|------------------------------------| | |
22 | + * *| 23|22...18|17.......10|9|8|7......0| | |
23 | + * *| r/w bank adr data | | |
24 | + * * ------------------------------------ | |
25 | + * | |
26 | + * This function shouldn't be called from interrupt | |
27 | + * context | |
28 | + */ | |
29 | +static int ab8500_spi_write(struct ab8500 *ab8500, u16 addr, u8 data) | |
30 | +{ | |
31 | + struct spi_device *spi = container_of(ab8500->dev, struct spi_device, | |
32 | + dev); | |
33 | + unsigned long spi_data = addr << 10 | data; | |
34 | + struct spi_transfer xfer; | |
35 | + struct spi_message msg; | |
36 | + | |
37 | + ab8500->tx_buf[0] = spi_data; | |
38 | + ab8500->rx_buf[0] = 0; | |
39 | + | |
40 | + xfer.tx_buf = ab8500->tx_buf; | |
41 | + xfer.rx_buf = NULL; | |
42 | + xfer.len = sizeof(unsigned long); | |
43 | + | |
44 | + spi_message_init(&msg); | |
45 | + spi_message_add_tail(&xfer, &msg); | |
46 | + | |
47 | + return spi_sync(spi, &msg); | |
48 | +} | |
49 | + | |
50 | +static int ab8500_spi_read(struct ab8500 *ab8500, u16 addr) | |
51 | +{ | |
52 | + struct spi_device *spi = container_of(ab8500->dev, struct spi_device, | |
53 | + dev); | |
54 | + unsigned long spi_data = 1 << 23 | addr << 10; | |
55 | + struct spi_transfer xfer; | |
56 | + struct spi_message msg; | |
57 | + int ret; | |
58 | + | |
59 | + ab8500->tx_buf[0] = spi_data; | |
60 | + ab8500->rx_buf[0] = 0; | |
61 | + | |
62 | + xfer.tx_buf = ab8500->tx_buf; | |
63 | + xfer.rx_buf = ab8500->rx_buf; | |
64 | + xfer.len = sizeof(unsigned long); | |
65 | + | |
66 | + spi_message_init(&msg); | |
67 | + spi_message_add_tail(&xfer, &msg); | |
68 | + | |
69 | + ret = spi_sync(spi, &msg); | |
70 | + if (!ret) | |
71 | + ret = ab8500->rx_buf[0]; | |
72 | + | |
73 | + return ret; | |
74 | +} | |
75 | + | |
76 | +static int __devinit ab8500_spi_probe(struct spi_device *spi) | |
77 | +{ | |
78 | + struct ab8500 *ab8500; | |
79 | + int ret; | |
80 | + | |
81 | + ab8500 = kzalloc(sizeof *ab8500, GFP_KERNEL); | |
82 | + if (!ab8500) | |
83 | + return -ENOMEM; | |
84 | + | |
85 | + ab8500->dev = &spi->dev; | |
86 | + ab8500->irq = spi->irq; | |
87 | + | |
88 | + ab8500->read = ab8500_spi_read; | |
89 | + ab8500->write = ab8500_spi_write; | |
90 | + | |
91 | + spi_set_drvdata(spi, ab8500); | |
92 | + | |
93 | + ret = ab8500_init(ab8500); | |
94 | + if (ret) | |
95 | + kfree(ab8500); | |
96 | + | |
97 | + return ret; | |
98 | +} | |
99 | + | |
100 | +static int __devexit ab8500_spi_remove(struct spi_device *spi) | |
101 | +{ | |
102 | + struct ab8500 *ab8500 = spi_get_drvdata(spi); | |
103 | + | |
104 | + ab8500_exit(ab8500); | |
105 | + kfree(ab8500); | |
106 | + | |
107 | + return 0; | |
108 | +} | |
109 | + | |
110 | +static struct spi_driver ab8500_spi_driver = { | |
111 | + .driver = { | |
112 | + .name = "ab8500", | |
113 | + .owner = THIS_MODULE, | |
114 | + }, | |
115 | + .probe = ab8500_spi_probe, | |
116 | + .remove = __devexit_p(ab8500_spi_remove) | |
117 | +}; | |
118 | + | |
119 | +static int __init ab8500_spi_init(void) | |
120 | +{ | |
121 | + return spi_register_driver(&ab8500_spi_driver); | |
122 | +} | |
123 | +subsys_initcall(ab8500_spi_init); | |
124 | + | |
125 | +static void __exit ab8500_spi_exit(void) | |
126 | +{ | |
127 | + spi_unregister_driver(&ab8500_spi_driver); | |
128 | +} | |
129 | +module_exit(ab8500_spi_exit); | |
130 | + | |
131 | +MODULE_AUTHOR("Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com"); | |
132 | +MODULE_DESCRIPTION("AB8500 SPI"); | |
133 | +MODULE_LICENSE("GPL v2"); |
include/linux/mfd/ab4500.h
1 | -/* | |
2 | - * Copyright (C) 2009 ST-Ericsson | |
3 | - * | |
4 | - * Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com> | |
5 | - * | |
6 | - * This program is free software; you can redistribute it and/or modify | |
7 | - * it under the terms of the GNU General Public License version 2, as | |
8 | - * published by the Free Software Foundation. | |
9 | - * | |
10 | - * AB4500 device core funtions, for client access | |
11 | - */ | |
12 | -#ifndef MFD_AB4500_H | |
13 | -#define MFD_AB4500_H | |
14 | - | |
15 | -#include <linux/device.h> | |
16 | - | |
17 | -/* | |
18 | - * AB4500 bank addresses | |
19 | - */ | |
20 | -#define AB4500_SYS_CTRL1_BLOCK 0x1 | |
21 | -#define AB4500_SYS_CTRL2_BLOCK 0x2 | |
22 | -#define AB4500_REGU_CTRL1 0x3 | |
23 | -#define AB4500_REGU_CTRL2 0x4 | |
24 | -#define AB4500_USB 0x5 | |
25 | -#define AB4500_TVOUT 0x6 | |
26 | -#define AB4500_DBI 0x7 | |
27 | -#define AB4500_ECI_AV_ACC 0x8 | |
28 | -#define AB4500_RESERVED 0x9 | |
29 | -#define AB4500_GPADC 0xA | |
30 | -#define AB4500_CHARGER 0xB | |
31 | -#define AB4500_GAS_GAUGE 0xC | |
32 | -#define AB4500_AUDIO 0xD | |
33 | -#define AB4500_INTERRUPT 0xE | |
34 | -#define AB4500_RTC 0xF | |
35 | -#define AB4500_MISC 0x10 | |
36 | -#define AB4500_DEBUG 0x12 | |
37 | -#define AB4500_PROD_TEST 0x13 | |
38 | -#define AB4500_OTP_EMUL 0x15 | |
39 | - | |
40 | -/* | |
41 | - * System control 1 register offsets. | |
42 | - * Bank = 0x01 | |
43 | - */ | |
44 | -#define AB4500_TURNON_STAT_REG 0x0100 | |
45 | -#define AB4500_RESET_STAT_REG 0x0101 | |
46 | -#define AB4500_PONKEY1_PRESS_STAT_REG 0x0102 | |
47 | - | |
48 | -#define AB4500_FSM_STAT1_REG 0x0140 | |
49 | -#define AB4500_FSM_STAT2_REG 0x0141 | |
50 | -#define AB4500_SYSCLK_REQ_STAT_REG 0x0142 | |
51 | -#define AB4500_USB_STAT1_REG 0x0143 | |
52 | -#define AB4500_USB_STAT2_REG 0x0144 | |
53 | -#define AB4500_STATUS_SPARE1_REG 0x0145 | |
54 | -#define AB4500_STATUS_SPARE2_REG 0x0146 | |
55 | - | |
56 | -#define AB4500_CTRL1_REG 0x0180 | |
57 | -#define AB4500_CTRL2_REG 0x0181 | |
58 | - | |
59 | -/* | |
60 | - * System control 2 register offsets. | |
61 | - * bank = 0x02 | |
62 | - */ | |
63 | -#define AB4500_CTRL3_REG 0x0200 | |
64 | -#define AB4500_MAIN_WDOG_CTRL_REG 0x0201 | |
65 | -#define AB4500_MAIN_WDOG_TIMER_REG 0x0202 | |
66 | -#define AB4500_LOW_BAT_REG 0x0203 | |
67 | -#define AB4500_BATT_OK_REG 0x0204 | |
68 | -#define AB4500_SYSCLK_TIMER_REG 0x0205 | |
69 | -#define AB4500_SMPSCLK_CTRL_REG 0x0206 | |
70 | -#define AB4500_SMPSCLK_SEL1_REG 0x0207 | |
71 | -#define AB4500_SMPSCLK_SEL2_REG 0x0208 | |
72 | -#define AB4500_SMPSCLK_SEL3_REG 0x0209 | |
73 | -#define AB4500_SYSULPCLK_CONF_REG 0x020A | |
74 | -#define AB4500_SYSULPCLK_CTRL1_REG 0x020B | |
75 | -#define AB4500_SYSCLK_CTRL_REG 0x020C | |
76 | -#define AB4500_SYSCLK_REQ1_VALID_REG 0x020D | |
77 | -#define AB4500_SYSCLK_REQ_VALID_REG 0x020E | |
78 | -#define AB4500_SYSCTRL_SPARE_REG 0x020F | |
79 | -#define AB4500_PAD_CONF_REG 0x0210 | |
80 | - | |
81 | -/* | |
82 | - * Regu control1 register offsets | |
83 | - * Bank = 0x03 | |
84 | - */ | |
85 | -#define AB4500_REGU_SERIAL_CTRL1_REG 0x0300 | |
86 | -#define AB4500_REGU_SERIAL_CTRL2_REG 0x0301 | |
87 | -#define AB4500_REGU_SERIAL_CTRL3_REG 0x0302 | |
88 | -#define AB4500_REGU_REQ_CTRL1_REG 0x0303 | |
89 | -#define AB4500_REGU_REQ_CTRL2_REG 0x0304 | |
90 | -#define AB4500_REGU_REQ_CTRL3_REG 0x0305 | |
91 | -#define AB4500_REGU_REQ_CTRL4_REG 0x0306 | |
92 | -#define AB4500_REGU_MISC1_REG 0x0380 | |
93 | -#define AB4500_REGU_OTGSUPPLY_CTRL_REG 0x0381 | |
94 | -#define AB4500_REGU_VUSB_CTRL_REG 0x0382 | |
95 | -#define AB4500_REGU_VAUDIO_SUPPLY_REG 0x0383 | |
96 | -#define AB4500_REGU_CTRL1_SPARE_REG 0x0384 | |
97 | - | |
98 | -/* | |
99 | - * Regu control2 Vmod register offsets | |
100 | - */ | |
101 | -#define AB4500_REGU_VMOD_REGU_REG 0x0440 | |
102 | -#define AB4500_REGU_VMOD_SEL1_REG 0x0441 | |
103 | -#define AB4500_REGU_VMOD_SEL2_REG 0x0442 | |
104 | -#define AB4500_REGU_CTRL_DISCH_REG 0x0443 | |
105 | -#define AB4500_REGU_CTRL_DISCH2_REG 0x0444 | |
106 | - | |
107 | -/* | |
108 | - * USB/ULPI register offsets | |
109 | - * Bank : 0x5 | |
110 | - */ | |
111 | -#define AB4500_USB_LINE_STAT_REG 0x0580 | |
112 | -#define AB4500_USB_LINE_CTRL1_REG 0x0581 | |
113 | -#define AB4500_USB_LINE_CTRL2_REG 0x0582 | |
114 | -#define AB4500_USB_LINE_CTRL3_REG 0x0583 | |
115 | -#define AB4500_USB_LINE_CTRL4_REG 0x0584 | |
116 | -#define AB4500_USB_LINE_CTRL5_REG 0x0585 | |
117 | -#define AB4500_USB_OTG_CTRL_REG 0x0587 | |
118 | -#define AB4500_USB_OTG_STAT_REG 0x0588 | |
119 | -#define AB4500_USB_OTG_STAT_REG 0x0588 | |
120 | -#define AB4500_USB_CTRL_SPARE_REG 0x0589 | |
121 | -#define AB4500_USB_PHY_CTRL_REG 0x058A | |
122 | - | |
123 | -/* | |
124 | - * TVOUT / CTRL register offsets | |
125 | - * Bank : 0x06 | |
126 | - */ | |
127 | -#define AB4500_TVOUT_CTRL_REG 0x0680 | |
128 | - | |
129 | -/* | |
130 | - * DBI register offsets | |
131 | - * Bank : 0x07 | |
132 | - */ | |
133 | -#define AB4500_DBI_REG1_REG 0x0700 | |
134 | -#define AB4500_DBI_REG2_REG 0x0701 | |
135 | - | |
136 | -/* | |
137 | - * ECI regsiter offsets | |
138 | - * Bank : 0x08 | |
139 | - */ | |
140 | -#define AB4500_ECI_CTRL_REG 0x0800 | |
141 | -#define AB4500_ECI_HOOKLEVEL_REG 0x0801 | |
142 | -#define AB4500_ECI_DATAOUT_REG 0x0802 | |
143 | -#define AB4500_ECI_DATAIN_REG 0x0803 | |
144 | - | |
145 | -/* | |
146 | - * AV Connector register offsets | |
147 | - * Bank : 0x08 | |
148 | - */ | |
149 | -#define AB4500_AV_CONN_REG 0x0840 | |
150 | - | |
151 | -/* | |
152 | - * Accessory detection register offsets | |
153 | - * Bank : 0x08 | |
154 | - */ | |
155 | -#define AB4500_ACC_DET_DB1_REG 0x0880 | |
156 | -#define AB4500_ACC_DET_DB2_REG 0x0881 | |
157 | - | |
158 | -/* | |
159 | - * GPADC register offsets | |
160 | - * Bank : 0x0A | |
161 | - */ | |
162 | -#define AB4500_GPADC_CTRL1_REG 0x0A00 | |
163 | -#define AB4500_GPADC_CTRL2_REG 0x0A01 | |
164 | -#define AB4500_GPADC_CTRL3_REG 0x0A02 | |
165 | -#define AB4500_GPADC_AUTO_TIMER_REG 0x0A03 | |
166 | -#define AB4500_GPADC_STAT_REG 0x0A04 | |
167 | -#define AB4500_GPADC_MANDATAL_REG 0x0A05 | |
168 | -#define AB4500_GPADC_MANDATAH_REG 0x0A06 | |
169 | -#define AB4500_GPADC_AUTODATAL_REG 0x0A07 | |
170 | -#define AB4500_GPADC_AUTODATAH_REG 0x0A08 | |
171 | -#define AB4500_GPADC_MUX_CTRL_REG 0x0A09 | |
172 | - | |
173 | -/* | |
174 | - * Charger / status register offfsets | |
175 | - * Bank : 0x0B | |
176 | - */ | |
177 | -#define AB4500_CH_STATUS1_REG 0x0B00 | |
178 | -#define AB4500_CH_STATUS2_REG 0x0B01 | |
179 | -#define AB4500_CH_USBCH_STAT1_REG 0x0B02 | |
180 | -#define AB4500_CH_USBCH_STAT2_REG 0x0B03 | |
181 | -#define AB4500_CH_FSM_STAT_REG 0x0B04 | |
182 | -#define AB4500_CH_STAT_REG 0x0B05 | |
183 | - | |
184 | -/* | |
185 | - * Charger / control register offfsets | |
186 | - * Bank : 0x0B | |
187 | - */ | |
188 | -#define AB4500_CH_VOLT_LVL_REG 0x0B40 | |
189 | - | |
190 | -/* | |
191 | - * Charger / main control register offfsets | |
192 | - * Bank : 0x0B | |
193 | - */ | |
194 | -#define AB4500_MCH_CTRL1 0x0B80 | |
195 | -#define AB4500_MCH_CTRL2 0x0B81 | |
196 | -#define AB4500_MCH_IPT_CURLVL_REG 0x0B82 | |
197 | -#define AB4500_CH_WD_REG 0x0B83 | |
198 | - | |
199 | -/* | |
200 | - * Charger / USB control register offsets | |
201 | - * Bank : 0x0B | |
202 | - */ | |
203 | -#define AB4500_USBCH_CTRL1_REG 0x0BC0 | |
204 | -#define AB4500_USBCH_CTRL2_REG 0x0BC1 | |
205 | -#define AB4500_USBCH_IPT_CRNTLVL_REG 0x0BC2 | |
206 | - | |
207 | -/* | |
208 | - * RTC bank register offsets | |
209 | - * Bank : 0xF | |
210 | - */ | |
211 | -#define AB4500_RTC_SOFF_STAT_REG 0x0F00 | |
212 | -#define AB4500_RTC_CC_CONF_REG 0x0F01 | |
213 | -#define AB4500_RTC_READ_REQ_REG 0x0F02 | |
214 | -#define AB4500_RTC_WATCH_TSECMID_REG 0x0F03 | |
215 | -#define AB4500_RTC_WATCH_TSECHI_REG 0x0F04 | |
216 | -#define AB4500_RTC_WATCH_TMIN_LOW_REG 0x0F05 | |
217 | -#define AB4500_RTC_WATCH_TMIN_MID_REG 0x0F06 | |
218 | -#define AB4500_RTC_WATCH_TMIN_HI_REG 0x0F07 | |
219 | -#define AB4500_RTC_ALRM_MIN_LOW_REG 0x0F08 | |
220 | -#define AB4500_RTC_ALRM_MIN_MID_REG 0x0F09 | |
221 | -#define AB4500_RTC_ALRM_MIN_HI_REG 0x0F0A | |
222 | -#define AB4500_RTC_STAT_REG 0x0F0B | |
223 | -#define AB4500_RTC_BKUP_CHG_REG 0x0F0C | |
224 | -#define AB4500_RTC_FORCE_BKUP_REG 0x0F0D | |
225 | -#define AB4500_RTC_CALIB_REG 0x0F0E | |
226 | -#define AB4500_RTC_SWITCH_STAT_REG 0x0F0F | |
227 | - | |
228 | -/* | |
229 | - * PWM Out generators | |
230 | - * Bank: 0x10 | |
231 | - */ | |
232 | -#define AB4500_PWM_OUT_CTRL1_REG 0x1060 | |
233 | -#define AB4500_PWM_OUT_CTRL2_REG 0x1061 | |
234 | -#define AB4500_PWM_OUT_CTRL3_REG 0x1062 | |
235 | -#define AB4500_PWM_OUT_CTRL4_REG 0x1063 | |
236 | -#define AB4500_PWM_OUT_CTRL5_REG 0x1064 | |
237 | -#define AB4500_PWM_OUT_CTRL6_REG 0x1065 | |
238 | -#define AB4500_PWM_OUT_CTRL7_REG 0x1066 | |
239 | - | |
240 | -#define AB4500_I2C_PAD_CTRL_REG 0x1067 | |
241 | -#define AB4500_REV_REG 0x1080 | |
242 | - | |
243 | -/** | |
244 | - * struct ab4500 | |
245 | - * @spi: spi device structure | |
246 | - * @tx_buf: transmit buffer | |
247 | - * @rx_buf: receive buffer | |
248 | - * @lock: sync primitive | |
249 | - */ | |
250 | -struct ab4500 { | |
251 | - struct spi_device *spi; | |
252 | - unsigned long tx_buf[4]; | |
253 | - unsigned long rx_buf[4]; | |
254 | - struct mutex lock; | |
255 | -}; | |
256 | - | |
257 | -int ab4500_write(struct ab4500 *ab4500, unsigned char block, | |
258 | - unsigned long addr, unsigned char data); | |
259 | -int ab4500_read(struct ab4500 *ab4500, unsigned char block, | |
260 | - unsigned long addr); | |
261 | - | |
262 | -#endif /* MFD_AB4500_H */ |
include/linux/mfd/ab8500.h
1 | +/* | |
2 | + * Copyright (C) ST-Ericsson SA 2010 | |
3 | + * | |
4 | + * License Terms: GNU General Public License v2 | |
5 | + * Author: Srinidhi Kasagar <srinidhi.kasagar@stericsson.com> | |
6 | + */ | |
7 | +#ifndef MFD_AB8500_H | |
8 | +#define MFD_AB8500_H | |
9 | + | |
10 | +#include <linux/device.h> | |
11 | + | |
12 | +/* | |
13 | + * Interrupts | |
14 | + */ | |
15 | + | |
16 | +#define AB8500_INT_MAIN_EXT_CH_NOT_OK 0 | |
17 | +#define AB8500_INT_UN_PLUG_TV_DET 1 | |
18 | +#define AB8500_INT_PLUG_TV_DET 2 | |
19 | +#define AB8500_INT_TEMP_WARM 3 | |
20 | +#define AB8500_INT_PON_KEY2DB_F 4 | |
21 | +#define AB8500_INT_PON_KEY2DB_R 5 | |
22 | +#define AB8500_INT_PON_KEY1DB_F 6 | |
23 | +#define AB8500_INT_PON_KEY1DB_R 7 | |
24 | +#define AB8500_INT_BATT_OVV 8 | |
25 | +#define AB8500_INT_MAIN_CH_UNPLUG_DET 10 | |
26 | +#define AB8500_INT_MAIN_CH_PLUG_DET 11 | |
27 | +#define AB8500_INT_USB_ID_DET_F 12 | |
28 | +#define AB8500_INT_USB_ID_DET_R 13 | |
29 | +#define AB8500_INT_VBUS_DET_F 14 | |
30 | +#define AB8500_INT_VBUS_DET_R 15 | |
31 | +#define AB8500_INT_VBUS_CH_DROP_END 16 | |
32 | +#define AB8500_INT_RTC_60S 17 | |
33 | +#define AB8500_INT_RTC_ALARM 18 | |
34 | +#define AB8500_INT_BAT_CTRL_INDB 20 | |
35 | +#define AB8500_INT_CH_WD_EXP 21 | |
36 | +#define AB8500_INT_VBUS_OVV 22 | |
37 | +#define AB8500_INT_MAIN_CH_DROP_END 23 | |
38 | +#define AB8500_INT_CCN_CONV_ACC 24 | |
39 | +#define AB8500_INT_INT_AUD 25 | |
40 | +#define AB8500_INT_CCEOC 26 | |
41 | +#define AB8500_INT_CC_INT_CALIB 27 | |
42 | +#define AB8500_INT_LOW_BAT_F 28 | |
43 | +#define AB8500_INT_LOW_BAT_R 29 | |
44 | +#define AB8500_INT_BUP_CHG_NOT_OK 30 | |
45 | +#define AB8500_INT_BUP_CHG_OK 31 | |
46 | +#define AB8500_INT_GP_HW_ADC_CONV_END 32 | |
47 | +#define AB8500_INT_ACC_DETECT_1DB_F 33 | |
48 | +#define AB8500_INT_ACC_DETECT_1DB_R 34 | |
49 | +#define AB8500_INT_ACC_DETECT_22DB_F 35 | |
50 | +#define AB8500_INT_ACC_DETECT_22DB_R 36 | |
51 | +#define AB8500_INT_ACC_DETECT_21DB_F 37 | |
52 | +#define AB8500_INT_ACC_DETECT_21DB_R 38 | |
53 | +#define AB8500_INT_GP_SW_ADC_CONV_END 39 | |
54 | +#define AB8500_INT_BTEMP_LOW 72 | |
55 | +#define AB8500_INT_BTEMP_LOW_MEDIUM 73 | |
56 | +#define AB8500_INT_BTEMP_MEDIUM_HIGH 74 | |
57 | +#define AB8500_INT_BTEMP_HIGH 75 | |
58 | +#define AB8500_INT_USB_CHARGER_NOT_OK 81 | |
59 | +#define AB8500_INT_ID_WAKEUP_R 82 | |
60 | +#define AB8500_INT_ID_DET_R1R 84 | |
61 | +#define AB8500_INT_ID_DET_R2R 85 | |
62 | +#define AB8500_INT_ID_DET_R3R 86 | |
63 | +#define AB8500_INT_ID_DET_R4R 87 | |
64 | +#define AB8500_INT_ID_WAKEUP_F 88 | |
65 | +#define AB8500_INT_ID_DET_R1F 90 | |
66 | +#define AB8500_INT_ID_DET_R2F 91 | |
67 | +#define AB8500_INT_ID_DET_R3F 92 | |
68 | +#define AB8500_INT_ID_DET_R4F 93 | |
69 | +#define AB8500_INT_USB_CHG_DET_DONE 94 | |
70 | +#define AB8500_INT_USB_CH_TH_PROT_F 96 | |
71 | +#define AB8500_INT_USB_CH_TH_PROP_R 97 | |
72 | +#define AB8500_INT_MAIN_CH_TH_PROP_F 98 | |
73 | +#define AB8500_INT_MAIN_CH_TH_PROT_R 99 | |
74 | +#define AB8500_INT_USB_CHARGER_NOT_OKF 103 | |
75 | + | |
76 | +#define AB8500_NR_IRQS 104 | |
77 | +#define AB8500_NUM_IRQ_REGS 13 | |
78 | + | |
79 | +/** | |
80 | + * struct ab8500 - ab8500 internal structure | |
81 | + * @dev: parent device | |
82 | + * @lock: read/write operations lock | |
83 | + * @irq_lock: genirq bus lock | |
84 | + * @revision: chip revision | |
85 | + * @irq: irq line | |
86 | + * @write: register write | |
87 | + * @read: register read | |
88 | + * @rx_buf: rx buf for SPI | |
89 | + * @tx_buf: tx buf for SPI | |
90 | + * @mask: cache of IRQ regs for bus lock | |
91 | + * @oldmask: cache of previous IRQ regs for bus lock | |
92 | + */ | |
93 | +struct ab8500 { | |
94 | + struct device *dev; | |
95 | + struct mutex lock; | |
96 | + struct mutex irq_lock; | |
97 | + int revision; | |
98 | + int irq_base; | |
99 | + int irq; | |
100 | + | |
101 | + int (*write) (struct ab8500 *a8500, u16 addr, u8 data); | |
102 | + int (*read) (struct ab8500 *a8500, u16 addr); | |
103 | + | |
104 | + unsigned long tx_buf[4]; | |
105 | + unsigned long rx_buf[4]; | |
106 | + | |
107 | + u8 mask[AB8500_NUM_IRQ_REGS]; | |
108 | + u8 oldmask[AB8500_NUM_IRQ_REGS]; | |
109 | +}; | |
110 | + | |
111 | +/** | |
112 | + * struct ab8500_platform_data - AB8500 platform data | |
113 | + * @irq_base: start of AB8500 IRQs, AB8500_NR_IRQS will be used | |
114 | + * @init: board-specific initialization after detection of ab8500 | |
115 | + */ | |
116 | +struct ab8500_platform_data { | |
117 | + int irq_base; | |
118 | + void (*init) (struct ab8500 *); | |
119 | +}; | |
120 | + | |
121 | +extern int ab8500_write(struct ab8500 *a8500, u16 addr, u8 data); | |
122 | +extern int ab8500_read(struct ab8500 *a8500, u16 addr); | |
123 | +extern int ab8500_set_bits(struct ab8500 *a8500, u16 addr, u8 mask, u8 data); | |
124 | + | |
125 | +extern int __devinit ab8500_init(struct ab8500 *ab8500); | |
126 | +extern int __devexit ab8500_exit(struct ab8500 *ab8500); | |
127 | + | |
128 | +#endif /* MFD_AB8500_H */ |