aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mfd
diff options
context:
space:
mode:
authorKevin Strasser <kevin.strasser@linux.intel.com>2013-06-24 00:00:03 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2013-06-24 07:48:22 -0400
commit43620a17945b598e707ef897b3866914f9f9056c (patch)
tree67a26eb8bc13e4a2ca0d393b15051eff747cf9ef /drivers/mfd
parent4124e6e291a7b1a21ea7c28c8f9899d050103308 (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')
-rw-r--r--drivers/mfd/Kconfig21
-rw-r--r--drivers/mfd/Makefile1
-rw-r--r--drivers/mfd/kempld-core.c641
3 files changed, 663 insertions, 0 deletions
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 3e3be603cf82..3bb2932eafb1 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -242,6 +242,27 @@ config MFD_JZ4740_ADC
242 Say yes here if you want support for the ADC unit in the JZ4740 SoC. 242 Say yes here if you want support for the ADC unit in the JZ4740 SoC.
243 This driver is necessary for jz4740-battery and jz4740-hwmon driver. 243 This driver is necessary for jz4740-battery and jz4740-hwmon driver.
244 244
245config MFD_KEMPLD
246 tristate "Kontron module PLD device"
247 select MFD_CORE
248 help
249 This is the core driver for the PLD (Programmable Logic Device) found
250 on some Kontron ETX and COMexpress (ETXexpress) modules. The PLD
251 device may provide functions like watchdog, GPIO, UART and I2C bus.
252
253 The following modules are supported:
254 * COMe-bIP#
255 * COMe-bPC2 (ETXexpress-PC)
256 * COMe-bSC# (ETXexpress-SC T#)
257 * COMe-cCT6
258 * COMe-cDC2 (microETXexpress-DC)
259 * COMe-cPC2 (microETXexpress-PC)
260 * COMe-mCT10
261 * ETX-OH
262
263 This driver can also be built as a module. If so, the module
264 will be called kempld-core.
265
245config MFD_88PM800 266config MFD_88PM800
246 tristate "Marvell 88PM800" 267 tristate "Marvell 88PM800"
247 depends on I2C=y && GENERIC_HARDIRQS 268 depends on I2C=y && GENERIC_HARDIRQS
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 4d70cdb044e0..3c90051ffa5a 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -129,6 +129,7 @@ obj-$(CONFIG_MFD_DB8500_PRCMU) += db8500-prcmu.o
129obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o 129obj-$(CONFIG_AB8500_CORE) += ab8500-core.o ab8500-sysctrl.o
130obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o 130obj-$(CONFIG_MFD_TIMBERDALE) += timberdale.o
131obj-$(CONFIG_PMIC_ADP5520) += adp5520.o 131obj-$(CONFIG_PMIC_ADP5520) += adp5520.o
132obj-$(CONFIG_MFD_KEMPLD) += kempld-core.o
132obj-$(CONFIG_LPC_SCH) += lpc_sch.o 133obj-$(CONFIG_LPC_SCH) += lpc_sch.o
133obj-$(CONFIG_LPC_ICH) += lpc_ich.o 134obj-$(CONFIG_LPC_ICH) += lpc_ich.o
134obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o 135obj-$(CONFIG_MFD_RDC321X) += rdc321x-southbridge.o
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
26static char force_device_id[MAX_ID_LEN + 1] = "";
27module_param_string(force_device_id, force_device_id, sizeof(force_device_id), 0);
28MODULE_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 */
35static 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
42static 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
48static 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
82enum kempld_cells {
83 KEMPLD_I2C = 0,
84 KEMPLD_WDT,
85 KEMPLD_GPIO,
86 KEMPLD_UART,
87};
88
89static 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
106static 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
126static struct resource kempld_ioresource = {
127 .start = KEMPLD_IOINDEX,
128 .end = KEMPLD_IODATA,
129 .flags = IORESOURCE_IO,
130};
131
132static 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
141static struct platform_device *kempld_pdev;
142
143static 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;
165err:
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 */
177u8 kempld_read8(struct kempld_device_data *pld, u8 index)
178{
179 iowrite8(index, pld->io_index);
180 return ioread8(pld->io_data);
181}
182EXPORT_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 */
192void 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}
197EXPORT_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 */
206u16 kempld_read16(struct kempld_device_data *pld, u8 index)
207{
208 return kempld_read8(pld, index) | kempld_read8(pld, index + 1) << 8;
209}
210EXPORT_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 */
220void 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}
225EXPORT_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 */
234u32 kempld_read32(struct kempld_device_data *pld, u8 index)
235{
236 return kempld_read16(pld, index) | kempld_read16(pld, index + 2) << 16;
237}
238EXPORT_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 */
248void 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}
253EXPORT_SYMBOL_GPL(kempld_write32);
254
255/**
256 * kempld_get_mutex - acquire PLD mutex
257 * @pld: kempld_device_data structure describing the PLD
258 */
259void 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}
266EXPORT_SYMBOL_GPL(kempld_get_mutex);
267
268/**
269 * kempld_release_mutex - release PLD mutex
270 * @pld: kempld_device_data structure describing the PLD
271 */
272void 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}
279EXPORT_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 */
289static 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 */
303static 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
310static 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
358static 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
394static 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
405static 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
414static 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};
601MODULE_DEVICE_TABLE(dmi, kempld_dmi_table);
602
603static 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
627static 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
635module_init(kempld_init);
636module_exit(kempld_exit);
637
638MODULE_DESCRIPTION("KEM PLD Core Driver");
639MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
640MODULE_LICENSE("GPL");
641MODULE_ALIAS("platform:kempld-core");