Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Siemens SIMATIC IPC platform driver
  4 *
  5 * Copyright (c) Siemens AG, 2018-2021
  6 *
  7 * Authors:
  8 *  Henning Schild <henning.schild@siemens.com>
  9 *  Jan Kiszka <jan.kiszka@siemens.com>
 10 *  Gerd Haeussler <gerd.haeussler.ext@siemens.com>
 11 */
 12
 13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 14
 15#include <linux/dmi.h>
 16#include <linux/kernel.h>
 17#include <linux/module.h>
 18#include <linux/pci.h>
 19#include <linux/platform_data/x86/simatic-ipc.h>
 20#include <linux/platform_device.h>
 21
 22static struct platform_device *ipc_led_platform_device;
 23static struct platform_device *ipc_wdt_platform_device;
 24
 25static const struct dmi_system_id simatic_ipc_whitelist[] = {
 26	{
 27		.matches = {
 28			DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"),
 29		},
 30	},
 31	{}
 32};
 33
 34static struct simatic_ipc_platform platform_data;
 35
 36static struct {
 37	u32 station_id;
 38	u8 led_mode;
 39	u8 wdt_mode;
 40} device_modes[] = {
 41	{SIMATIC_IPC_IPC127E, SIMATIC_IPC_DEVICE_127E, SIMATIC_IPC_DEVICE_NONE},
 42	{SIMATIC_IPC_IPC227D, SIMATIC_IPC_DEVICE_227D, SIMATIC_IPC_DEVICE_NONE},
 43	{SIMATIC_IPC_IPC227E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_227E},
 44	{SIMATIC_IPC_IPC227G, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_227G},
 45	{SIMATIC_IPC_IPC277E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227E},
 46	{SIMATIC_IPC_IPC427D, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_NONE},
 47	{SIMATIC_IPC_IPC427E, SIMATIC_IPC_DEVICE_427E, SIMATIC_IPC_DEVICE_427E},
 48	{SIMATIC_IPC_IPC477E, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_427E},
 49	{SIMATIC_IPC_IPCBX_39A, SIMATIC_IPC_DEVICE_227G, SIMATIC_IPC_DEVICE_227G},
 50	{SIMATIC_IPC_IPCPX_39A, SIMATIC_IPC_DEVICE_NONE, SIMATIC_IPC_DEVICE_227G},
 51};
 52
 53static int register_platform_devices(u32 station_id)
 54{
 55	u8 ledmode = SIMATIC_IPC_DEVICE_NONE;
 56	u8 wdtmode = SIMATIC_IPC_DEVICE_NONE;
 57	char *pdevname = KBUILD_MODNAME "_leds";
 58	int i;
 59
 60	platform_data.devmode = SIMATIC_IPC_DEVICE_NONE;
 61
 62	for (i = 0; i < ARRAY_SIZE(device_modes); i++) {
 63		if (device_modes[i].station_id == station_id) {
 64			ledmode = device_modes[i].led_mode;
 65			wdtmode = device_modes[i].wdt_mode;
 66			break;
 67		}
 68	}
 69
 70	if (ledmode != SIMATIC_IPC_DEVICE_NONE) {
 71		if (ledmode == SIMATIC_IPC_DEVICE_127E ||
 72		    ledmode == SIMATIC_IPC_DEVICE_227G)
 73			pdevname = KBUILD_MODNAME "_leds_gpio";
 74		platform_data.devmode = ledmode;
 75		ipc_led_platform_device =
 76			platform_device_register_data(NULL,
 77				pdevname, PLATFORM_DEVID_NONE,
 78				&platform_data,
 79				sizeof(struct simatic_ipc_platform));
 80		if (IS_ERR(ipc_led_platform_device))
 81			return PTR_ERR(ipc_led_platform_device);
 82
 83		pr_debug("device=%s created\n",
 84			 ipc_led_platform_device->name);
 85	}
 86
 87	if (wdtmode == SIMATIC_IPC_DEVICE_227G) {
 88		request_module("w83627hf_wdt");
 89		return 0;
 90	}
 91
 92	if (wdtmode != SIMATIC_IPC_DEVICE_NONE) {
 93		platform_data.devmode = wdtmode;
 94		ipc_wdt_platform_device =
 95			platform_device_register_data(NULL,
 96				KBUILD_MODNAME "_wdt", PLATFORM_DEVID_NONE,
 97				&platform_data,
 98				sizeof(struct simatic_ipc_platform));
 99		if (IS_ERR(ipc_wdt_platform_device))
100			return PTR_ERR(ipc_wdt_platform_device);
101
102		pr_debug("device=%s created\n",
103			 ipc_wdt_platform_device->name);
104	}
105
106	if (ledmode == SIMATIC_IPC_DEVICE_NONE &&
107	    wdtmode == SIMATIC_IPC_DEVICE_NONE) {
108		pr_warn("unsupported IPC detected, station id=%08x\n",
109			station_id);
110		return -EINVAL;
111	}
112
113	return 0;
114}
115
116static int __init simatic_ipc_init_module(void)
117{
118	const struct dmi_system_id *match;
119	u32 station_id;
120	int err;
121
122	match = dmi_first_match(simatic_ipc_whitelist);
123	if (!match)
124		return 0;
125
126	err = dmi_walk(simatic_ipc_find_dmi_entry_helper, &station_id);
127
128	if (err || station_id == SIMATIC_IPC_INVALID_STATION_ID) {
129		pr_warn("DMI entry %d not found\n", SIMATIC_IPC_DMI_ENTRY_OEM);
130		return 0;
131	}
132
133	return register_platform_devices(station_id);
134}
135
136static void __exit simatic_ipc_exit_module(void)
137{
138	platform_device_unregister(ipc_led_platform_device);
139	ipc_led_platform_device = NULL;
140
141	platform_device_unregister(ipc_wdt_platform_device);
142	ipc_wdt_platform_device = NULL;
143}
144
145module_init(simatic_ipc_init_module);
146module_exit(simatic_ipc_exit_module);
147
148MODULE_LICENSE("GPL v2");
149MODULE_AUTHOR("Gerd Haeussler <gerd.haeussler.ext@siemens.com>");
150MODULE_ALIAS("dmi:*:svnSIEMENSAG:*");