Exemple #1
0
static void dockin_isr_work_function(struct work_struct *dat)
{
	struct i2c_client *client = charger->client;

	int dock_in = gpio_dock_in;
	int ac_ok = GPIO_AC_OK;

	wake_lock(&charger->wake_lock_dockin);
	mutex_lock(&charger->dockin_lock);

	if (gpio_get_value(dock_in)) {
		if (!gpio_get_value(ac_ok)) {
			SMB_NOTICE("dc_in=H & ac_ok=L\n");
			cable_type_detect();
		}
	} else {
		if (!gpio_get_value(ac_ok)) {
			SMB_NOTICE("dc_in=L & ac_ok=L\n");
			msleep(40);
			cable_type_detect();
		}
	}

	mutex_unlock(&charger->dockin_lock);
	wake_unlock(&charger->wake_lock_dockin);
}
/* workqueue function */
static int cable_type_detect(void)
{
	struct i2c_client *client = charger->client;
	u8 retval;
	int  success = 0;
	int gpio = TEGRA_GPIO_PV1;

	if(grouper_query_pcba_revision() <= 0x02)
		return 0;

	mutex_lock(&charger->cable_lock);

	if (gpio_get_value(gpio)) {
			printk("INOK=H\n");
			success = battery_callback(non_cable);
	} else {
			printk("INOK=L\n");

			/* cable type dection */
			retval = smb347_read(client, smb347_STS_REG_E);
			SMB_NOTICE("Reg3F : 0x%02x\n", retval);
			if(retval & USBIN) {	//USBIN
					retval = smb347_read(client, smb347_STS_REG_D);
					SMB_NOTICE("Reg3E : 0x%02x\n", retval);
				if(retval & APSD_OK) {	//APSD completed
						retval &= APSD_RESULT;
					if(retval == APSD_CDP) {	//APSD resulted
							printk("Cable: CDP\n");
							success = battery_callback(ac_cable);
					} else if(retval == APSD_DCP) {
							printk("Cable: DCP\n");
							success = battery_callback(ac_cable);
					} else if(retval == APSD_OTHER) {
							printk("Cable: OTHER\n");
					} else if(retval == APSD_SDP) {
							printk("Cable: SDP\n");
							success = battery_callback(usb_cable);
					} else
							printk("Unkown Plug In Cable type !\n");
				}else
					printk("APSD not completed\n");
			}
			else
			{
					printk("USBIN=0\n");
			}
	}

	mutex_unlock(&charger->cable_lock);

	return success;
}
void smb345_otg_status(bool on)
{
	struct i2c_client *client = charger->client;
	int ret;

	SMB_NOTICE("otg function: %s\n", on ? "on" : "off");

	if (on) {
		otg_on = true;
		/* ENABLE OTG */
		ret = smb345_configure_otg(client);
		if (ret < 0) {
			dev_err(&client->dev, "%s() error in configuring"
				"otg..\n", __func__);
			return;
		}
		if (wireless_is_plugged())
			wireless_reset();
		return;
	} else
		otg_on = false;

	if (wireless_is_plugged())
		wireless_set();
}
static int smb345_inok_irq(struct smb345_charger *smb)
{
	int err = 0 ;
	unsigned gpio = GPIO_AC_OK;
	unsigned irq_num = gpio_to_irq(gpio);

	err = gpio_request(gpio, "smb345_inok");
	if (err) {
		SMB_ERR("gpio %d request failed \n", gpio);
	}

	err = gpio_direction_input(gpio);
	if (err) {
		SMB_ERR("gpio %d unavaliable for input \n", gpio);
	}

	err = request_irq(irq_num, smb345_inok_isr, IRQF_TRIGGER_FALLING |IRQF_TRIGGER_RISING|IRQF_SHARED,
		"smb345_inok", smb);
	if (err < 0) {
		SMB_ERR("%s irq %d request failed \n","smb345_inok", irq_num);
		goto fault ;
	}
	enable_irq_wake(irq_num);
	SMB_NOTICE("GPIO pin irq %d requested ok, smb345_INOK = %s\n", irq_num, gpio_get_value(gpio)? "H":"L");
	return 0;

fault:
	gpio_free(gpio);
	return err;
}
static void wireless_isr_work_function(struct work_struct *dat)
{
	if (delayed_work_pending(&charger->wireless_isr_work))
		cancel_delayed_work(&charger->wireless_isr_work);

	SMB_NOTICE("wireless state = %d\n", wireless_is_plugged());

	if (otg_on) {
		SMB_NOTICE("bypass wireless isr due to otg_on\n");
		return;
	}

	if (wireless_is_plugged())
		wireless_set();
	else
		wireless_reset();
}
Exemple #6
0
void usb_det_cable_callback(unsigned cable_type)
{
	usb_det_cable_type = cable_type;
	SMB_NOTICE("usb_det_cable_type=%d\n", usb_det_cable_type);

	if(unknow_cable == charger->cur_cable_type) {
		cable_type_detect();
	}
}
static void wireless_det_work_function(struct work_struct *dat)
{
	if (otg_on) {
		SMB_NOTICE("bypass wireless isr due to otg_on\n");
		return;
	}
	if (wireless_is_plugged())
		wireless_set();
}
void reconfig_AICL(void)
{
	struct i2c_client *client = charger->client;

	if (ac_on && !gpio_get_value(GPIO_AC_OK)) {
		int retval;
		retval = smb345_read(client, smb345_STS_REG_E);
		if (retval < 0)
			dev_err(&client->dev, "%s(): Failed in reading 0x%02x",
			__func__, smb345_STS_REG_E);
		else {
			SMB_NOTICE("Status Reg E=0x%02x\n", retval);

			if ((retval & 0xF) <= 0x1) {
				SMB_NOTICE("reconfig input current limit\n");
				smb345_set_InputCurrentlimit(client, 1200);
			}
		}
	}
}
static void wireless_isr_work_function(struct work_struct *dat)
{
	if (delayed_work_pending(&charger->wireless_isr_work))
		cancel_delayed_work(&charger->wireless_isr_work);

	SMB_NOTICE("wireless state = %d\n", wireless_is_plugged());

	if (wireless_is_plugged())
		wireless_set();
	else
		wireless_reset();
}
int smb345_config_thermal_limit(void)
{
	struct i2c_client *client = charger->client;
	int ret = 0, retval, setting = 0;

	ret = smb345_volatile_writes(client, smb345_ENABLE_WRITE);
	if (ret < 0) {
		dev_err(&client->dev, "%s() charger enable write error..\n", __func__);
		goto error;
	}

	retval = smb345_read(client, smb345_HRD_SFT_TEMP);
	if (retval < 0) {
		dev_err(&client->dev, "%s(): Failed in reading 0x%02x",
				__func__, smb345_HRD_SFT_TEMP);
		goto error;
	}

	setting = retval & HOT_LIMIT_MASK;
	if (setting != 0x33) {
		setting = retval & (~HOT_LIMIT_MASK);
		setting |= 0x33;
		SMB_NOTICE("Set HRD SFT limit, retval=%x setting=%x\n", retval, setting);
		ret = smb345_write(client, smb345_HRD_SFT_TEMP, setting);
		if (ret < 0) {
			dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register"
				"0x%02x\n", __func__, setting, smb345_HRD_SFT_TEMP);
			goto error;
		}
	} else
		SMB_NOTICE("Bypass set HRD SFT limit=%x\n", retval);

	ret = smb345_volatile_writes(client, smb345_DISABLE_WRITE);
	if (ret < 0) {
		dev_err(&client->dev, "%s() charger enable write error..\n", __func__);
		goto error;
	}
