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