diff options
author | Kevin Strasser <kevin.strasser@linux.intel.com> | 2013-06-24 00:00:03 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2013-06-24 07:48:22 -0400 |
commit | 43620a17945b598e707ef897b3866914f9f9056c (patch) | |
tree | 67a26eb8bc13e4a2ca0d393b15051eff747cf9ef /drivers/mfd/kempld-core.c | |
parent | 4124e6e291a7b1a21ea7c28c8f9899d050103308 (diff) |
mfd: Kontron PLD mfd driver
Add core MFD driver for the on-board PLD found on some Kontron embedded
modules. The PLD device may provide functions like watchdog, GPIO, UART
and I2C bus.
The following modules are supported:
* COMe-bIP#
* COMe-bPC2 (ETXexpress-PC)
* COMe-bSC# (ETXexpress-SC T#)
* COMe-cCT6
* COMe-cDC2 (microETXexpress-DC)
* COMe-cPC2 (microETXexpress-PC)
* COMe-mCT10
* ETX-OH
Originally-From: Michael Brunner <michael.brunner@kontron.com>
Signed-off-by: Kevin Strasser <kevin.strasser@linux.intel.com>
Acked-by: Guenter Roeck <linux@roeck-us.net>
Acked-by: Darren Hart <dvhart@linux.intel.com>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers/mfd/kempld-core.c')
-rw-r--r-- | drivers/mfd/kempld-core.c | 641 |
1 files changed, 641 insertions, 0 deletions
diff --git a/drivers/mfd/kempld-core.c b/drivers/mfd/kempld-core.c new file mode 100644 index 000000000000..686a4565acb6 --- /dev/null +++ b/drivers/mfd/kempld-core.c | |||
@@ -0,0 +1,641 @@ | |||
1 | /* | ||
2 | * Kontron PLD MFD core driver | ||
3 | * | ||
4 | * Copyright (c) 2010-2013 Kontron Europe GmbH | ||
5 | * Author: Michael Brunner <michael.brunner@kontron.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License 2 as published | ||
9 | * by the Free Software Foundation. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/platform_device.h> | ||
18 | #include <linux/mfd/core.h> | ||
19 | #include <linux/mfd/kempld.h> | ||
20 | #include <linux/module.h> | ||
21 | #include <linux/dmi.h> | ||
22 | #include <linux/io.h> | ||
23 | #include <linux/delay.h> | ||
24 | |||
25 | #define MAX_ID_LEN 4 | ||
26 | static char force_device_id[MAX_ID_LEN + 1] = ""; | ||
27 | module_param_string(force_device_id, force_device_id, sizeof(force_device_id), 0); | ||
28 | MODULE_PARM_DESC(force_device_id, "Override detected product"); | ||
29 | |||
30 | /* | ||
31 | * Get hardware mutex to block firmware from accessing the pld. | ||
32 | * It is possible for the firmware may hold the mutex for an extended length of | ||
33 | * time. This function will block until access has been granted. | ||
34 | */ | ||
35 | static void kempld_get_hardware_mutex(struct kempld_device_data *pld) | ||
36 | { | ||
37 | /* The mutex bit will read 1 until access has been granted */ | ||
38 | while (ioread8(pld->io_index) & KEMPLD_MUTEX_KEY) | ||
39 | msleep(1); | ||
40 | } | ||
41 | |||
42 | static void kempld_release_hardware_mutex(struct kempld_device_data *pld) | ||
43 | { | ||
44 | /* The harware mutex is released when 1 is written to the mutex bit. */ | ||
45 | iowrite8(KEMPLD_MUTEX_KEY, pld->io_index); | ||
46 | } | ||
47 | |||
48 | static int kempld_get_info_generic(struct kempld_device_data *pld) | ||
49 | { | ||
50 | u16 version; | ||
51 | u8 spec; | ||
52 | |||
53 | kempld_get_mutex(pld); | ||
54 | |||
55 | version = kempld_read16(pld, KEMPLD_VERSION); | ||
56 | spec = kempld_read8(pld, KEMPLD_SPEC); | ||
57 | pld->info.buildnr = kempld_read16(pld, KEMPLD_BUILDNR); | ||
58 | |||
59 | pld->info.minor = KEMPLD_VERSION_GET_MINOR(version); | ||
60 | pld->info.major = KEMPLD_VERSION_GET_MAJOR(version); | ||
61 | pld->info.number = KEMPLD_VERSION_GET_NUMBER(version); | ||
62 | pld->info.type = KEMPLD_VERSION_GET_TYPE(version); | ||
63 | |||
64 | if (spec == 0xff) { | ||
65 | pld->info.spec_minor = 0; | ||
66 | pld->info.spec_major = 1; | ||
67 | } else { | ||
68 | pld->info.spec_minor = KEMPLD_SPEC_GET_MINOR(spec); | ||
69 | pld->info.spec_major = KEMPLD_SPEC_GET_MAJOR(spec); | ||
70 | } | ||
71 | |||
72 | if (pld->info.spec_major > 0) | ||
73 | pld->feature_mask = kempld_read16(pld, KEMPLD_FEATURE); | ||
74 | else | ||
75 | pld->feature_mask = 0; | ||
76 | |||
77 | kempld_release_mutex(pld); | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | enum kempld_cells { | ||
83 | KEMPLD_I2C = 0, | ||
84 | KEMPLD_WDT, | ||
85 | KEMPLD_GPIO, | ||
86 | KEMPLD_UART, | ||
87 | }; | ||
88 | |||
89 | static struct mfd_cell kempld_devs[] = { | ||
90 | [KEMPLD_I2C] = { | ||
91 | .name = "kempld-i2c", | ||
92 | }, | ||
93 | [KEMPLD_WDT] = { | ||
94 | .name = "kempld-wdt", | ||
95 | }, | ||
96 | [KEMPLD_GPIO] = { | ||
97 | .name = "kempld-gpio", | ||
98 | }, | ||
99 | [KEMPLD_UART] = { | ||
100 | .name = "kempld-uart", | ||
101 | }, | ||
102 | }; | ||
103 | |||
104 | #define KEMPLD_MAX_DEVS ARRAY_SIZE(kempld_devs) | ||
105 | |||
106 | static int kempld_register_cells_generic(struct kempld_device_data *pld) | ||
107 | { | ||
108 | struct mfd_cell devs[KEMPLD_MAX_DEVS]; | ||
109 | int i = 0; | ||
110 | |||
111 | if (pld->feature_mask & KEMPLD_FEATURE_BIT_I2C) | ||
112 | devs[i++] = kempld_devs[KEMPLD_I2C]; | ||
113 | |||
114 | if (pld->feature_mask & KEMPLD_FEATURE_BIT_WATCHDOG) | ||
115 | devs[i++] = kempld_devs[KEMPLD_WDT]; | ||
116 | |||
117 | if (pld->feature_mask & KEMPLD_FEATURE_BIT_GPIO) | ||
118 | devs[i++] = kempld_devs[KEMPLD_GPIO]; | ||
119 | |||
120 | if (pld->feature_mask & KEMPLD_FEATURE_MASK_UART) | ||
121 | devs[i++] = kempld_devs[KEMPLD_UART]; | ||
122 | |||
123 | return mfd_add_devices(pld->dev, -1, devs, i, NULL, 0, NULL); | ||
124 | } | ||
125 | |||
126 | static struct resource kempld_ioresource = { | ||
127 | .start = KEMPLD_IOINDEX, | ||
128 | .end = KEMPLD_IODATA, | ||
129 | .flags = IORESOURCE_IO, | ||
130 | }; | ||
131 | |||
132 | static const struct kempld_platform_data kempld_platform_data_generic = { | ||
133 | .pld_clock = KEMPLD_CLK, | ||
134 | .ioresource = &kempld_ioresource, | ||
135 | .get_hardware_mutex = kempld_get_hardware_mutex, | ||
136 | .release_hardware_mutex = kempld_release_hardware_mutex, | ||
137 | .get_info = kempld_get_info_generic, | ||
138 | .register_cells = kempld_register_cells_generic, | ||
139 | }; | ||
140 | |||
141 | static struct platform_device *kempld_pdev; | ||
142 | |||
143 | static int kempld_create_platform_device(const struct dmi_system_id *id) | ||
144 | { | ||
145 | struct kempld_platform_data *pdata = id->driver_data; | ||
146 | int ret; | ||
147 | |||
148 | kempld_pdev = platform_device_alloc("kempld", -1); | ||
149 | if (!kempld_pdev) | ||
150 | return -ENOMEM; | ||
151 | |||
152 | ret = platform_device_add_data(kempld_pdev, pdata, sizeof(*pdata)); | ||
153 | if (ret) | ||
154 | goto err; | ||
155 | |||
156 | ret = platform_device_add_resources(kempld_pdev, pdata->ioresource, 1); | ||
157 | if (ret) | ||
158 | goto err; | ||
159 | |||
160 | ret = platform_device_add(kempld_pdev); | ||
161 | if (ret) | ||
162 | goto err; | ||
163 | |||
164 | return 0; | ||
165 | err: | ||
166 | platform_device_put(kempld_pdev); | ||
167 | return ret; | ||
168 | } | ||
169 | |||
170 | /** | ||
171 | * kempld_read8 - read 8 bit register | ||
172 | * @pld: kempld_device_data structure describing the PLD | ||
173 | * @index: register index on the chip | ||
174 | * | ||
175 | * kempld_get_mutex must be called prior to calling this function. | ||
176 | */ | ||
177 | u8 kempld_read8(struct kempld_device_data *pld, u8 index) | ||
178 | { | ||
179 | iowrite8(index, pld->io_index); | ||
180 | return ioread8(pld->io_data); | ||
181 | } | ||
182 | EXPORT_SYMBOL_GPL(kempld_read8); | ||
183 | |||
184 | /** | ||
185 | * kempld_write8 - write 8 bit register | ||
186 | * @pld: kempld_device_data structure describing the PLD | ||
187 | * @index: register index on the chip | ||
188 | * @data: new register value | ||
189 | * | ||
190 | * kempld_get_mutex must be called prior to calling this function. | ||
191 | */ | ||
192 | void kempld_write8(struct kempld_device_data *pld, u8 index, u8 data) | ||
193 | { | ||
194 | iowrite8(index, pld->io_index); | ||
195 | iowrite8(data, pld->io_data); | ||
196 | } | ||
197 | EXPORT_SYMBOL_GPL(kempld_write8); | ||
198 | |||
199 | /** | ||
200 | * kempld_read16 - read 16 bit register | ||
201 | * @pld: kempld_device_data structure describing the PLD | ||
202 | * @index: register index on the chip | ||
203 | * | ||
204 | * kempld_get_mutex must be called prior to calling this function. | ||
205 | */ | ||
206 | u16 kempld_read16(struct kempld_device_data *pld, u8 index) | ||
207 | { | ||
208 | return kempld_read8(pld, index) | kempld_read8(pld, index + 1) << 8; | ||
209 | } | ||
210 | EXPORT_SYMBOL_GPL(kempld_read16); | ||
211 | |||
212 | /** | ||
213 | * kempld_write16 - write 16 bit register | ||
214 | * @pld: kempld_device_data structure describing the PLD | ||
215 | * @index: register index on the chip | ||
216 | * @data: new register value | ||
217 | * | ||
218 | * kempld_get_mutex must be called prior to calling this function. | ||
219 | */ | ||
220 | void kempld_write16(struct kempld_device_data *pld, u8 index, u16 data) | ||
221 | { | ||
222 | kempld_write8(pld, index, (u8)data); | ||
223 | kempld_write8(pld, index + 1, (u8)(data >> 8)); | ||
224 | } | ||
225 | EXPORT_SYMBOL_GPL(kempld_write16); | ||
226 | |||
227 | /** | ||
228 | * kempld_read32 - read 32 bit register | ||
229 | * @pld: kempld_device_data structure describing the PLD | ||
230 | * @index: register index on the chip | ||
231 | * | ||
232 | * kempld_get_mutex must be called prior to calling this function. | ||
233 | */ | ||
234 | u32 kempld_read32(struct kempld_device_data *pld, u8 index) | ||
235 | { | ||
236 | return kempld_read16(pld, index) | kempld_read16(pld, index + 2) << 16; | ||
237 | } | ||
238 | EXPORT_SYMBOL_GPL(kempld_read32); | ||
239 | |||
240 | /** | ||
241 | * kempld_write32 - write 32 bit register | ||
242 | * @pld: kempld_device_data structure describing the PLD | ||
243 | * @index: register index on the chip | ||
244 | * @data: new register value | ||
245 | * | ||
246 | * kempld_get_mutex must be called prior to calling this function. | ||
247 | */ | ||
248 | void kempld_write32(struct kempld_device_data *pld, u8 index, u32 data) | ||
249 | { | ||
250 | kempld_write16(pld, index, (u16)data); | ||
251 | kempld_write16(pld, index + 2, (u16)(data >> 16)); | ||
252 | } | ||
253 | EXPORT_SYMBOL_GPL(kempld_write32); | ||
254 | |||
255 | /** | ||
256 | * kempld_get_mutex - acquire PLD mutex | ||
257 | * @pld: kempld_device_data structure describing the PLD | ||
258 | */ | ||
259 | void kempld_get_mutex(struct kempld_device_data *pld) | ||
260 | { | ||
261 | struct kempld_platform_data *pdata = pld->dev->platform_data; | ||
262 | |||
263 | mutex_lock(&pld->lock); | ||
264 | pdata->get_hardware_mutex(pld); | ||
265 | } | ||
266 | EXPORT_SYMBOL_GPL(kempld_get_mutex); | ||
267 | |||
268 | /** | ||
269 | * kempld_release_mutex - release PLD mutex | ||
270 | * @pld: kempld_device_data structure describing the PLD | ||
271 | */ | ||
272 | void kempld_release_mutex(struct kempld_device_data *pld) | ||
273 | { | ||
274 | struct kempld_platform_data *pdata = pld->dev->platform_data; | ||
275 | |||
276 | pdata->release_hardware_mutex(pld); | ||
277 | mutex_unlock(&pld->lock); | ||
278 | } | ||
279 | EXPORT_SYMBOL_GPL(kempld_release_mutex); | ||
280 | |||
281 | /** | ||
282 | * kempld_get_info - update device specific information | ||
283 | * @pld: kempld_device_data structure describing the PLD | ||
284 | * | ||
285 | * This function calls the configured board specific kempld_get_info_XXXX | ||
286 | * function which is responsible for gathering information about the specific | ||
287 | * hardware. The information is then stored within the pld structure. | ||
288 | */ | ||
289 | static int kempld_get_info(struct kempld_device_data *pld) | ||
290 | { | ||
291 | struct kempld_platform_data *pdata = pld->dev->platform_data; | ||
292 | |||
293 | return pdata->get_info(pld); | ||
294 | } | ||
295 | |||
296 | /* | ||
297 | * kempld_register_cells - register cell drivers | ||
298 | * | ||
299 | * This function registers cell drivers for the detected hardware by calling | ||
300 | * the configured kempld_register_cells_XXXX function which is responsible | ||
301 | * to detect and register the needed cell drivers. | ||
302 | */ | ||
303 | static int kempld_register_cells(struct kempld_device_data *pld) | ||
304 | { | ||
305 | struct kempld_platform_data *pdata = pld->dev->platform_data; | ||
306 | |||
307 | return pdata->register_cells(pld); | ||
308 | } | ||
309 | |||
310 | static int kempld_detect_device(struct kempld_device_data *pld) | ||
311 | { | ||
312 | char *version_type; | ||
313 | u8 index_reg; | ||
314 | int ret; | ||
315 | |||
316 | mutex_lock(&pld->lock); | ||
317 | |||
318 | /* Check for empty IO space */ | ||
319 | index_reg = ioread8(pld->io_index); | ||
320 | if (index_reg == 0xff && ioread8(pld->io_data) == 0xff) { | ||
321 | mutex_unlock(&pld->lock); | ||
322 | return -ENODEV; | ||
323 | } | ||
324 | |||
325 | /* Release hardware mutex if aquired */ | ||
326 | if (!(index_reg & KEMPLD_MUTEX_KEY)) | ||
327 | iowrite8(KEMPLD_MUTEX_KEY, pld->io_index); | ||
328 | |||
329 | mutex_unlock(&pld->lock); | ||
330 | |||
331 | ret = kempld_get_info(pld); | ||
332 | if (ret) | ||
333 | return ret; | ||
334 | |||
335 | switch (pld->info.type) { | ||
336 | case 0: | ||
337 | version_type = "release"; | ||
338 | break; | ||
339 | case 1: | ||
340 | version_type = "debug"; | ||
341 | break; | ||
342 | case 2: | ||
343 | version_type = "custom"; | ||
344 | break; | ||
345 | default: | ||
346 | version_type = "unspecified"; | ||
347 | } | ||
348 | |||
349 | dev_info(pld->dev, "Found Kontron PLD %d\n", pld->info.number); | ||
350 | dev_info(pld->dev, "%s version %d.%d build %d, specification %d.%d\n", | ||
351 | version_type, pld->info.major, pld->info.minor, | ||
352 | pld->info.buildnr, pld->info.spec_major, | ||
353 | pld->info.spec_minor); | ||
354 | |||
355 | return kempld_register_cells(pld); | ||
356 | } | ||
357 | |||
358 | static int kempld_probe(struct platform_device *pdev) | ||
359 | { | ||
360 | struct kempld_platform_data *pdata = pdev->dev.platform_data; | ||
361 | struct device *dev = &pdev->dev; | ||
362 | struct kempld_device_data *pld; | ||
363 | struct resource *ioport; | ||
364 | int ret; | ||
365 | |||
366 | pld = devm_kzalloc(dev, sizeof(*pld), GFP_KERNEL); | ||
367 | if (!pld) | ||
368 | return -ENOMEM; | ||
369 | |||
370 | ioport = platform_get_resource(pdev, IORESOURCE_IO, 0); | ||
371 | if (!ioport) | ||
372 | return -EINVAL; | ||
373 | |||
374 | pld->io_base = devm_ioport_map(dev, ioport->start, | ||
375 | ioport->end - ioport->start); | ||
376 | if (!pld->io_base) | ||
377 | return -ENOMEM; | ||
378 | |||
379 | pld->io_index = pld->io_base; | ||
380 | pld->io_data = pld->io_base + 1; | ||
381 | pld->pld_clock = pdata->pld_clock; | ||
382 | pld->dev = dev; | ||
383 | |||
384 | mutex_init(&pld->lock); | ||
385 | platform_set_drvdata(pdev, pld); | ||
386 | |||
387 | ret = kempld_detect_device(pld); | ||
388 | if (ret) | ||
389 | return ret; | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int kempld_remove(struct platform_device *pdev) | ||
395 | { | ||
396 | struct kempld_device_data *pld = platform_get_drvdata(pdev); | ||
397 | struct kempld_platform_data *pdata = pld->dev->platform_data; | ||
398 | |||
399 | mfd_remove_devices(&pdev->dev); | ||
400 | pdata->release_hardware_mutex(pld); | ||
401 | |||
402 | return 0; | ||
403 | } | ||
404 | |||
405 | static struct platform_driver kempld_driver = { | ||
406 | .driver = { | ||
407 | .name = "kempld", | ||
408 | .owner = THIS_MODULE, | ||
409 | }, | ||
410 | .probe = kempld_probe, | ||
411 | .remove = kempld_remove, | ||
412 | }; | ||
413 | |||
414 | static struct dmi_system_id __initdata kempld_dmi_table[] = { | ||
415 | { | ||
416 | .ident = "CCR2", | ||
417 | .matches = { | ||
418 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
419 | DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP2"), | ||
420 | }, | ||
421 | .driver_data = (void *)&kempld_platform_data_generic, | ||
422 | .callback = kempld_create_platform_device, | ||
423 | }, { | ||
424 | .ident = "CCR6", | ||
425 | .matches = { | ||
426 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
427 | DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP6"), | ||
428 | }, | ||
429 | .driver_data = (void *)&kempld_platform_data_generic, | ||
430 | .callback = kempld_create_platform_device, | ||
431 | }, { | ||
432 | .ident = "CHR2", | ||
433 | .matches = { | ||
434 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
435 | DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T2"), | ||
436 | }, | ||
437 | .driver_data = (void *)&kempld_platform_data_generic, | ||
438 | .callback = kempld_create_platform_device, | ||
439 | }, { | ||
440 | .ident = "CHR2", | ||
441 | .matches = { | ||
442 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
443 | DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T2"), | ||
444 | }, | ||
445 | .driver_data = (void *)&kempld_platform_data_generic, | ||
446 | .callback = kempld_create_platform_device, | ||
447 | }, { | ||
448 | .ident = "CHR2", | ||
449 | .matches = { | ||
450 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
451 | DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC2"), | ||
452 | }, | ||
453 | .driver_data = (void *)&kempld_platform_data_generic, | ||
454 | .callback = kempld_create_platform_device, | ||
455 | }, { | ||
456 | .ident = "CHR6", | ||
457 | .matches = { | ||
458 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
459 | DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T6"), | ||
460 | }, | ||
461 | .driver_data = (void *)&kempld_platform_data_generic, | ||
462 | .callback = kempld_create_platform_device, | ||
463 | }, { | ||
464 | .ident = "CHR6", | ||
465 | .matches = { | ||
466 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
467 | DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T6"), | ||
468 | }, | ||
469 | .driver_data = (void *)&kempld_platform_data_generic, | ||
470 | .callback = kempld_create_platform_device, | ||
471 | }, { | ||
472 | .ident = "CHR6", | ||
473 | .matches = { | ||
474 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
475 | DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC6"), | ||
476 | }, | ||
477 | .driver_data = (void *)&kempld_platform_data_generic, | ||
478 | .callback = kempld_create_platform_device, | ||
479 | }, { | ||
480 | .ident = "CNTG", | ||
481 | .matches = { | ||
482 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
483 | DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-PC"), | ||
484 | }, | ||
485 | .driver_data = (void *)&kempld_platform_data_generic, | ||
486 | .callback = kempld_create_platform_device, | ||
487 | }, { | ||
488 | .ident = "CNTG", | ||
489 | .matches = { | ||
490 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
491 | DMI_MATCH(DMI_BOARD_NAME, "COMe-bPC2"), | ||
492 | }, | ||
493 | .driver_data = (void *)&kempld_platform_data_generic, | ||
494 | .callback = kempld_create_platform_device, | ||
495 | }, { | ||
496 | .ident = "CNTX", | ||
497 | .matches = { | ||
498 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
499 | DMI_MATCH(DMI_BOARD_NAME, "PXT"), | ||
500 | }, | ||
501 | .driver_data = (void *)&kempld_platform_data_generic, | ||
502 | .callback = kempld_create_platform_device, | ||
503 | }, { | ||
504 | .ident = "FRI2", | ||
505 | .matches = { | ||
506 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
507 | DMI_MATCH(DMI_BIOS_VERSION, "FRI2"), | ||
508 | }, | ||
509 | .driver_data = (void *)&kempld_platform_data_generic, | ||
510 | .callback = kempld_create_platform_device, | ||
511 | }, { | ||
512 | .ident = "FRI2", | ||
513 | .matches = { | ||
514 | DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II"), | ||
515 | }, | ||
516 | .driver_data = (void *)&kempld_platform_data_generic, | ||
517 | .callback = kempld_create_platform_device, | ||
518 | }, { | ||
519 | .ident = "MBR1", | ||
520 | .matches = { | ||
521 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
522 | DMI_MATCH(DMI_BOARD_NAME, "ETX-OH"), | ||
523 | }, | ||
524 | .driver_data = (void *)&kempld_platform_data_generic, | ||
525 | .callback = kempld_create_platform_device, | ||
526 | }, { | ||
527 | .ident = "NTC1", | ||
528 | .matches = { | ||
529 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
530 | DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT"), | ||
531 | }, | ||
532 | .driver_data = (void *)&kempld_platform_data_generic, | ||
533 | .callback = kempld_create_platform_device, | ||
534 | }, { | ||
535 | .ident = "NTC1", | ||
536 | .matches = { | ||
537 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
538 | DMI_MATCH(DMI_BOARD_NAME, "nETXe-TT"), | ||
539 | }, | ||
540 | .driver_data = (void *)&kempld_platform_data_generic, | ||
541 | .callback = kempld_create_platform_device, | ||
542 | }, { | ||
543 | .ident = "NTC1", | ||
544 | .matches = { | ||
545 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
546 | DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT"), | ||
547 | }, | ||
548 | .driver_data = (void *)&kempld_platform_data_generic, | ||
549 | .callback = kempld_create_platform_device, | ||
550 | }, { | ||
551 | .ident = "NUP1", | ||
552 | .matches = { | ||
553 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
554 | DMI_MATCH(DMI_BOARD_NAME, "COMe-mCT"), | ||
555 | }, | ||
556 | .driver_data = (void *)&kempld_platform_data_generic, | ||
557 | .callback = kempld_create_platform_device, | ||
558 | }, { | ||
559 | .ident = "UNP1", | ||
560 | .matches = { | ||
561 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
562 | DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-DC"), | ||
563 | }, | ||
564 | .driver_data = (void *)&kempld_platform_data_generic, | ||
565 | .callback = kempld_create_platform_device, | ||
566 | }, { | ||
567 | .ident = "UNP1", | ||
568 | .matches = { | ||
569 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
570 | DMI_MATCH(DMI_BOARD_NAME, "COMe-cDC2"), | ||
571 | }, | ||
572 | .driver_data = (void *)&kempld_platform_data_generic, | ||
573 | .callback = kempld_create_platform_device, | ||
574 | }, { | ||
575 | .ident = "UNTG", | ||
576 | .matches = { | ||
577 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
578 | DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-PC"), | ||
579 | }, | ||
580 | .driver_data = (void *)&kempld_platform_data_generic, | ||
581 | .callback = kempld_create_platform_device, | ||
582 | }, { | ||
583 | .ident = "UNTG", | ||
584 | .matches = { | ||
585 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
586 | DMI_MATCH(DMI_BOARD_NAME, "COMe-cPC2"), | ||
587 | }, | ||
588 | .driver_data = (void *)&kempld_platform_data_generic, | ||
589 | .callback = kempld_create_platform_device, | ||
590 | }, { | ||
591 | .ident = "UUP6", | ||
592 | .matches = { | ||
593 | DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"), | ||
594 | DMI_MATCH(DMI_BOARD_NAME, "COMe-cCT6"), | ||
595 | }, | ||
596 | .driver_data = (void *)&kempld_platform_data_generic, | ||
597 | .callback = kempld_create_platform_device, | ||
598 | }, | ||
599 | {} | ||
600 | }; | ||
601 | MODULE_DEVICE_TABLE(dmi, kempld_dmi_table); | ||
602 | |||
603 | static int __init kempld_init(void) | ||
604 | { | ||
605 | const struct dmi_system_id *id; | ||
606 | int ret; | ||
607 | |||
608 | if (force_device_id[0]) { | ||
609 | for (id = kempld_dmi_table; id->matches[0].slot != DMI_NONE; id++) | ||
610 | if (strstr(id->ident, force_device_id)) | ||
611 | if (id->callback && id->callback(id)) | ||
612 | break; | ||
613 | if (id->matches[0].slot == DMI_NONE) | ||
614 | return -ENODEV; | ||
615 | } else { | ||
616 | if (!dmi_check_system(kempld_dmi_table)) | ||
617 | return -ENODEV; | ||
618 | } | ||
619 | |||
620 | ret = platform_driver_register(&kempld_driver); | ||
621 | if (ret) | ||
622 | return ret; | ||
623 | |||
624 | return 0; | ||
625 | } | ||
626 | |||
627 | static void __exit kempld_exit(void) | ||
628 | { | ||
629 | if (kempld_pdev) | ||
630 | platform_device_unregister(kempld_pdev); | ||
631 | |||
632 | platform_driver_unregister(&kempld_driver); | ||
633 | } | ||
634 | |||
635 | module_init(kempld_init); | ||
636 | module_exit(kempld_exit); | ||
637 | |||
638 | MODULE_DESCRIPTION("KEM PLD Core Driver"); | ||
639 | MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>"); | ||
640 | MODULE_LICENSE("GPL"); | ||
641 | MODULE_ALIAS("platform:kempld-core"); | ||