xref: /linux/drivers/platform/cznic/turris-omnia-mcu-gpio.c (revision dfa556e45ae9ecc199e598222debc8f1883a7cce)
1*dfa556e4SMarek Behún // SPDX-License-Identifier: GPL-2.0
2*dfa556e4SMarek Behún /*
3*dfa556e4SMarek Behún  * CZ.NIC's Turris Omnia MCU GPIO and IRQ driver
4*dfa556e4SMarek Behún  *
5*dfa556e4SMarek Behún  * 2024 by Marek Behún <kabel@kernel.org>
6*dfa556e4SMarek Behún  */
7*dfa556e4SMarek Behún 
8*dfa556e4SMarek Behún #include <linux/array_size.h>
9*dfa556e4SMarek Behún #include <linux/bitfield.h>
10*dfa556e4SMarek Behún #include <linux/bitops.h>
11*dfa556e4SMarek Behún #include <linux/bug.h>
12*dfa556e4SMarek Behún #include <linux/cleanup.h>
13*dfa556e4SMarek Behún #include <linux/device.h>
14*dfa556e4SMarek Behún #include <linux/devm-helpers.h>
15*dfa556e4SMarek Behún #include <linux/errno.h>
16*dfa556e4SMarek Behún #include <linux/gpio/driver.h>
17*dfa556e4SMarek Behún #include <linux/i2c.h>
18*dfa556e4SMarek Behún #include <linux/interrupt.h>
19*dfa556e4SMarek Behún #include <linux/mutex.h>
20*dfa556e4SMarek Behún #include <linux/sysfs.h>
21*dfa556e4SMarek Behún #include <linux/types.h>
22*dfa556e4SMarek Behún #include <linux/workqueue.h>
23*dfa556e4SMarek Behún #include <asm/unaligned.h>
24*dfa556e4SMarek Behún 
25*dfa556e4SMarek Behún #include <linux/turris-omnia-mcu-interface.h>
26*dfa556e4SMarek Behún #include "turris-omnia-mcu.h"
27*dfa556e4SMarek Behún 
28*dfa556e4SMarek Behún #define OMNIA_CMD_INT_ARG_LEN		8
29*dfa556e4SMarek Behún #define FRONT_BUTTON_RELEASE_DELAY_MS	50
30*dfa556e4SMarek Behún 
31*dfa556e4SMarek Behún static const char * const omnia_mcu_gpio_templates[64] = {
32*dfa556e4SMarek Behún 	/* GPIOs with value read from the 16-bit wide status */
33*dfa556e4SMarek Behún 	[4]  = "MiniPCIe0 Card Detect",
34*dfa556e4SMarek Behún 	[5]  = "MiniPCIe0 mSATA Indicator",
35*dfa556e4SMarek Behún 	[6]  = "Front USB3 port over-current",
36*dfa556e4SMarek Behún 	[7]  = "Rear USB3 port over-current",
37*dfa556e4SMarek Behún 	[8]  = "Front USB3 port power",
38*dfa556e4SMarek Behún 	[9]  = "Rear USB3 port power",
39*dfa556e4SMarek Behún 	[12] = "Front Button",
40*dfa556e4SMarek Behún 
41*dfa556e4SMarek Behún 	/* GPIOs with value read from the 32-bit wide extended status */
42*dfa556e4SMarek Behún 	[16] = "SFP nDET",
43*dfa556e4SMarek Behún 	[28] = "MiniPCIe0 LED",
44*dfa556e4SMarek Behún 	[29] = "MiniPCIe1 LED",
45*dfa556e4SMarek Behún 	[30] = "MiniPCIe2 LED",
46*dfa556e4SMarek Behún 	[31] = "MiniPCIe0 PAN LED",
47*dfa556e4SMarek Behún 	[32] = "MiniPCIe1 PAN LED",
48*dfa556e4SMarek Behún 	[33] = "MiniPCIe2 PAN LED",
49*dfa556e4SMarek Behún 	[34] = "WAN PHY LED0",
50*dfa556e4SMarek Behún 	[35] = "WAN PHY LED1",
51*dfa556e4SMarek Behún 	[36] = "LAN switch p0 LED0",
52*dfa556e4SMarek Behún 	[37] = "LAN switch p0 LED1",
53*dfa556e4SMarek Behún 	[38] = "LAN switch p1 LED0",
54*dfa556e4SMarek Behún 	[39] = "LAN switch p1 LED1",
55*dfa556e4SMarek Behún 	[40] = "LAN switch p2 LED0",
56*dfa556e4SMarek Behún 	[41] = "LAN switch p2 LED1",
57*dfa556e4SMarek Behún 	[42] = "LAN switch p3 LED0",
58*dfa556e4SMarek Behún 	[43] = "LAN switch p3 LED1",
59*dfa556e4SMarek Behún 	[44] = "LAN switch p4 LED0",
60*dfa556e4SMarek Behún 	[45] = "LAN switch p4 LED1",
61*dfa556e4SMarek Behún 	[46] = "LAN switch p5 LED0",
62*dfa556e4SMarek Behún 	[47] = "LAN switch p5 LED1",
63*dfa556e4SMarek Behún 
64*dfa556e4SMarek Behún 	/* GPIOs with value read from the 16-bit wide extended control status */
65*dfa556e4SMarek Behún 	[48] = "eMMC nRESET",
66*dfa556e4SMarek Behún 	[49] = "LAN switch nRESET",
67*dfa556e4SMarek Behún 	[50] = "WAN PHY nRESET",
68*dfa556e4SMarek Behún 	[51] = "MiniPCIe0 nPERST",
69*dfa556e4SMarek Behún 	[52] = "MiniPCIe1 nPERST",
70*dfa556e4SMarek Behún 	[53] = "MiniPCIe2 nPERST",
71*dfa556e4SMarek Behún 	[54] = "WAN PHY SFP mux",
72*dfa556e4SMarek Behún 	[56] = "VHV power disable",
73*dfa556e4SMarek Behún };
74*dfa556e4SMarek Behún 
75*dfa556e4SMarek Behún struct omnia_gpio {
76*dfa556e4SMarek Behún 	u8 cmd;
77*dfa556e4SMarek Behún 	u8 ctl_cmd;
78*dfa556e4SMarek Behún 	u8 bit;
79*dfa556e4SMarek Behún 	u8 ctl_bit;
80*dfa556e4SMarek Behún 	u8 int_bit;
81*dfa556e4SMarek Behún 	u16 feat;
82*dfa556e4SMarek Behún 	u16 feat_mask;
83*dfa556e4SMarek Behún };
84*dfa556e4SMarek Behún 
85*dfa556e4SMarek Behún #define OMNIA_GPIO_INVALID_INT_BIT	0xff
86*dfa556e4SMarek Behún 
87*dfa556e4SMarek Behún #define _DEF_GPIO(_cmd, _ctl_cmd, _bit, _ctl_bit, _int_bit, _feat, _feat_mask) \
88*dfa556e4SMarek Behún 	{								\
89*dfa556e4SMarek Behún 		.cmd = _cmd,						\
90*dfa556e4SMarek Behún 		.ctl_cmd = _ctl_cmd,					\
91*dfa556e4SMarek Behún 		.bit = _bit,						\
92*dfa556e4SMarek Behún 		.ctl_bit = _ctl_bit,					\
93*dfa556e4SMarek Behún 		.int_bit = (_int_bit) < 0 ? OMNIA_GPIO_INVALID_INT_BIT	\
94*dfa556e4SMarek Behún 					  : (_int_bit),			\
95*dfa556e4SMarek Behún 		.feat = _feat,						\
96*dfa556e4SMarek Behún 		.feat_mask = _feat_mask,				\
97*dfa556e4SMarek Behún 	}
98*dfa556e4SMarek Behún 
99*dfa556e4SMarek Behún #define _DEF_GPIO_STS(_name) \
100*dfa556e4SMarek Behún 	_DEF_GPIO(OMNIA_CMD_GET_STATUS_WORD, 0, __bf_shf(OMNIA_STS_ ## _name), \
101*dfa556e4SMarek Behún 		  0, __bf_shf(OMNIA_INT_ ## _name), 0, 0)
102*dfa556e4SMarek Behún 
103*dfa556e4SMarek Behún #define _DEF_GPIO_CTL(_name) \
104*dfa556e4SMarek Behún 	_DEF_GPIO(OMNIA_CMD_GET_STATUS_WORD, OMNIA_CMD_GENERAL_CONTROL, \
105*dfa556e4SMarek Behún 		  __bf_shf(OMNIA_STS_ ## _name), __bf_shf(OMNIA_CTL_ ## _name), \
106*dfa556e4SMarek Behún 		  -1, 0, 0)
107*dfa556e4SMarek Behún 
108*dfa556e4SMarek Behún #define _DEF_GPIO_EXT_STS(_name, _feat) \
109*dfa556e4SMarek Behún 	_DEF_GPIO(OMNIA_CMD_GET_EXT_STATUS_DWORD, 0, \
110*dfa556e4SMarek Behún 		  __bf_shf(OMNIA_EXT_STS_ ## _name), 0, \
111*dfa556e4SMarek Behún 		  __bf_shf(OMNIA_INT_ ## _name), \
112*dfa556e4SMarek Behún 		  OMNIA_FEAT_ ## _feat | OMNIA_FEAT_EXT_CMDS, \
113*dfa556e4SMarek Behún 		  OMNIA_FEAT_ ## _feat | OMNIA_FEAT_EXT_CMDS)
114*dfa556e4SMarek Behún 
115*dfa556e4SMarek Behún #define _DEF_GPIO_EXT_STS_LED(_name, _ledext) \
116*dfa556e4SMarek Behún 	_DEF_GPIO(OMNIA_CMD_GET_EXT_STATUS_DWORD, 0, \
117*dfa556e4SMarek Behún 		  __bf_shf(OMNIA_EXT_STS_ ## _name), 0, \
118*dfa556e4SMarek Behún 		  __bf_shf(OMNIA_INT_ ## _name), \
119*dfa556e4SMarek Behún 		  OMNIA_FEAT_LED_STATE_ ## _ledext, \
120*dfa556e4SMarek Behún 		  OMNIA_FEAT_LED_STATE_EXT_MASK)
121*dfa556e4SMarek Behún 
122*dfa556e4SMarek Behún #define _DEF_GPIO_EXT_STS_LEDALL(_name) \
123*dfa556e4SMarek Behún 	_DEF_GPIO(OMNIA_CMD_GET_EXT_STATUS_DWORD, 0, \
124*dfa556e4SMarek Behún 		  __bf_shf(OMNIA_EXT_STS_ ## _name), 0, \
125*dfa556e4SMarek Behún 		  __bf_shf(OMNIA_INT_ ## _name), \
126*dfa556e4SMarek Behún 		  OMNIA_FEAT_LED_STATE_EXT_MASK, 0)
127*dfa556e4SMarek Behún 
128*dfa556e4SMarek Behún #define _DEF_GPIO_EXT_CTL(_name, _feat) \
129*dfa556e4SMarek Behún 	_DEF_GPIO(OMNIA_CMD_GET_EXT_CONTROL_STATUS, OMNIA_CMD_EXT_CONTROL, \
130*dfa556e4SMarek Behún 		  __bf_shf(OMNIA_EXT_CTL_ ## _name), \
131*dfa556e4SMarek Behún 		  __bf_shf(OMNIA_EXT_CTL_ ## _name), -1, \
132*dfa556e4SMarek Behún 		  OMNIA_FEAT_ ## _feat | OMNIA_FEAT_EXT_CMDS, \
133*dfa556e4SMarek Behún 		  OMNIA_FEAT_ ## _feat | OMNIA_FEAT_EXT_CMDS)
134*dfa556e4SMarek Behún 
135*dfa556e4SMarek Behún #define _DEF_INT(_name) \
136*dfa556e4SMarek Behún 	_DEF_GPIO(0, 0, 0, 0, __bf_shf(OMNIA_INT_ ## _name), 0, 0)
137*dfa556e4SMarek Behún 
138*dfa556e4SMarek Behún static inline bool is_int_bit_valid(const struct omnia_gpio *gpio)
139*dfa556e4SMarek Behún {
140*dfa556e4SMarek Behún 	return gpio->int_bit != OMNIA_GPIO_INVALID_INT_BIT;
141*dfa556e4SMarek Behún }
142*dfa556e4SMarek Behún 
143*dfa556e4SMarek Behún static const struct omnia_gpio omnia_gpios[64] = {
144*dfa556e4SMarek Behún 	/* GPIOs with value read from the 16-bit wide status */
145*dfa556e4SMarek Behún 	[4]  = _DEF_GPIO_STS(CARD_DET),
146*dfa556e4SMarek Behún 	[5]  = _DEF_GPIO_STS(MSATA_IND),
147*dfa556e4SMarek Behún 	[6]  = _DEF_GPIO_STS(USB30_OVC),
148*dfa556e4SMarek Behún 	[7]  = _DEF_GPIO_STS(USB31_OVC),
149*dfa556e4SMarek Behún 	[8]  = _DEF_GPIO_CTL(USB30_PWRON),
150*dfa556e4SMarek Behún 	[9]  = _DEF_GPIO_CTL(USB31_PWRON),
151*dfa556e4SMarek Behún 
152*dfa556e4SMarek Behún 	/* brightness changed interrupt, no GPIO */
153*dfa556e4SMarek Behún 	[11] = _DEF_INT(BRIGHTNESS_CHANGED),
154*dfa556e4SMarek Behún 
155*dfa556e4SMarek Behún 	[12] = _DEF_GPIO_STS(BUTTON_PRESSED),
156*dfa556e4SMarek Behún 
157*dfa556e4SMarek Behún 	/* TRNG interrupt, no GPIO */
158*dfa556e4SMarek Behún 	[13] = _DEF_INT(TRNG),
159*dfa556e4SMarek Behún 
160*dfa556e4SMarek Behún 	/* MESSAGE_SIGNED interrupt, no GPIO */
161*dfa556e4SMarek Behún 	[14] = _DEF_INT(MESSAGE_SIGNED),
162*dfa556e4SMarek Behún 
163*dfa556e4SMarek Behún 	/* GPIOs with value read from the 32-bit wide extended status */
164*dfa556e4SMarek Behún 	[16] = _DEF_GPIO_EXT_STS(SFP_nDET, PERIPH_MCU),
165*dfa556e4SMarek Behún 	[28] = _DEF_GPIO_EXT_STS_LEDALL(WLAN0_MSATA_LED),
166*dfa556e4SMarek Behún 	[29] = _DEF_GPIO_EXT_STS_LEDALL(WLAN1_LED),
167*dfa556e4SMarek Behún 	[30] = _DEF_GPIO_EXT_STS_LEDALL(WLAN2_LED),
168*dfa556e4SMarek Behún 	[31] = _DEF_GPIO_EXT_STS_LED(WPAN0_LED, EXT),
169*dfa556e4SMarek Behún 	[32] = _DEF_GPIO_EXT_STS_LED(WPAN1_LED, EXT),
170*dfa556e4SMarek Behún 	[33] = _DEF_GPIO_EXT_STS_LED(WPAN2_LED, EXT),
171*dfa556e4SMarek Behún 	[34] = _DEF_GPIO_EXT_STS_LEDALL(WAN_LED0),
172*dfa556e4SMarek Behún 	[35] = _DEF_GPIO_EXT_STS_LED(WAN_LED1, EXT_V32),
173*dfa556e4SMarek Behún 	[36] = _DEF_GPIO_EXT_STS_LEDALL(LAN0_LED0),
174*dfa556e4SMarek Behún 	[37] = _DEF_GPIO_EXT_STS_LEDALL(LAN0_LED1),
175*dfa556e4SMarek Behún 	[38] = _DEF_GPIO_EXT_STS_LEDALL(LAN1_LED0),
176*dfa556e4SMarek Behún 	[39] = _DEF_GPIO_EXT_STS_LEDALL(LAN1_LED1),
177*dfa556e4SMarek Behún 	[40] = _DEF_GPIO_EXT_STS_LEDALL(LAN2_LED0),
178*dfa556e4SMarek Behún 	[41] = _DEF_GPIO_EXT_STS_LEDALL(LAN2_LED1),
179*dfa556e4SMarek Behún 	[42] = _DEF_GPIO_EXT_STS_LEDALL(LAN3_LED0),
180*dfa556e4SMarek Behún 	[43] = _DEF_GPIO_EXT_STS_LEDALL(LAN3_LED1),
181*dfa556e4SMarek Behún 	[44] = _DEF_GPIO_EXT_STS_LEDALL(LAN4_LED0),
182*dfa556e4SMarek Behún 	[45] = _DEF_GPIO_EXT_STS_LEDALL(LAN4_LED1),
183*dfa556e4SMarek Behún 	[46] = _DEF_GPIO_EXT_STS_LEDALL(LAN5_LED0),
184*dfa556e4SMarek Behún 	[47] = _DEF_GPIO_EXT_STS_LEDALL(LAN5_LED1),
185*dfa556e4SMarek Behún 
186*dfa556e4SMarek Behún 	/* GPIOs with value read from the 16-bit wide extended control status */
187*dfa556e4SMarek Behún 	[48] = _DEF_GPIO_EXT_CTL(nRES_MMC, PERIPH_MCU),
188*dfa556e4SMarek Behún 	[49] = _DEF_GPIO_EXT_CTL(nRES_LAN, PERIPH_MCU),
189*dfa556e4SMarek Behún 	[50] = _DEF_GPIO_EXT_CTL(nRES_PHY, PERIPH_MCU),
190*dfa556e4SMarek Behún 	[51] = _DEF_GPIO_EXT_CTL(nPERST0, PERIPH_MCU),
191*dfa556e4SMarek Behún 	[52] = _DEF_GPIO_EXT_CTL(nPERST1, PERIPH_MCU),
192*dfa556e4SMarek Behún 	[53] = _DEF_GPIO_EXT_CTL(nPERST2, PERIPH_MCU),
193*dfa556e4SMarek Behún 	[54] = _DEF_GPIO_EXT_CTL(PHY_SFP, PERIPH_MCU),
194*dfa556e4SMarek Behún 	[56] = _DEF_GPIO_EXT_CTL(nVHV_CTRL, PERIPH_MCU),
195*dfa556e4SMarek Behún };
196*dfa556e4SMarek Behún 
197*dfa556e4SMarek Behún /* mapping from interrupts to indexes of GPIOs in the omnia_gpios array */
198*dfa556e4SMarek Behún static const u8 omnia_int_to_gpio_idx[32] = {
199*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_CARD_DET)]			= 4,
200*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_MSATA_IND)]			= 5,
201*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_USB30_OVC)]			= 6,
202*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_USB31_OVC)]			= 7,
203*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_BUTTON_PRESSED)]		= 12,
204*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_TRNG)]			= 13,
205*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_MESSAGE_SIGNED)]		= 14,
206*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_SFP_nDET)]			= 16,
207*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_BRIGHTNESS_CHANGED)]	= 11,
208*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_WLAN0_MSATA_LED)]		= 28,
209*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_WLAN1_LED)]			= 29,
210*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_WLAN2_LED)]			= 30,
211*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_WPAN0_LED)]			= 31,
212*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_WPAN1_LED)]			= 32,
213*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_WPAN2_LED)]			= 33,
214*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_WAN_LED0)]			= 34,
215*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_WAN_LED1)]			= 35,
216*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_LAN0_LED0)]			= 36,
217*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_LAN0_LED1)]			= 37,
218*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_LAN1_LED0)]			= 38,
219*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_LAN1_LED1)]			= 39,
220*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_LAN2_LED0)]			= 40,
221*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_LAN2_LED1)]			= 41,
222*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_LAN3_LED0)]			= 42,
223*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_LAN3_LED1)]			= 43,
224*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_LAN4_LED0)]			= 44,
225*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_LAN4_LED1)]			= 45,
226*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_LAN5_LED0)]			= 46,
227*dfa556e4SMarek Behún 	[__bf_shf(OMNIA_INT_LAN5_LED1)]			= 47,
228*dfa556e4SMarek Behún };
229*dfa556e4SMarek Behún 
230*dfa556e4SMarek Behún /* index of PHY_SFP GPIO in the omnia_gpios array */
231*dfa556e4SMarek Behún #define OMNIA_GPIO_PHY_SFP_OFFSET	54
232*dfa556e4SMarek Behún 
233*dfa556e4SMarek Behún static int omnia_ctl_cmd_locked(struct omnia_mcu *mcu, u8 cmd, u16 val, u16 mask)
234*dfa556e4SMarek Behún {
235*dfa556e4SMarek Behún 	unsigned int len;
236*dfa556e4SMarek Behún 	u8 buf[5];
237*dfa556e4SMarek Behún 
238*dfa556e4SMarek Behún 	buf[0] = cmd;
239*dfa556e4SMarek Behún 
240*dfa556e4SMarek Behún 	switch (cmd) {
241*dfa556e4SMarek Behún 	case OMNIA_CMD_GENERAL_CONTROL:
242*dfa556e4SMarek Behún 		buf[1] = val;
243*dfa556e4SMarek Behún 		buf[2] = mask;
244*dfa556e4SMarek Behún 		len = 3;
245*dfa556e4SMarek Behún 		break;
246*dfa556e4SMarek Behún 
247*dfa556e4SMarek Behún 	case OMNIA_CMD_EXT_CONTROL:
248*dfa556e4SMarek Behún 		put_unaligned_le16(val, &buf[1]);
249*dfa556e4SMarek Behún 		put_unaligned_le16(mask, &buf[3]);
250*dfa556e4SMarek Behún 		len = 5;
251*dfa556e4SMarek Behún 		break;
252*dfa556e4SMarek Behún 
253*dfa556e4SMarek Behún 	default:
254*dfa556e4SMarek Behún 		BUG();
255*dfa556e4SMarek Behún 	}
256*dfa556e4SMarek Behún 
257*dfa556e4SMarek Behún 	return omnia_cmd_write(mcu->client, buf, len);
258*dfa556e4SMarek Behún }
259*dfa556e4SMarek Behún 
260*dfa556e4SMarek Behún static int omnia_ctl_cmd(struct omnia_mcu *mcu, u8 cmd, u16 val, u16 mask)
261*dfa556e4SMarek Behún {
262*dfa556e4SMarek Behún 	guard(mutex)(&mcu->lock);
263*dfa556e4SMarek Behún 
264*dfa556e4SMarek Behún 	return omnia_ctl_cmd_locked(mcu, cmd, val, mask);
265*dfa556e4SMarek Behún }
266*dfa556e4SMarek Behún 
267*dfa556e4SMarek Behún static int omnia_gpio_request(struct gpio_chip *gc, unsigned int offset)
268*dfa556e4SMarek Behún {
269*dfa556e4SMarek Behún 	if (!omnia_gpios[offset].cmd)
270*dfa556e4SMarek Behún 		return -EINVAL;
271*dfa556e4SMarek Behún 
272*dfa556e4SMarek Behún 	return 0;
273*dfa556e4SMarek Behún }
274*dfa556e4SMarek Behún 
275*dfa556e4SMarek Behún static int omnia_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
276*dfa556e4SMarek Behún {
277*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = gpiochip_get_data(gc);
278*dfa556e4SMarek Behún 
279*dfa556e4SMarek Behún 	if (offset == OMNIA_GPIO_PHY_SFP_OFFSET) {
280*dfa556e4SMarek Behún 		int val;
281*dfa556e4SMarek Behún 
282*dfa556e4SMarek Behún 		scoped_guard(mutex, &mcu->lock) {
283*dfa556e4SMarek Behún 			val = omnia_cmd_read_bit(mcu->client,
284*dfa556e4SMarek Behún 						 OMNIA_CMD_GET_EXT_CONTROL_STATUS,
285*dfa556e4SMarek Behún 						 OMNIA_EXT_CTL_PHY_SFP_AUTO);
286*dfa556e4SMarek Behún 			if (val < 0)
287*dfa556e4SMarek Behún 				return val;
288*dfa556e4SMarek Behún 		}
289*dfa556e4SMarek Behún 
290*dfa556e4SMarek Behún 		if (val)
291*dfa556e4SMarek Behún 			return GPIO_LINE_DIRECTION_IN;
292*dfa556e4SMarek Behún 
293*dfa556e4SMarek Behún 		return GPIO_LINE_DIRECTION_OUT;
294*dfa556e4SMarek Behún 	}
295*dfa556e4SMarek Behún 
296*dfa556e4SMarek Behún 	if (omnia_gpios[offset].ctl_cmd)
297*dfa556e4SMarek Behún 		return GPIO_LINE_DIRECTION_OUT;
298*dfa556e4SMarek Behún 
299*dfa556e4SMarek Behún 	return GPIO_LINE_DIRECTION_IN;
300*dfa556e4SMarek Behún }
301*dfa556e4SMarek Behún 
302*dfa556e4SMarek Behún static int omnia_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
303*dfa556e4SMarek Behún {
304*dfa556e4SMarek Behún 	const struct omnia_gpio *gpio = &omnia_gpios[offset];
305*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = gpiochip_get_data(gc);
306*dfa556e4SMarek Behún 
307*dfa556e4SMarek Behún 	if (offset == OMNIA_GPIO_PHY_SFP_OFFSET)
308*dfa556e4SMarek Behún 		return omnia_ctl_cmd(mcu, OMNIA_CMD_EXT_CONTROL,
309*dfa556e4SMarek Behún 				     OMNIA_EXT_CTL_PHY_SFP_AUTO,
310*dfa556e4SMarek Behún 				     OMNIA_EXT_CTL_PHY_SFP_AUTO);
311*dfa556e4SMarek Behún 
312*dfa556e4SMarek Behún 	if (gpio->ctl_cmd)
313*dfa556e4SMarek Behún 		return -ENOTSUPP;
314*dfa556e4SMarek Behún 
315*dfa556e4SMarek Behún 	return 0;
316*dfa556e4SMarek Behún }
317*dfa556e4SMarek Behún 
318*dfa556e4SMarek Behún static int omnia_gpio_direction_output(struct gpio_chip *gc,
319*dfa556e4SMarek Behún 				       unsigned int offset, int value)
320*dfa556e4SMarek Behún {
321*dfa556e4SMarek Behún 	const struct omnia_gpio *gpio = &omnia_gpios[offset];
322*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = gpiochip_get_data(gc);
323*dfa556e4SMarek Behún 	u16 val, mask;
324*dfa556e4SMarek Behún 
325*dfa556e4SMarek Behún 	if (!gpio->ctl_cmd)
326*dfa556e4SMarek Behún 		return -ENOTSUPP;
327*dfa556e4SMarek Behún 
328*dfa556e4SMarek Behún 	mask = BIT(gpio->ctl_bit);
329*dfa556e4SMarek Behún 	val = value ? mask : 0;
330*dfa556e4SMarek Behún 
331*dfa556e4SMarek Behún 	if (offset == OMNIA_GPIO_PHY_SFP_OFFSET)
332*dfa556e4SMarek Behún 		mask |= OMNIA_EXT_CTL_PHY_SFP_AUTO;
333*dfa556e4SMarek Behún 
334*dfa556e4SMarek Behún 	return omnia_ctl_cmd(mcu, gpio->ctl_cmd, val, mask);
335*dfa556e4SMarek Behún }
336*dfa556e4SMarek Behún 
337*dfa556e4SMarek Behún static int omnia_gpio_get(struct gpio_chip *gc, unsigned int offset)
338*dfa556e4SMarek Behún {
339*dfa556e4SMarek Behún 	const struct omnia_gpio *gpio = &omnia_gpios[offset];
340*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = gpiochip_get_data(gc);
341*dfa556e4SMarek Behún 
342*dfa556e4SMarek Behún 	/*
343*dfa556e4SMarek Behún 	 * If firmware does not support the new interrupt API, we are informed
344*dfa556e4SMarek Behún 	 * of every change of the status word by an interrupt from MCU and save
345*dfa556e4SMarek Behún 	 * its value in the interrupt service routine. Simply return the saved
346*dfa556e4SMarek Behún 	 * value.
347*dfa556e4SMarek Behún 	 */
348*dfa556e4SMarek Behún 	if (gpio->cmd == OMNIA_CMD_GET_STATUS_WORD &&
349*dfa556e4SMarek Behún 	    !(mcu->features & OMNIA_FEAT_NEW_INT_API))
350*dfa556e4SMarek Behún 		return test_bit(gpio->bit, &mcu->last_status);
351*dfa556e4SMarek Behún 
352*dfa556e4SMarek Behún 	guard(mutex)(&mcu->lock);
353*dfa556e4SMarek Behún 
354*dfa556e4SMarek Behún 	/*
355*dfa556e4SMarek Behún 	 * If firmware does support the new interrupt API, we may have cached
356*dfa556e4SMarek Behún 	 * the value of a GPIO in the interrupt service routine. If not, read
357*dfa556e4SMarek Behún 	 * the relevant bit now.
358*dfa556e4SMarek Behún 	 */
359*dfa556e4SMarek Behún 	if (is_int_bit_valid(gpio) && test_bit(gpio->int_bit, &mcu->is_cached))
360*dfa556e4SMarek Behún 		return test_bit(gpio->int_bit, &mcu->cached);
361*dfa556e4SMarek Behún 
362*dfa556e4SMarek Behún 	return omnia_cmd_read_bit(mcu->client, gpio->cmd, BIT(gpio->bit));
363*dfa556e4SMarek Behún }
364*dfa556e4SMarek Behún 
365*dfa556e4SMarek Behún static unsigned long *
366*dfa556e4SMarek Behún _relevant_field_for_sts_cmd(u8 cmd, unsigned long *sts, unsigned long *ext_sts,
367*dfa556e4SMarek Behún 			    unsigned long *ext_ctl)
368*dfa556e4SMarek Behún {
369*dfa556e4SMarek Behún 	switch (cmd) {
370*dfa556e4SMarek Behún 	case OMNIA_CMD_GET_STATUS_WORD:
371*dfa556e4SMarek Behún 		return sts;
372*dfa556e4SMarek Behún 	case OMNIA_CMD_GET_EXT_STATUS_DWORD:
373*dfa556e4SMarek Behún 		return ext_sts;
374*dfa556e4SMarek Behún 	case OMNIA_CMD_GET_EXT_CONTROL_STATUS:
375*dfa556e4SMarek Behún 		return ext_ctl;
376*dfa556e4SMarek Behún 	default:
377*dfa556e4SMarek Behún 		return NULL;
378*dfa556e4SMarek Behún 	}
379*dfa556e4SMarek Behún }
380*dfa556e4SMarek Behún 
381*dfa556e4SMarek Behún static int omnia_gpio_get_multiple(struct gpio_chip *gc, unsigned long *mask,
382*dfa556e4SMarek Behún 				   unsigned long *bits)
383*dfa556e4SMarek Behún {
384*dfa556e4SMarek Behún 	unsigned long sts = 0, ext_sts = 0, ext_ctl = 0, *field;
385*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = gpiochip_get_data(gc);
386*dfa556e4SMarek Behún 	struct i2c_client *client = mcu->client;
387*dfa556e4SMarek Behún 	unsigned int i;
388*dfa556e4SMarek Behún 	int err;
389*dfa556e4SMarek Behún 
390*dfa556e4SMarek Behún 	/* determine which bits to read from the 3 possible commands */
391*dfa556e4SMarek Behún 	for_each_set_bit(i, mask, ARRAY_SIZE(omnia_gpios)) {
392*dfa556e4SMarek Behún 		field = _relevant_field_for_sts_cmd(omnia_gpios[i].cmd,
393*dfa556e4SMarek Behún 						    &sts, &ext_sts, &ext_ctl);
394*dfa556e4SMarek Behún 		if (!field)
395*dfa556e4SMarek Behún 			continue;
396*dfa556e4SMarek Behún 
397*dfa556e4SMarek Behún 		__set_bit(omnia_gpios[i].bit, field);
398*dfa556e4SMarek Behún 	}
399*dfa556e4SMarek Behún 
400*dfa556e4SMarek Behún 	guard(mutex)(&mcu->lock);
401*dfa556e4SMarek Behún 
402*dfa556e4SMarek Behún 	if (mcu->features & OMNIA_FEAT_NEW_INT_API) {
403*dfa556e4SMarek Behún 		/* read relevant bits from status */
404*dfa556e4SMarek Behún 		err = omnia_cmd_read_bits(client, OMNIA_CMD_GET_STATUS_WORD,
405*dfa556e4SMarek Behún 					  sts, &sts);
406*dfa556e4SMarek Behún 		if (err)
407*dfa556e4SMarek Behún 			return err;
408*dfa556e4SMarek Behún 	} else {
409*dfa556e4SMarek Behún 		/*
410*dfa556e4SMarek Behún 		 * Use status word value cached in the interrupt service routine
411*dfa556e4SMarek Behún 		 * if firmware does not support the new interrupt API.
412*dfa556e4SMarek Behún 		 */
413*dfa556e4SMarek Behún 		sts = mcu->last_status;
414*dfa556e4SMarek Behún 	}
415*dfa556e4SMarek Behún 
416*dfa556e4SMarek Behún 	/* read relevant bits from extended status */
417*dfa556e4SMarek Behún 	err = omnia_cmd_read_bits(client, OMNIA_CMD_GET_EXT_STATUS_DWORD,
418*dfa556e4SMarek Behún 				  ext_sts, &ext_sts);
419*dfa556e4SMarek Behún 	if (err)
420*dfa556e4SMarek Behún 		return err;
421*dfa556e4SMarek Behún 
422*dfa556e4SMarek Behún 	/* read relevant bits from extended control */
423*dfa556e4SMarek Behún 	err = omnia_cmd_read_bits(client, OMNIA_CMD_GET_EXT_CONTROL_STATUS,
424*dfa556e4SMarek Behún 				  ext_ctl, &ext_ctl);
425*dfa556e4SMarek Behún 	if (err)
426*dfa556e4SMarek Behún 		return err;
427*dfa556e4SMarek Behún 
428*dfa556e4SMarek Behún 	/* assign relevant bits in result */
429*dfa556e4SMarek Behún 	for_each_set_bit(i, mask, ARRAY_SIZE(omnia_gpios)) {
430*dfa556e4SMarek Behún 		field = _relevant_field_for_sts_cmd(omnia_gpios[i].cmd,
431*dfa556e4SMarek Behún 						    &sts, &ext_sts, &ext_ctl);
432*dfa556e4SMarek Behún 		if (!field)
433*dfa556e4SMarek Behún 			continue;
434*dfa556e4SMarek Behún 
435*dfa556e4SMarek Behún 		__assign_bit(i, bits, test_bit(omnia_gpios[i].bit, field));
436*dfa556e4SMarek Behún 	}
437*dfa556e4SMarek Behún 
438*dfa556e4SMarek Behún 	return 0;
439*dfa556e4SMarek Behún }
440*dfa556e4SMarek Behún 
441*dfa556e4SMarek Behún static void omnia_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
442*dfa556e4SMarek Behún {
443*dfa556e4SMarek Behún 	const struct omnia_gpio *gpio = &omnia_gpios[offset];
444*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = gpiochip_get_data(gc);
445*dfa556e4SMarek Behún 	u16 val, mask;
446*dfa556e4SMarek Behún 
447*dfa556e4SMarek Behún 	if (!gpio->ctl_cmd)
448*dfa556e4SMarek Behún 		return;
449*dfa556e4SMarek Behún 
450*dfa556e4SMarek Behún 	mask = BIT(gpio->ctl_bit);
451*dfa556e4SMarek Behún 	val = value ? mask : 0;
452*dfa556e4SMarek Behún 
453*dfa556e4SMarek Behún 	omnia_ctl_cmd(mcu, gpio->ctl_cmd, val, mask);
454*dfa556e4SMarek Behún }
455*dfa556e4SMarek Behún 
456*dfa556e4SMarek Behún static void omnia_gpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
457*dfa556e4SMarek Behún 				    unsigned long *bits)
458*dfa556e4SMarek Behún {
459*dfa556e4SMarek Behún 	unsigned long ctl = 0, ctl_mask = 0, ext_ctl = 0, ext_ctl_mask = 0;
460*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = gpiochip_get_data(gc);
461*dfa556e4SMarek Behún 	unsigned int i;
462*dfa556e4SMarek Behún 
463*dfa556e4SMarek Behún 	for_each_set_bit(i, mask, ARRAY_SIZE(omnia_gpios)) {
464*dfa556e4SMarek Behún 		unsigned long *field, *field_mask;
465*dfa556e4SMarek Behún 		u8 bit = omnia_gpios[i].ctl_bit;
466*dfa556e4SMarek Behún 
467*dfa556e4SMarek Behún 		switch (omnia_gpios[i].ctl_cmd) {
468*dfa556e4SMarek Behún 		case OMNIA_CMD_GENERAL_CONTROL:
469*dfa556e4SMarek Behún 			field = &ctl;
470*dfa556e4SMarek Behún 			field_mask = &ctl_mask;
471*dfa556e4SMarek Behún 			break;
472*dfa556e4SMarek Behún 		case OMNIA_CMD_EXT_CONTROL:
473*dfa556e4SMarek Behún 			field = &ext_ctl;
474*dfa556e4SMarek Behún 			field_mask = &ext_ctl_mask;
475*dfa556e4SMarek Behún 			break;
476*dfa556e4SMarek Behún 		default:
477*dfa556e4SMarek Behún 			field = field_mask = NULL;
478*dfa556e4SMarek Behún 			break;
479*dfa556e4SMarek Behún 		}
480*dfa556e4SMarek Behún 
481*dfa556e4SMarek Behún 		if (!field)
482*dfa556e4SMarek Behún 			continue;
483*dfa556e4SMarek Behún 
484*dfa556e4SMarek Behún 		__set_bit(bit, field_mask);
485*dfa556e4SMarek Behún 		__assign_bit(bit, field, test_bit(i, bits));
486*dfa556e4SMarek Behún 	}
487*dfa556e4SMarek Behún 
488*dfa556e4SMarek Behún 	guard(mutex)(&mcu->lock);
489*dfa556e4SMarek Behún 
490*dfa556e4SMarek Behún 	if (ctl_mask)
491*dfa556e4SMarek Behún 		omnia_ctl_cmd_locked(mcu, OMNIA_CMD_GENERAL_CONTROL,
492*dfa556e4SMarek Behún 				     ctl, ctl_mask);
493*dfa556e4SMarek Behún 
494*dfa556e4SMarek Behún 	if (ext_ctl_mask)
495*dfa556e4SMarek Behún 		omnia_ctl_cmd_locked(mcu, OMNIA_CMD_EXT_CONTROL,
496*dfa556e4SMarek Behún 				     ext_ctl, ext_ctl_mask);
497*dfa556e4SMarek Behún }
498*dfa556e4SMarek Behún 
499*dfa556e4SMarek Behún static bool omnia_gpio_available(struct omnia_mcu *mcu,
500*dfa556e4SMarek Behún 				 const struct omnia_gpio *gpio)
501*dfa556e4SMarek Behún {
502*dfa556e4SMarek Behún 	if (gpio->feat_mask)
503*dfa556e4SMarek Behún 		return (mcu->features & gpio->feat_mask) == gpio->feat;
504*dfa556e4SMarek Behún 
505*dfa556e4SMarek Behún 	if (gpio->feat)
506*dfa556e4SMarek Behún 		return mcu->features & gpio->feat;
507*dfa556e4SMarek Behún 
508*dfa556e4SMarek Behún 	return true;
509*dfa556e4SMarek Behún }
510*dfa556e4SMarek Behún 
511*dfa556e4SMarek Behún static int omnia_gpio_init_valid_mask(struct gpio_chip *gc,
512*dfa556e4SMarek Behún 				      unsigned long *valid_mask,
513*dfa556e4SMarek Behún 				      unsigned int ngpios)
514*dfa556e4SMarek Behún {
515*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = gpiochip_get_data(gc);
516*dfa556e4SMarek Behún 
517*dfa556e4SMarek Behún 	for (unsigned int i = 0; i < ngpios; i++) {
518*dfa556e4SMarek Behún 		const struct omnia_gpio *gpio = &omnia_gpios[i];
519*dfa556e4SMarek Behún 
520*dfa556e4SMarek Behún 		if (gpio->cmd || is_int_bit_valid(gpio))
521*dfa556e4SMarek Behún 			__assign_bit(i, valid_mask,
522*dfa556e4SMarek Behún 				     omnia_gpio_available(mcu, gpio));
523*dfa556e4SMarek Behún 		else
524*dfa556e4SMarek Behún 			__clear_bit(i, valid_mask);
525*dfa556e4SMarek Behún 	}
526*dfa556e4SMarek Behún 
527*dfa556e4SMarek Behún 	return 0;
528*dfa556e4SMarek Behún }
529*dfa556e4SMarek Behún 
530*dfa556e4SMarek Behún static int omnia_gpio_of_xlate(struct gpio_chip *gc,
531*dfa556e4SMarek Behún 			       const struct of_phandle_args *gpiospec,
532*dfa556e4SMarek Behún 			       u32 *flags)
533*dfa556e4SMarek Behún {
534*dfa556e4SMarek Behún 	u32 bank, gpio;
535*dfa556e4SMarek Behún 
536*dfa556e4SMarek Behún 	if (WARN_ON(gpiospec->args_count != 3))
537*dfa556e4SMarek Behún 		return -EINVAL;
538*dfa556e4SMarek Behún 
539*dfa556e4SMarek Behún 	if (flags)
540*dfa556e4SMarek Behún 		*flags = gpiospec->args[2];
541*dfa556e4SMarek Behún 
542*dfa556e4SMarek Behún 	bank = gpiospec->args[0];
543*dfa556e4SMarek Behún 	gpio = gpiospec->args[1];
544*dfa556e4SMarek Behún 
545*dfa556e4SMarek Behún 	switch (bank) {
546*dfa556e4SMarek Behún 	case 0:
547*dfa556e4SMarek Behún 		return gpio < 16 ? gpio : -EINVAL;
548*dfa556e4SMarek Behún 	case 1:
549*dfa556e4SMarek Behún 		return gpio < 32 ? 16 + gpio : -EINVAL;
550*dfa556e4SMarek Behún 	case 2:
551*dfa556e4SMarek Behún 		return gpio < 16 ? 48 + gpio : -EINVAL;
552*dfa556e4SMarek Behún 	default:
553*dfa556e4SMarek Behún 		return -EINVAL;
554*dfa556e4SMarek Behún 	}
555*dfa556e4SMarek Behún }
556*dfa556e4SMarek Behún 
557*dfa556e4SMarek Behún static void omnia_irq_shutdown(struct irq_data *d)
558*dfa556e4SMarek Behún {
559*dfa556e4SMarek Behún 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
560*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = gpiochip_get_data(gc);
561*dfa556e4SMarek Behún 	irq_hw_number_t hwirq = irqd_to_hwirq(d);
562*dfa556e4SMarek Behún 	u8 bit = omnia_gpios[hwirq].int_bit;
563*dfa556e4SMarek Behún 
564*dfa556e4SMarek Behún 	__clear_bit(bit, &mcu->rising);
565*dfa556e4SMarek Behún 	__clear_bit(bit, &mcu->falling);
566*dfa556e4SMarek Behún }
567*dfa556e4SMarek Behún 
568*dfa556e4SMarek Behún static void omnia_irq_mask(struct irq_data *d)
569*dfa556e4SMarek Behún {
570*dfa556e4SMarek Behún 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
571*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = gpiochip_get_data(gc);
572*dfa556e4SMarek Behún 	irq_hw_number_t hwirq = irqd_to_hwirq(d);
573*dfa556e4SMarek Behún 	u8 bit = omnia_gpios[hwirq].int_bit;
574*dfa556e4SMarek Behún 
575*dfa556e4SMarek Behún 	if (!omnia_gpios[hwirq].cmd)
576*dfa556e4SMarek Behún 		__clear_bit(bit, &mcu->rising);
577*dfa556e4SMarek Behún 	__clear_bit(bit, &mcu->mask);
578*dfa556e4SMarek Behún 	gpiochip_disable_irq(gc, hwirq);
579*dfa556e4SMarek Behún }
580*dfa556e4SMarek Behún 
581*dfa556e4SMarek Behún static void omnia_irq_unmask(struct irq_data *d)
582*dfa556e4SMarek Behún {
583*dfa556e4SMarek Behún 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
584*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = gpiochip_get_data(gc);
585*dfa556e4SMarek Behún 	irq_hw_number_t hwirq = irqd_to_hwirq(d);
586*dfa556e4SMarek Behún 	u8 bit = omnia_gpios[hwirq].int_bit;
587*dfa556e4SMarek Behún 
588*dfa556e4SMarek Behún 	gpiochip_enable_irq(gc, hwirq);
589*dfa556e4SMarek Behún 	__set_bit(bit, &mcu->mask);
590*dfa556e4SMarek Behún 	if (!omnia_gpios[hwirq].cmd)
591*dfa556e4SMarek Behún 		__set_bit(bit, &mcu->rising);
592*dfa556e4SMarek Behún }
593*dfa556e4SMarek Behún 
594*dfa556e4SMarek Behún static int omnia_irq_set_type(struct irq_data *d, unsigned int type)
595*dfa556e4SMarek Behún {
596*dfa556e4SMarek Behún 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
597*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = gpiochip_get_data(gc);
598*dfa556e4SMarek Behún 	irq_hw_number_t hwirq = irqd_to_hwirq(d);
599*dfa556e4SMarek Behún 	struct device *dev = &mcu->client->dev;
600*dfa556e4SMarek Behún 	u8 bit = omnia_gpios[hwirq].int_bit;
601*dfa556e4SMarek Behún 
602*dfa556e4SMarek Behún 	if (!(type & IRQ_TYPE_EDGE_BOTH)) {
603*dfa556e4SMarek Behún 		dev_err(dev, "irq %u: unsupported type %u\n", d->irq, type);
604*dfa556e4SMarek Behún 		return -EINVAL;
605*dfa556e4SMarek Behún 	}
606*dfa556e4SMarek Behún 
607*dfa556e4SMarek Behún 	__assign_bit(bit, &mcu->rising, type & IRQ_TYPE_EDGE_RISING);
608*dfa556e4SMarek Behún 	__assign_bit(bit, &mcu->falling, type & IRQ_TYPE_EDGE_FALLING);
609*dfa556e4SMarek Behún 
610*dfa556e4SMarek Behún 	return 0;
611*dfa556e4SMarek Behún }
612*dfa556e4SMarek Behún 
613*dfa556e4SMarek Behún static void omnia_irq_bus_lock(struct irq_data *d)
614*dfa556e4SMarek Behún {
615*dfa556e4SMarek Behún 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
616*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = gpiochip_get_data(gc);
617*dfa556e4SMarek Behún 
618*dfa556e4SMarek Behún 	/* nothing to do if MCU firmware does not support new interrupt API */
619*dfa556e4SMarek Behún 	if (!(mcu->features & OMNIA_FEAT_NEW_INT_API))
620*dfa556e4SMarek Behún 		return;
621*dfa556e4SMarek Behún 
622*dfa556e4SMarek Behún 	mutex_lock(&mcu->lock);
623*dfa556e4SMarek Behún }
624*dfa556e4SMarek Behún 
625*dfa556e4SMarek Behún /**
626*dfa556e4SMarek Behún  * omnia_mask_interleave - Interleaves the bytes from @rising and @falling
627*dfa556e4SMarek Behún  * @dst: the destination u8 array of interleaved bytes
628*dfa556e4SMarek Behún  * @rising: rising mask
629*dfa556e4SMarek Behún  * @falling: falling mask
630*dfa556e4SMarek Behún  *
631*dfa556e4SMarek Behún  * Interleaves the little-endian bytes from @rising and @falling words.
632*dfa556e4SMarek Behún  *
633*dfa556e4SMarek Behún  * If @rising = (r0, r1, r2, r3) and @falling = (f0, f1, f2, f3), the result is
634*dfa556e4SMarek Behún  * @dst = (r0, f0, r1, f1, r2, f2, r3, f3).
635*dfa556e4SMarek Behún  *
636*dfa556e4SMarek Behún  * The MCU receives an interrupt mask and reports a pending interrupt bitmap in
637*dfa556e4SMarek Behún  * this interleaved format. The rationale behind this is that the low-indexed
638*dfa556e4SMarek Behún  * bits are more important - in many cases, the user will be interested only in
639*dfa556e4SMarek Behún  * interrupts with indexes 0 to 7, and so the system can stop reading after
640*dfa556e4SMarek Behún  * first 2 bytes (r0, f0), to save time on the slow I2C bus.
641*dfa556e4SMarek Behún  *
642*dfa556e4SMarek Behún  * Feel free to remove this function and its inverse, omnia_mask_deinterleave,
643*dfa556e4SMarek Behún  * and use an appropriate bitmap_*() function once such a function exists.
644*dfa556e4SMarek Behún  */
645*dfa556e4SMarek Behún static void
646*dfa556e4SMarek Behún omnia_mask_interleave(u8 *dst, unsigned long rising, unsigned long falling)
647*dfa556e4SMarek Behún {
648*dfa556e4SMarek Behún 	for (unsigned int i = 0; i < sizeof(u32); i++) {
649*dfa556e4SMarek Behún 		dst[2 * i] = rising >> (8 * i);
650*dfa556e4SMarek Behún 		dst[2 * i + 1] = falling >> (8 * i);
651*dfa556e4SMarek Behún 	}
652*dfa556e4SMarek Behún }
653*dfa556e4SMarek Behún 
654*dfa556e4SMarek Behún /**
655*dfa556e4SMarek Behún  * omnia_mask_deinterleave - Deinterleaves the bytes into @rising and @falling
656*dfa556e4SMarek Behún  * @src: the source u8 array containing the interleaved bytes
657*dfa556e4SMarek Behún  * @rising: pointer where to store the rising mask gathered from @src
658*dfa556e4SMarek Behún  * @falling: pointer where to store the falling mask gathered from @src
659*dfa556e4SMarek Behún  *
660*dfa556e4SMarek Behún  * This is the inverse function to omnia_mask_interleave.
661*dfa556e4SMarek Behún  */
662*dfa556e4SMarek Behún static void omnia_mask_deinterleave(const u8 *src, unsigned long *rising,
663*dfa556e4SMarek Behún 				    unsigned long *falling)
664*dfa556e4SMarek Behún {
665*dfa556e4SMarek Behún 	*rising = *falling = 0;
666*dfa556e4SMarek Behún 
667*dfa556e4SMarek Behún 	for (unsigned int i = 0; i < sizeof(u32); i++) {
668*dfa556e4SMarek Behún 		*rising |= src[2 * i] << (8 * i);
669*dfa556e4SMarek Behún 		*falling |= src[2 * i + 1] << (8 * i);
670*dfa556e4SMarek Behún 	}
671*dfa556e4SMarek Behún }
672*dfa556e4SMarek Behún 
673*dfa556e4SMarek Behún static void omnia_irq_bus_sync_unlock(struct irq_data *d)
674*dfa556e4SMarek Behún {
675*dfa556e4SMarek Behún 	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
676*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = gpiochip_get_data(gc);
677*dfa556e4SMarek Behún 	struct device *dev = &mcu->client->dev;
678*dfa556e4SMarek Behún 	u8 cmd[1 + OMNIA_CMD_INT_ARG_LEN];
679*dfa556e4SMarek Behún 	unsigned long rising, falling;
680*dfa556e4SMarek Behún 	int err;
681*dfa556e4SMarek Behún 
682*dfa556e4SMarek Behún 	/* nothing to do if MCU firmware does not support new interrupt API */
683*dfa556e4SMarek Behún 	if (!(mcu->features & OMNIA_FEAT_NEW_INT_API))
684*dfa556e4SMarek Behún 		return;
685*dfa556e4SMarek Behún 
686*dfa556e4SMarek Behún 	cmd[0] = OMNIA_CMD_SET_INT_MASK;
687*dfa556e4SMarek Behún 
688*dfa556e4SMarek Behún 	rising = mcu->rising & mcu->mask;
689*dfa556e4SMarek Behún 	falling = mcu->falling & mcu->mask;
690*dfa556e4SMarek Behún 
691*dfa556e4SMarek Behún 	/* interleave the rising and falling bytes into the command arguments */
692*dfa556e4SMarek Behún 	omnia_mask_interleave(&cmd[1], rising, falling);
693*dfa556e4SMarek Behún 
694*dfa556e4SMarek Behún 	dev_dbg(dev, "set int mask %8ph\n", &cmd[1]);
695*dfa556e4SMarek Behún 
696*dfa556e4SMarek Behún 	err = omnia_cmd_write(mcu->client, cmd, sizeof(cmd));
697*dfa556e4SMarek Behún 	if (err) {
698*dfa556e4SMarek Behún 		dev_err(dev, "Cannot set mask: %d\n", err);
699*dfa556e4SMarek Behún 		goto unlock;
700*dfa556e4SMarek Behún 	}
701*dfa556e4SMarek Behún 
702*dfa556e4SMarek Behún 	/*
703*dfa556e4SMarek Behún 	 * Remember which GPIOs have both rising and falling interrupts enabled.
704*dfa556e4SMarek Behún 	 * For those we will cache their value so that .get() method is faster.
705*dfa556e4SMarek Behún 	 * We also need to forget cached values of GPIOs that aren't cached
706*dfa556e4SMarek Behún 	 * anymore.
707*dfa556e4SMarek Behún 	 */
708*dfa556e4SMarek Behún 	mcu->both = rising & falling;
709*dfa556e4SMarek Behún 	mcu->is_cached &= mcu->both;
710*dfa556e4SMarek Behún 
711*dfa556e4SMarek Behún unlock:
712*dfa556e4SMarek Behún 	mutex_unlock(&mcu->lock);
713*dfa556e4SMarek Behún }
714*dfa556e4SMarek Behún 
715*dfa556e4SMarek Behún static const struct irq_chip omnia_mcu_irq_chip = {
716*dfa556e4SMarek Behún 	.name			= "Turris Omnia MCU interrupts",
717*dfa556e4SMarek Behún 	.irq_shutdown		= omnia_irq_shutdown,
718*dfa556e4SMarek Behún 	.irq_mask		= omnia_irq_mask,
719*dfa556e4SMarek Behún 	.irq_unmask		= omnia_irq_unmask,
720*dfa556e4SMarek Behún 	.irq_set_type		= omnia_irq_set_type,
721*dfa556e4SMarek Behún 	.irq_bus_lock		= omnia_irq_bus_lock,
722*dfa556e4SMarek Behún 	.irq_bus_sync_unlock	= omnia_irq_bus_sync_unlock,
723*dfa556e4SMarek Behún 	.flags			= IRQCHIP_IMMUTABLE,
724*dfa556e4SMarek Behún 	GPIOCHIP_IRQ_RESOURCE_HELPERS,
725*dfa556e4SMarek Behún };
726*dfa556e4SMarek Behún 
727*dfa556e4SMarek Behún static void omnia_irq_init_valid_mask(struct gpio_chip *gc,
728*dfa556e4SMarek Behún 				      unsigned long *valid_mask,
729*dfa556e4SMarek Behún 				      unsigned int ngpios)
730*dfa556e4SMarek Behún {
731*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = gpiochip_get_data(gc);
732*dfa556e4SMarek Behún 
733*dfa556e4SMarek Behún 	for (unsigned int i = 0; i < ngpios; i++) {
734*dfa556e4SMarek Behún 		const struct omnia_gpio *gpio = &omnia_gpios[i];
735*dfa556e4SMarek Behún 
736*dfa556e4SMarek Behún 		if (is_int_bit_valid(gpio))
737*dfa556e4SMarek Behún 			__assign_bit(i, valid_mask,
738*dfa556e4SMarek Behún 				     omnia_gpio_available(mcu, gpio));
739*dfa556e4SMarek Behún 		else
740*dfa556e4SMarek Behún 			__clear_bit(i, valid_mask);
741*dfa556e4SMarek Behún 	}
742*dfa556e4SMarek Behún }
743*dfa556e4SMarek Behún 
744*dfa556e4SMarek Behún static int omnia_irq_init_hw(struct gpio_chip *gc)
745*dfa556e4SMarek Behún {
746*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = gpiochip_get_data(gc);
747*dfa556e4SMarek Behún 	u8 cmd[1 + OMNIA_CMD_INT_ARG_LEN] = {};
748*dfa556e4SMarek Behún 
749*dfa556e4SMarek Behún 	cmd[0] = OMNIA_CMD_SET_INT_MASK;
750*dfa556e4SMarek Behún 
751*dfa556e4SMarek Behún 	return omnia_cmd_write(mcu->client, cmd, sizeof(cmd));
752*dfa556e4SMarek Behún }
753*dfa556e4SMarek Behún 
754*dfa556e4SMarek Behún /*
755*dfa556e4SMarek Behún  * Determine how many bytes we need to read from the reply to the
756*dfa556e4SMarek Behún  * OMNIA_CMD_GET_INT_AND_CLEAR command in order to retrieve all unmasked
757*dfa556e4SMarek Behún  * interrupts.
758*dfa556e4SMarek Behún  */
759*dfa556e4SMarek Behún static unsigned int
760*dfa556e4SMarek Behún omnia_irq_compute_pending_length(unsigned long rising, unsigned long falling)
761*dfa556e4SMarek Behún {
762*dfa556e4SMarek Behún 	return max(omnia_compute_reply_length(rising, true, 0),
763*dfa556e4SMarek Behún 		   omnia_compute_reply_length(falling, true, 1));
764*dfa556e4SMarek Behún }
765*dfa556e4SMarek Behún 
766*dfa556e4SMarek Behún static bool omnia_irq_read_pending_new(struct omnia_mcu *mcu,
767*dfa556e4SMarek Behún 				       unsigned long *pending)
768*dfa556e4SMarek Behún {
769*dfa556e4SMarek Behún 	struct device *dev = &mcu->client->dev;
770*dfa556e4SMarek Behún 	u8 reply[OMNIA_CMD_INT_ARG_LEN] = {};
771*dfa556e4SMarek Behún 	unsigned long rising, falling;
772*dfa556e4SMarek Behún 	unsigned int len;
773*dfa556e4SMarek Behún 	int err;
774*dfa556e4SMarek Behún 
775*dfa556e4SMarek Behún 	len = omnia_irq_compute_pending_length(mcu->rising & mcu->mask,
776*dfa556e4SMarek Behún 					       mcu->falling & mcu->mask);
777*dfa556e4SMarek Behún 	if (!len)
778*dfa556e4SMarek Behún 		return false;
779*dfa556e4SMarek Behún 
780*dfa556e4SMarek Behún 	guard(mutex)(&mcu->lock);
781*dfa556e4SMarek Behún 
782*dfa556e4SMarek Behún 	err = omnia_cmd_read(mcu->client, OMNIA_CMD_GET_INT_AND_CLEAR, reply,
783*dfa556e4SMarek Behún 			     len);
784*dfa556e4SMarek Behún 	if (err) {
785*dfa556e4SMarek Behún 		dev_err(dev, "Cannot read pending IRQs: %d\n", err);
786*dfa556e4SMarek Behún 		return false;
787*dfa556e4SMarek Behún 	}
788*dfa556e4SMarek Behún 
789*dfa556e4SMarek Behún 	/* deinterleave the reply bytes into rising and falling */
790*dfa556e4SMarek Behún 	omnia_mask_deinterleave(reply, &rising, &falling);
791*dfa556e4SMarek Behún 
792*dfa556e4SMarek Behún 	rising &= mcu->mask;
793*dfa556e4SMarek Behún 	falling &= mcu->mask;
794*dfa556e4SMarek Behún 	*pending = rising | falling;
795*dfa556e4SMarek Behún 
796*dfa556e4SMarek Behún 	/* cache values for GPIOs that have both edges enabled */
797*dfa556e4SMarek Behún 	mcu->is_cached &= ~(rising & falling);
798*dfa556e4SMarek Behún 	mcu->is_cached |= mcu->both & (rising ^ falling);
799*dfa556e4SMarek Behún 	mcu->cached = (mcu->cached | rising) & ~falling;
800*dfa556e4SMarek Behún 
801*dfa556e4SMarek Behún 	return true;
802*dfa556e4SMarek Behún }
803*dfa556e4SMarek Behún 
804*dfa556e4SMarek Behún static int omnia_read_status_word_old_fw(struct omnia_mcu *mcu,
805*dfa556e4SMarek Behún 					 unsigned long *status)
806*dfa556e4SMarek Behún {
807*dfa556e4SMarek Behún 	u16 raw_status;
808*dfa556e4SMarek Behún 	int err;
809*dfa556e4SMarek Behún 
810*dfa556e4SMarek Behún 	err = omnia_cmd_read_u16(mcu->client, OMNIA_CMD_GET_STATUS_WORD,
811*dfa556e4SMarek Behún 				 &raw_status);
812*dfa556e4SMarek Behún 	if (err)
813*dfa556e4SMarek Behún 		return err;
814*dfa556e4SMarek Behún 
815*dfa556e4SMarek Behún 	/*
816*dfa556e4SMarek Behún 	 * Old firmware has a bug wherein it never resets the USB port
817*dfa556e4SMarek Behún 	 * overcurrent bits back to zero. Ignore them.
818*dfa556e4SMarek Behún 	 */
819*dfa556e4SMarek Behún 	*status = raw_status & ~(OMNIA_STS_USB30_OVC | OMNIA_STS_USB31_OVC);
820*dfa556e4SMarek Behún 
821*dfa556e4SMarek Behún 	return 0;
822*dfa556e4SMarek Behún }
823*dfa556e4SMarek Behún 
824*dfa556e4SMarek Behún static void button_release_emul_fn(struct work_struct *work)
825*dfa556e4SMarek Behún {
826*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = container_of(to_delayed_work(work),
827*dfa556e4SMarek Behún 					     struct omnia_mcu,
828*dfa556e4SMarek Behún 					     button_release_emul_work);
829*dfa556e4SMarek Behún 
830*dfa556e4SMarek Behún 	mcu->button_pressed_emul = false;
831*dfa556e4SMarek Behún 	generic_handle_irq_safe(mcu->client->irq);
832*dfa556e4SMarek Behún }
833*dfa556e4SMarek Behún 
834*dfa556e4SMarek Behún static void
835*dfa556e4SMarek Behún fill_int_from_sts(unsigned long *rising, unsigned long *falling,
836*dfa556e4SMarek Behún 		  unsigned long rising_sts, unsigned long falling_sts,
837*dfa556e4SMarek Behún 		  unsigned long sts_bit, unsigned long int_bit)
838*dfa556e4SMarek Behún {
839*dfa556e4SMarek Behún 	if (rising_sts & sts_bit)
840*dfa556e4SMarek Behún 		*rising |= int_bit;
841*dfa556e4SMarek Behún 	if (falling_sts & sts_bit)
842*dfa556e4SMarek Behún 		*falling |= int_bit;
843*dfa556e4SMarek Behún }
844*dfa556e4SMarek Behún 
845*dfa556e4SMarek Behún static bool omnia_irq_read_pending_old(struct omnia_mcu *mcu,
846*dfa556e4SMarek Behún 				       unsigned long *pending)
847*dfa556e4SMarek Behún {
848*dfa556e4SMarek Behún 	unsigned long status, rising_sts, falling_sts, rising, falling;
849*dfa556e4SMarek Behún 	struct device *dev = &mcu->client->dev;
850*dfa556e4SMarek Behún 	int err;
851*dfa556e4SMarek Behún 
852*dfa556e4SMarek Behún 	guard(mutex)(&mcu->lock);
853*dfa556e4SMarek Behún 
854*dfa556e4SMarek Behún 	err = omnia_read_status_word_old_fw(mcu, &status);
855*dfa556e4SMarek Behún 	if (err) {
856*dfa556e4SMarek Behún 		dev_err(dev, "Cannot read pending IRQs: %d\n", err);
857*dfa556e4SMarek Behún 		return false;
858*dfa556e4SMarek Behún 	}
859*dfa556e4SMarek Behún 
860*dfa556e4SMarek Behún 	/*
861*dfa556e4SMarek Behún 	 * The old firmware triggers an interrupt whenever status word changes,
862*dfa556e4SMarek Behún 	 * but does not inform about which bits rose or fell. We need to compute
863*dfa556e4SMarek Behún 	 * this here by comparing with the last status word value.
864*dfa556e4SMarek Behún 	 *
865*dfa556e4SMarek Behún 	 * The OMNIA_STS_BUTTON_PRESSED bit needs special handling, because the
866*dfa556e4SMarek Behún 	 * old firmware clears the OMNIA_STS_BUTTON_PRESSED bit on successful
867*dfa556e4SMarek Behún 	 * completion of the OMNIA_CMD_GET_STATUS_WORD command, resulting in
868*dfa556e4SMarek Behún 	 * another interrupt:
869*dfa556e4SMarek Behún 	 * - first we get an interrupt, we read the status word where
870*dfa556e4SMarek Behún 	 *   OMNIA_STS_BUTTON_PRESSED is present,
871*dfa556e4SMarek Behún 	 * - MCU clears the OMNIA_STS_BUTTON_PRESSED bit because we read the
872*dfa556e4SMarek Behún 	 *   status word,
873*dfa556e4SMarek Behún 	 * - we get another interrupt because the status word changed again
874*dfa556e4SMarek Behún 	 *   (the OMNIA_STS_BUTTON_PRESSED bit was cleared).
875*dfa556e4SMarek Behún 	 *
876*dfa556e4SMarek Behún 	 * The gpiolib-cdev, gpiolib-sysfs and gpio-keys input driver all call
877*dfa556e4SMarek Behún 	 * the gpiochip's .get() method after an edge event on a requested GPIO
878*dfa556e4SMarek Behún 	 * occurs.
879*dfa556e4SMarek Behún 	 *
880*dfa556e4SMarek Behún 	 * We ensure that the .get() method reads 1 for the button GPIO for some
881*dfa556e4SMarek Behún 	 * time.
882*dfa556e4SMarek Behún 	 */
883*dfa556e4SMarek Behún 
884*dfa556e4SMarek Behún 	if (status & OMNIA_STS_BUTTON_PRESSED) {
885*dfa556e4SMarek Behún 		mcu->button_pressed_emul = true;
886*dfa556e4SMarek Behún 		mod_delayed_work(system_wq, &mcu->button_release_emul_work,
887*dfa556e4SMarek Behún 				 msecs_to_jiffies(FRONT_BUTTON_RELEASE_DELAY_MS));
888*dfa556e4SMarek Behún 	} else if (mcu->button_pressed_emul) {
889*dfa556e4SMarek Behún 		status |= OMNIA_STS_BUTTON_PRESSED;
890*dfa556e4SMarek Behún 	}
891*dfa556e4SMarek Behún 
892*dfa556e4SMarek Behún 	rising_sts = ~mcu->last_status & status;
893*dfa556e4SMarek Behún 	falling_sts = mcu->last_status & ~status;
894*dfa556e4SMarek Behún 
895*dfa556e4SMarek Behún 	mcu->last_status = status;
896*dfa556e4SMarek Behún 
897*dfa556e4SMarek Behún 	/*
898*dfa556e4SMarek Behún 	 * Fill in the relevant interrupt bits from status bits for CARD_DET,
899*dfa556e4SMarek Behún 	 * MSATA_IND and BUTTON_PRESSED.
900*dfa556e4SMarek Behún 	 */
901*dfa556e4SMarek Behún 	rising = 0;
902*dfa556e4SMarek Behún 	falling = 0;
903*dfa556e4SMarek Behún 	fill_int_from_sts(&rising, &falling, rising_sts, falling_sts,
904*dfa556e4SMarek Behún 			  OMNIA_STS_CARD_DET, OMNIA_INT_CARD_DET);
905*dfa556e4SMarek Behún 	fill_int_from_sts(&rising, &falling, rising_sts, falling_sts,
906*dfa556e4SMarek Behún 			  OMNIA_STS_MSATA_IND, OMNIA_INT_MSATA_IND);
907*dfa556e4SMarek Behún 	fill_int_from_sts(&rising, &falling, rising_sts, falling_sts,
908*dfa556e4SMarek Behún 			  OMNIA_STS_BUTTON_PRESSED, OMNIA_INT_BUTTON_PRESSED);
909*dfa556e4SMarek Behún 
910*dfa556e4SMarek Behún 	/* Use only bits that are enabled */
911*dfa556e4SMarek Behún 	rising &= mcu->rising & mcu->mask;
912*dfa556e4SMarek Behún 	falling &= mcu->falling & mcu->mask;
913*dfa556e4SMarek Behún 	*pending = rising | falling;
914*dfa556e4SMarek Behún 
915*dfa556e4SMarek Behún 	return true;
916*dfa556e4SMarek Behún }
917*dfa556e4SMarek Behún 
918*dfa556e4SMarek Behún static bool omnia_irq_read_pending(struct omnia_mcu *mcu,
919*dfa556e4SMarek Behún 				   unsigned long *pending)
920*dfa556e4SMarek Behún {
921*dfa556e4SMarek Behún 	if (mcu->features & OMNIA_FEAT_NEW_INT_API)
922*dfa556e4SMarek Behún 		return omnia_irq_read_pending_new(mcu, pending);
923*dfa556e4SMarek Behún 	else
924*dfa556e4SMarek Behún 		return omnia_irq_read_pending_old(mcu, pending);
925*dfa556e4SMarek Behún }
926*dfa556e4SMarek Behún 
927*dfa556e4SMarek Behún static irqreturn_t omnia_irq_thread_handler(int irq, void *dev_id)
928*dfa556e4SMarek Behún {
929*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = dev_id;
930*dfa556e4SMarek Behún 	struct irq_domain *domain;
931*dfa556e4SMarek Behún 	unsigned long pending;
932*dfa556e4SMarek Behún 	unsigned int i;
933*dfa556e4SMarek Behún 
934*dfa556e4SMarek Behún 	if (!omnia_irq_read_pending(mcu, &pending))
935*dfa556e4SMarek Behún 		return IRQ_NONE;
936*dfa556e4SMarek Behún 
937*dfa556e4SMarek Behún 	domain = mcu->gc.irq.domain;
938*dfa556e4SMarek Behún 
939*dfa556e4SMarek Behún 	for_each_set_bit(i, &pending, 32) {
940*dfa556e4SMarek Behún 		unsigned int nested_irq;
941*dfa556e4SMarek Behún 
942*dfa556e4SMarek Behún 		nested_irq = irq_find_mapping(domain, omnia_int_to_gpio_idx[i]);
943*dfa556e4SMarek Behún 
944*dfa556e4SMarek Behún 		handle_nested_irq(nested_irq);
945*dfa556e4SMarek Behún 	}
946*dfa556e4SMarek Behún 
947*dfa556e4SMarek Behún 	return IRQ_RETVAL(pending);
948*dfa556e4SMarek Behún }
949*dfa556e4SMarek Behún 
950*dfa556e4SMarek Behún static const char * const front_button_modes[] = { "mcu", "cpu" };
951*dfa556e4SMarek Behún 
952*dfa556e4SMarek Behún static ssize_t front_button_mode_show(struct device *dev,
953*dfa556e4SMarek Behún 				      struct device_attribute *a, char *buf)
954*dfa556e4SMarek Behún {
955*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = dev_get_drvdata(dev);
956*dfa556e4SMarek Behún 	int val;
957*dfa556e4SMarek Behún 
958*dfa556e4SMarek Behún 	if (mcu->features & OMNIA_FEAT_NEW_INT_API) {
959*dfa556e4SMarek Behún 		val = omnia_cmd_read_bit(mcu->client, OMNIA_CMD_GET_STATUS_WORD,
960*dfa556e4SMarek Behún 					 OMNIA_STS_BUTTON_MODE);
961*dfa556e4SMarek Behún 		if (val < 0)
962*dfa556e4SMarek Behún 			return val;
963*dfa556e4SMarek Behún 	} else {
964*dfa556e4SMarek Behún 		val = !!(mcu->last_status & OMNIA_STS_BUTTON_MODE);
965*dfa556e4SMarek Behún 	}
966*dfa556e4SMarek Behún 
967*dfa556e4SMarek Behún 	return sysfs_emit(buf, "%s\n", front_button_modes[val]);
968*dfa556e4SMarek Behún }
969*dfa556e4SMarek Behún 
970*dfa556e4SMarek Behún static ssize_t front_button_mode_store(struct device *dev,
971*dfa556e4SMarek Behún 				       struct device_attribute *a,
972*dfa556e4SMarek Behún 				       const char *buf, size_t count)
973*dfa556e4SMarek Behún {
974*dfa556e4SMarek Behún 	struct omnia_mcu *mcu = dev_get_drvdata(dev);
975*dfa556e4SMarek Behún 	int err, i;
976*dfa556e4SMarek Behún 
977*dfa556e4SMarek Behún 	i = sysfs_match_string(front_button_modes, buf);
978*dfa556e4SMarek Behún 	if (i < 0)
979*dfa556e4SMarek Behún 		return i;
980*dfa556e4SMarek Behún 
981*dfa556e4SMarek Behún 	err = omnia_ctl_cmd_locked(mcu, OMNIA_CMD_GENERAL_CONTROL,
982*dfa556e4SMarek Behún 				   i ? OMNIA_CTL_BUTTON_MODE : 0,
983*dfa556e4SMarek Behún 				   OMNIA_CTL_BUTTON_MODE);
984*dfa556e4SMarek Behún 	if (err)
985*dfa556e4SMarek Behún 		return err;
986*dfa556e4SMarek Behún 
987*dfa556e4SMarek Behún 	return count;
988*dfa556e4SMarek Behún }
989*dfa556e4SMarek Behún static DEVICE_ATTR_RW(front_button_mode);
990*dfa556e4SMarek Behún 
991*dfa556e4SMarek Behún static struct attribute *omnia_mcu_gpio_attrs[] = {
992*dfa556e4SMarek Behún 	&dev_attr_front_button_mode.attr,
993*dfa556e4SMarek Behún 	NULL
994*dfa556e4SMarek Behún };
995*dfa556e4SMarek Behún 
996*dfa556e4SMarek Behún const struct attribute_group omnia_mcu_gpio_group = {
997*dfa556e4SMarek Behún 	.attrs = omnia_mcu_gpio_attrs,
998*dfa556e4SMarek Behún };
999*dfa556e4SMarek Behún 
1000*dfa556e4SMarek Behún int omnia_mcu_register_gpiochip(struct omnia_mcu *mcu)
1001*dfa556e4SMarek Behún {
1002*dfa556e4SMarek Behún 	bool new_api = mcu->features & OMNIA_FEAT_NEW_INT_API;
1003*dfa556e4SMarek Behún 	struct device *dev = &mcu->client->dev;
1004*dfa556e4SMarek Behún 	unsigned long irqflags;
1005*dfa556e4SMarek Behún 	int err;
1006*dfa556e4SMarek Behún 
1007*dfa556e4SMarek Behún 	err = devm_mutex_init(dev, &mcu->lock);
1008*dfa556e4SMarek Behún 	if (err)
1009*dfa556e4SMarek Behún 		return err;
1010*dfa556e4SMarek Behún 
1011*dfa556e4SMarek Behún 	mcu->gc.request = omnia_gpio_request;
1012*dfa556e4SMarek Behún 	mcu->gc.get_direction = omnia_gpio_get_direction;
1013*dfa556e4SMarek Behún 	mcu->gc.direction_input = omnia_gpio_direction_input;
1014*dfa556e4SMarek Behún 	mcu->gc.direction_output = omnia_gpio_direction_output;
1015*dfa556e4SMarek Behún 	mcu->gc.get = omnia_gpio_get;
1016*dfa556e4SMarek Behún 	mcu->gc.get_multiple = omnia_gpio_get_multiple;
1017*dfa556e4SMarek Behún 	mcu->gc.set = omnia_gpio_set;
1018*dfa556e4SMarek Behún 	mcu->gc.set_multiple = omnia_gpio_set_multiple;
1019*dfa556e4SMarek Behún 	mcu->gc.init_valid_mask = omnia_gpio_init_valid_mask;
1020*dfa556e4SMarek Behún 	mcu->gc.can_sleep = true;
1021*dfa556e4SMarek Behún 	mcu->gc.names = omnia_mcu_gpio_templates;
1022*dfa556e4SMarek Behún 	mcu->gc.base = -1;
1023*dfa556e4SMarek Behún 	mcu->gc.ngpio = ARRAY_SIZE(omnia_gpios);
1024*dfa556e4SMarek Behún 	mcu->gc.label = "Turris Omnia MCU GPIOs";
1025*dfa556e4SMarek Behún 	mcu->gc.parent = dev;
1026*dfa556e4SMarek Behún 	mcu->gc.owner = THIS_MODULE;
1027*dfa556e4SMarek Behún 	mcu->gc.of_gpio_n_cells = 3;
1028*dfa556e4SMarek Behún 	mcu->gc.of_xlate = omnia_gpio_of_xlate;
1029*dfa556e4SMarek Behún 
1030*dfa556e4SMarek Behún 	gpio_irq_chip_set_chip(&mcu->gc.irq, &omnia_mcu_irq_chip);
1031*dfa556e4SMarek Behún 	/* This will let us handle the parent IRQ in the driver */
1032*dfa556e4SMarek Behún 	mcu->gc.irq.parent_handler = NULL;
1033*dfa556e4SMarek Behún 	mcu->gc.irq.num_parents = 0;
1034*dfa556e4SMarek Behún 	mcu->gc.irq.parents = NULL;
1035*dfa556e4SMarek Behún 	mcu->gc.irq.default_type = IRQ_TYPE_NONE;
1036*dfa556e4SMarek Behún 	mcu->gc.irq.handler = handle_bad_irq;
1037*dfa556e4SMarek Behún 	mcu->gc.irq.threaded = true;
1038*dfa556e4SMarek Behún 	if (new_api)
1039*dfa556e4SMarek Behún 		mcu->gc.irq.init_hw = omnia_irq_init_hw;
1040*dfa556e4SMarek Behún 	mcu->gc.irq.init_valid_mask = omnia_irq_init_valid_mask;
1041*dfa556e4SMarek Behún 
1042*dfa556e4SMarek Behún 	err = devm_gpiochip_add_data(dev, &mcu->gc, mcu);
1043*dfa556e4SMarek Behún 	if (err)
1044*dfa556e4SMarek Behún 		return dev_err_probe(dev, err, "Cannot add GPIO chip\n");
1045*dfa556e4SMarek Behún 
1046*dfa556e4SMarek Behún 	/*
1047*dfa556e4SMarek Behún 	 * Before requesting the interrupt, if firmware does not support the new
1048*dfa556e4SMarek Behún 	 * interrupt API, we need to cache the value of the status word, so that
1049*dfa556e4SMarek Behún 	 * when it changes, we may compare the new value with the cached one in
1050*dfa556e4SMarek Behún 	 * the interrupt handler.
1051*dfa556e4SMarek Behún 	 */
1052*dfa556e4SMarek Behún 	if (!new_api) {
1053*dfa556e4SMarek Behún 		err = omnia_read_status_word_old_fw(mcu, &mcu->last_status);
1054*dfa556e4SMarek Behún 		if (err)
1055*dfa556e4SMarek Behún 			return dev_err_probe(dev, err,
1056*dfa556e4SMarek Behún 					     "Cannot read status word\n");
1057*dfa556e4SMarek Behún 
1058*dfa556e4SMarek Behún 		INIT_DELAYED_WORK(&mcu->button_release_emul_work,
1059*dfa556e4SMarek Behún 				  button_release_emul_fn);
1060*dfa556e4SMarek Behún 	}
1061*dfa556e4SMarek Behún 
1062*dfa556e4SMarek Behún 	irqflags = IRQF_ONESHOT;
1063*dfa556e4SMarek Behún 	if (new_api)
1064*dfa556e4SMarek Behún 		irqflags |= IRQF_TRIGGER_LOW;
1065*dfa556e4SMarek Behún 	else
1066*dfa556e4SMarek Behún 		irqflags |= IRQF_TRIGGER_FALLING;
1067*dfa556e4SMarek Behún 
1068*dfa556e4SMarek Behún 	err = devm_request_threaded_irq(dev, mcu->client->irq, NULL,
1069*dfa556e4SMarek Behún 					omnia_irq_thread_handler, irqflags,
1070*dfa556e4SMarek Behún 					"turris-omnia-mcu", mcu);
1071*dfa556e4SMarek Behún 	if (err)
1072*dfa556e4SMarek Behún 		return dev_err_probe(dev, err, "Cannot request IRQ\n");
1073*dfa556e4SMarek Behún 
1074*dfa556e4SMarek Behún 	if (!new_api) {
1075*dfa556e4SMarek Behún 		/*
1076*dfa556e4SMarek Behún 		 * The button_release_emul_work has to be initialized before the
1077*dfa556e4SMarek Behún 		 * thread is requested, and on driver remove it needs to be
1078*dfa556e4SMarek Behún 		 * canceled before the thread is freed. Therefore we can't use
1079*dfa556e4SMarek Behún 		 * devm_delayed_work_autocancel() directly, because the order
1080*dfa556e4SMarek Behún 		 *   devm_delayed_work_autocancel();
1081*dfa556e4SMarek Behún 		 *   devm_request_threaded_irq();
1082*dfa556e4SMarek Behún 		 * would cause improper release order:
1083*dfa556e4SMarek Behún 		 *   free_irq();
1084*dfa556e4SMarek Behún 		 *   cancel_delayed_work_sync();
1085*dfa556e4SMarek Behún 		 * Instead we first initialize the work above, and only now
1086*dfa556e4SMarek Behún 		 * after IRQ is requested we add the work devm action.
1087*dfa556e4SMarek Behún 		 */
1088*dfa556e4SMarek Behún 		err = devm_add_action(dev, devm_delayed_work_drop,
1089*dfa556e4SMarek Behún 				      &mcu->button_release_emul_work);
1090*dfa556e4SMarek Behún 		if (err)
1091*dfa556e4SMarek Behún 			return err;
1092*dfa556e4SMarek Behún 	}
1093*dfa556e4SMarek Behún 
1094*dfa556e4SMarek Behún 	return 0;
1095*dfa556e4SMarek Behún }
1096