xref: /openbmc/linux/drivers/pcmcia/pxa2xx_base.c (revision d6df7df7)
1f7be8ec1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
21da177e4SLinus Torvalds /*======================================================================
31da177e4SLinus Torvalds 
41da177e4SLinus Torvalds   Device driver for the PCMCIA control functionality of PXA2xx
51da177e4SLinus Torvalds   microprocessors.
61da177e4SLinus Torvalds 
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds     (c) Ian Molton (spyro@f2s.com) 2003
91da177e4SLinus Torvalds     (c) Stefan Eletzhofer (stefan.eletzhofer@inquant.de) 2003,4
101da177e4SLinus Torvalds 
111da177e4SLinus Torvalds     derived from sa11xx_base.c
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds      Portions created by John G. Dorsey are
141da177e4SLinus Torvalds      Copyright (C) 1999 John G. Dorsey.
151da177e4SLinus Torvalds 
161da177e4SLinus Torvalds   ======================================================================*/
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds #include <linux/module.h>
195a0e3ad6STejun Heo #include <linux/slab.h>
201da177e4SLinus Torvalds #include <linux/init.h>
211da177e4SLinus Torvalds #include <linux/cpufreq.h>
221da177e4SLinus Torvalds #include <linux/ioport.h>
231da177e4SLinus Torvalds #include <linux/kernel.h>
241da177e4SLinus Torvalds #include <linux/spinlock.h>
25d052d1beSRussell King #include <linux/platform_device.h>
2608d3df8cSArnd Bergmann #include <linux/soc/pxa/cpu.h>
276a946f1bSArnd Bergmann #include <linux/soc/pxa/smemc.h>
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds #include <asm/io.h>
301da177e4SLinus Torvalds #include <asm/irq.h>
3120f18ff3SMarc Zyngier #include <asm/mach-types.h>
321da177e4SLinus Torvalds 
331da177e4SLinus Torvalds #include <pcmcia/ss.h>
341da177e4SLinus Torvalds #include <pcmcia/cistpl.h>
351da177e4SLinus Torvalds 
361da177e4SLinus Torvalds #include "soc_common.h"
371da177e4SLinus Torvalds #include "pxa2xx_base.h"
381da177e4SLinus Torvalds 
39b393c696SEric Miao /*
40b393c696SEric Miao  * Personal Computer Memory Card International Association (PCMCIA) sockets
41b393c696SEric Miao  */
42b393c696SEric Miao 
43b393c696SEric Miao #define PCMCIAPrtSp	0x04000000	/* PCMCIA Partition Space [byte]   */
44b393c696SEric Miao #define PCMCIASp	(4*PCMCIAPrtSp)	/* PCMCIA Space [byte]             */
45b393c696SEric Miao #define PCMCIAIOSp	PCMCIAPrtSp	/* PCMCIA I/O Space [byte]         */
46b393c696SEric Miao #define PCMCIAAttrSp	PCMCIAPrtSp	/* PCMCIA Attribute Space [byte]   */
47b393c696SEric Miao #define PCMCIAMemSp	PCMCIAPrtSp	/* PCMCIA Memory Space [byte]      */
48b393c696SEric Miao 
49b393c696SEric Miao #define PCMCIA0Sp	PCMCIASp	/* PCMCIA 0 Space [byte]           */
50b393c696SEric Miao #define PCMCIA0IOSp	PCMCIAIOSp	/* PCMCIA 0 I/O Space [byte]       */
51b393c696SEric Miao #define PCMCIA0AttrSp	PCMCIAAttrSp	/* PCMCIA 0 Attribute Space [byte] */
52b393c696SEric Miao #define PCMCIA0MemSp	PCMCIAMemSp	/* PCMCIA 0 Memory Space [byte]    */
53b393c696SEric Miao 
54b393c696SEric Miao #define PCMCIA1Sp	PCMCIASp	/* PCMCIA 1 Space [byte]           */
55b393c696SEric Miao #define PCMCIA1IOSp	PCMCIAIOSp	/* PCMCIA 1 I/O Space [byte]       */
56b393c696SEric Miao #define PCMCIA1AttrSp	PCMCIAAttrSp	/* PCMCIA 1 Attribute Space [byte] */
57b393c696SEric Miao #define PCMCIA1MemSp	PCMCIAMemSp	/* PCMCIA 1 Memory Space [byte]    */
58b393c696SEric Miao 
59b393c696SEric Miao #define _PCMCIA(Nb)			/* PCMCIA [0..1]                   */ \
60b393c696SEric Miao 			(0x20000000 + (Nb) * PCMCIASp)
61b393c696SEric Miao #define _PCMCIAIO(Nb)	_PCMCIA(Nb)	/* PCMCIA I/O [0..1]               */
62b393c696SEric Miao #define _PCMCIAAttr(Nb)			/* PCMCIA Attribute [0..1]         */ \
63b393c696SEric Miao 			(_PCMCIA(Nb) + 2 * PCMCIAPrtSp)
64b393c696SEric Miao #define _PCMCIAMem(Nb)			/* PCMCIA Memory [0..1]            */ \
65b393c696SEric Miao 			(_PCMCIA(Nb) + 3 * PCMCIAPrtSp)
66b393c696SEric Miao 
67b393c696SEric Miao #define _PCMCIA0	_PCMCIA(0)	/* PCMCIA 0                        */
68b393c696SEric Miao #define _PCMCIA0IO	_PCMCIAIO(0)	/* PCMCIA 0 I/O                    */
69b393c696SEric Miao #define _PCMCIA0Attr	_PCMCIAAttr(0)	/* PCMCIA 0 Attribute              */
70b393c696SEric Miao #define _PCMCIA0Mem	_PCMCIAMem(0)	/* PCMCIA 0 Memory                 */
71b393c696SEric Miao 
72b393c696SEric Miao #define _PCMCIA1	_PCMCIA(1)	/* PCMCIA 1                        */
73b393c696SEric Miao #define _PCMCIA1IO	_PCMCIAIO(1)	/* PCMCIA 1 I/O                    */
74b393c696SEric Miao #define _PCMCIA1Attr	_PCMCIAAttr(1)	/* PCMCIA 1 Attribute              */
75b393c696SEric Miao #define _PCMCIA1Mem	_PCMCIAMem(1)	/* PCMCIA 1 Memory                 */
76b393c696SEric Miao 
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds #define MCXX_SETUP_MASK     (0x7f)
791da177e4SLinus Torvalds #define MCXX_ASST_MASK      (0x1f)
801da177e4SLinus Torvalds #define MCXX_HOLD_MASK      (0x3f)
811da177e4SLinus Torvalds #define MCXX_SETUP_SHIFT    (0)
821da177e4SLinus Torvalds #define MCXX_ASST_SHIFT     (7)
831da177e4SLinus Torvalds #define MCXX_HOLD_SHIFT     (14)
841da177e4SLinus Torvalds 
pxa2xx_mcxx_hold(u_int pcmcia_cycle_ns,u_int mem_clk_10khz)851da177e4SLinus Torvalds static inline u_int pxa2xx_mcxx_hold(u_int pcmcia_cycle_ns,
861da177e4SLinus Torvalds 				     u_int mem_clk_10khz)
871da177e4SLinus Torvalds {
881da177e4SLinus Torvalds 	u_int code = pcmcia_cycle_ns * mem_clk_10khz;
891da177e4SLinus Torvalds 	return (code / 300000) + ((code % 300000) ? 1 : 0) - 1;
901da177e4SLinus Torvalds }
911da177e4SLinus Torvalds 
pxa2xx_mcxx_asst(u_int pcmcia_cycle_ns,u_int mem_clk_10khz)921da177e4SLinus Torvalds static inline u_int pxa2xx_mcxx_asst(u_int pcmcia_cycle_ns,
931da177e4SLinus Torvalds 				     u_int mem_clk_10khz)
941da177e4SLinus Torvalds {
951da177e4SLinus Torvalds 	u_int code = pcmcia_cycle_ns * mem_clk_10khz;
9624d6572bSMilan Plzik 	return (code / 300000) + ((code % 300000) ? 1 : 0) + 1;
971da177e4SLinus Torvalds }
981da177e4SLinus Torvalds 
pxa2xx_mcxx_setup(u_int pcmcia_cycle_ns,u_int mem_clk_10khz)991da177e4SLinus Torvalds static inline u_int pxa2xx_mcxx_setup(u_int pcmcia_cycle_ns,
1001da177e4SLinus Torvalds 				      u_int mem_clk_10khz)
1011da177e4SLinus Torvalds {
1021da177e4SLinus Torvalds 	u_int code = pcmcia_cycle_ns * mem_clk_10khz;
1031da177e4SLinus Torvalds 	return (code / 100000) + ((code % 100000) ? 1 : 0) - 1;
1041da177e4SLinus Torvalds }
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds /* This function returns the (approximate) command assertion period, in
1071da177e4SLinus Torvalds  * nanoseconds, for a given CPU clock frequency and MCXX_ASST value:
1081da177e4SLinus Torvalds  */
pxa2xx_pcmcia_cmd_time(u_int mem_clk_10khz,u_int pcmcia_mcxx_asst)1091da177e4SLinus Torvalds static inline u_int pxa2xx_pcmcia_cmd_time(u_int mem_clk_10khz,
1101da177e4SLinus Torvalds 					   u_int pcmcia_mcxx_asst)
1111da177e4SLinus Torvalds {
1121da177e4SLinus Torvalds 	return (300000 * (pcmcia_mcxx_asst + 1) / mem_clk_10khz);
1131da177e4SLinus Torvalds }
1141da177e4SLinus Torvalds 
pxa2xx_pcmcia_mcmem(int sock,int speed,int clock)1156a946f1bSArnd Bergmann static uint32_t pxa2xx_pcmcia_mcmem(int sock, int speed, int clock)
1161da177e4SLinus Torvalds {
117ad68bb9fSMarek Vasut 	uint32_t val;
118ad68bb9fSMarek Vasut 
119ad68bb9fSMarek Vasut 	val = ((pxa2xx_mcxx_setup(speed, clock)
1201da177e4SLinus Torvalds 		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
1211da177e4SLinus Torvalds 		| ((pxa2xx_mcxx_asst(speed, clock)
1221da177e4SLinus Torvalds 		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
1231da177e4SLinus Torvalds 		| ((pxa2xx_mcxx_hold(speed, clock)
1241da177e4SLinus Torvalds 		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
1251da177e4SLinus Torvalds 
1266a946f1bSArnd Bergmann 	return val;
1271da177e4SLinus Torvalds }
1281da177e4SLinus Torvalds 
pxa2xx_pcmcia_mcio(int sock,int speed,int clock)1296a946f1bSArnd Bergmann static int pxa2xx_pcmcia_mcio(int sock, int speed, int clock)
1301da177e4SLinus Torvalds {
131ad68bb9fSMarek Vasut 	uint32_t val;
132ad68bb9fSMarek Vasut 
133ad68bb9fSMarek Vasut 	val = ((pxa2xx_mcxx_setup(speed, clock)
1341da177e4SLinus Torvalds 		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
1351da177e4SLinus Torvalds 		| ((pxa2xx_mcxx_asst(speed, clock)
1361da177e4SLinus Torvalds 		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
1371da177e4SLinus Torvalds 		| ((pxa2xx_mcxx_hold(speed, clock)
1381da177e4SLinus Torvalds 		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
1391da177e4SLinus Torvalds 
140ad68bb9fSMarek Vasut 
1416a946f1bSArnd Bergmann 	return val;
1421da177e4SLinus Torvalds }
1431da177e4SLinus Torvalds 
pxa2xx_pcmcia_mcatt(int sock,int speed,int clock)1446a946f1bSArnd Bergmann static int pxa2xx_pcmcia_mcatt(int sock, int speed, int clock)
1451da177e4SLinus Torvalds {
146ad68bb9fSMarek Vasut 	uint32_t val;
147ad68bb9fSMarek Vasut 
148ad68bb9fSMarek Vasut 	val = ((pxa2xx_mcxx_setup(speed, clock)
1491da177e4SLinus Torvalds 		& MCXX_SETUP_MASK) << MCXX_SETUP_SHIFT)
1501da177e4SLinus Torvalds 		| ((pxa2xx_mcxx_asst(speed, clock)
1511da177e4SLinus Torvalds 		& MCXX_ASST_MASK) << MCXX_ASST_SHIFT)
1521da177e4SLinus Torvalds 		| ((pxa2xx_mcxx_hold(speed, clock)
1531da177e4SLinus Torvalds 		& MCXX_HOLD_MASK) << MCXX_HOLD_SHIFT);
1541da177e4SLinus Torvalds 
155ad68bb9fSMarek Vasut 
1566a946f1bSArnd Bergmann 	return val;
1571da177e4SLinus Torvalds }
1581da177e4SLinus Torvalds 
pxa2xx_pcmcia_set_timing(struct soc_pcmcia_socket * skt)1596a946f1bSArnd Bergmann static int pxa2xx_pcmcia_set_timing(struct soc_pcmcia_socket *skt)
1601da177e4SLinus Torvalds {
1616a946f1bSArnd Bergmann 	unsigned long clk = clk_get_rate(skt->clk) / 10000;
1621da177e4SLinus Torvalds 	struct soc_pcmcia_timing timing;
1631da177e4SLinus Torvalds 	int sock = skt->nr;
1641da177e4SLinus Torvalds 
1651da177e4SLinus Torvalds 	soc_common_pcmcia_get_timing(skt, &timing);
1661da177e4SLinus Torvalds 
1676a946f1bSArnd Bergmann 	pxa_smemc_set_pcmcia_timing(sock,
1686a946f1bSArnd Bergmann 		pxa2xx_pcmcia_mcmem(sock, timing.mem, clk),
1696a946f1bSArnd Bergmann 		pxa2xx_pcmcia_mcatt(sock, timing.attr, clk),
1706a946f1bSArnd Bergmann 		pxa2xx_pcmcia_mcio(sock, timing.io, clk));
1711da177e4SLinus Torvalds 
1721da177e4SLinus Torvalds 	return 0;
1731da177e4SLinus Torvalds }
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds #ifdef CONFIG_CPU_FREQ
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds static int
pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket * skt,unsigned long val,struct cpufreq_freqs * freqs)1781da177e4SLinus Torvalds pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt,
1791da177e4SLinus Torvalds 			       unsigned long val,
1801da177e4SLinus Torvalds 			       struct cpufreq_freqs *freqs)
1811da177e4SLinus Torvalds {
1821da177e4SLinus Torvalds 	switch (val) {
1831da177e4SLinus Torvalds 	case CPUFREQ_PRECHANGE:
1841da177e4SLinus Torvalds 		if (freqs->new > freqs->old) {
1851da177e4SLinus Torvalds 			debug(skt, 2, "new frequency %u.%uMHz > %u.%uMHz, "
1861da177e4SLinus Torvalds 			       "pre-updating\n",
1871da177e4SLinus Torvalds 			       freqs->new / 1000, (freqs->new / 100) % 10,
1881da177e4SLinus Torvalds 			       freqs->old / 1000, (freqs->old / 100) % 10);
189d344a21aSMarek Vasut 			pxa2xx_pcmcia_set_timing(skt);
1901da177e4SLinus Torvalds 		}
1911da177e4SLinus Torvalds 		break;
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds 	case CPUFREQ_POSTCHANGE:
1941da177e4SLinus Torvalds 		if (freqs->new < freqs->old) {
1951da177e4SLinus Torvalds 			debug(skt, 2, "new frequency %u.%uMHz < %u.%uMHz, "
1961da177e4SLinus Torvalds 			       "post-updating\n",
1971da177e4SLinus Torvalds 			       freqs->new / 1000, (freqs->new / 100) % 10,
1981da177e4SLinus Torvalds 			       freqs->old / 1000, (freqs->old / 100) % 10);
199d344a21aSMarek Vasut 			pxa2xx_pcmcia_set_timing(skt);
2001da177e4SLinus Torvalds 		}
2011da177e4SLinus Torvalds 		break;
2021da177e4SLinus Torvalds 	}
2031da177e4SLinus Torvalds 	return 0;
2041da177e4SLinus Torvalds }
2051da177e4SLinus Torvalds #endif
2061da177e4SLinus Torvalds 
pxa2xx_configure_sockets(struct device * dev,struct pcmcia_low_level * ops)207817ed574SRobert Jarzmik void pxa2xx_configure_sockets(struct device *dev, struct pcmcia_low_level *ops)
2081da177e4SLinus Torvalds {
209*d6df7df7SArnd Bergmann 	pxa_smemc_set_pcmcia_socket(1);
2101da177e4SLinus Torvalds }
211d5240dfdSRussell King EXPORT_SYMBOL(pxa2xx_configure_sockets);
2121da177e4SLinus Torvalds 
213b393c696SEric Miao static const char *skt_names[] = {
214b393c696SEric Miao 	"PCMCIA socket 0",
215b393c696SEric Miao 	"PCMCIA socket 1",
216b393c696SEric Miao };
217b393c696SEric Miao 
218b393c696SEric Miao #define SKT_DEV_INFO_SIZE(n) \
219b393c696SEric Miao 	(sizeof(struct skt_dev_info) + (n)*sizeof(struct soc_pcmcia_socket))
220b393c696SEric Miao 
pxa2xx_drv_pcmcia_add_one(struct soc_pcmcia_socket * skt)221701a5dc0SRussell King - ARM Linux int pxa2xx_drv_pcmcia_add_one(struct soc_pcmcia_socket *skt)
22220f18ff3SMarc Zyngier {
223b393c696SEric Miao 	skt->res_skt.start = _PCMCIA(skt->nr);
224b393c696SEric Miao 	skt->res_skt.end = _PCMCIA(skt->nr) + PCMCIASp - 1;
225b393c696SEric Miao 	skt->res_skt.name = skt_names[skt->nr];
226b393c696SEric Miao 	skt->res_skt.flags = IORESOURCE_MEM;
227b393c696SEric Miao 
228b393c696SEric Miao 	skt->res_io.start = _PCMCIAIO(skt->nr);
229b393c696SEric Miao 	skt->res_io.end = _PCMCIAIO(skt->nr) + PCMCIAIOSp - 1;
230b393c696SEric Miao 	skt->res_io.name = "io";
231b393c696SEric Miao 	skt->res_io.flags = IORESOURCE_MEM | IORESOURCE_BUSY;
232b393c696SEric Miao 
233b393c696SEric Miao 	skt->res_mem.start = _PCMCIAMem(skt->nr);
234b393c696SEric Miao 	skt->res_mem.end = _PCMCIAMem(skt->nr) + PCMCIAMemSp - 1;
235b393c696SEric Miao 	skt->res_mem.name = "memory";
236b393c696SEric Miao 	skt->res_mem.flags = IORESOURCE_MEM;
237b393c696SEric Miao 
238b393c696SEric Miao 	skt->res_attr.start = _PCMCIAAttr(skt->nr);
239b393c696SEric Miao 	skt->res_attr.end = _PCMCIAAttr(skt->nr) + PCMCIAAttrSp - 1;
240b393c696SEric Miao 	skt->res_attr.name = "attribute";
241b393c696SEric Miao 	skt->res_attr.flags = IORESOURCE_MEM;
242da4f0073SRussell King - ARM Linux 
243da4f0073SRussell King - ARM Linux 	return soc_pcmcia_add_one(skt);
244b393c696SEric Miao }
245d0d26c33SRussell King EXPORT_SYMBOL(pxa2xx_drv_pcmcia_add_one);
246b393c696SEric Miao 
pxa2xx_drv_pcmcia_ops(struct pcmcia_low_level * ops)247701a5dc0SRussell King - ARM Linux void pxa2xx_drv_pcmcia_ops(struct pcmcia_low_level *ops)
248701a5dc0SRussell King - ARM Linux {
249701a5dc0SRussell King - ARM Linux 	/* Provide our PXA2xx specific timing routines. */
250701a5dc0SRussell King - ARM Linux 	ops->set_timing  = pxa2xx_pcmcia_set_timing;
251701a5dc0SRussell King - ARM Linux #ifdef CONFIG_CPU_FREQ
252701a5dc0SRussell King - ARM Linux 	ops->frequency_change = pxa2xx_pcmcia_frequency_change;
253701a5dc0SRussell King - ARM Linux #endif
254701a5dc0SRussell King - ARM Linux }
255d0d26c33SRussell King EXPORT_SYMBOL(pxa2xx_drv_pcmcia_ops);
256701a5dc0SRussell King - ARM Linux 
pxa2xx_drv_pcmcia_probe(struct platform_device * dev)257d0d26c33SRussell King static int pxa2xx_drv_pcmcia_probe(struct platform_device *dev)
258da4f0073SRussell King - ARM Linux {
259701a5dc0SRussell King - ARM Linux 	int i, ret = 0;
260da4f0073SRussell King - ARM Linux 	struct pcmcia_low_level *ops;
261da4f0073SRussell King - ARM Linux 	struct skt_dev_info *sinfo;
262da4f0073SRussell King - ARM Linux 	struct soc_pcmcia_socket *skt;
2632a125dd5SEric Miao 	struct clk *clk;
264da4f0073SRussell King - ARM Linux 
265d0d26c33SRussell King 	ops = (struct pcmcia_low_level *)dev->dev.platform_data;
266a4257af5SMarek Vasut 	if (!ops) {
267a4257af5SMarek Vasut 		ret = -ENODEV;
268a4257af5SMarek Vasut 		goto err0;
269a4257af5SMarek Vasut 	}
270a4257af5SMarek Vasut 
271a4257af5SMarek Vasut 	if (cpu_is_pxa320() && ops->nr > 1) {
272a4257af5SMarek Vasut 		dev_err(&dev->dev, "pxa320 supports only one pcmcia slot");
273a4257af5SMarek Vasut 		ret = -EINVAL;
274a4257af5SMarek Vasut 		goto err0;
275a4257af5SMarek Vasut 	}
276da4f0073SRussell King - ARM Linux 
277ac92f151SRussell King 	clk = devm_clk_get(&dev->dev, NULL);
278e09a7164SWei Yongjun 	if (IS_ERR(clk))
2792a125dd5SEric Miao 		return -ENODEV;
2802a125dd5SEric Miao 
281701a5dc0SRussell King - ARM Linux 	pxa2xx_drv_pcmcia_ops(ops);
28220f18ff3SMarc Zyngier 
2838e2caf0dSRussell King 	sinfo = devm_kzalloc(&dev->dev, SKT_DEV_INFO_SIZE(ops->nr),
2848e2caf0dSRussell King 			     GFP_KERNEL);
285ac92f151SRussell King 	if (!sinfo)
286da4f0073SRussell King - ARM Linux 		return -ENOMEM;
28720f18ff3SMarc Zyngier 
288da4f0073SRussell King - ARM Linux 	sinfo->nskt = ops->nr;
289da4f0073SRussell King - ARM Linux 
290da4f0073SRussell King - ARM Linux 	/* Initialize processor specific parameters */
291da4f0073SRussell King - ARM Linux 	for (i = 0; i < ops->nr; i++) {
292da4f0073SRussell King - ARM Linux 		skt = &sinfo->skt[i];
293da4f0073SRussell King - ARM Linux 
294da4f0073SRussell King - ARM Linux 		skt->nr = ops->first + i;
2952a125dd5SEric Miao 		skt->clk = clk;
296e0d21178SRussell King 		soc_pcmcia_init_one(skt, ops, &dev->dev);
297da4f0073SRussell King - ARM Linux 
298da4f0073SRussell King - ARM Linux 		ret = pxa2xx_drv_pcmcia_add_one(skt);
299da4f0073SRussell King - ARM Linux 		if (ret)
300a4257af5SMarek Vasut 			goto err1;
301da4f0073SRussell King - ARM Linux 	}
302da4f0073SRussell King - ARM Linux 
303817ed574SRobert Jarzmik 	pxa2xx_configure_sockets(&dev->dev, ops);
304a7a5ac58SMarc Zyngier 	dev_set_drvdata(&dev->dev, sinfo);
30520f18ff3SMarc Zyngier 
306a4257af5SMarek Vasut 	return 0;
307a4257af5SMarek Vasut 
308a4257af5SMarek Vasut err1:
309a4257af5SMarek Vasut 	while (--i >= 0)
310a4257af5SMarek Vasut 		soc_pcmcia_remove_one(&sinfo->skt[i]);
3118e2caf0dSRussell King 
312a4257af5SMarek Vasut err0:
3131da177e4SLinus Torvalds 	return ret;
3141da177e4SLinus Torvalds }
3159468613bSRussell King 
pxa2xx_drv_pcmcia_remove(struct platform_device * dev)3169468613bSRussell King static int pxa2xx_drv_pcmcia_remove(struct platform_device *dev)
3179468613bSRussell King {
318be85458eSRussell King - ARM Linux 	struct skt_dev_info *sinfo = platform_get_drvdata(dev);
319be85458eSRussell King - ARM Linux 	int i;
320be85458eSRussell King - ARM Linux 
321be85458eSRussell King - ARM Linux 	for (i = 0; i < sinfo->nskt; i++)
322be85458eSRussell King - ARM Linux 		soc_pcmcia_remove_one(&sinfo->skt[i]);
323be85458eSRussell King - ARM Linux 
324be85458eSRussell King - ARM Linux 	return 0;
3259468613bSRussell King }
3269468613bSRussell King 
pxa2xx_drv_pcmcia_resume(struct device * dev)32785c61021SMike Rapoport static int pxa2xx_drv_pcmcia_resume(struct device *dev)
3289468613bSRussell King {
329817ed574SRobert Jarzmik 	struct pcmcia_low_level *ops = (struct pcmcia_low_level *)dev->platform_data;
330817ed574SRobert Jarzmik 
331817ed574SRobert Jarzmik 	pxa2xx_configure_sockets(dev, ops);
332d7646f76SDominik Brodowski 	return 0;
3331da177e4SLinus Torvalds }
3341da177e4SLinus Torvalds 
33547145210SAlexey Dobriyan static const struct dev_pm_ops pxa2xx_drv_pcmcia_pm_ops = {
33685c61021SMike Rapoport 	.resume		= pxa2xx_drv_pcmcia_resume,
33785c61021SMike Rapoport };
33885c61021SMike Rapoport 
3399468613bSRussell King static struct platform_driver pxa2xx_pcmcia_driver = {
3401da177e4SLinus Torvalds 	.probe		= pxa2xx_drv_pcmcia_probe,
3419468613bSRussell King 	.remove		= pxa2xx_drv_pcmcia_remove,
3429468613bSRussell King 	.driver		= {
3431da177e4SLinus Torvalds 		.name	= "pxa2xx-pcmcia",
34485c61021SMike Rapoport 		.pm	= &pxa2xx_drv_pcmcia_pm_ops,
3459468613bSRussell King 	},
3461da177e4SLinus Torvalds };
3471da177e4SLinus Torvalds 
pxa2xx_pcmcia_init(void)3481da177e4SLinus Torvalds static int __init pxa2xx_pcmcia_init(void)
3491da177e4SLinus Torvalds {
3509468613bSRussell King 	return platform_driver_register(&pxa2xx_pcmcia_driver);
3511da177e4SLinus Torvalds }
3521da177e4SLinus Torvalds 
pxa2xx_pcmcia_exit(void)3531da177e4SLinus Torvalds static void __exit pxa2xx_pcmcia_exit(void)
3541da177e4SLinus Torvalds {
3559468613bSRussell King 	platform_driver_unregister(&pxa2xx_pcmcia_driver);
3561da177e4SLinus Torvalds }
3571da177e4SLinus Torvalds 
358f36598aeSRichard Purdie fs_initcall(pxa2xx_pcmcia_init);
3591da177e4SLinus Torvalds module_exit(pxa2xx_pcmcia_exit);
3601da177e4SLinus Torvalds 
3611da177e4SLinus Torvalds MODULE_AUTHOR("Stefan Eletzhofer <stefan.eletzhofer@inquant.de> and Ian Molton <spyro@f2s.com>");
3621da177e4SLinus Torvalds MODULE_DESCRIPTION("Linux PCMCIA Card Services: PXA2xx core socket driver");
3631da177e4SLinus Torvalds MODULE_LICENSE("GPL");
36412c2c019SKay Sievers MODULE_ALIAS("platform:pxa2xx-pcmcia");
365