1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Kontron PLD MFD core driver
4 *
5 * Copyright (c) 2010-2013 Kontron Europe GmbH
6 * Author: Michael Brunner <michael.brunner@kontron.com>
7 */
8
9 #include <linux/err.h>
10 #include <linux/platform_device.h>
11 #include <linux/mfd/core.h>
12 #include <linux/mfd/kempld.h>
13 #include <linux/mod_devicetable.h>
14 #include <linux/module.h>
15 #include <linux/property.h>
16 #include <linux/dmi.h>
17 #include <linux/io.h>
18 #include <linux/delay.h>
19 #include <linux/sysfs.h>
20
21 #define MAX_ID_LEN 4
22 static char force_device_id[MAX_ID_LEN + 1] = "";
23 module_param_string(force_device_id, force_device_id,
24 sizeof(force_device_id), 0);
25 MODULE_PARM_DESC(force_device_id, "Override detected product");
26
27 /*
28 * Get hardware mutex to block firmware from accessing the pld.
29 * It is possible for the firmware may hold the mutex for an extended length of
30 * time. This function will block until access has been granted.
31 */
kempld_get_hardware_mutex(struct kempld_device_data * pld)32 static void kempld_get_hardware_mutex(struct kempld_device_data *pld)
33 {
34 /* The mutex bit will read 1 until access has been granted */
35 while (ioread8(pld->io_index) & KEMPLD_MUTEX_KEY)
36 usleep_range(1000, 3000);
37 }
38
kempld_release_hardware_mutex(struct kempld_device_data * pld)39 static void kempld_release_hardware_mutex(struct kempld_device_data *pld)
40 {
41 /* The harware mutex is released when 1 is written to the mutex bit. */
42 iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
43 }
44
kempld_get_info_generic(struct kempld_device_data * pld)45 static int kempld_get_info_generic(struct kempld_device_data *pld)
46 {
47 u16 version;
48 u8 spec;
49
50 kempld_get_mutex(pld);
51
52 version = kempld_read16(pld, KEMPLD_VERSION);
53 spec = kempld_read8(pld, KEMPLD_SPEC);
54 pld->info.buildnr = kempld_read16(pld, KEMPLD_BUILDNR);
55
56 pld->info.minor = KEMPLD_VERSION_GET_MINOR(version);
57 pld->info.major = KEMPLD_VERSION_GET_MAJOR(version);
58 pld->info.number = KEMPLD_VERSION_GET_NUMBER(version);
59 pld->info.type = KEMPLD_VERSION_GET_TYPE(version);
60
61 if (spec == 0xff) {
62 pld->info.spec_minor = 0;
63 pld->info.spec_major = 1;
64 } else {
65 pld->info.spec_minor = KEMPLD_SPEC_GET_MINOR(spec);
66 pld->info.spec_major = KEMPLD_SPEC_GET_MAJOR(spec);
67 }
68
69 if (pld->info.spec_major > 0)
70 pld->feature_mask = kempld_read16(pld, KEMPLD_FEATURE);
71 else
72 pld->feature_mask = 0;
73
74 kempld_release_mutex(pld);
75
76 return 0;
77 }
78
79 enum kempld_cells {
80 KEMPLD_I2C = 0,
81 KEMPLD_WDT,
82 KEMPLD_GPIO,
83 KEMPLD_UART,
84 };
85
86 static const char *kempld_dev_names[] = {
87 [KEMPLD_I2C] = "kempld-i2c",
88 [KEMPLD_WDT] = "kempld-wdt",
89 [KEMPLD_GPIO] = "kempld-gpio",
90 [KEMPLD_UART] = "kempld-uart",
91 };
92
93 #define KEMPLD_MAX_DEVS ARRAY_SIZE(kempld_dev_names)
94
kempld_register_cells_generic(struct kempld_device_data * pld)95 static int kempld_register_cells_generic(struct kempld_device_data *pld)
96 {
97 struct mfd_cell devs[KEMPLD_MAX_DEVS] = {};
98 int i = 0;
99
100 if (pld->feature_mask & KEMPLD_FEATURE_BIT_I2C)
101 devs[i++].name = kempld_dev_names[KEMPLD_I2C];
102
103 if (pld->feature_mask & KEMPLD_FEATURE_BIT_WATCHDOG)
104 devs[i++].name = kempld_dev_names[KEMPLD_WDT];
105
106 if (pld->feature_mask & KEMPLD_FEATURE_BIT_GPIO)
107 devs[i++].name = kempld_dev_names[KEMPLD_GPIO];
108
109 if (pld->feature_mask & KEMPLD_FEATURE_MASK_UART)
110 devs[i++].name = kempld_dev_names[KEMPLD_UART];
111
112 return mfd_add_devices(pld->dev, PLATFORM_DEVID_NONE, devs, i, NULL, 0, NULL);
113 }
114
115 static struct resource kempld_ioresource = {
116 .start = KEMPLD_IOINDEX,
117 .end = KEMPLD_IODATA,
118 .flags = IORESOURCE_IO,
119 };
120
121 static const struct kempld_platform_data kempld_platform_data_generic = {
122 .pld_clock = KEMPLD_CLK,
123 .ioresource = &kempld_ioresource,
124 .get_hardware_mutex = kempld_get_hardware_mutex,
125 .release_hardware_mutex = kempld_release_hardware_mutex,
126 .get_info = kempld_get_info_generic,
127 .register_cells = kempld_register_cells_generic,
128 };
129
130 static struct platform_device *kempld_pdev;
131
kempld_create_platform_device(const struct kempld_platform_data * pdata)132 static int kempld_create_platform_device(const struct kempld_platform_data *pdata)
133 {
134 const struct platform_device_info pdevinfo = {
135 .name = "kempld",
136 .id = PLATFORM_DEVID_NONE,
137 .res = pdata->ioresource,
138 .num_res = 1,
139 .data = pdata,
140 .size_data = sizeof(*pdata),
141 };
142
143 kempld_pdev = platform_device_register_full(&pdevinfo);
144 if (IS_ERR(kempld_pdev))
145 return PTR_ERR(kempld_pdev);
146
147 return 0;
148 }
149
150 /**
151 * kempld_read8 - read 8 bit register
152 * @pld: kempld_device_data structure describing the PLD
153 * @index: register index on the chip
154 *
155 * kempld_get_mutex must be called prior to calling this function.
156 */
kempld_read8(struct kempld_device_data * pld,u8 index)157 u8 kempld_read8(struct kempld_device_data *pld, u8 index)
158 {
159 iowrite8(index, pld->io_index);
160 return ioread8(pld->io_data);
161 }
162 EXPORT_SYMBOL_GPL(kempld_read8);
163
164 /**
165 * kempld_write8 - write 8 bit register
166 * @pld: kempld_device_data structure describing the PLD
167 * @index: register index on the chip
168 * @data: new register value
169 *
170 * kempld_get_mutex must be called prior to calling this function.
171 */
kempld_write8(struct kempld_device_data * pld,u8 index,u8 data)172 void kempld_write8(struct kempld_device_data *pld, u8 index, u8 data)
173 {
174 iowrite8(index, pld->io_index);
175 iowrite8(data, pld->io_data);
176 }
177 EXPORT_SYMBOL_GPL(kempld_write8);
178
179 /**
180 * kempld_read16 - read 16 bit register
181 * @pld: kempld_device_data structure describing the PLD
182 * @index: register index on the chip
183 *
184 * kempld_get_mutex must be called prior to calling this function.
185 */
kempld_read16(struct kempld_device_data * pld,u8 index)186 u16 kempld_read16(struct kempld_device_data *pld, u8 index)
187 {
188 return kempld_read8(pld, index) | kempld_read8(pld, index + 1) << 8;
189 }
190 EXPORT_SYMBOL_GPL(kempld_read16);
191
192 /**
193 * kempld_write16 - write 16 bit register
194 * @pld: kempld_device_data structure describing the PLD
195 * @index: register index on the chip
196 * @data: new register value
197 *
198 * kempld_get_mutex must be called prior to calling this function.
199 */
kempld_write16(struct kempld_device_data * pld,u8 index,u16 data)200 void kempld_write16(struct kempld_device_data *pld, u8 index, u16 data)
201 {
202 kempld_write8(pld, index, (u8)data);
203 kempld_write8(pld, index + 1, (u8)(data >> 8));
204 }
205 EXPORT_SYMBOL_GPL(kempld_write16);
206
207 /**
208 * kempld_read32 - read 32 bit register
209 * @pld: kempld_device_data structure describing the PLD
210 * @index: register index on the chip
211 *
212 * kempld_get_mutex must be called prior to calling this function.
213 */
kempld_read32(struct kempld_device_data * pld,u8 index)214 u32 kempld_read32(struct kempld_device_data *pld, u8 index)
215 {
216 return kempld_read16(pld, index) | kempld_read16(pld, index + 2) << 16;
217 }
218 EXPORT_SYMBOL_GPL(kempld_read32);
219
220 /**
221 * kempld_write32 - write 32 bit register
222 * @pld: kempld_device_data structure describing the PLD
223 * @index: register index on the chip
224 * @data: new register value
225 *
226 * kempld_get_mutex must be called prior to calling this function.
227 */
kempld_write32(struct kempld_device_data * pld,u8 index,u32 data)228 void kempld_write32(struct kempld_device_data *pld, u8 index, u32 data)
229 {
230 kempld_write16(pld, index, (u16)data);
231 kempld_write16(pld, index + 2, (u16)(data >> 16));
232 }
233 EXPORT_SYMBOL_GPL(kempld_write32);
234
235 /**
236 * kempld_get_mutex - acquire PLD mutex
237 * @pld: kempld_device_data structure describing the PLD
238 */
kempld_get_mutex(struct kempld_device_data * pld)239 void kempld_get_mutex(struct kempld_device_data *pld)
240 {
241 const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
242
243 mutex_lock(&pld->lock);
244 pdata->get_hardware_mutex(pld);
245 }
246 EXPORT_SYMBOL_GPL(kempld_get_mutex);
247
248 /**
249 * kempld_release_mutex - release PLD mutex
250 * @pld: kempld_device_data structure describing the PLD
251 */
kempld_release_mutex(struct kempld_device_data * pld)252 void kempld_release_mutex(struct kempld_device_data *pld)
253 {
254 const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
255
256 pdata->release_hardware_mutex(pld);
257 mutex_unlock(&pld->lock);
258 }
259 EXPORT_SYMBOL_GPL(kempld_release_mutex);
260
261 /**
262 * kempld_get_info - update device specific information
263 * @pld: kempld_device_data structure describing the PLD
264 *
265 * This function calls the configured board specific kempld_get_info_XXXX
266 * function which is responsible for gathering information about the specific
267 * hardware. The information is then stored within the pld structure.
268 */
kempld_get_info(struct kempld_device_data * pld)269 static int kempld_get_info(struct kempld_device_data *pld)
270 {
271 int ret;
272 const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
273 char major, minor;
274
275 ret = pdata->get_info(pld);
276 if (ret)
277 return ret;
278
279 /* The Kontron PLD firmware version string has the following format:
280 * Pwxy.zzzz
281 * P: Fixed
282 * w: PLD number - 1 hex digit
283 * x: Major version - 1 alphanumerical digit (0-9A-V)
284 * y: Minor version - 1 alphanumerical digit (0-9A-V)
285 * zzzz: Build number - 4 zero padded hex digits */
286
287 if (pld->info.major < 10)
288 major = pld->info.major + '0';
289 else
290 major = (pld->info.major - 10) + 'A';
291 if (pld->info.minor < 10)
292 minor = pld->info.minor + '0';
293 else
294 minor = (pld->info.minor - 10) + 'A';
295
296 scnprintf(pld->info.version, sizeof(pld->info.version), "P%X%c%c.%04X",
297 pld->info.number, major, minor, pld->info.buildnr);
298
299 return 0;
300 }
301
302 /*
303 * kempld_register_cells - register cell drivers
304 *
305 * This function registers cell drivers for the detected hardware by calling
306 * the configured kempld_register_cells_XXXX function which is responsible
307 * to detect and register the needed cell drivers.
308 */
kempld_register_cells(struct kempld_device_data * pld)309 static int kempld_register_cells(struct kempld_device_data *pld)
310 {
311 const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
312
313 return pdata->register_cells(pld);
314 }
315
kempld_get_type_string(struct kempld_device_data * pld)316 static const char *kempld_get_type_string(struct kempld_device_data *pld)
317 {
318 const char *version_type;
319
320 switch (pld->info.type) {
321 case 0:
322 version_type = "release";
323 break;
324 case 1:
325 version_type = "debug";
326 break;
327 case 2:
328 version_type = "custom";
329 break;
330 default:
331 version_type = "unspecified";
332 break;
333 }
334
335 return version_type;
336 }
337
pld_version_show(struct device * dev,struct device_attribute * attr,char * buf)338 static ssize_t pld_version_show(struct device *dev,
339 struct device_attribute *attr, char *buf)
340 {
341 struct kempld_device_data *pld = dev_get_drvdata(dev);
342
343 return sysfs_emit(buf, "%s\n", pld->info.version);
344 }
345
pld_specification_show(struct device * dev,struct device_attribute * attr,char * buf)346 static ssize_t pld_specification_show(struct device *dev,
347 struct device_attribute *attr, char *buf)
348 {
349 struct kempld_device_data *pld = dev_get_drvdata(dev);
350
351 return sysfs_emit(buf, "%d.%d\n", pld->info.spec_major, pld->info.spec_minor);
352 }
353
pld_type_show(struct device * dev,struct device_attribute * attr,char * buf)354 static ssize_t pld_type_show(struct device *dev,
355 struct device_attribute *attr, char *buf)
356 {
357 struct kempld_device_data *pld = dev_get_drvdata(dev);
358
359 return sysfs_emit(buf, "%s\n", kempld_get_type_string(pld));
360 }
361
362 static DEVICE_ATTR_RO(pld_version);
363 static DEVICE_ATTR_RO(pld_specification);
364 static DEVICE_ATTR_RO(pld_type);
365
366 static struct attribute *pld_attrs[] = {
367 &dev_attr_pld_version.attr,
368 &dev_attr_pld_specification.attr,
369 &dev_attr_pld_type.attr,
370 NULL
371 };
372 ATTRIBUTE_GROUPS(pld);
373
kempld_detect_device(struct kempld_device_data * pld)374 static int kempld_detect_device(struct kempld_device_data *pld)
375 {
376 u8 index_reg;
377 int ret;
378
379 mutex_lock(&pld->lock);
380
381 /* Check for empty IO space */
382 index_reg = ioread8(pld->io_index);
383 if (index_reg == 0xff && ioread8(pld->io_data) == 0xff) {
384 mutex_unlock(&pld->lock);
385 return -ENODEV;
386 }
387
388 /* Release hardware mutex if acquired */
389 if (!(index_reg & KEMPLD_MUTEX_KEY)) {
390 iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
391 /* PXT and COMe-cPC2 boards may require a second release */
392 iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
393 }
394
395 mutex_unlock(&pld->lock);
396
397 ret = kempld_get_info(pld);
398 if (ret)
399 return ret;
400
401 dev_info(pld->dev, "Found Kontron PLD - %s (%s), spec %d.%d\n",
402 pld->info.version, kempld_get_type_string(pld),
403 pld->info.spec_major, pld->info.spec_minor);
404
405 return kempld_register_cells(pld);
406 }
407
kempld_probe(struct platform_device * pdev)408 static int kempld_probe(struct platform_device *pdev)
409 {
410 const struct kempld_platform_data *pdata;
411 struct device *dev = &pdev->dev;
412 struct kempld_device_data *pld;
413 struct resource *ioport;
414 int ret;
415
416 if (IS_ERR_OR_NULL(kempld_pdev)) {
417 /*
418 * No kempld_pdev device has been registered in kempld_init,
419 * so we seem to be probing an ACPI platform device.
420 */
421 pdata = device_get_match_data(dev);
422 if (!pdata)
423 return -ENODEV;
424
425 ret = platform_device_add_data(pdev, pdata, sizeof(*pdata));
426 if (ret)
427 return ret;
428 } else if (kempld_pdev == pdev) {
429 pdata = dev_get_platdata(dev);
430 } else {
431 /*
432 * The platform device we are probing is not the one we
433 * registered in kempld_init using the DMI table, so this one
434 * comes from ACPI.
435 * As we can only probe one - abort here and use the DMI
436 * based one instead.
437 */
438 dev_notice(dev, "platform device exists - not using ACPI\n");
439 return -ENODEV;
440 }
441
442 pld = devm_kzalloc(dev, sizeof(*pld), GFP_KERNEL);
443 if (!pld)
444 return -ENOMEM;
445
446 ioport = platform_get_resource(pdev, IORESOURCE_IO, 0);
447 if (!ioport)
448 return -EINVAL;
449
450 pld->io_base = devm_ioport_map(dev, ioport->start,
451 resource_size(ioport));
452 if (!pld->io_base)
453 return -ENOMEM;
454
455 pld->io_index = pld->io_base;
456 pld->io_data = pld->io_base + 1;
457 pld->pld_clock = pdata->pld_clock;
458 pld->dev = dev;
459
460 mutex_init(&pld->lock);
461 platform_set_drvdata(pdev, pld);
462
463 return kempld_detect_device(pld);
464 }
465
kempld_remove(struct platform_device * pdev)466 static void kempld_remove(struct platform_device *pdev)
467 {
468 struct kempld_device_data *pld = platform_get_drvdata(pdev);
469 const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
470
471 mfd_remove_devices(&pdev->dev);
472 pdata->release_hardware_mutex(pld);
473 }
474
475 static const struct acpi_device_id kempld_acpi_table[] = {
476 { "KEM0000", (kernel_ulong_t)&kempld_platform_data_generic },
477 { "KEM0001", (kernel_ulong_t)&kempld_platform_data_generic },
478 {}
479 };
480 MODULE_DEVICE_TABLE(acpi, kempld_acpi_table);
481
482 static struct platform_driver kempld_driver = {
483 .driver = {
484 .name = "kempld",
485 .acpi_match_table = kempld_acpi_table,
486 .dev_groups = pld_groups,
487 },
488 .probe = kempld_probe,
489 .remove = kempld_remove,
490 };
491
492 static const struct dmi_system_id kempld_dmi_table[] __initconst = {
493 {
494 .ident = "BBD6",
495 .matches = {
496 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
497 DMI_MATCH(DMI_BOARD_NAME, "COMe-bBD"),
498 },
499 }, {
500 .ident = "BBL6",
501 .matches = {
502 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
503 DMI_MATCH(DMI_BOARD_NAME, "COMe-bBL6"),
504 },
505 }, {
506 .ident = "BDV7",
507 .matches = {
508 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
509 DMI_MATCH(DMI_BOARD_NAME, "COMe-bDV7"),
510 },
511 }, {
512 .ident = "BHL6",
513 .matches = {
514 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
515 DMI_MATCH(DMI_BOARD_NAME, "COMe-bHL6"),
516 },
517 }, {
518 .ident = "BKL6",
519 .matches = {
520 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
521 DMI_MATCH(DMI_BOARD_NAME, "COMe-bKL6"),
522 },
523 }, {
524 .ident = "BSL6",
525 .matches = {
526 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
527 DMI_MATCH(DMI_BOARD_NAME, "COMe-bSL6"),
528 },
529 }, {
530 .ident = "CAL6",
531 .matches = {
532 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
533 DMI_MATCH(DMI_BOARD_NAME, "COMe-cAL"),
534 },
535 }, {
536 .ident = "CBL6",
537 .matches = {
538 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
539 DMI_MATCH(DMI_BOARD_NAME, "COMe-cBL6"),
540 },
541 }, {
542 .ident = "CBW6",
543 .matches = {
544 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
545 DMI_MATCH(DMI_BOARD_NAME, "COMe-cBW6"),
546 },
547 }, {
548 .ident = "CCR2",
549 .matches = {
550 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
551 DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP2"),
552 },
553 }, {
554 .ident = "CCR6",
555 .matches = {
556 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
557 DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP6"),
558 },
559 }, {
560 .ident = "CDV7",
561 .matches = {
562 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
563 DMI_MATCH(DMI_BOARD_NAME, "COMe-cDV7"),
564 },
565 }, {
566 .ident = "CHL6",
567 .matches = {
568 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
569 DMI_MATCH(DMI_BOARD_NAME, "COMe-cHL6"),
570 },
571 }, {
572 .ident = "CHR2",
573 .matches = {
574 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
575 DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T2"),
576 },
577 }, {
578 .ident = "CHR2",
579 .matches = {
580 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
581 DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T2"),
582 },
583 }, {
584 .ident = "CHR2",
585 .matches = {
586 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
587 DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC2"),
588 },
589 }, {
590 .ident = "CHR6",
591 .matches = {
592 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
593 DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T6"),
594 },
595 }, {
596 .ident = "CHR6",
597 .matches = {
598 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
599 DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T6"),
600 },
601 }, {
602 .ident = "CHR6",
603 .matches = {
604 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
605 DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC6"),
606 },
607 }, {
608 .ident = "CKL6",
609 .matches = {
610 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
611 DMI_MATCH(DMI_BOARD_NAME, "COMe-cKL6"),
612 },
613 }, {
614 .ident = "CNTG",
615 .matches = {
616 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
617 DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-PC"),
618 },
619 }, {
620 .ident = "CNTG",
621 .matches = {
622 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
623 DMI_MATCH(DMI_BOARD_NAME, "COMe-bPC2"),
624 },
625 }, {
626 .ident = "CNTX",
627 .matches = {
628 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
629 DMI_MATCH(DMI_BOARD_NAME, "PXT"),
630 },
631 }, {
632 .ident = "CSL6",
633 .matches = {
634 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
635 DMI_MATCH(DMI_BOARD_NAME, "COMe-cSL6"),
636 },
637 }, {
638 .ident = "CVV6",
639 .matches = {
640 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
641 DMI_MATCH(DMI_BOARD_NAME, "COMe-cBT"),
642 },
643 }, {
644 .ident = "FRI2",
645 .matches = {
646 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
647 DMI_MATCH(DMI_BIOS_VERSION, "FRI2"),
648 },
649 }, {
650 .ident = "FRI2",
651 .matches = {
652 DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II"),
653 },
654 }, {
655 .ident = "A203",
656 .matches = {
657 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
658 DMI_MATCH(DMI_BOARD_NAME, "KBox A-203"),
659 },
660 }, {
661 .ident = "M4A1",
662 .matches = {
663 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
664 DMI_MATCH(DMI_BOARD_NAME, "COMe-m4AL"),
665 },
666 }, {
667 .ident = "MAL1",
668 .matches = {
669 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
670 DMI_MATCH(DMI_BOARD_NAME, "COMe-mAL10"),
671 },
672 }, {
673 .ident = "MAPL",
674 .matches = {
675 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
676 DMI_MATCH(DMI_BOARD_NAME, "mITX-APL"),
677 },
678 }, {
679 .ident = "MBR1",
680 .matches = {
681 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
682 DMI_MATCH(DMI_BOARD_NAME, "ETX-OH"),
683 },
684 }, {
685 .ident = "MVV1",
686 .matches = {
687 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
688 DMI_MATCH(DMI_BOARD_NAME, "COMe-mBT"),
689 },
690 }, {
691 .ident = "NTC1",
692 .matches = {
693 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
694 DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT"),
695 },
696 }, {
697 .ident = "NTC1",
698 .matches = {
699 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
700 DMI_MATCH(DMI_BOARD_NAME, "nETXe-TT"),
701 },
702 }, {
703 .ident = "NTC1",
704 .matches = {
705 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
706 DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT"),
707 },
708 }, {
709 .ident = "NUP1",
710 .matches = {
711 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
712 DMI_MATCH(DMI_BOARD_NAME, "COMe-mCT"),
713 },
714 }, {
715 .ident = "PAPL",
716 .matches = {
717 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
718 DMI_MATCH(DMI_BOARD_NAME, "pITX-APL"),
719 },
720 }, {
721 .ident = "SXAL",
722 .matches = {
723 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
724 DMI_MATCH(DMI_BOARD_NAME, "SMARC-sXAL"),
725 },
726 }, {
727 .ident = "SXAL4",
728 .matches = {
729 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
730 DMI_MATCH(DMI_BOARD_NAME, "SMARC-sXA4"),
731 },
732 }, {
733 .ident = "UNP1",
734 .matches = {
735 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
736 DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-DC"),
737 },
738 }, {
739 .ident = "UNP1",
740 .matches = {
741 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
742 DMI_MATCH(DMI_BOARD_NAME, "COMe-cDC2"),
743 },
744 }, {
745 .ident = "UNTG",
746 .matches = {
747 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
748 DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-PC"),
749 },
750 }, {
751 .ident = "UNTG",
752 .matches = {
753 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
754 DMI_MATCH(DMI_BOARD_NAME, "COMe-cPC2"),
755 },
756 }, {
757 .ident = "UUP6",
758 .matches = {
759 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
760 DMI_MATCH(DMI_BOARD_NAME, "COMe-cCT6"),
761 },
762 }, {
763 .ident = "UTH6",
764 .matches = {
765 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
766 DMI_MATCH(DMI_BOARD_NAME, "COMe-cTH6"),
767 },
768 }, {
769 .ident = "Q7AL",
770 .matches = {
771 DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
772 DMI_MATCH(DMI_BOARD_NAME, "Qseven-Q7AL"),
773 },
774 },
775 {}
776 };
777 MODULE_DEVICE_TABLE(dmi, kempld_dmi_table);
778
kempld_init(void)779 static int __init kempld_init(void)
780 {
781 const struct dmi_system_id *id;
782 int ret = -ENODEV;
783
784 for (id = dmi_first_match(kempld_dmi_table); id; id = dmi_first_match(id + 1)) {
785 /* Check, if user asked for the exact device ID match */
786 if (force_device_id[0] && !strstr(id->ident, force_device_id))
787 continue;
788
789 ret = kempld_create_platform_device(&kempld_platform_data_generic);
790 if (ret)
791 continue;
792
793 break;
794 }
795 if (ret)
796 return ret;
797
798 return platform_driver_register(&kempld_driver);
799 }
800
kempld_exit(void)801 static void __exit kempld_exit(void)
802 {
803 platform_device_unregister(kempld_pdev);
804 platform_driver_unregister(&kempld_driver);
805 }
806
807 module_init(kempld_init);
808 module_exit(kempld_exit);
809
810 MODULE_DESCRIPTION("KEM PLD Core Driver");
811 MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
812 MODULE_LICENSE("GPL");
813 MODULE_ALIAS("platform:kempld-core");
814