aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd/lpc_ich.c
diff options
context:
space:
mode:
authorAaron Sierra <asierra@xes-inc.com>2012-03-28 10:43:10 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-05-01 06:00:21 -0400
commit4630b130b30be6420394ba31121e111c8771ca08 (patch)
treefce77d11a96017ff4cea9fe1e7ecb5d082354677 /drivers/mfd/lpc_ich.c
parentf4bf7cf4cab90c98fe68a7afa12fb72790fd04bf (diff)
mfd: Add LPC driver for Intel ICH chipsets
This driver currently creates resources for use by a forthcoming ICH chipset GPIO driver. It could be expanded to create the resources for converting the esb2rom (mtd) and iTCO_wdt (wdt), and potentially more, drivers to use the mfd model. Signed-off-by: Aaron Sierra <asierra@xes-inc.com> Signed-off-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/lpc_ich.c')
-rw-r--r--drivers/mfd/lpc_ich.c719
1 files changed, 719 insertions, 0 deletions
diff --git a/drivers/mfd/lpc_ich.c b/drivers/mfd/lpc_ich.c
new file mode 100644
index 000000000000..7e3a7b6ab022
--- /dev/null
+++ b/drivers/mfd/lpc_ich.c
@@ -0,0 +1,719 @@
1/*
2 * lpc_ich.c - LPC interface for Intel ICH
3 *
4 * LPC bridge function of the Intel ICH contains many other
5 * functional units, such as Interrupt controllers, Timers,
6 * Power Management, System Management, GPIO, RTC, and LPC
7 * Configuration Registers.
8 *
9 * This driver is derived from lpc_sch.
10
11 * Copyright (c) 2011 Extreme Engineering Solution, Inc.
12 * Author: Aaron Sierra <asierra@xes-inc.com>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License 2 as published
16 * by the Free Software Foundation.
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; see the file COPYING. If not, write to
25 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26 *
27 * This driver supports the following I/O Controller hubs:
28 * (See the intel documentation on http://developer.intel.com.)
29 * document number 290655-003, 290677-014: 82801AA (ICH), 82801AB (ICHO)
30 * document number 290687-002, 298242-027: 82801BA (ICH2)
31 * document number 290733-003, 290739-013: 82801CA (ICH3-S)
32 * document number 290716-001, 290718-007: 82801CAM (ICH3-M)
33 * document number 290744-001, 290745-025: 82801DB (ICH4)
34 * document number 252337-001, 252663-008: 82801DBM (ICH4-M)
35 * document number 273599-001, 273645-002: 82801E (C-ICH)
36 * document number 252516-001, 252517-028: 82801EB (ICH5), 82801ER (ICH5R)
37 * document number 300641-004, 300884-013: 6300ESB
38 * document number 301473-002, 301474-026: 82801F (ICH6)
39 * document number 313082-001, 313075-006: 631xESB, 632xESB
40 * document number 307013-003, 307014-024: 82801G (ICH7)
41 * document number 322896-001, 322897-001: NM10
42 * document number 313056-003, 313057-017: 82801H (ICH8)
43 * document number 316972-004, 316973-012: 82801I (ICH9)
44 * document number 319973-002, 319974-002: 82801J (ICH10)
45 * document number 322169-001, 322170-003: 5 Series, 3400 Series (PCH)
46 * document number 320066-003, 320257-008: EP80597 (IICH)
47 * document number 324645-001, 324646-001: Cougar Point (CPT)
48 * document number TBD : Patsburg (PBG)
49 * document number TBD : DH89xxCC
50 * document number TBD : Panther Point
51 * document number TBD : Lynx Point
52 */
53
54#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
55
56#include <linux/init.h>
57#include <linux/kernel.h>
58#include <linux/module.h>
59#include <linux/errno.h>
60#include <linux/acpi.h>
61#include <linux/pci.h>
62#include <linux/mfd/core.h>
63#include <linux/mfd/lpc_ich.h>
64
65#define ACPIBASE 0x40
66#define ACPIBASE_GPE_OFF 0x28
67#define ACPIBASE_GPE_END 0x2f
68#define ACPICTRL 0x44
69
70#define GPIOBASE 0x48
71#define GPIOCTRL 0x4C
72
73static int lpc_ich_acpi_save = -1;
74static int lpc_ich_gpio_save = -1;
75
76static struct resource gpio_ich_res[] = {
77 /* GPIO */
78 {
79 .flags = IORESOURCE_IO,
80 },
81 /* ACPI - GPE0 */
82 {
83 .flags = IORESOURCE_IO,
84 },
85};
86
87enum lpc_cells {
88 LPC_GPIO = 0,
89};
90
91static struct mfd_cell lpc_ich_cells[] = {
92 [LPC_GPIO] = {
93 .name = "gpio_ich",
94 .num_resources = ARRAY_SIZE(gpio_ich_res),
95 .resources = gpio_ich_res,
96 .ignore_resource_conflicts = true,
97 },
98};
99
100/* chipset related info */
101enum lpc_chipsets {
102 LPC_ICH = 0, /* ICH */
103 LPC_ICH0, /* ICH0 */
104 LPC_ICH2, /* ICH2 */
105 LPC_ICH2M, /* ICH2-M */
106 LPC_ICH3, /* ICH3-S */
107 LPC_ICH3M, /* ICH3-M */
108 LPC_ICH4, /* ICH4 */
109 LPC_ICH4M, /* ICH4-M */
110 LPC_CICH, /* C-ICH */
111 LPC_ICH5, /* ICH5 & ICH5R */
112 LPC_6300ESB, /* 6300ESB */
113 LPC_ICH6, /* ICH6 & ICH6R */
114 LPC_ICH6M, /* ICH6-M */
115 LPC_ICH6W, /* ICH6W & ICH6RW */
116 LPC_631XESB, /* 631xESB/632xESB */
117 LPC_ICH7, /* ICH7 & ICH7R */
118 LPC_ICH7DH, /* ICH7DH */
119 LPC_ICH7M, /* ICH7-M & ICH7-U */
120 LPC_ICH7MDH, /* ICH7-M DH */
121 LPC_NM10, /* NM10 */
122 LPC_ICH8, /* ICH8 & ICH8R */
123 LPC_ICH8DH, /* ICH8DH */
124 LPC_ICH8DO, /* ICH8DO */
125 LPC_ICH8M, /* ICH8M */
126 LPC_ICH8ME, /* ICH8M-E */
127 LPC_ICH9, /* ICH9 */
128 LPC_ICH9R, /* ICH9R */
129 LPC_ICH9DH, /* ICH9DH */
130 LPC_ICH9DO, /* ICH9DO */
131 LPC_ICH9M, /* ICH9M */
132 LPC_ICH9ME, /* ICH9M-E */
133 LPC_ICH10, /* ICH10 */
134 LPC_ICH10R, /* ICH10R */
135 LPC_ICH10D, /* ICH10D */
136 LPC_ICH10DO, /* ICH10DO */
137 LPC_PCH, /* PCH Desktop Full Featured */
138 LPC_PCHM, /* PCH Mobile Full Featured */
139 LPC_P55, /* P55 */
140 LPC_PM55, /* PM55 */
141 LPC_H55, /* H55 */
142 LPC_QM57, /* QM57 */
143 LPC_H57, /* H57 */
144 LPC_HM55, /* HM55 */
145 LPC_Q57, /* Q57 */
146 LPC_HM57, /* HM57 */
147 LPC_PCHMSFF, /* PCH Mobile SFF Full Featured */
148 LPC_QS57, /* QS57 */
149 LPC_3400, /* 3400 */
150 LPC_3420, /* 3420 */
151 LPC_3450, /* 3450 */
152 LPC_EP80579, /* EP80579 */
153 LPC_CPT, /* Cougar Point */
154 LPC_CPTD, /* Cougar Point Desktop */
155 LPC_CPTM, /* Cougar Point Mobile */
156 LPC_PBG, /* Patsburg */
157 LPC_DH89XXCC, /* DH89xxCC */
158 LPC_PPT, /* Panther Point */
159 LPC_LPT, /* Lynx Point */
160};
161
162struct lpc_ich_info lpc_chipset_info[] __devinitdata = {
163 [LPC_ICH] = {
164 .name = "ICH",
165 },
166 [LPC_ICH0] = {
167 .name = "ICH0",
168 },
169 [LPC_ICH2] = {
170 .name = "ICH2",
171 },
172 [LPC_ICH2M] = {
173 .name = "ICH2-M",
174 },
175 [LPC_ICH3] = {
176 .name = "ICH3-S",
177 },
178 [LPC_ICH3M] = {
179 .name = "ICH3-M",
180 },
181 [LPC_ICH4] = {
182 .name = "ICH4",
183 },
184 [LPC_ICH4M] = {
185 .name = "ICH4-M",
186 },
187 [LPC_CICH] = {
188 .name = "C-ICH",
189 },
190 [LPC_ICH5] = {
191 .name = "ICH5 or ICH5R",
192 },
193 [LPC_6300ESB] = {
194 .name = "6300ESB",
195 },
196 [LPC_ICH6] = {
197 .name = "ICH6 or ICH6R",
198 .gpio_version = ICH_V6_GPIO,
199 },
200 [LPC_ICH6M] = {
201 .name = "ICH6-M",
202 .gpio_version = ICH_V6_GPIO,
203 },
204 [LPC_ICH6W] = {
205 .name = "ICH6W or ICH6RW",
206 .gpio_version = ICH_V6_GPIO,
207 },
208 [LPC_631XESB] = {
209 .name = "631xESB/632xESB",
210 .gpio_version = ICH_V6_GPIO,
211 },
212 [LPC_ICH7] = {
213 .name = "ICH7 or ICH7R",
214 .gpio_version = ICH_V7_GPIO,
215 },
216 [LPC_ICH7DH] = {
217 .name = "ICH7DH",
218 .gpio_version = ICH_V7_GPIO,
219 },
220 [LPC_ICH7M] = {
221 .name = "ICH7-M or ICH7-U",
222 .gpio_version = ICH_V7_GPIO,
223 },
224 [LPC_ICH7MDH] = {
225 .name = "ICH7-M DH",
226 .gpio_version = ICH_V7_GPIO,
227 },
228 [LPC_NM10] = {
229 .name = "NM10",
230 },
231 [LPC_ICH8] = {
232 .name = "ICH8 or ICH8R",
233 .gpio_version = ICH_V7_GPIO,
234 },
235 [LPC_ICH8DH] = {
236 .name = "ICH8DH",
237 .gpio_version = ICH_V7_GPIO,
238 },
239 [LPC_ICH8DO] = {
240 .name = "ICH8DO",
241 .gpio_version = ICH_V7_GPIO,
242 },
243 [LPC_ICH8M] = {
244 .name = "ICH8M",
245 .gpio_version = ICH_V7_GPIO,
246 },
247 [LPC_ICH8ME] = {
248 .name = "ICH8M-E",
249 .gpio_version = ICH_V7_GPIO,
250 },
251 [LPC_ICH9] = {
252 .name = "ICH9",
253 .gpio_version = ICH_V9_GPIO,
254 },
255 [LPC_ICH9R] = {
256 .name = "ICH9R",
257 .gpio_version = ICH_V9_GPIO,
258 },
259 [LPC_ICH9DH] = {
260 .name = "ICH9DH",
261 .gpio_version = ICH_V9_GPIO,
262 },
263 [LPC_ICH9DO] = {
264 .name = "ICH9DO",
265 .gpio_version = ICH_V9_GPIO,
266 },
267 [LPC_ICH9M] = {
268 .name = "ICH9M",
269 .gpio_version = ICH_V9_GPIO,
270 },
271 [LPC_ICH9ME] = {
272 .name = "ICH9M-E",
273 .gpio_version = ICH_V9_GPIO,
274 },
275 [LPC_ICH10] = {
276 .name = "ICH10",
277 .gpio_version = ICH_V10CONS_GPIO,
278 },
279 [LPC_ICH10R] = {
280 .name = "ICH10R",
281 .gpio_version = ICH_V10CONS_GPIO,
282 },
283 [LPC_ICH10D] = {
284 .name = "ICH10D",
285 .gpio_version = ICH_V10CORP_GPIO,
286 },
287 [LPC_ICH10DO] = {
288 .name = "ICH10DO",
289 .gpio_version = ICH_V10CORP_GPIO,
290 },
291 [LPC_PCH] = {
292 .name = "PCH Desktop Full Featured",
293 .gpio_version = ICH_V5_GPIO,
294 },
295 [LPC_PCHM] = {
296 .name = "PCH Mobile Full Featured",
297 .gpio_version = ICH_V5_GPIO,
298 },
299 [LPC_P55] = {
300 .name = "P55",
301 .gpio_version = ICH_V5_GPIO,
302 },
303 [LPC_PM55] = {
304 .name = "PM55",
305 .gpio_version = ICH_V5_GPIO,
306 },
307 [LPC_H55] = {
308 .name = "H55",
309 .gpio_version = ICH_V5_GPIO,
310 },
311 [LPC_QM57] = {
312 .name = "QM57",
313 .gpio_version = ICH_V5_GPIO,
314 },
315 [LPC_H57] = {
316 .name = "H57",
317 .gpio_version = ICH_V5_GPIO,
318 },
319 [LPC_HM55] = {
320 .name = "HM55",
321 .gpio_version = ICH_V5_GPIO,
322 },
323 [LPC_Q57] = {
324 .name = "Q57",
325 .gpio_version = ICH_V5_GPIO,
326 },
327 [LPC_HM57] = {
328 .name = "HM57",
329 .gpio_version = ICH_V5_GPIO,
330 },
331 [LPC_PCHMSFF] = {
332 .name = "PCH Mobile SFF Full Featured",
333 .gpio_version = ICH_V5_GPIO,
334 },
335 [LPC_QS57] = {
336 .name = "QS57",
337 .gpio_version = ICH_V5_GPIO,
338 },
339 [LPC_3400] = {
340 .name = "3400",
341 .gpio_version = ICH_V5_GPIO,
342 },
343 [LPC_3420] = {
344 .name = "3420",
345 .gpio_version = ICH_V5_GPIO,
346 },
347 [LPC_3450] = {
348 .name = "3450",
349 .gpio_version = ICH_V5_GPIO,
350 },
351 [LPC_EP80579] = {
352 .name = "EP80579",
353 },
354 [LPC_CPT] = {
355 .name = "Cougar Point",
356 .gpio_version = ICH_V5_GPIO,
357 },
358 [LPC_CPTD] = {
359 .name = "Cougar Point Desktop",
360 .gpio_version = ICH_V5_GPIO,
361 },
362 [LPC_CPTM] = {
363 .name = "Cougar Point Mobile",
364 .gpio_version = ICH_V5_GPIO,
365 },
366 [LPC_PBG] = {
367 .name = "Patsburg",
368 },
369 [LPC_DH89XXCC] = {
370 .name = "DH89xxCC",
371 },
372 [LPC_PPT] = {
373 .name = "Panther Point",
374 },
375 [LPC_LPT] = {
376 .name = "Lynx Point",
377 },
378};
379
380/*
381 * This data only exists for exporting the supported PCI ids
382 * via MODULE_DEVICE_TABLE. We do not actually register a
383 * pci_driver, because the I/O Controller Hub has also other
384 * functions that probably will be registered by other drivers.
385 */
386static DEFINE_PCI_DEVICE_TABLE(lpc_ich_ids) = {
387 { PCI_VDEVICE(INTEL, 0x2410), LPC_ICH},
388 { PCI_VDEVICE(INTEL, 0x2420), LPC_ICH0},
389 { PCI_VDEVICE(INTEL, 0x2440), LPC_ICH2},
390 { PCI_VDEVICE(INTEL, 0x244c), LPC_ICH2M},
391 { PCI_VDEVICE(INTEL, 0x2480), LPC_ICH3},
392 { PCI_VDEVICE(INTEL, 0x248c), LPC_ICH3M},
393 { PCI_VDEVICE(INTEL, 0x24c0), LPC_ICH4},
394 { PCI_VDEVICE(INTEL, 0x24cc), LPC_ICH4M},
395 { PCI_VDEVICE(INTEL, 0x2450), LPC_CICH},
396 { PCI_VDEVICE(INTEL, 0x24d0), LPC_ICH5},
397 { PCI_VDEVICE(INTEL, 0x25a1), LPC_6300ESB},
398 { PCI_VDEVICE(INTEL, 0x2640), LPC_ICH6},
399 { PCI_VDEVICE(INTEL, 0x2641), LPC_ICH6M},
400 { PCI_VDEVICE(INTEL, 0x2642), LPC_ICH6W},
401 { PCI_VDEVICE(INTEL, 0x2670), LPC_631XESB},
402 { PCI_VDEVICE(INTEL, 0x2671), LPC_631XESB},
403 { PCI_VDEVICE(INTEL, 0x2672), LPC_631XESB},
404 { PCI_VDEVICE(INTEL, 0x2673), LPC_631XESB},
405 { PCI_VDEVICE(INTEL, 0x2674), LPC_631XESB},
406 { PCI_VDEVICE(INTEL, 0x2675), LPC_631XESB},
407 { PCI_VDEVICE(INTEL, 0x2676), LPC_631XESB},
408 { PCI_VDEVICE(INTEL, 0x2677), LPC_631XESB},
409 { PCI_VDEVICE(INTEL, 0x2678), LPC_631XESB},
410 { PCI_VDEVICE(INTEL, 0x2679), LPC_631XESB},
411 { PCI_VDEVICE(INTEL, 0x267a), LPC_631XESB},
412 { PCI_VDEVICE(INTEL, 0x267b), LPC_631XESB},
413 { PCI_VDEVICE(INTEL, 0x267c), LPC_631XESB},
414 { PCI_VDEVICE(INTEL, 0x267d), LPC_631XESB},
415 { PCI_VDEVICE(INTEL, 0x267e), LPC_631XESB},
416 { PCI_VDEVICE(INTEL, 0x267f), LPC_631XESB},
417 { PCI_VDEVICE(INTEL, 0x27b8), LPC_ICH7},
418 { PCI_VDEVICE(INTEL, 0x27b0), LPC_ICH7DH},
419 { PCI_VDEVICE(INTEL, 0x27b9), LPC_ICH7M},
420 { PCI_VDEVICE(INTEL, 0x27bd), LPC_ICH7MDH},
421 { PCI_VDEVICE(INTEL, 0x27bc), LPC_NM10},
422 { PCI_VDEVICE(INTEL, 0x2810), LPC_ICH8},
423 { PCI_VDEVICE(INTEL, 0x2812), LPC_ICH8DH},
424 { PCI_VDEVICE(INTEL, 0x2814), LPC_ICH8DO},
425 { PCI_VDEVICE(INTEL, 0x2815), LPC_ICH8M},
426 { PCI_VDEVICE(INTEL, 0x2811), LPC_ICH8ME},
427 { PCI_VDEVICE(INTEL, 0x2918), LPC_ICH9},
428 { PCI_VDEVICE(INTEL, 0x2916), LPC_ICH9R},
429 { PCI_VDEVICE(INTEL, 0x2912), LPC_ICH9DH},
430 { PCI_VDEVICE(INTEL, 0x2914), LPC_ICH9DO},
431 { PCI_VDEVICE(INTEL, 0x2919), LPC_ICH9M},
432 { PCI_VDEVICE(INTEL, 0x2917), LPC_ICH9ME},
433 { PCI_VDEVICE(INTEL, 0x3a18), LPC_ICH10},
434 { PCI_VDEVICE(INTEL, 0x3a16), LPC_ICH10R},
435 { PCI_VDEVICE(INTEL, 0x3a1a), LPC_ICH10D},
436 { PCI_VDEVICE(INTEL, 0x3a14), LPC_ICH10DO},
437 { PCI_VDEVICE(INTEL, 0x3b00), LPC_PCH},
438 { PCI_VDEVICE(INTEL, 0x3b01), LPC_PCHM},
439 { PCI_VDEVICE(INTEL, 0x3b02), LPC_P55},
440 { PCI_VDEVICE(INTEL, 0x3b03), LPC_PM55},
441 { PCI_VDEVICE(INTEL, 0x3b06), LPC_H55},
442 { PCI_VDEVICE(INTEL, 0x3b07), LPC_QM57},
443 { PCI_VDEVICE(INTEL, 0x3b08), LPC_H57},
444 { PCI_VDEVICE(INTEL, 0x3b09), LPC_HM55},
445 { PCI_VDEVICE(INTEL, 0x3b0a), LPC_Q57},
446 { PCI_VDEVICE(INTEL, 0x3b0b), LPC_HM57},
447 { PCI_VDEVICE(INTEL, 0x3b0d), LPC_PCHMSFF},
448 { PCI_VDEVICE(INTEL, 0x3b0f), LPC_QS57},
449 { PCI_VDEVICE(INTEL, 0x3b12), LPC_3400},
450 { PCI_VDEVICE(INTEL, 0x3b14), LPC_3420},
451 { PCI_VDEVICE(INTEL, 0x3b16), LPC_3450},
452 { PCI_VDEVICE(INTEL, 0x5031), LPC_EP80579},
453 { PCI_VDEVICE(INTEL, 0x1c41), LPC_CPT},
454 { PCI_VDEVICE(INTEL, 0x1c42), LPC_CPTD},
455 { PCI_VDEVICE(INTEL, 0x1c43), LPC_CPTM},
456 { PCI_VDEVICE(INTEL, 0x1c44), LPC_CPT},
457 { PCI_VDEVICE(INTEL, 0x1c45), LPC_CPT},
458 { PCI_VDEVICE(INTEL, 0x1c46), LPC_CPT},
459 { PCI_VDEVICE(INTEL, 0x1c47), LPC_CPT},
460 { PCI_VDEVICE(INTEL, 0x1c48), LPC_CPT},
461 { PCI_VDEVICE(INTEL, 0x1c49), LPC_CPT},
462 { PCI_VDEVICE(INTEL, 0x1c4a), LPC_CPT},
463 { PCI_VDEVICE(INTEL, 0x1c4b), LPC_CPT},
464 { PCI_VDEVICE(INTEL, 0x1c4c), LPC_CPT},
465 { PCI_VDEVICE(INTEL, 0x1c4d), LPC_CPT},
466 { PCI_VDEVICE(INTEL, 0x1c4e), LPC_CPT},
467 { PCI_VDEVICE(INTEL, 0x1c4f), LPC_CPT},
468 { PCI_VDEVICE(INTEL, 0x1c50), LPC_CPT},
469 { PCI_VDEVICE(INTEL, 0x1c51), LPC_CPT},
470 { PCI_VDEVICE(INTEL, 0x1c52), LPC_CPT},
471 { PCI_VDEVICE(INTEL, 0x1c53), LPC_CPT},
472 { PCI_VDEVICE(INTEL, 0x1c54), LPC_CPT},
473 { PCI_VDEVICE(INTEL, 0x1c55), LPC_CPT},
474 { PCI_VDEVICE(INTEL, 0x1c56), LPC_CPT},
475 { PCI_VDEVICE(INTEL, 0x1c57), LPC_CPT},
476 { PCI_VDEVICE(INTEL, 0x1c58), LPC_CPT},
477 { PCI_VDEVICE(INTEL, 0x1c59), LPC_CPT},
478 { PCI_VDEVICE(INTEL, 0x1c5a), LPC_CPT},
479 { PCI_VDEVICE(INTEL, 0x1c5b), LPC_CPT},
480 { PCI_VDEVICE(INTEL, 0x1c5c), LPC_CPT},
481 { PCI_VDEVICE(INTEL, 0x1c5d), LPC_CPT},
482 { PCI_VDEVICE(INTEL, 0x1c5e), LPC_CPT},
483 { PCI_VDEVICE(INTEL, 0x1c5f), LPC_CPT},
484 { PCI_VDEVICE(INTEL, 0x1d40), LPC_PBG},
485 { PCI_VDEVICE(INTEL, 0x1d41), LPC_PBG},
486 { PCI_VDEVICE(INTEL, 0x2310), LPC_DH89XXCC},
487 { PCI_VDEVICE(INTEL, 0x1e40), LPC_PPT},
488 { PCI_VDEVICE(INTEL, 0x1e41), LPC_PPT},
489 { PCI_VDEVICE(INTEL, 0x1e42), LPC_PPT},
490 { PCI_VDEVICE(INTEL, 0x1e43), LPC_PPT},
491 { PCI_VDEVICE(INTEL, 0x1e44), LPC_PPT},
492 { PCI_VDEVICE(INTEL, 0x1e45), LPC_PPT},
493 { PCI_VDEVICE(INTEL, 0x1e46), LPC_PPT},
494 { PCI_VDEVICE(INTEL, 0x1e47), LPC_PPT},
495 { PCI_VDEVICE(INTEL, 0x1e48), LPC_PPT},
496 { PCI_VDEVICE(INTEL, 0x1e49), LPC_PPT},
497 { PCI_VDEVICE(INTEL, 0x1e4a), LPC_PPT},
498 { PCI_VDEVICE(INTEL, 0x1e4b), LPC_PPT},
499 { PCI_VDEVICE(INTEL, 0x1e4c), LPC_PPT},
500 { PCI_VDEVICE(INTEL, 0x1e4d), LPC_PPT},
501 { PCI_VDEVICE(INTEL, 0x1e4e), LPC_PPT},
502 { PCI_VDEVICE(INTEL, 0x1e4f), LPC_PPT},
503 { PCI_VDEVICE(INTEL, 0x1e50), LPC_PPT},
504 { PCI_VDEVICE(INTEL, 0x1e51), LPC_PPT},
505 { PCI_VDEVICE(INTEL, 0x1e52), LPC_PPT},
506 { PCI_VDEVICE(INTEL, 0x1e53), LPC_PPT},
507 { PCI_VDEVICE(INTEL, 0x1e54), LPC_PPT},
508 { PCI_VDEVICE(INTEL, 0x1e55), LPC_PPT},
509 { PCI_VDEVICE(INTEL, 0x1e56), LPC_PPT},
510 { PCI_VDEVICE(INTEL, 0x1e57), LPC_PPT},
511 { PCI_VDEVICE(INTEL, 0x1e58), LPC_PPT},
512 { PCI_VDEVICE(INTEL, 0x1e59), LPC_PPT},
513 { PCI_VDEVICE(INTEL, 0x1e5a), LPC_PPT},
514 { PCI_VDEVICE(INTEL, 0x1e5b), LPC_PPT},
515 { PCI_VDEVICE(INTEL, 0x1e5c), LPC_PPT},
516 { PCI_VDEVICE(INTEL, 0x1e5d), LPC_PPT},
517 { PCI_VDEVICE(INTEL, 0x1e5e), LPC_PPT},
518 { PCI_VDEVICE(INTEL, 0x1e5f), LPC_PPT},
519 { PCI_VDEVICE(INTEL, 0x8c40), LPC_LPT},
520 { PCI_VDEVICE(INTEL, 0x8c41), LPC_LPT},
521 { PCI_VDEVICE(INTEL, 0x8c42), LPC_LPT},
522 { PCI_VDEVICE(INTEL, 0x8c43), LPC_LPT},
523 { PCI_VDEVICE(INTEL, 0x8c44), LPC_LPT},
524 { PCI_VDEVICE(INTEL, 0x8c45), LPC_LPT},
525 { PCI_VDEVICE(INTEL, 0x8c46), LPC_LPT},
526 { PCI_VDEVICE(INTEL, 0x8c47), LPC_LPT},
527 { PCI_VDEVICE(INTEL, 0x8c48), LPC_LPT},
528 { PCI_VDEVICE(INTEL, 0x8c49), LPC_LPT},
529 { PCI_VDEVICE(INTEL, 0x8c4a), LPC_LPT},
530 { PCI_VDEVICE(INTEL, 0x8c4b), LPC_LPT},
531 { PCI_VDEVICE(INTEL, 0x8c4c), LPC_LPT},
532 { PCI_VDEVICE(INTEL, 0x8c4d), LPC_LPT},
533 { PCI_VDEVICE(INTEL, 0x8c4e), LPC_LPT},
534 { PCI_VDEVICE(INTEL, 0x8c4f), LPC_LPT},
535 { PCI_VDEVICE(INTEL, 0x8c50), LPC_LPT},
536 { PCI_VDEVICE(INTEL, 0x8c51), LPC_LPT},
537 { PCI_VDEVICE(INTEL, 0x8c52), LPC_LPT},
538 { PCI_VDEVICE(INTEL, 0x8c53), LPC_LPT},
539 { PCI_VDEVICE(INTEL, 0x8c54), LPC_LPT},
540 { PCI_VDEVICE(INTEL, 0x8c55), LPC_LPT},
541 { PCI_VDEVICE(INTEL, 0x8c56), LPC_LPT},
542 { PCI_VDEVICE(INTEL, 0x8c57), LPC_LPT},
543 { PCI_VDEVICE(INTEL, 0x8c58), LPC_LPT},
544 { PCI_VDEVICE(INTEL, 0x8c59), LPC_LPT},
545 { PCI_VDEVICE(INTEL, 0x8c5a), LPC_LPT},
546 { PCI_VDEVICE(INTEL, 0x8c5b), LPC_LPT},
547 { PCI_VDEVICE(INTEL, 0x8c5c), LPC_LPT},
548 { PCI_VDEVICE(INTEL, 0x8c5d), LPC_LPT},
549 { PCI_VDEVICE(INTEL, 0x8c5e), LPC_LPT},
550 { PCI_VDEVICE(INTEL, 0x8c5f), LPC_LPT},
551 { 0, }, /* End of list */
552};
553MODULE_DEVICE_TABLE(pci, lpc_ich_ids);
554
555static void lpc_ich_restore_config_space(struct pci_dev *dev)
556{
557 if (lpc_ich_acpi_save >= 0) {
558 pci_write_config_byte(dev, ACPICTRL, lpc_ich_acpi_save);
559 lpc_ich_acpi_save = -1;
560 }
561
562 if (lpc_ich_gpio_save >= 0) {
563 pci_write_config_byte(dev, GPIOCTRL, lpc_ich_gpio_save);
564 lpc_ich_gpio_save = -1;
565 }
566}
567
568static void __devinit lpc_ich_enable_acpi_space(struct pci_dev *dev)
569{
570 u8 reg_save;
571
572 pci_read_config_byte(dev, ACPICTRL, &reg_save);
573 pci_write_config_byte(dev, ACPICTRL, reg_save | 0x10);
574 lpc_ich_acpi_save = reg_save;
575}
576
577static void __devinit lpc_ich_enable_gpio_space(struct pci_dev *dev)
578{
579 u8 reg_save;
580
581 pci_read_config_byte(dev, GPIOCTRL, &reg_save);
582 pci_write_config_byte(dev, GPIOCTRL, reg_save | 0x10);
583 lpc_ich_gpio_save = reg_save;
584}
585
586static void __devinit lpc_ich_finalize_cell(struct mfd_cell *cell,
587 const struct pci_device_id *id)
588{
589 cell->platform_data = &lpc_chipset_info[id->driver_data];
590 cell->pdata_size = sizeof(struct lpc_ich_info);
591}
592
593static int __devinit lpc_ich_init_gpio(struct pci_dev *dev,
594 const struct pci_device_id *id)
595{
596 u32 base_addr_cfg;
597 u32 base_addr;
598 int ret;
599 bool acpi_conflict = false;
600 struct resource *res;
601
602 /* Setup power management base register */
603 pci_read_config_dword(dev, ACPIBASE, &base_addr_cfg);
604 base_addr = base_addr_cfg & 0x0000ff80;
605 if (!base_addr) {
606 dev_err(&dev->dev, "I/O space for ACPI uninitialized\n");
607 lpc_ich_cells[LPC_GPIO].num_resources--;
608 goto gpe0_done;
609 }
610
611 res = &gpio_ich_res[ICH_RES_GPE0];
612 res->start = base_addr + ACPIBASE_GPE_OFF;
613 res->end = base_addr + ACPIBASE_GPE_END;
614 ret = acpi_check_resource_conflict(res);
615 if (ret) {
616 /*
617 * This isn't fatal for the GPIO, but we have to make sure that
618 * the platform_device subsystem doesn't see this resource
619 * or it will register an invalid region.
620 */
621 lpc_ich_cells[LPC_GPIO].num_resources--;
622 acpi_conflict = true;
623 } else {
624 lpc_ich_enable_acpi_space(dev);
625 }
626
627gpe0_done:
628 /* Setup GPIO base register */
629 pci_read_config_dword(dev, GPIOBASE, &base_addr_cfg);
630 base_addr = base_addr_cfg & 0x0000ff80;
631 if (!base_addr) {
632 dev_err(&dev->dev, "I/O space for GPIO uninitialized\n");
633 ret = -ENODEV;
634 goto gpio_done;
635 }
636
637 /* Older devices provide fewer GPIO and have a smaller resource size. */
638 res = &gpio_ich_res[ICH_RES_GPIO];
639 res->start = base_addr;
640 switch (lpc_chipset_info[id->driver_data].gpio_version) {
641 case ICH_V5_GPIO:
642 case ICH_V10CORP_GPIO:
643 res->end = res->start + 128 - 1;
644 break;
645 default:
646 res->end = res->start + 64 - 1;
647 break;
648 }
649
650 ret = acpi_check_resource_conflict(res);
651 if (ret) {
652 /* this isn't necessarily fatal for the GPIO */
653 acpi_conflict = true;
654 goto gpio_done;
655 }
656 lpc_ich_enable_gpio_space(dev);
657
658 lpc_ich_finalize_cell(&lpc_ich_cells[LPC_GPIO], id);
659 ret = mfd_add_devices(&dev->dev, -1, &lpc_ich_cells[LPC_GPIO],
660 1, NULL, 0);
661
662gpio_done:
663 if (acpi_conflict)
664 pr_warn("Resource conflict(s) found affecting %s\n",
665 lpc_ich_cells[LPC_GPIO].name);
666 return ret;
667}
668
669static int __devinit lpc_ich_probe(struct pci_dev *dev,
670 const struct pci_device_id *id)
671{
672 int ret;
673 bool cell_added = false;
674
675 ret = lpc_ich_init_gpio(dev, id);
676 if (!ret)
677 cell_added = true;
678
679 /*
680 * We only care if at least one or none of the cells registered
681 * successfully.
682 */
683 if (!cell_added) {
684 lpc_ich_restore_config_space(dev);
685 return -ENODEV;
686 }
687
688 return 0;
689}
690
691static void __devexit lpc_ich_remove(struct pci_dev *dev)
692{
693 mfd_remove_devices(&dev->dev);
694 lpc_ich_restore_config_space(dev);
695}
696
697static struct pci_driver lpc_ich_driver = {
698 .name = "lpc_ich",
699 .id_table = lpc_ich_ids,
700 .probe = lpc_ich_probe,
701 .remove = __devexit_p(lpc_ich_remove),
702};
703
704static int __init lpc_ich_init(void)
705{
706 return pci_register_driver(&lpc_ich_driver);
707}
708
709static void __exit lpc_ich_exit(void)
710{
711 pci_unregister_driver(&lpc_ich_driver);
712}
713
714module_init(lpc_ich_init);
715module_exit(lpc_ich_exit);
716
717MODULE_AUTHOR("Aaron Sierra <asierra@xes-inc.com>");
718MODULE_DESCRIPTION("LPC interface for Intel ICH");
719MODULE_LICENSE("GPL");