linux/drivers/platform/cznic/turris-omnia-mcu-gpio.c

// SPDX-License-Identifier: GPL-2.0
/*
 * CZ.NIC's Turris Omnia MCU GPIO and IRQ driver
 *
 * 2024 by Marek Behún <[email protected]>
 */

#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/bitops.h>
#include <linux/bug.h>
#include <linux/cleanup.h>
#include <linux/device.h>
#include <linux/devm-helpers.h>
#include <linux/errno.h>
#include <linux/gpio/driver.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <linux/sysfs.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include <asm/unaligned.h>

#include <linux/turris-omnia-mcu-interface.h>
#include "turris-omnia-mcu.h"

#define OMNIA_CMD_INT_ARG_LEN
#define FRONT_BUTTON_RELEASE_DELAY_MS

static const char * const omnia_mcu_gpio_templates[64] =;

struct omnia_gpio {};

#define OMNIA_GPIO_INVALID_INT_BIT

#define _DEF_GPIO(_cmd, _ctl_cmd, _bit, _ctl_bit, _int_bit, _feat, _feat_mask)

#define _DEF_GPIO_STS(_name)

#define _DEF_GPIO_CTL(_name)

#define _DEF_GPIO_EXT_STS(_name, _feat)

#define _DEF_GPIO_EXT_STS_LED(_name, _ledext)

#define _DEF_GPIO_EXT_STS_LEDALL(_name)

#define _DEF_GPIO_EXT_CTL(_name, _feat)

#define _DEF_INT(_name)

static inline bool is_int_bit_valid(const struct omnia_gpio *gpio)
{}

static const struct omnia_gpio omnia_gpios[64] =;

/* mapping from interrupts to indexes of GPIOs in the omnia_gpios array */
const u8 omnia_int_to_gpio_idx[32] =;

/* index of PHY_SFP GPIO in the omnia_gpios array */
#define OMNIA_GPIO_PHY_SFP_OFFSET

static int omnia_ctl_cmd_locked(struct omnia_mcu *mcu, u8 cmd, u16 val, u16 mask)
{}

static int omnia_ctl_cmd(struct omnia_mcu *mcu, u8 cmd, u16 val, u16 mask)
{}

static int omnia_gpio_request(struct gpio_chip *gc, unsigned int offset)
{}

static int omnia_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
{}

static int omnia_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
{}

static int omnia_gpio_direction_output(struct gpio_chip *gc,
				       unsigned int offset, int value)
{}

static int omnia_gpio_get(struct gpio_chip *gc, unsigned int offset)
{}

static unsigned long *
_relevant_field_for_sts_cmd(u8 cmd, unsigned long *sts, unsigned long *ext_sts,
			    unsigned long *ext_ctl)
{}

static int omnia_gpio_get_multiple(struct gpio_chip *gc, unsigned long *mask,
				   unsigned long *bits)
{}

static void omnia_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
{}

static void omnia_gpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
				    unsigned long *bits)
{}

static bool omnia_gpio_available(struct omnia_mcu *mcu,
				 const struct omnia_gpio *gpio)
{}

static int omnia_gpio_init_valid_mask(struct gpio_chip *gc,
				      unsigned long *valid_mask,
				      unsigned int ngpios)
{}

static int omnia_gpio_of_xlate(struct gpio_chip *gc,
			       const struct of_phandle_args *gpiospec,
			       u32 *flags)
{}

static void omnia_irq_shutdown(struct irq_data *d)
{}

static void omnia_irq_mask(struct irq_data *d)
{}

static void omnia_irq_unmask(struct irq_data *d)
{}

static int omnia_irq_set_type(struct irq_data *d, unsigned int type)
{}

static void omnia_irq_bus_lock(struct irq_data *d)
{}

/**
 * omnia_mask_interleave - Interleaves the bytes from @rising and @falling
 * @dst: the destination u8 array of interleaved bytes
 * @rising: rising mask
 * @falling: falling mask
 *
 * Interleaves the little-endian bytes from @rising and @falling words.
 *
 * If @rising = (r0, r1, r2, r3) and @falling = (f0, f1, f2, f3), the result is
 * @dst = (r0, f0, r1, f1, r2, f2, r3, f3).
 *
 * The MCU receives an interrupt mask and reports a pending interrupt bitmap in
 * this interleaved format. The rationale behind this is that the low-indexed
 * bits are more important - in many cases, the user will be interested only in
 * interrupts with indexes 0 to 7, and so the system can stop reading after
 * first 2 bytes (r0, f0), to save time on the slow I2C bus.
 *
 * Feel free to remove this function and its inverse, omnia_mask_deinterleave,
 * and use an appropriate bitmap_*() function once such a function exists.
 */
static void
omnia_mask_interleave(u8 *dst, unsigned long rising, unsigned long falling)
{}

/**
 * omnia_mask_deinterleave - Deinterleaves the bytes into @rising and @falling
 * @src: the source u8 array containing the interleaved bytes
 * @rising: pointer where to store the rising mask gathered from @src
 * @falling: pointer where to store the falling mask gathered from @src
 *
 * This is the inverse function to omnia_mask_interleave.
 */
static void omnia_mask_deinterleave(const u8 *src, unsigned long *rising,
				    unsigned long *falling)
{}

static void omnia_irq_bus_sync_unlock(struct irq_data *d)
{}

static const struct irq_chip omnia_mcu_irq_chip =;

static void omnia_irq_init_valid_mask(struct gpio_chip *gc,
				      unsigned long *valid_mask,
				      unsigned int ngpios)
{}

static int omnia_irq_init_hw(struct gpio_chip *gc)
{}

/*
 * Determine how many bytes we need to read from the reply to the
 * OMNIA_CMD_GET_INT_AND_CLEAR command in order to retrieve all unmasked
 * interrupts.
 */
static unsigned int
omnia_irq_compute_pending_length(unsigned long rising, unsigned long falling)
{}

static bool omnia_irq_read_pending_new(struct omnia_mcu *mcu,
				       unsigned long *pending)
{}

static int omnia_read_status_word_old_fw(struct omnia_mcu *mcu,
					 unsigned long *status)
{}

static void button_release_emul_fn(struct work_struct *work)
{}

static void
fill_int_from_sts(unsigned long *rising, unsigned long *falling,
		  unsigned long rising_sts, unsigned long falling_sts,
		  unsigned long sts_bit, unsigned long int_bit)
{}

static bool omnia_irq_read_pending_old(struct omnia_mcu *mcu,
				       unsigned long *pending)
{}

static bool omnia_irq_read_pending(struct omnia_mcu *mcu,
				   unsigned long *pending)
{}

static irqreturn_t omnia_irq_thread_handler(int irq, void *dev_id)
{}

static const char * const front_button_modes[] =;

static ssize_t front_button_mode_show(struct device *dev,
				      struct device_attribute *a, char *buf)
{}

static ssize_t front_button_mode_store(struct device *dev,
				       struct device_attribute *a,
				       const char *buf, size_t count)
{}
static DEVICE_ATTR_RW(front_button_mode);

static struct attribute *omnia_mcu_gpio_attrs[] =;

const struct attribute_group omnia_mcu_gpio_group =;

int omnia_mcu_register_gpiochip(struct omnia_mcu *mcu)
{}