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 #ifdef CONFIG_TURRIS_OMNIA_MCU_GPIO 37 /* GPIO chip */ 38 struct gpio_chip gc; 39 struct mutex lock; 40 unsigned long mask, rising, falling, both, cached, is_cached; 41 /* Old MCU firmware handling needs the following */ 42 struct delayed_work button_release_emul_work; 43 unsigned long last_status; 44 bool button_pressed_emul; 45 #endif 46 47 #ifdef CONFIG_TURRIS_OMNIA_MCU_SYSOFF_WAKEUP 48 /* RTC device for configuring wake-up */ 49 struct rtc_device *rtcdev; 50 u32 rtc_alarm; 51 bool front_button_poweron; 52 #endif 53 54 #ifdef CONFIG_TURRIS_OMNIA_MCU_WATCHDOG 55 /* MCU watchdog */ 56 struct watchdog_device wdt; 57 #endif 58 59 #ifdef CONFIG_TURRIS_OMNIA_MCU_TRNG 60 /* true random number generator */ 61 struct hwrng trng; 62 struct completion trng_entropy_ready; 63 #endif 64 }; 65 66 int omnia_cmd_write_read(const struct i2c_client *client, 67 void *cmd, unsigned int cmd_len, 68 void *reply, unsigned int reply_len); 69 70 static inline int omnia_cmd_write(const struct i2c_client *client, void *cmd, 71 unsigned int len) 72 { 73 return omnia_cmd_write_read(client, cmd, len, NULL, 0); 74 } 75 76 static inline int omnia_cmd_write_u8(const struct i2c_client *client, u8 cmd, 77 u8 val) 78 { 79 u8 buf[2] = { cmd, val }; 80 81 return omnia_cmd_write(client, buf, sizeof(buf)); 82 } 83 84 static inline int omnia_cmd_write_u16(const struct i2c_client *client, u8 cmd, 85 u16 val) 86 { 87 u8 buf[3]; 88 89 buf[0] = cmd; 90 put_unaligned_le16(val, &buf[1]); 91 92 return omnia_cmd_write(client, buf, sizeof(buf)); 93 } 94 95 static inline int omnia_cmd_write_u32(const struct i2c_client *client, u8 cmd, 96 u32 val) 97 { 98 u8 buf[5]; 99 100 buf[0] = cmd; 101 put_unaligned_le32(val, &buf[1]); 102 103 return omnia_cmd_write(client, buf, sizeof(buf)); 104 } 105 106 static inline int omnia_cmd_read(const struct i2c_client *client, u8 cmd, 107 void *reply, unsigned int len) 108 { 109 return omnia_cmd_write_read(client, &cmd, 1, reply, len); 110 } 111 112 static inline unsigned int 113 omnia_compute_reply_length(unsigned long mask, bool interleaved, 114 unsigned int offset) 115 { 116 if (!mask) 117 return 0; 118 119 return ((__fls(mask) >> 3) << interleaved) + 1 + offset; 120 } 121 122 /* Returns 0 on success */ 123 static inline int omnia_cmd_read_bits(const struct i2c_client *client, u8 cmd, 124 unsigned long bits, unsigned long *dst) 125 { 126 __le32 reply; 127 int err; 128 129 if (!bits) { 130 *dst = 0; 131 return 0; 132 } 133 134 err = omnia_cmd_read(client, cmd, &reply, 135 omnia_compute_reply_length(bits, false, 0)); 136 if (err) 137 return err; 138 139 *dst = le32_to_cpu(reply) & bits; 140 141 return 0; 142 } 143 144 static inline int omnia_cmd_read_bit(const struct i2c_client *client, u8 cmd, 145 unsigned long bit) 146 { 147 unsigned long reply; 148 int err; 149 150 err = omnia_cmd_read_bits(client, cmd, bit, &reply); 151 if (err) 152 return err; 153 154 return !!reply; 155 } 156 157 static inline int omnia_cmd_read_u32(const struct i2c_client *client, u8 cmd, 158 u32 *dst) 159 { 160 __le32 reply; 161 int err; 162 163 err = omnia_cmd_read(client, cmd, &reply, sizeof(reply)); 164 if (err) 165 return err; 166 167 *dst = le32_to_cpu(reply); 168 169 return 0; 170 } 171 172 static inline int omnia_cmd_read_u16(const struct i2c_client *client, u8 cmd, 173 u16 *dst) 174 { 175 __le16 reply; 176 int err; 177 178 err = omnia_cmd_read(client, cmd, &reply, sizeof(reply)); 179 if (err) 180 return err; 181 182 *dst = le16_to_cpu(reply); 183 184 return 0; 185 } 186 187 static inline int omnia_cmd_read_u8(const struct i2c_client *client, u8 cmd, 188 u8 *reply) 189 { 190 return omnia_cmd_read(client, cmd, reply, sizeof(*reply)); 191 } 192 193 #ifdef CONFIG_TURRIS_OMNIA_MCU_GPIO 194 extern const u8 omnia_int_to_gpio_idx[32]; 195 extern const struct attribute_group omnia_mcu_gpio_group; 196 int omnia_mcu_register_gpiochip(struct omnia_mcu *mcu); 197 #else 198 static inline int omnia_mcu_register_gpiochip(struct omnia_mcu *mcu) 199 { 200 return 0; 201 } 202 #endif 203 204 #ifdef CONFIG_TURRIS_OMNIA_MCU_SYSOFF_WAKEUP 205 extern const struct attribute_group omnia_mcu_poweroff_group; 206 int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu); 207 #else 208 static inline int omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu *mcu) 209 { 210 return 0; 211 } 212 #endif 213 214 #ifdef CONFIG_TURRIS_OMNIA_MCU_TRNG 215 int omnia_mcu_register_trng(struct omnia_mcu *mcu); 216 #else 217 static inline int omnia_mcu_register_trng(struct omnia_mcu *mcu) 218 { 219 return 0; 220 } 221 #endif 222 223 #ifdef CONFIG_TURRIS_OMNIA_MCU_WATCHDOG 224 int omnia_mcu_register_watchdog(struct omnia_mcu *mcu); 225 #else 226 static inline int omnia_mcu_register_watchdog(struct omnia_mcu *mcu) 227 { 228 return 0; 229 } 230 #endif 231 232 #endif /* __TURRIS_OMNIA_MCU_H */ 233