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