xref: /openbmc/linux/drivers/mfd/kempld-core.c (revision 8cc5e62b)
19f806850SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
243620a17SKevin Strasser /*
343620a17SKevin Strasser  * Kontron PLD MFD core driver
443620a17SKevin Strasser  *
543620a17SKevin Strasser  * Copyright (c) 2010-2013 Kontron Europe GmbH
643620a17SKevin Strasser  * Author: Michael Brunner <michael.brunner@kontron.com>
743620a17SKevin Strasser  */
843620a17SKevin Strasser 
943620a17SKevin Strasser #include <linux/platform_device.h>
1043620a17SKevin Strasser #include <linux/mfd/core.h>
1143620a17SKevin Strasser #include <linux/mfd/kempld.h>
1243620a17SKevin Strasser #include <linux/module.h>
1343620a17SKevin Strasser #include <linux/dmi.h>
1443620a17SKevin Strasser #include <linux/io.h>
1543620a17SKevin Strasser #include <linux/delay.h>
16e8299c73SMichael Brunner #include <linux/acpi.h>
1743620a17SKevin Strasser 
1843620a17SKevin Strasser #define MAX_ID_LEN 4
1943620a17SKevin Strasser static char force_device_id[MAX_ID_LEN + 1] = "";
209ef4e935SLee Jones module_param_string(force_device_id, force_device_id,
219ef4e935SLee Jones 		    sizeof(force_device_id), 0);
2243620a17SKevin Strasser MODULE_PARM_DESC(force_device_id, "Override detected product");
2343620a17SKevin Strasser 
2443620a17SKevin Strasser /*
2543620a17SKevin Strasser  * Get hardware mutex to block firmware from accessing the pld.
2643620a17SKevin Strasser  * It is possible for the firmware may hold the mutex for an extended length of
2743620a17SKevin Strasser  * time. This function will block until access has been granted.
2843620a17SKevin Strasser  */
kempld_get_hardware_mutex(struct kempld_device_data * pld)2943620a17SKevin Strasser static void kempld_get_hardware_mutex(struct kempld_device_data *pld)
3043620a17SKevin Strasser {
3143620a17SKevin Strasser 	/* The mutex bit will read 1 until access has been granted */
3243620a17SKevin Strasser 	while (ioread8(pld->io_index) & KEMPLD_MUTEX_KEY)
339ef4e935SLee Jones 		usleep_range(1000, 3000);
3443620a17SKevin Strasser }
3543620a17SKevin Strasser 
kempld_release_hardware_mutex(struct kempld_device_data * pld)3643620a17SKevin Strasser static void kempld_release_hardware_mutex(struct kempld_device_data *pld)
3743620a17SKevin Strasser {
3843620a17SKevin Strasser 	/* The harware mutex is released when 1 is written to the mutex bit. */
3943620a17SKevin Strasser 	iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
4043620a17SKevin Strasser }
4143620a17SKevin Strasser 
kempld_get_info_generic(struct kempld_device_data * pld)4243620a17SKevin Strasser static int kempld_get_info_generic(struct kempld_device_data *pld)
4343620a17SKevin Strasser {
4443620a17SKevin Strasser 	u16 version;
4543620a17SKevin Strasser 	u8 spec;
4643620a17SKevin Strasser 
4743620a17SKevin Strasser 	kempld_get_mutex(pld);
4843620a17SKevin Strasser 
4943620a17SKevin Strasser 	version = kempld_read16(pld, KEMPLD_VERSION);
5043620a17SKevin Strasser 	spec = kempld_read8(pld, KEMPLD_SPEC);
5143620a17SKevin Strasser 	pld->info.buildnr = kempld_read16(pld, KEMPLD_BUILDNR);
5243620a17SKevin Strasser 
5343620a17SKevin Strasser 	pld->info.minor = KEMPLD_VERSION_GET_MINOR(version);
5443620a17SKevin Strasser 	pld->info.major = KEMPLD_VERSION_GET_MAJOR(version);
5543620a17SKevin Strasser 	pld->info.number = KEMPLD_VERSION_GET_NUMBER(version);
5643620a17SKevin Strasser 	pld->info.type = KEMPLD_VERSION_GET_TYPE(version);
5743620a17SKevin Strasser 
5843620a17SKevin Strasser 	if (spec == 0xff) {
5943620a17SKevin Strasser 		pld->info.spec_minor = 0;
6043620a17SKevin Strasser 		pld->info.spec_major = 1;
6143620a17SKevin Strasser 	} else {
6243620a17SKevin Strasser 		pld->info.spec_minor = KEMPLD_SPEC_GET_MINOR(spec);
6343620a17SKevin Strasser 		pld->info.spec_major = KEMPLD_SPEC_GET_MAJOR(spec);
6443620a17SKevin Strasser 	}
6543620a17SKevin Strasser 
6643620a17SKevin Strasser 	if (pld->info.spec_major > 0)
6743620a17SKevin Strasser 		pld->feature_mask = kempld_read16(pld, KEMPLD_FEATURE);
6843620a17SKevin Strasser 	else
6943620a17SKevin Strasser 		pld->feature_mask = 0;
7043620a17SKevin Strasser 
7143620a17SKevin Strasser 	kempld_release_mutex(pld);
7243620a17SKevin Strasser 
7343620a17SKevin Strasser 	return 0;
7443620a17SKevin Strasser }
7543620a17SKevin Strasser 
7643620a17SKevin Strasser enum kempld_cells {
7743620a17SKevin Strasser 	KEMPLD_I2C = 0,
7843620a17SKevin Strasser 	KEMPLD_WDT,
7943620a17SKevin Strasser 	KEMPLD_GPIO,
8043620a17SKevin Strasser 	KEMPLD_UART,
8143620a17SKevin Strasser };
8243620a17SKevin Strasser 
83564de762SStephen Rothwell static const char *kempld_dev_names[] = {
84564de762SStephen Rothwell 	[KEMPLD_I2C] = "kempld-i2c",
85564de762SStephen Rothwell 	[KEMPLD_WDT] = "kempld-wdt",
86564de762SStephen Rothwell 	[KEMPLD_GPIO] = "kempld-gpio",
87564de762SStephen Rothwell 	[KEMPLD_UART] = "kempld-uart",
8843620a17SKevin Strasser };
8943620a17SKevin Strasser 
90564de762SStephen Rothwell #define KEMPLD_MAX_DEVS	ARRAY_SIZE(kempld_dev_names)
9143620a17SKevin Strasser 
kempld_register_cells_generic(struct kempld_device_data * pld)9243620a17SKevin Strasser static int kempld_register_cells_generic(struct kempld_device_data *pld)
9343620a17SKevin Strasser {
94564de762SStephen Rothwell 	struct mfd_cell devs[KEMPLD_MAX_DEVS] = {};
9543620a17SKevin Strasser 	int i = 0;
9643620a17SKevin Strasser 
9743620a17SKevin Strasser 	if (pld->feature_mask & KEMPLD_FEATURE_BIT_I2C)
98564de762SStephen Rothwell 		devs[i++].name = kempld_dev_names[KEMPLD_I2C];
9943620a17SKevin Strasser 
10043620a17SKevin Strasser 	if (pld->feature_mask & KEMPLD_FEATURE_BIT_WATCHDOG)
101564de762SStephen Rothwell 		devs[i++].name = kempld_dev_names[KEMPLD_WDT];
10243620a17SKevin Strasser 
10343620a17SKevin Strasser 	if (pld->feature_mask & KEMPLD_FEATURE_BIT_GPIO)
104564de762SStephen Rothwell 		devs[i++].name = kempld_dev_names[KEMPLD_GPIO];
10543620a17SKevin Strasser 
10643620a17SKevin Strasser 	if (pld->feature_mask & KEMPLD_FEATURE_MASK_UART)
107564de762SStephen Rothwell 		devs[i++].name = kempld_dev_names[KEMPLD_UART];
10843620a17SKevin Strasser 
10943620a17SKevin Strasser 	return mfd_add_devices(pld->dev, -1, devs, i, NULL, 0, NULL);
11043620a17SKevin Strasser }
11143620a17SKevin Strasser 
11243620a17SKevin Strasser static struct resource kempld_ioresource = {
11343620a17SKevin Strasser 	.start	= KEMPLD_IOINDEX,
11443620a17SKevin Strasser 	.end	= KEMPLD_IODATA,
11543620a17SKevin Strasser 	.flags	= IORESOURCE_IO,
11643620a17SKevin Strasser };
11743620a17SKevin Strasser 
11843620a17SKevin Strasser static const struct kempld_platform_data kempld_platform_data_generic = {
11943620a17SKevin Strasser 	.pld_clock		= KEMPLD_CLK,
12043620a17SKevin Strasser 	.ioresource		= &kempld_ioresource,
12143620a17SKevin Strasser 	.get_hardware_mutex	= kempld_get_hardware_mutex,
12243620a17SKevin Strasser 	.release_hardware_mutex	= kempld_release_hardware_mutex,
12343620a17SKevin Strasser 	.get_info		= kempld_get_info_generic,
12443620a17SKevin Strasser 	.register_cells		= kempld_register_cells_generic,
12543620a17SKevin Strasser };
12643620a17SKevin Strasser 
12743620a17SKevin Strasser static struct platform_device *kempld_pdev;
12843620a17SKevin Strasser 
kempld_create_platform_device(const struct dmi_system_id * id)12943620a17SKevin Strasser static int kempld_create_platform_device(const struct dmi_system_id *id)
13043620a17SKevin Strasser {
131bf1cafa1SJulia Lawall 	const struct kempld_platform_data *pdata = id->driver_data;
13243620a17SKevin Strasser 	int ret;
13343620a17SKevin Strasser 
13443620a17SKevin Strasser 	kempld_pdev = platform_device_alloc("kempld", -1);
13543620a17SKevin Strasser 	if (!kempld_pdev)
13643620a17SKevin Strasser 		return -ENOMEM;
13743620a17SKevin Strasser 
13843620a17SKevin Strasser 	ret = platform_device_add_data(kempld_pdev, pdata, sizeof(*pdata));
13943620a17SKevin Strasser 	if (ret)
14043620a17SKevin Strasser 		goto err;
14143620a17SKevin Strasser 
14243620a17SKevin Strasser 	ret = platform_device_add_resources(kempld_pdev, pdata->ioresource, 1);
14343620a17SKevin Strasser 	if (ret)
14443620a17SKevin Strasser 		goto err;
14543620a17SKevin Strasser 
14643620a17SKevin Strasser 	ret = platform_device_add(kempld_pdev);
14743620a17SKevin Strasser 	if (ret)
14843620a17SKevin Strasser 		goto err;
14943620a17SKevin Strasser 
15043620a17SKevin Strasser 	return 0;
15143620a17SKevin Strasser err:
15243620a17SKevin Strasser 	platform_device_put(kempld_pdev);
15343620a17SKevin Strasser 	return ret;
15443620a17SKevin Strasser }
15543620a17SKevin Strasser 
15643620a17SKevin Strasser /**
15743620a17SKevin Strasser  * kempld_read8 - read 8 bit register
15843620a17SKevin Strasser  * @pld: kempld_device_data structure describing the PLD
15943620a17SKevin Strasser  * @index: register index on the chip
16043620a17SKevin Strasser  *
16143620a17SKevin Strasser  * kempld_get_mutex must be called prior to calling this function.
16243620a17SKevin Strasser  */
kempld_read8(struct kempld_device_data * pld,u8 index)16343620a17SKevin Strasser u8 kempld_read8(struct kempld_device_data *pld, u8 index)
16443620a17SKevin Strasser {
16543620a17SKevin Strasser 	iowrite8(index, pld->io_index);
16643620a17SKevin Strasser 	return ioread8(pld->io_data);
16743620a17SKevin Strasser }
16843620a17SKevin Strasser EXPORT_SYMBOL_GPL(kempld_read8);
16943620a17SKevin Strasser 
17043620a17SKevin Strasser /**
17143620a17SKevin Strasser  * kempld_write8 - write 8 bit register
17243620a17SKevin Strasser  * @pld: kempld_device_data structure describing the PLD
17343620a17SKevin Strasser  * @index: register index on the chip
17443620a17SKevin Strasser  * @data: new register value
17543620a17SKevin Strasser  *
17643620a17SKevin Strasser  * kempld_get_mutex must be called prior to calling this function.
17743620a17SKevin Strasser  */
kempld_write8(struct kempld_device_data * pld,u8 index,u8 data)17843620a17SKevin Strasser void kempld_write8(struct kempld_device_data *pld, u8 index, u8 data)
17943620a17SKevin Strasser {
18043620a17SKevin Strasser 	iowrite8(index, pld->io_index);
18143620a17SKevin Strasser 	iowrite8(data, pld->io_data);
18243620a17SKevin Strasser }
18343620a17SKevin Strasser EXPORT_SYMBOL_GPL(kempld_write8);
18443620a17SKevin Strasser 
18543620a17SKevin Strasser /**
18643620a17SKevin Strasser  * kempld_read16 - read 16 bit register
18743620a17SKevin Strasser  * @pld: kempld_device_data structure describing the PLD
18843620a17SKevin Strasser  * @index: register index on the chip
18943620a17SKevin Strasser  *
19043620a17SKevin Strasser  * kempld_get_mutex must be called prior to calling this function.
19143620a17SKevin Strasser  */
kempld_read16(struct kempld_device_data * pld,u8 index)19243620a17SKevin Strasser u16 kempld_read16(struct kempld_device_data *pld, u8 index)
19343620a17SKevin Strasser {
19443620a17SKevin Strasser 	return kempld_read8(pld, index) | kempld_read8(pld, index + 1) << 8;
19543620a17SKevin Strasser }
19643620a17SKevin Strasser EXPORT_SYMBOL_GPL(kempld_read16);
19743620a17SKevin Strasser 
19843620a17SKevin Strasser /**
19943620a17SKevin Strasser  * kempld_write16 - write 16 bit register
20043620a17SKevin Strasser  * @pld: kempld_device_data structure describing the PLD
20143620a17SKevin Strasser  * @index: register index on the chip
20243620a17SKevin Strasser  * @data: new register value
20343620a17SKevin Strasser  *
20443620a17SKevin Strasser  * kempld_get_mutex must be called prior to calling this function.
20543620a17SKevin Strasser  */
kempld_write16(struct kempld_device_data * pld,u8 index,u16 data)20643620a17SKevin Strasser void kempld_write16(struct kempld_device_data *pld, u8 index, u16 data)
20743620a17SKevin Strasser {
20843620a17SKevin Strasser 	kempld_write8(pld, index, (u8)data);
20943620a17SKevin Strasser 	kempld_write8(pld, index + 1, (u8)(data >> 8));
21043620a17SKevin Strasser }
21143620a17SKevin Strasser EXPORT_SYMBOL_GPL(kempld_write16);
21243620a17SKevin Strasser 
21343620a17SKevin Strasser /**
21443620a17SKevin Strasser  * kempld_read32 - read 32 bit register
21543620a17SKevin Strasser  * @pld: kempld_device_data structure describing the PLD
21643620a17SKevin Strasser  * @index: register index on the chip
21743620a17SKevin Strasser  *
21843620a17SKevin Strasser  * kempld_get_mutex must be called prior to calling this function.
21943620a17SKevin Strasser  */
kempld_read32(struct kempld_device_data * pld,u8 index)22043620a17SKevin Strasser u32 kempld_read32(struct kempld_device_data *pld, u8 index)
22143620a17SKevin Strasser {
22243620a17SKevin Strasser 	return kempld_read16(pld, index) | kempld_read16(pld, index + 2) << 16;
22343620a17SKevin Strasser }
22443620a17SKevin Strasser EXPORT_SYMBOL_GPL(kempld_read32);
22543620a17SKevin Strasser 
22643620a17SKevin Strasser /**
22743620a17SKevin Strasser  * kempld_write32 - write 32 bit register
22843620a17SKevin Strasser  * @pld: kempld_device_data structure describing the PLD
22943620a17SKevin Strasser  * @index: register index on the chip
23043620a17SKevin Strasser  * @data: new register value
23143620a17SKevin Strasser  *
23243620a17SKevin Strasser  * kempld_get_mutex must be called prior to calling this function.
23343620a17SKevin Strasser  */
kempld_write32(struct kempld_device_data * pld,u8 index,u32 data)23443620a17SKevin Strasser void kempld_write32(struct kempld_device_data *pld, u8 index, u32 data)
23543620a17SKevin Strasser {
23643620a17SKevin Strasser 	kempld_write16(pld, index, (u16)data);
23743620a17SKevin Strasser 	kempld_write16(pld, index + 2, (u16)(data >> 16));
23843620a17SKevin Strasser }
23943620a17SKevin Strasser EXPORT_SYMBOL_GPL(kempld_write32);
24043620a17SKevin Strasser 
24143620a17SKevin Strasser /**
24243620a17SKevin Strasser  * kempld_get_mutex - acquire PLD mutex
24343620a17SKevin Strasser  * @pld: kempld_device_data structure describing the PLD
24443620a17SKevin Strasser  */
kempld_get_mutex(struct kempld_device_data * pld)24543620a17SKevin Strasser void kempld_get_mutex(struct kempld_device_data *pld)
24643620a17SKevin Strasser {
247bf1cafa1SJulia Lawall 	const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
24843620a17SKevin Strasser 
24943620a17SKevin Strasser 	mutex_lock(&pld->lock);
25043620a17SKevin Strasser 	pdata->get_hardware_mutex(pld);
25143620a17SKevin Strasser }
25243620a17SKevin Strasser EXPORT_SYMBOL_GPL(kempld_get_mutex);
25343620a17SKevin Strasser 
25443620a17SKevin Strasser /**
25543620a17SKevin Strasser  * kempld_release_mutex - release PLD mutex
25643620a17SKevin Strasser  * @pld: kempld_device_data structure describing the PLD
25743620a17SKevin Strasser  */
kempld_release_mutex(struct kempld_device_data * pld)25843620a17SKevin Strasser void kempld_release_mutex(struct kempld_device_data *pld)
25943620a17SKevin Strasser {
260bf1cafa1SJulia Lawall 	const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
26143620a17SKevin Strasser 
26243620a17SKevin Strasser 	pdata->release_hardware_mutex(pld);
26343620a17SKevin Strasser 	mutex_unlock(&pld->lock);
26443620a17SKevin Strasser }
26543620a17SKevin Strasser EXPORT_SYMBOL_GPL(kempld_release_mutex);
26643620a17SKevin Strasser 
26743620a17SKevin Strasser /**
26843620a17SKevin Strasser  * kempld_get_info - update device specific information
26943620a17SKevin Strasser  * @pld: kempld_device_data structure describing the PLD
27043620a17SKevin Strasser  *
27143620a17SKevin Strasser  * This function calls the configured board specific kempld_get_info_XXXX
27243620a17SKevin Strasser  * function which is responsible for gathering information about the specific
27343620a17SKevin Strasser  * hardware. The information is then stored within the pld structure.
27443620a17SKevin Strasser  */
kempld_get_info(struct kempld_device_data * pld)27543620a17SKevin Strasser static int kempld_get_info(struct kempld_device_data *pld)
27643620a17SKevin Strasser {
27758a9e5b9SMichael Brunner 	int ret;
278bf1cafa1SJulia Lawall 	const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
27958a9e5b9SMichael Brunner 	char major, minor;
28043620a17SKevin Strasser 
28158a9e5b9SMichael Brunner 	ret = pdata->get_info(pld);
28258a9e5b9SMichael Brunner 	if (ret)
28358a9e5b9SMichael Brunner 		return ret;
28458a9e5b9SMichael Brunner 
28558a9e5b9SMichael Brunner 	/* The Kontron PLD firmware version string has the following format:
28658a9e5b9SMichael Brunner 	 * Pwxy.zzzz
28758a9e5b9SMichael Brunner 	 *   P:    Fixed
28858a9e5b9SMichael Brunner 	 *   w:    PLD number    - 1 hex digit
28958a9e5b9SMichael Brunner 	 *   x:    Major version - 1 alphanumerical digit (0-9A-V)
29058a9e5b9SMichael Brunner 	 *   y:    Minor version - 1 alphanumerical digit (0-9A-V)
29158a9e5b9SMichael Brunner 	 *   zzzz: Build number  - 4 zero padded hex digits */
29258a9e5b9SMichael Brunner 
29358a9e5b9SMichael Brunner 	if (pld->info.major < 10)
29458a9e5b9SMichael Brunner 		major = pld->info.major + '0';
29558a9e5b9SMichael Brunner 	else
29658a9e5b9SMichael Brunner 		major = (pld->info.major - 10) + 'A';
29758a9e5b9SMichael Brunner 	if (pld->info.minor < 10)
29858a9e5b9SMichael Brunner 		minor = pld->info.minor + '0';
29958a9e5b9SMichael Brunner 	else
30058a9e5b9SMichael Brunner 		minor = (pld->info.minor - 10) + 'A';
30158a9e5b9SMichael Brunner 
30258a9e5b9SMichael Brunner 	ret = scnprintf(pld->info.version, sizeof(pld->info.version),
30358a9e5b9SMichael Brunner 			"P%X%c%c.%04X", pld->info.number, major, minor,
30458a9e5b9SMichael Brunner 			pld->info.buildnr);
30558a9e5b9SMichael Brunner 	if (ret < 0)
30658a9e5b9SMichael Brunner 		return ret;
30758a9e5b9SMichael Brunner 
30858a9e5b9SMichael Brunner 	return 0;
30943620a17SKevin Strasser }
31043620a17SKevin Strasser 
31143620a17SKevin Strasser /*
31243620a17SKevin Strasser  * kempld_register_cells - register cell drivers
31343620a17SKevin Strasser  *
31443620a17SKevin Strasser  * This function registers cell drivers for the detected hardware by calling
31543620a17SKevin Strasser  * the configured kempld_register_cells_XXXX function which is responsible
31643620a17SKevin Strasser  * to detect and register the needed cell drivers.
31743620a17SKevin Strasser  */
kempld_register_cells(struct kempld_device_data * pld)31843620a17SKevin Strasser static int kempld_register_cells(struct kempld_device_data *pld)
31943620a17SKevin Strasser {
320bf1cafa1SJulia Lawall 	const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
32143620a17SKevin Strasser 
32243620a17SKevin Strasser 	return pdata->register_cells(pld);
32343620a17SKevin Strasser }
32443620a17SKevin Strasser 
kempld_get_type_string(struct kempld_device_data * pld)32558a9e5b9SMichael Brunner static const char *kempld_get_type_string(struct kempld_device_data *pld)
32658a9e5b9SMichael Brunner {
32758a9e5b9SMichael Brunner 	const char *version_type;
32858a9e5b9SMichael Brunner 
32958a9e5b9SMichael Brunner 	switch (pld->info.type) {
33058a9e5b9SMichael Brunner 	case 0:
33158a9e5b9SMichael Brunner 		version_type = "release";
33258a9e5b9SMichael Brunner 		break;
33358a9e5b9SMichael Brunner 	case 1:
33458a9e5b9SMichael Brunner 		version_type = "debug";
33558a9e5b9SMichael Brunner 		break;
33658a9e5b9SMichael Brunner 	case 2:
33758a9e5b9SMichael Brunner 		version_type = "custom";
33858a9e5b9SMichael Brunner 		break;
33958a9e5b9SMichael Brunner 	default:
34058a9e5b9SMichael Brunner 		version_type = "unspecified";
34158a9e5b9SMichael Brunner 		break;
34258a9e5b9SMichael Brunner 	}
34358a9e5b9SMichael Brunner 
34458a9e5b9SMichael Brunner 	return version_type;
34558a9e5b9SMichael Brunner }
34658a9e5b9SMichael Brunner 
pld_version_show(struct device * dev,struct device_attribute * attr,char * buf)347cd5bde2cSZhen Lei static ssize_t pld_version_show(struct device *dev,
34858a9e5b9SMichael Brunner 				struct device_attribute *attr, char *buf)
34958a9e5b9SMichael Brunner {
35058a9e5b9SMichael Brunner 	struct kempld_device_data *pld = dev_get_drvdata(dev);
35158a9e5b9SMichael Brunner 
352*8cc5e62bSye xingchen 	return sysfs_emit(buf, "%s\n", pld->info.version);
35358a9e5b9SMichael Brunner }
35458a9e5b9SMichael Brunner 
pld_specification_show(struct device * dev,struct device_attribute * attr,char * buf)355cd5bde2cSZhen Lei static ssize_t pld_specification_show(struct device *dev,
35658a9e5b9SMichael Brunner 				      struct device_attribute *attr, char *buf)
35758a9e5b9SMichael Brunner {
35858a9e5b9SMichael Brunner 	struct kempld_device_data *pld = dev_get_drvdata(dev);
35958a9e5b9SMichael Brunner 
360*8cc5e62bSye xingchen 	return sysfs_emit(buf, "%d.%d\n", pld->info.spec_major, pld->info.spec_minor);
36158a9e5b9SMichael Brunner }
36258a9e5b9SMichael Brunner 
pld_type_show(struct device * dev,struct device_attribute * attr,char * buf)363cd5bde2cSZhen Lei static ssize_t pld_type_show(struct device *dev,
36458a9e5b9SMichael Brunner 			     struct device_attribute *attr, char *buf)
36558a9e5b9SMichael Brunner {
36658a9e5b9SMichael Brunner 	struct kempld_device_data *pld = dev_get_drvdata(dev);
36758a9e5b9SMichael Brunner 
368*8cc5e62bSye xingchen 	return sysfs_emit(buf, "%s\n", kempld_get_type_string(pld));
36958a9e5b9SMichael Brunner }
37058a9e5b9SMichael Brunner 
371cd5bde2cSZhen Lei static DEVICE_ATTR_RO(pld_version);
372cd5bde2cSZhen Lei static DEVICE_ATTR_RO(pld_specification);
373cd5bde2cSZhen Lei static DEVICE_ATTR_RO(pld_type);
37458a9e5b9SMichael Brunner 
37558a9e5b9SMichael Brunner static struct attribute *pld_attributes[] = {
37658a9e5b9SMichael Brunner 	&dev_attr_pld_version.attr,
37758a9e5b9SMichael Brunner 	&dev_attr_pld_specification.attr,
37858a9e5b9SMichael Brunner 	&dev_attr_pld_type.attr,
37958a9e5b9SMichael Brunner 	NULL
38058a9e5b9SMichael Brunner };
38158a9e5b9SMichael Brunner 
38258a9e5b9SMichael Brunner static const struct attribute_group pld_attr_group = {
38358a9e5b9SMichael Brunner 	.attrs = pld_attributes,
38458a9e5b9SMichael Brunner };
38558a9e5b9SMichael Brunner 
kempld_detect_device(struct kempld_device_data * pld)38643620a17SKevin Strasser static int kempld_detect_device(struct kempld_device_data *pld)
38743620a17SKevin Strasser {
38843620a17SKevin Strasser 	u8 index_reg;
38943620a17SKevin Strasser 	int ret;
39043620a17SKevin Strasser 
39143620a17SKevin Strasser 	mutex_lock(&pld->lock);
39243620a17SKevin Strasser 
39343620a17SKevin Strasser 	/* Check for empty IO space */
39443620a17SKevin Strasser 	index_reg = ioread8(pld->io_index);
39543620a17SKevin Strasser 	if (index_reg == 0xff && ioread8(pld->io_data) == 0xff) {
39643620a17SKevin Strasser 		mutex_unlock(&pld->lock);
39743620a17SKevin Strasser 		return -ENODEV;
39843620a17SKevin Strasser 	}
39943620a17SKevin Strasser 
400204747c9SGuenter Roeck 	/* Release hardware mutex if acquired */
401204747c9SGuenter Roeck 	if (!(index_reg & KEMPLD_MUTEX_KEY)) {
40243620a17SKevin Strasser 		iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
403204747c9SGuenter Roeck 		/* PXT and COMe-cPC2 boards may require a second release */
404204747c9SGuenter Roeck 		iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
405204747c9SGuenter Roeck 	}
40643620a17SKevin Strasser 
40743620a17SKevin Strasser 	mutex_unlock(&pld->lock);
40843620a17SKevin Strasser 
40943620a17SKevin Strasser 	ret = kempld_get_info(pld);
41043620a17SKevin Strasser 	if (ret)
41143620a17SKevin Strasser 		return ret;
41243620a17SKevin Strasser 
41358a9e5b9SMichael Brunner 	dev_info(pld->dev, "Found Kontron PLD - %s (%s), spec %d.%d\n",
41458a9e5b9SMichael Brunner 		 pld->info.version, kempld_get_type_string(pld),
41558a9e5b9SMichael Brunner 		 pld->info.spec_major, pld->info.spec_minor);
41643620a17SKevin Strasser 
41758a9e5b9SMichael Brunner 	ret = sysfs_create_group(&pld->dev->kobj, &pld_attr_group);
41858a9e5b9SMichael Brunner 	if (ret)
41958a9e5b9SMichael Brunner 		return ret;
42043620a17SKevin Strasser 
42158a9e5b9SMichael Brunner 	ret = kempld_register_cells(pld);
42258a9e5b9SMichael Brunner 	if (ret)
42358a9e5b9SMichael Brunner 		sysfs_remove_group(&pld->dev->kobj, &pld_attr_group);
42458a9e5b9SMichael Brunner 
42558a9e5b9SMichael Brunner 	return ret;
42643620a17SKevin Strasser }
42743620a17SKevin Strasser 
428e8299c73SMichael Brunner #ifdef CONFIG_ACPI
kempld_get_acpi_data(struct platform_device * pdev)429e8299c73SMichael Brunner static int kempld_get_acpi_data(struct platform_device *pdev)
430e8299c73SMichael Brunner {
431e8299c73SMichael Brunner 	struct list_head resource_list;
432e8299c73SMichael Brunner 	struct resource *resources;
433e8299c73SMichael Brunner 	struct resource_entry *rentry;
434e8299c73SMichael Brunner 	struct device *dev = &pdev->dev;
435e8299c73SMichael Brunner 	struct acpi_device *acpi_dev = ACPI_COMPANION(dev);
436e8299c73SMichael Brunner 	const struct kempld_platform_data *pdata;
437e8299c73SMichael Brunner 	int ret;
438e8299c73SMichael Brunner 	int count;
439e8299c73SMichael Brunner 
440e8299c73SMichael Brunner 	pdata = acpi_device_get_match_data(dev);
441e8299c73SMichael Brunner 	ret = platform_device_add_data(pdev, pdata,
442e8299c73SMichael Brunner 				       sizeof(struct kempld_platform_data));
443e8299c73SMichael Brunner 	if (ret)
444e8299c73SMichael Brunner 		return ret;
445e8299c73SMichael Brunner 
446e8299c73SMichael Brunner 	INIT_LIST_HEAD(&resource_list);
447e8299c73SMichael Brunner 	ret = acpi_dev_get_resources(acpi_dev, &resource_list, NULL, NULL);
448e8299c73SMichael Brunner 	if (ret < 0)
449e8299c73SMichael Brunner 		goto out;
450e8299c73SMichael Brunner 
451e8299c73SMichael Brunner 	count = ret;
452e8299c73SMichael Brunner 
453e8299c73SMichael Brunner 	if (count == 0) {
454e8299c73SMichael Brunner 		ret = platform_device_add_resources(pdev, pdata->ioresource, 1);
455e8299c73SMichael Brunner 		goto out;
456e8299c73SMichael Brunner 	}
457e8299c73SMichael Brunner 
458e8299c73SMichael Brunner 	resources = devm_kcalloc(&acpi_dev->dev, count, sizeof(*resources),
459e8299c73SMichael Brunner 				 GFP_KERNEL);
460e8299c73SMichael Brunner 	if (!resources) {
461e8299c73SMichael Brunner 		ret = -ENOMEM;
462e8299c73SMichael Brunner 		goto out;
463e8299c73SMichael Brunner 	}
464e8299c73SMichael Brunner 
465e8299c73SMichael Brunner 	count = 0;
466e8299c73SMichael Brunner 	list_for_each_entry(rentry, &resource_list, node) {
467e8299c73SMichael Brunner 		memcpy(&resources[count], rentry->res,
468e8299c73SMichael Brunner 		       sizeof(*resources));
469e8299c73SMichael Brunner 		count++;
470e8299c73SMichael Brunner 	}
471e8299c73SMichael Brunner 	ret = platform_device_add_resources(pdev, resources, count);
472e8299c73SMichael Brunner 
473e8299c73SMichael Brunner out:
474e8299c73SMichael Brunner 	acpi_dev_free_resource_list(&resource_list);
475e8299c73SMichael Brunner 
476e8299c73SMichael Brunner 	return ret;
477e8299c73SMichael Brunner }
478e8299c73SMichael Brunner #else
kempld_get_acpi_data(struct platform_device * pdev)479e8299c73SMichael Brunner static int kempld_get_acpi_data(struct platform_device *pdev)
480e8299c73SMichael Brunner {
481e8299c73SMichael Brunner 	return -ENODEV;
482e8299c73SMichael Brunner }
483e8299c73SMichael Brunner #endif /* CONFIG_ACPI */
484e8299c73SMichael Brunner 
kempld_probe(struct platform_device * pdev)48543620a17SKevin Strasser static int kempld_probe(struct platform_device *pdev)
48643620a17SKevin Strasser {
487e8299c73SMichael Brunner 	const struct kempld_platform_data *pdata;
48843620a17SKevin Strasser 	struct device *dev = &pdev->dev;
48943620a17SKevin Strasser 	struct kempld_device_data *pld;
49043620a17SKevin Strasser 	struct resource *ioport;
491e8299c73SMichael Brunner 	int ret;
492e8299c73SMichael Brunner 
493e8299c73SMichael Brunner 	if (kempld_pdev == NULL) {
494e8299c73SMichael Brunner 		/*
495e8299c73SMichael Brunner 		 * No kempld_pdev device has been registered in kempld_init,
496e8299c73SMichael Brunner 		 * so we seem to be probing an ACPI platform device.
497e8299c73SMichael Brunner 		 */
498e8299c73SMichael Brunner 		ret = kempld_get_acpi_data(pdev);
499e8299c73SMichael Brunner 		if (ret)
500e8299c73SMichael Brunner 			return ret;
501e8299c73SMichael Brunner 	} else if (kempld_pdev != pdev) {
502e8299c73SMichael Brunner 		/*
503e8299c73SMichael Brunner 		 * The platform device we are probing is not the one we
504e8299c73SMichael Brunner 		 * registered in kempld_init using the DMI table, so this one
505e8299c73SMichael Brunner 		 * comes from ACPI.
506e8299c73SMichael Brunner 		 * As we can only probe one - abort here and use the DMI
507e8299c73SMichael Brunner 		 * based one instead.
508e8299c73SMichael Brunner 		 */
509e8299c73SMichael Brunner 		dev_notice(dev, "platform device exists - not using ACPI\n");
510e8299c73SMichael Brunner 		return -ENODEV;
511e8299c73SMichael Brunner 	}
512e8299c73SMichael Brunner 	pdata = dev_get_platdata(dev);
51343620a17SKevin Strasser 
51443620a17SKevin Strasser 	pld = devm_kzalloc(dev, sizeof(*pld), GFP_KERNEL);
51543620a17SKevin Strasser 	if (!pld)
51643620a17SKevin Strasser 		return -ENOMEM;
51743620a17SKevin Strasser 
51843620a17SKevin Strasser 	ioport = platform_get_resource(pdev, IORESOURCE_IO, 0);
51943620a17SKevin Strasser 	if (!ioport)
52043620a17SKevin Strasser 		return -EINVAL;
52143620a17SKevin Strasser 
52243620a17SKevin Strasser 	pld->io_base = devm_ioport_map(dev, ioport->start,
523263a7c57SVasyl Gomonovych 					resource_size(ioport));
52443620a17SKevin Strasser 	if (!pld->io_base)
52543620a17SKevin Strasser 		return -ENOMEM;
52643620a17SKevin Strasser 
52743620a17SKevin Strasser 	pld->io_index = pld->io_base;
52843620a17SKevin Strasser 	pld->io_data = pld->io_base + 1;
52943620a17SKevin Strasser 	pld->pld_clock = pdata->pld_clock;
53043620a17SKevin Strasser 	pld->dev = dev;
53143620a17SKevin Strasser 
53243620a17SKevin Strasser 	mutex_init(&pld->lock);
53343620a17SKevin Strasser 	platform_set_drvdata(pdev, pld);
53443620a17SKevin Strasser 
535d8498df1SJavier Martinez Canillas 	return kempld_detect_device(pld);
53643620a17SKevin Strasser }
53743620a17SKevin Strasser 
kempld_remove(struct platform_device * pdev)53843620a17SKevin Strasser static int kempld_remove(struct platform_device *pdev)
53943620a17SKevin Strasser {
54043620a17SKevin Strasser 	struct kempld_device_data *pld = platform_get_drvdata(pdev);
541bf1cafa1SJulia Lawall 	const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
54243620a17SKevin Strasser 
54358a9e5b9SMichael Brunner 	sysfs_remove_group(&pld->dev->kobj, &pld_attr_group);
54458a9e5b9SMichael Brunner 
54543620a17SKevin Strasser 	mfd_remove_devices(&pdev->dev);
54643620a17SKevin Strasser 	pdata->release_hardware_mutex(pld);
54743620a17SKevin Strasser 
54843620a17SKevin Strasser 	return 0;
54943620a17SKevin Strasser }
55043620a17SKevin Strasser 
5516d81dc3cSLee Jones #ifdef CONFIG_ACPI
552e8299c73SMichael Brunner static const struct acpi_device_id kempld_acpi_table[] = {
5530cd3aa99SMichael Brunner 	{ "KEM0000", (kernel_ulong_t)&kempld_platform_data_generic },
554e8299c73SMichael Brunner 	{ "KEM0001", (kernel_ulong_t)&kempld_platform_data_generic },
555e8299c73SMichael Brunner 	{}
556e8299c73SMichael Brunner };
557e8299c73SMichael Brunner MODULE_DEVICE_TABLE(acpi, kempld_acpi_table);
5586d81dc3cSLee Jones #endif
559e8299c73SMichael Brunner 
56043620a17SKevin Strasser static struct platform_driver kempld_driver = {
56143620a17SKevin Strasser 	.driver		= {
56243620a17SKevin Strasser 		.name	= "kempld",
563e8299c73SMichael Brunner 		.acpi_match_table = ACPI_PTR(kempld_acpi_table),
56443620a17SKevin Strasser 	},
56543620a17SKevin Strasser 	.probe		= kempld_probe,
56643620a17SKevin Strasser 	.remove		= kempld_remove,
56743620a17SKevin Strasser };
56843620a17SKevin Strasser 
5696faadbbbSChristoph Hellwig static const struct dmi_system_id kempld_dmi_table[] __initconst = {
57043620a17SKevin Strasser 	{
571e33ad65aSMichael Brunner 		.ident = "BBD6",
572e33ad65aSMichael Brunner 		.matches = {
573e33ad65aSMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
574e33ad65aSMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-bBD"),
575e33ad65aSMichael Brunner 		},
576e33ad65aSMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
577e33ad65aSMichael Brunner 		.callback = kempld_create_platform_device,
578e33ad65aSMichael Brunner 	}, {
57918ca2ba5SMichael Brunner 		.ident = "BBL6",
58018ca2ba5SMichael Brunner 		.matches = {
58118ca2ba5SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
58218ca2ba5SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-bBL6"),
58318ca2ba5SMichael Brunner 		},
58418ca2ba5SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
58518ca2ba5SMichael Brunner 		.callback = kempld_create_platform_device,
58618ca2ba5SMichael Brunner 	}, {
5870cd3aa99SMichael Brunner 		.ident = "BDV7",
5880cd3aa99SMichael Brunner 		.matches = {
5890cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
5900cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-bDV7"),
5910cd3aa99SMichael Brunner 		},
5920cd3aa99SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
5930cd3aa99SMichael Brunner 		.callback = kempld_create_platform_device,
5940cd3aa99SMichael Brunner 	}, {
595c1d33b1bSMichael Brunner 		.ident = "BHL6",
596c1d33b1bSMichael Brunner 		.matches = {
597c1d33b1bSMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
598c1d33b1bSMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-bHL6"),
599c1d33b1bSMichael Brunner 		},
600c1d33b1bSMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
601c1d33b1bSMichael Brunner 		.callback = kempld_create_platform_device,
602fb358e43SMichael Brunner 	}, {
603e33ad65aSMichael Brunner 		.ident = "BKL6",
604e33ad65aSMichael Brunner 		.matches = {
605e33ad65aSMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
606e33ad65aSMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-bKL6"),
607e33ad65aSMichael Brunner 		},
608e33ad65aSMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
609e33ad65aSMichael Brunner 		.callback = kempld_create_platform_device,
610e33ad65aSMichael Brunner 	}, {
611e33ad65aSMichael Brunner 		.ident = "BSL6",
612e33ad65aSMichael Brunner 		.matches = {
613e33ad65aSMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
614e33ad65aSMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-bSL6"),
615e33ad65aSMichael Brunner 		},
616e33ad65aSMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
617e33ad65aSMichael Brunner 		.callback = kempld_create_platform_device,
618e33ad65aSMichael Brunner 	}, {
619e33ad65aSMichael Brunner 		.ident = "CAL6",
620e33ad65aSMichael Brunner 		.matches = {
621e33ad65aSMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
622e33ad65aSMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-cAL"),
623e33ad65aSMichael Brunner 		},
624e33ad65aSMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
625e33ad65aSMichael Brunner 		.callback = kempld_create_platform_device,
626e33ad65aSMichael Brunner 	}, {
627fb358e43SMichael Brunner 		.ident = "CBL6",
628fb358e43SMichael Brunner 		.matches = {
629fb358e43SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
630fb358e43SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-cBL6"),
631c1d33b1bSMichael Brunner 		},
632fb358e43SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
633fb358e43SMichael Brunner 		.callback = kempld_create_platform_device,
634fb358e43SMichael Brunner 	}, {
63518ca2ba5SMichael Brunner 		.ident = "CBW6",
63618ca2ba5SMichael Brunner 		.matches = {
63718ca2ba5SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
63818ca2ba5SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-cBW6"),
63918ca2ba5SMichael Brunner 		},
64018ca2ba5SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
64118ca2ba5SMichael Brunner 		.callback = kempld_create_platform_device,
64218ca2ba5SMichael Brunner 	}, {
64343620a17SKevin Strasser 		.ident = "CCR2",
64443620a17SKevin Strasser 		.matches = {
64543620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
64643620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP2"),
64743620a17SKevin Strasser 		},
64843620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
64943620a17SKevin Strasser 		.callback = kempld_create_platform_device,
65043620a17SKevin Strasser 	}, {
65143620a17SKevin Strasser 		.ident = "CCR6",
65243620a17SKevin Strasser 		.matches = {
65343620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
65443620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP6"),
65543620a17SKevin Strasser 		},
65643620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
65743620a17SKevin Strasser 		.callback = kempld_create_platform_device,
65843620a17SKevin Strasser 	}, {
6590cd3aa99SMichael Brunner 		.ident = "CDV7",
6600cd3aa99SMichael Brunner 		.matches = {
6610cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
6620cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-cDV7"),
6630cd3aa99SMichael Brunner 		},
6640cd3aa99SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
6650cd3aa99SMichael Brunner 		.callback = kempld_create_platform_device,
6660cd3aa99SMichael Brunner 	}, {
667a3ee7509SMichael Brunner 		.ident = "CHL6",
668a3ee7509SMichael Brunner 		.matches = {
669a3ee7509SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
670a3ee7509SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-cHL6"),
671a3ee7509SMichael Brunner 		},
672a3ee7509SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
673a3ee7509SMichael Brunner 		.callback = kempld_create_platform_device,
674a3ee7509SMichael Brunner 	}, {
67543620a17SKevin Strasser 		.ident = "CHR2",
67643620a17SKevin Strasser 		.matches = {
67743620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
67843620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T2"),
67943620a17SKevin Strasser 		},
68043620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
68143620a17SKevin Strasser 		.callback = kempld_create_platform_device,
68243620a17SKevin Strasser 	}, {
68343620a17SKevin Strasser 		.ident = "CHR2",
68443620a17SKevin Strasser 		.matches = {
68543620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
68643620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T2"),
68743620a17SKevin Strasser 		},
68843620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
68943620a17SKevin Strasser 		.callback = kempld_create_platform_device,
69043620a17SKevin Strasser 	}, {
69143620a17SKevin Strasser 		.ident = "CHR2",
69243620a17SKevin Strasser 		.matches = {
69343620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
69443620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC2"),
69543620a17SKevin Strasser 		},
69643620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
69743620a17SKevin Strasser 		.callback = kempld_create_platform_device,
69843620a17SKevin Strasser 	}, {
69943620a17SKevin Strasser 		.ident = "CHR6",
70043620a17SKevin Strasser 		.matches = {
70143620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
70243620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T6"),
70343620a17SKevin Strasser 		},
70443620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
70543620a17SKevin Strasser 		.callback = kempld_create_platform_device,
70643620a17SKevin Strasser 	}, {
70743620a17SKevin Strasser 		.ident = "CHR6",
70843620a17SKevin Strasser 		.matches = {
70943620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
71043620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T6"),
71143620a17SKevin Strasser 		},
71243620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
71343620a17SKevin Strasser 		.callback = kempld_create_platform_device,
71443620a17SKevin Strasser 	}, {
71543620a17SKevin Strasser 		.ident = "CHR6",
71643620a17SKevin Strasser 		.matches = {
71743620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
71843620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC6"),
71943620a17SKevin Strasser 		},
72043620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
72143620a17SKevin Strasser 		.callback = kempld_create_platform_device,
72243620a17SKevin Strasser 	}, {
723e33ad65aSMichael Brunner 		.ident = "CKL6",
724e33ad65aSMichael Brunner 		.matches = {
725e33ad65aSMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
726e33ad65aSMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-cKL6"),
727e33ad65aSMichael Brunner 		},
728e33ad65aSMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
729e33ad65aSMichael Brunner 		.callback = kempld_create_platform_device,
730e33ad65aSMichael Brunner 	}, {
73143620a17SKevin Strasser 		.ident = "CNTG",
73243620a17SKevin Strasser 		.matches = {
73343620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
73443620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-PC"),
73543620a17SKevin Strasser 		},
73643620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
73743620a17SKevin Strasser 		.callback = kempld_create_platform_device,
73843620a17SKevin Strasser 	}, {
73943620a17SKevin Strasser 		.ident = "CNTG",
74043620a17SKevin Strasser 		.matches = {
74143620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
74243620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "COMe-bPC2"),
74343620a17SKevin Strasser 		},
74443620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
74543620a17SKevin Strasser 		.callback = kempld_create_platform_device,
74643620a17SKevin Strasser 	}, {
74743620a17SKevin Strasser 		.ident = "CNTX",
74843620a17SKevin Strasser 		.matches = {
74943620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
75043620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "PXT"),
75143620a17SKevin Strasser 		},
75243620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
75343620a17SKevin Strasser 		.callback = kempld_create_platform_device,
75443620a17SKevin Strasser 	}, {
7551db3ba28SMichael Brunner 		.ident = "CSL6",
7561db3ba28SMichael Brunner 		.matches = {
7571db3ba28SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
7581db3ba28SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-cSL6"),
7591db3ba28SMichael Brunner 		},
7601db3ba28SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
7611db3ba28SMichael Brunner 		.callback = kempld_create_platform_device,
7621db3ba28SMichael Brunner 	}, {
763a3ee7509SMichael Brunner 		.ident = "CVV6",
764a3ee7509SMichael Brunner 		.matches = {
765a3ee7509SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
766a3ee7509SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-cBT"),
767a3ee7509SMichael Brunner 		},
768a3ee7509SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
769a3ee7509SMichael Brunner 		.callback = kempld_create_platform_device,
770a3ee7509SMichael Brunner 	}, {
77143620a17SKevin Strasser 		.ident = "FRI2",
77243620a17SKevin Strasser 		.matches = {
77343620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
77443620a17SKevin Strasser 			DMI_MATCH(DMI_BIOS_VERSION, "FRI2"),
77543620a17SKevin Strasser 		},
77643620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
77743620a17SKevin Strasser 		.callback = kempld_create_platform_device,
77843620a17SKevin Strasser 	}, {
77943620a17SKevin Strasser 		.ident = "FRI2",
78043620a17SKevin Strasser 		.matches = {
78143620a17SKevin Strasser 			DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II"),
78243620a17SKevin Strasser 		},
78343620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
78443620a17SKevin Strasser 		.callback = kempld_create_platform_device,
78543620a17SKevin Strasser 	}, {
7860cd3aa99SMichael Brunner 		.ident = "A203",
7870cd3aa99SMichael Brunner 		.matches = {
7880cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
7890cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "KBox A-203"),
7900cd3aa99SMichael Brunner 		},
7910cd3aa99SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
7920cd3aa99SMichael Brunner 		.callback = kempld_create_platform_device,
7930cd3aa99SMichael Brunner 	}, {
7940cd3aa99SMichael Brunner 		.ident = "M4A1",
7950cd3aa99SMichael Brunner 		.matches = {
7960cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
7970cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-m4AL"),
7980cd3aa99SMichael Brunner 		},
7990cd3aa99SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
8000cd3aa99SMichael Brunner 		.callback = kempld_create_platform_device,
8010cd3aa99SMichael Brunner 	}, {
8021db3ba28SMichael Brunner 		.ident = "MAL1",
8031db3ba28SMichael Brunner 		.matches = {
8041db3ba28SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
8051db3ba28SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-mAL10"),
8061db3ba28SMichael Brunner 		},
8071db3ba28SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
8081db3ba28SMichael Brunner 		.callback = kempld_create_platform_device,
8091db3ba28SMichael Brunner 	}, {
8100cd3aa99SMichael Brunner 		.ident = "MAPL",
8110cd3aa99SMichael Brunner 		.matches = {
8120cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
8130cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "mITX-APL"),
8140cd3aa99SMichael Brunner 		},
8150cd3aa99SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
8160cd3aa99SMichael Brunner 		.callback = kempld_create_platform_device,
8170cd3aa99SMichael Brunner 	}, {
81843620a17SKevin Strasser 		.ident = "MBR1",
81943620a17SKevin Strasser 		.matches = {
82043620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
82143620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "ETX-OH"),
82243620a17SKevin Strasser 		},
82343620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
82443620a17SKevin Strasser 		.callback = kempld_create_platform_device,
82543620a17SKevin Strasser 	}, {
826a3ee7509SMichael Brunner 		.ident = "MVV1",
827a3ee7509SMichael Brunner 		.matches = {
828a3ee7509SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
829a3ee7509SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-mBT"),
830a3ee7509SMichael Brunner 		},
831a3ee7509SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
832a3ee7509SMichael Brunner 		.callback = kempld_create_platform_device,
833a3ee7509SMichael Brunner 	}, {
83443620a17SKevin Strasser 		.ident = "NTC1",
83543620a17SKevin Strasser 		.matches = {
83643620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
83743620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT"),
83843620a17SKevin Strasser 		},
83943620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
84043620a17SKevin Strasser 		.callback = kempld_create_platform_device,
84143620a17SKevin Strasser 	}, {
84243620a17SKevin Strasser 		.ident = "NTC1",
84343620a17SKevin Strasser 		.matches = {
84443620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
84543620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "nETXe-TT"),
84643620a17SKevin Strasser 		},
84743620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
84843620a17SKevin Strasser 		.callback = kempld_create_platform_device,
84943620a17SKevin Strasser 	}, {
85043620a17SKevin Strasser 		.ident = "NTC1",
85143620a17SKevin Strasser 		.matches = {
85243620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
85343620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT"),
85443620a17SKevin Strasser 		},
85543620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
85643620a17SKevin Strasser 		.callback = kempld_create_platform_device,
85743620a17SKevin Strasser 	}, {
85843620a17SKevin Strasser 		.ident = "NUP1",
85943620a17SKevin Strasser 		.matches = {
86043620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
86143620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "COMe-mCT"),
86243620a17SKevin Strasser 		},
86343620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
86443620a17SKevin Strasser 		.callback = kempld_create_platform_device,
86543620a17SKevin Strasser 	}, {
8660cd3aa99SMichael Brunner 		.ident = "PAPL",
8670cd3aa99SMichael Brunner 		.matches = {
8680cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
8690cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "pITX-APL"),
8700cd3aa99SMichael Brunner 		},
8710cd3aa99SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
8720cd3aa99SMichael Brunner 		.callback = kempld_create_platform_device,
8730cd3aa99SMichael Brunner 	}, {
8740cd3aa99SMichael Brunner 		.ident = "SXAL",
8750cd3aa99SMichael Brunner 		.matches = {
8760cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
8770cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "SMARC-sXAL"),
8780cd3aa99SMichael Brunner 		},
8790cd3aa99SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
8800cd3aa99SMichael Brunner 		.callback = kempld_create_platform_device,
8810cd3aa99SMichael Brunner 	}, {
8820cd3aa99SMichael Brunner 		.ident = "SXAL4",
8830cd3aa99SMichael Brunner 		.matches = {
8840cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
8850cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "SMARC-sXA4"),
8860cd3aa99SMichael Brunner 		},
8870cd3aa99SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
8880cd3aa99SMichael Brunner 		.callback = kempld_create_platform_device,
8890cd3aa99SMichael Brunner 	}, {
89043620a17SKevin Strasser 		.ident = "UNP1",
89143620a17SKevin Strasser 		.matches = {
89243620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
89343620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-DC"),
89443620a17SKevin Strasser 		},
89543620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
89643620a17SKevin Strasser 		.callback = kempld_create_platform_device,
89743620a17SKevin Strasser 	}, {
89843620a17SKevin Strasser 		.ident = "UNP1",
89943620a17SKevin Strasser 		.matches = {
90043620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
90143620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "COMe-cDC2"),
90243620a17SKevin Strasser 		},
90343620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
90443620a17SKevin Strasser 		.callback = kempld_create_platform_device,
90543620a17SKevin Strasser 	}, {
90643620a17SKevin Strasser 		.ident = "UNTG",
90743620a17SKevin Strasser 		.matches = {
90843620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
90943620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-PC"),
91043620a17SKevin Strasser 		},
91143620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
91243620a17SKevin Strasser 		.callback = kempld_create_platform_device,
91343620a17SKevin Strasser 	}, {
91443620a17SKevin Strasser 		.ident = "UNTG",
91543620a17SKevin Strasser 		.matches = {
91643620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
91743620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "COMe-cPC2"),
91843620a17SKevin Strasser 		},
91943620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
92043620a17SKevin Strasser 		.callback = kempld_create_platform_device,
92143620a17SKevin Strasser 	}, {
92243620a17SKevin Strasser 		.ident = "UUP6",
92343620a17SKevin Strasser 		.matches = {
92443620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
92543620a17SKevin Strasser 			DMI_MATCH(DMI_BOARD_NAME, "COMe-cCT6"),
92643620a17SKevin Strasser 		},
92743620a17SKevin Strasser 		.driver_data = (void *)&kempld_platform_data_generic,
92843620a17SKevin Strasser 		.callback = kempld_create_platform_device,
9290cd3aa99SMichael Brunner 	}, {
930c1d33b1bSMichael Brunner 		.ident = "UTH6",
931c1d33b1bSMichael Brunner 		.matches = {
932c1d33b1bSMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
933c1d33b1bSMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "COMe-cTH6"),
934c1d33b1bSMichael Brunner 		},
935c1d33b1bSMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
936c1d33b1bSMichael Brunner 		.callback = kempld_create_platform_device,
9370cd3aa99SMichael Brunner 	}, {
9380cd3aa99SMichael Brunner 		.ident = "Q7AL",
9390cd3aa99SMichael Brunner 		.matches = {
9400cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
9410cd3aa99SMichael Brunner 			DMI_MATCH(DMI_BOARD_NAME, "Qseven-Q7AL"),
9420cd3aa99SMichael Brunner 		},
9430cd3aa99SMichael Brunner 		.driver_data = (void *)&kempld_platform_data_generic,
9440cd3aa99SMichael Brunner 		.callback = kempld_create_platform_device,
945c1d33b1bSMichael Brunner 	},
94643620a17SKevin Strasser 	{}
94743620a17SKevin Strasser };
94843620a17SKevin Strasser MODULE_DEVICE_TABLE(dmi, kempld_dmi_table);
94943620a17SKevin Strasser 
kempld_init(void)95043620a17SKevin Strasser static int __init kempld_init(void)
95143620a17SKevin Strasser {
95243620a17SKevin Strasser 	const struct dmi_system_id *id;
95343620a17SKevin Strasser 
95443620a17SKevin Strasser 	if (force_device_id[0]) {
9559ef4e935SLee Jones 		for (id = kempld_dmi_table;
9569ef4e935SLee Jones 		     id->matches[0].slot != DMI_NONE; id++)
95743620a17SKevin Strasser 			if (strstr(id->ident, force_device_id))
958c8648508SAmeya Palande 				if (id->callback && !id->callback(id))
95943620a17SKevin Strasser 					break;
96043620a17SKevin Strasser 		if (id->matches[0].slot == DMI_NONE)
96143620a17SKevin Strasser 			return -ENODEV;
962f31cc6afSMichael Brunner 	} else {
963f31cc6afSMichael Brunner 		dmi_check_system(kempld_dmi_table);
96443620a17SKevin Strasser 	}
96543620a17SKevin Strasser 
966f31cc6afSMichael Brunner 	return platform_driver_register(&kempld_driver);
96743620a17SKevin Strasser }
96843620a17SKevin Strasser 
kempld_exit(void)96943620a17SKevin Strasser static void __exit kempld_exit(void)
97043620a17SKevin Strasser {
97143620a17SKevin Strasser 	if (kempld_pdev)
97243620a17SKevin Strasser 		platform_device_unregister(kempld_pdev);
97343620a17SKevin Strasser 
97443620a17SKevin Strasser 	platform_driver_unregister(&kempld_driver);
97543620a17SKevin Strasser }
97643620a17SKevin Strasser 
97743620a17SKevin Strasser module_init(kempld_init);
97843620a17SKevin Strasser module_exit(kempld_exit);
97943620a17SKevin Strasser 
98043620a17SKevin Strasser MODULE_DESCRIPTION("KEM PLD Core Driver");
98143620a17SKevin Strasser MODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
98243620a17SKevin Strasser MODULE_LICENSE("GPL");
98343620a17SKevin Strasser MODULE_ALIAS("platform:kempld-core");
984