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