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