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 = 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"); 814