You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
siox: new driver framework for eckelmann SIOX
SIOX is a bus system invented at Eckelmann AG to control their building
management and refrigeration systems. Traditionally the bus was
implemented on custom microcontrollers, today Linux based machines are
in use, too.
The topology on a SIOX bus looks as follows:
,------->--DCLK-->---------------+----------------------.
^ v v
,--------. ,----------------------. ,------
| | | ,--------------. | |
| |--->--DOUT-->---|->-|shift register|->-|--->---|
| | | `--------------' | |
| master | | device | | device
| | | ,--------------. | |
| |---<--DIN---<---|-<-|shift register|-<-|---<---|
| | | `--------------' | |
`--------' `----------------------' `------
v ^ ^
`----------DLD-------------------+----------------------'
There are two control lines (DCLK and DLD) driven from the bus master to
all devices in parallel and two daisy chained data lines, one for input
and one for output. DCLK is the clock to shift both chains by a single
bit. On an edge of DLD the devices latch both their input and output
shift registers.
This patch adds a framework for this bus type.
Acked-by: Gavin Schenk <g.schenk@eckelmann.de>
Signed-off-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
0ba002bc43
commit
bbecb07fa0
87
Documentation/ABI/testing/sysfs-bus-siox
Normal file
87
Documentation/ABI/testing/sysfs-bus-siox
Normal file
@@ -0,0 +1,87 @@
|
||||
What: /sys/bus/siox/devices/siox-X/active
|
||||
KernelVersion: 4.16
|
||||
Contact: Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
|
||||
Description:
|
||||
On reading represents the current state of the bus. If it
|
||||
contains a "0" the bus is stopped and connected devices are
|
||||
expected to not do anything because their watchdog triggered.
|
||||
When the file contains a "1" the bus is operated and periodically
|
||||
does a push-pull cycle to write and read data from the
|
||||
connected devices.
|
||||
When writing a "0" or "1" the bus moves to the described state.
|
||||
|
||||
What: /sys/bus/siox/devices/siox-X/device_add
|
||||
KernelVersion: 4.16
|
||||
Contact: Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
|
||||
Description:
|
||||
Write-only file. Write
|
||||
|
||||
<type> <inbytes> <outbytes> <statustype>
|
||||
|
||||
to add a new device dynamically. <type> is the name that is used to match
|
||||
to a driver (similar to the platform bus). <inbytes> and <outbytes> define
|
||||
the length of the input and output shift register in bytes respectively.
|
||||
<statustype> defines the 4 bit device type that is check to identify connection
|
||||
problems.
|
||||
The new device is added to the end of the existing chain.
|
||||
|
||||
What: /sys/bus/siox/devices/siox-X/device_remove
|
||||
KernelVersion: 4.16
|
||||
Contact: Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
|
||||
Description:
|
||||
Write-only file. A single write removes the last device in the siox chain.
|
||||
|
||||
What: /sys/bus/siox/devices/siox-X/poll_interval_ns
|
||||
KernelVersion: 4.16
|
||||
Contact: Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
|
||||
Description:
|
||||
Defines the interval between two poll cycles in nano seconds.
|
||||
Note this is rounded to jiffies on writing. On reading the current value
|
||||
is returned.
|
||||
|
||||
What: /sys/bus/siox/devices/siox-X-Y/connected
|
||||
KernelVersion: 4.16
|
||||
Contact: Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
|
||||
Description:
|
||||
Read-only value. "0" means the Yth device on siox bus X isn't "connected" i.e.
|
||||
communication with it is not ensured. "1" signals a working connection.
|
||||
|
||||
What: /sys/bus/siox/devices/siox-X-Y/inbytes
|
||||
KernelVersion: 4.16
|
||||
Contact: Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
|
||||
Description:
|
||||
Read-only value reporting the inbytes value provided to siox-X/device_add
|
||||
|
||||
What: /sys/bus/siox/devices/siox-X-Y/status_errors
|
||||
KernelVersion: 4.16
|
||||
Contact: Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
|
||||
Description:
|
||||
Counts the number of time intervals when the read status byte doesn't yield the
|
||||
expected value.
|
||||
|
||||
What: /sys/bus/siox/devices/siox-X-Y/type
|
||||
KernelVersion: 4.16
|
||||
Contact: Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
|
||||
Description:
|
||||
Read-only value reporting the type value provided to siox-X/device_add.
|
||||
|
||||
What: /sys/bus/siox/devices/siox-X-Y/watchdog
|
||||
KernelVersion: 4.16
|
||||
Contact: Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
|
||||
Description:
|
||||
Read-only value reporting if the watchdog of the siox device is
|
||||
active. "0" means the watchdog is not active and the device is expected to
|
||||
be operational. "1" means the watchdog keeps the device in reset.
|
||||
|
||||
What: /sys/bus/siox/devices/siox-X-Y/watchdog_errors
|
||||
KernelVersion: 4.16
|
||||
Contact: Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
|
||||
Description:
|
||||
Read-only value reporting the number to time intervals when the
|
||||
watchdog was active.
|
||||
|
||||
What: /sys/bus/siox/devices/siox-X-Y/outbytes
|
||||
KernelVersion: 4.16
|
||||
Contact: Gavin Schenk <g.schenk@eckelmann.de>, Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
|
||||
Description:
|
||||
Read-only value reporting the outbytes value provided to siox-X/device_add.
|
||||
@@ -211,4 +211,6 @@ source "drivers/mux/Kconfig"
|
||||
|
||||
source "drivers/opp/Kconfig"
|
||||
|
||||
source "drivers/siox/Kconfig"
|
||||
|
||||
endmenu
|
||||
|
||||
@@ -184,3 +184,4 @@ obj-$(CONFIG_FPGA) += fpga/
|
||||
obj-$(CONFIG_FSI) += fsi/
|
||||
obj-$(CONFIG_TEE) += tee/
|
||||
obj-$(CONFIG_MULTIPLEXER) += mux/
|
||||
obj-$(CONFIG_SIOX) += siox/
|
||||
|
||||
9
drivers/siox/Kconfig
Normal file
9
drivers/siox/Kconfig
Normal file
@@ -0,0 +1,9 @@
|
||||
menuconfig SIOX
|
||||
tristate "Eckelmann SIOX Support"
|
||||
help
|
||||
SIOX stands for Serial Input Output eXtension and is a synchronous
|
||||
bus system invented by Eckelmann AG. It is used in their control and
|
||||
remote monitoring systems for commercial and industrial refrigeration
|
||||
to drive additional I/O units.
|
||||
|
||||
Unless you know better, it is probably safe to say "no" here.
|
||||
1
drivers/siox/Makefile
Normal file
1
drivers/siox/Makefile
Normal file
@@ -0,0 +1 @@
|
||||
obj-$(CONFIG_SIOX) += siox-core.o
|
||||
922
drivers/siox/siox-core.c
Normal file
922
drivers/siox/siox-core.c
Normal file
File diff suppressed because it is too large
Load Diff
49
drivers/siox/siox.h
Normal file
49
drivers/siox/siox.h
Normal file
@@ -0,0 +1,49 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2015-2017 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/siox.h>
|
||||
|
||||
#define to_siox_master(_dev) container_of((_dev), struct siox_master, dev)
|
||||
struct siox_master {
|
||||
/* these fields should be initialized by the driver */
|
||||
int busno;
|
||||
int (*pushpull)(struct siox_master *smaster,
|
||||
size_t setbuf_len, const u8 setbuf[],
|
||||
size_t getbuf_len, u8 getbuf[]);
|
||||
|
||||
/* might be initialized by the driver, if 0 it is set to HZ / 40 */
|
||||
unsigned long poll_interval; /* in jiffies */
|
||||
|
||||
/* framework private stuff */
|
||||
struct mutex lock;
|
||||
bool active;
|
||||
struct module *owner;
|
||||
struct device dev;
|
||||
unsigned int num_devices;
|
||||
struct list_head devices;
|
||||
|
||||
size_t setbuf_len, getbuf_len;
|
||||
size_t buf_len;
|
||||
u8 *buf;
|
||||
u8 status;
|
||||
|
||||
unsigned long last_poll;
|
||||
struct task_struct *poll_thread;
|
||||
};
|
||||
|
||||
static inline void *siox_master_get_devdata(struct siox_master *smaster)
|
||||
{
|
||||
return dev_get_drvdata(&smaster->dev);
|
||||
}
|
||||
|
||||
struct siox_master *siox_master_alloc(struct device *dev, size_t size);
|
||||
static inline void siox_master_put(struct siox_master *smaster)
|
||||
{
|
||||
put_device(&smaster->dev);
|
||||
}
|
||||
|
||||
int siox_master_register(struct siox_master *smaster);
|
||||
void siox_master_unregister(struct siox_master *smaster);
|
||||
77
include/linux/siox.h
Normal file
77
include/linux/siox.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (C) 2015 Pengutronix, Uwe Kleine-König <kernel@pengutronix.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License version 2 as published by the
|
||||
* Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
|
||||
#define to_siox_device(_dev) container_of((_dev), struct siox_device, dev)
|
||||
struct siox_device {
|
||||
struct list_head node; /* node in smaster->devices */
|
||||
struct siox_master *smaster;
|
||||
struct device dev;
|
||||
|
||||
const char *type;
|
||||
size_t inbytes;
|
||||
size_t outbytes;
|
||||
u8 statustype;
|
||||
|
||||
u8 status_read_clean;
|
||||
u8 status_written;
|
||||
u8 status_written_lastcycle;
|
||||
bool connected;
|
||||
|
||||
/* statistics */
|
||||
unsigned int watchdog_errors;
|
||||
unsigned int status_errors;
|
||||
|
||||
struct kernfs_node *status_errors_kn;
|
||||
struct kernfs_node *watchdog_kn;
|
||||
struct kernfs_node *watchdog_errors_kn;
|
||||
struct kernfs_node *connected_kn;
|
||||
};
|
||||
|
||||
bool siox_device_synced(struct siox_device *sdevice);
|
||||
bool siox_device_connected(struct siox_device *sdevice);
|
||||
|
||||
struct siox_driver {
|
||||
int (*probe)(struct siox_device *sdevice);
|
||||
int (*remove)(struct siox_device *sdevice);
|
||||
void (*shutdown)(struct siox_device *sdevice);
|
||||
|
||||
/*
|
||||
* buf is big enough to hold sdev->inbytes - 1 bytes, the status byte
|
||||
* is in the scope of the framework.
|
||||
*/
|
||||
int (*set_data)(struct siox_device *sdevice, u8 status, u8 buf[]);
|
||||
/*
|
||||
* buf is big enough to hold sdev->outbytes - 1 bytes, the status byte
|
||||
* is in the scope of the framework
|
||||
*/
|
||||
int (*get_data)(struct siox_device *sdevice, const u8 buf[]);
|
||||
|
||||
struct device_driver driver;
|
||||
};
|
||||
|
||||
static inline struct siox_driver *to_siox_driver(struct device_driver *driver)
|
||||
{
|
||||
if (driver)
|
||||
return container_of(driver, struct siox_driver, driver);
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int __siox_driver_register(struct siox_driver *sdriver, struct module *owner);
|
||||
|
||||
static inline int siox_driver_register(struct siox_driver *sdriver)
|
||||
{
|
||||
return __siox_driver_register(sdriver, THIS_MODULE);
|
||||
}
|
||||
|
||||
static inline void siox_driver_unregister(struct siox_driver *sdriver)
|
||||
{
|
||||
return driver_unregister(&sdriver->driver);
|
||||
}
|
||||
Reference in New Issue
Block a user