adc: spin_lock->mutex_lock
authorkfx <kfx@rock-chips.com>
Thu, 23 Aug 2012 03:11:46 +0000 (11:11 +0800)
committerkfx <kfx@rock-chips.com>
Thu, 23 Aug 2012 03:11:46 +0000 (11:11 +0800)
drivers/adc/adc_priv.h
drivers/adc/core.c
drivers/adc/plat/rk30_adc.c

index 078bf75dd1b481e6c0860cf958e39f563e0c430f..d7a3c7fd9ea83eecdb1c27b46f3bfa775d120fd7 100755 (executable)
 #include <linux/time.h>\r
 #include <linux/err.h>\r
 #include <linux/io.h>\r
+#include <linux/mutex.h>\r
 #include <linux/clk.h>\r
 #include <linux/workqueue.h>\r
 #include <linux/interrupt.h>\r
 #include <mach/board.h>\r
+#ifdef CONFIG_ADC_RK28\r
+#include "plat/rk28_adc.h"\r
+#endif\r
+#ifdef CONFIG_ADC_RK29\r
+#include "plat/rk29_adc.h"\r
+#endif\r
+#ifdef CONFIG_ADC_RK30\r
+#include "plat/rk30_adc.h"\r
+#endif\r
 \r
 #define ADC_READ_TMO    100 // ms\r
 \r
