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