ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / arm / mach-sa1100 / system3.c
1 /*
2  * linux/arch/arm/mach-sa1100/system3.c
3  *
4  * Copyright (C) 2001 Stefan Eletzhofer <stefan.eletzhofer@eletztrick.de>
5  *
6  * $Id: system3.c,v 1.1.6.1 2001/12/04 17:28:06 seletz Exp $
7  *
8  * This file contains all PT Sytsem 3 tweaks. Based on original work from
9  * Nicolas Pitre's assabet fixes
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License version 2 as
13  * published by the Free Software Foundation.
14  *
15  * $Log: system3.c,v $
16  * Revision 1.1.6.1  2001/12/04 17:28:06  seletz
17  * - merged from previous branch
18  *
19  * Revision 1.1.4.3  2001/12/04 15:16:31  seletz
20  * - merged from linux_2_4_13_ac5_rmk2
21  *
22  * Revision 1.1.4.2  2001/11/19 17:18:57  seletz
23  * - more code cleanups
24  *
25  * Revision 1.1.4.1  2001/11/16 13:52:05  seletz
26  * - PT Digital Board Support Code
27  *
28  * Revision 1.1.2.2  2001/11/05 16:46:18  seletz
29  * - cleanups
30  *
31  * Revision 1.1.2.1  2001/10/15 16:00:43  seletz
32  * - first revision working with new board
33  *
34  *
35  */
36
37 #include <linux/config.h>
38 #include <linux/init.h>
39 #include <linux/kernel.h>
40 #include <linux/tty.h>
41 #include <linux/module.h>
42 #include <linux/errno.h>
43 #include <linux/cpufreq.h>
44
45 #include <asm/hardware.h>
46 #include <asm/mach-types.h>
47 #include <asm/setup.h>
48 #include <asm/irq.h>
49
50 #include <asm/mach/arch.h>
51 #include <asm/mach/map.h>
52 #include <asm/mach/irq.h>
53 #include <asm/mach/serial_sa1100.h>
54
55 #include <linux/serial_core.h>
56
57 #include "generic.h"
58 #include <asm/hardware/sa1111.h>
59
60 #define DEBUG 1
61
62 #ifdef DEBUG
63 #       define DPRINTK( x, args... )    printk( "%s: line %d: "x, __FUNCTION__, __LINE__, ## args  );
64 #else
65 #       define DPRINTK( x, args... )    /* nix */
66 #endif
67
68 /**********************************************************************
69  *  prototypes
70  */
71
72 /* init funcs */
73 static int __init system3_init(void);
74 static void __init system3_init_irq(void);
75 static void __init system3_map_io(void);
76
77 static u_int system3_get_mctrl(struct uart_port *port);
78 static void system3_set_mctrl(struct uart_port *port, u_int mctrl);
79 static void system3_uart_pm(struct uart_port *port, u_int state, u_int oldstate);
80 static int sdram_notifier(struct notifier_block *nb, unsigned long event, void *data);
81
82 static void system3_lcd_power(int on);
83 static void system3_backlight_power(int on);
84
85
86 /**********************************************************************
87  *  global data
88  */
89
90 /**********************************************************************
91  *  static data
92  */
93
94 static struct map_desc system3_io_desc[] __initdata = {
95  /* virtual     physical        length      type */
96   { 0xf3000000, PT_CPLD_BASE,   0x00100000, MT_DEVICE }, /* System Registers */
97   { 0xf4000000, PT_SA1111_BASE, 0x00100000, MT_DEVICE }  /* SA-1111 */
98 };
99
100 static struct sa1100_port_fns system3_port_fns __initdata = {
101         .set_mctrl      = system3_set_mctrl,
102         .get_mctrl      = system3_get_mctrl,
103         .pm             = system3_uart_pm,
104 };
105
106 static struct notifier_block system3_clkchg_block = {
107         .notifier_call  = sdram_notifier,
108 };
109
110 /**********************************************************************
111  *  Static functions
112  */
113
114 static void __init system3_map_io(void)
115 {
116         DPRINTK( "%s\n", "START" );
117         sa1100_map_io();
118         iotable_init(system3_io_desc, ARRAY_SIZE(system3_io_desc));
119
120         sa1100_register_uart_fns(&system3_port_fns);
121         sa1100_register_uart(0, 1);     /* com port */
122         sa1100_register_uart(1, 2);
123         sa1100_register_uart(2, 3);     /* radio module */
124
125         Ser1SDCR0 |= SDCR0_SUS;
126 }
127
128
129 /*********************************************************************
130  * Install IRQ handler
131  */
132 static void
133 system3_irq_handler(unsigned int irq, struct irqdesc *desc, struct pt_regs *regs)
134 {
135         u_char irr;
136
137         //DPRINTK( "irq=%d, desc=%p, regs=%p\n", irq, desc, regs );
138
139         while (1) {
140                 struct irqdesc *d;
141
142                 /*
143                  * Acknowledge the parent IRQ.
144                  */
145                 desc->chip->ack(irq);
146
147                 /*
148                  * Read the interrupt reason register.  Let's have all
149                  * active IRQ bits high.  Note: there is a typo in the
150                  * Neponset user's guide for the SA1111 IRR level.
151                  */
152                 //irr = PT_IRQSR & (PT_IRR_LAN | PT_IRR_SA1111);
153                 irr = PT_IRQSR & (PT_IRR_SA1111);
154
155                 /* SMC IRQ is low-active, so "switch" bit over */
156                 //irr ^= (PT_IRR_LAN);
157
158                 //DPRINTK( "irr=0x%02x\n", irr );
159
160                 if ((irr & (PT_IRR_LAN | PT_IRR_SA1111)) == 0)
161                         break;
162
163                 /*
164                  * Since there is no individual mask, we have to
165                  * mask the parent IRQ.  This is safe, since we'll
166                  * recheck the register for any pending IRQs.
167                  */
168                 if (irr & (PT_IRR_LAN)) {
169                         desc->chip->mask(irq);
170
171                         if (irr & PT_IRR_LAN) {
172                                 //DPRINTK( "SMC9196, irq=%d\n", IRQ_SYSTEM3_SMC9196 );
173                                 d = irq_desc + IRQ_SYSTEM3_SMC9196;
174                                 d->handle(IRQ_SYSTEM3_SMC9196, d, regs);
175                         }
176
177 #if 0 /* no SSP yet on system 4 */
178                         if (irr & IRR_USAR) {
179                                 d = irq_desc + IRQ_NEPONSET_USAR;
180                                 d->handle(IRQ_NEPONSET_USAR, d, regs);
181                         }
182 #endif
183
184                         desc->chip->unmask(irq);
185                 }
186
187                 if (irr & PT_IRR_SA1111) {
188                         //DPRINTK( "SA1111, irq=%d\n", IRQ_SYSTEM3_SA1111 );
189                         d = irq_desc + IRQ_SYSTEM3_SA1111;
190                         d->handle(IRQ_SYSTEM3_SA1111, d, regs);
191                 }
192         }
193 }
194
195 static void __init system3_init_irq(void)
196 {
197         /*
198          * Install handler for GPIO25.
199          */
200         set_irq_type(IRQ_GPIO25, IRQT_RISING);
201         set_irq_chained_handler(IRQ_GPIO25, system3_irq_handler);
202
203         /*
204          * install eth irq
205          */
206         set_irq_handler(IRQ_SYSTEM3_SMC9196, do_simple_IRQ);
207         set_irq_flags(IRQ_SYSTEM3_SMC9196, IRQF_VALID | IRQF_PROBE);
208 }
209
210 /**********************************************************************
211  * On system 3 limit cpu frequency to 206 Mhz
212  */
213 static int sdram_notifier(struct notifier_block *nb, unsigned long event,
214                 void *data)
215 {
216         struct cpufreq_policy *policy = data;
217         switch (event) {
218                 case CPUFREQ_ADJUST:
219                 case CPUFREQ_INCOMPATIBLE:
220                         cpufreq_verify_within_limits(policy, 147500, 206000);
221                         break;
222                 case CPUFREQ_NOTIFY:
223                         if ((policy->min < 147500) || 
224                             (policy->max > 206000))
225                                 panic("cpufreq failed to limit the speed\n");
226                         break;
227         }
228         return 0;
229 }
230
231 /**
232  *      system3_uart_pm - powermgmt callback function for system 3 UART
233  *      @port: uart port structure
234  *      @state: pm state
235  *      @oldstate: old pm state
236  *
237  */
238 static void system3_uart_pm(struct uart_port *port, u_int state, u_int oldstate)
239 {
240         /* TODO: switch on/off uart in powersave mode */
241 }
242
243 /*
244  * Note! this can be called from IRQ context.
245  * FIXME: Handle PT Digital Board CTRL regs irq-safe.
246  *
247  * NB: system3 uses COM_RTS and COM_DTR for both UART1 (com port)
248  * and UART3 (radio module).  We only handle them for UART1 here.
249  */
250 static void system3_set_mctrl(struct uart_port *port, u_int mctrl)
251 {
252         if (port->mapbase == _Ser1UTCR0) {
253                 u_int set = 0, clear = 0;
254
255                 if (mctrl & TIOCM_RTS)
256                         set |= PT_CTRL2_RS1_RTS;
257                 else
258                         clear |= PT_CTRL2_RS1_RTS;
259
260                 if (mctrl & TIOCM_DTR)
261                         set |= PT_CTRL2_RS1_DTR;
262                 else
263                         clear |= PT_CTRL2_RS1_DTR;
264
265                 PTCTRL2_clear(clear);
266                 PTCTRL2_set(set);
267         }
268 }
269
270 static u_int system3_get_mctrl(struct uart_port *port)
271 {
272         u_int ret = 0;
273         u_int irqsr = PT_IRQSR;
274
275         /* need 2 reads to read current value */
276         irqsr = PT_IRQSR;
277
278         /* TODO: check IRQ source register for modem/com
279          status lines and set them correctly. */
280
281         ret = TIOCM_CD | TIOCM_CTS | TIOCM_DSR;
282
283         return ret;
284 }
285
286 /**
287  *      system3_lcd_backlight_on - switch system 3 lcd backlight on
288  *
289  */
290 int system3_lcd_backlight_on( void )
291 {
292         PTCTRL0_set( PT_CTRL0_LCD_BL );
293         return 0;
294 }
295
296 /**
297  *      system3_lcd_backlight_off - switch system 3 lcd backlight off
298  *
299  */
300 static void system3_lcd_backlight_off(void)
301 {
302         PTCTRL0_clear( PT_CTRL0_LCD_BL );
303 }
304
305 /**
306  *      system3_lcd_on - switch system 3 lcd on
307  *
308  */
309 static void system3_lcd_on(void)
310 {
311         DPRINTK( "%s\n", "START" );
312         PTCTRL0_set( PT_CTRL0_LCD_EN );
313
314         /* brightness / contrast */
315         sa1111_enable_device(SKPCR_PWMCLKEN);
316         PB_DDR = 0xFFFFFFFF;
317         SKPEN0 = 1;
318         SKPEN1 = 1;
319 }
320
321 /**
322  *      system3_lcd_off - switch system 3 lcd off
323  *
324  */
325 static void system3_lcd_off(void)
326 {
327         DPRINTK( "%s\n", "START" );
328         PTCTRL0_clear( PT_CTRL0_LCD_EN );
329         SKPEN0 = 0;
330         SKPEN1 = 0;
331         sa1111_disable_device(SKPCR_PWMCLKEN);
332 }
333
334 /**
335  *      system3_lcd_contrast - set system 3 contrast
336  *      @value:         the new contrast
337  *
338  */
339 static void system3_lcd_contrast(unsigned char value)
340 {
341         DPRINTK( "value=0x%02x\n", value );
342         SYS3LCDCONTR = value;
343 }
344
345 /**
346  *      system3_lcd_brightness - set system 3 brightness
347  *      @value:         the new brightness
348  *
349  */
350 static void system3_lcd_brightness(unsigned char value)
351 {
352         DPRINTK( "value=0x%02x\n", value );
353         SYS3LCDBRIGHT = value;
354 }
355
356 static void system3_lcd_power(int on)
357 {
358         if (on) {
359                 system3_lcd_on();
360         } else {
361                 system3_lcd_off();
362         }
363 }
364
365 static void system3_backlight_power(int on)
366 {
367         if (on) {
368                 system3_lcd_backlight_on();
369                 system3_lcd_contrast(0x95);
370                 system3_lcd_brightness(240);
371         } else {
372                 system3_lcd_backlight_off();
373         }
374 }
375
376 static struct resource sa1111_resources[] = {
377         [0] = {
378                 .start          = PT_SA1111_BASE,
379                 .end            = PT_SA1111_BASE + 0x00001fff,
380                 .flags          = IORESOURCE_MEM,
381         },
382         [1] = {
383                 .start          = IRQ_SYSTEM3_SA1111,
384                 .end            = IRQ_SYSTEM3_SA1111,
385                 .flags          = IORESOURCE_IRQ,
386         },
387 };
388
389 static u64 sa1111_dmamask = 0xffffffffUL;
390
391 static struct platform_device sa1111_device = {
392         .name           = "sa1111",
393         .id             = 0,
394         .dev            = {
395                 .dma_mask = &sa1111_dmamask,
396                 .coherent_dma_mask = 0xffffffff,
397         },
398         .num_resources  = ARRAY_SIZE(sa1111_resources),
399         .resource       = sa1111_resources,
400 };
401
402 static struct platform_device *devices[] __initdata = {
403         &sa1111_device,
404 };
405
406 static int __init system3_init(void)
407 {
408         int ret = 0;
409         DPRINTK( "%s\n", "START" );
410
411         if ( !machine_is_pt_system3() ) {
412                 ret = -EINVAL;
413                 goto DONE;
414         }
415
416         sa1100fb_lcd_power = system3_lcd_power;
417         sa1100fb_backlight_power = system3_backlight_power;
418
419         /* init control register */
420         PT_CTRL0 = PT_CTRL0_INIT;
421         PT_CTRL1 = 0x02;
422         PT_CTRL2 = 0x00;
423         DPRINTK( "CTRL[0]=0x%02x\n", PT_CTRL0 );
424         DPRINTK( "CTRL[1]=0x%02x\n", PT_CTRL1 );
425         DPRINTK( "CTRL[2]=0x%02x\n", PT_CTRL2 );
426
427         /*
428          * Ensure that the memory bus request/grant signals are setup,
429          * and the grant is held in its inactive state.
430          */
431         sa1110_mb_disable();
432
433         system3_init_irq();
434
435         /*
436          * Probe for a SA1111.
437          */
438         ret = platform_add_devices(devices, ARRAY_SIZE(devices));
439         if (ret < 0) {
440                 printk( KERN_WARNING"PT Digital Board: no SA1111 found!\n" );
441                 goto DONE;
442         }
443
444 #ifdef CONFIG_CPU_FREQ
445         ret = cpufreq_register_notifier(&system3_clkchg_block);
446         if ( ret != 0 ) {
447                 printk( KERN_WARNING"PT Digital Board: could not register clock scale callback\n" );
448                 goto DONE;
449         }
450 #endif
451
452
453         ret = 0;
454 DONE:
455         DPRINTK( "ret=%d\n", ret );
456         return ret;
457 }
458
459 /**********************************************************************
460  *  Exported Functions
461  */
462
463 /**********************************************************************
464  *  kernel magic macros
465  */
466 arch_initcall(system3_init);
467
468 MACHINE_START(PT_SYSTEM3, "PT System 3")
469         BOOT_MEM(0xc0000000, 0x80000000, 0xf8000000)
470         BOOT_PARAMS(0xc0000100)
471         MAPIO(system3_map_io)
472         INITIRQ(sa1100_init_irq)
473 MACHINE_END