From 9bc289b8123ce149bc4088dbe74300057fa244c3 Mon Sep 17 00:00:00 2001 From: Henning Schild Date: Wed, 19 Jul 2023 17:35:18 +0200 Subject: platform/x86: Move all simatic ipc drivers to the subdirectory siemens 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 Signed-off-by: Henning Schild Reviewed-by: Andy Shevchenko Link: https://lore.kernel.org/r/20230719153518.13073-4-henning.schild@siemens.com Reviewed-by: Hans de Goede Signed-off-by: Hans de Goede --- drivers/platform/x86/Kconfig | 59 +---- drivers/platform/x86/Makefile | 6 +- drivers/platform/x86/siemens/Kconfig | 63 ++++++ drivers/platform/x86/siemens/Makefile | 11 + .../x86/siemens/simatic-ipc-batt-apollolake.c | 51 +++++ .../x86/siemens/simatic-ipc-batt-elkhartlake.c | 51 +++++ .../platform/x86/siemens/simatic-ipc-batt-f7188x.c | 70 ++++++ drivers/platform/x86/siemens/simatic-ipc-batt.c | 252 +++++++++++++++++++++ drivers/platform/x86/siemens/simatic-ipc-batt.h | 20 ++ drivers/platform/x86/siemens/simatic-ipc.c | 228 +++++++++++++++++++ drivers/platform/x86/simatic-ipc-batt-apollolake.c | 51 ----- .../platform/x86/simatic-ipc-batt-elkhartlake.c | 51 ----- drivers/platform/x86/simatic-ipc-batt-f7188x.c | 70 ------ drivers/platform/x86/simatic-ipc-batt.c | 252 --------------------- drivers/platform/x86/simatic-ipc-batt.h | 20 -- drivers/platform/x86/simatic-ipc.c | 228 ------------------- 16 files changed, 748 insertions(+), 735 deletions(-) create mode 100644 drivers/platform/x86/siemens/Kconfig create mode 100644 drivers/platform/x86/siemens/Makefile create mode 100644 drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c create mode 100644 drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c create mode 100644 drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c create mode 100644 drivers/platform/x86/siemens/simatic-ipc-batt.c create mode 100644 drivers/platform/x86/siemens/simatic-ipc-batt.h create mode 100644 drivers/platform/x86/siemens/simatic-ipc.c delete mode 100644 drivers/platform/x86/simatic-ipc-batt-apollolake.c delete mode 100644 drivers/platform/x86/simatic-ipc-batt-elkhartlake.c delete mode 100644 drivers/platform/x86/simatic-ipc-batt-f7188x.c delete mode 100644 drivers/platform/x86/simatic-ipc-batt.c delete mode 100644 drivers/platform/x86/simatic-ipc-batt.h delete mode 100644 drivers/platform/x86/simatic-ipc.c diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 487d3d8f4da9..f5fcb1ca1b63 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -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" diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 522da0d1584d..affce39f3c67 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -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 index 000000000000..618790f132f7 --- /dev/null +++ b/drivers/platform/x86/siemens/Kconfig @@ -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 index 000000000000..2b384b4cb8ba --- /dev/null +++ b/drivers/platform/x86/siemens/Makefile @@ -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 index 000000000000..8a67979d8f96 --- /dev/null +++ b/drivers/platform/x86/siemens/simatic-ipc-batt-apollolake.c @@ -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 + */ + +#include +#include +#include +#include +#include + +#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 "); 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 index 000000000000..607d033911a2 --- /dev/null +++ b/drivers/platform/x86/siemens/simatic-ipc-batt-elkhartlake.c @@ -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 + */ + +#include +#include +#include +#include +#include + +#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 "); 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 index 000000000000..ed330f6a8ea8 --- /dev/null +++ b/drivers/platform/x86/siemens/simatic-ipc-batt-f7188x.c @@ -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 + */ + +#include +#include +#include +#include +#include +#include + +#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 "); diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt.c b/drivers/platform/x86/siemens/simatic-ipc-batt.c new file mode 100644 index 000000000000..d2791ff84f23 --- /dev/null +++ b/drivers/platform/x86/siemens/simatic-ipc-batt.c @@ -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 + * Henning Schild + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 "); diff --git a/drivers/platform/x86/siemens/simatic-ipc-batt.h b/drivers/platform/x86/siemens/simatic-ipc-batt.h new file mode 100644 index 000000000000..4545cd3e3026 --- /dev/null +++ b/drivers/platform/x86/siemens/simatic-ipc-batt.h @@ -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 + */ + +#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 index 000000000000..13c857316c7f --- /dev/null +++ b/drivers/platform/x86/siemens/simatic-ipc.c @@ -0,0 +1,228 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Siemens SIMATIC IPC platform driver + * + * Copyright (c) Siemens AG, 2018-2023 + * + * Authors: + * Henning Schild + * Jan Kiszka + * Gerd Haeussler + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include +#include +#include + +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 "); +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 index 8a67979d8f96..000000000000 --- a/drivers/platform/x86/simatic-ipc-batt-apollolake.c +++ /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 - */ - -#include -#include -#include -#include -#include - -#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 "); diff --git a/drivers/platform/x86/simatic-ipc-batt-elkhartlake.c b/drivers/platform/x86/simatic-ipc-batt-elkhartlake.c deleted file mode 100644 index 607d033911a2..000000000000 --- a/drivers/platform/x86/simatic-ipc-batt-elkhartlake.c +++ /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 - */ - -#include -#include -#include -#include -#include - -#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 "); diff --git a/drivers/platform/x86/simatic-ipc-batt-f7188x.c b/drivers/platform/x86/simatic-ipc-batt-f7188x.c deleted file mode 100644 index ed330f6a8ea8..000000000000 --- a/drivers/platform/x86/simatic-ipc-batt-f7188x.c +++ /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 - */ - -#include -#include -#include -#include -#include -#include - -#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 "); diff --git a/drivers/platform/x86/simatic-ipc-batt.c b/drivers/platform/x86/simatic-ipc-batt.c deleted file mode 100644 index d2791ff84f23..000000000000 --- a/drivers/platform/x86/simatic-ipc-batt.c +++ /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 - * Henning Schild - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#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 "); diff --git a/drivers/platform/x86/simatic-ipc-batt.h b/drivers/platform/x86/simatic-ipc-batt.h deleted file mode 100644 index 4545cd3e3026..000000000000 --- a/drivers/platform/x86/simatic-ipc-batt.h +++ /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 - */ - -#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 index 13c857316c7f..000000000000 --- a/drivers/platform/x86/simatic-ipc.c +++ /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 - * Jan Kiszka - * Gerd Haeussler - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include - -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 "); -MODULE_ALIAS("dmi:*:svnSIEMENSAG:*"); -- cgit v1.2.3