mfd: cpcap-irq: Add debugfs file for CPCAP IRQ data
authorGreg Meiste <w30289@motorola.com>
Mon, 26 Jul 2010 19:39:57 +0000 (14:39 -0500)
committerColin Cross <ccross@android.com>
Wed, 6 Oct 2010 23:33:23 +0000 (16:33 -0700)
This change will add the file cpcap-irq to the debug fs directory. The file will
provide data for each of the cpcap interrupts. The data includes the interrupt
name, if the interrupt is enabled/disabled, if a handler has been registered
with the interrupt, and the number of times the interrupt has been generated.

Signed-off-by: Greg Meiste <w30289@motorola.com>
drivers/mfd/cpcap-irq.c

index e010e0dda74d1ae4df2a05d2a330e3dd9050eddc..9c133be6812601f7323533e371e4ff0170c51c6e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2009, Motorola, All Rights Reserved.
+ * Copyright (C) 2009 - 2010, Motorola, All Rights Reserved.
  *
  * 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
@@ -27,6 +27,7 @@
 #include <linux/spi/cpcap.h>
 #include <linux/spi/spi.h>
 #include <linux/debugfs.h>
+#include <linux/seq_file.h>
 
 #define NUM_INT_REGS      5
 #define NUM_INTS_PER_REG  16
@@ -42,14 +43,19 @@ struct cpcap_event_handler {
        void *data;
 };
 
+struct cpcap_irq_info {
+       uint8_t registered;
+       uint8_t enabled;
+       uint32_t count;
+};
+
 struct cpcap_irqdata {
        struct mutex lock;
        struct work_struct work;
        struct workqueue_struct *workqueue;
        struct cpcap_device *cpcap;
        struct cpcap_event_handler event_handler[CPCAP_IRQ__NUM];
-       uint64_t registered;
-       uint64_t enabled;
+       struct cpcap_irq_info irq_info[CPCAP_IRQ__NUM];
        struct wake_lock wake_lock;
 };
 
@@ -293,6 +299,8 @@ static void irq_work_func(struct work_struct *work)
 
                        if (event_handler->func)
                                event_handler->func(index, event_handler->data);
+
+                       data->irq_info[index].count++;
                }
        }
 error:
@@ -300,12 +308,125 @@ error:
        wake_unlock(&data->wake_lock);
 }
 
