diff options
author | Zhou Jingyu <b02241@shlinux1.ap.freescale.net> | 2009-12-24 16:37:22 +0800 |
---|---|---|
committer | Zhou Jingyu <b02241@shlinux1.ap.freescale.net> | 2009-12-28 15:28:13 +0800 |
commit | 6d42e87cd0d03698c6982080652f9d38449073ad (patch) | |
tree | 6405e2eacd046e067bf141402ef183958f494f26 | |
parent | 8b85700c6135228034200996c8df9ec2b6e30cf7 (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.c | 4 | ||||
-rw-r--r-- | drivers/mxc/pmic/core/pmic.h | 4 | ||||
-rw-r--r-- | drivers/mxc/pmic/core/pmic_common.c | 67 | ||||
-rw-r--r-- | drivers/mxc/pmic/core/pmic_core_i2c.c | 25 | ||||
-rw-r--r-- | drivers/mxc/pmic/core/pmic_core_spi.c | 16 |
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(); |