xref: /linux/drivers/platform/cznic/turris-omnia-mcu.h (revision d40981350844c2cfa437abfc80596e10ea8f1149)
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