+#ifdef CONFIG_DEBUG_FS
+static int cpcap_dbg_irq_show(struct seq_file *s, void *data)
+{
+       static const char *irq_name[] = {
+               [CPCAP_IRQ_HSCLK]                 = "HSCLK",
+               [CPCAP_IRQ_PRIMAC]                = "PRIMAC",
+               [CPCAP_IRQ_SECMAC]                = "SECMAC",
+               [CPCAP_IRQ_LOWBPL]                = "LOWBPL",
+               [CPCAP_IRQ_SEC2PRI]               = "SEC2PRI",
+               [CPCAP_IRQ_LOWBPH]                = "LOWBPH",
+               [CPCAP_IRQ_EOL]                   = "EOL",
+               [CPCAP_IRQ_TS]                    = "TS",
+               [CPCAP_IRQ_ADCDONE]               = "ADCDONE",
+               [CPCAP_IRQ_HS]                    = "HS",
+               [CPCAP_IRQ_MB2]                   = "MB2",
+               [CPCAP_IRQ_VBUSOV]                = "VBUSOV",
+               [CPCAP_IRQ_RVRS_CHRG]             = "RVRS_CHRG",
+               [CPCAP_IRQ_CHRG_DET]              = "CHRG_DET",
+               [CPCAP_IRQ_IDFLOAT]               = "IDFLOAT",
+               [CPCAP_IRQ_IDGND]                 = "IDGND",
+
+               [CPCAP_IRQ_SE1]                   = "SE1",
+               [CPCAP_IRQ_SESSEND]               = "SESSEND",
+               [CPCAP_IRQ_SESSVLD]               = "SESSVLD",
+               [CPCAP_IRQ_VBUSVLD]               = "VBUSVLD",
+               [CPCAP_IRQ_CHRG_CURR1]            = "CHRG_CURR1",
+               [CPCAP_IRQ_CHRG_CURR2]            = "CHRG_CURR2",
+               [CPCAP_IRQ_RVRS_MODE]             = "RVRS_MODE",
+               [CPCAP_IRQ_ON]                    = "ON",
+               [CPCAP_IRQ_ON2]                   = "ON2",
+               [CPCAP_IRQ_CLK]                   = "CLK",
+               [CPCAP_IRQ_1HZ]                   = "1HZ",
+               [CPCAP_IRQ_PTT]                   = "PTT",
+               [CPCAP_IRQ_SE0CONN]               = "SE0CONN",
+               [CPCAP_IRQ_CHRG_SE1B]             = "CHRG_SE1B",
+               [CPCAP_IRQ_UART_ECHO_OVERRUN]     = "UART_ECHO_OVERRUN",
+               [CPCAP_IRQ_EXTMEMHD]              = "EXTMEMHD",
+
+               [CPCAP_IRQ_WARM]                  = "WARM",
+               [CPCAP_IRQ_SYSRSTR]               = "SYSRSTR",
+               [CPCAP_IRQ_SOFTRST]               = "SOFTRST",
+               [CPCAP_IRQ_DIEPWRDWN]             = "DIEPWRDWN",
+               [CPCAP_IRQ_DIETEMPH]              = "DIETEMPH",
+               [CPCAP_IRQ_PC]                    = "PC",
+               [CPCAP_IRQ_OFLOWSW]               = "OFLOWSW",
+               [CPCAP_IRQ_TODA]                  = "TODA",
+               [CPCAP_IRQ_OPT_SEL_DTCH]          = "OPT_SEL_DTCH",
+               [CPCAP_IRQ_OPT_SEL_STATE]         = "OPT_SEL_STATE",
+               [CPCAP_IRQ_ONEWIRE1]              = "ONEWIRE1",
+               [CPCAP_IRQ_ONEWIRE2]              = "ONEWIRE2",
+               [CPCAP_IRQ_ONEWIRE3]              = "ONEWIRE3",
+               [CPCAP_IRQ_UCRESET]               = "UCRESET",
+               [CPCAP_IRQ_PWRGOOD]               = "PWRGOOD",
+               [CPCAP_IRQ_USBDPLLCLK]            = "USBDPLLCLK",
+
+               [CPCAP_IRQ_DPI]                   = "DPI",
+               [CPCAP_IRQ_DMI]                   = "DMI",
+               [CPCAP_IRQ_UCBUSY]                = "UCBUSY",
+               [CPCAP_IRQ_GCAI_CURR1]            = "GCAI_CURR1",
+               [CPCAP_IRQ_GCAI_CURR2]            = "GCAI_CURR2",
+               [CPCAP_IRQ_SB_MAX_RETRANSMIT_ERR] = "SB_MAX_RETRANSMIT_ERR",
+               [CPCAP_IRQ_BATTDETB]              = "BATTDETB",
+               [CPCAP_IRQ_PRIHALT]               = "PRIHALT",
+               [CPCAP_IRQ_SECHALT]               = "SECHALT",
+               [CPCAP_IRQ_CC_CAL]                = "CC_CAL",
+
+               [CPCAP_IRQ_UC_PRIROMR]            = "UC_PRIROMR",
+               [CPCAP_IRQ_UC_PRIRAMW]            = "UC_PRIRAMW",
+               [CPCAP_IRQ_UC_PRIRAMR]            = "UC_PRIRAMR",
+               [CPCAP_IRQ_UC_USEROFF]            = "UC_USEROFF",
+               [CPCAP_IRQ_UC_PRIMACRO_4]         = "UC_PRIMACRO_4",
+               [CPCAP_IRQ_UC_PRIMACRO_5]         = "UC_PRIMACRO_5",
+               [CPCAP_IRQ_UC_PRIMACRO_6]         = "UC_PRIMACRO_6",
+               [CPCAP_IRQ_UC_PRIMACRO_7]         = "UC_PRIMACRO_7",
+               [CPCAP_IRQ_UC_PRIMACRO_8]         = "UC_PRIMACRO_8",
+               [CPCAP_IRQ_UC_PRIMACRO_9]         = "UC_PRIMACRO_9",
+               [CPCAP_IRQ_UC_PRIMACRO_10]        = "UC_PRIMACRO_10",
+               [CPCAP_IRQ_UC_PRIMACRO_11]        = "UC_PRIMACRO_11",
+               [CPCAP_IRQ_UC_PRIMACRO_12]        = "UC_PRIMACRO_12",
+               [CPCAP_IRQ_UC_PRIMACRO_13]        = "UC_PRIMACRO_13",
+               [CPCAP_IRQ_UC_PRIMACRO_14]        = "UC_PRIMACRO_14",
+               [CPCAP_IRQ_UC_PRIMACRO_15]        = "UC_PRIMACRO_15",
+       };
+       unsigned int i;
+       struct cpcap_irqdata *irqdata = s->private;
+
+       seq_printf(s, "%21s%9s%12s%10s\n",
+                  "CPCAP IRQ", "Enabled", "Registered", "Count");
+
+       for (i = 0; i < CPCAP_IRQ__NUM; i++) {
+               if ((i <= CPCAP_IRQ_CC_CAL) || (i >= CPCAP_IRQ_UC_PRIROMR)) {
+                       seq_printf(s, "%21s%9d%12d%10d\n",
+                                  irq_name[i],
+                                  irqdata->irq_info[i].enabled,
+                                  irqdata->irq_info[i].registered,
+                                  irqdata->irq_info[i].count);
+               }
+       }
+       return 0;
+}
+
+static int cpcap_dbg_irq_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, cpcap_dbg_irq_show, inode->i_private);
+}
+
+static const struct file_operations debug_fops = {
+       .open    = cpcap_dbg_irq_open,
+       .read    = seq_read,
+       .llseek  = seq_lseek,
+       .release = single_release,
+};
+#endif
+
 int cpcap_irq_init(struct cpcap_device *cpcap)
 {
        int retval;
        struct spi_device *spi = cpcap->spi;
        struct cpcap_irqdata *data;
-       struct dentry *debug_dir;
 
        data = kzalloc(sizeof(struct cpcap_irqdata), GFP_KERNEL);
        if (!data)
@@ -334,13 +455,10 @@ int cpcap_irq_init(struct cpcap_device *cpcap)
                printk(KERN_ERR "cpcap_irq: Failed initializing pwrkey.\n");
                goto error;
        }
