]>
Commit | Line | Data |
---|---|---|
18a1e013 JN |
1 | /* |
2 | * Artec-3 general port I/O device | |
3 | * | |
4 | * Copyright (c) 2007 Axis Communications AB | |
5 | * | |
6 | * Authors: Bjorn Wesen (initial version) | |
7 | * Ola Knutsson (LED handling) | |
8 | * Johan Adolfsson (read/set directions, write, port G, | |
9 | * port to ETRAX FS. | |
10 | * Ricard Wanderlof (PWM for Artpec-3) | |
11 | * | |
12 | */ | |
13 | ||
14 | #include <linux/module.h> | |
15 | #include <linux/sched.h> | |
16 | #include <linux/slab.h> | |
17 | #include <linux/ioport.h> | |
18 | #include <linux/errno.h> | |
19 | #include <linux/kernel.h> | |
20 | #include <linux/fs.h> | |
21 | #include <linux/string.h> | |
22 | #include <linux/poll.h> | |
23 | #include <linux/init.h> | |
24 | #include <linux/interrupt.h> | |
25 | #include <linux/spinlock.h> | |
26 | ||
27 | #include <asm/etraxgpio.h> | |
28 | #include <hwregs/reg_map.h> | |
29 | #include <hwregs/reg_rdwr.h> | |
30 | #include <hwregs/gio_defs.h> | |
31 | #include <hwregs/intr_vect_defs.h> | |
32 | #include <asm/io.h> | |
33 | #include <asm/system.h> | |
34 | #include <asm/irq.h> | |
35 | #include <asm/arch/mach/pinmux.h> | |
36 | ||
37 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
38 | #include "../i2c.h" | |
39 | ||
40 | #define VIRT_I2C_ADDR 0x40 | |
41 | #endif | |
42 | ||
43 | /* The following gio ports on ARTPEC-3 is available: | |
44 | * pa 32 bits | |
45 | * pb 32 bits | |
46 | * pc 16 bits | |
47 | * each port has a rw_px_dout, r_px_din and rw_px_oe register. | |
48 | */ | |
49 | ||
50 | #define GPIO_MAJOR 120 /* experimental MAJOR number */ | |
51 | ||
52 | #define I2C_INTERRUPT_BITS 0x300 /* i2c0_done and i2c1_done bits */ | |
53 | ||
54 | #define D(x) | |
55 | ||
56 | #if 0 | |
57 | static int dp_cnt; | |
58 | #define DP(x) \ | |
59 | do { \ | |
60 | dp_cnt++; \ | |
61 | if (dp_cnt % 1000 == 0) \ | |
62 | x; \ | |
63 | } while (0) | |
64 | #else | |
65 | #define DP(x) | |
66 | #endif | |
67 | ||
68 | static char gpio_name[] = "etrax gpio"; | |
69 | ||
70 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
71 | static int virtual_gpio_ioctl(struct file *file, unsigned int cmd, | |
72 | unsigned long arg); | |
73 | #endif | |
74 | static int gpio_ioctl(struct inode *inode, struct file *file, | |
a34d2442 JN |
75 | unsigned int cmd, unsigned long arg); |
76 | static ssize_t gpio_write(struct file *file, const char __user *buf, | |
77 | size_t count, loff_t *off); | |
18a1e013 JN |
78 | static int gpio_open(struct inode *inode, struct file *filp); |
79 | static int gpio_release(struct inode *inode, struct file *filp); | |
80 | static unsigned int gpio_poll(struct file *filp, | |
a34d2442 | 81 | struct poll_table_struct *wait); |
18a1e013 JN |
82 | |
83 | /* private data per open() of this driver */ | |
84 | ||
85 | struct gpio_private { | |
86 | struct gpio_private *next; | |
87 | /* The IO_CFG_WRITE_MODE_VALUE only support 8 bits: */ | |
88 | unsigned char clk_mask; | |
89 | unsigned char data_mask; | |
90 | unsigned char write_msb; | |
91 | unsigned char pad1; | |
92 | /* These fields are generic */ | |
93 | unsigned long highalarm, lowalarm; | |
94 | wait_queue_head_t alarm_wq; | |
95 | int minor; | |
96 | }; | |
97 | ||
98 | static void gpio_set_alarm(struct gpio_private *priv); | |
a34d2442 JN |
99 | static int gpio_leds_ioctl(unsigned int cmd, unsigned long arg); |
100 | static int gpio_pwm_ioctl(struct gpio_private *priv, unsigned int cmd, | |
101 | unsigned long arg); | |
102 | ||
18a1e013 JN |
103 | |
104 | /* linked list of alarms to check for */ | |
105 | ||
106 | static struct gpio_private *alarmlist; | |
107 | ||
108 | static int wanted_interrupts; | |
109 | ||
a34d2442 | 110 | static DEFINE_SPINLOCK(gpio_lock); |
18a1e013 JN |
111 | |
112 | #define NUM_PORTS (GPIO_MINOR_LAST+1) | |
113 | #define GIO_REG_RD_ADDR(reg) \ | |
a34d2442 | 114 | (unsigned long *)(regi_gio + REG_RD_ADDR_gio_##reg) |
18a1e013 | 115 | #define GIO_REG_WR_ADDR(reg) \ |
a34d2442 JN |
116 | (unsigned long *)(regi_gio + REG_WR_ADDR_gio_##reg) |
117 | static unsigned long led_dummy; | |
118 | static unsigned long port_d_dummy; /* Only input on Artpec-3 */ | |
18a1e013 | 119 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO |
a34d2442 | 120 | static unsigned long port_e_dummy; /* Non existent on Artpec-3 */ |
18a1e013 JN |
121 | static unsigned long virtual_dummy; |
122 | static unsigned long virtual_rw_pv_oe = CONFIG_ETRAX_DEF_GIO_PV_OE; | |
123 | static unsigned short cached_virtual_gpio_read; | |
124 | #endif | |
125 | ||
a34d2442 | 126 | static unsigned long *data_out[NUM_PORTS] = { |
18a1e013 JN |
127 | GIO_REG_WR_ADDR(rw_pa_dout), |
128 | GIO_REG_WR_ADDR(rw_pb_dout), | |
129 | &led_dummy, | |
130 | GIO_REG_WR_ADDR(rw_pc_dout), | |
131 | &port_d_dummy, | |
132 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
133 | &port_e_dummy, | |
134 | &virtual_dummy, | |
135 | #endif | |
136 | }; | |
137 | ||
a34d2442 | 138 | static unsigned long *data_in[NUM_PORTS] = { |
18a1e013 JN |
139 | GIO_REG_RD_ADDR(r_pa_din), |
140 | GIO_REG_RD_ADDR(r_pb_din), | |
141 | &led_dummy, | |
142 | GIO_REG_RD_ADDR(r_pc_din), | |
143 | GIO_REG_RD_ADDR(r_pd_din), | |
144 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
145 | &port_e_dummy, | |
146 | &virtual_dummy, | |
147 | #endif | |
148 | }; | |
149 | ||
150 | static unsigned long changeable_dir[NUM_PORTS] = { | |
151 | CONFIG_ETRAX_PA_CHANGEABLE_DIR, | |
152 | CONFIG_ETRAX_PB_CHANGEABLE_DIR, | |
153 | 0, | |
154 | CONFIG_ETRAX_PC_CHANGEABLE_DIR, | |
155 | 0, | |
156 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
157 | 0, | |
158 | CONFIG_ETRAX_PV_CHANGEABLE_DIR, | |
159 | #endif | |
160 | }; | |
161 | ||
162 | static unsigned long changeable_bits[NUM_PORTS] = { | |
163 | CONFIG_ETRAX_PA_CHANGEABLE_BITS, | |
164 | CONFIG_ETRAX_PB_CHANGEABLE_BITS, | |
165 | 0, | |
166 | CONFIG_ETRAX_PC_CHANGEABLE_BITS, | |
167 | 0, | |
168 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
169 | 0, | |
170 | CONFIG_ETRAX_PV_CHANGEABLE_BITS, | |
171 | #endif | |
172 | }; | |
173 | ||
a34d2442 | 174 | static unsigned long *dir_oe[NUM_PORTS] = { |
18a1e013 JN |
175 | GIO_REG_WR_ADDR(rw_pa_oe), |
176 | GIO_REG_WR_ADDR(rw_pb_oe), | |
177 | &led_dummy, | |
178 | GIO_REG_WR_ADDR(rw_pc_oe), | |
179 | &port_d_dummy, | |
180 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
181 | &port_e_dummy, | |
182 | &virtual_rw_pv_oe, | |
183 | #endif | |
184 | }; | |
185 | ||
a34d2442 | 186 | static void gpio_set_alarm(struct gpio_private *priv) |
18a1e013 JN |
187 | { |
188 | int bit; | |
189 | int intr_cfg; | |
190 | int mask; | |
191 | int pins; | |
192 | unsigned long flags; | |
193 | ||
a34d2442 | 194 | spin_lock_irqsave(&gpio_lock, flags); |
18a1e013 JN |
195 | intr_cfg = REG_RD_INT(gio, regi_gio, rw_intr_cfg); |
196 | pins = REG_RD_INT(gio, regi_gio, rw_intr_pins); | |
197 | mask = REG_RD_INT(gio, regi_gio, rw_intr_mask) & I2C_INTERRUPT_BITS; | |
198 | ||
199 | for (bit = 0; bit < 32; bit++) { | |
200 | int intr = bit % 8; | |
201 | int pin = bit / 8; | |
202 | if (priv->minor < GPIO_MINOR_LEDS) | |
203 | pin += priv->minor * 4; | |
204 | else | |
205 | pin += (priv->minor - 1) * 4; | |
206 | ||
207 | if (priv->highalarm & (1<<bit)) { | |
208 | intr_cfg |= (regk_gio_hi << (intr * 3)); | |
209 | mask |= 1 << intr; | |
210 | wanted_interrupts = mask & 0xff; | |
211 | pins |= pin << (intr * 4); | |
212 | } else if (priv->lowalarm & (1<<bit)) { | |
213 | intr_cfg |= (regk_gio_lo << (intr * 3)); | |
214 | mask |= 1 << intr; | |
215 | wanted_interrupts = mask & 0xff; | |
216 | pins |= pin << (intr * 4); | |
217 | } | |
218 | } | |
219 | ||
220 | REG_WR_INT(gio, regi_gio, rw_intr_cfg, intr_cfg); | |
221 | REG_WR_INT(gio, regi_gio, rw_intr_pins, pins); | |
222 | REG_WR_INT(gio, regi_gio, rw_intr_mask, mask); | |
223 | ||
a34d2442 | 224 | spin_unlock_irqrestore(&gpio_lock, flags); |
18a1e013 JN |
225 | } |
226 | ||
a34d2442 | 227 | static unsigned int gpio_poll(struct file *file, struct poll_table_struct *wait) |
18a1e013 JN |
228 | { |
229 | unsigned int mask = 0; | |
a34d2442 | 230 | struct gpio_private *priv = file->private_data; |
18a1e013 JN |
231 | unsigned long data; |
232 | unsigned long tmp; | |
233 | ||
234 | if (priv->minor >= GPIO_MINOR_PWM0 && | |
235 | priv->minor <= GPIO_MINOR_LAST_PWM) | |
236 | return 0; | |
237 | ||
238 | poll_wait(file, &priv->alarm_wq, wait); | |
239 | if (priv->minor <= GPIO_MINOR_D) { | |
a34d2442 | 240 | data = readl(data_in[priv->minor]); |
18a1e013 JN |
241 | REG_WR_INT(gio, regi_gio, rw_ack_intr, wanted_interrupts); |
242 | tmp = REG_RD_INT(gio, regi_gio, rw_intr_mask); | |
243 | tmp &= I2C_INTERRUPT_BITS; | |
244 | tmp |= wanted_interrupts; | |
245 | REG_WR_INT(gio, regi_gio, rw_intr_mask, tmp); | |
246 | } else | |
247 | return 0; | |
248 | ||
249 | if ((data & priv->highalarm) || (~data & priv->lowalarm)) | |
250 | mask = POLLIN|POLLRDNORM; | |
251 | ||
252 | DP(printk(KERN_DEBUG "gpio_poll ready: mask 0x%08X\n", mask)); | |
253 | return mask; | |
254 | } | |
255 | ||
a34d2442 | 256 | static irqreturn_t gpio_interrupt(int irq, void *dev_id) |
18a1e013 JN |
257 | { |
258 | reg_gio_rw_intr_mask intr_mask; | |
259 | reg_gio_r_masked_intr masked_intr; | |
260 | reg_gio_rw_ack_intr ack_intr; | |
a34d2442 | 261 | unsigned long flags; |
18a1e013 JN |
262 | unsigned long tmp; |
263 | unsigned long tmp2; | |
264 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
265 | unsigned char enable_gpiov_ack = 0; | |
266 | #endif | |
267 | ||
268 | /* Find what PA interrupts are active */ | |
269 | masked_intr = REG_RD(gio, regi_gio, r_masked_intr); | |
270 | tmp = REG_TYPE_CONV(unsigned long, reg_gio_r_masked_intr, masked_intr); | |
271 | ||
272 | /* Find those that we have enabled */ | |
a34d2442 | 273 | spin_lock_irqsave(&gpio_lock, flags); |
18a1e013 | 274 | tmp &= wanted_interrupts; |
a34d2442 | 275 | spin_unlock_irqrestore(&gpio_lock, flags); |
18a1e013 JN |
276 | |
277 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
278 | /* Something changed on virtual GPIO. Interrupt is acked by | |
279 | * reading the device. | |
280 | */ | |
281 | if (tmp & (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN)) { | |
282 | i2c_read(VIRT_I2C_ADDR, (void *)&cached_virtual_gpio_read, | |
283 | sizeof(cached_virtual_gpio_read)); | |
284 | enable_gpiov_ack = 1; | |
285 | } | |
286 | #endif | |
287 | ||
288 | /* Ack them */ | |
289 | ack_intr = REG_TYPE_CONV(reg_gio_rw_ack_intr, unsigned long, tmp); | |
290 | REG_WR(gio, regi_gio, rw_ack_intr, ack_intr); | |
291 | ||
292 | /* Disable those interrupts.. */ | |
293 | intr_mask = REG_RD(gio, regi_gio, rw_intr_mask); | |
294 | tmp2 = REG_TYPE_CONV(unsigned long, reg_gio_rw_intr_mask, intr_mask); | |
295 | tmp2 &= ~tmp; | |
296 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
297 | /* Do not disable interrupt on virtual GPIO. Changes on virtual | |
298 | * pins are only noticed by an interrupt. | |
299 | */ | |
300 | if (enable_gpiov_ack) | |
301 | tmp2 |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); | |
302 | #endif | |
303 | intr_mask = REG_TYPE_CONV(reg_gio_rw_intr_mask, unsigned long, tmp2); | |
304 | REG_WR(gio, regi_gio, rw_intr_mask, intr_mask); | |
305 | ||
306 | return IRQ_RETVAL(tmp); | |
307 | } | |
308 | ||
a34d2442 JN |
309 | static void gpio_write_bit(unsigned long *port, unsigned char data, int bit, |
310 | unsigned char clk_mask, unsigned char data_mask) | |
311 | { | |
312 | unsigned long shadow = readl(port) & ~clk_mask; | |
313 | writel(shadow, port); | |
314 | if (data & 1 << bit) | |
315 | shadow |= data_mask; | |
316 | else | |
317 | shadow &= ~data_mask; | |
318 | writel(shadow, port); | |
319 | /* For FPGA: min 5.0ns (DCC) before CCLK high */ | |
320 | shadow |= clk_mask; | |
321 | writel(shadow, port); | |
322 | } | |
323 | ||
324 | static void gpio_write_byte(struct gpio_private *priv, unsigned long *port, | |
325 | unsigned char data) | |
326 | { | |
327 | int i; | |
328 | ||
329 | if (priv->write_msb) | |
330 | for (i = 7; i >= 0; i--) | |
331 | gpio_write_bit(port, data, i, priv->clk_mask, | |
332 | priv->data_mask); | |
333 | else | |
334 | for (i = 0; i <= 7; i++) | |
335 | gpio_write_bit(port, data, i, priv->clk_mask, | |
336 | priv->data_mask); | |
337 | } | |
338 | ||
18a1e013 | 339 | |
a34d2442 JN |
340 | static ssize_t gpio_write(struct file *file, const char __user *buf, |
341 | size_t count, loff_t *off) | |
18a1e013 | 342 | { |
a34d2442 | 343 | struct gpio_private *priv = file->private_data; |
18a1e013 | 344 | unsigned long flags; |
18a1e013 JN |
345 | ssize_t retval = count; |
346 | /* Only bits 0-7 may be used for write operations but allow all | |
347 | devices except leds... */ | |
348 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
349 | if (priv->minor == GPIO_MINOR_V) | |
350 | return -EFAULT; | |
351 | #endif | |
352 | if (priv->minor == GPIO_MINOR_LEDS) | |
353 | return -EFAULT; | |
354 | ||
355 | if (priv->minor >= GPIO_MINOR_PWM0 && | |
356 | priv->minor <= GPIO_MINOR_LAST_PWM) | |
357 | return -EFAULT; | |
358 | ||
359 | if (!access_ok(VERIFY_READ, buf, count)) | |
360 | return -EFAULT; | |
361 | ||
18a1e013 JN |
362 | /* It must have been configured using the IO_CFG_WRITE_MODE */ |
363 | /* Perhaps a better error code? */ | |
a34d2442 | 364 | if (priv->clk_mask == 0 || priv->data_mask == 0) |
18a1e013 JN |
365 | return -EPERM; |
366 | ||
18a1e013 JN |
367 | D(printk(KERN_DEBUG "gpio_write: %lu to data 0x%02X clk 0x%02X " |
368 | "msb: %i\n", | |
a34d2442 JN |
369 | count, priv->data_mask, priv->clk_mask, priv->write_msb)); |
370 | ||
371 | spin_lock_irqsave(&gpio_lock, flags); | |
372 | ||
373 | while (count--) | |
374 | gpio_write_byte(priv, data_out[priv->minor], *buf++); | |
375 | ||
376 | spin_unlock_irqrestore(&gpio_lock, flags); | |
18a1e013 JN |
377 | return retval; |
378 | } | |
379 | ||
a34d2442 | 380 | static int gpio_open(struct inode *inode, struct file *filp) |
18a1e013 JN |
381 | { |
382 | struct gpio_private *priv; | |
383 | int p = iminor(inode); | |
384 | ||
385 | if (p > GPIO_MINOR_LAST_PWM || | |
386 | (p > GPIO_MINOR_LAST && p < GPIO_MINOR_PWM0)) | |
387 | return -EINVAL; | |
388 | ||
389 | priv = kmalloc(sizeof(struct gpio_private), GFP_KERNEL); | |
390 | ||
391 | if (!priv) | |
392 | return -ENOMEM; | |
393 | memset(priv, 0, sizeof(*priv)); | |
394 | ||
395 | priv->minor = p; | |
a34d2442 | 396 | filp->private_data = priv; |
18a1e013 JN |
397 | |
398 | /* initialize the io/alarm struct, not for PWM ports though */ | |
399 | if (p <= GPIO_MINOR_LAST) { | |
400 | ||
401 | priv->clk_mask = 0; | |
402 | priv->data_mask = 0; | |
403 | priv->highalarm = 0; | |
404 | priv->lowalarm = 0; | |
405 | ||
406 | init_waitqueue_head(&priv->alarm_wq); | |
407 | ||
408 | /* link it into our alarmlist */ | |
a34d2442 | 409 | spin_lock_irq(&gpio_lock); |
18a1e013 JN |
410 | priv->next = alarmlist; |
411 | alarmlist = priv; | |
a34d2442 | 412 | spin_unlock_irq(&gpio_lock); |
18a1e013 JN |
413 | } |
414 | ||
415 | return 0; | |
416 | } | |
417 | ||
a34d2442 | 418 | static int gpio_release(struct inode *inode, struct file *filp) |
18a1e013 JN |
419 | { |
420 | struct gpio_private *p; | |
421 | struct gpio_private *todel; | |
422 | /* local copies while updating them: */ | |
423 | unsigned long a_high, a_low; | |
424 | ||
425 | /* prepare to free private structure */ | |
a34d2442 | 426 | todel = filp->private_data; |
18a1e013 JN |
427 | |
428 | /* unlink from alarmlist - only for non-PWM ports though */ | |
429 | if (todel->minor <= GPIO_MINOR_LAST) { | |
a34d2442 | 430 | spin_lock_irq(&gpio_lock); |
18a1e013 JN |
431 | p = alarmlist; |
432 | ||
433 | if (p == todel) | |
434 | alarmlist = todel->next; | |
435 | else { | |
436 | while (p->next != todel) | |
437 | p = p->next; | |
438 | p->next = todel->next; | |
439 | } | |
440 | ||
441 | /* Check if there are still any alarms set */ | |
442 | p = alarmlist; | |
443 | a_high = 0; | |
444 | a_low = 0; | |
445 | while (p) { | |
446 | if (p->minor == GPIO_MINOR_A) { | |
447 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
448 | p->lowalarm |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); | |
449 | #endif | |
450 | a_high |= p->highalarm; | |
451 | a_low |= p->lowalarm; | |
452 | } | |
453 | ||
454 | p = p->next; | |
455 | } | |
456 | ||
457 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
458 | /* Variable 'a_low' needs to be set here again | |
459 | * to ensure that interrupt for virtual GPIO is handled. | |
460 | */ | |
461 | a_low |= (1 << CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN); | |
462 | #endif | |
463 | ||
a34d2442 | 464 | spin_unlock_irq(&gpio_lock); |
18a1e013 JN |
465 | } |
466 | kfree(todel); | |
467 | ||
468 | return 0; | |
469 | } | |
470 | ||
471 | /* Main device API. ioctl's to read/set/clear bits, as well as to | |
472 | * set alarms to wait for using a subsequent select(). | |
473 | */ | |
474 | ||
475 | inline unsigned long setget_input(struct gpio_private *priv, unsigned long arg) | |
476 | { | |
477 | /* Set direction 0=unchanged 1=input, | |
478 | * return mask with 1=input | |
479 | */ | |
480 | unsigned long flags; | |
481 | unsigned long dir_shadow; | |
482 | ||
a34d2442 JN |
483 | spin_lock_irqsave(&gpio_lock, flags); |
484 | ||
485 | dir_shadow = readl(dir_oe[priv->minor]) & | |
486 | ~(arg & changeable_dir[priv->minor]); | |
487 | writel(dir_shadow, dir_oe[priv->minor]); | |
488 | ||
489 | spin_unlock_irqrestore(&gpio_lock, flags); | |
18a1e013 JN |
490 | |
491 | if (priv->minor == GPIO_MINOR_C) | |
492 | dir_shadow ^= 0xFFFF; /* Only 16 bits */ | |
493 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
494 | else if (priv->minor == GPIO_MINOR_V) | |
495 | dir_shadow ^= 0xFFFF; /* Only 16 bits */ | |
496 | #endif | |
497 | else | |
498 | dir_shadow ^= 0xFFFFFFFF; /* PA, PB and PD 32 bits */ | |
499 | ||
500 | return dir_shadow; | |
501 | ||
502 | } /* setget_input */ | |
503 | ||
a34d2442 JN |
504 | static inline unsigned long setget_output(struct gpio_private *priv, |
505 | unsigned long arg) | |
18a1e013 JN |
506 | { |
507 | unsigned long flags; | |
508 | unsigned long dir_shadow; | |
509 | ||
a34d2442 | 510 | spin_lock_irqsave(&gpio_lock, flags); |
18a1e013 | 511 | |
a34d2442 JN |
512 | dir_shadow = readl(dir_oe[priv->minor]) | |
513 | (arg & changeable_dir[priv->minor]); | |
514 | writel(dir_shadow, dir_oe[priv->minor]); | |
18a1e013 | 515 | |
a34d2442 JN |
516 | spin_unlock_irqrestore(&gpio_lock, flags); |
517 | return dir_shadow; | |
518 | } /* setget_output */ | |
18a1e013 | 519 | |
a34d2442 JN |
520 | static int gpio_ioctl(struct inode *inode, struct file *file, |
521 | unsigned int cmd, unsigned long arg) | |
18a1e013 JN |
522 | { |
523 | unsigned long flags; | |
524 | unsigned long val; | |
525 | unsigned long shadow; | |
a34d2442 | 526 | struct gpio_private *priv = file->private_data; |
18a1e013 JN |
527 | |
528 | if (_IOC_TYPE(cmd) != ETRAXGPIO_IOCTYPE) | |
a34d2442 | 529 | return -ENOTTY; |
18a1e013 JN |
530 | |
531 | /* Check for special ioctl handlers first */ | |
532 | ||
533 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
534 | if (priv->minor == GPIO_MINOR_V) | |
535 | return virtual_gpio_ioctl(file, cmd, arg); | |
536 | #endif | |
537 | ||
538 | if (priv->minor == GPIO_MINOR_LEDS) | |
539 | return gpio_leds_ioctl(cmd, arg); | |
540 | ||
541 | if (priv->minor >= GPIO_MINOR_PWM0 && | |
542 | priv->minor <= GPIO_MINOR_LAST_PWM) | |
543 | return gpio_pwm_ioctl(priv, cmd, arg); | |
544 | ||
545 | switch (_IOC_NR(cmd)) { | |
546 | case IO_READBITS: /* Use IO_READ_INBITS and IO_READ_OUTBITS instead */ | |
547 | /* Read the port. */ | |
a34d2442 | 548 | return readl(data_in[priv->minor]); |
18a1e013 | 549 | case IO_SETBITS: |
a34d2442 | 550 | spin_lock_irqsave(&gpio_lock, flags); |
18a1e013 | 551 | /* Set changeable bits with a 1 in arg. */ |
a34d2442 JN |
552 | shadow = readl(data_out[priv->minor]) | |
553 | (arg & changeable_bits[priv->minor]); | |
554 | writel(shadow, data_out[priv->minor]); | |
555 | spin_unlock_irqrestore(&gpio_lock, flags); | |
18a1e013 JN |
556 | break; |
557 | case IO_CLRBITS: | |
a34d2442 | 558 | spin_lock_irqsave(&gpio_lock, flags); |
18a1e013 | 559 | /* Clear changeable bits with a 1 in arg. */ |
a34d2442 JN |
560 | shadow = readl(data_out[priv->minor]) & |
561 | ~(arg & changeable_bits[priv->minor]); | |
562 | writel(shadow, data_out[priv->minor]); | |
563 | spin_unlock_irqrestore(&gpio_lock, flags); | |
18a1e013 JN |
564 | break; |
565 | case IO_HIGHALARM: | |
566 | /* Set alarm when bits with 1 in arg go high. */ | |
567 | priv->highalarm |= arg; | |
568 | gpio_set_alarm(priv); | |
569 | break; | |
570 | case IO_LOWALARM: | |
571 | /* Set alarm when bits with 1 in arg go low. */ | |
572 | priv->lowalarm |= arg; | |
573 | gpio_set_alarm(priv); | |
574 | break; | |
575 | case IO_CLRALARM: | |
576 | /* Clear alarm for bits with 1 in arg. */ | |
577 | priv->highalarm &= ~arg; | |
578 | priv->lowalarm &= ~arg; | |
579 | gpio_set_alarm(priv); | |
580 | break; | |
581 | case IO_READDIR: /* Use IO_SETGET_INPUT/OUTPUT instead! */ | |
582 | /* Read direction 0=input 1=output */ | |
a34d2442 JN |
583 | return readl(dir_oe[priv->minor]); |
584 | ||
18a1e013 JN |
585 | case IO_SETINPUT: /* Use IO_SETGET_INPUT instead! */ |
586 | /* Set direction 0=unchanged 1=input, | |
587 | * return mask with 1=input | |
588 | */ | |
589 | return setget_input(priv, arg); | |
a34d2442 | 590 | |
18a1e013 JN |
591 | case IO_SETOUTPUT: /* Use IO_SETGET_OUTPUT instead! */ |
592 | /* Set direction 0=unchanged 1=output, | |
593 | * return mask with 1=output | |
594 | */ | |
595 | return setget_output(priv, arg); | |
596 | ||
597 | case IO_CFG_WRITE_MODE: | |
598 | { | |
a34d2442 JN |
599 | int res = -EPERM; |
600 | unsigned long dir_shadow, clk_mask, data_mask, write_msb; | |
601 | ||
602 | clk_mask = arg & 0xFF; | |
603 | data_mask = (arg >> 8) & 0xFF; | |
604 | write_msb = (arg >> 16) & 0x01; | |
18a1e013 | 605 | |
18a1e013 JN |
606 | /* Check if we're allowed to change the bits and |
607 | * the direction is correct | |
608 | */ | |
a34d2442 JN |
609 | spin_lock_irqsave(&gpio_lock, flags); |
610 | dir_shadow = readl(dir_oe[priv->minor]); | |
611 | if ((clk_mask & changeable_bits[priv->minor]) && | |
612 | (data_mask & changeable_bits[priv->minor]) && | |
613 | (clk_mask & dir_shadow) && | |
614 | (data_mask & dir_shadow)) { | |
615 | priv->clk_mask = clk_mask; | |
616 | priv->data_mask = data_mask; | |
617 | priv->write_msb = write_msb; | |
618 | res = 0; | |
18a1e013 | 619 | } |
a34d2442 JN |
620 | spin_unlock_irqrestore(&gpio_lock, flags); |
621 | ||
622 | return res; | |
18a1e013 JN |
623 | } |
624 | case IO_READ_INBITS: | |
625 | /* *arg is result of reading the input pins */ | |
a34d2442 JN |
626 | val = readl(data_in[priv->minor]); |
627 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) | |
18a1e013 JN |
628 | return -EFAULT; |
629 | return 0; | |
18a1e013 JN |
630 | case IO_READ_OUTBITS: |
631 | /* *arg is result of reading the output shadow */ | |
632 | val = *data_out[priv->minor]; | |
a34d2442 | 633 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
18a1e013 JN |
634 | return -EFAULT; |
635 | break; | |
636 | case IO_SETGET_INPUT: | |
637 | /* bits set in *arg is set to input, | |
638 | * *arg updated with current input pins. | |
639 | */ | |
a34d2442 | 640 | if (copy_from_user(&val, (void __user *)arg, sizeof(val))) |
18a1e013 JN |
641 | return -EFAULT; |
642 | val = setget_input(priv, val); | |
a34d2442 | 643 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
18a1e013 JN |
644 | return -EFAULT; |
645 | break; | |
646 | case IO_SETGET_OUTPUT: | |
647 | /* bits set in *arg is set to output, | |
648 | * *arg updated with current output pins. | |
649 | */ | |
a34d2442 | 650 | if (copy_from_user(&val, (void __user *)arg, sizeof(val))) |
18a1e013 JN |
651 | return -EFAULT; |
652 | val = setget_output(priv, val); | |
a34d2442 | 653 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
18a1e013 JN |
654 | return -EFAULT; |
655 | break; | |
656 | default: | |
657 | return -EINVAL; | |
658 | } /* switch */ | |
659 | ||
660 | return 0; | |
661 | } | |
662 | ||
663 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
a34d2442 JN |
664 | static int virtual_gpio_ioctl(struct file *file, unsigned int cmd, |
665 | unsigned long arg) | |
18a1e013 JN |
666 | { |
667 | unsigned long flags; | |
668 | unsigned short val; | |
669 | unsigned short shadow; | |
a34d2442 | 670 | struct gpio_private *priv = file->private_data; |
18a1e013 JN |
671 | |
672 | switch (_IOC_NR(cmd)) { | |
673 | case IO_SETBITS: | |
a34d2442 | 674 | spin_lock_irqsave(&gpio_lock, flags); |
18a1e013 JN |
675 | /* Set changeable bits with a 1 in arg. */ |
676 | i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | |
a34d2442 JN |
677 | shadow |= ~readl(dir_oe[priv->minor]) | |
678 | (arg & changeable_bits[priv->minor]); | |
18a1e013 | 679 | i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); |
a34d2442 | 680 | spin_lock_irqrestore(&gpio_lock, flags); |
18a1e013 JN |
681 | break; |
682 | case IO_CLRBITS: | |
a34d2442 | 683 | spin_lock_irqsave(&gpio_lock, flags); |
18a1e013 JN |
684 | /* Clear changeable bits with a 1 in arg. */ |
685 | i2c_read(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | |
a34d2442 JN |
686 | shadow |= ~readl(dir_oe[priv->minor]) & |
687 | ~(arg & changeable_bits[priv->minor]); | |
18a1e013 | 688 | i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); |
a34d2442 | 689 | spin_lock_irqrestore(&gpio_lock, flags); |
18a1e013 JN |
690 | break; |
691 | case IO_HIGHALARM: | |
692 | /* Set alarm when bits with 1 in arg go high. */ | |
693 | priv->highalarm |= arg; | |
694 | break; | |
695 | case IO_LOWALARM: | |
696 | /* Set alarm when bits with 1 in arg go low. */ | |
697 | priv->lowalarm |= arg; | |
698 | break; | |
699 | case IO_CLRALARM: | |
700 | /* Clear alarm for bits with 1 in arg. */ | |
701 | priv->highalarm &= ~arg; | |
702 | priv->lowalarm &= ~arg; | |
703 | break; | |
704 | case IO_CFG_WRITE_MODE: | |
705 | { | |
706 | unsigned long dir_shadow; | |
a34d2442 | 707 | dir_shadow = readl(dir_oe[priv->minor]); |
18a1e013 JN |
708 | |
709 | priv->clk_mask = arg & 0xFF; | |
710 | priv->data_mask = (arg >> 8) & 0xFF; | |
711 | priv->write_msb = (arg >> 16) & 0x01; | |
712 | /* Check if we're allowed to change the bits and | |
713 | * the direction is correct | |
714 | */ | |
715 | if (!((priv->clk_mask & changeable_bits[priv->minor]) && | |
716 | (priv->data_mask & changeable_bits[priv->minor]) && | |
717 | (priv->clk_mask & dir_shadow) && | |
718 | (priv->data_mask & dir_shadow))) { | |
719 | priv->clk_mask = 0; | |
720 | priv->data_mask = 0; | |
721 | return -EPERM; | |
722 | } | |
723 | break; | |
724 | } | |
725 | case IO_READ_INBITS: | |
726 | /* *arg is result of reading the input pins */ | |
a34d2442 JN |
727 | val = cached_virtual_gpio_read & ~readl(dir_oe[priv->minor]); |
728 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) | |
18a1e013 JN |
729 | return -EFAULT; |
730 | return 0; | |
a34d2442 | 731 | |
18a1e013 JN |
732 | case IO_READ_OUTBITS: |
733 | /* *arg is result of reading the output shadow */ | |
734 | i2c_read(VIRT_I2C_ADDR, (void *)&val, sizeof(val)); | |
a34d2442 JN |
735 | val &= readl(dir_oe[priv->minor]); |
736 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) | |
18a1e013 JN |
737 | return -EFAULT; |
738 | break; | |
739 | case IO_SETGET_INPUT: | |
740 | { | |
741 | /* bits set in *arg is set to input, | |
742 | * *arg updated with current input pins. | |
743 | */ | |
a34d2442 JN |
744 | unsigned short input_mask = ~readl(dir_oe[priv->minor]); |
745 | if (copy_from_user(&val, (void __user *)arg, sizeof(val))) | |
18a1e013 JN |
746 | return -EFAULT; |
747 | val = setget_input(priv, val); | |
a34d2442 | 748 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
18a1e013 JN |
749 | return -EFAULT; |
750 | if ((input_mask & val) != input_mask) { | |
751 | /* Input pins changed. All ports desired as input | |
752 | * should be set to logic 1. | |
753 | */ | |
754 | unsigned short change = input_mask ^ val; | |
755 | i2c_read(VIRT_I2C_ADDR, (void *)&shadow, | |
756 | sizeof(shadow)); | |
757 | shadow &= ~change; | |
758 | shadow |= val; | |
759 | i2c_write(VIRT_I2C_ADDR, (void *)&shadow, | |
760 | sizeof(shadow)); | |
761 | } | |
762 | break; | |
763 | } | |
764 | case IO_SETGET_OUTPUT: | |
765 | /* bits set in *arg is set to output, | |
766 | * *arg updated with current output pins. | |
767 | */ | |
a34d2442 | 768 | if (copy_from_user(&val, (void __user *)arg, sizeof(val))) |
18a1e013 JN |
769 | return -EFAULT; |
770 | val = setget_output(priv, val); | |
a34d2442 | 771 | if (copy_to_user((void __user *)arg, &val, sizeof(val))) |
18a1e013 JN |
772 | return -EFAULT; |
773 | break; | |
774 | default: | |
775 | return -EINVAL; | |
776 | } /* switch */ | |
777 | return 0; | |
778 | } | |
779 | #endif /* CONFIG_ETRAX_VIRTUAL_GPIO */ | |
780 | ||
a34d2442 | 781 | static int gpio_leds_ioctl(unsigned int cmd, unsigned long arg) |
18a1e013 JN |
782 | { |
783 | unsigned char green; | |
784 | unsigned char red; | |
785 | ||
786 | switch (_IOC_NR(cmd)) { | |
787 | case IO_LEDACTIVE_SET: | |
788 | green = ((unsigned char) arg) & 1; | |
789 | red = (((unsigned char) arg) >> 1) & 1; | |
cacc0cc8 JN |
790 | CRIS_LED_ACTIVE_SET_G(green); |
791 | CRIS_LED_ACTIVE_SET_R(red); | |
18a1e013 JN |
792 | break; |
793 | ||
794 | default: | |
795 | return -EINVAL; | |
796 | } /* switch */ | |
797 | ||
798 | return 0; | |
799 | } | |
800 | ||
801 | static int gpio_pwm_set_mode(unsigned long arg, int pwm_port) | |
802 | { | |
803 | int pinmux_pwm = pinmux_pwm0 + pwm_port; | |
804 | int mode; | |
805 | reg_gio_rw_pwm0_ctrl rw_pwm_ctrl = { | |
806 | .ccd_val = 0, | |
807 | .ccd_override = regk_gio_no, | |
808 | .mode = regk_gio_no | |
809 | }; | |
810 | int allocstatus; | |
811 | ||
812 | if (get_user(mode, &((struct io_pwm_set_mode *) arg)->mode)) | |
813 | return -EFAULT; | |
814 | rw_pwm_ctrl.mode = mode; | |
815 | if (mode != PWM_OFF) | |
816 | allocstatus = crisv32_pinmux_alloc_fixed(pinmux_pwm); | |
817 | else | |
818 | allocstatus = crisv32_pinmux_dealloc_fixed(pinmux_pwm); | |
819 | if (allocstatus) | |
820 | return allocstatus; | |
821 | REG_WRITE(reg_gio_rw_pwm0_ctrl, REG_ADDR(gio, regi_gio, rw_pwm0_ctrl) + | |
822 | 12 * pwm_port, rw_pwm_ctrl); | |
823 | return 0; | |
824 | } | |
825 | ||
826 | static int gpio_pwm_set_period(unsigned long arg, int pwm_port) | |
827 | { | |
828 | struct io_pwm_set_period periods; | |
829 | reg_gio_rw_pwm0_var rw_pwm_widths; | |
830 | ||
a34d2442 | 831 | if (copy_from_user(&periods, (void __user *)arg, sizeof(periods))) |
18a1e013 JN |
832 | return -EFAULT; |
833 | if (periods.lo > 8191 || periods.hi > 8191) | |
834 | return -EINVAL; | |
835 | rw_pwm_widths.lo = periods.lo; | |
836 | rw_pwm_widths.hi = periods.hi; | |
837 | REG_WRITE(reg_gio_rw_pwm0_var, REG_ADDR(gio, regi_gio, rw_pwm0_var) + | |
838 | 12 * pwm_port, rw_pwm_widths); | |
839 | return 0; | |
840 | } | |
841 | ||
842 | static int gpio_pwm_set_duty(unsigned long arg, int pwm_port) | |
843 | { | |
844 | unsigned int duty; | |
845 | reg_gio_rw_pwm0_data rw_pwm_duty; | |
846 | ||
847 | if (get_user(duty, &((struct io_pwm_set_duty *) arg)->duty)) | |
848 | return -EFAULT; | |
849 | if (duty > 255) | |
850 | return -EINVAL; | |
851 | rw_pwm_duty.data = duty; | |
852 | REG_WRITE(reg_gio_rw_pwm0_data, REG_ADDR(gio, regi_gio, rw_pwm0_data) + | |
853 | 12 * pwm_port, rw_pwm_duty); | |
854 | return 0; | |
855 | } | |
856 | ||
a34d2442 JN |
857 | static int gpio_pwm_ioctl(struct gpio_private *priv, unsigned int cmd, |
858 | unsigned long arg) | |
18a1e013 JN |
859 | { |
860 | int pwm_port = priv->minor - GPIO_MINOR_PWM0; | |
861 | ||
862 | switch (_IOC_NR(cmd)) { | |
863 | case IO_PWM_SET_MODE: | |
864 | return gpio_pwm_set_mode(arg, pwm_port); | |
865 | case IO_PWM_SET_PERIOD: | |
866 | return gpio_pwm_set_period(arg, pwm_port); | |
867 | case IO_PWM_SET_DUTY: | |
868 | return gpio_pwm_set_duty(arg, pwm_port); | |
869 | default: | |
870 | return -EINVAL; | |
871 | } | |
872 | return 0; | |
873 | } | |
874 | ||
a34d2442 | 875 | static const struct file_operations gpio_fops = { |
18a1e013 JN |
876 | .owner = THIS_MODULE, |
877 | .poll = gpio_poll, | |
878 | .ioctl = gpio_ioctl, | |
879 | .write = gpio_write, | |
880 | .open = gpio_open, | |
881 | .release = gpio_release, | |
882 | }; | |
883 | ||
884 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
a34d2442 | 885 | static void __init virtual_gpio_init(void) |
18a1e013 JN |
886 | { |
887 | reg_gio_rw_intr_cfg intr_cfg; | |
888 | reg_gio_rw_intr_mask intr_mask; | |
889 | unsigned short shadow; | |
890 | ||
891 | shadow = ~virtual_rw_pv_oe; /* Input ports should be set to logic 1 */ | |
892 | shadow |= CONFIG_ETRAX_DEF_GIO_PV_OUT; | |
893 | i2c_write(VIRT_I2C_ADDR, (void *)&shadow, sizeof(shadow)); | |
894 | ||
895 | /* Set interrupt mask and on what state the interrupt shall trigger. | |
896 | * For virtual gpio the interrupt shall trigger on logic '0'. | |
897 | */ | |
898 | intr_cfg = REG_RD(gio, regi_gio, rw_intr_cfg); | |
899 | intr_mask = REG_RD(gio, regi_gio, rw_intr_mask); | |
900 | ||
901 | switch (CONFIG_ETRAX_VIRTUAL_GPIO_INTERRUPT_PA_PIN) { | |
902 | case 0: | |
903 | intr_cfg.pa0 = regk_gio_lo; | |
904 | intr_mask.pa0 = regk_gio_yes; | |
905 | break; | |
906 | case 1: | |
907 | intr_cfg.pa1 = regk_gio_lo; | |
908 | intr_mask.pa1 = regk_gio_yes; | |
909 | break; | |
910 | case 2: | |
911 | intr_cfg.pa2 = regk_gio_lo; | |
912 | intr_mask.pa2 = regk_gio_yes; | |
913 | break; | |
914 | case 3: | |
915 | intr_cfg.pa3 = regk_gio_lo; | |
916 | intr_mask.pa3 = regk_gio_yes; | |
917 | break; | |
918 | case 4: | |
919 | intr_cfg.pa4 = regk_gio_lo; | |
920 | intr_mask.pa4 = regk_gio_yes; | |
921 | break; | |
922 | case 5: | |
923 | intr_cfg.pa5 = regk_gio_lo; | |
924 | intr_mask.pa5 = regk_gio_yes; | |
925 | break; | |
926 | case 6: | |
927 | intr_cfg.pa6 = regk_gio_lo; | |
928 | intr_mask.pa6 = regk_gio_yes; | |
929 | break; | |
930 | case 7: | |
931 | intr_cfg.pa7 = regk_gio_lo; | |
932 | intr_mask.pa7 = regk_gio_yes; | |
933 | break; | |
934 | } | |
935 | ||
936 | REG_WR(gio, regi_gio, rw_intr_cfg, intr_cfg); | |
937 | REG_WR(gio, regi_gio, rw_intr_mask, intr_mask); | |
938 | } | |
939 | #endif | |
940 | ||
941 | /* main driver initialization routine, called from mem.c */ | |
942 | ||
a34d2442 | 943 | static int __init gpio_init(void) |
18a1e013 JN |
944 | { |
945 | int res; | |
946 | ||
a34d2442 JN |
947 | printk(KERN_INFO "ETRAX FS GPIO driver v2.7, (c) 2003-2008 " |
948 | "Axis Communications AB\n"); | |
949 | ||
18a1e013 JN |
950 | /* do the formalities */ |
951 | ||
952 | res = register_chrdev(GPIO_MAJOR, gpio_name, &gpio_fops); | |
953 | if (res < 0) { | |
954 | printk(KERN_ERR "gpio: couldn't get a major number.\n"); | |
955 | return res; | |
956 | } | |
957 | ||
958 | /* Clear all leds */ | |
cacc0cc8 JN |
959 | CRIS_LED_NETWORK_GRP0_SET(0); |
960 | CRIS_LED_NETWORK_GRP1_SET(0); | |
961 | CRIS_LED_ACTIVE_SET(0); | |
962 | CRIS_LED_DISK_READ(0); | |
963 | CRIS_LED_DISK_WRITE(0); | |
18a1e013 | 964 | |
a34d2442 JN |
965 | int res2 = request_irq(GIO_INTR_VECT, gpio_interrupt, |
966 | IRQF_SHARED | IRQF_DISABLED, "gpio", &alarmlist); | |
967 | if (res2) { | |
18a1e013 | 968 | printk(KERN_ERR "err: irq for gpio\n"); |
a34d2442 JN |
969 | return res2; |
970 | } | |
18a1e013 JN |
971 | |
972 | /* No IRQs by default. */ | |
973 | REG_WR_INT(gio, regi_gio, rw_intr_pins, 0); | |
974 | ||
975 | #ifdef CONFIG_ETRAX_VIRTUAL_GPIO | |
976 | virtual_gpio_init(); | |
977 | #endif | |
978 | ||
979 | return res; | |
980 | } | |
981 | ||
982 | /* this makes sure that gpio_init is called during kernel boot */ | |
983 | ||
984 | module_init(gpio_init); |