platform: cznic: turris-omnia-mcu: Add support for MCU connected GPIOs

Add 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

Signed-off-by: Marek Behún <kabel@kernel.org>
Acked-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
Link: https://lore.kernel.org/r/20240701113010.16447-4-kabel@kernel.org
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Marek Behún 2024-07-01 13:30:05 +02:00 committed by Arnd Bergmann
parent 992f1a3d4e
commit dfa556e45a
No known key found for this signature in database
GPG Key ID: 60AB47FFC9095227
6 changed files with 1197 additions and 1 deletions

View File

@ -22,6 +22,22 @@ Description: (RO) Contains device first MAC address. Each Turris Omnia is
Format: %pM.
What: /sys/bus/i2c/devices/<mcu_device>/front_button_mode
Date: September 2024
KernelVersion: 6.11
Contact: Marek Behún <kabel@kernel.org>
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: September 2024
KernelVersion: 6.11

View File

@ -16,9 +16,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.

View File

@ -2,3 +2,4 @@
obj-$(CONFIG_TURRIS_OMNIA_MCU) += turris-omnia-mcu.o
turris-omnia-mcu-y := turris-omnia-mcu-base.o
turris-omnia-mcu-y += turris-omnia-mcu-gpio.o

View File

@ -197,6 +197,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,
NULL
};
@ -371,7 +372,7 @@ static int omnia_mcu_probe(struct i2c_client *client)
"Cannot read board info\n");
}
return 0;
return omnia_mcu_register_gpiochip(mcu);
}
static const struct of_device_id of_omnia_mcu_match[] = {

File diff suppressed because it is too large Load Diff

View File

@ -8,8 +8,12 @@
#ifndef __TURRIS_OMNIA_MCU_H
#define __TURRIS_OMNIA_MCU_H
#include <linux/bitops.h>
#include <linux/gpio/driver.h>
#include <linux/if_ether.h>
#include <linux/mutex.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include <asm/byteorder.h>
struct i2c_client;
@ -23,18 +27,78 @@ struct omnia_mcu {
u64 board_serial_number;
u8 board_first_mac[ETH_ALEN];
u8 board_revision;
/* GPIO chip */
struct gpio_chip gc;
struct mutex lock;
unsigned long mask, rising, falling, both, cached, is_cached;
/* Old MCU firmware handling needs the following */
struct delayed_work button_release_emul_work;
unsigned long last_status;
bool button_pressed_emul;
};
int omnia_cmd_write_read(const struct i2c_client *client,
void *cmd, unsigned int cmd_len,
void *reply, unsigned int reply_len);
static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd,
unsigned int len)
{
return omnia_cmd_write_read(client, cmd, len, NULL, 0);
}
static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd,
void *reply, unsigned int len)
{
return omnia_cmd_write_read(client, &cmd, 1, reply, len);
}
static inline unsigned int
omnia_compute_reply_length(unsigned long mask, bool interleaved,
unsigned int offset)
{
if (!mask)
return 0;
return ((__fls(mask) >> 3) << interleaved) + 1 + offset;
}
/* Returns 0 on success */
static inline int omnia_cmd_read_bits(const struct i2c_client *client, u8 cmd,
unsigned long bits, unsigned long *dst)
{
__le32 reply;
int err;
if (!bits) {
*dst = 0;
return 0;
}
err = omnia_cmd_read(client, cmd, &reply,
omnia_compute_reply_length(bits, false, 0));
if (err)
return err;
*dst = le32_to_cpu(reply) & bits;
return 0;
}
static inline int omnia_cmd_read_bit(const struct i2c_client *client, u8 cmd,
unsigned long bit)
{
unsigned long reply;
int err;
err = omnia_cmd_read_bits(client, cmd, bit, &reply);
if (err)
return err;
return !!reply;
}
static inline int omnia_cmd_read_u32(const struct i2c_client *client, u8 cmd,
u32 *dst)
{
@ -71,4 +135,8 @@ static inline int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd,
return omnia_cmd_read(client, cmd, reply, sizeof(*reply));
}
extern const struct attribute_group omnia_mcu_gpio_group;
int omnia_mcu_register_gpiochip(struct omnia_mcu *mcu);
#endif /* __TURRIS_OMNIA_MCU_H */