platform/x86: Move all simatic ipc drivers to the subdirectory siemens
authorHenning Schild <henning.schild@siemens.com>
Wed, 19 Jul 2023 15:35:18 +0000 (17:35 +0200)
committerHans de Goede <hdegoede@redhat.com>
Mon, 31 Jul 2023 10:50:19 +0000 (12:50 +0200)
With more files around move everything to a subdirectory. Users will
only see the several options once they enable the main one.

Suggested-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Henning Schild <henning.schild@siemens.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20230719153518.13073-4-henning.schild@siemens.com
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
16 files changed:
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/siemens/Kconfig [new file with mode: 0644]
drivers/platform/x86/siemens/Makefile [new file with mode: 0644]
drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c [new file with mode: 0644]
drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c [new file with mode: 0644]
drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c [new file with mode: 0644]
drivers/platform/x86/siemens/simatic-ipc-batt.c [new file with mode: 0644]
drivers/platform/x86/siemens/simatic-ipc-batt.h [new file with mode: 0644]
drivers/platform/x86/siemens/simatic-ipc.c [new file with mode: 0644]
drivers/platform/x86/simatic-ipc-batt-apollolake.c [deleted file]
drivers/platform/x86/simatic-ipc-batt-elkhartlake.c [deleted file]
drivers/platform/x86/simatic-ipc-batt-f7188x.c [deleted file]
drivers/platform/x86/simatic-ipc-batt.c [deleted file]
drivers/platform/x86/simatic-ipc-batt.h [deleted file]
drivers/platform/x86/simatic-ipc.c [deleted file]

index 487d3d8f4da9c58fbbf17f91a22c4be7e1c4a927..f5fcb1ca1b6362da159ac343ac7c17f02bdb94f8 100644 (file)
@@ -1074,64 +1074,7 @@ config INTEL_SCU_IPC_UTIL
          low level access for debug work and updating the firmware. Say
          N unless you will be doing this on an Intel MID platform.
 
-config SIEMENS_SIMATIC_IPC
-       tristate "Siemens Simatic IPC Class driver"
-       help
-         This Simatic IPC class driver is the central of several drivers. It
-         is mainly used for system identification, after which drivers in other
-         classes will take care of driving specifics of those machines.
-         i.e. LEDs and watchdog.
-
-         To compile this driver as a module, choose M here: the module
-         will be called simatic-ipc.
-
-config SIEMENS_SIMATIC_IPC_BATT
-       tristate "CMOS battery driver for Siemens Simatic IPCs"
-       depends on HWMON
-       depends on SIEMENS_SIMATIC_IPC
-       default SIEMENS_SIMATIC_IPC
-       help
-         This option enables support for monitoring the voltage of the CMOS
-         batteries of several Industrial PCs from Siemens.
-
-         To compile this driver as a module, choose M here: the module
-         will be called simatic-ipc-batt.
-
-config SIEMENS_SIMATIC_IPC_BATT_APOLLOLAKE
-       tristate "CMOS Battery monitoring for Simatic IPCs based on Apollo Lake GPIO"
-       depends on PINCTRL_BROXTON
-       depends on SIEMENS_SIMATIC_IPC_BATT
-       default SIEMENS_SIMATIC_IPC_BATT
-       help
-         This option enables CMOS battery monitoring for Simatic Industrial PCs
-         from Siemens based on Apollo Lake GPIO.
-
-         To compile this driver as a module, choose M here: the module
-         will be called simatic-ipc-batt-apollolake.
-
-config SIEMENS_SIMATIC_IPC_BATT_ELKHARTLAKE
-       tristate "CMOS Battery monitoring for Simatic IPCs based on Elkhart Lake GPIO"
-       depends on PINCTRL_ELKHARTLAKE
-       depends on SIEMENS_SIMATIC_IPC_BATT
-       default SIEMENS_SIMATIC_IPC_BATT
-       help
-         This option enables CMOS battery monitoring for Simatic Industrial PCs
-         from Siemens based on Elkhart Lake GPIO.
-
-         To compile this driver as a module, choose M here: the module
-         will be called simatic-ipc-batt-elkhartlake.
-
-config SIEMENS_SIMATIC_IPC_BATT_F7188X
-       tristate "CMOS Battery monitoring for Simatic IPCs based on Nuvoton GPIO"
-       depends on GPIO_F7188X
-       depends on SIEMENS_SIMATIC_IPC_BATT
-       default SIEMENS_SIMATIC_IPC_BATT
-       help
-         This option enables CMOS battery monitoring for Simatic Industrial PCs
-         from Siemens based on Nuvoton GPIO.
-
-         To compile this driver as a module, choose M here: the module
-         will be called simatic-ipc-batt-elkhartlake.
+source "drivers/platform/x86/siemens/Kconfig"
 
 config WINMATE_FM07_KEYS
        tristate "Winmate FM07/FM07P front-panel keys driver"
index 522da0d1584d20d786c66a137949b916b2ca4066..affce39f3c67d88771264b56f568b5ae3327d5d0 100644 (file)
@@ -131,11 +131,7 @@ obj-$(CONFIG_INTEL_SCU_IPC_UTIL)   += intel_scu_ipcutil.o
 obj-$(CONFIG_X86_INTEL_LPSS)           += pmc_atom.o
 
 # Siemens Simatic Industrial PCs
-obj-$(CONFIG_SIEMENS_SIMATIC_IPC)                      += simatic-ipc.o
-obj-$(CONFIG_SIEMENS_SIMATIC_IPC_BATT)                 += simatic-ipc-batt.o
-obj-$(CONFIG_SIEMENS_SIMATIC_IPC_BATT_APOLLOLAKE)      += simatic-ipc-batt-apollolake.o
-obj-$(CONFIG_SIEMENS_SIMATIC_IPC_BATT_ELKHARTLAKE)     += simatic-ipc-batt-elkhartlake.o
-obj-$(CONFIG_SIEMENS_SIMATIC_IPC_BATT_F7188X)          += simatic-ipc-batt-f7188x.o
+obj-$(CONFIG_SIEMENS_SIMATIC_IPC)      += siemens/
 
 # Winmate
 obj-$(CONFIG_WINMATE_FM07_KEYS)                += winmate-fm07-keys.o
