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