V4L/DVB (9689): gspca: Memory leak when disconnect while streaming.
[linux-2.6] / drivers / pcmcia / pxa2xx_palmtx.c
1 /*
2  * linux/drivers/pcmcia/pxa2xx_palmtx.c
3  *
4  * Driver for Palm T|X PCMCIA
5  *
6  * Copyright (C) 2007-2008 Marek Vasut <marek.vasut@gmail.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  *
12  */
13
14 #include <linux/module.h>
15 #include <linux/platform_device.h>
16
17 #include <asm/mach-types.h>
18
19 #include <mach/gpio.h>
20 #include <mach/palmtx.h>
21
22 #include "soc_common.h"
23
24 static int palmtx_pcmcia_hw_init(struct soc_pcmcia_socket *skt)
25 {
26         int ret;
27
28         ret = gpio_request(GPIO_NR_PALMTX_PCMCIA_POWER1, "PCMCIA PWR1");
29         if (ret)
30                 goto err1;
31         ret = gpio_direction_output(GPIO_NR_PALMTX_PCMCIA_POWER1, 0);
32         if (ret)
33                 goto err2;
34
35         ret = gpio_request(GPIO_NR_PALMTX_PCMCIA_POWER2, "PCMCIA PWR2");
36         if (ret)
37                 goto err2;
38         ret = gpio_direction_output(GPIO_NR_PALMTX_PCMCIA_POWER2, 0);
39         if (ret)
40                 goto err3;
41
42         ret = gpio_request(GPIO_NR_PALMTX_PCMCIA_RESET, "PCMCIA RST");
43         if (ret)
44                 goto err3;
45         ret = gpio_direction_output(GPIO_NR_PALMTX_PCMCIA_RESET, 1);
46         if (ret)
47                 goto err4;
48
49         ret = gpio_request(GPIO_NR_PALMTX_PCMCIA_READY, "PCMCIA RDY");
50         if (ret)
51                 goto err4;
52         ret = gpio_direction_input(GPIO_NR_PALMTX_PCMCIA_READY);
53         if (ret)
54                 goto err5;
55
56         skt->irq = gpio_to_irq(GPIO_NR_PALMTX_PCMCIA_READY);
57         return 0;
58
59 err5:
60         gpio_free(GPIO_NR_PALMTX_PCMCIA_READY);
61 err4:
62         gpio_free(GPIO_NR_PALMTX_PCMCIA_RESET);
63 err3:
64         gpio_free(GPIO_NR_PALMTX_PCMCIA_POWER2);
65 err2:
66         gpio_free(GPIO_NR_PALMTX_PCMCIA_POWER1);
67 err1:
68         return ret;
69 }
70
71 static void palmtx_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt)
72 {
73         gpio_free(GPIO_NR_PALMTX_PCMCIA_READY);
74         gpio_free(GPIO_NR_PALMTX_PCMCIA_RESET);
75         gpio_free(GPIO_NR_PALMTX_PCMCIA_POWER2);
76         gpio_free(GPIO_NR_PALMTX_PCMCIA_POWER1);
77 }
78
79 static void palmtx_pcmcia_socket_state(struct soc_pcmcia_socket *skt,
80                                         struct pcmcia_state *state)
81 {
82         state->detect = 1; /* always inserted */
83         state->ready  = !!gpio_get_value(GPIO_NR_PALMTX_PCMCIA_READY);
84         state->bvd1   = 1;
85         state->bvd2   = 1;
86         state->wrprot = 0;
87         state->vs_3v  = 1;
88         state->vs_Xv  = 0;
89 }
90
91 static int
92 palmtx_pcmcia_configure_socket(struct soc_pcmcia_socket *skt,
93                                 const socket_state_t *state)
94 {
95         gpio_set_value(GPIO_NR_PALMTX_PCMCIA_POWER1, 1);
96         gpio_set_value(GPIO_NR_PALMTX_PCMCIA_POWER2, 1);
97         gpio_set_value(GPIO_NR_PALMTX_PCMCIA_RESET,
98                         !!(state->flags & SS_RESET));
99
100         return 0;
101 }
102
103 static void palmtx_pcmcia_socket_init(struct soc_pcmcia_socket *skt)
104 {
105 }
106
107 static void palmtx_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
108 {
109 }
110
111 static struct pcmcia_low_level palmtx_pcmcia_ops = {
112         .owner                  = THIS_MODULE,
113
114         .first                  = 0,
115         .nr                     = 1,
116
117         .hw_init                = palmtx_pcmcia_hw_init,
118         .hw_shutdown            = palmtx_pcmcia_hw_shutdown,
119
120         .socket_state           = palmtx_pcmcia_socket_state,
121         .configure_socket       = palmtx_pcmcia_configure_socket,
122
123         .socket_init            = palmtx_pcmcia_socket_init,
124         .socket_suspend         = palmtx_pcmcia_socket_suspend,
125 };
126
127 static struct platform_device *palmtx_pcmcia_device;
128
129 static int __init palmtx_pcmcia_init(void)
130 {
131         int ret;
132
133         if (!machine_is_palmtx())
134                 return -ENODEV;
135
136         palmtx_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1);
137         if (!palmtx_pcmcia_device)
138                 return -ENOMEM;
139
140         ret = platform_device_add_data(palmtx_pcmcia_device, &palmtx_pcmcia_ops,
141                                         sizeof(palmtx_pcmcia_ops));
142
143         if (!ret)
144                 ret = platform_device_add(palmtx_pcmcia_device);
145
146         if (ret)
147                 platform_device_put(palmtx_pcmcia_device);
148
149         return ret;
150 }
151
152 static void __exit palmtx_pcmcia_exit(void)
153 {
154         platform_device_unregister(palmtx_pcmcia_device);
155 }
156
157 module_init(palmtx_pcmcia_init);
158 module_exit(palmtx_pcmcia_exit);
159
160 MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>");
161 MODULE_DESCRIPTION("PCMCIA support for Palm T|X");
162 MODULE_ALIAS("platform:pxa2xx-pcmcia");
163 MODULE_LICENSE("GPL");