error:
	return ret;
}
int smb345_vflt_setting(void)
{
	struct i2c_client *client = charger->client;
	u8 ret = 0, setting;

	ret = smb345_volatile_writes(client, smb345_ENABLE_WRITE);
	if (ret < 0) {
		dev_err(&client->dev, "%s() error in smb345 volatile writes \n", __func__);
		goto error;
	}

	ret = smb345_read(client, smb345_FLOAT_VLTG);
	if (ret < 0) {
		dev_err(&client->dev, "%s() error in smb345 read \n", __func__);
		goto error;
	}

	setting = ret & FLOAT_VOLT_MASK;
	if (setting != FLOAT_VOLT_43V) {
		setting = ret & (~FLOAT_VOLT_MASK);
		setting |= FLOAT_VOLT_43V;
		SMB_NOTICE("Set Float Volt, retval=%x setting=%x\n", ret, setting);
		ret = smb345_write(client, smb345_FLOAT_VLTG, setting);
		if (ret < 0) {
			dev_err(&client->dev, "%s() error in smb345 write \n", __func__);
			goto error;
		}
	} else
		SMB_NOTICE("Bypass set Float Volt=%x\n", ret);

	ret = smb345_volatile_writes(client, smb345_DISABLE_WRITE);
	if (ret < 0) {
		dev_err(&client->dev, "%s() error in smb345 volatile writes \n", __func__);
		goto error;
	}

error:
	return ret;
}
static void cable_det_work_function(struct work_struct *dat)
{
	struct i2c_client *client = charger->client;

	if (delayed_work_pending(&charger->cable_det_work))
		cancel_delayed_work(&charger->cable_det_work);

	if (ac_on && !gpio_get_value(GPIO_AC_OK)) {
		int retval;
		retval = smb345_read(client, smb345_STS_REG_E);
		if (retval < 0)
			dev_err(&client->dev, "%s(): Failed in reading 0x%02x",
			__func__, smb345_STS_REG_E);
		else {
			SMB_NOTICE("Status Reg E=0x02%x\n", retval);

			if ((retval & 0xF) <= 0x1) {
				SMB_NOTICE("reconfig input current limit\n");
				smb345_set_InputCurrentlimit(client, 1200);
			}
		}
	}
}
static irqreturn_t smb345_inok_isr(int irq, void *dev_id)
{
	struct smb345_charger *smb = dev_id;
	int status = gpio_get_value(GPIO_AC_OK);

	SMB_NOTICE("VBUS_DET = %s\n", status ? "H" : "L");

	if (ac_on && !status)
		queue_delayed_work(smb345_wq, &smb->cable_det_work, 0);
	else {
		if (delayed_work_pending(&charger->cable_det_work))
			cancel_delayed_work(&charger->cable_det_work);
	}

	return IRQ_HANDLED;
}
Exemple #14
0
static int __init smb347_init(void)
{
	project_id = grouper_get_project_id();
	pcba_ver = grouper_query_pcba_revision();
	u32 project_info = grouper_get_project_id();

	if (project_info == GROUPER_PROJECT_NAKASI_3G)
		gpio_dock_in = TEGRA_GPIO_PO5;
	else
		gpio_dock_in = TEGRA_GPIO_PU4;

	SMB_NOTICE("project_id=%x, pcba_ver=%d, dock_in_gpio=%d\n",
		project_id, pcba_ver, gpio_dock_in);

	return i2c_add_driver(&smb347_i2c_driver);
}
static int smb345_wireless_en_config(struct smb345_charger *smb)
{
	int err = 0 ;

	err = gpio_request(charger->wpc_en1, "WPC_EN1");
	if (err)
		return -ENODEV;
	err = gpio_request(charger->wpc_en2, "WPC_EN2");
	if (err)
		goto fault;

	gpio_set_value(charger->wpc_en1, 0);
	gpio_set_value(charger->wpc_en2, 0);

	SMB_NOTICE("GPIO pin %d, %d requested ok, wpc_en1 = %s, wpc_en2 = %s\n",
		charger->wpc_en1, charger->wpc_en2, gpio_get_value(charger->wpc_en1) ? "H" : "L",
		gpio_get_value(charger->wpc_en2) ? "H" : "L");

	return 0;
fault:
	gpio_free(charger->wpc_en1);
	return err;
}
Exemple #16
0
/* workqueue function */
static int cable_type_detect(void)
{
	struct i2c_client *client = charger->client;
	u8 retval;
	int  success = 0;
	int ac_ok = GPIO_AC_OK;
	int dock_in = gpio_dock_in;

	/*
	printk("cable_type_detect %d %lu %d %x jiffies=%lu %lu+\n",
	charger->old_cable_type,
	charger->time_of_1800mA_limit,
	gpio_get_value(gpio),
	time_after(charger->time_of_1800mA_limit+(4*HZ), jiffies ),
	jiffies,
	charger->time_of_1800mA_limit+(ADAPTER_PROTECT_DELAY*HZ));
	*/

	if((pcba_ver <= GROUPER_PCBA_ER2) && (project_id == GROUPER_PROJECT_NAKASI))
		return 0;

	mutex_lock(&charger->cable_lock);

	if ((charger->old_cable_type == ac_cable) &&
	charger->time_of_1800mA_limit && gpio_get_value(ac_ok) &&
	time_after(charger->time_of_1800mA_limit+
					ADAPTER_PROTECT_DELAY, jiffies)) {
		smb347_set_InputCurrentlimit(client, 900);
		charger->test_1800mA_fail = 1;
		queue_delayed_work(smb347_wq,
				&charger->test_fail_clear_work, 1*HZ);
	}

	if (gpio_get_value(ac_ok)) {
		printk(KERN_INFO "INOK=H\n");
		charger->cur_cable_type = non_cable;
		smb347_set_InputCurrentlimit(client, 900);
		success = battery_callback(non_cable);
#ifdef TOUCH_CALLBACK_ENABLED
               touch_callback(non_cable);
#endif
		wake_unlock(&charger_wakelock);
	} else {
		printk(KERN_INFO "INOK=L\n");
		retval = smb347_read(client, smb347_INTR_STS_E);
		SMB_NOTICE("Reg39 : 0x%02x\n", retval);
		if (!(retval & DCIN_OV_UV_STS) && !gpio_get_value(dock_in)) {
			SMB_NOTICE("DC_IN\n");
			success = battery_callback(ac_cable);
		} else {

			/* cable type dection */
			retval = smb347_read(client, smb347_STS_REG_E);
			SMB_NOTICE("Reg3F : 0x%02x\n", retval);
			if (retval & USBIN) {
				SMB_NOTICE("USB_IN\n");
				retval = smb347_read(client, smb347_STS_REG_D);
				SMB_NOTICE("Reg3E : 0x%02x\n", retval);
				if (retval & APSD_OK) {
						retval &= APSD_RESULT;
					if (retval == APSD_CDP) {
						printk(KERN_INFO "Cable: CDP\n");
						charger->cur_cable_type = ac_cable;
						success = battery_callback(ac_cable);
#ifdef TOUCH_CALLBACK_ENABLED
	                                    touch_callback(ac_cable);
#endif
					} else if (retval == APSD_DCP) {
						printk(KERN_INFO "Cable: DCP\n");
						charger->cur_cable_type = ac_cable;
						success = battery_callback(ac_cable);
#ifdef TOUCH_CALLBACK_ENABLED
	                                    touch_callback(ac_cable);
#endif
					} else if (retval == APSD_OTHER) {
						charger->cur_cable_type = ac_cable;
						success = battery_callback(ac_cable);
#ifdef TOUCH_CALLBACK_ENABLED
	                                   touch_callback(ac_cable);
#endif
						printk(KERN_INFO "Cable: OTHER\n");
					} else if (retval == APSD_SDP) {
						printk(KERN_INFO "Cable: SDP\n");
						charger->cur_cable_type = usb_cable;
						success = battery_callback(usb_cable);
#ifdef TOUCH_CALLBACK_ENABLED
	                                    touch_callback(usb_cable);
#endif
					} else {
						charger->cur_cable_type = unknow_cable;
						printk(KERN_INFO "Unkown Plug In Cable type !\n");

						if(usb_det_cable_type) {
							printk(KERN_INFO "Use usb det %s cable to report\n",
								(usb_det_cable_type == ac_cable) ? "ac" : "usb");
							charger->cur_cable_type = usb_det_cable_type;
							success = battery_callback(usb_det_cable_type);
						}
					}
				} else {
					charger->cur_cable_type = unknow_cable;
					printk(KERN_INFO "APSD not completed\n");
				}
			} else {
				charger->cur_cable_type = unknow_cable;
				printk(KERN_INFO "USBIN=0\n");
			}
		}
	}

	if (charger->cur_cable_type == ac_cable &&
		charger->old_cable_type != ac_cable &&
		charger->test_1800mA_fail == 0) {
		wake_lock(&charger_wakelock);
		queue_delayed_work(smb347_wq, &charger->curr_limit_work,
					DELAY_FOR_CURR_LIMIT_RECONF*HZ);
	}
	charger->old_cable_type = charger->cur_cable_type;

	mutex_unlock(&charger->cable_lock);
	return success;
}
int usb_cable_type_detect(unsigned int chgr_type)
{
	struct i2c_client *client = charger->client;
	int  success = 0;

	mutex_lock(&charger->usb_lock);

	if (chgr_type == CHARGER_NONE) {
		SMB_NOTICE("INOK=H\n");
		if (wpc_en) {
			if (disable_DCIN) {
				SMB_NOTICE("enable wpc_pok, enable DCIN\n");
				disable_DCIN = false;
				enable_irq_wake(gpio_to_irq(charger->wpc_pok_gpio));
				enable_irq(gpio_to_irq(charger->wpc_pok_gpio));
				gpio_set_value(charger->wpc_en1, 0);
				gpio_set_value(charger->wpc_en2, 0);
			}
		}
		success =  bq27541_battery_callback(non_cable);
		touch_callback(non_cable);
	} else {
		SMB_NOTICE("INOK=L\n");

		if (chgr_type == CHARGER_SDP) {
			SMB_NOTICE("Cable: SDP\n");
			smb345_vflt_setting();
			success =  bq27541_battery_callback(usb_cable);
			touch_callback(usb_cable);
		} else {
			if (chgr_type == CHARGER_CDP) {
				SMB_NOTICE("Cable: CDP\n");
			} else if (chgr_type == CHARGER_DCP) {
				SMB_NOTICE("Cable: DCP\n");
			} else if (chgr_type == CHARGER_OTHER) {
				SMB_NOTICE("Cable: OTHER\n");
			} else if (chgr_type == CHARGER_ACA) {
				SMB_NOTICE("Cable: ACA\n");
			} else {
				SMB_NOTICE("Cable: TBD\n");
				smb345_vflt_setting();
				success =  bq27541_battery_callback(usb_cable);
				touch_callback(usb_cable);
				goto done;
			}
			smb345_set_InputCurrentlimit(client, 1200);
			smb345_vflt_setting();
			success =  bq27541_battery_callback(ac_cable);
			touch_callback(ac_cable);
			if (wpc_en) {
				if (delayed_work_pending(&charger->wireless_set_current_work))
					cancel_delayed_work(&charger->wireless_set_current_work);
				if (!disable_DCIN) {
					SMB_NOTICE("AC cable detect, disable wpc_pok, disable DCIN");
					disable_DCIN = true;
					disable_irq(gpio_to_irq(charger->wpc_pok_gpio));
					disable_irq_wake(gpio_to_irq(charger->wpc_pok_gpio));
					gpio_set_value(charger->wpc_en1, 1);
					gpio_set_value(charger->wpc_en2, 1);
					mdelay(200);
					if (wireless_on)
						wireless_reset();
				}
			}
		}
	}
done:
	mutex_unlock(&charger->usb_lock);
	return success;
}
static irqreturn_t smb345_inok_isr(int irq, void *dev_id)
{
	SMB_NOTICE("VBUS_DET = %s\n", gpio_get_value(GPIO_AC_OK) ? "H" : "L");

	return IRQ_HANDLED;
}
int
smb345_set_WCInputCurrentlimit(struct i2c_client *client, u32 current_setting)
{
	int ret = 0, retval;
	u8 setting;

	charger->wpc_curr_limit_count++;

	ret = smb345_volatile_writes(client, smb345_ENABLE_WRITE);
	if (ret < 0) {
		dev_err(&client->dev, "%s() error in configuring charger..\n",
								__func__);
		goto error;
	}

	if (current_setting != 0) {
		retval = smb345_read(client, smb345_CHRG_CRNTS);
		if (retval < 0) {
			dev_err(&client->dev, "%s(): Failed in reading 0x%02x",
				__func__, smb345_CHRG_CRNTS);
			goto error;
		}

		setting = retval & 0x0F;
		if (current_setting == 2000)
			setting |= 0x70;
		else if (current_setting == 1800)
			setting |= 0x60;
		else if (current_setting == 1200)
			setting |= 0x40;
		else if (current_setting == 900)
			setting |= 0x30;
		else if (current_setting == 700)
			setting |= 0x20;
		else if (current_setting == 500)
			setting |= 0x10;
		else if (current_setting == 300)
			setting |= 0x00;
		else
			setting |= 0x20;

		SMB_NOTICE("Set ICL=%u retval =%x setting=%x\n",
			current_setting, retval, setting);

		ret = smb345_write(client, smb345_CHRG_CRNTS, setting);
		if (ret < 0) {
			dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register"
				"0x%02x\n", __func__, setting, smb345_CHRG_CRNTS);
			goto error;
		}

		charger->wpc_curr_limit = current_setting;
	}

	if (current_setting == 300) {
		retval = smb345_read(client, smb345_VRS_FUNC);
		if (retval < 0) {
			dev_err(&client->dev, "%s(): Failed in reading 0x%02x",
					__func__, smb345_VRS_FUNC);
			goto error;
		}

		setting = retval & (~(BIT(4)));
		SMB_NOTICE("Disable AICL, retval=%x setting=%x\n", retval, setting);
		ret = smb345_write(client, smb345_VRS_FUNC, setting);
		if (ret < 0) {
			dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register"
				"0x%02x\n", __func__, setting, smb345_VRS_FUNC);
			goto error;
		}
	}

	ret = smb345_volatile_writes(client, smb345_DISABLE_WRITE);
	if (ret < 0) {
		dev_err(&client->dev, "%s() error in configuring charger..\n",
								__func__);
		goto error;
	}

