2 * linux/drivers/pcmcia/sa1111_generic.c
4 * We implement the generic parts of a SA1111 PCMCIA driver. This
5 * basically means we handle everything except controlling the
6 * power. Power is machine specific...
8 #include <linux/module.h>
9 #include <linux/kernel.h>
10 #include <linux/ioport.h>
11 #include <linux/device.h>
12 #include <linux/interrupt.h>
13 #include <linux/init.h>
15 #include <linux/slab.h>
17 #include <pcmcia/ss.h>
19 #include <mach/hardware.h>
20 #include <asm/hardware/sa1111.h>
23 #include "sa1111_generic.h"
26 * These are offsets from the above base.
32 #define PCSR_S0_READY (1<<0)
33 #define PCSR_S1_READY (1<<1)
34 #define PCSR_S0_DETECT (1<<2)
35 #define PCSR_S1_DETECT (1<<3)
36 #define PCSR_S0_VS1 (1<<4)
37 #define PCSR_S0_VS2 (1<<5)
38 #define PCSR_S1_VS1 (1<<6)
39 #define PCSR_S1_VS2 (1<<7)
40 #define PCSR_S0_WP (1<<8)
41 #define PCSR_S1_WP (1<<9)
42 #define PCSR_S0_BVD1 (1<<10)
43 #define PCSR_S0_BVD2 (1<<11)
44 #define PCSR_S1_BVD1 (1<<12)
45 #define PCSR_S1_BVD2 (1<<13)
47 #define PCCR_S0_RST (1<<0)
48 #define PCCR_S1_RST (1<<1)
49 #define PCCR_S0_FLT (1<<2)
50 #define PCCR_S1_FLT (1<<3)
51 #define PCCR_S0_PWAITEN (1<<4)
52 #define PCCR_S1_PWAITEN (1<<5)
53 #define PCCR_S0_PSE (1<<6)
54 #define PCCR_S1_PSE (1<<7)
56 #define PCSSR_S0_SLEEP (1<<0)
57 #define PCSSR_S1_SLEEP (1<<1)
59 #define IDX_IRQ_S0_READY_NINT (0)
60 #define IDX_IRQ_S0_CD_VALID (1)
61 #define IDX_IRQ_S0_BVD1_STSCHG (2)
62 #define IDX_IRQ_S1_READY_NINT (3)
63 #define IDX_IRQ_S1_CD_VALID (4)
64 #define IDX_IRQ_S1_BVD1_STSCHG (5)
66 void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket
*skt
, struct pcmcia_state
*state
)
68 struct sa1111_pcmcia_socket
*s
= to_skt(skt
);
69 unsigned long status
= sa1111_readl(s
->dev
->mapbase
+ PCSR
);
73 state
->detect
= status
& PCSR_S0_DETECT
? 0 : 1;
74 state
->ready
= status
& PCSR_S0_READY
? 1 : 0;
75 state
->bvd1
= status
& PCSR_S0_BVD1
? 1 : 0;
76 state
->bvd2
= status
& PCSR_S0_BVD2
? 1 : 0;
77 state
->wrprot
= status
& PCSR_S0_WP
? 1 : 0;
78 state
->vs_3v
= status
& PCSR_S0_VS1
? 0 : 1;
79 state
->vs_Xv
= status
& PCSR_S0_VS2
? 0 : 1;
83 state
->detect
= status
& PCSR_S1_DETECT
? 0 : 1;
84 state
->ready
= status
& PCSR_S1_READY
? 1 : 0;
85 state
->bvd1
= status
& PCSR_S1_BVD1
? 1 : 0;
86 state
->bvd2
= status
& PCSR_S1_BVD2
? 1 : 0;
87 state
->wrprot
= status
& PCSR_S1_WP
? 1 : 0;
88 state
->vs_3v
= status
& PCSR_S1_VS1
? 0 : 1;
89 state
->vs_Xv
= status
& PCSR_S1_VS2
? 0 : 1;
94 int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket
*skt
, const socket_state_t
*state
)
96 struct sa1111_pcmcia_socket
*s
= to_skt(skt
);
97 unsigned int pccr_skt_mask
, pccr_set_mask
, val
;
102 pccr_skt_mask
= PCCR_S0_RST
|PCCR_S0_FLT
|PCCR_S0_PWAITEN
|PCCR_S0_PSE
;
106 pccr_skt_mask
= PCCR_S1_RST
|PCCR_S1_FLT
|PCCR_S1_PWAITEN
|PCCR_S1_PSE
;
116 pccr_set_mask
|= PCCR_S0_PWAITEN
|PCCR_S1_PWAITEN
;
117 if (state
->Vcc
== 50)
118 pccr_set_mask
|= PCCR_S0_PSE
|PCCR_S1_PSE
;
119 if (state
->flags
& SS_RESET
)
120 pccr_set_mask
|= PCCR_S0_RST
|PCCR_S1_RST
;
121 if (state
->flags
& SS_OUTPUT_ENA
)
122 pccr_set_mask
|= PCCR_S0_FLT
|PCCR_S1_FLT
;
124 local_irq_save(flags
);
125 val
= sa1111_readl(s
->dev
->mapbase
+ PCCR
);
126 val
&= ~pccr_skt_mask
;
127 val
|= pccr_set_mask
& pccr_skt_mask
;
128 sa1111_writel(val
, s
->dev
->mapbase
+ PCCR
);
129 local_irq_restore(flags
);
134 int sa1111_pcmcia_add(struct sa1111_dev
*dev
, struct pcmcia_low_level
*ops
,
135 int (*add
)(struct soc_pcmcia_socket
*))
137 struct sa1111_pcmcia_socket
*s
;
140 ops
->socket_state
= sa1111_pcmcia_socket_state
;
142 for (i
= 0; i
< ops
->nr
; i
++) {
143 s
= kzalloc(sizeof(*s
), GFP_KERNEL
);
147 s
->soc
.nr
= ops
->first
+ i
;
148 s
->soc
.clk
= clk_get(&dev
->dev
, NULL
);
149 if (IS_ERR(s
->soc
.clk
)) {
150 ret
= PTR_ERR(s
->soc
.clk
);
154 soc_pcmcia_init_one(&s
->soc
, ops
, &dev
->dev
);
157 s
->soc
.socket
.pci_irq
= dev
->irq
[IDX_IRQ_S1_READY_NINT
];
158 s
->soc
.stat
[SOC_STAT_CD
].irq
= dev
->irq
[IDX_IRQ_S1_CD_VALID
];
159 s
->soc
.stat
[SOC_STAT_CD
].name
= "SA1111 CF card detect";
160 s
->soc
.stat
[SOC_STAT_BVD1
].irq
= dev
->irq
[IDX_IRQ_S1_BVD1_STSCHG
];
161 s
->soc
.stat
[SOC_STAT_BVD1
].name
= "SA1111 CF BVD1";
163 s
->soc
.socket
.pci_irq
= dev
->irq
[IDX_IRQ_S0_READY_NINT
];
164 s
->soc
.stat
[SOC_STAT_CD
].irq
= dev
->irq
[IDX_IRQ_S0_CD_VALID
];
165 s
->soc
.stat
[SOC_STAT_CD
].name
= "SA1111 PCMCIA card detect";
166 s
->soc
.stat
[SOC_STAT_BVD1
].irq
= dev
->irq
[IDX_IRQ_S0_BVD1_STSCHG
];
167 s
->soc
.stat
[SOC_STAT_BVD1
].name
= "SA1111 PCMCIA BVD1";
172 s
->next
= dev_get_drvdata(&dev
->dev
);
173 dev_set_drvdata(&dev
->dev
, s
);
181 static int pcmcia_probe(struct sa1111_dev
*dev
)
186 ret
= sa1111_enable_device(dev
);
190 dev_set_drvdata(&dev
->dev
, NULL
);
192 if (!request_mem_region(dev
->res
.start
, 512, SA1111_DRIVER_NAME(dev
))) {
193 sa1111_disable_device(dev
);
200 * Initialise the suspend state.
202 sa1111_writel(PCSSR_S0_SLEEP
| PCSSR_S1_SLEEP
, base
+ PCSSR
);
203 sa1111_writel(PCCR_S0_FLT
| PCCR_S1_FLT
, base
+ PCCR
);
205 #ifdef CONFIG_SA1100_BADGE4
206 pcmcia_badge4_init(dev
);
208 #ifdef CONFIG_SA1100_JORNADA720
209 pcmcia_jornada720_init(dev
);
211 #ifdef CONFIG_ARCH_LUBBOCK
212 pcmcia_lubbock_init(dev
);
214 #ifdef CONFIG_ASSABET_NEPONSET
215 pcmcia_neponset_init(dev
);
220 static int pcmcia_remove(struct sa1111_dev
*dev
)
222 struct sa1111_pcmcia_socket
*next
, *s
= dev_get_drvdata(&dev
->dev
);
224 dev_set_drvdata(&dev
->dev
, NULL
);
226 for (; s
; s
= next
) {
228 soc_pcmcia_remove_one(&s
->soc
);
233 release_mem_region(dev
->res
.start
, 512);
234 sa1111_disable_device(dev
);
238 static struct sa1111_driver pcmcia_driver
= {
240 .name
= "sa1111-pcmcia",
242 .devid
= SA1111_DEVID_PCMCIA
,
243 .probe
= pcmcia_probe
,
244 .remove
= pcmcia_remove
,
247 static int __init
sa1111_drv_pcmcia_init(void)
249 return sa1111_driver_register(&pcmcia_driver
);
252 static void __exit
sa1111_drv_pcmcia_exit(void)
254 sa1111_driver_unregister(&pcmcia_driver
);
257 fs_initcall(sa1111_drv_pcmcia_init
);
258 module_exit(sa1111_drv_pcmcia_exit
);
260 MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver");
261 MODULE_LICENSE("GPL");