]> Git Repo - linux.git/blob - drivers/platform/x86/siemens/simatic-ipc.c
net: wan: Add framer framework support
[linux.git] / drivers / platform / x86 / siemens / simatic-ipc.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Siemens SIMATIC IPC platform driver
4  *
5  * Copyright (c) Siemens AG, 2018-2023
6  *
7  * Authors:
8  *  Henning Schild <[email protected]>
9  *  Jan Kiszka <[email protected]>
10  *  Gerd Haeussler <[email protected]>
11  */
12
13 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
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
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;
24
25 static const struct dmi_system_id simatic_ipc_whitelist[] = {
26         {
27                 .matches = {
28                         DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"),
29                 },
30         },
31         {}
32 };
33
34 static struct simatic_ipc_platform platform_data;
35
36 #define SIMATIC_IPC_MAX_EXTRA_MODULES 2
37
38 static 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
89 static 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
174 static 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                 else
193                         break;
194         }
195 }
196
197 static 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
219 static 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
231 module_init(simatic_ipc_init_module);
232 module_exit(simatic_ipc_exit_module);
233
234 MODULE_LICENSE("GPL v2");
235 MODULE_AUTHOR("Gerd Haeussler <[email protected]>");
236 MODULE_ALIAS("dmi:*:svnSIEMENSAG:*");
This page took 0.047922 seconds and 4 git commands to generate.