error:
	return ret;
}
int smb345_config_thermal_charging(int temp, int volt, int rule)
{
	struct i2c_client *client = charger->client;
	int ret = 0, retval, setting = 0;
	int BAT_Mid_Temp = BAT_Mid_Temp_Wired;

	if (rule == THERMAL_RULE1)
		BAT_Mid_Temp = BAT_Mid_Temp_Wired;
	else if (rule == THERMAL_RULE2)
		BAT_Mid_Temp = BAT_Mid_Temp_Wireless;

	smb345_config_thermal_limit();

	SMB_NOTICE("temp=%d, volt=%d\n", temp, volt);

	ret = smb345_volatile_writes(client, smb345_ENABLE_WRITE);
	if (ret < 0) {
		dev_err(&client->dev, "%s() charger enable write error..\n", __func__);
		goto error;
	}

	/*control float voltage*/
	retval = smb345_read(client, smb345_FLOAT_VLTG);
	if (retval < 0) {
		dev_err(&client->dev, "%s(): Failed in reading 0x%02x",
				__func__, smb345_FLOAT_VLTG);
		goto error;
	}

	setting = retval & FLOAT_VOLT_MASK;
	if (temp <= BAT_Mid_Temp
		|| (temp > BAT_Mid_Temp && volt > FLOAT_VOLT_LOW_DECIMAL)
		|| temp > BAT_Hot_Limit) {
		if (setting != FLOAT_VOLT_43V) {
			setting = retval & (~FLOAT_VOLT_MASK);
			setting |= FLOAT_VOLT_43V;
			SMB_NOTICE("Set Float Volt, retval=%x setting=%x\n", retval, setting);
			ret = smb345_write(client, smb345_FLOAT_VLTG, setting);
			if (ret < 0) {
				dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register"
					"0x%02x\n", __func__, setting, smb345_FLOAT_VLTG);
				goto error;
			}
		} else
			SMB_NOTICE("Bypass set Float Volt=%x\n", retval);
	} else {
		if (setting != FLOAT_VOLT_LOW) {
			setting = retval & (~FLOAT_VOLT_MASK);
			setting |= FLOAT_VOLT_LOW;
			SMB_NOTICE("Set Float Volt, retval=%x setting=%x\n", retval, setting);
			ret = smb345_write(client, smb345_FLOAT_VLTG, setting);
			if (ret < 0) {
				dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register"
					"0x%02x\n", __func__, setting, smb345_FLOAT_VLTG);
				goto error;
			}
		} else
			SMB_NOTICE("Bypass set Float Volt=%x\n", retval);
	}

	/*charger enable/disable*/
	retval = smb345_read(client, smb345_PIN_CTRL);
	if (retval < 0) {
		dev_err(&client->dev, "%s(): Failed in reading 0x%02x",
				__func__, smb345_PIN_CTRL);
		goto error;
	}

	setting = retval & ENABLE_PIN_CTRL_MASK;
	if (temp < BAT_Cold_Limit || temp > BAT_Hot_Limit ||
		(temp > BAT_Mid_Temp && volt > FLOAT_VOLT_LOW_DECIMAL)) {
		if (setting != 0x40) {
			SMB_NOTICE("Charger disable\n");
			smb345_charger_enable(false);
		} else
			SMB_NOTICE("Bypass charger disable\n");
	} else {
		if (setting != 0x60) {
			SMB_NOTICE("Charger enable\n");
			smb345_charger_enable(true);
		} else {
			/*interrupt status*/
			retval = smb345_read(client, smb345_INTR_STS_B);
			if (retval < 0) {
				dev_err(&client->dev, "%s(): Failed in reading 0x%02x",
					__func__, smb345_INTR_STS_B);
				goto error;
			}
			if ((retval & BAT_OVER_VOLT_MASK) == 0x40) {
				SMB_NOTICE("disable then enable charger to recover bat over-volt\n");
				smb345_charger_enable(false);
				smb345_charger_enable(true);
			} else
				SMB_NOTICE("Bypass charger enable\n");
		}
	}

	ret = smb345_volatile_writes(client, smb345_DISABLE_WRITE);
	if (ret < 0) {
		dev_err(&client->dev, "%s() charger enable write error..\n", __func__);
		goto error;
	}
