brintos

brintos / linux-shallow public Read only

0
0
Text · 19.8 KiB · 8a33285 Raw
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