mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
Merge tag 'staging-6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging driver updates from Greg KH:
"Here is the big set of staging driver changes for 6.13-rc1.
Lots of changes this merge cycle, drivers removed and drivers added.
Highlights include:
- removals of the following staging drivers due to no forward
progress and no one having either the hardware or the time/energy
to deal with them anymore:
- fieldbus
- gdm724x
- olpc_dcon
- rtl8712
- rts5208
- vt6655
- vt6656
If anyone has this hardware and wants to work on the drivers, it
can be an easy revert to get them back.
- addition of the gpib driver subsystem. Lots of drivers for really
old and semi-old interfaces to lab equipments. We expect lots of
churn in these drivers as they get cleaned up to "working" order.
These were added at the request of a user and the maintainer/author
of them is helping out with the effort
- loads and loads of tiny coding style cleanups for almost all
staging drivers. Too many to list, see the shortlog for details.
All of these have been in linux-next for a very long time with no
reported issues"
* tag 'staging-6.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (216 commits)
Staging: gpib: gpib_os.c - Remove unnecessary OOM message
staging: gpib: avoid unintended sign extension
staging: vchiq_debugfs: Use forward declarations
staging: vchiq_core: Rectify header include for vchiq_dump_state()
staging: vc04_services: Cleanup TODO entry
staging: most: Remove TODO contact information
staging: rtl8723bs: Remove TODO contact information
staging: sm750fb: Remove TODO contact information
staging: iio: Remove TODO file
staging: greybus: uart: Fix atomicity violation in get_serial_info()
staging: rtl8723bs: Remove unused function Efuse_GetCurrentSize
staging: rtl8723bs: Remove unused function efuse_WordEnableDataRead
staging: rtl8723bs: Remove function hal_EfusePgPacketWrite1ByteHeader
staging: rtl8723bs: Remove function hal_EfusePgPacketWrite2ByteHeader
staging: rtl8723bs: Remove unused function hal_EfusePgCheckAvailableAddr
staging: rtl8723bs: Remove unused function hal_EfuseConstructPGPkt
staging: rtl8723bs: Remove unused function hal_EfusePartialWriteCheck
staging: rtl8723bs: Remove unused function hal_EfusePgPacketWriteHeader
staging: rtl8723bs: Remove unused function hal_EfusePgPacketWriteData
staging: rtl8723bs: Remove unused function Hal_EfusePgPacketWrite_BT
...
This commit is contained in:
+5
-28
@@ -9718,6 +9718,11 @@ L: platform-driver-x86@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/platform/x86/gpd-pocket-fan.c
|
||||
|
||||
GPIB DRIVERS
|
||||
M: Dave Penkler <dpenkler@gmail.com>
|
||||
S: Maintained
|
||||
F: drivers/staging/gpib/
|
||||
|
||||
GPIO ACPI SUPPORT
|
||||
M: Mika Westerberg <mika.westerberg@linux.intel.com>
|
||||
M: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
|
||||
@@ -22135,17 +22140,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
|
||||
@@ -22160,18 +22154,6 @@ L: linux-tegra@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/staging/nvec/
|
||||
|
||||
STAGING - OLPC SECONDARY DISPLAY CONTROLLER (DCON)
|
||||
M: Jens Frederich <jfrederich@gmail.com>
|
||||
M: Jon Nettleton <jon.nettleton@gmail.com>
|
||||
S: Maintained
|
||||
W: http://wiki.laptop.org/go/DCON
|
||||
F: drivers/staging/olpc_dcon/
|
||||
|
||||
STAGING - REALTEK RTL8712U DRIVERS
|
||||
M: Florian Schilhabel <florian.c.schilhabel@googlemail.com>.
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/rtl8712/
|
||||
|
||||
STAGING - SEPS525 LCD CONTROLLER DRIVERS
|
||||
M: Michael Hennerich <michael.hennerich@analog.com>
|
||||
L: linux-fbdev@vger.kernel.org
|
||||
@@ -22187,11 +22169,6 @@ L: linux-fbdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/staging/sm750fb/
|
||||
|
||||
STAGING - VIA VT665X DRIVERS
|
||||
M: Philipp Hortmann <philipp.g.hortmann@gmail.com>
|
||||
S: Odd Fixes
|
||||
F: drivers/staging/vt665?/
|
||||
|
||||
STAGING SUBSYSTEM
|
||||
M: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
|
||||
L: linux-staging@lists.linux.dev
|
||||
|
||||
+2
-14
@@ -24,20 +24,10 @@ menuconfig STAGING
|
||||
|
||||
if STAGING
|
||||
|
||||
source "drivers/staging/olpc_dcon/Kconfig"
|
||||
|
||||
source "drivers/staging/rtl8723bs/Kconfig"
|
||||
|
||||
source "drivers/staging/rtl8712/Kconfig"
|
||||
|
||||
source "drivers/staging/rts5208/Kconfig"
|
||||
|
||||
source "drivers/staging/octeon/Kconfig"
|
||||
|
||||
source "drivers/staging/vt6655/Kconfig"
|
||||
|
||||
source "drivers/staging/vt6656/Kconfig"
|
||||
|
||||
source "drivers/staging/iio/Kconfig"
|
||||
|
||||
source "drivers/staging/sm750fb/Kconfig"
|
||||
@@ -46,8 +36,6 @@ source "drivers/staging/nvec/Kconfig"
|
||||
|
||||
source "drivers/staging/media/Kconfig"
|
||||
|
||||
source "drivers/staging/gdm724x/Kconfig"
|
||||
|
||||
source "drivers/staging/fbtft/Kconfig"
|
||||
|
||||
source "drivers/staging/most/Kconfig"
|
||||
@@ -58,8 +46,8 @@ 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"
|
||||
|
||||
endif # STAGING
|
||||
|
||||
@@ -2,21 +2,15 @@
|
||||
# Makefile for staging directory
|
||||
|
||||
obj-y += media/
|
||||
obj-$(CONFIG_FB_OLPC_DCON) += olpc_dcon/
|
||||
obj-$(CONFIG_RTL8723BS) += rtl8723bs/
|
||||
obj-$(CONFIG_R8712U) += rtl8712/
|
||||
obj-$(CONFIG_RTS5208) += rts5208/
|
||||
obj-$(CONFIG_OCTEON_ETHERNET) += octeon/
|
||||
obj-$(CONFIG_VT6655) += vt6655/
|
||||
obj-$(CONFIG_VT6656) += vt6656/
|
||||
obj-$(CONFIG_VME_BUS) += vme_user/
|
||||
obj-$(CONFIG_IIO) += iio/
|
||||
obj-$(CONFIG_FB_SM750) += sm750fb/
|
||||
obj-$(CONFIG_MFD_NVEC) += nvec/
|
||||
obj-$(CONFIG_LTE_GDM724X) += gdm724x/
|
||||
obj-$(CONFIG_FB_TFT) += fbtft/
|
||||
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/
|
||||
|
||||
@@ -919,7 +919,7 @@ static struct platform_driver axis_fifo_driver = {
|
||||
.of_match_table = axis_fifo_of_match,
|
||||
},
|
||||
.probe = axis_fifo_probe,
|
||||
.remove_new = axis_fifo_remove,
|
||||
.remove = axis_fifo_remove,
|
||||
};
|
||||
|
||||
static int __init axis_fifo_init(void)
|
||||
|
||||
@@ -330,7 +330,7 @@ static struct platform_driver fbtft_driver_platform_driver = { \
|
||||
.of_match_table = dt_ids, \
|
||||
}, \
|
||||
.probe = fbtft_driver_probe_pdev, \
|
||||
.remove_new = fbtft_driver_remove_pdev, \
|
||||
.remove = fbtft_driver_remove_pdev, \
|
||||
}; \
|
||||
\
|
||||
static int __init fbtft_driver_module_init(void) \
|
||||
|
||||
@@ -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
|
||||
@@ -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).
|
||||
-71
@@ -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 */
|
||||
};
|
||||
};
|
||||
};
|
||||
@@ -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.
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
@@ -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>
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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__ */
|
||||
@@ -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__ */
|
||||
@@ -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_new = 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");
|
||||
@@ -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");
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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");
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user