error:
	return ret;
}
int
smb345_set_InputCurrentlimit(struct i2c_client *client, u32 current_setting)
{
	int ret = 0, retval;
	u8 setting = 0;

	wake_lock(&charger_wakelock);

	ret = smb345_volatile_writes(client, smb345_ENABLE_WRITE);
	if (ret < 0) {
		dev_err(&client->dev, "%s() error in configuring charger..\n",
								__func__);
		goto error;
	}

	if (charge_en_flag)
		smb345_pin_control(0);

	retval = smb345_read(client, smb345_VRS_FUNC);
	if (retval < 0) {
		dev_err(&client->dev, "%s(): Failed in reading 0x%02x",
				__func__, smb345_VRS_FUNC);
		goto error;
	}

	setting = retval & (~(BIT(4)));
	SMB_NOTICE("Disable AICL, retval=%x setting=%x\n", retval, setting);
	ret = smb345_write(client, smb345_VRS_FUNC, setting);
	if (ret < 0) {
		dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register"
			"0x%02x\n", __func__, setting, smb345_VRS_FUNC);
		goto error;
	}

	retval = smb345_read(client, smb345_CHRG_CRNTS);
	if (retval < 0) {
		dev_err(&client->dev, "%s(): Failed in reading 0x%02x",
			__func__, smb345_CHRG_CRNTS);
		goto error;
	}
	setting = retval & 0xF0;
	if(current_setting == 2000)
		setting |= 0x07;
	else if(current_setting == 1800)
		setting |= 0x06;
	else if (current_setting == 1200)
		setting |= 0x04;
	else if(current_setting == 900)
		setting |= 0x03;
	else if(current_setting == 500)
		setting |= 0x01;
	else
		setting |= 0x07;

	SMB_NOTICE("Set ICL=%u retval =%x setting=%x\n", current_setting, retval, setting);

	ret = smb345_write(client, smb345_CHRG_CRNTS, setting);
	if (ret < 0) {
		dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register"
			"0x%02x\n", __func__, setting, smb345_CHRG_CRNTS);
		goto error;
	}

	if(current_setting == 2000)
		charger->curr_limit = 2000;
	else if(current_setting == 1800)
		charger->curr_limit = 1800;
	else if (current_setting == 1200)
		charger->curr_limit = 1200;
	else if(current_setting == 900)
		charger->curr_limit = 900;
	else if(current_setting == 500)
		charger->curr_limit = 500;
	else
		charger->curr_limit = 2000;

	if (current_setting > 900) {
		charger->time_of_1800mA_limit = jiffies;
	} else{
		charger->time_of_1800mA_limit = 0;
	}

	retval = smb345_read(client, smb345_VRS_FUNC);
	if (retval < 0) {
		dev_err(&client->dev, "%s(): Failed in reading 0x%02x",
				__func__, smb345_VRS_FUNC);
		goto error;
	}

	setting = retval | BIT(4);
	SMB_NOTICE("Re-enable AICL, setting=%x\n", setting);
	msleep(20);
	ret = smb345_write(client, smb345_VRS_FUNC, setting);
	if (ret < 0) {
		dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register"
			"0x%02x\n", __func__, setting, smb345_VRS_FUNC);
			goto error;
	}

	if (charge_en_flag)
		smb345_pin_control(1);

	ret = smb345_volatile_writes(client, smb345_DISABLE_WRITE);
	if (ret < 0) {
		dev_err(&client->dev, "%s() error in configuring charger..\n",
								__func__);
		goto error;
	}