@@ -53,14 +63,15 @@ struct adc_ops {
 struct adc_host {\r
         struct list_head entry;\r
         struct list_head req_head;\r
+        struct list_head callback_head;\r
         unsigned int is_suspended;\r
         enum host_chn_mask mask;\r
         struct device *dev;\r
         unsigned int chn;\r
         spinlock_t lock;\r
+        struct mutex m_lock;\r
         unsigned int client_count;\r
        const struct adc_ops *ops;\r
-        struct work_struct work;\r
         unsigned long priv[0];\r
 };\r
 \r
index 04531911b722b12a39601792ff5ba80533c5f734..3e92c3a04c5bcb17c80552f64e8bcb03284e7caa 100755 (executable)
@@ -9,7 +9,6 @@
 
 struct list_head adc_host_head;
 
-static void adc_host_work(struct work_struct *work);
 struct adc_host *adc_alloc_host(struct device *dev, int extra, enum host_chn_mask mask)
 {
        struct adc_host *adc;
@@ -21,8 +20,9 @@ struct adc_host *adc_alloc_host(struct device *dev, int extra, enum host_chn_mas
        adc->dev = dev;
         adc->chn = -1;
         spin_lock_init(&adc->lock);
+        mutex_init(&adc->m_lock);
         INIT_LIST_HEAD(&adc->req_head);
-        INIT_WORK(&adc->work, adc_host_work);
+        INIT_LIST_HEAD(&adc->callback_head);
 
         list_add_tail(&adc->entry, &adc_host_head);
 
@@ -80,38 +80,32 @@ static inline void trigger_next_adc_job_if_any(struct adc_host *adc)
 {
         struct adc_request *req = NULL;
 
-        if(adc->chn != -1)
-                return;
         req = list_first_entry(&adc->req_head, struct adc_request, entry);
         if(req){
+                if(req->client == NULL){
+                        dev_err(adc->dev, "Abnormal: client piont is NULL...............\n");
+                        return;
+                }
                 adc->chn = req->client->chn;
                adc->ops->start(adc);
         }
 
        return;
 }
-static void adc_host_work(struct work_struct *work)
-{
-        unsigned long flags;
-       struct adc_host *adc =
-               container_of(work, struct adc_host, work);
 
-       spin_lock_irqsave(&adc->lock, flags);
-        trigger_next_adc_job_if_any(adc);
-       spin_unlock_irqrestore(&adc->lock, flags);
-}
 static int adc_request_add(struct adc_host *adc, struct adc_client *client)
 {
         struct adc_request *req = NULL;
 
         req = kzalloc(sizeof(struct adc_request), GFP_ATOMIC);
 
-        if(!req)
+        if(unlikely(!req))
                 return -ENOMEM;
         INIT_LIST_HEAD(&req->entry);
         req->client = client;
         list_add_tail(&req->entry, &adc->req_head);
-        trigger_next_adc_job_if_any(adc);
+        if(adc->chn == -1)
+                trigger_next_adc_job_if_any(adc);
         return 0;
 }
 static void
@@ -119,43 +113,59 @@ adc_sync_read_callback(struct adc_client *client, void *param, int result)
 {
         client->result = result;
 }
-static void adc_finished(struct adc_host *adc, int result)
+static void adc_callback(struct adc_host *adc)
 {
         struct adc_request *req = NULL, *n = NULL;
 
-        adc_dbg(adc->dev, "chn[%d] read value: %d\n", adc->chn, result);
+        list_for_each_entry_safe(req, n, &adc->callback_head, entry) {
+                if(req->client->flags & (1<<ADC_ASYNC_READ)){
+                        req->client->callback(req->client, req->client->callback_param, req->client->result);
+                }
+                if(req->client->flags & (1<<ADC_SYNC_READ)){
+                        adc_sync_read_callback(req->client, NULL, req->client->result);
+                        req->client->is_finished = 1;
+                        wake_up(&req->client->wait);
+                }
+                req->client->flags = 0;
+                list_del_init(&req->entry);
+                kfree(req);
+        }
+}
+void adc_finished(struct adc_host *adc, int result)
+{
+       unsigned long flags;
+        struct adc_request *req = NULL, *n = NULL;
+
         adc->ops->stop(adc);
+        udelay(SAMPLE_RATE);
+       spin_lock_irqsave(&adc->lock, flags);
         list_for_each_entry_safe(req, n, &adc->req_head, entry) {
                 if(req->client->chn == adc->chn){
-                        if(req->client->flags & (1<<ADC_ASYNC_READ)){
-                                req->client->callback(req->client, req->client->callback_param, result);
-                        }
-                        if(req->client->flags & (1<<ADC_SYNC_READ)){
-                                adc_sync_read_callback(req->client, NULL, result);
-                                req->client->is_finished = 1;
-                                wake_up(&req->client->wait);
-                        }
                         req->client->result = result;
-                        req->client->flags = 0;
-                        list_del_init(&req->entry);
-                        kfree(req);
+                        list_move_tail(&req->entry, &adc->callback_head);
                 }
         }
         adc->chn = -1;
+        if(!list_empty(&adc->req_head))
+                trigger_next_adc_job_if_any(adc);
+       spin_unlock_irqrestore(&adc->lock, flags);
+
+        adc_callback(adc);
 }
 void adc_core_irq_handle(struct adc_host *adc)
 {
-        unsigned long flags;
         int result = 0;
 
-       spin_lock_irqsave(&adc->lock, flags);
+        WARN_ON(adc->chn == -1);
+
+        mutex_lock(&adc->m_lock);
+
         result = adc->ops->read(adc);
+        adc_dbg(adc->dev, "chn[%d] read value: %d\n", adc->chn, result);
 
         adc_finished(adc, result);
 
-        if(!list_empty(&adc->req_head))
-                schedule_work(&adc->work);
-       spin_unlock_irqrestore(&adc->lock, flags);
+        mutex_unlock(&adc->m_lock);
 }
 
 int adc_host_read(struct adc_client *client, enum read_type type)
@@ -199,16 +209,16 @@ int adc_host_read(struct adc_client *client, enum read_type type)
        spin_unlock_irqrestore(&adc->lock, flags);
 
         tmo = wait_event_timeout(client->wait, ( client->is_finished == 1 ), msecs_to_jiffies(ADC_READ_TMO));
-       spin_lock_irqsave(&adc->lock, flags);
+        mutex_lock(&adc->m_lock);
         if(unlikely((tmo <= 0) && (client->is_finished == 0))) {
+                dev_err(adc->dev, "get adc value timeout.................................\n");
                 if(adc->ops->dump)
                         adc->ops->dump(adc);
-                dev_err(adc->dev, "get adc value timeout.................................\n");
                 adc_finished(adc, -1);
-               spin_unlock_irqrestore(&adc->lock, flags);
+                mutex_unlock(&adc->m_lock);
                 return -ETIMEDOUT;
         } 
-       spin_unlock_irqrestore(&adc->lock, flags);
+        mutex_unlock(&adc->m_lock);
 
         return client->result;
 }
index e7a427569a00586139e0547b251bc54fd406852a..359f275023c43368540d9169e129a1be395a0587 100755 (executable)
@@ -45,7 +45,6 @@ static void rk30_adc_stop(struct adc_host *adc)
        struct rk30_adc_device *dev  = adc_priv(adc);\r
        \r
        adc_writel(0, dev->regs + ADC_CTRL);\r
-        udelay(SAMPLE_RATE);\r
 }\r
 static int rk30_adc_read(struct adc_host *adc)\r
 {\r
@@ -122,7 +121,6 @@ static int rk30_adc_probe(struct platform_device *pdev)
        struct resource *res;\r
        int ret;\r
 \r
-        printk("%s: start\n", __func__);\r
        adc = adc_alloc_host(&pdev->dev, sizeof(struct rk30_adc_device), SARADC_CHN_MASK);\r
        if (!adc)\r
                return -ENOMEM;\r
@@ -261,7 +259,6 @@ static struct platform_driver rk30_adc_driver = {
 \r
 static int __init rk30_adc_init(void)\r
 {\r
-        printk("%s: start\n", __func__);\r
        return platform_driver_register(&rk30_adc_driver);\r
 }\r
 subsys_initcall(rk30_adc_init);\r