18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Kontron PLD MFD core driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (c) 2010-2013 Kontron Europe GmbH
68c2ecf20Sopenharmony_ci * Author: Michael Brunner <michael.brunner@kontron.com>
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
108c2ecf20Sopenharmony_ci#include <linux/mfd/core.h>
118c2ecf20Sopenharmony_ci#include <linux/mfd/kempld.h>
128c2ecf20Sopenharmony_ci#include <linux/module.h>
138c2ecf20Sopenharmony_ci#include <linux/dmi.h>
148c2ecf20Sopenharmony_ci#include <linux/io.h>
158c2ecf20Sopenharmony_ci#include <linux/delay.h>
168c2ecf20Sopenharmony_ci#include <linux/acpi.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define MAX_ID_LEN 4
198c2ecf20Sopenharmony_cistatic char force_device_id[MAX_ID_LEN + 1] = "";
208c2ecf20Sopenharmony_cimodule_param_string(force_device_id, force_device_id,
218c2ecf20Sopenharmony_ci		    sizeof(force_device_id), 0);
228c2ecf20Sopenharmony_ciMODULE_PARM_DESC(force_device_id, "Override detected product");
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci/*
258c2ecf20Sopenharmony_ci * Get hardware mutex to block firmware from accessing the pld.
268c2ecf20Sopenharmony_ci * It is possible for the firmware may hold the mutex for an extended length of
278c2ecf20Sopenharmony_ci * time. This function will block until access has been granted.
288c2ecf20Sopenharmony_ci */
298c2ecf20Sopenharmony_cistatic void kempld_get_hardware_mutex(struct kempld_device_data *pld)
308c2ecf20Sopenharmony_ci{
318c2ecf20Sopenharmony_ci	/* The mutex bit will read 1 until access has been granted */
328c2ecf20Sopenharmony_ci	while (ioread8(pld->io_index) & KEMPLD_MUTEX_KEY)
338c2ecf20Sopenharmony_ci		usleep_range(1000, 3000);
348c2ecf20Sopenharmony_ci}
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_cistatic void kempld_release_hardware_mutex(struct kempld_device_data *pld)
378c2ecf20Sopenharmony_ci{
388c2ecf20Sopenharmony_ci	/* The harware mutex is released when 1 is written to the mutex bit. */
398c2ecf20Sopenharmony_ci	iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
408c2ecf20Sopenharmony_ci}
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_cistatic int kempld_get_info_generic(struct kempld_device_data *pld)
438c2ecf20Sopenharmony_ci{
448c2ecf20Sopenharmony_ci	u16 version;
458c2ecf20Sopenharmony_ci	u8 spec;
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci	kempld_get_mutex(pld);
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	version = kempld_read16(pld, KEMPLD_VERSION);
508c2ecf20Sopenharmony_ci	spec = kempld_read8(pld, KEMPLD_SPEC);
518c2ecf20Sopenharmony_ci	pld->info.buildnr = kempld_read16(pld, KEMPLD_BUILDNR);
528c2ecf20Sopenharmony_ci
538c2ecf20Sopenharmony_ci	pld->info.minor = KEMPLD_VERSION_GET_MINOR(version);
548c2ecf20Sopenharmony_ci	pld->info.major = KEMPLD_VERSION_GET_MAJOR(version);
558c2ecf20Sopenharmony_ci	pld->info.number = KEMPLD_VERSION_GET_NUMBER(version);
568c2ecf20Sopenharmony_ci	pld->info.type = KEMPLD_VERSION_GET_TYPE(version);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if (spec == 0xff) {
598c2ecf20Sopenharmony_ci		pld->info.spec_minor = 0;
608c2ecf20Sopenharmony_ci		pld->info.spec_major = 1;
618c2ecf20Sopenharmony_ci	} else {
628c2ecf20Sopenharmony_ci		pld->info.spec_minor = KEMPLD_SPEC_GET_MINOR(spec);
638c2ecf20Sopenharmony_ci		pld->info.spec_major = KEMPLD_SPEC_GET_MAJOR(spec);
648c2ecf20Sopenharmony_ci	}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	if (pld->info.spec_major > 0)
678c2ecf20Sopenharmony_ci		pld->feature_mask = kempld_read16(pld, KEMPLD_FEATURE);
688c2ecf20Sopenharmony_ci	else
698c2ecf20Sopenharmony_ci		pld->feature_mask = 0;
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	kempld_release_mutex(pld);
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	return 0;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cienum kempld_cells {
778c2ecf20Sopenharmony_ci	KEMPLD_I2C = 0,
788c2ecf20Sopenharmony_ci	KEMPLD_WDT,
798c2ecf20Sopenharmony_ci	KEMPLD_GPIO,
808c2ecf20Sopenharmony_ci	KEMPLD_UART,
818c2ecf20Sopenharmony_ci};
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_cistatic const char *kempld_dev_names[] = {
848c2ecf20Sopenharmony_ci	[KEMPLD_I2C] = "kempld-i2c",
858c2ecf20Sopenharmony_ci	[KEMPLD_WDT] = "kempld-wdt",
868c2ecf20Sopenharmony_ci	[KEMPLD_GPIO] = "kempld-gpio",
878c2ecf20Sopenharmony_ci	[KEMPLD_UART] = "kempld-uart",
888c2ecf20Sopenharmony_ci};
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci#define KEMPLD_MAX_DEVS	ARRAY_SIZE(kempld_dev_names)
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic int kempld_register_cells_generic(struct kempld_device_data *pld)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	struct mfd_cell devs[KEMPLD_MAX_DEVS] = {};
958c2ecf20Sopenharmony_ci	int i = 0;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	if (pld->feature_mask & KEMPLD_FEATURE_BIT_I2C)
988c2ecf20Sopenharmony_ci		devs[i++].name = kempld_dev_names[KEMPLD_I2C];
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	if (pld->feature_mask & KEMPLD_FEATURE_BIT_WATCHDOG)
1018c2ecf20Sopenharmony_ci		devs[i++].name = kempld_dev_names[KEMPLD_WDT];
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	if (pld->feature_mask & KEMPLD_FEATURE_BIT_GPIO)
1048c2ecf20Sopenharmony_ci		devs[i++].name = kempld_dev_names[KEMPLD_GPIO];
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	if (pld->feature_mask & KEMPLD_FEATURE_MASK_UART)
1078c2ecf20Sopenharmony_ci		devs[i++].name = kempld_dev_names[KEMPLD_UART];
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	return mfd_add_devices(pld->dev, -1, devs, i, NULL, 0, NULL);
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cistatic struct resource kempld_ioresource = {
1138c2ecf20Sopenharmony_ci	.start	= KEMPLD_IOINDEX,
1148c2ecf20Sopenharmony_ci	.end	= KEMPLD_IODATA,
1158c2ecf20Sopenharmony_ci	.flags	= IORESOURCE_IO,
1168c2ecf20Sopenharmony_ci};
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_cistatic const struct kempld_platform_data kempld_platform_data_generic = {
1198c2ecf20Sopenharmony_ci	.pld_clock		= KEMPLD_CLK,
1208c2ecf20Sopenharmony_ci	.ioresource		= &kempld_ioresource,
1218c2ecf20Sopenharmony_ci	.get_hardware_mutex	= kempld_get_hardware_mutex,
1228c2ecf20Sopenharmony_ci	.release_hardware_mutex	= kempld_release_hardware_mutex,
1238c2ecf20Sopenharmony_ci	.get_info		= kempld_get_info_generic,
1248c2ecf20Sopenharmony_ci	.register_cells		= kempld_register_cells_generic,
1258c2ecf20Sopenharmony_ci};
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic struct platform_device *kempld_pdev;
1288c2ecf20Sopenharmony_cistatic bool kempld_acpi_mode;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic int kempld_create_platform_device(const struct dmi_system_id *id)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	const struct kempld_platform_data *pdata = id->driver_data;
1338c2ecf20Sopenharmony_ci	int ret;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	kempld_pdev = platform_device_alloc("kempld", -1);
1368c2ecf20Sopenharmony_ci	if (!kempld_pdev)
1378c2ecf20Sopenharmony_ci		return -ENOMEM;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	ret = platform_device_add_data(kempld_pdev, pdata, sizeof(*pdata));
1408c2ecf20Sopenharmony_ci	if (ret)
1418c2ecf20Sopenharmony_ci		goto err;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	ret = platform_device_add_resources(kempld_pdev, pdata->ioresource, 1);
1448c2ecf20Sopenharmony_ci	if (ret)
1458c2ecf20Sopenharmony_ci		goto err;
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	ret = platform_device_add(kempld_pdev);
1488c2ecf20Sopenharmony_ci	if (ret)
1498c2ecf20Sopenharmony_ci		goto err;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	return 0;
1528c2ecf20Sopenharmony_cierr:
1538c2ecf20Sopenharmony_ci	platform_device_put(kempld_pdev);
1548c2ecf20Sopenharmony_ci	return ret;
1558c2ecf20Sopenharmony_ci}
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci/**
1588c2ecf20Sopenharmony_ci * kempld_read8 - read 8 bit register
1598c2ecf20Sopenharmony_ci * @pld: kempld_device_data structure describing the PLD
1608c2ecf20Sopenharmony_ci * @index: register index on the chip
1618c2ecf20Sopenharmony_ci *
1628c2ecf20Sopenharmony_ci * kempld_get_mutex must be called prior to calling this function.
1638c2ecf20Sopenharmony_ci */
1648c2ecf20Sopenharmony_ciu8 kempld_read8(struct kempld_device_data *pld, u8 index)
1658c2ecf20Sopenharmony_ci{
1668c2ecf20Sopenharmony_ci	iowrite8(index, pld->io_index);
1678c2ecf20Sopenharmony_ci	return ioread8(pld->io_data);
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kempld_read8);
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci/**
1728c2ecf20Sopenharmony_ci * kempld_write8 - write 8 bit register
1738c2ecf20Sopenharmony_ci * @pld: kempld_device_data structure describing the PLD
1748c2ecf20Sopenharmony_ci * @index: register index on the chip
1758c2ecf20Sopenharmony_ci * @data: new register value
1768c2ecf20Sopenharmony_ci *
1778c2ecf20Sopenharmony_ci * kempld_get_mutex must be called prior to calling this function.
1788c2ecf20Sopenharmony_ci */
1798c2ecf20Sopenharmony_civoid kempld_write8(struct kempld_device_data *pld, u8 index, u8 data)
1808c2ecf20Sopenharmony_ci{
1818c2ecf20Sopenharmony_ci	iowrite8(index, pld->io_index);
1828c2ecf20Sopenharmony_ci	iowrite8(data, pld->io_data);
1838c2ecf20Sopenharmony_ci}
1848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kempld_write8);
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci/**
1878c2ecf20Sopenharmony_ci * kempld_read16 - read 16 bit register
1888c2ecf20Sopenharmony_ci * @pld: kempld_device_data structure describing the PLD
1898c2ecf20Sopenharmony_ci * @index: register index on the chip
1908c2ecf20Sopenharmony_ci *
1918c2ecf20Sopenharmony_ci * kempld_get_mutex must be called prior to calling this function.
1928c2ecf20Sopenharmony_ci */
1938c2ecf20Sopenharmony_ciu16 kempld_read16(struct kempld_device_data *pld, u8 index)
1948c2ecf20Sopenharmony_ci{
1958c2ecf20Sopenharmony_ci	return kempld_read8(pld, index) | kempld_read8(pld, index + 1) << 8;
1968c2ecf20Sopenharmony_ci}
1978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kempld_read16);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci/**
2008c2ecf20Sopenharmony_ci * kempld_write16 - write 16 bit register
2018c2ecf20Sopenharmony_ci * @pld: kempld_device_data structure describing the PLD
2028c2ecf20Sopenharmony_ci * @index: register index on the chip
2038c2ecf20Sopenharmony_ci * @data: new register value
2048c2ecf20Sopenharmony_ci *
2058c2ecf20Sopenharmony_ci * kempld_get_mutex must be called prior to calling this function.
2068c2ecf20Sopenharmony_ci */
2078c2ecf20Sopenharmony_civoid kempld_write16(struct kempld_device_data *pld, u8 index, u16 data)
2088c2ecf20Sopenharmony_ci{
2098c2ecf20Sopenharmony_ci	kempld_write8(pld, index, (u8)data);
2108c2ecf20Sopenharmony_ci	kempld_write8(pld, index + 1, (u8)(data >> 8));
2118c2ecf20Sopenharmony_ci}
2128c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kempld_write16);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci/**
2158c2ecf20Sopenharmony_ci * kempld_read32 - read 32 bit register
2168c2ecf20Sopenharmony_ci * @pld: kempld_device_data structure describing the PLD
2178c2ecf20Sopenharmony_ci * @index: register index on the chip
2188c2ecf20Sopenharmony_ci *
2198c2ecf20Sopenharmony_ci * kempld_get_mutex must be called prior to calling this function.
2208c2ecf20Sopenharmony_ci */
2218c2ecf20Sopenharmony_ciu32 kempld_read32(struct kempld_device_data *pld, u8 index)
2228c2ecf20Sopenharmony_ci{
2238c2ecf20Sopenharmony_ci	return kempld_read16(pld, index) | kempld_read16(pld, index + 2) << 16;
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kempld_read32);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci/**
2288c2ecf20Sopenharmony_ci * kempld_write32 - write 32 bit register
2298c2ecf20Sopenharmony_ci * @pld: kempld_device_data structure describing the PLD
2308c2ecf20Sopenharmony_ci * @index: register index on the chip
2318c2ecf20Sopenharmony_ci * @data: new register value
2328c2ecf20Sopenharmony_ci *
2338c2ecf20Sopenharmony_ci * kempld_get_mutex must be called prior to calling this function.
2348c2ecf20Sopenharmony_ci */
2358c2ecf20Sopenharmony_civoid kempld_write32(struct kempld_device_data *pld, u8 index, u32 data)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	kempld_write16(pld, index, (u16)data);
2388c2ecf20Sopenharmony_ci	kempld_write16(pld, index + 2, (u16)(data >> 16));
2398c2ecf20Sopenharmony_ci}
2408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kempld_write32);
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci/**
2438c2ecf20Sopenharmony_ci * kempld_get_mutex - acquire PLD mutex
2448c2ecf20Sopenharmony_ci * @pld: kempld_device_data structure describing the PLD
2458c2ecf20Sopenharmony_ci */
2468c2ecf20Sopenharmony_civoid kempld_get_mutex(struct kempld_device_data *pld)
2478c2ecf20Sopenharmony_ci{
2488c2ecf20Sopenharmony_ci	const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	mutex_lock(&pld->lock);
2518c2ecf20Sopenharmony_ci	pdata->get_hardware_mutex(pld);
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kempld_get_mutex);
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci/**
2568c2ecf20Sopenharmony_ci * kempld_release_mutex - release PLD mutex
2578c2ecf20Sopenharmony_ci * @pld: kempld_device_data structure describing the PLD
2588c2ecf20Sopenharmony_ci */
2598c2ecf20Sopenharmony_civoid kempld_release_mutex(struct kempld_device_data *pld)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	pdata->release_hardware_mutex(pld);
2648c2ecf20Sopenharmony_ci	mutex_unlock(&pld->lock);
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(kempld_release_mutex);
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci/**
2698c2ecf20Sopenharmony_ci * kempld_get_info - update device specific information
2708c2ecf20Sopenharmony_ci * @pld: kempld_device_data structure describing the PLD
2718c2ecf20Sopenharmony_ci *
2728c2ecf20Sopenharmony_ci * This function calls the configured board specific kempld_get_info_XXXX
2738c2ecf20Sopenharmony_ci * function which is responsible for gathering information about the specific
2748c2ecf20Sopenharmony_ci * hardware. The information is then stored within the pld structure.
2758c2ecf20Sopenharmony_ci */
2768c2ecf20Sopenharmony_cistatic int kempld_get_info(struct kempld_device_data *pld)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	int ret;
2798c2ecf20Sopenharmony_ci	const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
2808c2ecf20Sopenharmony_ci	char major, minor;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	ret = pdata->get_info(pld);
2838c2ecf20Sopenharmony_ci	if (ret)
2848c2ecf20Sopenharmony_ci		return ret;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	/* The Kontron PLD firmware version string has the following format:
2878c2ecf20Sopenharmony_ci	 * Pwxy.zzzz
2888c2ecf20Sopenharmony_ci	 *   P:    Fixed
2898c2ecf20Sopenharmony_ci	 *   w:    PLD number    - 1 hex digit
2908c2ecf20Sopenharmony_ci	 *   x:    Major version - 1 alphanumerical digit (0-9A-V)
2918c2ecf20Sopenharmony_ci	 *   y:    Minor version - 1 alphanumerical digit (0-9A-V)
2928c2ecf20Sopenharmony_ci	 *   zzzz: Build number  - 4 zero padded hex digits */
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	if (pld->info.major < 10)
2958c2ecf20Sopenharmony_ci		major = pld->info.major + '0';
2968c2ecf20Sopenharmony_ci	else
2978c2ecf20Sopenharmony_ci		major = (pld->info.major - 10) + 'A';
2988c2ecf20Sopenharmony_ci	if (pld->info.minor < 10)
2998c2ecf20Sopenharmony_ci		minor = pld->info.minor + '0';
3008c2ecf20Sopenharmony_ci	else
3018c2ecf20Sopenharmony_ci		minor = (pld->info.minor - 10) + 'A';
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	ret = scnprintf(pld->info.version, sizeof(pld->info.version),
3048c2ecf20Sopenharmony_ci			"P%X%c%c.%04X", pld->info.number, major, minor,
3058c2ecf20Sopenharmony_ci			pld->info.buildnr);
3068c2ecf20Sopenharmony_ci	if (ret < 0)
3078c2ecf20Sopenharmony_ci		return ret;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	return 0;
3108c2ecf20Sopenharmony_ci}
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci/*
3138c2ecf20Sopenharmony_ci * kempld_register_cells - register cell drivers
3148c2ecf20Sopenharmony_ci *
3158c2ecf20Sopenharmony_ci * This function registers cell drivers for the detected hardware by calling
3168c2ecf20Sopenharmony_ci * the configured kempld_register_cells_XXXX function which is responsible
3178c2ecf20Sopenharmony_ci * to detect and register the needed cell drivers.
3188c2ecf20Sopenharmony_ci */
3198c2ecf20Sopenharmony_cistatic int kempld_register_cells(struct kempld_device_data *pld)
3208c2ecf20Sopenharmony_ci{
3218c2ecf20Sopenharmony_ci	const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	return pdata->register_cells(pld);
3248c2ecf20Sopenharmony_ci}
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_cistatic const char *kempld_get_type_string(struct kempld_device_data *pld)
3278c2ecf20Sopenharmony_ci{
3288c2ecf20Sopenharmony_ci	const char *version_type;
3298c2ecf20Sopenharmony_ci
3308c2ecf20Sopenharmony_ci	switch (pld->info.type) {
3318c2ecf20Sopenharmony_ci	case 0:
3328c2ecf20Sopenharmony_ci		version_type = "release";
3338c2ecf20Sopenharmony_ci		break;
3348c2ecf20Sopenharmony_ci	case 1:
3358c2ecf20Sopenharmony_ci		version_type = "debug";
3368c2ecf20Sopenharmony_ci		break;
3378c2ecf20Sopenharmony_ci	case 2:
3388c2ecf20Sopenharmony_ci		version_type = "custom";
3398c2ecf20Sopenharmony_ci		break;
3408c2ecf20Sopenharmony_ci	default:
3418c2ecf20Sopenharmony_ci		version_type = "unspecified";
3428c2ecf20Sopenharmony_ci		break;
3438c2ecf20Sopenharmony_ci	}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_ci	return version_type;
3468c2ecf20Sopenharmony_ci}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_cistatic ssize_t kempld_version_show(struct device *dev,
3498c2ecf20Sopenharmony_ci		struct device_attribute *attr, char *buf)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	struct kempld_device_data *pld = dev_get_drvdata(dev);
3528c2ecf20Sopenharmony_ci
3538c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%s\n", pld->info.version);
3548c2ecf20Sopenharmony_ci}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_cistatic ssize_t kempld_specification_show(struct device *dev,
3578c2ecf20Sopenharmony_ci		struct device_attribute *attr, char *buf)
3588c2ecf20Sopenharmony_ci{
3598c2ecf20Sopenharmony_ci	struct kempld_device_data *pld = dev_get_drvdata(dev);
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%d.%d\n", pld->info.spec_major,
3628c2ecf20Sopenharmony_ci		       pld->info.spec_minor);
3638c2ecf20Sopenharmony_ci}
3648c2ecf20Sopenharmony_ci
3658c2ecf20Sopenharmony_cistatic ssize_t kempld_type_show(struct device *dev,
3668c2ecf20Sopenharmony_ci		struct device_attribute *attr, char *buf)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	struct kempld_device_data *pld = dev_get_drvdata(dev);
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci	return scnprintf(buf, PAGE_SIZE, "%s\n", kempld_get_type_string(pld));
3718c2ecf20Sopenharmony_ci}
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_cistatic DEVICE_ATTR(pld_version, S_IRUGO, kempld_version_show, NULL);
3748c2ecf20Sopenharmony_cistatic DEVICE_ATTR(pld_specification, S_IRUGO, kempld_specification_show,
3758c2ecf20Sopenharmony_ci		   NULL);
3768c2ecf20Sopenharmony_cistatic DEVICE_ATTR(pld_type, S_IRUGO, kempld_type_show, NULL);
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic struct attribute *pld_attributes[] = {
3798c2ecf20Sopenharmony_ci	&dev_attr_pld_version.attr,
3808c2ecf20Sopenharmony_ci	&dev_attr_pld_specification.attr,
3818c2ecf20Sopenharmony_ci	&dev_attr_pld_type.attr,
3828c2ecf20Sopenharmony_ci	NULL
3838c2ecf20Sopenharmony_ci};
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistatic const struct attribute_group pld_attr_group = {
3868c2ecf20Sopenharmony_ci	.attrs = pld_attributes,
3878c2ecf20Sopenharmony_ci};
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic int kempld_detect_device(struct kempld_device_data *pld)
3908c2ecf20Sopenharmony_ci{
3918c2ecf20Sopenharmony_ci	u8 index_reg;
3928c2ecf20Sopenharmony_ci	int ret;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	mutex_lock(&pld->lock);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci	/* Check for empty IO space */
3978c2ecf20Sopenharmony_ci	index_reg = ioread8(pld->io_index);
3988c2ecf20Sopenharmony_ci	if (index_reg == 0xff && ioread8(pld->io_data) == 0xff) {
3998c2ecf20Sopenharmony_ci		mutex_unlock(&pld->lock);
4008c2ecf20Sopenharmony_ci		return -ENODEV;
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci
4038c2ecf20Sopenharmony_ci	/* Release hardware mutex if acquired */
4048c2ecf20Sopenharmony_ci	if (!(index_reg & KEMPLD_MUTEX_KEY)) {
4058c2ecf20Sopenharmony_ci		iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
4068c2ecf20Sopenharmony_ci		/* PXT and COMe-cPC2 boards may require a second release */
4078c2ecf20Sopenharmony_ci		iowrite8(KEMPLD_MUTEX_KEY, pld->io_index);
4088c2ecf20Sopenharmony_ci	}
4098c2ecf20Sopenharmony_ci
4108c2ecf20Sopenharmony_ci	mutex_unlock(&pld->lock);
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	ret = kempld_get_info(pld);
4138c2ecf20Sopenharmony_ci	if (ret)
4148c2ecf20Sopenharmony_ci		return ret;
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_ci	dev_info(pld->dev, "Found Kontron PLD - %s (%s), spec %d.%d\n",
4178c2ecf20Sopenharmony_ci		 pld->info.version, kempld_get_type_string(pld),
4188c2ecf20Sopenharmony_ci		 pld->info.spec_major, pld->info.spec_minor);
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	ret = sysfs_create_group(&pld->dev->kobj, &pld_attr_group);
4218c2ecf20Sopenharmony_ci	if (ret)
4228c2ecf20Sopenharmony_ci		return ret;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	ret = kempld_register_cells(pld);
4258c2ecf20Sopenharmony_ci	if (ret)
4268c2ecf20Sopenharmony_ci		sysfs_remove_group(&pld->dev->kobj, &pld_attr_group);
4278c2ecf20Sopenharmony_ci
4288c2ecf20Sopenharmony_ci	return ret;
4298c2ecf20Sopenharmony_ci}
4308c2ecf20Sopenharmony_ci
4318c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
4328c2ecf20Sopenharmony_cistatic int kempld_get_acpi_data(struct platform_device *pdev)
4338c2ecf20Sopenharmony_ci{
4348c2ecf20Sopenharmony_ci	struct list_head resource_list;
4358c2ecf20Sopenharmony_ci	struct resource *resources;
4368c2ecf20Sopenharmony_ci	struct resource_entry *rentry;
4378c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
4388c2ecf20Sopenharmony_ci	struct acpi_device *acpi_dev = ACPI_COMPANION(dev);
4398c2ecf20Sopenharmony_ci	const struct kempld_platform_data *pdata;
4408c2ecf20Sopenharmony_ci	int ret;
4418c2ecf20Sopenharmony_ci	int count;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	pdata = acpi_device_get_match_data(dev);
4448c2ecf20Sopenharmony_ci	ret = platform_device_add_data(pdev, pdata,
4458c2ecf20Sopenharmony_ci				       sizeof(struct kempld_platform_data));
4468c2ecf20Sopenharmony_ci	if (ret)
4478c2ecf20Sopenharmony_ci		return ret;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&resource_list);
4508c2ecf20Sopenharmony_ci	ret = acpi_dev_get_resources(acpi_dev, &resource_list, NULL, NULL);
4518c2ecf20Sopenharmony_ci	if (ret < 0)
4528c2ecf20Sopenharmony_ci		goto out;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_ci	count = ret;
4558c2ecf20Sopenharmony_ci
4568c2ecf20Sopenharmony_ci	if (count == 0) {
4578c2ecf20Sopenharmony_ci		ret = platform_device_add_resources(pdev, pdata->ioresource, 1);
4588c2ecf20Sopenharmony_ci		goto out;
4598c2ecf20Sopenharmony_ci	}
4608c2ecf20Sopenharmony_ci
4618c2ecf20Sopenharmony_ci	resources = devm_kcalloc(&acpi_dev->dev, count, sizeof(*resources),
4628c2ecf20Sopenharmony_ci				 GFP_KERNEL);
4638c2ecf20Sopenharmony_ci	if (!resources) {
4648c2ecf20Sopenharmony_ci		ret = -ENOMEM;
4658c2ecf20Sopenharmony_ci		goto out;
4668c2ecf20Sopenharmony_ci	}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_ci	count = 0;
4698c2ecf20Sopenharmony_ci	list_for_each_entry(rentry, &resource_list, node) {
4708c2ecf20Sopenharmony_ci		memcpy(&resources[count], rentry->res,
4718c2ecf20Sopenharmony_ci		       sizeof(*resources));
4728c2ecf20Sopenharmony_ci		count++;
4738c2ecf20Sopenharmony_ci	}
4748c2ecf20Sopenharmony_ci	ret = platform_device_add_resources(pdev, resources, count);
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ciout:
4778c2ecf20Sopenharmony_ci	acpi_dev_free_resource_list(&resource_list);
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	return ret;
4808c2ecf20Sopenharmony_ci}
4818c2ecf20Sopenharmony_ci#else
4828c2ecf20Sopenharmony_cistatic int kempld_get_acpi_data(struct platform_device *pdev)
4838c2ecf20Sopenharmony_ci{
4848c2ecf20Sopenharmony_ci	return -ENODEV;
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ci#endif /* CONFIG_ACPI */
4878c2ecf20Sopenharmony_ci
4888c2ecf20Sopenharmony_cistatic int kempld_probe(struct platform_device *pdev)
4898c2ecf20Sopenharmony_ci{
4908c2ecf20Sopenharmony_ci	const struct kempld_platform_data *pdata;
4918c2ecf20Sopenharmony_ci	struct device *dev = &pdev->dev;
4928c2ecf20Sopenharmony_ci	struct kempld_device_data *pld;
4938c2ecf20Sopenharmony_ci	struct resource *ioport;
4948c2ecf20Sopenharmony_ci	int ret;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	if (kempld_pdev == NULL) {
4978c2ecf20Sopenharmony_ci		/*
4988c2ecf20Sopenharmony_ci		 * No kempld_pdev device has been registered in kempld_init,
4998c2ecf20Sopenharmony_ci		 * so we seem to be probing an ACPI platform device.
5008c2ecf20Sopenharmony_ci		 */
5018c2ecf20Sopenharmony_ci		ret = kempld_get_acpi_data(pdev);
5028c2ecf20Sopenharmony_ci		if (ret)
5038c2ecf20Sopenharmony_ci			return ret;
5048c2ecf20Sopenharmony_ci
5058c2ecf20Sopenharmony_ci		kempld_acpi_mode = true;
5068c2ecf20Sopenharmony_ci	} else if (kempld_pdev != pdev) {
5078c2ecf20Sopenharmony_ci		/*
5088c2ecf20Sopenharmony_ci		 * The platform device we are probing is not the one we
5098c2ecf20Sopenharmony_ci		 * registered in kempld_init using the DMI table, so this one
5108c2ecf20Sopenharmony_ci		 * comes from ACPI.
5118c2ecf20Sopenharmony_ci		 * As we can only probe one - abort here and use the DMI
5128c2ecf20Sopenharmony_ci		 * based one instead.
5138c2ecf20Sopenharmony_ci		 */
5148c2ecf20Sopenharmony_ci		dev_notice(dev, "platform device exists - not using ACPI\n");
5158c2ecf20Sopenharmony_ci		return -ENODEV;
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci	pdata = dev_get_platdata(dev);
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_ci	pld = devm_kzalloc(dev, sizeof(*pld), GFP_KERNEL);
5208c2ecf20Sopenharmony_ci	if (!pld)
5218c2ecf20Sopenharmony_ci		return -ENOMEM;
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	ioport = platform_get_resource(pdev, IORESOURCE_IO, 0);
5248c2ecf20Sopenharmony_ci	if (!ioport)
5258c2ecf20Sopenharmony_ci		return -EINVAL;
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_ci	pld->io_base = devm_ioport_map(dev, ioport->start,
5288c2ecf20Sopenharmony_ci					resource_size(ioport));
5298c2ecf20Sopenharmony_ci	if (!pld->io_base)
5308c2ecf20Sopenharmony_ci		return -ENOMEM;
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	pld->io_index = pld->io_base;
5338c2ecf20Sopenharmony_ci	pld->io_data = pld->io_base + 1;
5348c2ecf20Sopenharmony_ci	pld->pld_clock = pdata->pld_clock;
5358c2ecf20Sopenharmony_ci	pld->dev = dev;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	mutex_init(&pld->lock);
5388c2ecf20Sopenharmony_ci	platform_set_drvdata(pdev, pld);
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	return kempld_detect_device(pld);
5418c2ecf20Sopenharmony_ci}
5428c2ecf20Sopenharmony_ci
5438c2ecf20Sopenharmony_cistatic int kempld_remove(struct platform_device *pdev)
5448c2ecf20Sopenharmony_ci{
5458c2ecf20Sopenharmony_ci	struct kempld_device_data *pld = platform_get_drvdata(pdev);
5468c2ecf20Sopenharmony_ci	const struct kempld_platform_data *pdata = dev_get_platdata(pld->dev);
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	sysfs_remove_group(&pld->dev->kobj, &pld_attr_group);
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci	mfd_remove_devices(&pdev->dev);
5518c2ecf20Sopenharmony_ci	pdata->release_hardware_mutex(pld);
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_ci	return 0;
5548c2ecf20Sopenharmony_ci}
5558c2ecf20Sopenharmony_ci
5568c2ecf20Sopenharmony_ci#ifdef CONFIG_ACPI
5578c2ecf20Sopenharmony_cistatic const struct acpi_device_id kempld_acpi_table[] = {
5588c2ecf20Sopenharmony_ci	{ "KEM0001", (kernel_ulong_t)&kempld_platform_data_generic },
5598c2ecf20Sopenharmony_ci	{}
5608c2ecf20Sopenharmony_ci};
5618c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, kempld_acpi_table);
5628c2ecf20Sopenharmony_ci#endif
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_cistatic struct platform_driver kempld_driver = {
5658c2ecf20Sopenharmony_ci	.driver		= {
5668c2ecf20Sopenharmony_ci		.name	= "kempld",
5678c2ecf20Sopenharmony_ci		.acpi_match_table = ACPI_PTR(kempld_acpi_table),
5688c2ecf20Sopenharmony_ci		.probe_type = PROBE_FORCE_SYNCHRONOUS,
5698c2ecf20Sopenharmony_ci	},
5708c2ecf20Sopenharmony_ci	.probe		= kempld_probe,
5718c2ecf20Sopenharmony_ci	.remove		= kempld_remove,
5728c2ecf20Sopenharmony_ci};
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_cistatic const struct dmi_system_id kempld_dmi_table[] __initconst = {
5758c2ecf20Sopenharmony_ci	{
5768c2ecf20Sopenharmony_ci		.ident = "BBD6",
5778c2ecf20Sopenharmony_ci		.matches = {
5788c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
5798c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-bBD"),
5808c2ecf20Sopenharmony_ci		},
5818c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
5828c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
5838c2ecf20Sopenharmony_ci	}, {
5848c2ecf20Sopenharmony_ci		.ident = "BBL6",
5858c2ecf20Sopenharmony_ci		.matches = {
5868c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
5878c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-bBL6"),
5888c2ecf20Sopenharmony_ci		},
5898c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
5908c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
5918c2ecf20Sopenharmony_ci	}, {
5928c2ecf20Sopenharmony_ci		.ident = "BHL6",
5938c2ecf20Sopenharmony_ci		.matches = {
5948c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
5958c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-bHL6"),
5968c2ecf20Sopenharmony_ci		},
5978c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
5988c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
5998c2ecf20Sopenharmony_ci	}, {
6008c2ecf20Sopenharmony_ci		.ident = "BKL6",
6018c2ecf20Sopenharmony_ci		.matches = {
6028c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
6038c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-bKL6"),
6048c2ecf20Sopenharmony_ci		},
6058c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
6068c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
6078c2ecf20Sopenharmony_ci	}, {
6088c2ecf20Sopenharmony_ci		.ident = "BSL6",
6098c2ecf20Sopenharmony_ci		.matches = {
6108c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
6118c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-bSL6"),
6128c2ecf20Sopenharmony_ci		},
6138c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
6148c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
6158c2ecf20Sopenharmony_ci	}, {
6168c2ecf20Sopenharmony_ci		.ident = "CAL6",
6178c2ecf20Sopenharmony_ci		.matches = {
6188c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
6198c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-cAL"),
6208c2ecf20Sopenharmony_ci		},
6218c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
6228c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
6238c2ecf20Sopenharmony_ci	}, {
6248c2ecf20Sopenharmony_ci		.ident = "CBL6",
6258c2ecf20Sopenharmony_ci		.matches = {
6268c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
6278c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-cBL6"),
6288c2ecf20Sopenharmony_ci		},
6298c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
6308c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
6318c2ecf20Sopenharmony_ci	}, {
6328c2ecf20Sopenharmony_ci		.ident = "CBW6",
6338c2ecf20Sopenharmony_ci		.matches = {
6348c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
6358c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-cBW6"),
6368c2ecf20Sopenharmony_ci		},
6378c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
6388c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
6398c2ecf20Sopenharmony_ci	}, {
6408c2ecf20Sopenharmony_ci		.ident = "CCR2",
6418c2ecf20Sopenharmony_ci		.matches = {
6428c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
6438c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP2"),
6448c2ecf20Sopenharmony_ci		},
6458c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
6468c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
6478c2ecf20Sopenharmony_ci	}, {
6488c2ecf20Sopenharmony_ci		.ident = "CCR6",
6498c2ecf20Sopenharmony_ci		.matches = {
6508c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
6518c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-bIP6"),
6528c2ecf20Sopenharmony_ci		},
6538c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
6548c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
6558c2ecf20Sopenharmony_ci	}, {
6568c2ecf20Sopenharmony_ci		.ident = "CHL6",
6578c2ecf20Sopenharmony_ci		.matches = {
6588c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
6598c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-cHL6"),
6608c2ecf20Sopenharmony_ci		},
6618c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
6628c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
6638c2ecf20Sopenharmony_ci	}, {
6648c2ecf20Sopenharmony_ci		.ident = "CHR2",
6658c2ecf20Sopenharmony_ci		.matches = {
6668c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
6678c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T2"),
6688c2ecf20Sopenharmony_ci		},
6698c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
6708c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
6718c2ecf20Sopenharmony_ci	}, {
6728c2ecf20Sopenharmony_ci		.ident = "CHR2",
6738c2ecf20Sopenharmony_ci		.matches = {
6748c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
6758c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T2"),
6768c2ecf20Sopenharmony_ci		},
6778c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
6788c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
6798c2ecf20Sopenharmony_ci	}, {
6808c2ecf20Sopenharmony_ci		.ident = "CHR2",
6818c2ecf20Sopenharmony_ci		.matches = {
6828c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
6838c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC2"),
6848c2ecf20Sopenharmony_ci		},
6858c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
6868c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
6878c2ecf20Sopenharmony_ci	}, {
6888c2ecf20Sopenharmony_ci		.ident = "CHR6",
6898c2ecf20Sopenharmony_ci		.matches = {
6908c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
6918c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-SC T6"),
6928c2ecf20Sopenharmony_ci		},
6938c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
6948c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
6958c2ecf20Sopenharmony_ci	}, {
6968c2ecf20Sopenharmony_ci		.ident = "CHR6",
6978c2ecf20Sopenharmony_ci		.matches = {
6988c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
6998c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "ETXe-SC T6"),
7008c2ecf20Sopenharmony_ci		},
7018c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
7028c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
7038c2ecf20Sopenharmony_ci	}, {
7048c2ecf20Sopenharmony_ci		.ident = "CHR6",
7058c2ecf20Sopenharmony_ci		.matches = {
7068c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
7078c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-bSC6"),
7088c2ecf20Sopenharmony_ci		},
7098c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
7108c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
7118c2ecf20Sopenharmony_ci	}, {
7128c2ecf20Sopenharmony_ci		.ident = "CKL6",
7138c2ecf20Sopenharmony_ci		.matches = {
7148c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
7158c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-cKL6"),
7168c2ecf20Sopenharmony_ci		},
7178c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
7188c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
7198c2ecf20Sopenharmony_ci	}, {
7208c2ecf20Sopenharmony_ci		.ident = "CNTG",
7218c2ecf20Sopenharmony_ci		.matches = {
7228c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
7238c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "ETXexpress-PC"),
7248c2ecf20Sopenharmony_ci		},
7258c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
7268c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
7278c2ecf20Sopenharmony_ci	}, {
7288c2ecf20Sopenharmony_ci		.ident = "CNTG",
7298c2ecf20Sopenharmony_ci		.matches = {
7308c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
7318c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-bPC2"),
7328c2ecf20Sopenharmony_ci		},
7338c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
7348c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
7358c2ecf20Sopenharmony_ci	}, {
7368c2ecf20Sopenharmony_ci		.ident = "CNTX",
7378c2ecf20Sopenharmony_ci		.matches = {
7388c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
7398c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "PXT"),
7408c2ecf20Sopenharmony_ci		},
7418c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
7428c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
7438c2ecf20Sopenharmony_ci	}, {
7448c2ecf20Sopenharmony_ci		.ident = "CSL6",
7458c2ecf20Sopenharmony_ci		.matches = {
7468c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
7478c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-cSL6"),
7488c2ecf20Sopenharmony_ci		},
7498c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
7508c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
7518c2ecf20Sopenharmony_ci	}, {
7528c2ecf20Sopenharmony_ci		.ident = "CVV6",
7538c2ecf20Sopenharmony_ci		.matches = {
7548c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
7558c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-cBT"),
7568c2ecf20Sopenharmony_ci		},
7578c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
7588c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
7598c2ecf20Sopenharmony_ci	}, {
7608c2ecf20Sopenharmony_ci		.ident = "FRI2",
7618c2ecf20Sopenharmony_ci		.matches = {
7628c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
7638c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BIOS_VERSION, "FRI2"),
7648c2ecf20Sopenharmony_ci		},
7658c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
7668c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
7678c2ecf20Sopenharmony_ci	}, {
7688c2ecf20Sopenharmony_ci		.ident = "FRI2",
7698c2ecf20Sopenharmony_ci		.matches = {
7708c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_PRODUCT_NAME, "Fish River Island II"),
7718c2ecf20Sopenharmony_ci		},
7728c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
7738c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
7748c2ecf20Sopenharmony_ci	}, {
7758c2ecf20Sopenharmony_ci		.ident = "MAL1",
7768c2ecf20Sopenharmony_ci		.matches = {
7778c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
7788c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-mAL10"),
7798c2ecf20Sopenharmony_ci		},
7808c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
7818c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
7828c2ecf20Sopenharmony_ci	}, {
7838c2ecf20Sopenharmony_ci		.ident = "MBR1",
7848c2ecf20Sopenharmony_ci		.matches = {
7858c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
7868c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "ETX-OH"),
7878c2ecf20Sopenharmony_ci		},
7888c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
7898c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
7908c2ecf20Sopenharmony_ci	}, {
7918c2ecf20Sopenharmony_ci		.ident = "MVV1",
7928c2ecf20Sopenharmony_ci		.matches = {
7938c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
7948c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-mBT"),
7958c2ecf20Sopenharmony_ci		},
7968c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
7978c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
7988c2ecf20Sopenharmony_ci	}, {
7998c2ecf20Sopenharmony_ci		.ident = "NTC1",
8008c2ecf20Sopenharmony_ci		.matches = {
8018c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
8028c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "nanoETXexpress-TT"),
8038c2ecf20Sopenharmony_ci		},
8048c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
8058c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
8068c2ecf20Sopenharmony_ci	}, {
8078c2ecf20Sopenharmony_ci		.ident = "NTC1",
8088c2ecf20Sopenharmony_ci		.matches = {
8098c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
8108c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "nETXe-TT"),
8118c2ecf20Sopenharmony_ci		},
8128c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
8138c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
8148c2ecf20Sopenharmony_ci	}, {
8158c2ecf20Sopenharmony_ci		.ident = "NTC1",
8168c2ecf20Sopenharmony_ci		.matches = {
8178c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
8188c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-mTT"),
8198c2ecf20Sopenharmony_ci		},
8208c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
8218c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
8228c2ecf20Sopenharmony_ci	}, {
8238c2ecf20Sopenharmony_ci		.ident = "NUP1",
8248c2ecf20Sopenharmony_ci		.matches = {
8258c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
8268c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-mCT"),
8278c2ecf20Sopenharmony_ci		},
8288c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
8298c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
8308c2ecf20Sopenharmony_ci	}, {
8318c2ecf20Sopenharmony_ci		.ident = "UNP1",
8328c2ecf20Sopenharmony_ci		.matches = {
8338c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
8348c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-DC"),
8358c2ecf20Sopenharmony_ci		},
8368c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
8378c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
8388c2ecf20Sopenharmony_ci	}, {
8398c2ecf20Sopenharmony_ci		.ident = "UNP1",
8408c2ecf20Sopenharmony_ci		.matches = {
8418c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
8428c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-cDC2"),
8438c2ecf20Sopenharmony_ci		},
8448c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
8458c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
8468c2ecf20Sopenharmony_ci	}, {
8478c2ecf20Sopenharmony_ci		.ident = "UNTG",
8488c2ecf20Sopenharmony_ci		.matches = {
8498c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
8508c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "microETXexpress-PC"),
8518c2ecf20Sopenharmony_ci		},
8528c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
8538c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
8548c2ecf20Sopenharmony_ci	}, {
8558c2ecf20Sopenharmony_ci		.ident = "UNTG",
8568c2ecf20Sopenharmony_ci		.matches = {
8578c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
8588c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-cPC2"),
8598c2ecf20Sopenharmony_ci		},
8608c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
8618c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
8628c2ecf20Sopenharmony_ci	}, {
8638c2ecf20Sopenharmony_ci		.ident = "UUP6",
8648c2ecf20Sopenharmony_ci		.matches = {
8658c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
8668c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-cCT6"),
8678c2ecf20Sopenharmony_ci		},
8688c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
8698c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
8708c2ecf20Sopenharmony_ci	},
8718c2ecf20Sopenharmony_ci	{
8728c2ecf20Sopenharmony_ci		.ident = "UTH6",
8738c2ecf20Sopenharmony_ci		.matches = {
8748c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_VENDOR, "Kontron"),
8758c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "COMe-cTH6"),
8768c2ecf20Sopenharmony_ci		},
8778c2ecf20Sopenharmony_ci		.driver_data = (void *)&kempld_platform_data_generic,
8788c2ecf20Sopenharmony_ci		.callback = kempld_create_platform_device,
8798c2ecf20Sopenharmony_ci	},
8808c2ecf20Sopenharmony_ci	{}
8818c2ecf20Sopenharmony_ci};
8828c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(dmi, kempld_dmi_table);
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cistatic int __init kempld_init(void)
8858c2ecf20Sopenharmony_ci{
8868c2ecf20Sopenharmony_ci	const struct dmi_system_id *id;
8878c2ecf20Sopenharmony_ci	int ret;
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	if (force_device_id[0]) {
8908c2ecf20Sopenharmony_ci		for (id = kempld_dmi_table;
8918c2ecf20Sopenharmony_ci		     id->matches[0].slot != DMI_NONE; id++)
8928c2ecf20Sopenharmony_ci			if (strstr(id->ident, force_device_id))
8938c2ecf20Sopenharmony_ci				if (id->callback && !id->callback(id))
8948c2ecf20Sopenharmony_ci					break;
8958c2ecf20Sopenharmony_ci		if (id->matches[0].slot == DMI_NONE)
8968c2ecf20Sopenharmony_ci			return -ENODEV;
8978c2ecf20Sopenharmony_ci	}
8988c2ecf20Sopenharmony_ci
8998c2ecf20Sopenharmony_ci	ret = platform_driver_register(&kempld_driver);
9008c2ecf20Sopenharmony_ci	if (ret)
9018c2ecf20Sopenharmony_ci		return ret;
9028c2ecf20Sopenharmony_ci
9038c2ecf20Sopenharmony_ci	/*
9048c2ecf20Sopenharmony_ci	 * With synchronous probing the device should already be probed now.
9058c2ecf20Sopenharmony_ci	 * If no device id is forced and also no ACPI definition for the
9068c2ecf20Sopenharmony_ci	 * device was found, scan DMI table as fallback.
9078c2ecf20Sopenharmony_ci	 *
9088c2ecf20Sopenharmony_ci	 * If drivers_autoprobing is disabled and the device is found here,
9098c2ecf20Sopenharmony_ci	 * only that device can be bound manually later.
9108c2ecf20Sopenharmony_ci	 */
9118c2ecf20Sopenharmony_ci	if (!kempld_pdev && !kempld_acpi_mode)
9128c2ecf20Sopenharmony_ci		dmi_check_system(kempld_dmi_table);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	return 0;
9158c2ecf20Sopenharmony_ci}
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_cistatic void __exit kempld_exit(void)
9188c2ecf20Sopenharmony_ci{
9198c2ecf20Sopenharmony_ci	if (kempld_pdev)
9208c2ecf20Sopenharmony_ci		platform_device_unregister(kempld_pdev);
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	platform_driver_unregister(&kempld_driver);
9238c2ecf20Sopenharmony_ci}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_cimodule_init(kempld_init);
9268c2ecf20Sopenharmony_cimodule_exit(kempld_exit);
9278c2ecf20Sopenharmony_ci
9288c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("KEM PLD Core Driver");
9298c2ecf20Sopenharmony_ciMODULE_AUTHOR("Michael Brunner <michael.brunner@kontron.com>");
9308c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
9318c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:kempld-core");
932