Blame view

drivers/pcmcia/sa1111_generic.c 6.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
  /*
   * linux/drivers/pcmcia/sa1111_generic.c
   *
   * We implement the generic parts of a SA1111 PCMCIA driver.  This
   * basically means we handle everything except controlling the
   * power.  Power is machine specific...
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
9
10
11
12
13
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/ioport.h>
  #include <linux/device.h>
  #include <linux/interrupt.h>
  #include <linux/init.h>
997302259   Russell King   [ARM] acorn,ebsa1...
14
  #include <linux/io.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
15
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
  
  #include <pcmcia/ss.h>
a09e64fbc   Russell King   [ARM] Move includ...
18
  #include <mach/hardware.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
  #include <asm/hardware/sa1111.h>
3f8df892b   Russell King   pcmcia: sa1111: f...
20
  #include <asm/mach-types.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
  #include <asm/irq.h>
  
  #include "sa1111_generic.h"
ea8c00ac1   Russell King   ARM: sa1111: move...
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  /*
   * These are offsets from the above base.
   */
  #define PCCR	0x0000
  #define PCSSR	0x0004
  #define PCSR	0x0008
  
  #define PCSR_S0_READY	(1<<0)
  #define PCSR_S1_READY	(1<<1)
  #define PCSR_S0_DETECT	(1<<2)
  #define PCSR_S1_DETECT	(1<<3)
  #define PCSR_S0_VS1	(1<<4)
  #define PCSR_S0_VS2	(1<<5)
  #define PCSR_S1_VS1	(1<<6)
  #define PCSR_S1_VS2	(1<<7)
  #define PCSR_S0_WP	(1<<8)
  #define PCSR_S1_WP	(1<<9)
  #define PCSR_S0_BVD1	(1<<10)
  #define PCSR_S0_BVD2	(1<<11)
  #define PCSR_S1_BVD1	(1<<12)
  #define PCSR_S1_BVD2	(1<<13)
  
  #define PCCR_S0_RST	(1<<0)
  #define PCCR_S1_RST	(1<<1)
  #define PCCR_S0_FLT	(1<<2)
  #define PCCR_S1_FLT	(1<<3)
  #define PCCR_S0_PWAITEN	(1<<4)
  #define PCCR_S1_PWAITEN	(1<<5)
  #define PCCR_S0_PSE	(1<<6)
  #define PCCR_S1_PSE	(1<<7)
  
  #define PCSSR_S0_SLEEP	(1<<0)
  #define PCSSR_S1_SLEEP	(1<<1)
08fa15900   Eric Miao   [ARM] sa1111: avo...
57
58
59
60
61
62
  #define IDX_IRQ_S0_READY_NINT	(0)
  #define IDX_IRQ_S0_CD_VALID	(1)
  #define IDX_IRQ_S0_BVD1_STSCHG	(2)
  #define IDX_IRQ_S1_READY_NINT	(3)
  #define IDX_IRQ_S1_CD_VALID	(4)
  #define IDX_IRQ_S1_BVD1_STSCHG	(5)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
