1 // SPDX-License-Identifier: GPL-2.0
3 * Siemens SIMATIC IPC platform driver
5 * Copyright (c) Siemens AG, 2018-2021
13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15 #include <linux/dmi.h>
16 #include <linux/kernel.h>
17 #include <linux/module.h>
18 #include <linux/pci.h>
19 #include <linux/platform_data/x86/simatic-ipc.h>
20 #include <linux/platform_device.h>
22 static struct platform_device *ipc_led_platform_device;
23 static struct platform_device *ipc_wdt_platform_device;
25 static const struct dmi_system_id simatic_ipc_whitelist[] = {
28 DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"),
34 static struct simatic_ipc_platform platform_data;
41 {SIMATIC_IPC_IPC127E, SIMATIC_IPC_DEVICE_127E, SIMATIC_IPC_DEVICE_NONE},
42 {SIMATIC_IPC_IPC227D, SIMATIC_IPC_DEVICE_227D, SIMATIC_IPC_DEVICE_NONE},
43 {SIMATIC_IPC_IPC227E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_227E},
44 {SIMATIC_IPC_IPC277E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227E},
45 {SIMATIC_IPC_IPC427D, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE},
46 {SIMATIC_IPC_IPC427E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_427E},
47 {SIMATIC_IPC_IPC477E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_427E},
50 static int register_platform_devices(u32 station_id)
52 u8 ledmode = SIMATIC_IPC_DEVICE_NONE;
53 u8 wdtmode = SIMATIC_IPC_DEVICE_NONE;
54 char *pdevname = KBUILD_MODNAME "_leds";
57 platform_data.devmode = SIMATIC_IPC_DEVICE_NONE;
59 for (i = 0; i < ARRAY_SIZE(device_modes); i++) {
60 if (device_modes[i].station_id == station_id) {
61 ledmode = device_modes[i].led_mode;
62 wdtmode = device_modes[i].wdt_mode;
67 if (ledmode != SIMATIC_IPC_DEVICE_NONE) {
68 if (ledmode == SIMATIC_IPC_DEVICE_127E)
69 pdevname = KBUILD_MODNAME "_leds_gpio";
70 platform_data.devmode = ledmode;
71 ipc_led_platform_device =
72 platform_device_register_data(NULL,
73 pdevname, PLATFORM_DEVID_NONE,
75 sizeof(struct simatic_ipc_platform));
76 if (IS_ERR(ipc_led_platform_device))
77 return PTR_ERR(ipc_led_platform_device);
79 pr_debug("device=%s created\n",
80 ipc_led_platform_device->name);
83 if (wdtmode != SIMATIC_IPC_DEVICE_NONE) {
84 platform_data.devmode = wdtmode;
85 ipc_wdt_platform_device =
86 platform_device_register_data(NULL,
87 KBUILD_MODNAME "_wdt", PLATFORM_DEVID_NONE,
89 sizeof(struct simatic_ipc_platform));
90 if (IS_ERR(ipc_wdt_platform_device))
91 return PTR_ERR(ipc_wdt_platform_device);
93 pr_debug("device=%s created\n",
94 ipc_wdt_platform_device->name);
97 if (ledmode == SIMATIC_IPC_DEVICE_NONE &&
98 wdtmode == SIMATIC_IPC_DEVICE_NONE) {
99 pr_warn("unsupported IPC detected, station id=%08x\n",
107 static int __init simatic_ipc_init_module(void)
109 const struct dmi_system_id *match;
113 match = dmi_first_match(simatic_ipc_whitelist);
117 err = dmi_walk(simatic_ipc_find_dmi_entry_helper, &station_id);
119 if (err || station_id == SIMATIC_IPC_INVALID_STATION_ID) {
120 pr_warn("DMI entry %d not found\n", SIMATIC_IPC_DMI_ENTRY_OEM);
124 return register_platform_devices(station_id);
127 static void __exit simatic_ipc_exit_module(void)
129 platform_device_unregister(ipc_led_platform_device);
130 ipc_led_platform_device = NULL;
132 platform_device_unregister(ipc_wdt_platform_device);
133 ipc_wdt_platform_device = NULL;
136 module_init(simatic_ipc_init_module);
137 module_exit(simatic_ipc_exit_module);
139 MODULE_LICENSE("GPL v2");
141 MODULE_ALIAS("dmi:*:svnSIEMENSAG:*");