-
-       debug_dir = debugfs_create_dir("cpcap-irq", NULL);
-       debugfs_create_u64("registered", S_IRUGO, debug_dir,
-                          &data->registered);
-       debugfs_create_u64("enabled", S_IRUGO, debug_dir,
-                          &data->enabled);
-
+#ifdef CONFIG_DEBUG_FS
+       (void)debugfs_create_file("cpcap-irq", S_IRUGO, NULL, data,
+                                 &debug_fops);
+#endif
        return 0;
 
 error:
@@ -376,7 +494,7 @@ int cpcap_irq_register(struct cpcap_device *cpcap,
        mutex_lock(&irqdata->lock);
 
        if (irqdata->event_handler[irq].func == NULL) {
-               irqdata->registered |= 1 << irq;
+               irqdata->irq_info[irq].registered = 1;
                cpcap_irq_unmask(cpcap, irq);
                irqdata->event_handler[irq].func = cb_func;
                irqdata->event_handler[irq].data = data;
@@ -401,7 +519,7 @@ int cpcap_irq_free(struct cpcap_device *cpcap, enum cpcap_irqs irq)
        retval = cpcap_irq_mask(cpcap, irq);
        data->event_handler[irq].func = NULL;
        data->event_handler[irq].data = NULL;
-       data->registered &= ~(1 << irq);
+       data->irq_info[irq].registered = 0;
        mutex_unlock(&data->lock);
 
        return retval;
@@ -448,7 +566,7 @@ int cpcap_irq_mask(struct cpcap_device *cpcap,
        int retval = -EINVAL;
 
        if ((irq < CPCAP_IRQ__NUM) && (irq != CPCAP_IRQ_SECMAC)) {
-               data->enabled &= ~(1 << irq);
+               data->irq_info[irq].enabled = 0;
                retval = cpcap_regacc_write(cpcap,
                                            get_mask_reg(irq),
                                            EVENT_MASK(irq),
@@ -466,7 +584,7 @@ int cpcap_irq_unmask(struct cpcap_device *cpcap,
        int retval = -EINVAL;
 
        if ((irq < CPCAP_IRQ__NUM) && (irq != CPCAP_IRQ_SECMAC)) {
-               data->enabled |= 1 << irq;
+               data->irq_info[irq].enabled = 1;
                retval = cpcap_regacc_write(cpcap,
                                            get_mask_reg(irq),
                                            0,
@@ -484,7 +602,7 @@ int cpcap_irq_mask_get(struct cpcap_device *cpcap,
        int retval = -EINVAL;
 
        if ((irq < CPCAP_IRQ__NUM) && (irq != CPCAP_IRQ_SECMAC))
-               return (data->enabled & (1 << irq)) ? 0 : 1;
+               return data->irq_info[irq].enabled;
 
        return retval;
 }