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 <linux/unaligned.h> 22 23 struct i2c_client; 24 struct rtc_device; 25 26 /** 27 * struct omnia_mcu - driver private data structure 28 * @client: I2C client 29 * @type: MCU type (STM32, GD32, MKL, or unknown) 30 * @features: bitmap of features supported by the MCU firmware 31 * @board_serial_number: board serial number, if stored in MCU 32 * @board_first_mac: board first MAC address, if stored in MCU 33 * @board_revision: board revision, if stored in MCU 34 * @gc: GPIO chip 35 * @lock: mutex to protect internal GPIO chip state 36 * @mask: bitmap of masked IRQs 37 * @rising: bitmap of rising edge IRQs 38 * @falling: bitmap of falling edge IRQs 39 * @both: bitmap of both edges IRQs 40 * @cached: bitmap of cached IRQ line values (when an IRQ line is configured for 41 * both edges, we cache the corresponding GPIO values in the IRQ 42 * handler) 43 * @is_cached: bitmap of which IRQ line values are cached 44 * @button_release_emul_work: front button release emulation work, used with old MCU firmware 45 * versions which did not send button release events, only button press 46 * events 47 * @last_status: cached value of the status word, to be compared with new value to 48 * determine which interrupt events occurred, used with old MCU 49 * firmware versions which only informed that the status word changed, 50 * but not which bits of the status word changed 51 * @button_pressed_emul: the front button is still emulated to be pressed 52 * @rtcdev: RTC device, does not actually count real-time, the device is only 53 * used for the RTC alarm mechanism, so that the board can be 54 * configured to wake up from poweroff state at a specific time 55 * @rtc_alarm: RTC alarm that was set for the board to wake up on, in MCU time 56 * (seconds since last MCU reset) 57 * @front_button_poweron: the front button should power on the device after it is powered off 58 * @wdt: watchdog driver structure 59 * @trng: RNG driver structure 60 * @trng_entropy_ready: RNG entropy ready completion 61 */ 62 struct omnia_mcu { 63 struct i2c_client *client; 64 const char *type; 65 u32 features; 66 67 u64 board_serial_number; 68 u8 board_first_mac[ETH_ALEN]; 69 u8 board_revision; 70 71 #ifdef CONFIG_TURRIS_OMNIA_MCU_GPIO 72 struct gpio_chip gc; 73 struct mutex lock; 74 unsigned long mask, rising, falling, both, cached, is_cached; 75 struct delayed_work button_release_emul_work; 76 unsigned long last_status; 77 bool button_pressed_emul; 78 #endif 79 80 #ifdef CONFIG_TURRIS_OMNIA_MCU_SYSOFF_WAKEUP 81 struct rtc_device *rtcdev; 82 u32 rtc_alarm; 83 bool front_button_poweron; 84 #endif 85 86 #ifdef CONFIG_TURRIS_OMNIA_MCU_WATCHDOG 87 struct watchdog_device wdt; 88 #endif 89 90 #ifdef CONFIG_TURRIS_OMNIA_MCU_TRNG 91 struct hwrng trng; 92 struct completion trng_entropy_ready; 93 #endif 94 }; 95 96 int omnia_cmd_write_read(const struct i2c_client *client, 97 void *cmd, unsigned int cmd_len, 98 void *reply, unsigned int reply_len); 99 100 static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd, 101 unsigned int len) 102 { 103 return omnia_cmd_write_read(client, cmd, len, NULL, 0); 104 } 105 106 static inline int omnia_cmd_write_u8(const struct i2c_client *client, u8 cmd, 107 u8 val) 108 { 109 u8 buf[2] = { cmd, val }; 110 111 return omnia_cmd_write(client, buf, sizeof(buf)); 112 } 113 114 static inline int omnia_cmd_write_u16(const struct i2c_client *client, u8 cmd, 115 u16 val) 116 { 117 u8 buf[3]; 118 119 buf[0] = cmd; 120 put_unaligned_le16(val, &buf[1]); 121 122 return omnia_cmd_write(client, buf, sizeof(buf)); 123 } 124 125 static inline int omnia_cmd_write_u32(const struct i2c_client *client, u8 cmd, 126 u32 val) 127 { 128 u8 buf[5]; 129 130 buf[0] = cmd; 131 put_unaligned_le32(val, &buf[1]); 132 133 return omnia_cmd_write(client, buf, sizeof(buf)); 134 } 135 136 static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd, 137 void *reply, unsigned int len) 138 { 139 return omnia_cmd_write_read(client, &cmd, 1, reply, len); 140 } 141 142 static inline unsigned int 143 omnia_compute_reply_length(unsigned long mask, bool interleaved, 144 unsigned int offset) 145 { 146 if (!mask) 147 return 0; 148 149 return ((__fls(mask) >> 3) << interleaved) + 1 + offset; 150 } 151 152 /* Returns 0 on success */ 153 static inline int omnia_cmd_read_bits(const struct i2c_client *client, u8 cmd, 154 unsigned long bits, unsigned long *dst) 155 { 156 __le32 reply; 157 int err; 158 159 if (!bits) { 160 *dst = 0; 161 return 0; 162 } 163 164 err = omnia_cmd_read(client, cmd, &reply, 165 omnia_compute_reply_length(bits, false, 0)); 166 if (err) 167 return err; 168 169 *dst = le32_to_cpu(reply) & bits; 170 171 return 0; 172 } 173 174 static inline int omnia_cmd_read_bit(const struct i2c_client *client, u8 cmd, 175 unsigned long bit) 176 { 177 unsigned long reply; 178 int err; 179 180 err = omnia_cmd_read_bits(client, cmd, bit, &reply); 181 if (err) 182 return err; 183 184 return !!reply; 185 } 186 187 static inline int omnia_cmd_read_u32(const struct i2c_client *client, u8 cmd, 188 u32 *dst) 189 { 190 __le32 reply; 191 int err; 192 193 err = omnia_cmd_read(client, cmd, &reply, sizeof(reply)); 194 if (err) 195 return err; 196 197 *dst = le32_to_cpu(reply); 198 199 return 0; 200 } 201 202 static inline int omnia_cmd_read_u16(const struct i2c_client *client, u8 cmd, 203 u16 *dst) 204 { 205 __le16 reply; 206 int err; 207 208 err = omnia_cmd_read(client, cmd, &reply, sizeof(reply)); 209 if (err) 210 return err; 211 212 *dst = le16_to_cpu(reply); 213 214 return 0; 215 } 216 217 static inline int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd, 218 u8 *reply) 219 { 220 return omnia_cmd_read(client, cmd, reply, sizeof(*reply)); 221 } 222 223 #ifdef CONFIG_TURRIS_OMNIA_MCU_GPIO 224 extern const u8 omnia_int_to_gpio_idx[32]; 225 extern const struct attribute_group omnia_mcu_gpio_group; 226 int omnia_mcu_register_gpiochip(struct omnia_mcu *mcu); 227 #else 228 static inline int omnia_mcu_register_gpiochip(struct omnia_mcu *mcu) 229 { 230 return 0; 231 } 232 #endif 233 234 #ifdef CONFIG_TURRIS_OMNIA_MCU_SYSOFF_WAKEUP 235 extern const struct attribute_group omnia_mcu_poweroff_group; 236 int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu); 237 #else 238 static inline int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu) 239 { 240 return 0; 241 } 242 #endif 243 244 #ifdef CONFIG_TURRIS_OMNIA_MCU_TRNG 245 int omnia_mcu_register_trng(struct omnia_mcu *mcu); 246 #else 247 static inline int omnia_mcu_register_trng(struct omnia_mcu *mcu) 248 { 249 return 0; 250 } 251 #endif 252 253 #ifdef CONFIG_TURRIS_OMNIA_MCU_WATCHDOG 254 int omnia_mcu_register_watchdog(struct omnia_mcu *mcu); 255 #else 256 static inline int omnia_mcu_register_watchdog(struct omnia_mcu *mcu) 257 { 258 return 0; 259 } 260 #endif 261 262 #endif /* __TURRIS_OMNIA_MCU_H */ 263