summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--MAINTAINERS11
-rw-r--r--drivers/staging/Kconfig2
-rw-r--r--drivers/staging/Makefile1
-rw-r--r--drivers/staging/fieldbus/Documentation/ABI/fieldbus-dev-cdev31
-rw-r--r--drivers/staging/fieldbus/Documentation/ABI/sysfs-class-fieldbus-dev62
-rw-r--r--drivers/staging/fieldbus/Documentation/devicetree/bindings/fieldbus/arcx,anybus-controller.txt71
-rw-r--r--drivers/staging/fieldbus/Documentation/fieldbus_dev.txt66
-rw-r--r--drivers/staging/fieldbus/Kconfig19
-rw-r--r--drivers/staging/fieldbus/Makefile7
-rw-r--r--drivers/staging/fieldbus/TODO5
-rw-r--r--drivers/staging/fieldbus/anybuss/Kconfig41
-rw-r--r--drivers/staging/fieldbus/anybuss/Makefile10
-rw-r--r--drivers/staging/fieldbus/anybuss/anybuss-client.h95
-rw-r--r--drivers/staging/fieldbus/anybuss/anybuss-controller.h47
-rw-r--r--drivers/staging/fieldbus/anybuss/arcx-anybus.c379
-rw-r--r--drivers/staging/fieldbus/anybuss/hms-profinet.c224
-rw-r--r--drivers/staging/fieldbus/anybuss/host.c1452
-rw-r--r--drivers/staging/fieldbus/dev_core.c344
-rw-r--r--drivers/staging/fieldbus/fieldbus_dev.h114
19 files changed, 0 insertions, 2981 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index b609f40e1420..e4c51d40d42b 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -21930,17 +21930,6 @@ L: linux-media@vger.kernel.org
S: Maintained
F: drivers/staging/media/atomisp/
-STAGING - FIELDBUS SUBSYSTEM
-M: Sven Van Asbroeck <TheSven73@gmail.com>
-S: Maintained
-F: drivers/staging/fieldbus/*
-F: drivers/staging/fieldbus/Documentation/
-
-STAGING - HMS ANYBUS-S BUS
-M: Sven Van Asbroeck <TheSven73@gmail.com>
-S: Maintained
-F: drivers/staging/fieldbus/anybuss/
-
STAGING - INDUSTRIAL IO
M: Jonathan Cameron <jic23@kernel.org>
L: linux-iio@vger.kernel.org
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 4018f95a31bc..075e775d3868 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -46,8 +46,6 @@ source "drivers/staging/vc04_services/Kconfig"
source "drivers/staging/axis-fifo/Kconfig"
-source "drivers/staging/fieldbus/Kconfig"
-
source "drivers/staging/vme_user/Kconfig"
source "drivers/staging/gpib/Kconfig"
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index f29d66da02eb..e681e403509c 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -13,5 +13,4 @@ obj-$(CONFIG_MOST) += most/
obj-$(CONFIG_GREYBUS) += greybus/
obj-$(CONFIG_BCM2835_VCHIQ) += vc04_services/
obj-$(CONFIG_XIL_AXIS_FIFO) += axis-fifo/
-obj-$(CONFIG_FIELDBUS_DEV) += fieldbus/
obj-$(CONFIG_GPIB) += gpib/
diff --git a/drivers/staging/fieldbus/Documentation/ABI/fieldbus-dev-cdev b/drivers/staging/fieldbus/Documentation/ABI/fieldbus-dev-cdev
deleted file mode 100644
index 45f631ea32a6..000000000000
--- a/drivers/staging/fieldbus/Documentation/ABI/fieldbus-dev-cdev
+++ /dev/null
@@ -1,31 +0,0 @@
-What: /dev/fieldbus_devX
-Date: December 2018
-KernelVersion: 5.1 (staging)
-Contact: Sven Van Asbroeck <TheSven73@gmail.com>
-Description:
- The cdev interface to drivers for Fieldbus Device Memory
- (aka. Process Memory).
-
- The following file operations are supported:
-
- open(2)
- Create an I/O context associated with the file descriptor.
-
- read(2)
- Read from Process Memory's "read area".
- Clears POLLERR | POLLPRI from the file descriptor.
-
- write(2)
- Write to Process Memory's "write area".
-
- poll(2), select(2), epoll_wait(2) etc.
- When a "Process Memory Read Area Changed" event occurs,
- POLLERR | POLLPRI will be set on the file descriptor.
- Note that POLLIN | POLLOUT events are always set, because the
- process memory area is always readable and writable.
-
- close(2)
- Free up the I/O context that was associated
- with the file descriptor.
-
-Users: TBD
diff --git a/drivers/staging/fieldbus/Documentation/ABI/sysfs-class-fieldbus-dev b/drivers/staging/fieldbus/Documentation/ABI/sysfs-class-fieldbus-dev
deleted file mode 100644
index 439f14d33c3b..000000000000
--- a/drivers/staging/fieldbus/Documentation/ABI/sysfs-class-fieldbus-dev
+++ /dev/null
@@ -1,62 +0,0 @@
-What: /sys/class/fieldbus_dev/fieldbus_devX/card_name
-KernelVersion: 5.1 (staging)
-Contact: Sven Van Asbroeck <TheSven73@gmail.com>
-Description:
- Human-readable name of the Fieldbus Device.
-
-What: /sys/class/fieldbus_dev/fieldbus_devX/fieldbus_type
-KernelVersion: 5.1 (staging)
-Contact: Sven Van Asbroeck <TheSven73@gmail.com>
-Description:
- The type of fieldbus implemented by this device.
- Possible values:
- 'unknown'
- 'profinet'
-
-What: /sys/class/fieldbus_dev/fieldbus_devX/fieldbus_id
-KernelVersion: 5.1 (staging)
-Contact: Sven Van Asbroeck <TheSven73@gmail.com>
-Description:
- The unique fieldbus id associated with this device.
- The exact format of this id is fieldbus type dependent, e.g.
- a mac address for profinet.
-
-What: /sys/class/fieldbus_dev/fieldbus_devX/read_area_size
-KernelVersion: 5.1 (staging)
-Contact: Sven Van Asbroeck <TheSven73@gmail.com>
-Description:
- The size, in bytes, of the Process Memory read area.
- Note: this area is accessible by reading from the associated
- character device (/dev/fieldbus_devX).
-
-What: /sys/class/fieldbus_dev/fieldbus_devX/write_area_size
-KernelVersion: 5.1 (staging)
-Contact: Sven Van Asbroeck <TheSven73@gmail.com>
-Description:
- The size, in bytes, of the Process Memory write area.
- Note: this area is accessible by writing to the associated
- character device (/dev/fieldbus_devX)
-
-What: /sys/class/fieldbus_dev/fieldbus_devX/online
-KernelVersion: 5.1 (staging)
-Contact: Sven Van Asbroeck <TheSven73@gmail.com>
-Description:
- Whether the fieldbus is online or offline.
- Possible values:
- '1' meaning 'online'
- '0' meaning 'offline'
- Note: an uevent is generated when this property changes.
-
-What: /sys/class/fieldbus_dev/fieldbus_devX/enabled
-KernelVersion: 5.1 (staging)
-Contact: Sven Van Asbroeck <TheSven73@gmail.com>
-Description:
- Whether the device is enabled (power on) or
- disabled (power off).
- Possible values:
- '1' meaning enabled
- '0' meaning disabled
- Normally a r/o property, but optionally r/w:
- Writing '1' enables the device (power on) with default
- settings.
- Writing '0' disables the card (power off).
diff --git a/drivers/staging/fieldbus/Documentation/devicetree/bindings/fieldbus/arcx,anybus-controller.txt b/drivers/staging/fieldbus/Documentation/devicetree/bindings/fieldbus/arcx,anybus-controller.txt
deleted file mode 100644
index f34a95611645..000000000000
--- a/drivers/staging/fieldbus/Documentation/devicetree/bindings/fieldbus/arcx,anybus-controller.txt
+++ /dev/null
@@ -1,71 +0,0 @@
-* Arcx Anybus-S controller
-
-This chip communicates with the SoC over a parallel bus. It is
-expected that its Device Tree node is specified as the child of a node
-corresponding to the parallel bus used for communication.
-
-Required properties:
---------------------
-
- - compatible : The following chip-specific string:
- "arcx,anybus-controller"
-
- - reg : three areas:
- index 0: bus memory area where the cpld registers are located.
- index 1: bus memory area of the first host's dual-port ram.
- index 2: bus memory area of the second host's dual-port ram.
-
- - reset-gpios : the GPIO pin connected to the reset line of the controller.
-
- - interrupts : two interrupts:
- index 0: interrupt connected to the first host
- index 1: interrupt connected to the second host
- Generic interrupt client node bindings are described in
- interrupt-controller/interrupts.txt
-
-Optional: use of subnodes
--------------------------
-
-The card connected to a host may need additional properties. These can be
-specified in subnodes to the controller node.
-
-The subnodes are identified by the standard 'reg' property. Which information
-exactly can be specified depends on the bindings for the function driver
-for the subnode.
-
-Required controller node properties when using subnodes:
-- #address-cells: should be one.
-- #size-cells: should be zero.
-
-Required subnode properties:
-- reg: Must contain the host index of the card this subnode describes:
- <0> for the first host on the controller
- <1> for the second host on the controller
- Note that only a single card can be plugged into a host, so the host
- index uniquely describes the card location.
-
-Example of usage:
------------------
-
-This example places the bridge on top of the i.MX WEIM parallel bus, see:
-Documentation/devicetree/bindings/memory-controllers/fsl/fsl,imx-weim.yaml
-
-&weim {
- controller@0,0 {
- compatible = "arcx,anybus-controller";
- reg = <0 0 0x100>, <0 0x400000 0x800>, <1 0x400000 0x800>;
- reset-gpios = <&gpio5 2 GPIO_ACTIVE_HIGH>;
- interrupt-parent = <&gpio1>;
- interrupts = <1 IRQ_TYPE_LEVEL_LOW>, <5 IRQ_TYPE_LEVEL_LOW>;
- /* fsl,weim-cs-timing is a i.MX WEIM bus specific property */
- fsl,weim-cs-timing = <0x024400b1 0x00001010 0x20081100
- 0x00000000 0xa0000240 0x00000000>;
- /* optional subnode for a card plugged into the first host */
- #address-cells = <1>;
- #size-cells = <0>;
- card@0 {
- reg = <0>;
- /* card specific properties go here */
- };
- };
-};
diff --git a/drivers/staging/fieldbus/Documentation/fieldbus_dev.txt b/drivers/staging/fieldbus/Documentation/fieldbus_dev.txt
deleted file mode 100644
index 89fb8e14676f..000000000000
--- a/drivers/staging/fieldbus/Documentation/fieldbus_dev.txt
+++ /dev/null
@@ -1,66 +0,0 @@
- Fieldbus-Device Subsystem
- ============================================
-
-Part 0 - What is a Fieldbus Device ?
-------------------------------------
-
-Fieldbus is the name of a family of industrial computer network protocols used
-for real-time distributed control, standardized as IEC 61158.
-
-A complex automated industrial system -- such as manufacturing assembly line --
-usually needs a distributed control system -- an organized hierarchy of
-controller systems -- to function. In this hierarchy, there is usually a
-Human Machine Interface (HMI) at the top, where an operator can monitor or
-operate the system. This is typically linked to a middle layer of programmable
-logic controllers (PLC) via a non-time-critical communications system
-(e.g. Ethernet). At the bottom of the control chain is the fieldbus that links
-the PLCs to the components that actually do the work, such as sensors,
-actuators, electric motors, console lights, switches, valves and contactors.
-
-(Source: Wikipedia)
-
-A "Fieldbus Device" is such an actuator, motor, console light, switch, ...
-controlled via the Fieldbus by a PLC aka "Fieldbus Controller".
-
-Communication between PLC and device typically happens via process data memory,
-separated into input and output areas. The Fieldbus then cyclically transfers
-the PLC's output area to the device's input area, and vice versa.
-
-Part I - Why do we need this subsystem?
----------------------------------------
-
-Fieldbus device (client) adapters are commercially available. They allow data
-exchange with a PLC aka "Fieldbus Controller" via process data memory.
-
-They are typically used when a Linux device wants to expose itself as an
-actuator, motor, console light, switch, etc. over the fieldbus.
-
-The purpose of this subsystem is:
-a) present a general, standardized, extensible API/ABI to userspace; and
-b) present a convenient interface to drivers.
-
-Part II - How can drivers use the subsystem?
---------------------------------------------
-
-Any driver that wants to register as a Fieldbus Device should allocate and
-populate a 'struct fieldbus_dev' (from include/linux/fieldbus_dev.h).
-Registration then happens by calling fieldbus_dev_register().
-
-Part III - How can userspace use the subsystem?
------------------------------------------------
-
-Fieldbus protocols and adapters are diverse and varied. However, they share
-a limited few common behaviours and properties. This allows us to define
-a simple interface consisting of a character device and a set of sysfs files:
-
-See:
-drivers/staging/fieldbus/Documentation/ABI/sysfs-class-fieldbus-dev
-drivers/staging/fieldbus/Documentation/ABI/fieldbus-dev-cdev
-
-Note that this simple interface does not provide a way to modify adapter
-configuration settings. It is therefore useful only for adapters that get their
-configuration settings some other way, e.g. non-volatile memory on the adapter,
-through the network, ...
-
-At a later phase, this simple interface can easily co-exist with a future
-(netlink-based ?) configuration settings interface.
diff --git a/drivers/staging/fieldbus/Kconfig b/drivers/staging/fieldbus/Kconfig
deleted file mode 100644
index b0b865acccfb..000000000000
--- a/drivers/staging/fieldbus/Kconfig
+++ /dev/null
@@ -1,19 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-menuconfig FIELDBUS_DEV
- tristate "Fieldbus Device Support"
- help
- Support for Fieldbus Device Adapters.
-
- Fieldbus device (client) adapters allow data exchange with a PLC aka.
- "Fieldbus Controller" over a fieldbus (Profinet, FLNet, etc.)
-
- They are typically used when a Linux device wants to expose itself
- as an actuator, motor, console light, switch, etc. over the fieldbus.
-
- This framework is designed to provide a generic interface to Fieldbus
- Devices from both the Linux Kernel and the userspace.
-
- If unsure, say no.
-
-source "drivers/staging/fieldbus/anybuss/Kconfig"
-
diff --git a/drivers/staging/fieldbus/Makefile b/drivers/staging/fieldbus/Makefile
deleted file mode 100644
index bdf645d41344..000000000000
--- a/drivers/staging/fieldbus/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Makefile for fieldbus_dev drivers.
-#
-
-obj-$(CONFIG_FIELDBUS_DEV) += fieldbus_dev.o anybuss/
-fieldbus_dev-y := dev_core.o
diff --git a/drivers/staging/fieldbus/TODO b/drivers/staging/fieldbus/TODO
deleted file mode 100644
index 6d6626af4ec7..000000000000
--- a/drivers/staging/fieldbus/TODO
+++ /dev/null
@@ -1,5 +0,0 @@
-TODO:
--Get more people/drivers to use the Fieldbus userspace ABI. It requires
- verification/sign-off by multiple users.
-
-Contact: Sven Van Asbroeck <TheSven73@gmail.com>
diff --git a/drivers/staging/fieldbus/anybuss/Kconfig b/drivers/staging/fieldbus/anybuss/Kconfig
deleted file mode 100644
index 635a0a7b7dd2..000000000000
--- a/drivers/staging/fieldbus/anybuss/Kconfig
+++ /dev/null
@@ -1,41 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0-only
-config HMS_ANYBUSS_BUS
- tristate "HMS Anybus-S Bus Support"
- select REGMAP
- depends on OF && FIELDBUS_DEV
- help
- Driver for the HMS Industrial Networks Anybus-S bus.
- You can attach a single Anybus-S compatible card to it, which
- typically provides fieldbus and industrial ethernet
- functionality.
-
-if HMS_ANYBUSS_BUS
-
-config ARCX_ANYBUS_CONTROLLER
- tristate "Arcx Anybus-S Controller"
- depends on OF && GPIOLIB && HAS_IOMEM && REGULATOR
- select REGMAP_MMIO
- help
- Select this to get support for the Arcx Anybus controller.
- It connects to the SoC via a parallel memory bus, and
- embeds up to two Anybus-S buses (slots).
- There is also a CAN power readout, unrelated to the Anybus,
- modelled as a regulator.
-
-config HMS_PROFINET
- tristate "HMS Profinet IRT Controller (Anybus-S)"
- depends on FIELDBUS_DEV && HMS_ANYBUSS_BUS
- help
- If you say yes here you get support for the HMS Industrial
- Networks Profinet IRT Controller.
-
- It will be registered with the kernel as a fieldbus_dev,
- so userspace can interact with it via the fieldbus_dev userspace
- interface(s).
-
- This driver can also be built as a module. If so, the module
- will be called hms-profinet.
-
- If unsure, say N.
-
-endif
diff --git a/drivers/staging/fieldbus/anybuss/Makefile b/drivers/staging/fieldbus/anybuss/Makefile
deleted file mode 100644
index 3ad3dcc6be56..000000000000
--- a/drivers/staging/fieldbus/anybuss/Makefile
+++ /dev/null
@@ -1,10 +0,0 @@
-# SPDX-License-Identifier: GPL-2.0
-#
-# Makefile for anybuss drivers.
-#
-
-obj-$(CONFIG_HMS_ANYBUSS_BUS) += anybuss_core.o
-anybuss_core-y += host.o
-
-obj-$(CONFIG_ARCX_ANYBUS_CONTROLLER) += arcx-anybus.o
-obj-$(CONFIG_HMS_PROFINET) += hms-profinet.o
diff --git a/drivers/staging/fieldbus/anybuss/anybuss-client.h b/drivers/staging/fieldbus/anybuss/anybuss-client.h
deleted file mode 100644
index c21c4bebfb84..000000000000
--- a/drivers/staging/fieldbus/anybuss/anybuss-client.h
+++ /dev/null
@@ -1,95 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Anybus-S client adapter definitions
- *
- * Copyright 2018 Arcx Inc
- */
-
-#ifndef __LINUX_ANYBUSS_CLIENT_H__
-#define __LINUX_ANYBUSS_CLIENT_H__
-
-#include <linux/device.h>
-#include <linux/types.h>
-#include <linux/poll.h>
-
-/* move to <linux/fieldbus_dev.h> when taking this out of staging */
-#include "../fieldbus_dev.h"
-
-struct anybuss_host;
-
-struct anybuss_client {
- struct device dev;
- struct anybuss_host *host;
- __be16 anybus_id;
- /*
- * these can be optionally set by the client to receive event
- * notifications from the host.
- */
- void (*on_area_updated)(struct anybuss_client *client);
- void (*on_online_changed)(struct anybuss_client *client, bool online);
-};
-
-struct anybuss_client_driver {
- struct device_driver driver;
- int (*probe)(struct anybuss_client *adev);
- void (*remove)(struct anybuss_client *adev);
- u16 anybus_id;
-};
-
-int anybuss_client_driver_register(struct anybuss_client_driver *drv);
-void anybuss_client_driver_unregister(struct anybuss_client_driver *drv);
-
-static inline struct anybuss_client *to_anybuss_client(struct device *dev)
-{
- return container_of(dev, struct anybuss_client, dev);
-}
-
-#define to_anybuss_client_driver(__drv) container_of_const(__drv, struct anybuss_client_driver, driver)
-
-static inline void *
-anybuss_get_drvdata(const struct anybuss_client *client)
-{
- return dev_get_drvdata(&client->dev);
-}
-
-static inline void
-anybuss_set_drvdata(struct anybuss_client *client, void *data)
-{
- dev_set_drvdata(&client->dev, data);
-}
-
-int anybuss_set_power(struct anybuss_client *client, bool power_on);
-
-struct anybuss_memcfg {
- u16 input_io;
- u16 input_dpram;
- u16 input_total;
-
- u16 output_io;
- u16 output_dpram;
- u16 output_total;
-
- enum fieldbus_dev_offl_mode offl_mode;
-};
-
-int anybuss_start_init(struct anybuss_client *client,
- const struct anybuss_memcfg *cfg);
-int anybuss_finish_init(struct anybuss_client *client);
-int anybuss_read_fbctrl(struct anybuss_client *client, u16 addr,
- void *buf, size_t count);
-int anybuss_send_msg(struct anybuss_client *client, u16 cmd_num,
- const void *buf, size_t count);
-int anybuss_send_ext(struct anybuss_client *client, u16 cmd_num,
- const void *buf, size_t count);
-int anybuss_recv_msg(struct anybuss_client *client, u16 cmd_num,
- void *buf, size_t count);
-
-/* these help clients make a struct file_operations */
-int anybuss_write_input(struct anybuss_client *client,
- const char __user *buf, size_t size,
- loff_t *offset);
-int anybuss_read_output(struct anybuss_client *client,
- char __user *buf, size_t size,
- loff_t *offset);
-
-#endif /* __LINUX_ANYBUSS_CLIENT_H__ */
diff --git a/drivers/staging/fieldbus/anybuss/anybuss-controller.h b/drivers/staging/fieldbus/anybuss/anybuss-controller.h
deleted file mode 100644
index 02fa0749043b..000000000000
--- a/drivers/staging/fieldbus/anybuss/anybuss-controller.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Anybus-S controller definitions
- *
- * Copyright 2018 Arcx Inc
- */
-
-#ifndef __LINUX_ANYBUSS_CONTROLLER_H__
-#define __LINUX_ANYBUSS_CONTROLLER_H__
-
-#include <linux/device.h>
-#include <linux/regmap.h>
-
-/*
- * To instantiate an Anybus-S host, a controller should provide the following:
- * - a reset function which resets the attached card;
- * - a regmap which provides access to the attached card's dpram;
- * - the irq of the attached card
- */
-/**
- * struct anybuss_ops - Controller resources to instantiate an Anybus-S host
- *
- * @reset: asserts/deasserts the anybus card's reset line.
- * @regmap: provides access to the card's dual-port RAM area.
- * @irq: number of the interrupt connected to the card's interrupt line.
- * @host_idx: for multi-host controllers, the host index:
- * 0 for the first host on the controller, 1 for the second, etc.
- */
-struct anybuss_ops {
- void (*reset)(struct device *dev, bool assert);
- struct regmap *regmap;
- int irq;
- int host_idx;
-};
-
-struct anybuss_host;
-
-struct anybuss_host * __must_check
-anybuss_host_common_probe(struct device *dev,
- const struct anybuss_ops *ops);
-void anybuss_host_common_remove(struct anybuss_host *host);
-
-struct anybuss_host * __must_check
-devm_anybuss_host_common_probe(struct device *dev,
- const struct anybuss_ops *ops);
-
-#endif /* __LINUX_ANYBUSS_CONTROLLER_H__ */
diff --git a/drivers/staging/fieldbus/anybuss/arcx-anybus.c b/drivers/staging/fieldbus/anybuss/arcx-anybus.c
deleted file mode 100644
index cda0d2cf84c5..000000000000
--- a/drivers/staging/fieldbus/anybuss/arcx-anybus.c
+++ /dev/null
@@ -1,379 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Arcx Anybus-S Controller driver
- *
- * Copyright (C) 2018 Arcx Inc
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/platform_device.h>
-#include <linux/gpio/consumer.h>
-#include <linux/io.h>
-#include <linux/of.h>
-#include <linux/delay.h>
-#include <linux/idr.h>
-#include <linux/mutex.h>
-#include <linux/regulator/driver.h>
-#include <linux/regulator/machine.h>
-#include <linux/regmap.h>
-
-/* move to <linux/anybuss-controller.h> when taking this out of staging */
-#include "anybuss-controller.h"
-
-#define CPLD_STATUS1 0x80
-#define CPLD_CONTROL 0x80
-#define CPLD_CONTROL_CRST 0x40
-#define CPLD_CONTROL_RST1 0x04
-#define CPLD_CONTROL_RST2 0x80
-#define CPLD_STATUS1_AB 0x02
-#define CPLD_STATUS1_CAN_POWER 0x01
-#define CPLD_DESIGN_LO 0x81
-#define CPLD_DESIGN_HI 0x82
-#define CPLD_CAP 0x83
-#define CPLD_CAP_COMPAT 0x01
-#define CPLD_CAP_SEP_RESETS 0x02
-
-struct controller_priv {
- struct device *class_dev;
- bool common_reset;
- struct gpio_desc *reset_gpiod;
- void __iomem *cpld_base;
- struct mutex ctrl_lock; /* protects CONTROL register */
- u8 control_reg;
- char version[3];
- u16 design_no;
-};
-
-static void do_reset(struct controller_priv *cd, u8 rst_bit, bool reset)
-{
- mutex_lock(&cd->ctrl_lock);
- /*
- * CPLD_CONTROL is write-only, so cache its value in
- * cd->control_reg
- */
- if (reset)
- cd->control_reg &= ~rst_bit;
- else
- cd->control_reg |= rst_bit;
- writeb(cd->control_reg, cd->cpld_base + CPLD_CONTROL);
- /*
- * h/w work-around:
- * the hardware is 'too fast', so a reset followed by an immediate
- * not-reset will _not_ change the anybus reset line in any way,
- * losing the reset. to prevent this from happening, introduce
- * a minimum reset duration.
- * Verified minimum safe duration required using a scope
- * on 14-June-2018: 100 us.
- */
- if (reset)
- usleep_range(100, 200);
- mutex_unlock(&cd->ctrl_lock);
-}
-
-static int anybuss_reset(struct controller_priv *cd,
- unsigned long id, bool reset)
-{
- if (id >= 2)
- return -EINVAL;
- if (cd->common_reset)
- do_reset(cd, CPLD_CONTROL_CRST, reset);
- else
- do_reset(cd, id ? CPLD_CONTROL_RST2 : CPLD_CONTROL_RST1, reset);
- return 0;
-}
-
-static void export_reset_0(struct device *dev, bool assert)
-{
- struct controller_priv *cd = dev_get_drvdata(dev);
-
- anybuss_reset(cd, 0, assert);
-}
-
-static void export_reset_1(struct device *dev, bool assert)
-{
- struct controller_priv *cd = dev_get_drvdata(dev);
-
- anybuss_reset(cd, 1, assert);
-}
-
-/*
- * parallel bus limitation:
- *
- * the anybus is 8-bit wide. we can't assume that the hardware will translate
- * word accesses on the parallel bus to multiple byte-accesses on the anybus.
- *
- * the imx WEIM bus does not provide this type of translation.
- *
- * to be safe, we will limit parallel bus accesses to a single byte
- * at a time for now.
- */
-
-static const struct regmap_config arcx_regmap_cfg = {
- .reg_bits = 16,
- .val_bits = 8,
- .max_register = 0x7ff,
- .use_single_read = true,
- .use_single_write = true,
- /*
- * single-byte parallel bus accesses are atomic, so don't
- * require any synchronization.
- */
- .disable_locking = true,
-};
-
-static struct regmap *create_parallel_regmap(struct platform_device *pdev,
- int idx)
-{
- void __iomem *base;
- struct device *dev = &pdev->dev;
-
- base = devm_platform_ioremap_resource(pdev, idx + 1);
- if (IS_ERR(base))
- return ERR_CAST(base);
- return devm_regmap_init_mmio(dev, base, &arcx_regmap_cfg);
-}
-
-static struct anybuss_host *
-create_anybus_host(struct platform_device *pdev, int idx)
-{
- struct anybuss_ops ops = {};
-
- switch (idx) {
- case 0:
- ops.reset = export_reset_0;
- break;
- case 1:
- ops.reset = export_reset_1;
- break;
- default:
- return ERR_PTR(-EINVAL);
- }
- ops.host_idx = idx;
- ops.regmap = create_parallel_regmap(pdev, idx);
- if (IS_ERR(ops.regmap))
- return ERR_CAST(ops.regmap);
- ops.irq = platform_get_irq(pdev, idx);
- if (ops.irq < 0)
- return ERR_PTR(ops.irq);
- return devm_anybuss_host_common_probe(&pdev->dev, &ops);
-}
-
-static ssize_t version_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct controller_priv *cd = dev_get_drvdata(dev);
-
- return sprintf(buf, "%s\n", cd->version);
-}
-static DEVICE_ATTR_RO(version);
-
-static ssize_t design_number_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct controller_priv *cd = dev_get_drvdata(dev);
-
- return sprintf(buf, "%d\n", cd->design_no);
-}
-static DEVICE_ATTR_RO(design_number);
-
-static struct attribute *controller_attributes[] = {
- &dev_attr_version.attr,
- &dev_attr_design_number.attr,
- NULL,
-};
-
-static const struct attribute_group controller_attribute_group = {
- .attrs = controller_attributes,
-};
-
-static const struct attribute_group *controller_attribute_groups[] = {
- &controller_attribute_group,
- NULL,
-};
-
-static void controller_device_release(struct device *dev)
-{
- kfree(dev);
-}
-
-static int can_power_is_enabled(struct regulator_dev *rdev)
-{
- struct controller_priv *cd = rdev_get_drvdata(rdev);
-
- return !(readb(cd->cpld_base + CPLD_STATUS1) & CPLD_STATUS1_CAN_POWER);
-}
-
-static const struct regulator_ops can_power_ops = {
- .is_enabled = can_power_is_enabled,
-};
-
-static const struct regulator_desc can_power_desc = {
- .name = "regulator-can-power",
- .id = -1,
- .type = REGULATOR_VOLTAGE,
- .owner = THIS_MODULE,
- .ops = &can_power_ops,
-};
-
-static const struct class controller_class = {
- .name = "arcx_anybus_controller",
-};
-
-static DEFINE_IDA(controller_index_ida);
-
-static int controller_probe(struct platform_device *pdev)
-{
- struct controller_priv *cd;
- struct device *dev = &pdev->dev;
- struct regulator_config config = { };
- struct regulator_dev *regulator;
- int err, id;
- struct anybuss_host *host;
- u8 status1, cap;
-
- cd = devm_kzalloc(dev, sizeof(*cd), GFP_KERNEL);
- if (!cd)
- return -ENOMEM;
- dev_set_drvdata(dev, cd);
- mutex_init(&cd->ctrl_lock);
- cd->reset_gpiod = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
- if (IS_ERR(cd->reset_gpiod))
- return PTR_ERR(cd->reset_gpiod);
-
- /* CPLD control memory, sits at index 0 */
- cd->cpld_base = devm_platform_ioremap_resource(pdev, 0);
- if (IS_ERR(cd->cpld_base)) {
- dev_err(dev,
- "failed to map cpld base address\n");
- err = PTR_ERR(cd->cpld_base);
- goto out_reset;
- }
-
- /* identify cpld */
- status1 = readb(cd->cpld_base + CPLD_STATUS1);
- cd->design_no = (readb(cd->cpld_base + CPLD_DESIGN_HI) << 8) |
- readb(cd->cpld_base + CPLD_DESIGN_LO);
- snprintf(cd->version, sizeof(cd->version), "%c%d",
- 'A' + ((status1 >> 5) & 0x7),
- (status1 >> 2) & 0x7);
- dev_info(dev, "design number %d, revision %s\n",
- cd->design_no,
- cd->version);
- cap = readb(cd->cpld_base + CPLD_CAP);
- if (!(cap & CPLD_CAP_COMPAT)) {
- dev_err(dev, "unsupported controller [cap=0x%02X]", cap);
- err = -ENODEV;
- goto out_reset;
- }
-
- if (status1 & CPLD_STATUS1_AB) {
- dev_info(dev, "has anybus-S slot(s)");
- cd->common_reset = !(cap & CPLD_CAP_SEP_RESETS);
- dev_info(dev, "supports %s", cd->common_reset ?
- "a common reset" : "separate resets");
- for (id = 0; id < 2; id++) {
- host = create_anybus_host(pdev, id);
- if (!IS_ERR(host))
- continue;
- err = PTR_ERR(host);
- /* -ENODEV is fine, it just means no card detected */
- if (err != -ENODEV)
- goto out_reset;
- }
- }
-
- id = ida_alloc(&controller_index_ida, GFP_KERNEL);
- if (id < 0) {
- err = id;
- goto out_reset;
- }
- /* export can power readout as a regulator */
- config.dev = dev;
- config.driver_data = cd;
- regulator = devm_regulator_register(dev, &can_power_desc, &config);
- if (IS_ERR(regulator)) {
- err = PTR_ERR(regulator);
- goto out_ida;
- }
- /* make controller info visible to userspace */
- cd->class_dev = kzalloc(sizeof(*cd->class_dev), GFP_KERNEL);
- if (!cd->class_dev) {
- err = -ENOMEM;
- goto out_ida;
- }
- cd->class_dev->class = &controller_class;
- cd->class_dev->groups = controller_attribute_groups;
- cd->class_dev->parent = dev;
- cd->class_dev->id = id;
- cd->class_dev->release = controller_device_release;
- dev_set_name(cd->class_dev, "%d", cd->class_dev->id);
- dev_set_drvdata(cd->class_dev, cd);
- err = device_register(cd->class_dev);
- if (err)
- goto out_dev;
- return 0;
-out_dev:
- put_device(cd->class_dev);
-out_ida:
- ida_free(&controller_index_ida, id);
-out_reset:
- gpiod_set_value_cansleep(cd->reset_gpiod, 1);
- return err;
-}
-
-static void controller_remove(struct platform_device *pdev)
-{
- struct controller_priv *cd = platform_get_drvdata(pdev);
- int id = cd->class_dev->id;
-
- device_unregister(cd->class_dev);
- ida_free(&controller_index_ida, id);
- gpiod_set_value_cansleep(cd->reset_gpiod, 1);
-}
-
-static const struct of_device_id controller_of_match[] = {
- { .compatible = "arcx,anybus-controller" },
- { }
-};
-
-MODULE_DEVICE_TABLE(of, controller_of_match);
-
-static struct platform_driver controller_driver = {
- .probe = controller_probe,
- .remove = controller_remove,
- .driver = {
- .name = "arcx-anybus-controller",
- .of_match_table = controller_of_match,
- },
-};
-
-static int __init controller_init(void)
-{
- int err;
-
- err = class_register(&controller_class);
- if (err)
- return err;
- err = platform_driver_register(&controller_driver);
- if (err)
- class_unregister(&controller_class);
-
- return err;
-}
-
-static void __exit controller_exit(void)
-{
- platform_driver_unregister(&controller_driver);
- class_unregister(&controller_class);
- ida_destroy(&controller_index_ida);
-}
-
-module_init(controller_init);
-module_exit(controller_exit);
-
-MODULE_DESCRIPTION("Arcx Anybus-S Controller driver");
-MODULE_AUTHOR("Sven Van Asbroeck <TheSven73@gmail.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/fieldbus/anybuss/hms-profinet.c b/drivers/staging/fieldbus/anybuss/hms-profinet.c
deleted file mode 100644
index e691736a53f1..000000000000
--- a/drivers/staging/fieldbus/anybuss/hms-profinet.c
+++ /dev/null
@@ -1,224 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * HMS Profinet Client Driver
- *
- * Copyright (C) 2018 Arcx Inc
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-
-/* move to <linux/fieldbus_dev.h> when taking this out of staging */
-#include "../fieldbus_dev.h"
-
-/* move to <linux/anybuss-client.h> when taking this out of staging */
-#include "anybuss-client.h"
-
-#define PROFI_DPRAM_SIZE 512
-
-/*
- * ---------------------------------------------------------------
- * Anybus Profinet mailbox messages - definitions
- * ---------------------------------------------------------------
- * note that we're depending on the layout of these structures being
- * exactly as advertised.
- */
-
-struct msg_mac_addr {
- u8 addr[6];
-};
-
-struct profi_priv {
- struct fieldbus_dev fbdev;
- struct anybuss_client *client;
- struct mutex enable_lock; /* serializes card enable */
- bool power_on;
-};
-
-static ssize_t
-profi_read_area(struct fieldbus_dev *fbdev, char __user *buf, size_t size,
- loff_t *offset)
-{
- struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev);
-
- return anybuss_read_output(priv->client, buf, size, offset);
-}
-
-static ssize_t
-profi_write_area(struct fieldbus_dev *fbdev, const char __user *buf,
- size_t size, loff_t *offset)
-{
- struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev);
-
- return anybuss_write_input(priv->client, buf, size, offset);
-}
-
-static int profi_id_get(struct fieldbus_dev *fbdev, char *buf,
- size_t max_size)
-{
- struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev);
- struct msg_mac_addr response;
- int ret;
-
- ret = anybuss_recv_msg(priv->client, 0x0010, &response,
- sizeof(response));
- if (ret < 0)
- return ret;
- return snprintf(buf, max_size, "%pM\n", response.addr);
-}
-
-static bool profi_enable_get(struct fieldbus_dev *fbdev)
-{
- struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev);
- bool power_on;
-
- mutex_lock(&priv->enable_lock);
- power_on = priv->power_on;
- mutex_unlock(&priv->enable_lock);
-
- return power_on;
-}
-
-static int __profi_enable(struct profi_priv *priv)
-{
- int ret;
- struct anybuss_client *client = priv->client;
- /* Initialization Sequence, Generic Anybus Mode */
- const struct anybuss_memcfg mem_cfg = {
- .input_io = 220,
- .input_dpram = PROFI_DPRAM_SIZE,
- .input_total = PROFI_DPRAM_SIZE,
- .output_io = 220,
- .output_dpram = PROFI_DPRAM_SIZE,
- .output_total = PROFI_DPRAM_SIZE,
- .offl_mode = FIELDBUS_DEV_OFFL_MODE_CLEAR,
- };
-
- /*
- * switch anybus off then on, this ensures we can do a complete
- * configuration cycle in case anybus was already on.
- */
- anybuss_set_power(client, false);
- ret = anybuss_set_power(client, true);
- if (ret)
- goto err;
- ret = anybuss_start_init(client, &mem_cfg);
- if (ret)
- goto err;
- ret = anybuss_finish_init(client);
- if (ret)
- goto err;
- priv->power_on = true;
- return 0;
-
-err:
- anybuss_set_power(client, false);
- priv->power_on = false;
- return ret;
-}
-
-static int __profi_disable(struct profi_priv *priv)
-{
- struct anybuss_client *client = priv->client;
-
- anybuss_set_power(client, false);
- priv->power_on = false;
- return 0;
-}
-
-static int profi_simple_enable(struct fieldbus_dev *fbdev, bool enable)
-{
- int ret;
- struct profi_priv *priv = container_of(fbdev, struct profi_priv, fbdev);
-
- mutex_lock(&priv->enable_lock);
- if (enable)
- ret = __profi_enable(priv);
- else
- ret = __profi_disable(priv);
- mutex_unlock(&priv->enable_lock);
-
- return ret;
-}
-
-static void profi_on_area_updated(struct anybuss_client *client)
-{
- struct profi_priv *priv = anybuss_get_drvdata(client);
-
- fieldbus_dev_area_updated(&priv->fbdev);
-}
-
-static void profi_on_online_changed(struct anybuss_client *client, bool online)
-{
- struct profi_priv *priv = anybuss_get_drvdata(client);
-
- fieldbus_dev_online_changed(&priv->fbdev, online);
-}
-
-static int profinet_probe(struct anybuss_client *client)
-{
- struct profi_priv *priv;
- struct device *dev = &client->dev;
- int err;
-
- client->on_area_updated = profi_on_area_updated;
- client->on_online_changed = profi_on_online_changed;
- priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv)
- return -ENOMEM;
- mutex_init(&priv->enable_lock);
- priv->client = client;
- priv->fbdev.read_area_sz = PROFI_DPRAM_SIZE;
- priv->fbdev.write_area_sz = PROFI_DPRAM_SIZE;
- priv->fbdev.card_name = "HMS Profinet IRT (Anybus-S)";
- priv->fbdev.fieldbus_type = FIELDBUS_DEV_TYPE_PROFINET;
- priv->fbdev.read_area = profi_read_area;
- priv->fbdev.write_area = profi_write_area;
- priv->fbdev.fieldbus_id_get = profi_id_get;
- priv->fbdev.enable_get = profi_enable_get;
- priv->fbdev.simple_enable_set = profi_simple_enable;
- priv->fbdev.parent = dev;
- err = fieldbus_dev_register(&priv->fbdev);
- if (err < 0)
- return err;
- dev_info(dev, "card detected, registered as %s",
- dev_name(priv->fbdev.dev));
- anybuss_set_drvdata(client, priv);
-
- return 0;
-}
-
-static void profinet_remove(struct anybuss_client *client)
-{
- struct profi_priv *priv = anybuss_get_drvdata(client);
-
- fieldbus_dev_unregister(&priv->fbdev);
-}
-
-static struct anybuss_client_driver profinet_driver = {
- .probe = profinet_probe,
- .remove = profinet_remove,
- .driver = {
- .name = "hms-profinet",
- .owner = THIS_MODULE,
- },
- .anybus_id = 0x0089,
-};
-
-static int __init profinet_init(void)
-{
- return anybuss_client_driver_register(&profinet_driver);
-}
-module_init(profinet_init);
-
-static void __exit profinet_exit(void)
-{
- return anybuss_client_driver_unregister(&profinet_driver);
-}
-module_exit(profinet_exit);
-
-MODULE_AUTHOR("Sven Van Asbroeck <TheSven73@gmail.com>");
-MODULE_DESCRIPTION("HMS Profinet IRT Driver (Anybus-S)");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/fieldbus/anybuss/host.c b/drivers/staging/fieldbus/anybuss/host.c
deleted file mode 100644
index 4f2b2fce92ee..000000000000
--- a/drivers/staging/fieldbus/anybuss/host.c
+++ /dev/null
@@ -1,1452 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * HMS Anybus-S Host Driver
- *
- * Copyright (C) 2018 Arcx Inc
- */
-
-/*
- * Architecture Overview
- * =====================
- * This driver (running on the CPU/SoC) and the Anybus-S card communicate
- * by reading and writing data to/from the Anybus-S Dual-Port RAM (dpram).
- * This is memory connected to both the SoC and Anybus-S card, which both sides
- * can access freely and concurrently.
- *
- * Synchronization happens by means of two registers located in the dpram:
- * IND_AB: written exclusively by the Anybus card; and
- * IND_AP: written exclusively by this driver.
- *
- * Communication happens using one of the following mechanisms:
- * 1. reserve, read/write, release dpram memory areas:
- * using an IND_AB/IND_AP protocol, the driver is able to reserve certain
- * memory areas. no dpram memory can be read or written except if reserved.
- * (with a few limited exceptions)
- * 2. send and receive data structures via a shared mailbox:
- * using an IND_AB/IND_AP protocol, the driver and Anybus card are able to
- * exchange commands and responses using a shared mailbox.
- * 3. receive software interrupts:
- * using an IND_AB/IND_AP protocol, the Anybus card is able to notify the
- * driver of certain events such as: bus online/offline, data available.
- * note that software interrupt event bits are located in a memory area
- * which must be reserved before it can be accessed.
- *
- * The manual[1] is silent on whether these mechanisms can happen concurrently,
- * or how they should be synchronized. However, section 13 (Driver Example)
- * provides the following suggestion for developing a driver:
- * a) an interrupt handler which updates global variables;
- * b) a continuously-running task handling area requests (1 above)
- * c) a continuously-running task handling mailbox requests (2 above)
- * The example conspicuously leaves out software interrupts (3 above), which
- * is the thorniest issue to get right (see below).
- *
- * The naive, straightforward way to implement this would be:
- * - create an isr which updates shared variables;
- * - create a work_struct which handles software interrupts on a queue;
- * - create a function which does reserve/update/unlock in a loop;
- * - create a function which does mailbox send/receive in a loop;
- * - call the above functions from the driver's read/write/ioctl;
- * - synchronize using mutexes/spinlocks:
- * + only one area request at a time
- * + only one mailbox request at a time
- * + protect AB_IND, AB_IND against data hazards (e.g. read-after-write)
- *
- * Unfortunately, the presence of the software interrupt causes subtle yet
- * considerable synchronization issues; especially problematic is the
- * requirement to reserve/release the area which contains the status bits.
- *
- * The driver architecture presented here sidesteps these synchronization issues
- * by accessing the dpram from a single kernel thread only. User-space throws
- * "tasks" (i.e. 1, 2 above) into a task queue, waits for their completion,
- * and the kernel thread runs them to completion.
- *
- * Each task has a task_function, which is called/run by the queue thread.
- * That function communicates with the Anybus card, and returns either
- * 0 (OK), a negative error code (error), or -EINPROGRESS (waiting).
- * On OK or error, the queue thread completes and dequeues the task,
- * which also releases the user space thread which may still be waiting for it.
- * On -EINPROGRESS (waiting), the queue thread will leave the task on the queue,
- * and revisit (call again) whenever an interrupt event comes in.
- *
- * Each task has a state machine, which is run by calling its task_function.
- * It ensures that the task will go through its various stages over time,
- * returning -EINPROGRESS if it wants to wait for an event to happen.
- *
- * Note that according to the manual's driver example, the following operations
- * may run independent of each other:
- * - area reserve/read/write/release (point 1 above)
- * - mailbox operations (point 2 above)
- * - switching power on/off
- *
- * To allow them to run independently, each operation class gets its own queue.
- *
- * Userspace processes A, B, C, D post tasks to the appropriate queue,
- * and wait for task completion:
- *
- * process A B C D
- * | | | |
- * v v v v
- * |<----- ========================================
- * | | | |
- * | v v v-------<-------+
- * | +--------------------------------------+ |
- * | | power q | mbox q | area q | |
- * | |------------|------------|------------| |
- * | | task | task | task | |
- * | | task | task | task | |
- * | | task wait | task wait | task wait | |
- * | +--------------------------------------+ |
- * | ^ ^ ^ |
- * | | | | ^
- * | +--------------------------------------+ |
- * | | queue thread | |
- * | |--------------------------------------| |
- * | | single-threaded: | |
- * | | loop: | |
- * v | for each queue: | |
- * | | run task state machine | |
- * | | if task waiting: | |
- * | | leave on queue | |
- * | | if task done: | |
- * | | complete task, remove from q | |
- * | | if software irq event bits set: | |
- * | | notify userspace | |
- * | | post clear event bits task------>|>-------+
- * | | wait for IND_AB changed event OR |
- * | | task added event OR |
- * | | timeout |
- * | | end loop |
- * | +--------------------------------------+
- * | + wake up +
- * | +--------------------------------------+
- * | ^ ^
- * | | |
- * +-------->------- |
- * |
- * +--------------------------------------+
- * | interrupt service routine |
- * |--------------------------------------|
- * | wake up queue thread on IND_AB change|
- * +--------------------------------------+
- *
- * Note that the Anybus interrupt is dual-purpose:
- * - after a reset, triggered when the card becomes ready;
- * - during normal operation, triggered when AB_IND changes.
- * This is why the interrupt service routine doesn't just wake up the
- * queue thread, but also completes the card_boot completion.
- *
- * [1] https://www.anybus.com/docs/librariesprovider7/default-document-library/
- * manuals-design-guides/hms-hmsi-27-275.pdf
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/atomic.h>
-#include <linux/kthread.h>
-#include <linux/kfifo.h>
-#include <linux/spinlock.h>
-#include <linux/uaccess.h>
-#include <linux/regmap.h>
-#include <linux/of.h>
-#include <linux/random.h>
-#include <linux/kref.h>
-#include <linux/of_address.h>
-
-/* move to <linux/anybuss-*.h> when taking this out of staging */
-#include "anybuss-client.h"
-#include "anybuss-controller.h"
-
-#define DPRAM_SIZE 0x800
-#define MAX_MBOX_MSG_SZ 0x0FF
-#define TIMEOUT (HZ * 2)
-#define MAX_DATA_AREA_SZ 0x200
-#define MAX_FBCTRL_AREA_SZ 0x1BE
-
-#define REG_BOOTLOADER_V 0x7C0
-#define REG_API_V 0x7C2
-#define REG_FIELDBUS_V 0x7C4
-#define REG_SERIAL_NO 0x7C6
-#define REG_FIELDBUS_TYPE 0x7CC
-#define REG_MODULE_SW_V 0x7CE
-#define REG_IND_AB 0x7FF
-#define REG_IND_AP 0x7FE
-#define REG_EVENT_CAUSE 0x7ED
-#define MBOX_IN_AREA 0x400
-#define MBOX_OUT_AREA 0x520
-#define DATA_IN_AREA 0x000
-#define DATA_OUT_AREA 0x200
-#define FBCTRL_AREA 0x640
-
-#define EVENT_CAUSE_DC 0x01
-#define EVENT_CAUSE_FBOF 0x02
-#define EVENT_CAUSE_FBON 0x04
-
-#define IND_AB_UPDATED 0x08
-#define IND_AX_MIN 0x80
-#define IND_AX_MOUT 0x40
-#define IND_AX_IN 0x04
-#define IND_AX_OUT 0x02
-#define IND_AX_FBCTRL 0x01
-#define IND_AP_LOCK 0x08
-#define IND_AP_ACTION 0x10
-#define IND_AX_EVNT 0x20
-#define IND_AP_ABITS (IND_AX_IN | IND_AX_OUT | \
- IND_AX_FBCTRL | \
- IND_AP_ACTION | IND_AP_LOCK)
-
-#define INFO_TYPE_FB 0x0002
-#define INFO_TYPE_APP 0x0001
-#define INFO_COMMAND 0x4000
-
-#define OP_MODE_FBFC 0x0002
-#define OP_MODE_FBS 0x0004
-#define OP_MODE_CD 0x0200
-
-#define CMD_START_INIT 0x0001
-#define CMD_ANYBUS_INIT 0x0002
-#define CMD_END_INIT 0x0003
-
-/*
- * ---------------------------------------------------------------
- * Anybus mailbox messages - definitions
- * ---------------------------------------------------------------
- * note that we're depending on the layout of these structures being
- * exactly as advertised.
- */
-
-struct anybus_mbox_hdr {
- __be16 id;
- __be16 info;
- __be16 cmd_num;
- __be16 data_size;
- __be16 frame_count;
- __be16 frame_num;
- __be16 offset_high;
- __be16 offset_low;
- __be16 extended[8];
-};
-
-struct msg_anybus_init {
- __be16 input_io_len;
- __be16 input_dpram_len;
- __be16 input_total_len;
- __be16 output_io_len;
- __be16 output_dpram_len;
- __be16 output_total_len;
- __be16 op_mode;
- __be16 notif_config;
- __be16 wd_val;
-};
-
-/* ------------- ref counted tasks ------------- */
-
-struct ab_task;
-typedef int (*ab_task_fn_t)(struct anybuss_host *cd,
- struct ab_task *t);
-typedef void (*ab_done_fn_t)(struct anybuss_host *cd);
-
-struct area_priv {
- bool is_write;
- u16 flags;
- u16 addr;
- size_t count;
- u8 buf[MAX_DATA_AREA_SZ];
-};
-
-struct mbox_priv {
- struct anybus_mbox_hdr hdr;
- size_t msg_out_sz;
- size_t msg_in_sz;
- u8 msg[MAX_MBOX_MSG_SZ];
-};
-
-struct ab_task {
- struct kmem_cache *cache;
- struct kref refcount;
- ab_task_fn_t task_fn;
- ab_done_fn_t done_fn;
- int result;
- struct completion done;
- unsigned long start_jiffies;
- union {
- struct area_priv area_pd;
- struct mbox_priv mbox_pd;
- };
-};
-
-static struct ab_task *ab_task_create_get(struct kmem_cache *cache,
- ab_task_fn_t task_fn)
-{
- struct ab_task *t;
-
- t = kmem_cache_alloc(cache, GFP_KERNEL);
- if (!t)
- return NULL;
- t->cache = cache;
- kref_init(&t->refcount);
- t->task_fn = task_fn;
- t->done_fn = NULL;
- t->result = 0;
- init_completion(&t->done);
- return t;
-}
-
-static void __ab_task_destroy(struct kref *refcount)
-{
- struct ab_task *t = container_of(refcount, struct ab_task, refcount);
- struct kmem_cache *cache = t->cache;
-
- kmem_cache_free(cache, t);
-}
-
-static void ab_task_put(struct ab_task *t)
-{
- kref_put(&t->refcount, __ab_task_destroy);
-}
-
-static struct ab_task *__ab_task_get(struct ab_task *t)
-{
- kref_get(&t->refcount);
- return t;
-}
-
-static void __ab_task_finish(struct ab_task *t, struct anybuss_host *cd)
-{
- if (t->done_fn)
- t->done_fn(cd);
- complete(&t->done);
-}
-
-static void
-ab_task_dequeue_finish_put(struct kfifo *q, struct anybuss_host *cd)
-{
- int ret;
- struct ab_task *t;
-
- ret = kfifo_out(q, &t, sizeof(t));
- WARN_ON(!ret);
- __ab_task_finish(t, cd);
- ab_task_put(t);
-}
-
-static int
-ab_task_enqueue(struct ab_task *t, struct kfifo *q, spinlock_t *slock,
- wait_queue_head_t *wq)
-{
- int ret;
-
- t->start_jiffies = jiffies;
- __ab_task_get(t);
- ret = kfifo_in_spinlocked(q, &t, sizeof(t), slock);
- if (!ret) {
- ab_task_put(t);
- return -ENOMEM;
- }
- wake_up(wq);
- return 0;
-}
-
-static int
-ab_task_enqueue_wait(struct ab_task *t, struct kfifo *q, spinlock_t *slock,
- wait_queue_head_t *wq)
-{
- int ret;
-
- ret = ab_task_enqueue(t, q, slock, wq);
- if (ret)
- return ret;
- ret = wait_for_completion_interruptible(&t->done);
- if (ret)
- return ret;
- return t->result;
-}
-
-/* ------------------------ anybus hardware ------------------------ */
-
-struct anybuss_host {
- struct device *dev;
- struct anybuss_client *client;
- void (*reset)(struct device *dev, bool assert);
- struct regmap *regmap;
- int irq;
- int host_idx;
- struct task_struct *qthread;
- wait_queue_head_t wq;
- struct completion card_boot;
- atomic_t ind_ab;
- spinlock_t qlock; /* protects IN side of powerq, mboxq, areaq */
- struct kmem_cache *qcache;
- struct kfifo qs[3];
- struct kfifo *powerq;
- struct kfifo *mboxq;
- struct kfifo *areaq;
- bool power_on;
- bool softint_pending;
-};
-
-static void reset_assert(struct anybuss_host *cd)
-{
- cd->reset(cd->dev, true);
-}
-
-static void reset_deassert(struct anybuss_host *cd)
-{
- cd->reset(cd->dev, false);
-}
-
-static int test_dpram(struct regmap *regmap)
-{
- int i;
- unsigned int val;
-
- for (i = 0; i < DPRAM_SIZE; i++)
- regmap_write(regmap, i, (u8)i);
- for (i = 0; i < DPRAM_SIZE; i++) {
- regmap_read(regmap, i, &val);
- if ((u8)val != (u8)i)
- return -EIO;
- }
- return 0;
-}
-
-static int read_ind_ab(struct regmap *regmap)
-{
- unsigned long timeout = jiffies + HZ / 2;
- unsigned int a, b, i = 0;
-
- while (time_before_eq(jiffies, timeout)) {
- regmap_read(regmap, REG_IND_AB, &a);
- regmap_read(regmap, REG_IND_AB, &b);
- if (likely(a == b))
- return (int)a;
- if (i < 10) {
- cpu_relax();
- i++;
- } else {
- usleep_range(500, 1000);
- }
- }
- WARN(1, "IND_AB register not stable");
- return -ETIMEDOUT;
-}
-
-static int write_ind_ap(struct regmap *regmap, unsigned int ind_ap)
-{
- unsigned long timeout = jiffies + HZ / 2;
- unsigned int v, i = 0;
-
- while (time_before_eq(jiffies, timeout)) {
- regmap_write(regmap, REG_IND_AP, ind_ap);
- regmap_read(regmap, REG_IND_AP, &v);
- if (likely(ind_ap == v))
- return 0;
- if (i < 10) {
- cpu_relax();
- i++;
- } else {
- usleep_range(500, 1000);
- }
- }
- WARN(1, "IND_AP register not stable");
- return -ETIMEDOUT;
-}
-
-static irqreturn_t irq_handler(int irq, void *data)
-{
- struct anybuss_host *cd = data;
- int ind_ab;
-
- /*
- * irq handler needs exclusive access to the IND_AB register,
- * because the act of reading the register acks the interrupt.
- *
- * store the register value in cd->ind_ab (an atomic_t), so that the
- * queue thread is able to read it without causing an interrupt ack
- * side-effect (and without spuriously acking an interrupt).
- */
- ind_ab = read_ind_ab(cd->regmap);
- if (ind_ab < 0)
- return IRQ_NONE;
- atomic_set(&cd->ind_ab, ind_ab);
- complete(&cd->card_boot);
- wake_up(&cd->wq);
- return IRQ_HANDLED;
-}
-
-/* ------------------------ power on/off tasks --------------------- */
-
-static int task_fn_power_off(struct anybuss_host *cd,
- struct ab_task *t)
-{
- struct anybuss_client *client = cd->client;
-
- if (!cd->power_on)
- return 0;
- disable_irq(cd->irq);
- reset_assert(cd);
- atomic_set(&cd->ind_ab, IND_AB_UPDATED);
- if (client->on_online_changed)
- client->on_online_changed(client, false);
- cd->power_on = false;
- return 0;
-}
-
-static int task_fn_power_on_2(struct anybuss_host *cd,
- struct ab_task *t)
-{
- if (completion_done(&cd->card_boot)) {
- cd->power_on = true;
- return 0;
- }
- if (time_after(jiffies, t->start_jiffies + TIMEOUT)) {
- disable_irq(cd->irq);
- reset_assert(cd);
- dev_err(cd->dev, "power on timed out");
- return -ETIMEDOUT;
- }
- return -EINPROGRESS;
-}
-
-static int task_fn_power_on(struct anybuss_host *cd,
- struct ab_task *t)
-{
- unsigned int dummy;
-
- if (cd->power_on)
- return 0;
- /*
- * anybus docs: prevent false 'init done' interrupt by
- * doing a dummy read of IND_AB register while in reset.
- */
- regmap_read(cd->regmap, REG_IND_AB, &dummy);
- reinit_completion(&cd->card_boot);
- enable_irq(cd->irq);
- reset_deassert(cd);
- t->task_fn = task_fn_power_on_2;
- return -EINPROGRESS;
-}
-
-int anybuss_set_power(struct anybuss_client *client, bool power_on)
-{
- struct anybuss_host *cd = client->host;
- struct ab_task *t;
- int err;
-
- t = ab_task_create_get(cd->qcache, power_on ?
- task_fn_power_on : task_fn_power_off);
- if (!t)
- return -ENOMEM;
- err = ab_task_enqueue_wait(t, cd->powerq, &cd->qlock, &cd->wq);
- ab_task_put(t);
- return err;
-}
-EXPORT_SYMBOL_GPL(anybuss_set_power);
-
-/* ---------------------------- area tasks ------------------------ */
-
-static int task_fn_area_3(struct anybuss_host *cd, struct ab_task *t)
-{
- struct area_priv *pd = &t->area_pd;
-
- if (!cd->power_on)
- return -EIO;
- if (atomic_read(&cd->ind_ab) & pd->flags) {
- /* area not released yet */
- if (time_after(jiffies, t->start_jiffies + TIMEOUT))
- return -ETIMEDOUT;
- return -EINPROGRESS;
- }
- return 0;
-}
-
-static int task_fn_area_2(struct anybuss_host *cd, struct ab_task *t)
-{
- struct area_priv *pd = &t->area_pd;
- unsigned int ind_ap;
- int ret;
-
- if (!cd->power_on)
- return -EIO;
- regmap_read(cd->regmap, REG_IND_AP, &ind_ap);
- if (!(atomic_read(&cd->ind_ab) & pd->flags)) {
- /* we don't own the area yet */
- if (time_after(jiffies, t->start_jiffies + TIMEOUT)) {
- dev_warn(cd->dev, "timeout waiting for area");
- dump_stack();
- return -ETIMEDOUT;
- }
- return -EINPROGRESS;
- }
- /* we own the area, do what we're here to do */
- if (pd->is_write)
- regmap_bulk_write(cd->regmap, pd->addr, pd->buf,
- pd->count);
- else
- regmap_bulk_read(cd->regmap, pd->addr, pd->buf,
- pd->count);
- /* ask to release the area, must use unlocked release */
- ind_ap &= ~IND_AP_ABITS;
- ind_ap |= pd->flags;
- ret = write_ind_ap(cd->regmap, ind_ap);
- if (ret)
- return ret;
- t->task_fn = task_fn_area_3;
- return -EINPROGRESS;
-}
-
-static int task_fn_area(struct anybuss_host *cd, struct ab_task *t)
-{
- struct area_priv *pd = &t->area_pd;
- unsigned int ind_ap;
- int ret;
-
- if (!cd->power_on)
- return -EIO;
- regmap_read(cd->regmap, REG_IND_AP, &ind_ap);
- /* ask to take the area */
- ind_ap &= ~IND_AP_ABITS;
- ind_ap |= pd->flags | IND_AP_ACTION | IND_AP_LOCK;
- ret = write_ind_ap(cd->regmap, ind_ap);
- if (ret)
- return ret;
- t->task_fn = task_fn_area_2;
- return -EINPROGRESS;
-}
-
-static struct ab_task *
-create_area_reader(struct kmem_cache *qcache, u16 flags, u16 addr,
- size_t count)
-{
- struct ab_task *t;
- struct area_priv *ap;
-
- t = ab_task_create_get(qcache, task_fn_area);
- if (!t)
- return NULL;
- ap = &t->area_pd;
- ap->flags = flags;
- ap->addr = addr;
- ap->is_write = false;
- ap->count = count;
- return t;
-}
-
-static struct ab_task *
-create_area_writer(struct kmem_cache *qcache, u16 flags, u16 addr,
- const void *buf, size_t count)
-{
- struct ab_task *t;
- struct area_priv *ap;
-
- t = ab_task_create_get(qcache, task_fn_area);
- if (!t)
- return NULL;
- ap = &t->area_pd;
- ap->flags = flags;
- ap->addr = addr;
- ap->is_write = true;
- ap->count = count;
- memcpy(ap->buf, buf, count);
- return t;
-}
-
-static struct ab_task *
-create_area_user_writer(struct kmem_cache *qcache, u16 flags, u16 addr,
- const void __user *buf, size_t count)
-{
- struct ab_task *t;
- struct area_priv *ap;
-
- t = ab_task_create_get(qcache, task_fn_area);
- if (!t)
- return ERR_PTR(-ENOMEM);
- ap = &t->area_pd;
- ap->flags = flags;
- ap->addr = addr;
- ap->is_write = true;
- ap->count = count;
- if (copy_from_user(ap->buf, buf, count)) {
- ab_task_put(t);
- return ERR_PTR(-EFAULT);
- }
- return t;
-}
-
-static bool area_range_ok(u16 addr, size_t count, u16 area_start,
- size_t area_sz)
-{
- u16 area_end_ex = area_start + area_sz;
- u16 addr_end_ex;
-
- if (addr < area_start)
- return false;
- if (addr >= area_end_ex)
- return false;
- addr_end_ex = addr + count;
- if (addr_end_ex > area_end_ex)
- return false;
- return true;
-}
-
-/* -------------------------- mailbox tasks ----------------------- */
-
-static int task_fn_mbox_2(struct anybuss_host *cd, struct ab_task *t)
-{
- struct mbox_priv *pd = &t->mbox_pd;
- unsigned int ind_ap;
-
- if (!cd->power_on)
- return -EIO;
- regmap_read(cd->regmap, REG_IND_AP, &ind_ap);
- if (((atomic_read(&cd->ind_ab) ^ ind_ap) & IND_AX_MOUT) == 0) {
- /* output message not here */
- if (time_after(jiffies, t->start_jiffies + TIMEOUT))
- return -ETIMEDOUT;
- return -EINPROGRESS;
- }
- /* grab the returned header and msg */
- regmap_bulk_read(cd->regmap, MBOX_OUT_AREA, &pd->hdr,
- sizeof(pd->hdr));
- regmap_bulk_read(cd->regmap, MBOX_OUT_AREA + sizeof(pd->hdr),
- pd->msg, pd->msg_in_sz);
- /* tell anybus we've consumed the message */
- ind_ap ^= IND_AX_MOUT;
- return write_ind_ap(cd->regmap, ind_ap);
-}
-
-static int task_fn_mbox(struct anybuss_host *cd, struct ab_task *t)
-{
- struct mbox_priv *pd = &t->mbox_pd;
- unsigned int ind_ap;
- int ret;
-
- if (!cd->power_on)
- return -EIO;
- regmap_read(cd->regmap, REG_IND_AP, &ind_ap);
- if ((atomic_read(&cd->ind_ab) ^ ind_ap) & IND_AX_MIN) {
- /* mbox input area busy */
- if (time_after(jiffies, t->start_jiffies + TIMEOUT))
- return -ETIMEDOUT;
- return -EINPROGRESS;
- }
- /* write the header and msg to input area */
- regmap_bulk_write(cd->regmap, MBOX_IN_AREA, &pd->hdr,
- sizeof(pd->hdr));
- regmap_bulk_write(cd->regmap, MBOX_IN_AREA + sizeof(pd->hdr),
- pd->msg, pd->msg_out_sz);
- /* tell anybus we gave it a message */
- ind_ap ^= IND_AX_MIN;
- ret = write_ind_ap(cd->regmap, ind_ap);
- if (ret)
- return ret;
- t->start_jiffies = jiffies;
- t->task_fn = task_fn_mbox_2;
- return -EINPROGRESS;
-}
-
-static void log_invalid_other(struct device *dev,
- struct anybus_mbox_hdr *hdr)
-{
- size_t ext_offs = ARRAY_SIZE(hdr->extended) - 1;
- u16 code = be16_to_cpu(hdr->extended[ext_offs]);
-
- dev_err(dev, " Invalid other: [0x%02X]", code);
-}
-
-static const char * const EMSGS[] = {
- "Invalid Message ID",
- "Invalid Message Type",
- "Invalid Command",
- "Invalid Data Size",
- "Message Header Malformed (offset 008h)",
- "Message Header Malformed (offset 00Ah)",
- "Message Header Malformed (offset 00Ch - 00Dh)",
- "Invalid Address",
- "Invalid Response",
- "Flash Config Error",
-};
-
-static int mbox_cmd_err(struct device *dev, struct mbox_priv *mpriv)
-{
- int i;
- u8 ecode;
- struct anybus_mbox_hdr *hdr = &mpriv->hdr;
- u16 info = be16_to_cpu(hdr->info);
- u8 *phdr = (u8 *)hdr;
- u8 *pmsg = mpriv->msg;
-
- if (!(info & 0x8000))
- return 0;
- ecode = (info >> 8) & 0x0F;
- dev_err(dev, "mailbox command failed:");
- if (ecode == 0x0F)
- log_invalid_other(dev, hdr);
- else if (ecode < ARRAY_SIZE(EMSGS))
- dev_err(dev, " Error code: %s (0x%02X)",
- EMSGS[ecode], ecode);
- else
- dev_err(dev, " Error code: 0x%02X\n", ecode);
- dev_err(dev, "Failed command:");
- dev_err(dev, "Message Header:");
- for (i = 0; i < sizeof(mpriv->hdr); i += 2)
- dev_err(dev, "%02X%02X", phdr[i], phdr[i + 1]);
- dev_err(dev, "Message Data:");
- for (i = 0; i < mpriv->msg_in_sz; i += 2)
- dev_err(dev, "%02X%02X", pmsg[i], pmsg[i + 1]);
- dev_err(dev, "Stack dump:");
- dump_stack();
- return -EIO;
-}
-
-static int _anybus_mbox_cmd(struct anybuss_host *cd,
- u16 cmd_num, bool is_fb_cmd,
- const void *msg_out, size_t msg_out_sz,
- void *msg_in, size_t msg_in_sz,
- const void *ext, size_t ext_sz)
-{
- struct ab_task *t;
- struct mbox_priv *pd;
- struct anybus_mbox_hdr *h;
- size_t msg_sz = max(msg_in_sz, msg_out_sz);
- u16 info;
- int err;
-
- if (msg_sz > MAX_MBOX_MSG_SZ)
- return -EINVAL;
- if (ext && ext_sz > sizeof(h->extended))
- return -EINVAL;
- t = ab_task_create_get(cd->qcache, task_fn_mbox);
- if (!t)
- return -ENOMEM;
- pd = &t->mbox_pd;
- h = &pd->hdr;
- info = is_fb_cmd ? INFO_TYPE_FB : INFO_TYPE_APP;
- /*
- * prevent uninitialized memory in the header from being sent
- * across the anybus
- */
- memset(h, 0, sizeof(*h));
- h->info = cpu_to_be16(info | INFO_COMMAND);
- h->cmd_num = cpu_to_be16(cmd_num);
- h->data_size = cpu_to_be16(msg_out_sz);
- h->frame_count = cpu_to_be16(1);
- h->frame_num = cpu_to_be16(1);
- h->offset_high = cpu_to_be16(0);
- h->offset_low = cpu_to_be16(0);
- if (ext)
- memcpy(h->extended, ext, ext_sz);
- memcpy(pd->msg, msg_out, msg_out_sz);
- pd->msg_out_sz = msg_out_sz;
- pd->msg_in_sz = msg_in_sz;
- err = ab_task_enqueue_wait(t, cd->powerq, &cd->qlock, &cd->wq);
- if (err)
- goto out;
- /*
- * mailbox mechanism worked ok, but maybe the mbox response
- * contains an error ?
- */
- err = mbox_cmd_err(cd->dev, pd);
- if (err)
- goto out;
- memcpy(msg_in, pd->msg, msg_in_sz);
-out:
- ab_task_put(t);
- return err;
-}
-
-/* ------------------------ anybus queues ------------------------ */
-
-static void process_q(struct anybuss_host *cd, struct kfifo *q)
-{
- struct ab_task *t;
- int ret;
-
- ret = kfifo_out_peek(q, &t, sizeof(t));
- if (!ret)
- return;
- t->result = t->task_fn(cd, t);
- if (t->result != -EINPROGRESS)
- ab_task_dequeue_finish_put(q, cd);
-}
-
-static bool qs_have_work(struct kfifo *qs, size_t num)
-{
- size_t i;
- struct ab_task *t;
- int ret;
-
- for (i = 0; i < num; i++, qs++) {
- ret = kfifo_out_peek(qs, &t, sizeof(t));
- if (ret && (t->result != -EINPROGRESS))
- return true;
- }
- return false;
-}
-
-static void process_qs(struct anybuss_host *cd)
-{
- size_t i;
- struct kfifo *qs = cd->qs;
- size_t nqs = ARRAY_SIZE(cd->qs);
-
- for (i = 0; i < nqs; i++, qs++)
- process_q(cd, qs);
-}
-
-static void softint_ack(struct anybuss_host *cd)
-{
- unsigned int ind_ap;
-
- cd->softint_pending = false;
- if (!cd->power_on)
- return;
- regmap_read(cd->regmap, REG_IND_AP, &ind_ap);
- ind_ap &= ~IND_AX_EVNT;
- ind_ap |= atomic_read(&cd->ind_ab) & IND_AX_EVNT;
- write_ind_ap(cd->regmap, ind_ap);
-}
-
-static void process_softint(struct anybuss_host *cd)
-{
- struct anybuss_client *client = cd->client;
- static const u8 zero;
- int ret;
- unsigned int ind_ap, ev;
- struct ab_task *t;
-
- if (!cd->power_on)
- return;
- if (cd->softint_pending)
- return;
- regmap_read(cd->regmap, REG_IND_AP, &ind_ap);
- if (!((atomic_read(&cd->ind_ab) ^ ind_ap) & IND_AX_EVNT))
- return;
- /* process software interrupt */
- regmap_read(cd->regmap, REG_EVENT_CAUSE, &ev);
- if (ev & EVENT_CAUSE_FBON) {
- if (client->on_online_changed)
- client->on_online_changed(client, true);
- dev_dbg(cd->dev, "Fieldbus ON");
- }
- if (ev & EVENT_CAUSE_FBOF) {
- if (client->on_online_changed)
- client->on_online_changed(client, false);
- dev_dbg(cd->dev, "Fieldbus OFF");
- }
- if (ev & EVENT_CAUSE_DC) {
- if (client->on_area_updated)
- client->on_area_updated(client);
- dev_dbg(cd->dev, "Fieldbus data changed");
- }
- /*
- * reset the event cause bits.
- * this must be done while owning the fbctrl area, so we'll
- * enqueue a task to do that.
- */
- t = create_area_writer(cd->qcache, IND_AX_FBCTRL,
- REG_EVENT_CAUSE, &zero, sizeof(zero));
- if (!t) {
- ret = -ENOMEM;
- goto out;
- }
- t->done_fn = softint_ack;
- ret = ab_task_enqueue(t, cd->powerq, &cd->qlock, &cd->wq);
- ab_task_put(t);
- cd->softint_pending = true;
-out:
- WARN_ON(ret);
- if (ret)
- softint_ack(cd);
-}
-
-static int qthread_fn(void *data)
-{
- struct anybuss_host *cd = data;
- struct kfifo *qs = cd->qs;
- size_t nqs = ARRAY_SIZE(cd->qs);
- unsigned int ind_ab;
-
- /*
- * this kernel thread has exclusive access to the anybus's memory.
- * only exception: the IND_AB register, which is accessed exclusively
- * by the interrupt service routine (ISR). This thread must not touch
- * the IND_AB register, but it does require access to its value.
- *
- * the interrupt service routine stores the register's value in
- * cd->ind_ab (an atomic_t), where we may safely access it, with the
- * understanding that it can be modified by the ISR at any time.
- */
-
- while (!kthread_should_stop()) {
- /*
- * make a local copy of IND_AB, so we can go around the loop
- * again in case it changed while processing queues and softint.
- */
- ind_ab = atomic_read(&cd->ind_ab);
- process_qs(cd);
- process_softint(cd);
- wait_event_timeout(cd->wq,
- (atomic_read(&cd->ind_ab) != ind_ab) ||
- qs_have_work(qs, nqs) ||
- kthread_should_stop(),
- HZ);
- /*
- * time out so even 'stuck' tasks will run eventually,
- * and can time out.
- */
- }
-
- return 0;
-}
-
-/* ------------------------ anybus exports ------------------------ */
-
-int anybuss_start_init(struct anybuss_client *client,
- const struct anybuss_memcfg *cfg)
-{
- int ret;
- u16 op_mode;
- struct anybuss_host *cd = client->host;
- struct msg_anybus_init msg = {
- .input_io_len = cpu_to_be16(cfg->input_io),
- .input_dpram_len = cpu_to_be16(cfg->input_dpram),
- .input_total_len = cpu_to_be16(cfg->input_total),
- .output_io_len = cpu_to_be16(cfg->output_io),
- .output_dpram_len = cpu_to_be16(cfg->output_dpram),
- .output_total_len = cpu_to_be16(cfg->output_total),
- .notif_config = cpu_to_be16(0x000F),
- .wd_val = cpu_to_be16(0),
- };
-
- switch (cfg->offl_mode) {
- case FIELDBUS_DEV_OFFL_MODE_CLEAR:
- op_mode = 0;
- break;
- case FIELDBUS_DEV_OFFL_MODE_FREEZE:
- op_mode = OP_MODE_FBFC;
- break;
- case FIELDBUS_DEV_OFFL_MODE_SET:
- op_mode = OP_MODE_FBS;
- break;
- default:
- return -EINVAL;
- }
- msg.op_mode = cpu_to_be16(op_mode | OP_MODE_CD);
- ret = _anybus_mbox_cmd(cd, CMD_START_INIT, false, NULL, 0,
- NULL, 0, NULL, 0);
- if (ret)
- return ret;
- return _anybus_mbox_cmd(cd, CMD_ANYBUS_INIT, false,
- &msg, sizeof(msg), NULL, 0, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(anybuss_start_init);
-
-int anybuss_finish_init(struct anybuss_client *client)
-{
- struct anybuss_host *cd = client->host;
-
- return _anybus_mbox_cmd(cd, CMD_END_INIT, false, NULL, 0,
- NULL, 0, NULL, 0);
-}
-EXPORT_SYMBOL_GPL(anybuss_finish_init);
-
-int anybuss_read_fbctrl(struct anybuss_client *client, u16 addr,
- void *buf, size_t count)
-{
- struct anybuss_host *cd = client->host;
- struct ab_task *t;
- int ret;
-
- if (count == 0)
- return 0;
- if (!area_range_ok(addr, count, FBCTRL_AREA,
- MAX_FBCTRL_AREA_SZ))
- return -EFAULT;
- t = create_area_reader(cd->qcache, IND_AX_FBCTRL, addr, count);
- if (!t)
- return -ENOMEM;
- ret = ab_task_enqueue_wait(t, cd->powerq, &cd->qlock, &cd->wq);
- if (ret)
- goto out;
- memcpy(buf, t->area_pd.buf, count);
-out:
- ab_task_put(t);
- return ret;
-}
-EXPORT_SYMBOL_GPL(anybuss_read_fbctrl);
-
-int anybuss_write_input(struct anybuss_client *client,
- const char __user *buf, size_t size,
- loff_t *offset)
-{
- ssize_t len = min_t(loff_t, MAX_DATA_AREA_SZ - *offset, size);
- struct anybuss_host *cd = client->host;
- struct ab_task *t;
- int ret;
-
- if (len <= 0)
- return 0;
- t = create_area_user_writer(cd->qcache, IND_AX_IN,
- DATA_IN_AREA + *offset, buf, len);
- if (IS_ERR(t))
- return PTR_ERR(t);
- ret = ab_task_enqueue_wait(t, cd->powerq, &cd->qlock, &cd->wq);
- ab_task_put(t);
- if (ret)
- return ret;
- /* success */
- *offset += len;
- return len;
-}
-EXPORT_SYMBOL_GPL(anybuss_write_input);
-
-int anybuss_read_output(struct anybuss_client *client,
- char __user *buf, size_t size,
- loff_t *offset)
-{
- ssize_t len = min_t(loff_t, MAX_DATA_AREA_SZ - *offset, size);
- struct anybuss_host *cd = client->host;
- struct ab_task *t;
- int ret;
-
- if (len <= 0)
- return 0;
- t = create_area_reader(cd->qcache, IND_AX_OUT,
- DATA_OUT_AREA + *offset, len);
- if (!t)
- return -ENOMEM;
- ret = ab_task_enqueue_wait(t, cd->powerq, &cd->qlock, &cd->wq);
- if (ret)
- goto out;
- if (copy_to_user(buf, t->area_pd.buf, len))
- ret = -EFAULT;
-out:
- ab_task_put(t);
- if (ret)
- return ret;
- /* success */
- *offset += len;
- return len;
-}
-EXPORT_SYMBOL_GPL(anybuss_read_output);
-
-int anybuss_send_msg(struct anybuss_client *client, u16 cmd_num,
- const void *buf, size_t count)
-{
- struct anybuss_host *cd = client->host;
-
- return _anybus_mbox_cmd(cd, cmd_num, true, buf, count, NULL, 0,
- NULL, 0);
-}
-EXPORT_SYMBOL_GPL(anybuss_send_msg);
-
-int anybuss_send_ext(struct anybuss_client *client, u16 cmd_num,
- const void *buf, size_t count)
-{
- struct anybuss_host *cd = client->host;
-
- return _anybus_mbox_cmd(cd, cmd_num, true, NULL, 0, NULL, 0,
- buf, count);
-}
-EXPORT_SYMBOL_GPL(anybuss_send_ext);
-
-int anybuss_recv_msg(struct anybuss_client *client, u16 cmd_num,
- void *buf, size_t count)
-{
- struct anybuss_host *cd = client->host;
-
- return _anybus_mbox_cmd(cd, cmd_num, true, NULL, 0, buf, count,
- NULL, 0);
-}
-EXPORT_SYMBOL_GPL(anybuss_recv_msg);
-
-/* ------------------------ bus functions ------------------------ */
-
-static int anybus_bus_match(struct device *dev,
- const struct device_driver *drv)
-{
- const struct anybuss_client_driver *adrv =
- to_anybuss_client_driver(drv);
- struct anybuss_client *adev =
- to_anybuss_client(dev);
-
- return adrv->anybus_id == be16_to_cpu(adev->anybus_id);
-}
-
-static int anybus_bus_probe(struct device *dev)
-{
- struct anybuss_client_driver *adrv =
- to_anybuss_client_driver(dev->driver);
- struct anybuss_client *adev =
- to_anybuss_client(dev);
-
- return adrv->probe(adev);
-}
-
-static void anybus_bus_remove(struct device *dev)
-{
- struct anybuss_client_driver *adrv =
- to_anybuss_client_driver(dev->driver);
-
- if (adrv->remove)
- adrv->remove(to_anybuss_client(dev));
-}
-
-static const struct bus_type anybus_bus = {
- .name = "anybuss",
- .match = anybus_bus_match,
- .probe = anybus_bus_probe,
- .remove = anybus_bus_remove,
-};
-
-int anybuss_client_driver_register(struct anybuss_client_driver *drv)
-{
- if (!drv->probe)
- return -ENODEV;
-
- drv->driver.bus = &anybus_bus;
- return driver_register(&drv->driver);
-}
-EXPORT_SYMBOL_GPL(anybuss_client_driver_register);
-
-void anybuss_client_driver_unregister(struct anybuss_client_driver *drv)
-{
- return driver_unregister(&drv->driver);
-}
-EXPORT_SYMBOL_GPL(anybuss_client_driver_unregister);
-
-static void client_device_release(struct device *dev)
-{
- kfree(to_anybuss_client(dev));
-}
-
-static int taskq_alloc(struct device *dev, struct kfifo *q)
-{
- void *buf;
- size_t size = 64 * sizeof(struct ab_task *);
-
- buf = devm_kzalloc(dev, size, GFP_KERNEL);
- if (!buf)
- return -EIO;
- return kfifo_init(q, buf, size);
-}
-
-static int anybus_of_get_host_idx(struct device_node *np)
-{
- const __be32 *host_idx;
-
- host_idx = of_get_address(np, 0, NULL, NULL);
- if (!host_idx)
- return -ENOENT;
- return __be32_to_cpu(*host_idx);
-}
-
-static struct device_node *
-anybus_of_find_child_device(struct device *dev, int host_idx)
-{
- struct device_node *node;
-
- if (!dev || !dev->of_node)
- return NULL;
- for_each_child_of_node(dev->of_node, node) {
- if (anybus_of_get_host_idx(node) == host_idx)
- return node;
- }
- return NULL;
-}
-
-struct anybuss_host * __must_check
-anybuss_host_common_probe(struct device *dev,
- const struct anybuss_ops *ops)
-{
- int ret, i;
- u8 val[4];
- __be16 fieldbus_type;
- struct anybuss_host *cd;
-
- cd = devm_kzalloc(dev, sizeof(*cd), GFP_KERNEL);
- if (!cd)
- return ERR_PTR(-ENOMEM);
- cd->dev = dev;
- cd->host_idx = ops->host_idx;
- init_completion(&cd->card_boot);
- init_waitqueue_head(&cd->wq);
- for (i = 0; i < ARRAY_SIZE(cd->qs); i++) {
- ret = taskq_alloc(dev, &cd->qs[i]);
- if (ret)
- return ERR_PTR(ret);
- }
- if (WARN_ON(ARRAY_SIZE(cd->qs) < 3))
- return ERR_PTR(-EINVAL);
- cd->powerq = &cd->qs[0];
- cd->mboxq = &cd->qs[1];
- cd->areaq = &cd->qs[2];
- cd->reset = ops->reset;
- if (!cd->reset)
- return ERR_PTR(-EINVAL);
- cd->regmap = ops->regmap;
- if (!cd->regmap)
- return ERR_PTR(-EINVAL);
- spin_lock_init(&cd->qlock);
- cd->qcache = kmem_cache_create(dev_name(dev),
- sizeof(struct ab_task), 0, 0, NULL);
- if (!cd->qcache)
- return ERR_PTR(-ENOMEM);
- cd->irq = ops->irq;
- if (cd->irq <= 0) {
- ret = -EINVAL;
- goto err_qcache;
- }
- /*
- * use a dpram test to check if a card is present, this is only
- * possible while in reset.
- */
- reset_assert(cd);
- if (test_dpram(cd->regmap)) {
- dev_err(dev, "no Anybus-S card in slot");
- ret = -ENODEV;
- goto err_qcache;
- }
- ret = devm_request_threaded_irq(dev, cd->irq, NULL, irq_handler,
- IRQF_ONESHOT, dev_name(dev), cd);
- if (ret) {
- dev_err(dev, "could not request irq");
- goto err_qcache;
- }
- /*
- * startup sequence:
- * a) perform dummy IND_AB read to prevent false 'init done' irq
- * (already done by test_dpram() above)
- * b) release reset
- * c) wait for first interrupt
- * d) interrupt came in: ready to go !
- */
- reset_deassert(cd);
- if (!wait_for_completion_timeout(&cd->card_boot, TIMEOUT)) {
- ret = -ETIMEDOUT;
- goto err_reset;
- }
- /*
- * according to the anybus docs, we're allowed to read these
- * without handshaking / reserving the area
- */
- dev_info(dev, "Anybus-S card detected");
- regmap_bulk_read(cd->regmap, REG_BOOTLOADER_V, val, 2);
- dev_info(dev, "Bootloader version: %02X%02X",
- val[0], val[1]);
- regmap_bulk_read(cd->regmap, REG_API_V, val, 2);
- dev_info(dev, "API version: %02X%02X", val[0], val[1]);
- regmap_bulk_read(cd->regmap, REG_FIELDBUS_V, val, 2);
- dev_info(dev, "Fieldbus version: %02X%02X", val[0], val[1]);
- regmap_bulk_read(cd->regmap, REG_SERIAL_NO, val, 4);
- dev_info(dev, "Serial number: %02X%02X%02X%02X",
- val[0], val[1], val[2], val[3]);
- add_device_randomness(&val, 4);
- regmap_bulk_read(cd->regmap, REG_FIELDBUS_TYPE, &fieldbus_type,
- sizeof(fieldbus_type));
- dev_info(dev, "Fieldbus type: %04X", be16_to_cpu(fieldbus_type));
- regmap_bulk_read(cd->regmap, REG_MODULE_SW_V, val, 2);
- dev_info(dev, "Module SW version: %02X%02X",
- val[0], val[1]);
- /* put card back reset until a client driver releases it */
- disable_irq(cd->irq);
- reset_assert(cd);
- atomic_set(&cd->ind_ab, IND_AB_UPDATED);
- /* fire up the queue thread */
- cd->qthread = kthread_run(qthread_fn, cd, dev_name(dev));
- if (IS_ERR(cd->qthread)) {
- dev_err(dev, "could not create kthread");
- ret = PTR_ERR(cd->qthread);
- goto err_reset;
- }
- /*
- * now advertise that we've detected a client device (card).
- * the bus infrastructure will match it to a client driver.
- */
- cd->client = kzalloc(sizeof(*cd->client), GFP_KERNEL);
- if (!cd->client) {
- ret = -ENOMEM;
- goto err_kthread;
- }
- cd->client->anybus_id = fieldbus_type;
- cd->client->host = cd;
- cd->client->dev.bus = &anybus_bus;
- cd->client->dev.parent = dev;
- cd->client->dev.release = client_device_release;
- cd->client->dev.of_node =
- anybus_of_find_child_device(dev, cd->host_idx);
- dev_set_name(&cd->client->dev, "anybuss.card%d", cd->host_idx);
- ret = device_register(&cd->client->dev);
- if (ret)
- goto err_device;
- return cd;
-err_device:
- put_device(&cd->client->dev);
-err_kthread:
- kthread_stop(cd->qthread);
-err_reset:
- reset_assert(cd);
-err_qcache:
- kmem_cache_destroy(cd->qcache);
- return ERR_PTR(ret);
-}
-EXPORT_SYMBOL_GPL(anybuss_host_common_probe);
-
-void anybuss_host_common_remove(struct anybuss_host *host)
-{
- struct anybuss_host *cd = host;
-
- device_unregister(&cd->client->dev);
- kthread_stop(cd->qthread);
- reset_assert(cd);
- kmem_cache_destroy(cd->qcache);
-}
-EXPORT_SYMBOL_GPL(anybuss_host_common_remove);
-
-static void host_release(void *res)
-{
- anybuss_host_common_remove(res);
-}
-
-struct anybuss_host * __must_check
-devm_anybuss_host_common_probe(struct device *dev,
- const struct anybuss_ops *ops)
-{
- struct anybuss_host *host;
- int ret;
-
- host = anybuss_host_common_probe(dev, ops);
- if (IS_ERR(host))
- return host;
-
- ret = devm_add_action_or_reset(dev, host_release, host);
- if (ret)
- return ERR_PTR(ret);
-
- return host;
-}
-EXPORT_SYMBOL_GPL(devm_anybuss_host_common_probe);
-
-static int __init anybus_init(void)
-{
- int ret;
-
- ret = bus_register(&anybus_bus);
- if (ret)
- pr_err("could not register Anybus-S bus: %d\n", ret);
- return ret;
-}
-module_init(anybus_init);
-
-static void __exit anybus_exit(void)
-{
- bus_unregister(&anybus_bus);
-}
-module_exit(anybus_exit);
-
-MODULE_DESCRIPTION("HMS Anybus-S Host Driver");
-MODULE_AUTHOR("Sven Van Asbroeck <TheSven73@gmail.com>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/fieldbus/dev_core.c b/drivers/staging/fieldbus/dev_core.c
deleted file mode 100644
index 0053ebd91442..000000000000
--- a/drivers/staging/fieldbus/dev_core.c
+++ /dev/null
@@ -1,344 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Fieldbus Device Driver Core
- *
- */
-
-#include <linux/mutex.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/idr.h>
-#include <linux/fs.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
-
-/* move to <linux/fieldbus_dev.h> when taking this out of staging */
-#include "fieldbus_dev.h"
-
-/* Maximum number of fieldbus devices */
-#define MAX_FIELDBUSES 32
-
-/* the dev_t structure to store the dynamically allocated fieldbus devices */
-static dev_t fieldbus_devt;
-static DEFINE_IDA(fieldbus_ida);
-static DEFINE_MUTEX(fieldbus_mtx);
-
-static ssize_t online_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct fieldbus_dev *fb = dev_get_drvdata(dev);
-
- return sysfs_emit(buf, "%d\n", !!fb->online);
-}
-static DEVICE_ATTR_RO(online);
-
-static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct fieldbus_dev *fb = dev_get_drvdata(dev);
-
- if (!fb->enable_get)
- return -EINVAL;
- return sysfs_emit(buf, "%d\n", !!fb->enable_get(fb));
-}
-
-static ssize_t enabled_store(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t n)
-{
- struct fieldbus_dev *fb = dev_get_drvdata(dev);
- bool value;
- int ret;
-
- if (!fb->simple_enable_set)
- return -ENOTSUPP;
- ret = kstrtobool(buf, &value);
- if (ret)
- return ret;
- ret = fb->simple_enable_set(fb, value);
- if (ret < 0)
- return ret;
- return n;
-}
-static DEVICE_ATTR_RW(enabled);
-
-static ssize_t card_name_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct fieldbus_dev *fb = dev_get_drvdata(dev);
-
- /* card_name was provided by child driver. */
- return sysfs_emit(buf, "%s\n", fb->card_name);
-}
-static DEVICE_ATTR_RO(card_name);
-
-static ssize_t read_area_size_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct fieldbus_dev *fb = dev_get_drvdata(dev);
-
- return sysfs_emit(buf, "%zu\n", fb->read_area_sz);
-}
-static DEVICE_ATTR_RO(read_area_size);
-
-static ssize_t write_area_size_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct fieldbus_dev *fb = dev_get_drvdata(dev);
-
- return sysfs_emit(buf, "%zu\n", fb->write_area_sz);
-}
-static DEVICE_ATTR_RO(write_area_size);
-
-static ssize_t fieldbus_id_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct fieldbus_dev *fb = dev_get_drvdata(dev);
-
- return fb->fieldbus_id_get(fb, buf, PAGE_SIZE);
-}
-static DEVICE_ATTR_RO(fieldbus_id);
-
-static ssize_t fieldbus_type_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct fieldbus_dev *fb = dev_get_drvdata(dev);
- const char *t;
-
- switch (fb->fieldbus_type) {
- case FIELDBUS_DEV_TYPE_PROFINET:
- t = "profinet";
- break;
- default:
- t = "unknown";
- break;
- }
-
- return sysfs_emit(buf, "%s\n", t);
-}
-static DEVICE_ATTR_RO(fieldbus_type);
-
-static struct attribute *fieldbus_attrs[] = {
- &dev_attr_enabled.attr,
- &dev_attr_card_name.attr,
- &dev_attr_fieldbus_id.attr,
- &dev_attr_read_area_size.attr,
- &dev_attr_write_area_size.attr,
- &dev_attr_online.attr,
- &dev_attr_fieldbus_type.attr,
- NULL,
-};
-
-static umode_t fieldbus_is_visible(struct kobject *kobj, struct attribute *attr,
- int n)
-{
- struct device *dev = kobj_to_dev(kobj);
- struct fieldbus_dev *fb = dev_get_drvdata(dev);
- umode_t mode = attr->mode;
-
- if (attr == &dev_attr_enabled.attr) {
- mode = 0;
- if (fb->enable_get)
- mode |= 0444;
- if (fb->simple_enable_set)
- mode |= 0200;
- }
-
- return mode;
-}
-
-static const struct attribute_group fieldbus_group = {
- .attrs = fieldbus_attrs,
- .is_visible = fieldbus_is_visible,
-};
-__ATTRIBUTE_GROUPS(fieldbus);
-
-static const struct class fieldbus_class = {
- .name = "fieldbus_dev",
- .dev_groups = fieldbus_groups,
-};
-
-struct fb_open_file {
- struct fieldbus_dev *fbdev;
- int dc_event;
-};
-
-static int fieldbus_open(struct inode *inode, struct file *filp)
-{
- struct fb_open_file *of;
- struct fieldbus_dev *fbdev = container_of(inode->i_cdev,
- struct fieldbus_dev,
- cdev);
-
- of = kzalloc(sizeof(*of), GFP_KERNEL);
- if (!of)
- return -ENOMEM;
- of->fbdev = fbdev;
- filp->private_data = of;
- return 0;
-}
-
-static int fieldbus_release(struct inode *node, struct file *filp)
-{
- struct fb_open_file *of = filp->private_data;
-
- kfree(of);
- return 0;
-}
-
-static ssize_t fieldbus_read(struct file *filp, char __user *buf, size_t size,
- loff_t *offset)
-{
- struct fb_open_file *of = filp->private_data;
- struct fieldbus_dev *fbdev = of->fbdev;
-
- of->dc_event = fbdev->dc_event;
- return fbdev->read_area(fbdev, buf, size, offset);
-}
-
-static ssize_t fieldbus_write(struct file *filp, const char __user *buf,
- size_t size, loff_t *offset)
-{
- struct fb_open_file *of = filp->private_data;
- struct fieldbus_dev *fbdev = of->fbdev;
-
- return fbdev->write_area(fbdev, buf, size, offset);
-}
-
-static __poll_t fieldbus_poll(struct file *filp, poll_table *wait)
-{
- struct fb_open_file *of = filp->private_data;
- struct fieldbus_dev *fbdev = of->fbdev;
- __poll_t mask = EPOLLIN | EPOLLRDNORM | EPOLLOUT | EPOLLWRNORM;
-
- poll_wait(filp, &fbdev->dc_wq, wait);
- /* data changed ? */
- if (fbdev->dc_event != of->dc_event)
- mask |= EPOLLPRI | EPOLLERR;
- return mask;
-}
-
-static const struct file_operations fieldbus_fops = {
- .open = fieldbus_open,
- .release = fieldbus_release,
- .read = fieldbus_read,
- .write = fieldbus_write,
- .poll = fieldbus_poll,
- .llseek = generic_file_llseek,
- .owner = THIS_MODULE,
-};
-
-void fieldbus_dev_area_updated(struct fieldbus_dev *fb)
-{
- fb->dc_event++;
- wake_up_all(&fb->dc_wq);
-}
-EXPORT_SYMBOL_GPL(fieldbus_dev_area_updated);
-
-void fieldbus_dev_online_changed(struct fieldbus_dev *fb, bool online)
-{
- fb->online = online;
- kobject_uevent(&fb->dev->kobj, KOBJ_CHANGE);
-}
-EXPORT_SYMBOL_GPL(fieldbus_dev_online_changed);
-
-static void __fieldbus_dev_unregister(struct fieldbus_dev *fb)
-{
- if (!fb)
- return;
- device_destroy(&fieldbus_class, fb->cdev.dev);
- cdev_del(&fb->cdev);
- ida_free(&fieldbus_ida, fb->id);
-}
-
-void fieldbus_dev_unregister(struct fieldbus_dev *fb)
-{
- mutex_lock(&fieldbus_mtx);
- __fieldbus_dev_unregister(fb);
- mutex_unlock(&fieldbus_mtx);
-}
-EXPORT_SYMBOL_GPL(fieldbus_dev_unregister);
-
-static int __fieldbus_dev_register(struct fieldbus_dev *fb)
-{
- dev_t devno;
- int err;
-
- if (!fb)
- return -EINVAL;
- if (!fb->read_area || !fb->write_area || !fb->fieldbus_id_get)
- return -EINVAL;
- fb->id = ida_alloc_max(&fieldbus_ida, MAX_FIELDBUSES - 1, GFP_KERNEL);
- if (fb->id < 0)
- return fb->id;
- devno = MKDEV(MAJOR(fieldbus_devt), fb->id);
- init_waitqueue_head(&fb->dc_wq);
- cdev_init(&fb->cdev, &fieldbus_fops);
- err = cdev_add(&fb->cdev, devno, 1);
- if (err) {
- pr_err("fieldbus_dev%d unable to add device %d:%d\n",
- fb->id, MAJOR(fieldbus_devt), fb->id);
- goto err_cdev;
- }
- fb->dev = device_create(&fieldbus_class, fb->parent, devno, fb,
- "fieldbus_dev%d", fb->id);
- if (IS_ERR(fb->dev)) {
- err = PTR_ERR(fb->dev);
- goto err_dev_create;
- }
- return 0;
-
-err_dev_create:
- cdev_del(&fb->cdev);
-err_cdev:
- ida_free(&fieldbus_ida, fb->id);
- return err;
-}
-
-int fieldbus_dev_register(struct fieldbus_dev *fb)
-{
- int err;
-
- mutex_lock(&fieldbus_mtx);
- err = __fieldbus_dev_register(fb);
- mutex_unlock(&fieldbus_mtx);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(fieldbus_dev_register);
-
-static int __init fieldbus_init(void)
-{
- int err;
-
- err = class_register(&fieldbus_class);
- if (err < 0) {
- pr_err("fieldbus_dev: could not register class\n");
- return err;
- }
- err = alloc_chrdev_region(&fieldbus_devt, 0,
- MAX_FIELDBUSES, "fieldbus_dev");
- if (err < 0) {
- pr_err("fieldbus_dev: unable to allocate char dev region\n");
- goto err_alloc;
- }
- return 0;
-
-err_alloc:
- class_unregister(&fieldbus_class);
- return err;
-}
-
-static void __exit fieldbus_exit(void)
-{
- unregister_chrdev_region(fieldbus_devt, MAX_FIELDBUSES);
- class_unregister(&fieldbus_class);
- ida_destroy(&fieldbus_ida);
-}
-
-subsys_initcall(fieldbus_init);
-module_exit(fieldbus_exit);
-
-MODULE_AUTHOR("Sven Van Asbroeck <TheSven73@gmail.com>");
-MODULE_AUTHOR("Jonathan Stiles <jonathans@arcx.com>");
-MODULE_DESCRIPTION("Fieldbus Device Driver Core");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/fieldbus/fieldbus_dev.h b/drivers/staging/fieldbus/fieldbus_dev.h
deleted file mode 100644
index 301dca3b8d71..000000000000
--- a/drivers/staging/fieldbus/fieldbus_dev.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Fieldbus Device Driver Core
- *
- */
-
-#ifndef __FIELDBUS_DEV_H
-#define __FIELDBUS_DEV_H
-
-#include <linux/cdev.h>
-#include <linux/wait.h>
-
-enum fieldbus_dev_type {
- FIELDBUS_DEV_TYPE_UNKNOWN = 0,
- FIELDBUS_DEV_TYPE_PROFINET,
-};
-
-enum fieldbus_dev_offl_mode {
- FIELDBUS_DEV_OFFL_MODE_CLEAR = 0,
- FIELDBUS_DEV_OFFL_MODE_FREEZE,
- FIELDBUS_DEV_OFFL_MODE_SET
-};
-
-/**
- * struct fieldbus_dev - Fieldbus device
- * @read_area: [DRIVER] function to read the process data area of the
- * device. same parameters/return values as
- * the read function in struct file_operations
- * @write_area: [DRIVER] function to write to the process data area of
- * the device. same parameters/return values as
- * the write function in struct file_operations
- * @write_area_sz [DRIVER] size of the writable process data area
- * @read_area_sz [DRIVER] size of the readable process data area
- * @card_name [DRIVER] name of the card, e.g. "ACME Inc. profinet"
- * @fieldbus_type [DRIVER] fieldbus type of this device, e.g.
- * FIELDBUS_DEV_TYPE_PROFINET
- * @enable_get [DRIVER] function which returns true if the card
- * is enabled, false otherwise
- * @fieldbus_id_get [DRIVER] function to retrieve the unique fieldbus id
- * by which this device can be identified;
- * return value follows the snprintf convention
- * @simple_enable_set [DRIVER] (optional) function to enable the device
- * according to its default settings
- * @parent [DRIVER] (optional) the device's parent device
- */
-struct fieldbus_dev {
- ssize_t (*read_area)(struct fieldbus_dev *fbdev, char __user *buf,
- size_t size, loff_t *offset);
- ssize_t (*write_area)(struct fieldbus_dev *fbdev,
- const char __user *buf, size_t size,
- loff_t *offset);
- size_t write_area_sz, read_area_sz;
- const char *card_name;
- enum fieldbus_dev_type fieldbus_type;
- bool (*enable_get)(struct fieldbus_dev *fbdev);
- int (*fieldbus_id_get)(struct fieldbus_dev *fbdev, char *buf,
- size_t max_size);
- int (*simple_enable_set)(struct fieldbus_dev *fbdev, bool enable);
- struct device *parent;
-
- /* private data */
- int id;
- struct cdev cdev;
- struct device *dev;
- int dc_event;
- wait_queue_head_t dc_wq;
- bool online;
-};
-
-#if IS_ENABLED(CONFIG_FIELDBUS_DEV)
-
-/**
- * fieldbus_dev_unregister()
- * - unregister a previously registered fieldbus device
- * @fb: Device structure previously registered
- **/
-void fieldbus_dev_unregister(struct fieldbus_dev *fb);
-
-/**
- * fieldbus_dev_register()
- * - register a device with the fieldbus device subsystem
- * @fb: Device structure filled by the device driver
- **/
-int __must_check fieldbus_dev_register(struct fieldbus_dev *fb);
-
-/**
- * fieldbus_dev_area_updated()
- * - notify the subsystem that an external fieldbus controller updated
- * the process data area
- * @fb: Device structure
- **/
-void fieldbus_dev_area_updated(struct fieldbus_dev *fb);
-
-/**
- * fieldbus_dev_online_changed()
- * - notify the subsystem that the fieldbus online status changed
- * @fb: Device structure
- **/
-void fieldbus_dev_online_changed(struct fieldbus_dev *fb, bool online);
-
-#else /* IS_ENABLED(CONFIG_FIELDBUS_DEV) */
-
-static inline void fieldbus_dev_unregister(struct fieldbus_dev *fb) {}
-static inline int __must_check fieldbus_dev_register(struct fieldbus_dev *fb)
-{
- return -ENOTSUPP;
-}
-
-static inline void fieldbus_dev_area_updated(struct fieldbus_dev *fb) {}
-static inline void fieldbus_dev_online_changed(struct fieldbus_dev *fb,
- bool online) {}
-
-#endif /* IS_ENABLED(CONFIG_FIELDBUS_DEV) */
-#endif /* __FIELDBUS_DEV_H */