Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'ib-pdx86-simatic-v6.6' into review-hans

Immutable branch between pdx86 simatic branch and LED due for the v6.6 merge window

v6.5-rc1 + recent pdx86 simatic-ipc patches for
merging into the LED subsystem for v6.6.

+607 -28
+48 -1
drivers/platform/x86/Kconfig
··· 1076 1076 1077 1077 config SIEMENS_SIMATIC_IPC 1078 1078 tristate "Siemens Simatic IPC Class driver" 1079 - depends on PCI 1080 1079 help 1081 1080 This Simatic IPC class driver is the central of several drivers. It 1082 1081 is mainly used for system identification, after which drivers in other ··· 1084 1085 1085 1086 To compile this driver as a module, choose M here: the module 1086 1087 will be called simatic-ipc. 1088 + 1089 + config SIEMENS_SIMATIC_IPC_BATT 1090 + tristate "CMOS battery driver for Siemens Simatic IPCs" 1091 + depends on HWMON 1092 + depends on SIEMENS_SIMATIC_IPC 1093 + default SIEMENS_SIMATIC_IPC 1094 + help 1095 + This option enables support for monitoring the voltage of the CMOS 1096 + batteries of several Industrial PCs from Siemens. 1097 + 1098 + To compile this driver as a module, choose M here: the module 1099 + will be called simatic-ipc-batt. 1100 + 1101 + config SIEMENS_SIMATIC_IPC_BATT_APOLLOLAKE 1102 + tristate "CMOS Battery monitoring for Simatic IPCs based on Apollo Lake GPIO" 1103 + depends on PINCTRL_BROXTON 1104 + depends on SIEMENS_SIMATIC_IPC_BATT 1105 + default SIEMENS_SIMATIC_IPC_BATT 1106 + help 1107 + This option enables CMOS battery monitoring for Simatic Industrial PCs 1108 + from Siemens based on Apollo Lake GPIO. 1109 + 1110 + To compile this driver as a module, choose M here: the module 1111 + will be called simatic-ipc-batt-apollolake. 1112 + 1113 + config SIEMENS_SIMATIC_IPC_BATT_ELKHARTLAKE 1114 + tristate "CMOS Battery monitoring for Simatic IPCs based on Elkhart Lake GPIO" 1115 + depends on PINCTRL_ELKHARTLAKE 1116 + depends on SIEMENS_SIMATIC_IPC_BATT 1117 + default SIEMENS_SIMATIC_IPC_BATT 1118 + help 1119 + This option enables CMOS battery monitoring for Simatic Industrial PCs 1120 + from Siemens based on Elkhart Lake GPIO. 1121 + 1122 + To compile this driver as a module, choose M here: the module 1123 + will be called simatic-ipc-batt-elkhartlake. 1124 + 1125 + config SIEMENS_SIMATIC_IPC_BATT_F7188X 1126 + tristate "CMOS Battery monitoring for Simatic IPCs based on Nuvoton GPIO" 1127 + depends on GPIO_F7188X 1128 + depends on SIEMENS_SIMATIC_IPC_BATT 1129 + default SIEMENS_SIMATIC_IPC_BATT 1130 + help 1131 + This option enables CMOS battery monitoring for Simatic Industrial PCs 1132 + from Siemens based on Nuvoton GPIO. 1133 + 1134 + To compile this driver as a module, choose M here: the module 1135 + will be called simatic-ipc-batt-elkhartlake. 1087 1136 1088 1137 config WINMATE_FM07_KEYS 1089 1138 tristate "Winmate FM07/FM07P front-panel keys driver"
+5 -1
drivers/platform/x86/Makefile
··· 131 131 obj-$(CONFIG_X86_INTEL_LPSS) += pmc_atom.o 132 132 133 133 # Siemens Simatic Industrial PCs 134 - obj-$(CONFIG_SIEMENS_SIMATIC_IPC) += simatic-ipc.o 134 + obj-$(CONFIG_SIEMENS_SIMATIC_IPC) += simatic-ipc.o 135 + obj-$(CONFIG_SIEMENS_SIMATIC_IPC_BATT) += simatic-ipc-batt.o 136 + obj-$(CONFIG_SIEMENS_SIMATIC_IPC_BATT_APOLLOLAKE) += simatic-ipc-batt-apollolake.o 137 + obj-$(CONFIG_SIEMENS_SIMATIC_IPC_BATT_ELKHARTLAKE) += simatic-ipc-batt-elkhartlake.o 138 + obj-$(CONFIG_SIEMENS_SIMATIC_IPC_BATT_F7188X) += simatic-ipc-batt-f7188x.o 135 139 136 140 # Winmate 137 141 obj-$(CONFIG_WINMATE_FM07_KEYS) += winmate-fm07-keys.o
+51
drivers/platform/x86/simatic-ipc-batt-apollolake.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Siemens SIMATIC IPC driver for CMOS battery monitoring 4 + * 5 + * Copyright (c) Siemens AG, 2023 6 + * 7 + * Authors: 8 + * Henning Schild <henning.schild@siemens.com> 9 + */ 10 + 11 + #include <linux/gpio/machine.h> 12 + #include <linux/gpio/consumer.h> 13 + #include <linux/kernel.h> 14 + #include <linux/module.h> 15 + #include <linux/platform_device.h> 16 + 17 + #include "simatic-ipc-batt.h" 18 + 19 + static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_127e = { 20 + .table = { 21 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 55, NULL, 0, GPIO_ACTIVE_HIGH), 22 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 61, NULL, 1, GPIO_ACTIVE_HIGH), 23 + GPIO_LOOKUP_IDX("apollolake-pinctrl.1", 41, NULL, 2, GPIO_ACTIVE_HIGH), 24 + {} /* Terminating entry */ 25 + }, 26 + }; 27 + 28 + static int simatic_ipc_batt_apollolake_remove(struct platform_device *pdev) 29 + { 30 + return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_127e); 31 + } 32 + 33 + static int simatic_ipc_batt_apollolake_probe(struct platform_device *pdev) 34 + { 35 + return simatic_ipc_batt_probe(pdev, &simatic_ipc_batt_gpio_table_127e); 36 + } 37 + 38 + static struct platform_driver simatic_ipc_batt_driver = { 39 + .probe = simatic_ipc_batt_apollolake_probe, 40 + .remove = simatic_ipc_batt_apollolake_remove, 41 + .driver = { 42 + .name = KBUILD_MODNAME, 43 + }, 44 + }; 45 + 46 + module_platform_driver(simatic_ipc_batt_driver); 47 + 48 + MODULE_LICENSE("GPL"); 49 + MODULE_ALIAS("platform:" KBUILD_MODNAME); 50 + MODULE_SOFTDEP("pre: simatic-ipc-batt platform:apollolake-pinctrl"); 51 + MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
+51
drivers/platform/x86/simatic-ipc-batt-elkhartlake.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Siemens SIMATIC IPC driver for CMOS battery monitoring 4 + * 5 + * Copyright (c) Siemens AG, 2023 6 + * 7 + * Authors: 8 + * Henning Schild <henning.schild@siemens.com> 9 + */ 10 + 11 + #include <linux/gpio/machine.h> 12 + #include <linux/gpio/consumer.h> 13 + #include <linux/kernel.h> 14 + #include <linux/module.h> 15 + #include <linux/platform_device.h> 16 + 17 + #include "simatic-ipc-batt.h" 18 + 19 + static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_bx_21a = { 20 + .table = { 21 + GPIO_LOOKUP_IDX("INTC1020:04", 18, NULL, 0, GPIO_ACTIVE_HIGH), 22 + GPIO_LOOKUP_IDX("INTC1020:04", 19, NULL, 1, GPIO_ACTIVE_HIGH), 23 + GPIO_LOOKUP_IDX("INTC1020:01", 66, NULL, 2, GPIO_ACTIVE_HIGH), 24 + {} /* Terminating entry */ 25 + }, 26 + }; 27 + 28 + static int simatic_ipc_batt_elkhartlake_remove(struct platform_device *pdev) 29 + { 30 + return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_bx_21a); 31 + } 32 + 33 + static int simatic_ipc_batt_elkhartlake_probe(struct platform_device *pdev) 34 + { 35 + return simatic_ipc_batt_probe(pdev, &simatic_ipc_batt_gpio_table_bx_21a); 36 + } 37 + 38 + static struct platform_driver simatic_ipc_batt_driver = { 39 + .probe = simatic_ipc_batt_elkhartlake_probe, 40 + .remove = simatic_ipc_batt_elkhartlake_remove, 41 + .driver = { 42 + .name = KBUILD_MODNAME, 43 + }, 44 + }; 45 + 46 + module_platform_driver(simatic_ipc_batt_driver); 47 + 48 + MODULE_LICENSE("GPL"); 49 + MODULE_ALIAS("platform:" KBUILD_MODNAME); 50 + MODULE_SOFTDEP("pre: simatic-ipc-batt platform:elkhartlake-pinctrl"); 51 + MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
+70
drivers/platform/x86/simatic-ipc-batt-f7188x.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Siemens SIMATIC IPC driver for CMOS battery monitoring 4 + * 5 + * Copyright (c) Siemens AG, 2023 6 + * 7 + * Authors: 8 + * Henning Schild <henning.schild@siemens.com> 9 + */ 10 + 11 + #include <linux/gpio/machine.h> 12 + #include <linux/gpio/consumer.h> 13 + #include <linux/kernel.h> 14 + #include <linux/module.h> 15 + #include <linux/platform_device.h> 16 + #include <linux/platform_data/x86/simatic-ipc-base.h> 17 + 18 + #include "simatic-ipc-batt.h" 19 + 20 + static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_227g = { 21 + .table = { 22 + GPIO_LOOKUP_IDX("gpio-f7188x-7", 6, NULL, 0, GPIO_ACTIVE_HIGH), 23 + GPIO_LOOKUP_IDX("gpio-f7188x-7", 5, NULL, 1, GPIO_ACTIVE_HIGH), 24 + GPIO_LOOKUP_IDX("INTC1020:01", 66, NULL, 2, GPIO_ACTIVE_HIGH), 25 + {} /* Terminating entry */ 26 + }, 27 + }; 28 + 29 + static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_bx_39a = { 30 + .table = { 31 + GPIO_LOOKUP_IDX("gpio-f7188x-6", 4, NULL, 0, GPIO_ACTIVE_HIGH), 32 + GPIO_LOOKUP_IDX("gpio-f7188x-6", 3, NULL, 1, GPIO_ACTIVE_HIGH), 33 + {} /* Terminating entry */ 34 + }, 35 + }; 36 + 37 + static int simatic_ipc_batt_f7188x_remove(struct platform_device *pdev) 38 + { 39 + const struct simatic_ipc_platform *plat = pdev->dev.platform_data; 40 + 41 + if (plat->devmode == SIMATIC_IPC_DEVICE_227G) 42 + return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_227g); 43 + 44 + return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_bx_39a); 45 + } 46 + 47 + static int simatic_ipc_batt_f7188x_probe(struct platform_device *pdev) 48 + { 49 + const struct simatic_ipc_platform *plat = pdev->dev.platform_data; 50 + 51 + if (plat->devmode == SIMATIC_IPC_DEVICE_227G) 52 + return simatic_ipc_batt_probe(pdev, &simatic_ipc_batt_gpio_table_227g); 53 + 54 + return simatic_ipc_batt_probe(pdev, &simatic_ipc_batt_gpio_table_bx_39a); 55 + } 56 + 57 + static struct platform_driver simatic_ipc_batt_driver = { 58 + .probe = simatic_ipc_batt_f7188x_probe, 59 + .remove = simatic_ipc_batt_f7188x_remove, 60 + .driver = { 61 + .name = KBUILD_MODNAME, 62 + }, 63 + }; 64 + 65 + module_platform_driver(simatic_ipc_batt_driver); 66 + 67 + MODULE_LICENSE("GPL"); 68 + MODULE_ALIAS("platform:" KBUILD_MODNAME); 69 + MODULE_SOFTDEP("pre: simatic-ipc-batt gpio_f7188x platform:elkhartlake-pinctrl"); 70 + MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
+252
drivers/platform/x86/simatic-ipc-batt.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Siemens SIMATIC IPC driver for CMOS battery monitoring 4 + * 5 + * Copyright (c) Siemens AG, 2023 6 + * 7 + * Authors: 8 + * Gerd Haeussler <gerd.haeussler.ext@siemens.com> 9 + * Henning Schild <henning.schild@siemens.com> 10 + */ 11 + 12 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 13 + 14 + #include <linux/delay.h> 15 + #include <linux/io.h> 16 + #include <linux/ioport.h> 17 + #include <linux/gpio/machine.h> 18 + #include <linux/gpio/consumer.h> 19 + #include <linux/hwmon.h> 20 + #include <linux/hwmon-sysfs.h> 21 + #include <linux/jiffies.h> 22 + #include <linux/kernel.h> 23 + #include <linux/module.h> 24 + #include <linux/platform_device.h> 25 + #include <linux/platform_data/x86/simatic-ipc-base.h> 26 + #include <linux/sizes.h> 27 + 28 + #include "simatic-ipc-batt.h" 29 + 30 + #define BATT_DELAY_MS (1000 * 60 * 60 * 24) /* 24 h delay */ 31 + 32 + #define SIMATIC_IPC_BATT_LEVEL_FULL 3000 33 + #define SIMATIC_IPC_BATT_LEVEL_CRIT 2750 34 + #define SIMATIC_IPC_BATT_LEVEL_EMPTY 0 35 + 36 + static struct simatic_ipc_batt { 37 + u8 devmode; 38 + long current_state; 39 + struct gpio_desc *gpios[3]; 40 + unsigned long last_updated_jiffies; 41 + } priv; 42 + 43 + static long simatic_ipc_batt_read_gpio(void) 44 + { 45 + long r = SIMATIC_IPC_BATT_LEVEL_FULL; 46 + 47 + if (priv.gpios[2]) { 48 + gpiod_set_value(priv.gpios[2], 1); 49 + msleep(150); 50 + } 51 + 52 + if (gpiod_get_value_cansleep(priv.gpios[0])) 53 + r = SIMATIC_IPC_BATT_LEVEL_EMPTY; 54 + else if (gpiod_get_value_cansleep(priv.gpios[1])) 55 + r = SIMATIC_IPC_BATT_LEVEL_CRIT; 56 + 57 + if (priv.gpios[2]) 58 + gpiod_set_value(priv.gpios[2], 0); 59 + 60 + return r; 61 + } 62 + 63 + #define SIMATIC_IPC_BATT_PORT_BASE 0x404D 64 + static struct resource simatic_ipc_batt_io_res = 65 + DEFINE_RES_IO_NAMED(SIMATIC_IPC_BATT_PORT_BASE, SZ_1, KBUILD_MODNAME); 66 + 67 + static long simatic_ipc_batt_read_io(struct device *dev) 68 + { 69 + long r = SIMATIC_IPC_BATT_LEVEL_FULL; 70 + struct resource *res = &simatic_ipc_batt_io_res; 71 + u8 val; 72 + 73 + if (!request_muxed_region(res->start, resource_size(res), res->name)) { 74 + dev_err(dev, "Unable to register IO resource at %pR\n", res); 75 + return -EBUSY; 76 + } 77 + 78 + val = inb(SIMATIC_IPC_BATT_PORT_BASE); 79 + release_region(simatic_ipc_batt_io_res.start, resource_size(&simatic_ipc_batt_io_res)); 80 + 81 + if (val & (1 << 7)) 82 + r = SIMATIC_IPC_BATT_LEVEL_EMPTY; 83 + else if (val & (1 << 6)) 84 + r = SIMATIC_IPC_BATT_LEVEL_CRIT; 85 + 86 + return r; 87 + } 88 + 89 + static long simatic_ipc_batt_read_value(struct device *dev) 90 + { 91 + unsigned long next_update; 92 + 93 + next_update = priv.last_updated_jiffies + msecs_to_jiffies(BATT_DELAY_MS); 94 + if (time_after(jiffies, next_update) || !priv.last_updated_jiffies) { 95 + switch (priv.devmode) { 96 + case SIMATIC_IPC_DEVICE_127E: 97 + case SIMATIC_IPC_DEVICE_227G: 98 + case SIMATIC_IPC_DEVICE_BX_39A: 99 + priv.current_state = simatic_ipc_batt_read_gpio(); 100 + break; 101 + case SIMATIC_IPC_DEVICE_227E: 102 + priv.current_state = simatic_ipc_batt_read_io(dev); 103 + break; 104 + } 105 + priv.last_updated_jiffies = jiffies; 106 + if (priv.current_state < SIMATIC_IPC_BATT_LEVEL_FULL) 107 + dev_warn(dev, "CMOS battery needs to be replaced."); 108 + } 109 + 110 + return priv.current_state; 111 + } 112 + 113 + static int simatic_ipc_batt_read(struct device *dev, enum hwmon_sensor_types type, 114 + u32 attr, int channel, long *val) 115 + { 116 + switch (attr) { 117 + case hwmon_in_input: 118 + *val = simatic_ipc_batt_read_value(dev); 119 + break; 120 + case hwmon_in_lcrit: 121 + *val = SIMATIC_IPC_BATT_LEVEL_CRIT; 122 + break; 123 + default: 124 + return -EOPNOTSUPP; 125 + } 126 + 127 + return 0; 128 + } 129 + 130 + static umode_t simatic_ipc_batt_is_visible(const void *data, enum hwmon_sensor_types type, 131 + u32 attr, int channel) 132 + { 133 + if (attr == hwmon_in_input || attr == hwmon_in_lcrit) 134 + return 0444; 135 + 136 + return 0; 137 + } 138 + 139 + static const struct hwmon_ops simatic_ipc_batt_ops = { 140 + .is_visible = simatic_ipc_batt_is_visible, 141 + .read = simatic_ipc_batt_read, 142 + }; 143 + 144 + static const struct hwmon_channel_info *simatic_ipc_batt_info[] = { 145 + HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_LCRIT), 146 + NULL 147 + }; 148 + 149 + static const struct hwmon_chip_info simatic_ipc_batt_chip_info = { 150 + .ops = &simatic_ipc_batt_ops, 151 + .info = simatic_ipc_batt_info, 152 + }; 153 + 154 + int simatic_ipc_batt_remove(struct platform_device *pdev, struct gpiod_lookup_table *table) 155 + { 156 + gpiod_remove_lookup_table(table); 157 + return 0; 158 + } 159 + EXPORT_SYMBOL_GPL(simatic_ipc_batt_remove); 160 + 161 + int simatic_ipc_batt_probe(struct platform_device *pdev, struct gpiod_lookup_table *table) 162 + { 163 + struct simatic_ipc_platform *plat; 164 + struct device *dev = &pdev->dev; 165 + struct device *hwmon_dev; 166 + int err; 167 + 168 + plat = pdev->dev.platform_data; 169 + priv.devmode = plat->devmode; 170 + 171 + switch (priv.devmode) { 172 + case SIMATIC_IPC_DEVICE_127E: 173 + case SIMATIC_IPC_DEVICE_227G: 174 + case SIMATIC_IPC_DEVICE_BX_39A: 175 + case SIMATIC_IPC_DEVICE_BX_21A: 176 + table->dev_id = dev_name(dev); 177 + gpiod_add_lookup_table(table); 178 + break; 179 + case SIMATIC_IPC_DEVICE_227E: 180 + goto nogpio; 181 + default: 182 + return -ENODEV; 183 + } 184 + 185 + priv.gpios[0] = devm_gpiod_get_index(dev, "CMOSBattery empty", 0, GPIOD_IN); 186 + if (IS_ERR(priv.gpios[0])) { 187 + err = PTR_ERR(priv.gpios[0]); 188 + priv.gpios[0] = NULL; 189 + goto out; 190 + } 191 + priv.gpios[1] = devm_gpiod_get_index(dev, "CMOSBattery low", 1, GPIOD_IN); 192 + if (IS_ERR(priv.gpios[1])) { 193 + err = PTR_ERR(priv.gpios[1]); 194 + priv.gpios[1] = NULL; 195 + goto out; 196 + } 197 + 198 + if (table->table[2].key) { 199 + priv.gpios[2] = devm_gpiod_get_index(dev, "CMOSBattery meter", 2, GPIOD_OUT_HIGH); 200 + if (IS_ERR(priv.gpios[2])) { 201 + err = PTR_ERR(priv.gpios[1]); 202 + priv.gpios[2] = NULL; 203 + goto out; 204 + } 205 + } else { 206 + priv.gpios[2] = NULL; 207 + } 208 + 209 + nogpio: 210 + hwmon_dev = devm_hwmon_device_register_with_info(dev, KBUILD_MODNAME, 211 + &priv, 212 + &simatic_ipc_batt_chip_info, 213 + NULL); 214 + if (IS_ERR(hwmon_dev)) { 215 + err = PTR_ERR(hwmon_dev); 216 + goto out; 217 + } 218 + 219 + /* warn about aging battery even if userspace never reads hwmon */ 220 + simatic_ipc_batt_read_value(dev); 221 + 222 + return 0; 223 + out: 224 + simatic_ipc_batt_remove(pdev, table); 225 + 226 + return err; 227 + } 228 + EXPORT_SYMBOL_GPL(simatic_ipc_batt_probe); 229 + 230 + static int simatic_ipc_batt_io_remove(struct platform_device *pdev) 231 + { 232 + return simatic_ipc_batt_remove(pdev, NULL); 233 + } 234 + 235 + static int simatic_ipc_batt_io_probe(struct platform_device *pdev) 236 + { 237 + return simatic_ipc_batt_probe(pdev, NULL); 238 + } 239 + 240 + static struct platform_driver simatic_ipc_batt_driver = { 241 + .probe = simatic_ipc_batt_io_probe, 242 + .remove = simatic_ipc_batt_io_remove, 243 + .driver = { 244 + .name = KBUILD_MODNAME, 245 + }, 246 + }; 247 + 248 + module_platform_driver(simatic_ipc_batt_driver); 249 + 250 + MODULE_LICENSE("GPL"); 251 + MODULE_ALIAS("platform:" KBUILD_MODNAME); 252 + MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
+20
drivers/platform/x86/simatic-ipc-batt.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Siemens SIMATIC IPC driver for CMOS battery monitoring 4 + * 5 + * Copyright (c) Siemens AG, 2023 6 + * 7 + * Author: 8 + * Henning Schild <henning.schild@siemens.com> 9 + */ 10 + 11 + #ifndef _SIMATIC_IPC_BATT_H 12 + #define _SIMATIC_IPC_BATT_H 13 + 14 + int simatic_ipc_batt_probe(struct platform_device *pdev, 15 + struct gpiod_lookup_table *table); 16 + 17 + int simatic_ipc_batt_remove(struct platform_device *pdev, 18 + struct gpiod_lookup_table *table); 19 + 20 + #endif /* _SIMATIC_IPC_BATT_H */
+98 -21
drivers/platform/x86/simatic-ipc.c
··· 2 2 /* 3 3 * Siemens SIMATIC IPC platform driver 4 4 * 5 - * Copyright (c) Siemens AG, 2018-2021 5 + * Copyright (c) Siemens AG, 2018-2023 6 6 * 7 7 * Authors: 8 8 * Henning Schild <henning.schild@siemens.com> ··· 15 15 #include <linux/dmi.h> 16 16 #include <linux/kernel.h> 17 17 #include <linux/module.h> 18 - #include <linux/pci.h> 19 18 #include <linux/platform_data/x86/simatic-ipc.h> 20 19 #include <linux/platform_device.h> 21 20 22 21 static struct platform_device *ipc_led_platform_device; 23 22 static struct platform_device *ipc_wdt_platform_device; 23 + static struct platform_device *ipc_batt_platform_device; 24 24 25 25 static const struct dmi_system_id simatic_ipc_whitelist[] = { 26 26 { ··· 33 33 34 34 static struct simatic_ipc_platform platform_data; 35 35 36 + #define SIMATIC_IPC_MAX_EXTRA_MODULES 2 37 + 36 38 static struct { 37 39 u32 station_id; 38 40 u8 led_mode; 39 41 u8 wdt_mode; 42 + u8 batt_mode; 43 + char *extra_modules[SIMATIC_IPC_MAX_EXTRA_MODULES]; 40 44 } device_modes[] = { 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_IPC227G, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_227G}, 45 - {SIMATIC_IPC_IPC277E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227E}, 46 - {SIMATIC_IPC_IPC427D, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE}, 47 - {SIMATIC_IPC_IPC427E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_427E}, 48 - {SIMATIC_IPC_IPC477E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_427E}, 49 - {SIMATIC_IPC_IPCBX_39A, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_227G}, 50 - {SIMATIC_IPC_IPCPX_39A, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227G}, 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 }}, 51 81 }; 52 82 53 83 static int register_platform_devices(u32 station_id) 54 84 { 55 85 u8 ledmode = SIMATIC_IPC_DEVICE_NONE; 56 86 u8 wdtmode = SIMATIC_IPC_DEVICE_NONE; 57 - char *pdevname = KBUILD_MODNAME "_leds"; 87 + u8 battmode = SIMATIC_IPC_DEVICE_NONE; 88 + char *pdevname; 58 89 int i; 59 - 60 - platform_data.devmode = SIMATIC_IPC_DEVICE_NONE; 61 90 62 91 for (i = 0; i < ARRAY_SIZE(device_modes); i++) { 63 92 if (device_modes[i].station_id == station_id) { 64 93 ledmode = device_modes[i].led_mode; 65 94 wdtmode = device_modes[i].wdt_mode; 95 + battmode = device_modes[i].batt_mode; 66 96 break; 67 97 } 68 98 } 69 99 100 + if (battmode != SIMATIC_IPC_DEVICE_NONE) { 101 + pdevname = KBUILD_MODNAME "_batt"; 102 + if (battmode == SIMATIC_IPC_DEVICE_127E) 103 + pdevname = KBUILD_MODNAME "_batt_apollolake"; 104 + if (battmode == SIMATIC_IPC_DEVICE_BX_21A) 105 + pdevname = KBUILD_MODNAME "_batt_elkhartlake"; 106 + if (battmode == SIMATIC_IPC_DEVICE_227G || battmode == SIMATIC_IPC_DEVICE_BX_39A) 107 + pdevname = KBUILD_MODNAME "_batt_f7188x"; 108 + platform_data.devmode = battmode; 109 + ipc_batt_platform_device = 110 + platform_device_register_data(NULL, pdevname, 111 + PLATFORM_DEVID_NONE, &platform_data, 112 + sizeof(struct simatic_ipc_platform)); 113 + if (IS_ERR(ipc_batt_platform_device)) 114 + return PTR_ERR(ipc_batt_platform_device); 115 + 116 + pr_debug("device=%s created\n", 117 + ipc_batt_platform_device->name); 118 + } 119 + 70 120 if (ledmode != SIMATIC_IPC_DEVICE_NONE) { 121 + pdevname = KBUILD_MODNAME "_leds"; 71 122 if (ledmode == SIMATIC_IPC_DEVICE_127E) 72 123 pdevname = KBUILD_MODNAME "_leds_gpio_apollolake"; 73 124 if (ledmode == SIMATIC_IPC_DEVICE_227G) 74 125 pdevname = KBUILD_MODNAME "_leds_gpio_f7188x"; 126 + if (ledmode == SIMATIC_IPC_DEVICE_BX_21A) 127 + pdevname = KBUILD_MODNAME "_leds_gpio_elkhartlake"; 75 128 platform_data.devmode = ledmode; 76 129 ipc_led_platform_device = 77 130 platform_device_register_data(NULL, ··· 136 83 137 84 pr_debug("device=%s created\n", 138 85 ipc_led_platform_device->name); 139 - } 140 - 141 - if (wdtmode == SIMATIC_IPC_DEVICE_227G) { 142 - request_module("w83627hf_wdt"); 143 - return 0; 144 86 } 145 87 146 88 if (wdtmode != SIMATIC_IPC_DEVICE_NONE) { ··· 153 105 } 154 106 155 107 if (ledmode == SIMATIC_IPC_DEVICE_NONE && 156 - wdtmode == SIMATIC_IPC_DEVICE_NONE) { 108 + wdtmode == SIMATIC_IPC_DEVICE_NONE && 109 + battmode == SIMATIC_IPC_DEVICE_NONE) { 157 110 pr_warn("unsupported IPC detected, station id=%08x\n", 158 111 station_id); 159 112 return -EINVAL; 160 113 } 161 114 162 115 return 0; 116 + } 117 + 118 + static void request_additional_modules(u32 station_id) 119 + { 120 + char **extra_modules = NULL; 121 + int i; 122 + 123 + for (i = 0; i < ARRAY_SIZE(device_modes); i++) { 124 + if (device_modes[i].station_id == station_id) { 125 + extra_modules = device_modes[i].extra_modules; 126 + break; 127 + } 128 + } 129 + 130 + if (!extra_modules) 131 + return; 132 + 133 + for (i = 0; i < SIMATIC_IPC_MAX_EXTRA_MODULES; i++) { 134 + if (extra_modules[i]) 135 + request_module(extra_modules[i]); 136 + else 137 + break; 138 + } 163 139 } 164 140 165 141 static int __init simatic_ipc_init_module(void) ··· 203 131 return 0; 204 132 } 205 133 134 + request_additional_modules(station_id); 135 + 206 136 return register_platform_devices(station_id); 207 137 } 208 138 ··· 215 141 216 142 platform_device_unregister(ipc_wdt_platform_device); 217 143 ipc_wdt_platform_device = NULL; 144 + 145 + platform_device_unregister(ipc_batt_platform_device); 146 + ipc_batt_platform_device = NULL; 218 147 } 219 148 220 149 module_init(simatic_ipc_init_module);
+6 -3
drivers/watchdog/simatic-ipc-wdt.c
··· 155 155 156 156 switch (plat->devmode) { 157 157 case SIMATIC_IPC_DEVICE_227E: 158 - if (!devm_request_region(dev, gp_status_reg_227e_res.start, 159 - resource_size(&gp_status_reg_227e_res), 160 - KBUILD_MODNAME)) { 158 + res = &gp_status_reg_227e_res; 159 + if (!request_muxed_region(res->start, resource_size(res), res->name)) { 161 160 dev_err(dev, 162 161 "Unable to register IO resource at %pR\n", 163 162 &gp_status_reg_227e_res); ··· 208 209 wdd_data.bootstatus = wd_setup(plat->devmode); 209 210 if (wdd_data.bootstatus) 210 211 dev_warn(dev, "last reboot caused by watchdog reset\n"); 212 + 213 + if (plat->devmode == SIMATIC_IPC_DEVICE_227E) 214 + release_region(gp_status_reg_227e_res.start, 215 + resource_size(&gp_status_reg_227e_res)); 211 216 212 217 watchdog_set_nowayout(&wdd_data, nowayout); 213 218 watchdog_stop_on_reboot(&wdd_data);
+3 -1
include/linux/platform_data/x86/simatic-ipc-base.h
··· 2 2 /* 3 3 * Siemens SIMATIC IPC drivers 4 4 * 5 - * Copyright (c) Siemens AG, 2018-2021 5 + * Copyright (c) Siemens AG, 2018-2023 6 6 * 7 7 * Authors: 8 8 * Henning Schild <henning.schild@siemens.com> ··· 20 20 #define SIMATIC_IPC_DEVICE_127E 3 21 21 #define SIMATIC_IPC_DEVICE_227E 4 22 22 #define SIMATIC_IPC_DEVICE_227G 5 23 + #define SIMATIC_IPC_DEVICE_BX_21A 6 24 + #define SIMATIC_IPC_DEVICE_BX_39A 7 23 25 24 26 struct simatic_ipc_platform { 25 27 u8 devmode;
+3 -1
include/linux/platform_data/x86/simatic-ipc.h
··· 2 2 /* 3 3 * Siemens SIMATIC IPC drivers 4 4 * 5 - * Copyright (c) Siemens AG, 2018-2021 5 + * Copyright (c) Siemens AG, 2018-2023 6 6 * 7 7 * Authors: 8 8 * Henning Schild <henning.schild@siemens.com> ··· 32 32 SIMATIC_IPC_IPC477E = 0x00000A02, 33 33 SIMATIC_IPC_IPC127E = 0x00000D01, 34 34 SIMATIC_IPC_IPC227G = 0x00000F01, 35 + SIMATIC_IPC_IPC277G = 0x00000F02, 35 36 SIMATIC_IPC_IPCBX_39A = 0x00001001, 36 37 SIMATIC_IPC_IPCPX_39A = 0x00001002, 38 + SIMATIC_IPC_IPCBX_21A = 0x00001101, 37 39 }; 38 40 39 41 static inline u32 simatic_ipc_get_station_id(u8 *data, int max_len)