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