patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / pcmcia / sa1100_xp860.c
1 /*
2  * drivers/pcmcia/sa1100_xp860.c
3  *
4  * XP860 PCMCIA specific routines
5  *
6  */
7 #include <linux/module.h>
8 #include <linux/kernel.h>
9 #include <linux/delay.h>
10 #include <linux/sched.h>
11 #include <linux/device.h>
12 #include <linux/init.h>
13
14 #include <asm/hardware.h>
15 #include <asm/mach-types.h>
16 #include <asm/irq.h>
17 #include "sa1100_generic.h"
18
19 #define NCR_A0VPP       (1<<16)
20 #define NCR_A1VPP       (1<<17)
21
22 static int xp860_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
23 {
24   /* Set GPIO_A<3:0> to be outputs for PCMCIA/CF power controller: */
25   PA_DDR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
26   
27   /* MAX1600 to standby mode: */
28   PA_DWR &= ~(GPIO_GPIO0 | GPIO_GPIO1 | GPIO_GPIO2 | GPIO_GPIO3);
29
30 #error Consider the following comment
31   /*
32    * 1- Please move GPDR initialisation  where it is interrupt or preemption
33    *    safe (like from xp860_map_io).
34    * 2- The GPCR line is bogus i.e. it will simply have absolutely no effect.
35    *    Please see its definition in the SA1110 manual.
36    * 3- Please do not use NCR_* values!
37    */
38   GPDR |= (NCR_A0VPP | NCR_A1VPP);
39   GPCR &= ~(NCR_A0VPP | NCR_A1VPP);
40
41   return sa1111_pcmcia_hw_init(skt);
42 }
43
44 static int
45 xp860_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
46 {
47   unsigned int gpio_mask, pa_dwr_mask;
48   unsigned int gpio_set, pa_dwr_set;
49   int ret;
50
51   /* Neponset uses the Maxim MAX1600, with the following connections:
52 #warning ^^^ This isn't a neponset!
53    *
54    *   MAX1600      Neponset
55    *
56    *    A0VCC        SA-1111 GPIO A<1>
57    *    A1VCC        SA-1111 GPIO A<0>
58    *    A0VPP        CPLD NCR A0VPP
59    *    A1VPP        CPLD NCR A1VPP
60    *    B0VCC        SA-1111 GPIO A<2>
61    *    B1VCC        SA-1111 GPIO A<3>
62    *    B0VPP        ground (slot B is CF)
63    *    B1VPP        ground (slot B is CF)
64    *
65    *     VX          VCC (5V)
66    *     VY          VCC3_3 (3.3V)
67    *     12INA       12V
68    *     12INB       ground (slot B is CF)
69    *
70    * The MAX1600 CODE pin is tied to ground, placing the device in 
71    * "Standard Intel code" mode. Refer to the Maxim data sheet for
72    * the corresponding truth table.
73    */
74
75   switch (skt->nr) {
76   case 0:
77     pa_dwr_mask = GPIO_GPIO0 | GPIO_GPIO1;
78     gpio_mask = NCR_A0VPP | NCR_A1VPP;
79
80     switch (state->Vcc) {
81     default:
82     case 0:     pa_dwr_set = 0;                 break;
83     case 33:    pa_dwr_set = GPIO_GPIO1;        break;
84     case 50:    pa_dwr_set = GPIO_GPIO0;        break;
85     }
86
87     switch (state->Vpp) {
88     case 0:     gpio_set = 0;                   break;
89     case 120:   gpio_set = NCR_A1VPP;           break;
90
91     default:
92       if (state->Vpp == state->Vcc)
93         gpio_set = NCR_A0VPP;
94       else {
95         printk(KERN_ERR "%s(): unrecognized Vpp %u\n",
96                __FUNCTION__, state->Vpp);
97         return -1;
98       }
99     }
100     break;
101
102   case 1:
103     pa_dwr_mask = GPIO_GPIO2 | GPIO_GPIO3;
104     gpio_mask = 0;
105     gpio_set = 0;
106
107     switch (state->Vcc) {
108     default:
109     case 0:     pa_dwr_set = 0;                 break;
110     case 33:    pa_dwr_set = GPIO_GPIO2;        break;
111     case 50:    pa_dwr_set = GPIO_GPIO3;        break;
112     }
113
114     if (state->Vpp != state->Vcc && state->Vpp != 0) {
115       printk(KERN_ERR "%s(): CF slot cannot support Vpp %u\n",
116              __FUNCTION__, state->Vpp);
117       return -1;
118     }
119     break;
120   }
121
122   ret = sa1111_pcmcia_configure_socket(skt, state);
123   if (ret == 0) {
124     unsigned long flags;
125
126     local_irq_save(flags);
127     PA_DWR = (PA_DWR & ~pa_dwr_mask) | pa_dwr_set;
128     GPSR = gpio_set;
129     GPCR = gpio_set ^ gpio_mask;
130     local_irq_restore(flags);
131   }
132
133   return ret;
134 }
135
136 static struct pcmcia_low_level xp860_pcmcia_ops = { 
137         .owner                  = THIS_MODULE,
138         .hw_init                = xp860_pcmcia_hw_init,
139         .hw_shutdown            = sa1111_pcmcia_hw_shutdown,
140         .socket_state           = sa1111_pcmcia_socket_state,
141         .configure_socket       = xp860_pcmcia_configure_socket,
142         .socket_init            = sa1111_pcmcia_socket_init,
143         .socket_suspend         = sa1111_pcmcia_socket_suspend,
144 };
145
146 int __init pcmcia_xp860_init(struct device *dev)
147 {
148         int ret = -ENODEV;
149
150         if (machine_is_xp860())
151                 ret = sa11xx_drv_pcmcia_probe(dev, &xp860_pcmcia_ops, 0, 2);
152
153         return ret;
154 }