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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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);            
}
Esempio n. 4
0
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;
}
Esempio n. 5
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;
}