1 /* SPDX-License-Identifier: GPL-2.0 */ 2 /* 3 * CZ.NIC's Turris Omnia MCU driver 4 * 5 * 2024 by Marek Behún <kabel@kernel.org> 6 */ 7 8 #ifndef __TURRIS_OMNIA_MCU_H 9 #define __TURRIS_OMNIA_MCU_H 10 11 #include <linux/bitops.h> 12 #include <linux/completion.h> 13 #include <linux/gpio/driver.h> 14 #include <linux/hw_random.h> 15 #include <linux/if_ether.h> 16 #include <linux/mutex.h> 17 #include <linux/types.h> 18 #include <linux/watchdog.h> 19 #include <linux/workqueue.h> 20 #include <asm/byteorder.h> 21 #include <asm/unaligned.h> 22 23 struct i2c_client; 24 struct rtc_device; 25 26 struct omnia_mcu { 27 struct i2c_client *client; 28 const char *type; 29 u32 features; 30 31 /* board information */ 32 u64 board_serial_number; 33 u8 board_first_mac[ETH_ALEN]; 34 u8 board_revision; 35 36 /* GPIO chip */ 37 struct gpio_chip gc; 38 struct mutex lock; 39 unsigned long mask, rising, falling, both, cached, is_cached; 40 /* Old MCU firmware handling needs the following */ 41 struct delayed_work button_release_emul_work; 42 unsigned long last_status; 43 bool button_pressed_emul; 44 45 /* RTC device for configuring wake-up */ 46 struct rtc_device *rtcdev; 47 u32 rtc_alarm; 48 bool front_button_poweron; 49 50 /* MCU watchdog */ 51 struct watchdog_device wdt; 52 53 /* true random number generator */ 54 struct hwrng trng; 55 struct completion trng_entropy_ready; 56 }; 57 58 int omnia_cmd_write_read(const struct i2c_client *client, 59 void *cmd, unsigned int cmd_len, 60 void *reply, unsigned int reply_len); 61 62 static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd, 63 unsigned int len) 64 { 65 return omnia_cmd_write_read(client, cmd, len, NULL, 0); 66 } 67 68 static inline int omnia_cmd_write_u8(const struct i2c_client *client, u8 cmd, 69 u8 val) 70 { 71 u8 buf[2] = { cmd, val }; 72 73 return omnia_cmd_write(client, buf, sizeof(buf)); 74 } 75 76 static inline int omnia_cmd_write_u16(const struct i2c_client *client, u8 cmd, 77 u16 val) 78 { 79 u8 buf[3]; 80 81 buf[0] = cmd; 82 put_unaligned_le16(val, &buf[1]); 83 84 return omnia_cmd_write(client, buf, sizeof(buf)); 85 } 86 87 static inline int omnia_cmd_write_u32(const struct i2c_client *client, u8 cmd, 88 u32 val) 89 { 90 u8 buf[5]; 91 92 buf[0] = cmd; 93 put_unaligned_le32(val, &buf[1]); 94 95 return omnia_cmd_write(client, buf, sizeof(buf)); 96 } 97 98 static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd, 99 void *reply, unsigned int len) 100 { 101 return omnia_cmd_write_read(client, &cmd, 1, reply, len); 102 } 103 104 static inline unsigned int 105 omnia_compute_reply_length(unsigned long mask, bool interleaved, 106 unsigned int offset) 107 { 108 if (!mask) 109 return 0; 110 111 return ((__fls(mask) >> 3) << interleaved) + 1 + offset; 112 } 113 114 /* Returns 0 on success */ 115 static inline int omnia_cmd_read_bits(const struct i2c_client *client, u8 cmd, 116 unsigned long bits, unsigned long *dst) 117 { 118 __le32 reply; 119 int err; 120 121 if (!bits) { 122 *dst = 0; 123 return 0; 124 } 125 126 err = omnia_cmd_read(client, cmd, &reply, 127 omnia_compute_reply_length(bits, false, 0)); 128 if (err) 129 return err; 130 131 *dst = le32_to_cpu(reply) & bits; 132 133 return 0; 134 } 135 136 static inline int omnia_cmd_read_bit(const struct i2c_client *client, u8 cmd, 137 unsigned long bit) 138 { 139 unsigned long reply; 140 int err; 141 142 err = omnia_cmd_read_bits(client, cmd, bit, &reply); 143 if (err) 144 return err; 145 146 return !!reply; 147 } 148 149 static inline int omnia_cmd_read_u32(const struct i2c_client *client, u8 cmd, 150 u32 *dst) 151 { 152 __le32 reply; 153 int err; 154 155 err = omnia_cmd_read(client, cmd, &reply, sizeof(reply)); 156 if (err) 157 return err; 158 159 *dst = le32_to_cpu(reply); 160 161 return 0; 162 } 163 164 static inline int omnia_cmd_read_u16(const struct i2c_client *client, u8 cmd, 165 u16 *dst) 166 { 167 __le16 reply; 168 int err; 169 170 err = omnia_cmd_read(client, cmd, &reply, sizeof(reply)); 171 if (err) 172 return err; 173 174 *dst = le16_to_cpu(reply); 175 176 return 0; 177 } 178 179 static inline int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd, 180 u8 *reply) 181 { 182 return omnia_cmd_read(client, cmd, reply, sizeof(*reply)); 183 } 184 185 extern const u8 omnia_int_to_gpio_idx[32]; 186 extern const struct attribute_group omnia_mcu_gpio_group; 187 extern const struct attribute_group omnia_mcu_poweroff_group; 188 189 int omnia_mcu_register_gpiochip(struct omnia_mcu *mcu); 190 int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu); 191 int omnia_mcu_register_trng(struct omnia_mcu *mcu); 192 int omnia_mcu_register_watchdog(struct omnia_mcu *mcu); 193 194 #endif /* __TURRIS_OMNIA_MCU_H */ 195