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