brintos

brintos / linux-shallow public Read only

0
0
Text · 6.9 KiB · 7039874 Raw
238 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Siemens SIMATIC IPC platform driver4 *5 * Copyright (c) Siemens AG, 2018-20236 *7 * Authors:8 *  Henning Schild <henning.schild@siemens.com>9 *  Jan Kiszka <jan.kiszka@siemens.com>10 *  Gerd Haeussler <gerd.haeussler.ext@siemens.com>11 */12 13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt14 15#include <linux/dmi.h>16#include <linux/kernel.h>17#include <linux/module.h>18#include <linux/platform_data/x86/simatic-ipc.h>19#include <linux/platform_device.h>20 21static struct platform_device *ipc_led_platform_device;22static struct platform_device *ipc_wdt_platform_device;23static struct platform_device *ipc_batt_platform_device;24 25static const struct dmi_system_id simatic_ipc_whitelist[] = {26	{27		.matches = {28			DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"),29		},30	},31	{}32};33 34static struct simatic_ipc_platform platform_data;35 36#define SIMATIC_IPC_MAX_EXTRA_MODULES 237 38static struct {39	u32 station_id;40	u8 led_mode;41	u8 wdt_mode;42	u8 batt_mode;43	char *extra_modules[SIMATIC_IPC_MAX_EXTRA_MODULES];44} device_modes[] = {45	{SIMATIC_IPC_IPC127E,46		SIMATIC_IPC_DEVICE_127E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_127E,47		{ "emc1403", NULL }},48	{SIMATIC_IPC_IPC227D,49		SIMATIC_IPC_DEVICE_227D, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_NONE,50		{ "emc1403", NULL }},51	{SIMATIC_IPC_IPC227E,52		SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_227E, SIMATIC_IPC_DEVICE_227E,53		{ "emc1403", NULL }},54	{SIMATIC_IPC_IPC227G,55		SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227G,56		{ "nct6775", "w83627hf_wdt" }},57	{SIMATIC_IPC_IPC277G,58		SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227G,59		{ "nct6775", "w83627hf_wdt" }},60	{SIMATIC_IPC_IPC277E,61		SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227E, SIMATIC_IPC_DEVICE_227E,62		{ "emc1403", NULL }},63	{SIMATIC_IPC_IPC427D,64		SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_NONE,65		{ "emc1403", NULL }},66	{SIMATIC_IPC_IPC427E,67		SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE,68		{ "emc1403", NULL }},69	{SIMATIC_IPC_IPC477E,70		SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE,71		{ "emc1403", NULL }},72	{SIMATIC_IPC_IPCBX_39A,73		SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_BX_39A,74		{ "nct6775", "w83627hf_wdt" }},75	{SIMATIC_IPC_IPCPX_39A,76		SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_BX_39A,77		{ "nct6775", "w83627hf_wdt" }},78	{SIMATIC_IPC_IPCBX_21A,79		SIMATIC_IPC_DEVICE_BX_21A, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_BX_21A,80		{ "emc1403", NULL }},81	{SIMATIC_IPC_IPCBX_56A,82		SIMATIC_IPC_DEVICE_BX_59A, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_BX_59A,83		{ "emc1403", "w83627hf_wdt" }},84	{SIMATIC_IPC_IPCBX_59A,85		SIMATIC_IPC_DEVICE_BX_59A, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_BX_59A,86		{ "emc1403", "w83627hf_wdt" }},87};88 89static int register_platform_devices(u32 station_id)90{91	u8 ledmode = SIMATIC_IPC_DEVICE_NONE;92	u8 wdtmode = SIMATIC_IPC_DEVICE_NONE;93	u8 battmode = SIMATIC_IPC_DEVICE_NONE;94	char *pdevname;95	int i;96 97	for (i = 0; i < ARRAY_SIZE(device_modes); i++) {98		if (device_modes[i].station_id == station_id) {99			ledmode = device_modes[i].led_mode;100			wdtmode = device_modes[i].wdt_mode;101			battmode = device_modes[i].batt_mode;102			break;103		}104	}105 106	if (battmode != SIMATIC_IPC_DEVICE_NONE) {107		pdevname = KBUILD_MODNAME "_batt";108		if (battmode == SIMATIC_IPC_DEVICE_127E)109			pdevname = KBUILD_MODNAME "_batt_apollolake";110		if (battmode == SIMATIC_IPC_DEVICE_BX_21A)111			pdevname = KBUILD_MODNAME "_batt_elkhartlake";112		if (battmode == SIMATIC_IPC_DEVICE_227G ||113		    battmode == SIMATIC_IPC_DEVICE_BX_39A ||114		    battmode == SIMATIC_IPC_DEVICE_BX_59A)115			pdevname = KBUILD_MODNAME "_batt_f7188x";116		platform_data.devmode = battmode;117		ipc_batt_platform_device =118			platform_device_register_data(NULL, pdevname,119				PLATFORM_DEVID_NONE, &platform_data,120				sizeof(struct simatic_ipc_platform));121		if (IS_ERR(ipc_batt_platform_device))122			return PTR_ERR(ipc_batt_platform_device);123 124		pr_debug("device=%s created\n",125			 ipc_batt_platform_device->name);126	}127 128	if (ledmode != SIMATIC_IPC_DEVICE_NONE) {129		pdevname = KBUILD_MODNAME "_leds";130		if (ledmode == SIMATIC_IPC_DEVICE_127E)131			pdevname = KBUILD_MODNAME "_leds_gpio_apollolake";132		if (ledmode == SIMATIC_IPC_DEVICE_227G || ledmode == SIMATIC_IPC_DEVICE_BX_59A)133			pdevname = KBUILD_MODNAME "_leds_gpio_f7188x";134		if (ledmode == SIMATIC_IPC_DEVICE_BX_21A)135			pdevname = KBUILD_MODNAME "_leds_gpio_elkhartlake";136		platform_data.devmode = ledmode;137		ipc_led_platform_device =138			platform_device_register_data(NULL,139				pdevname, PLATFORM_DEVID_NONE,140				&platform_data,141				sizeof(struct simatic_ipc_platform));142		if (IS_ERR(ipc_led_platform_device))143			return PTR_ERR(ipc_led_platform_device);144 145		pr_debug("device=%s created\n",146			 ipc_led_platform_device->name);147	}148 149	if (wdtmode != SIMATIC_IPC_DEVICE_NONE) {150		platform_data.devmode = wdtmode;151		ipc_wdt_platform_device =152			platform_device_register_data(NULL,153				KBUILD_MODNAME "_wdt", PLATFORM_DEVID_NONE,154				&platform_data,155				sizeof(struct simatic_ipc_platform));156		if (IS_ERR(ipc_wdt_platform_device))157			return PTR_ERR(ipc_wdt_platform_device);158 159		pr_debug("device=%s created\n",160			 ipc_wdt_platform_device->name);161	}162 163	if (ledmode == SIMATIC_IPC_DEVICE_NONE &&164	    wdtmode == SIMATIC_IPC_DEVICE_NONE &&165	    battmode == SIMATIC_IPC_DEVICE_NONE) {166		pr_warn("unsupported IPC detected, station id=%08x\n",167			station_id);168		return -EINVAL;169	}170 171	return 0;172}173 174static void request_additional_modules(u32 station_id)175{176	char **extra_modules = NULL;177	int i;178 179	for (i = 0; i < ARRAY_SIZE(device_modes); i++) {180		if (device_modes[i].station_id == station_id) {181			extra_modules = device_modes[i].extra_modules;182			break;183		}184	}185 186	if (!extra_modules)187		return;188 189	for (i = 0; i < SIMATIC_IPC_MAX_EXTRA_MODULES; i++) {190		if (extra_modules[i])191			request_module(extra_modules[i]);192		else193			break;194	}195}196 197static int __init simatic_ipc_init_module(void)198{199	const struct dmi_system_id *match;200	u32 station_id;201	int err;202 203	match = dmi_first_match(simatic_ipc_whitelist);204	if (!match)205		return 0;206 207	err = dmi_walk(simatic_ipc_find_dmi_entry_helper, &station_id);208 209	if (err || station_id == SIMATIC_IPC_INVALID_STATION_ID) {210		pr_warn("DMI entry %d not found\n", SIMATIC_IPC_DMI_ENTRY_OEM);211		return 0;212	}213 214	request_additional_modules(station_id);215 216	return register_platform_devices(station_id);217}218 219static void __exit simatic_ipc_exit_module(void)220{221	platform_device_unregister(ipc_led_platform_device);222	ipc_led_platform_device = NULL;223 224	platform_device_unregister(ipc_wdt_platform_device);225	ipc_wdt_platform_device = NULL;226 227	platform_device_unregister(ipc_batt_platform_device);228	ipc_batt_platform_device = NULL;229}230 231module_init(simatic_ipc_init_module);232module_exit(simatic_ipc_exit_module);233 234MODULE_DESCRIPTION("Siemens SIMATIC IPC platform driver");235MODULE_LICENSE("GPL v2");236MODULE_AUTHOR("Gerd Haeussler <gerd.haeussler.ext@siemens.com>");237MODULE_ALIAS("dmi:*:svnSIEMENSAG:*");238