error:
	wake_unlock(&charger_wakelock);
	return ret;
}
Exemple #22
0
/* workqueue function */
static int cable_type_detect(void)
{
	struct i2c_client *client = charger->client;
	u8 retval;
	int  success = 0;
	int ac_ok = GPIO_AC_OK;

	/*
	printk("cable_type_detect %d %lu %d %x jiffies=%lu %lu+\n",
	charger->old_cable_type,
	charger->time_of_1800mA_limit,
	gpio_get_value(gpio),
	time_after(charger->time_of_1800mA_limit+(4*HZ), jiffies ),
	jiffies,
	charger->time_of_1800mA_limit+(ADAPTER_PROTECT_DELAY*HZ));
	*/

	mutex_lock(&charger->cable_lock);

	if ((charger->old_cable_type == ac_cable) &&
	charger->time_of_1800mA_limit && gpio_get_value(ac_ok) &&
	time_after(charger->time_of_1800mA_limit+
					ADAPTER_PROTECT_DELAY, jiffies)) {
		smb347_set_InputCurrentlimit(client, 900);
		charger->test_1800mA_fail = 1;
		queue_delayed_work(smb347_wq,
				&charger->test_fail_clear_work, 1*HZ);
	}

	if (gpio_get_value(ac_ok)) {
		printk(KERN_INFO "INOK=H\n");
		charger->cur_cable_type = non_cable;
		smb347_set_InputCurrentlimit(client, 900);
		success = bq27541_battery_callback(non_cable);
#ifdef TOUCH_CALLBACK_ENABLED
               touch_callback(non_cable);
#endif
		wake_unlock(&charger_wakelock);
	} else {
		printk(KERN_INFO "INOK=L\n");

		/* cable type dection */
		retval = smb347_read(client, smb347_STS_REG_E);
		SMB_NOTICE("Reg3F : 0x%02x\n", retval);
		if (retval & USBIN) {
			retval = smb347_read(client, smb347_STS_REG_D);
			SMB_NOTICE("Reg3E : 0x%02x\n", retval);
			if (retval & APSD_OK) {
					retval &= APSD_RESULT;
				if (retval == APSD_CDP) {
					printk(KERN_INFO "Cable: CDP\n");
					charger->cur_cable_type = ac_cable;
					success = bq27541_battery_callback(ac_cable);
#ifdef TOUCH_CALLBACK_ENABLED
                                    touch_callback(ac_cable);
#endif
				} else if (retval == APSD_DCP) {
					printk(KERN_INFO "Cable: DCP\n");
					charger->cur_cable_type = ac_cable;
					success = bq27541_battery_callback(ac_cable);
#ifdef TOUCH_CALLBACK_ENABLED
                                    touch_callback(ac_cable);
#endif
				} else if (retval == APSD_OTHER) {
					charger->cur_cable_type = ac_cable;
					success = bq27541_battery_callback(ac_cable);
#ifdef TOUCH_CALLBACK_ENABLED
                                   touch_callback(ac_cable);
#endif
					printk(KERN_INFO "Cable: OTHER\n");
				} else if (retval == APSD_SDP) {
					printk(KERN_INFO "Cable: SDP\n");
					charger->cur_cable_type = usb_cable;
					success = bq27541_battery_callback(usb_cable);
#ifdef TOUCH_CALLBACK_ENABLED
                                    touch_callback(usb_cable);
#endif
				} else {
					charger->cur_cable_type = unknow_cable;
					printk(KERN_INFO "Unkown Plug In Cable type !\n");

					if(ac_cable == cable_state_detect)
					{
						charger->cur_cable_type = ac_cable;
						success = bq27541_battery_callback(ac_cable);
#ifdef TOUCH_CALLBACK_ENABLED
						touch_callback(ac_cable);
#endif
						printk(KERN_INFO "Change unknow type to ac\n");
					}
					else if(usb_cable == cable_state_detect)
					{
						charger->cur_cable_type = usb_cable;
						success = bq27541_battery_callback(usb_cable);
#ifdef TOUCH_CALLBACK_ENABLED
						touch_callback(usb_cable);
#endif
						printk(KERN_INFO "Change unknow type to usb\n");
					}
				}
			} else {
				charger->cur_cable_type = unknow_cable;
				printk(KERN_INFO "APSD not completed\n");
			}
		} else {
			charger->cur_cable_type = unknow_cable;
			printk(KERN_INFO "USBIN=0\n");
		}
	}

	if (charger->cur_cable_type == ac_cable &&
		charger->old_cable_type != ac_cable &&
		charger->test_1800mA_fail == 0) {
		wake_lock(&charger_wakelock);
		queue_delayed_work(smb347_wq, &charger->curr_limit_work,
					DELAY_FOR_CURR_LIMIT_RECONF*HZ);
	}
	charger->old_cable_type = charger->cur_cable_type;

	mutex_unlock(&charger->cable_lock);
	return success;
}
int smb345_config_thermal_charging(int temp, int volt, int rule)
{
	struct i2c_client *client = charger->client;
	int ret = 0, retval, setting = 0;
	int BAT_Mid_Temp = BAT_Mid_Temp_Wired;
	/*Charger float voltage for normal temperature conditions. Default 4.3V.*/
	int flt_volt_43 = FLOAT_VOLT_43V;
	/*Charger float voltage for high temperature conditions. Default 4.1V.*/
	int flt_volt_low = FLOAT_VOLT_LOW;

	flt_volt_43 = (float_volt_setting - 3500) / 20;

	if(flt_volt_43 < 0 || flt_volt_43 > FLOAT_VOLT_43V) {
		SMB_NOTICE("BUG: Invalid float voltage setting calculated: %d\n", flt_volt_43);
		flt_volt_43 = FLOAT_VOLT_43V;
	}
	if(flt_volt_low > flt_volt_43) flt_volt_low = flt_volt_43;

	if (rule == THERMAL_RULE1)
		BAT_Mid_Temp = BAT_Mid_Temp_Wired;
	else if (rule == THERMAL_RULE2)
		BAT_Mid_Temp = BAT_Mid_Temp_Wireless;

	mdelay(100);
	smb345_config_thermal_limit();

	SMB_NOTICE("temp=%d, volt=%d\n", temp, volt);

	ret = smb345_volatile_writes(client, smb345_ENABLE_WRITE);
	if (ret < 0) {
		dev_err(&client->dev, "%s() charger enable write error..\n", __func__);
		goto error;
	}

	/*control float voltage*/
	retval = smb345_read(client, smb345_FLOAT_VLTG);
	if (retval < 0) {
		dev_err(&client->dev, "%s(): Failed in reading 0x%02x",
				__func__, smb345_FLOAT_VLTG);
		goto error;
	}

	setting = retval & FLOAT_VOLT_MASK;
	if (temp <= BAT_Mid_Temp
		|| (temp > BAT_Mid_Temp && volt > FLOAT_VOLT_LOW_DECIMAL)
		|| temp > BAT_Hot_Limit) {
		if (setting != flt_volt_43) {
			setting = retval & (~FLOAT_VOLT_MASK);
			setting |= flt_volt_43;
			SMB_NOTICE("Set Float Volt, retval=%x setting=%x V=%dmV\n", retval, setting, float_volt_setting);
			ret = smb345_write(client, smb345_FLOAT_VLTG, setting);
			if (ret < 0) {
				dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register"
					"0x%02x\n", __func__, setting, smb345_FLOAT_VLTG);
				goto error;
			}
		} else
			SMB_NOTICE("Bypass set Float Volt setting=%x V=%dmV\n", retval, float_volt_setting);
	} else {
		if (setting != flt_volt_low) {
			setting = retval & (~FLOAT_VOLT_MASK);
			setting |= flt_volt_low;
			SMB_NOTICE("Set Float Volt, retval=%x setting=%x\n", retval, setting);
			ret = smb345_write(client, smb345_FLOAT_VLTG, setting);
			if (ret < 0) {
				dev_err(&client->dev, "%s(): Failed in writing 0x%02x to register"
					"0x%02x\n", __func__, setting, smb345_FLOAT_VLTG);
				goto error;
			}
		} else
			SMB_NOTICE("Bypass set Float Volt=%x\n", retval);
	}

	/*charger enable/disable*/
	retval = smb345_read(client, smb345_PIN_CTRL);
	if (retval < 0) {
		dev_err(&client->dev, "%s(): Failed in reading 0x%02x",
				__func__, smb345_PIN_CTRL);
		goto error;
	}

	setting = retval & ENABLE_PIN_CTRL_MASK;
	if (temp < BAT_Cold_Limit || temp > BAT_Hot_Limit ||
		(temp > BAT_Mid_Temp && volt > FLOAT_VOLT_LOW_DECIMAL)) {
		if (setting != 0x40) {
			SMB_NOTICE("Charger disable\n");
			smb345_charger_enable(false);
		} else
			SMB_NOTICE("Bypass charger disable\n");
	} else {
		if (setting != 0x60) {
			SMB_NOTICE("Charger enable\n");
			smb345_charger_enable(true);
		} else {
			/*interrupt status*/
			retval = smb345_read(client, smb345_INTR_STS_B);
			if (retval < 0) {
				dev_err(&client->dev, "%s(): Failed in reading 0x%02x",
					__func__, smb345_INTR_STS_B);
				goto error;
			}
			if ((retval & BAT_OVER_VOLT_MASK) == 0x40) {
				SMB_NOTICE("disable then enable charger to recover bat over-volt\n");
				smb345_charger_enable(false);
				smb345_charger_enable(true);
			} else
				SMB_NOTICE("Bypass charger enable\n");
		}
	}

	ret = smb345_volatile_writes(client, smb345_DISABLE_WRITE);
	if (ret < 0) {
		dev_err(&client->dev, "%s() charger enable write error..\n", __func__);
		goto error;
	}
error:
	return ret;
}