summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZhou Jingyu <b02241@shlinux1.ap.freescale.net>2009-12-24 16:37:22 +0800
committerZhou Jingyu <b02241@shlinux1.ap.freescale.net>2009-12-28 15:28:13 +0800
commit6d42e87cd0d03698c6982080652f9d38449073ad (patch)
tree6405e2eacd046e067bf141402ef183958f494f26
parent8b85700c6135228034200996c8df9ec2b6e30cf7 (diff)
ENGR00116787 change pmic event handling method
use level irq for pmic event handling to avoid potential pmic event lost Signed-off-by: Zhou Jingyu <Jingyu.Zhou@freescale.com>
-rw-r--r--drivers/mxc/pmic/core/mc13892.c4
-rw-r--r--drivers/mxc/pmic/core/pmic.h4
-rw-r--r--drivers/mxc/pmic/core/pmic_common.c67
-rw-r--r--drivers/mxc/pmic/core/pmic_core_i2c.c25
-rw-r--r--drivers/mxc/pmic/core/pmic_core_spi.c16
5 files changed, 74 insertions, 42 deletions
diff --git a/drivers/mxc/pmic/core/mc13892.c b/drivers/mxc/pmic/core/mc13892.c
index 34ceec59221e..9f232a4f5718 100644
--- a/drivers/mxc/pmic/core/mc13892.c
+++ b/drivers/mxc/pmic/core/mc13892.c
@@ -74,7 +74,7 @@ int pmic_i2c_24bit_read(struct i2c_client *client, unsigned int reg_num,
*value = buf[0] << 16 | buf[1] << 8 | buf[2];
return ret;
} else {
- pr_debug("24bit read error, ret = %d\n", ret);
+ pr_err("24bit read error, ret = %d\n", ret);
return -1; /* return -1 on failure */
}
}
@@ -96,6 +96,8 @@ int pmic_i2c_24bit_write(struct i2c_client *client,
break;
msleep(1);
}
+ if (i == MC13892_I2C_RETRY_TIMES)
+ pr_err("24bit write error, ret = %d\n", ret);
return ret;
}
diff --git a/drivers/mxc/pmic/core/pmic.h b/drivers/mxc/pmic/core/pmic.h
index b1382a34e850..770fbb72a044 100644
--- a/drivers/mxc/pmic/core/pmic.h
+++ b/drivers/mxc/pmic/core/pmic.h
@@ -131,4 +131,8 @@ static inline PMIC_STATUS pmic_fix_arbitration(struct spi_device *spi)
void *pmic_alloc_data(struct device *dev);
+int pmic_start_event_thread(int irq_num);
+
+void pmic_stop_event_thread(void);
+
#endif /* __PMIC_H__ */
diff --git a/drivers/mxc/pmic/core/pmic_common.c b/drivers/mxc/pmic/core/pmic_common.c
index 55f34b29cd93..fe907ead762c 100644
--- a/drivers/mxc/pmic/core/pmic_common.c
+++ b/drivers/mxc/pmic/core/pmic_common.c
@@ -29,6 +29,7 @@
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/kthread.h>
#include <linux/pmic_external.h>
#include <linux/pmic_status.h>
@@ -41,31 +42,59 @@
*/
pmic_version_t mxc_pmic_version;
unsigned int active_events[MAX_ACTIVE_EVENTS];
-struct workqueue_struct *pmic_event_wq;
-void pmic_bh_handler(struct work_struct *work);
-/*!
- * Bottom half handler of PMIC event handling.
- */
-DECLARE_WORK(pmic_ws, pmic_bh_handler);
-/*!
- * This function is the bottom half handler of the PMIC interrupt.
- * It checks for active events and launches callback for the
- * active events.
- */
-void pmic_bh_handler(struct work_struct *work)
+static struct completion event_completion;
+static struct task_struct *tstask;
+
+static int pmic_event_thread_func(void *v)
{
unsigned int loop;
unsigned int count = 0;
+ unsigned int irq = (int)v;
+
+ while (1) {
+ wait_for_completion_interruptible(
+ &event_completion);
+ if (kthread_should_stop())
+ break;
- count = pmic_get_active_events(active_events);
- pr_debug("active events number %d\n", count);
+ count = pmic_get_active_events(
+ active_events);
+ pr_debug("active events number %d\n", count);
- for (loop = 0; loop < count; loop++)
- pmic_event_callback(active_events[loop]);
+ for (loop = 0; loop < count; loop++)
+ pmic_event_callback(
+ active_events[loop]);
+ enable_irq(irq);
+ }
+
+ return 0;
+}
- return;
+int pmic_start_event_thread(int irq_num)
+{
+ int ret = 0;
+
+ if (tstask)
+ return ret;
+
+ init_completion(&event_completion);
+
+ tstask = kthread_run(pmic_event_thread_func,
+ (void *)irq_num, "pmic-event-thread");
+ ret = IS_ERR(tstask) ? -1 : 0;
+ if (IS_ERR(tstask))
+ tstask = NULL;
+ return ret;
+}
+
+void pmic_stop_event_thread(void)
+{
+ if (tstask) {
+ complete(&event_completion);
+ kthread_stop(tstask);
+ }
}
/*!
@@ -79,8 +108,8 @@ void pmic_bh_handler(struct work_struct *work)
*/
irqreturn_t pmic_irq_handler(int irq, void *dev_id)
{
- /* prepare a task */
- queue_work(pmic_event_wq, &pmic_ws);
+ disable_irq_nosync(irq);
+ complete(&event_completion);
return IRQ_HANDLED;
}
diff --git a/drivers/mxc/pmic/core/pmic_core_i2c.c b/drivers/mxc/pmic/core/pmic_core_i2c.c
index d529891973cd..ef32386f85ad 100644
--- a/drivers/mxc/pmic/core/pmic_core_i2c.c
+++ b/drivers/mxc/pmic/core/pmic_core_i2c.c
@@ -53,10 +53,8 @@
*/
struct i2c_client *mc13892_client;
-extern struct workqueue_struct *pmic_event_wq;
extern pmic_version_t mxc_pmic_version;
extern irqreturn_t pmic_irq_handler(int irq, void *dev_id);
-
/*
* Platform device structure for PMIC client drivers
*/
@@ -245,18 +243,21 @@ static int __devinit pmic_probe(struct i2c_client *client,
if (ret != PMIC_SUCCESS)
return PMIC_ERROR;
- pmic_event_wq = create_workqueue("mc13892");
- if (!pmic_event_wq) {
- pr_err("mc13892 pmic driver init: fail to create work queue");
- return -EFAULT;
- }
-
- /* Set and install PMIC IRQ handler */
pmic_irq = (int)(client->irq);
if (pmic_irq == 0)
return PMIC_ERROR;
- set_irq_type(pmic_irq, IRQF_TRIGGER_RISING);
+ ret = pmic_start_event_thread(pmic_irq);
+ if (ret) {
+ pr_err("mc13892 pmic driver init: \
+ fail to start event thread\n");
+ return PMIC_ERROR;
+ }
+
+ /* Set and install PMIC IRQ handler */
+
+ set_irq_type(pmic_irq, IRQF_TRIGGER_HIGH);
+
ret =
request_irq(pmic_irq, pmic_irq_handler, 0, "PMIC_IRQ",
0);
@@ -288,9 +289,7 @@ static int pmic_remove(struct i2c_client *client)
{
int pmic_irq = (int)(client->irq);
- if (pmic_event_wq)
- destroy_workqueue(pmic_event_wq);
-
+ pmic_stop_event_thread();
free_irq(pmic_irq, 0);
pmic_pdev_unregister();
return 0;
diff --git a/drivers/mxc/pmic/core/pmic_core_spi.c b/drivers/mxc/pmic/core/pmic_core_spi.c
index 4cc9eedec9de..300ae9aafdaa 100644
--- a/drivers/mxc/pmic/core/pmic_core_spi.c
+++ b/drivers/mxc/pmic/core/pmic_core_spi.c
@@ -88,7 +88,6 @@ extern void pmic_event_callback(type_event event);
extern void gpio_pmic_active(void);
extern irqreturn_t pmic_irq_handler(int irq, void *dev_id);
extern pmic_version_t mxc_pmic_version;
-extern struct workqueue_struct *pmic_event_wq;
/*!
* This function registers platform device structures for
@@ -192,16 +191,17 @@ static int __devinit pmic_probe(struct spi_device *spi)
return PMIC_ERROR;
}
- pmic_event_wq = create_workqueue("pmic_spi");
- if (!pmic_event_wq) {
- pr_err("pmic driver init: fail to create work queue");
+ ret = pmic_start_event_thread(spi->irq);
+ if (ret) {
+ pr_err("mc13892 pmic driver init: \
+ fail to start event thread\n");
kfree(spi_get_drvdata(spi));
spi_set_drvdata(spi, NULL);
- return -EFAULT;
+ return PMIC_ERROR;
}
/* Set and install PMIC IRQ handler */
- set_irq_type(spi->irq, IRQF_TRIGGER_RISING);
+ set_irq_type(spi->irq, IRQF_TRIGGER_HIGH);
ret = request_irq(spi->irq, pmic_irq_handler, 0, "PMIC_IRQ", 0);
if (ret) {
kfree(spi_get_drvdata(spi));
@@ -239,9 +239,7 @@ static int __devinit pmic_probe(struct spi_device *spi)
*/
static int __devexit pmic_remove(struct spi_device *spi)
{
- if (pmic_event_wq)
- destroy_workqueue(pmic_event_wq);
-
+ pmic_stop_event_thread();
free_irq(spi->irq, 0);
pmic_pdev_unregister();