diff options
Diffstat (limited to 'drivers/mfd/ricoh619-irq.c')
-rwxr-xr-x | drivers/mfd/ricoh619-irq.c | 609 |
1 files changed, 609 insertions, 0 deletions
diff --git a/drivers/mfd/ricoh619-irq.c b/drivers/mfd/ricoh619-irq.c new file mode 100755 index 00000000..259bb86a --- /dev/null +++ b/drivers/mfd/ricoh619-irq.c @@ -0,0 +1,609 @@ +/* + * driver/mfd/ricoh619-irq.c + * + * Interrupt driver for RICOH R5T619 power management chip. + * + * Copyright (C) 2012-2014 RICOH COMPANY,LTD + * + * Based on code + * Copyright (C) 2011 NVIDIA Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. + * + */ +#include <linux/interrupt.h> +#include <linux/irq.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/init.h> +#include <linux/i2c.h> +#include <linux/mfd/ricoh619.h> + + +enum int_type { + SYS_INT = 0x1, + DCDC_INT = 0x2, + RTC_INT = 0x4, + ADC_INT = 0x8, + GPIO_INT = 0x10, + WDOG_INT = 0x20, + CHG_INT = 0x40, +}; + +static int gpedge_add[] = { + RICOH61x_GPIO_GPEDGE1, + RICOH61x_GPIO_GPEDGE2 +}; + +static int irq_en_add[] = { + RICOH61x_INT_EN_SYS, + RICOH61x_INT_EN_DCDC, + RICOH61x_INT_EN_RTC, + RICOH61x_INT_EN_ADC1, + RICOH61x_INT_EN_ADC2, + RICOH61x_INT_EN_ADC3, + RICOH61x_INT_EN_GPIO, + RICOH61x_INT_EN_GPIO2, + RICOH61x_INT_MSK_CHGCTR, + RICOH61x_INT_MSK_CHGSTS1, + RICOH61x_INT_MSK_CHGSTS2, + RICOH61x_INT_MSK_CHGERR, + RICOH61x_INT_MSK_CHGEXTIF +}; + +static int irq_mon_add[] = { + RICOH61x_INT_IR_SYS, /* RICOH61x_INT_MON_SYS, */ + RICOH61x_INT_IR_DCDC, /* RICOH61x_INT_MON_DCDC, */ + RICOH61x_INT_IR_RTC, /* RICOH61x_INT_MON_RTC, */ + RICOH61x_INT_IR_ADCL, + RICOH61x_INT_IR_ADCH, + RICOH61x_INT_IR_ADCEND, + RICOH61x_INT_IR_GPIOR, + RICOH61x_INT_IR_GPIOF, + RICOH61x_INT_IR_CHGCTR, /* RICOH61x_INT_MON_CHGCTR, */ + RICOH61x_INT_IR_CHGSTS1, /* RICOH61x_INT_MON_CHGSTS1, */ + RICOH61x_INT_IR_CHGSTS2, /* RICOH61x_INT_MON_CHGSTS2, */ + RICOH61x_INT_IR_CHGERR, /* RICOH61x_INT_MON_CHGERR */ + RICOH61x_INT_IR_CHGEXTIF /* RICOH61x_INT_MON_CHGEXTIF */ +}; + +static int irq_clr_add[] = { + RICOH61x_INT_IR_SYS, + RICOH61x_INT_IR_DCDC, + RICOH61x_INT_IR_RTC, + RICOH61x_INT_IR_ADCL, + RICOH61x_INT_IR_ADCH, + RICOH61x_INT_IR_ADCEND, + RICOH61x_INT_IR_GPIOR, + RICOH61x_INT_IR_GPIOF, + RICOH61x_INT_IR_CHGCTR, + RICOH61x_INT_IR_CHGSTS1, + RICOH61x_INT_IR_CHGSTS2, + RICOH61x_INT_IR_CHGERR, + RICOH61x_INT_IR_CHGEXTIF +}; + +static int main_int_type[] = { + SYS_INT|WDOG_INT, + DCDC_INT, + RTC_INT, + ADC_INT, + ADC_INT, + ADC_INT, + GPIO_INT, + GPIO_INT, + CHG_INT, + CHG_INT, + CHG_INT, + CHG_INT, + CHG_INT, +}; + +struct ricoh61x_irq_data { + u8 int_type; + u8 master_bit; + u8 int_en_bit; + u8 mask_reg_index; + int grp_index; +}; + +#define RICOH61x_IRQ(_int_type, _master_bit, _grp_index, _int_bit, _mask_ind) \ + { \ + .int_type = _int_type, \ + .master_bit = _master_bit, \ + .grp_index = _grp_index, \ + .int_en_bit = _int_bit, \ + .mask_reg_index = _mask_ind, \ + } + +static const struct ricoh61x_irq_data ricoh61x_irqs[RICOH61x_NR_IRQS] = { + [RICOH61x_IRQ_POWER_ON] = RICOH61x_IRQ(SYS_INT, 0, 0, 0, 0), + [RICOH61x_IRQ_EXTIN] = RICOH61x_IRQ(SYS_INT, 0, 1, 1, 0), + [RICOH61x_IRQ_PRE_VINDT] = RICOH61x_IRQ(SYS_INT, 0, 2, 2, 0), + [RICOH61x_IRQ_PREOT] = RICOH61x_IRQ(SYS_INT, 0, 3, 3, 0), + [RICOH61x_IRQ_POWER_OFF] = RICOH61x_IRQ(SYS_INT, 0, 4, 4, 0), + [RICOH61x_IRQ_NOE_OFF] = RICOH61x_IRQ(SYS_INT, 0, 5, 5, 0), + [RICOH61x_IRQ_WD] = RICOH61x_IRQ(SYS_INT, 0, 6, 6, 0), + + [RICOH61x_IRQ_DC1LIM] = RICOH61x_IRQ(DCDC_INT, 1, 0, 0, 1), + [RICOH61x_IRQ_DC2LIM] = RICOH61x_IRQ(DCDC_INT, 1, 1, 1, 1), + [RICOH61x_IRQ_DC3LIM] = RICOH61x_IRQ(DCDC_INT, 1, 2, 2, 1), + [RICOH61x_IRQ_DC4LIM] = RICOH61x_IRQ(DCDC_INT, 1, 3, 3, 1), + [RICOH61x_IRQ_DC5LIM] = RICOH61x_IRQ(DCDC_INT, 1, 4, 4, 1), + + [RICOH61x_IRQ_CTC] = RICOH61x_IRQ(RTC_INT, 2, 0, 0, 2), + [RICOH61x_IRQ_DALE] = RICOH61x_IRQ(RTC_INT, 2, 1, 6, 2), + + [RICOH61x_IRQ_ILIMLIR] = RICOH61x_IRQ(ADC_INT, 3, 0, 0, 3), + [RICOH61x_IRQ_VBATLIR] = RICOH61x_IRQ(ADC_INT, 3, 1, 1, 3), + [RICOH61x_IRQ_VADPLIR] = RICOH61x_IRQ(ADC_INT, 3, 2, 2, 3), + [RICOH61x_IRQ_VUSBLIR] = RICOH61x_IRQ(ADC_INT, 3, 3, 3, 3), + [RICOH61x_IRQ_VSYSLIR] = RICOH61x_IRQ(ADC_INT, 3, 4, 4, 3), + [RICOH61x_IRQ_VTHMLIR] = RICOH61x_IRQ(ADC_INT, 3, 5, 5, 3), + [RICOH61x_IRQ_AIN1LIR] = RICOH61x_IRQ(ADC_INT, 3, 6, 6, 3), + [RICOH61x_IRQ_AIN0LIR] = RICOH61x_IRQ(ADC_INT, 3, 7, 7, 3), + + [RICOH61x_IRQ_ILIMHIR] = RICOH61x_IRQ(ADC_INT, 3, 8, 0, 4), + [RICOH61x_IRQ_VBATHIR] = RICOH61x_IRQ(ADC_INT, 3, 9, 1, 4), + [RICOH61x_IRQ_VADPHIR] = RICOH61x_IRQ(ADC_INT, 3, 10, 2, 4), + [RICOH61x_IRQ_VUSBHIR] = RICOH61x_IRQ(ADC_INT, 3, 11, 3, 4), + [RICOH61x_IRQ_VSYSHIR] = RICOH61x_IRQ(ADC_INT, 3, 12, 4, 4), + [RICOH61x_IRQ_VTHMHIR] = RICOH61x_IRQ(ADC_INT, 3, 13, 5, 4), + [RICOH61x_IRQ_AIN1HIR] = RICOH61x_IRQ(ADC_INT, 3, 14, 6, 4), + [RICOH61x_IRQ_AIN0HIR] = RICOH61x_IRQ(ADC_INT, 3, 15, 7, 4), + + [RICOH61x_IRQ_ADC_ENDIR] = RICOH61x_IRQ(ADC_INT, 3, 16, 0, 5), + + [RICOH61x_IRQ_GPIO0] = RICOH61x_IRQ(GPIO_INT, 4, 0, 0, 6), + [RICOH61x_IRQ_GPIO1] = RICOH61x_IRQ(GPIO_INT, 4, 1, 1, 6), + [RICOH61x_IRQ_GPIO2] = RICOH61x_IRQ(GPIO_INT, 4, 2, 2, 6), + [RICOH61x_IRQ_GPIO3] = RICOH61x_IRQ(GPIO_INT, 4, 3, 3, 6), + [RICOH61x_IRQ_GPIO4] = RICOH61x_IRQ(GPIO_INT, 4, 4, 4, 6), + + [RICOH61x_IRQ_FVADPDETSINT] = RICOH61x_IRQ(CHG_INT, 6, 0, 0, 8), + [RICOH61x_IRQ_FVUSBDETSINT] = RICOH61x_IRQ(CHG_INT, 6, 1, 1, 8), + [RICOH61x_IRQ_FVADPLVSINT] = RICOH61x_IRQ(CHG_INT, 6, 2, 2, 8), + [RICOH61x_IRQ_FVUSBLVSINT] = RICOH61x_IRQ(CHG_INT, 6, 3, 3, 8), + [RICOH61x_IRQ_FWVADPSINT] = RICOH61x_IRQ(CHG_INT, 6, 4, 4, 8), + [RICOH61x_IRQ_FWVUSBSINT] = RICOH61x_IRQ(CHG_INT, 6, 5, 5, 8), + + [RICOH61x_IRQ_FONCHGINT] = RICOH61x_IRQ(CHG_INT, 6, 6, 0, 9), + [RICOH61x_IRQ_FCHGCMPINT] = RICOH61x_IRQ(CHG_INT, 6, 7, 1, 9), + [RICOH61x_IRQ_FBATOPENINT] = RICOH61x_IRQ(CHG_INT, 6, 8, 2, 9), + [RICOH61x_IRQ_FSLPMODEINT] = RICOH61x_IRQ(CHG_INT, 6, 9, 3, 9), + [RICOH61x_IRQ_FBTEMPJTA1INT] = RICOH61x_IRQ(CHG_INT, 6, 10, 4, 9), + [RICOH61x_IRQ_FBTEMPJTA2INT] = RICOH61x_IRQ(CHG_INT, 6, 11, 5, 9), + [RICOH61x_IRQ_FBTEMPJTA3INT] = RICOH61x_IRQ(CHG_INT, 6, 12, 6, 9), + [RICOH61x_IRQ_FBTEMPJTA4INT] = RICOH61x_IRQ(CHG_INT, 6, 13, 7, 9), + + [RICOH61x_IRQ_FCURTERMINT] = RICOH61x_IRQ(CHG_INT, 6, 14, 0, 10), + [RICOH61x_IRQ_FVOLTERMINT] = RICOH61x_IRQ(CHG_INT, 6, 15, 1, 10), + [RICOH61x_IRQ_FICRVSINT] = RICOH61x_IRQ(CHG_INT, 6, 16, 2, 10), + [RICOH61x_IRQ_FPOOR_CHGCURINT] = RICOH61x_IRQ(CHG_INT, 6, 17, 3, 10), + [RICOH61x_IRQ_FOSCFDETINT1] = RICOH61x_IRQ(CHG_INT, 6, 18, 4, 10), + [RICOH61x_IRQ_FOSCFDETINT2] = RICOH61x_IRQ(CHG_INT, 6, 19, 5, 10), + [RICOH61x_IRQ_FOSCFDETINT3] = RICOH61x_IRQ(CHG_INT, 6, 20, 6, 10), + [RICOH61x_IRQ_FOSCMDETINT] = RICOH61x_IRQ(CHG_INT, 6, 21, 7, 10), + + [RICOH61x_IRQ_FDIEOFFINT] = RICOH61x_IRQ(CHG_INT, 6, 22, 0, 11), + [RICOH61x_IRQ_FDIEERRINT] = RICOH61x_IRQ(CHG_INT, 6, 23, 1, 11), + [RICOH61x_IRQ_FBTEMPERRINT] = RICOH61x_IRQ(CHG_INT, 6, 24, 2, 11), + [RICOH61x_IRQ_FVBATOVINT] = RICOH61x_IRQ(CHG_INT, 6, 25, 3, 11), + [RICOH61x_IRQ_FTTIMOVINT] = RICOH61x_IRQ(CHG_INT, 6, 26, 4, 11), + [RICOH61x_IRQ_FRTIMOVINT] = RICOH61x_IRQ(CHG_INT, 6, 27, 5, 11), + [RICOH61x_IRQ_FVADPOVSINT] = RICOH61x_IRQ(CHG_INT, 6, 28, 6, 11), + [RICOH61x_IRQ_FVUSBOVSINT] = RICOH61x_IRQ(CHG_INT, 6, 29, 7, 11), + + [RICOH61x_IRQ_FGCDET] = RICOH61x_IRQ(CHG_INT, 6, 30, 0, 12), + [RICOH61x_IRQ_FPCDET] = RICOH61x_IRQ(CHG_INT, 6, 31, 1, 12), + [RICOH61x_IRQ_FWARN_ADP] = RICOH61x_IRQ(CHG_INT, 6, 32, 3, 12), + +}; + +static void ricoh61x_irq_lock(struct irq_data *irq_data) +{ + struct ricoh61x *ricoh61x = irq_data_get_irq_chip_data(irq_data); + + mutex_lock(&ricoh61x->irq_lock); +} + +static void ricoh61x_irq_unmask(struct irq_data *irq_data) +{ + struct ricoh61x *ricoh61x = irq_data_get_irq_chip_data(irq_data); + unsigned int __irq = irq_data->irq - ricoh61x->irq_base; + const struct ricoh61x_irq_data *data = &ricoh61x_irqs[__irq]; + + ricoh61x->group_irq_en[data->master_bit] |= (1 << data->grp_index); + if (ricoh61x->group_irq_en[data->master_bit]) + ricoh61x->intc_inten_reg |= 1 << data->master_bit; + + if (data->master_bit == 6) /* if Charger */ + ricoh61x->irq_en_reg[data->mask_reg_index] + &= ~(1 << data->int_en_bit); + else + ricoh61x->irq_en_reg[data->mask_reg_index] + |= 1 << data->int_en_bit; +} + +static void ricoh61x_irq_mask(struct irq_data *irq_data) +{ + struct ricoh61x *ricoh61x = irq_data_get_irq_chip_data(irq_data); + unsigned int __irq = irq_data->irq - ricoh61x->irq_base; + const struct ricoh61x_irq_data *data = &ricoh61x_irqs[__irq]; + + ricoh61x->group_irq_en[data->master_bit] &= ~(1 << data->grp_index); + if (!ricoh61x->group_irq_en[data->master_bit]) + ricoh61x->intc_inten_reg &= ~(1 << data->master_bit); + + if (data->master_bit == 6) /* if Charger */ + ricoh61x->irq_en_reg[data->mask_reg_index] + |= 1 << data->int_en_bit; + else + ricoh61x->irq_en_reg[data->mask_reg_index] + &= ~(1 << data->int_en_bit); +} + +static void ricoh61x_irq_sync_unlock(struct irq_data *irq_data) +{ + struct ricoh61x *ricoh61x = irq_data_get_irq_chip_data(irq_data); + int i; + + for (i = 0; i < ARRAY_SIZE(ricoh61x->gpedge_reg); i++) { + if (ricoh61x->gpedge_reg[i] != ricoh61x->gpedge_cache[i]) { + if (!WARN_ON(ricoh61x_write(ricoh61x->dev, + gpedge_add[i], + ricoh61x->gpedge_reg[i]))) + ricoh61x->gpedge_cache[i] = + ricoh61x->gpedge_reg[i]; + } + } + + for (i = 0; i < ARRAY_SIZE(ricoh61x->irq_en_reg); i++) { + if (ricoh61x->irq_en_reg[i] != ricoh61x->irq_en_cache[i]) { + if (2 == i) + printk("[%s-%d] set 0x%02X to 0x%02X\n",__func__,__LINE__,irq_en_add[i],ricoh61x->irq_en_reg[i]); + if (!WARN_ON(ricoh61x_write(ricoh61x->dev, + irq_en_add[i], + ricoh61x->irq_en_reg[i]))) + ricoh61x->irq_en_cache[i] = + ricoh61x->irq_en_reg[i]; + } + } + + if (ricoh61x->intc_inten_reg != ricoh61x->intc_inten_cache) { + if (!WARN_ON(ricoh61x_write(ricoh61x->dev, + RICOH61x_INTC_INTEN, ricoh61x->intc_inten_reg))) + ricoh61x->intc_inten_cache = ricoh61x->intc_inten_reg; + } + + mutex_unlock(&ricoh61x->irq_lock); +} + +static int ricoh61x_irq_set_type(struct irq_data *irq_data, unsigned int type) +{ + struct ricoh61x *ricoh61x = irq_data_get_irq_chip_data(irq_data); + unsigned int __irq = irq_data->irq - ricoh61x->irq_base; + const struct ricoh61x_irq_data *data = &ricoh61x_irqs[__irq]; + int val = 0; + int gpedge_index; + int gpedge_bit_pos; + + if (data->int_type & GPIO_INT) { + gpedge_index = data->int_en_bit / 4; + gpedge_bit_pos = data->int_en_bit % 4; + + if (type & IRQ_TYPE_EDGE_FALLING) + val |= 0x2; + + if (type & IRQ_TYPE_EDGE_RISING) + val |= 0x1; + + ricoh61x->gpedge_reg[gpedge_index] &= ~(3 << gpedge_bit_pos); + ricoh61x->gpedge_reg[gpedge_index] |= (val << gpedge_bit_pos); + ricoh61x_irq_unmask(irq_data); + } + return 0; +} + +#ifdef CONFIG_PM_SLEEP +static int ricoh61x_irq_set_wake(struct irq_data *irq_data, unsigned int on) +{ + struct ricoh61x *ricoh61x = irq_data_get_irq_chip_data(irq_data); + return irq_set_irq_wake(ricoh61x->chip_irq, on); /* i2c->irq */ +} +#else +#define ricoh61x_irq_set_wake NULL +#endif + +static irqreturn_t ricoh61x_irq(int irq, void *data) +{ + struct ricoh61x *ricoh61x = data; + u8 int_sts[MAX_INTERRUPT_MASKS]; + u8 master_int; + int i; + int ret; + int isIrqHandled = 0; + unsigned int rtc_int_sts = 0; + + /* printk("PMU: %s: irq=%d\n", __func__, irq); */ + /* disable_irq_nosync(irq); */ + /* Clear the status */ + for (i = 0; i < MAX_INTERRUPT_MASKS; i++) + int_sts[i] = 0; + + ret = ricoh61x_read(ricoh61x->dev, RICOH61x_INTC_INTMON, + &master_int); +// printk(KERN_INFO "PMU1: %s: master_int=0x%x\n", __func__, master_int); + if (ret < 0) { + dev_err(ricoh61x->dev, "Error in reading reg 0x%02x " + "error: %d\n", RICOH61x_INTC_INTMON, ret); + return IRQ_HANDLED; + } + + for (i = 0; i < MAX_INTERRUPT_MASKS; ++i) { + /* Even if INTC_INTMON register = 1, INT signal might not + * output because INTC_INTMON register indicates only interrupt + * facter level. + * So remove the following procedure + */ + if (!(master_int & main_int_type[i])) + continue; + + ret = ricoh61x_read(ricoh61x->dev, + irq_mon_add[i], &int_sts[i]); +// printk(KERN_INFO "PMU2: %s: int_sts[%d]=0x%x (add=0x%X)\n", +// __func__, i, int_sts[i], irq_mon_add[i]); + if (ret < 0) { + dev_err(ricoh61x->dev, "Error in reading reg 0x%02x " + "error: %d\n", irq_mon_add[i], ret); + int_sts[i] = 0; + continue; + } + if (!int_sts[i]) + continue; + + if (main_int_type[i] & RTC_INT) { + /* Changes status bit position + from RTCCNT2 to RTCCNT1 */ + rtc_int_sts = 0; + if (int_sts[i] & 0x1) + rtc_int_sts |= BIT(6); + if (int_sts[i] & 0x4) + rtc_int_sts |= BIT(0); + } + + if(irq_clr_add[i] == RICOH61x_INT_IR_RTC) + { + int_sts[i] &= ~0x85; + ret = ricoh61x_write(ricoh61x->dev, + irq_clr_add[i], int_sts[i]); + if (ret < 0) { + dev_err(ricoh61x->dev, "Error in writing reg 0x%02x " + "error: %d\n", irq_clr_add[i], ret); + } + } + else + { + if ((irq_clr_add[i] == RICOH61x_INT_IR_SYS) && (int_sts[i] & 0x40)) { + isIrqHandled = 1; +// printk(KERN_INFO "PMU2: Watchdog timeout triggered. ===============\n", __func__); +// return IRQ_HANDLED; + } + ret = ricoh61x_write(ricoh61x->dev, + irq_clr_add[i], ~int_sts[i]); + if (ret < 0) { + dev_err(ricoh61x->dev, "Error in writing reg 0x%02x " + "error: %d\n", irq_clr_add[i], ret); + } + } + + /* Mask Charger Interrupt */ + if (main_int_type[i] & CHG_INT) { + if (int_sts[i]) + ret = ricoh61x_write(ricoh61x->dev, + irq_en_add[i], 0xff); + if (ret < 0) { + dev_err(ricoh61x->dev, + "Error in write reg 0x%02x error: %d\n", + irq_en_add[i], ret); + } + } + /* Mask ADC Interrupt */ + if (main_int_type[i] & ADC_INT) { + if (int_sts[i]) + ret = ricoh61x_write(ricoh61x->dev, + irq_en_add[i], 0); + if (ret < 0) { + dev_err(ricoh61x->dev, + "Error in write reg 0x%02x error: %d\n", + irq_en_add[i], ret); + } + } + + if (main_int_type[i] & RTC_INT) + int_sts[i] = rtc_int_sts; + + } + + /* Merge gpio interrupts for rising and falling case*/ + int_sts[6] |= int_sts[7]; + + /* Call interrupt handler if enabled */ + for (i = 0; i < RICOH61x_NR_IRQS; ++i) { + const struct ricoh61x_irq_data *data = &ricoh61x_irqs[i]; + if ((int_sts[data->mask_reg_index] & (1 << data->int_en_bit)) && + (ricoh61x->group_irq_en[data->master_bit] & + (1 << data->grp_index))) + { + isIrqHandled = 1; + handle_nested_irq(ricoh61x->irq_base + i); + } + } + if (! isIrqHandled) { + printk(KERN_INFO "PMU2: unhandled irq. ===============\n", __func__); + for (i = 0; i < MAX_INTERRUPT_MASKS; ++i) { + printk(KERN_INFO "PMU2: %s: int_sts[%d]=0x%x main_int_type[%d]=0x%X\n", + __func__, i, int_sts[i], i, main_int_type[i]); + } + } + +// printk(KERN_INFO "PMU: %s: out\n", __func__); + return IRQ_HANDLED; +} + +static struct irq_chip ricoh61x_irq_chip = { + .name = "ricoh619", + .irq_mask = ricoh61x_irq_mask, + .irq_unmask = ricoh61x_irq_unmask, + .irq_bus_lock = ricoh61x_irq_lock, + .irq_bus_sync_unlock = ricoh61x_irq_sync_unlock, + .irq_set_type = ricoh61x_irq_set_type, + .irq_set_wake = ricoh61x_irq_set_wake, +}; + +int ricoh61x_irq_init(struct ricoh61x *ricoh61x, int irq, + int irq_base) +{ + int i, ret; + u8 reg_data = 0; + + if (!irq_base) { + dev_warn(ricoh61x->dev, "No interrupt support on IRQ base\n"); + return -EINVAL; + } + + mutex_init(&ricoh61x->irq_lock); + ret = ricoh61x_read(ricoh61x->dev, + RICOH61x_INT_IR_CHGSTS1, ®_data); + if (ret < 0) + dev_err(ricoh61x->dev, "Error in writing reg 0x%02x " + "error: %d\n", RICOH61x_INT_IR_CHGSTS1, ret); + + if (reg_data & 0x02) { + g_full_flag = 1; + } else { + g_full_flag = 0; + } + printk(KERN_INFO "PMU: %s: g_full_flag: %d, CHGSTS1: 0x%02x\n", + __func__, g_full_flag, reg_data); + + /* Initialize all locals to 0 */ + for (i = 0; i < 2; i++) { + ricoh61x->irq_en_cache[i] = 0; + ricoh61x->irq_en_reg[i] = 0; + } + /* Initialize rtc */ + ricoh61x->irq_en_cache[2] = 0x20; + ricoh61x->irq_en_reg[2] = 0x20; + + /* Initialize all locals to 0 */ + for (i = 3; i < 8; i++) { + ricoh61x->irq_en_cache[i] = 0; + ricoh61x->irq_en_reg[i] = 0; + } + /* Charger Mask register must be set to 0xff for masking Int output. */ + for (i = 8; i < MAX_INTERRUPT_MASKS; i++) { + ricoh61x->irq_en_cache[i] = 0xff; + ricoh61x->irq_en_reg[i] = 0xff; + } + + ricoh61x->intc_inten_cache = 0; + ricoh61x->intc_inten_reg = 0; + for (i = 0; i < MAX_GPEDGE_REG; i++) { + ricoh61x->gpedge_cache[i] = 0; + ricoh61x->gpedge_reg[i] = 0; + } + + /* Initailize all int register to 0 */ + for (i = 0; i < MAX_INTERRUPT_MASKS; i++) { + ret = ricoh61x_write(ricoh61x->dev, + irq_en_add[i], + ricoh61x->irq_en_reg[i]); + if (ret < 0) + dev_err(ricoh61x->dev, "Error in writing reg 0x%02x " + "error: %d\n", irq_en_add[i], ret); + } + + for (i = 0; i < MAX_GPEDGE_REG; i++) { + ret = ricoh61x_write(ricoh61x->dev, + gpedge_add[i], + ricoh61x->gpedge_reg[i]); + if (ret < 0) + dev_err(ricoh61x->dev, "Error in writing reg 0x%02x " + "error: %d\n", gpedge_add[i], ret); + } + + ret = ricoh61x_write(ricoh61x->dev, RICOH61x_INTC_INTEN, 0x0); + if (ret < 0) + dev_err(ricoh61x->dev, "Error in writing reg 0x%02x " + "error: %d\n", RICOH61x_INTC_INTEN, ret); + + /* Clear all interrupts in case they woke up active. */ + for (i = 0; i < MAX_INTERRUPT_MASKS; i++) { + if (irq_clr_add[i] != RICOH61x_INT_IR_RTC) { + ret = ricoh61x_write(ricoh61x->dev, + irq_clr_add[i], 0); + if (ret < 0) + dev_err(ricoh61x->dev, "Error in writing reg 0x%02x " + "error: %d\n", irq_clr_add[i], ret); + } else { + ret = ricoh61x_read(ricoh61x->dev, + RICOH61x_INT_IR_RTC, ®_data); + if (ret < 0) + dev_err(ricoh61x->dev, "Error in reading reg 0x%02x " + "error: %d\n", RICOH61x_INT_IR_RTC, ret); + reg_data &= 0xf0; + ret = ricoh61x_write(ricoh61x->dev, + RICOH61x_INT_IR_RTC, reg_data); + if (ret < 0) + dev_err(ricoh61x->dev, "Error in writing reg 0x%02x " + "error: %d\n", RICOH61x_INT_IR_RTC, ret); + } + } + + ricoh61x->irq_base = irq_base; + ricoh61x->chip_irq = irq; + + for (i = 0; i < RICOH61x_NR_IRQS; i++) { + int __irq = i + ricoh61x->irq_base; + irq_set_chip_data(__irq, ricoh61x); + irq_set_chip_and_handler(__irq, &ricoh61x_irq_chip, + handle_simple_irq); + irq_set_nested_thread(__irq, 1); +#ifdef CONFIG_ARM + set_irq_flags(__irq, IRQF_VALID); +#endif + } + + ret = request_threaded_irq(irq, NULL, ricoh61x_irq, + IRQ_TYPE_LEVEL_LOW|IRQF_DISABLED|IRQF_ONESHOT, + "ricoh61x", ricoh61x); + if (ret < 0) + dev_err(ricoh61x->dev, "Error in registering interrupt " + "error: %d\n", ret); + if (!ret) { + device_init_wakeup(ricoh61x->dev, 1); + enable_irq_wake(irq); + } + + return ret; +} + +int ricoh61x_irq_exit(struct ricoh61x *ricoh61x) +{ + if (ricoh61x->chip_irq) + free_irq(ricoh61x->chip_irq, ricoh61x); + return 0; +} + |