patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / drivers / pcmcia / sa1100_trizeps.c
1 /*
2  * drivers/pcmcia/sa1100_trizeps.c
3  *
4  * PCMCIA implementation routines for Trizeps
5  *
6  * Authors:
7  * Andreas Hofer <ho@dsa-ac.de>,
8  * Peter Lueg <pl@dsa-ac.de>,
9  * Guennadi Liakhovetski <gl@dsa-ac.de>
10  *
11  */
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/sched.h>
15 #include <linux/device.h>
16 #include <linux/init.h>
17
18 #include <asm/hardware.h>
19 #include <asm/arch/trizeps.h>
20 #include <asm/mach-types.h>
21 #include <asm/system.h>
22 #include <asm/irq.h>
23 #include "sa1100_generic.h"
24
25 #define NUMBER_OF_TRIZEPS_PCMCIA_SLOTS 1
26
27 static struct pcmcia_irqs irqs[] = {
28         { 0, TRIZEPS_IRQ_PCMCIA_CD0, "PCMCIA_CD0" },
29 };
30
31 /**
32  *
33  *
34  ******************************************************/
35 static int trizeps_pcmcia_init(struct soc_pcmcia_socket *skt)
36 {
37         skt->irq = TRIZEPS_IRQ_PCMCIA_IRQ0;
38
39         /* Enable CF bus: */
40         TRIZEPS_BCR_clear(TRIZEPS_BCR1, TRIZEPS_nPCM_ENA_REG);
41
42         /* All those are inputs */
43         GPDR &= ~((GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_CD0))
44                     | (GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_IRQ0)));
45
46         return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs));
47 }
48
49 /**
50  *
51  *
52  ******************************************************/
53 static void trizeps_pcmcia_shutdown(struct soc_pcmcia_socket *skt)
54 {
55         printk(">>>>>PCMCIA TRIZEPS shutdown\n");
56
57         soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs));
58
59         /* Disable CF bus: */
60         TRIZEPS_BCR_set(TRIZEPS_BCR1, TRIZEPS_nPCM_ENA_REG);
61 }
62
63 /**
64  *
65  ******************************************************/
66 static void
67 trizeps_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
68                             struct pcmcia_state *state_array)
69 {
70         unsigned long levels = GPLR;
71
72         state->detect = ((levels & GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_CD0)) == 0) ? 1 : 0;
73         state->ready  = ((levels & GPIO_GPIO(TRIZEPS_GPIO_PCMCIA_IRQ0)) != 0) ? 1 : 0;
74         state->bvd1   = ((TRIZEPS_BCR1 & TRIZEPS_PCM_BVD1) !=0 ) ? 1 : 0;
75         state->bvd2   = ((TRIZEPS_BCR1 & TRIZEPS_PCM_BVD2) != 0) ? 1 : 0;
76         state->wrprot = 0; // not write protected
77         state->vs_3v  = ((TRIZEPS_BCR1 & TRIZEPS_nPCM_VS1) == 0) ? 1 : 0; //VS1=0 -> vs_3v=1
78         state->vs_Xv  = ((TRIZEPS_BCR1 & TRIZEPS_nPCM_VS2) == 0) ? 1 : 0; //VS2=0 -> vs_Xv=1
79 }
80
81 /**
82  *
83  *
84  ******************************************************/
85 static int
86 trizeps_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
87                                 const socket_state_t *state)
88 {
89         unsigned long flags;
90
91         local_irq_save(flags);
92
93         switch (state->Vcc) {
94         case 0:
95                 printk(">>> PCMCIA Power off\n");
96                 TRIZEPS_BCR_clear(TRIZEPS_BCR1, TRIZEPS_PCM_V3_EN_REG);
97                 TRIZEPS_BCR_clear(TRIZEPS_BCR1, TRIZEPS_PCM_V5_EN_REG);
98                 break;
99
100         case 33:
101                 // 3.3V Power on
102                 TRIZEPS_BCR_clear(TRIZEPS_BCR1, TRIZEPS_PCM_V3_EN_REG);
103                 TRIZEPS_BCR_set(TRIZEPS_BCR1, TRIZEPS_PCM_V5_EN_REG);
104                 break;
105         case 50:
106                 // 5.0V Power on
107                 TRIZEPS_BCR_set(TRIZEPS_BCR1, TRIZEPS_PCM_V3_EN_REG);
108                 TRIZEPS_BCR_clear(TRIZEPS_BCR1, TRIZEPS_PCM_V5_EN_REG);
109                 break;
110         default:
111                 printk(KERN_ERR "%s(): unrecognized Vcc %u\n", __FUNCTION__,
112                        state->Vcc);
113                 local_irq_restore(flags);
114                 return -1;
115         }
116
117         if (state->flags & SS_RESET)
118                 TRIZEPS_BCR_set(TRIZEPS_BCR1, TRIZEPS_nPCM_RESET_DISABLE);   // Reset
119         else
120                 TRIZEPS_BCR_clear(TRIZEPS_BCR1, TRIZEPS_nPCM_RESET_DISABLE); // no Reset
121         /*
122           printk(" vcc=%u vpp=%u -->reset=%i\n",
123           state->Vcc,
124           state->Vpp,
125           ((BCR_read(1) & nPCM_RESET_DISABLE)? 1:0));
126         */
127         local_irq_restore(flags);
128
129         return 0;
130 }
131
132 static void trizeps_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
133 {
134         soc_pcmcia_enable_irqs(skt, irqs, ARRAY_SIZE(irqs));
135 }
136
137 static void trizeps_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
138 {
139         soc_pcmcia_disable_irqs(skt, irqs, ARRAY_SIZE(irqs));
140 }
141
142 /**
143  * low-level PCMCIA interface
144  *
145  ******************************************************/
146 struct pcmcia_low_level trizeps_pcmcia_ops = {
147         .owner                  = THIS_MODULE,
148         .hw_init                = trizeps_pcmcia_hw_init,
149         .hw_shutdown            = trizeps_pcmcia_hw_shutdown,
150         .socket_state           = trizeps_pcmcia_socket_state,
151         .configure_socket       = trizeps_pcmcia_configure_socket,
152         .socket_init            = trizeps_pcmcia_socket_init,
153         .socket_suspend         = trizeps_pcmcia_socket_suspend,
154 };
155
156 int __init pcmcia_trizeps_init(struct device *dev)
157 {
158         int ret = -ENODEV;
159
160         if (machine_is_trizeps())
161                 ret = sa11xx_drv_pcmcia_probe(dev, &trizeps_pcmcia_ops, 0,
162                                               NUMBER_OF_TRIZEPS_PCMCIA_SLOTS);
163
164         return ret;
165 }