static irqreturn_t isl_valid_handler(int irq, void *dev_id)
{
	int val;
	struct isl9519q_struct *isl_chg;
	struct i2c_client *client = dev_id;

	isl_chg = i2c_get_clientdata(client);
	val = gpio_get_value_cansleep(isl_chg->valid_n_gpio);
	if (val < 0) {
		dev_err(&isl_chg->client->dev,
			"%s gpio_get_value failed for %d ret=%d\n", __func__,
			isl_chg->valid_n_gpio, val);
		goto err;
	}
	dev_dbg(&isl_chg->client->dev, "%s val=%d\n", __func__, val);

	if (val) {
		if (isl_chg->present == 1) {
			msm_charger_notify_event(&isl_chg->adapter_hw_chg,
						 CHG_REMOVED_EVENT);
			isl_chg->present = 0;
		}
	} else {
		if (isl_chg->present == 0) {
			msm_charger_notify_event(&isl_chg->adapter_hw_chg,
						 CHG_INSERTED_EVENT);
			isl_chg->present = 1;
		}
	}
err:
	return IRQ_HANDLED;
}
Example #2
0
/*
 * store_usb_chg_enable() - Enable/Disable max8903 usb charge
 */
static ssize_t store_usb_chg_enable(struct device *dev, struct device_attribute *attr,
			    const char *buf, size_t count)
{
	struct max8903_struct *max_chg;	
	char *after;
	unsigned long num;
	
	max_chg = dev_get_drvdata(dev);
	
	num = simple_strtoul(buf, &after, 10);
	if (num == 0)
	{
		/* disable max8903 usb charge */
		max_chg->usb_chg_enable = 0;
	
		/*
		 * if current is USB charger, need to stop it
		 * set the source current to 0 mA
		 */
		if (USB_CHG_TYPE__SDP == cur_chg_type){
			cancel_delayed_work(&max_chg->charge_work);	/* cancel the charger work */
			msm_set_source_current(&max_chg->adapter_hw_chg, 0);
			msm_charger_notify_event(&max_chg->adapter_hw_chg,
							CHG_ENUMERATED_EVENT);
		}
		
		/* pull the USUS up */
		gpio_direction_output(max_chg->usus, 1);
	}
	else
	{
		/* enable max8903 usb charge */
		max_chg->usb_chg_enable = 1;

		/* pull the USUS down */
		gpio_direction_output(max_chg->usus, 0);
		
		/*
		 * if current is USB charger, need to start it
		 * set the source current to 500 mA
		 */
		if (USB_CHG_TYPE__SDP == cur_chg_type){
			msm_set_source_current(&max_chg->adapter_hw_chg, 500);
			msm_charger_notify_event(&max_chg->adapter_hw_chg,
							CHG_ENUMERATED_EVENT);
		}
	}
	
	return count;
}
static void  pm8058_chg_determine_initial_state(struct msm_hardware_charger *pchg)
{

	if (pchg->get_charger_status(pchg->gpio_num)) {
		msm_charger_notify_event(pchg, CHG_INSERTED_EVENT);
	}
	enable_irq(pchg->irq);
}
static irqreturn_t pm8058_chg_handler(int irq, void *dev_id)
{
	struct msm_hardware_charger *pchg = dev_id;
	//if (pchg->get_charger_status(pchg->gpio_num)) {	/*this debounces it */
		msm_charger_notify_event(pchg, CHG_STAT_EVENT);
	//} else {
		//msm_charger_notify_event(pchg, CHG_REMOVED_EVENT);
	//}
	return IRQ_HANDLED;
}
static irqreturn_t soc_irqhandler(int irq, void *dev_id)
{
	int status = 0, temp = 0;

	temp = if_notify_msm_charger(&status);
	update_current_battery_status(status);
	if (temp)
		msm_charger_notify_event(NULL, CHG_BATT_STATUS_CHANGE);
	return IRQ_HANDLED;
}
static void isl9519q_charge(struct work_struct *isl9519_work)
{
	u16 temp;
	int ret;
	struct isl9519q_struct *isl_chg;
	int isl_charger_current;
	int mv_reading;

	isl_chg = container_of(isl9519_work, struct isl9519q_struct,
			charge_work.work);

	dev_dbg(&isl_chg->client->dev, "%s\n", __func__);

	if (isl_chg->charging) {
		isl_charger_current = isl_read_adc(CHANNEL_ADC_BATT_AMON,
								&mv_reading);
		dev_dbg(&isl_chg->client->dev, "%s mv_reading=%d\n",
				__func__, mv_reading);
		dev_dbg(&isl_chg->client->dev, "%s isl_charger_current=%d\n",
				__func__, isl_charger_current);
		if (isl_charger_current >= 0
			&& isl_charger_current <= isl_chg->term_current) {
			msm_charger_notify_event(
					&isl_chg->adapter_hw_chg,
					CHG_DONE_EVENT);
		}
		isl9519q_write_reg(isl_chg->client, CHG_CURRENT_REG,
				isl_chg->chgcurrent);
		ret = isl9519q_read_reg(isl_chg->client, CONTROL_REG, &temp);
		if (!ret) {
			if (!(temp & TRCKL_CHG_STATUS_BIT))
				msm_charger_notify_event(
						&isl_chg->adapter_hw_chg,
						CHG_BATT_BEGIN_FAST_CHARGING);
		} else {
			dev_err(&isl_chg->client->dev,
				"%s couldnt read cntrl reg\n", __func__);
		}
		schedule_delayed_work(&isl_chg->charge_work,
						ISL9519_CHG_PERIOD);
	}
}
static void battery_status_poller(struct work_struct *work)
{
	int status = 0, temp = 0;

	temp = if_notify_msm_charger(&status);
	update_current_battery_status(status);
	if (temp)
		msm_charger_notify_event(NULL, CHG_BATT_STATUS_CHANGE);

	schedule_delayed_work(&current_battery_status.poller,
				BQ27520_POLLING_STATUS);
}
static void isl_adapter_check_ichg(struct isl9519q_struct *isl_chg)
{
	int ichg; /* isl charger current */
	int mv_reading = 0;

	ichg = isl_read_adc(CHANNEL_ADC_BATT_AMON, &mv_reading);

	dev_dbg(&isl_chg->client->dev, "%s mv_reading=%d\n",
		__func__, mv_reading);
	dev_dbg(&isl_chg->client->dev, "%s isl_charger_current=%d\n",
		__func__, ichg);

	if (ichg >= 0 && ichg <= isl_chg->term_current)
		msm_charger_notify_event(&isl_chg->adapter_hw_chg,
					 CHG_DONE_EVENT);

	isl_chg->trickle = is_trickle_charging(isl_chg);
	if (isl_chg->trickle)
		msm_charger_notify_event(&isl_chg->adapter_hw_chg,
					 CHG_BATT_BEGIN_FAST_CHARGING);
}
static void bq27520_hw_config(struct work_struct *work)
{
	int ret = 0, flags = 0, type = 0, fw_ver = 0, status = 0;
	struct bq27520_device_info *di;

	di  = container_of(work, struct bq27520_device_info, hw_config.work);

	pr_debug(KERN_INFO "Enter bq27520_hw_config\n");
	ret = bq27520_chip_config(di);
	if (ret) {
		dev_err(di->dev, "Failed to config Bq27520 ret = %d\n", ret);
		return;
	}
	/* bq27520 is ready for access, update current_battery_status by reading
	 * from hardware
	 */
	if_notify_msm_charger(&status);
	update_current_battery_status(status);
	msm_battery_gauge_register(&bq27520_batt_gauge);
	msm_charger_notify_event(NULL, CHG_BATT_STATUS_CHANGE);

	enable_irq(di->irq);

	/* poll battery status every 3 seconds, if charging status changes,
	 * notify msm_charger
	 */
	schedule_delayed_work(&current_battery_status.poller,
				BQ27520_POLLING_STATUS);

	if (di->pdata->enable_dlog) {
		schedule_work(&di->counter);
		init_timer(&timer);
		timer.function = &bq27520_every_30secs;
		timer.data = (unsigned long)di;
		timer.expires = jiffies + BQ27520_COULOMB_POLL;
		add_timer(&timer);
	}

	bq27520_cntl_cmd(di, BQ27520_SUBCMD_CTNL_STATUS);
	udelay(66);
	bq27520_read(BQ27520_REG_CNTL, &flags, 0, di);
	bq27520_cntl_cmd(di, BQ27520_SUBCMD_DEVCIE_TYPE);
	udelay(66);
	bq27520_read(BQ27520_REG_CNTL, &type, 0, di);
	bq27520_cntl_cmd(di, BQ27520_SUBCMD_FW_VER);
	udelay(66);
	bq27520_read(BQ27520_REG_CNTL, &fw_ver, 0, di);

	dev_info(di->dev, "DEVICE_TYPE is 0x%02X, FIRMWARE_VERSION\
		is 0x%02X\n", type, fw_ver);
	dev_info(di->dev, "Complete bq27520 configuration 0x%02X\n", flags);
}
static int __devexit isl9519q_remove(struct i2c_client *client)
{
	struct isl_platform_data *pdata;
	struct isl9519q_struct *isl_chg = i2c_get_clientdata(client);

	pdata = client->dev.platform_data;
	gpio_free(pdata->valid_n_gpio);
	free_irq(client->irq, client);
	cancel_delayed_work_sync(&isl_chg->charge_work);
	msm_charger_notify_event(&isl_chg->adapter_hw_chg, CHG_REMOVED_EVENT);
	msm_charger_unregister(&isl_chg->adapter_hw_chg);
	return 0;
}
Example #11
0
/*
 * max8903_chg_connected() - notify the charger connected event
 * @chg_type:	charger type 
 */
