misc: ti-st: clean up st_host_wake driver
[linux-2.6.git] / drivers / misc / ti-st / st_host_wake.c
1 /*
2  *  Shared Transport Host wake up driver
3  *  For protocols registered over Shared Transport
4  *  Copyright (C) 2011-2012 Texas Instruments
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License version 2 as
8  *  published by the Free Software Foundation.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 #include <linux/module.h>
22 #include <linux/init.h>
23 #include <linux/interrupt.h>
24 #include <linux/platform_device.h>
25
26 #include <linux/ti_wilink_st.h>
27
28 #include <linux/regulator/consumer.h>
29
30 #define VERSION         "1.2"
31 #define FLAG_RESET      0x00
32 #define HOST_WAKE       0x01
33 #define IRQ_WAKE        0x02
34
35 #define CHANNEL_ACL     0x02
36 #define CHANNEL_EVT     0x04
37 #define CHANNEL_FM      0x08
38 #define CHANNEL_GPS     0x09
39 #define CHANNEL_NFC     0x0C
40
41 struct st_host_wake_info {
42         unsigned host_wake_irq;
43         struct regulator *vdd_3v3;
44         struct regulator *vdd_1v8;
45         unsigned int supp_proto_reg;
46 };
47
48 static unsigned long flags;
49 static struct st_host_wake_info *bsi;
50 static char  dev_id[12] = "st_host_wake";
51
52 void st_host_wake_notify(int chan_id, int reg_state)
53 {
54         /* HOST_WAKE to be set after all BT channels including CHANNEL_SCO
55          * is registered
56          */
57         if (chan_id == CHANNEL_ACL || chan_id == CHANNEL_EVT)
58                 return;
59
60 #ifndef CONFIG_ST_HOST_WAKE_GPS
61         if (chan_id == CHANNEL_GPS) {
62                 pr_info("CONFIG_ST_HOST_WAKE_GPS not set hence reject");
63                 return;
64         }
65 #endif
66
67 #ifndef CONFIG_ST_HOST_WAKE_FM
68         if (chan_id == CHANNEL_FM) {
69                 pr_info("CONFIG_ST_HOST_WAKE_FM not set hence reject");
70                 return;
71         }
72 #endif
73
74 #ifndef CONFIG_ST_HOST_WAKE_NFC
75         if (chan_id == CHANNEL_NFC) {
76                 pr_info("CONFIG_ST_HOST_WAKE_NFC not set hence reject");
77                 return;
78         }
79 #endif
80         switch (reg_state) {
81         case ST_PROTO_REGISTERED:
82                 pr_info("Channel %d registered", chan_id);
83                 bsi->supp_proto_reg++;
84                 set_bit(HOST_WAKE, &flags);
85                 pr_info("HOST_WAKE set");
86                 break;
87
88         case ST_PROTO_UNREGISTERED:
89                 pr_info("Channel %d un-registered", chan_id);
90                 bsi->supp_proto_reg--;
91
92                 if (!bsi->supp_proto_reg) {
93                         pr_info("All supported protocols un-registered");
94                         if (bsi && test_bit(IRQ_WAKE, &flags)) {
95                                 pr_info("disabling wake_irq after unregister");
96                                 disable_irq_wake(bsi->host_wake_irq);
97                                 clear_bit(IRQ_WAKE, &flags);
98                         }
99
100                         clear_bit(HOST_WAKE, &flags);
101                         pr_info("HOST_WAKE cleared");
102                 }
103                 break;
104
105         default:
106                 break;
107         }
108 }
109 EXPORT_SYMBOL(st_host_wake_notify);
110
111 void st_vltg_regulation(int state)
112 {
113         pr_info("%s with state %d", __func__, state);
114
115         if (ST_VLTG_REG_ENABLE == state) {
116                 if (bsi->vdd_3v3)
117                         regulator_enable(bsi->vdd_3v3);
118                 if (bsi->vdd_1v8)
119                         regulator_enable(bsi->vdd_1v8);
120
121         } else if (ST_VLTG_REG_DISABLE == state) {
122                 if (bsi->vdd_3v3)
123                         regulator_disable(bsi->vdd_3v3);
124                 if (bsi->vdd_1v8)
125                         regulator_disable(bsi->vdd_1v8);
126
127         } else {
128                 pr_warn("Unknown voltage regulation state");
129         }
130 }
131 EXPORT_SYMBOL(st_vltg_regulation);
132
133 static irqreturn_t st_host_wake_isr(int irq, void *dev_id)
134 {
135         pr_debug("%s", __func__);
136
137         return IRQ_HANDLED;
138 }
139
140 static int st_host_wake_probe(struct platform_device *pdev)
141 {
142         int ret = 0;
143         struct resource *res = NULL;
144
145         pr_info("TI Host Wakeup Driver [Ver %s]", VERSION);
146
147         bsi = kzalloc(sizeof(struct st_host_wake_info), GFP_KERNEL);
148         if (!bsi)
149                 return -ENOMEM;
150
151         bsi->vdd_3v3 = regulator_get(&pdev->dev, "vdd_st_3v3");
152         if (IS_ERR_OR_NULL(bsi->vdd_3v3)) {
153                 pr_warn("%s: regulator vdd_st_3v3 not available\n", __func__);
154                 bsi->vdd_3v3 = NULL;
155         }
156         bsi->vdd_1v8 = regulator_get(&pdev->dev, "vddio_st_1v8");
157         if (IS_ERR_OR_NULL(bsi->vdd_1v8)) {
158                 pr_warn("%s: regulator vddio_st_1v8 not available\n", __func__);
159                 bsi->vdd_1v8 = NULL;
160         }
161
162         res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
163                                                 "host_wake");
164         if (!res) {
165                 pr_err("couldn't find host_wake irq\n");
166                 ret = -ENODEV;
167                 goto free_bsi;
168         }
169
170         bsi->host_wake_irq = res->start;
171         clear_bit(IRQ_WAKE, &flags);
172
173         if (bsi->host_wake_irq < 0) {
174                 pr_err("couldn't find host_wake irq");
175                 ret = -ENODEV;
176                 goto free_bsi;
177         }
178
179         if (res->flags & IORESOURCE_IRQ_LOWEDGE)
180                 ret = request_irq(bsi->host_wake_irq, st_host_wake_isr,
181                                 IRQF_DISABLED | IRQF_TRIGGER_FALLING,
182                                 "bluetooth hostwake", dev_id);
183         else
184                 ret = request_irq(bsi->host_wake_irq, st_host_wake_isr,
185                                 IRQF_DISABLED | IRQF_TRIGGER_RISING,
186                                 "bluetooth hostwake", dev_id);
187
188         if (ret < 0) {
189                 pr_err("Couldn't acquire HOST_WAKE IRQ");
190                 goto free_bsi;
191         }
192
193         clear_bit(HOST_WAKE, &flags);
194         bsi->supp_proto_reg = 0;
195
196         goto finish;
197
198 free_bsi:
199         kfree(bsi);
200 finish:
201         return ret;
202 }
203
204 static int st_host_wake_remove(struct platform_device *pdev)
205 {
206         pr_debug("%s", __func__);
207
208         free_irq(bsi->host_wake_irq, dev_id);
209
210         if (bsi->vdd_3v3)
211                 regulator_put(bsi->vdd_3v3);
212         if (bsi->vdd_1v8)
213                 regulator_put(bsi->vdd_1v8);
214
215         kfree(bsi);
216
217         return 0;
218 }
219
220 static int st_host_wake_resume(struct platform_device *pdev)
221 {
222         pr_info("%s", __func__);
223
224         if (test_bit(HOST_WAKE, &flags) && test_bit(IRQ_WAKE, &flags)) {
225                 pr_info("disable the host_wake irq");
226                 disable_irq_wake(bsi->host_wake_irq);
227                 clear_bit(IRQ_WAKE, &flags);
228         }
229
230         return 0;
231 }
232
233 static int st_host_wake_suspend(void)
234 {
235         int retval = 0;
236
237         pr_info("%s", __func__);
238
239         if (test_bit(HOST_WAKE, &flags) && (!test_bit(IRQ_WAKE, &flags))) {
240                 retval = enable_irq_wake(bsi->host_wake_irq);
241                 if (retval < 0) {
242                         pr_err("Failed to enable HOST_WAKE irq (%d)", retval);
243                         goto fail;
244                 }
245                 set_bit(IRQ_WAKE, &flags);
246                 pr_info("enabled the host_wake irq");
247         }
248 fail:
249         return retval;
250 }
251
252
253 static struct platform_driver st_host_wake_driver = {
254         .probe = st_host_wake_probe,
255         .remove = st_host_wake_remove,
256         .suspend = st_host_wake_suspend,
257         .resume = st_host_wake_resume,
258         .driver = {
259                 .name = "st_host_wake",
260                 .owner = THIS_MODULE,
261         },
262 };
263
264 static int __init st_host_wake_init(void)
265 {
266         int retval = 0;
267
268         pr_debug("%s", __func__);
269
270         retval = platform_driver_register(&st_host_wake_driver);
271         if (retval)
272                 pr_err("st_host_wake_init failed");
273
274         return retval;
275 }
276
277 static void __exit st_host_wake_exit(void)
278 {
279         pr_debug("%s", __func__);
280
281         if (bsi == NULL)
282                 return;
283
284         platform_driver_unregister(&st_host_wake_driver);
285 }
286
287 module_init(st_host_wake_init);
288 module_exit(st_host_wake_exit);
289
290 MODULE_DESCRIPTION("TI Host Wakeup Driver [Ver %s]" VERSION);
291 #ifdef MODULE_LICENSE
292 MODULE_LICENSE("GPL");
293 #endif