danube gpio clean up
[openwrt.git] / target / linux / danube / files / drivers / char / danube_led.c
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
15 *
16 * Copyright (C) 2006 infineon
17 * Copyright (C) 2007 John Crispin <blogic@openwrt.org>
18 *
19 */
20
21 #include <linux/kernel.h>
22 #include <linux/module.h>
23 #include <linux/version.h>
24 #include <linux/types.h>
25 #include <linux/fs.h>
26 #include <linux/miscdevice.h>
27 #include <linux/init.h>
28 #include <asm/uaccess.h>
29 #include <asm/unistd.h>
30 #include <linux/errno.h>
31 #include <asm/danube/danube.h>
32 #include <asm/danube/port.h>
33 #include <asm/danube/danube_led.h>
34 #include <asm/danube/danube_gptu.h>
35
36 #define LED_CONFIG 0x01
37
38 #define CONFIG_OPERATION_UPDATE_SOURCE 0x0001
39 #define CONFIG_OPERATION_BLINK 0x0002
40 #define CONFIG_OPERATION_UPDATE_CLOCK 0x0004
41 #define CONFIG_OPERATION_STORE_MODE 0x0008
42 #define CONFIG_OPERATION_SHIFT_CLOCK 0x0010
43 #define CONFIG_OPERATION_DATA_OFFSET 0x0020
44 #define CONFIG_OPERATION_NUMBER_OF_LED 0x0040
45 #define CONFIG_OPERATION_DATA 0x0080
46 #define CONFIG_OPERATION_MIPS0_ACCESS 0x0100
47 #define CONFIG_DATA_CLOCK_EDGE 0x0200
48
49
50 /*
51 * Data Type Used to Call ioctl
52 */
53 struct led_config_param {
54 unsigned long operation_mask; // Select operations to be performed
55 unsigned long led; // LED to change update source (LED or ADSL)
56 unsigned long source; // Corresponding update source (LED or ADSL)
57 unsigned long blink_mask; // LEDs to set blink mode
58 unsigned long blink; // Set to blink mode or normal mode
59 unsigned long update_clock; // Select the source of update clock
60 unsigned long fpid; // If FPI is the source of update clock, set the divider
61 // else if GPT is the source, set the frequency
62 unsigned long store_mode; // Set clock mode or single pulse mode for store signal
63 unsigned long fpis; // FPI is the source of shift clock, set the divider
64 unsigned long data_offset; // Set cycles to be inserted before data is transmitted
65 unsigned long number_of_enabled_led; // Total number of LED to be enabled
66 unsigned long data_mask; // LEDs to set value
67 unsigned long data; // Corresponding value
68 unsigned long mips0_access_mask; // LEDs to set access right
69 unsigned long mips0_access; // 1: the corresponding data is output from MIPS0, 0: MIPS1
70 unsigned long f_data_clock_on_rising; // 1: data clock on rising edge, 0: data clock on falling edge
71 };
72
73
74 extern int danube_led_set_blink(unsigned int, unsigned int);
75 extern int danube_led_set_data(unsigned int, unsigned int);
76 extern int danube_led_config(struct led_config_param *);
77
78 #define DATA_CLOCKING_EDGE FALLING_EDGE
79 #define RISING_EDGE 0
80 #define FALLING_EDGE 1
81
82 #define port_reserve_pin danube_port_reserve_pin
83 #define port_free_pin danube_port_free_pin
84 #define port_set_altsel0 danube_port_set_altsel0
85 #define port_clear_altsel0 danube_port_clear_altsel0
86 #define port_set_altsel1 danube_port_set_altsel1
87 #define port_clear_altsel1 danube_port_clear_altsel1
88 #define port_set_dir_out danube_port_set_dir_out
89 #define port_clear_dir_out danube_port_clear_dir_out
90 #define port_set_open_drain danube_port_set_open_drain
91 #define port_clear_open_drain danube_port_clear_open_drain
92
93 #define LED_SH_PORT 0
94 #define LED_SH_PIN 4
95 #define LED_SH_DIR 1
96 #define LED_SH_ALTSEL0 1
97 #define LED_SH_ALTSEL1 0
98 #define LED_SH_OPENDRAIN 1
99 #define LED_D_PORT 0
100 #define LED_D_PIN 5
101 #define LED_D_DIR 1
102 #define LED_D_ALTSEL0 1
103 #define LED_D_ALTSEL1 0
104 #define LED_D_OPENDRAIN 1
105 #define LED_ST_PORT 0
106 #define LED_ST_PIN 6
107 #define LED_ST_DIR 1
108 #define LED_ST_ALTSEL0 1
109 #define LED_ST_ALTSEL1 0
110 #define LED_ST_OPENDRAIN 1
111
112 #define LED_ADSL0_PORT 0
113 #define LED_ADSL0_PIN 4
114 #define LED_ADSL0_DIR 1
115 #define LED_ADSL0_ALTSEL0 0
116 #define LED_ADSL0_ALTSEL1 1
117 #define LED_ADSL0_OPENDRAIN 1
118 #define LED_ADSL1_PORT 0
119 #define LED_ADSL1_PIN 5
120 #define LED_ADSL1_DIR 1
121 #define LED_ADSL1_ALTSEL0 1
122 #define LED_ADSL1_ALTSEL1 1
123 #define LED_ADSL1_OPENDRAIN 1
124
125 #if (LED_SH_PORT == LED_ADSL0_PORT && LED_SH_PIN == LED_ADSL0_PIN) \
126 || (LED_D_PORT == LED_ADSL0_PORT && LED_D_PIN == LED_ADSL0_PIN) \
127 || (LED_ST_PORT == LED_ADSL0_PORT && LED_ST_PIN == LED_ADSL0_PIN) \
128 || (LED_SH_PORT == LED_ADSL1_PORT && LED_SH_PIN == LED_ADSL1_PIN) \
129 || (LED_D_PORT == LED_ADSL1_PORT && LED_D_PIN == LED_ADSL1_PIN) \
130 || (LED_ST_PORT == LED_ADSL1_PORT && LED_ST_PIN == LED_ADSL1_PIN)
131 #define ADSL_LED_IS_EXCLUSIVE 1
132 #else
133 #define ADSL_LED_IS_EXCLUSIVE 0
134 #endif
135
136 #if LED_SH_DIR
137 #define LED_SH_DIR_SETUP port_set_dir_out
138 #else
139 #define LED_SH_DIR_SETUP port_clear_dir_out
140 #endif
141 #if LED_SH_ALTSEL0
142 #define LED_SH_ALTSEL0_SETUP port_set_altsel0
143 #else
144 #define LED_SH_ALTSEL0_SETUP port_clear_altsel0
145 #endif
146 #if LED_SH_ALTSEL1
147 #define LED_SH_ALTSEL1_SETUP port_set_altsel1
148 #else
149 #define LED_SH_ALTSEL1_SETUP port_clear_altsel1
150 #endif
151 #if LED_SH_OPENDRAIN
152 #define LED_SH_OPENDRAIN_SETUP port_set_open_drain
153 #else
154 #define LED_SH_OPENDRAIN_SETUP port_clear_open_drain
155 #endif
156
157 #if LED_D_DIR
158 #define LED_D_DIR_SETUP port_set_dir_out
159 #else
160 #define LED_D_DIR_SETUP port_clear_dir_out
161 #endif
162 #if LED_D_ALTSEL0
163 #define LED_D_ALTSEL0_SETUP port_set_altsel0
164 #else
165 #define LED_D_ALTSEL0_SETUP port_clear_altsel0
166 #endif
167 #if LED_D_ALTSEL1
168 #define LED_D_ALTSEL1_SETUP port_set_altsel1
169 #else
170 #define LED_D_ALTSEL1_SETUP port_clear_altsel1
171 #endif
172 #if LED_D_OPENDRAIN
173 #define LED_D_OPENDRAIN_SETUP port_set_open_drain
174 #else
175 #define LED_D_OPENDRAIN_SETUP port_clear_open_drain
176 #endif
177
178 #if LED_ST_DIR
179 #define LED_ST_DIR_SETUP port_set_dir_out
180 #else
181 #define LED_ST_DIR_SETUP port_clear_dir_out
182 #endif
183 #if LED_ST_ALTSEL0
184 #define LED_ST_ALTSEL0_SETUP port_set_altsel0
185 #else
186 #define LED_ST_ALTSEL0_SETUP port_clear_altsel0
187 #endif
188 #if LED_ST_ALTSEL1
189 #define LED_ST_ALTSEL1_SETUP port_set_altsel1
190 #else
191 #define LED_ST_ALTSEL1_SETUP port_clear_altsel1
192 #endif
193 #if LED_ST_OPENDRAIN
194 #define LED_ST_OPENDRAIN_SETUP port_set_open_drain
195 #else
196 #define LED_ST_OPENDRAIN_SETUP port_clear_open_drain
197 #endif
198
199 #if LED_ADSL0_DIR
200 #define LED_ADSL0_DIR_SETUP port_set_dir_out
201 #else
202 #define LED_ADSL0_DIR_SETUP port_clear_dir_out
203 #endif
204 #if LED_ADSL0_ALTSEL0
205 #define LED_ADSL0_ALTSEL0_SETUP port_set_altsel0
206 #else
207 #define LED_ADSL0_ALTSEL0_SETUP port_clear_altsel0
208 #endif
209 #if LED_ADSL0_ALTSEL1
210 #define LED_ADSL0_ALTSEL1_SETUP port_set_altsel1
211 #else
212 #define LED_ADSL0_ALTSEL1_SETUP port_clear_altsel1
213 #endif
214 #if LED_ADSL0_OPENDRAIN
215 #define LED_ADSL0_OPENDRAIN_SETUP port_set_open_drain
216 #else
217 #define LED_ADSL0_OPENDRAIN_SETUP port_clear_open_drain
218 #endif
219
220 #if LED_ADSL1_DIR
221 #define LED_ADSL1_DIR_SETUP port_set_dir_out
222 #else
223 #define LED_ADSL1_DIR_SETUP port_clear_dir_out
224 #endif
225 #if LED_ADSL1_ALTSEL0
226 #define LED_ADSL1_ALTSEL0_SETUP port_set_altsel0
227 #else
228 #define LED_ADSL1_ALTSEL0_SETUP port_clear_altsel0
229 #endif
230 #if LED_ADSL1_ALTSEL1
231 #define LED_ADSL1_ALTSEL1_SETUP port_set_altsel1
232 #else
233 #define LED_ADSL1_ALTSEL1_SETUP port_clear_altsel1
234 #endif
235 #if LED_ADSL1_OPENDRAIN
236 #define LED_ADSL1_OPENDRAIN_SETUP port_set_open_drain
237 #else
238 #define LED_ADSL1_OPENDRAIN_SETUP port_clear_open_drain
239 #endif
240
241 #define SET_BITS(x, msb, lsb, value) (((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | (((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb)))
242
243 static inline int update_led(void);
244
245 static inline unsigned int set_update_source(unsigned int, unsigned long, unsigned long);
246 static inline unsigned int set_blink_in_batch(unsigned int, unsigned long, unsigned long);
247 static inline unsigned int set_data_clock_edge(unsigned int, unsigned long);
248 static inline unsigned int set_update_clock(unsigned int, unsigned long, unsigned long);
249 static inline unsigned int set_store_mode(unsigned int, unsigned long);
250 static inline unsigned int set_shift_clock(unsigned int, unsigned long);
251 static inline unsigned int set_data_offset(unsigned int, unsigned long);
252 static inline unsigned int set_number_of_enabled_led(unsigned int, unsigned long);
253 static inline unsigned int set_data_in_batch(unsigned int, unsigned long, unsigned long);
254 static inline unsigned int set_access_right(unsigned int, unsigned long, unsigned long);
255
256 static inline void enable_led(void);
257 static inline void disable_led(void);
258
259 static inline int setup_gpio_port(unsigned long);
260 static inline void release_gpio_port(unsigned long);
261
262 static inline int setup_gpt(int, unsigned long);
263 static inline void release_gpt(int);
264
265 static inline int turn_on_led(unsigned long);
266 static inline void turn_off_led(unsigned long);
267
268
269 static struct semaphore led_sem;
270
271 static unsigned long gpt_on = 0;
272 static unsigned long gpt_freq = 0;
273
274 static unsigned long adsl_on = 0;
275 static unsigned long f_led_on = 0;
276
277 static int module_id;
278
279
280 static inline int
281 update_led (void)
282 {
283 int i, j;
284
285 /*
286 * GPT2 or FPID is the clock to update LEDs automatically.
287 */
288 if (readl(DANUBE_LED_CON1) >> 30)
289 return 0;
290
291 /*
292 * Check the status to prevent conflict of two consecutive update
293 */
294 for ( i = 100000; i != 0; i -= j / 16 )
295 {
296 down(&led_sem);
297 if (!(readl(DANUBE_LED_CON0) & LED_CON0_SWU))
298 {
299 *DANUBE_LED_CON0 |= 1 << 31;
300 up(&led_sem);
301 return 0;
302 }
303 else
304 up(&led_sem);
305 for ( j = 0; j < 1000 * 16; j++ );
306 }
307
308 return -EBUSY;
309 }
310
311 static inline unsigned int
312 set_update_source (unsigned int reg, unsigned long led, unsigned long source)
313 {
314 return (reg & ~((led & 0x03) << 24)) | ((source & 0x03) << 24);
315 }
316
317 static inline unsigned int
318 set_blink_in_batch (unsigned int reg, unsigned long mask, unsigned long blink)
319 {
320 return (reg & (~(mask & 0x00FFFFFF) & 0x87FFFFFF)) | (blink & 0x00FFFFFF);
321 }
322
323 static inline unsigned int
324 set_data_clock_edge (unsigned int reg, unsigned long f_on_rising_edge)
325 {
326 return f_on_rising_edge ? (reg & ~(1 << 26)) : (reg | (1 << 26));
327 }
328
329 static inline unsigned int
330 set_update_clock (unsigned int reg, unsigned long clock, unsigned long fpid)
331 {
332 switch ( clock )
333 {
334 case 0: reg &= ~0xC0000000; break;
335 case 1: reg = (reg & ~0xC0000000) | 0x40000000; break;
336 case 2: reg = (reg & ~0xCF800000) | 0x80000000 | ((fpid & 0x1F) << 23); break;
337 }
338 return reg;
339 }
340
341 static inline unsigned int
342 set_store_mode (unsigned int reg, unsigned long mode)
343 {
344 return mode ? (reg | (1 << 28)) : (reg & ~(1 << 28));
345 }
346
347 static inline
348 unsigned int set_shift_clock (unsigned int reg, unsigned long fpis)
349 {
350 return SET_BITS(reg, 21, 20, fpis);
351 }
352
353 static inline
354 unsigned int set_data_offset (unsigned int reg, unsigned long offset)
355 {
356 return SET_BITS(reg, 19, 18, offset);
357 }
358
359 static inline
360 unsigned int set_number_of_enabled_led (unsigned int reg, unsigned long number)
361 {
362 unsigned int bit_mask;
363
364 bit_mask = number > 16 ? 0x07 : (number > 8 ? 0x03 : (number ? 0x01 : 0x00));
365 return (reg & ~0x07) | bit_mask;
366 }
367
368 static inline unsigned int
369 set_data_in_batch (unsigned int reg, unsigned long mask, unsigned long data)
370 {
371 return (reg & ~(mask & 0x00FFFFFF)) | (data & 0x00FFFFFF);
372 }
373
374 static inline unsigned int
375 set_access_right (unsigned int reg, unsigned long mask, unsigned long ar)
376 {
377 return (reg & ~(mask & 0x00FFFFFF)) | (~ar & mask);
378 }
379
380 static inline void
381 enable_led (void)
382 {
383 /* Activate LED module in PMU. */
384 int i = 1000000;
385
386 *(unsigned long *)0xBF10201C &= ~(1 << 11);
387 while ( --i && (*(unsigned long *)0xBF102020 & (1 << 11)) );
388 if ( !i )
389 panic("Activating LED in PMU failed!");
390 }
391
392 static inline void
393 disable_led (void)
394 {
395 *(unsigned long *)0xBF10201C |= 1 << 11;
396 }
397
398 static inline int
399 setup_gpio_port (unsigned long adsl)
400 {
401 int ret = 0;
402
403 /*
404 * Reserve all pins before config them.
405 */
406 if ( adsl )
407 {
408 ret |= port_reserve_pin(LED_ADSL0_PORT, LED_ADSL0_PIN, module_id);
409 ret |= port_reserve_pin(LED_ADSL1_PORT, LED_ADSL1_PIN, module_id);
410 }
411 else
412 {
413 ret |= port_reserve_pin(LED_ST_PORT, LED_ST_PIN, module_id);
414 ret |= port_reserve_pin(LED_D_PORT, LED_D_PIN, module_id);
415 ret |= port_reserve_pin(LED_SH_PORT, LED_SH_PIN, module_id);
416 }
417 if ( ret )
418 {
419 release_gpio_port(adsl);
420 return ret; // Should be -EBUSY
421 }
422
423 if ( adsl )
424 {
425 LED_ADSL0_ALTSEL0_SETUP(LED_ADSL0_PORT, LED_ADSL0_PIN, module_id);
426 LED_ADSL0_ALTSEL1_SETUP(LED_ADSL0_PORT, LED_ADSL0_PIN, module_id);
427 LED_ADSL0_DIR_SETUP(LED_ADSL0_PORT, LED_ADSL0_PIN, module_id);
428 LED_ADSL0_OPENDRAIN_SETUP(LED_ADSL0_PORT, LED_ADSL0_PIN, module_id);
429
430 LED_ADSL1_ALTSEL0_SETUP(LED_ADSL1_PORT, LED_ADSL1_PIN, module_id);
431 LED_ADSL1_ALTSEL1_SETUP(LED_ADSL1_PORT, LED_ADSL1_PIN, module_id);
432 LED_ADSL1_DIR_SETUP(LED_ADSL1_PORT, LED_ADSL1_PIN, module_id);
433 LED_ADSL1_OPENDRAIN_SETUP(LED_ADSL1_PORT, LED_ADSL1_PIN, module_id);
434 }
435 else
436 {
437 /*
438 * Set LED_ST
439 * I don't check the return value, because I'm sure the value is valid
440 * and the pins are reserved already.
441 */
442 LED_ST_ALTSEL0_SETUP(LED_ST_PORT, LED_ST_PIN, module_id);
443 LED_ST_ALTSEL1_SETUP(LED_ST_PORT, LED_ST_PIN, module_id);
444 LED_ST_DIR_SETUP(LED_ST_PORT, LED_ST_PIN, module_id);
445 LED_ST_OPENDRAIN_SETUP(LED_ST_PORT, LED_ST_PIN, module_id);
446
447 /*
448 * Set LED_D
449 */
450 LED_D_ALTSEL0_SETUP(LED_D_PORT, LED_D_PIN, module_id);
451 LED_D_ALTSEL1_SETUP(LED_D_PORT, LED_D_PIN, module_id);
452 LED_D_DIR_SETUP(LED_D_PORT, LED_D_PIN, module_id);
453 LED_D_OPENDRAIN_SETUP(LED_D_PORT, LED_D_PIN, module_id);
454
455 /*
456 * Set LED_SH
457 */
458 LED_SH_ALTSEL0_SETUP(LED_SH_PORT, LED_SH_PIN, module_id);
459 LED_SH_ALTSEL1_SETUP(LED_SH_PORT, LED_SH_PIN, module_id);
460 LED_SH_DIR_SETUP(LED_SH_PORT, LED_SH_PIN, module_id);
461 LED_SH_OPENDRAIN_SETUP(LED_SH_PORT, LED_SH_PIN, module_id);
462 }
463
464 return 0;
465 }
466
467 static inline void
468 release_gpio_port (unsigned long adsl)
469 {
470 if ( adsl )
471 {
472 port_free_pin(LED_ADSL0_PORT, LED_ADSL0_PIN, module_id);
473 port_free_pin(LED_ADSL1_PORT, LED_ADSL1_PIN, module_id);
474 }
475 else
476 {
477 port_free_pin(LED_ST_PORT, LED_ST_PIN, module_id);
478 port_free_pin(LED_D_PORT, LED_D_PIN, module_id);
479 port_free_pin(LED_SH_PORT, LED_SH_PIN, module_id);
480 }
481 }
482
483 static inline int
484 setup_gpt (int timer, unsigned long freq)
485 {
486 int ret;
487
488 timer = TIMER(timer, 1);
489
490 ret = request_timer(timer,
491 TIMER_FLAG_SYNC
492 | TIMER_FLAG_16BIT
493 | TIMER_FLAG_INT_SRC
494 | TIMER_FLAG_CYCLIC | TIMER_FLAG_COUNTER | TIMER_FLAG_DOWN
495 | TIMER_FLAG_ANY_EDGE
496 | TIMER_FLAG_NO_HANDLE,
497 8000000 / freq,
498 0,
499 0);
500
501 if ( !ret )
502 {
503 ret = start_timer(timer, 0);
504 if ( ret )
505 free_timer(timer);
506 }
507
508 return ret;
509 }
510
511 static inline void
512 release_gpt (int timer)
513 {
514 timer = TIMER(timer, 1);
515 stop_timer(timer);
516 free_timer(timer);
517 }
518
519 static inline int
520 turn_on_led (unsigned long adsl)
521 {
522 int ret;
523
524 ret = setup_gpio_port(adsl);
525 if ( ret )
526 return ret;
527
528 enable_led();
529
530 return 0;
531 }
532
533 static inline void
534 turn_off_led (unsigned long adsl)
535 {
536 release_gpio_port(adsl);
537 disable_led();
538 }
539
540
541 int
542 danube_led_set_blink (unsigned int led, unsigned int blink)
543 {
544 unsigned int bit_mask;
545
546 if ( led > 23 )
547 return -EINVAL;
548
549 bit_mask = 1 << led;
550 down(&led_sem);
551 if ( blink )
552 *DANUBE_LED_CON0 |= bit_mask;
553 else
554 *DANUBE_LED_CON0 &= ~bit_mask;
555 up(&led_sem);
556
557 return (led == 0 && (readl(DANUBE_LED_CON0) & LED_CON0_AD0)) || (led == 1 && (readl(DANUBE_LED_CON0) & LED_CON0_AD1)) ? -EINVAL : 0;
558 }
559
560 int
561 danube_led_set_data (unsigned int led, unsigned int data)
562 {
563 unsigned long f_update;
564 unsigned int bit_mask;
565
566 if ( led > 23 )
567 return -EINVAL;
568
569 bit_mask = 1 << led;
570 down(&led_sem);
571 if ( data )
572 *DANUBE_LED_CPU0 |= bit_mask;
573 else
574 *DANUBE_LED_CPU0 &= ~bit_mask;
575 f_update = !(*DANUBE_LED_AR & bit_mask);
576 up(&led_sem);
577
578 return f_update ? update_led() : 0;
579 }
580
581 int
582 danube_led_config (struct led_config_param* param)
583 {
584 int ret;
585 unsigned int reg_con0, reg_con1, reg_cpu0, reg_ar;
586 unsigned int clean_reg_con0, clean_reg_con1, clean_reg_cpu0, clean_reg_ar;
587 unsigned int f_setup_gpt2;
588 unsigned int f_software_update;
589 unsigned int new_led_on, new_adsl_on;
590
591 if ( !param )
592 return -EINVAL;
593
594 down(&led_sem);
595
596 reg_con0 = *DANUBE_LED_CON0;
597 reg_con1 = *DANUBE_LED_CON1;
598 reg_cpu0 = *DANUBE_LED_CPU0;
599 reg_ar = *DANUBE_LED_AR;
600
601 clean_reg_con0 = 1;
602 clean_reg_con1 = 1;
603 clean_reg_cpu0 = 1;
604 clean_reg_ar = 1;
605
606 f_setup_gpt2 = 0;
607
608 f_software_update = (readl(DANUBE_LED_CON0) & LED_CON0_SWU) ? 0 : 1;
609
610 new_led_on = f_led_on;
611 new_adsl_on = adsl_on;
612
613 /* ADSL or LED */
614 if ( (param->operation_mask & CONFIG_OPERATION_UPDATE_SOURCE) )
615 {
616 if ( param->led > 0x03 || param->source > 0x03 )
617 goto INVALID_PARAM;
618 clean_reg_con0 = 0;
619 reg_con0 = set_update_source(reg_con0, param->led, param->source);
620 #if 0 // ADSL0,1 is source for bit 0, 1 in shift register
621 new_adsl_on = param->source;
622 #endif
623 }
624
625 /* Blink */
626 if ( (param->operation_mask & CONFIG_OPERATION_BLINK) )
627 {
628 if ( (param->blink_mask & 0xFF000000) || (param->blink & 0xFF000000) )
629 goto INVALID_PARAM;
630 clean_reg_con0 = 0;
631 reg_con0 = set_blink_in_batch(reg_con0, param->blink_mask, param->blink);
632 }
633
634 /* Edge */
635 if ( (param->operation_mask & CONFIG_DATA_CLOCK_EDGE) )
636 {
637 clean_reg_con0 = 0;
638 reg_con0 = set_data_clock_edge(reg_con0, param->f_data_clock_on_rising);
639 }
640
641 /* Update Clock */
642 if ( (param->operation_mask & CONFIG_OPERATION_UPDATE_CLOCK) )
643 {
644 if ( param->update_clock > 0x02 || (param->update_clock == 0x02 && param->fpid > 0x3) )
645 goto INVALID_PARAM;
646 clean_reg_con1 = 0;
647 f_software_update = param->update_clock == 0 ? 1 : 0;
648 if ( param->update_clock == 0x01 )
649 f_setup_gpt2 = 1;
650 reg_con1 = set_update_clock(reg_con1, param->update_clock, param->fpid);
651 }
652
653 /* Store Mode */
654 if ( (param->operation_mask & CONFIG_OPERATION_STORE_MODE) )
655 {
656 clean_reg_con1 = 0;
657 reg_con1 = set_store_mode(reg_con1, param->store_mode);
658 }
659
660 /* Shift Clock */
661 if ( (param->operation_mask & CONFIG_OPERATION_SHIFT_CLOCK) )
662 {
663 if ( param->fpis > 0x03 )
664 goto INVALID_PARAM;
665 clean_reg_con1 = 0;
666 reg_con1 = set_shift_clock(reg_con1, param->fpis);
667 }
668
669 /* Data Offset */
670 if ( (param->operation_mask & CONFIG_OPERATION_DATA_OFFSET) )
671 {
672 if ( param->data_offset > 0x03 )
673 goto INVALID_PARAM;
674 clean_reg_con1 = 0;
675 reg_con1 = set_data_offset(reg_con1, param->data_offset);
676 }
677
678 /* Number of LED */
679 if ( (param->operation_mask & CONFIG_OPERATION_NUMBER_OF_LED) )
680 {
681 if ( param->number_of_enabled_led > 0x24 )
682 goto INVALID_PARAM;
683
684 /*
685 * If there is at lease one LED enabled, the GPIO pin must be setup.
686 */
687 new_led_on = param->number_of_enabled_led ? 1 : 0;
688
689 clean_reg_con1 = 0;
690 reg_con1 = set_number_of_enabled_led(reg_con1, param->number_of_enabled_led);
691 }
692
693 /* LED Data */
694 if ( (param->operation_mask & CONFIG_OPERATION_DATA) )
695 {
696 if ( (param->data_mask & 0xFF000000) || (param->data & 0xFF000000) )
697 goto INVALID_PARAM;
698 clean_reg_cpu0 = 0;
699 reg_cpu0 = set_data_in_batch(reg_cpu0, param->data_mask, param->data);
700 if ( f_software_update )
701 {
702 clean_reg_con0 = 0;
703 reg_con0 |= 0x80000000;
704 }
705 }
706
707 /* Access Right */
708 if ( (param->operation_mask & CONFIG_OPERATION_MIPS0_ACCESS) )
709 {
710 if ( (param->mips0_access_mask & 0xFF000000) || (param->mips0_access & 0xFF000000) )
711 goto INVALID_PARAM;
712 clean_reg_ar = 0;
713 reg_ar = set_access_right(reg_ar, param->mips0_access_mask, param->mips0_access);
714 }
715
716 /* Setup GPT */
717 if ( f_setup_gpt2 && !new_adsl_on ) // If ADSL led is on, GPT is disabled.
718 {
719 ret = 0;
720
721 if ( gpt_on )
722 {
723 if ( gpt_freq != param->fpid )
724 {
725 release_gpt(2);
726 gpt_on = 0;
727 ret = setup_gpt(2, param->fpid);
728 }
729 }
730 else
731 ret = setup_gpt(2, param->fpid);
732
733 if ( ret )
734 {
735 #if 1
736 printk("Setup GPT error!\n");
737 #endif
738 goto SETUP_GPT_ERROR;
739 }
740 else
741 {
742 #if 0
743 printk("Setup GPT successfully!\n");
744 #endif
745 gpt_on = 1;
746 }
747 }
748 else
749 if ( gpt_on )
750 {
751 release_gpt(2);
752 gpt_on = 0;
753 }
754
755 /* Turn on LED */
756 if ( new_adsl_on )
757 new_led_on = 1;
758 if ( !new_led_on || adsl_on != new_adsl_on )
759 {
760 turn_off_led(adsl_on);
761 f_led_on = 0;
762 adsl_on = 0;
763 }
764 if ( !f_led_on && new_led_on )
765 {
766 ret = turn_on_led(new_adsl_on);
767 if ( ret )
768 {
769 printk("Setup GPIO error!\n");
770 goto SETUP_GPIO_ERROR;
771 }
772 adsl_on = new_adsl_on;
773 f_led_on = 1;
774 }
775
776 /* Write Register */
777 if ( !f_led_on )
778 enable_led();
779 if ( !clean_reg_ar )
780 *DANUBE_LED_AR = reg_ar;
781 if ( !clean_reg_cpu0 )
782 *DANUBE_LED_CPU0 = reg_cpu0;
783 if ( !clean_reg_con1 )
784 *DANUBE_LED_CON1 = reg_con1;
785 if ( !clean_reg_con0 )
786 *DANUBE_LED_CON0 = reg_con0;
787 if ( !f_led_on )
788 disable_led();
789
790 up(&led_sem);
791 return 0;
792
793 SETUP_GPIO_ERROR:
794 release_gpt(2);
795 gpt_on = 0;
796 SETUP_GPT_ERROR:
797 up(&led_sem);
798 return ret;
799
800 INVALID_PARAM:
801 up(&led_sem);
802 return -EINVAL;
803 }
804
805 static int
806 led_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
807 {
808 int ret = -EINVAL;
809 struct led_config_param param;
810
811 switch ( cmd )
812 {
813 case LED_CONFIG:
814 copy_from_user(&param, (char*)arg, sizeof(param));
815 ret = danube_led_config(&param);
816 break;
817 }
818
819 return ret;
820 }
821
822 static int
823 led_open (struct inode *inode, struct file *file)
824 {
825 return 0;
826 }
827
828 static int
829 led_release (struct inode *inode, struct file *file)
830 {
831 return 0;
832 }
833
834 static struct file_operations led_fops = {
835 owner: THIS_MODULE,
836 ioctl: led_ioctl,
837 open: led_open,
838 release: led_release
839 };
840
841 static struct miscdevice led_miscdev = {
842 151,
843 "led",
844 &led_fops,
845 NULL,
846 NULL,
847 NULL
848 };
849
850 int __init
851 danube_led_init (void)
852 {
853 int ret = 0;
854 struct led_config_param param = {0};
855
856 enable_led();
857
858 writel(0, DANUBE_LED_AR);
859 writel(0, DANUBE_LED_CPU0);
860 writel(0, DANUBE_LED_CPU1);
861 writel(0, DANUBE_LED_CON1);
862 writel((0x80000000 | (DATA_CLOCKING_EDGE << 26)), DANUBE_LED_CON0);
863
864 disable_led();
865
866 sema_init(&led_sem, 0);
867
868 ret = misc_register(&led_miscdev);
869 if (ret == -EBUSY)
870 {
871 led_miscdev.minor = MISC_DYNAMIC_MINOR;
872 ret = misc_register(&led_miscdev);
873 }
874
875 if (ret)
876 {
877 printk(KERN_ERR "led: can't misc_register\n");
878 goto out;
879 } else {
880 printk(KERN_INFO "led: misc_register on minor = %d\n", led_miscdev.minor);
881 }
882
883 module_id = THIS_MODULE ? (int)THIS_MODULE : ((MISC_MAJOR << 8) | led_miscdev.minor);
884
885 up(&led_sem);
886
887 /* Add to enable hardware relay */
888 /* Map for LED on reference board
889 WLAN_READ LED11 OUT1 15
890 WARNING LED12 OUT2 14
891 FXS1_LINK LED13 OUT3 13
892 FXS2_LINK LED14 OUT4 12
893 FXO_ACT LED15 OUT5 11
894 USB_LINK LED16 OUT6 10
895 ADSL2_LINK LED19 OUT7 9
896 BT_LINK LED17 OUT8 8
897 SD_LINK LED20 OUT9 7
898 ADSL2_TRAFFIC LED31 OUT16 0
899 Map for hardware relay on reference board
900 USB Power On OUT11 5
901 RELAY OUT12 4
902 */
903 param.operation_mask = CONFIG_OPERATION_NUMBER_OF_LED;
904 param.number_of_enabled_led = 16;
905 danube_led_config(&param);
906 param.operation_mask = CONFIG_OPERATION_DATA;
907 param.data_mask = 1 << 4;
908 param.data = 1 << 4;
909 danube_led_config(&param);
910
911 // by default, update by FSC clock (FPID)
912 param.operation_mask = CONFIG_OPERATION_UPDATE_CLOCK;
913 param.update_clock = 2; // FPID
914 param.fpid = 3; // 10Hz
915 danube_led_config(&param);
916
917 // source of LED 0, 1 is ADSL
918 param.operation_mask = CONFIG_OPERATION_UPDATE_SOURCE;
919 param.led = 3; // LED 0, 1
920 param.source = 3; // ADSL
921 danube_led_config(&param);
922
923 // turn on USB
924 param.operation_mask = CONFIG_OPERATION_DATA;
925 param.data_mask = 1 << 5;
926 param.data = 1 << 5;
927 danube_led_config(&param);
928
929 out:
930 return ret;
931 }
932
933 void __exit
934 danube_led_exit (void)
935 {
936 int ret;
937
938 ret = misc_deregister(&led_miscdev);
939 if ( ret )
940 printk(KERN_ERR "led: can't misc_deregister, get error number %d\n", -ret);
941 else
942 printk(KERN_INFO "led: misc_deregister successfully\n");
943 }
944
945 EXPORT_SYMBOL(danube_led_set_blink);
946 EXPORT_SYMBOL(danube_led_set_data);
947 EXPORT_SYMBOL(danube_led_config);
948
949 module_init(danube_led_init);
950 module_exit(danube_led_exit);
951
This page took 0.108833 seconds and 5 git commands to generate.