xref: /OK3568_Linux_fs/kernel/drivers/pcmcia/electra_cf.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Copyright (C) 2007 PA Semi, Inc
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Maintained by: Olof Johansson <olof@lixom.net>
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * Based on drivers/pcmcia/omap_cf.c
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/module.h>
11*4882a593Smuzhiyun #include <linux/kernel.h>
12*4882a593Smuzhiyun #include <linux/sched.h>
13*4882a593Smuzhiyun #include <linux/platform_device.h>
14*4882a593Smuzhiyun #include <linux/errno.h>
15*4882a593Smuzhiyun #include <linux/init.h>
16*4882a593Smuzhiyun #include <linux/delay.h>
17*4882a593Smuzhiyun #include <linux/interrupt.h>
18*4882a593Smuzhiyun #include <linux/mm.h>
19*4882a593Smuzhiyun #include <linux/vmalloc.h>
20*4882a593Smuzhiyun #include <linux/of_address.h>
21*4882a593Smuzhiyun #include <linux/of_irq.h>
22*4882a593Smuzhiyun #include <linux/of_platform.h>
23*4882a593Smuzhiyun #include <linux/slab.h>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun #include <pcmcia/ss.h>
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun static const char driver_name[] = "electra-cf";
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun struct electra_cf_socket {
30*4882a593Smuzhiyun 	struct pcmcia_socket	socket;
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun 	struct timer_list	timer;
33*4882a593Smuzhiyun 	unsigned		present:1;
34*4882a593Smuzhiyun 	unsigned		active:1;
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	struct platform_device	*ofdev;
37*4882a593Smuzhiyun 	unsigned long		mem_phys;
38*4882a593Smuzhiyun 	void __iomem		*mem_base;
39*4882a593Smuzhiyun 	unsigned long		mem_size;
40*4882a593Smuzhiyun 	void __iomem		*io_virt;
41*4882a593Smuzhiyun 	unsigned int		io_base;
42*4882a593Smuzhiyun 	unsigned int		io_size;
43*4882a593Smuzhiyun 	u_int			irq;
44*4882a593Smuzhiyun 	struct resource		iomem;
45*4882a593Smuzhiyun 	void __iomem		*gpio_base;
46*4882a593Smuzhiyun 	int			gpio_detect;
47*4882a593Smuzhiyun 	int			gpio_vsense;
48*4882a593Smuzhiyun 	int			gpio_3v;
49*4882a593Smuzhiyun 	int			gpio_5v;
50*4882a593Smuzhiyun };
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #define	POLL_INTERVAL		(2 * HZ)
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun 
electra_cf_present(struct electra_cf_socket * cf)55*4882a593Smuzhiyun static int electra_cf_present(struct electra_cf_socket *cf)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun 	unsigned int gpio;
58*4882a593Smuzhiyun 
59*4882a593Smuzhiyun 	gpio = in_le32(cf->gpio_base+0x40);
60*4882a593Smuzhiyun 	return !(gpio & (1 << cf->gpio_detect));
61*4882a593Smuzhiyun }
62*4882a593Smuzhiyun 
electra_cf_ss_init(struct pcmcia_socket * s)63*4882a593Smuzhiyun static int electra_cf_ss_init(struct pcmcia_socket *s)
64*4882a593Smuzhiyun {
65*4882a593Smuzhiyun 	return 0;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun /* the timer is primarily to kick this socket's pccardd */
electra_cf_timer(struct timer_list * t)69*4882a593Smuzhiyun static void electra_cf_timer(struct timer_list *t)
70*4882a593Smuzhiyun {
71*4882a593Smuzhiyun 	struct electra_cf_socket *cf = from_timer(cf, t, timer);
72*4882a593Smuzhiyun 	int present = electra_cf_present(cf);
73*4882a593Smuzhiyun 
74*4882a593Smuzhiyun 	if (present != cf->present) {
75*4882a593Smuzhiyun 		cf->present = present;
76*4882a593Smuzhiyun 		pcmcia_parse_events(&cf->socket, SS_DETECT);
77*4882a593Smuzhiyun 	}
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	if (cf->active)
80*4882a593Smuzhiyun 		mod_timer(&cf->timer, jiffies + POLL_INTERVAL);
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun 
electra_cf_irq(int irq,void * _cf)83*4882a593Smuzhiyun static irqreturn_t electra_cf_irq(int irq, void *_cf)
84*4882a593Smuzhiyun {
85*4882a593Smuzhiyun 	struct electra_cf_socket *cf = _cf;
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 	electra_cf_timer(&cf->timer);
88*4882a593Smuzhiyun 	return IRQ_HANDLED;
89*4882a593Smuzhiyun }
90*4882a593Smuzhiyun 
electra_cf_get_status(struct pcmcia_socket * s,u_int * sp)91*4882a593Smuzhiyun static int electra_cf_get_status(struct pcmcia_socket *s, u_int *sp)
92*4882a593Smuzhiyun {
93*4882a593Smuzhiyun 	struct electra_cf_socket *cf;
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun 	if (!sp)
96*4882a593Smuzhiyun 		return -EINVAL;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	cf = container_of(s, struct electra_cf_socket, socket);
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 	/* NOTE CF is always 3VCARD */
101*4882a593Smuzhiyun 	if (electra_cf_present(cf)) {
102*4882a593Smuzhiyun 		*sp = SS_READY | SS_DETECT | SS_POWERON | SS_3VCARD;
103*4882a593Smuzhiyun 
104*4882a593Smuzhiyun 		s->pci_irq = cf->irq;
105*4882a593Smuzhiyun 	} else
106*4882a593Smuzhiyun 		*sp = 0;
107*4882a593Smuzhiyun 	return 0;
108*4882a593Smuzhiyun }
109*4882a593Smuzhiyun 
electra_cf_set_socket(struct pcmcia_socket * sock,struct socket_state_t * s)110*4882a593Smuzhiyun static int electra_cf_set_socket(struct pcmcia_socket *sock,
111*4882a593Smuzhiyun 				 struct socket_state_t *s)
112*4882a593Smuzhiyun {
113*4882a593Smuzhiyun 	unsigned int gpio;
114*4882a593Smuzhiyun 	unsigned int vcc;
115*4882a593Smuzhiyun 	struct electra_cf_socket *cf;
116*4882a593Smuzhiyun 
117*4882a593Smuzhiyun 	cf = container_of(sock, struct electra_cf_socket, socket);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	/* "reset" means no power in our case */
120*4882a593Smuzhiyun 	vcc = (s->flags & SS_RESET) ? 0 : s->Vcc;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	switch (vcc) {
123*4882a593Smuzhiyun 	case 0:
124*4882a593Smuzhiyun 		gpio = 0;
125*4882a593Smuzhiyun 		break;
126*4882a593Smuzhiyun 	case 33:
127*4882a593Smuzhiyun 		gpio = (1 << cf->gpio_3v);
128*4882a593Smuzhiyun 		break;
129*4882a593Smuzhiyun 	case 5:
130*4882a593Smuzhiyun 		gpio = (1 << cf->gpio_5v);
131*4882a593Smuzhiyun 		break;
132*4882a593Smuzhiyun 	default:
133*4882a593Smuzhiyun 		return -EINVAL;
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	gpio |= 1 << (cf->gpio_3v + 16); /* enwr */
137*4882a593Smuzhiyun 	gpio |= 1 << (cf->gpio_5v + 16); /* enwr */
138*4882a593Smuzhiyun 	out_le32(cf->gpio_base+0x90, gpio);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	pr_debug("%s: Vcc %d, io_irq %d, flags %04x csc %04x\n",
141*4882a593Smuzhiyun 		driver_name, s->Vcc, s->io_irq, s->flags, s->csc_mask);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	return 0;
144*4882a593Smuzhiyun }
145*4882a593Smuzhiyun 
electra_cf_set_io_map(struct pcmcia_socket * s,struct pccard_io_map * io)146*4882a593Smuzhiyun static int electra_cf_set_io_map(struct pcmcia_socket *s,
147*4882a593Smuzhiyun 				 struct pccard_io_map *io)
148*4882a593Smuzhiyun {
149*4882a593Smuzhiyun 	return 0;
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
electra_cf_set_mem_map(struct pcmcia_socket * s,struct pccard_mem_map * map)152*4882a593Smuzhiyun static int electra_cf_set_mem_map(struct pcmcia_socket *s,
153*4882a593Smuzhiyun 				  struct pccard_mem_map *map)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	struct electra_cf_socket *cf;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	if (map->card_start)
158*4882a593Smuzhiyun 		return -EINVAL;
159*4882a593Smuzhiyun 	cf = container_of(s, struct electra_cf_socket, socket);
160*4882a593Smuzhiyun 	map->static_start = cf->mem_phys;
161*4882a593Smuzhiyun 	map->flags &= MAP_ACTIVE|MAP_ATTRIB;
162*4882a593Smuzhiyun 	if (!(map->flags & MAP_ATTRIB))
163*4882a593Smuzhiyun 		map->static_start += 0x800;
164*4882a593Smuzhiyun 	return 0;
165*4882a593Smuzhiyun }
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun static struct pccard_operations electra_cf_ops = {
168*4882a593Smuzhiyun 	.init			= electra_cf_ss_init,
169*4882a593Smuzhiyun 	.get_status		= electra_cf_get_status,
170*4882a593Smuzhiyun 	.set_socket		= electra_cf_set_socket,
171*4882a593Smuzhiyun 	.set_io_map		= electra_cf_set_io_map,
172*4882a593Smuzhiyun 	.set_mem_map		= electra_cf_set_mem_map,
173*4882a593Smuzhiyun };
174*4882a593Smuzhiyun 
electra_cf_probe(struct platform_device * ofdev)175*4882a593Smuzhiyun static int electra_cf_probe(struct platform_device *ofdev)
176*4882a593Smuzhiyun {
177*4882a593Smuzhiyun 	struct device *device = &ofdev->dev;
178*4882a593Smuzhiyun 	struct device_node *np = ofdev->dev.of_node;
179*4882a593Smuzhiyun 	struct electra_cf_socket   *cf;
180*4882a593Smuzhiyun 	struct resource mem, io;
181*4882a593Smuzhiyun 	int status = -ENOMEM;
182*4882a593Smuzhiyun 	const unsigned int *prop;
183*4882a593Smuzhiyun 	int err;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	err = of_address_to_resource(np, 0, &mem);
186*4882a593Smuzhiyun 	if (err)
187*4882a593Smuzhiyun 		return -EINVAL;
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 	err = of_address_to_resource(np, 1, &io);
190*4882a593Smuzhiyun 	if (err)
191*4882a593Smuzhiyun 		return -EINVAL;
192*4882a593Smuzhiyun 
193*4882a593Smuzhiyun 	cf = kzalloc(sizeof(*cf), GFP_KERNEL);
194*4882a593Smuzhiyun 	if (!cf)
195*4882a593Smuzhiyun 		return -ENOMEM;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	timer_setup(&cf->timer, electra_cf_timer, 0);
198*4882a593Smuzhiyun 	cf->irq = 0;
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	cf->ofdev = ofdev;
201*4882a593Smuzhiyun 	cf->mem_phys = mem.start;
202*4882a593Smuzhiyun 	cf->mem_size = PAGE_ALIGN(resource_size(&mem));
203*4882a593Smuzhiyun 	cf->mem_base = ioremap(cf->mem_phys, cf->mem_size);
204*4882a593Smuzhiyun 	if (!cf->mem_base)
205*4882a593Smuzhiyun 		goto out_free_cf;
206*4882a593Smuzhiyun 	cf->io_size = PAGE_ALIGN(resource_size(&io));
207*4882a593Smuzhiyun 	cf->io_virt = ioremap_phb(io.start, cf->io_size);
208*4882a593Smuzhiyun 	if (!cf->io_virt)
209*4882a593Smuzhiyun 		goto out_unmap_mem;
210*4882a593Smuzhiyun 
211*4882a593Smuzhiyun 	cf->gpio_base = ioremap(0xfc103000, 0x1000);
212*4882a593Smuzhiyun 	if (!cf->gpio_base)
213*4882a593Smuzhiyun 		goto out_unmap_virt;
214*4882a593Smuzhiyun 	dev_set_drvdata(device, cf);
215*4882a593Smuzhiyun 
216*4882a593Smuzhiyun 	cf->io_base = (unsigned long)cf->io_virt - VMALLOC_END;
217*4882a593Smuzhiyun 	cf->iomem.start = (unsigned long)cf->mem_base;
218*4882a593Smuzhiyun 	cf->iomem.end = (unsigned long)cf->mem_base + (mem.end - mem.start);
219*4882a593Smuzhiyun 	cf->iomem.flags = IORESOURCE_MEM;
220*4882a593Smuzhiyun 
221*4882a593Smuzhiyun 	cf->irq = irq_of_parse_and_map(np, 0);
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	status = request_irq(cf->irq, electra_cf_irq, IRQF_SHARED,
224*4882a593Smuzhiyun 			     driver_name, cf);
225*4882a593Smuzhiyun 	if (status < 0) {
226*4882a593Smuzhiyun 		dev_err(device, "request_irq failed\n");
227*4882a593Smuzhiyun 		goto fail1;
228*4882a593Smuzhiyun 	}
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	cf->socket.pci_irq = cf->irq;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	prop = of_get_property(np, "card-detect-gpio", NULL);
233*4882a593Smuzhiyun 	if (!prop)
234*4882a593Smuzhiyun 		goto fail1;
235*4882a593Smuzhiyun 	cf->gpio_detect = *prop;
236*4882a593Smuzhiyun 
237*4882a593Smuzhiyun 	prop = of_get_property(np, "card-vsense-gpio", NULL);
238*4882a593Smuzhiyun 	if (!prop)
239*4882a593Smuzhiyun 		goto fail1;
240*4882a593Smuzhiyun 	cf->gpio_vsense = *prop;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	prop = of_get_property(np, "card-3v-gpio", NULL);
243*4882a593Smuzhiyun 	if (!prop)
244*4882a593Smuzhiyun 		goto fail1;
245*4882a593Smuzhiyun 	cf->gpio_3v = *prop;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	prop = of_get_property(np, "card-5v-gpio", NULL);
248*4882a593Smuzhiyun 	if (!prop)
249*4882a593Smuzhiyun 		goto fail1;
250*4882a593Smuzhiyun 	cf->gpio_5v = *prop;
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun 	cf->socket.io_offset = cf->io_base;
253*4882a593Smuzhiyun 
254*4882a593Smuzhiyun 	/* reserve chip-select regions */
255*4882a593Smuzhiyun 	if (!request_mem_region(cf->mem_phys, cf->mem_size, driver_name)) {
256*4882a593Smuzhiyun 		status = -ENXIO;
257*4882a593Smuzhiyun 		dev_err(device, "Can't claim memory region\n");
258*4882a593Smuzhiyun 		goto fail1;
259*4882a593Smuzhiyun 	}
260*4882a593Smuzhiyun 
261*4882a593Smuzhiyun 	if (!request_region(cf->io_base, cf->io_size, driver_name)) {
262*4882a593Smuzhiyun 		status = -ENXIO;
263*4882a593Smuzhiyun 		dev_err(device, "Can't claim I/O region\n");
264*4882a593Smuzhiyun 		goto fail2;
265*4882a593Smuzhiyun 	}
266*4882a593Smuzhiyun 
267*4882a593Smuzhiyun 	cf->socket.owner = THIS_MODULE;
268*4882a593Smuzhiyun 	cf->socket.dev.parent = &ofdev->dev;
269*4882a593Smuzhiyun 	cf->socket.ops = &electra_cf_ops;
270*4882a593Smuzhiyun 	cf->socket.resource_ops = &pccard_static_ops;
271*4882a593Smuzhiyun 	cf->socket.features = SS_CAP_PCCARD | SS_CAP_STATIC_MAP |
272*4882a593Smuzhiyun 				SS_CAP_MEM_ALIGN;
273*4882a593Smuzhiyun 	cf->socket.map_size = 0x800;
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	status = pcmcia_register_socket(&cf->socket);
276*4882a593Smuzhiyun 	if (status < 0) {
277*4882a593Smuzhiyun 		dev_err(device, "pcmcia_register_socket failed\n");
278*4882a593Smuzhiyun 		goto fail3;
279*4882a593Smuzhiyun 	}
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	dev_info(device, "at mem 0x%lx io 0x%llx irq %d\n",
282*4882a593Smuzhiyun 		 cf->mem_phys, io.start, cf->irq);
283*4882a593Smuzhiyun 
284*4882a593Smuzhiyun 	cf->active = 1;
285*4882a593Smuzhiyun 	electra_cf_timer(&cf->timer);
286*4882a593Smuzhiyun 	return 0;
287*4882a593Smuzhiyun 
288*4882a593Smuzhiyun fail3:
289*4882a593Smuzhiyun 	release_region(cf->io_base, cf->io_size);
290*4882a593Smuzhiyun fail2:
291*4882a593Smuzhiyun 	release_mem_region(cf->mem_phys, cf->mem_size);
292*4882a593Smuzhiyun fail1:
293*4882a593Smuzhiyun 	if (cf->irq)
294*4882a593Smuzhiyun 		free_irq(cf->irq, cf);
295*4882a593Smuzhiyun 
296*4882a593Smuzhiyun 	iounmap(cf->gpio_base);
297*4882a593Smuzhiyun out_unmap_virt:
298*4882a593Smuzhiyun 	device_init_wakeup(&ofdev->dev, 0);
299*4882a593Smuzhiyun 	iounmap(cf->io_virt);
300*4882a593Smuzhiyun out_unmap_mem:
301*4882a593Smuzhiyun 	iounmap(cf->mem_base);
302*4882a593Smuzhiyun out_free_cf:
303*4882a593Smuzhiyun 	kfree(cf);
304*4882a593Smuzhiyun 	return status;
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun 
electra_cf_remove(struct platform_device * ofdev)308*4882a593Smuzhiyun static int electra_cf_remove(struct platform_device *ofdev)
309*4882a593Smuzhiyun {
310*4882a593Smuzhiyun 	struct device *device = &ofdev->dev;
311*4882a593Smuzhiyun 	struct electra_cf_socket *cf;
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 	cf = dev_get_drvdata(device);
314*4882a593Smuzhiyun 
315*4882a593Smuzhiyun 	cf->active = 0;
316*4882a593Smuzhiyun 	pcmcia_unregister_socket(&cf->socket);
317*4882a593Smuzhiyun 	free_irq(cf->irq, cf);
318*4882a593Smuzhiyun 	del_timer_sync(&cf->timer);
319*4882a593Smuzhiyun 
320*4882a593Smuzhiyun 	iounmap(cf->io_virt);
321*4882a593Smuzhiyun 	iounmap(cf->mem_base);
322*4882a593Smuzhiyun 	iounmap(cf->gpio_base);
323*4882a593Smuzhiyun 	release_mem_region(cf->mem_phys, cf->mem_size);
324*4882a593Smuzhiyun 	release_region(cf->io_base, cf->io_size);
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun 	kfree(cf);
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	return 0;
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun static const struct of_device_id electra_cf_match[] = {
332*4882a593Smuzhiyun 	{
333*4882a593Smuzhiyun 		.compatible   = "electra-cf",
334*4882a593Smuzhiyun 	},
335*4882a593Smuzhiyun 	{},
336*4882a593Smuzhiyun };
337*4882a593Smuzhiyun MODULE_DEVICE_TABLE(of, electra_cf_match);
338*4882a593Smuzhiyun 
339*4882a593Smuzhiyun static struct platform_driver electra_cf_driver = {
340*4882a593Smuzhiyun 	.driver = {
341*4882a593Smuzhiyun 		.name = driver_name,
342*4882a593Smuzhiyun 		.of_match_table = electra_cf_match,
343*4882a593Smuzhiyun 	},
344*4882a593Smuzhiyun 	.probe	  = electra_cf_probe,
345*4882a593Smuzhiyun 	.remove   = electra_cf_remove,
346*4882a593Smuzhiyun };
347*4882a593Smuzhiyun 
348*4882a593Smuzhiyun module_platform_driver(electra_cf_driver);
349*4882a593Smuzhiyun 
350*4882a593Smuzhiyun MODULE_LICENSE("GPL");
351*4882a593Smuzhiyun MODULE_AUTHOR("Olof Johansson <olof@lixom.net>");
352*4882a593Smuzhiyun MODULE_DESCRIPTION("PA Semi Electra CF driver");
353