Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc
[pandora-kernel.git] / drivers / mmc / core / sdio_irq.c
1 /*
2  * linux/drivers/mmc/core/sdio_irq.c
3  *
4  * Author:      Nicolas Pitre
5  * Created:     June 18, 2007
6  * Copyright:   MontaVista Software Inc.
7  *
8  * Copyright 2008 Pierre Ossman
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or (at
13  * your option) any later version.
14  */
15
16 #include <linux/kernel.h>
17 #include <linux/sched.h>
18 #include <linux/kthread.h>
19 #include <linux/wait.h>
20 #include <linux/delay.h>
21
22 #include <linux/mmc/core.h>
23 #include <linux/mmc/host.h>
24 #include <linux/mmc/card.h>
25 #include <linux/mmc/sdio.h>
26 #include <linux/mmc/sdio_func.h>
27
28 #include "sdio_ops.h"
29
30 static int process_sdio_pending_irqs(struct mmc_card *card)
31 {
32         int i, ret, count;
33         unsigned char pending;
34         struct sdio_func *func;
35
36         /*
37          * Optimization, if there is only 1 function interrupt registered
38          * call irq handler directly
39          */
40         func = card->sdio_single_irq;
41         if (func) {
42                 func->irq_handler(func);
43                 return 1;
44         }
45
46         ret = mmc_io_rw_direct(card, 0, 0, SDIO_CCCR_INTx, 0, &pending);
47         if (ret) {
48                 printk(KERN_DEBUG "%s: error %d reading SDIO_CCCR_INTx\n",
49                        mmc_card_id(card), ret);
50                 return ret;
51         }
52
53         count = 0;
54         for (i = 1; i <= 7; i++) {
55                 if (pending & (1 << i)) {
56                         func = card->sdio_func[i - 1];
57                         if (!func) {
58                                 printk(KERN_WARNING "%s: pending IRQ for "
59                                         "non-existent function\n",
60                                         mmc_card_id(card));
61                                 ret = -EINVAL;
62                         } else if (func->irq_handler) {
63                                 func->irq_handler(func);
64                                 count++;
65                         } else {
66                                 printk(KERN_WARNING "%s: pending IRQ with no handler\n",
67                                        sdio_func_id(func));
68                                 ret = -EINVAL;
69                         }
70                 }
71         }
72
73         if (count)
74                 return count;
75
76         return ret;
77 }
78
79 static int sdio_irq_thread(void *_host)
80 {
81         struct mmc_host *host = _host;
82         struct sched_param param = { .sched_priority = 1 };
83         unsigned long period, idle_period;
84         int ret;
85
86         sched_setscheduler(current, SCHED_FIFO, &param);
87
88         /*
89          * We want to allow for SDIO cards to work even on non SDIO
90          * aware hosts.  One thing that non SDIO host cannot do is
91          * asynchronous notification of pending SDIO card interrupts
92          * hence we poll for them in that case.
93          */
94         idle_period = msecs_to_jiffies(10);
95         period = (host->caps & MMC_CAP_SDIO_IRQ) ?
96                 MAX_SCHEDULE_TIMEOUT : idle_period;
97
98         pr_debug("%s: IRQ thread started (poll period = %lu jiffies)\n",
99                  mmc_hostname(host), period);
100
101         do {
102                 /*
103                  * We claim the host here on drivers behalf for a couple
104                  * reasons:
105                  *
106                  * 1) it is already needed to retrieve the CCCR_INTx;
107                  * 2) we want the driver(s) to clear the IRQ condition ASAP;
108                  * 3) we need to control the abort condition locally.
109                  *
110                  * Just like traditional hard IRQ handlers, we expect SDIO
111                  * IRQ handlers to be quick and to the point, so that the
112                  * holding of the host lock does not cover too much work
113                  * that doesn't require that lock to be held.
114                  */
115                 ret = __mmc_claim_host(host, &host->sdio_irq_thread_abort);
116                 if (ret)
117                         break;
118                 ret = process_sdio_pending_irqs(host->card);
119                 mmc_release_host(host);
120
121                 /*
122                  * Give other threads a chance to run in the presence of
123                  * errors.
124                  */
125                 if (ret < 0) {
126                         set_current_state(TASK_INTERRUPTIBLE);
127                         if (!kthread_should_stop())
128                                 schedule_timeout(HZ);
129                         set_current_state(TASK_RUNNING);
130                 }
131
132                 /*
133                  * Adaptive polling frequency based on the assumption
134                  * that an interrupt will be closely followed by more.
135                  * This has a substantial benefit for network devices.
136                  */
137                 if (!(host->caps & MMC_CAP_SDIO_IRQ)) {
138                         if (ret > 0)
139                                 period /= 2;
140                         else {
141                                 period++;
142                                 if (period > idle_period)
143                                         period = idle_period;
144                         }
145                 }
146
147                 set_current_state(TASK_INTERRUPTIBLE);
148                 if (host->caps & MMC_CAP_SDIO_IRQ)
149                         host->ops->enable_sdio_irq(host, 1);
150                 if (!kthread_should_stop())
151                         schedule_timeout(period);
152                 set_current_state(TASK_RUNNING);
153         } while (!kthread_should_stop());
154
155         if (host->caps & MMC_CAP_SDIO_IRQ)
156                 host->ops->enable_sdio_irq(host, 0);
157
158         pr_debug("%s: IRQ thread exiting with code %d\n",
159                  mmc_hostname(host), ret);
160
161         return ret;
162 }
163
164 static int sdio_card_irq_get(struct mmc_card *card)
165 {
166         struct mmc_host *host = card->host;
167
168         WARN_ON(!host->claimed);
169
170         if (!host->sdio_irqs++) {
171                 atomic_set(&host->sdio_irq_thread_abort, 0);
172                 host->sdio_irq_thread =
173                         kthread_run(sdio_irq_thread, host, "ksdioirqd/%s",
174                                 mmc_hostname(host));
175                 if (IS_ERR(host->sdio_irq_thread)) {
176                         int err = PTR_ERR(host->sdio_irq_thread);
177                         host->sdio_irqs--;
178                         return err;
179                 }
180         }
181
182         return 0;
183 }
184
185 static int sdio_card_irq_put(struct mmc_card *card)
186 {
187         struct mmc_host *host = card->host;
188
189         WARN_ON(!host->claimed);
190         BUG_ON(host->sdio_irqs < 1);
191
192         if (!--host->sdio_irqs) {
193                 atomic_set(&host->sdio_irq_thread_abort, 1);
194                 kthread_stop(host->sdio_irq_thread);
195         }
196
197         return 0;
198 }
199
200 /* If there is only 1 function registered set sdio_single_irq */
201 static void sdio_single_irq_set(struct mmc_card *card)
202 {
203         struct sdio_func *func;
204         int i;
205
206         card->sdio_single_irq = NULL;
207         if ((card->host->caps & MMC_CAP_SDIO_IRQ) &&
208             card->host->sdio_irqs == 1)
209                 for (i = 0; i < card->sdio_funcs; i++) {
210                        func = card->sdio_func[i];
211                        if (func && func->irq_handler) {
212                                card->sdio_single_irq = func;
213                                break;
214                        }
215                }
216 }
217
218 /**
219  *      sdio_claim_irq - claim the IRQ for a SDIO function
220  *      @func: SDIO function
221  *      @handler: IRQ handler callback
222  *
223  *      Claim and activate the IRQ for the given SDIO function. The provided
224  *      handler will be called when that IRQ is asserted.  The host is always
225  *      claimed already when the handler is called so the handler must not
226  *      call sdio_claim_host() nor sdio_release_host().
227  */
228 int sdio_claim_irq(struct sdio_func *func, sdio_irq_handler_t *handler)
229 {
230         int ret;
231         unsigned char reg;
232
233         BUG_ON(!func);
234         BUG_ON(!func->card);
235
236         pr_debug("SDIO: Enabling IRQ for %s...\n", sdio_func_id(func));
237
238         if (func->irq_handler) {
239                 pr_debug("SDIO: IRQ for %s already in use.\n", sdio_func_id(func));
240                 return -EBUSY;
241         }
242
243         ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
244         if (ret)
245                 return ret;
246
247         reg |= 1 << func->num;
248
249         reg |= 1; /* Master interrupt enable */
250
251         ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
252         if (ret)
253                 return ret;
254
255         func->irq_handler = handler;
256         ret = sdio_card_irq_get(func->card);
257         if (ret)
258                 func->irq_handler = NULL;
259         sdio_single_irq_set(func->card);
260
261         return ret;
262 }
263 EXPORT_SYMBOL_GPL(sdio_claim_irq);
264
265 /**
266  *      sdio_release_irq - release the IRQ for a SDIO function
267  *      @func: SDIO function
268  *
269  *      Disable and release the IRQ for the given SDIO function.
270  */
271 int sdio_release_irq(struct sdio_func *func)
272 {
273         int ret;
274         unsigned char reg;
275
276         BUG_ON(!func);
277         BUG_ON(!func->card);
278
279         pr_debug("SDIO: Disabling IRQ for %s...\n", sdio_func_id(func));
280
281         if (func->irq_handler) {
282                 func->irq_handler = NULL;
283                 sdio_card_irq_put(func->card);
284                 sdio_single_irq_set(func->card);
285         }
286
287         ret = mmc_io_rw_direct(func->card, 0, 0, SDIO_CCCR_IENx, 0, &reg);
288         if (ret)
289                 return ret;
290
291         reg &= ~(1 << func->num);
292
293         /* Disable master interrupt with the last function interrupt */
294         if (!(reg & 0xFE))
295                 reg = 0;
296
297         ret = mmc_io_rw_direct(func->card, 1, 0, SDIO_CCCR_IENx, reg, NULL);
298         if (ret)
299                 return ret;
300
301         return 0;
302 }
303 EXPORT_SYMBOL_GPL(sdio_release_irq);
304