static int max8971_set_bits(struct i2c_client *client, u8 reg, u8 mask, u8 data) { u8 value = 0; int ret; ret = max8971_read_reg(client, reg); if (ret < 0) goto out; value &= ~mask; value |= data; ret = max8971_write_reg(client, reg, value); out: return ret; }
static int max8971_set_bits(struct i2c_client *client, u8 reg, u8 mask, u8 data) { u8 value = 0; int ret; ret = max8971_read_reg(client, reg); if (ret < 0) { dev_err(&client->dev, "%s failed : %d\n", __func__, ret); goto out; } value &= ~mask; value |= data; ret = max8971_write_reg(client, reg, value); out: return ret; }
static void max8971_topoff_work(struct work_struct *max8971_work) { struct max8971_chip *chip; int irq_val, irq_mask, irq_name; u8 val[3]; chip = container_of(max8971_work, struct max8971_chip, topoff_work); dev_dbg(&chip->client->dev, "%s\n", __func__); chip->start_topoff_work = 0; irq_val = max8971_read_reg(chip->client, MAX8971_REG_CHGINT); irq_mask = max8971_read_reg(chip->client, MAX8971_REG_CHGINT_MASK); //printk(KERN_DEBUG "%s(%d), irq_val = %d, irq_mask = %d\n", __func__, __LINE__, irq_val , irq_mask); val[0] = max8971_read_reg(chip->client, MAX8971_REG_CHG_STAT); val[1] = max8971_read_reg(chip->client, MAX8971_REG_DETAILS1); val[2] = max8971_read_reg(chip->client, MAX8971_REG_DETAILS2); //printk(KERN_DEBUG "%s(%d), val[0] = 0x%x, val[1] = 0x%x, val[2] = 0x%x\n" // , __func__, __LINE__, val[0], val[1], val[2]); for (irq_name = MAX8971_IRQ_PWRUP_OK; irq_name < MAX8971_NR_IRQS; irq_name++) { if ((irq_val & (0x01<<irq_name)) && !(irq_mask & (0x01<<irq_name))) { max8971_charger_detail_irq(irq_name, chip, val); //printk(KERN_DEBUG "%s(%d), irq_val = %d, irq_mask = %d\n", __func__, __LINE__, irq_val , irq_mask); } } max8971_write_reg(chip->client, MAX8971_REG_CHGINT_MASK, chip->pdata->int_mask); }
static int max8971_charger_detail_irq(int irq, void *data, u8 *val) { struct max8971_chip *chip = (struct max8971_chip *)data; dev_dbg(&chip->client->dev, "val[0] = 0x%x, val[1] = 0x%x, val[2] = 0x%x\n" , val[0], val[1], val[2]); switch (irq) { case MAX8971_IRQ_PWRUP_OK: dev_dbg(&chip->client->dev, "Power Up OK Interrupt\n"); chg_flag_muic = chg_flag_muic+1; // if ((val[0] & MAX8971_DCUVP_MASK) == 0) { // check DCUVP_OK bit in CGH_STAT // Vbus is valid // // Mask interrupt regsiter // max8971_write_reg(chip->client, MAX8971_REG_PROTCMD, 0xC0); max8971_write_reg(chip->client, MAX8971_REG_CHGINT_MASK,chip->pdata->int_mask); max8971_write_reg(chip->client, MAX8971_REG_TOPOFF, 0x62); chip->chg_online = 1; cancel_delayed_work(&chip->monitor_work); schedule_delayed_work(&chip->monitor_work, 2*HZ); //max8971_set_reg(chip, 1); // DC_V valid and start charging //chip->chg_cable_type = POWER_SUPPLY_TYPE_USB; printk("%s: chip->chg_cable_type 0x%02x\n",__func__,chip->chg_cable_type); // max8971_set_reg(chip, 1); } break; case MAX8971_IRQ_THM: dev_dbg(&chip->client->dev, "Thermistor Interrupt: details-0x%x\n", (val[1] & MAX8971_THM_DTLS_MASK)); break; case MAX8971_IRQ_BAT: dev_dbg(&chip->client->dev, "Battery Interrupt: details-0x%x\n", (val[2] & MAX8971_BAT_DTLS_MASK)); switch ((val[2] & MAX8971_BAT_MASK)>>MAX8971_BAT_SHIFT) { case MAX8971_BAT_DTLS_BATDEAD: break; case MAX8971_BAT_DTLS_TIMER_FAULT: break; case MAX8971_BAT_DTLS_BATOK: break; case MAX8971_BAT_DTLS_GTBATOV: break; default: break; } break; case MAX8971_IRQ_CHG: dev_info(&chip->client->dev, "Fast Charge Interrupt: details-0x%x\n", (val[2] & MAX8971_CHG_DTLS_MASK)); switch (val[2] & MAX8971_CHG_DTLS_MASK) { case MAX8971_CHG_DTLS_DEAD_BAT: // insert event if a customer need to do something // break; case MAX8971_CHG_DTLS_PREQUAL: // insert event if a customer need to do something // break; case MAX8971_CHG_DTLS_FAST_CHARGE_CC: // insert event if a customer need to do something // break; case MAX8971_CHG_DTLS_FAST_CHARGE_CV: // insert event if a customer need to do something // #ifdef MAX8971_TOPOFF_WORKAROUND chip->chg_online = 1; if ((chip->prev_chg_dtl == MAX8971_CHG_DTLS_FAST_CHARGE_CV) && (chip->start_topoff_work = 0)) { max8971_write_reg(chip->client, MAX8971_REG_CHGINT_MASK, 0xCE); schedule_delayed_work(&chip->topoff_work, MAX8971_TOPOFF_DELAY); chip->start_topoff_work = 1; } #endif break; case MAX8971_CHG_DTLS_TOP_OFF: // insert event if a customer need to do something // break; case MAX8971_CHG_DTLS_DONE: // insert event if a customer need to do something // // Charging done and charge off automatically break; case MAX8971_CHG_DTLS_TIMER_FAULT: // insert event if a customer need to do something // break; case MAX8971_CHG_DTLS_TEMP_SUSPEND: // insert event if a customer need to do something // break; case MAX8971_CHG_DTLS_USB_SUSPEND: // insert event if a customer need to do something // break; case MAX8971_CHG_DTLS_THERMAL_LOOP_ACTIVE: // insert event if a customer need to do something // break; case MAX8971_CHG_DTLS_CHG_OFF: // insert event if a customer need to do something // break; default: break; } #ifdef MAX8971_TOPOFF_WORKAROUND if (chip->start_topoff_work == 1 ) { chip->prev_chg_dtl = MAX8971_CHG_DTLS_TOP_OFF; } else { chip->prev_chg_dtl = val[2] & MAX8971_CHG_DTLS_MASK; } #endif break; case MAX8971_IRQ_DCUVP: if ((val[1] & MAX8971_DC_UVP_MASK) == 0) { // VBUS is invalid. VDC < VDC_UVLO // max8971_set_reg(chip, 0); #ifdef MAX8971_TOPOFF_WORKAROUND if (chip->start_topoff_work == 1) { cancel_delayed_work(&chip->topoff_work); chip->start_topoff_work = 0; } #endif } dev_dbg(&chip->client->dev, "DC Under voltage Interrupt: details-0x%x\n", (val[1] & MAX8971_DC_UVP_MASK)); break; case MAX8971_IRQ_DCOVP: if (val[1] & MAX8971_DC_OVP_MASK) { // VBUS is invalid. VDC > VDC_OVLO max8971_set_reg(chip, 0); } dev_dbg(&chip->client->dev, "DC Over voltage Interrupt: details-0x%x\n", (val[1] & MAX8971_DC_OVP_MASK)); break; case MAX8971_IRQ_DCI: dev_dbg(&chip->client->dev, "DC Input Current Limit Interrupt: details-0x%x\n", (val[1] & MAX8971_DC_I_MASK)); break; case MAX8971_IRQ_DCV: dev_dbg(&chip->client->dev, "DC Input Voltage Limit Interrupt: details-0x%x\n", (val[1] & MAX8971_DC_V_MASK)); break; } return 0; }
static int max8971_set_reg(struct max8971_chip *chip, int enable) { u8 reg_val= 0; int chg_cable_type = chip->chg_cable_type; if (chip->chgcc_forced >= 5 && chip->chgcc_forced <= 31) { chg_cable_type = POWER_SUPPLY_TYPE_FORCED; } // unlock charger protection reg_val = chip->pdata->chg_proctection << MAX8971_CHGPROT_SHIFT; max8971_write_reg(chip->client, MAX8971_REG_PROTCMD, reg_val); dev_dbg(&chip->client->dev, "MAX8971_REG_PROTCMD (0x%x) = 0x%x\n", MAX8971_REG_PROTCMD, reg_val); if (enable) { /* enable charger */ dev_dbg(&chip->client->dev, "Charing enable..\n"); // Set fast charge current and timer switch(chg_cable_type) { case POWER_SUPPLY_TYPE_USB: // if( charging_mode != CHARGING_MHL ) { // // #if defined(CONFIG_MACH_VU10) || defined(CONFIG_MACH_X3) if (current_limit_request == CURRENT_LIMIT_400MA) { reg_val = ((chip->pdata->chgcc_400 << MAX8971_CHGCC_SHIFT) | (chip->pdata->fchgtime<<MAX8971_FCHGTIME_SHIFT)); } else #endif // { reg_val = ((chip->pdata->chgcc_usb500 << MAX8971_CHGCC_SHIFT) | (chip->pdata->fchgtime<<MAX8971_FCHGTIME_SHIFT)); } } else { reg_val = ((chip->pdata->chgcc_mhl400 << MAX8971_CHGCC_SHIFT) | (chip->pdata->fchgtime<<MAX8971_FCHGTIME_SHIFT)); } break; case POWER_SUPPLY_TYPE_FORCED: reg_val = (chip->chgcc_forced << MAX8971_CHGCC_SHIFT) | (chip->pdata->fchgtime << MAX8971_FCHGTIME_SHIFT); break; case POWER_SUPPLY_TYPE_MAINS: // // #if defined(CONFIG_MACH_VU10) || defined(CONFIG_MACH_X3) if (current_limit_request == CURRENT_LIMIT_400MA) { reg_val = ((chip->pdata->chgcc_400 << MAX8971_CHGCC_SHIFT) | (chip->pdata->fchgtime<<MAX8971_FCHGTIME_SHIFT)); } else #endif // { reg_val = ((chip->pdata->chgcc_ta << MAX8971_CHGCC_SHIFT) | (chip->pdata->fchgtime<<MAX8971_FCHGTIME_SHIFT)); } break; case POWER_SUPPLY_TYPE_FACTORY: reg_val = ((chip->pdata->chgcc_factory << MAX8971_CHGCC_SHIFT) | (chip->pdata->fchgtime<<MAX8971_FCHGTIME_SHIFT)); break; default : dev_dbg(&chip->client->dev, "Unknown charger cabel type!!!\n"); reg_val = ((chip->pdata->chgcc_usb500 << MAX8971_CHGCC_SHIFT) | (chip->pdata->fchgtime<<MAX8971_FCHGTIME_SHIFT)); break; } max8971_write_reg(chip->client, MAX8971_REG_FCHGCRNT, reg_val); // /* */ #if 0 //defined(CONFIG_MACH_VU10) current_limit_state = current_limit_request; #endif /* */ // dev_dbg(&chip->client->dev, "MAX8971_REG_FCHGCRNT(0x%x) = 0x%x\n", MAX8971_REG_FCHGCRNT, reg_val); // Set input current limit and charger restart threshold switch(chg_cable_type) { case POWER_SUPPLY_TYPE_USB: // if( charging_mode != CHARGING_MHL ) { reg_val = ((chip->pdata->chgrstrt << MAX8971_CHGRSTRT_SHIFT) | (chip->pdata->dcilmt_usb500 << MAX8971_DCILMT_SHIFT)); } else { reg_val = ((chip->pdata->chgrstrt << MAX8971_CHGRSTRT_SHIFT) | (chip->pdata->dcilmt_mhl400 << MAX8971_DCILMT_SHIFT)); } break; case POWER_SUPPLY_TYPE_FORCED: reg_val = (chip->pdata->chgrstrt << MAX8971_CHGRSTRT_SHIFT) | (chip->dcilmt_forced << MAX8971_DCILMT_SHIFT); break; case POWER_SUPPLY_TYPE_MAINS: if(chg_700_flag == 1){ reg_val = ((chip->pdata->chgrstrt << MAX8971_CHGRSTRT_SHIFT) | (chip->pdata->dcilmt_soc700 << MAX8971_DCILMT_SHIFT)); }else{ reg_val = ((chip->pdata->chgrstrt << MAX8971_CHGRSTRT_SHIFT) | (chip->pdata->dcilmt_ta << MAX8971_DCILMT_SHIFT)); } break; case POWER_SUPPLY_TYPE_FACTORY: reg_val = ((chip->pdata->chgrstrt << MAX8971_CHGRSTRT_SHIFT) | (chip->pdata->dcilmt_factory << MAX8971_DCILMT_SHIFT)); break; default : printk("%s: unknown chager cabel type!!!\n",__func__); reg_val = ((chip->pdata->chgrstrt << MAX8971_CHGRSTRT_SHIFT) | (chip->pdata->dcilmt_usb500 << MAX8971_DCILMT_SHIFT)); break; break; } max8971_write_reg(chip->client, MAX8971_REG_DCCRNT, reg_val); dev_dbg(&chip->client->dev, "MAX8971_REG_DCCRNT(0x%x) = 0x%02x\n", MAX8971_REG_DCCRNT, reg_val); // Set topoff condition #if 0 reg_val = ((chip->pdata->topofftime << MAX8971_TOPOFFTIME_SHIFT) | (chip->pdata->topofftshld << MAX8971_TOPOFFTSHLD_SHIFT) | (chip->pdata->chgcv << MAX8971_CHGCV_SHIFT) | (chip->pdata->ifst2p8 << MAX8971_IFST2P8_SHIFT)); #endif switch(chg_cable_type) { case POWER_SUPPLY_TYPE_USB: // if( charging_mode != CHARGING_MHL ) { reg_val = ((chip->pdata->topofftime << MAX8971_TOPOFFTIME_SHIFT) | (chip->pdata->topofftshld << MAX8971_TOPOFFTSHLD_SHIFT) | (chip->pdata->chgcv << MAX8971_CHGCV_SHIFT) | (chip->pdata->ifst2p8_usb500 << MAX8971_IFST2P8_SHIFT)); } else { reg_val = ((chip->pdata->topofftime << MAX8971_TOPOFFTIME_SHIFT) | (chip->pdata->topofftshld << MAX8971_TOPOFFTSHLD_SHIFT) | (chip->pdata->chgcv << MAX8971_CHGCV_SHIFT) | (chip->pdata->ifst2p8_mhl400 << MAX8971_IFST2P8_SHIFT)); } break; case POWER_SUPPLY_TYPE_FORCED: case POWER_SUPPLY_TYPE_MAINS: reg_val = ((chip->pdata->topofftime << MAX8971_TOPOFFTIME_SHIFT) | (chip->pdata->topofftshld << MAX8971_TOPOFFTSHLD_SHIFT) | (chip->pdata->chgcv << MAX8971_CHGCV_SHIFT) | (chip->pdata->ifst2p8_ta << MAX8971_IFST2P8_SHIFT)); break; case POWER_SUPPLY_TYPE_FACTORY: reg_val = ((chip->pdata->topofftime << MAX8971_TOPOFFTIME_SHIFT) | (chip->pdata->topofftshld << MAX8971_TOPOFFTSHLD_SHIFT) | (chip->pdata->chgcv << MAX8971_CHGCV_SHIFT) | (chip->pdata->ifst2p8_factory<< MAX8971_IFST2P8_SHIFT)); break; default : printk("%s: unknown chager cabel type!!!\n",__func__); break; } max8971_write_reg(chip->client, MAX8971_REG_TOPOFF, reg_val); dev_dbg(&chip->client->dev, "MAX8971_REG_TOPOFF(0x%x) = 0x%02x\n", MAX8971_REG_TOPOFF, reg_val); // Set temperature condition // reg_val = ((chip->pdata->regtemp << MAX8971_REGTEMP_SHIFT) | // (chip->pdata->thm_config << MAX8971_THM_CNFG_SHIFT) | // (chip->pdata->safetyreg << MAX8971_SAFETYREG_SHIFT)); // max8971_write_reg(chip->client, MAX8971_REG_TEMPREG, reg_val); // dev_dbg(&chip->client->dev, "MAX8971_REG_TEMPREG(0x%x) = 0x%02x\n", MAX8971_REG_TEMPREG, reg_val); // USB Suspend and DC Voltage Monitoring // Set DC Voltage Monitoring to Enable and USB Suspend to Disable if(chg_flag_muic >= MAX_CHARGER_INT_COUNT) // { // if(chg_cable_type == POWER_SUPPLY_TYPE_USB){ reg_val = (0x0 << MAX8971_DCMON_DIS_SHIFT) |(chip->pdata->suspend_usb << MAX8971_USB_SUS_SHIFT); } } else { reg_val = (chip->pdata->m_input_vol << MAX8971_DCMON_DIS_SHIFT) |(chip->pdata->suspend_usb << MAX8971_USB_SUS_SHIFT); } max8971_write_reg(chip->client, MAX8971_REG_CHGCNTL1, reg_val); dev_dbg(&chip->client->dev, "MAX8971_REG_CHGCNTL1(0x%x) = 0x%02x\n", MAX8971_REG_CHGCNTL1, reg_val); dev_dbg(&chip->client->dev, "chg_flag_muic = %d\n",chg_flag_muic); } else { /* disable charge */ max8971_set_bits(chip->client, MAX8971_REG_CHGCNTL1, MAX8971_USB_SUS_MASK, 1); } /* */ #if defined(CONFIG_MACH_VU10) current_limit_state = current_limit_request; #endif /* */ dev_info(&chip->client->dev, "%s\n", (enable) ? "Enable charger" : "Disable charger"); return 0; }