Turris Omnia MCU driver
Subsystems (5)
Marek Behún
maintainerv4 cover Turris Omnia MCU driver
Hello Andy, Linus, Arnd, Gregory, and others,
I am sending v4 of the series adding Turris Omnia MCU driver. See the cover letters for v1, v2 and v3:
https://patchwork.kernel.org/project/linux-soc/cover/[email protected]/
https://patchwork.kernel.org/project/linux-soc/cover/[email protected]/
https://patchwork.kernel.org/project/linux-soc/cover/[email protected]/
Changes since v3:
- addressed Andy's suggestions for patches 3/7 and 4/7
Marek Behún (7):
dt-bindings: arm: add cznic,turris-omnia-mcu binding
platform: cznic: Add preliminary support for Turris Omnia MCU
platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs
platform: cznic: turris-omnia-mcu: Add support for poweroff and wakeup
platform: cznic: turris-omnia-mcu: Add support for MCU watchdog
ARM: dts: turris-omnia: Add MCU system-controller node
ARM: dts: turris-omnia: Add GPIO key node for front button
.../sysfs-bus-i2c-devices-turris-omnia-mcu | 77 ++ .../bindings/arm/cznic,turris-omnia-mcu.yaml | 67 ++ MAINTAINERS | 4 + .../dts/marvell/armada-385-turris-omnia.dts | 35 +- drivers/platform/Kconfig | 2 + drivers/platform/Makefile | 1 + drivers/platform/cznic/Kconfig | 47 + drivers/platform/cznic/Makefile | 7 + .../platform/cznic/turris-omnia-mcu-base.c | 271 +++++ .../platform/cznic/turris-omnia-mcu-gpio.c | 1018 +++++++++++++++++ .../cznic/turris-omnia-mcu-sys-off-wakeup.c | 257 +++++ .../cznic/turris-omnia-mcu-watchdog.c | 122 ++ drivers/platform/cznic/turris-omnia-mcu.h | 170 +++ include/linux/turris-omnia-mcu-interface.h | 194 ++++ 14 files changed, 2271 insertions(+), 1 deletion(-) create mode 100644 Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu create mode 100644 Documentation/devicetree/bindings/arm/cznic,turris-omnia-mcu.yaml create mode 100644 drivers/platform/cznic/Kconfig create mode 100644 drivers/platform/cznic/Makefile create mode 100644 drivers/platform/cznic/turris-omnia-mcu-base.c create mode 100644 drivers/platform/cznic/turris-omnia-mcu-gpio.c create mode 100644 drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c create mode 100644 drivers/platform/cznic/turris-omnia-mcu-watchdog.c create mode 100644 drivers/platform/cznic/turris-omnia-mcu.h create mode 100644 include/linux/turris-omnia-mcu-interface.h
Signature · 1 line
2.41.0
Marek Behún
maintainerPATCH v4 1/7 dt-bindings: arm: add cznic,turris-omnia-mcu binding
Add binding for cznic,turris-omnia-mcu, the device-tree node representing the system-controller features provided by the MCU on the Turris Omnia router.
--- .../bindings/arm/cznic,turris-omnia-mcu.yaml | 67 +++++++++++++++++++ MAINTAINERS | 1 + 2 files changed, 68 insertions(+) create mode 100644 Documentation/devicetree/bindings/arm/cznic,turris-omnia-mcu.yaml
Documentation/devicetree/bindings/arm/cznic,turris-omnia-mcu.yaml new file +67 -0
@@ -0,0 +1,67 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/arm/cznic,turris-omnia-mcu.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: CZ.NIC's Turris Omnia MCU + +maintainers: + - Marek Behún <[email protected]> + +description: + The MCU on Turris Omnia acts as a system controller providing additional + GPIOs, interrupts, watchdog, system power off and wakeup configuration. + +properties: + compatible: + const: cznic,turris-omnia-mcu + + reg: + description: MCU I2C slave address + maxItems: 1 + + interrupts: + maxItems: 1 + + interrupt-controller: true + + '#interrupt-cells': + const: 2 + + gpio-controller: true + + '#gpio-cells': + const: 2 + +required: + - compatible + - reg + - interrupts + - interrupt-controller + - gpio-controller + +additionalProperties: false + +examples: + - | + #include <dt-bindings/interrupt-controller/irq.h> + + i2c { + #address-cells = <1>; + #size-cells = <0>; + + system-controller@2a { + compatible = "cznic,turris-omnia-mcu"; + reg = <0x2a>; + + interrupt-parent = <&gpio1>; + interrupts = <11 IRQ_TYPE_NONE>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; + };
MAINTAINERS +1 -0
@@ -2102,6 +2102,7 @@ W: https://www.turris.cz/ F: Documentation/ABI/testing/debugfs-moxtet F: Documentation/ABI/testing/sysfs-bus-moxtet-devices F: Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm +F: Documentation/devicetree/bindings/arm/cznic,turris-omnia-mcu.yaml F: Documentation/devicetree/bindings/bus/moxtet.txt F: Documentation/devicetree/bindings/firmware/cznic,turris-mox-rwtm.txt F: Documentation/devicetree/bindings/gpio/gpio-moxtet.txt
Signature · 1 line
2.41.0
Re: [PATCH v4 1/7] dt-bindings: arm: add cznic,turris-omnia-mcu binding
Forgot that Krzysztof already gave R-b for this patch:
Marek Behún
maintainerPATCH v4 2/7 platform: cznic: Add preliminary support for Turris Omnia MCU
In reply to Marek BehúnAdd the basic skeleton for a new platform driver for the microcontroller found on the Turris Omnia board.
--- .../sysfs-bus-i2c-devices-turris-omnia-mcu | 45 ++++ MAINTAINERS | 3 + drivers/platform/Kconfig | 2 + drivers/platform/Makefile | 1 + drivers/platform/cznic/Kconfig | 26 ++ drivers/platform/cznic/Makefile | 4 + .../platform/cznic/turris-omnia-mcu-base.c | 253 ++++++++++++++++++ drivers/platform/cznic/turris-omnia-mcu.h | 65 +++++ include/linux/turris-omnia-mcu-interface.h | 194 ++++++++++++++ 9 files changed, 593 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu create mode 100644 drivers/platform/cznic/Kconfig create mode 100644 drivers/platform/cznic/Makefile create mode 100644 drivers/platform/cznic/turris-omnia-mcu-base.c create mode 100644 drivers/platform/cznic/turris-omnia-mcu.h create mode 100644 include/linux/turris-omnia-mcu-interface.h
Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu new file +45 -0
@@ -0,0 +1,45 @@ +What: /sys/bus/i2c/devices/<mcu_device>/fw_features +Date: November 2023 +KernelVersion: 6.7 +Contact: Marek Behún <[email protected]> +Description: (RO) Newer versions of the microcontroller firmware report the + features they support. These can be read from this file. If the + MCU firmware is too old, this file reads 0x0. + + Format: 0x%x. + +What: /sys/bus/i2c/devices/<mcu_device>/fw_version_hash_application +Date: November 2023 +KernelVersion: 6.7 +Contact: Marek Behún <[email protected]> +Description: (RO) Contains the version hash (commit hash) of the application + part of the microcontroller firmware. + + Format: %s. + +What: /sys/bus/i2c/devices/<mcu_device>/fw_version_hash_bootloader +Date: November 2023 +KernelVersion: 6.7 +Contact: Marek Behún <[email protected]> +Description: (RO) Contains the version hash (commit hash) of the bootloader + part of the microcontroller firmware. + + Format: %s. + +What: /sys/bus/i2c/devices/<mcu_device>/mcu_type +Date: November 2023 +KernelVersion: 6.7 +Contact: Marek Behún <[email protected]> +Description: (RO) Contains the microcontroller type (STM32, GD32, MKL). + + Format: %s. + +What: /sys/bus/i2c/devices/<mcu_device>/reset_selector +Date: November 2023 +KernelVersion: 6.7 +Contact: Marek Behún <[email protected]> +Description: (RO) Contains the selected factory reset level, determined by + how long the rear reset button was held by the user during board + reset. + + Format: %i.
MAINTAINERS +3 -0
@@ -2100,6 +2100,7 @@ M: Marek Behún <[email protected]> S: Maintained W: https://www.turris.cz/ F: Documentation/ABI/testing/debugfs-moxtet +F: Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu F: Documentation/ABI/testing/sysfs-bus-moxtet-devices F: Documentation/ABI/testing/sysfs-firmware-turris-mox-rwtm F: Documentation/devicetree/bindings/arm/cznic,turris-omnia-mcu.yaml
@@ -2113,10 +2114,12 @@ F: drivers/firmware/turris-mox-rwtm.c F: drivers/gpio/gpio-moxtet.c F: drivers/leds/leds-turris-omnia.c F: drivers/mailbox/armada-37xx-rwtm-mailbox.c +F: drivers/platform/cznic/ F: drivers/watchdog/armada_37xx_wdt.c F: include/dt-bindings/bus/moxtet.h F: include/linux/armada-37xx-rwtm-mailbox.h F: include/linux/moxtet.h +F: include/linux/turris-omnia-mcu-interface.h ARM/FARADAY FA526 PORT M: Hans Ulli Kroll <[email protected]>
drivers/platform/Kconfig +2 -0
@@ -7,6 +7,8 @@ source "drivers/platform/goldfish/Kconfig" source "drivers/platform/chrome/Kconfig" +source "drivers/platform/cznic/Kconfig" + source "drivers/platform/mellanox/Kconfig" source "drivers/platform/olpc/Kconfig"
drivers/platform/Makefile +1 -0
@@ -10,4 +10,5 @@ obj-$(CONFIG_MIPS) += mips/ obj-$(CONFIG_OLPC_EC) += olpc/ obj-$(CONFIG_GOLDFISH) += goldfish/ obj-$(CONFIG_CHROME_PLATFORMS) += chrome/ +obj-$(CONFIG_CZNIC_PLATFORMS) += cznic/ obj-$(CONFIG_SURFACE_PLATFORMS) += surface/
drivers/platform/cznic/Kconfig new file +26 -0
@@ -0,0 +1,26 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# For a description of the syntax of this configuration file, +# see Documentation/kbuild/kconfig-language.rst. +# + +menuconfig CZNIC_PLATFORMS + bool "Platform support for CZ.NIC's Turris hardware" + depends on MACH_ARMADA_38X || COMPILE_TEST + help + Say Y here to be able to choose driver support for CZ.NIC's Turris + devices. This option alone does not add any kernel code. + +if CZNIC_PLATFORMS + +config TURRIS_OMNIA_MCU + tristate "Turris Omnia MCU driver" + depends on MACH_ARMADA_38X || COMPILE_TEST + depends on I2C + help + Say Y here to add support for the features implemented by the + microcontroller on the CZ.NIC's Turris Omnia SOHO router. + To compile this driver as a module, choose M here; the module will be + called turris-omnia-mcu. + +endif # CZNIC_PLATFORMS
drivers/platform/cznic/Makefile new file +4 -0
@@ -0,0 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_TURRIS_OMNIA_MCU) += turris-omnia-mcu.o +turris-omnia-mcu-objs := turris-omnia-mcu-base.o
drivers/platform/cznic/turris-omnia-mcu-base.c new file +253 -0
253 lines not on this page · raw message
drivers/platform/cznic/turris-omnia-mcu.h new file +65 -0
65 lines not on this page · raw message
include/linux/turris-omnia-mcu-interface.h new file +194 -0
194 lines not on this page · raw message
Signature · 1 line
2.41.0
Marek Behún
maintainerPATCH v4 3/7 platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs
In reply to Marek BehúnAdd support for GPIOs connected to the MCU on the Turris Omnia board.
This includes:
- front button pin
- enable pins for USB regulators
- MiniPCIe / mSATA card presence pins in MiniPCIe port 0
- LED output pins from WAN ethernet PHY, LAN switch and MiniPCIe ports
- on board revisions 32+ also various peripheral resets and another voltage regulator enable pin
--- .../sysfs-bus-i2c-devices-turris-omnia-mcu | 16 + drivers/platform/cznic/Kconfig | 15 + drivers/platform/cznic/Makefile | 1 + .../platform/cznic/turris-omnia-mcu-base.c | 13 +- .../platform/cznic/turris-omnia-mcu-gpio.c | 1018 +++++++++++++++++ drivers/platform/cznic/turris-omnia-mcu.h | 61 + 6 files changed, 1122 insertions(+), 2 deletions(-) create mode 100644 drivers/platform/cznic/turris-omnia-mcu-gpio.c
Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu +16 -0
@@ -1,3 +1,19 @@ +What: /sys/bus/i2c/devices/<mcu_device>/front_button_mode +Date: November 2023 +KernelVersion: 6.7 +Contact: Marek Behún <[email protected]> +Description: (RW) The front button on the Turris Omnia router can be + configured either to change the intensity of all the LEDs on the + front panel, or to send the press event to the CPU as an + interrupt. + + This file switches between these two modes: + - "mcu" makes the button press event be handled by the MCU to + change the LEDs panel intensity. + - "cpu" makes the button press event be handled by the CPU. + + Format: %s. + What: /sys/bus/i2c/devices/<mcu_device>/fw_features Date: November 2023 KernelVersion: 6.7
drivers/platform/cznic/Kconfig +15 -0
@@ -17,9 +17,24 @@ config TURRIS_OMNIA_MCU tristate "Turris Omnia MCU driver" depends on MACH_ARMADA_38X || COMPILE_TEST depends on I2C + select GPIOLIB + select GPIOLIB_IRQCHIP help Say Y here to add support for the features implemented by the microcontroller on the CZ.NIC's Turris Omnia SOHO router. + The features include: + - GPIO pins + - to get front button press events (the front button can be + configured either to generate press events to the CPU or to change + front LEDs panel brightness) + - to enable / disable USB port voltage regulators and to detect + USB overcurrent + - to detect MiniPCIe / mSATA card presence in MiniPCIe port 0 + - to configure resets of various peripherals on board revisions 32+ + - to enable / disable the VHV voltage regulator to the SOC in order + to be able to program SOC's OTP on board revisions 32+ + - to get input from the LED output pins of the WAN ethernet PHY, LAN + switch and MiniPCIe ports To compile this driver as a module, choose M here; the module will be called turris-omnia-mcu.
drivers/platform/cznic/Makefile +1 -0
@@ -2,3 +2,4 @@ obj-$(CONFIG_TURRIS_OMNIA_MCU) += turris-omnia-mcu.o turris-omnia-mcu-objs := turris-omnia-mcu-base.o +turris-omnia-mcu-objs += turris-omnia-mcu-gpio.o
drivers/platform/cznic/turris-omnia-mcu-base.c +11 -2
@@ -105,7 +105,16 @@ static struct attribute *omnia_mcu_attrs[] = { &dev_attr_reset_selector.attr, NULL }; -ATTRIBUTE_GROUPS (omnia_mcu); + +static const struct attribute_group omnia_mcu_base_group = { + .attrs = omnia_mcu_attrs, +}; + +static const struct attribute_group *omnia_mcu_groups[] = { + &omnia_mcu_base_group, + &omnia_mcu_gpio_group, +NULL +};static void omnia_mcu_print_version_hash (struct omnia_mcu *mcu,bool bootloader) {
@@ -229,7 +238,7 @@ static int omnia_mcu_probe(struct i2c_client *client)return dev_err_probe (dev, err,"Cannot determine MCU supported features\n" ); -return 0 ; +return omnia_mcu_register_gpiochip (mcu); }static const struct of_device_id of_omnia_mcu_match[] = {
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +1018 -0
1,018 lines not on this page · raw message
drivers/platform/cznic/turris-omnia-mcu.h +61 -0
87 lines not on this page · raw message
Signature · 1 line
2.41.0
Marek Behún
maintainerRe: [PATCH v4 3/7] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs
Quoted 6 lines · On Thu, 26 Oct 2023 18:17:59 +0200 Marek Behún <[email protected]> wrote:
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +6
-0+ mcu->gc.request = omnia_gpio_request; + mcu->gc.get_direction = omnia_gpio_get_direction; + mcu->gc.direction_input = omnia_gpio_direction_input; + mcu->gc.direction_output = omnia_gpio_direction_output; + mcu->gc.get = omnia_gpio_get; + mcu->gc.get_multiple = omnia_gpio_get_multiple;
drivers/platform/cznic/turris-omnia-mcu-gpio.c line 951
Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +10
-0+ mcu->gc.set = omnia_gpio_set; + mcu->gc.set_multiple = omnia_gpio_set_multiple; + mcu->gc.init_valid_mask = omnia_gpio_init_valid_mask; + mcu->gc.can_sleep = true; + mcu->gc.names = omnia_mcu_gpio_templates; + mcu->gc.base =-1 ; + mcu->gc.ngpio =ARRAY_SIZE (omnia_gpios); + mcu->gc.label ="Turris Omnia MCU GPIOs" ; + mcu->gc.parent = dev; + mcu->gc.owner =THIS_MODULE ;
Sigh. I will need to add a custom of_xlate here that accepts 3 cells instead of 2. The reason is that Pali prepared U-Boot code last year to patch reset-gpios into pcie nodes if MCU node is present in the devicetree, and back then we decided that the binding should be 3-celled:
reset-gpios = <&mcu BANK GPIO FLAGS>;
So now the pcie controllers do not work because OF cannot give proper GPIOs.
I will fix this in v5.
Marek
Gregory CLEMENT
maintainerRe: [PATCH v4 3/7] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs
Hello Marek,
Quoted 27 lines
Quoted 6 lines · On Thu, 26 Oct 2023 18:17:59 +0200 Marek Behún <[email protected]> wrote:
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +6
-0+ mcu->gc.request = omnia_gpio_request; + mcu->gc.get_direction = omnia_gpio_get_direction; + mcu->gc.direction_input = omnia_gpio_direction_input; + mcu->gc.direction_output = omnia_gpio_direction_output; + mcu->gc.get = omnia_gpio_get; + mcu->gc.get_multiple = omnia_gpio_get_multiple;drivers/platform/cznic/turris-omnia-mcu-gpio.c line 951
Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +10
-0+ mcu->gc.set = omnia_gpio_set; + mcu->gc.set_multiple = omnia_gpio_set_multiple; + mcu->gc.init_valid_mask = omnia_gpio_init_valid_mask; + mcu->gc.can_sleep = true; + mcu->gc.names = omnia_mcu_gpio_templates; + mcu->gc.base =-1 ; + mcu->gc.ngpio =ARRAY_SIZE (omnia_gpios); + mcu->gc.label ="Turris Omnia MCU GPIOs" ; + mcu->gc.parent = dev; + mcu->gc.owner =THIS_MODULE ;Sigh. I will need to add a custom
of_xlatehere that accepts 3 cells instead of 2. The reason is that Pali prepared U-Boot code last year to patch reset-gpios into pcie nodes if MCU node is present in the devicetree, and back then we decided that the binding should be 3-celled:
reset-gpios = <&mcu BANK GPIO FLAGS>;
Quoted 4 lines
So now the pcie controllers do not work because OF cannot give proper GPIOs.
I will fix this in v5.
I was reviewing the seris in order to apply it, but I didn't find your v5 in the mainling list. Did you send it ?
Regards,
Gregory
Signature · 3 lines
Gregory Clement, Bootlin Embedded Linux and Kernel engineering http://bootlin.com
Marek Behún
maintainerRe: [PATCH v4 3/7] platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs
Quoted 29 lines · On Fri, 08 Dec 2023 15:26:02 +0100 Gregory CLEMENT…
Hello Marek,
Quoted 27 lines
Quoted 6 lines · On Thu, 26 Oct 2023 18:17:59 +0200 Marek Behún <[email protected]> wrote:
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +6
-0+ mcu->gc.request = omnia_gpio_request; + mcu->gc.get_direction = omnia_gpio_get_direction; + mcu->gc.direction_input = omnia_gpio_direction_input; + mcu->gc.direction_output = omnia_gpio_direction_output; + mcu->gc.get = omnia_gpio_get; + mcu->gc.get_multiple = omnia_gpio_get_multiple;drivers/platform/cznic/turris-omnia-mcu-gpio.c line 951
Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-gpio.c new file +10
-0+ mcu->gc.set = omnia_gpio_set; + mcu->gc.set_multiple = omnia_gpio_set_multiple; + mcu->gc.init_valid_mask = omnia_gpio_init_valid_mask; + mcu->gc.can_sleep = true; + mcu->gc.names = omnia_mcu_gpio_templates; + mcu->gc.base =-1 ; + mcu->gc.ngpio =ARRAY_SIZE (omnia_gpios); + mcu->gc.label ="Turris Omnia MCU GPIOs" ; + mcu->gc.parent = dev; + mcu->gc.owner =THIS_MODULE ;Sigh. I will need to add a custom
of_xlatehere that accepts 3 cells instead of 2. The reason is that Pali prepared U-Boot code last year to patch reset-gpios into pcie nodes if MCU node is present in the devicetree, and back then we decided that the binding should be 3-celled:
reset-gpios = <&mcu BANK GPIO FLAGS>;
Quoted 7 lines
Quoted 4 lines
So now the pcie controllers do not work because OF cannot give proper GPIOs.
I will fix this in v5.
I was reviewing the seris in order to apply it, but I didn't find your v5 in the mainling list. Did you send it ?
Hi Gregory, no I haven't yet. I was on a vacation and before I had to work on some other issues. Hopefully I will be able to finish it within the month. I will ping you then.
Thank you.
Marek
Marek Behún
maintainerPATCH v4 4/7 platform: cznic: turris-omnia-mcu: Add support for poweroff and wakeup
In reply to Marek BehúnAdd support for true board poweroff (MCU can disable all unnecessary voltage regulators) and wakeup at a specified time, implemented via a RTC driver so that the rtcwake utility can be used to configure it.
--- .../sysfs-bus-i2c-devices-turris-omnia-mcu | 16 ++ drivers/platform/cznic/Kconfig | 4 + drivers/platform/cznic/Makefile | 1 + .../platform/cznic/turris-omnia-mcu-base.c | 5 + .../cznic/turris-omnia-mcu-sys-off-wakeup.c | 257 ++++++++++++++++++ drivers/platform/cznic/turris-omnia-mcu.h | 20 ++ 6 files changed, 303 insertions(+) create mode 100644 drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c
Documentation/ABI/testing/sysfs-bus-i2c-devices-turris-omnia-mcu +16 -0
@@ -14,6 +14,22 @@ Description: (RW) The front button on the Turris Omnia router can be Format: %s. +What: /sys/bus/i2c/devices/<mcu_device>/front_button_poweron +Date: August 2023 +KernelVersion: 6.6 +Contact: Marek Behún <[email protected]> +Description: (RW) Newer versions of the microcontroller firmware of the + Turris Omnia router support powering off the router into true + low power mode. The router can be powered on by pressing the + front button. + + This file configures whether front button power on is enabled. + + This file is present only if the power off feature is supported + by the firmware. + + Format: %i. + What: /sys/bus/i2c/devices/<mcu_device>/fw_features Date: November 2023 KernelVersion: 6.7
drivers/platform/cznic/Kconfig +4 -0
@@ -19,10 +19,14 @@ config TURRIS_OMNIA_MCU depends on I2C select GPIOLIB select GPIOLIB_IRQCHIP + select RTC_CLASS help Say Y here to add support for the features implemented by the microcontroller on the CZ.NIC's Turris Omnia SOHO router. The features include: + - board poweroff into true low power mode (with voltage regulators + disabled) and the ability to configure wake up from this mode (via + rtcwake) - GPIO pins - to get front button press events (the front button can be configured either to generate press events to the CPU or to change
drivers/platform/cznic/Makefile +1 -0
@@ -3,3 +3,4 @@ obj-$(CONFIG_TURRIS_OMNIA_MCU) += turris-omnia-mcu.o turris-omnia-mcu-objs := turris-omnia-mcu-base.o turris-omnia-mcu-objs += turris-omnia-mcu-gpio.o +turris-omnia-mcu-objs += turris-omnia-mcu-sys-off-wakeup.o
drivers/platform/cznic/turris-omnia-mcu-base.c +5 -0
@@ -113,6 +113,7 @@ static const struct attribute_group omnia_mcu_base_group = {static const struct attribute_group *omnia_mcu_groups[] = { &omnia_mcu_base_group, &omnia_mcu_gpio_group, + &omnia_mcu_poweroff_group,NULL };
@@ -238,6 +239,10 @@ static int omnia_mcu_probe(struct i2c_client *client)return dev_err_probe (dev, err,"Cannot determine MCU supported features\n" ); + err =omnia_mcu_register_sys_off_and_wakeup (mcu); +if (err) +return err; +return omnia_mcu_register_gpiochip (mcu); }
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c new file +257 -0
257 lines not on this page · raw message
drivers/platform/cznic/turris-omnia-mcu.h +20 -0
@@ -12,9 +12,11 @@#include <linux/gpio/driver.h> #include <linux/i2c.h> #include <linux/mutex.h> +#include <linux/rtc.h> #include <linux/types.h> #include <linux/workqueue.h> #include <asm/byteorder.h> +#include <asm/unaligned.h> struct omnia_mcu {struct i2c_client *client;
@@ -29,6 +31,11 @@ struct omnia_mcu {struct delayed_work button_release_emul_work;u16 last_status;bool button_pressed_emul; + +/* RTC device for configuring wake-up */ +struct rtc_device *rtcdev; +u32 rtc_alarm; +bool front_button_poweron; }; static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd,
@@ -41,6 +48,17 @@ static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd,return ret <0 ? ret :0 ; } +static inline int omnia_cmd_write_u32 (const struct i2c_client *client,u8 cmd, +u32 val) +{ +u8 buf[5 ]; + + buf[0 ] = cmd; +put_unaligned_le32 (val, &buf[1 ]); + +return omnia_cmd_write (client, buf,sizeof (buf)); +} +static inline int omnia_cmd_read (const struct i2c_client *client,u8 cmd,void *reply,unsigned int len) {
@@ -120,7 +138,9 @@ static inline int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd) }extern const struct attribute_group omnia_mcu_gpio_group; +extern const struct attribute_group omnia_mcu_poweroff_group;int omnia_mcu_register_gpiochip (struct omnia_mcu *mcu); +int omnia_mcu_register_sys_off_and_wakeup (struct omnia_mcu *mcu);#endif /* __TURRIS_OMNIA_MCU_H */
Signature · 1 line
2.41.0
Alexandre Belloni
maintainerRe: [PATCH v4 4/7] platform: cznic: turris-omnia-mcu: Add support for poweroff and wakeup
Quoted 18 lines · Marek Behún
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c new file +18
-0+static int omnia_get_uptime_wakeup (const struct i2c_client *client,u32 *uptime, +u32 *wakeup) +{ +__le32 reply[2 ]; +int err; + + err =omnia_cmd_read (client,CMD_GET_UPTIME_AND_WAKEUP , reply, +sizeof (reply)); +if (err) +return err; + +if (uptime) + *uptime =le32_to_cpu (reply[0 ]); + +if (wakeup) + *wakeup =le32_to_cpu (reply[1 ]); + +return 0 ;
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c line 52
Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c new file +10
-0+} + +static int omnia_read_time (struct device *dev,struct rtc_time *tm) +{ +u32 uptime; +int err; + + err =omnia_get_uptime_wakeup (to_i2c_client (dev), &uptime,NULL ); +if (err) +return err;
Does this get the real time or the board uptime?
Quoted 9 lines
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c new file +9
-0+ +rtc_time64_to_tm (uptime, tm); + +return 0 ; +} + +static int omnia_read_alarm (struct device *dev,struct rtc_wkalrm *alrm) +{ +struct i2c_client *client =to_i2c_client (dev);
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c line 71
Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c new file +10
-0+struct omnia_mcu *mcu =i2c_get_clientdata (client); +u32 wakeup; +int err; + + err =omnia_get_uptime_wakeup (client,NULL , &wakeup); +if (err) +return err; + + alrm->enabled = !!wakeup; +rtc_time64_to_tm (wakeup ?: mcu->rtc_alarm, &alrm->time);
I don't think this works properly as on boot, mcu->rtc_alarm will not be set whereas wakeup could be.
Also, is wakeup actually an absolute time? I'm not sure I get how the MCU works then.
Quoted 167 lines
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c new file +167
-0+ +return 0 ; +} + +static int omnia_set_alarm (struct device *dev,struct rtc_wkalrm *alrm) +{ +struct i2c_client *client =to_i2c_client (dev); +struct omnia_mcu *mcu =i2c_get_clientdata (client); + + mcu->rtc_alarm =rtc_tm_to_time64 (&alrm->time); + +if (alrm->enabled) +return omnia_cmd_write_u32 (client,CMD_SET_WAKEUP , + mcu->rtc_alarm); + +return 0 ; +} + +static int omnia_alarm_irq_enable (struct device *dev,unsigned int enabled) +{ +struct i2c_client *client =to_i2c_client (dev); +struct omnia_mcu *mcu =i2c_get_clientdata (client); + +return omnia_cmd_write_u32 (client,CMD_SET_WAKEUP , + enabled ? mcu->rtc_alarm :0 ); +} + +static const struct rtc_class_ops omnia_rtc_ops = { + .read_time = omnia_read_time, + .read_alarm = omnia_read_alarm, + .set_alarm = omnia_set_alarm, + .alarm_irq_enable = omnia_alarm_irq_enable, +}; + +static int omnia_power_off (struct sys_off_data *data) +{ +struct omnia_mcu *mcu = data->cb_data; +__be32 tmp; +u8 cmd[9 ]; +u16 arg; +int err; + +if (mcu->front_button_poweron) + arg =CMD_POWER_OFF_POWERON_BUTTON ; +else + arg =0 ; + + cmd[0 ] =CMD_POWER_OFF ; +put_unaligned_le16 (CMD_POWER_OFF_MAGIC , &cmd[1 ]); +put_unaligned_le16 (arg, &cmd[3 ]); + +/* +* Although all values from and to MCU are passed in little-endian, the +* MCU's CRC unit uses big-endian CRC32 polynomial (0x04c11db7), so we +* need to use crc32_be() here. +*/ + tmp =cpu_to_be32 (get_unaligned_le32 (&cmd[1 ])); +put_unaligned_le32 (crc32_be (0xffffffff , (void *)&tmp,sizeof (tmp)), + &cmd[5 ]); + + err =omnia_cmd_write (mcu->client, cmd,sizeof (cmd)); +if (err) +dev_err (&mcu->client->dev, +"Unable to send the poweroff command: %d\n" , err); + +return NOTIFY_DONE ; +} + +static int omnia_restart (struct sys_off_data *data) +{ +struct omnia_mcu *mcu = data->cb_data; +u8 cmd[3 ]; +int err; + + cmd[0 ] =CMD_GENERAL_CONTROL ; + +if (reboot_mode ==REBOOT_HARD ) + cmd[1 ] = cmd[2 ] =CTL_HARD_RST ; +else + cmd[1 ] = cmd[2 ] =CTL_LIGHT_RST ; + + err =omnia_cmd_write (mcu->client, cmd,sizeof (cmd)); +if (err) +dev_err (&mcu->client->dev, +"Unable to send the restart command: %d\n" , err); + +/* +* MCU needs a little bit to process the I2C command, otherwise it will +* do a light reset based on SOC SYSRES_OUT pin. +*/ +mdelay (1 ); + +return NOTIFY_DONE ; +} + +static ssize_t front_button_poweron_show (struct device *dev, +struct device_attribute *a,char *buf) +{ +struct omnia_mcu *mcu =i2c_get_clientdata (to_i2c_client (dev)); + +return sysfs_emit (buf,"%d\n" , mcu->front_button_poweron); +} + +static ssize_t front_button_poweron_store (struct device *dev, +struct device_attribute *a, +const char *buf,size_t count) +{ +struct omnia_mcu *mcu =i2c_get_clientdata (to_i2c_client (dev)); +bool val; +int err; + + err =kstrtobool (buf, &val); +if (err) +return err; + + mcu->front_button_poweron = val; + +return count; +} +static DEVICE_ATTR_RW (front_button_poweron); + +static struct attribute *omnia_mcu_poweroff_attrs[] = { + &dev_attr_front_button_poweron.attr, +NULL +}; + +static umode_t poweroff_attrs_visible (struct kobject *kobj,struct attribute *a, +int n) +{ +struct device *dev =kobj_to_dev (kobj); +struct omnia_mcu *mcu =i2c_get_clientdata (to_i2c_client (dev)); + +if (mcu->features &FEAT_POWEROFF_WAKEUP ) +return a->mode; + +return 0 ; +} + +const struct attribute_group omnia_mcu_poweroff_group = { + .attrs = omnia_mcu_poweroff_attrs, + .is_visible = poweroff_attrs_visible, +}; + +int omnia_mcu_register_sys_off_and_wakeup (struct omnia_mcu *mcu) +{ +struct device *dev = &mcu->client->dev; +int err; + +/* MCU restart is always available */ + err =devm_register_sys_off_handler (dev,SYS_OFF_MODE_RESTART , +SYS_OFF_PRIO_FIRMWARE , + omnia_restart, mcu); +if (err) +return dev_err_probe (dev, err, +"Cannot register system restart handler\n" ); + +/* +* Poweroff and wakeup are available only if POWEROFF_WAKEUP feature is +* present. +*/ +if (!(mcu->features &FEAT_POWEROFF_WAKEUP )) +return 0 ; + + err =devm_register_sys_off_handler (dev,SYS_OFF_MODE_POWER_OFF , +SYS_OFF_PRIO_FIRMWARE , + omnia_power_off, mcu); +if (err)
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c line 248
Quoted 10 lines
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c new file +10
-0+return dev_err_probe (dev, err, +"Cannot register system power off handler\n" ); + + mcu->rtcdev =devm_rtc_allocate_device (dev); +if (IS_ERR (mcu->rtcdev)) +return dev_err_probe (dev,PTR_ERR (mcu->rtcdev), +"Cannot allocate RTC device\n" ); + + mcu->rtcdev->ops = &omnia_rtc_ops; + mcu->rtcdev->range_max =U32_MAX ;
You probably need to add:
set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, mcu->rtcdev->features);
Signature · 3 lines
Alexandre Belloni, co-owner and COO, Bootlin Embedded Linux and Kernel engineering https://bootlin.com
Marek Behún
maintainerRe: [PATCH v4 4/7] platform: cznic: turris-omnia-mcu: Add support for poweroff and wakeup
Quoted 23 lines · On Fri, 3 Nov 2023 20:23:16 +0100 Alexandre Belloni…
Quoted 22 lines · Marek Behún
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c new file +22
-0+static int omnia_get_uptime_wakeup (const struct i2c_client *client,u32 *uptime, +u32 *wakeup) +{ +__le32 reply[2 ]; +int err; + + err =omnia_cmd_read (client,CMD_GET_UPTIME_AND_WAKEUP , reply, +sizeof (reply)); +if (err) +return err; + +if (uptime) + *uptime =le32_to_cpu (reply[0 ]); + +if (wakeup) + *wakeup =le32_to_cpu (reply[1 ]); + +return 0 ; +} + +static int omnia_read_time (struct device *dev,struct rtc_time *tm) +{
Quoted 8 lines
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c line 52
Quoted 6 lines
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c new file +6
-0+u32 uptime; +int err; + + err =omnia_get_uptime_wakeup (to_i2c_client (dev), &uptime,NULL ); +if (err) +return err;Does this get the real time or the board uptime?
Hi Alexandre,
sorry I did not notice your email sooner.
This returns board uptime. The MCU does not remember real time.
Quoted 14 lines
Quoted 14 lines
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c new file +14
-0+ +rtc_time64_to_tm (uptime, tm); + +return 0 ; +} + +static int omnia_read_alarm (struct device *dev,struct rtc_wkalrm *alrm) +{ +struct i2c_client *client =to_i2c_client (dev); +struct omnia_mcu *mcu =i2c_get_clientdata (client); +u32 wakeup; +int err; + + err =omnia_get_uptime_wakeup (client,NULL , &wakeup);
Quoted 8 lines
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c line 71
Quoted 5 lines
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c new file +5
-0+if (err) +return err; + + alrm->enabled = !!wakeup; +rtc_time64_to_tm (wakeup ?: mcu->rtc_alarm, &alrm->time);I don't think this works properly as on boot,
mcu->rtc_alarmwill not be set whereas wakeup could be.
mcu->rtc_alarm is the value that is to be written to MCU wakeup register when we enable the RTC alarm with .alarm_irq_enable().
When the alarm is enabled by other means than the driver (prior boot or by a userspace utility), the omnia_read_alarm() will determine it correctly, since it will read via I2C the MCU wakeup value.
If it is non-zero, it will return that the alarm is enabled and the alarm time is determined by this non-zero value.
If the alarm is disabled on the MCU, we return that the alarm is disabled, but we fill in the alrm->time with the cached value of mcu->rtc_alarm which was set in previous call to the .set_alarm method. This is because we want to support both the new IOCTLs (RTC_WKALM_RD, RTC_WKALM_SET) and the old (RTC_ALM_SET, RTC_AIE_ON, RTC_AIE_OFF).
Quoted 3 lines
Also, is wakeup actually an absolute time? I'm not sure I get how the MCU works then.
The wakeup value is in the same units as uptime: seconds elapsed since MCU started.
Example:
- uptime is 2000 seconds (MCU has been powered on 2000 seconds ago)
- we are going to power off the board, but we want it to power on in one hour
- we will therefore set wakeup to uptime + 3600 = 2000 + 3600 = 5600
Quoted 7 lines
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c line 248
Quoted 2 lines
drivers/platform/cznic/turris-omnia-mcu-sys-off-wakeup.c new file +2
-0+ mcu->rtcdev->ops = &omnia_rtc_ops; + mcu->rtcdev->range_max =U32_MAX ;You probably need to add:
set_bit(RTC_FEATURE_ALARM_WAKEUP_ONLY, mcu->rtcdev->features);
Thx, will do. Is this bit documented? Could only find its definition and one usage with git grep.
Marek
Marek Behún
maintainerPATCH v4 5/7 platform: cznic: turris-omnia-mcu: Add support for MCU watchdog
In reply to Marek BehúnAdd support for the watchdog mechanism provided by the MCU.
--- drivers/platform/cznic/Kconfig | 2 + drivers/platform/cznic/Makefile | 1 + .../platform/cznic/turris-omnia-mcu-base.c | 4 + .../cznic/turris-omnia-mcu-watchdog.c | 122 ++++++++++++++++++ drivers/platform/cznic/turris-omnia-mcu.h | 24 ++++ 5 files changed, 153 insertions(+) create mode 100644 drivers/platform/cznic/turris-omnia-mcu-watchdog.c
drivers/platform/cznic/Kconfig +2 -0
@@ -20,6 +20,7 @@ config TURRIS_OMNIA_MCU select GPIOLIB select GPIOLIB_IRQCHIP select RTC_CLASS + select WATCHDOG_CORE help Say Y here to add support for the features implemented by the microcontroller on the CZ.NIC's Turris Omnia SOHO router.
@@ -27,6 +28,7 @@ config TURRIS_OMNIA_MCU - board poweroff into true low power mode (with voltage regulators disabled) and the ability to configure wake up from this mode (via rtcwake) + - MCU watchdog - GPIO pins - to get front button press events (the front button can be configured either to generate press events to the CPU or to change
drivers/platform/cznic/Makefile +1 -0
@@ -4,3 +4,4 @@ obj-$(CONFIG_TURRIS_OMNIA_MCU) += turris-omnia-mcu.o turris-omnia-mcu-objs := turris-omnia-mcu-base.o turris-omnia-mcu-objs += turris-omnia-mcu-gpio.o turris-omnia-mcu-objs += turris-omnia-mcu-sys-off-wakeup.o +turris-omnia-mcu-objs += turris-omnia-mcu-watchdog.o
drivers/platform/cznic/turris-omnia-mcu-base.c +4 -0
@@ -243,6 +243,10 @@ static int omnia_mcu_probe(struct i2c_client *client)if (err)return err; + err =omnia_mcu_register_watchdog (mcu); +if (err) +return err; +return omnia_mcu_register_gpiochip (mcu); }
drivers/platform/cznic/turris-omnia-mcu-watchdog.c new file +122 -0
122 lines not on this page · raw message
drivers/platform/cznic/turris-omnia-mcu.h +24 -0
@@ -14,6 +14,7 @@#include <linux/mutex.h> #include <linux/rtc.h> #include <linux/types.h> +#include <linux/watchdog.h> #include <linux/workqueue.h> #include <asm/byteorder.h> #include <asm/unaligned.h>
@@ -36,6 +37,9 @@ struct omnia_mcu {struct rtc_device *rtcdev;u32 rtc_alarm;bool front_button_poweron; + +/* MCU watchdog */ +struct watchdog_device wdt; }; static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd,
@@ -48,6 +52,25 @@ static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd,return ret <0 ? ret :0 ; } +static inline int omnia_cmd_write_u8 (const struct i2c_client *client,u8 cmd, +u8 val) +{ +u8 buf[2 ] = { cmd, val }; + +return omnia_cmd_write (client, buf,sizeof (buf)); +} + +static inline int omnia_cmd_write_u16 (const struct i2c_client *client,u8 cmd, +u16 val) +{ +u8 buf[3 ]; + + buf[0 ] = cmd; +put_unaligned_le16 (val, &buf[1 ]); + +return omnia_cmd_write (client, buf,sizeof (buf)); +} +static inline int omnia_cmd_write_u32 (const struct i2c_client *client,u8 cmd,u32 val) {
@@ -142,5 +165,6 @@ extern const struct attribute_group omnia_mcu_poweroff_group;int omnia_mcu_register_gpiochip (struct omnia_mcu *mcu);int omnia_mcu_register_sys_off_and_wakeup (struct omnia_mcu *mcu); +int omnia_mcu_register_watchdog (struct omnia_mcu *mcu);#endif /* __TURRIS_OMNIA_MCU_H */
Signature · 1 line
2.41.0
Marek Behún
maintainerPATCH v4 6/7 ARM: dts: turris-omnia: Add MCU system-controller node
In reply to Marek BehúnTurris Omnia's MCU provides various features that can be configured over I2C at address 0x2a. Add device-tree node.
--- .../dts/marvell/armada-385-turris-omnia.dts | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-)
arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts +21 -1
@@ -218,7 +218,22 @@ i2c@0 { #size-cells = <0>; reg = <0>; - /* STM32F0 command interface at address 0x2a */ + mcu: system-controller@2a { + compatible = "cznic,turris-omnia-mcu"; + reg = <0x2a>; + + pinctrl-names = "default"; + pinctrl-0 = <&mcu_pins>; + + interrupt-parent = <&gpio1>; + interrupts = <11 IRQ_TYPE_NONE>; + + gpio-controller; + #gpio-cells = <2>; + + interrupt-controller; + #interrupt-cells = <2>; + }; led-controller@2b { compatible = "cznic,turris-omnia-leds";
@@ -503,6 +518,11 @@ fixed-link { }; &pinctrl { + mcu_pins: mcu-pins { + marvell,pins = "mpp43"; + marvell,function = "gpio"; + }; + pcawan_pins: pcawan-pins { marvell,pins = "mpp46"; marvell,function = "gpio";
Signature · 1 line
2.41.0
Marek Behún
maintainerPATCH v4 7/7 ARM: dts: turris-omnia: Add GPIO key node for front button
In reply to Marek BehúnNow that we have the MCU device-tree node, which acts as a GPIO controller, add GPIO key node for the front button.
--- .../boot/dts/marvell/armada-385-turris-omnia.dts | 13 +++++++++++++ 1 file changed, 13 insertions(+)
arch/arm/boot/dts/marvell/armada-385-turris-omnia.dts +13 -0
@@ -112,6 +112,19 @@ sfp: sfp { status = "disabled"; }; + gpio-keys { + compatible = "gpio-keys"; + + front-button { + label = "Front Button"; + linux,code = <KEY_VENDOR>; + linux,can-disable; + gpios = <&mcu 12 GPIO_ACTIVE_HIGH>; + /* debouncing is done by the microcontroller */ + debounce-interval = <0>; + }; + }; + sound { compatible = "simple-audio-card"; simple-audio-card,name = "SPDIF";
Signature · 1 line
2.41.0