xref: /OK3568_Linux_fs/kernel/drivers/gpio/gpio-viperboard.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0+
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *  Nano River Technologies viperboard GPIO lib driver
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  *  (C) 2012 by Lemonage GmbH
6*4882a593Smuzhiyun  *  Author: Lars Poeschel <poeschel@lemonage.de>
7*4882a593Smuzhiyun  *  All rights reserved.
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/errno.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/slab.h>
14*4882a593Smuzhiyun #include <linux/types.h>
15*4882a593Smuzhiyun #include <linux/mutex.h>
16*4882a593Smuzhiyun #include <linux/platform_device.h>
17*4882a593Smuzhiyun #include <linux/usb.h>
18*4882a593Smuzhiyun #include <linux/gpio/driver.h>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #include <linux/mfd/viperboard.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #define VPRBRD_GPIOA_CLK_1MHZ		0
23*4882a593Smuzhiyun #define VPRBRD_GPIOA_CLK_100KHZ		1
24*4882a593Smuzhiyun #define VPRBRD_GPIOA_CLK_10KHZ		2
25*4882a593Smuzhiyun #define VPRBRD_GPIOA_CLK_1KHZ		3
26*4882a593Smuzhiyun #define VPRBRD_GPIOA_CLK_100HZ		4
27*4882a593Smuzhiyun #define VPRBRD_GPIOA_CLK_10HZ		5
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun #define VPRBRD_GPIOA_FREQ_DEFAULT	1000
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun #define VPRBRD_GPIOA_CMD_CONT		0x00
32*4882a593Smuzhiyun #define VPRBRD_GPIOA_CMD_PULSE		0x01
33*4882a593Smuzhiyun #define VPRBRD_GPIOA_CMD_PWM		0x02
34*4882a593Smuzhiyun #define VPRBRD_GPIOA_CMD_SETOUT		0x03
35*4882a593Smuzhiyun #define VPRBRD_GPIOA_CMD_SETIN		0x04
36*4882a593Smuzhiyun #define VPRBRD_GPIOA_CMD_SETINT		0x05
37*4882a593Smuzhiyun #define VPRBRD_GPIOA_CMD_GETIN		0x06
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #define VPRBRD_GPIOB_CMD_SETDIR		0x00
40*4882a593Smuzhiyun #define VPRBRD_GPIOB_CMD_SETVAL		0x01
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun struct vprbrd_gpioa_msg {
43*4882a593Smuzhiyun 	u8 cmd;
44*4882a593Smuzhiyun 	u8 clk;
45*4882a593Smuzhiyun 	u8 offset;
46*4882a593Smuzhiyun 	u8 t1;
47*4882a593Smuzhiyun 	u8 t2;
48*4882a593Smuzhiyun 	u8 invert;
49*4882a593Smuzhiyun 	u8 pwmlevel;
50*4882a593Smuzhiyun 	u8 outval;
51*4882a593Smuzhiyun 	u8 risefall;
52*4882a593Smuzhiyun 	u8 answer;
53*4882a593Smuzhiyun 	u8 __fill;
54*4882a593Smuzhiyun } __packed;
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun struct vprbrd_gpiob_msg {
57*4882a593Smuzhiyun 	u8 cmd;
58*4882a593Smuzhiyun 	u16 val;
59*4882a593Smuzhiyun 	u16 mask;
60*4882a593Smuzhiyun } __packed;
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun struct vprbrd_gpio {
63*4882a593Smuzhiyun 	struct gpio_chip gpioa; /* gpio a related things */
64*4882a593Smuzhiyun 	u32 gpioa_out;
65*4882a593Smuzhiyun 	u32 gpioa_val;
66*4882a593Smuzhiyun 	struct gpio_chip gpiob; /* gpio b related things */
67*4882a593Smuzhiyun 	u32 gpiob_out;
68*4882a593Smuzhiyun 	u32 gpiob_val;
69*4882a593Smuzhiyun 	struct vprbrd *vb;
70*4882a593Smuzhiyun };
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun /* gpioa sampling clock module parameter */
73*4882a593Smuzhiyun static unsigned char gpioa_clk;
74*4882a593Smuzhiyun static unsigned int gpioa_freq = VPRBRD_GPIOA_FREQ_DEFAULT;
75*4882a593Smuzhiyun module_param(gpioa_freq, uint, 0);
76*4882a593Smuzhiyun MODULE_PARM_DESC(gpioa_freq,
77*4882a593Smuzhiyun 	"gpio-a sampling freq in Hz (default is 1000Hz) valid values: 10, 100, 1000, 10000, 100000, 1000000");
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun /* ----- begin of gipo a chip -------------------------------------------- */
80*4882a593Smuzhiyun 
vprbrd_gpioa_get(struct gpio_chip * chip,unsigned int offset)81*4882a593Smuzhiyun static int vprbrd_gpioa_get(struct gpio_chip *chip,
82*4882a593Smuzhiyun 		unsigned int offset)
83*4882a593Smuzhiyun {
84*4882a593Smuzhiyun 	int ret, answer, error = 0;
85*4882a593Smuzhiyun 	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
86*4882a593Smuzhiyun 	struct vprbrd *vb = gpio->vb;
87*4882a593Smuzhiyun 	struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun 	/* if io is set to output, just return the saved value */
90*4882a593Smuzhiyun 	if (gpio->gpioa_out & (1 << offset))
91*4882a593Smuzhiyun 		return !!(gpio->gpioa_val & (1 << offset));
92*4882a593Smuzhiyun 
93*4882a593Smuzhiyun 	mutex_lock(&vb->lock);
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	gamsg->cmd = VPRBRD_GPIOA_CMD_GETIN;
96*4882a593Smuzhiyun 	gamsg->clk = 0x00;
97*4882a593Smuzhiyun 	gamsg->offset = offset;
98*4882a593Smuzhiyun 	gamsg->t1 = 0x00;
99*4882a593Smuzhiyun 	gamsg->t2 = 0x00;
100*4882a593Smuzhiyun 	gamsg->invert = 0x00;
101*4882a593Smuzhiyun 	gamsg->pwmlevel = 0x00;
102*4882a593Smuzhiyun 	gamsg->outval = 0x00;
103*4882a593Smuzhiyun 	gamsg->risefall = 0x00;
104*4882a593Smuzhiyun 	gamsg->answer = 0x00;
105*4882a593Smuzhiyun 	gamsg->__fill = 0x00;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun 	ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0),
108*4882a593Smuzhiyun 		VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000,
109*4882a593Smuzhiyun 		0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg),
110*4882a593Smuzhiyun 		VPRBRD_USB_TIMEOUT_MS);
111*4882a593Smuzhiyun 	if (ret != sizeof(struct vprbrd_gpioa_msg))
112*4882a593Smuzhiyun 		error = -EREMOTEIO;
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0),
115*4882a593Smuzhiyun 		VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_IN, 0x0000,
116*4882a593Smuzhiyun 		0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg),
117*4882a593Smuzhiyun 		VPRBRD_USB_TIMEOUT_MS);
118*4882a593Smuzhiyun 	answer = gamsg->answer & 0x01;
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	mutex_unlock(&vb->lock);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	if (ret != sizeof(struct vprbrd_gpioa_msg))
123*4882a593Smuzhiyun 		error = -EREMOTEIO;
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	if (error)
126*4882a593Smuzhiyun 		return error;
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	return answer;
129*4882a593Smuzhiyun }
130*4882a593Smuzhiyun 
vprbrd_gpioa_set(struct gpio_chip * chip,unsigned int offset,int value)131*4882a593Smuzhiyun static void vprbrd_gpioa_set(struct gpio_chip *chip,
132*4882a593Smuzhiyun 		unsigned int offset, int value)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun 	int ret;
135*4882a593Smuzhiyun 	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
136*4882a593Smuzhiyun 	struct vprbrd *vb = gpio->vb;
137*4882a593Smuzhiyun 	struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;
138*4882a593Smuzhiyun 
139*4882a593Smuzhiyun 	if (gpio->gpioa_out & (1 << offset)) {
140*4882a593Smuzhiyun 		if (value)
141*4882a593Smuzhiyun 			gpio->gpioa_val |= (1 << offset);
142*4882a593Smuzhiyun 		else
143*4882a593Smuzhiyun 			gpio->gpioa_val &= ~(1 << offset);
144*4882a593Smuzhiyun 
145*4882a593Smuzhiyun 		mutex_lock(&vb->lock);
146*4882a593Smuzhiyun 
147*4882a593Smuzhiyun 		gamsg->cmd = VPRBRD_GPIOA_CMD_SETOUT;
148*4882a593Smuzhiyun 		gamsg->clk = 0x00;
149*4882a593Smuzhiyun 		gamsg->offset = offset;
150*4882a593Smuzhiyun 		gamsg->t1 = 0x00;
151*4882a593Smuzhiyun 		gamsg->t2 = 0x00;
152*4882a593Smuzhiyun 		gamsg->invert = 0x00;
153*4882a593Smuzhiyun 		gamsg->pwmlevel = 0x00;
154*4882a593Smuzhiyun 		gamsg->outval = value;
155*4882a593Smuzhiyun 		gamsg->risefall = 0x00;
156*4882a593Smuzhiyun 		gamsg->answer = 0x00;
157*4882a593Smuzhiyun 		gamsg->__fill = 0x00;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 		ret = usb_control_msg(vb->usb_dev,
160*4882a593Smuzhiyun 			usb_sndctrlpipe(vb->usb_dev, 0),
161*4882a593Smuzhiyun 			VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT,
162*4882a593Smuzhiyun 			0x0000,	0x0000, gamsg,
163*4882a593Smuzhiyun 			sizeof(struct vprbrd_gpioa_msg), VPRBRD_USB_TIMEOUT_MS);
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 		mutex_unlock(&vb->lock);
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 		if (ret != sizeof(struct vprbrd_gpioa_msg))
168*4882a593Smuzhiyun 			dev_err(chip->parent, "usb error setting pin value\n");
169*4882a593Smuzhiyun 	}
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
vprbrd_gpioa_direction_input(struct gpio_chip * chip,unsigned int offset)172*4882a593Smuzhiyun static int vprbrd_gpioa_direction_input(struct gpio_chip *chip,
173*4882a593Smuzhiyun 			unsigned int offset)
174*4882a593Smuzhiyun {
175*4882a593Smuzhiyun 	int ret;
176*4882a593Smuzhiyun 	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
177*4882a593Smuzhiyun 	struct vprbrd *vb = gpio->vb;
178*4882a593Smuzhiyun 	struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 	gpio->gpioa_out &= ~(1 << offset);
181*4882a593Smuzhiyun 
182*4882a593Smuzhiyun 	mutex_lock(&vb->lock);
183*4882a593Smuzhiyun 
184*4882a593Smuzhiyun 	gamsg->cmd = VPRBRD_GPIOA_CMD_SETIN;
185*4882a593Smuzhiyun 	gamsg->clk = gpioa_clk;
186*4882a593Smuzhiyun 	gamsg->offset = offset;
187*4882a593Smuzhiyun 	gamsg->t1 = 0x00;
188*4882a593Smuzhiyun 	gamsg->t2 = 0x00;
189*4882a593Smuzhiyun 	gamsg->invert = 0x00;
190*4882a593Smuzhiyun 	gamsg->pwmlevel = 0x00;
191*4882a593Smuzhiyun 	gamsg->outval = 0x00;
192*4882a593Smuzhiyun 	gamsg->risefall = 0x00;
193*4882a593Smuzhiyun 	gamsg->answer = 0x00;
194*4882a593Smuzhiyun 	gamsg->__fill = 0x00;
195*4882a593Smuzhiyun 
196*4882a593Smuzhiyun 	ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0),
197*4882a593Smuzhiyun 		VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000,
198*4882a593Smuzhiyun 		0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg),
199*4882a593Smuzhiyun 		VPRBRD_USB_TIMEOUT_MS);
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun 	mutex_unlock(&vb->lock);
202*4882a593Smuzhiyun 
203*4882a593Smuzhiyun 	if (ret != sizeof(struct vprbrd_gpioa_msg))
204*4882a593Smuzhiyun 		return -EREMOTEIO;
205*4882a593Smuzhiyun 
206*4882a593Smuzhiyun 	return 0;
207*4882a593Smuzhiyun }
208*4882a593Smuzhiyun 
vprbrd_gpioa_direction_output(struct gpio_chip * chip,unsigned int offset,int value)209*4882a593Smuzhiyun static int vprbrd_gpioa_direction_output(struct gpio_chip *chip,
210*4882a593Smuzhiyun 			unsigned int offset, int value)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun 	int ret;
213*4882a593Smuzhiyun 	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
214*4882a593Smuzhiyun 	struct vprbrd *vb = gpio->vb;
215*4882a593Smuzhiyun 	struct vprbrd_gpioa_msg *gamsg = (struct vprbrd_gpioa_msg *)vb->buf;
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun 	gpio->gpioa_out |= (1 << offset);
218*4882a593Smuzhiyun 	if (value)
219*4882a593Smuzhiyun 		gpio->gpioa_val |= (1 << offset);
220*4882a593Smuzhiyun 	else
221*4882a593Smuzhiyun 		gpio->gpioa_val &= ~(1 << offset);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	mutex_lock(&vb->lock);
224*4882a593Smuzhiyun 
225*4882a593Smuzhiyun 	gamsg->cmd = VPRBRD_GPIOA_CMD_SETOUT;
226*4882a593Smuzhiyun 	gamsg->clk = 0x00;
227*4882a593Smuzhiyun 	gamsg->offset = offset;
228*4882a593Smuzhiyun 	gamsg->t1 = 0x00;
229*4882a593Smuzhiyun 	gamsg->t2 = 0x00;
230*4882a593Smuzhiyun 	gamsg->invert = 0x00;
231*4882a593Smuzhiyun 	gamsg->pwmlevel = 0x00;
232*4882a593Smuzhiyun 	gamsg->outval = value;
233*4882a593Smuzhiyun 	gamsg->risefall = 0x00;
234*4882a593Smuzhiyun 	gamsg->answer = 0x00;
235*4882a593Smuzhiyun 	gamsg->__fill = 0x00;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0),
238*4882a593Smuzhiyun 		VPRBRD_USB_REQUEST_GPIOA, VPRBRD_USB_TYPE_OUT, 0x0000,
239*4882a593Smuzhiyun 		0x0000, gamsg, sizeof(struct vprbrd_gpioa_msg),
240*4882a593Smuzhiyun 		VPRBRD_USB_TIMEOUT_MS);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	mutex_unlock(&vb->lock);
243*4882a593Smuzhiyun 
244*4882a593Smuzhiyun 	if (ret != sizeof(struct vprbrd_gpioa_msg))
245*4882a593Smuzhiyun 		return -EREMOTEIO;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	return 0;
248*4882a593Smuzhiyun }
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun /* ----- end of gpio a chip ---------------------------------------------- */
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun /* ----- begin of gipo b chip -------------------------------------------- */
253*4882a593Smuzhiyun 
vprbrd_gpiob_setdir(struct vprbrd * vb,unsigned int offset,unsigned int dir)254*4882a593Smuzhiyun static int vprbrd_gpiob_setdir(struct vprbrd *vb, unsigned int offset,
255*4882a593Smuzhiyun 	unsigned int dir)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun 	struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;
258*4882a593Smuzhiyun 	int ret;
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	gbmsg->cmd = VPRBRD_GPIOB_CMD_SETDIR;
261*4882a593Smuzhiyun 	gbmsg->val = cpu_to_be16(dir << offset);
262*4882a593Smuzhiyun 	gbmsg->mask = cpu_to_be16(0x0001 << offset);
263*4882a593Smuzhiyun 
264*4882a593Smuzhiyun 	ret = usb_control_msg(vb->usb_dev, usb_sndctrlpipe(vb->usb_dev, 0),
265*4882a593Smuzhiyun 		VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_OUT, 0x0000,
266*4882a593Smuzhiyun 		0x0000, gbmsg, sizeof(struct vprbrd_gpiob_msg),
267*4882a593Smuzhiyun 		VPRBRD_USB_TIMEOUT_MS);
268*4882a593Smuzhiyun 
269*4882a593Smuzhiyun 	if (ret != sizeof(struct vprbrd_gpiob_msg))
270*4882a593Smuzhiyun 		return -EREMOTEIO;
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun 	return 0;
273*4882a593Smuzhiyun }
274*4882a593Smuzhiyun 
vprbrd_gpiob_get(struct gpio_chip * chip,unsigned int offset)275*4882a593Smuzhiyun static int vprbrd_gpiob_get(struct gpio_chip *chip,
276*4882a593Smuzhiyun 		unsigned int offset)
277*4882a593Smuzhiyun {
278*4882a593Smuzhiyun 	int ret;
279*4882a593Smuzhiyun 	u16 val;
280*4882a593Smuzhiyun 	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
281*4882a593Smuzhiyun 	struct vprbrd *vb = gpio->vb;
282*4882a593Smuzhiyun 	struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	/* if io is set to output, just return the saved value */
285*4882a593Smuzhiyun 	if (gpio->gpiob_out & (1 << offset))
286*4882a593Smuzhiyun 		return gpio->gpiob_val & (1 << offset);
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun 	mutex_lock(&vb->lock);
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	ret = usb_control_msg(vb->usb_dev, usb_rcvctrlpipe(vb->usb_dev, 0),
291*4882a593Smuzhiyun 		VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_IN, 0x0000,
292*4882a593Smuzhiyun 		0x0000, gbmsg,	sizeof(struct vprbrd_gpiob_msg),
293*4882a593Smuzhiyun 		VPRBRD_USB_TIMEOUT_MS);
294*4882a593Smuzhiyun 	val = gbmsg->val;
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	mutex_unlock(&vb->lock);
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	if (ret != sizeof(struct vprbrd_gpiob_msg))
299*4882a593Smuzhiyun 		return ret;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	/* cache the read values */
302*4882a593Smuzhiyun 	gpio->gpiob_val = be16_to_cpu(val);
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 	return (gpio->gpiob_val >> offset) & 0x1;
305*4882a593Smuzhiyun }
306*4882a593Smuzhiyun 
vprbrd_gpiob_set(struct gpio_chip * chip,unsigned int offset,int value)307*4882a593Smuzhiyun static void vprbrd_gpiob_set(struct gpio_chip *chip,
308*4882a593Smuzhiyun 		unsigned int offset, int value)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun 	int ret;
311*4882a593Smuzhiyun 	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
312*4882a593Smuzhiyun 	struct vprbrd *vb = gpio->vb;
313*4882a593Smuzhiyun 	struct vprbrd_gpiob_msg *gbmsg = (struct vprbrd_gpiob_msg *)vb->buf;
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	if (gpio->gpiob_out & (1 << offset)) {
316*4882a593Smuzhiyun 		if (value)
317*4882a593Smuzhiyun 			gpio->gpiob_val |= (1 << offset);
318*4882a593Smuzhiyun 		else
319*4882a593Smuzhiyun 			gpio->gpiob_val &= ~(1 << offset);
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 		mutex_lock(&vb->lock);
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 		gbmsg->cmd = VPRBRD_GPIOB_CMD_SETVAL;
324*4882a593Smuzhiyun 		gbmsg->val = cpu_to_be16(value << offset);
325*4882a593Smuzhiyun 		gbmsg->mask = cpu_to_be16(0x0001 << offset);
326*4882a593Smuzhiyun 
327*4882a593Smuzhiyun 		ret = usb_control_msg(vb->usb_dev,
328*4882a593Smuzhiyun 			usb_sndctrlpipe(vb->usb_dev, 0),
329*4882a593Smuzhiyun 			VPRBRD_USB_REQUEST_GPIOB, VPRBRD_USB_TYPE_OUT,
330*4882a593Smuzhiyun 			0x0000,	0x0000, gbmsg,
331*4882a593Smuzhiyun 			sizeof(struct vprbrd_gpiob_msg), VPRBRD_USB_TIMEOUT_MS);
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 		mutex_unlock(&vb->lock);
334*4882a593Smuzhiyun 
335*4882a593Smuzhiyun 		if (ret != sizeof(struct vprbrd_gpiob_msg))
336*4882a593Smuzhiyun 			dev_err(chip->parent, "usb error setting pin value\n");
337*4882a593Smuzhiyun 	}
338*4882a593Smuzhiyun }
339*4882a593Smuzhiyun 
vprbrd_gpiob_direction_input(struct gpio_chip * chip,unsigned int offset)340*4882a593Smuzhiyun static int vprbrd_gpiob_direction_input(struct gpio_chip *chip,
341*4882a593Smuzhiyun 			unsigned int offset)
342*4882a593Smuzhiyun {
343*4882a593Smuzhiyun 	int ret;
344*4882a593Smuzhiyun 	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
345*4882a593Smuzhiyun 	struct vprbrd *vb = gpio->vb;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	gpio->gpiob_out &= ~(1 << offset);
348*4882a593Smuzhiyun 
349*4882a593Smuzhiyun 	mutex_lock(&vb->lock);
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 	ret = vprbrd_gpiob_setdir(vb, offset, 0);
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	mutex_unlock(&vb->lock);
354*4882a593Smuzhiyun 
355*4882a593Smuzhiyun 	if (ret)
356*4882a593Smuzhiyun 		dev_err(chip->parent, "usb error setting pin to input\n");
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 	return ret;
359*4882a593Smuzhiyun }
360*4882a593Smuzhiyun 
vprbrd_gpiob_direction_output(struct gpio_chip * chip,unsigned int offset,int value)361*4882a593Smuzhiyun static int vprbrd_gpiob_direction_output(struct gpio_chip *chip,
362*4882a593Smuzhiyun 			unsigned int offset, int value)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun 	int ret;
365*4882a593Smuzhiyun 	struct vprbrd_gpio *gpio = gpiochip_get_data(chip);
366*4882a593Smuzhiyun 	struct vprbrd *vb = gpio->vb;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	gpio->gpiob_out |= (1 << offset);
369*4882a593Smuzhiyun 
370*4882a593Smuzhiyun 	mutex_lock(&vb->lock);
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	ret = vprbrd_gpiob_setdir(vb, offset, 1);
373*4882a593Smuzhiyun 	if (ret)
374*4882a593Smuzhiyun 		dev_err(chip->parent, "usb error setting pin to output\n");
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 	mutex_unlock(&vb->lock);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	vprbrd_gpiob_set(chip, offset, value);
379*4882a593Smuzhiyun 
380*4882a593Smuzhiyun 	return ret;
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun /* ----- end of gpio b chip ---------------------------------------------- */
384*4882a593Smuzhiyun 
vprbrd_gpio_probe(struct platform_device * pdev)385*4882a593Smuzhiyun static int vprbrd_gpio_probe(struct platform_device *pdev)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun 	struct vprbrd *vb = dev_get_drvdata(pdev->dev.parent);
388*4882a593Smuzhiyun 	struct vprbrd_gpio *vb_gpio;
389*4882a593Smuzhiyun 	int ret;
390*4882a593Smuzhiyun 
391*4882a593Smuzhiyun 	vb_gpio = devm_kzalloc(&pdev->dev, sizeof(*vb_gpio), GFP_KERNEL);
392*4882a593Smuzhiyun 	if (vb_gpio == NULL)
393*4882a593Smuzhiyun 		return -ENOMEM;
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	vb_gpio->vb = vb;
396*4882a593Smuzhiyun 	/* registering gpio a */
397*4882a593Smuzhiyun 	vb_gpio->gpioa.label = "viperboard gpio a";
398*4882a593Smuzhiyun 	vb_gpio->gpioa.parent = &pdev->dev;
399*4882a593Smuzhiyun 	vb_gpio->gpioa.owner = THIS_MODULE;
400*4882a593Smuzhiyun 	vb_gpio->gpioa.base = -1;
401*4882a593Smuzhiyun 	vb_gpio->gpioa.ngpio = 16;
402*4882a593Smuzhiyun 	vb_gpio->gpioa.can_sleep = true;
403*4882a593Smuzhiyun 	vb_gpio->gpioa.set = vprbrd_gpioa_set;
404*4882a593Smuzhiyun 	vb_gpio->gpioa.get = vprbrd_gpioa_get;
405*4882a593Smuzhiyun 	vb_gpio->gpioa.direction_input = vprbrd_gpioa_direction_input;
406*4882a593Smuzhiyun 	vb_gpio->gpioa.direction_output = vprbrd_gpioa_direction_output;
407*4882a593Smuzhiyun 	ret = devm_gpiochip_add_data(&pdev->dev, &vb_gpio->gpioa, vb_gpio);
408*4882a593Smuzhiyun 	if (ret < 0) {
409*4882a593Smuzhiyun 		dev_err(vb_gpio->gpioa.parent, "could not add gpio a");
410*4882a593Smuzhiyun 		return ret;
411*4882a593Smuzhiyun 	}
412*4882a593Smuzhiyun 
413*4882a593Smuzhiyun 	/* registering gpio b */
414*4882a593Smuzhiyun 	vb_gpio->gpiob.label = "viperboard gpio b";
415*4882a593Smuzhiyun 	vb_gpio->gpiob.parent = &pdev->dev;
416*4882a593Smuzhiyun 	vb_gpio->gpiob.owner = THIS_MODULE;
417*4882a593Smuzhiyun 	vb_gpio->gpiob.base = -1;
418*4882a593Smuzhiyun 	vb_gpio->gpiob.ngpio = 16;
419*4882a593Smuzhiyun 	vb_gpio->gpiob.can_sleep = true;
420*4882a593Smuzhiyun 	vb_gpio->gpiob.set = vprbrd_gpiob_set;
421*4882a593Smuzhiyun 	vb_gpio->gpiob.get = vprbrd_gpiob_get;
422*4882a593Smuzhiyun 	vb_gpio->gpiob.direction_input = vprbrd_gpiob_direction_input;
423*4882a593Smuzhiyun 	vb_gpio->gpiob.direction_output = vprbrd_gpiob_direction_output;
424*4882a593Smuzhiyun 	ret = devm_gpiochip_add_data(&pdev->dev, &vb_gpio->gpiob, vb_gpio);
425*4882a593Smuzhiyun 	if (ret < 0) {
426*4882a593Smuzhiyun 		dev_err(vb_gpio->gpiob.parent, "could not add gpio b");
427*4882a593Smuzhiyun 		return ret;
428*4882a593Smuzhiyun 	}
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	platform_set_drvdata(pdev, vb_gpio);
431*4882a593Smuzhiyun 
432*4882a593Smuzhiyun 	return ret;
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun static struct platform_driver vprbrd_gpio_driver = {
436*4882a593Smuzhiyun 	.driver.name	= "viperboard-gpio",
437*4882a593Smuzhiyun 	.probe		= vprbrd_gpio_probe,
438*4882a593Smuzhiyun };
439*4882a593Smuzhiyun 
vprbrd_gpio_init(void)440*4882a593Smuzhiyun static int __init vprbrd_gpio_init(void)
441*4882a593Smuzhiyun {
442*4882a593Smuzhiyun 	switch (gpioa_freq) {
443*4882a593Smuzhiyun 	case 1000000:
444*4882a593Smuzhiyun 		gpioa_clk = VPRBRD_GPIOA_CLK_1MHZ;
445*4882a593Smuzhiyun 		break;
446*4882a593Smuzhiyun 	case 100000:
447*4882a593Smuzhiyun 		gpioa_clk = VPRBRD_GPIOA_CLK_100KHZ;
448*4882a593Smuzhiyun 		break;
449*4882a593Smuzhiyun 	case 10000:
450*4882a593Smuzhiyun 		gpioa_clk = VPRBRD_GPIOA_CLK_10KHZ;
451*4882a593Smuzhiyun 		break;
452*4882a593Smuzhiyun 	case 1000:
453*4882a593Smuzhiyun 		gpioa_clk = VPRBRD_GPIOA_CLK_1KHZ;
454*4882a593Smuzhiyun 		break;
455*4882a593Smuzhiyun 	case 100:
456*4882a593Smuzhiyun 		gpioa_clk = VPRBRD_GPIOA_CLK_100HZ;
457*4882a593Smuzhiyun 		break;
458*4882a593Smuzhiyun 	case 10:
459*4882a593Smuzhiyun 		gpioa_clk = VPRBRD_GPIOA_CLK_10HZ;
460*4882a593Smuzhiyun 		break;
461*4882a593Smuzhiyun 	default:
462*4882a593Smuzhiyun 		pr_warn("invalid gpioa_freq (%d)\n", gpioa_freq);
463*4882a593Smuzhiyun 		gpioa_clk = VPRBRD_GPIOA_CLK_1KHZ;
464*4882a593Smuzhiyun 	}
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	return platform_driver_register(&vprbrd_gpio_driver);
467*4882a593Smuzhiyun }
468*4882a593Smuzhiyun subsys_initcall(vprbrd_gpio_init);
469*4882a593Smuzhiyun 
vprbrd_gpio_exit(void)470*4882a593Smuzhiyun static void __exit vprbrd_gpio_exit(void)
471*4882a593Smuzhiyun {
472*4882a593Smuzhiyun 	platform_driver_unregister(&vprbrd_gpio_driver);
473*4882a593Smuzhiyun }
474*4882a593Smuzhiyun module_exit(vprbrd_gpio_exit);
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun MODULE_AUTHOR("Lars Poeschel <poeschel@lemonage.de>");
477*4882a593Smuzhiyun MODULE_DESCRIPTION("GPIO driver for Nano River Techs Viperboard");
478*4882a593Smuzhiyun MODULE_LICENSE("GPL");
479*4882a593Smuzhiyun MODULE_ALIAS("platform:viperboard-gpio");
480