void max8903_chg_connected(enum chg_type chg_type)
{
	cur_chg_type = chg_type;
	pr_info("%s:chg type =%d\n", __func__, cur_chg_type);

	if (delay_ac_charger_detect){
		delay_ac_charger_detect = 0;
		cancel_delayed_work(&saved_msm_chg->ac_charger);
		
		pr_info("%s: queue a insert event\n", __func__);
		msm_charger_notify_event(&saved_msm_chg->adapter_hw_chg,
				CHG_INSERTED_EVENT);
	}	
}
Example #12
0
static irqreturn_t max_valid_handler(int irq, void *dev_id)
{
	struct max8903_struct *max_chg;
    struct platform_device *pdev;
    struct pm8058_chip *chip;
    int state;

    pdev = (struct platform_device *)dev_id;
    max_chg = platform_get_drvdata(pdev);
    chip = get_irq_data(irq);
	
#if 0
	/* Dock insert, think it as AC charger */
	if (gpio_get_value_cansleep(max_chg->dock_det) && (BOARD_NUM(hw_ver) != BOARD_NUM_V11))
		max_chg->adapter_hw_chg.type = CHG_TYPE_USB;
	else
		max_chg->adapter_hw_chg.type = CHG_TYPE_AC;
#endif
	/* reinitialize charger type */
	if ((BOARD_NUM(hw_ver) == BOARD_NUM_V11))
		max_chg->adapter_hw_chg.type = CHG_TYPE_AC;
	else
		max_chg->adapter_hw_chg.type = CHG_TYPE_USB;

    state = pm8058_irq_get_rt_status(chip, irq);
    pr_info("%s:charge state=%d, hw_chg_type=%d\n", __func__, state, max_chg->adapter_hw_chg.type);
    if(state){
		/* delay to queue charge insert envent when charger inserted,
		 * need to detect if it is an ac charger
		 */
        //msm_charger_notify_event(&max_chg->adapter_hw_chg,
        //			 CHG_INSERTED_EVENT);
		delay_ac_charger_detect = 1;
		pr_info("%s:delay_ac_charger_detect=%d start ac charger delay work\n", __func__, delay_ac_charger_detect);
		schedule_delayed_work(&max_chg->ac_charger,
					AC_CHARGER_DETECT_DELAY);
        max_chg->present = 1;
		wake_lock(&max_chg->wl);
    }else{
    	delay_ac_charger_detect = 0;
		pr_info("%s:delay_ac_charger_detect=%d cancel ac charger delay work\n", __func__, delay_ac_charger_detect);
		cancel_delayed_work(&saved_msm_chg->ac_charger);
		
        msm_charger_notify_event(&max_chg->adapter_hw_chg,
        			 CHG_REMOVED_EVENT);
        max_chg->present = 0;
		wake_unlock(&max_chg->wl);
    }
	return IRQ_HANDLED;
}
static int __devexit pm8058_charger_remove(struct platform_device *pdev)
{
	struct msm_hardware_charger *pchg = dev_get_drvdata(&pdev->dev);
//		container_of(&pdev, struct msm_hardware_charger, pdev);

	pchg->chg_detection_config(0, pchg->gpio_num);	
	msm_charger_notify_event(pchg, CHG_REMOVED_EVENT);
	msm_charger_unregister(pchg);
//
//#ifdef CONFIG_HAS_EARLYSUSPEND
//	unregister_early_suspend(&pchg->early_suspend);
//#endif
//
	free_irqs(pchg);
	kfree(pchg);

	return 0;
}
static int __devexit isl9519q_remove(struct i2c_client *client)
{
	struct isl_platform_data *pdata;
	struct isl9519q_struct *isl_chg = i2c_get_clientdata(client);

	pdata = client->dev.platform_data;
	gpio_free(pdata->valid_n_gpio);
	free_irq(client->irq, client);
	cancel_delayed_work_sync(&isl_chg->charge_work);
	if (isl_chg->notify_by_pmic) {
		power_supply_unregister(&isl_chg->dc_psy);
	} else {
		msm_charger_notify_event(&isl_chg->adapter_hw_chg,
							CHG_REMOVED_EVENT);
	msm_charger_unregister(&isl_chg->adapter_hw_chg);
	}
	remove_debugfs_entries(isl_chg);
	the_isl_chg = NULL;
	kfree(isl_chg);
	return 0;
}
Example #15
0
static __devexit int max8903_remove(struct platform_device *pdev)
{
	struct max8903_struct *max_chg;
    
    max_chg = platform_get_drvdata(pdev);

	if (max_chg) {
		
		device_remove_file(max_chg->dev, &usb_chg_enable_attr);
		
    	free_irq(max_chg->irq, pdev);
        free_irq(gpio_to_irq(max_chg->flt), pdev);
        gpio_free(max_chg->flt);
        gpio_free(max_chg->chg);
        gpio_free(max_chg->cen);
    	cancel_delayed_work_sync(&max_chg->charge_work);
    	msm_charger_notify_event(&max_chg->adapter_hw_chg, CHG_REMOVED_EVENT);
    	msm_charger_unregister(&max_chg->adapter_hw_chg);
    	kfree(max_chg);            
	}

	return 0;
}
Example #16
0
static void max8903_charge(struct work_struct *max8903_work)
{
	struct max8903_struct *max_chg;
	int current_capacity;
    int current_voltage;

	max_chg = container_of(max8903_work, struct max8903_struct,
			charge_work.work);

	dev_info(max_chg->dev, "%s\n", __func__);

	if (max_chg->charging) {
        current_capacity = max17040_get_soc(max17040_bak_client);
        current_voltage  = max17040_get_vcell(max17040_bak_client);
		pr_info("%s:capacity=%d voltage=%d\n ", __func__, current_capacity, current_voltage); 

        //get the charger status value
        if ((gpio_get_value(max_chg->chg) == 1) && (current_capacity > MAX8903_BATTERY_FULL))
		    msm_charger_notify_event(&max_chg->adapter_hw_chg,  CHG_DONE_EVENT);
        
		schedule_delayed_work(&max_chg->charge_work,
						MAX8903_CHG_PERIOD);
	}
}
Example #17
0
static void ac_charger_detect(struct work_struct *max8903_work)
{
	struct max8903_struct *max_chg;

	max_chg = container_of(max8903_work, struct max8903_struct,
			ac_charger.work);

	dev_info(max_chg->dev, "%s\n", __func__);

	/*
	 * if it's not a stadard USB charger
	 * think it as an AC charger
	 */
	if (delay_ac_charger_detect){
		delay_ac_charger_detect = 0;
		/* change charger type */
		max_chg->adapter_hw_chg.type = CHG_TYPE_AC;
		
		/* queue a insert envent */
		pr_info("%s: queue a insert event\n", __func__);
		msm_charger_notify_event(&max_chg->adapter_hw_chg,
			 CHG_INSERTED_EVENT);
	}
}
static int __devinit isl9519q_init_adapter(struct isl9519q_struct *isl_chg)
{
	int ret;
	struct i2c_client *client = isl_chg->client;
	struct isl_platform_data *pdata = client->dev.platform_data;

	isl_chg->adapter_hw_chg.type = CHG_TYPE_AC;
	isl_chg->adapter_hw_chg.rating = 2;
	isl_chg->adapter_hw_chg.name = "isl-adapter";
	isl_chg->adapter_hw_chg.start_charging = isl_adapter_start_charging;
	isl_chg->adapter_hw_chg.stop_charging = isl_adapter_stop_charging;
	isl_chg->adapter_hw_chg.charging_switched = isl9519q_charging_switched;

	ret = gpio_request(pdata->valid_n_gpio, "isl_charger_valid");
	if (ret) {
		dev_err(&client->dev, "%s gpio_request failed "
				      "for %d ret=%d\n",
			__func__, pdata->valid_n_gpio, ret);
		goto out;
	}

	ret = msm_charger_register(&isl_chg->adapter_hw_chg);
	if (ret) {
		dev_err(&client->dev,
			"%s msm_charger_register failed for ret =%d\n",
			__func__, ret);
		goto free_gpio;
	}

	ret = request_threaded_irq(client->irq, NULL,
				   isl_valid_handler,
				   IRQF_TRIGGER_FALLING |
				   IRQF_TRIGGER_RISING,
				   "isl_charger_valid", client);
	if (ret) {
		dev_err(&client->dev,
			"%s request_threaded_irq failed "
			"for %d ret =%d\n",
			__func__, client->irq, ret);
		goto unregister;
	}
	irq_set_irq_wake(client->irq, 1);

	ret = gpio_get_value_cansleep(isl_chg->valid_n_gpio);
	if (ret < 0) {
		dev_err(&client->dev,
			"%s gpio_get_value failed for %d ret=%d\n",
			__func__, pdata->valid_n_gpio, ret);
		/* assume absent */
		ret = 1;
	}
	if (!ret) {
		msm_charger_notify_event(&isl_chg->adapter_hw_chg,
				CHG_INSERTED_EVENT);
		isl_chg->present = 1;
	}

	return 0;

unregister:
	msm_charger_unregister(&isl_chg->adapter_hw_chg);
free_gpio:
	gpio_free(pdata->valid_n_gpio);
out:
	return ret;

}
Example #19
0
static int __devinit max8903_probe(struct platform_device *pdev)
{
	struct max8903_struct *max_chg;
	struct device *dev = &pdev->dev;
	struct max8903_platform_data *pdata = pdev->dev.platform_data;
    struct pm8058_chip *chip;
	int ret = 0;
    
    //printk("%s\n", __func__);
	max_chg = kzalloc(sizeof(struct max8903_struct), GFP_KERNEL);
	if (max_chg == NULL) {
		dev_err(dev, "Cannot allocate memory.\n");
		return -ENOMEM;
	}
	
	saved_msm_chg = max_chg;
	
	if (pdata == NULL) {
		dev_err(&pdev->dev, "%s no platform data\n", __func__);
		ret = -EINVAL;
		goto out;
	}

	INIT_DELAYED_WORK(&max_chg->charge_work, max8903_charge);
	INIT_DELAYED_WORK(&max_chg->ac_charger, ac_charger_detect);
	wake_lock_init(&max_chg->wl, WAKE_LOCK_SUSPEND, "max8903");
    
	max_chg->dev = &pdev->dev;;
    max_chg->irq = pdata->irq;
    max_chg->cen = pdata->cen;
    max_chg->chg = pdata->chg;
    max_chg->flt = pdata->flt;
	max_chg->usus = pdata->usus;
	max_chg->dock_det = pdata->dock_det;
	max_chg->usb_chg_enable = 1;	/* enable usb charge */

	if (BOARD_NUM(hw_ver) == BOARD_NUM_V11)
		max_chg->adapter_hw_chg.type = CHG_TYPE_AC;
	else
		max_chg->adapter_hw_chg.type = CHG_TYPE_USB;
	max_chg->adapter_hw_chg.rating = 2;
	max_chg->adapter_hw_chg.name = "max8903-charger";
	max_chg->adapter_hw_chg.start_charging = max8903_start_charging;
	max_chg->adapter_hw_chg.stop_charging = max8903_stop_charging;
	max_chg->adapter_hw_chg.charging_switched = max8903_charging_switched;
    
	platform_set_drvdata(pdev, max_chg);

	ret = gpio_request(max_chg->cen, "CHARGER_CEN_N");
	if (ret) {
		dev_err(max_chg->dev, "%s gpio_request failed for %d ret=%d\n",
			__func__, max_chg->cen, ret);
		goto free_max_chg;
	}

	ret = gpio_request(max_chg->chg, "CHARGER_STATUS");
	if (ret) {
		dev_err(max_chg->dev, "%s gpio_request failed for %d ret=%d\n",
			__func__, max_chg->chg, ret);
		goto free_cen;
	}
    gpio_direction_input(max_chg->chg);

    ret = gpio_request(max_chg->flt, "CHARGER_FAULT_N");
	if (ret) {
		dev_err(max_chg->dev, "%s gpio_request failed for %d ret=%d\n",
			__func__, max_chg->flt, ret);
		goto free_chg;
	}    
    gpio_direction_input(max_chg->flt);

    ret = request_threaded_irq(gpio_to_irq(max_chg->flt),
                            NULL, max8903_fault,
                            IRQF_TRIGGER_FALLING ,"MAX8903 Fault", pdev);
    if (ret) {
        dev_err(dev, "Cannot request irq %d for Fault (%d)\n",
                gpio_to_irq(max_chg->flt), ret);
        goto free_flt;
    }

	ret = gpio_request(max_chg->usus, "USUS_CTRL");
	if (ret) {
		dev_err(max_chg->dev, "%s gpio_request failed for %d ret=%d\n",
			__func__, max_chg->usus, ret);
		goto err_flt_irq;
	}

	ret = gpio_request(max_chg->dock_det, "DOCK_DET");
	if (ret) {
		dev_err(max_chg->dev, "%s gpio_request failed for %d ret=%d\n",
			__func__, max_chg->dock_det, ret);
		goto free_usus;
	}
	gpio_direction_input(max_chg->dock_det);
    
	ret = msm_charger_register(&max_chg->adapter_hw_chg);
	if (ret) {
		dev_err(max_chg->dev,
			"%s msm_charger_register failed for ret =%d\n",
			__func__, ret);
		goto free_dock_det;
	}
	
	ret = device_create_file(max_chg->dev, &usb_chg_enable_attr);
	if (ret) {
		dev_err(max_chg->dev, "failed: create usb_chg_enable file\n");
	}
	
	ret = request_threaded_irq(max_chg->irq, NULL,
				   max_valid_handler,
				   IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
				   "max_valid_handler", pdev);
	if (ret) {
		dev_err(max_chg->dev,
			"%s request_threaded_irq failed for %d ret =%d\n",
			__func__, max_chg->irq, ret);
		goto unregister;
	}
	set_irq_wake(max_chg->irq, 1);

    chip = get_irq_data(max_chg->irq);
    ret = pm8058_irq_get_rt_status(chip, max_chg->irq);
	if (ret) {
	#if 0
		if (!gpio_get_value_cansleep(max_chg->dock_det))	/* Dock insert, think it as AC charger */
			max_chg->adapter_hw_chg.type = CHG_TYPE_AC;
		msm_charger_notify_event(&max_chg->adapter_hw_chg,
				CHG_INSERTED_EVENT);
	#else
		/* Charger inserted, but not a valid USB charger
		 * think it as a AC charger
		 */
		if (USB_CHG_TYPE__INVALID == cur_chg_type)
			max_chg->adapter_hw_chg.type = CHG_TYPE_AC;
		
		msm_charger_notify_event(&max_chg->adapter_hw_chg,
				CHG_INSERTED_EVENT);
	#endif
		max_chg->present = 1;
		wake_lock(&max_chg->wl);
	}

	msm_register_usb_charger_state(max8903_usb_charger_state);

	pr_info("%s OK chg_present=%d\n", __func__, max_chg->present);
	return 0;

unregister:
	msm_charger_unregister(&max_chg->adapter_hw_chg);
free_dock_det:
	gpio_free(max_chg->dock_det);
free_usus:
    gpio_free(max_chg->usus);
err_flt_irq:
    free_irq(gpio_to_irq(max_chg->flt), pdev);
free_flt:
    gpio_free(max_chg->flt);
free_chg:
    gpio_free(max_chg->chg);
free_cen:
    gpio_free(max_chg->cen);
free_max_chg:
	kfree(max_chg);
out:
	return ret;
}
static void bq24160_charge(struct work_struct *bq24160_work)
{
#ifdef BQ24160_WORKAROUND_CHG_DONE /* work around for charge done*/
	int val;
#endif
	u8 temp = 0;
	u8 status = 0;
	int rc;
	struct bq24160_chip *bq24160_chg;

	bq24160_chg = container_of(bq24160_work, struct bq24160_chip,
			charge_work.work);

	dev_dbg(&bq24160_chg->client->dev, "%s\n", __func__);

	/* Watchdog timer reset */
	bq24160_set_bits(bq24160_chg->client, BQ24160_REG_STAT_CTRL, BQ24160_WDOG_TMR_MASK, (1<<BQ24160_WDOG_TMR_SHFT));

	if (bq24160_chg->chg_online) 
	{
		temp = bq24160_read_reg(bq24160_chg->client, BQ24160_REG_BATTNPS_STAT);
		dev_dbg(&bq24160_chg->client->dev, "%s STATUS Register[#1]: 0x%x\n", __func__,temp);

		temp = bq24160_read_reg(bq24160_chg->client, BQ24160_REG_STAT_CTRL);
		dev_dbg(&bq24160_chg->client->dev, "%s STATUS Register[#0]: 0x%x\n", __func__,temp);

		status = temp & BQ24160_STAT_MASK;
		status = status >> BQ24160_STAT_SHFT;

		dev_dbg(&bq24160_chg->client->dev, "%s STATUS: %d\n", __func__,status);
		switch(status)
		{
			case BQ24160_STAT_NO_VALID_SRC_DETECTED:
				break;
			case BQ24160_STAT_IN_READY:
				break;
			case BQ24160_STAT_USB_READY:
				break;
			case BQ24160_STAT_CHARGING_FROM_IN:
				break;
			case BQ24160_STAT_CHARGING_FROM_USB:
				break;
			case BQ24160_STAT_CHARGE_DONE:
				dev_dbg(&bq24160_chg->client->dev, "%s Charge done by Status Register!!!\n", __func__);
				rc = gpio_direction_output(WIRELESS_CHARGE_COMPLETE, 1);
				if (rc) {
					dev_err(&bq24160_chg->client->dev,"%s: gpio_direction_output failed for %d\n",
							__func__, WIRELESS_CHARGE_COMPLETE);
				}

				msm_charger_notify_event(&bq24160_chg->adapter_hw_chg, CHG_DONE_EVENT);

				wake_lock(&bq24160_chg->wl);
				//schedule_delayed_work(&bq24160_chg->charge_done_work, BQ24160_CHG_DONE_WORK_PERIOD);
				queue_delayed_work(local_charge_done_wq, &bq24160_chg->charge_done_work, BQ24160_CHG_DONE_WORK_PERIOD);
				break;
			case BQ24160_STAT_NA:
				break;
			case BQ24160_STAT_FAULT:
				break;
		}

#ifdef BQ24160_WORKAROUND_CHG_DONE /* work around for charge done*/
		val = gpio_get_value_cansleep(WIRELESS_CHARGE_INT);
		if (val < 0) {
			dev_err(&bq24160_chg->client->dev,
				"%s gpio_get_value failed for %d ret=%d\n", __func__,
				WIRELESS_CHARGE_INT, val);
		}
		dev_dbg(&bq24160_chg->client->dev, "%s val=%d\n", __func__, val);
		if(val)
		{
			chg_done_cnt++;
			if(chg_done_cnt >= 2)
			{
				dev_dbg(&bq24160_chg->client->dev, "%s Charge done by Interrupt High!!!\n", __func__);
				rc = gpio_direction_output(WIRELESS_CHARGE_COMPLETE, 1);
				if (rc) {
					dev_err(&bq24160_chg->client->dev,"%s: gpio_direction_output failed for %d\n",
							__func__, WIRELESS_CHARGE_COMPLETE);
				}
				msm_charger_notify_event(&bq24160_chg->adapter_hw_chg, CHG_DONE_EVENT);
				
				wake_lock(&bq24160_chg->wl);
				//schedule_delayed_work(&bq24160_chg->charge_done_work, BQ24160_CHG_DONE_WORK_PERIOD);
				queue_delayed_work(local_charge_done_wq, &bq24160_chg->charge_done_work, BQ24160_CHG_DONE_WORK_PERIOD);
			}	
		}
		else
		{
			chg_done_cnt = 0;
		}
#endif
		//schedule_delayed_work(&bq24160_chg->charge_work, BQ24160_CHG_WORK_PERIOD);
		queue_delayed_work(local_charge_wq, &bq24160_chg->charge_work, BQ24160_CHG_WORK_PERIOD);
	}
static int __devinit isl9519q_probe(struct i2c_client *client,
				    const struct i2c_device_id *id)
{
	struct isl_platform_data *pdata;
	struct isl9519q_struct *isl_chg;
	int ret;

	ret = 0;
	pdata = client->dev.platform_data;

	if (pdata == NULL) {
		dev_err(&client->dev, "%s no platform data\n", __func__);
		ret = -EINVAL;
		goto out;
	}

	if (!i2c_check_functionality(client->adapter,
				I2C_FUNC_SMBUS_WORD_DATA)) {
		ret = -EIO;
		goto out;
	}

	isl_chg = kzalloc(sizeof(*isl_chg), GFP_KERNEL);
	if (!isl_chg) {
		ret = -ENOMEM;
		goto out;
	}

	INIT_DELAYED_WORK(&isl_chg->charge_work, isl9519q_charge);
	isl_chg->client = client;
	isl_chg->chgcurrent = pdata->chgcurrent;
	isl_chg->term_current = pdata->term_current;
	isl_chg->input_current = pdata->input_current;
	isl_chg->max_system_voltage = pdata->max_system_voltage;
	isl_chg->min_system_voltage = pdata->min_system_voltage;
	isl_chg->valid_n_gpio = pdata->valid_n_gpio;

	/* h/w ignores lower 7 bits of charging current and input current */
	isl_chg->chgcurrent &= ~0x7F;
	isl_chg->input_current &= ~0x7F;

	isl_chg->adapter_hw_chg.type = CHG_TYPE_AC;
	isl_chg->adapter_hw_chg.rating = 2;
	isl_chg->adapter_hw_chg.name = "isl-adapter";
	isl_chg->adapter_hw_chg.start_charging = isl9519q_start_charging;
	isl_chg->adapter_hw_chg.stop_charging = isl9519q_stop_charging;
	isl_chg->adapter_hw_chg.charging_switched = isl9519q_charging_switched;

	if (pdata->chg_detection_config) {
		ret = pdata->chg_detection_config();
		if (ret) {
			dev_err(&client->dev, "%s valid config failed ret=%d\n",
				__func__, ret);
			goto free_isl_chg;
		}
	}

	ret = gpio_request(pdata->valid_n_gpio, "isl_charger_valid");
	if (ret) {
		dev_err(&client->dev, "%s gpio_request failed for %d ret=%d\n",
			__func__, pdata->valid_n_gpio, ret);
		goto free_isl_chg;
	}

	i2c_set_clientdata(client, isl_chg);

	ret = msm_charger_register(&isl_chg->adapter_hw_chg);
	if (ret) {
		dev_err(&client->dev,
			"%s msm_charger_register failed for ret =%d\n",
			__func__, ret);
		goto free_gpio;
	}

	ret = request_threaded_irq(client->irq, NULL,
				   isl_valid_handler,
				   IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
				   "isl_charger_valid", client);
	if (ret) {
		dev_err(&client->dev,
			"%s request_threaded_irq failed for %d ret =%d\n",
			__func__, client->irq, ret);
		goto unregister;
	}
	set_irq_wake(client->irq, 1);

	isl_chg->max_system_voltage &= MAX_VOLTAGE_REG_MASK;
	isl_chg->min_system_voltage &= MIN_VOLTAGE_REG_MASK;
	if (isl_chg->max_system_voltage == 0)
		isl_chg->max_system_voltage = DEFAULT_MAX_VOLTAGE_REG_VALUE;
	if (isl_chg->min_system_voltage == 0)
		isl_chg->min_system_voltage = DEFAULT_MIN_VOLTAGE_REG_VALUE;

	ret = isl9519q_write_reg(isl_chg->client, MAX_SYS_VOLTAGE_REG,
			isl_chg->max_system_voltage);
	if (ret) {
		dev_err(&client->dev,
			"%s couldnt write to MAX_SYS_VOLTAGE_REG ret=%d\n",
			__func__, ret);
		goto free_irq;
	}

	ret = isl9519q_write_reg(isl_chg->client, MIN_SYS_VOLTAGE_REG,
			isl_chg->min_system_voltage);
	if (ret) {
		dev_err(&client->dev,
			"%s couldnt write to MIN_SYS_VOLTAGE_REG ret=%d\n",
			__func__, ret);
		goto free_irq;
	}

	if (isl_chg->input_current) {
		ret = isl9519q_write_reg(isl_chg->client,
				INPUT_CURRENT_REG,
				isl_chg->input_current);
		if (ret) {
			dev_err(&client->dev,
				"%s couldnt write INPUT_CURRENT_REG ret=%d\n",
				__func__, ret);
			goto free_irq;
		}
	}

	ret = gpio_get_value_cansleep(isl_chg->valid_n_gpio);
	if (ret < 0) {
		dev_err(&client->dev,
			"%s gpio_get_value failed for %d ret=%d\n", __func__,
			pdata->valid_n_gpio, ret);
		/* assume absent */
		ret = 1;
	}
	if (!ret) {
		msm_charger_notify_event(&isl_chg->adapter_hw_chg,
				CHG_INSERTED_EVENT);
		isl_chg->present = 1;
	}

	pr_debug("%s OK chg_present=%d\n", __func__, isl_chg->present);
	return 0;

free_irq:
	free_irq(client->irq, NULL);
unregister:
	msm_charger_unregister(&isl_chg->adapter_hw_chg);
free_gpio:
	gpio_free(pdata->valid_n_gpio);
free_isl_chg:
	kfree(isl_chg);
out:
	return ret;
}