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. -----BEGIN PGP SIGNATURE----- iQFIBAABCAAyFiEEuvA7XScYQRpenhd+kuxHeUQDJ9wFAmSxSdMUHGhkZWdvZWRl QHJlZGhhdC5jb20ACgkQkuxHeUQDJ9xdyAf9HQ841da0W+ZQCxgcltLZtd5cyLbp HC1VcjjkA/xLzFpKQOAT3fXijxGWprI8nbzAnA1UT1qqy2dn6Q31OarZ/ubraQvs kQxCPV2HBXMlYeTktRbvvnHRSHE/dvqzEYY1Ktk1+fEqJvCwrw5E7Zig2Y9Vj+J2 KMTvXuSgImY18mgWaX0aUDnxV2M7vVmgvctxiW2MZyJ7oaz2rnv8jDc9Trpr5oBj MJzuGp9JhVDCcUsEMpuyx6DdejOoxEQ/pL30faYEqzTu/dBFRqkt7ACyODdeFfdT mx3kcE8um9Z/qKf6vsEh4kpEPMA4vTDlVBxBRwwpUTADOZrypV0/FPPoEg== =0t7p -----END PGP SIGNATURE----- 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.
This commit is contained in:
commit
2dd074c405
@ -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
|
||||
|
@ -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
|
||||
|
51
drivers/platform/x86/simatic-ipc-batt-apollolake.c
Normal file
51
drivers/platform/x86/simatic-ipc-batt-apollolake.c
Normal file
@ -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>");
|
51
drivers/platform/x86/simatic-ipc-batt-elkhartlake.c
Normal file
51
drivers/platform/x86/simatic-ipc-batt-elkhartlake.c
Normal file
@ -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>");
|
70
drivers/platform/x86/simatic-ipc-batt-f7188x.c
Normal file
70
drivers/platform/x86/simatic-ipc-batt-f7188x.c
Normal file
@ -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>");
|
252
drivers/platform/x86/simatic-ipc-batt.c
Normal file
252
drivers/platform/x86/simatic-ipc-batt.c
Normal file
@ -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>");
|
20
drivers/platform/x86/simatic-ipc-batt.h
Normal file
20
drivers/platform/x86/simatic-ipc-batt.h
Normal file
@ -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 */
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user