summaryrefslogtreecommitdiff
path: root/drivers/mfd/m4sensorhub-irq.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mfd/m4sensorhub-irq.c')
-rw-r--r--drivers/mfd/m4sensorhub-irq.c675
1 files changed, 675 insertions, 0 deletions
diff --git a/drivers/mfd/m4sensorhub-irq.c b/drivers/mfd/m4sensorhub-irq.c
new file mode 100644
index 00000000000..56b9504fecd
--- /dev/null
+++ b/drivers/mfd/m4sensorhub-irq.c
@@ -0,0 +1,675 @@
+/*
+ * Copyright (C) 2012 Motorola, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ * 02111-1307, USA
+ */
+
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/wakelock.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <linux/m4sensorhub.h>
+
+#ifdef CONFIG_PM_DEEPSLEEP
+#include <linux/suspend.h>
+#endif
+
+#define NUM_INT_REGS 2
+#define NUM_INTS_PER_REG 8
+#define NUM_INTS_LAST_REG (((M4SH_IRQ__NUM-1)%NUM_INTS_PER_REG)+1)
+#define INTR_VALID_BITS(n) (unsigned char)((1 << (n)) - 1)
+
+#define EVENT_MASK(event) (1 << ((event) % NUM_INTS_PER_REG))
+
+#define DBG_BUF_LINE_LEN 80
+
+/* --------------- Global Declarations -------------- */
+
+/* ------------ Local Function Prototypes ----------- */
+static int m4sensorhub_irq_disable_all(struct m4sensorhub_data *m4sensorhub);
+static unsigned short get_enable_reg(enum m4sensorhub_irqs event);
+static void irq_work_func(struct work_struct *work);
+#ifdef CONFIG_DEBUG_FS
+static int m4sensorhub_dbg_irq_open(struct inode *inode, struct file *file);
+#endif
+static void m4sensorhub_irq_restore(struct m4sensorhub_data *m4sensorhub,\
+ void *data);
+
+/* ---------------- Local Declarations -------------- */
+
+static const char *irq_name[] = {
+ [M4SH_IRQ_TMP_DATA_READY] = "TMP_DATA_READY",
+ [M4SH_IRQ_PRESSURE_DATA_READY] = "PRES_DATA_READY",
+ [M4SH_IRQ_GYRO_DATA_READY] = "GYRO_DATA_READY",
+ [M4SH_IRQ_PEDOMETER_DATA_READY] = "PEDO_DATA_READY",
+ [M4SH_IRQ_COMPASS_DATA_READY] = "COMPASS_DATA_READY",
+ [M4SH_IRQ_FUSION_DATA_READY] = "FUSION_DATA_READY",
+ [M4SH_IRQ_ACCEL_DATA_READY] = "ACCEL_DATA_READY",
+ [M4SH_IRQ_GESTURE_DETECTED] = "GESTURE_DETECTED",
+ [M4SH_IRQ_STILL_DETECTED] = "STILL_DETECTED",
+ [M4SH_IRQ_MOTION_DETECTED] = "MOTION_DETECTED",
+ [M4SH_IRQ_ACTIVITY_CHANGE] = "ACTIVITY_CHANGE",
+ [M4SH_IRQ_DLCMD_RESP_READY] = "DLCMD_RESP_READY",
+ [M4SH_IRQ_MIC_DATA_READY] = "MIC_DATA_READY",
+ [M4SH_IRQ_WRIST_READY] = "WRIST_READY",
+ [M4SH_IRQ_PASSIVE_BUFFER_FULL] = "PASSIVE_BUFFER_FULL",
+};
+
+/* -------------- Local Data Structures ------------- */
+
+struct m4sensorhub_event_handler {
+ void (*func)(enum m4sensorhub_irqs, void *);
+ void *data;
+};
+
+struct m4sensorhub_irq_info {
+ uint8_t registered;
+ uint8_t enabled;
+ uint32_t ena_fired;
+ uint32_t disa_fired;
+};
+
+struct m4sensorhub_irqdata {
+ struct mutex lock; /* lock event handlers and data */
+ struct work_struct work;
+ struct workqueue_struct *workqueue;
+ struct m4sensorhub_data *m4sensorhub;
+ struct m4sensorhub_event_handler event_handler[M4SH_IRQ__NUM];
+ struct m4sensorhub_irq_info irq_info[M4SH_IRQ__NUM];
+ struct wake_lock wake_lock;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *debugfs;
+#endif
+};
+
+
+static const struct {
+ enum m4sensorhub_reg status_reg;
+ enum m4sensorhub_reg enable_reg;
+ unsigned char valid_bits;
+} int_registers[NUM_INT_REGS] = {
+ {M4SH_REG_GENERAL_INTERRUPT0STATUS,
+ M4SH_REG_GENERAL_INTERRUPT0ENABLE,
+ INTR_VALID_BITS(NUM_INTS_PER_REG)},
+ {M4SH_REG_GENERAL_INTERRUPT1STATUS,
+ M4SH_REG_GENERAL_INTERRUPT1ENABLE,
+ INTR_VALID_BITS(NUM_INTS_LAST_REG)},
+};
+
+static irqreturn_t event_isr(int irq, void *data)
+{
+ /* Interrupts are left enabled; if multiple interrupts arrive, there
+ * will be multiple jobs in the workqueue. In this case, the first
+ * job in the workqueue may service multple interrupts and
+ * susbsequent jobs will have no interrupts left to service.
+ */
+ struct m4sensorhub_irqdata *irq_data = data;
+ wake_lock(&irq_data->wake_lock);
+ queue_work(irq_data->workqueue, &irq_data->work);
+
+ return IRQ_HANDLED;
+}
+
+static struct mrsensorhub_irq_dbg {
+ unsigned short en_ints[NUM_INT_REGS];
+ unsigned char suspend;
+ unsigned char wakeup;
+} irq_dbg_info;
+
+#ifdef CONFIG_DEBUG_FS
+static const struct file_operations debug_fops = {
+ .open = m4sensorhub_dbg_irq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+#endif
+
+/* -------------- Global Functions ----------------- */
+
+/* m4sensorhub_irq_init()
+
+ Intialize M4 sensor hub IRQ subsystem
+
+ Returns 0 on success. Returns negative error code on failure
+
+ m4sensorhub - pointer to the main m4sensorhub data struct
+*/
+
+int m4sensorhub_irq_init(struct m4sensorhub_data *m4sensorhub)
+{
+ int retval;
+ struct i2c_client *i2c = m4sensorhub->i2c_client;
+ struct m4sensorhub_irqdata *data;
+
+ data = kzalloc(sizeof(struct m4sensorhub_irqdata), GFP_KERNEL);
+ if (!data) {
+ KDEBUG(M4SH_ERROR, "m4sensorhub: Memory error in irq_init\n");
+ retval = -ENOMEM;
+ goto done;
+ }
+
+ KDEBUG(M4SH_INFO, "m4sensorhub: %u IRQs with valid_bits %02X%02X\n",\
+ M4SH_IRQ__NUM, int_registers[1].valid_bits,\
+ int_registers[0].valid_bits);
+ retval = m4sensorhub_irq_disable_all(m4sensorhub);
+ if (retval) {
+ KDEBUG(M4SH_ERROR, "m4sensorhub: Failed disable all irqs\n");
+ goto err_free;
+ }
+
+ data->workqueue = create_workqueue("m4sensorhub_irq");
+ if (data->workqueue == NULL) {
+ KDEBUG(M4SH_ERROR, "m4sensorhub: IRQ Workqueue init failure\n");
+ retval = -ENOMEM;
+ goto err_free;
+ }
+ INIT_WORK(&data->work, irq_work_func);
+
+ mutex_init(&data->lock);
+
+ wake_lock_init(&data->wake_lock, WAKE_LOCK_SUSPEND, "m4sensorhub-irq");
+
+ retval = request_irq(i2c->irq, event_isr, IRQF_DISABLED |
+ IRQF_TRIGGER_RISING, "m4sensorhub-irq", data);
+ if (retval) {
+ KDEBUG(M4SH_ERROR, "m4sensorhub: Failed requesting irq.\n");
+ goto err_destroy_wq;
+ }
+
+ data->m4sensorhub = m4sensorhub;
+ m4sensorhub->irqdata = data;
+
+ retval = enable_irq_wake(i2c->irq);
+ if (retval) {
+ KDEBUG(M4SH_ERROR, "m4sensorhub: Failed enabling irq wake.\n");
+ goto err_free_irq;
+ }
+
+#ifdef CONFIG_DEBUG_FS
+ data->debugfs = debugfs_create_file("m4sensorhub-irq", S_IRUGO, NULL,
+ data, &debug_fops);
+ if (data->debugfs == NULL) {
+ KDEBUG(M4SH_ERROR, "m4sensorhub: Error creating debufs\n");
+ retval = -EINVAL;
+ goto err_disa_irq;
+ }
+#endif
+ m4sensorhub_panic_register(m4sensorhub, PANICHDL_IRQ_RESTORE,\
+ m4sensorhub_irq_restore, data);
+ KDEBUG(M4SH_INFO, "m4sensorhub IRQ subsystem initialized\n");
+ retval = 0;
+ goto done;
+
+err_disa_irq:
+ disable_irq_wake(i2c->irq);
+err_free_irq:
+ free_irq(i2c->irq, data);
+ m4sensorhub->irqdata = NULL;
+ data->m4sensorhub = NULL;
+err_destroy_wq:
+ wake_lock_destroy(&data->wake_lock);
+ mutex_destroy(&data->lock);
+ destroy_workqueue(data->workqueue);
+err_free:
+ kfree(data);
+done:
+ return retval;
+}
+EXPORT_SYMBOL_GPL(m4sensorhub_irq_init);
+
+/* m4sensorhub_irq_shutdown()
+
+ Shutdown the M4 sensor hub IRQ subsystem
+
+ m4sensorhub - pointer to the main m4sensorhub data struct
+*/
+void m4sensorhub_irq_shutdown(struct m4sensorhub_data *m4sensorhub)
+{
+ struct i2c_client *i2c = m4sensorhub->i2c_client;
+ struct m4sensorhub_irqdata *data = m4sensorhub->irqdata;
+
+ KDEBUG(M4SH_INFO, "shutdown m4sensorhub IRQ subsystem\n");
+
+ m4sensorhub_panic_unregister(m4sensorhub, PANICHDL_IRQ_RESTORE);
+
+#ifdef CONFIG_DEBUG_FS
+ debugfs_remove(data->debugfs);
+#endif
+
+ disable_irq_wake(i2c->irq);
+ free_irq(i2c->irq, data);
+
+ m4sensorhub->irqdata = NULL;
+ data->m4sensorhub = NULL;
+
+ if (wake_lock_active(&data->wake_lock))
+ wake_unlock(&data->wake_lock);
+ wake_lock_destroy(&data->wake_lock);
+
+ if (mutex_is_locked(&data->lock))
+ mutex_unlock(&data->lock);
+ mutex_destroy(&data->lock);
+
+ cancel_work_sync(&data->work);
+ destroy_workqueue(data->workqueue);
+
+ kfree(data);
+}
+EXPORT_SYMBOL_GPL(m4sensorhub_irq_shutdown);
+
+/* m4sensorhub_irq_register()
+
+ Register an interupt handler in the M4 Sensor Hub IRQ subsystem.
+ This does not enable the IRQ, that needs to be done by caller
+ with m4sensorhub_irq_enable()
+
+ Returns 0 on success. Returns negative error code on failure
+
+ m4sensorhub - pointer to the main m4sensorhub data struct
+ irq - M4 Sensor Hub interupt to resiter for
+ cb_func - IRQ handler function to execute on inturrupt
+ data - pointer to data for IRQ handler function
+*/
+
+int m4sensorhub_irq_register(struct m4sensorhub_data *m4sensorhub,
+ enum m4sensorhub_irqs irq,
+ void (*cb_func) (enum m4sensorhub_irqs, void *),
+ void *data)
+{
+ struct m4sensorhub_irqdata *irqdata;
+ int retval = 0;
+
+ if ((!m4sensorhub) || (irq >= M4SH_IRQ__NUM) || (!cb_func))
+ return -EINVAL;
+
+ irqdata = m4sensorhub->irqdata;
+
+ mutex_lock(&irqdata->lock);
+
+ if (irqdata->event_handler[irq].func == NULL) {
+ irqdata->irq_info[irq].registered = 1;
+ irqdata->event_handler[irq].func = cb_func;
+ irqdata->event_handler[irq].data = data;
+ KDEBUG(M4SH_NOTICE, "m4sensorhub: %s IRQ registered\n",
+ irq_name[irq]);
+ } else {
+ KDEBUG(M4SH_ERROR, "m4sensorhub: %s IRQ registration failed\n",
+ irq_name[irq]);
+ retval = -EPERM;
+ }
+
+ mutex_unlock(&irqdata->lock);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(m4sensorhub_irq_register);
+
+/* m4sensorhub_irq_unregister()
+
+ Unregister an interupt handler in the M4 Sensor Hub IRQ subsystem
+
+ Returns 0 on success. Returns negative error code on failure
+
+ m4sensorhub - pointer to the main m4sensorhub data struct
+ irq - M4 Sensor Hub interupt to unresiter for
+*/
+int m4sensorhub_irq_unregister(struct m4sensorhub_data *m4sensorhub,
+ enum m4sensorhub_irqs irq)
+{
+ struct m4sensorhub_irqdata *data = m4sensorhub->irqdata;
+ int retval;
+
+ if (irq >= M4SH_IRQ__NUM)
+ return -EINVAL;
+
+ retval = m4sensorhub_irq_disable(m4sensorhub, irq);
+
+ mutex_lock(&data->lock);
+ data->event_handler[irq].func = NULL;
+ data->event_handler[irq].data = NULL;
+ data->irq_info[irq].registered = 0;
+ mutex_unlock(&data->lock);
+
+ KDEBUG(M4SH_NOTICE, "m4sensorhub: %s IRQ un-registered\n",
+ irq_name[irq]);
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(m4sensorhub_irq_unregister);
+
+/* m4sensorhub_irq_enable_get()
+
+ Check if an IRQ is enabled
+
+ Returns 1 if enabled, 0 if disabled.
+ Returns negative error code on failure
+
+ m4sensorhub - pointer to the main m4sensorhub data struct
+ irq - M4 Sensor Hub interupt to check
+*/
+
+int m4sensorhub_irq_enable_get(struct m4sensorhub_data *m4sensorhub,
+ enum m4sensorhub_irqs irq)
+{
+ struct m4sensorhub_irqdata *data = m4sensorhub->irqdata;
+ int retval = -EINVAL;
+
+ if (irq < M4SH_IRQ__NUM)
+ return data->irq_info[irq].enabled;
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(m4sensorhub_irq_enable_get);
+
+/* m4sensorhub_irq_disable()
+
+ Disable M4 Sensor Hub subsystem IRQ
+
+ Returns 0 on success. Returns negative error code on failure
+
+ m4sensorhub - pointer to the main m4sensorhub data struct
+ irq - M4 Sensor Hub interupt to disable
+*/
+
+int m4sensorhub_irq_disable(struct m4sensorhub_data *m4sensorhub,
+ enum m4sensorhub_irqs irq)
+{
+ struct m4sensorhub_irqdata *data = m4sensorhub->irqdata;
+ int retval = -EINVAL;
+
+ if (irq < M4SH_IRQ__NUM) {
+ mutex_lock(&data->lock);
+ data->irq_info[irq].enabled = 0;
+ mutex_unlock(&data->lock);
+ retval = m4sensorhub_reg_write_1byte(m4sensorhub,
+ get_enable_reg(irq), 0, EVENT_MASK(irq));
+ retval = CHECK_REG_ACCESS_RETVAL(m4sensorhub, retval,
+ get_enable_reg(irq));
+ }
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(m4sensorhub_irq_disable);
+
+/* m4sensorhub_irq_enable()
+
+ Enable M4 Sensor Hub subsystem IRQ
+
+ Returns 0 on success. Returns negative error code on failure
+
+ m4sensorhub - pointer to the main m4sensorhub data struct
+ irq - M4 Sensor Hub interupt to enable
+*/
+
+int m4sensorhub_irq_enable(struct m4sensorhub_data *m4sensorhub,
+ enum m4sensorhub_irqs irq)
+{
+ struct m4sensorhub_irqdata *data = m4sensorhub->irqdata;
+ int retval = -EINVAL;
+
+ if (irq < M4SH_IRQ__NUM) {
+ mutex_lock(&data->lock);
+ data->irq_info[irq].enabled = 1;
+ mutex_unlock(&data->lock);
+ retval = m4sensorhub_reg_write_1byte(m4sensorhub,
+ get_enable_reg(irq), EVENT_MASK(irq),
+ EVENT_MASK(irq));
+ retval = CHECK_REG_ACCESS_RETVAL(m4sensorhub, retval,
+ get_enable_reg(irq));
+ }
+
+ return retval;
+}
+EXPORT_SYMBOL_GPL(m4sensorhub_irq_enable);
+
+/* m4sensorhub_irq_pm_suspend()
+
+ Called by core to track suspend state and wakeup cause
+
+*/
+
+void m4sensorhub_irq_pm_dbg_suspend(void)
+{
+ irq_dbg_info.suspend = 1;
+ irq_dbg_info.wakeup = 0;
+}
+EXPORT_SYMBOL_GPL(m4sensorhub_irq_pm_dbg_suspend);
+
+/* m4sensorhub_irq_pm_resume()
+
+ Called by core to print interupt source on M4SH wakeup
+
+*/
+
+void m4sensorhub_irq_pm_dbg_resume(void)
+{
+ char buffer[DBG_BUF_LINE_LEN];
+ int i;
+
+ irq_dbg_info.suspend = 0;
+ if ((irq_dbg_info.wakeup != 0) && (m4sensorhub_debug >= M4SH_NOTICE)) {
+ strcpy(buffer, "M4 Sensor Hub IRQ registers:");
+ for (i = 0; (i < NUM_INT_REGS) &&
+ (strlen(buffer) < DBG_BUF_LINE_LEN-5); ++i) {
+ sprintf(&buffer[strlen(buffer)], " 0x%02x",
+ irq_dbg_info.en_ints[i]);
+ }
+
+ KDEBUG(M4SH_NOTICE, "newbuf: %s\n", buffer);
+
+ /* Decode the bits */
+ KDEBUG(M4SH_NOTICE, "M4 Sensor Hub IRQ sources:\n");
+ for (i = 0; i < NUM_INT_REGS; ++i) {
+ unsigned char index;
+
+ while (irq_dbg_info.en_ints[i] > 0) {
+ /* find the first set bit */
+ index = (unsigned char)
+ (ffs(irq_dbg_info.en_ints[i]) - 1);
+ if (index >= M4SH_IRQ__NUM)
+ goto error;
+
+ /* clear the bit */
+ irq_dbg_info.en_ints[i] &= ~(1 << index);
+ /* find the event that occurred */
+ index += M4SH_IRQ__START +
+ (i * NUM_INTS_PER_REG);
+ if (index >= M4SH_IRQ__NUM)
+ goto error;
+
+ KDEBUG(M4SH_NOTICE, "\t%s\n", irq_name[index]);
+ }
+ }
+ }
+error:
+ return;
+}
+EXPORT_SYMBOL_GPL(m4sensorhub_irq_pm_dbg_resume);
+
+/* --------------- Local Functions ----------------- */
+
+static unsigned short get_enable_reg(enum m4sensorhub_irqs event)
+{
+ unsigned short ret;
+
+ if ((event) >= M4SH_IRQ__NUM)
+ ret = M4SH_REG__INVALID;
+ else if ((event) >= M4SH_IRQ_INT1_INDEX)
+ ret = M4SH_REG_GENERAL_INTERRUPT1ENABLE;
+ else if ((event) >= M4SH_IRQ_INT0_INDEX)
+ ret = M4SH_REG_GENERAL_INTERRUPT0ENABLE;
+ else
+ ret = M4SH_REG__INVALID;
+
+ return ret;
+}
+
+static int m4sensorhub_irq_disable_all(struct m4sensorhub_data *m4sensorhub)
+{
+ int i;
+
+ for (i = 0; i < NUM_INT_REGS; i++) {
+ if (1 != m4sensorhub_reg_write_1byte(m4sensorhub,
+ int_registers[i].enable_reg, 0,
+ int_registers[i].valid_bits)) {
+ KDEBUG(M4SH_ERROR, "m4sensorhub_irq: "
+ "Failed disabling INT%d\n", i);
+ return -EFAULT;
+ }
+ }
+ return 0;
+}
+
+static void irq_work_func(struct work_struct *work)
+{
+ unsigned short en_ints[NUM_INT_REGS] = { 0 };
+ int i;
+ struct m4sensorhub_irqdata *data;
+ struct m4sensorhub_data *m4sensorhub;
+ struct i2c_client *i2c;
+ unsigned char value, is_irq_set = 0;
+
+ data = container_of(work, struct m4sensorhub_irqdata, work);
+ m4sensorhub = data->m4sensorhub;
+ i2c = m4sensorhub->i2c_client;
+
+ for (i = 0; i < NUM_INT_REGS; ++i) {
+ /* M4 is expected to clear these bits when read */
+ if (1 != m4sensorhub_reg_read(m4sensorhub,
+ int_registers[i].status_reg, &value)) {
+ dev_err(&m4sensorhub->i2c_client->dev,
+ "Error reading INT%d\n", i);
+ goto error;
+ }
+ en_ints[i] = value;
+ is_irq_set |= value;
+ }
+
+ if (!is_irq_set) {
+ /* Got the checkpoint to check if M4 panicked */
+ m4sensorhub_panic_process(m4sensorhub);
+ goto error;
+ }
+
+ if ((irq_dbg_info.suspend != 0) && (irq_dbg_info.wakeup == 0)) {
+ for (i = 0; i < NUM_INT_REGS; ++i)
+ irq_dbg_info.en_ints[i] = en_ints[i];
+ irq_dbg_info.wakeup = 1;
+ }
+
+ for (i = 0; i < NUM_INT_REGS; ++i) {
+ unsigned char index;
+
+ while (en_ints[i] > 0) {
+ struct m4sensorhub_event_handler *event_handler;
+
+ /* find the first set bit */
+ index = (unsigned char)(ffs(en_ints[i]) - 1);
+ if (index >= M4SH_IRQ__NUM)
+ goto error;
+ /* clear the bit */
+ en_ints[i] &= ~(1 << index);
+ /* find the event that occurred */
+ index += M4SH_IRQ__START + (i * NUM_INTS_PER_REG);
+ if (index >= M4SH_IRQ__NUM)
+ goto error;
+
+ if (data->irq_info[index].enabled) {
+ event_handler = &data->event_handler[index];
+
+ if (event_handler && event_handler->func)
+ event_handler->func(index,
+ event_handler->data);
+
+ mutex_lock(&data->lock);
+ data->irq_info[index].ena_fired++;
+ mutex_unlock(&data->lock);
+ } else {
+ mutex_lock(&data->lock);
+ data->irq_info[index].disa_fired++;
+ mutex_unlock(&data->lock);
+ }
+ }
+ }
+error:
+ wake_unlock(&data->wake_lock);
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int m4sensorhub_dbg_irq_show(struct seq_file *s, void *data)
+{
+ unsigned int i;
+ struct m4sensorhub_irqdata *irqdata = s->private;
+
+ seq_printf(s, "%21s%9s%12s%15s%16s\n",
+ "M4SENSORHUB IRQ", "Enabled", "Registered",
+ "Fired Enabled", "Fired Disabled");
+
+ for (i = 0; i < M4SH_IRQ__NUM; i++) {
+ seq_printf(s, "%21s%9d%12d%15d%16d\n",
+ irq_name[i],
+ irqdata->irq_info[i].enabled,
+ irqdata->irq_info[i].registered,
+ irqdata->irq_info[i].ena_fired,
+ irqdata->irq_info[i].disa_fired);
+ }
+ return 0;
+}
+
+static int m4sensorhub_dbg_irq_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, m4sensorhub_dbg_irq_show, inode->i_private);
+}
+#endif
+
+/* m4sensorhub_irq_restore()
+
+ Callback Handler is called by Panic after M4 has been restarted
+
+*/
+static void m4sensorhub_irq_restore(\
+ struct m4sensorhub_data *m4sensorhub, void *data)
+{
+ int i;
+ unsigned short en_ints[NUM_INT_REGS] = {0};
+
+ mutex_lock(&((struct m4sensorhub_irqdata *)data)->lock);
+ for (i = 0; i < M4SH_IRQ__NUM; i++) {
+ if (!((struct m4sensorhub_irqdata *)data)->irq_info[i].enabled)
+ continue;
+ en_ints[i/NUM_INTS_PER_REG] |= EVENT_MASK(i);
+ }
+ mutex_unlock(&((struct m4sensorhub_irqdata *)data)->lock);
+
+ for (i = 0; i < NUM_INT_REGS; i++) {
+ KDEBUG(M4SH_INFO, "m4sensorhub_irq: Reseting INT%d-%02X\n",\
+ i, en_ints[i]);
+ if (1 != m4sensorhub_reg_write_1byte(m4sensorhub,
+ int_registers[i].enable_reg, en_ints[i],
+ int_registers[i].valid_bits)) {
+ KDEBUG(M4SH_ERROR, "m4sensorhub_irq: "
+ "Failed reseting INT%d\n", i);
+ }
+ }
+}