diff options
| author | Hans de Goede <hdegoede@redhat.com> | 2023-07-14 15:21:53 +0200 |
|---|---|---|
| committer | Hans de Goede <hdegoede@redhat.com> | 2023-07-14 15:21:53 +0200 |
| commit | 2dd074c405d4c7bcdf97619c079b345021164109 (patch) | |
| tree | a2255dce2e693377baaddebbaae605dcb67672e0 | |
| parent | 38831eaf7d4ca95c5052e1f6f0ac7cacd46d6fef (diff) | |
| parent | 8766addf665e9f0ace15cca894ba225e5a4d580a (diff) | |
Merge tag 'ib-pdx86-simatic-v6.6' into review-hans
Immutable branch between pdx86 simatic branch and LED due for the v6.6 merge window
v6.5-rc1 + recent pdx86 simatic-ipc patches for
merging into the LED subsystem for v6.6.
| -rw-r--r-- | drivers/platform/x86/Kconfig | 49 | ||||
| -rw-r--r-- | drivers/platform/x86/Makefile | 6 | ||||
| -rw-r--r-- | drivers/platform/x86/simatic-ipc-batt-apollolake.c | 51 | ||||
| -rw-r--r-- | drivers/platform/x86/simatic-ipc-batt-elkhartlake.c | 51 | ||||
| -rw-r--r-- | drivers/platform/x86/simatic-ipc-batt-f7188x.c | 70 | ||||
| -rw-r--r-- | drivers/platform/x86/simatic-ipc-batt.c | 252 | ||||
| -rw-r--r-- | drivers/platform/x86/simatic-ipc-batt.h | 20 | ||||
| -rw-r--r-- | drivers/platform/x86/simatic-ipc.c | 119 | ||||
| -rw-r--r-- | drivers/watchdog/simatic-ipc-wdt.c | 9 | ||||
| -rw-r--r-- | include/linux/platform_data/x86/simatic-ipc-base.h | 4 | ||||
| -rw-r--r-- | include/linux/platform_data/x86/simatic-ipc.h | 4 |
11 files changed, 607 insertions, 28 deletions
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 49c2c4cd8d00..487d3d8f4da9 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1076,7 +1076,6 @@ config INTEL_SCU_IPC_UTIL config SIEMENS_SIMATIC_IPC tristate "Siemens Simatic IPC Class driver" - depends on PCI help This Simatic IPC class driver is the central of several drivers. It is mainly used for system identification, after which drivers in other @@ -1086,6 +1085,54 @@ config SIEMENS_SIMATIC_IPC 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. + config WINMATE_FM07_KEYS tristate "Winmate FM07/FM07P front-panel keys driver" depends on INPUT diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 52dfdf574ac2..522da0d1584d 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -131,7 +131,11 @@ 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) += 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 # Winmate obj-$(CONFIG_WINMATE_FM07_KEYS) += winmate-fm07-keys.o diff --git a/drivers/platform/x86/simatic-ipc-batt-apollolake.c b/drivers/platform/x86/simatic-ipc-batt-apollolake.c new file mode 100644 index 000000000000..8a67979d8f96 --- /dev/null +++ b/drivers/platform/x86/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 <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 new file mode 100644 index 000000000000..607d033911a2 --- /dev/null +++ b/drivers/platform/x86/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 <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 new file mode 100644 index 000000000000..ed330f6a8ea8 --- /dev/null +++ b/drivers/platform/x86/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 <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 new file mode 100644 index 000000000000..d2791ff84f23 --- /dev/null +++ b/drivers/platform/x86/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 <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 new file mode 100644 index 000000000000..4545cd3e3026 --- /dev/null +++ b/drivers/platform/x86/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 <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 index c773995b230d..13c857316c7f 100644 --- a/drivers/platform/x86/simatic-ipc.c +++ b/drivers/platform/x86/simatic-ipc.c @@ -2,7 +2,7 @@ /* * Siemens SIMATIC IPC platform driver * - * Copyright (c) Siemens AG, 2018-2021 + * Copyright (c) Siemens AG, 2018-2023 * * Authors: * Henning Schild <henning.schild@siemens.com> @@ -15,12 +15,12 @@ #include <linux/dmi.h> #include <linux/kernel.h> #include <linux/module.h> -#include <linux/pci.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[] = { { @@ -33,45 +33,98 @@ static const struct dmi_system_id simatic_ipc_whitelist[] = { 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_IPC227D, SIMATIC_IPC_DEVICE_227D, SIMATIC_IPC_DEVICE_NONE}, - {SIMATIC_IPC_IPC227E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_227E}, - {SIMATIC_IPC_IPC227G, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_227G}, - {SIMATIC_IPC_IPC277E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227E}, - {SIMATIC_IPC_IPC427D, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE}, - {SIMATIC_IPC_IPC427E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_427E}, - {SIMATIC_IPC_IPC477E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_427E}, - {SIMATIC_IPC_IPCBX_39A, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_227G}, - {SIMATIC_IPC_IPCPX_39A, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227G}, + {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; - char *pdevname = KBUILD_MODNAME "_leds"; + u8 battmode = SIMATIC_IPC_DEVICE_NONE; + char *pdevname; int i; - platform_data.devmode = SIMATIC_IPC_DEVICE_NONE; - 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, @@ -85,11 +138,6 @@ static int register_platform_devices(u32 station_id) ipc_led_platform_device->name); } - if (wdtmode == SIMATIC_IPC_DEVICE_227G) { - request_module("w83627hf_wdt"); - return 0; - } - if (wdtmode != SIMATIC_IPC_DEVICE_NONE) { platform_data.devmode = wdtmode; ipc_wdt_platform_device = @@ -105,7 +153,8 @@ static int register_platform_devices(u32 station_id) } if (ledmode == SIMATIC_IPC_DEVICE_NONE && - wdtmode == 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; @@ -114,6 +163,29 @@ static int register_platform_devices(u32 station_id) 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; @@ -131,6 +203,8 @@ static int __init simatic_ipc_init_module(void) return 0; } + request_additional_modules(station_id); + return register_platform_devices(station_id); } @@ -141,6 +215,9 @@ static void __exit simatic_ipc_exit_module(void) 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); diff --git a/drivers/watchdog/simatic-ipc-wdt.c b/drivers/watchdog/simatic-ipc-wdt.c index 6599695dc672..cdc1a2e15180 100644 --- a/drivers/watchdog/simatic-ipc-wdt.c +++ b/drivers/watchdog/simatic-ipc-wdt.c @@ -155,9 +155,8 @@ static int simatic_ipc_wdt_probe(struct platform_device *pdev) switch (plat->devmode) { case SIMATIC_IPC_DEVICE_227E: - if (!devm_request_region(dev, gp_status_reg_227e_res.start, - resource_size(&gp_status_reg_227e_res), - KBUILD_MODNAME)) { + res = &gp_status_reg_227e_res; + if (!request_muxed_region(res->start, resource_size(res), res->name)) { dev_err(dev, "Unable to register IO resource at %pR\n", &gp_status_reg_227e_res); @@ -210,6 +209,10 @@ static int simatic_ipc_wdt_probe(struct platform_device *pdev) if (wdd_data.bootstatus) dev_warn(dev, "last reboot caused by watchdog reset\n"); + if (plat->devmode == SIMATIC_IPC_DEVICE_227E) + release_region(gp_status_reg_227e_res.start, + resource_size(&gp_status_reg_227e_res)); + watchdog_set_nowayout(&wdd_data, nowayout); watchdog_stop_on_reboot(&wdd_data); return devm_watchdog_register_device(dev, &wdd_data); diff --git a/include/linux/platform_data/x86/simatic-ipc-base.h b/include/linux/platform_data/x86/simatic-ipc-base.h index 57d6a10dfc9e..4ca21065c862 100644 --- a/include/linux/platform_data/x86/simatic-ipc-base.h +++ b/include/linux/platform_data/x86/simatic-ipc-base.h @@ -2,7 +2,7 @@ /* * Siemens SIMATIC IPC drivers * - * Copyright (c) Siemens AG, 2018-2021 + * Copyright (c) Siemens AG, 2018-2023 * * Authors: * Henning Schild <henning.schild@siemens.com> @@ -20,6 +20,8 @@ #define SIMATIC_IPC_DEVICE_127E 3 #define SIMATIC_IPC_DEVICE_227E 4 #define SIMATIC_IPC_DEVICE_227G 5 +#define SIMATIC_IPC_DEVICE_BX_21A 6 +#define SIMATIC_IPC_DEVICE_BX_39A 7 struct simatic_ipc_platform { u8 devmode; diff --git a/include/linux/platform_data/x86/simatic-ipc.h b/include/linux/platform_data/x86/simatic-ipc.h index a48bb5240977..f2eafa43a605 100644 --- a/include/linux/platform_data/x86/simatic-ipc.h +++ b/include/linux/platform_data/x86/simatic-ipc.h @@ -2,7 +2,7 @@ /* * Siemens SIMATIC IPC drivers * - * Copyright (c) Siemens AG, 2018-2021 + * Copyright (c) Siemens AG, 2018-2023 * * Authors: * Henning Schild <henning.schild@siemens.com> @@ -32,8 +32,10 @@ enum simatic_ipc_station_ids { SIMATIC_IPC_IPC477E = 0x00000A02, SIMATIC_IPC_IPC127E = 0x00000D01, SIMATIC_IPC_IPC227G = 0x00000F01, + SIMATIC_IPC_IPC277G = 0x00000F02, SIMATIC_IPC_IPCBX_39A = 0x00001001, SIMATIC_IPC_IPCPX_39A = 0x00001002, + SIMATIC_IPC_IPCBX_21A = 0x00001101, }; static inline u32 simatic_ipc_get_station_id(u8 *data, int max_len) |
