1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * linux/drivers/pcmcia/pxa2xx_palmld.c
4  *
5  * Driver for Palm LifeDrive PCMCIA
6  *
7  * Copyright (C) 2006 Alex Osborne <ato@meshy.org>
8  * Copyright (C) 2007-2011 Marek Vasut <marek.vasut@gmail.com>
9  */
10 
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/gpio.h>
14 
15 #include <asm/mach-types.h>
16 #include <mach/palmld.h>
17 #include "soc_common.h"
18 
19 static struct gpio palmld_pcmcia_gpios[] = {
20 	{ GPIO_NR_PALMLD_PCMCIA_POWER,	GPIOF_INIT_LOW,	"PCMCIA Power" },
21 	{ GPIO_NR_PALMLD_PCMCIA_RESET,	GPIOF_INIT_HIGH,"PCMCIA Reset" },
22 };
23 
palmld_pcmcia_hw_init(struct soc_pcmcia_socket * skt)24 static int palmld_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
25 {
26 	int ret;
27 
28 	ret = gpio_request_array(palmld_pcmcia_gpios,
29 				ARRAY_SIZE(palmld_pcmcia_gpios));
30 
31 	skt->stat[SOC_STAT_RDY].gpio = GPIO_NR_PALMLD_PCMCIA_READY;
32 	skt->stat[SOC_STAT_RDY].name = "PCMCIA Ready";
33 
34 	return ret;
35 }
36 
palmld_pcmcia_hw_shutdown(struct soc_pcmcia_socket * skt)37 static void palmld_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
38 {
39 	gpio_free_array(palmld_pcmcia_gpios, ARRAY_SIZE(palmld_pcmcia_gpios));
40 }
41 
palmld_pcmcia_socket_state(struct soc_pcmcia_socket * skt,struct pcmcia_state * state)42 static void palmld_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
43 					struct pcmcia_state *state)
44 {
45 	state->detect = 1; /* always inserted */
46 	state->vs_3v  = 1;
47 	state->vs_Xv  = 0;
48 }
49 
palmld_pcmcia_configure_socket(struct soc_pcmcia_socket * skt,const socket_state_t * state)50 static int palmld_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
51 					const socket_state_t *state)
52 {
53 	gpio_set_value(GPIO_NR_PALMLD_PCMCIA_POWER, 1);
54 	gpio_set_value(GPIO_NR_PALMLD_PCMCIA_RESET,
55 			!!(state->flags & SS_RESET));
56 
57 	return 0;
58 }
59 
60 static struct pcmcia_low_level palmld_pcmcia_ops = {
61 	.owner			= THIS_MODULE,
62 
63 	.first			= 1,
64 	.nr			= 1,
65 
66 	.hw_init		= palmld_pcmcia_hw_init,
67 	.hw_shutdown		= palmld_pcmcia_hw_shutdown,
68 
69 	.socket_state		= palmld_pcmcia_socket_state,
70 	.configure_socket	= palmld_pcmcia_configure_socket,
71 };
72 
73 static struct platform_device *palmld_pcmcia_device;
74 
palmld_pcmcia_init(void)75 static int __init palmld_pcmcia_init(void)
76 {
77 	int ret;
78 
79 	if (!machine_is_palmld())
80 		return -ENODEV;
81 
82 	palmld_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
83 	if (!palmld_pcmcia_device)
84 		return -ENOMEM;
85 
86 	ret = platform_device_add_data(palmld_pcmcia_device, &palmld_pcmcia_ops,
87 					sizeof(palmld_pcmcia_ops));
88 
89 	if (!ret)
90 		ret = platform_device_add(palmld_pcmcia_device);
91 
92 	if (ret)
93 		platform_device_put(palmld_pcmcia_device);
94 
95 	return ret;
96 }
97 
palmld_pcmcia_exit(void)98 static void __exit palmld_pcmcia_exit(void)
99 {
100 	platform_device_unregister(palmld_pcmcia_device);
101 }
102 
103 module_init(palmld_pcmcia_init);
104 module_exit(palmld_pcmcia_exit);
105 
106 MODULE_AUTHOR("Alex Osborne <ato@meshy.org>,"
107 	    " Marek Vasut <marek.vasut@gmail.com>");
108 MODULE_DESCRIPTION("PCMCIA support for Palm LifeDrive");
109 MODULE_ALIAS("platform:pxa2xx-pcmcia");
110 MODULE_LICENSE("GPL");
111