63
64
  void sa1111_pcmcia_socket_state(struct soc_pcmcia_socket *skt, struct pcmcia_state *state)
  {
701a5dc05   Russell King - ARM Linux   PCMCIA: sa1111: w...
65
  	struct sa1111_pcmcia_socket *s = to_skt(skt);
ea8c00ac1   Russell King   ARM: sa1111: move...
66
  	unsigned long status = sa1111_readl(s->dev->mapbase + PCSR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  
  	switch (skt->nr) {
  	case 0:
  		state->detect = status & PCSR_S0_DETECT ? 0 : 1;
  		state->ready  = status & PCSR_S0_READY  ? 1 : 0;
  		state->bvd1   = status & PCSR_S0_BVD1   ? 1 : 0;
  		state->bvd2   = status & PCSR_S0_BVD2   ? 1 : 0;
  		state->wrprot = status & PCSR_S0_WP     ? 1 : 0;
  		state->vs_3v  = status & PCSR_S0_VS1    ? 0 : 1;
  		state->vs_Xv  = status & PCSR_S0_VS2    ? 0 : 1;
  		break;
  
  	case 1:
  		state->detect = status & PCSR_S1_DETECT ? 0 : 1;
  		state->ready  = status & PCSR_S1_READY  ? 1 : 0;
  		state->bvd1   = status & PCSR_S1_BVD1   ? 1 : 0;
  		state->bvd2   = status & PCSR_S1_BVD2   ? 1 : 0;
  		state->wrprot = status & PCSR_S1_WP     ? 1 : 0;
  		state->vs_3v  = status & PCSR_S1_VS1    ? 0 : 1;
  		state->vs_Xv  = status & PCSR_S1_VS2    ? 0 : 1;
  		break;
  	}
  }
  
  int sa1111_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, const socket_state_t *state)
  {
701a5dc05   Russell King - ARM Linux   PCMCIA: sa1111: w...
93
  	struct sa1111_pcmcia_socket *s = to_skt(skt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  	unsigned int pccr_skt_mask, pccr_set_mask, val;
  	unsigned long flags;
  
  	switch (skt->nr) {
  	case 0:
  		pccr_skt_mask = PCCR_S0_RST|PCCR_S0_FLT|PCCR_S0_PWAITEN|PCCR_S0_PSE;
  		break;
  
  	case 1:
  		pccr_skt_mask = PCCR_S1_RST|PCCR_S1_FLT|PCCR_S1_PWAITEN|PCCR_S1_PSE;
  		break;
  
  	default:
  		return -1;
  	}
  
  	pccr_set_mask = 0;
  
  	if (state->Vcc != 0)
  		pccr_set_mask |= PCCR_S0_PWAITEN|PCCR_S1_PWAITEN;
  	if (state->Vcc == 50)
  		pccr_set_mask |= PCCR_S0_PSE|PCCR_S1_PSE;
  	if (state->flags & SS_RESET)
  		pccr_set_mask |= PCCR_S0_RST|PCCR_S1_RST;
  	if (state->flags & SS_OUTPUT_ENA)
  		pccr_set_mask |= PCCR_S0_FLT|PCCR_S1_FLT;
  
  	local_irq_save(flags);
ea8c00ac1   Russell King   ARM: sa1111: move...
122
  	val = sa1111_readl(s->dev->mapbase + PCCR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
  	val &= ~pccr_skt_mask;
  	val |= pccr_set_mask & pccr_skt_mask;
ea8c00ac1   Russell King   ARM: sa1111: move...
125
  	sa1111_writel(val, s->dev->mapbase + PCCR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
129
  	local_irq_restore(flags);
  
  	return 0;
  }
701a5dc05   Russell King - ARM Linux   PCMCIA: sa1111: w...
130
131
132
133
  int sa1111_pcmcia_add(struct sa1111_dev *dev, struct pcmcia_low_level *ops,
  	int (*add)(struct soc_pcmcia_socket *))
  {
  	struct sa1111_pcmcia_socket *s;
321ae9646   Russell King   pcmcia: sa1111: s...
134
  	struct clk *clk;
701a5dc05   Russell King - ARM Linux   PCMCIA: sa1111: w...
135
  	int i, ret = 0;
321ae9646   Russell King   pcmcia: sa1111: s...
136
137
138
  	clk = devm_clk_get(&dev->dev, NULL);
  	if (IS_ERR(clk))
  		return PTR_ERR(clk);
dabd14684   Russell King - ARM Linux   PCMCIA: sa1111: r...
139
  	ops->socket_state = sa1111_pcmcia_socket_state;
dabd14684   Russell King - ARM Linux   PCMCIA: sa1111: r...
140

701a5dc05   Russell King - ARM Linux   PCMCIA: sa1111: w...
141
142
143
144
145
146
  	for (i = 0; i < ops->nr; i++) {
  		s = kzalloc(sizeof(*s), GFP_KERNEL);
  		if (!s)
  			return -ENOMEM;
  
  		s->soc.nr = ops->first + i;
321ae9646   Russell King   pcmcia: sa1111: s...
147
  		s->soc.clk = clk;
e0d21178c   Russell King   PCMCIA: soc_commo...
148
  		soc_pcmcia_init_one(&s->soc, ops, &dev->dev);
701a5dc05   Russell King - ARM Linux   PCMCIA: sa1111: w...
149
  		s->dev = dev;
81f33c65e   Russell King   PCMCIA: sa1111: u...
150
151
152
153
154
155
156
157
158
159
160
161
162
  		if (s->soc.nr) {
  			s->soc.socket.pci_irq = dev->irq[IDX_IRQ_S1_READY_NINT];
  			s->soc.stat[SOC_STAT_CD].irq = dev->irq[IDX_IRQ_S1_CD_VALID];
  			s->soc.stat[SOC_STAT_CD].name = "SA1111 CF card detect";
  			s->soc.stat[SOC_STAT_BVD1].irq = dev->irq[IDX_IRQ_S1_BVD1_STSCHG];
  			s->soc.stat[SOC_STAT_BVD1].name = "SA1111 CF BVD1";
  		} else {
  			s->soc.socket.pci_irq = dev->irq[IDX_IRQ_S0_READY_NINT];
  			s->soc.stat[SOC_STAT_CD].irq = dev->irq[IDX_IRQ_S0_CD_VALID];
  			s->soc.stat[SOC_STAT_CD].name = "SA1111 PCMCIA card detect";
  			s->soc.stat[SOC_STAT_BVD1].irq = dev->irq[IDX_IRQ_S0_BVD1_STSCHG];
  			s->soc.stat[SOC_STAT_BVD1].name = "SA1111 PCMCIA BVD1";
  		}
701a5dc05   Russell King - ARM Linux   PCMCIA: sa1111: w...
163
164
165
166
167
168
169
170
171
172
173
  
  		ret = add(&s->soc);
  		if (ret == 0) {
  			s->next = dev_get_drvdata(&dev->dev);
  			dev_set_drvdata(&dev->dev, s);
  		} else
  			kfree(s);
  	}
  
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
174
175
  static int pcmcia_probe(struct sa1111_dev *dev)
  {
f339ab3d6   Russell King   [ARM] Fix sparse ...
176
  	void __iomem *base;
ae99ddbc9   Russell King   ARM: sa1111: add ...
177
178
179
180
181
  	int ret;
  
  	ret = sa1111_enable_device(dev);
  	if (ret)
  		return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182

701a5dc05   Russell King - ARM Linux   PCMCIA: sa1111: w...
183
  	dev_set_drvdata(&dev->dev, NULL);
ae99ddbc9   Russell King   ARM: sa1111: add ...
184
185
  	if (!request_mem_region(dev->res.start, 512, SA1111_DRIVER_NAME(dev))) {
  		sa1111_disable_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
  		return -EBUSY;
ae99ddbc9   Russell King   ARM: sa1111: add ...
187
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
189
190
191
192
193
  
  	base = dev->mapbase;
  
  	/*
  	 * Initialise the suspend state.
  	 */
ea8c00ac1   Russell King   ARM: sa1111: move...
194
195
  	sa1111_writel(PCSSR_S0_SLEEP | PCSSR_S1_SLEEP, base + PCSSR);
  	sa1111_writel(PCCR_S0_FLT | PCCR_S1_FLT, base + PCCR);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196

3f8df892b   Russell King   pcmcia: sa1111: f...
197
  	ret = -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  #ifdef CONFIG_SA1100_BADGE4
3f8df892b   Russell King   pcmcia: sa1111: f...
199
200
  	if (machine_is_badge4())
  		ret = pcmcia_badge4_init(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
201
202
  #endif
  #ifdef CONFIG_SA1100_JORNADA720
3f8df892b   Russell King   pcmcia: sa1111: f...
203
204
  	if (machine_is_jornada720())
  		ret = pcmcia_jornada720_init(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
205
206
  #endif
  #ifdef CONFIG_ARCH_LUBBOCK
3f8df892b   Russell King   pcmcia: sa1111: f...
207
208
  	if (machine_is_lubbock())
  		ret = pcmcia_lubbock_init(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
209
210
  #endif
  #ifdef CONFIG_ASSABET_NEPONSET
3f8df892b   Russell King   pcmcia: sa1111: f...
211
212
  	if (machine_is_assabet())
  		ret = pcmcia_neponset_init(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
  #endif
3f8df892b   Russell King   pcmcia: sa1111: f...
214
215
216
217
218
219
220
  
  	if (ret) {
  		release_mem_region(dev->res.start, 512);
  		sa1111_disable_device(dev);
  	}
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
  }
e765a02cb   Bill Pemberton   pcmcia: remove us...
222
  static int pcmcia_remove(struct sa1111_dev *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  {
701a5dc05   Russell King - ARM Linux   PCMCIA: sa1111: w...
224
  	struct sa1111_pcmcia_socket *next, *s = dev_get_drvdata(&dev->dev);
be85458ed   Russell King - ARM Linux   PCMCIA: soc_commo...
225
226
  
  	dev_set_drvdata(&dev->dev, NULL);
171cf94cc   Russell King   PCMCIA: fix sa111...
227
228
  	for (; s; s = next) {
  		next = s->next;
701a5dc05   Russell King - ARM Linux   PCMCIA: sa1111: w...
229
230
231
  		soc_pcmcia_remove_one(&s->soc);
  		kfree(s);
  	}
be85458ed   Russell King - ARM Linux   PCMCIA: soc_commo...
232

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
233
  	release_mem_region(dev->res.start, 512);
ae99ddbc9   Russell King   ARM: sa1111: add ...
234
  	sa1111_disable_device(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
239
240
241
242
  static struct sa1111_driver pcmcia_driver = {
  	.drv = {
  		.name	= "sa1111-pcmcia",
  	},
  	.devid		= SA1111_DEVID_PCMCIA,
  	.probe		= pcmcia_probe,
96364e3a5   Bill Pemberton   pcmcia: remove us...
243
  	.remove		= pcmcia_remove,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
246
247
248
249
250
251
252
253
254
  };
  
  static int __init sa1111_drv_pcmcia_init(void)
  {
  	return sa1111_driver_register(&pcmcia_driver);
  }
  
  static void __exit sa1111_drv_pcmcia_exit(void)
  {
  	sa1111_driver_unregister(&pcmcia_driver);
  }
f36598aec   Richard Purdie   [ARM] 2873/1: PCM...
255
  fs_initcall(sa1111_drv_pcmcia_init);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
258
259
  module_exit(sa1111_drv_pcmcia_exit);
  
  MODULE_DESCRIPTION("SA1111 PCMCIA card socket driver");
  MODULE_LICENSE("GPL");