--- drivers/cbus/Kconfig | 8 +++ drivers/cbus/retu-user.c | 117 +++++++++++++++++++++++++++++++++++++++++++++- drivers/cbus/tahvo-user.c | 75 +++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+), 2 deletions(-) --- linux-2.6.35.orig/drivers/cbus/Kconfig +++ linux-2.6.35/drivers/cbus/Kconfig @@ -28,6 +28,10 @@ config CBUS_TAHVO_USER If you want support for Tahvo's user space read/write etc. functions, you should say Y here. +config CBUS_TAHVO_USER_DEBUG + depends on CBUS_TAHVO_USER + bool "Enable Tahvo user space interface debugging" + config CBUS_TAHVO_USB depends on CBUS_TAHVO && USB tristate "Support for Tahvo USB transceiver" @@ -56,6 +60,10 @@ config CBUS_RETU_USER If you want support for Retu's user space read/write etc. functions, you should say Y here. +config CBUS_RETU_USER_DEBUG + depends on CBUS_RETU_USER + bool "Enable Retu user space interface debugging" + config CBUS_RETU_POWERBUTTON depends on CBUS_RETU bool "Support for Retu power button" --- linux-2.6.35.orig/drivers/cbus/retu-user.c +++ linux-2.6.35/drivers/cbus/retu-user.c @@ -46,6 +46,12 @@ #define PFX "retu-user: " +#ifdef CONFIG_CBUS_RETU_USER_DEBUG +# define dprintk(fmt, x...) printk(KERN_DEBUG PFX fmt, x) +#else +# define dprintk(fmt, x...) do { } while (0) +#endif + /* Bitmap for marking the interrupt sources as having the handlers */ static u32 retu_irq_bits; @@ -105,6 +111,94 @@ static const u8 retu_access_bits[] = { 3 }; +#ifdef CONFIG_CBUS_RETU_USER_DEBUG +static const char * reg_access_text(unsigned int reg) +{ + if (WARN_ON(reg >= ARRAY_SIZE(retu_access_bits))) + return "X"; + switch (retu_access_bits[reg]) { + case READ_ONLY: + return "R"; + case WRITE_ONLY: + return "W"; + case READ_WRITE: + return "RW"; + case TOGGLE: + return "T"; + } + return "X"; +} + +static const char * reg_name(unsigned int reg) +{ + static const char *names[] = { + [RETU_REG_ASICR] = "ASIC ID & revision", + [RETU_REG_IDR] = "Interrupt ID", + [RETU_REG_IMR] = "Interrupt mask", + [RETU_REG_RTCDSR] = "RTC seconds register", + [RETU_REG_RTCHMR] = "RTC hours and minutes register", + [RETU_REG_RTCHMAR] = "hours and minutes alarm and time set register", + [RETU_REG_RTCCALR] = "RTC calibration register", + [RETU_REG_ADCR] = "ADC result", + [RETU_REG_ADCSCR] = "ADC sample ctrl", + [RETU_REG_CC1] = "Common control register 1", + [RETU_REG_CC2] = "Common control register 2", + [RETU_REG_CTRL_CLR] = "Regulator clear register", + [RETU_REG_CTRL_SET] = "Regulator set register", + [RETU_REG_STATUS] = "Status register", + [RETU_REG_WATCHDOG] = "Watchdog register", + [RETU_REG_AUDTXR] = "Audio Codec Tx register", + [0x14] = "Charger detect?", + }; + const char *name; + + if (reg >= ARRAY_SIZE(names)) + return ""; + name = names[reg]; + if (!name) + return ""; + return name; +} + +static const char * adc_chan_name(unsigned int chan) +{ + static const char *names[] = { + [0x05] = "Headset hook detect", + }; + const char *name; + + if (chan >= ARRAY_SIZE(names)) + return ""; + name = names[chan]; + if (!name) + return ""; + return name; +} + +static const char * retu_irq_name(unsigned int id) +{ + static const char *names[] = { + [RETU_INT_PWR] = "Power", + [RETU_INT_CHAR] = "Char", + [RETU_INT_RTCS] = "RTCS", + [RETU_INT_RTCM] = "RTCM", + [RETU_INT_RTCD] = "RTCD", + [RETU_INT_RTCA] = "RTCA", + [RETU_INT_HOOK] = "Hook", + [RETU_INT_HEAD] = "Head", + [RETU_INT_ADCS] = "ADC timer", + }; + const char *name; + + if (id >= ARRAY_SIZE(names)) + return ""; + name = names[id]; + if (!name) + return ""; + return name; +} +#endif + /* * The handler for all RETU interrupts. * @@ -157,6 +251,8 @@ static int retu_user_subscribe_to_irq(in /* Mark that this interrupt has a handler */ retu_irq_bits |= 1 << id; + dprintk("Subscribed to IRQ %d (%s)\n", id, retu_irq_name(id)); + return 0; } @@ -216,6 +312,10 @@ static int retu_user_write_with_mask(u32 /* Generate new value */ tmp = (tmp & ~MASK(field)) | (value & MASK(field)); + + dprintk("{WRITE %s} 0x%02X(%s) <= msk 0x%04X, val 0x%04X ==> res 0x%04X\n", + reg_name(reg), reg, reg_access_text(reg), MASK(field), value, tmp); + /* Write data to RETU */ retu_write_reg(reg, tmp); spin_unlock_irqrestore(&retu_lock, flags); @@ -244,6 +344,9 @@ static u32 retu_user_read_with_mask(u32 /* Read the register */ value = retu_read_reg(reg) & mask; + dprintk("{READ %s} 0x%02X(%s) <= msk 0x%04X ==> res 0x%04X\n", + reg_name(reg), reg, reg_access_text(reg), mask, value); + /* Right justify value */ while (!(mask & 1)) { value = value >> 1; @@ -274,7 +377,7 @@ static int retu_ioctl(struct inode *inod unsigned int cmd, unsigned long arg) { struct retu_tahvo_write_parms par; - int ret; + int ret, result; switch (cmd) { case URT_IOCT_IRQ_SUBSCR: @@ -291,7 +394,15 @@ static int retu_ioctl(struct inode *inod printk(KERN_ERR "copy_to_user failed: %d\n", ret); break; case RETU_IOCH_ADC_READ: - return retu_read_adc(arg); + result = retu_read_adc(arg); + if (result >= 0) { + dprintk("{READ-ADC %s} chan 0x%02lX ==> result 0x%04X\n", + adc_chan_name(arg), arg, result); + } else { + dprintk("{READ-ADC %s} chan 0x%02lX ==> failed %d\n", + adc_chan_name(arg), arg, result); + } + return result; default: return -ENOIOCTLCMD; } @@ -333,6 +444,8 @@ static ssize_t retu_read(struct file *fi list_move(&irq->node, &retu_irqs_reserve); spin_unlock_irqrestore(&retu_irqs_lock, flags); + dprintk("{IRQ %s} %d delivered\n", retu_irq_name(irq_id), (int)irq_id); + ret = copy_to_user(buf + i * sizeof(irq_id), &irq_id, sizeof(irq_id)); if (ret) --- linux-2.6.35.orig/drivers/cbus/tahvo-user.c +++ linux-2.6.35/drivers/cbus/tahvo-user.c @@ -46,6 +46,12 @@ #define PFX "tahvo-user: " +#ifdef CONFIG_CBUS_TAHVO_USER_DEBUG +# define dprintk(fmt, x...) printk(KERN_DEBUG PFX fmt, x) +#else +# define dprintk(fmt, x...) do { } while (0) +#endif + /* Bitmap for marking the interrupt sources as having the handlers */ static u32 tahvo_irq_bits; @@ -87,6 +93,64 @@ static const u8 tahvo_access_bits[] = { 1 }; +#ifdef CONFIG_CBUS_TAHVO_USER_DEBUG +static const char * reg_access_text(unsigned int reg) +{ + if (WARN_ON(reg >= ARRAY_SIZE(tahvo_access_bits))) + return "X"; + switch (tahvo_access_bits[reg]) { + case READ_ONLY: + return "R"; + case WRITE_ONLY: + return "W"; + case READ_WRITE: + return "RW"; + case TOGGLE: + return "T"; + } + return "X"; +} + +static const char * reg_name(unsigned int reg) +{ + static const char *names[] = { + [TAHVO_REG_ASICR] = "ASIC ID & revision", + [TAHVO_REG_IDR] = "Interrupt ID", + [TAHVO_REG_IDSR] = "Interrupt status", + [TAHVO_REG_IMR] = "Interrupt mask", + [TAHVO_REG_LEDPWMR] = "LED PWM", + [TAHVO_REG_USBR] = "USB control", + [0x04] = "Charge current control?", + [0x08] = "Charge ctl 1?", + [0x0C] = "Charge ctl 2?", + [0x0D] = "Battery current ADC?", + }; + const char *name; + + if (reg >= ARRAY_SIZE(names)) + return ""; + name = names[reg]; + if (!name) + return ""; + return name; +} + +static const char * tahvo_irq_name(unsigned int id) +{ + static const char *names[] = { + [TAHVO_INT_VBUSON] = "VBUSON", + }; + const char *name; + + if (id >= ARRAY_SIZE(names)) + return ""; + name = names[id]; + if (!name) + return ""; + return name; +} +#endif + /* * The handler for all TAHVO interrupts. * @@ -142,6 +206,8 @@ static int tahvo_user_subscribe_to_irq(i /* Mark that this interrupt has a handler */ tahvo_irq_bits |= 1 << id; + dprintk("Subscribed to IRQ %d (%s)\n", id, tahvo_irq_name(id)); + return 0; } @@ -200,6 +266,10 @@ static int tahvo_user_write_with_mask(u3 } /* Generate a new value */ tmp = (tmp & ~MASK(field)) | (value & MASK(field)); + + dprintk("{WRITE %s} 0x%02X(%s) <= msk 0x%04X, val 0x%04X ==> res 0x%04X\n", + reg_name(reg), reg, reg_access_text(reg), MASK(field), value, tmp); + /* Write data to TAHVO */ tahvo_write_reg(reg, tmp); spin_unlock_irqrestore(&tahvo_lock, flags); @@ -228,6 +298,9 @@ static u32 tahvo_user_read_with_mask(u32 /* Read the register */ value = tahvo_read_reg(reg) & mask; + dprintk("{READ %s} 0x%02X(%s) <= msk 0x%04X ==> res 0x%04X\n", + reg_name(reg), reg, reg_access_text(reg), mask, value); + /* Right justify value */ while (!(mask & 1)) { value = value >> 1; @@ -315,6 +388,8 @@ static ssize_t tahvo_read(struct file *f list_move(&irq->node, &tahvo_irqs_reserve); spin_unlock_irqrestore(&tahvo_irqs_lock, flags); + dprintk("{IRQ %s} %d delivered\n", tahvo_irq_name(irq_id), (int)irq_id); + ret = copy_to_user(buf + i * sizeof(irq_id), &irq_id, sizeof(irq_id)); if (ret)