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 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 
omnia_cmd_write(const struct i2c_client * client,void * cmd,unsigned int len)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 
omnia_cmd_write_u8(const struct i2c_client * client,u8 cmd,u8 val)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 
omnia_cmd_write_u16(const struct i2c_client * client,u8 cmd,u16 val)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 
omnia_cmd_write_u32(const struct i2c_client * client,u8 cmd,u32 val)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 
omnia_cmd_read(const struct i2c_client * client,u8 cmd,void * reply,unsigned int len)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
omnia_compute_reply_length(unsigned long mask,bool interleaved,unsigned int offset)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 */
omnia_cmd_read_bits(const struct i2c_client * client,u8 cmd,unsigned long bits,unsigned long * dst)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 
omnia_cmd_read_bit(const struct i2c_client * client,u8 cmd,unsigned long bit)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 
omnia_cmd_read_u32(const struct i2c_client * client,u8 cmd,u32 * dst)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 
omnia_cmd_read_u16(const struct i2c_client * client,u8 cmd,u16 * dst)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 
omnia_cmd_read_u8(const struct i2c_client * client,u8 cmd,u8 * reply)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
omnia_mcu_register_gpiochip(struct omnia_mcu * mcu)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
omnia_mcu_register_sys_off_and_wakeup(struct omnia_mcu * mcu)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
omnia_mcu_register_trng(struct omnia_mcu * mcu)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
omnia_mcu_register_watchdog(struct omnia_mcu * mcu)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