diff --git a/drivers/platform/x86/siemens/Kconfig b/drivers/platform/x86/siemens/Kconfig
new file mode 100644 (file)
index 0000000..618790f
--- /dev/null
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# Siemens X86 Platform Specific Drivers
+#
+
+config SIEMENS_SIMATIC_IPC
+       tristate "Siemens Simatic IPC Class driver"
+       help
+         This Simatic IPC class driver is the central of several drivers. It
+         is mainly used for system identification, after which drivers in other
+         classes will take care of driving specifics of those machines.
+         i.e. LEDs and watchdog.
+
+         To compile this driver as a module, choose M here: the module
+         will be called simatic-ipc.
+
+config SIEMENS_SIMATIC_IPC_BATT
+       tristate "CMOS battery driver for Siemens Simatic IPCs"
+       default SIEMENS_SIMATIC_IPC
+       depends on HWMON
+       depends on SIEMENS_SIMATIC_IPC
+       help
+         This option enables support for monitoring the voltage of the CMOS
+         batteries of several Industrial PCs from Siemens.
+
+         To compile this driver as a module, choose M here: the module
+         will be called simatic-ipc-batt.
+
+config SIEMENS_SIMATIC_IPC_BATT_APOLLOLAKE
+       tristate "CMOS Battery monitoring for Simatic IPCs based on Apollo Lake GPIO"
+       default SIEMENS_SIMATIC_IPC_BATT
+       depends on PINCTRL_BROXTON
+       depends on SIEMENS_SIMATIC_IPC_BATT
+       help
+         This option enables CMOS battery monitoring for Simatic Industrial PCs
+         from Siemens based on Apollo Lake GPIO.
+
+         To compile this driver as a module, choose M here: the module
+         will be called simatic-ipc-batt-apollolake.
+
+config SIEMENS_SIMATIC_IPC_BATT_ELKHARTLAKE
+       tristate "CMOS Battery monitoring for Simatic IPCs based on Elkhart Lake GPIO"
+       default SIEMENS_SIMATIC_IPC_BATT
+       depends on PINCTRL_ELKHARTLAKE
+       depends on SIEMENS_SIMATIC_IPC_BATT
+       help
+         This option enables CMOS battery monitoring for Simatic Industrial PCs
+         from Siemens based on Elkhart Lake GPIO.
+
+         To compile this driver as a module, choose M here: the module
+         will be called simatic-ipc-batt-elkhartlake.
+
+config SIEMENS_SIMATIC_IPC_BATT_F7188X
+       tristate "CMOS Battery monitoring for Simatic IPCs based on Nuvoton GPIO"
+       default SIEMENS_SIMATIC_IPC_BATT
+       depends on GPIO_F7188X
+       depends on SIEMENS_SIMATIC_IPC_BATT
+       help
+         This option enables CMOS battery monitoring for Simatic Industrial PCs
+         from Siemens based on Nuvoton GPIO.
+
+         To compile this driver as a module, choose M here: the module
+         will be called simatic-ipc-batt-elkhartlake.
diff --git a/drivers/platform/x86/siemens/Makefile b/drivers/platform/x86/siemens/Makefile
new file mode 100644 (file)
index 0000000..2b384b4
--- /dev/null
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for linux/drivers/platform/x86/siemens
+# Siemens x86 Platform-Specific Drivers
+#
+
+obj-$(CONFIG_SIEMENS_SIMATIC_IPC)                      += simatic-ipc.o
+obj-$(CONFIG_SIEMENS_SIMATIC_IPC_BATT)                 += simatic-ipc-batt.o
+obj-$(CONFIG_SIEMENS_SIMATIC_IPC_BATT_APOLLOLAKE)      += simatic-ipc-batt-apollolake.o
+obj-$(CONFIG_SIEMENS_SIMATIC_IPC_BATT_ELKHARTLAKE)     += simatic-ipc-batt-elkhartlake.o
+obj-$(CONFIG_SIEMENS_SIMATIC_IPC_BATT_F7188X)          += simatic-ipc-batt-f7188x.o
diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c b/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c
new file mode 100644 (file)
index 0000000..8a67979
--- /dev/null
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Siemens SIMATIC IPC driver for CMOS battery monitoring
+ *
+ * Copyright (c) Siemens AG, 2023
+ *
+ * Authors:
+ *  Henning Schild <henning.schild@siemens.com>
+ */
+
+#include <linux/gpio/machine.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "simatic-ipc-batt.h"
+
+static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_127e = {
+       .table = {
+               GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 55, NULL, 0, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 61, NULL, 1, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP_IDX("apollolake-pinctrl.1", 41, NULL, 2, GPIO_ACTIVE_HIGH),
+               {} /* Terminating entry */
+       },
+};
+
+static int simatic_ipc_batt_apollolake_remove(struct platform_device *pdev)
+{
+       return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_127e);
+}
+
+static int simatic_ipc_batt_apollolake_probe(struct platform_device *pdev)
+{
+       return simatic_ipc_batt_probe(pdev, &simatic_ipc_batt_gpio_table_127e);
+}
+
+static struct platform_driver simatic_ipc_batt_driver = {
+       .probe = simatic_ipc_batt_apollolake_probe,
+       .remove = simatic_ipc_batt_apollolake_remove,
+       .driver = {
+               .name = KBUILD_MODNAME,
+       },
+};
+
+module_platform_driver(simatic_ipc_batt_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" KBUILD_MODNAME);
+MODULE_SOFTDEP("pre: simatic-ipc-batt platform:apollolake-pinctrl");
+MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c b/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c
new file mode 100644 (file)
index 0000000..607d033
--- /dev/null
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Siemens SIMATIC IPC driver for CMOS battery monitoring
+ *
+ * Copyright (c) Siemens AG, 2023
+ *
+ * Authors:
+ *  Henning Schild <henning.schild@siemens.com>
+ */
+
+#include <linux/gpio/machine.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "simatic-ipc-batt.h"
+
+static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_bx_21a = {
+       .table = {
+               GPIO_LOOKUP_IDX("INTC1020:04", 18, NULL, 0, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP_IDX("INTC1020:04", 19, NULL, 1, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP_IDX("INTC1020:01", 66, NULL, 2, GPIO_ACTIVE_HIGH),
+               {} /* Terminating entry */
+       },
+};
+
+static int simatic_ipc_batt_elkhartlake_remove(struct platform_device *pdev)
+{
+       return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_bx_21a);
+}
+
+static int simatic_ipc_batt_elkhartlake_probe(struct platform_device *pdev)
+{
+       return simatic_ipc_batt_probe(pdev, &simatic_ipc_batt_gpio_table_bx_21a);
+}
+
+static struct platform_driver simatic_ipc_batt_driver = {
+       .probe = simatic_ipc_batt_elkhartlake_probe,
+       .remove = simatic_ipc_batt_elkhartlake_remove,
+       .driver = {
+               .name = KBUILD_MODNAME,
+       },
+};
+
+module_platform_driver(simatic_ipc_batt_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" KBUILD_MODNAME);
+MODULE_SOFTDEP("pre: simatic-ipc-batt platform:elkhartlake-pinctrl");
+MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c b/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c
new file mode 100644 (file)
index 0000000..ed330f6
--- /dev/null
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Siemens SIMATIC IPC driver for CMOS battery monitoring
+ *
+ * Copyright (c) Siemens AG, 2023
+ *
+ * Authors:
+ *  Henning Schild <henning.schild@siemens.com>
+ */
+
+#include <linux/gpio/machine.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/x86/simatic-ipc-base.h>
+
+#include "simatic-ipc-batt.h"
+
+static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_227g = {
+       .table = {
+               GPIO_LOOKUP_IDX("gpio-f7188x-7", 6, NULL, 0, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP_IDX("gpio-f7188x-7", 5, NULL, 1, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP_IDX("INTC1020:01",  66, NULL, 2, GPIO_ACTIVE_HIGH),
+               {} /* Terminating entry */
+       },
+};
+
+static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_bx_39a = {
+       .table = {
+               GPIO_LOOKUP_IDX("gpio-f7188x-6", 4, NULL, 0, GPIO_ACTIVE_HIGH),
+               GPIO_LOOKUP_IDX("gpio-f7188x-6", 3, NULL, 1, GPIO_ACTIVE_HIGH),
+               {} /* Terminating entry */
+       },
+};
+
+static int simatic_ipc_batt_f7188x_remove(struct platform_device *pdev)
+{
+       const struct simatic_ipc_platform *plat = pdev->dev.platform_data;
+
+       if (plat->devmode == SIMATIC_IPC_DEVICE_227G)
+               return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_227g);
+
+       return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_bx_39a);
+}
+
+static int simatic_ipc_batt_f7188x_probe(struct platform_device *pdev)
+{
+       const struct simatic_ipc_platform *plat = pdev->dev.platform_data;
+
+       if (plat->devmode == SIMATIC_IPC_DEVICE_227G)
+               return simatic_ipc_batt_probe(pdev, &simatic_ipc_batt_gpio_table_227g);
+
+       return simatic_ipc_batt_probe(pdev, &simatic_ipc_batt_gpio_table_bx_39a);
+}
+
+static struct platform_driver simatic_ipc_batt_driver = {
+       .probe = simatic_ipc_batt_f7188x_probe,
+       .remove = simatic_ipc_batt_f7188x_remove,
+       .driver = {
+               .name = KBUILD_MODNAME,
+       },
+};
+
+module_platform_driver(simatic_ipc_batt_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" KBUILD_MODNAME);
+MODULE_SOFTDEP("pre: simatic-ipc-batt gpio_f7188x platform:elkhartlake-pinctrl");
+MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt.c b/drivers/platform/x86/siemens/simatic-ipc-batt.c
new file mode 100644 (file)
index 0000000..d2791ff
--- /dev/null
@@ -0,0 +1,252 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Siemens SIMATIC IPC driver for CMOS battery monitoring
+ *
+ * Copyright (c) Siemens AG, 2023
+ *
+ * Authors:
+ *  Gerd Haeussler <gerd.haeussler.ext@siemens.com>
+ *  Henning Schild <henning.schild@siemens.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/gpio/machine.h>
+#include <linux/gpio/consumer.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/x86/simatic-ipc-base.h>
+#include <linux/sizes.h>
+
+#include "simatic-ipc-batt.h"
+
+#define BATT_DELAY_MS  (1000 * 60 * 60 * 24)   /* 24 h delay */
+
+#define SIMATIC_IPC_BATT_LEVEL_FULL    3000
+#define SIMATIC_IPC_BATT_LEVEL_CRIT    2750
+#define SIMATIC_IPC_BATT_LEVEL_EMPTY      0
+
+static struct simatic_ipc_batt {
+       u8 devmode;
+       long current_state;
+       struct gpio_desc *gpios[3];
+       unsigned long last_updated_jiffies;
+} priv;
+
+static long simatic_ipc_batt_read_gpio(void)
+{
+       long r = SIMATIC_IPC_BATT_LEVEL_FULL;
+
+       if (priv.gpios[2]) {
+               gpiod_set_value(priv.gpios[2], 1);
+               msleep(150);
+       }
+
+       if (gpiod_get_value_cansleep(priv.gpios[0]))
+               r = SIMATIC_IPC_BATT_LEVEL_EMPTY;
+       else if (gpiod_get_value_cansleep(priv.gpios[1]))
+               r = SIMATIC_IPC_BATT_LEVEL_CRIT;
+
+       if (priv.gpios[2])
+               gpiod_set_value(priv.gpios[2], 0);
+
+       return r;
+}
+
+#define SIMATIC_IPC_BATT_PORT_BASE     0x404D
+static struct resource simatic_ipc_batt_io_res =
+       DEFINE_RES_IO_NAMED(SIMATIC_IPC_BATT_PORT_BASE, SZ_1, KBUILD_MODNAME);
+
+static long simatic_ipc_batt_read_io(struct device *dev)
+{
+       long r = SIMATIC_IPC_BATT_LEVEL_FULL;
+       struct resource *res = &simatic_ipc_batt_io_res;
+       u8 val;
+
+       if (!request_muxed_region(res->start, resource_size(res), res->name)) {
+               dev_err(dev, "Unable to register IO resource at %pR\n", res);
+               return -EBUSY;
+       }
+
+       val = inb(SIMATIC_IPC_BATT_PORT_BASE);
+       release_region(simatic_ipc_batt_io_res.start, resource_size(&simatic_ipc_batt_io_res));
+
+       if (val & (1 << 7))
+               r = SIMATIC_IPC_BATT_LEVEL_EMPTY;
+       else if (val & (1 << 6))
+               r = SIMATIC_IPC_BATT_LEVEL_CRIT;
+
+       return r;
+}
+
+static long simatic_ipc_batt_read_value(struct device *dev)
+{
+       unsigned long next_update;
+
+       next_update = priv.last_updated_jiffies + msecs_to_jiffies(BATT_DELAY_MS);
+       if (time_after(jiffies, next_update) || !priv.last_updated_jiffies) {
+               switch (priv.devmode) {
+               case SIMATIC_IPC_DEVICE_127E:
+               case SIMATIC_IPC_DEVICE_227G:
+               case SIMATIC_IPC_DEVICE_BX_39A:
+                       priv.current_state = simatic_ipc_batt_read_gpio();
+                       break;
+               case SIMATIC_IPC_DEVICE_227E:
+                       priv.current_state = simatic_ipc_batt_read_io(dev);
+                       break;
+               }
+               priv.last_updated_jiffies = jiffies;
+               if (priv.current_state < SIMATIC_IPC_BATT_LEVEL_FULL)
+                       dev_warn(dev, "CMOS battery needs to be replaced.");
+       }
+
+       return priv.current_state;
+}
+
+static int simatic_ipc_batt_read(struct device *dev, enum hwmon_sensor_types type,
+                                u32 attr, int channel, long *val)
+{
+       switch (attr) {
+       case hwmon_in_input:
+               *val = simatic_ipc_batt_read_value(dev);
+               break;
+       case hwmon_in_lcrit:
+               *val = SIMATIC_IPC_BATT_LEVEL_CRIT;
+               break;
+       default:
+               return -EOPNOTSUPP;
+       }
+
+       return 0;
+}
+
+static umode_t simatic_ipc_batt_is_visible(const void *data, enum hwmon_sensor_types type,
+                                          u32 attr, int channel)
+{
+       if (attr == hwmon_in_input || attr == hwmon_in_lcrit)
+               return 0444;
+
+       return 0;
+}
+
+static const struct hwmon_ops simatic_ipc_batt_ops = {
+       .is_visible = simatic_ipc_batt_is_visible,
+       .read = simatic_ipc_batt_read,
+};
+
+static const struct hwmon_channel_info *simatic_ipc_batt_info[] = {
+       HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_LCRIT),
+       NULL
+};
+
+static const struct hwmon_chip_info simatic_ipc_batt_chip_info = {
+       .ops = &simatic_ipc_batt_ops,
+       .info = simatic_ipc_batt_info,
+};
+
+int simatic_ipc_batt_remove(struct platform_device *pdev, struct gpiod_lookup_table *table)
+{
+       gpiod_remove_lookup_table(table);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(simatic_ipc_batt_remove);
+
+int simatic_ipc_batt_probe(struct platform_device *pdev, struct gpiod_lookup_table *table)
+{
+       struct simatic_ipc_platform *plat;
+       struct device *dev = &pdev->dev;
+       struct device *hwmon_dev;
+       int err;
+
+       plat = pdev->dev.platform_data;
+       priv.devmode = plat->devmode;
+
+       switch (priv.devmode) {
+       case SIMATIC_IPC_DEVICE_127E:
+       case SIMATIC_IPC_DEVICE_227G:
+       case SIMATIC_IPC_DEVICE_BX_39A:
+       case SIMATIC_IPC_DEVICE_BX_21A:
+               table->dev_id = dev_name(dev);
+               gpiod_add_lookup_table(table);
+               break;
+       case SIMATIC_IPC_DEVICE_227E:
+               goto nogpio;
+       default:
+               return -ENODEV;
+       }
+
+       priv.gpios[0] = devm_gpiod_get_index(dev, "CMOSBattery empty", 0, GPIOD_IN);
+       if (IS_ERR(priv.gpios[0])) {
+               err = PTR_ERR(priv.gpios[0]);
+               priv.gpios[0] = NULL;
+               goto out;
+       }
+       priv.gpios[1] = devm_gpiod_get_index(dev, "CMOSBattery low", 1, GPIOD_IN);
+       if (IS_ERR(priv.gpios[1])) {
+               err = PTR_ERR(priv.gpios[1]);
+               priv.gpios[1] = NULL;
+               goto out;
+       }
+
+       if (table->table[2].key) {
+               priv.gpios[2] = devm_gpiod_get_index(dev, "CMOSBattery meter", 2, GPIOD_OUT_HIGH);
+               if (IS_ERR(priv.gpios[2])) {
+                       err = PTR_ERR(priv.gpios[1]);
+                       priv.gpios[2] = NULL;
+                       goto out;
+               }
+       } else {
+               priv.gpios[2] = NULL;
+       }
+
+nogpio:
+       hwmon_dev = devm_hwmon_device_register_with_info(dev, KBUILD_MODNAME,
+                                                        &priv,
+                                                        &simatic_ipc_batt_chip_info,
+                                                        NULL);
+       if (IS_ERR(hwmon_dev)) {
+               err = PTR_ERR(hwmon_dev);
+               goto out;
+       }
+
+       /* warn about aging battery even if userspace never reads hwmon */
+       simatic_ipc_batt_read_value(dev);
+
+       return 0;
+out:
+       simatic_ipc_batt_remove(pdev, table);
+
+       return err;
+}
+EXPORT_SYMBOL_GPL(simatic_ipc_batt_probe);
+
+static int simatic_ipc_batt_io_remove(struct platform_device *pdev)
+{
+       return simatic_ipc_batt_remove(pdev, NULL);
+}
+
+static int simatic_ipc_batt_io_probe(struct platform_device *pdev)
+{
+       return simatic_ipc_batt_probe(pdev, NULL);
+}
+
+static struct platform_driver simatic_ipc_batt_driver = {
+       .probe = simatic_ipc_batt_io_probe,
+       .remove = simatic_ipc_batt_io_remove,
+       .driver = {
+               .name = KBUILD_MODNAME,
+       },
+};
+
+module_platform_driver(simatic_ipc_batt_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" KBUILD_MODNAME);
+MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt.h b/drivers/platform/x86/siemens/simatic-ipc-batt.h
new file mode 100644 (file)
index 0000000..4545cd3
--- /dev/null
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Siemens SIMATIC IPC driver for CMOS battery monitoring
+ *
+ * Copyright (c) Siemens AG, 2023
+ *
+ * Author:
+ *  Henning Schild <henning.schild@siemens.com>
+ */
+
+#ifndef _SIMATIC_IPC_BATT_H
+#define _SIMATIC_IPC_BATT_H
+
+int simatic_ipc_batt_probe(struct platform_device *pdev,
+                          struct gpiod_lookup_table *table);
+
+int simatic_ipc_batt_remove(struct platform_device *pdev,
+                           struct gpiod_lookup_table *table);
+
+#endif /* _SIMATIC_IPC_BATT_H */
diff --git a/drivers/platform/x86/siemens/simatic-ipc.c b/drivers/platform/x86/siemens/simatic-ipc.c
new file mode 100644 (file)
index 0000000..13c8573
--- /dev/null
@@ -0,0 +1,228 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Siemens SIMATIC IPC platform driver
+ *
+ * Copyright (c) Siemens AG, 2018-2023
+ *
+ * Authors:
+ *  Henning Schild <henning.schild@siemens.com>
+ *  Jan Kiszka <jan.kiszka@siemens.com>
+ *  Gerd Haeussler <gerd.haeussler.ext@siemens.com>
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/dmi.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_data/x86/simatic-ipc.h>
+#include <linux/platform_device.h>
+
+static struct platform_device *ipc_led_platform_device;
+static struct platform_device *ipc_wdt_platform_device;
+static struct platform_device *ipc_batt_platform_device;
+
+static const struct dmi_system_id simatic_ipc_whitelist[] = {
+       {
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"),
+               },
+       },
+       {}
+};
+
+static struct simatic_ipc_platform platform_data;
+
+#define SIMATIC_IPC_MAX_EXTRA_MODULES 2
+
+static struct {
+       u32 station_id;
+       u8 led_mode;
+       u8 wdt_mode;
+       u8 batt_mode;
+       char *extra_modules[SIMATIC_IPC_MAX_EXTRA_MODULES];
+} device_modes[] = {
+       {SIMATIC_IPC_IPC127E,
+               SIMATIC_IPC_DEVICE_127E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_127E,
+               { "emc1403", NULL }},
+       {SIMATIC_IPC_IPC227D,
+               SIMATIC_IPC_DEVICE_227D, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_NONE,
+               { "emc1403", NULL }},
+       {SIMATIC_IPC_IPC227E,
+               SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_227E, SIMATIC_IPC_DEVICE_227E,
+               { "emc1403", NULL }},
+       {SIMATIC_IPC_IPC227G,
+               SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227G,
+               { "nct6775", "w83627hf_wdt" }},
+       {SIMATIC_IPC_IPC277G,
+               SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227G,
+               { "nct6775", "w83627hf_wdt" }},
+       {SIMATIC_IPC_IPC277E,
+               SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227E, SIMATIC_IPC_DEVICE_227E,
+               { "emc1403", NULL }},
+       {SIMATIC_IPC_IPC427D,
+               SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_NONE,
+               { "emc1403", NULL }},
+       {SIMATIC_IPC_IPC427E,
+               SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE,
+               { "emc1403", NULL }},
+       {SIMATIC_IPC_IPC477E,
+               SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE,
+               { "emc1403", NULL }},
+       {SIMATIC_IPC_IPCBX_39A,
+               SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_BX_39A,
+               { "nct6775", "w83627hf_wdt" }},
+       {SIMATIC_IPC_IPCPX_39A,
+               SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_BX_39A,
+               { "nct6775", "w83627hf_wdt" }},
+       {SIMATIC_IPC_IPCBX_21A,
+               SIMATIC_IPC_DEVICE_BX_21A, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_BX_21A,
+               { "emc1403", NULL }},
+};
+
+static int register_platform_devices(u32 station_id)
+{
+       u8 ledmode = SIMATIC_IPC_DEVICE_NONE;
+       u8 wdtmode = SIMATIC_IPC_DEVICE_NONE;
+       u8 battmode = SIMATIC_IPC_DEVICE_NONE;
+       char *pdevname;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(device_modes); i++) {
+               if (device_modes[i].station_id == station_id) {
+                       ledmode = device_modes[i].led_mode;
+                       wdtmode = device_modes[i].wdt_mode;
+                       battmode = device_modes[i].batt_mode;
+                       break;
+               }
+       }
+
+       if (battmode != SIMATIC_IPC_DEVICE_NONE) {
+               pdevname = KBUILD_MODNAME "_batt";
+               if (battmode == SIMATIC_IPC_DEVICE_127E)
+                       pdevname = KBUILD_MODNAME "_batt_apollolake";
+               if (battmode == SIMATIC_IPC_DEVICE_BX_21A)
+                       pdevname = KBUILD_MODNAME "_batt_elkhartlake";
+               if (battmode == SIMATIC_IPC_DEVICE_227G || battmode == SIMATIC_IPC_DEVICE_BX_39A)
+                       pdevname = KBUILD_MODNAME "_batt_f7188x";
+               platform_data.devmode = battmode;
+               ipc_batt_platform_device =
+                       platform_device_register_data(NULL, pdevname,
+                               PLATFORM_DEVID_NONE, &platform_data,
+                               sizeof(struct simatic_ipc_platform));
+               if (IS_ERR(ipc_batt_platform_device))
+                       return PTR_ERR(ipc_batt_platform_device);
+
+               pr_debug("device=%s created\n",
+                        ipc_batt_platform_device->name);
+       }
+
+       if (ledmode != SIMATIC_IPC_DEVICE_NONE) {
+               pdevname = KBUILD_MODNAME "_leds";
+               if (ledmode == SIMATIC_IPC_DEVICE_127E)
+                       pdevname = KBUILD_MODNAME "_leds_gpio_apollolake";
+               if (ledmode == SIMATIC_IPC_DEVICE_227G)
+                       pdevname = KBUILD_MODNAME "_leds_gpio_f7188x";
+               if (ledmode == SIMATIC_IPC_DEVICE_BX_21A)
+                       pdevname = KBUILD_MODNAME "_leds_gpio_elkhartlake";
+               platform_data.devmode = ledmode;
+               ipc_led_platform_device =
+                       platform_device_register_data(NULL,
+                               pdevname, PLATFORM_DEVID_NONE,
+                               &platform_data,
+                               sizeof(struct simatic_ipc_platform));
+               if (IS_ERR(ipc_led_platform_device))
+                       return PTR_ERR(ipc_led_platform_device);
+
+               pr_debug("device=%s created\n",
+                        ipc_led_platform_device->name);
+       }
+
+       if (wdtmode != SIMATIC_IPC_DEVICE_NONE) {
+               platform_data.devmode = wdtmode;
+               ipc_wdt_platform_device =
+                       platform_device_register_data(NULL,
+                               KBUILD_MODNAME "_wdt", PLATFORM_DEVID_NONE,
+                               &platform_data,
+                               sizeof(struct simatic_ipc_platform));
+               if (IS_ERR(ipc_wdt_platform_device))
+                       return PTR_ERR(ipc_wdt_platform_device);
+
+               pr_debug("device=%s created\n",
+                        ipc_wdt_platform_device->name);
+       }
+
+       if (ledmode == SIMATIC_IPC_DEVICE_NONE &&
+           wdtmode == SIMATIC_IPC_DEVICE_NONE &&
+           battmode == SIMATIC_IPC_DEVICE_NONE) {
+               pr_warn("unsupported IPC detected, station id=%08x\n",
+                       station_id);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static void request_additional_modules(u32 station_id)
+{
+       char **extra_modules = NULL;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(device_modes); i++) {
+               if (device_modes[i].station_id == station_id) {
+                       extra_modules = device_modes[i].extra_modules;
+                       break;
+               }
+       }
+
+       if (!extra_modules)
+               return;
+
+       for (i = 0; i < SIMATIC_IPC_MAX_EXTRA_MODULES; i++) {
+               if (extra_modules[i])
+                       request_module(extra_modules[i]);
+               else
+                       break;
+       }
+}
+
+static int __init simatic_ipc_init_module(void)
+{
+       const struct dmi_system_id *match;
+       u32 station_id;
+       int err;
+
+       match = dmi_first_match(simatic_ipc_whitelist);
+       if (!match)
+               return 0;
+
+       err = dmi_walk(simatic_ipc_find_dmi_entry_helper, &station_id);
+
+       if (err || station_id == SIMATIC_IPC_INVALID_STATION_ID) {
+               pr_warn("DMI entry %d not found\n", SIMATIC_IPC_DMI_ENTRY_OEM);
+               return 0;
+       }
+
+       request_additional_modules(station_id);
+
+       return register_platform_devices(station_id);
+}
+
+static void __exit simatic_ipc_exit_module(void)
+{
+       platform_device_unregister(ipc_led_platform_device);
+       ipc_led_platform_device = NULL;
+
+       platform_device_unregister(ipc_wdt_platform_device);
+       ipc_wdt_platform_device = NULL;
+
+       platform_device_unregister(ipc_batt_platform_device);
+       ipc_batt_platform_device = NULL;
+}
+
+module_init(simatic_ipc_init_module);
+module_exit(simatic_ipc_exit_module);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Gerd Haeussler <gerd.haeussler.ext@siemens.com>");
+MODULE_ALIAS("dmi:*:svnSIEMENSAG:*");
diff --git a/drivers/platform/x86/simatic-ipc-batt-apollolake.c b/drivers/platform/x86/simatic-ipc-batt-apollolake.c
deleted file mode 100644 (file)
index 8a67979..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Siemens SIMATIC IPC driver for CMOS battery monitoring
- *
- * Copyright (c) Siemens AG, 2023
- *
- * Authors:
- *  Henning Schild <henning.schild@siemens.com>
- */
-
-#include <linux/gpio/machine.h>
-#include <linux/gpio/consumer.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include "simatic-ipc-batt.h"
-
-static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_127e = {
-       .table = {
-               GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 55, NULL, 0, GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 61, NULL, 1, GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP_IDX("apollolake-pinctrl.1", 41, NULL, 2, GPIO_ACTIVE_HIGH),
-               {} /* Terminating entry */
-       },
-};
-
-static int simatic_ipc_batt_apollolake_remove(struct platform_device *pdev)
-{
-       return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_127e);
-}
-
-static int simatic_ipc_batt_apollolake_probe(struct platform_device *pdev)
-{
-       return simatic_ipc_batt_probe(pdev, &simatic_ipc_batt_gpio_table_127e);
-}
-
-static struct platform_driver simatic_ipc_batt_driver = {
-       .probe = simatic_ipc_batt_apollolake_probe,
-       .remove = simatic_ipc_batt_apollolake_remove,
-       .driver = {
-               .name = KBUILD_MODNAME,
-       },
-};
-
-module_platform_driver(simatic_ipc_batt_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" KBUILD_MODNAME);
-MODULE_SOFTDEP("pre: simatic-ipc-batt platform:apollolake-pinctrl");
-MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
diff --git a/drivers/platform/x86/simatic-ipc-batt-elkhartlake.c b/drivers/platform/x86/simatic-ipc-batt-elkhartlake.c
deleted file mode 100644 (file)
index 607d033..0000000
+++ /dev/null
@@ -1,51 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Siemens SIMATIC IPC driver for CMOS battery monitoring
- *
- * Copyright (c) Siemens AG, 2023
- *
- * Authors:
- *  Henning Schild <henning.schild@siemens.com>
- */
-
-#include <linux/gpio/machine.h>
-#include <linux/gpio/consumer.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include "simatic-ipc-batt.h"
-
-static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_bx_21a = {
-       .table = {
-               GPIO_LOOKUP_IDX("INTC1020:04", 18, NULL, 0, GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP_IDX("INTC1020:04", 19, NULL, 1, GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP_IDX("INTC1020:01", 66, NULL, 2, GPIO_ACTIVE_HIGH),
-               {} /* Terminating entry */
-       },
-};
-
-static int simatic_ipc_batt_elkhartlake_remove(struct platform_device *pdev)
-{
-       return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_bx_21a);
-}
-
-static int simatic_ipc_batt_elkhartlake_probe(struct platform_device *pdev)
-{
-       return simatic_ipc_batt_probe(pdev, &simatic_ipc_batt_gpio_table_bx_21a);
-}
-
-static struct platform_driver simatic_ipc_batt_driver = {
-       .probe = simatic_ipc_batt_elkhartlake_probe,
-       .remove = simatic_ipc_batt_elkhartlake_remove,
-       .driver = {
-               .name = KBUILD_MODNAME,
-       },
-};
-
-module_platform_driver(simatic_ipc_batt_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" KBUILD_MODNAME);
-MODULE_SOFTDEP("pre: simatic-ipc-batt platform:elkhartlake-pinctrl");
-MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
diff --git a/drivers/platform/x86/simatic-ipc-batt-f7188x.c b/drivers/platform/x86/simatic-ipc-batt-f7188x.c
deleted file mode 100644 (file)
index ed330f6..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Siemens SIMATIC IPC driver for CMOS battery monitoring
- *
- * Copyright (c) Siemens AG, 2023
- *
- * Authors:
- *  Henning Schild <henning.schild@siemens.com>
- */
-
-#include <linux/gpio/machine.h>
-#include <linux/gpio/consumer.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/platform_data/x86/simatic-ipc-base.h>
-
-#include "simatic-ipc-batt.h"
-
-static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_227g = {
-       .table = {
-               GPIO_LOOKUP_IDX("gpio-f7188x-7", 6, NULL, 0, GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP_IDX("gpio-f7188x-7", 5, NULL, 1, GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP_IDX("INTC1020:01",  66, NULL, 2, GPIO_ACTIVE_HIGH),
-               {} /* Terminating entry */
-       },
-};
-
-static struct gpiod_lookup_table simatic_ipc_batt_gpio_table_bx_39a = {
-       .table = {
-               GPIO_LOOKUP_IDX("gpio-f7188x-6", 4, NULL, 0, GPIO_ACTIVE_HIGH),
-               GPIO_LOOKUP_IDX("gpio-f7188x-6", 3, NULL, 1, GPIO_ACTIVE_HIGH),
-               {} /* Terminating entry */
-       },
-};
-
-static int simatic_ipc_batt_f7188x_remove(struct platform_device *pdev)
-{
-       const struct simatic_ipc_platform *plat = pdev->dev.platform_data;
-
-       if (plat->devmode == SIMATIC_IPC_DEVICE_227G)
-               return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_227g);
-
-       return simatic_ipc_batt_remove(pdev, &simatic_ipc_batt_gpio_table_bx_39a);
-}
-
-static int simatic_ipc_batt_f7188x_probe(struct platform_device *pdev)
-{
-       const struct simatic_ipc_platform *plat = pdev->dev.platform_data;
-
-       if (plat->devmode == SIMATIC_IPC_DEVICE_227G)
-               return simatic_ipc_batt_probe(pdev, &simatic_ipc_batt_gpio_table_227g);
-
-       return simatic_ipc_batt_probe(pdev, &simatic_ipc_batt_gpio_table_bx_39a);
-}
-
-static struct platform_driver simatic_ipc_batt_driver = {
-       .probe = simatic_ipc_batt_f7188x_probe,
-       .remove = simatic_ipc_batt_f7188x_remove,
-       .driver = {
-               .name = KBUILD_MODNAME,
-       },
-};
-
-module_platform_driver(simatic_ipc_batt_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" KBUILD_MODNAME);
-MODULE_SOFTDEP("pre: simatic-ipc-batt gpio_f7188x platform:elkhartlake-pinctrl");
-MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
diff --git a/drivers/platform/x86/simatic-ipc-batt.c b/drivers/platform/x86/simatic-ipc-batt.c
deleted file mode 100644 (file)
index d2791ff..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Siemens SIMATIC IPC driver for CMOS battery monitoring
- *
- * Copyright (c) Siemens AG, 2023
- *
- * Authors:
- *  Gerd Haeussler <gerd.haeussler.ext@siemens.com>
- *  Henning Schild <henning.schild@siemens.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/delay.h>
-#include <linux/io.h>
-#include <linux/ioport.h>
-#include <linux/gpio/machine.h>
-#include <linux/gpio/consumer.h>
-#include <linux/hwmon.h>
-#include <linux/hwmon-sysfs.h>
-#include <linux/jiffies.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/platform_data/x86/simatic-ipc-base.h>
-#include <linux/sizes.h>
-
-#include "simatic-ipc-batt.h"
-
-#define BATT_DELAY_MS  (1000 * 60 * 60 * 24)   /* 24 h delay */
-
-#define SIMATIC_IPC_BATT_LEVEL_FULL    3000
-#define SIMATIC_IPC_BATT_LEVEL_CRIT    2750
-#define SIMATIC_IPC_BATT_LEVEL_EMPTY      0
-
-static struct simatic_ipc_batt {
-       u8 devmode;
-       long current_state;
-       struct gpio_desc *gpios[3];
-       unsigned long last_updated_jiffies;
-} priv;
-
-static long simatic_ipc_batt_read_gpio(void)
-{
-       long r = SIMATIC_IPC_BATT_LEVEL_FULL;
-
-       if (priv.gpios[2]) {
-               gpiod_set_value(priv.gpios[2], 1);
-               msleep(150);
-       }
-
-       if (gpiod_get_value_cansleep(priv.gpios[0]))
-               r = SIMATIC_IPC_BATT_LEVEL_EMPTY;
-       else if (gpiod_get_value_cansleep(priv.gpios[1]))
-               r = SIMATIC_IPC_BATT_LEVEL_CRIT;
-
-       if (priv.gpios[2])
-               gpiod_set_value(priv.gpios[2], 0);
-
-       return r;
-}
-
-#define SIMATIC_IPC_BATT_PORT_BASE     0x404D
-static struct resource simatic_ipc_batt_io_res =
-       DEFINE_RES_IO_NAMED(SIMATIC_IPC_BATT_PORT_BASE, SZ_1, KBUILD_MODNAME);
-
-static long simatic_ipc_batt_read_io(struct device *dev)
-{
-       long r = SIMATIC_IPC_BATT_LEVEL_FULL;
-       struct resource *res = &simatic_ipc_batt_io_res;
-       u8 val;
-
-       if (!request_muxed_region(res->start, resource_size(res), res->name)) {
-               dev_err(dev, "Unable to register IO resource at %pR\n", res);
-               return -EBUSY;
-       }
-
-       val = inb(SIMATIC_IPC_BATT_PORT_BASE);
-       release_region(simatic_ipc_batt_io_res.start, resource_size(&simatic_ipc_batt_io_res));
-
-       if (val & (1 << 7))
-               r = SIMATIC_IPC_BATT_LEVEL_EMPTY;
-       else if (val & (1 << 6))
-               r = SIMATIC_IPC_BATT_LEVEL_CRIT;
-
-       return r;
-}
-
-static long simatic_ipc_batt_read_value(struct device *dev)
-{
-       unsigned long next_update;
-
-       next_update = priv.last_updated_jiffies + msecs_to_jiffies(BATT_DELAY_MS);
-       if (time_after(jiffies, next_update) || !priv.last_updated_jiffies) {
-               switch (priv.devmode) {
-               case SIMATIC_IPC_DEVICE_127E:
-               case SIMATIC_IPC_DEVICE_227G:
-               case SIMATIC_IPC_DEVICE_BX_39A:
-                       priv.current_state = simatic_ipc_batt_read_gpio();
-                       break;
-               case SIMATIC_IPC_DEVICE_227E:
-                       priv.current_state = simatic_ipc_batt_read_io(dev);
-                       break;
-               }
-               priv.last_updated_jiffies = jiffies;
-               if (priv.current_state < SIMATIC_IPC_BATT_LEVEL_FULL)
-                       dev_warn(dev, "CMOS battery needs to be replaced.");
-       }
-
-       return priv.current_state;
-}
-
-static int simatic_ipc_batt_read(struct device *dev, enum hwmon_sensor_types type,
-                                u32 attr, int channel, long *val)
-{
-       switch (attr) {
-       case hwmon_in_input:
-               *val = simatic_ipc_batt_read_value(dev);
-               break;
-       case hwmon_in_lcrit:
-               *val = SIMATIC_IPC_BATT_LEVEL_CRIT;
-               break;
-       default:
-               return -EOPNOTSUPP;
-       }
-
-       return 0;
-}
-
-static umode_t simatic_ipc_batt_is_visible(const void *data, enum hwmon_sensor_types type,
-                                          u32 attr, int channel)
-{
-       if (attr == hwmon_in_input || attr == hwmon_in_lcrit)
-               return 0444;
-
-       return 0;
-}
-
-static const struct hwmon_ops simatic_ipc_batt_ops = {
-       .is_visible = simatic_ipc_batt_is_visible,
-       .read = simatic_ipc_batt_read,
-};
-
-static const struct hwmon_channel_info *simatic_ipc_batt_info[] = {
-       HWMON_CHANNEL_INFO(in, HWMON_I_INPUT | HWMON_I_LCRIT),
-       NULL
-};
-
-static const struct hwmon_chip_info simatic_ipc_batt_chip_info = {
-       .ops = &simatic_ipc_batt_ops,
-       .info = simatic_ipc_batt_info,
-};
-
-int simatic_ipc_batt_remove(struct platform_device *pdev, struct gpiod_lookup_table *table)
-{
-       gpiod_remove_lookup_table(table);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(simatic_ipc_batt_remove);
-
-int simatic_ipc_batt_probe(struct platform_device *pdev, struct gpiod_lookup_table *table)
-{
-       struct simatic_ipc_platform *plat;
-       struct device *dev = &pdev->dev;
-       struct device *hwmon_dev;
-       int err;
-
-       plat = pdev->dev.platform_data;
-       priv.devmode = plat->devmode;
-
-       switch (priv.devmode) {
-       case SIMATIC_IPC_DEVICE_127E:
-       case SIMATIC_IPC_DEVICE_227G:
-       case SIMATIC_IPC_DEVICE_BX_39A:
-       case SIMATIC_IPC_DEVICE_BX_21A:
-               table->dev_id = dev_name(dev);
-               gpiod_add_lookup_table(table);
-               break;
-       case SIMATIC_IPC_DEVICE_227E:
-               goto nogpio;
-       default:
-               return -ENODEV;
-       }
-
-       priv.gpios[0] = devm_gpiod_get_index(dev, "CMOSBattery empty", 0, GPIOD_IN);
-       if (IS_ERR(priv.gpios[0])) {
-               err = PTR_ERR(priv.gpios[0]);
-               priv.gpios[0] = NULL;
-               goto out;
-       }
-       priv.gpios[1] = devm_gpiod_get_index(dev, "CMOSBattery low", 1, GPIOD_IN);
-       if (IS_ERR(priv.gpios[1])) {
-               err = PTR_ERR(priv.gpios[1]);
-               priv.gpios[1] = NULL;
-               goto out;
-       }
-
-       if (table->table[2].key) {
-               priv.gpios[2] = devm_gpiod_get_index(dev, "CMOSBattery meter", 2, GPIOD_OUT_HIGH);
-               if (IS_ERR(priv.gpios[2])) {
-                       err = PTR_ERR(priv.gpios[1]);
-                       priv.gpios[2] = NULL;
-                       goto out;
-               }
-       } else {
-               priv.gpios[2] = NULL;
-       }
-
-nogpio:
-       hwmon_dev = devm_hwmon_device_register_with_info(dev, KBUILD_MODNAME,
-                                                        &priv,
-                                                        &simatic_ipc_batt_chip_info,
-                                                        NULL);
-       if (IS_ERR(hwmon_dev)) {
-               err = PTR_ERR(hwmon_dev);
-               goto out;
-       }
-
-       /* warn about aging battery even if userspace never reads hwmon */
-       simatic_ipc_batt_read_value(dev);
-
-       return 0;
-out:
-       simatic_ipc_batt_remove(pdev, table);
-
-       return err;
-}
-EXPORT_SYMBOL_GPL(simatic_ipc_batt_probe);
-
-static int simatic_ipc_batt_io_remove(struct platform_device *pdev)
-{
-       return simatic_ipc_batt_remove(pdev, NULL);
-}
-
-static int simatic_ipc_batt_io_probe(struct platform_device *pdev)
-{
-       return simatic_ipc_batt_probe(pdev, NULL);
-}
-
-static struct platform_driver simatic_ipc_batt_driver = {
-       .probe = simatic_ipc_batt_io_probe,
-       .remove = simatic_ipc_batt_io_remove,
-       .driver = {
-               .name = KBUILD_MODNAME,
-       },
-};
-
-module_platform_driver(simatic_ipc_batt_driver);
-
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" KBUILD_MODNAME);
-MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
diff --git a/drivers/platform/x86/simatic-ipc-batt.h b/drivers/platform/x86/simatic-ipc-batt.h
deleted file mode 100644 (file)
index 4545cd3..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Siemens SIMATIC IPC driver for CMOS battery monitoring
- *
- * Copyright (c) Siemens AG, 2023
- *
- * Author:
- *  Henning Schild <henning.schild@siemens.com>
- */
-
-#ifndef _SIMATIC_IPC_BATT_H
-#define _SIMATIC_IPC_BATT_H
-
-int simatic_ipc_batt_probe(struct platform_device *pdev,
-                          struct gpiod_lookup_table *table);
-
-int simatic_ipc_batt_remove(struct platform_device *pdev,
-                           struct gpiod_lookup_table *table);
-
-#endif /* _SIMATIC_IPC_BATT_H */
diff --git a/drivers/platform/x86/simatic-ipc.c b/drivers/platform/x86/simatic-ipc.c
deleted file mode 100644 (file)
index 13c8573..0000000
+++ /dev/null
@@ -1,228 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Siemens SIMATIC IPC platform driver
- *
- * Copyright (c) Siemens AG, 2018-2023
- *
- * Authors:
- *  Henning Schild <henning.schild@siemens.com>
- *  Jan Kiszka <jan.kiszka@siemens.com>
- *  Gerd Haeussler <gerd.haeussler.ext@siemens.com>
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/dmi.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_data/x86/simatic-ipc.h>
-#include <linux/platform_device.h>
-
-static struct platform_device *ipc_led_platform_device;
-static struct platform_device *ipc_wdt_platform_device;
-static struct platform_device *ipc_batt_platform_device;
-
-static const struct dmi_system_id simatic_ipc_whitelist[] = {
-       {
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"),
-               },
-       },
-       {}
-};
-
-static struct simatic_ipc_platform platform_data;
-
-#define SIMATIC_IPC_MAX_EXTRA_MODULES 2
-
-static struct {
-       u32 station_id;
-       u8 led_mode;
-       u8 wdt_mode;
-       u8 batt_mode;
-       char *extra_modules[SIMATIC_IPC_MAX_EXTRA_MODULES];
-} device_modes[] = {
-       {SIMATIC_IPC_IPC127E,
-               SIMATIC_IPC_DEVICE_127E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_127E,
-               { "emc1403", NULL }},
-       {SIMATIC_IPC_IPC227D,
-               SIMATIC_IPC_DEVICE_227D, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_NONE,
-               { "emc1403", NULL }},
-       {SIMATIC_IPC_IPC227E,
-               SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_227E, SIMATIC_IPC_DEVICE_227E,
-               { "emc1403", NULL }},
-       {SIMATIC_IPC_IPC227G,
-               SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227G,
-               { "nct6775", "w83627hf_wdt" }},
-       {SIMATIC_IPC_IPC277G,
-               SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227G,
-               { "nct6775", "w83627hf_wdt" }},
-       {SIMATIC_IPC_IPC277E,
-               SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227E, SIMATIC_IPC_DEVICE_227E,
-               { "emc1403", NULL }},
-       {SIMATIC_IPC_IPC427D,
-               SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_NONE,
-               { "emc1403", NULL }},
-       {SIMATIC_IPC_IPC427E,
-               SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE,
-               { "emc1403", NULL }},
-       {SIMATIC_IPC_IPC477E,
-               SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE,
-               { "emc1403", NULL }},
-       {SIMATIC_IPC_IPCBX_39A,
-               SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_BX_39A,
-               { "nct6775", "w83627hf_wdt" }},
-       {SIMATIC_IPC_IPCPX_39A,
-               SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_BX_39A,
-               { "nct6775", "w83627hf_wdt" }},
-       {SIMATIC_IPC_IPCBX_21A,
-               SIMATIC_IPC_DEVICE_BX_21A, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_BX_21A,
-               { "emc1403", NULL }},
-};
-
-static int register_platform_devices(u32 station_id)
-{
-       u8 ledmode = SIMATIC_IPC_DEVICE_NONE;
-       u8 wdtmode = SIMATIC_IPC_DEVICE_NONE;
-       u8 battmode = SIMATIC_IPC_DEVICE_NONE;
-       char *pdevname;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(device_modes); i++) {
-               if (device_modes[i].station_id == station_id) {
-                       ledmode = device_modes[i].led_mode;
-                       wdtmode = device_modes[i].wdt_mode;
-                       battmode = device_modes[i].batt_mode;
-                       break;
-               }
-       }
-
-       if (battmode != SIMATIC_IPC_DEVICE_NONE) {
-               pdevname = KBUILD_MODNAME "_batt";
-               if (battmode == SIMATIC_IPC_DEVICE_127E)
-                       pdevname = KBUILD_MODNAME "_batt_apollolake";
-               if (battmode == SIMATIC_IPC_DEVICE_BX_21A)
-                       pdevname = KBUILD_MODNAME "_batt_elkhartlake";
-               if (battmode == SIMATIC_IPC_DEVICE_227G || battmode == SIMATIC_IPC_DEVICE_BX_39A)
-                       pdevname = KBUILD_MODNAME "_batt_f7188x";
-               platform_data.devmode = battmode;
-               ipc_batt_platform_device =
-                       platform_device_register_data(NULL, pdevname,
-                               PLATFORM_DEVID_NONE, &platform_data,
-                               sizeof(struct simatic_ipc_platform));
-               if (IS_ERR(ipc_batt_platform_device))
-                       return PTR_ERR(ipc_batt_platform_device);
-
-               pr_debug("device=%s created\n",
-                        ipc_batt_platform_device->name);
-       }
-
-       if (ledmode != SIMATIC_IPC_DEVICE_NONE) {
-               pdevname = KBUILD_MODNAME "_leds";
-               if (ledmode == SIMATIC_IPC_DEVICE_127E)
-                       pdevname = KBUILD_MODNAME "_leds_gpio_apollolake";
-               if (ledmode == SIMATIC_IPC_DEVICE_227G)
-                       pdevname = KBUILD_MODNAME "_leds_gpio_f7188x";
-               if (ledmode == SIMATIC_IPC_DEVICE_BX_21A)
-                       pdevname = KBUILD_MODNAME "_leds_gpio_elkhartlake";
-               platform_data.devmode = ledmode;
-               ipc_led_platform_device =
-                       platform_device_register_data(NULL,
-                               pdevname, PLATFORM_DEVID_NONE,
-                               &platform_data,
-                               sizeof(struct simatic_ipc_platform));
-               if (IS_ERR(ipc_led_platform_device))
-                       return PTR_ERR(ipc_led_platform_device);
-
-               pr_debug("device=%s created\n",
-                        ipc_led_platform_device->name);
-       }
-
-       if (wdtmode != SIMATIC_IPC_DEVICE_NONE) {
-               platform_data.devmode = wdtmode;
-               ipc_wdt_platform_device =
-                       platform_device_register_data(NULL,
-                               KBUILD_MODNAME "_wdt", PLATFORM_DEVID_NONE,
-                               &platform_data,
-                               sizeof(struct simatic_ipc_platform));
-               if (IS_ERR(ipc_wdt_platform_device))
-                       return PTR_ERR(ipc_wdt_platform_device);
-
-               pr_debug("device=%s created\n",
-                        ipc_wdt_platform_device->name);
-       }
-
-       if (ledmode == SIMATIC_IPC_DEVICE_NONE &&
-           wdtmode == SIMATIC_IPC_DEVICE_NONE &&
-           battmode == SIMATIC_IPC_DEVICE_NONE) {
-               pr_warn("unsupported IPC detected, station id=%08x\n",
-                       station_id);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static void request_additional_modules(u32 station_id)
-{
-       char **extra_modules = NULL;
-       int i;
-
-       for (i = 0; i < ARRAY_SIZE(device_modes); i++) {
-               if (device_modes[i].station_id == station_id) {
-                       extra_modules = device_modes[i].extra_modules;
-                       break;
-               }
-       }
-
-       if (!extra_modules)
-               return;
-
-       for (i = 0; i < SIMATIC_IPC_MAX_EXTRA_MODULES; i++) {
-               if (extra_modules[i])
-                       request_module(extra_modules[i]);
-               else
-                       break;
-       }
-}
-
-static int __init simatic_ipc_init_module(void)
-{
-       const struct dmi_system_id *match;
-       u32 station_id;
-       int err;
-
-       match = dmi_first_match(simatic_ipc_whitelist);
-       if (!match)
-               return 0;
-
-       err = dmi_walk(simatic_ipc_find_dmi_entry_helper, &station_id);
-
-       if (err || station_id == SIMATIC_IPC_INVALID_STATION_ID) {
-               pr_warn("DMI entry %d not found\n", SIMATIC_IPC_DMI_ENTRY_OEM);
-               return 0;
-       }
-
-       request_additional_modules(station_id);
-
-       return register_platform_devices(station_id);
-}
-
-static void __exit simatic_ipc_exit_module(void)
-{
-       platform_device_unregister(ipc_led_platform_device);
-       ipc_led_platform_device = NULL;
-
-       platform_device_unregister(ipc_wdt_platform_device);
-       ipc_wdt_platform_device = NULL;
-
-       platform_device_unregister(ipc_batt_platform_device);
-       ipc_batt_platform_device = NULL;
-}
-
-module_init(simatic_ipc_init_module);
-module_exit(simatic_ipc_exit_module);
-
-MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Gerd Haeussler <gerd.haeussler.ext@siemens.com>");
-MODULE_ALIAS("dmi:*:svnSIEMENSAG:*");