Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Kontron PLD MFD core driver
0004  *
0005  * Copyright (c) 2010-2013 Kontron Europe GmbH
0006  * Author: Michael Brunner <michael.brunner@kontron.com>
0007  */
0008 
0009 #include <linux/platform_device.h>
0010 #include <linux/mfd/core.h>
0011 #include <linux/mfd/kempld.h>
0012 #include <linux/module.h>
0013 #include <linux/dmi.h>
0014 #include <linux/io.h>
0015 #include <linux/delay.h>
0016 #include <linux/acpi.h>
0017 
0018 #define MAX_ID_LEN 4
0019 static char force_device_id[MAX_ID_LEN + 1] = "";
0020 module_param_string(force_device_id, force_device_id,
0021             sizeof(force_device_id), 0);
0022 MODULE_PARM_DESC(force_device_id, "Override detected product");
0023 
0024 /*
0025  * Get hardware mutex to block firmware from accessing the pld.
0026  * It is possible for the firmware may hold the mutex for an extended length of
0027  * time. This function will block until access has been granted.
0028  */
0029 static void kempld_get_hardware_mutex(struct kempld_device_data *pld)
0030 {
0031     /* The mutex bit will read 1 until access has been granted */
0032     while (ioread8(pld->io_index) & KEMPLD_MUTEX_KEY)
0033         usleep_range(1000, 3000);
0034 }
0035 
0036 static void kempld_release_hardware_mutex(struct kempld_device_data *pld)
0037 {
0038     /* The harware mutex is released when 1 is written to the mutex bit. */
0039     iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
0040 }
0041 
0042 static int kempld_get_info_generic(struct kempld_device_data *pld)
0043 {
0044     u16 version;
0045     u8 spec;
0046 
0047     kempld_get_mutex(pld);
0048 
0049     version = kempld_read16(pld, KEMPLD_VERSION);
0050     spec = kempld_read8(pld, KEMPLD_SPEC);
0051     pld->info.buildnr = kempld_read16(pld, KEMPLD_BUILDNR);
0052 
0053     pld->info.minor = KEMPLD_VERSION_GET_MINOR(version);
0054     pld->info.major = KEMPLD_VERSION_GET_MAJOR(version);
0055     pld->info.number = KEMPLD_VERSION_GET_NUMBER(version);
0056     pld->info.type = KEMPLD_VERSION_GET_TYPE(version);
0057 
0058     if (spec == 0xff) {
0059         pld->info.spec_minor = 0;
0060         pld->info.spec_major = 1;
0061     } else {
0062         pld->info.spec_minor = KEMPLD_SPEC_GET_MINOR(spec);
0063         pld->info.spec_major = KEMPLD_SPEC_GET_MAJOR(spec);
0064     }
0065 
0066     if (pld->info.spec_major > 0)
0067         pld->feature_mask = kempld_read16(pld, KEMPLD_FEATURE);
0068     else
0069         pld->feature_mask = 0;
0070 
0071     kempld_release_mutex(pld);
0072 
0073     return 0;
0074 }
0075 
0076 enum kempld_cells {
0077     KEMPLD_I2C = 0,
0078     KEMPLD_WDT,
0079     KEMPLD_GPIO,
0080     KEMPLD_UART,
0081 };
0082 
0083 static const char *kempld_dev_names[] = {
0084     [KEMPLD_I2C] = "kempld-i2c",
0085     [KEMPLD_WDT] = "kempld-wdt",
0086     [KEMPLD_GPIO] = "kempld-gpio",
0087     [KEMPLD_UART] = "kempld-uart",
0088 };
0089 
0090 #define KEMPLD_MAX_DEVS ARRAY_SIZE(kempld_dev_names)
0091 
0092 static int kempld_register_cells_generic(struct kempld_device_data *pld)
0093 {
0094     struct mfd_cell devs[KEMPLD_MAX_DEVS] = {};
0095     int i = 0;
0096 
0097     if (pld->feature_mask & KEMPLD_FEATURE_BIT_I2C)
0098         devs[i++].name = kempld_dev_names[KEMPLD_I2C];
0099 
0100     if (pld->feature_mask & KEMPLD_FEATURE_BIT_WATCHDOG)
0101         devs[i++].name = kempld_dev_names[KEMPLD_WDT];
0102 
0103     if (pld->feature_mask & KEMPLD_FEATURE_BIT_GPIO)
0104         devs[i++].name = kempld_dev_names[KEMPLD_GPIO];
0105 
0106     if (pld->feature_mask & KEMPLD_FEATURE_MASK_UART)
0107         devs[i++].name = kempld_dev_names[KEMPLD_UART];
0108 
0109     return mfd_add_devices(pld->dev, -1, devs, i, NULL, 0, NULL);
0110 }
0111 
0112 static struct resource kempld_ioresource = {
0113     .start  = KEMPLD_IOINDEX,
0114     .end    = KEMPLD_IODATA,
0115     .flags  = IORESOURCE_IO,
0116 };
0117 
0118 static const struct kempld_platform_data kempld_platform_data_generic = {
0119     .pld_clock      = KEMPLD_CLK,
0120     .ioresource     = &kempld_ioresource,
0121     .get_hardware_mutex = kempld_get_hardware_mutex,
0122     .release_hardware_mutex = kempld_release_hardware_mutex,
0123     .get_info       = kempld_get_info_generic,
0124     .register_cells     = kempld_register_cells_generic,
0125 };
0126 
0127 static struct platform_device *kempld_pdev;
0128 
0129 static int kempld_create_platform_device(const struct dmi_system_id *id)
0130 {
0131     const struct kempld_platform_data *pdata = id->driver_data;
0132     int ret;
0133 
0134     kempld_pdev = platform_device_alloc("kempld", -1);
0135     if (!kempld_pdev)
0136         return -ENOMEM;
0137 
0138     ret = platform_device_add_data(kempld_pdev, pdata, sizeof(*pdata));
0139     if (ret)
0140         goto err;
0141 
0142     ret = platform_device_add_resources(kempld_pdev, pdata->ioresource, 1);
0143     if (ret)
0144         goto err;
0145 
0146     ret = platform_device_add(kempld_pdev);
0147     if (ret)
0148         goto err;
0149 
0150     return 0;
0151 err:
0152     platform_device_put(kempld_pdev);
0153     return ret;
0154 }
0155 
0156 /**
0157  * kempld_read8 - read 8 bit register
0158  * @pld: kempld_device_data structure describing the PLD
0159  * @index: register index on the chip
0160  *
0161  * kempld_get_mutex must be called prior to calling this function.
0162  */
0163 u8 kempld_read8(struct kempld_device_data *pld, u8 index)
0164 {
0165     iowrite8(index, pld->io_index);
0166     return ioread8(pld->io_data);
0167 }
0168 EXPORT_SYMBOL_GPL(kempld_read8);
0169 
0170 /**
0171  * kempld_write8 - write 8 bit register
0172  * @pld: kempld_device_data structure describing the PLD
0173  * @index: register index on the chip
0174  * @data: new register value
0175  *
0176  * kempld_get_mutex must be called prior to calling this function.
0177  */
0178 void kempld_write8(struct kempld_device_data *pld, u8 index, u8 data)
0179 {
0180     iowrite8(index, pld->io_index);
0181     iowrite8(data, pld->io_data);
0182 }
0183 EXPORT_SYMBOL_GPL(kempld_write8);
0184 
0185 /**
0186  * kempld_read16 - read 16 bit register
0187  * @pld: kempld_device_data structure describing the PLD
0188  * @index: register index on the chip
0189  *
0190  * kempld_get_mutex must be called prior to calling this function.
0191  */
0192 u16 kempld_read16(struct kempld_device_data *pld, u8 index)
0193 {
0194     return kempld_read8(pld, index) | kempld_read8(pld, index + 1) << 8;
0195 }
0196 EXPORT_SYMBOL_GPL(kempld_read16);
0197 
0198 /**
0199  * kempld_write16 - write 16 bit register
0200  * @pld: kempld_device_data structure describing the PLD
0201  * @index: register index on the chip
0202  * @data: new register value
0203  *
0204  * kempld_get_mutex must be called prior to calling this function.
0205  */
0206 void kempld_write16(struct kempld_device_data *pld, u8 index, u16 data)
0207 {
0208     kempld_write8(pld, index, (u8)data);
0209     kempld_write8(pld, index + 1, (u8)(data >> 8));
0210 }
0211 EXPORT_SYMBOL_GPL(kempld_write16);
0212 
0213 /**
0214  * kempld_read32 - read 32 bit register
0215  * @pld: kempld_device_data structure describing the PLD
0216  * @index: register index on the chip
0217  *
0218  * kempld_get_mutex must be called prior to calling this function.
0219  */
0220 u32 kempld_read32(struct kempld_device_data *pld, u8 index)
0221 {
0222     return kempld_read16(pld, index) | kempld_read16(pld, index + 2) << 16;
0223 }
0224 EXPORT_SYMBOL_GPL(kempld_read32);
0225 
0226 /**
0227  * kempld_write32 - write 32 bit register
0228  * @pld: kempld_device_data structure describing the PLD
0229  * @index: register index on the chip
0230  * @data: new register value
0231  *
0232  * kempld_get_mutex must be called prior to calling this function.
0233  */
0234 void kempld_write32(struct kempld_device_data *pld, u8 index, u32 data)
0235 {
0236     kempld_write16(pld, index, (u16)data);
0237     kempld_write16(pld, index + 2, (u16)(data >> 16));
0238 }
0239 EXPORT_SYMBOL_GPL(kempld_write32);
0240 
0241 /**
0242  * kempld_get_mutex - acquire PLD mutex
0243  * @pld: kempld_device_data structure describing the PLD
0244  */
0245 void kempld_get_mutex(struct kempld_device_data *pld)
0246 {
0247     const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
0248 
0249     mutex_lock(&pld->lock);
0250     pdata->get_hardware_mutex(pld);
0251 }
0252 EXPORT_SYMBOL_GPL(kempld_get_mutex);
0253 
0254 /**
0255  * kempld_release_mutex - release PLD mutex
0256  * @pld: kempld_device_data structure describing the PLD
0257  */
0258 void kempld_release_mutex(struct kempld_device_data *pld)
0259 {
0260     const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
0261 
0262     pdata->release_hardware_mutex(pld);
0263     mutex_unlock(&pld->lock);
0264 }
0265 EXPORT_SYMBOL_GPL(kempld_release_mutex);
0266 
0267 /**
0268  * kempld_get_info - update device specific information
0269  * @pld: kempld_device_data structure describing the PLD
0270  *
0271  * This function calls the configured board specific kempld_get_info_XXXX
0272  * function which is responsible for gathering information about the specific
0273  * hardware. The information is then stored within the pld structure.
0274  */
0275 static int kempld_get_info(struct kempld_device_data *pld)
0276 {
0277     int ret;
0278     const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
0279     char major, minor;
0280 
0281     ret = pdata->get_info(pld);
0282     if (ret)
0283         return ret;
0284 
0285     /* The Kontron PLD firmware version string has the following format:
0286      * Pwxy.zzzz
0287      *   P:    Fixed
0288      *   w:    PLD number    - 1 hex digit
0289      *   x:    Major version - 1 alphanumerical digit (0-9A-V)
0290      *   y:    Minor version - 1 alphanumerical digit (0-9A-V)
0291      *   zzzz: Build number  - 4 zero padded hex digits */
0292 
0293     if (pld->info.major < 10)
0294         major = pld->info.major + '0';
0295     else
0296         major = (pld->info.major - 10) + 'A';
0297     if (pld->info.minor < 10)
0298         minor = pld->info.minor + '0';
0299     else
0300         minor = (pld->info.minor - 10) + 'A';
0301 
0302     ret = scnprintf(pld->info.version, sizeof(pld->info.version),
0303             "P%X%c%c.%04X", pld->info.number, major, minor,
0304             pld->info.buildnr);
0305     if (ret < 0)
0306         return ret;
0307 
0308     return 0;
0309 }
0310 
0311 /*
0312  * kempld_register_cells - register cell drivers
0313  *
0314  * This function registers cell drivers for the detected hardware by calling
0315  * the configured kempld_register_cells_XXXX function which is responsible
0316  * to detect and register the needed cell drivers.
0317  */
0318 static int kempld_register_cells(struct kempld_device_data *pld)
0319 {
0320     const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
0321 
0322     return pdata->register_cells(pld);
0323 }
0324 
0325 static const char *kempld_get_type_string(struct kempld_device_data *pld)
0326 {
0327     const char *version_type;
0328 
0329     switch (pld->info.type) {
0330     case 0:
0331         version_type = "release";
0332         break;
0333     case 1:
0334         version_type = "debug";
0335         break;
0336     case 2:
0337         version_type = "custom";
0338         break;
0339     default:
0340         version_type = "unspecified";
0341         break;
0342     }
0343 
0344     return version_type;
0345 }
0346 
0347 static ssize_t pld_version_show(struct device *dev,
0348                 struct device_attribute *attr, char *buf)
0349 {
0350     struct kempld_device_data *pld = dev_get_drvdata(dev);
0351 
0352     return scnprintf(buf, PAGE_SIZE, "%s\n", pld->info.version);
0353 }
0354 
0355 static ssize_t pld_specification_show(struct device *dev,
0356                       struct device_attribute *attr, char *buf)
0357 {
0358     struct kempld_device_data *pld = dev_get_drvdata(dev);
0359 
0360     return scnprintf(buf, PAGE_SIZE, "%d.%d\n", pld->info.spec_major,
0361                pld->info.spec_minor);
0362 }
0363 
0364 static ssize_t pld_type_show(struct device *dev,
0365                  struct device_attribute *attr, char *buf)
0366 {
0367     struct kempld_device_data *pld = dev_get_drvdata(dev);
0368 
0369     return scnprintf(buf, PAGE_SIZE, "%s\n", kempld_get_type_string(pld));
0370 }
0371 
0372 static DEVICE_ATTR_RO(pld_version);
0373 static DEVICE_ATTR_RO(pld_specification);
0374 static DEVICE_ATTR_RO(pld_type);
0375 
0376 static struct attribute *pld_attributes[] = {
0377     &dev_attr_pld_version.attr,
0378     &dev_attr_pld_specification.attr,
0379     &dev_attr_pld_type.attr,
0380     NULL
0381 };
0382 
0383 static const struct attribute_group pld_attr_group = {
0384     .attrs = pld_attributes,
0385 };
0386 
0387 static int kempld_detect_device(struct kempld_device_data *pld)
0388 {
0389     u8 index_reg;
0390     int ret;
0391 
0392     mutex_lock(&pld->lock);
0393 
0394     /* Check for empty IO space */
0395     index_reg = ioread8(pld->io_index);
0396     if (index_reg == 0xff && ioread8(pld->io_data) == 0xff) {
0397         mutex_unlock(&pld->lock);
0398         return -ENODEV;
0399     }
0400 
0401     /* Release hardware mutex if acquired */
0402     if (!(index_reg & KEMPLD_MUTEX_KEY)) {
0403         iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
0404         /* PXT and COMe-cPC2 boards may require a second release */
0405         iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
0406     }
0407 
0408     mutex_unlock(&pld->lock);
0409 
0410     ret = kempld_get_info(pld);
0411     if (ret)
0412         return ret;
0413 
0414     dev_info(pld->dev, "Found Kontron PLD - %s (%s), spec %d.%d\n",
0415          pld->info.version, kempld_get_type_string(pld),
0416          pld->info.spec_major, pld->info.spec_minor);
0417 
0418     ret = sysfs_create_group(&pld->dev->kobj, &pld_attr_group);
0419     if (ret)
0420         return ret;
0421 
0422     ret = kempld_register_cells(pld);
0423     if (ret)
0424         sysfs_remove_group(&pld->dev->kobj, &pld_attr_group);
0425 
0426     return ret;
0427 }
0428 
0429 #ifdef CONFIG_ACPI
0430 static int kempld_get_acpi_data(struct platform_device *pdev)
0431 {
0432     struct list_head resource_list;
0433     struct resource *resources;
0434     struct resource_entry *rentry;
0435     struct device *dev = &pdev->dev;
0436     struct acpi_device *acpi_dev = ACPI_COMPANION(dev);
0437     const struct kempld_platform_data *pdata;
0438     int ret;
0439     int count;
0440 
0441     pdata = acpi_device_get_match_data(dev);
0442     ret = platform_device_add_data(pdev, pdata,
0443                        sizeof(struct kempld_platform_data));
0444     if (ret)
0445         return ret;
0446 
0447     INIT_LIST_HEAD(&resource_list);
0448     ret = acpi_dev_get_resources(acpi_dev, &resource_list, NULL, NULL);
0449     if (ret < 0)
0450         goto out;
0451 
0452     count = ret;
0453 
0454     if (count == 0) {
0455         ret = platform_device_add_resources(pdev, pdata->ioresource, 1);
0456         goto out;
0457     }
0458 
0459     resources = devm_kcalloc(&acpi_dev->dev, count, sizeof(*resources),
0460                  GFP_KERNEL);
0461     if (!resources) {
0462         ret = -ENOMEM;
0463         goto out;
0464     }
0465 
0466     count = 0;
0467     list_for_each_entry(rentry, &resource_list, node) {
0468         memcpy(&resources[count], rentry->res,
0469                sizeof(*resources));
0470         count++;
0471     }
0472     ret = platform_device_add_resources(pdev, resources, count);
0473 
0474 out:
0475     acpi_dev_free_resource_list(&resource_list);
0476 
0477     return ret;
0478 }
0479 #else
0480 static int kempld_get_acpi_data(struct platform_device *pdev)
0481 {
0482     return -ENODEV;
0483 }
0484 #endif /* CONFIG_ACPI */
0485 
0486 static int kempld_probe(struct platform_device *pdev)
0487 {
0488     const struct kempld_platform_data *pdata;
0489     struct device *dev = &pdev->dev;
0490     struct kempld_device_data *pld;
0491     struct resource *ioport;
0492     int ret;
0493 
0494     if (kempld_pdev == NULL) {
0495         /*
0496          * No kempld_pdev device has been registered in kempld_init,
0497          * so we seem to be probing an ACPI platform device.
0498          */
0499         ret = kempld_get_acpi_data(pdev);
0500         if (ret)
0501             return ret;
0502     } else if (kempld_pdev != pdev) {
0503         /*
0504          * The platform device we are probing is not the one we
0505          * registered in kempld_init using the DMI table, so this one
0506          * comes from ACPI.
0507          * As we can only probe one - abort here and use the DMI
0508          * based one instead.
0509          */
0510         dev_notice(dev, "platform device exists - not using ACPI\n");
0511         return -ENODEV;
0512     }
0513     pdata = dev_get_platdata(dev);
0514 
0515     pld = devm_kzalloc(dev, sizeof(*pld), GFP_KERNEL);
0516     if (!pld)
0517         return -ENOMEM;
0518 
0519     ioport = platform_get_resource(pdev, IORESOURCE_IO, 0);
0520     if (!ioport)
0521         return -EINVAL;
0522 
0523     pld->io_base = devm_ioport_map(dev, ioport->start,
0524                     resource_size(ioport));
0525     if (!pld->io_base)
0526         return -ENOMEM;
0527 
0528     pld->io_index = pld->io_base;
0529     pld->io_data = pld->io_base + 1;
0530     pld->pld_clock = pdata->pld_clock;
0531     pld->dev = dev;
0532 
0533     mutex_init(&pld->lock);
0534     platform_set_drvdata(pdev, pld);
0535 
0536     return kempld_detect_device(pld);
0537 }
0538 
0539 static int kempld_remove(struct platform_device *pdev)
0540 {
0541     struct kempld_device_data *pld = platform_get_drvdata(pdev);
0542     const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
0543 
0544     sysfs_remove_group(&pld->dev->kobj, &pld_attr_group);
0545 
0546     mfd_remove_devices(&pdev->dev);
0547     pdata->release_hardware_mutex(pld);
0548 
0549     return 0;
0550 }
0551 
0552 #ifdef CONFIG_ACPI
0553 static const struct acpi_device_id kempld_acpi_table[] = {
0554     { "KEM0000", (kernel_ulong_t)&kempld_platform_data_generic },
0555     { "KEM0001", (kernel_ulong_t)&kempld_platform_data_generic },
0556     {}
0557 };
0558 MODULE_DEVICE_TABLE(acpi, kempld_acpi_table);
0559 #endif
0560 
0561 static struct platform_driver kempld_driver = {
0562     .driver     = {
0563         .name   = "kempld",
0564         .acpi_match_table = ACPI_PTR(kempld_acpi_table),
0565     },
0566     .probe      = kempld_probe,
0567     .remove     = kempld_remove,
0568 };
0569 
0570 static const struct dmi_system_id kempld_dmi_table[] __initconst = {
0571     {
0572         .ident = "BBD6",
0573         .matches = {
0574             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0575             DMI_MATCH(DMI_BOARD_NAME, "COMe-bBD"),
0576         },
0577         .driver_data = (void *)&kempld_platform_data_generic,
0578         .callback = kempld_create_platform_device,
0579     }, {
0580         .ident = "BBL6",
0581         .matches = {
0582             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0583             DMI_MATCH(DMI_BOARD_NAME, "COMe-bBL6"),
0584         },
0585         .driver_data = (void *)&kempld_platform_data_generic,
0586         .callback = kempld_create_platform_device,
0587     }, {
0588         .ident = "BDV7",
0589         .matches = {
0590             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0591             DMI_MATCH(DMI_BOARD_NAME, "COMe-bDV7"),
0592         },
0593         .driver_data = (void *)&kempld_platform_data_generic,
0594         .callback = kempld_create_platform_device,
0595     }, {
0596         .ident = "BHL6",
0597         .matches = {
0598             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0599             DMI_MATCH(DMI_BOARD_NAME, "COMe-bHL6"),
0600         },
0601         .driver_data = (void *)&kempld_platform_data_generic,
0602         .callback = kempld_create_platform_device,
0603     }, {
0604         .ident = "BKL6",
0605         .matches = {
0606             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0607             DMI_MATCH(DMI_BOARD_NAME, "COMe-bKL6"),
0608         },
0609         .driver_data = (void *)&kempld_platform_data_generic,
0610         .callback = kempld_create_platform_device,
0611     }, {
0612         .ident = "BSL6",
0613         .matches = {
0614             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0615             DMI_MATCH(DMI_BOARD_NAME, "COMe-bSL6"),
0616         },
0617         .driver_data = (void *)&kempld_platform_data_generic,
0618         .callback = kempld_create_platform_device,
0619     }, {
0620         .ident = "CAL6",
0621         .matches = {
0622             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0623             DMI_MATCH(DMI_BOARD_NAME, "COMe-cAL"),
0624         },
0625         .driver_data = (void *)&kempld_platform_data_generic,
0626         .callback = kempld_create_platform_device,
0627     }, {
0628         .ident = "CBL6",
0629         .matches = {
0630             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0631             DMI_MATCH(DMI_BOARD_NAME, "COMe-cBL6"),
0632         },
0633         .driver_data = (void *)&kempld_platform_data_generic,
0634         .callback = kempld_create_platform_device,
0635     }, {
0636         .ident = "CBW6",
0637         .matches = {
0638             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0639             DMI_MATCH(DMI_BOARD_NAME, "COMe-cBW6"),
0640         },
0641         .driver_data = (void *)&kempld_platform_data_generic,
0642         .callback = kempld_create_platform_device,
0643     }, {
0644         .ident = "CCR2",
0645         .matches = {
0646             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0647             DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP2"),
0648         },
0649         .driver_data = (void *)&kempld_platform_data_generic,
0650         .callback = kempld_create_platform_device,
0651     }, {
0652         .ident = "CCR6",
0653         .matches = {
0654             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0655             DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP6"),
0656         },
0657         .driver_data = (void *)&kempld_platform_data_generic,
0658         .callback = kempld_create_platform_device,
0659     }, {
0660         .ident = "CDV7",
0661         .matches = {
0662             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0663             DMI_MATCH(DMI_BOARD_NAME, "COMe-cDV7"),
0664         },
0665         .driver_data = (void *)&kempld_platform_data_generic,
0666         .callback = kempld_create_platform_device,
0667     }, {
0668         .ident = "CHL6",
0669         .matches = {
0670             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0671             DMI_MATCH(DMI_BOARD_NAME, "COMe-cHL6"),
0672         },
0673         .driver_data = (void *)&kempld_platform_data_generic,
0674         .callback = kempld_create_platform_device,
0675     }, {
0676         .ident = "CHR2",
0677         .matches = {
0678             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0679             DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T2"),
0680         },
0681         .driver_data = (void *)&kempld_platform_data_generic,
0682         .callback = kempld_create_platform_device,
0683     }, {
0684         .ident = "CHR2",
0685         .matches = {
0686             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0687             DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T2"),
0688         },
0689         .driver_data = (void *)&kempld_platform_data_generic,
0690         .callback = kempld_create_platform_device,
0691     }, {
0692         .ident = "CHR2",
0693         .matches = {
0694             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0695             DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC2"),
0696         },
0697         .driver_data = (void *)&kempld_platform_data_generic,
0698         .callback = kempld_create_platform_device,
0699     }, {
0700         .ident = "CHR6",
0701         .matches = {
0702             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0703             DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T6"),
0704         },
0705         .driver_data = (void *)&kempld_platform_data_generic,
0706         .callback = kempld_create_platform_device,
0707     }, {
0708         .ident = "CHR6",
0709         .matches = {
0710             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0711             DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T6"),
0712         },
0713         .driver_data = (void *)&kempld_platform_data_generic,
0714         .callback = kempld_create_platform_device,
0715     }, {
0716         .ident = "CHR6",
0717         .matches = {
0718             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0719             DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC6"),
0720         },
0721         .driver_data = (void *)&kempld_platform_data_generic,
0722         .callback = kempld_create_platform_device,
0723     }, {
0724         .ident = "CKL6",
0725         .matches = {
0726             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0727             DMI_MATCH(DMI_BOARD_NAME, "COMe-cKL6"),
0728         },
0729         .driver_data = (void *)&kempld_platform_data_generic,
0730         .callback = kempld_create_platform_device,
0731     }, {
0732         .ident = "CNTG",
0733         .matches = {
0734             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0735             DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-PC"),
0736         },
0737         .driver_data = (void *)&kempld_platform_data_generic,
0738         .callback = kempld_create_platform_device,
0739     }, {
0740         .ident = "CNTG",
0741         .matches = {
0742             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0743             DMI_MATCH(DMI_BOARD_NAME, "COMe-bPC2"),
0744         },
0745         .driver_data = (void *)&kempld_platform_data_generic,
0746         .callback = kempld_create_platform_device,
0747     }, {
0748         .ident = "CNTX",
0749         .matches = {
0750             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0751             DMI_MATCH(DMI_BOARD_NAME, "PXT"),
0752         },
0753         .driver_data = (void *)&kempld_platform_data_generic,
0754         .callback = kempld_create_platform_device,
0755     }, {
0756         .ident = "CSL6",
0757         .matches = {
0758             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0759             DMI_MATCH(DMI_BOARD_NAME, "COMe-cSL6"),
0760         },
0761         .driver_data = (void *)&kempld_platform_data_generic,
0762         .callback = kempld_create_platform_device,
0763     }, {
0764         .ident = "CVV6",
0765         .matches = {
0766             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0767             DMI_MATCH(DMI_BOARD_NAME, "COMe-cBT"),
0768         },
0769         .driver_data = (void *)&kempld_platform_data_generic,
0770         .callback = kempld_create_platform_device,
0771     }, {
0772         .ident = "FRI2",
0773         .matches = {
0774             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0775             DMI_MATCH(DMI_BIOS_VERSION, "FRI2"),
0776         },
0777         .driver_data = (void *)&kempld_platform_data_generic,
0778         .callback = kempld_create_platform_device,
0779     }, {
0780         .ident = "FRI2",
0781         .matches = {
0782             DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II"),
0783         },
0784         .driver_data = (void *)&kempld_platform_data_generic,
0785         .callback = kempld_create_platform_device,
0786     }, {
0787         .ident = "A203",
0788         .matches = {
0789             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0790             DMI_MATCH(DMI_BOARD_NAME, "KBox A-203"),
0791         },
0792         .driver_data = (void *)&kempld_platform_data_generic,
0793         .callback = kempld_create_platform_device,
0794     }, {
0795         .ident = "M4A1",
0796         .matches = {
0797             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0798             DMI_MATCH(DMI_BOARD_NAME, "COMe-m4AL"),
0799         },
0800         .driver_data = (void *)&kempld_platform_data_generic,
0801         .callback = kempld_create_platform_device,
0802     }, {
0803         .ident = "MAL1",
0804         .matches = {
0805             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0806             DMI_MATCH(DMI_BOARD_NAME, "COMe-mAL10"),
0807         },
0808         .driver_data = (void *)&kempld_platform_data_generic,
0809         .callback = kempld_create_platform_device,
0810     }, {
0811         .ident = "MAPL",
0812         .matches = {
0813             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0814             DMI_MATCH(DMI_BOARD_NAME, "mITX-APL"),
0815         },
0816         .driver_data = (void *)&kempld_platform_data_generic,
0817         .callback = kempld_create_platform_device,
0818     }, {
0819         .ident = "MBR1",
0820         .matches = {
0821             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0822             DMI_MATCH(DMI_BOARD_NAME, "ETX-OH"),
0823         },
0824         .driver_data = (void *)&kempld_platform_data_generic,
0825         .callback = kempld_create_platform_device,
0826     }, {
0827         .ident = "MVV1",
0828         .matches = {
0829             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0830             DMI_MATCH(DMI_BOARD_NAME, "COMe-mBT"),
0831         },
0832         .driver_data = (void *)&kempld_platform_data_generic,
0833         .callback = kempld_create_platform_device,
0834     }, {
0835         .ident = "NTC1",
0836         .matches = {
0837             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0838             DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT"),
0839         },
0840         .driver_data = (void *)&kempld_platform_data_generic,
0841         .callback = kempld_create_platform_device,
0842     }, {
0843         .ident = "NTC1",
0844         .matches = {
0845             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0846             DMI_MATCH(DMI_BOARD_NAME, "nETXe-TT"),
0847         },
0848         .driver_data = (void *)&kempld_platform_data_generic,
0849         .callback = kempld_create_platform_device,
0850     }, {
0851         .ident = "NTC1",
0852         .matches = {
0853             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0854             DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT"),
0855         },
0856         .driver_data = (void *)&kempld_platform_data_generic,
0857         .callback = kempld_create_platform_device,
0858     }, {
0859         .ident = "NUP1",
0860         .matches = {
0861             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0862             DMI_MATCH(DMI_BOARD_NAME, "COMe-mCT"),
0863         },
0864         .driver_data = (void *)&kempld_platform_data_generic,
0865         .callback = kempld_create_platform_device,
0866     }, {
0867         .ident = "PAPL",
0868         .matches = {
0869             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0870             DMI_MATCH(DMI_BOARD_NAME, "pITX-APL"),
0871         },
0872         .driver_data = (void *)&kempld_platform_data_generic,
0873         .callback = kempld_create_platform_device,
0874     }, {
0875         .ident = "SXAL",
0876         .matches = {
0877             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0878             DMI_MATCH(DMI_BOARD_NAME, "SMARC-sXAL"),
0879         },
0880         .driver_data = (void *)&kempld_platform_data_generic,
0881         .callback = kempld_create_platform_device,
0882     }, {
0883         .ident = "SXAL4",
0884         .matches = {
0885             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0886             DMI_MATCH(DMI_BOARD_NAME, "SMARC-sXA4"),
0887         },
0888         .driver_data = (void *)&kempld_platform_data_generic,
0889         .callback = kempld_create_platform_device,
0890     }, {
0891         .ident = "UNP1",
0892         .matches = {
0893             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0894             DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-DC"),
0895         },
0896         .driver_data = (void *)&kempld_platform_data_generic,
0897         .callback = kempld_create_platform_device,
0898     }, {
0899         .ident = "UNP1",
0900         .matches = {
0901             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0902             DMI_MATCH(DMI_BOARD_NAME, "COMe-cDC2"),
0903         },
0904         .driver_data = (void *)&kempld_platform_data_generic,
0905         .callback = kempld_create_platform_device,
0906     }, {
0907         .ident = "UNTG",
0908         .matches = {
0909             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0910             DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-PC"),
0911         },
0912         .driver_data = (void *)&kempld_platform_data_generic,
0913         .callback = kempld_create_platform_device,
0914     }, {
0915         .ident = "UNTG",
0916         .matches = {
0917             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0918             DMI_MATCH(DMI_BOARD_NAME, "COMe-cPC2"),
0919         },
0920         .driver_data = (void *)&kempld_platform_data_generic,
0921         .callback = kempld_create_platform_device,
0922     }, {
0923         .ident = "UUP6",
0924         .matches = {
0925             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0926             DMI_MATCH(DMI_BOARD_NAME, "COMe-cCT6"),
0927         },
0928         .driver_data = (void *)&kempld_platform_data_generic,
0929         .callback = kempld_create_platform_device,
0930     }, {
0931         .ident = "UTH6",
0932         .matches = {
0933             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0934             DMI_MATCH(DMI_BOARD_NAME, "COMe-cTH6"),
0935         },
0936         .driver_data = (void *)&kempld_platform_data_generic,
0937         .callback = kempld_create_platform_device,
0938     }, {
0939         .ident = "Q7AL",
0940         .matches = {
0941             DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
0942             DMI_MATCH(DMI_BOARD_NAME, "Qseven-Q7AL"),
0943         },
0944         .driver_data = (void *)&kempld_platform_data_generic,
0945         .callback = kempld_create_platform_device,
0946     },
0947     {}
0948 };
0949 MODULE_DEVICE_TABLE(dmi, kempld_dmi_table);
0950 
0951 static int __init kempld_init(void)
0952 {
0953     const struct dmi_system_id *id;
0954 
0955     if (force_device_id[0]) {
0956         for (id = kempld_dmi_table;
0957              id->matches[0].slot != DMI_NONE; id++)
0958             if (strstr(id->ident, force_device_id))
0959                 if (id->callback && !id->callback(id))
0960                     break;
0961         if (id->matches[0].slot == DMI_NONE)
0962             return -ENODEV;
0963     } else {
0964         dmi_check_system(kempld_dmi_table);
0965     }
0966 
0967     return platform_driver_register(&kempld_driver);
0968 }
0969 
0970 static void __exit kempld_exit(void)
0971 {
0972     if (kempld_pdev)
0973         platform_device_unregister(kempld_pdev);
0974 
0975     platform_driver_unregister(&kempld_driver);
0976 }
0977 
0978 module_init(kempld_init);
0979 module_exit(kempld_exit);
0980 
0981 MODULE_DESCRIPTION("KEM PLD Core Driver");
0982 MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
0983 MODULE_LICENSE("GPL");
0984 MODULE_ALIAS("platform:kempld-core");