blob: f7ff0188603deac34e0c872d642efd4a775e1549 [file] [log] [blame]
Kevin Strasser43620a12013-06-23 21:00:03 -07001/*
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
Krzysztof Kozlowskibd6d35a62014-05-13 12:58:42 +020089static const struct mfd_cell kempld_devs[] = {
Kevin Strasser43620a12013-06-23 21:00:03 -070090 [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{
Jingoo Han334a41c2013-07-30 17:10:05 +0900261 struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
Kevin Strasser43620a12013-06-23 21:00:03 -0700262
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{
Jingoo Han334a41c2013-07-30 17:10:05 +0900274 struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
Kevin Strasser43620a12013-06-23 21:00:03 -0700275
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{
Michael Brunner58a9e5b2014-04-08 08:21:06 +0200291 int ret;
Jingoo Han334a41c2013-07-30 17:10:05 +0900292 struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
Michael Brunner58a9e5b2014-04-08 08:21:06 +0200293 char major, minor;
Kevin Strasser43620a12013-06-23 21:00:03 -0700294
Michael Brunner58a9e5b2014-04-08 08:21:06 +0200295 ret = pdata->get_info(pld);
296 if (ret)
297 return ret;
298
299 /* The Kontron PLD firmware version string has the following format:
300 * Pwxy.zzzz
301 * P: Fixed
302 * w: PLD number - 1 hex digit
303 * x: Major version - 1 alphanumerical digit (0-9A-V)
304 * y: Minor version - 1 alphanumerical digit (0-9A-V)
305 * zzzz: Build number - 4 zero padded hex digits */
306
307 if (pld->info.major < 10)
308 major = pld->info.major + '0';
309 else
310 major = (pld->info.major - 10) + 'A';
311 if (pld->info.minor < 10)
312 minor = pld->info.minor + '0';
313 else
314 minor = (pld->info.minor - 10) + 'A';
315
316 ret = scnprintf(pld->info.version, sizeof(pld->info.version),
317 "P%X%c%c.%04X", pld->info.number, major, minor,
318 pld->info.buildnr);
319 if (ret < 0)
320 return ret;
321
322 return 0;
Kevin Strasser43620a12013-06-23 21:00:03 -0700323}
324
325/*
326 * kempld_register_cells - register cell drivers
327 *
328 * This function registers cell drivers for the detected hardware by calling
329 * the configured kempld_register_cells_XXXX function which is responsible
330 * to detect and register the needed cell drivers.
331 */
332static int kempld_register_cells(struct kempld_device_data *pld)
333{
Jingoo Han334a41c2013-07-30 17:10:05 +0900334 struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
Kevin Strasser43620a12013-06-23 21:00:03 -0700335
336 return pdata->register_cells(pld);
337}
338
Michael Brunner58a9e5b2014-04-08 08:21:06 +0200339static const char *kempld_get_type_string(struct kempld_device_data *pld)
340{
341 const char *version_type;
342
343 switch (pld->info.type) {
344 case 0:
345 version_type = "release";
346 break;
347 case 1:
348 version_type = "debug";
349 break;
350 case 2:
351 version_type = "custom";
352 break;
353 default:
354 version_type = "unspecified";
355 break;
356 }
357
358 return version_type;
359}
360
361static ssize_t kempld_version_show(struct device *dev,
362 struct device_attribute *attr, char *buf)
363{
364 struct kempld_device_data *pld = dev_get_drvdata(dev);
365
366 return scnprintf(buf, PAGE_SIZE, "%s\n", pld->info.version);
367}
368
369static ssize_t kempld_specification_show(struct device *dev,
370 struct device_attribute *attr, char *buf)
371{
372 struct kempld_device_data *pld = dev_get_drvdata(dev);
373
374 return scnprintf(buf, PAGE_SIZE, "%d.%d\n", pld->info.spec_major,
375 pld->info.spec_minor);
376}
377
378static ssize_t kempld_type_show(struct device *dev,
379 struct device_attribute *attr, char *buf)
380{
381 struct kempld_device_data *pld = dev_get_drvdata(dev);
382
383 return scnprintf(buf, PAGE_SIZE, "%s\n", kempld_get_type_string(pld));
384}
385
386static DEVICE_ATTR(pld_version, S_IRUGO, kempld_version_show, NULL);
387static DEVICE_ATTR(pld_specification, S_IRUGO, kempld_specification_show,
388 NULL);
389static DEVICE_ATTR(pld_type, S_IRUGO, kempld_type_show, NULL);
390
391static struct attribute *pld_attributes[] = {
392 &dev_attr_pld_version.attr,
393 &dev_attr_pld_specification.attr,
394 &dev_attr_pld_type.attr,
395 NULL
396};
397
398static const struct attribute_group pld_attr_group = {
399 .attrs = pld_attributes,
400};
401
Kevin Strasser43620a12013-06-23 21:00:03 -0700402static int kempld_detect_device(struct kempld_device_data *pld)
403{
Kevin Strasser43620a12013-06-23 21:00:03 -0700404 u8 index_reg;
405 int ret;
406
407 mutex_lock(&pld->lock);
408
409 /* Check for empty IO space */
410 index_reg = ioread8(pld->io_index);
411 if (index_reg == 0xff && ioread8(pld->io_data) == 0xff) {
412 mutex_unlock(&pld->lock);
413 return -ENODEV;
414 }
415
Guenter Roeck204747c2014-03-20 08:12:28 -0700416 /* Release hardware mutex if acquired */
417 if (!(index_reg & KEMPLD_MUTEX_KEY)) {
Kevin Strasser43620a12013-06-23 21:00:03 -0700418 iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
Guenter Roeck204747c2014-03-20 08:12:28 -0700419 /* PXT and COMe-cPC2 boards may require a second release */
420 iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
421 }
Kevin Strasser43620a12013-06-23 21:00:03 -0700422
423 mutex_unlock(&pld->lock);
424
425 ret = kempld_get_info(pld);
426 if (ret)
427 return ret;
428
Michael Brunner58a9e5b2014-04-08 08:21:06 +0200429 dev_info(pld->dev, "Found Kontron PLD - %s (%s), spec %d.%d\n",
430 pld->info.version, kempld_get_type_string(pld),
431 pld->info.spec_major, pld->info.spec_minor);
Kevin Strasser43620a12013-06-23 21:00:03 -0700432
Michael Brunner58a9e5b2014-04-08 08:21:06 +0200433 ret = sysfs_create_group(&pld->dev->kobj, &pld_attr_group);
434 if (ret)
435 return ret;
Kevin Strasser43620a12013-06-23 21:00:03 -0700436
Michael Brunner58a9e5b2014-04-08 08:21:06 +0200437 ret = kempld_register_cells(pld);
438 if (ret)
439 sysfs_remove_group(&pld->dev->kobj, &pld_attr_group);
440
441 return ret;
Kevin Strasser43620a12013-06-23 21:00:03 -0700442}
443
444static int kempld_probe(struct platform_device *pdev)
445{
Jingoo Han334a41c2013-07-30 17:10:05 +0900446 struct kempld_platform_data *pdata = dev_get_platdata(&pdev->dev);
Kevin Strasser43620a12013-06-23 21:00:03 -0700447 struct device *dev = &pdev->dev;
448 struct kempld_device_data *pld;
449 struct resource *ioport;
450 int ret;
451
452 pld = devm_kzalloc(dev, sizeof(*pld), GFP_KERNEL);
453 if (!pld)
454 return -ENOMEM;
455
456 ioport = platform_get_resource(pdev, IORESOURCE_IO, 0);
457 if (!ioport)
458 return -EINVAL;
459
460 pld->io_base = devm_ioport_map(dev, ioport->start,
461 ioport->end - ioport->start);
462 if (!pld->io_base)
463 return -ENOMEM;
464
465 pld->io_index = pld->io_base;
466 pld->io_data = pld->io_base + 1;
467 pld->pld_clock = pdata->pld_clock;
468 pld->dev = dev;
469
470 mutex_init(&pld->lock);
471 platform_set_drvdata(pdev, pld);
472
473 ret = kempld_detect_device(pld);
474 if (ret)
475 return ret;
476
477 return 0;
478}
479
480static int kempld_remove(struct platform_device *pdev)
481{
482 struct kempld_device_data *pld = platform_get_drvdata(pdev);
Jingoo Han334a41c2013-07-30 17:10:05 +0900483 struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
Kevin Strasser43620a12013-06-23 21:00:03 -0700484
Michael Brunner58a9e5b2014-04-08 08:21:06 +0200485 sysfs_remove_group(&pld->dev->kobj, &pld_attr_group);
486
Kevin Strasser43620a12013-06-23 21:00:03 -0700487 mfd_remove_devices(&pdev->dev);
488 pdata->release_hardware_mutex(pld);
489
490 return 0;
491}
492
493static struct platform_driver kempld_driver = {
494 .driver = {
495 .name = "kempld",
496 .owner = THIS_MODULE,
497 },
498 .probe = kempld_probe,
499 .remove = kempld_remove,
500};
501
502static struct dmi_system_id __initdata kempld_dmi_table[] = {
503 {
Michael Brunnerc1d33b12013-08-09 17:33:43 +0200504 .ident = "BHL6",
505 .matches = {
506 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
507 DMI_MATCH(DMI_BOARD_NAME, "COMe-bHL6"),
508 },
509 .driver_data = (void *)&kempld_platform_data_generic,
510 .callback = kempld_create_platform_device,
511 },
512 {
Kevin Strasser43620a12013-06-23 21:00:03 -0700513 .ident = "CCR2",
514 .matches = {
515 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
516 DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP2"),
517 },
518 .driver_data = (void *)&kempld_platform_data_generic,
519 .callback = kempld_create_platform_device,
520 }, {
521 .ident = "CCR6",
522 .matches = {
523 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
524 DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP6"),
525 },
526 .driver_data = (void *)&kempld_platform_data_generic,
527 .callback = kempld_create_platform_device,
528 }, {
Michael Brunnera3ee7502014-02-24 08:53:46 +0100529 .ident = "CHL6",
530 .matches = {
531 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
532 DMI_MATCH(DMI_BOARD_NAME, "COMe-cHL6"),
533 },
534 .driver_data = (void *)&kempld_platform_data_generic,
535 .callback = kempld_create_platform_device,
536 }, {
Kevin Strasser43620a12013-06-23 21:00:03 -0700537 .ident = "CHR2",
538 .matches = {
539 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
540 DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T2"),
541 },
542 .driver_data = (void *)&kempld_platform_data_generic,
543 .callback = kempld_create_platform_device,
544 }, {
545 .ident = "CHR2",
546 .matches = {
547 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
548 DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T2"),
549 },
550 .driver_data = (void *)&kempld_platform_data_generic,
551 .callback = kempld_create_platform_device,
552 }, {
553 .ident = "CHR2",
554 .matches = {
555 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
556 DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC2"),
557 },
558 .driver_data = (void *)&kempld_platform_data_generic,
559 .callback = kempld_create_platform_device,
560 }, {
561 .ident = "CHR6",
562 .matches = {
563 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
564 DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T6"),
565 },
566 .driver_data = (void *)&kempld_platform_data_generic,
567 .callback = kempld_create_platform_device,
568 }, {
569 .ident = "CHR6",
570 .matches = {
571 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
572 DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T6"),
573 },
574 .driver_data = (void *)&kempld_platform_data_generic,
575 .callback = kempld_create_platform_device,
576 }, {
577 .ident = "CHR6",
578 .matches = {
579 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
580 DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC6"),
581 },
582 .driver_data = (void *)&kempld_platform_data_generic,
583 .callback = kempld_create_platform_device,
584 }, {
585 .ident = "CNTG",
586 .matches = {
587 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
588 DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-PC"),
589 },
590 .driver_data = (void *)&kempld_platform_data_generic,
591 .callback = kempld_create_platform_device,
592 }, {
593 .ident = "CNTG",
594 .matches = {
595 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
596 DMI_MATCH(DMI_BOARD_NAME, "COMe-bPC2"),
597 },
598 .driver_data = (void *)&kempld_platform_data_generic,
599 .callback = kempld_create_platform_device,
600 }, {
601 .ident = "CNTX",
602 .matches = {
603 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
604 DMI_MATCH(DMI_BOARD_NAME, "PXT"),
605 },
606 .driver_data = (void *)&kempld_platform_data_generic,
607 .callback = kempld_create_platform_device,
608 }, {
Michael Brunnera3ee7502014-02-24 08:53:46 +0100609 .ident = "CVV6",
610 .matches = {
611 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
612 DMI_MATCH(DMI_BOARD_NAME, "COMe-cBT"),
613 },
614 .driver_data = (void *)&kempld_platform_data_generic,
615 .callback = kempld_create_platform_device,
616 }, {
Kevin Strasser43620a12013-06-23 21:00:03 -0700617 .ident = "FRI2",
618 .matches = {
619 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
620 DMI_MATCH(DMI_BIOS_VERSION, "FRI2"),
621 },
622 .driver_data = (void *)&kempld_platform_data_generic,
623 .callback = kempld_create_platform_device,
624 }, {
625 .ident = "FRI2",
626 .matches = {
627 DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II"),
628 },
629 .driver_data = (void *)&kempld_platform_data_generic,
630 .callback = kempld_create_platform_device,
631 }, {
632 .ident = "MBR1",
633 .matches = {
634 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
635 DMI_MATCH(DMI_BOARD_NAME, "ETX-OH"),
636 },
637 .driver_data = (void *)&kempld_platform_data_generic,
638 .callback = kempld_create_platform_device,
639 }, {
Michael Brunnera3ee7502014-02-24 08:53:46 +0100640 .ident = "MVV1",
641 .matches = {
642 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
643 DMI_MATCH(DMI_BOARD_NAME, "COMe-mBT"),
644 },
645 .driver_data = (void *)&kempld_platform_data_generic,
646 .callback = kempld_create_platform_device,
647 }, {
Kevin Strasser43620a12013-06-23 21:00:03 -0700648 .ident = "NTC1",
649 .matches = {
650 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
651 DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT"),
652 },
653 .driver_data = (void *)&kempld_platform_data_generic,
654 .callback = kempld_create_platform_device,
655 }, {
656 .ident = "NTC1",
657 .matches = {
658 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
659 DMI_MATCH(DMI_BOARD_NAME, "nETXe-TT"),
660 },
661 .driver_data = (void *)&kempld_platform_data_generic,
662 .callback = kempld_create_platform_device,
663 }, {
664 .ident = "NTC1",
665 .matches = {
666 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
667 DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT"),
668 },
669 .driver_data = (void *)&kempld_platform_data_generic,
670 .callback = kempld_create_platform_device,
671 }, {
672 .ident = "NUP1",
673 .matches = {
674 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
675 DMI_MATCH(DMI_BOARD_NAME, "COMe-mCT"),
676 },
677 .driver_data = (void *)&kempld_platform_data_generic,
678 .callback = kempld_create_platform_device,
679 }, {
680 .ident = "UNP1",
681 .matches = {
682 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
683 DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-DC"),
684 },
685 .driver_data = (void *)&kempld_platform_data_generic,
686 .callback = kempld_create_platform_device,
687 }, {
688 .ident = "UNP1",
689 .matches = {
690 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
691 DMI_MATCH(DMI_BOARD_NAME, "COMe-cDC2"),
692 },
693 .driver_data = (void *)&kempld_platform_data_generic,
694 .callback = kempld_create_platform_device,
695 }, {
696 .ident = "UNTG",
697 .matches = {
698 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
699 DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-PC"),
700 },
701 .driver_data = (void *)&kempld_platform_data_generic,
702 .callback = kempld_create_platform_device,
703 }, {
704 .ident = "UNTG",
705 .matches = {
706 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
707 DMI_MATCH(DMI_BOARD_NAME, "COMe-cPC2"),
708 },
709 .driver_data = (void *)&kempld_platform_data_generic,
710 .callback = kempld_create_platform_device,
711 }, {
712 .ident = "UUP6",
713 .matches = {
714 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
715 DMI_MATCH(DMI_BOARD_NAME, "COMe-cCT6"),
716 },
717 .driver_data = (void *)&kempld_platform_data_generic,
718 .callback = kempld_create_platform_device,
719 },
Michael Brunnerc1d33b12013-08-09 17:33:43 +0200720 {
721 .ident = "UTH6",
722 .matches = {
723 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
724 DMI_MATCH(DMI_BOARD_NAME, "COMe-cTH6"),
725 },
726 .driver_data = (void *)&kempld_platform_data_generic,
727 .callback = kempld_create_platform_device,
728 },
Kevin Strasser43620a12013-06-23 21:00:03 -0700729 {}
730};
731MODULE_DEVICE_TABLE(dmi, kempld_dmi_table);
732
733static int __init kempld_init(void)
734{
735 const struct dmi_system_id *id;
736 int ret;
737
738 if (force_device_id[0]) {
739 for (id = kempld_dmi_table; id->matches[0].slot != DMI_NONE; id++)
740 if (strstr(id->ident, force_device_id))
741 if (id->callback && id->callback(id))
742 break;
743 if (id->matches[0].slot == DMI_NONE)
744 return -ENODEV;
745 } else {
746 if (!dmi_check_system(kempld_dmi_table))
747 return -ENODEV;
748 }
749
750 ret = platform_driver_register(&kempld_driver);
751 if (ret)
752 return ret;
753
754 return 0;
755}
756
757static void __exit kempld_exit(void)
758{
759 if (kempld_pdev)
760 platform_device_unregister(kempld_pdev);
761
762 platform_driver_unregister(&kempld_driver);
763}
764
765module_init(kempld_init);
766module_exit(kempld_exit);
767
768MODULE_DESCRIPTION("KEM PLD Core Driver");
769MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
770MODULE_LICENSE("GPL");
771MODULE_ALIAS("platform:kempld-core");