diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/char/hw_random/Kconfig | 2 | ||||
-rw-r--r-- | drivers/clocksource/Kconfig | 2 | ||||
-rw-r--r-- | drivers/input/touchscreen/Kconfig | 4 | ||||
-rw-r--r-- | drivers/mfd/Kconfig | 27 | ||||
-rw-r--r-- | drivers/mfd/Makefile | 3 | ||||
-rw-r--r-- | drivers/mfd/ab5500-core.c | 1439 | ||||
-rw-r--r-- | drivers/mfd/ab5500-debugfs.c | 807 | ||||
-rw-r--r-- | drivers/mfd/ab5500-debugfs.h | 22 | ||||
-rw-r--r-- | drivers/mfd/db5500-prcmu.c | 451 | ||||
-rw-r--r-- | drivers/mtd/nand/autcpu12.c | 10 | ||||
-rw-r--r-- | drivers/mtd/nand/h1910.c | 2 | ||||
-rw-r--r-- | drivers/net/irda/Kconfig | 4 | ||||
-rw-r--r-- | drivers/rtc/Kconfig | 2 | ||||
-rw-r--r-- | drivers/tty/serial/clps711x.c | 1 | ||||
-rw-r--r-- | drivers/usb/host/ohci-omap.c | 5 | ||||
-rw-r--r-- | drivers/video/clps711xfb.c | 1 | ||||
-rw-r--r-- | drivers/video/omap2/displays/Kconfig | 8 | ||||
-rw-r--r-- | drivers/video/omap2/displays/Makefile | 2 | ||||
-rw-r--r-- | drivers/video/omap2/displays/panel-taal.c | 22 | ||||
-rw-r--r-- | drivers/video/omap2/displays/panel-tfp410.c (renamed from drivers/video/omap2/displays/panel-dvi.c) | 134 | ||||
-rw-r--r-- | drivers/video/omap2/dss/dsi.c | 133 |
21 files changed, 186 insertions, 2895 deletions
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig index 0689bf6b0183..b2402eb076c7 100644 --- a/drivers/char/hw_random/Kconfig +++ b/drivers/char/hw_random/Kconfig | |||
@@ -62,7 +62,7 @@ config HW_RANDOM_AMD | |||
62 | 62 | ||
63 | config HW_RANDOM_ATMEL | 63 | config HW_RANDOM_ATMEL |
64 | tristate "Atmel Random Number Generator support" | 64 | tristate "Atmel Random Number Generator support" |
65 | depends on HW_RANDOM && ARCH_AT91SAM9G45 | 65 | depends on HW_RANDOM && HAVE_CLK |
66 | default HW_RANDOM | 66 | default HW_RANDOM |
67 | ---help--- | 67 | ---help--- |
68 | This driver provides kernel-side support for the Random Number | 68 | This driver provides kernel-side support for the Random Number |
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig index 5138927a416c..99c6b203e6cd 100644 --- a/drivers/clocksource/Kconfig +++ b/drivers/clocksource/Kconfig | |||
@@ -18,7 +18,7 @@ config DW_APB_TIMER | |||
18 | 18 | ||
19 | config CLKSRC_DBX500_PRCMU | 19 | config CLKSRC_DBX500_PRCMU |
20 | bool "Clocksource PRCMU Timer" | 20 | bool "Clocksource PRCMU Timer" |
21 | depends on UX500_SOC_DB5500 || UX500_SOC_DB8500 | 21 | depends on UX500_SOC_DB8500 |
22 | default y | 22 | default y |
23 | help | 23 | help |
24 | Use the always on PRCMU Timer as clocksource | 24 | Use the always on PRCMU Timer as clocksource |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 2a2141915aa0..75838d7710ce 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -489,10 +489,10 @@ config TOUCHSCREEN_TI_TSCADC | |||
489 | 489 | ||
490 | config TOUCHSCREEN_ATMEL_TSADCC | 490 | config TOUCHSCREEN_ATMEL_TSADCC |
491 | tristate "Atmel Touchscreen Interface" | 491 | tristate "Atmel Touchscreen Interface" |
492 | depends on ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 | 492 | depends on ARCH_AT91 |
493 | help | 493 | help |
494 | Say Y here if you have a 4-wire touchscreen connected to the | 494 | Say Y here if you have a 4-wire touchscreen connected to the |
495 | ADC Controller on your Atmel SoC (such as the AT91SAM9RL). | 495 | ADC Controller on your Atmel SoC. |
496 | 496 | ||
497 | If unsure, say N. | 497 | If unsure, say N. |
498 | 498 | ||
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index b5a0032f616e..49ef8b0794ae 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -652,23 +652,6 @@ config EZX_PCAP | |||
652 | This enables the PCAP ASIC present on EZX Phones. This is | 652 | This enables the PCAP ASIC present on EZX Phones. This is |
653 | needed for MMC, TouchScreen, Sound, USB, etc.. | 653 | needed for MMC, TouchScreen, Sound, USB, etc.. |
654 | 654 | ||
655 | config AB5500_CORE | ||
656 | bool "ST-Ericsson AB5500 Mixed Signal Power Management chip" | ||
657 | depends on ABX500_CORE && MFD_DB5500_PRCMU | ||
658 | select MFD_CORE | ||
659 | help | ||
660 | Select this option to enable access to AB5500 power management | ||
661 | chip. This connects to the db5500 chip via the I2C bus via PRCMU. | ||
662 | This chip embeds various other multimedia funtionalities as well. | ||
663 | |||
664 | config AB5500_DEBUG | ||
665 | bool "Enable debug info via debugfs" | ||
666 | depends on AB5500_CORE && DEBUG_FS | ||
667 | default y if DEBUG_FS | ||
668 | help | ||
669 | Select this option if you want debug information from the AB5500 | ||
670 | using the debug filesystem, debugfs. | ||
671 | |||
672 | config AB8500_CORE | 655 | config AB8500_CORE |
673 | bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" | 656 | bool "ST-Ericsson AB8500 Mixed Signal Power Management chip" |
674 | depends on GENERIC_HARDIRQS && ABX500_CORE | 657 | depends on GENERIC_HARDIRQS && ABX500_CORE |
@@ -715,16 +698,6 @@ config MFD_DB8500_PRCMU | |||
715 | system controller running an XP70 microprocessor, which is accessed | 698 | system controller running an XP70 microprocessor, which is accessed |
716 | through a register map. | 699 | through a register map. |
717 | 700 | ||
718 | config MFD_DB5500_PRCMU | ||
719 | bool "ST-Ericsson DB5500 Power Reset Control Management Unit" | ||
720 | depends on UX500_SOC_DB5500 | ||
721 | select MFD_CORE | ||
722 | help | ||
723 | Select this option to enable support for the DB5500 Power Reset | ||
724 | and Control Management Unit. This is basically an autonomous | ||
725 | system controller running an XP70 microprocessor, which is accessed | ||
726 | through a register map. | ||
727 | |||
728 | config MFD_CS5535 | 701 | config MFD_CS5535 |
729 | tristate "Support for CS5535 and CS5536 southbridge core functions" | 702 | tristate "Support for CS5535 and CS5536 southbridge core functions" |
730 | select MFD_CORE | 703 | select MFD_CORE |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 77293e150239..43672b87805a 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -87,15 +87,12 @@ obj-$(CONFIG_PCF50633_GPIO) += pcf50633-gpio.o | |||
87 | obj-$(CONFIG_ABX500_CORE) += abx500-core.o | 87 | obj-$(CONFIG_ABX500_CORE) += abx500-core.o |
88 | obj-$(CONFIG_AB3100_CORE) += ab3100-core.o | 88 | obj-$(CONFIG_AB3100_CORE) += ab3100-core.o |
89 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o | 89 | obj-$(CONFIG_AB3100_OTP) += ab3100-otp.o |
90 | obj-$(CONFIG_AB5500_CORE) += ab5500-core.o | ||
91 | obj-$(CONFIG_AB5500_DEBUG) += ab5500-debugfs.o | ||
92 | obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o | 90 | obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o |
93 | obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o | 91 | obj-$(CONFIG_AB8500_DEBUG) += ab8500-debugfs.o |
94 | obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o | 92 | obj-$(CONFIG_AB8500_GPADC) += ab8500-gpadc.o |
95 | obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o | 93 | obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o |
96 | # ab8500-i2c need to come after db8500-prcmu (which provides the channel) | 94 | # ab8500-i2c need to come after db8500-prcmu (which provides the channel) |
97 | obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o | 95 | obj-$(CONFIG_AB8500_I2C_CORE) += ab8500-i2c.o |
98 | obj-$(CONFIG_MFD_DB5500_PRCMU) += db5500-prcmu.o | ||
99 | obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o | 96 | obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o |
100 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o | 97 | obj-$(CONFIG_PMIC_ADP5520) += adp5520.o |
101 | obj-$(CONFIG_LPC_SCH) += lpc_sch.o | 98 | obj-$(CONFIG_LPC_SCH) += lpc_sch.o |
diff --git a/drivers/mfd/ab5500-core.c b/drivers/mfd/ab5500-core.c deleted file mode 100644 index 54d0fe40845f..000000000000 --- a/drivers/mfd/ab5500-core.c +++ /dev/null | |||
@@ -1,1439 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2007-2011 ST-Ericsson | ||
3 | * License terms: GNU General Public License (GPL) version 2 | ||
4 | * Low-level core for exclusive access to the AB5500 IC on the I2C bus | ||
5 | * and some basic chip-configuration. | ||
6 | * Author: Bengt Jonsson <bengt.g.jonsson@stericsson.com> | ||
7 | * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> | ||
8 | * Author: Mattias Wallin <mattias.wallin@stericsson.com> | ||
9 | * Author: Rickard Andersson <rickard.andersson@stericsson.com> | ||
10 | * Author: Karl Komierowski <karl.komierowski@stericsson.com> | ||
11 | * Author: Bibek Basu <bibek.basu@stericsson.com> | ||
12 | * | ||
13 | * TODO: Event handling with irq_chip. Waiting for PRCMU fw support. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/mutex.h> | ||
18 | #include <linux/err.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/slab.h> | ||
21 | #include <linux/device.h> | ||
22 | #include <linux/irq.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/random.h> | ||
25 | #include <linux/mfd/abx500.h> | ||
26 | #include <linux/mfd/abx500/ab5500.h> | ||
27 | #include <linux/list.h> | ||
28 | #include <linux/bitops.h> | ||
29 | #include <linux/spinlock.h> | ||
30 | #include <linux/mfd/core.h> | ||
31 | #include <linux/mfd/db5500-prcmu.h> | ||
32 | |||
33 | #include "ab5500-core.h" | ||
34 | #include "ab5500-debugfs.h" | ||
35 | |||
36 | #define AB5500_NUM_EVENT_REG 23 | ||
37 | #define AB5500_IT_LATCH0_REG 0x40 | ||
38 | #define AB5500_IT_MASK0_REG 0x60 | ||
39 | |||
40 | /* | ||
41 | * Permissible register ranges for reading and writing per device and bank. | ||
42 | * | ||
43 | * The ranges must be listed in increasing address order, and no overlaps are | ||
44 | * allowed. It is assumed that write permission implies read permission | ||
45 | * (i.e. only RO and RW permissions should be used). Ranges with write | ||
46 | * permission must not be split up. | ||
47 | */ | ||
48 | |||
49 | #define NO_RANGE {.count = 0, .range = NULL,} | ||
50 | static struct ab5500_i2c_banks ab5500_bank_ranges[AB5500_NUM_DEVICES] = { | ||
51 | [AB5500_DEVID_USB] = { | ||
52 | .nbanks = 1, | ||
53 | .bank = (struct ab5500_i2c_ranges []) { | ||
54 | { | ||
55 | .bankid = AB5500_BANK_USB, | ||
56 | .nranges = 12, | ||
57 | .range = (struct ab5500_reg_range[]) { | ||
58 | { | ||
59 | .first = 0x01, | ||
60 | .last = 0x01, | ||
61 | .perm = AB5500_PERM_RW, | ||
62 | }, | ||
63 | { | ||
64 | .first = 0x80, | ||
65 | .last = 0x83, | ||
66 | .perm = AB5500_PERM_RW, | ||
67 | }, | ||
68 | { | ||
69 | .first = 0x87, | ||
70 | .last = 0x8A, | ||
71 | .perm = AB5500_PERM_RW, | ||
72 | }, | ||
73 | { | ||
74 | .first = 0x8B, | ||
75 | .last = 0x8B, | ||
76 | .perm = AB5500_PERM_RO, | ||
77 | }, | ||
78 | { | ||
79 | .first = 0x91, | ||
80 | .last = 0x92, | ||
81 | .perm = AB5500_PERM_RO, | ||
82 | }, | ||
83 | { | ||
84 | .first = 0x93, | ||
85 | .last = 0x93, | ||
86 | .perm = AB5500_PERM_RW, | ||
87 | }, | ||
88 | { | ||
89 | .first = 0x94, | ||
90 | .last = 0x94, | ||
91 | .perm = AB5500_PERM_RO, | ||
92 | }, | ||
93 | { | ||
94 | .first = 0xA8, | ||
95 | .last = 0xB0, | ||
96 | .perm = AB5500_PERM_RO, | ||
97 | }, | ||
98 | { | ||
99 | .first = 0xB2, | ||
100 | .last = 0xB2, | ||
101 | .perm = AB5500_PERM_RO, | ||
102 | }, | ||
103 | { | ||
104 | .first = 0xB4, | ||
105 | .last = 0xBC, | ||
106 | .perm = AB5500_PERM_RO, | ||
107 | }, | ||
108 | { | ||
109 | .first = 0xBF, | ||
110 | .last = 0xBF, | ||
111 | .perm = AB5500_PERM_RO, | ||
112 | }, | ||
113 | { | ||
114 | .first = 0xC1, | ||
115 | .last = 0xC5, | ||
116 | .perm = AB5500_PERM_RO, | ||
117 | }, | ||
118 | }, | ||
119 | }, | ||
120 | }, | ||
121 | }, | ||
122 | [AB5500_DEVID_ADC] = { | ||
123 | .nbanks = 1, | ||
124 | .bank = (struct ab5500_i2c_ranges []) { | ||
125 | { | ||
126 | .bankid = AB5500_BANK_ADC, | ||
127 | .nranges = 6, | ||
128 | .range = (struct ab5500_reg_range[]) { | ||
129 | { | ||
130 | .first = 0x1F, | ||
131 | .last = 0x22, | ||
132 | .perm = AB5500_PERM_RO, | ||
133 | }, | ||
134 | { | ||
135 | .first = 0x23, | ||
136 | .last = 0x24, | ||
137 | .perm = AB5500_PERM_RW, | ||
138 | }, | ||
139 | { | ||
140 | .first = 0x26, | ||
141 | .last = 0x2D, | ||
142 | .perm = AB5500_PERM_RO, | ||
143 | }, | ||
144 | { | ||
145 | .first = 0x2F, | ||
146 | .last = 0x34, | ||
147 | .perm = AB5500_PERM_RW, | ||
148 | }, | ||
149 | { | ||
150 | .first = 0x37, | ||
151 | .last = 0x57, | ||
152 | .perm = AB5500_PERM_RW, | ||
153 | }, | ||
154 | { | ||
155 | .first = 0x58, | ||
156 | .last = 0x58, | ||
157 | .perm = AB5500_PERM_RO, | ||
158 | }, | ||
159 | }, | ||
160 | }, | ||
161 | }, | ||
162 | }, | ||
163 | [AB5500_DEVID_LEDS] = { | ||
164 | .nbanks = 1, | ||
165 | .bank = (struct ab5500_i2c_ranges []) { | ||
166 | { | ||
167 | .bankid = AB5500_BANK_LED, | ||
168 | .nranges = 1, | ||
169 | .range = (struct ab5500_reg_range[]) { | ||
170 | { | ||
171 | .first = 0x00, | ||
172 | .last = 0x0C, | ||
173 | .perm = AB5500_PERM_RW, | ||
174 | }, | ||
175 | }, | ||
176 | }, | ||
177 | }, | ||
178 | }, | ||
179 | [AB5500_DEVID_VIDEO] = { | ||
180 | .nbanks = 1, | ||
181 | .bank = (struct ab5500_i2c_ranges []) { | ||
182 | { | ||
183 | .bankid = AB5500_BANK_VDENC, | ||
184 | .nranges = 12, | ||
185 | .range = (struct ab5500_reg_range[]) { | ||
186 | { | ||
187 | .first = 0x00, | ||
188 | .last = 0x08, | ||
189 | .perm = AB5500_PERM_RW, | ||
190 | }, | ||
191 | { | ||
192 | .first = 0x09, | ||
193 | .last = 0x09, | ||
194 | .perm = AB5500_PERM_RO, | ||
195 | }, | ||
196 | { | ||
197 | .first = 0x0A, | ||
198 | .last = 0x12, | ||
199 | .perm = AB5500_PERM_RW, | ||
200 | }, | ||
201 | { | ||
202 | .first = 0x15, | ||
203 | .last = 0x19, | ||
204 | .perm = AB5500_PERM_RW, | ||
205 | }, | ||
206 | { | ||
207 | .first = 0x1B, | ||
208 | .last = 0x21, | ||
209 | .perm = AB5500_PERM_RW, | ||
210 | }, | ||
211 | { | ||
212 | .first = 0x27, | ||
213 | .last = 0x2C, | ||
214 | .perm = AB5500_PERM_RW, | ||
215 | }, | ||
216 | { | ||
217 | .first = 0x41, | ||
218 | .last = 0x41, | ||
219 | .perm = AB5500_PERM_RW, | ||
220 | }, | ||
221 | { | ||
222 | .first = 0x45, | ||
223 | .last = 0x5B, | ||
224 | .perm = AB5500_PERM_RW, | ||
225 | }, | ||
226 | { | ||
227 | .first = 0x5D, | ||
228 | .last = 0x5D, | ||
229 | .perm = AB5500_PERM_RW, | ||
230 | }, | ||
231 | { | ||
232 | .first = 0x69, | ||
233 | .last = 0x69, | ||
234 | .perm = AB5500_PERM_RW, | ||
235 | }, | ||
236 | { | ||
237 | .first = 0x6C, | ||
238 | .last = 0x6D, | ||
239 | .perm = AB5500_PERM_RW, | ||
240 | }, | ||
241 | { | ||
242 | .first = 0x80, | ||
243 | .last = 0x81, | ||
244 | .perm = AB5500_PERM_RW, | ||
245 | }, | ||
246 | }, | ||
247 | }, | ||
248 | }, | ||
249 | }, | ||
250 | [AB5500_DEVID_REGULATORS] = { | ||
251 | .nbanks = 2, | ||
252 | .bank = (struct ab5500_i2c_ranges []) { | ||
253 | { | ||
254 | .bankid = AB5500_BANK_STARTUP, | ||
255 | .nranges = 12, | ||
256 | .range = (struct ab5500_reg_range[]) { | ||
257 | { | ||
258 | .first = 0x00, | ||
259 | .last = 0x01, | ||
260 | .perm = AB5500_PERM_RW, | ||
261 | }, | ||
262 | { | ||
263 | .first = 0x1F, | ||
264 | .last = 0x1F, | ||
265 | .perm = AB5500_PERM_RW, | ||
266 | }, | ||
267 | { | ||
268 | .first = 0x2E, | ||
269 | .last = 0x2E, | ||
270 | .perm = AB5500_PERM_RO, | ||
271 | }, | ||
272 | { | ||
273 | .first = 0x2F, | ||
274 | .last = 0x30, | ||
275 | .perm = AB5500_PERM_RW, | ||
276 | }, | ||
277 | { | ||
278 | .first = 0x50, | ||
279 | .last = 0x51, | ||
280 | .perm = AB5500_PERM_RW, | ||
281 | }, | ||
282 | { | ||
283 | .first = 0x60, | ||
284 | .last = 0x61, | ||
285 | .perm = AB5500_PERM_RW, | ||
286 | }, | ||
287 | { | ||
288 | .first = 0x66, | ||
289 | .last = 0x8A, | ||
290 | .perm = AB5500_PERM_RW, | ||
291 | }, | ||
292 | { | ||
293 | .first = 0x8C, | ||
294 | .last = 0x96, | ||
295 | .perm = AB5500_PERM_RW, | ||
296 | }, | ||
297 | { | ||
298 | .first = 0xAA, | ||
299 | .last = 0xB4, | ||
300 | .perm = AB5500_PERM_RW, | ||
301 | }, | ||
302 | { | ||
303 | .first = 0xB7, | ||
304 | .last = 0xBF, | ||
305 | .perm = AB5500_PERM_RW, | ||
306 | }, | ||
307 | { | ||
308 | .first = 0xC1, | ||
309 | .last = 0xCA, | ||
310 | .perm = AB5500_PERM_RW, | ||
311 | }, | ||
312 | { | ||
313 | .first = 0xD3, | ||
314 | .last = 0xE0, | ||
315 | .perm = AB5500_PERM_RW, | ||
316 | }, | ||
317 | }, | ||
318 | }, | ||
319 | { | ||
320 | .bankid = AB5500_BANK_SIM_USBSIM, | ||
321 | .nranges = 1, | ||
322 | .range = (struct ab5500_reg_range[]) { | ||
323 | { | ||
324 | .first = 0x13, | ||
325 | .last = 0x19, | ||
326 | .perm = AB5500_PERM_RW, | ||
327 | }, | ||
328 | }, | ||
329 | }, | ||
330 | }, | ||
331 | }, | ||
332 | [AB5500_DEVID_SIM] = { | ||
333 | .nbanks = 1, | ||
334 | .bank = (struct ab5500_i2c_ranges []) { | ||
335 | { | ||
336 | .bankid = AB5500_BANK_SIM_USBSIM, | ||
337 | .nranges = 1, | ||
338 | .range = (struct ab5500_reg_range[]) { | ||
339 | { | ||
340 | .first = 0x13, | ||
341 | .last = 0x19, | ||
342 | .perm = AB5500_PERM_RW, | ||
343 | }, | ||
344 | }, | ||
345 | }, | ||
346 | }, | ||
347 | }, | ||
348 | [AB5500_DEVID_RTC] = { | ||
349 | .nbanks = 1, | ||
350 | .bank = (struct ab5500_i2c_ranges []) { | ||
351 | { | ||
352 | .bankid = AB5500_BANK_RTC, | ||
353 | .nranges = 2, | ||
354 | .range = (struct ab5500_reg_range[]) { | ||
355 | { | ||
356 | .first = 0x00, | ||
357 | .last = 0x04, | ||
358 | .perm = AB5500_PERM_RW, | ||
359 | }, | ||
360 | { | ||
361 | .first = 0x06, | ||
362 | .last = 0x0C, | ||
363 | .perm = AB5500_PERM_RW, | ||
364 | }, | ||
365 | }, | ||
366 | }, | ||
367 | }, | ||
368 | }, | ||
369 | [AB5500_DEVID_CHARGER] = { | ||
370 | .nbanks = 1, | ||
371 | .bank = (struct ab5500_i2c_ranges []) { | ||
372 | { | ||
373 | .bankid = AB5500_BANK_CHG, | ||
374 | .nranges = 2, | ||
375 | .range = (struct ab5500_reg_range[]) { | ||
376 | { | ||
377 | .first = 0x11, | ||
378 | .last = 0x11, | ||
379 | .perm = AB5500_PERM_RO, | ||
380 | }, | ||
381 | { | ||
382 | .first = 0x12, | ||
383 | .last = 0x1B, | ||
384 | .perm = AB5500_PERM_RW, | ||
385 | }, | ||
386 | }, | ||
387 | }, | ||
388 | }, | ||
389 | }, | ||
390 | [AB5500_DEVID_FUELGAUGE] = { | ||
391 | .nbanks = 1, | ||
392 | .bank = (struct ab5500_i2c_ranges []) { | ||
393 | { | ||
394 | .bankid = AB5500_BANK_FG_BATTCOM_ACC, | ||
395 | .nranges = 2, | ||
396 | .range = (struct ab5500_reg_range[]) { | ||
397 | { | ||
398 | .first = 0x00, | ||
399 | .last = 0x0B, | ||
400 | .perm = AB5500_PERM_RO, | ||
401 | }, | ||
402 | { | ||
403 | .first = 0x0C, | ||
404 | .last = 0x10, | ||
405 | .perm = AB5500_PERM_RW, | ||
406 | }, | ||
407 | }, | ||
408 | }, | ||
409 | }, | ||
410 | }, | ||
411 | [AB5500_DEVID_VIBRATOR] = { | ||
412 | .nbanks = 1, | ||
413 | .bank = (struct ab5500_i2c_ranges []) { | ||
414 | { | ||
415 | .bankid = AB5500_BANK_VIBRA, | ||
416 | .nranges = 2, | ||
417 | .range = (struct ab5500_reg_range[]) { | ||
418 | { | ||
419 | .first = 0x10, | ||
420 | .last = 0x13, | ||
421 | .perm = AB5500_PERM_RW, | ||
422 | }, | ||
423 | { | ||
424 | .first = 0xFE, | ||
425 | .last = 0xFE, | ||
426 | .perm = AB5500_PERM_RW, | ||
427 | }, | ||
428 | }, | ||
429 | }, | ||
430 | }, | ||
431 | }, | ||
432 | [AB5500_DEVID_CODEC] = { | ||
433 | .nbanks = 1, | ||
434 | .bank = (struct ab5500_i2c_ranges []) { | ||
435 | { | ||
436 | .bankid = AB5500_BANK_AUDIO_HEADSETUSB, | ||
437 | .nranges = 2, | ||
438 | .range = (struct ab5500_reg_range[]) { | ||
439 | { | ||
440 | .first = 0x00, | ||
441 | .last = 0x48, | ||
442 | .perm = AB5500_PERM_RW, | ||
443 | }, | ||
444 | { | ||
445 | .first = 0xEB, | ||
446 | .last = 0xFB, | ||
447 | .perm = AB5500_PERM_RW, | ||
448 | }, | ||
449 | }, | ||
450 | }, | ||
451 | }, | ||
452 | }, | ||
453 | [AB5500_DEVID_POWER] = { | ||
454 | .nbanks = 2, | ||
455 | .bank = (struct ab5500_i2c_ranges []) { | ||
456 | { | ||
457 | .bankid = AB5500_BANK_STARTUP, | ||
458 | .nranges = 1, | ||
459 | .range = (struct ab5500_reg_range[]) { | ||
460 | { | ||
461 | .first = 0x30, | ||
462 | .last = 0x30, | ||
463 | .perm = AB5500_PERM_RW, | ||
464 | }, | ||
465 | }, | ||
466 | }, | ||
467 | { | ||
468 | .bankid = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP, | ||
469 | .nranges = 1, | ||
470 | .range = (struct ab5500_reg_range[]) { | ||
471 | { | ||
472 | .first = 0x01, | ||
473 | .last = 0x01, | ||
474 | .perm = AB5500_PERM_RW, | ||
475 | }, | ||
476 | }, | ||
477 | }, | ||
478 | }, | ||
479 | }, | ||
480 | }; | ||
481 | |||
482 | #define AB5500_IRQ(bank, bit) ((bank) * 8 + (bit)) | ||
483 | |||
484 | /* I appologize for the resource names beeing a mix of upper case | ||
485 | * and lower case but I want them to be exact as the documentation */ | ||
486 | static struct mfd_cell ab5500_devs[AB5500_NUM_DEVICES] = { | ||
487 | [AB5500_DEVID_LEDS] = { | ||
488 | .name = "ab5500-leds", | ||
489 | .id = AB5500_DEVID_LEDS, | ||
490 | }, | ||
491 | [AB5500_DEVID_POWER] = { | ||
492 | .name = "ab5500-power", | ||
493 | .id = AB5500_DEVID_POWER, | ||
494 | }, | ||
495 | [AB5500_DEVID_REGULATORS] = { | ||
496 | .name = "ab5500-regulator", | ||
497 | .id = AB5500_DEVID_REGULATORS, | ||
498 | }, | ||
499 | [AB5500_DEVID_SIM] = { | ||
500 | .name = "ab5500-sim", | ||
501 | .id = AB5500_DEVID_SIM, | ||
502 | .num_resources = 1, | ||
503 | .resources = (struct resource[]) { | ||
504 | { | ||
505 | .name = "SIMOFF", | ||
506 | .flags = IORESOURCE_IRQ, | ||
507 | .start = AB5500_IRQ(2, 0), /*rising*/ | ||
508 | .end = AB5500_IRQ(2, 1), /*falling*/ | ||
509 | }, | ||
510 | }, | ||
511 | }, | ||
512 | [AB5500_DEVID_RTC] = { | ||
513 | .name = "ab5500-rtc", | ||
514 | .id = AB5500_DEVID_RTC, | ||
515 | .num_resources = 1, | ||
516 | .resources = (struct resource[]) { | ||
517 | { | ||
518 | .name = "RTC_Alarm", | ||
519 | .flags = IORESOURCE_IRQ, | ||
520 | .start = AB5500_IRQ(1, 7), | ||
521 | .end = AB5500_IRQ(1, 7), | ||
522 | } | ||
523 | }, | ||
524 | }, | ||
525 | [AB5500_DEVID_CHARGER] = { | ||
526 | .name = "ab5500-charger", | ||
527 | .id = AB5500_DEVID_CHARGER, | ||
528 | }, | ||
529 | [AB5500_DEVID_ADC] = { | ||
530 | .name = "ab5500-adc", | ||
531 | .id = AB5500_DEVID_ADC, | ||
532 | .num_resources = 10, | ||
533 | .resources = (struct resource[]) { | ||
534 | { | ||
535 | .name = "TRIGGER-0", | ||
536 | .flags = IORESOURCE_IRQ, | ||
537 | .start = AB5500_IRQ(0, 0), | ||
538 | .end = AB5500_IRQ(0, 0), | ||
539 | }, | ||
540 | { | ||
541 | .name = "TRIGGER-1", | ||
542 | .flags = IORESOURCE_IRQ, | ||
543 | .start = AB5500_IRQ(0, 1), | ||
544 | .end = AB5500_IRQ(0, 1), | ||
545 | }, | ||
546 | { | ||
547 | .name = "TRIGGER-2", | ||
548 | .flags = IORESOURCE_IRQ, | ||
549 | .start = AB5500_IRQ(0, 2), | ||
550 | .end = AB5500_IRQ(0, 2), | ||
551 | }, | ||
552 | { | ||
553 | .name = "TRIGGER-3", | ||
554 | .flags = IORESOURCE_IRQ, | ||
555 | .start = AB5500_IRQ(0, 3), | ||
556 | .end = AB5500_IRQ(0, 3), | ||
557 | }, | ||
558 | { | ||
559 | .name = "TRIGGER-4", | ||
560 | .flags = IORESOURCE_IRQ, | ||
561 | .start = AB5500_IRQ(0, 4), | ||
562 | .end = AB5500_IRQ(0, 4), | ||
563 | }, | ||
564 | { | ||
565 | .name = "TRIGGER-5", | ||
566 | .flags = IORESOURCE_IRQ, | ||
567 | .start = AB5500_IRQ(0, 5), | ||
568 | .end = AB5500_IRQ(0, 5), | ||
569 | }, | ||
570 | { | ||
571 | .name = "TRIGGER-6", | ||
572 | .flags = IORESOURCE_IRQ, | ||
573 | .start = AB5500_IRQ(0, 6), | ||
574 | .end = AB5500_IRQ(0, 6), | ||
575 | }, | ||
576 | { | ||
577 | .name = "TRIGGER-7", | ||
578 | .flags = IORESOURCE_IRQ, | ||
579 | .start = AB5500_IRQ(0, 7), | ||
580 | .end = AB5500_IRQ(0, 7), | ||
581 | }, | ||
582 | { | ||
583 | .name = "TRIGGER-VBAT", | ||
584 | .flags = IORESOURCE_IRQ, | ||
585 | .start = AB5500_IRQ(0, 8), | ||
586 | .end = AB5500_IRQ(0, 8), | ||
587 | }, | ||
588 | { | ||
589 | .name = "TRIGGER-VBAT-TXON", | ||
590 | .flags = IORESOURCE_IRQ, | ||
591 | .start = AB5500_IRQ(0, 9), | ||
592 | .end = AB5500_IRQ(0, 9), | ||
593 | }, | ||
594 | }, | ||
595 | }, | ||
596 | [AB5500_DEVID_FUELGAUGE] = { | ||
597 | .name = "ab5500-fuelgauge", | ||
598 | .id = AB5500_DEVID_FUELGAUGE, | ||
599 | .num_resources = 6, | ||
600 | .resources = (struct resource[]) { | ||
601 | { | ||
602 | .name = "Batt_attach", | ||
603 | .flags = IORESOURCE_IRQ, | ||
604 | .start = AB5500_IRQ(7, 5), | ||
605 | .end = AB5500_IRQ(7, 5), | ||
606 | }, | ||
607 | { | ||
608 | .name = "Batt_removal", | ||
609 | .flags = IORESOURCE_IRQ, | ||
610 | .start = AB5500_IRQ(7, 6), | ||
611 | .end = AB5500_IRQ(7, 6), | ||
612 | }, | ||
613 | { | ||
614 | .name = "UART_framing", | ||
615 | .flags = IORESOURCE_IRQ, | ||
616 | .start = AB5500_IRQ(7, 7), | ||
617 | .end = AB5500_IRQ(7, 7), | ||
618 | }, | ||
619 | { | ||
620 | .name = "UART_overrun", | ||
621 | .flags = IORESOURCE_IRQ, | ||
622 | .start = AB5500_IRQ(8, 0), | ||
623 | .end = AB5500_IRQ(8, 0), | ||
624 | }, | ||
625 | { | ||
626 | .name = "UART_Rdy_RX", | ||
627 | .flags = IORESOURCE_IRQ, | ||
628 | .start = AB5500_IRQ(8, 1), | ||
629 | .end = AB5500_IRQ(8, 1), | ||
630 | }, | ||
631 | { | ||
632 | .name = "UART_Rdy_TX", | ||
633 | .flags = IORESOURCE_IRQ, | ||
634 | .start = AB5500_IRQ(8, 2), | ||
635 | .end = AB5500_IRQ(8, 2), | ||
636 | }, | ||
637 | }, | ||
638 | }, | ||
639 | [AB5500_DEVID_VIBRATOR] = { | ||
640 | .name = "ab5500-vibrator", | ||
641 | .id = AB5500_DEVID_VIBRATOR, | ||
642 | }, | ||
643 | [AB5500_DEVID_CODEC] = { | ||
644 | .name = "ab5500-codec", | ||
645 | .id = AB5500_DEVID_CODEC, | ||
646 | .num_resources = 3, | ||
647 | .resources = (struct resource[]) { | ||
648 | { | ||
649 | .name = "audio_spkr1_ovc", | ||
650 | .flags = IORESOURCE_IRQ, | ||
651 | .start = AB5500_IRQ(9, 5), | ||
652 | .end = AB5500_IRQ(9, 5), | ||
653 | }, | ||
654 | { | ||
655 | .name = "audio_plllocked", | ||
656 | .flags = IORESOURCE_IRQ, | ||
657 | .start = AB5500_IRQ(9, 6), | ||
658 | .end = AB5500_IRQ(9, 6), | ||
659 | }, | ||
660 | { | ||
661 | .name = "audio_spkr2_ovc", | ||
662 | .flags = IORESOURCE_IRQ, | ||
663 | .start = AB5500_IRQ(17, 4), | ||
664 | .end = AB5500_IRQ(17, 4), | ||
665 | }, | ||
666 | }, | ||
667 | }, | ||
668 | [AB5500_DEVID_USB] = { | ||
669 | .name = "ab5500-usb", | ||
670 | .id = AB5500_DEVID_USB, | ||
671 | .num_resources = 36, | ||
672 | .resources = (struct resource[]) { | ||
673 | { | ||
674 | .name = "Link_Update", | ||
675 | .flags = IORESOURCE_IRQ, | ||
676 | .start = AB5500_IRQ(22, 1), | ||
677 | .end = AB5500_IRQ(22, 1), | ||
678 | }, | ||
679 | { | ||
680 | .name = "DCIO", | ||
681 | .flags = IORESOURCE_IRQ, | ||
682 | .start = AB5500_IRQ(8, 3), | ||
683 | .end = AB5500_IRQ(8, 4), | ||
684 | }, | ||
685 | { | ||
686 | .name = "VBUS_R", | ||
687 | .flags = IORESOURCE_IRQ, | ||
688 | .start = AB5500_IRQ(8, 5), | ||
689 | .end = AB5500_IRQ(8, 5), | ||
690 | }, | ||
691 | { | ||
692 | .name = "VBUS_F", | ||
693 | .flags = IORESOURCE_IRQ, | ||
694 | .start = AB5500_IRQ(8, 6), | ||
695 | .end = AB5500_IRQ(8, 6), | ||
696 | }, | ||
697 | { | ||
698 | .name = "CHGstate_10_PCVBUSchg", | ||
699 | .flags = IORESOURCE_IRQ, | ||
700 | .start = AB5500_IRQ(8, 7), | ||
701 | .end = AB5500_IRQ(8, 7), | ||
702 | }, | ||
703 | { | ||
704 | .name = "DCIOreverse_ovc", | ||
705 | .flags = IORESOURCE_IRQ, | ||
706 | .start = AB5500_IRQ(9, 0), | ||
707 | .end = AB5500_IRQ(9, 0), | ||
708 | }, | ||
709 | { | ||
710 | .name = "USBCharDetDone", | ||
711 | .flags = IORESOURCE_IRQ, | ||
712 | .start = AB5500_IRQ(9, 1), | ||
713 | .end = AB5500_IRQ(9, 1), | ||
714 | }, | ||
715 | { | ||
716 | .name = "DCIO_no_limit", | ||
717 | .flags = IORESOURCE_IRQ, | ||
718 | .start = AB5500_IRQ(9, 2), | ||
719 | .end = AB5500_IRQ(9, 2), | ||
720 | }, | ||
721 | { | ||
722 | .name = "USB_suspend", | ||
723 | .flags = IORESOURCE_IRQ, | ||
724 | .start = AB5500_IRQ(9, 3), | ||
725 | .end = AB5500_IRQ(9, 3), | ||
726 | }, | ||
727 | { | ||
728 | .name = "DCIOreverse_fwdcurrent", | ||
729 | .flags = IORESOURCE_IRQ, | ||
730 | .start = AB5500_IRQ(9, 4), | ||
731 | .end = AB5500_IRQ(9, 4), | ||
732 | }, | ||
733 | { | ||
734 | .name = "Vbus_Imeasmax_change", | ||
735 | .flags = IORESOURCE_IRQ, | ||
736 | .start = AB5500_IRQ(9, 5), | ||
737 | .end = AB5500_IRQ(9, 6), | ||
738 | }, | ||
739 | { | ||
740 | .name = "OVV", | ||
741 | .flags = IORESOURCE_IRQ, | ||
742 | .start = AB5500_IRQ(14, 5), | ||
743 | .end = AB5500_IRQ(14, 5), | ||
744 | }, | ||
745 | { | ||
746 | .name = "USBcharging_NOTok", | ||
747 | .flags = IORESOURCE_IRQ, | ||
748 | .start = AB5500_IRQ(15, 3), | ||
749 | .end = AB5500_IRQ(15, 3), | ||
750 | }, | ||
751 | { | ||
752 | .name = "usb_adp_sensoroff", | ||
753 | .flags = IORESOURCE_IRQ, | ||
754 | .start = AB5500_IRQ(15, 6), | ||
755 | .end = AB5500_IRQ(15, 6), | ||
756 | }, | ||
757 | { | ||
758 | .name = "usb_adp_probeplug", | ||
759 | .flags = IORESOURCE_IRQ, | ||
760 | .start = AB5500_IRQ(15, 7), | ||
761 | .end = AB5500_IRQ(15, 7), | ||
762 | }, | ||
763 | { | ||
764 | .name = "usb_adp_sinkerror", | ||
765 | .flags = IORESOURCE_IRQ, | ||
766 | .start = AB5500_IRQ(16, 0), | ||
767 | .end = AB5500_IRQ(16, 6), | ||
768 | }, | ||
769 | { | ||
770 | .name = "usb_adp_sourceerror", | ||
771 | .flags = IORESOURCE_IRQ, | ||
772 | .start = AB5500_IRQ(16, 1), | ||
773 | .end = AB5500_IRQ(16, 1), | ||
774 | }, | ||
775 | { | ||
776 | .name = "usb_idgnd_r", | ||
777 | .flags = IORESOURCE_IRQ, | ||
778 | .start = AB5500_IRQ(16, 2), | ||
779 | .end = AB5500_IRQ(16, 2), | ||
780 | }, | ||
781 | { | ||
782 | .name = "usb_idgnd_f", | ||
783 | .flags = IORESOURCE_IRQ, | ||
784 | .start = AB5500_IRQ(16, 3), | ||
785 | .end = AB5500_IRQ(16, 3), | ||
786 | }, | ||
787 | { | ||
788 | .name = "usb_iddetR1", | ||
789 | .flags = IORESOURCE_IRQ, | ||
790 | .start = AB5500_IRQ(16, 4), | ||
791 | .end = AB5500_IRQ(16, 5), | ||
792 | }, | ||
793 | { | ||
794 | .name = "usb_iddetR2", | ||
795 | .flags = IORESOURCE_IRQ, | ||
796 | .start = AB5500_IRQ(16, 6), | ||
797 | .end = AB5500_IRQ(16, 7), | ||
798 | }, | ||
799 | { | ||
800 | .name = "usb_iddetR3", | ||
801 | .flags = IORESOURCE_IRQ, | ||
802 | .start = AB5500_IRQ(17, 0), | ||
803 | .end = AB5500_IRQ(17, 1), | ||
804 | }, | ||
805 | { | ||
806 | .name = "usb_iddetR4", | ||
807 | .flags = IORESOURCE_IRQ, | ||
808 | .start = AB5500_IRQ(17, 2), | ||
809 | .end = AB5500_IRQ(17, 3), | ||
810 | }, | ||
811 | { | ||
812 | .name = "CharTempWindowOk", | ||
813 | .flags = IORESOURCE_IRQ, | ||
814 | .start = AB5500_IRQ(17, 7), | ||
815 | .end = AB5500_IRQ(18, 0), | ||
816 | }, | ||
817 | { | ||
818 | .name = "USB_SprDetect", | ||
819 | .flags = IORESOURCE_IRQ, | ||
820 | .start = AB5500_IRQ(18, 1), | ||
821 | .end = AB5500_IRQ(18, 1), | ||
822 | }, | ||
823 | { | ||
824 | .name = "usb_adp_probe_unplug", | ||
825 | .flags = IORESOURCE_IRQ, | ||
826 | .start = AB5500_IRQ(18, 2), | ||
827 | .end = AB5500_IRQ(18, 2), | ||
828 | }, | ||
829 | { | ||
830 | .name = "VBUSChDrop", | ||
831 | .flags = IORESOURCE_IRQ, | ||
832 | .start = AB5500_IRQ(18, 3), | ||
833 | .end = AB5500_IRQ(18, 4), | ||
834 | }, | ||
835 | { | ||
836 | .name = "dcio_char_rec_done", | ||
837 | .flags = IORESOURCE_IRQ, | ||
838 | .start = AB5500_IRQ(18, 5), | ||
839 | .end = AB5500_IRQ(18, 5), | ||
840 | }, | ||
841 | { | ||
842 | .name = "Charging_stopped_by_temp", | ||
843 | .flags = IORESOURCE_IRQ, | ||
844 | .start = AB5500_IRQ(18, 6), | ||
845 | .end = AB5500_IRQ(18, 6), | ||
846 | }, | ||
847 | { | ||
848 | .name = "CHGstate_11_SafeModeVBUS", | ||
849 | .flags = IORESOURCE_IRQ, | ||
850 | .start = AB5500_IRQ(21, 1), | ||
851 | .end = AB5500_IRQ(21, 2), | ||
852 | }, | ||
853 | { | ||
854 | .name = "CHGstate_12_comletedVBUS", | ||
855 | .flags = IORESOURCE_IRQ, | ||
856 | .start = AB5500_IRQ(21, 2), | ||
857 | .end = AB5500_IRQ(21, 2), | ||
858 | }, | ||
859 | { | ||
860 | .name = "CHGstate_13_completedVBUS", | ||
861 | .flags = IORESOURCE_IRQ, | ||
862 | .start = AB5500_IRQ(21, 3), | ||
863 | .end = AB5500_IRQ(21, 3), | ||
864 | }, | ||
865 | { | ||
866 | .name = "CHGstate_14_FullChgDCIO", | ||
867 | .flags = IORESOURCE_IRQ, | ||
868 | .start = AB5500_IRQ(21, 4), | ||
869 | .end = AB5500_IRQ(21, 4), | ||
870 | }, | ||
871 | { | ||
872 | .name = "CHGstate_15_SafeModeDCIO", | ||
873 | .flags = IORESOURCE_IRQ, | ||
874 | .start = AB5500_IRQ(21, 5), | ||
875 | .end = AB5500_IRQ(21, 5), | ||
876 | }, | ||
877 | { | ||
878 | .name = "CHGstate_16_OFFsuspendDCIO", | ||
879 | .flags = IORESOURCE_IRQ, | ||
880 | .start = AB5500_IRQ(21, 6), | ||
881 | .end = AB5500_IRQ(21, 6), | ||
882 | }, | ||
883 | { | ||
884 | .name = "CHGstate_17_completedDCIO", | ||
885 | .flags = IORESOURCE_IRQ, | ||
886 | .start = AB5500_IRQ(21, 7), | ||
887 | .end = AB5500_IRQ(21, 7), | ||
888 | }, | ||
889 | }, | ||
890 | }, | ||
891 | [AB5500_DEVID_OTP] = { | ||
892 | .name = "ab5500-otp", | ||
893 | .id = AB5500_DEVID_OTP, | ||
894 | }, | ||
895 | [AB5500_DEVID_VIDEO] = { | ||
896 | .name = "ab5500-video", | ||
897 | .id = AB5500_DEVID_VIDEO, | ||
898 | .num_resources = 1, | ||
899 | .resources = (struct resource[]) { | ||
900 | { | ||
901 | .name = "plugTVdet", | ||
902 | .flags = IORESOURCE_IRQ, | ||
903 | .start = AB5500_IRQ(22, 2), | ||
904 | .end = AB5500_IRQ(22, 2), | ||
905 | }, | ||
906 | }, | ||
907 | }, | ||
908 | [AB5500_DEVID_DBIECI] = { | ||
909 | .name = "ab5500-dbieci", | ||
910 | .id = AB5500_DEVID_DBIECI, | ||
911 | .num_resources = 10, | ||
912 | .resources = (struct resource[]) { | ||
913 | { | ||
914 | .name = "COLL", | ||
915 | .flags = IORESOURCE_IRQ, | ||
916 | .start = AB5500_IRQ(14, 0), | ||
917 | .end = AB5500_IRQ(14, 0), | ||
918 | }, | ||
919 | { | ||
920 | .name = "RESERR", | ||
921 | .flags = IORESOURCE_IRQ, | ||
922 | .start = AB5500_IRQ(14, 1), | ||
923 | .end = AB5500_IRQ(14, 1), | ||
924 | }, | ||
925 | { | ||
926 | .name = "FRAERR", | ||
927 | .flags = IORESOURCE_IRQ, | ||
928 | .start = AB5500_IRQ(14, 2), | ||
929 | .end = AB5500_IRQ(14, 2), | ||
930 | }, | ||
931 | { | ||
932 | .name = "COMERR", | ||
933 | .flags = IORESOURCE_IRQ, | ||
934 | .start = AB5500_IRQ(14, 3), | ||
935 | .end = AB5500_IRQ(14, 3), | ||
936 | }, | ||
937 | { | ||
938 | .name = "BSI_indicator", | ||
939 | .flags = IORESOURCE_IRQ, | ||
940 | .start = AB5500_IRQ(14, 4), | ||
941 | .end = AB5500_IRQ(14, 4), | ||
942 | }, | ||
943 | { | ||
944 | .name = "SPDSET", | ||
945 | .flags = IORESOURCE_IRQ, | ||
946 | .start = AB5500_IRQ(14, 6), | ||
947 | .end = AB5500_IRQ(14, 6), | ||
948 | }, | ||
949 | { | ||
950 | .name = "DSENT", | ||
951 | .flags = IORESOURCE_IRQ, | ||
952 | .start = AB5500_IRQ(14, 7), | ||
953 | .end = AB5500_IRQ(14, 7), | ||
954 | }, | ||
955 | { | ||
956 | .name = "DREC", | ||
957 | .flags = IORESOURCE_IRQ, | ||
958 | .start = AB5500_IRQ(15, 0), | ||
959 | .end = AB5500_IRQ(15, 0), | ||
960 | }, | ||
961 | { | ||
962 | .name = "ACCINT", | ||
963 | .flags = IORESOURCE_IRQ, | ||
964 | .start = AB5500_IRQ(15, 1), | ||
965 | .end = AB5500_IRQ(15, 1), | ||
966 | }, | ||
967 | { | ||
968 | .name = "NOPINT", | ||
969 | .flags = IORESOURCE_IRQ, | ||
970 | .start = AB5500_IRQ(15, 2), | ||
971 | .end = AB5500_IRQ(15, 2), | ||
972 | }, | ||
973 | }, | ||
974 | }, | ||
975 | [AB5500_DEVID_ONSWA] = { | ||
976 | .name = "ab5500-onswa", | ||
977 | .id = AB5500_DEVID_ONSWA, | ||
978 | .num_resources = 2, | ||
979 | .resources = (struct resource[]) { | ||
980 | { | ||
981 | .name = "ONSWAn_rising", | ||
982 | .flags = IORESOURCE_IRQ, | ||
983 | .start = AB5500_IRQ(1, 3), | ||
984 | .end = AB5500_IRQ(1, 3), | ||
985 | }, | ||
986 | { | ||
987 | .name = "ONSWAn_falling", | ||
988 | .flags = IORESOURCE_IRQ, | ||
989 | .start = AB5500_IRQ(1, 4), | ||
990 | .end = AB5500_IRQ(1, 4), | ||
991 | }, | ||
992 | }, | ||
993 | }, | ||
994 | }; | ||
995 | |||
996 | /* | ||
997 | * Functionality for getting/setting register values. | ||
998 | */ | ||
999 | int ab5500_get_register_interruptible_raw(struct ab5500 *ab, | ||
1000 | u8 bank, u8 reg, | ||
1001 | u8 *value) | ||
1002 | { | ||
1003 | int err; | ||
1004 | |||
1005 | if (bank >= AB5500_NUM_BANKS) | ||
1006 | return -EINVAL; | ||
1007 | |||
1008 | err = mutex_lock_interruptible(&ab->access_mutex); | ||
1009 | if (err) | ||
1010 | return err; | ||
1011 | err = db5500_prcmu_abb_read(bankinfo[bank].slave_addr, reg, value, 1); | ||
1012 | |||
1013 | mutex_unlock(&ab->access_mutex); | ||
1014 | return err; | ||
1015 | } | ||
1016 | |||
1017 | static int get_register_page_interruptible(struct ab5500 *ab, u8 bank, | ||
1018 | u8 first_reg, u8 *regvals, u8 numregs) | ||
1019 | { | ||
1020 | int err; | ||
1021 | |||
1022 | if (bank >= AB5500_NUM_BANKS) | ||
1023 | return -EINVAL; | ||
1024 | |||
1025 | err = mutex_lock_interruptible(&ab->access_mutex); | ||
1026 | if (err) | ||
1027 | return err; | ||
1028 | |||
1029 | while (numregs) { | ||
1030 | /* The hardware limit for get page is 4 */ | ||
1031 | u8 curnum = min_t(u8, numregs, 4u); | ||
1032 | |||
1033 | err = db5500_prcmu_abb_read(bankinfo[bank].slave_addr, | ||
1034 | first_reg, regvals, curnum); | ||
1035 | if (err) | ||
1036 | goto out; | ||
1037 | |||
1038 | numregs -= curnum; | ||
1039 | first_reg += curnum; | ||
1040 | regvals += curnum; | ||
1041 | } | ||
1042 | |||
1043 | out: | ||
1044 | mutex_unlock(&ab->access_mutex); | ||
1045 | return err; | ||
1046 | } | ||
1047 | |||
1048 | int ab5500_mask_and_set_register_interruptible_raw(struct ab5500 *ab, u8 bank, | ||
1049 | u8 reg, u8 bitmask, u8 bitvalues) | ||
1050 | { | ||
1051 | int err = 0; | ||
1052 | |||
1053 | if (bank >= AB5500_NUM_BANKS) | ||
1054 | return -EINVAL; | ||
1055 | |||
1056 | if (bitmask) { | ||
1057 | u8 buf; | ||
1058 | |||
1059 | err = mutex_lock_interruptible(&ab->access_mutex); | ||
1060 | if (err) | ||
1061 | return err; | ||
1062 | |||
1063 | if (bitmask == 0xFF) /* No need to read in this case. */ | ||
1064 | buf = bitvalues; | ||
1065 | else { /* Read and modify the register value. */ | ||
1066 | err = db5500_prcmu_abb_read(bankinfo[bank].slave_addr, | ||
1067 | reg, &buf, 1); | ||
1068 | if (err) | ||
1069 | return err; | ||
1070 | |||
1071 | buf = ((~bitmask & buf) | (bitmask & bitvalues)); | ||
1072 | } | ||
1073 | /* Write the new value. */ | ||
1074 | err = db5500_prcmu_abb_write(bankinfo[bank].slave_addr, reg, | ||
1075 | &buf, 1); | ||
1076 | |||
1077 | mutex_unlock(&ab->access_mutex); | ||
1078 | } | ||
1079 | return err; | ||
1080 | } | ||
1081 | |||
1082 | static int | ||
1083 | set_register_interruptible(struct ab5500 *ab, u8 bank, u8 reg, u8 value) | ||
1084 | { | ||
1085 | return ab5500_mask_and_set_register_interruptible_raw(ab, bank, reg, | ||
1086 | 0xff, value); | ||
1087 | } | ||
1088 | |||
1089 | /* | ||
1090 | * Read/write permission checking functions. | ||
1091 | */ | ||
1092 | static const struct ab5500_i2c_ranges *get_bankref(u8 devid, u8 bank) | ||
1093 | { | ||
1094 | u8 i; | ||
1095 | |||
1096 | if (devid < AB5500_NUM_DEVICES) { | ||
1097 | for (i = 0; i < ab5500_bank_ranges[devid].nbanks; i++) { | ||
1098 | if (ab5500_bank_ranges[devid].bank[i].bankid == bank) | ||
1099 | return &ab5500_bank_ranges[devid].bank[i]; | ||
1100 | } | ||
1101 | } | ||
1102 | return NULL; | ||
1103 | } | ||
1104 | |||
1105 | static bool page_write_allowed(u8 devid, u8 bank, u8 first_reg, u8 last_reg) | ||
1106 | { | ||
1107 | u8 i; /* range loop index */ | ||
1108 | const struct ab5500_i2c_ranges *bankref; | ||
1109 | |||
1110 | bankref = get_bankref(devid, bank); | ||
1111 | if (bankref == NULL || last_reg < first_reg) | ||
1112 | return false; | ||
1113 | |||
1114 | for (i = 0; i < bankref->nranges; i++) { | ||
1115 | if (first_reg < bankref->range[i].first) | ||
1116 | break; | ||
1117 | if ((last_reg <= bankref->range[i].last) && | ||
1118 | (bankref->range[i].perm & AB5500_PERM_WR)) | ||
1119 | return true; | ||
1120 | } | ||
1121 | return false; | ||
1122 | } | ||
1123 | |||
1124 | static bool reg_write_allowed(u8 devid, u8 bank, u8 reg) | ||
1125 | { | ||
1126 | return page_write_allowed(devid, bank, reg, reg); | ||
1127 | } | ||
1128 | |||
1129 | static bool page_read_allowed(u8 devid, u8 bank, u8 first_reg, u8 last_reg) | ||
1130 | { | ||
1131 | u8 i; | ||
1132 | const struct ab5500_i2c_ranges *bankref; | ||
1133 | |||
1134 | bankref = get_bankref(devid, bank); | ||
1135 | if (bankref == NULL || last_reg < first_reg) | ||
1136 | return false; | ||
1137 | |||
1138 | |||
1139 | /* Find the range (if it exists in the list) that includes first_reg. */ | ||
1140 | for (i = 0; i < bankref->nranges; i++) { | ||
1141 | if (first_reg < bankref->range[i].first) | ||
1142 | return false; | ||
1143 | if (first_reg <= bankref->range[i].last) | ||
1144 | break; | ||
1145 | } | ||
1146 | /* Make sure that the entire range up to and including last_reg is | ||
1147 | * readable. This may span several of the ranges in the list. | ||
1148 | */ | ||
1149 | while ((i < bankref->nranges) && | ||
1150 | (bankref->range[i].perm & AB5500_PERM_RD)) { | ||
1151 | if (last_reg <= bankref->range[i].last) | ||
1152 | return true; | ||
1153 | if ((++i >= bankref->nranges) || | ||
1154 | (bankref->range[i].first != | ||
1155 | (bankref->range[i - 1].last + 1))) { | ||
1156 | break; | ||
1157 | } | ||
1158 | } | ||
1159 | return false; | ||
1160 | } | ||
1161 | |||
1162 | static bool reg_read_allowed(u8 devid, u8 bank, u8 reg) | ||
1163 | { | ||
1164 | return page_read_allowed(devid, bank, reg, reg); | ||
1165 | } | ||
1166 | |||
1167 | |||
1168 | /* | ||
1169 | * The exported register access functionality. | ||
1170 | */ | ||
1171 | static int ab5500_get_chip_id(struct device *dev) | ||
1172 | { | ||
1173 | struct ab5500 *ab = dev_get_drvdata(dev->parent); | ||
1174 | |||
1175 | return (int)ab->chip_id; | ||
1176 | } | ||
1177 | |||
1178 | static int ab5500_mask_and_set_register_interruptible(struct device *dev, | ||
1179 | u8 bank, u8 reg, u8 bitmask, u8 bitvalues) | ||
1180 | { | ||
1181 | struct ab5500 *ab; | ||
1182 | struct platform_device *pdev = to_platform_device(dev); | ||
1183 | |||
1184 | if ((AB5500_NUM_BANKS <= bank) || | ||
1185 | !reg_write_allowed(pdev->id, bank, reg)) | ||
1186 | return -EINVAL; | ||
1187 | |||
1188 | ab = dev_get_drvdata(dev->parent); | ||
1189 | return ab5500_mask_and_set_register_interruptible_raw(ab, bank, reg, | ||
1190 | bitmask, bitvalues); | ||
1191 | } | ||
1192 | |||
1193 | static int ab5500_set_register_interruptible(struct device *dev, u8 bank, | ||
1194 | u8 reg, u8 value) | ||
1195 | { | ||
1196 | return ab5500_mask_and_set_register_interruptible(dev, bank, reg, 0xFF, | ||
1197 | value); | ||
1198 | } | ||
1199 | |||
1200 | static int ab5500_get_register_interruptible(struct device *dev, u8 bank, | ||
1201 | u8 reg, u8 *value) | ||
1202 | { | ||
1203 | struct ab5500 *ab; | ||
1204 | struct platform_device *pdev = to_platform_device(dev); | ||
1205 | |||
1206 | if ((AB5500_NUM_BANKS <= bank) || | ||
1207 | !reg_read_allowed(pdev->id, bank, reg)) | ||
1208 | return -EINVAL; | ||
1209 | |||
1210 | ab = dev_get_drvdata(dev->parent); | ||
1211 | return ab5500_get_register_interruptible_raw(ab, bank, reg, value); | ||
1212 | } | ||
1213 | |||
1214 | static int ab5500_get_register_page_interruptible(struct device *dev, u8 bank, | ||
1215 | u8 first_reg, u8 *regvals, u8 numregs) | ||
1216 | { | ||
1217 | struct ab5500 *ab; | ||
1218 | struct platform_device *pdev = to_platform_device(dev); | ||
1219 | |||
1220 | if ((AB5500_NUM_BANKS <= bank) || | ||
1221 | !page_read_allowed(pdev->id, bank, | ||
1222 | first_reg, (first_reg + numregs - 1))) | ||
1223 | return -EINVAL; | ||
1224 | |||
1225 | ab = dev_get_drvdata(dev->parent); | ||
1226 | return get_register_page_interruptible(ab, bank, first_reg, regvals, | ||
1227 | numregs); | ||
1228 | } | ||
1229 | |||
1230 | static int | ||
1231 | ab5500_event_registers_startup_state_get(struct device *dev, u8 *event) | ||
1232 | { | ||
1233 | struct ab5500 *ab; | ||
1234 | |||
1235 | ab = dev_get_drvdata(dev->parent); | ||
1236 | if (!ab->startup_events_read) | ||
1237 | return -EAGAIN; /* Try again later */ | ||
1238 | |||
1239 | memcpy(event, ab->startup_events, AB5500_NUM_EVENT_REG); | ||
1240 | return 0; | ||
1241 | } | ||
1242 | |||
1243 | static struct abx500_ops ab5500_ops = { | ||
1244 | .get_chip_id = ab5500_get_chip_id, | ||
1245 | .get_register = ab5500_get_register_interruptible, | ||
1246 | .set_register = ab5500_set_register_interruptible, | ||
1247 | .get_register_page = ab5500_get_register_page_interruptible, | ||
1248 | .set_register_page = NULL, | ||
1249 | .mask_and_set_register = ab5500_mask_and_set_register_interruptible, | ||
1250 | .event_registers_startup_state_get = | ||
1251 | ab5500_event_registers_startup_state_get, | ||
1252 | .startup_irq_enabled = NULL, | ||
1253 | }; | ||
1254 | |||
1255 | /* | ||
1256 | * ab5500_setup : Basic set-up, datastructure creation/destruction | ||
1257 | * and I2C interface.This sets up a default config | ||
1258 | * in the AB5500 chip so that it will work as expected. | ||
1259 | * @ab : Pointer to ab5500 structure | ||
1260 | * @settings : Pointer to struct abx500_init_settings | ||
1261 | * @size : Size of init data | ||
1262 | */ | ||
1263 | static int __init ab5500_setup(struct ab5500 *ab, | ||
1264 | struct abx500_init_settings *settings, unsigned int size) | ||
1265 | { | ||
1266 | int err = 0; | ||
1267 | int i; | ||
1268 | |||
1269 | for (i = 0; i < size; i++) { | ||
1270 | err = ab5500_mask_and_set_register_interruptible_raw(ab, | ||
1271 | settings[i].bank, | ||
1272 | settings[i].reg, | ||
1273 | 0xFF, settings[i].setting); | ||
1274 | if (err) | ||
1275 | goto exit_no_setup; | ||
1276 | |||
1277 | /* If event mask register update the event mask in ab5500 */ | ||
1278 | if ((settings[i].bank == AB5500_BANK_IT) && | ||
1279 | (AB5500_MASK_BASE <= settings[i].reg) && | ||
1280 | (settings[i].reg <= AB5500_MASK_END)) { | ||
1281 | ab->mask[settings[i].reg - AB5500_MASK_BASE] = | ||
1282 | settings[i].setting; | ||
1283 | } | ||
1284 | } | ||
1285 | exit_no_setup: | ||
1286 | return err; | ||
1287 | } | ||
1288 | |||
1289 | struct ab_family_id { | ||
1290 | u8 id; | ||
1291 | char *name; | ||
1292 | }; | ||
1293 | |||
1294 | static const struct ab_family_id ids[] __initdata = { | ||
1295 | /* AB5500 */ | ||
1296 | { | ||
1297 | .id = AB5500_1_0, | ||
1298 | .name = "1.0" | ||
1299 | }, | ||
1300 | { | ||
1301 | .id = AB5500_1_1, | ||
1302 | .name = "1.1" | ||
1303 | }, | ||
1304 | /* Terminator */ | ||
1305 | { | ||
1306 | .id = 0x00, | ||
1307 | } | ||
1308 | }; | ||
1309 | |||
1310 | static int __init ab5500_probe(struct platform_device *pdev) | ||
1311 | { | ||
1312 | struct ab5500 *ab; | ||
1313 | struct ab5500_platform_data *ab5500_plf_data = | ||
1314 | pdev->dev.platform_data; | ||
1315 | int err; | ||
1316 | int i; | ||
1317 | |||
1318 | ab = kzalloc(sizeof(struct ab5500), GFP_KERNEL); | ||
1319 | if (!ab) { | ||
1320 | dev_err(&pdev->dev, | ||
1321 | "could not allocate ab5500 device\n"); | ||
1322 | return -ENOMEM; | ||
1323 | } | ||
1324 | |||
1325 | /* Initialize data structure */ | ||
1326 | mutex_init(&ab->access_mutex); | ||
1327 | mutex_init(&ab->irq_lock); | ||
1328 | ab->dev = &pdev->dev; | ||
1329 | |||
1330 | platform_set_drvdata(pdev, ab); | ||
1331 | |||
1332 | /* Read chip ID register */ | ||
1333 | err = ab5500_get_register_interruptible_raw(ab, | ||
1334 | AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP, | ||
1335 | AB5500_CHIP_ID, &ab->chip_id); | ||
1336 | if (err) { | ||
1337 | dev_err(&pdev->dev, "could not communicate with the analog " | ||
1338 | "baseband chip\n"); | ||
1339 | goto exit_no_detect; | ||
1340 | } | ||
1341 | |||
1342 | for (i = 0; ids[i].id != 0x0; i++) { | ||
1343 | if (ids[i].id == ab->chip_id) { | ||
1344 | snprintf(&ab->chip_name[0], sizeof(ab->chip_name) - 1, | ||
1345 | "AB5500 %s", ids[i].name); | ||
1346 | break; | ||
1347 | } | ||
1348 | } | ||
1349 | if (ids[i].id == 0x0) { | ||
1350 | dev_err(&pdev->dev, "unknown analog baseband chip id: 0x%x\n", | ||
1351 | ab->chip_id); | ||
1352 | dev_err(&pdev->dev, "driver not started!\n"); | ||
1353 | goto exit_no_detect; | ||
1354 | } | ||
1355 | |||
1356 | /* Clear and mask all interrupts */ | ||
1357 | for (i = 0; i < AB5500_NUM_IRQ_REGS; i++) { | ||
1358 | u8 latchreg = AB5500_IT_LATCH0_REG + i; | ||
1359 | u8 maskreg = AB5500_IT_MASK0_REG + i; | ||
1360 | u8 val; | ||
1361 | |||
1362 | ab5500_get_register_interruptible_raw(ab, AB5500_BANK_IT, | ||
1363 | latchreg, &val); | ||
1364 | set_register_interruptible(ab, AB5500_BANK_IT, maskreg, 0xff); | ||
1365 | ab->mask[i] = ab->oldmask[i] = 0xff; | ||
1366 | } | ||
1367 | |||
1368 | err = abx500_register_ops(&pdev->dev, &ab5500_ops); | ||
1369 | if (err) { | ||
1370 | dev_err(&pdev->dev, "ab5500_register ops error\n"); | ||
1371 | goto exit_no_detect; | ||
1372 | } | ||
1373 | |||
1374 | /* Set up and register the platform devices. */ | ||
1375 | for (i = 0; i < AB5500_NUM_DEVICES; i++) { | ||
1376 | ab5500_devs[i].platform_data = ab5500_plf_data->dev_data[i]; | ||
1377 | ab5500_devs[i].pdata_size = | ||
1378 | sizeof(ab5500_plf_data->dev_data[i]); | ||
1379 | } | ||
1380 | |||
1381 | err = mfd_add_devices(&pdev->dev, 0, ab5500_devs, | ||
1382 | ARRAY_SIZE(ab5500_devs), NULL, | ||
1383 | ab5500_plf_data->irq.base); | ||
1384 | if (err) { | ||
1385 | dev_err(&pdev->dev, "ab5500_mfd_add_device error\n"); | ||
1386 | goto exit_no_detect; | ||
1387 | } | ||
1388 | |||
1389 | err = ab5500_setup(ab, ab5500_plf_data->init_settings, | ||
1390 | ab5500_plf_data->init_settings_sz); | ||
1391 | if (err) { | ||
1392 | dev_err(&pdev->dev, "ab5500_setup error\n"); | ||
1393 | goto exit_no_detect; | ||
1394 | } | ||
1395 | |||
1396 | ab5500_setup_debugfs(ab); | ||
1397 | |||
1398 | dev_info(&pdev->dev, "detected AB chip: %s\n", &ab->chip_name[0]); | ||
1399 | return 0; | ||
1400 | |||
1401 | exit_no_detect: | ||
1402 | kfree(ab); | ||
1403 | return err; | ||
1404 | } | ||
1405 | |||
1406 | static int __exit ab5500_remove(struct platform_device *pdev) | ||
1407 | { | ||
1408 | struct ab5500 *ab = platform_get_drvdata(pdev); | ||
1409 | |||
1410 | ab5500_remove_debugfs(); | ||
1411 | mfd_remove_devices(&pdev->dev); | ||
1412 | kfree(ab); | ||
1413 | return 0; | ||
1414 | } | ||
1415 | |||
1416 | static struct platform_driver ab5500_driver = { | ||
1417 | .driver = { | ||
1418 | .name = "ab5500-core", | ||
1419 | .owner = THIS_MODULE, | ||
1420 | }, | ||
1421 | .remove = __exit_p(ab5500_remove), | ||
1422 | }; | ||
1423 | |||
1424 | static int __init ab5500_core_init(void) | ||
1425 | { | ||
1426 | return platform_driver_probe(&ab5500_driver, ab5500_probe); | ||
1427 | } | ||
1428 | |||
1429 | static void __exit ab5500_core_exit(void) | ||
1430 | { | ||
1431 | platform_driver_unregister(&ab5500_driver); | ||
1432 | } | ||
1433 | |||
1434 | subsys_initcall(ab5500_core_init); | ||
1435 | module_exit(ab5500_core_exit); | ||
1436 | |||
1437 | MODULE_AUTHOR("Mattias Wallin <mattias.wallin@stericsson.com>"); | ||
1438 | MODULE_DESCRIPTION("AB5500 core driver"); | ||
1439 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mfd/ab5500-debugfs.c b/drivers/mfd/ab5500-debugfs.c deleted file mode 100644 index 72006940937a..000000000000 --- a/drivers/mfd/ab5500-debugfs.c +++ /dev/null | |||
@@ -1,807 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 ST-Ericsson | ||
3 | * License terms: GNU General Public License (GPL) version 2 | ||
4 | * Debugfs support for the AB5500 MFD driver | ||
5 | */ | ||
6 | |||
7 | #include <linux/module.h> | ||
8 | #include <linux/debugfs.h> | ||
9 | #include <linux/seq_file.h> | ||
10 | #include <linux/mfd/abx500.h> | ||
11 | #include <linux/mfd/abx500/ab5500.h> | ||
12 | #include <linux/uaccess.h> | ||
13 | |||
14 | #include "ab5500-core.h" | ||
15 | #include "ab5500-debugfs.h" | ||
16 | |||
17 | static struct ab5500_i2c_ranges ab5500_reg_ranges[AB5500_NUM_BANKS] = { | ||
18 | [AB5500_BANK_LED] = { | ||
19 | .bankid = AB5500_BANK_LED, | ||
20 | .nranges = 1, | ||
21 | .range = (struct ab5500_reg_range[]) { | ||
22 | { | ||
23 | .first = 0x00, | ||
24 | .last = 0x0C, | ||
25 | .perm = AB5500_PERM_RW, | ||
26 | }, | ||
27 | }, | ||
28 | }, | ||
29 | [AB5500_BANK_ADC] = { | ||
30 | .bankid = AB5500_BANK_ADC, | ||
31 | .nranges = 6, | ||
32 | .range = (struct ab5500_reg_range[]) { | ||
33 | { | ||
34 | .first = 0x1F, | ||
35 | .last = 0x22, | ||
36 | .perm = AB5500_PERM_RO, | ||
37 | }, | ||
38 | { | ||
39 | .first = 0x23, | ||
40 | .last = 0x24, | ||
41 | .perm = AB5500_PERM_RW, | ||
42 | }, | ||
43 | { | ||
44 | .first = 0x26, | ||
45 | .last = 0x2D, | ||
46 | .perm = AB5500_PERM_RO, | ||
47 | }, | ||
48 | { | ||
49 | .first = 0x2F, | ||
50 | .last = 0x34, | ||
51 | .perm = AB5500_PERM_RW, | ||
52 | }, | ||
53 | { | ||
54 | .first = 0x37, | ||
55 | .last = 0x57, | ||
56 | .perm = AB5500_PERM_RW, | ||
57 | }, | ||
58 | { | ||
59 | .first = 0x58, | ||
60 | .last = 0x58, | ||
61 | .perm = AB5500_PERM_RO, | ||
62 | }, | ||
63 | }, | ||
64 | }, | ||
65 | [AB5500_BANK_RTC] = { | ||
66 | .bankid = AB5500_BANK_RTC, | ||
67 | .nranges = 2, | ||
68 | .range = (struct ab5500_reg_range[]) { | ||
69 | { | ||
70 | .first = 0x00, | ||
71 | .last = 0x04, | ||
72 | .perm = AB5500_PERM_RW, | ||
73 | }, | ||
74 | { | ||
75 | .first = 0x06, | ||
76 | .last = 0x0C, | ||
77 | .perm = AB5500_PERM_RW, | ||
78 | }, | ||
79 | }, | ||
80 | }, | ||
81 | [AB5500_BANK_STARTUP] = { | ||
82 | .bankid = AB5500_BANK_STARTUP, | ||
83 | .nranges = 12, | ||
84 | .range = (struct ab5500_reg_range[]) { | ||
85 | { | ||
86 | .first = 0x00, | ||
87 | .last = 0x01, | ||
88 | .perm = AB5500_PERM_RW, | ||
89 | }, | ||
90 | { | ||
91 | .first = 0x1F, | ||
92 | .last = 0x1F, | ||
93 | .perm = AB5500_PERM_RW, | ||
94 | }, | ||
95 | { | ||
96 | .first = 0x2E, | ||
97 | .last = 0x2E, | ||
98 | .perm = AB5500_PERM_RO, | ||
99 | }, | ||
100 | { | ||
101 | .first = 0x2F, | ||
102 | .last = 0x30, | ||
103 | .perm = AB5500_PERM_RW, | ||
104 | }, | ||
105 | { | ||
106 | .first = 0x50, | ||
107 | .last = 0x51, | ||
108 | .perm = AB5500_PERM_RW, | ||
109 | }, | ||
110 | { | ||
111 | .first = 0x60, | ||
112 | .last = 0x61, | ||
113 | .perm = AB5500_PERM_RW, | ||
114 | }, | ||
115 | { | ||
116 | .first = 0x66, | ||
117 | .last = 0x8A, | ||
118 | .perm = AB5500_PERM_RW, | ||
119 | }, | ||
120 | { | ||
121 | .first = 0x8C, | ||
122 | .last = 0x96, | ||
123 | .perm = AB5500_PERM_RW, | ||
124 | }, | ||
125 | { | ||
126 | .first = 0xAA, | ||
127 | .last = 0xB4, | ||
128 | .perm = AB5500_PERM_RW, | ||
129 | }, | ||
130 | { | ||
131 | .first = 0xB7, | ||
132 | .last = 0xBF, | ||
133 | .perm = AB5500_PERM_RW, | ||
134 | }, | ||
135 | { | ||
136 | .first = 0xC1, | ||
137 | .last = 0xCA, | ||
138 | .perm = AB5500_PERM_RW, | ||
139 | }, | ||
140 | { | ||
141 | .first = 0xD3, | ||
142 | .last = 0xE0, | ||
143 | .perm = AB5500_PERM_RW, | ||
144 | }, | ||
145 | }, | ||
146 | }, | ||
147 | [AB5500_BANK_DBI_ECI] = { | ||
148 | .bankid = AB5500_BANK_DBI_ECI, | ||
149 | .nranges = 3, | ||
150 | .range = (struct ab5500_reg_range[]) { | ||
151 | { | ||
152 | .first = 0x00, | ||
153 | .last = 0x07, | ||
154 | .perm = AB5500_PERM_RW, | ||
155 | }, | ||
156 | { | ||
157 | .first = 0x10, | ||
158 | .last = 0x10, | ||
159 | .perm = AB5500_PERM_RW, | ||
160 | }, | ||
161 | { | ||
162 | .first = 0x13, | ||
163 | .last = 0x13, | ||
164 | .perm = AB5500_PERM_RW, | ||
165 | }, | ||
166 | }, | ||
167 | }, | ||
168 | [AB5500_BANK_CHG] = { | ||
169 | .bankid = AB5500_BANK_CHG, | ||
170 | .nranges = 2, | ||
171 | .range = (struct ab5500_reg_range[]) { | ||
172 | { | ||
173 | .first = 0x11, | ||
174 | .last = 0x11, | ||
175 | .perm = AB5500_PERM_RO, | ||
176 | }, | ||
177 | { | ||
178 | .first = 0x12, | ||
179 | .last = 0x1B, | ||
180 | .perm = AB5500_PERM_RW, | ||
181 | }, | ||
182 | }, | ||
183 | }, | ||
184 | [AB5500_BANK_FG_BATTCOM_ACC] = { | ||
185 | .bankid = AB5500_BANK_FG_BATTCOM_ACC, | ||
186 | .nranges = 2, | ||
187 | .range = (struct ab5500_reg_range[]) { | ||
188 | { | ||
189 | .first = 0x00, | ||
190 | .last = 0x0B, | ||
191 | .perm = AB5500_PERM_RO, | ||
192 | }, | ||
193 | { | ||
194 | .first = 0x0C, | ||
195 | .last = 0x10, | ||
196 | .perm = AB5500_PERM_RW, | ||
197 | }, | ||
198 | }, | ||
199 | }, | ||
200 | [AB5500_BANK_USB] = { | ||
201 | .bankid = AB5500_BANK_USB, | ||
202 | .nranges = 12, | ||
203 | .range = (struct ab5500_reg_range[]) { | ||
204 | { | ||
205 | .first = 0x01, | ||
206 | .last = 0x01, | ||
207 | .perm = AB5500_PERM_RW, | ||
208 | }, | ||
209 | { | ||
210 | .first = 0x80, | ||
211 | .last = 0x83, | ||
212 | .perm = AB5500_PERM_RW, | ||
213 | }, | ||
214 | { | ||
215 | .first = 0x87, | ||
216 | .last = 0x8A, | ||
217 | .perm = AB5500_PERM_RW, | ||
218 | }, | ||
219 | { | ||
220 | .first = 0x8B, | ||
221 | .last = 0x8B, | ||
222 | .perm = AB5500_PERM_RO, | ||
223 | }, | ||
224 | { | ||
225 | .first = 0x91, | ||
226 | .last = 0x92, | ||
227 | .perm = AB5500_PERM_RO, | ||
228 | }, | ||
229 | { | ||
230 | .first = 0x93, | ||
231 | .last = 0x93, | ||
232 | .perm = AB5500_PERM_RW, | ||
233 | }, | ||
234 | { | ||
235 | .first = 0x94, | ||
236 | .last = 0x94, | ||
237 | .perm = AB5500_PERM_RO, | ||
238 | }, | ||
239 | { | ||
240 | .first = 0xA8, | ||
241 | .last = 0xB0, | ||
242 | .perm = AB5500_PERM_RO, | ||
243 | }, | ||
244 | { | ||
245 | .first = 0xB2, | ||
246 | .last = 0xB2, | ||
247 | .perm = AB5500_PERM_RO, | ||
248 | }, | ||
249 | { | ||
250 | .first = 0xB4, | ||
251 | .last = 0xBC, | ||
252 | .perm = AB5500_PERM_RO, | ||
253 | }, | ||
254 | { | ||
255 | .first = 0xBF, | ||
256 | .last = 0xBF, | ||
257 | .perm = AB5500_PERM_RO, | ||
258 | }, | ||
259 | { | ||
260 | .first = 0xC1, | ||
261 | .last = 0xC5, | ||
262 | .perm = AB5500_PERM_RO, | ||
263 | }, | ||
264 | }, | ||
265 | }, | ||
266 | [AB5500_BANK_IT] = { | ||
267 | .bankid = AB5500_BANK_IT, | ||
268 | .nranges = 4, | ||
269 | .range = (struct ab5500_reg_range[]) { | ||
270 | { | ||
271 | .first = 0x00, | ||
272 | .last = 0x02, | ||
273 | .perm = AB5500_PERM_RO, | ||
274 | }, | ||
275 | { | ||
276 | .first = 0x20, | ||
277 | .last = 0x36, | ||
278 | .perm = AB5500_PERM_RO, | ||
279 | }, | ||
280 | { | ||
281 | .first = 0x40, | ||
282 | .last = 0x56, | ||
283 | .perm = AB5500_PERM_RO, | ||
284 | }, | ||
285 | { | ||
286 | .first = 0x60, | ||
287 | .last = 0x76, | ||
288 | .perm = AB5500_PERM_RO, | ||
289 | }, | ||
290 | }, | ||
291 | }, | ||
292 | [AB5500_BANK_VDDDIG_IO_I2C_CLK_TST] = { | ||
293 | .bankid = AB5500_BANK_VDDDIG_IO_I2C_CLK_TST, | ||
294 | .nranges = 7, | ||
295 | .range = (struct ab5500_reg_range[]) { | ||
296 | { | ||
297 | .first = 0x02, | ||
298 | .last = 0x02, | ||
299 | .perm = AB5500_PERM_RW, | ||
300 | }, | ||
301 | { | ||
302 | .first = 0x12, | ||
303 | .last = 0x12, | ||
304 | .perm = AB5500_PERM_RW, | ||
305 | }, | ||
306 | { | ||
307 | .first = 0x30, | ||
308 | .last = 0x34, | ||
309 | .perm = AB5500_PERM_RW, | ||
310 | }, | ||
311 | { | ||
312 | .first = 0x40, | ||
313 | .last = 0x44, | ||
314 | .perm = AB5500_PERM_RW, | ||
315 | }, | ||
316 | { | ||
317 | .first = 0x50, | ||
318 | .last = 0x54, | ||
319 | .perm = AB5500_PERM_RW, | ||
320 | }, | ||
321 | { | ||
322 | .first = 0x60, | ||
323 | .last = 0x64, | ||
324 | .perm = AB5500_PERM_RW, | ||
325 | }, | ||
326 | { | ||
327 | .first = 0x70, | ||
328 | .last = 0x74, | ||
329 | .perm = AB5500_PERM_RW, | ||
330 | }, | ||
331 | }, | ||
332 | }, | ||
333 | [AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP] = { | ||
334 | .bankid = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP, | ||
335 | .nranges = 13, | ||
336 | .range = (struct ab5500_reg_range[]) { | ||
337 | { | ||
338 | .first = 0x01, | ||
339 | .last = 0x01, | ||
340 | .perm = AB5500_PERM_RW, | ||
341 | }, | ||
342 | { | ||
343 | .first = 0x02, | ||
344 | .last = 0x02, | ||
345 | .perm = AB5500_PERM_RO, | ||
346 | }, | ||
347 | { | ||
348 | .first = 0x0D, | ||
349 | .last = 0x0F, | ||
350 | .perm = AB5500_PERM_RW, | ||
351 | }, | ||
352 | { | ||
353 | .first = 0x1C, | ||
354 | .last = 0x1C, | ||
355 | .perm = AB5500_PERM_RW, | ||
356 | }, | ||
357 | { | ||
358 | .first = 0x1E, | ||
359 | .last = 0x1E, | ||
360 | .perm = AB5500_PERM_RW, | ||
361 | }, | ||
362 | { | ||
363 | .first = 0x20, | ||
364 | .last = 0x21, | ||
365 | .perm = AB5500_PERM_RW, | ||
366 | }, | ||
367 | { | ||
368 | .first = 0x25, | ||
369 | .last = 0x25, | ||
370 | .perm = AB5500_PERM_RW, | ||
371 | }, | ||
372 | { | ||
373 | .first = 0x28, | ||
374 | .last = 0x2A, | ||
375 | .perm = AB5500_PERM_RW, | ||
376 | }, | ||
377 | { | ||
378 | .first = 0x30, | ||
379 | .last = 0x33, | ||
380 | .perm = AB5500_PERM_RW, | ||
381 | }, | ||
382 | { | ||
383 | .first = 0x40, | ||
384 | .last = 0x43, | ||
385 | .perm = AB5500_PERM_RW, | ||
386 | }, | ||
387 | { | ||
388 | .first = 0x50, | ||
389 | .last = 0x53, | ||
390 | .perm = AB5500_PERM_RW, | ||
391 | }, | ||
392 | { | ||
393 | .first = 0x60, | ||
394 | .last = 0x63, | ||
395 | .perm = AB5500_PERM_RW, | ||
396 | }, | ||
397 | { | ||
398 | .first = 0x70, | ||
399 | .last = 0x73, | ||
400 | .perm = AB5500_PERM_RW, | ||
401 | }, | ||
402 | }, | ||
403 | }, | ||
404 | [AB5500_BANK_VIBRA] = { | ||
405 | .bankid = AB5500_BANK_VIBRA, | ||
406 | .nranges = 2, | ||
407 | .range = (struct ab5500_reg_range[]) { | ||
408 | { | ||
409 | .first = 0x10, | ||
410 | .last = 0x13, | ||
411 | .perm = AB5500_PERM_RW, | ||
412 | }, | ||
413 | { | ||
414 | .first = 0xFE, | ||
415 | .last = 0xFE, | ||
416 | .perm = AB5500_PERM_RW, | ||
417 | }, | ||
418 | }, | ||
419 | }, | ||
420 | [AB5500_BANK_AUDIO_HEADSETUSB] = { | ||
421 | .bankid = AB5500_BANK_AUDIO_HEADSETUSB, | ||
422 | .nranges = 2, | ||
423 | .range = (struct ab5500_reg_range[]) { | ||
424 | { | ||
425 | .first = 0x00, | ||
426 | .last = 0x48, | ||
427 | .perm = AB5500_PERM_RW, | ||
428 | }, | ||
429 | { | ||
430 | .first = 0xEB, | ||
431 | .last = 0xFB, | ||
432 | .perm = AB5500_PERM_RW, | ||
433 | }, | ||
434 | }, | ||
435 | }, | ||
436 | [AB5500_BANK_SIM_USBSIM] = { | ||
437 | .bankid = AB5500_BANK_SIM_USBSIM, | ||
438 | .nranges = 1, | ||
439 | .range = (struct ab5500_reg_range[]) { | ||
440 | { | ||
441 | .first = 0x13, | ||
442 | .last = 0x19, | ||
443 | .perm = AB5500_PERM_RW, | ||
444 | }, | ||
445 | }, | ||
446 | }, | ||
447 | [AB5500_BANK_VDENC] = { | ||
448 | .bankid = AB5500_BANK_VDENC, | ||
449 | .nranges = 12, | ||
450 | .range = (struct ab5500_reg_range[]) { | ||
451 | { | ||
452 | .first = 0x00, | ||
453 | .last = 0x08, | ||
454 | .perm = AB5500_PERM_RW, | ||
455 | }, | ||
456 | { | ||
457 | .first = 0x09, | ||
458 | .last = 0x09, | ||
459 | .perm = AB5500_PERM_RO, | ||
460 | }, | ||
461 | { | ||
462 | .first = 0x0A, | ||
463 | .last = 0x12, | ||
464 | .perm = AB5500_PERM_RW, | ||
465 | }, | ||
466 | { | ||
467 | .first = 0x15, | ||
468 | .last = 0x19, | ||
469 | .perm = AB5500_PERM_RW, | ||
470 | }, | ||
471 | { | ||
472 | .first = 0x1B, | ||
473 | .last = 0x21, | ||
474 | .perm = AB5500_PERM_RW, | ||
475 | }, | ||
476 | { | ||
477 | .first = 0x27, | ||
478 | .last = 0x2C, | ||
479 | .perm = AB5500_PERM_RW, | ||
480 | }, | ||
481 | { | ||
482 | .first = 0x41, | ||
483 | .last = 0x41, | ||
484 | .perm = AB5500_PERM_RW, | ||
485 | }, | ||
486 | { | ||
487 | .first = 0x45, | ||
488 | .last = 0x5B, | ||
489 | .perm = AB5500_PERM_RW, | ||
490 | }, | ||
491 | { | ||
492 | .first = 0x5D, | ||
493 | .last = 0x5D, | ||
494 | .perm = AB5500_PERM_RW, | ||
495 | }, | ||
496 | { | ||
497 | .first = 0x69, | ||
498 | .last = 0x69, | ||
499 | .perm = AB5500_PERM_RW, | ||
500 | }, | ||
501 | { | ||
502 | .first = 0x6C, | ||
503 | .last = 0x6D, | ||
504 | .perm = AB5500_PERM_RW, | ||
505 | }, | ||
506 | { | ||
507 | .first = 0x80, | ||
508 | .last = 0x81, | ||
509 | .perm = AB5500_PERM_RW, | ||
510 | }, | ||
511 | }, | ||
512 | }, | ||
513 | }; | ||
514 | |||
515 | static int ab5500_registers_print(struct seq_file *s, void *p) | ||
516 | { | ||
517 | struct ab5500 *ab = s->private; | ||
518 | unsigned int i; | ||
519 | u8 bank = (u8)ab->debug_bank; | ||
520 | |||
521 | seq_printf(s, "ab5500 register values:\n"); | ||
522 | for (bank = 0; bank < AB5500_NUM_BANKS; bank++) { | ||
523 | seq_printf(s, " bank %u, %s (0x%x):\n", bank, | ||
524 | bankinfo[bank].name, | ||
525 | bankinfo[bank].slave_addr); | ||
526 | for (i = 0; i < ab5500_reg_ranges[bank].nranges; i++) { | ||
527 | u8 reg; | ||
528 | int err; | ||
529 | |||
530 | for (reg = ab5500_reg_ranges[bank].range[i].first; | ||
531 | reg <= ab5500_reg_ranges[bank].range[i].last; | ||
532 | reg++) { | ||
533 | u8 value; | ||
534 | |||
535 | err = ab5500_get_register_interruptible_raw(ab, | ||
536 | bank, reg, | ||
537 | &value); | ||
538 | if (err < 0) { | ||
539 | dev_err(ab->dev, "get_reg failed %d" | ||
540 | "bank 0x%x reg 0x%x\n", | ||
541 | err, bank, reg); | ||
542 | return err; | ||
543 | } | ||
544 | |||
545 | err = seq_printf(s, "[%d/0x%02X]: 0x%02X\n", | ||
546 | bank, reg, value); | ||
547 | if (err < 0) { | ||
548 | dev_err(ab->dev, | ||
549 | "seq_printf overflow\n"); | ||
550 | /* | ||
551 | * Error is not returned here since | ||
552 | * the output is wanted in any case | ||
553 | */ | ||
554 | return 0; | ||
555 | } | ||
556 | } | ||
557 | } | ||
558 | } | ||
559 | return 0; | ||
560 | } | ||
561 | |||
562 | static int ab5500_registers_open(struct inode *inode, struct file *file) | ||
563 | { | ||
564 | return single_open(file, ab5500_registers_print, inode->i_private); | ||
565 | } | ||
566 | |||
567 | static const struct file_operations ab5500_registers_fops = { | ||
568 | .open = ab5500_registers_open, | ||
569 | .read = seq_read, | ||
570 | .llseek = seq_lseek, | ||
571 | .release = single_release, | ||
572 | .owner = THIS_MODULE, | ||
573 | }; | ||
574 | |||
575 | static int ab5500_bank_print(struct seq_file *s, void *p) | ||
576 | { | ||
577 | struct ab5500 *ab = s->private; | ||
578 | |||
579 | seq_printf(s, "%d\n", ab->debug_bank); | ||
580 | return 0; | ||
581 | } | ||
582 | |||
583 | static int ab5500_bank_open(struct inode *inode, struct file *file) | ||
584 | { | ||
585 | return single_open(file, ab5500_bank_print, inode->i_private); | ||
586 | } | ||
587 | |||
588 | static ssize_t ab5500_bank_write(struct file *file, | ||
589 | const char __user *user_buf, | ||
590 | size_t count, loff_t *ppos) | ||
591 | { | ||
592 | struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private; | ||
593 | char buf[32]; | ||
594 | int buf_size; | ||
595 | unsigned long user_bank; | ||
596 | int err; | ||
597 | |||
598 | /* Get userspace string and assure termination */ | ||
599 | buf_size = min(count, (sizeof(buf) - 1)); | ||
600 | if (copy_from_user(buf, user_buf, buf_size)) | ||
601 | return -EFAULT; | ||
602 | buf[buf_size] = 0; | ||
603 | |||
604 | err = strict_strtoul(buf, 0, &user_bank); | ||
605 | if (err) | ||
606 | return -EINVAL; | ||
607 | |||
608 | if (user_bank >= AB5500_NUM_BANKS) { | ||
609 | dev_err(ab->dev, | ||
610 | "debugfs error input > number of banks\n"); | ||
611 | return -EINVAL; | ||
612 | } | ||
613 | |||
614 | ab->debug_bank = user_bank; | ||
615 | |||
616 | return buf_size; | ||
617 | } | ||
618 | |||
619 | static int ab5500_address_print(struct seq_file *s, void *p) | ||
620 | { | ||
621 | struct ab5500 *ab = s->private; | ||
622 | |||
623 | seq_printf(s, "0x%02X\n", ab->debug_address); | ||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | static int ab5500_address_open(struct inode *inode, struct file *file) | ||
628 | { | ||
629 | return single_open(file, ab5500_address_print, inode->i_private); | ||
630 | } | ||
631 | |||
632 | static ssize_t ab5500_address_write(struct file *file, | ||
633 | const char __user *user_buf, | ||
634 | size_t count, loff_t *ppos) | ||
635 | { | ||
636 | struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private; | ||
637 | char buf[32]; | ||
638 | int buf_size; | ||
639 | unsigned long user_address; | ||
640 | int err; | ||
641 | |||
642 | /* Get userspace string and assure termination */ | ||
643 | buf_size = min(count, (sizeof(buf) - 1)); | ||
644 | if (copy_from_user(buf, user_buf, buf_size)) | ||
645 | return -EFAULT; | ||
646 | buf[buf_size] = 0; | ||
647 | |||
648 | err = strict_strtoul(buf, 0, &user_address); | ||
649 | if (err) | ||
650 | return -EINVAL; | ||
651 | if (user_address > 0xff) { | ||
652 | dev_err(ab->dev, | ||
653 | "debugfs error input > 0xff\n"); | ||
654 | return -EINVAL; | ||
655 | } | ||
656 | ab->debug_address = user_address; | ||
657 | return buf_size; | ||
658 | } | ||
659 | |||
660 | static int ab5500_val_print(struct seq_file *s, void *p) | ||
661 | { | ||
662 | struct ab5500 *ab = s->private; | ||
663 | int err; | ||
664 | u8 regvalue; | ||
665 | |||
666 | err = ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank, | ||
667 | (u8)ab->debug_address, ®value); | ||
668 | if (err) { | ||
669 | dev_err(ab->dev, "get_reg failed %d, bank 0x%x" | ||
670 | ", reg 0x%x\n", err, ab->debug_bank, | ||
671 | ab->debug_address); | ||
672 | return -EINVAL; | ||
673 | } | ||
674 | seq_printf(s, "0x%02X\n", regvalue); | ||
675 | |||
676 | return 0; | ||
677 | } | ||
678 | |||
679 | static int ab5500_val_open(struct inode *inode, struct file *file) | ||
680 | { | ||
681 | return single_open(file, ab5500_val_print, inode->i_private); | ||
682 | } | ||
683 | |||
684 | static ssize_t ab5500_val_write(struct file *file, | ||
685 | const char __user *user_buf, | ||
686 | size_t count, loff_t *ppos) | ||
687 | { | ||
688 | struct ab5500 *ab = ((struct seq_file *)(file->private_data))->private; | ||
689 | char buf[32]; | ||
690 | int buf_size; | ||
691 | unsigned long user_val; | ||
692 | int err; | ||
693 | u8 regvalue; | ||
694 | |||
695 | /* Get userspace string and assure termination */ | ||
696 | buf_size = min(count, (sizeof(buf)-1)); | ||
697 | if (copy_from_user(buf, user_buf, buf_size)) | ||
698 | return -EFAULT; | ||
699 | buf[buf_size] = 0; | ||
700 | |||
701 | err = strict_strtoul(buf, 0, &user_val); | ||
702 | if (err) | ||
703 | return -EINVAL; | ||
704 | if (user_val > 0xff) { | ||
705 | dev_err(ab->dev, | ||
706 | "debugfs error input > 0xff\n"); | ||
707 | return -EINVAL; | ||
708 | } | ||
709 | err = ab5500_mask_and_set_register_interruptible_raw( | ||
710 | ab, (u8)ab->debug_bank, | ||
711 | (u8)ab->debug_address, 0xFF, (u8)user_val); | ||
712 | if (err) | ||
713 | return -EINVAL; | ||
714 | |||
715 | ab5500_get_register_interruptible_raw(ab, (u8)ab->debug_bank, | ||
716 | (u8)ab->debug_address, ®value); | ||
717 | if (err) | ||
718 | return -EINVAL; | ||
719 | |||
720 | return buf_size; | ||
721 | } | ||
722 | |||
723 | static const struct file_operations ab5500_bank_fops = { | ||
724 | .open = ab5500_bank_open, | ||
725 | .write = ab5500_bank_write, | ||
726 | .read = seq_read, | ||
727 | .llseek = seq_lseek, | ||
728 | .release = single_release, | ||
729 | .owner = THIS_MODULE, | ||
730 | }; | ||
731 | |||
732 | static const struct file_operations ab5500_address_fops = { | ||
733 | .open = ab5500_address_open, | ||
734 | .write = ab5500_address_write, | ||
735 | .read = seq_read, | ||
736 | .llseek = seq_lseek, | ||
737 | .release = single_release, | ||
738 | .owner = THIS_MODULE, | ||
739 | }; | ||
740 | |||
741 | static const struct file_operations ab5500_val_fops = { | ||
742 | .open = ab5500_val_open, | ||
743 | .write = ab5500_val_write, | ||
744 | .read = seq_read, | ||
745 | .llseek = seq_lseek, | ||
746 | .release = single_release, | ||
747 | .owner = THIS_MODULE, | ||
748 | }; | ||
749 | |||
750 | static struct dentry *ab5500_dir; | ||
751 | static struct dentry *ab5500_reg_file; | ||
752 | static struct dentry *ab5500_bank_file; | ||
753 | static struct dentry *ab5500_address_file; | ||
754 | static struct dentry *ab5500_val_file; | ||
755 | |||
756 | void __init ab5500_setup_debugfs(struct ab5500 *ab) | ||
757 | { | ||
758 | ab->debug_bank = AB5500_BANK_VIT_IO_I2C_CLK_TST_OTP; | ||
759 | ab->debug_address = AB5500_CHIP_ID; | ||
760 | |||
761 | ab5500_dir = debugfs_create_dir("ab5500", NULL); | ||
762 | if (!ab5500_dir) | ||
763 | goto exit_no_debugfs; | ||
764 | |||
765 | ab5500_reg_file = debugfs_create_file("all-bank-registers", | ||
766 | S_IRUGO, ab5500_dir, ab, &ab5500_registers_fops); | ||
767 | if (!ab5500_reg_file) | ||
768 | goto exit_destroy_dir; | ||
769 | |||
770 | ab5500_bank_file = debugfs_create_file("register-bank", | ||
771 | (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_bank_fops); | ||
772 | if (!ab5500_bank_file) | ||
773 | goto exit_destroy_reg; | ||
774 | |||
775 | ab5500_address_file = debugfs_create_file("register-address", | ||
776 | (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_address_fops); | ||
777 | if (!ab5500_address_file) | ||
778 | goto exit_destroy_bank; | ||
779 | |||
780 | ab5500_val_file = debugfs_create_file("register-value", | ||
781 | (S_IRUGO | S_IWUGO), ab5500_dir, ab, &ab5500_val_fops); | ||
782 | if (!ab5500_val_file) | ||
783 | goto exit_destroy_address; | ||
784 | |||
785 | return; | ||
786 | |||
787 | exit_destroy_address: | ||
788 | debugfs_remove(ab5500_address_file); | ||
789 | exit_destroy_bank: | ||
790 | debugfs_remove(ab5500_bank_file); | ||
791 | exit_destroy_reg: | ||
792 | debugfs_remove(ab5500_reg_file); | ||
793 | exit_destroy_dir: | ||
794 | debugfs_remove(ab5500_dir); | ||
795 | exit_no_debugfs: | ||
796 | dev_err(ab->dev, "failed to create debugfs entries.\n"); | ||
797 | return; | ||
798 | } | ||
799 | |||
800 | void __exit ab5500_remove_debugfs(void) | ||
801 | { | ||
802 | debugfs_remove(ab5500_val_file); | ||
803 | debugfs_remove(ab5500_address_file); | ||
804 | debugfs_remove(ab5500_bank_file); | ||
805 | debugfs_remove(ab5500_reg_file); | ||
806 | debugfs_remove(ab5500_dir); | ||
807 | } | ||
diff --git a/drivers/mfd/ab5500-debugfs.h b/drivers/mfd/ab5500-debugfs.h deleted file mode 100644 index 7330a9b6afa6..000000000000 --- a/drivers/mfd/ab5500-debugfs.h +++ /dev/null | |||
@@ -1,22 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 ST-Ericsson | ||
3 | * License terms: GNU General Public License (GPL) version 2 | ||
4 | * Debugfs interface to the AB5500 core driver | ||
5 | */ | ||
6 | |||
7 | #ifdef CONFIG_DEBUG_FS | ||
8 | |||
9 | void ab5500_setup_debugfs(struct ab5500 *ab); | ||
10 | void ab5500_remove_debugfs(void); | ||
11 | |||
12 | #else /* !CONFIG_DEBUG_FS */ | ||
13 | |||
14 | static inline void ab5500_setup_debugfs(struct ab5500 *ab) | ||
15 | { | ||
16 | } | ||
17 | |||
18 | static inline void ab5500_remove_debugfs(void) | ||
19 | { | ||
20 | } | ||
21 | |||
22 | #endif | ||
diff --git a/drivers/mfd/db5500-prcmu.c b/drivers/mfd/db5500-prcmu.c deleted file mode 100644 index bb115b2f04e9..000000000000 --- a/drivers/mfd/db5500-prcmu.c +++ /dev/null | |||
@@ -1,451 +0,0 @@ | |||
1 | /* | ||
2 | * Copyright (C) ST-Ericsson SA 2010 | ||
3 | * | ||
4 | * License Terms: GNU General Public License v2 | ||
5 | * Author: Mattias Nilsson <mattias.i.nilsson@stericsson.com> | ||
6 | * | ||
7 | * U5500 PRCM Unit interface driver | ||
8 | */ | ||
9 | #include <linux/module.h> | ||
10 | #include <linux/kernel.h> | ||
11 | #include <linux/delay.h> | ||
12 | #include <linux/errno.h> | ||
13 | #include <linux/err.h> | ||
14 | #include <linux/spinlock.h> | ||
15 | #include <linux/io.h> | ||
16 | #include <linux/slab.h> | ||
17 | #include <linux/mutex.h> | ||
18 | #include <linux/completion.h> | ||
19 | #include <linux/irq.h> | ||
20 | #include <linux/jiffies.h> | ||
21 | #include <linux/bitops.h> | ||
22 | #include <linux/interrupt.h> | ||
23 | #include <linux/mfd/dbx500-prcmu.h> | ||
24 | #include <mach/hardware.h> | ||
25 | #include <mach/irqs.h> | ||
26 | #include <mach/db5500-regs.h> | ||
27 | #include "dbx500-prcmu-regs.h" | ||
28 | |||
29 | #define _PRCM_MB_HEADER (tcdm_base + 0xFE8) | ||
30 | #define PRCM_REQ_MB0_HEADER (_PRCM_MB_HEADER + 0x0) | ||
31 | #define PRCM_REQ_MB1_HEADER (_PRCM_MB_HEADER + 0x1) | ||
32 | #define PRCM_REQ_MB2_HEADER (_PRCM_MB_HEADER + 0x2) | ||
33 | #define PRCM_REQ_MB3_HEADER (_PRCM_MB_HEADER + 0x3) | ||
34 | #define PRCM_REQ_MB4_HEADER (_PRCM_MB_HEADER + 0x4) | ||
35 | #define PRCM_REQ_MB5_HEADER (_PRCM_MB_HEADER + 0x5) | ||
36 | #define PRCM_REQ_MB6_HEADER (_PRCM_MB_HEADER + 0x6) | ||
37 | #define PRCM_REQ_MB7_HEADER (_PRCM_MB_HEADER + 0x7) | ||
38 | #define PRCM_ACK_MB0_HEADER (_PRCM_MB_HEADER + 0x8) | ||
39 | #define PRCM_ACK_MB1_HEADER (_PRCM_MB_HEADER + 0x9) | ||
40 | #define PRCM_ACK_MB2_HEADER (_PRCM_MB_HEADER + 0xa) | ||
41 | #define PRCM_ACK_MB3_HEADER (_PRCM_MB_HEADER + 0xb) | ||
42 | #define PRCM_ACK_MB4_HEADER (_PRCM_MB_HEADER + 0xc) | ||
43 | #define PRCM_ACK_MB5_HEADER (_PRCM_MB_HEADER + 0xd) | ||
44 | #define PRCM_ACK_MB6_HEADER (_PRCM_MB_HEADER + 0xe) | ||
45 | #define PRCM_ACK_MB7_HEADER (_PRCM_MB_HEADER + 0xf) | ||
46 | |||
47 | /* Req Mailboxes */ | ||
48 | #define PRCM_REQ_MB0 (tcdm_base + 0xFD8) | ||
49 | #define PRCM_REQ_MB1 (tcdm_base + 0xFCC) | ||
50 | #define PRCM_REQ_MB2 (tcdm_base + 0xFC4) | ||
51 | #define PRCM_REQ_MB3 (tcdm_base + 0xFC0) | ||
52 | #define PRCM_REQ_MB4 (tcdm_base + 0xF98) | ||
53 | #define PRCM_REQ_MB5 (tcdm_base + 0xF90) | ||
54 | #define PRCM_REQ_MB6 (tcdm_base + 0xF8C) | ||
55 | #define PRCM_REQ_MB7 (tcdm_base + 0xF84) | ||
56 | |||
57 | /* Ack Mailboxes */ | ||
58 | #define PRCM_ACK_MB0 (tcdm_base + 0xF38) | ||
59 | #define PRCM_ACK_MB1 (tcdm_base + 0xF30) | ||
60 | #define PRCM_ACK_MB2 (tcdm_base + 0xF24) | ||
61 | #define PRCM_ACK_MB3 (tcdm_base + 0xF20) | ||
62 | #define PRCM_ACK_MB4 (tcdm_base + 0xF1C) | ||
63 | #define PRCM_ACK_MB5 (tcdm_base + 0xF14) | ||
64 | #define PRCM_ACK_MB6 (tcdm_base + 0xF0C) | ||
65 | #define PRCM_ACK_MB7 (tcdm_base + 0xF08) | ||
66 | |||
67 | enum mb_return_code { | ||
68 | RC_SUCCESS, | ||
69 | RC_FAIL, | ||
70 | }; | ||
71 | |||
72 | /* Mailbox 0 headers. */ | ||
73 | enum mb0_header { | ||
74 | /* request */ | ||
75 | RMB0H_PWR_STATE_TRANS = 1, | ||
76 | RMB0H_WAKE_UP_CFG, | ||
77 | RMB0H_RD_WAKE_UP_ACK, | ||
78 | /* acknowledge */ | ||
79 | AMB0H_WAKE_UP = 1, | ||
80 | }; | ||
81 | |||
82 | /* Mailbox 5 headers. */ | ||
83 | enum mb5_header { | ||
84 | MB5H_I2C_WRITE = 1, | ||
85 | MB5H_I2C_READ, | ||
86 | }; | ||
87 | |||
88 | /* Request mailbox 5 fields. */ | ||
89 | #define PRCM_REQ_MB5_I2C_SLAVE (PRCM_REQ_MB5 + 0) | ||
90 | #define PRCM_REQ_MB5_I2C_REG (PRCM_REQ_MB5 + 1) | ||
91 | #define PRCM_REQ_MB5_I2C_SIZE (PRCM_REQ_MB5 + 2) | ||
92 | #define PRCM_REQ_MB5_I2C_DATA (PRCM_REQ_MB5 + 4) | ||
93 | |||
94 | /* Acknowledge mailbox 5 fields. */ | ||
95 | #define PRCM_ACK_MB5_RETURN_CODE (PRCM_ACK_MB5 + 0) | ||
96 | #define PRCM_ACK_MB5_I2C_DATA (PRCM_ACK_MB5 + 4) | ||
97 | |||
98 | #define NUM_MB 8 | ||
99 | #define MBOX_BIT BIT | ||
100 | #define ALL_MBOX_BITS (MBOX_BIT(NUM_MB) - 1) | ||
101 | |||
102 | /* | ||
103 | * Used by MCDE to setup all necessary PRCMU registers | ||
104 | */ | ||
105 | #define PRCMU_RESET_DSIPLL 0x00004000 | ||
106 | #define PRCMU_UNCLAMP_DSIPLL 0x00400800 | ||
107 | |||
108 | /* HDMI CLK MGT PLLSW=001 (PLLSOC0), PLLDIV=0x8, = 50 Mhz*/ | ||
109 | #define PRCMU_DSI_CLOCK_SETTING 0x00000128 | ||
110 | /* TVCLK_MGT PLLSW=001 (PLLSOC0) PLLDIV=0x13, = 19.05 MHZ */ | ||
111 | #define PRCMU_DSI_LP_CLOCK_SETTING 0x00000135 | ||
112 | #define PRCMU_PLLDSI_FREQ_SETTING 0x00020121 | ||
113 | #define PRCMU_DSI_PLLOUT_SEL_SETTING 0x00000002 | ||
114 | #define PRCMU_ENABLE_ESCAPE_CLOCK_DIV 0x03000201 | ||
115 | #define PRCMU_DISABLE_ESCAPE_CLOCK_DIV 0x00000101 | ||
116 | |||
117 | #define PRCMU_ENABLE_PLLDSI 0x00000001 | ||
118 | #define PRCMU_DISABLE_PLLDSI 0x00000000 | ||
119 | |||
120 | #define PRCMU_DSI_RESET_SW 0x00000003 | ||
121 | #define PRCMU_RESOUTN0_PIN 0x00000001 | ||
122 | #define PRCMU_RESOUTN1_PIN 0x00000002 | ||
123 | #define PRCMU_RESOUTN2_PIN 0x00000004 | ||
124 | |||
125 | #define PRCMU_PLLDSI_LOCKP_LOCKED 0x3 | ||
126 | |||
127 | /* | ||
128 | * mb0_transfer - state needed for mailbox 0 communication. | ||
129 | * @lock: The transaction lock. | ||
130 | */ | ||
131 | static struct { | ||
132 | spinlock_t lock; | ||
133 | } mb0_transfer; | ||
134 | |||
135 | /* | ||
136 | * mb5_transfer - state needed for mailbox 5 communication. | ||
137 | * @lock: The transaction lock. | ||
138 | * @work: The transaction completion structure. | ||
139 | * @ack: Reply ("acknowledge") data. | ||
140 | */ | ||
141 | static struct { | ||
142 | struct mutex lock; | ||
143 | struct completion work; | ||
144 | struct { | ||
145 | u8 header; | ||
146 | u8 status; | ||
147 | u8 value[4]; | ||
148 | } ack; | ||
149 | } mb5_transfer; | ||
150 | |||
151 | /* PRCMU TCDM base IO address. */ | ||
152 | static __iomem void *tcdm_base; | ||
153 | |||
154 | /** | ||
155 | * db5500_prcmu_abb_read() - Read register value(s) from the ABB. | ||
156 | * @slave: The I2C slave address. | ||
157 | * @reg: The (start) register address. | ||
158 | * @value: The read out value(s). | ||
159 | * @size: The number of registers to read. | ||
160 | * | ||
161 | * Reads register value(s) from the ABB. | ||
162 | * @size has to be <= 4. | ||
163 | */ | ||
164 | int db5500_prcmu_abb_read(u8 slave, u8 reg, u8 *value, u8 size) | ||
165 | { | ||
166 | int r; | ||
167 | |||
168 | if ((size < 1) || (4 < size)) | ||
169 | return -EINVAL; | ||
170 | |||
171 | mutex_lock(&mb5_transfer.lock); | ||
172 | |||
173 | while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5)) | ||
174 | cpu_relax(); | ||
175 | writeb(slave, PRCM_REQ_MB5_I2C_SLAVE); | ||
176 | writeb(reg, PRCM_REQ_MB5_I2C_REG); | ||
177 | writeb(size, PRCM_REQ_MB5_I2C_SIZE); | ||
178 | writeb(MB5H_I2C_READ, PRCM_REQ_MB5_HEADER); | ||
179 | |||
180 | writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET); | ||
181 | wait_for_completion(&mb5_transfer.work); | ||
182 | |||
183 | r = 0; | ||
184 | if ((mb5_transfer.ack.header == MB5H_I2C_READ) && | ||
185 | (mb5_transfer.ack.status == RC_SUCCESS)) | ||
186 | memcpy(value, mb5_transfer.ack.value, (size_t)size); | ||
187 | else | ||
188 | r = -EIO; | ||
189 | |||
190 | mutex_unlock(&mb5_transfer.lock); | ||
191 | |||
192 | return r; | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * db5500_prcmu_abb_write() - Write register value(s) to the ABB. | ||
197 | * @slave: The I2C slave address. | ||
198 | * @reg: The (start) register address. | ||
199 | * @value: The value(s) to write. | ||
200 | * @size: The number of registers to write. | ||
201 | * | ||
202 | * Writes register value(s) to the ABB. | ||
203 | * @size has to be <= 4. | ||
204 | */ | ||
205 | int db5500_prcmu_abb_write(u8 slave, u8 reg, u8 *value, u8 size) | ||
206 | { | ||
207 | int r; | ||
208 | |||
209 | if ((size < 1) || (4 < size)) | ||
210 | return -EINVAL; | ||
211 | |||
212 | mutex_lock(&mb5_transfer.lock); | ||
213 | |||
214 | while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(5)) | ||
215 | cpu_relax(); | ||
216 | writeb(slave, PRCM_REQ_MB5_I2C_SLAVE); | ||
217 | writeb(reg, PRCM_REQ_MB5_I2C_REG); | ||
218 | writeb(size, PRCM_REQ_MB5_I2C_SIZE); | ||
219 | memcpy_toio(PRCM_REQ_MB5_I2C_DATA, value, size); | ||
220 | writeb(MB5H_I2C_WRITE, PRCM_REQ_MB5_HEADER); | ||
221 | |||
222 | writel(MBOX_BIT(5), PRCM_MBOX_CPU_SET); | ||
223 | wait_for_completion(&mb5_transfer.work); | ||
224 | |||
225 | if ((mb5_transfer.ack.header == MB5H_I2C_WRITE) && | ||
226 | (mb5_transfer.ack.status == RC_SUCCESS)) | ||
227 | r = 0; | ||
228 | else | ||
229 | r = -EIO; | ||
230 | |||
231 | mutex_unlock(&mb5_transfer.lock); | ||
232 | |||
233 | return r; | ||
234 | } | ||
235 | |||
236 | int db5500_prcmu_enable_dsipll(void) | ||
237 | { | ||
238 | int i; | ||
239 | |||
240 | /* Enable DSIPLL_RESETN resets */ | ||
241 | writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_CLR); | ||
242 | /* Unclamp DSIPLL in/out */ | ||
243 | writel(PRCMU_UNCLAMP_DSIPLL, PRCM_MMIP_LS_CLAMP_CLR); | ||
244 | /* Set DSI PLL FREQ */ | ||
245 | writel(PRCMU_PLLDSI_FREQ_SETTING, PRCM_PLLDSI_FREQ); | ||
246 | writel(PRCMU_DSI_PLLOUT_SEL_SETTING, | ||
247 | PRCM_DSI_PLLOUT_SEL); | ||
248 | /* Enable Escape clocks */ | ||
249 | writel(PRCMU_ENABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV); | ||
250 | |||
251 | /* Start DSI PLL */ | ||
252 | writel(PRCMU_ENABLE_PLLDSI, PRCM_PLLDSI_ENABLE); | ||
253 | /* Reset DSI PLL */ | ||
254 | writel(PRCMU_DSI_RESET_SW, PRCM_DSI_SW_RESET); | ||
255 | for (i = 0; i < 10; i++) { | ||
256 | if ((readl(PRCM_PLLDSI_LOCKP) & | ||
257 | PRCMU_PLLDSI_LOCKP_LOCKED) == PRCMU_PLLDSI_LOCKP_LOCKED) | ||
258 | break; | ||
259 | udelay(100); | ||
260 | } | ||
261 | /* Release DSIPLL_RESETN */ | ||
262 | writel(PRCMU_RESET_DSIPLL, PRCM_APE_RESETN_SET); | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | int db5500_prcmu_disable_dsipll(void) | ||
267 | { | ||
268 | /* Disable dsi pll */ | ||
269 | writel(PRCMU_DISABLE_PLLDSI, PRCM_PLLDSI_ENABLE); | ||
270 | /* Disable escapeclock */ | ||
271 | writel(PRCMU_DISABLE_ESCAPE_CLOCK_DIV, PRCM_DSITVCLK_DIV); | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | int db5500_prcmu_set_display_clocks(void) | ||
276 | { | ||
277 | /* HDMI and TVCLK Should be handled somewhere else */ | ||
278 | /* PLLDIV=8, PLLSW=2, CLKEN=1 */ | ||
279 | writel(PRCMU_DSI_CLOCK_SETTING, PRCM_HDMICLK_MGT); | ||
280 | /* PLLDIV=14, PLLSW=2, CLKEN=1 */ | ||
281 | writel(PRCMU_DSI_LP_CLOCK_SETTING, PRCM_TVCLK_MGT); | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static void ack_dbb_wakeup(void) | ||
286 | { | ||
287 | unsigned long flags; | ||
288 | |||
289 | spin_lock_irqsave(&mb0_transfer.lock, flags); | ||
290 | |||
291 | while (readl(PRCM_MBOX_CPU_VAL) & MBOX_BIT(0)) | ||
292 | cpu_relax(); | ||
293 | |||
294 | writeb(RMB0H_RD_WAKE_UP_ACK, PRCM_REQ_MB0_HEADER); | ||
295 | writel(MBOX_BIT(0), PRCM_MBOX_CPU_SET); | ||
296 | |||
297 | spin_unlock_irqrestore(&mb0_transfer.lock, flags); | ||
298 | } | ||
299 | |||
300 | static inline void print_unknown_header_warning(u8 n, u8 header) | ||
301 | { | ||
302 | pr_warning("prcmu: Unknown message header (%d) in mailbox %d.\n", | ||
303 | header, n); | ||
304 | } | ||
305 | |||
306 | static bool read_mailbox_0(void) | ||
307 | { | ||
308 | bool r; | ||
309 | u8 header; | ||
310 | |||
311 | header = readb(PRCM_ACK_MB0_HEADER); | ||
312 | switch (header) { | ||
313 | case AMB0H_WAKE_UP: | ||
314 | r = true; | ||
315 | break; | ||
316 | default: | ||
317 | print_unknown_header_warning(0, header); | ||
318 | r = false; | ||
319 | break; | ||
320 | } | ||
321 | writel(MBOX_BIT(0), PRCM_ARM_IT1_CLR); | ||
322 | return r; | ||
323 | } | ||
324 | |||
325 | static bool read_mailbox_1(void) | ||
326 | { | ||
327 | writel(MBOX_BIT(1), PRCM_ARM_IT1_CLR); | ||
328 | return false; | ||
329 | } | ||
330 | |||
331 | static bool read_mailbox_2(void) | ||
332 | { | ||
333 | writel(MBOX_BIT(2), PRCM_ARM_IT1_CLR); | ||
334 | return false; | ||
335 | } | ||
336 | |||
337 | static bool read_mailbox_3(void) | ||
338 | { | ||
339 | writel(MBOX_BIT(3), PRCM_ARM_IT1_CLR); | ||
340 | return false; | ||
341 | } | ||
342 | |||
343 | static bool read_mailbox_4(void) | ||
344 | { | ||
345 | writel(MBOX_BIT(4), PRCM_ARM_IT1_CLR); | ||
346 | return false; | ||
347 | } | ||
348 | |||
349 | static bool read_mailbox_5(void) | ||
350 | { | ||
351 | u8 header; | ||
352 | |||
353 | header = readb(PRCM_ACK_MB5_HEADER); | ||
354 | switch (header) { | ||
355 | case MB5H_I2C_READ: | ||
356 | memcpy_fromio(mb5_transfer.ack.value, PRCM_ACK_MB5_I2C_DATA, 4); | ||
357 | case MB5H_I2C_WRITE: | ||
358 | mb5_transfer.ack.header = header; | ||
359 | mb5_transfer.ack.status = readb(PRCM_ACK_MB5_RETURN_CODE); | ||
360 | complete(&mb5_transfer.work); | ||
361 | break; | ||
362 | default: | ||
363 | print_unknown_header_warning(5, header); | ||
364 | break; | ||
365 | } | ||
366 | writel(MBOX_BIT(5), PRCM_ARM_IT1_CLR); | ||
367 | return false; | ||
368 | } | ||
369 | |||
370 | static bool read_mailbox_6(void) | ||
371 | { | ||
372 | writel(MBOX_BIT(6), PRCM_ARM_IT1_CLR); | ||
373 | return false; | ||
374 | } | ||
375 | |||
376 | static bool read_mailbox_7(void) | ||
377 | { | ||
378 | writel(MBOX_BIT(7), PRCM_ARM_IT1_CLR); | ||
379 | return false; | ||
380 | } | ||
381 | |||
382 | static bool (* const read_mailbox[NUM_MB])(void) = { | ||
383 | read_mailbox_0, | ||
384 | read_mailbox_1, | ||
385 | read_mailbox_2, | ||
386 | read_mailbox_3, | ||
387 | read_mailbox_4, | ||
388 | read_mailbox_5, | ||
389 | read_mailbox_6, | ||
390 | read_mailbox_7 | ||
391 | }; | ||
392 | |||
393 | static irqreturn_t prcmu_irq_handler(int irq, void *data) | ||
394 | { | ||
395 | u32 bits; | ||
396 | u8 n; | ||
397 | irqreturn_t r; | ||
398 | |||
399 | bits = (readl(PRCM_ARM_IT1_VAL) & ALL_MBOX_BITS); | ||
400 | if (unlikely(!bits)) | ||
401 | return IRQ_NONE; | ||
402 | |||
403 | r = IRQ_HANDLED; | ||
404 | for (n = 0; bits; n++) { | ||
405 | if (bits & MBOX_BIT(n)) { | ||
406 | bits -= MBOX_BIT(n); | ||
407 | if (read_mailbox[n]()) | ||
408 | r = IRQ_WAKE_THREAD; | ||
409 | } | ||
410 | } | ||
411 | return r; | ||
412 | } | ||
413 | |||
414 | static irqreturn_t prcmu_irq_thread_fn(int irq, void *data) | ||
415 | { | ||
416 | ack_dbb_wakeup(); | ||
417 | return IRQ_HANDLED; | ||
418 | } | ||
419 | |||
420 | void __init db5500_prcmu_early_init(void) | ||
421 | { | ||
422 | tcdm_base = __io_address(U5500_PRCMU_TCDM_BASE); | ||
423 | spin_lock_init(&mb0_transfer.lock); | ||
424 | mutex_init(&mb5_transfer.lock); | ||
425 | init_completion(&mb5_transfer.work); | ||
426 | } | ||
427 | |||
428 | /** | ||
429 | * prcmu_fw_init - arch init call for the Linux PRCMU fw init logic | ||
430 | * | ||
431 | */ | ||
432 | int __init db5500_prcmu_init(void) | ||
433 | { | ||
434 | int r = 0; | ||
435 | |||
436 | if (ux500_is_svp() || !cpu_is_u5500()) | ||
437 | return -ENODEV; | ||
438 | |||
439 | /* Clean up the mailbox interrupts after pre-kernel code. */ | ||
440 | writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR); | ||
441 | |||
442 | r = request_threaded_irq(IRQ_DB5500_PRCMU1, prcmu_irq_handler, | ||
443 | prcmu_irq_thread_fn, 0, "prcmu", NULL); | ||
444 | if (r < 0) { | ||
445 | pr_err("prcmu: Failed to allocate IRQ_DB5500_PRCMU1.\n"); | ||
446 | return -EBUSY; | ||
447 | } | ||
448 | return 0; | ||
449 | } | ||
450 | |||
451 | arch_initcall(db5500_prcmu_init); | ||
diff --git a/drivers/mtd/nand/autcpu12.c b/drivers/mtd/nand/autcpu12.c index 2e42ec2e8ff4..04769a49a7cb 100644 --- a/drivers/mtd/nand/autcpu12.c +++ b/drivers/mtd/nand/autcpu12.c | |||
@@ -102,10 +102,10 @@ static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd, | |||
102 | void __iomem *addr; | 102 | void __iomem *addr; |
103 | unsigned char bits; | 103 | unsigned char bits; |
104 | 104 | ||
105 | addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET; | 105 | bits = clps_readb(AUTCPU12_SMC_PORT_OFFSET) & ~0x30; |
106 | bits = (ctrl & NAND_CLE) << 4; | 106 | bits |= (ctrl & NAND_CLE) << 4; |
107 | bits |= (ctrl & NAND_ALE) << 2; | 107 | bits |= (ctrl & NAND_ALE) << 2; |
108 | writeb((readb(addr) & ~0x30) | bits, addr); | 108 | clps_writeb(bits, AUTCPU12_SMC_PORT_OFFSET); |
109 | 109 | ||
110 | addr = autcpu12_fio_base + AUTCPU12_SMC_SELECT_OFFSET; | 110 | addr = autcpu12_fio_base + AUTCPU12_SMC_SELECT_OFFSET; |
111 | writeb((readb(addr) & ~0x1) | (ctrl & NAND_NCE), addr); | 111 | writeb((readb(addr) & ~0x1) | (ctrl & NAND_NCE), addr); |
@@ -120,9 +120,7 @@ static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd, | |||
120 | */ | 120 | */ |
121 | int autcpu12_device_ready(struct mtd_info *mtd) | 121 | int autcpu12_device_ready(struct mtd_info *mtd) |
122 | { | 122 | { |
123 | void __iomem *addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET; | 123 | return clps_readb(AUTCPU12_SMC_PORT_OFFSET) & AUTCPU12_SMC_RDY; |
124 | |||
125 | return readb(addr) & AUTCPU12_SMC_RDY; | ||
126 | } | 124 | } |
127 | 125 | ||
128 | /* | 126 | /* |
diff --git a/drivers/mtd/nand/h1910.c b/drivers/mtd/nand/h1910.c index 11e487813428..9bf5ce5fa22d 100644 --- a/drivers/mtd/nand/h1910.c +++ b/drivers/mtd/nand/h1910.c | |||
@@ -24,7 +24,7 @@ | |||
24 | #include <linux/mtd/nand.h> | 24 | #include <linux/mtd/nand.h> |
25 | #include <linux/mtd/partitions.h> | 25 | #include <linux/mtd/partitions.h> |
26 | #include <asm/io.h> | 26 | #include <asm/io.h> |
27 | #include <mach/hardware.h> /* for CLPS7111_VIRT_BASE */ | 27 | #include <mach/hardware.h> |
28 | #include <asm/sizes.h> | 28 | #include <asm/sizes.h> |
29 | #include <mach/h1900-gpio.h> | 29 | #include <mach/h1900-gpio.h> |
30 | #include <mach/ipaq.h> | 30 | #include <mach/ipaq.h> |
diff --git a/drivers/net/irda/Kconfig b/drivers/net/irda/Kconfig index 35758445297e..031d8e8ed1ad 100644 --- a/drivers/net/irda/Kconfig +++ b/drivers/net/irda/Kconfig | |||
@@ -211,8 +211,8 @@ config KINGSUN_DONGLE | |||
211 | kingsun-sir. | 211 | kingsun-sir. |
212 | 212 | ||
213 | config EP7211_DONGLE | 213 | config EP7211_DONGLE |
214 | tristate "EP7211 I/R support" | 214 | tristate "Cirrus Logic clps711x I/R support" |
215 | depends on IRTTY_SIR && ARCH_EP7211 && IRDA && EXPERIMENTAL | 215 | depends on IRTTY_SIR && ARCH_CLPS711X && IRDA && EXPERIMENTAL |
216 | help | 216 | help |
217 | Say Y here if you want to build support for the Cirrus logic | 217 | Say Y here if you want to build support for the Cirrus logic |
218 | EP7211 chipset's infrared module. | 218 | EP7211 chipset's infrared module. |
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig index 8c8377d50c4c..4161bfe462cd 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig | |||
@@ -838,7 +838,7 @@ config RTC_DRV_AT32AP700X | |||
838 | 838 | ||
839 | config RTC_DRV_AT91RM9200 | 839 | config RTC_DRV_AT91RM9200 |
840 | tristate "AT91RM9200 or some AT91SAM9 RTC" | 840 | tristate "AT91RM9200 or some AT91SAM9 RTC" |
841 | depends on ARCH_AT91RM9200 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45 | 841 | depends on ARCH_AT91 |
842 | help | 842 | help |
843 | Driver for the internal RTC (Realtime Clock) module found on | 843 | Driver for the internal RTC (Realtime Clock) module found on |
844 | Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips | 844 | Atmel AT91RM9200's and some AT91SAM9 chips. On AT91SAM9 chips |
diff --git a/drivers/tty/serial/clps711x.c b/drivers/tty/serial/clps711x.c index 836fe2731234..d0f719fafc84 100644 --- a/drivers/tty/serial/clps711x.c +++ b/drivers/tty/serial/clps711x.c | |||
@@ -40,7 +40,6 @@ | |||
40 | 40 | ||
41 | #include <mach/hardware.h> | 41 | #include <mach/hardware.h> |
42 | #include <asm/irq.h> | 42 | #include <asm/irq.h> |
43 | #include <asm/hardware/clps7111.h> | ||
44 | 43 | ||
45 | #define UART_NR 2 | 44 | #define UART_NR 2 |
46 | 45 | ||
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c index 96451e41ee8a..71229cb97e3e 100644 --- a/drivers/usb/host/ohci-omap.c +++ b/drivers/usb/host/ohci-omap.c | |||
@@ -205,8 +205,9 @@ static int ohci_omap_init(struct usb_hcd *hcd) | |||
205 | need_transceiver = need_transceiver | 205 | need_transceiver = need_transceiver |
206 | || machine_is_omap_h2() || machine_is_omap_h3(); | 206 | || machine_is_omap_h2() || machine_is_omap_h3(); |
207 | 207 | ||
208 | if (cpu_is_omap16xx()) | 208 | /* XXX OMAP16xx only */ |
209 | ocpi_enable(); | 209 | if (config->ocpi_enable) |
210 | config->ocpi_enable(); | ||
210 | 211 | ||
211 | #ifdef CONFIG_USB_OTG | 212 | #ifdef CONFIG_USB_OTG |
212 | if (need_transceiver) { | 213 | if (need_transceiver) { |
diff --git a/drivers/video/clps711xfb.c b/drivers/video/clps711xfb.c index 99b354b8e257..f994c8b8f10a 100644 --- a/drivers/video/clps711xfb.c +++ b/drivers/video/clps711xfb.c | |||
@@ -33,7 +33,6 @@ | |||
33 | #include <asm/mach-types.h> | 33 | #include <asm/mach-types.h> |
34 | #include <linux/uaccess.h> | 34 | #include <linux/uaccess.h> |
35 | 35 | ||
36 | #include <asm/hardware/clps7111.h> | ||
37 | #include <mach/syspld.h> | 36 | #include <mach/syspld.h> |
38 | 37 | ||
39 | struct fb_info *cfb; | 38 | struct fb_info *cfb; |
diff --git a/drivers/video/omap2/displays/Kconfig b/drivers/video/omap2/displays/Kconfig index 408a9927be92..c3853c92279b 100644 --- a/drivers/video/omap2/displays/Kconfig +++ b/drivers/video/omap2/displays/Kconfig | |||
@@ -10,12 +10,12 @@ config PANEL_GENERIC_DPI | |||
10 | Supports LCD Panel used in TI SDP3430 and EVM boards, | 10 | Supports LCD Panel used in TI SDP3430 and EVM boards, |
11 | OMAP3517 EVM boards and CM-T35. | 11 | OMAP3517 EVM boards and CM-T35. |
12 | 12 | ||
13 | config PANEL_DVI | 13 | config PANEL_TFP410 |
14 | tristate "DVI output" | 14 | tristate "TFP410 DPI-to-DVI chip" |
15 | depends on OMAP2_DSS_DPI && I2C | 15 | depends on OMAP2_DSS_DPI && I2C |
16 | help | 16 | help |
17 | Driver for external monitors, connected via DVI. The driver uses i2c | 17 | Driver for TFP410 DPI-to-DVI chip. The driver uses i2c to read EDID |
18 | to read EDID information from the monitor. | 18 | information from the monitor. |
19 | 19 | ||
20 | config PANEL_LGPHILIPS_LB035Q02 | 20 | config PANEL_LGPHILIPS_LB035Q02 |
21 | tristate "LG.Philips LB035Q02 LCD Panel" | 21 | tristate "LG.Philips LB035Q02 LCD Panel" |
diff --git a/drivers/video/omap2/displays/Makefile b/drivers/video/omap2/displays/Makefile index fbfafc6eebb4..58a5176b07b0 100644 --- a/drivers/video/omap2/displays/Makefile +++ b/drivers/video/omap2/displays/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o | 1 | obj-$(CONFIG_PANEL_GENERIC_DPI) += panel-generic-dpi.o |
2 | obj-$(CONFIG_PANEL_DVI) += panel-dvi.o | 2 | obj-$(CONFIG_PANEL_TFP410) += panel-tfp410.o |
3 | obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o | 3 | obj-$(CONFIG_PANEL_LGPHILIPS_LB035Q02) += panel-lgphilips-lb035q02.o |
4 | obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o | 4 | obj-$(CONFIG_PANEL_SHARP_LS037V7DW01) += panel-sharp-ls037v7dw01.o |
5 | obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o | 5 | obj-$(CONFIG_PANEL_NEC_NL8048HL11_01B) += panel-nec-nl8048hl11-01b.o |
diff --git a/drivers/video/omap2/displays/panel-taal.c b/drivers/video/omap2/displays/panel-taal.c index 0f21fa5a16ae..b2dd88b48420 100644 --- a/drivers/video/omap2/displays/panel-taal.c +++ b/drivers/video/omap2/displays/panel-taal.c | |||
@@ -993,6 +993,15 @@ static int taal_probe(struct omap_dss_device *dssdev) | |||
993 | 993 | ||
994 | dev_set_drvdata(&dssdev->dev, td); | 994 | dev_set_drvdata(&dssdev->dev, td); |
995 | 995 | ||
996 | if (gpio_is_valid(panel_data->reset_gpio)) { | ||
997 | r = gpio_request_one(panel_data->reset_gpio, GPIOF_OUT_INIT_LOW, | ||
998 | "taal rst"); | ||
999 | if (r) { | ||
1000 | dev_err(&dssdev->dev, "failed to request reset gpio\n"); | ||
1001 | goto err_rst_gpio; | ||
1002 | } | ||
1003 | } | ||
1004 | |||
996 | taal_hw_reset(dssdev); | 1005 | taal_hw_reset(dssdev); |
997 | 1006 | ||
998 | if (panel_data->use_dsi_backlight) { | 1007 | if (panel_data->use_dsi_backlight) { |
@@ -1073,6 +1082,9 @@ err_gpio: | |||
1073 | if (bldev != NULL) | 1082 | if (bldev != NULL) |
1074 | backlight_device_unregister(bldev); | 1083 | backlight_device_unregister(bldev); |
1075 | err_bl: | 1084 | err_bl: |
1085 | if (gpio_is_valid(panel_data->reset_gpio)) | ||
1086 | gpio_free(panel_data->reset_gpio); | ||
1087 | err_rst_gpio: | ||
1076 | destroy_workqueue(td->workqueue); | 1088 | destroy_workqueue(td->workqueue); |
1077 | err_wq: | 1089 | err_wq: |
1078 | free_regulators(panel_config->regulators, panel_config->num_regulators); | 1090 | free_regulators(panel_config->regulators, panel_config->num_regulators); |
@@ -1116,15 +1128,25 @@ static void __exit taal_remove(struct omap_dss_device *dssdev) | |||
1116 | free_regulators(td->panel_config->regulators, | 1128 | free_regulators(td->panel_config->regulators, |
1117 | td->panel_config->num_regulators); | 1129 | td->panel_config->num_regulators); |
1118 | 1130 | ||
1131 | if (gpio_is_valid(panel_data->reset_gpio)) | ||
1132 | gpio_free(panel_data->reset_gpio); | ||
1133 | |||
1119 | kfree(td); | 1134 | kfree(td); |
1120 | } | 1135 | } |
1121 | 1136 | ||
1122 | static int taal_power_on(struct omap_dss_device *dssdev) | 1137 | static int taal_power_on(struct omap_dss_device *dssdev) |
1123 | { | 1138 | { |
1124 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); | 1139 | struct taal_data *td = dev_get_drvdata(&dssdev->dev); |
1140 | struct nokia_dsi_panel_data *panel_data = get_panel_data(dssdev); | ||
1125 | u8 id1, id2, id3; | 1141 | u8 id1, id2, id3; |
1126 | int r; | 1142 | int r; |
1127 | 1143 | ||
1144 | r = omapdss_dsi_configure_pins(dssdev, &panel_data->pin_config); | ||
1145 | if (r) { | ||
1146 | dev_err(&dssdev->dev, "failed to configure DSI pins\n"); | ||
1147 | goto err0; | ||
1148 | }; | ||
1149 | |||
1128 | r = omapdss_dsi_display_enable(dssdev); | 1150 | r = omapdss_dsi_display_enable(dssdev); |
1129 | if (r) { | 1151 | if (r) { |
1130 | dev_err(&dssdev->dev, "failed to enable DSI\n"); | 1152 | dev_err(&dssdev->dev, "failed to enable DSI\n"); |
diff --git a/drivers/video/omap2/displays/panel-dvi.c b/drivers/video/omap2/displays/panel-tfp410.c index 03eb14af33e0..52637fa8fda8 100644 --- a/drivers/video/omap2/displays/panel-dvi.c +++ b/drivers/video/omap2/displays/panel-tfp410.c | |||
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | * DVI output support | 2 | * TFP410 DPI-to-DVI chip |
3 | * | 3 | * |
4 | * Copyright (C) 2011 Texas Instruments Inc | 4 | * Copyright (C) 2011 Texas Instruments Inc |
5 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> | 5 | * Author: Tomi Valkeinen <tomi.valkeinen@ti.com> |
@@ -21,11 +21,12 @@ | |||
21 | #include <linux/slab.h> | 21 | #include <linux/slab.h> |
22 | #include <video/omapdss.h> | 22 | #include <video/omapdss.h> |
23 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
24 | #include <linux/gpio.h> | ||
24 | #include <drm/drm_edid.h> | 25 | #include <drm/drm_edid.h> |
25 | 26 | ||
26 | #include <video/omap-panel-dvi.h> | 27 | #include <video/omap-panel-tfp410.h> |
27 | 28 | ||
28 | static const struct omap_video_timings panel_dvi_default_timings = { | 29 | static const struct omap_video_timings tfp410_default_timings = { |
29 | .x_res = 640, | 30 | .x_res = 640, |
30 | .y_res = 480, | 31 | .y_res = 480, |
31 | 32 | ||
@@ -44,17 +45,19 @@ struct panel_drv_data { | |||
44 | struct omap_dss_device *dssdev; | 45 | struct omap_dss_device *dssdev; |
45 | 46 | ||
46 | struct mutex lock; | 47 | struct mutex lock; |
48 | |||
49 | int pd_gpio; | ||
47 | }; | 50 | }; |
48 | 51 | ||
49 | static inline struct panel_dvi_platform_data | 52 | static inline struct tfp410_platform_data |
50 | *get_pdata(const struct omap_dss_device *dssdev) | 53 | *get_pdata(const struct omap_dss_device *dssdev) |
51 | { | 54 | { |
52 | return dssdev->data; | 55 | return dssdev->data; |
53 | } | 56 | } |
54 | 57 | ||
55 | static int panel_dvi_power_on(struct omap_dss_device *dssdev) | 58 | static int tfp410_power_on(struct omap_dss_device *dssdev) |
56 | { | 59 | { |
57 | struct panel_dvi_platform_data *pdata = get_pdata(dssdev); | 60 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); |
58 | int r; | 61 | int r; |
59 | 62 | ||
60 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) | 63 | if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) |
@@ -64,57 +67,72 @@ static int panel_dvi_power_on(struct omap_dss_device *dssdev) | |||
64 | if (r) | 67 | if (r) |
65 | goto err0; | 68 | goto err0; |
66 | 69 | ||
67 | if (pdata->platform_enable) { | 70 | if (gpio_is_valid(ddata->pd_gpio)) |
68 | r = pdata->platform_enable(dssdev); | 71 | gpio_set_value(ddata->pd_gpio, 1); |
69 | if (r) | ||
70 | goto err1; | ||
71 | } | ||
72 | 72 | ||
73 | return 0; | 73 | return 0; |
74 | err1: | ||
75 | omapdss_dpi_display_disable(dssdev); | ||
76 | err0: | 74 | err0: |
77 | return r; | 75 | return r; |
78 | } | 76 | } |
79 | 77 | ||
80 | static void panel_dvi_power_off(struct omap_dss_device *dssdev) | 78 | static void tfp410_power_off(struct omap_dss_device *dssdev) |
81 | { | 79 | { |
82 | struct panel_dvi_platform_data *pdata = get_pdata(dssdev); | 80 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); |
83 | 81 | ||
84 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) | 82 | if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE) |
85 | return; | 83 | return; |
86 | 84 | ||
87 | if (pdata->platform_disable) | 85 | if (gpio_is_valid(ddata->pd_gpio)) |
88 | pdata->platform_disable(dssdev); | 86 | gpio_set_value(ddata->pd_gpio, 0); |
89 | 87 | ||
90 | omapdss_dpi_display_disable(dssdev); | 88 | omapdss_dpi_display_disable(dssdev); |
91 | } | 89 | } |
92 | 90 | ||
93 | static int panel_dvi_probe(struct omap_dss_device *dssdev) | 91 | static int tfp410_probe(struct omap_dss_device *dssdev) |
94 | { | 92 | { |
93 | struct tfp410_platform_data *pdata = get_pdata(dssdev); | ||
95 | struct panel_drv_data *ddata; | 94 | struct panel_drv_data *ddata; |
95 | int r; | ||
96 | 96 | ||
97 | ddata = kzalloc(sizeof(*ddata), GFP_KERNEL); | 97 | ddata = kzalloc(sizeof(*ddata), GFP_KERNEL); |
98 | if (!ddata) | 98 | if (!ddata) |
99 | return -ENOMEM; | 99 | return -ENOMEM; |
100 | 100 | ||
101 | dssdev->panel.timings = panel_dvi_default_timings; | 101 | dssdev->panel.timings = tfp410_default_timings; |
102 | dssdev->panel.config = OMAP_DSS_LCD_TFT; | 102 | dssdev->panel.config = OMAP_DSS_LCD_TFT; |
103 | 103 | ||
104 | ddata->dssdev = dssdev; | 104 | ddata->dssdev = dssdev; |
105 | mutex_init(&ddata->lock); | 105 | mutex_init(&ddata->lock); |
106 | 106 | ||
107 | if (pdata) | ||
108 | ddata->pd_gpio = pdata->power_down_gpio; | ||
109 | else | ||
110 | ddata->pd_gpio = -1; | ||
111 | |||
112 | if (gpio_is_valid(ddata->pd_gpio)) { | ||
113 | r = gpio_request_one(ddata->pd_gpio, GPIOF_OUT_INIT_LOW, | ||
114 | "tfp410 pd"); | ||
115 | if (r) { | ||
116 | dev_err(&dssdev->dev, "Failed to request PD GPIO %d\n", | ||
117 | ddata->pd_gpio); | ||
118 | ddata->pd_gpio = -1; | ||
119 | } | ||
120 | } | ||
121 | |||
107 | dev_set_drvdata(&dssdev->dev, ddata); | 122 | dev_set_drvdata(&dssdev->dev, ddata); |
108 | 123 | ||
109 | return 0; | 124 | return 0; |
110 | } | 125 | } |
111 | 126 | ||
112 | static void __exit panel_dvi_remove(struct omap_dss_device *dssdev) | 127 | static void __exit tfp410_remove(struct omap_dss_device *dssdev) |
113 | { | 128 | { |
114 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 129 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); |
115 | 130 | ||
116 | mutex_lock(&ddata->lock); | 131 | mutex_lock(&ddata->lock); |
117 | 132 | ||
133 | if (gpio_is_valid(ddata->pd_gpio)) | ||
134 | gpio_free(ddata->pd_gpio); | ||
135 | |||
118 | dev_set_drvdata(&dssdev->dev, NULL); | 136 | dev_set_drvdata(&dssdev->dev, NULL); |
119 | 137 | ||
120 | mutex_unlock(&ddata->lock); | 138 | mutex_unlock(&ddata->lock); |
@@ -122,14 +140,14 @@ static void __exit panel_dvi_remove(struct omap_dss_device *dssdev) | |||
122 | kfree(ddata); | 140 | kfree(ddata); |
123 | } | 141 | } |
124 | 142 | ||
125 | static int panel_dvi_enable(struct omap_dss_device *dssdev) | 143 | static int tfp410_enable(struct omap_dss_device *dssdev) |
126 | { | 144 | { |
127 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 145 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); |
128 | int r; | 146 | int r; |
129 | 147 | ||
130 | mutex_lock(&ddata->lock); | 148 | mutex_lock(&ddata->lock); |
131 | 149 | ||
132 | r = panel_dvi_power_on(dssdev); | 150 | r = tfp410_power_on(dssdev); |
133 | if (r == 0) | 151 | if (r == 0) |
134 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | 152 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; |
135 | 153 | ||
@@ -138,26 +156,26 @@ static int panel_dvi_enable(struct omap_dss_device *dssdev) | |||
138 | return r; | 156 | return r; |
139 | } | 157 | } |
140 | 158 | ||
141 | static void panel_dvi_disable(struct omap_dss_device *dssdev) | 159 | static void tfp410_disable(struct omap_dss_device *dssdev) |
142 | { | 160 | { |
143 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 161 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); |
144 | 162 | ||
145 | mutex_lock(&ddata->lock); | 163 | mutex_lock(&ddata->lock); |
146 | 164 | ||
147 | panel_dvi_power_off(dssdev); | 165 | tfp410_power_off(dssdev); |
148 | 166 | ||
149 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; | 167 | dssdev->state = OMAP_DSS_DISPLAY_DISABLED; |
150 | 168 | ||
151 | mutex_unlock(&ddata->lock); | 169 | mutex_unlock(&ddata->lock); |
152 | } | 170 | } |
153 | 171 | ||
154 | static int panel_dvi_suspend(struct omap_dss_device *dssdev) | 172 | static int tfp410_suspend(struct omap_dss_device *dssdev) |
155 | { | 173 | { |
156 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 174 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); |
157 | 175 | ||
158 | mutex_lock(&ddata->lock); | 176 | mutex_lock(&ddata->lock); |
159 | 177 | ||
160 | panel_dvi_power_off(dssdev); | 178 | tfp410_power_off(dssdev); |
161 | 179 | ||
162 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; | 180 | dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED; |
163 | 181 | ||
@@ -166,14 +184,14 @@ static int panel_dvi_suspend(struct omap_dss_device *dssdev) | |||
166 | return 0; | 184 | return 0; |
167 | } | 185 | } |
168 | 186 | ||
169 | static int panel_dvi_resume(struct omap_dss_device *dssdev) | 187 | static int tfp410_resume(struct omap_dss_device *dssdev) |
170 | { | 188 | { |
171 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 189 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); |
172 | int r; | 190 | int r; |
173 | 191 | ||
174 | mutex_lock(&ddata->lock); | 192 | mutex_lock(&ddata->lock); |
175 | 193 | ||
176 | r = panel_dvi_power_on(dssdev); | 194 | r = tfp410_power_on(dssdev); |
177 | if (r == 0) | 195 | if (r == 0) |
178 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; | 196 | dssdev->state = OMAP_DSS_DISPLAY_ACTIVE; |
179 | 197 | ||
@@ -182,7 +200,7 @@ static int panel_dvi_resume(struct omap_dss_device *dssdev) | |||
182 | return r; | 200 | return r; |
183 | } | 201 | } |
184 | 202 | ||
185 | static void panel_dvi_set_timings(struct omap_dss_device *dssdev, | 203 | static void tfp410_set_timings(struct omap_dss_device *dssdev, |
186 | struct omap_video_timings *timings) | 204 | struct omap_video_timings *timings) |
187 | { | 205 | { |
188 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 206 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); |
@@ -192,7 +210,7 @@ static void panel_dvi_set_timings(struct omap_dss_device *dssdev, | |||
192 | mutex_unlock(&ddata->lock); | 210 | mutex_unlock(&ddata->lock); |
193 | } | 211 | } |
194 | 212 | ||
195 | static void panel_dvi_get_timings(struct omap_dss_device *dssdev, | 213 | static void tfp410_get_timings(struct omap_dss_device *dssdev, |
196 | struct omap_video_timings *timings) | 214 | struct omap_video_timings *timings) |
197 | { | 215 | { |
198 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 216 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); |
@@ -202,7 +220,7 @@ static void panel_dvi_get_timings(struct omap_dss_device *dssdev, | |||
202 | mutex_unlock(&ddata->lock); | 220 | mutex_unlock(&ddata->lock); |
203 | } | 221 | } |
204 | 222 | ||
205 | static int panel_dvi_check_timings(struct omap_dss_device *dssdev, | 223 | static int tfp410_check_timings(struct omap_dss_device *dssdev, |
206 | struct omap_video_timings *timings) | 224 | struct omap_video_timings *timings) |
207 | { | 225 | { |
208 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 226 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); |
@@ -216,7 +234,7 @@ static int panel_dvi_check_timings(struct omap_dss_device *dssdev, | |||
216 | } | 234 | } |
217 | 235 | ||
218 | 236 | ||
219 | static int panel_dvi_ddc_read(struct i2c_adapter *adapter, | 237 | static int tfp410_ddc_read(struct i2c_adapter *adapter, |
220 | unsigned char *buf, u16 count, u8 offset) | 238 | unsigned char *buf, u16 count, u8 offset) |
221 | { | 239 | { |
222 | int r, retries; | 240 | int r, retries; |
@@ -247,11 +265,11 @@ static int panel_dvi_ddc_read(struct i2c_adapter *adapter, | |||
247 | return r < 0 ? r : -EIO; | 265 | return r < 0 ? r : -EIO; |
248 | } | 266 | } |
249 | 267 | ||
250 | static int panel_dvi_read_edid(struct omap_dss_device *dssdev, | 268 | static int tfp410_read_edid(struct omap_dss_device *dssdev, |
251 | u8 *edid, int len) | 269 | u8 *edid, int len) |
252 | { | 270 | { |
253 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 271 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); |
254 | struct panel_dvi_platform_data *pdata = get_pdata(dssdev); | 272 | struct tfp410_platform_data *pdata = get_pdata(dssdev); |
255 | struct i2c_adapter *adapter; | 273 | struct i2c_adapter *adapter; |
256 | int r, l, bytes_read; | 274 | int r, l, bytes_read; |
257 | 275 | ||
@@ -271,7 +289,7 @@ static int panel_dvi_read_edid(struct omap_dss_device *dssdev, | |||
271 | } | 289 | } |
272 | 290 | ||
273 | l = min(EDID_LENGTH, len); | 291 | l = min(EDID_LENGTH, len); |
274 | r = panel_dvi_ddc_read(adapter, edid, l, 0); | 292 | r = tfp410_ddc_read(adapter, edid, l, 0); |
275 | if (r) | 293 | if (r) |
276 | goto err; | 294 | goto err; |
277 | 295 | ||
@@ -281,7 +299,7 @@ static int panel_dvi_read_edid(struct omap_dss_device *dssdev, | |||
281 | if (len > EDID_LENGTH && edid[0x7e] > 0) { | 299 | if (len > EDID_LENGTH && edid[0x7e] > 0) { |
282 | l = min(EDID_LENGTH, len - EDID_LENGTH); | 300 | l = min(EDID_LENGTH, len - EDID_LENGTH); |
283 | 301 | ||
284 | r = panel_dvi_ddc_read(adapter, edid + EDID_LENGTH, | 302 | r = tfp410_ddc_read(adapter, edid + EDID_LENGTH, |
285 | l, EDID_LENGTH); | 303 | l, EDID_LENGTH); |
286 | if (r) | 304 | if (r) |
287 | goto err; | 305 | goto err; |
@@ -298,10 +316,10 @@ err: | |||
298 | return r; | 316 | return r; |
299 | } | 317 | } |
300 | 318 | ||
301 | static bool panel_dvi_detect(struct omap_dss_device *dssdev) | 319 | static bool tfp410_detect(struct omap_dss_device *dssdev) |
302 | { | 320 | { |
303 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); | 321 | struct panel_drv_data *ddata = dev_get_drvdata(&dssdev->dev); |
304 | struct panel_dvi_platform_data *pdata = get_pdata(dssdev); | 322 | struct tfp410_platform_data *pdata = get_pdata(dssdev); |
305 | struct i2c_adapter *adapter; | 323 | struct i2c_adapter *adapter; |
306 | unsigned char out; | 324 | unsigned char out; |
307 | int r; | 325 | int r; |
@@ -315,7 +333,7 @@ static bool panel_dvi_detect(struct omap_dss_device *dssdev) | |||
315 | if (!adapter) | 333 | if (!adapter) |
316 | goto out; | 334 | goto out; |
317 | 335 | ||
318 | r = panel_dvi_ddc_read(adapter, &out, 1, 0); | 336 | r = tfp410_ddc_read(adapter, &out, 1, 0); |
319 | 337 | ||
320 | mutex_unlock(&ddata->lock); | 338 | mutex_unlock(&ddata->lock); |
321 | 339 | ||
@@ -326,38 +344,38 @@ out: | |||
326 | return true; | 344 | return true; |
327 | } | 345 | } |
328 | 346 | ||
329 | static struct omap_dss_driver panel_dvi_driver = { | 347 | static struct omap_dss_driver tfp410_driver = { |
330 | .probe = panel_dvi_probe, | 348 | .probe = tfp410_probe, |
331 | .remove = __exit_p(panel_dvi_remove), | 349 | .remove = __exit_p(tfp410_remove), |
332 | 350 | ||
333 | .enable = panel_dvi_enable, | 351 | .enable = tfp410_enable, |
334 | .disable = panel_dvi_disable, | 352 | .disable = tfp410_disable, |
335 | .suspend = panel_dvi_suspend, | 353 | .suspend = tfp410_suspend, |
336 | .resume = panel_dvi_resume, | 354 | .resume = tfp410_resume, |
337 | 355 | ||
338 | .set_timings = panel_dvi_set_timings, | 356 | .set_timings = tfp410_set_timings, |
339 | .get_timings = panel_dvi_get_timings, | 357 | .get_timings = tfp410_get_timings, |
340 | .check_timings = panel_dvi_check_timings, | 358 | .check_timings = tfp410_check_timings, |
341 | 359 | ||
342 | .read_edid = panel_dvi_read_edid, | 360 | .read_edid = tfp410_read_edid, |
343 | .detect = panel_dvi_detect, | 361 | .detect = tfp410_detect, |
344 | 362 | ||
345 | .driver = { | 363 | .driver = { |
346 | .name = "dvi", | 364 | .name = "tfp410", |
347 | .owner = THIS_MODULE, | 365 | .owner = THIS_MODULE, |
348 | }, | 366 | }, |
349 | }; | 367 | }; |
350 | 368 | ||
351 | static int __init panel_dvi_init(void) | 369 | static int __init tfp410_init(void) |
352 | { | 370 | { |
353 | return omap_dss_register_driver(&panel_dvi_driver); | 371 | return omap_dss_register_driver(&tfp410_driver); |
354 | } | 372 | } |
355 | 373 | ||
356 | static void __exit panel_dvi_exit(void) | 374 | static void __exit tfp410_exit(void) |
357 | { | 375 | { |
358 | omap_dss_unregister_driver(&panel_dvi_driver); | 376 | omap_dss_unregister_driver(&tfp410_driver); |
359 | } | 377 | } |
360 | 378 | ||
361 | module_init(panel_dvi_init); | 379 | module_init(tfp410_init); |
362 | module_exit(panel_dvi_exit); | 380 | module_exit(tfp410_exit); |
363 | MODULE_LICENSE("GPL"); | 381 | MODULE_LICENSE("GPL"); |
diff --git a/drivers/video/omap2/dss/dsi.c b/drivers/video/omap2/dss/dsi.c index 662d14f8c2c3..210a3c4f6150 100644 --- a/drivers/video/omap2/dss/dsi.c +++ b/drivers/video/omap2/dss/dsi.c | |||
@@ -2076,65 +2076,6 @@ static unsigned dsi_get_line_buf_size(struct platform_device *dsidev) | |||
2076 | } | 2076 | } |
2077 | } | 2077 | } |
2078 | 2078 | ||
2079 | static int dsi_parse_lane_config(struct omap_dss_device *dssdev) | ||
2080 | { | ||
2081 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
2082 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
2083 | u8 lanes[DSI_MAX_NR_LANES]; | ||
2084 | u8 polarities[DSI_MAX_NR_LANES]; | ||
2085 | int num_lanes, i; | ||
2086 | |||
2087 | static const enum dsi_lane_function functions[] = { | ||
2088 | DSI_LANE_CLK, | ||
2089 | DSI_LANE_DATA1, | ||
2090 | DSI_LANE_DATA2, | ||
2091 | DSI_LANE_DATA3, | ||
2092 | DSI_LANE_DATA4, | ||
2093 | }; | ||
2094 | |||
2095 | lanes[0] = dssdev->phy.dsi.clk_lane; | ||
2096 | lanes[1] = dssdev->phy.dsi.data1_lane; | ||
2097 | lanes[2] = dssdev->phy.dsi.data2_lane; | ||
2098 | lanes[3] = dssdev->phy.dsi.data3_lane; | ||
2099 | lanes[4] = dssdev->phy.dsi.data4_lane; | ||
2100 | polarities[0] = dssdev->phy.dsi.clk_pol; | ||
2101 | polarities[1] = dssdev->phy.dsi.data1_pol; | ||
2102 | polarities[2] = dssdev->phy.dsi.data2_pol; | ||
2103 | polarities[3] = dssdev->phy.dsi.data3_pol; | ||
2104 | polarities[4] = dssdev->phy.dsi.data4_pol; | ||
2105 | |||
2106 | num_lanes = 0; | ||
2107 | |||
2108 | for (i = 0; i < dsi->num_lanes_supported; ++i) | ||
2109 | dsi->lanes[i].function = DSI_LANE_UNUSED; | ||
2110 | |||
2111 | for (i = 0; i < dsi->num_lanes_supported; ++i) { | ||
2112 | int num; | ||
2113 | |||
2114 | if (lanes[i] == DSI_LANE_UNUSED) | ||
2115 | break; | ||
2116 | |||
2117 | num = lanes[i] - 1; | ||
2118 | |||
2119 | if (num >= dsi->num_lanes_supported) | ||
2120 | return -EINVAL; | ||
2121 | |||
2122 | if (dsi->lanes[num].function != DSI_LANE_UNUSED) | ||
2123 | return -EINVAL; | ||
2124 | |||
2125 | dsi->lanes[num].function = functions[i]; | ||
2126 | dsi->lanes[num].polarity = polarities[i]; | ||
2127 | num_lanes++; | ||
2128 | } | ||
2129 | |||
2130 | if (num_lanes < 2 || num_lanes > dsi->num_lanes_supported) | ||
2131 | return -EINVAL; | ||
2132 | |||
2133 | dsi->num_lanes_used = num_lanes; | ||
2134 | |||
2135 | return 0; | ||
2136 | } | ||
2137 | |||
2138 | static int dsi_set_lane_config(struct omap_dss_device *dssdev) | 2079 | static int dsi_set_lane_config(struct omap_dss_device *dssdev) |
2139 | { | 2080 | { |
2140 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 2081 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
@@ -3975,6 +3916,74 @@ static void dsi_proto_timings(struct omap_dss_device *dssdev) | |||
3975 | } | 3916 | } |
3976 | } | 3917 | } |
3977 | 3918 | ||
3919 | int omapdss_dsi_configure_pins(struct omap_dss_device *dssdev, | ||
3920 | const struct omap_dsi_pin_config *pin_cfg) | ||
3921 | { | ||
3922 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | ||
3923 | struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev); | ||
3924 | int num_pins; | ||
3925 | const int *pins; | ||
3926 | struct dsi_lane_config lanes[DSI_MAX_NR_LANES]; | ||
3927 | int num_lanes; | ||
3928 | int i; | ||
3929 | |||
3930 | static const enum dsi_lane_function functions[] = { | ||
3931 | DSI_LANE_CLK, | ||
3932 | DSI_LANE_DATA1, | ||
3933 | DSI_LANE_DATA2, | ||
3934 | DSI_LANE_DATA3, | ||
3935 | DSI_LANE_DATA4, | ||
3936 | }; | ||
3937 | |||
3938 | num_pins = pin_cfg->num_pins; | ||
3939 | pins = pin_cfg->pins; | ||
3940 | |||
3941 | if (num_pins < 4 || num_pins > dsi->num_lanes_supported * 2 | ||
3942 | || num_pins % 2 != 0) | ||
3943 | return -EINVAL; | ||
3944 | |||
3945 | for (i = 0; i < DSI_MAX_NR_LANES; ++i) | ||
3946 | lanes[i].function = DSI_LANE_UNUSED; | ||
3947 | |||
3948 | num_lanes = 0; | ||
3949 | |||
3950 | for (i = 0; i < num_pins; i += 2) { | ||
3951 | u8 lane, pol; | ||
3952 | int dx, dy; | ||
3953 | |||
3954 | dx = pins[i]; | ||
3955 | dy = pins[i + 1]; | ||
3956 | |||
3957 | if (dx < 0 || dx >= dsi->num_lanes_supported * 2) | ||
3958 | return -EINVAL; | ||
3959 | |||
3960 | if (dy < 0 || dy >= dsi->num_lanes_supported * 2) | ||
3961 | return -EINVAL; | ||
3962 | |||
3963 | if (dx & 1) { | ||
3964 | if (dy != dx - 1) | ||
3965 | return -EINVAL; | ||
3966 | pol = 1; | ||
3967 | } else { | ||
3968 | if (dy != dx + 1) | ||
3969 | return -EINVAL; | ||
3970 | pol = 0; | ||
3971 | } | ||
3972 | |||
3973 | lane = dx / 2; | ||
3974 | |||
3975 | lanes[lane].function = functions[i / 2]; | ||
3976 | lanes[lane].polarity = pol; | ||
3977 | num_lanes++; | ||
3978 | } | ||
3979 | |||
3980 | memcpy(dsi->lanes, lanes, sizeof(dsi->lanes)); | ||
3981 | dsi->num_lanes_used = num_lanes; | ||
3982 | |||
3983 | return 0; | ||
3984 | } | ||
3985 | EXPORT_SYMBOL(omapdss_dsi_configure_pins); | ||
3986 | |||
3978 | int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) | 3987 | int dsi_enable_video_output(struct omap_dss_device *dssdev, int channel) |
3979 | { | 3988 | { |
3980 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); | 3989 | struct platform_device *dsidev = dsi_get_dsidev_from_dssdev(dssdev); |
@@ -4339,12 +4348,6 @@ static int dsi_display_init_dsi(struct omap_dss_device *dssdev) | |||
4339 | int dsi_module = dsi_get_dsidev_id(dsidev); | 4348 | int dsi_module = dsi_get_dsidev_id(dsidev); |
4340 | int r; | 4349 | int r; |
4341 | 4350 | ||
4342 | r = dsi_parse_lane_config(dssdev); | ||
4343 | if (r) { | ||
4344 | DSSERR("illegal lane config"); | ||
4345 | goto err0; | ||
4346 | } | ||
4347 | |||
4348 | r = dsi_pll_init(dsidev, true, true); | 4351 | r = dsi_pll_init(dsidev, true, true); |
4349 | if (r) | 4352 | if (r) |
4350 | goto err0; | 4353 | goto err0; |