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 */ 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 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 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 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 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 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 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 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 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 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 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 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