1 // SPDX-License-Identifier: GPL-2.0
3 * Siemens SIMATIC IPC platform driver
5 * Copyright (c) Siemens AG, 2018-2023
8 * Henning Schild <henning.schild@siemens.com>
9 * Jan Kiszka <jan.kiszka@siemens.com>
10 * Gerd Haeussler <gerd.haeussler.ext@siemens.com>
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/platform_data/x86/simatic-ipc.h>
19 #include <linux/platform_device.h>
21 static struct platform_device
*ipc_led_platform_device
;
22 static struct platform_device
*ipc_wdt_platform_device
;
23 static struct platform_device
*ipc_batt_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
;
36 #define SIMATIC_IPC_MAX_EXTRA_MODULES 2
43 char *extra_modules
[SIMATIC_IPC_MAX_EXTRA_MODULES
];
46 SIMATIC_IPC_DEVICE_127E
, SIMATIC_IPC_DEVICE_NONE
, SIMATIC_IPC_DEVICE_127E
,
49 SIMATIC_IPC_DEVICE_227D
, SIMATIC_IPC_DEVICE_NONE
, SIMATIC_IPC_DEVICE_NONE
,
52 SIMATIC_IPC_DEVICE_427E
, SIMATIC_IPC_DEVICE_227E
, SIMATIC_IPC_DEVICE_227E
,
55 SIMATIC_IPC_DEVICE_227G
, SIMATIC_IPC_DEVICE_NONE
, SIMATIC_IPC_DEVICE_227G
,
56 { "nct6775", "w83627hf_wdt" }},
58 SIMATIC_IPC_DEVICE_NONE
, SIMATIC_IPC_DEVICE_NONE
, SIMATIC_IPC_DEVICE_227G
,
59 { "nct6775", "w83627hf_wdt" }},
61 SIMATIC_IPC_DEVICE_NONE
, SIMATIC_IPC_DEVICE_227E
, SIMATIC_IPC_DEVICE_227E
,
64 SIMATIC_IPC_DEVICE_427E
, SIMATIC_IPC_DEVICE_NONE
, SIMATIC_IPC_DEVICE_NONE
,
67 SIMATIC_IPC_DEVICE_427E
, SIMATIC_IPC_DEVICE_427E
, SIMATIC_IPC_DEVICE_NONE
,
70 SIMATIC_IPC_DEVICE_NONE
, SIMATIC_IPC_DEVICE_427E
, SIMATIC_IPC_DEVICE_NONE
,
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
,
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" }},
89 static int register_platform_devices(u32 station_id
)
91 u8 ledmode
= SIMATIC_IPC_DEVICE_NONE
;
92 u8 wdtmode
= SIMATIC_IPC_DEVICE_NONE
;
93 u8 battmode
= SIMATIC_IPC_DEVICE_NONE
;
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
;
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
);
124 pr_debug("device=%s created\n",
125 ipc_batt_platform_device
->name
);
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
,
141 sizeof(struct simatic_ipc_platform
));
142 if (IS_ERR(ipc_led_platform_device
))
143 return PTR_ERR(ipc_led_platform_device
);
145 pr_debug("device=%s created\n",
146 ipc_led_platform_device
->name
);
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
,
155 sizeof(struct simatic_ipc_platform
));
156 if (IS_ERR(ipc_wdt_platform_device
))
157 return PTR_ERR(ipc_wdt_platform_device
);
159 pr_debug("device=%s created\n",
160 ipc_wdt_platform_device
->name
);
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",
174 static void request_additional_modules(u32 station_id
)
176 char **extra_modules
= NULL
;
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
;
189 for (i
= 0; i
< SIMATIC_IPC_MAX_EXTRA_MODULES
; i
++) {
190 if (extra_modules
[i
])
191 request_module(extra_modules
[i
]);
197 static int __init
simatic_ipc_init_module(void)
199 const struct dmi_system_id
*match
;
203 match
= dmi_first_match(simatic_ipc_whitelist
);
207 err
= dmi_walk(simatic_ipc_find_dmi_entry_helper
, &station_id
);
209 if (err
|| station_id
== SIMATIC_IPC_INVALID_STATION_ID
) {
210 pr_warn("DMI entry %d not found\n", SIMATIC_IPC_DMI_ENTRY_OEM
);
214 request_additional_modules(station_id
);
216 return register_platform_devices(station_id
);
219 static void __exit
simatic_ipc_exit_module(void)
221 platform_device_unregister(ipc_led_platform_device
);
222 ipc_led_platform_device
= NULL
;
224 platform_device_unregister(ipc_wdt_platform_device
);
225 ipc_wdt_platform_device
= NULL
;
227 platform_device_unregister(ipc_batt_platform_device
);
228 ipc_batt_platform_device
= NULL
;
231 module_init(simatic_ipc_init_module
);
232 module_exit(simatic_ipc_exit_module
);
234 MODULE_DESCRIPTION("Siemens SIMATIC IPC platform driver");
235 MODULE_LICENSE("GPL v2");
236 MODULE_AUTHOR("Gerd Haeussler <gerd.haeussler.ext@siemens.com>");
237 MODULE_ALIAS("dmi:*:svnSIEMENSAG:*");