2024-07-01 13:30:04 +02:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
|
|
|
/*
|
|
|
|
* CZ.NIC's Turris Omnia MCU driver
|
|
|
|
*
|
|
|
|
* 2024 by Marek Behún <kabel@kernel.org>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef __TURRIS_OMNIA_MCU_H
|
|
|
|
#define __TURRIS_OMNIA_MCU_H
|
|
|
|
|
2024-07-01 13:30:05 +02:00
|
|
|
#include <linux/bitops.h>
|
2024-07-01 13:30:08 +02:00
|
|
|
#include <linux/completion.h>
|
2024-07-01 13:30:05 +02:00
|
|
|
#include <linux/gpio/driver.h>
|
2024-07-01 13:30:08 +02:00
|
|
|
#include <linux/hw_random.h>
|
2024-07-01 13:30:04 +02:00
|
|
|
#include <linux/if_ether.h>
|
2024-07-01 13:30:05 +02:00
|
|
|
#include <linux/mutex.h>
|
2024-07-01 13:30:04 +02:00
|
|
|
#include <linux/types.h>
|
2024-07-01 13:30:07 +02:00
|
|
|
#include <linux/watchdog.h>
|
2024-07-01 13:30:05 +02:00
|
|
|
#include <linux/workqueue.h>
|
2024-07-01 13:30:04 +02:00
|
|
|
#include <asm/byteorder.h>
|
2024-07-01 13:30:06 +02:00
|
|
|
#include <asm/unaligned.h>
|
2024-07-01 13:30:04 +02:00
|
|
|
|
|
|
|
struct i2c_client;
|
2024-07-01 13:30:06 +02:00
|
|
|
struct rtc_device;
|
2024-07-01 13:30:04 +02:00
|
|
|
|
|
|
|
struct omnia_mcu {
|
|
|
|
struct i2c_client *client;
|
|
|
|
const char *type;
|
|
|
|
u32 features;
|
|
|
|
|
|
|
|
/* board information */
|
|
|
|
u64 board_serial_number;
|
|
|
|
u8 board_first_mac[ETH_ALEN];
|
|
|
|
u8 board_revision;
|
2024-07-01 13:30:05 +02:00
|
|
|
|
|
|
|
/* 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;
|
2024-07-01 13:30:06 +02:00
|
|
|
|
|
|
|
/* RTC device for configuring wake-up */
|
|
|
|
struct rtc_device *rtcdev;
|
|
|
|
u32 rtc_alarm;
|
|
|
|
bool front_button_poweron;
|
2024-07-01 13:30:07 +02:00
|
|
|
|
2024-07-19 10:57:53 +02:00
|
|
|
#ifdef CONFIG_TURRIS_OMNIA_MCU_WATCHDOG
|
2024-07-01 13:30:07 +02:00
|
|
|
/* MCU watchdog */
|
|
|
|
struct watchdog_device wdt;
|
2024-07-19 10:57:53 +02:00
|
|
|
#endif
|
2024-07-01 13:30:08 +02:00
|
|
|
|
2024-07-19 10:57:54 +02:00
|
|
|
#ifdef CONFIG_TURRIS_OMNIA_MCU_TRNG
|
2024-07-01 13:30:08 +02:00
|
|
|
/* true random number generator */
|
|
|
|
struct hwrng trng;
|
|
|
|
struct completion trng_entropy_ready;
|
2024-07-19 10:57:54 +02:00
|
|
|
#endif
|
2024-07-01 13:30:04 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
int omnia_cmd_write_read(const struct i2c_client *client,
|
|
|
|
void *cmd, unsigned int cmd_len,
|
|
|
|
void *reply, unsigned int reply_len);
|
|
|
|
|
2024-07-01 13:30:05 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2024-07-01 13:30:07 +02:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2024-07-01 13:30:06 +02:00
|
|
|
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));
|
|
|
|
}
|
|
|
|
|
2024-07-01 13:30:04 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2024-07-01 13:30:05 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2024-07-01 13:30:04 +02:00
|
|
|
static inline int omnia_cmd_read_u32(const struct i2c_client *client, u8 cmd,
|
|
|
|
u32 *dst)
|
|
|
|
{
|
|
|
|
__le32 reply;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = omnia_cmd_read(client, cmd, &reply, sizeof(reply));
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
*dst = le32_to_cpu(reply);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int omnia_cmd_read_u16(const struct i2c_client *client, u8 cmd,
|
|
|
|
u16 *dst)
|
|
|
|
{
|
|
|
|
__le16 reply;
|
|
|
|
int err;
|
|
|
|
|
|
|
|
err = omnia_cmd_read(client, cmd, &reply, sizeof(reply));
|
|
|
|
if (err)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
*dst = le16_to_cpu(reply);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd,
|
|
|
|
u8 *reply)
|
|
|
|
{
|
|
|
|
return omnia_cmd_read(client, cmd, reply, sizeof(*reply));
|
|
|
|
}
|
|
|
|
|
2024-07-01 13:30:08 +02:00
|
|
|
extern const u8 omnia_int_to_gpio_idx[32];
|
2024-07-01 13:30:05 +02:00
|
|
|
extern const struct attribute_group omnia_mcu_gpio_group;
|
2024-07-01 13:30:06 +02:00
|
|
|
extern const struct attribute_group omnia_mcu_poweroff_group;
|
2024-07-01 13:30:05 +02:00
|
|
|
|
|
|
|
int omnia_mcu_register_gpiochip(struct omnia_mcu *mcu);
|
2024-07-01 13:30:06 +02:00
|
|
|
int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu);
|
2024-07-19 10:57:54 +02:00
|
|
|
|
|
|
|
#ifdef CONFIG_TURRIS_OMNIA_MCU_TRNG
|
2024-07-01 13:30:08 +02:00
|
|
|
int omnia_mcu_register_trng(struct omnia_mcu *mcu);
|
2024-07-19 10:57:54 +02:00
|
|
|
#else
|
|
|
|
static inline int omnia_mcu_register_trng(struct omnia_mcu *mcu)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
2024-07-19 10:57:53 +02:00
|
|
|
|
|
|
|
#ifdef CONFIG_TURRIS_OMNIA_MCU_WATCHDOG
|
2024-07-01 13:30:07 +02:00
|
|
|
int omnia_mcu_register_watchdog(struct omnia_mcu *mcu);
|
2024-07-19 10:57:53 +02:00
|
|
|
#else
|
|
|
|
static inline int omnia_mcu_register_watchdog(struct omnia_mcu *mcu)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
2024-07-01 13:30:05 +02:00
|
|
|
|
2024-07-01 13:30:04 +02:00
|
|
|
#endif /* __TURRIS_OMNIA_MCU_H */
|