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