Merge branch 'for-linus' of git://git.kernel.dk/linux-2.6-block
[safe/jmp/linux-2.6] / drivers / mfd / pcf50633-adc.c
index c2d05be..fe8f922 100644 (file)
@@ -17,6 +17,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/device.h>
@@ -73,15 +74,10 @@ static void trigger_next_adc_job_if_any(struct pcf50633 *pcf)
        struct pcf50633_adc *adc = __to_adc(pcf);
        int head;
 
-       mutex_lock(&adc->queue_mutex);
-
        head = adc->queue_head;
 
-       if (!adc->queue[head]) {
-               mutex_unlock(&adc->queue_mutex);
+       if (!adc->queue[head])
                return;
-       }
-       mutex_unlock(&adc->queue_mutex);
 
        adc_setup(pcf, adc->queue[head]->mux, adc->queue[head]->avg);
 }
@@ -99,16 +95,17 @@ adc_enqueue_request(struct pcf50633 *pcf, struct pcf50633_adc_request *req)
 
        if (adc->queue[tail]) {
                mutex_unlock(&adc->queue_mutex);
+               dev_err(pcf->dev, "ADC queue is full, dropping request\n");
                return -EBUSY;
        }
 
        adc->queue[tail] = req;
+       if (head == tail)
+               trigger_next_adc_job_if_any(pcf);
        adc->queue_tail = (tail + 1) & (PCF50633_MAX_ADC_FIFO_DEPTH - 1);
 
        mutex_unlock(&adc->queue_mutex);
 
-       trigger_next_adc_job_if_any(pcf);
-
        return 0;
 }
 
@@ -124,6 +121,7 @@ pcf50633_adc_sync_read_callback(struct pcf50633 *pcf, void *param, int result)
 int pcf50633_adc_sync_read(struct pcf50633 *pcf, int mux, int avg)
 {
        struct pcf50633_adc_request *req;
+       int err;
 
        /* req is freed when the result is ready, in interrupt handler */
        req = kzalloc(sizeof(*req), GFP_KERNEL);
@@ -136,9 +134,13 @@ int pcf50633_adc_sync_read(struct pcf50633 *pcf, int mux, int avg)
        req->callback_param = req;
 
        init_completion(&req->completion);
-       adc_enqueue_request(pcf, req);
+       err = adc_enqueue_request(pcf, req);
+       if (err)
+               return err;
+
        wait_for_completion(&req->completion);
 
+       /* FIXME by this time req might be already freed */
        return req->result;
 }
 EXPORT_SYMBOL_GPL(pcf50633_adc_sync_read);
@@ -159,9 +161,7 @@ int pcf50633_adc_async_read(struct pcf50633 *pcf, int mux, int avg,
        req->callback = callback;
        req->callback_param = callback_param;
 
-       adc_enqueue_request(pcf, req);
-
-       return 0;
+       return adc_enqueue_request(pcf, req);
 }
 EXPORT_SYMBOL_GPL(pcf50633_adc_async_read);
 
@@ -184,7 +184,7 @@ static void pcf50633_adc_irq(int irq, void *data)
        struct pcf50633_adc *adc = data;
        struct pcf50633 *pcf = adc->pcf;
        struct pcf50633_adc_request *req;
-       int head;
+       int head, res;
 
        mutex_lock(&adc->queue_mutex);
        head = adc->queue_head;
@@ -199,27 +199,27 @@ static void pcf50633_adc_irq(int irq, void *data)
        adc->queue_head = (head + 1) &
                                      (PCF50633_MAX_ADC_FIFO_DEPTH - 1);
 
+       res = adc_result(pcf);
+       trigger_next_adc_job_if_any(pcf);
+
        mutex_unlock(&adc->queue_mutex);
 
-       req->callback(pcf, req->callback_param, adc_result(pcf));
+       req->callback(pcf, req->callback_param, res);
        kfree(req);
-
-       trigger_next_adc_job_if_any(pcf);
 }
 
 static int __devinit pcf50633_adc_probe(struct platform_device *pdev)
 {
-       struct pcf50633_subdev_pdata *pdata = pdev->dev.platform_data;
        struct pcf50633_adc *adc;
 
        adc = kzalloc(sizeof(*adc), GFP_KERNEL);
        if (!adc)
                return -ENOMEM;
 
-       adc->pcf = pdata->pcf;
+       adc->pcf = dev_to_pcf50633(pdev->dev.parent);
        platform_set_drvdata(pdev, adc);
 
-       pcf50633_register_irq(pdata->pcf, PCF50633_IRQ_ADCRDY,
+       pcf50633_register_irq(adc->pcf, PCF50633_IRQ_ADCRDY,
                                        pcf50633_adc_irq, adc);
 
        mutex_init(&adc->queue_mutex);