From: Vincent Pelletier <plr.vincent@gmail.com>
To: linux-gpio@vger.kernel.org
Subject: [RFC] qnap-tsx51: add new driver for leds and button support on QNAP TS-x51 series
Date: Mon, 6 Jun 2016 00:44:06 +0000 [thread overview]
Message-ID: <20160606004406.29f016de@gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 7468 bytes --]
Hello,
(please keep me CC'ed in replies, I'm not getting a majordomo
subscription confirmation mail)
I own a QNAP TS-651 NAS enclosure (the 6-drives variant of the TS-x51
product family). It is a regular x86-64, and it can work with vanilla
kernel & generic distro as a replacement to vendor firmware.
ACPI tables do not declare GPIOs used to interface with the enclosure:
- two buttons for input
- one red led per disk slot (for failure events)
- USB activity led
- two-colours status led (for off/green/orange/red result)
I wrote the following platform driver, that I would like to contribute
to the kernel.
Could someone please review below patch ?
It is my first attempt at writing a module from scratch, so watch out
for naive mistakes.
I see drivers using GPIOs should use descriptors instead of gpio
number. I fail to see how I should convert this driver to use
descriptors. Or at least, I like a lot that this module has extremely
little actual code, as I would expect from something which essentially
does the same work as ACPI tables. Is it also achievable with
descriptors ?
About disk leds, there exist 2, 4, 6 and 8-drives versions of this
enclosure. I do not know how to detect which one the module is being
loaded on, so I declare all 8 leds, and userland should drive leds
which match detected drives.
For completeness, I attached udev configuration file (to have device
symlinks correctly mapping SCSI devices to slots - 6 drives version)
and "mdadm --monitor --program"-compatible led control shell script
(which depends on udev disk symlinks and led names being consistent).
Regards,
Vincent Pelletier
From 8c59f4f1c4f0c69b9168979fdf130b301b1be20b Mon Sep 17 00:00:00 2001
Message-Id: <8c59f4f1c4f0c69b9168979fdf130b301b1be20b.1465170970.git.plr.vincent@gmail.com>
From: Vincent Pelletier <plr.vincent@gmail.com>
Date: Mon, 17 Aug 2015 18:50:13 +0200
Subject: qnap-tsx51: add new driver for leds and button support on QNAP TS-x51
series
This adds QNAP TS-x51 driver. It exposes led and buttons present on this NAS
enclosure to userland for convenient access. Ideally, all this driver does
should be declared by ACPI, but even SuperIO GPIO pins are not.
Also, ideally this driver should check DMI strings, but OEM did not initialise
any.
Signed-off-by: Vincent Pelletier <plr.vincent@gmail.com>
---
drivers/platform/x86/Kconfig | 9 ++
drivers/platform/x86/Makefile | 1 +
drivers/platform/x86/qnap-tsx51.c | 168 ++++++++++++++++++++++++++++++++++++++
3 files changed, 178 insertions(+)
create mode 100644 drivers/platform/x86/qnap-tsx51.c
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index ed2004b..4da05bc 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -1001,4 +1001,13 @@ config INTEL_TELEMETRY
used to get various SoC events and parameters
directly via debugfs files. Various tools may use
this interface for SoC state monitoring.
+
+config QNAP_TSX51
+ tristate "QNAP TS-x51 NAS"
+ select LEDS_GPIO
+ select KEYBOARD_GPIO_POLLED
+ select GPIO_F7188X
+ ---help---
+ This driver provides support for QNAP TS-x51 NAS enclosure
+ leds (drive error, status, usb) and buttons.
endif # X86_PLATFORM_DEVICES
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
index 448443c..e03c507 100644
--- a/drivers/platform/x86/Makefile
+++ b/drivers/platform/x86/Makefile
@@ -69,3 +69,4 @@ obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o
obj-$(CONFIG_INTEL_TELEMETRY) += intel_telemetry_core.o \
intel_telemetry_pltdrv.o \
intel_telemetry_debugfs.o
+obj-$(CONFIG_QNAP_TSX51) += qnap-tsx51.o
diff --git a/drivers/platform/x86/qnap-tsx51.c b/drivers/platform/x86/qnap-tsx51.c
new file mode 100644
index 0000000..c6304b9
--- /dev/null
+++ b/drivers/platform/x86/qnap-tsx51.c
@@ -0,0 +1,168 @@
+/*
+ * Support for LEDs and buttons available on the QNAP TS-x51 NAS.
+ *
+ * Copyright (C) 2015 Vincent Pelletier <plr.vincent@gmail.com>
+ */
+
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+
+static void qnap_tsx51_device_pdev_release(struct device *dev);
+
+static struct gpio_led qnap_tsx51_led[] = {
+ {
+ .name = "qnap_tsx51:green:status",
+ .gpio = 62,
+ .active_low = 1,
+ .default_state = LEDS_GPIO_DEFSTATE_ON,
+ },
+ {
+ .name = "qnap_tsx51:red:status",
+ .gpio = 63,
+ .active_low = 1,
+ },
+ {
+ .name = "qnap_tsx51:blue:usb",
+ .default_trigger = "usb-host",
+ .gpio = 17,
+ .active_low = 1,
+ },
+ {
+ .name = "hdd1:red:sata",
+ .gpio = 70,
+ .active_low = 1,
+ },
+ {
+ .name = "hdd2:red:sata",
+ .gpio = 71,
+ .active_low = 1,
+ },
+ {
+ .name = "hdd3:red:sata",
+ .gpio = 72,
+ .active_low = 1,
+ },
+ {
+ .name = "hdd4:red:sata",
+ .gpio = 73,
+ .active_low = 1,
+ },
+ {
+ .name = "hdd5:red:sata",
+ .gpio = 74,
+ .active_low = 1,
+ },
+ {
+ .name = "hdd6:red:sata",
+ .gpio = 75,
+ .active_low = 1,
+ },
+ {
+ .name = "hdd7:red:sata",
+ .gpio = 76,
+ .active_low = 1,
+ },
+ {
+ .name = "hdd8:red:sata",
+ .gpio = 77,
+ .active_low = 1,
+ },
+};
+
+static struct gpio_led_platform_data qnap_tsx51_led_data = {
+ .num_leds = ARRAY_SIZE(qnap_tsx51_led),
+ .leds = qnap_tsx51_led,
+};
+
+static struct platform_device qnap_tsx51_leds_dev = {
+ .name = "leds-gpio",
+ .id = -1,
+ .dev = {
+ .release = qnap_tsx51_device_pdev_release,
+ .platform_data = &qnap_tsx51_led_data,
+ },
+};
+
+static struct gpio_keys_button qnap_tsx51_gpio_buttons[] = {
+ {
+ .code = KEY_COPY,
+ .gpio = 12,
+ .active_low = 1,
+ .desc = "Copy button",
+ .type = EV_KEY,
+ .wakeup = 0,
+ .debounce_interval = 100,
+ .can_disable = 0,
+ },
+ {
+ .code = KEY_RESTART,
+ .gpio = 61,
+ .active_low = 1,
+ .desc = "Reset button",
+ .type = EV_KEY,
+ .wakeup = 0,
+ .debounce_interval = 100,
+ .can_disable = 0,
+ },
+};
+
+static struct gpio_keys_platform_data qnap_tsx51_buttons_data = {
+ .buttons = qnap_tsx51_gpio_buttons,
+ .nbuttons = ARRAY_SIZE(qnap_tsx51_gpio_buttons),
+ .poll_interval = 20,
+};
+
+static struct platform_device qnap_tsx51_buttons_dev = {
+ .name = "gpio-keys-polled",
+ .id = -1,
+ .dev = {
+ .release = qnap_tsx51_device_pdev_release,
+ .platform_data = &qnap_tsx51_buttons_data,
+ },
+};
+
+static struct platform_device *qnap_tsx51_devs[] = {
+ &qnap_tsx51_buttons_dev,
+ &qnap_tsx51_leds_dev,
+};
+
+static void qnap_tsx51_device_pdev_release(struct device *dev)
+{
+/*
+ * Needed to silence this message:
+ * Device 'xxx' does not have a release() function, it is broken and must be
+ * fixed.
+ */
+}
+
+static int __init qnap_tsx51_init(void)
+{
+ int ret;
+
+ ret = request_module("gpio_f7188x");
+ if (ret)
+ return ret;
+
+ return platform_add_devices(
+ qnap_tsx51_devs,
+ ARRAY_SIZE(qnap_tsx51_devs)
+ );
+
+}
+
+static void __exit qnap_tsx51_exit(void)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(qnap_tsx51_devs); i++)
+ platform_device_unregister(qnap_tsx51_devs[i]);
+}
+
+module_init(qnap_tsx51_init);
+module_exit(qnap_tsx51_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("QNAP TS-x51 NAS");
+MODULE_AUTHOR("Vincent Pelletier <plr.vincent@gmail.com>");
--
2.8.1
[-- Attachment #2: hdd.rules --]
[-- Type: application/octet-stream, Size: 790 bytes --]
ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="sd?", KERNELS=="4:0:0:0", SYMLINK+="qnap/hdd1"
ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="sd?", KERNELS=="3:0:0:0", SYMLINK+="qnap/hdd2"
ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="sd?", KERNELS=="2:0:0:0", SYMLINK+="qnap/hdd3"
ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="sd?", KERNELS=="8:0:0:0", SYMLINK+="qnap/hdd4"
ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="sd?", KERNELS=="7:0:0:0", SYMLINK+="qnap/hdd5"
ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="sd?", KERNELS=="6:0:0:0", SYMLINK+="qnap/hdd6"
ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="sd?", KERNELS=="1-4", SYMLINK+="qnap/builtin_usb"
ACTION=="add|change", SUBSYSTEM=="block", KERNEL=="sd?", KERNELS=="2-1.3", SYMLINK+="qnap/front_usb"
[-- Attachment #3: mdadm2leds --]
[-- Type: application/octet-stream, Size: 3455 bytes --]
#!/bin/sh
MDEVENT="$1"
MDDEVICE="$2"
PHYSDEVICE="$3"
LED_PATH="/sys/class/leds"
LED_DISK_SUFFIX=":red:sata"
STATUS_PATH="/run/$(basename "$0")"
test -d "$STATUS_PATH" || mkdir "$STATUS_PATH"
update_led()
{
LED="${LED_PATH}/$1"
STATUS="${STATUS_PATH}/${1}:"
test -d "$LED" || return 1
if [ -e "${STATUS}locate" ]; then
TRIGGER="timer"
BRIGHTNESS=1
DELAY_ON=125
DELAY_OFF=125
elif [ -e "${STATUS}error" ]; then
TRIGGER="none"
BRIGHTNESS=1
elif [ -e "${STATUS}prefail" ]; then
# XXX: standard says "2 blinks at 4 Hz, 1 pause at 2 Hz" but led
# triggers cannot reproduct this, so instead go for 1Hz,
# 25% duty cycle.
TRIGGER="timer"
BRIGHTNESS=1
DELAY_ON=250
DELAY_OFF=750
elif [ -e "${STATUS}rebuild" ]; then
TRIGGER="timer"
BRIGHTNESS=1
DELAY_ON=500
DELAY_OFF=500
else
# All fine, turn led off
TRIGGER="none"
BRIGHTNESS=0
fi
echo "$TRIGGER" > "${LED}/trigger"
echo "$BRIGHTNESS" > "${LED}/brightness"
case "$TRIGGER" in
timer)
echo "$DELAY_ON" > "${LED}/delay_on"
echo "$DELAY_OFF" > "${LED}/delay_off"
;;
esac
}
set_led()
{
STATUS="${STATUS_PATH}/${1}:"
case "$2" in
fail)
touch "${STATUS}error"
;;
recovering)
touch "${STATUS}rebuild"
rm "${STATUS}error"
;;
recovered)
rm "${STATUS}rebuild"
;;
prefail)
touch "${STATUS}prefail"
;;
start_locate)
touch "${STATUS}locate"
;;
stop_locate)
rm "${STATUS}locate"
;;
forget)
rm "${STATUS}locate"
rm "${STATUS}error"
rm "${STATUS}prefail"
rm "${STATUS}rebuild"
;;
*)
return 1
;;
esac
update_led "$1"
}
disk_led()
{
DISK="$1"
shift
test -n "$DISK" || return 1
SYSPATH="/sys$(udevadm info --query=path "$DISK")"
test -e "$SYSPATH/partition" && SYSPATH="$(dirname "$SYSPATH")"
for SYMLINK in $(udevadm info --query=symlink "$SYSPATH"); do
if echo "$SYMLINK" | grep -q "^qnap/"; then
set_led "$(echo "$SYMLINK" | sed "s@^qnap/@@")$LED_DISK_SUFFIX" "$@"
return $?
fi
done
return 1
}
array_led()
{
ARRAY="$1"
shift
for DEVICE in "/sys$(udevadm info --query=path "$ARRAY")/"slaves/*; do
disk_led "$DEVICE" "$@"
done
}
case "$MDEVENT" in
DegradedArray | SparesMissing)
array_led "$MDDEVICE" prefail
;;
Fail | FailSpare)
disk_led "$PHYSDEVICE" fail
;;
TestMessage)
if [ $# -eq 3 ]; then
trap "disk_led \"$PHYSDEVICE\" stop_locate" 0
disk_led "$PHYSDEVICE" start_locate
else
trap "array_led \"$MDDEVICE\" stop_locate" 0
array_led "$MDDEVICE" start_locate
fi
sleep 5
;;
RebuildStarted | Rebuild??)
array_led "$MDDEVICE" recovering
;;
RebuildFinished)
array_led "$MDDEVICE" recovered
;;
# Non-mdadm events
refresh)
for LED in "$LED_PATH/"hdd*"$LED_DISK_SUFFIX"; do
update_led "$(basename "$LED")"
done
;;
esac
next reply other threads:[~2016-06-06 0:44 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-06-06 0:44 Vincent Pelletier [this message]
2016-06-14 7:17 ` [RFC] qnap-tsx51: add new driver for leds and button support on QNAP TS-x51 series Linus Walleij
2016-06-15 0:45 ` Vincent Pelletier
2016-06-17 21:02 ` Linus Walleij
2016-06-18 7:18 ` Vincent Pelletier
2016-06-18 8:00 ` Linus Walleij
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20160606004406.29f016de@gmail.com \
--to=plr.vincent@gmail.com \
--cc=linux-gpio@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).