Merge tag 'soc-ep93xx-dt-6.12' of git://git.kernel.org/pub/scm/linux/kernel/git/soc/soc
[linux-2.6-block.git] / drivers / mfd / kempld-core.c
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  */
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
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
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
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
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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
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
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
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
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
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
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
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_new     = 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
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
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");