Ejemplo n.º 1
0
static void bq24192_irq_worker(struct work_struct *work)
{
	struct bq24192_chip *chip =
		container_of(work, struct bq24192_chip, irq_work);
	union power_supply_propval ret = {0,};
	bool ext_pwr;
	bool wlc_pwr = 0;
	bool chg_done = false;
	u8 temp;
	int rc;
	unsigned long flags;

	wake_lock(&chip->irq_wake_lock);

	msleep(100 * chip->irq_scheduled_time_status);

	rc = bq24192_read_reg(chip->client, SYSTEM_STATUS_REG, &temp);
	/* Open up for next possible interrupt handler beyond read reg
	 * asap, lest we miss an interrupt
	 */
	spin_lock_irqsave(&chip->irq_work_lock, flags);
	chip->irq_scheduled_time_status = 0;
	spin_unlock_irqrestore(&chip->irq_work_lock, flags);

	if (rc) {
		pr_err("failed to read SYSTEM_STATUS_REG rc=%d\n", rc);
		goto irq_worker_exit;
	}

	ext_pwr = !!(temp & PG_STAT_MASK);
	chg_done = (temp & CHARGING_MASK) == 0x30 ? true : false;
	if (chg_done) {
		if (chip->batt_health != POWER_SUPPLY_HEALTH_OVERHEAT &&
				bq24192_get_soc_from_batt_psy(chip) < 100) {
			wake_lock(&chip->extra_chg_lock);
			bq24192_enable_chg_term(chip, false);
			bq24192_trigger_recharge(chip);
			schedule_delayed_work(&chip->extra_chg_work,
					msecs_to_jiffies(EXTRA_CHG_TIME_MS));
		} else {
			if (chip->batt_health != POWER_SUPPLY_HEALTH_OVERHEAT)
				bq24192_set_rechg_voltage(chip, VRECHG_300MV);
			power_supply_changed(&chip->ac_psy);
			pr_debug("charge done!!\n");
		}
	}

	if (chip->wlc_psy) {
		chip->wlc_psy->get_property(chip->wlc_psy,
				POWER_SUPPLY_PROP_PRESENT, &ret);
		wlc_pwr = ret.intval;
	}

	if ((chip->ext_pwr ^ ext_pwr) || (chip->wlc_pwr ^ wlc_pwr)) {
		pr_debug("power source changed! ext_pwr = %d wlc_pwr = %d\n",
				ext_pwr, wlc_pwr);
		if (wake_lock_active(&chip->icl_wake_lock))
			wake_unlock(&chip->icl_wake_lock);
		if (wake_lock_active(&chip->extra_chg_lock))
			wake_unlock(&chip->extra_chg_lock);
		cancel_delayed_work_sync(&chip->input_limit_work);
		cancel_delayed_work_sync(&chip->therm_work);
		cancel_delayed_work_sync(&chip->extra_chg_work);
		bq24192_enable_chg_term(chip, true);
		bq24192_step_down_detect_disable(chip);
		chip->saved_ibat_ma = 0;
		chip->set_chg_current_ma = chip->chg_current_ma;
		chip->max_input_i_ma = INPUT_CURRENT_LIMIT_MAX_MA;

		if (chip->wlc_psy) {
			if (wlc_pwr && ext_pwr) {
				chip->wlc_pwr = true;
				power_supply_set_online(chip->wlc_psy, true);
			} else if (chip->wlc_pwr && !(ext_pwr && wlc_pwr)) {
				chip->wlc_pwr = false;
				power_supply_set_online(chip->wlc_psy, false);
			}
		}

		if (!wlc_pwr) {
			pr_debug("notify vbus to usb otg ext_pwr = %d\n", ext_pwr);
			power_supply_set_present(chip->usb_psy, ext_pwr);
		}

		chip->ext_pwr = ext_pwr;
	}

irq_worker_exit:
	wake_lock_timeout(&chip->irq_wake_lock, 2*HZ);
}
Ejemplo n.º 2
0
static void twl4030_madc_bat_ext_changed(struct power_supply *psy)
{
	power_supply_changed(psy);
}
static int tps65090_charger_probe(struct platform_device *pdev)
{
	struct tps65090_charger *cdata;
	struct tps65090_platform_data *pdata;
	uint8_t status1 = 0;
	int ret;
	int irq;

	pdata = dev_get_platdata(pdev->dev.parent);

	if (!pdata && pdev->dev.of_node)
		pdata = tps65090_parse_dt_charger_data(pdev);

	if (!pdata) {
		dev_err(&pdev->dev, "%s():no platform data available\n",
				__func__);
		return -ENODEV;
	}

	cdata = devm_kzalloc(&pdev->dev, sizeof(*cdata), GFP_KERNEL);
	if (!cdata) {
		dev_err(&pdev->dev, "failed to allocate memory status\n");
		return -ENOMEM;
	}

	dev_set_drvdata(&pdev->dev, cdata);

	cdata->dev			= &pdev->dev;
	cdata->pdata			= pdata;

	cdata->ac.name			= "tps65090-ac";
	cdata->ac.type			= POWER_SUPPLY_TYPE_MAINS;
	cdata->ac.get_property		= tps65090_ac_get_property;
	cdata->ac.properties		= tps65090_ac_props;
	cdata->ac.num_properties	= ARRAY_SIZE(tps65090_ac_props);
	cdata->ac.supplied_to		= pdata->supplied_to;
	cdata->ac.num_supplicants	= pdata->num_supplicants;

	ret = power_supply_register(&pdev->dev, &cdata->ac);
	if (ret) {
		dev_err(&pdev->dev, "failed: power supply register\n");
		return ret;
	}

	irq = platform_get_irq(pdev, 0);
	if (irq <= 0) {
		dev_warn(&pdev->dev, "Unable to get charger irq = %d\n", irq);
		ret = irq;
		goto fail_unregister_supply;
	}

	cdata->irq = irq;

	ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
		tps65090_charger_isr, 0, "tps65090-charger", cdata);
	if (ret) {
		dev_err(cdata->dev, "Unable to register irq %d err %d\n", irq,
			ret);
		goto fail_free_irq;
	}

	ret = tps65090_config_charger(cdata);
	if (ret < 0) {
		dev_err(&pdev->dev, "charger config failed, err %d\n", ret);
		goto fail_free_irq;
	}

	/* Check for charger presence */
	ret = tps65090_read(cdata->dev->parent, TPS65090_REG_CG_STATUS1,
			&status1);
	if (ret < 0) {
		dev_err(cdata->dev, "%s(): Error in reading reg 0x%x", __func__,
			TPS65090_REG_CG_STATUS1);
		goto fail_free_irq;
	}

	if (status1 != 0) {
		ret = tps65090_enable_charging(cdata, 1);
		if (ret < 0) {
			dev_err(cdata->dev, "error enabling charger\n");
			goto fail_free_irq;
		}
		cdata->ac_online = 1;
		power_supply_changed(&cdata->ac);
	}

	return 0;

fail_free_irq:
	devm_free_irq(cdata->dev, irq, cdata);
fail_unregister_supply:
	power_supply_unregister(&cdata->ac);

	return ret;
}
Ejemplo n.º 4
0
static int pm2xxx_wall_charger_probe(struct i2c_client *i2c_client,
		const struct i2c_device_id *id)
{
	struct pm2xxx_platform_data *pl_data = i2c_client->dev.platform_data;
	struct power_supply_config psy_cfg = {};
	struct pm2xxx_charger *pm2;
	int ret = 0;
	u8 val;
	int i;

	if (!pl_data) {
		dev_err(&i2c_client->dev, "No platform data supplied\n");
		return -EINVAL;
	}

	pm2 = kzalloc(sizeof(struct pm2xxx_charger), GFP_KERNEL);
	if (!pm2) {
		dev_err(&i2c_client->dev, "pm2xxx_charger allocation failed\n");
		return -ENOMEM;
	}

	/* get parent data */
	pm2->dev = &i2c_client->dev;

	pm2->pm2_int = &pm2xxx_int;

	/* get charger spcific platform data */
	if (!pl_data->wall_charger) {
		dev_err(pm2->dev, "no charger platform data supplied\n");
		ret = -EINVAL;
		goto free_device_info;
	}

	pm2->pdata = pl_data->wall_charger;

	/* get battery specific platform data */
	if (!pl_data->battery) {
		dev_err(pm2->dev, "no battery platform data supplied\n");
		ret = -EINVAL;
		goto free_device_info;
	}

	pm2->bat = pl_data->battery;

	if (!i2c_check_functionality(i2c_client->adapter,
			I2C_FUNC_SMBUS_BYTE_DATA |
			I2C_FUNC_SMBUS_READ_WORD_DATA)) {
		ret = -ENODEV;
		dev_info(pm2->dev, "pm2301 i2c_check_functionality failed\n");
		goto free_device_info;
	}

	pm2->config.pm2xxx_i2c = i2c_client;
	pm2->config.pm2xxx_id = (struct i2c_device_id *) id;
	i2c_set_clientdata(i2c_client, pm2);

	/* AC supply */
	/* power_supply base class */
	pm2->ac_chg_desc.name = pm2->pdata->label;
	pm2->ac_chg_desc.type = POWER_SUPPLY_TYPE_MAINS;
	pm2->ac_chg_desc.properties = pm2xxx_charger_ac_props;
	pm2->ac_chg_desc.num_properties = ARRAY_SIZE(pm2xxx_charger_ac_props);
	pm2->ac_chg_desc.get_property = pm2xxx_charger_ac_get_property;

	psy_cfg.supplied_to = pm2->pdata->supplied_to;
	psy_cfg.num_supplicants = pm2->pdata->num_supplicants;
	/* pm2xxx_charger sub-class */
	pm2->ac_chg.ops.enable = &pm2xxx_charger_ac_en;
	pm2->ac_chg.ops.kick_wd = &pm2xxx_charger_watchdog_kick;
	pm2->ac_chg.ops.update_curr = &pm2xxx_charger_update_charger_current;
	pm2->ac_chg.max_out_volt = pm2xxx_charger_voltage_map[
		ARRAY_SIZE(pm2xxx_charger_voltage_map) - 1];
	pm2->ac_chg.max_out_curr = pm2xxx_charger_current_map[
		ARRAY_SIZE(pm2xxx_charger_current_map) - 1];
	pm2->ac_chg.wdt_refresh = WD_KICK_INTERVAL;
	pm2->ac_chg.enabled = true;
	pm2->ac_chg.external = true;

	/* Create a work queue for the charger */
	pm2->charger_wq = create_singlethread_workqueue("pm2xxx_charger_wq");
	if (pm2->charger_wq == NULL) {
		ret = -ENOMEM;
		dev_err(pm2->dev, "failed to create work queue\n");
		goto free_device_info;
	}

	/* Init work for charger detection */
	INIT_WORK(&pm2->ac_work, pm2xxx_charger_ac_work);

	/* Init work for checking HW status */
	INIT_WORK(&pm2->check_main_thermal_prot_work,
		pm2xxx_charger_check_main_thermal_prot_work);

	/* Init work for HW failure check */
	INIT_DEFERRABLE_WORK(&pm2->check_hw_failure_work,
		pm2xxx_charger_check_hw_failure_work);

	/*
	 * VDD ADC supply needs to be enabled from this driver when there
	 * is a charger connected to avoid erroneous BTEMP_HIGH/LOW
	 * interrupts during charging
	 */
	pm2->regu = regulator_get(pm2->dev, "vddadc");
	if (IS_ERR(pm2->regu)) {
		ret = PTR_ERR(pm2->regu);
		dev_err(pm2->dev, "failed to get vddadc regulator\n");
		goto free_charger_wq;
	}

	/* Register AC charger class */
	pm2->ac_chg.psy = power_supply_register(pm2->dev, &pm2->ac_chg_desc,
						&psy_cfg);
	if (IS_ERR(pm2->ac_chg.psy)) {
		dev_err(pm2->dev, "failed to register AC charger\n");
		ret = PTR_ERR(pm2->ac_chg.psy);
		goto free_regulator;
	}

	/* Register interrupts */
	ret = request_threaded_irq(gpio_to_irq(pm2->pdata->gpio_irq_number),
				NULL,
				pm2xxx_charger_irq[0].isr,
				pm2->pdata->irq_type,
				pm2xxx_charger_irq[0].name, pm2);

	if (ret != 0) {
		dev_err(pm2->dev, "failed to request %s IRQ %d: %d\n",
		pm2xxx_charger_irq[0].name,
			gpio_to_irq(pm2->pdata->gpio_irq_number), ret);
		goto unregister_pm2xxx_charger;
	}

	ret = pm_runtime_set_active(pm2->dev);
	if (ret)
		dev_err(pm2->dev, "set active Error\n");

	pm_runtime_enable(pm2->dev);
	pm_runtime_set_autosuspend_delay(pm2->dev, PM2XXX_AUTOSUSPEND_DELAY);
	pm_runtime_use_autosuspend(pm2->dev);
	pm_runtime_resume(pm2->dev);

	/* pm interrupt can wake up system */
	ret = enable_irq_wake(gpio_to_irq(pm2->pdata->gpio_irq_number));
	if (ret) {
		dev_err(pm2->dev, "failed to set irq wake\n");
		goto unregister_pm2xxx_interrupt;
	}

	mutex_init(&pm2->lock);

	if (gpio_is_valid(pm2->pdata->lpn_gpio)) {
		/* get lpn GPIO from platform data */
		pm2->lpn_pin = pm2->pdata->lpn_gpio;

		/*
		 * Charger detection mechanism requires pulling up the LPN pin
		 * while i2c communication if Charger is not connected
		 * LPN pin of PM2301 is GPIO60 of AB9540
		 */
		ret = gpio_request(pm2->lpn_pin, "pm2301_lpm_gpio");

		if (ret < 0) {
			dev_err(pm2->dev, "pm2301_lpm_gpio request failed\n");
			goto disable_pm2_irq_wake;
		}
		ret = gpio_direction_output(pm2->lpn_pin, 0);
		if (ret < 0) {
			dev_err(pm2->dev, "pm2301_lpm_gpio direction failed\n");
			goto free_gpio;
		}
		set_lpn_pin(pm2);
	}

	/* read  interrupt registers */
	for (i = 0; i < PM2XXX_NUM_INT_REG; i++)
		pm2xxx_reg_read(pm2,
			pm2xxx_interrupt_registers[i],
			&val);

	ret = pm2xxx_charger_detection(pm2, &val);

	if ((ret == 0) && val) {
		pm2->ac.charger_connected = 1;
		ab8500_override_turn_on_stat(~AB8500_POW_KEY_1_ON,
					     AB8500_MAIN_CH_DET);
		pm2->ac_conn = true;
		power_supply_changed(pm2->ac_chg.psy);
		sysfs_notify(&pm2->ac_chg.psy->dev.kobj, NULL, "present");
	}

	return 0;

free_gpio:
	if (gpio_is_valid(pm2->lpn_pin))
		gpio_free(pm2->lpn_pin);
disable_pm2_irq_wake:
	disable_irq_wake(gpio_to_irq(pm2->pdata->gpio_irq_number));
unregister_pm2xxx_interrupt:
	/* disable interrupt */
	free_irq(gpio_to_irq(pm2->pdata->gpio_irq_number), pm2);
unregister_pm2xxx_charger:
	/* unregister power supply */
	power_supply_unregister(pm2->ac_chg.psy);
free_regulator:
	/* disable the regulator */
	regulator_put(pm2->regu);
free_charger_wq:
	destroy_workqueue(pm2->charger_wq);
free_device_info:
	kfree(pm2);

	return ret;
}
Ejemplo n.º 5
0
int pcf50633_mbc_usb_curlim_set(struct pcf50633 *pcf, int ma)
{
	struct pcf50633_mbc *mbc = platform_get_drvdata(pcf->mbc_pdev);
	int ret = 0;
	u8 bits;
	u8 mbcs2, chgmod;
	unsigned int mbcc5;

	if (ma >= 1000) {
		bits = PCF50633_MBCC7_USB_1000mA;
		ma = 1000;
	} else if (ma >= 500) {
		bits = PCF50633_MBCC7_USB_500mA;
		ma = 500;
	} else if (ma >= 100) {
		bits = PCF50633_MBCC7_USB_100mA;
		ma = 100;
	} else {
		bits = PCF50633_MBCC7_USB_SUSPEND;
		ma = 0;
	}

	ret = pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC7,
					PCF50633_MBCC7_USB_MASK, bits);
	if (ret)
		dev_err(pcf->dev, "error setting usb curlim to %d mA\n", ma);
	else
		dev_info(pcf->dev, "usb curlim to %d mA\n", ma);

	/*
	 * We limit the charging current to be the USB current limit.
	 * The reason is that on pcf50633, when it enters PMU Standby mode,
	 * which it does when the device goes "off", the USB current limit
	 * reverts to the variant default.  In at least one common case, that
	 * default is 500mA.  By setting the charging current to be the same
	 * as the USB limit we set here before PMU standby, we enforce it only
	 * using the correct amount of current even when the USB current limit
	 * gets reset to the wrong thing
	 */

	if (mbc->pcf->pdata->charger_reference_current_ma) {
		mbcc5 = (ma << 8) / mbc->pcf->pdata->charger_reference_current_ma;
		if (mbcc5 > 255)
			mbcc5 = 255;
		pcf50633_reg_write(mbc->pcf, PCF50633_REG_MBCC5, mbcc5);
	}

	mbcs2 = pcf50633_reg_read(mbc->pcf, PCF50633_REG_MBCS2);
	chgmod = (mbcs2 & PCF50633_MBCS2_MBC_MASK);

	/* If chgmod == BATFULL, setting chgena has no effect.
	 * Datasheet says we need to set resume instead but when autoresume is
	 * used resume doesn't work. Clear and set chgena instead.
	 */
	if (chgmod != PCF50633_MBCS2_MBC_BAT_FULL)
		pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
				PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA);
	else {
		pcf50633_reg_clear_bits(pcf, PCF50633_REG_MBCC1,
				PCF50633_MBCC1_CHGENA);
		pcf50633_reg_set_bit_mask(pcf, PCF50633_REG_MBCC1,
				PCF50633_MBCC1_CHGENA, PCF50633_MBCC1_CHGENA);
	}

	power_supply_changed(mbc->usb);

	return ret;
}
Ejemplo n.º 6
0
static int dwc3_otg_set_power(struct usb_phy *phy, unsigned mA)
{
	static int power_supply_type;
	struct dwc3_otg *dotg = container_of(phy->otg, struct dwc3_otg, otg);
#if defined(CONFIG_DWC3_MSM_BC_12_VZW_SUPPORT) && defined(CONFIG_LGE_PM)
	static bool chglogo_check = false;
#endif

	if (!dotg->psy || !dotg->charger) {
		dev_err(phy->dev, "no usb power supply/charger registered\n");
		return 0;
	}

	if (dotg->charger->charging_disabled)
		return 0;

#ifdef CONFIG_LGE_PM
	if (dotg->charger->chg_type == DWC3_SDP_CHARGER ||
			dotg->charger->chg_type == DWC3_FLOATED_CHARGER)
#else
	if (dotg->charger->chg_type == DWC3_SDP_CHARGER)
#endif
		power_supply_type = POWER_SUPPLY_TYPE_USB;
	else if (dotg->charger->chg_type == DWC3_CDP_CHARGER)
		power_supply_type = POWER_SUPPLY_TYPE_USB_CDP;
	else if (dotg->charger->chg_type == DWC3_DCP_CHARGER ||
			dotg->charger->chg_type == DWC3_PROPRIETARY_CHARGER)
		power_supply_type = POWER_SUPPLY_TYPE_USB_DCP;
	else
		power_supply_type = POWER_SUPPLY_TYPE_UNKNOWN;

#ifndef CONFIG_LGE_PM
	power_supply_set_supply_type(dotg->psy, power_supply_type);
#endif

#if defined (CONFIG_TOUCHSCREEN_SYNAPTICS_G3) && defined (CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4)
	update_status(1, dotg->charger->chg_type);
#endif

#if defined(CONFIG_DWC3_MSM_BC_12_VZW_SUPPORT) && defined(CONFIG_LGE_PM)
	if (!chglogo_check && lge_get_boot_mode() == LGE_BOOT_MODE_CHARGERLOGO &&
			dotg->charger->chg_type == DWC3_SDP_CHARGER) {
		if (mA > IUNIT)
			chglogo_check = true;
		else if (mA <= 2) {
			dotg->charger->max_power = mA;
			return 0;
		}
	}

	if (mA > 2 && lge_pm_get_cable_type() != NO_INIT_CABLE) {
		if (dotg->charger->chg_type == DWC3_DCP_CHARGER)
			mA = lge_pm_get_ta_current();
	}
#elif defined(CONFIG_LGE_PM)
	if (mA > 2 && lge_pm_get_cable_type() != NO_INIT_CABLE) {
		if (dotg->charger->chg_type == DWC3_SDP_CHARGER) {
			if (dotg->dwc->gadget.speed == USB_SPEED_SUPER) {
				if (dotg->charger->max_power > 2)
					dotg->charger->max_power = 0;
				mA = DWC3_USB30_CHG_CURRENT;
			} else {
				mA = lge_pm_get_usb_current();
			}
#ifdef CONFIG_QPNP_CHARGER
			/* For MST, boost current up over 900mA in spite of USB */
			if (pseudo_batt_info.mode && mA == 500 )
				mA = DWC3_USB30_CHG_CURRENT;
#endif
		} else if (dotg->charger->chg_type == DWC3_DCP_CHARGER) {
			mA = lge_pm_get_ta_current();
		} else if (dotg->charger->chg_type == DWC3_FLOATED_CHARGER) {
			mA = lge_pm_get_usb_current();
		}
	}
#endif

	if (dotg->charger->chg_type == DWC3_CDP_CHARGER)
		mA = DWC3_IDEV_CHG_MAX;

	if (dotg->charger->max_power == mA)
		return 0;

	dev_info(phy->dev, "Avail curr from USB = %u\n", mA);

/*                                                                                           */
#ifdef CONFIG_LGE_PM
#ifndef CONFIG_USB_DWC3_LGE_SINGLE_PSY
	if (dwc3_otg_get_psy(phy) < 0)
		goto psy_error;
#else
	if (strcmp(dotg->psy->name, "usb")) {
		pr_info("%s psy name is %s, so change psy to usb.\n", __func__, dotg->psy->name);
		dotg->psy = power_supply_get_by_name("usb");
		if (!dotg->psy)
			goto psy_error;
	}
#endif
	power_supply_set_supply_type(dotg->psy, power_supply_type);
#endif

#if defined(CONFIG_DWC3_MSM_BC_12_VZW_SUPPORT) && defined(CONFIG_LGE_PM)
	if (dotg->charger->max_power <= IUNIT && mA > 2) {
#else
	if (dotg->charger->max_power <= 2 && mA > 2) {
#endif
		/* Enable charging */
		if (power_supply_set_online(dotg->psy, true))
			goto psy_error;
		if (power_supply_set_current_limit(dotg->psy, 1000*mA))
			goto psy_error;
#ifdef CONFIG_QPNP_CHARGER
		if (!strncmp(dotg->psy->name, "ac", 2)) {
			dotg->psy = power_supply_get_by_name("usb");
			if (!dotg->psy)
				goto psy_error;

			if (power_supply_set_online(dotg->psy, true))
				goto psy_error;

			if (power_supply_set_supply_type(dotg->psy, power_supply_type))
				goto psy_error;

			if (power_supply_set_current_limit(dotg->psy, 1000*mA))
				goto psy_error;

			dotg->psy = power_supply_get_by_name("ac");
			if (!dotg->psy)
				goto psy_error;
		}
#endif
	} else if (dotg->charger->max_power > 0 && (mA == 0 || mA == 2)) {
		/* Disable charging */
		if (power_supply_set_online(dotg->psy, false))
			goto psy_error;
		/* Set max current limit */
		if (power_supply_set_current_limit(dotg->psy, 0))
			goto psy_error;

#ifdef CONFIG_QPNP_CHARGER
		if (!strncmp(dotg->psy->name, "ac", 2)) {
			dotg->psy = power_supply_get_by_name("usb");
			if (!dotg->psy)
				goto psy_error;

			if (power_supply_set_online(dotg->psy, false))
				goto psy_error;

			if (power_supply_set_supply_type(dotg->psy, power_supply_type))
				goto psy_error;

			if (power_supply_set_current_limit(dotg->psy, 0))
				goto psy_error;

			dotg->psy = power_supply_get_by_name("ac");
			if (!dotg->psy)
				goto psy_error;
		}
#endif
#ifndef CONFIG_USB_DWC3_LGE_SINGLE_PSY
		dotg->charger->chg_type = DWC3_INVALID_CHARGER;
#endif
	}

	power_supply_changed(dotg->psy);

	dotg->charger->max_power = mA;

#if defined (CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) || defined(CONFIG_TOUCHSCREEN_ATMEL_S540)
#if defined (CONFIG_TOUCHSCREEN_SYNAPTICS_G2) || defined (CONFIG_MACH_MSM8974_TIGERS) || defined(CONFIG_MACH_MSM8974_B1_KR) || defined(CONFIG_MACH_MSM8974_B1W)
	queue_work(touch_otg_wq, &dotg->touch_work);
#endif
#endif

	return 0;

psy_error:
	dev_dbg(phy->dev, "power supply error when setting property\n");
	return -ENXIO;
}

/* IRQs which OTG driver is interested in handling */
#define DWC3_OEVT_MASK		(DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT | \
				 DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT)

/**
 * dwc3_otg_interrupt - interrupt handler for dwc3 otg events.
 * @_dotg: Pointer to out controller context structure
 *
 * Returns IRQ_HANDLED on success otherwise IRQ_NONE.
 */
static irqreturn_t dwc3_otg_interrupt(int irq, void *_dotg)
{
	struct dwc3_otg *dotg = (struct dwc3_otg *)_dotg;
	u32 osts, oevt_reg;
	int ret = IRQ_NONE;
	int handled_irqs = 0;
	struct usb_phy *phy = dotg->otg.phy;

	oevt_reg = dwc3_readl(dotg->regs, DWC3_OEVT);

	if (!(oevt_reg & DWC3_OEVT_MASK))
		return IRQ_NONE;

	osts = dwc3_readl(dotg->regs, DWC3_OSTS);

	if ((oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) ||
	    (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT)) {
		/*
		 * ID sts has changed, set inputs later, in the workqueue
		 * function, switch from A to B or from B to A.
		 */

		if (oevt_reg & DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT) {
			if (osts & DWC3_OTG_OSTS_CONIDSTS) {
				dev_dbg(phy->dev, "ID set\n");
				set_bit(ID, &dotg->inputs);
			} else {
				dev_dbg(phy->dev, "ID clear\n");
				clear_bit(ID, &dotg->inputs);
			}
			handled_irqs |= DWC3_OEVTEN_OTGCONIDSTSCHNGEVNT;
		}

		if (oevt_reg & DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT) {
			if (osts & DWC3_OTG_OSTS_BSESVALID) {
				dev_dbg(phy->dev, "BSV set\n");
				set_bit(B_SESS_VLD, &dotg->inputs);
			} else {
				dev_dbg(phy->dev, "BSV clear\n");
				clear_bit(B_SESS_VLD, &dotg->inputs);
			}
			handled_irqs |= DWC3_OEVTEN_OTGBDEVVBUSCHNGEVNT;
		}

		queue_delayed_work(system_nrt_wq, &dotg->sm_work, 0);

		ret = IRQ_HANDLED;

		/* Clear the interrupts we handled */
		dwc3_writel(dotg->regs, DWC3_OEVT, handled_irqs);
	}

	return ret;
}

/**
 * dwc3_otg_init_sm - initialize OTG statemachine input
 * @dotg: Pointer to the dwc3_otg structure
 *
 */
void dwc3_otg_init_sm(struct dwc3_otg *dotg)
{
	u32 osts = dwc3_readl(dotg->regs, DWC3_OSTS);
	struct usb_phy *phy = dotg->otg.phy;
	struct dwc3_ext_xceiv *ext_xceiv;
	int ret;

	dev_dbg(phy->dev, "Initialize OTG inputs, osts: 0x%x\n", osts);

	/*
	 * VBUS initial state is reported after PMIC
	 * driver initialization. Wait for it.
	 */
	ret = wait_for_completion_timeout(&dotg->dwc3_xcvr_vbus_init, HZ * 5);
	if (!ret) {
		dev_err(phy->dev, "%s: completion timeout\n", __func__);
		/* We can safely assume no cable connected */
		set_bit(ID, &dotg->inputs);
	}

	ext_xceiv = dotg->ext_xceiv;
	dwc3_otg_reset(dotg);
	if (ext_xceiv && !ext_xceiv->otg_capability) {
		if (osts & DWC3_OTG_OSTS_CONIDSTS)
			set_bit(ID, &dotg->inputs);
		else
			clear_bit(ID, &dotg->inputs);

		if (osts & DWC3_OTG_OSTS_BSESVALID)
			set_bit(B_SESS_VLD, &dotg->inputs);
		else
			clear_bit(B_SESS_VLD, &dotg->inputs);
	}
}
Ejemplo n.º 7
0
static int mc13892_charger_update_status(struct mc13892_dev_info *di)
{
	int ret;
#ifndef CONFIG_MACH_MX51_ERDOS
	unsigned int value;
#endif /* CONFIG_MACH_MX51_ERDOS */
	int online;

#ifdef CONFIG_MACH_MX51_ERDOS
	ret = pmic_get_dcinput_voltage ((unsigned short *)0);
	if (ret == 0) {
		online = 1;
	} else if (ret == 1) {
		online = 0;
	} else {
		online = di->charger_online;	/* keep previous */
	}
	ret = 0;
		/*
	 * Battery/DCinput update
		 */
		if (online == 1) {
			gpio_battery_enable ( 0 );
	} else if (online == 0) {
			gpio_battery_enable ( 1 );
		}
	if (online != di->charger_online) {
		di->charger_online = online;
		/*
		 * check power_supply_register.
		 */
		if (di->charger.dev != 0) {
		dev_info(di->charger.dev, "charger status: %s\n",
			online ? "online" : "offline");
		power_supply_changed(&di->charger);
		} else {
			printk ("mc13892_charger_update_status: charger status: %s\n",
				online ? "online" : "offline");
		}
	}
#else
	ret = pmic_read_reg(REG_INT_SENSE0, &value, BITFMASK(BIT_CHG_DETS));

	if (ret == 0) {
		online = BITFEXT(value, BIT_CHG_DETS);
		if (online != di->charger_online) {
			di->charger_online = online;
			dev_info(di->charger.dev, "charger status: %s\n",
				online ? "online" : "offline");
			power_supply_changed(&di->charger);

			cancel_delayed_work(&di->monitor_work);
			queue_delayed_work(di->monitor_wqueue,
				&di->monitor_work, HZ / 10);
			if (online) {
				pmic_start_coulomb_counter();
				pmic_restart_charging();
			} else
				pmic_stop_coulomb_counter();
		}
	}
#endif /* CONFIG_MACH_MX51_ERDOS */

	return ret;
}
Ejemplo n.º 8
0
static void axp_charging_monitor(struct work_struct *work)
{
	struct axp_charger *charger;
	uint8_t	val,temp_val[4];
	int	pre_rest_vol,pre_bat_curr_dir;
	unsigned long power_sply = 0;

	charger = container_of(work, struct axp_charger, work.work);
	pre_rest_vol = charger->rest_vol;
	pre_bat_curr_dir = charger->bat_current_direction;
	axp_charger_update_state(charger);
	axp_charger_update(charger, &axp81x_config);
	axp_read(charger->master, AXP81X_CAP,&val);

	spin_lock(&charger->charger_lock);
	charger->rest_vol	= (int)	(val & 0x7F);
	spin_unlock(&charger->charger_lock);

	if (axp_debug & DEBUG_SPLY) {
		DBG_PSY_MSG(DEBUG_SPLY, "charger->ic_temp = %d\n",charger->ic_temp);
		DBG_PSY_MSG(DEBUG_SPLY, "charger->bat_temp = %d\n",charger->bat_temp);
		DBG_PSY_MSG(DEBUG_SPLY, "charger->vbat = %d\n",charger->vbat);
		DBG_PSY_MSG(DEBUG_SPLY, "charger->ibat = %d\n",charger->ibat);
		DBG_PSY_MSG(DEBUG_SPLY, "charger->ocv = %d\n",charger->ocv);
		DBG_PSY_MSG(DEBUG_SPLY, "charger->disvbat = %d\n",charger->disvbat);
		DBG_PSY_MSG(DEBUG_SPLY, "charger->disibat = %d\n",charger->disibat);
		power_sply = charger->disvbat * charger->disibat;
		if (0 != power_sply)
			power_sply = power_sply/1000;
		DBG_PSY_MSG(DEBUG_SPLY, "power_sply = %ld mW\n",power_sply);
		DBG_PSY_MSG(DEBUG_SPLY, "charger->rest_vol = %d\n",charger->rest_vol);
		axp_reads(charger->master,0xba,2,temp_val);
		DBG_PSY_MSG(DEBUG_SPLY, "Axp Rdc = %d\n",(((temp_val[0] & 0x1f) <<8) + temp_val[1])*10742/10000);
		axp_reads(charger->master,0xe0,2,temp_val);
		DBG_PSY_MSG(DEBUG_SPLY, "Axp batt_max_cap = %d\n",(((temp_val[0] & 0x7f) <<8) + temp_val[1])*1456/1000);
		axp_reads(charger->master,0xe2,2,temp_val);
		DBG_PSY_MSG(DEBUG_SPLY, "Axp coulumb_counter = %d\n",(((temp_val[0] & 0x7f) <<8) + temp_val[1])*1456/1000);
		axp_read(charger->master,0xb8,temp_val);
		DBG_PSY_MSG(DEBUG_SPLY, "Axp REG_B8 = %x\n",temp_val[0]);
		axp_reads(charger->master,0xe4,2,temp_val);
		DBG_PSY_MSG(DEBUG_SPLY, "Axp OCV_percentage = %d\n",(temp_val[0] & 0x7f));
		DBG_PSY_MSG(DEBUG_SPLY, "Axp Coulumb_percentage = %d\n",(temp_val[1] & 0x7f));
		DBG_PSY_MSG(DEBUG_SPLY, "charger->is_on = %d\n",charger->is_on);
		DBG_PSY_MSG(DEBUG_SPLY, "charger->bat_current_direction = %d\n",charger->bat_current_direction);
		DBG_PSY_MSG(DEBUG_SPLY, "charger->charge_on = %d\n",charger->charge_on);
		DBG_PSY_MSG(DEBUG_SPLY, "charger->ext_valid = %d\n",charger->ext_valid);
		DBG_PSY_MSG(DEBUG_SPLY, "pmu_runtime_chgcur           = %d\n",axp81x_config.pmu_runtime_chgcur);
		DBG_PSY_MSG(DEBUG_SPLY, "pmu_earlysuspend_chgcur   = %d\n",axp81x_config.pmu_earlysuspend_chgcur);
		DBG_PSY_MSG(DEBUG_SPLY, "pmu_suspend_chgcur        = %d\n",axp81x_config.pmu_suspend_chgcur);
		DBG_PSY_MSG(DEBUG_SPLY, "pmu_shutdown_chgcur       = %d\n\n\n",axp81x_config.pmu_shutdown_chgcur);
	}

	/* if battery volume changed, inform uevent */
	if((charger->rest_vol - pre_rest_vol) || (charger->bat_current_direction != pre_bat_curr_dir)){	
		axp_reads(charger->master,0xe2,2,temp_val);
		axp_reads(charger->master,0xe4,2,(temp_val+2));
		DBG_PSY_MSG(DEBUG_SPLY, "battery vol change: %d->%d \n", pre_rest_vol, charger->rest_vol);
		DBG_PSY_MSG(DEBUG_SPLY, "for test %d %d %d %d %d %d\n",charger->vbat,charger->ocv,charger->ibat,
			(temp_val[2] & 0x7f),(temp_val[3] & 0x7f),(((temp_val[0] & 0x7f) <<8) + temp_val[1])*1456/1000);
		pre_rest_vol = charger->rest_vol;
		power_supply_changed(&charger->batt);
	}
	/* reschedule for the next time */
	schedule_delayed_work(&charger->work, charger->interval);
}
Ejemplo n.º 9
0
static void axp288_charger_extcon_evt_worker(struct work_struct *work)
{
	struct axp288_chrg_info *info =
	    container_of(work, struct axp288_chrg_info, cable.work);
	int ret, current_limit;
	bool changed = false;
	struct extcon_dev *edev = info->cable.edev;
	bool old_connected = info->cable.connected;

	/* Determine cable/charger type */
	if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_SDP) > 0) {
		dev_dbg(&info->pdev->dev, "USB SDP charger  is connected");
		info->cable.connected = true;
		info->cable.chg_type = POWER_SUPPLY_TYPE_USB;
	} else if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_CDP) > 0) {
		dev_dbg(&info->pdev->dev, "USB CDP charger is connected");
		info->cable.connected = true;
		info->cable.chg_type = POWER_SUPPLY_TYPE_USB_CDP;
	} else if (extcon_get_cable_state_(edev, EXTCON_CHG_USB_DCP) > 0) {
		dev_dbg(&info->pdev->dev, "USB DCP charger is connected");
		info->cable.connected = true;
		info->cable.chg_type = POWER_SUPPLY_TYPE_USB_DCP;
	} else {
		if (old_connected)
			dev_dbg(&info->pdev->dev, "USB charger disconnected");
		info->cable.connected = false;
		info->cable.chg_type = POWER_SUPPLY_TYPE_USB;
	}

	/* Cable status changed */
	if (old_connected != info->cable.connected)
		changed = true;

	if (!changed)
		return;

	mutex_lock(&info->lock);

	if (info->is_charger_enabled && !info->cable.connected) {
		info->enable_charger = false;
		ret = axp288_charger_enable_charger(info, info->enable_charger);
		if (ret < 0)
			dev_err(&info->pdev->dev,
				"cannot disable charger (%d)", ret);

	} else if (!info->is_charger_enabled && info->cable.connected) {
		switch (info->cable.chg_type) {
		case POWER_SUPPLY_TYPE_USB:
			current_limit = ILIM_500MA;
			break;
		case POWER_SUPPLY_TYPE_USB_CDP:
			current_limit = ILIM_1500MA;
			break;
		case POWER_SUPPLY_TYPE_USB_DCP:
			current_limit = ILIM_2000MA;
			break;
		default:
			/* Unknown */
			current_limit = 0;
			break;
		}

		/* Set vbus current limit first, then enable charger */
		ret = axp288_charger_set_vbus_inlmt(info, current_limit);
		if (ret < 0) {
			dev_err(&info->pdev->dev,
				"error setting current limit (%d)", ret);
		} else {
			info->enable_charger = (current_limit > 0);
			ret = axp288_charger_enable_charger(info,
							info->enable_charger);
			if (ret < 0)
				dev_err(&info->pdev->dev,
					"cannot enable charger (%d)", ret);
		}
	}

	if (changed)
		info->health = axp288_get_charger_health(info);

	mutex_unlock(&info->lock);

	if (changed)
		power_supply_changed(info->psy_usb);
}
Ejemplo n.º 10
0
static void manta_bat_send_uevent(void)
{
	power_supply_changed(&manta_battery_psy);
}
Ejemplo n.º 11
0
static void update_charge_state(void)
{
	int module_type = 0;
	int usb_type;

	if( _usb && !_dcin ) {
		// usb without DC-in
		usb_type = atmega_io_getUsbType();
DBG 		printk("usb_type=%d\n", usb_type);

		if (usb_type & USB_LOCAL) {
			if ( usb_charge_level() ) {
				enable_high_charging();
			} else {
				enable_low_charging();
			}
		} else if (usb_type == USB_EXT) {
			module_type = atmega_io_getModuleType();
DBG 			printk("module_type=%d\n", module_type);

			if ( module_type == MODULE_ID_SERIAL_ADAPTER ) {
				enable_low_charging();
			} else {
				disable_charging();
			}
		} else {
			// no charge with only ext usb & can't happen when plugging the PC cable
			disable_charging();
		}
		goto out;
	}

	if( _dcin && !_usb ){
		// ! warning ! this case should appears with pc_cable during plug or with
		// not complete connection, don't enable high charge in this case
		// enable high charge only if an allowed module is identified
		module_type = atmega_io_getModuleType();
DBG 		printk("module_type=%d\n", module_type);

		if ( is_module_capable_high_charging(module_type) ) {
			enable_high_charging();
		}
		goto out;
	}

	if( _usb && _dcin ){
		// Means normally that both the USB cable and DC-in are plugged.
		// But be careful that both flags are also enabled when plugging the PC cable
		module_type = atmega_io_getModuleType();
DBG 		printk("module_type=%d\n", module_type);

		if ( is_module_capable_high_charging(module_type) ) {
			enable_high_charging();
		} else {	// pc cable only or pc cable and micro usb
			usb_type = atmega_io_getUsbType();
DBG 			printk("usb_type=%d\n", usb_type);

			if (usb_type == USB_EXT) {		// pc cable only
				if ( usb_charge_level() ) {
					enable_high_charging();
				} else {
					enable_low_charging();
				}
			} else	// in this case, usb source to check is not the power source
				enable_low_charging();

		}	
		goto out;
	}

	if( charge_state && ( !_usb && !_dcin )){
		disable_charging();	
		goto out;
	}
	
 out:
#ifdef CONFIG_POWER_SUPPLY
	 power_supply_changed(&main_battery);
#endif
	 /* make compiler happy if CONFIG_POWER_SUPPLY is not defined */
	 return;
}
Ejemplo n.º 12
0
static void bq27x00_update(struct bq27x00_device_info *di)
{
	struct bq27x00_reg_cache cache = {0, };
	bool is_bq27500 = di->chip == BQ27500;
	bool is_bq27510 = di->chip == BQ27510;
	bool is_bq27425 = di->chip == BQ27425;
	bool is_bq27742 = di->chip == BQ27742;
	bool flags_1b = !(is_bq27500 || is_bq27742);

	cache.flags = bq27x00_read(di, BQ27x00_REG_FLAGS, flags_1b);
	if ((cache.flags & 0xff) == 0xff)
		/* read error */
		cache.flags = -1;
	if (cache.flags >= 0) {
		if (!is_bq27500 && !is_bq27425 && !is_bq27742 && !is_bq27510
				&& (cache.flags & BQ27000_FLAG_CI)) {
			dev_info(di->dev, "battery is not calibrated! ignoring capacity values\n");
			cache.capacity = -ENODATA;
			cache.energy = -ENODATA;
			cache.time_to_empty = -ENODATA;
			cache.time_to_empty_avg = -ENODATA;
			cache.time_to_full = -ENODATA;
			cache.charge_full = -ENODATA;
			cache.health = -ENODATA;
		} else {
			cache.capacity = bq27x00_battery_read_rsoc(di);
			if (is_bq27742 || is_bq27510)
				cache.time_to_empty =
					bq27x00_battery_read_time(di,
							BQ27x00_REG_TTE);
			else if (!is_bq27425) {
				cache.energy = bq27x00_battery_read_energy(di);
				cache.time_to_empty =
					bq27x00_battery_read_time(di,
							BQ27x00_REG_TTE);
				cache.time_to_empty_avg =
					bq27x00_battery_read_time(di,
							BQ27x00_REG_TTECP);
				cache.time_to_full =
					bq27x00_battery_read_time(di,
							BQ27x00_REG_TTF);
			}
			cache.charge_full = bq27x00_battery_read_lmd(di);
			cache.health = bq27x00_battery_read_health(di);
		}
		cache.temperature = bq27x00_battery_read_temperature(di);
		if (!is_bq27425)
			cache.cycle_count = bq27x00_battery_read_cyct(di);
		if (is_bq27742)
			cache.power_avg =
				bq27x00_battery_read_pwr_avg(di,
						BQ27742_POWER_AVG);
		else
			cache.power_avg =
				bq27x00_battery_read_pwr_avg(di,
						BQ27x00_POWER_AVG);

		/* We only have to read charge design full once */
		if (di->charge_design_full <= 0)
			di->charge_design_full = bq27x00_battery_read_ilmd(di);
	}

	if (di->cache.capacity != cache.capacity)
		power_supply_changed(di->bat);

	if (memcmp(&di->cache, &cache, sizeof(cache)) != 0)
		di->cache = cache;

	di->last_update = jiffies;
}
Ejemplo n.º 13
0
static void dev_detect_isr(struct mhl_tx_ctrl *mhl_ctrl)
{
	uint8_t status, reg ;
	struct i2c_client *client = mhl_ctrl->i2c_handle;

	/* INTR_STATUS4 */
	status = MHL_SII_REG_NAME_RD(REG_INTR4);
	pr_debug("%s: reg int4 st=%02X\n", __func__, status);

	if ((0x00 == status) &&\
	    (mhl_ctrl->cur_state == POWER_STATE_D3)) {
		pr_err("%s: invalid intr\n", __func__);
		return;
	}

	if (0xFF == status) {
		pr_debug("%s: invalid intr 0xff\n", __func__);
		MHL_SII_REG_NAME_WR(REG_INTR4, status);
		return;
	}

	if ((status & BIT0) && (mhl_ctrl->chip_rev_id < 1)) {
		pr_debug("%s: scdt intr\n", __func__);
		scdt_st_chg(client);
	}

	if (status & BIT1)
		pr_debug("mhl: int4 bit1 set\n");

	/* mhl_est interrupt */
	if (status & BIT2) {
		pr_debug("%s: mhl_est st=%02X\n", __func__,
			 (int) status);
		mhl_msm_connection(mhl_ctrl);
	} else if (status & BIT3) {
		pr_debug("%s: uUSB-a type dev detct\n", __func__);
		/* Short RGND */
		MHL_SII_REG_NAME_MOD(REG_DISC_STAT2, BIT0 | BIT1, 0x00);
		mhl_msm_disconnection(mhl_ctrl);
		power_supply_changed(&mhl_ctrl->mhl_psy);
		if (mhl_ctrl->notify_usb_online)
			mhl_ctrl->notify_usb_online(0);
	}

	if (status & BIT5) {
		/* clr intr - reg int4 */
		pr_debug("%s: mhl discon: int4 st=%02X\n", __func__,
			 (int)status);
		reg = MHL_SII_REG_NAME_RD(REG_INTR4);
		MHL_SII_REG_NAME_WR(REG_INTR4, reg);
		mhl_msm_disconnection(mhl_ctrl);
		power_supply_changed(&mhl_ctrl->mhl_psy);
		if (mhl_ctrl->notify_usb_online)
			mhl_ctrl->notify_usb_online(0);
	}

	if ((mhl_ctrl->cur_state != POWER_STATE_D0_NO_MHL) &&\
	    (status & BIT6)) {
		/* rgnd rdy Intr */
		pr_debug("%s: rgnd ready intr\n", __func__);
		switch_mode(mhl_ctrl, POWER_STATE_D0_NO_MHL);
		mhl_msm_read_rgnd_int(mhl_ctrl);
	}

	/* Can't succeed at these in D3 */
	if ((mhl_ctrl->cur_state != POWER_STATE_D3) &&\
	     (status & BIT4)) {
		/* cbus lockout interrupt?
		 * Hardware detection mechanism figures that
		 * CBUS line is latched and raises this intr
		 * where we force usb switch open and release
		 */
		pr_warn("%s: cbus locked out!\n", __func__);
		force_usb_switch_open(mhl_ctrl);
		release_usb_switch_open(mhl_ctrl);
	}
	MHL_SII_REG_NAME_WR(REG_INTR4, status);

	return;
}
Ejemplo n.º 14
0
int opchg_battery_set_property(struct power_supply *psy,
                               enum power_supply_property prop,
                               const union power_supply_propval *val)
{
    int rc;
    struct opchg_charger *chip = container_of(psy,
                                 struct opchg_charger, batt_psy);

    switch (prop) {
    case POWER_SUPPLY_PROP_STATUS:
        if (!chip->bms_controlled_charging)
            return -EINVAL;
        switch (val->intval) {
        case POWER_SUPPLY_STATUS_FULL:
            rc = smb358_charging_disable(chip, SOC, true);
            if (rc < 0) {
                dev_err(chip->dev,"Couldn't set charging disable rc = %d\n",rc);
            } else {
                chip->batt_full = true;
                dev_dbg(chip->dev, "status = FULL, batt_full = %d\n",chip->batt_full);
            }
            break;
        case POWER_SUPPLY_STATUS_DISCHARGING:
            chip->batt_full = false;
            power_supply_changed(&chip->batt_psy);
            dev_dbg(chip->dev, "status = DISCHARGING, batt_full = %d\n",chip->batt_full);
            break;
        case POWER_SUPPLY_STATUS_CHARGING:
            rc = smb358_charging_disable(chip, SOC, false);
            if (rc < 0) {
                dev_err(chip->dev,"Couldn't set charging disable rc = %d\n",rc);
            } else {
                chip->batt_full = false;
                dev_dbg(chip->dev, "status = CHARGING, batt_full = %d\n",chip->batt_full);
            }
            break;
        default:
            return -EINVAL;
        }
        break;
    case POWER_SUPPLY_PROP_CHARGING_ENABLED:
        opchg_config_charging_disable(chip, USER_DISABLE, !val->intval);//smb358_charging(chip, val->intval);
        break;

    case POWER_SUPPLY_PROP_CAPACITY:
        chip->fake_battery_soc = val->intval;
        power_supply_changed(&chip->batt_psy);
        break;

    case POWER_SUPPLY_PROP_BATTERY_CHARGER_ENABLE:
        chip->is_factory_mode= val->intval;
        if(chip->is_factory_mode == true)
        {
            if(is_project(OPPO_15011)||is_project(OPPO_14045)||is_project(OPPO_15005) || is_project(OPPO_15025))
            {
                opchg_config_charging_disable(chip, FACTORY_MODE_DISABLE, 0);
            }
        }
        else
        {
            if(is_project(OPPO_15011)||is_project(OPPO_14045)||is_project(OPPO_15005) || is_project(OPPO_15025))
            {
                opchg_config_charging_disable(chip, FACTORY_MODE_DISABLE, 1);
            }
        }
        break;

    default:
        return -EINVAL;
    }

    return 0;
}
static void rk2918_battery_timer_work(struct work_struct *work)
{		
	dprint("func=%s, line=%d :\n", __func__, __LINE__);
	
	rk2918_get_bat_status(gBatteryData);
	rk2918_get_bat_health(gBatteryData);
	rk2918_get_bat_present(gBatteryData);
	rk2918_get_bat_voltage(gBatteryData);
	
	//to prevent gBatCapacity be changed sharply
	
	if (gBatCapacity < 0)
	{
		gBatCapacity = 0;
	}
	else
	{
		if (gBatCapacity > 100)
		{
			gBatCapacity = 100;
		}
	}
	rk2918_get_bat_capacity(gBatteryData);
	
	if (rk29_battery_dbg_level)
	{
    	if (++AdcTestCnt >= 20)
    	{
    	    AdcTestCnt = 0;
    	    printk("\nchg_ok_level =%d, chg_ok= %d, gBatStatus = %d, adc_val = %d, TrueBatVol = %d,gBatVol = %d, gBatCap = %d, captmp = %d, sec = %lu, time_chg_flag = %d, first_flag  = %d\n", 
    	            gBatteryData->charge_ok_level, gpio_get_value(gBatteryData->charge_ok_pin), gBatStatus, AdcTestvalue, adc_to_voltage(AdcTestvalue), 
    	            gBatVoltage, gBatCapacity, capacitytmp, batteryspendcnt, time_chg_flag, first_flag);
    	}
    }

	/*update battery parameter after adc and capacity has been changed*/
	if(((gBatStatus != gBatLastStatus) || (gBatPresent != gBatLastPresent) || (gBatCapacity != gBatLastCapacity))&&(suspend_flag==0))
	{
		//for debug
		if (rk29_battery_dbg_level)
		{
			char _tmp_buf[250];
			int buf_len = 0;
			struct file* fp;
			sprintf(_tmp_buf, "gBatStatus = %d, adc_val = %d, TrueBatVol = %d,gBatVol = %d, gBatCap = %d, captmp = %d, sec = %lu, inter_sec = %lu, time_chg_flag = %d, first_flag = %d\n", 
		    	            gBatStatus, AdcTestvalue, ((AdcTestvalue * BAT_2V5_VALUE * (BAT_PULL_UP_R + BAT_PULL_DOWN_R)) / (1024 * BAT_PULL_DOWN_R)), 
		    	            gBatVoltage, gBatCapacity, capacitytmp, batteryspendcnt, batteryspendcnt - last_batteryspendcnt, time_chg_flag, first_flag);
			buf_len = strlen(_tmp_buf);
			fp = filp_open(BATT_DBG_FILE,O_RDWR | O_APPEND | O_CREAT, 0);
			if(IS_ERR(fp))
			{
				printk("bryan---->open file /data/bat_dbg_record.dat failed\n");
			}
			else
			{
				kernel_write(fp, _tmp_buf, buf_len ,buf_offset);
			    filp_close(fp,NULL);
				buf_offset += buf_len; 
			}
			last_batteryspendcnt = batteryspendcnt;
		}
		
		gBatLastStatus = gBatStatus;
		gBatLastPresent = gBatPresent;
		gBatLastCapacity = gBatCapacity;
		power_supply_changed(&gBatteryData->battery);
	}
}
Ejemplo n.º 16
0
static void opchg_external_power_changed(struct power_supply *psy)
{
    struct opchg_charger *chip = container_of(psy, struct opchg_charger, batt_psy);
    union power_supply_propval prop = {0,};
    int rc, current_limit = 0, online = 0;

    if (chip->bms_psy_name) {
        chip->bms_psy = power_supply_get_by_name((char *)chip->bms_psy_name);
    }

    rc = chip->usb_psy->get_property(chip->usb_psy, POWER_SUPPLY_PROP_ONLINE, &prop);
    if (rc) {
        dev_err(chip->dev, "Couldn't read USB online property, rc=%d\n", rc);
    }
    else {
        online = prop.intval;
    }

    rc = chip->usb_psy->get_property(chip->usb_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &prop);
    if (rc) {
        dev_err(chip->dev, "Couldn't read USB current_max property, rc=%d\n", rc);
    }
    else {
        current_limit = prop.intval / 1000;
    }

    if(current_limit > chip->limit_current_max_ma) {
        current_limit = chip->limit_current_max_ma;
    }

    //lfc add for charger_ovp
    chip->charger_vol = opchg_get_prop_charger_voltage_now(chip);
    opchg_get_charger_ov_status(chip);
    if(chip->charger_ov_status == true) {
        dev_err(chip->dev,"%s charger-ovp,return \n",__func__);
        return ;
    }

    opchg_set_enable_volatile_writes(chip);
    opchg_config_input_chg_current(chip, INPUT_CURRENT_LCD, chip->limit_current_max_ma);
    opchg_config_input_chg_current(chip, INPUT_CURRENT_CAMERA, chip->limit_current_max_ma);
    opchg_config_input_chg_current(chip, INPUT_CURRENT_BY_POWER, current_limit);
    if(is_project(OPPO_14043) || is_project(OPPO_14051)
            || is_project(OPPO_15005) || is_project(OPPO_15057) || is_project(OPPO_15025))
        opchg_set_input_chg_current(chip, chip->max_input_current[INPUT_CURRENT_BY_POWER], false);
    else
        opchg_set_input_chg_current(chip, chip->max_input_current[INPUT_CURRENT_MIN], false);

    if ((chip->multiple_test == 1) && (current_limit >= 500)) {
        opchg_config_suspend_enable(chip, FACTORY_ENABLE, 1);
    }

    opchg_config_over_time(chip, current_limit);//opchg_set_complete_charge_timeout(chip);
    dev_dbg(chip->dev, "%s set charger input current=%d,online = %d, current_limit = %d\n", __func__,chip->max_input_current[INPUT_CURRENT_MIN], online, current_limit);

    opchg_check_status(chip);
    power_supply_changed(&chip->batt_psy);

    if(is_project(OPPO_14043) || is_project(OPPO_15005) || is_project(OPPO_15025)) {
        if(qpnp_charger_type_get(chip) == POWER_SUPPLY_TYPE_USB_DCP) {
            if(!chip->check_stat_again && (current_limit >= 500) && (chip->charging_current > -250)) {
                msleep(550);
                opchg_check_status(chip);
                chip->check_stat_again = true;
                power_supply_changed(&chip->batt_psy);
            }
        }
    }
}
Ejemplo n.º 17
0
int _charger_state_change_( int category, int value, bool is_sleep )
{   
    printk( "[BM] cate: %d, value: %d\n", category, value );

    if( category == STATUS_CATEGORY_CABLE )
    {
        switch( value )
        {
            case POWER_SUPPLY_TYPE_BATTERY :
                /*Stop monitoring the batt. level for Re-charging*/
                sec_bci.battery.monitor_field_rechg_vol = false;

                /*Stop monitoring the temperature*/
                sec_bci.battery.monitor_field_temp = false;

                sec_bci.battery.confirm_full_by_current = 0;
                sec_bci.battery.confirm_recharge = 0;

                sec_bci.charger.charging_timeout = DEFAULT_CHARGING_TIMEOUT;

                sec_bci.charger.full_charge_dur_sleep = 0x0;
                break;

            case POWER_SUPPLY_TYPE_MAINS :
                sec_bci.charger.charging_timeout = DEFAULT_CHARGING_TIMEOUT;
                wake_lock_timeout( &sec_bc_wakelock , HZ );         
                break;

            case POWER_SUPPLY_TYPE_USB :            
                break;

            default :
                break;
        }

        goto Out_Charger_State_Change;
    }
    else if( category == STATUS_CATEGORY_CHARGING )
    {
        switch( value )
        {
            case POWER_SUPPLY_STATUS_UNKNOWN :
            case POWER_SUPPLY_STATUS_NOT_CHARGING :
                //sec_bci.charger.full_charge = false;
                
                /*Stop monitoring the batt. level for Re-charging*/
                sec_bci.battery.monitor_field_rechg_vol = false;

                if( sec_bci.battery.battery_health != POWER_SUPPLY_HEALTH_OVERHEAT 
                    && sec_bci.battery.battery_health != POWER_SUPPLY_HEALTH_COLD )
                {
                    /*Stop monitoring the temperature*/
                    sec_bci.battery.monitor_field_temp = false;
                }

                break;

            case POWER_SUPPLY_STATUS_DISCHARGING :
                break;

            case POWER_SUPPLY_STATUS_FULL :
                /*Start monitoring the batt. level for Re-charging*/
                sec_bci.battery.monitor_field_rechg_vol = true;

                /*Stop monitoring the temperature*/
                sec_bci.battery.monitor_field_temp = false;

                wake_lock_timeout( &sec_bc_wakelock , HZ );
                break;

            case POWER_SUPPLY_STATUS_CHARGING :
                /*Start monitoring the temperature*/
                sec_bci.battery.monitor_field_temp = true;

                /*Stop monitoring the batt. level for Re-charging*/
                sec_bci.battery.monitor_field_rechg_vol = false;

                break;

            case POWER_SUPPLY_STATUS_RECHARGING_FOR_FULL :
                /*Start monitoring the temperature*/
                sec_bci.battery.monitor_field_temp = true;

                /*Stop monitoring the batt. level for Re-charging*/
                sec_bci.battery.monitor_field_rechg_vol = false;

				/*Not change the battery bar - keep battery full screen*/
				//goto Out_Charger_State_Change;
                break;

            case POWER_SUPPLY_STATUS_RECHARGING_FOR_TEMP :
                /*Start monitoring the temperature*/
                sec_bci.battery.monitor_field_temp = true;

                /*Stop monitoring the batt. level for Re-charging*/
                sec_bci.battery.monitor_field_rechg_vol = false;

                break;

            default :
                break;
        }

    }

    if( !is_sleep )
    {
        struct battery_device_info *di;
        struct platform_device *pdev;

        pdev = to_platform_device( this_dev );
        di = platform_get_drvdata( pdev );
        cancel_delayed_work( &di->battery_monitor_work );
        queue_delayed_work( sec_bci.sec_battery_workq, &di->battery_monitor_work, 5 * HZ ); 

        power_supply_changed( &di->sec_battery );
        power_supply_changed( &di->sec_ac );
        power_supply_changed( &di->sec_usb );
    }
    else
    {
        release_gptimer12( &batt_gptimer_12 );
        request_gptimer12( &batt_gptimer_12 );
    }

Out_Charger_State_Change :
    return 0;
}
Ejemplo n.º 18
0
static void charger_work(struct work_struct *work)
{
	struct charger_info *di = container_of(work, struct charger_info, work);
	int next_state;
	bool limiting_active;
	bool charge_source;

	if (is_charging(di))
		charger_pet_watchdog(di);

	charger_lock(di);

	/* update inputs and limit conditions */
	charger_gas_gauge_update(di);
	charger_check_temp_limits(di);
	charger_check_battery_level(di);

	/* aggregate limiting factors */
	limiting_active = di->battery_full || di->charge_disabled ||
		di->temperature_lockout;

	/* hardware ready for charging? */
	charge_source = di->vbus_online && !di->otg_online;

	dev_dbg(di->dev, "%s: battery_full=%d charge_disabled=%d temperature_lockout=%d "
			"invalid_charger=%d vbus_online=%d usb_online=%d otg_online=%d\n", __func__,
			di->battery_full, di->charge_disabled, di->temperature_lockout,
			di->invalid_charger, di->vbus_online, di->usb_online, di->otg_online);

	/* determine the next charger state */
	switch (di->state) {
		case CHARGER_STATE_UNPLUGGED:
		case CHARGER_STATE_CHARGING:
			if (charge_source) {
				if (limiting_active)
					next_state = CHARGER_STATE_NOT_CHARGING;
				else
					next_state = CHARGER_STATE_CHARGING;
			} else {
				next_state = CHARGER_STATE_UNPLUGGED;
			}
			break;

		case CHARGER_STATE_NOT_CHARGING:
			if (charge_source) {
				if (limiting_active)
					next_state = CHARGER_STATE_NOT_CHARGING;
				else
					next_state = CHARGER_STATE_CHARGING;
			} else {
				next_state = CHARGER_STATE_UNPLUGGED;
			}
			break;

		default:
			next_state = di->state; // silence compiler warning
	}

	/* if the state changed, fulfill the required changes */
	if (next_state != di->state) {
		dev_info(di->dev, "transitioning from %s to %s\n", state_to_str(di->state),
				state_to_str(next_state));

		switch (next_state) {
			case CHARGER_STATE_UNPLUGGED:
				wake_lock_timeout(&di->wake_lock, HZ / 2);
				charger_stop_usb_charger(di);
				break;

			case CHARGER_STATE_NOT_CHARGING:
				if (!is_powered(di))
					wake_lock(&di->wake_lock);

				charger_stop_usb_charger(di);
				break;

			case CHARGER_STATE_CHARGING:
				if (!is_powered(di))
					wake_lock(&di->wake_lock);

				charger_start_usb_charger(di);
				break;
		}

		di->state = next_state;
		power_supply_changed(&di->usb);

		twl6030_eval_led_state(di->led, is_powered(di), is_charging(di));
	}

	charger_unlock(di);

	/* update timer */
	mod_timer(&di->timer, di->monitor_interval_jiffies + jiffies);
}
Ejemplo n.º 19
0
static void battery_monitor_work_handler( struct work_struct *work )
{
    int is_full = 0;
    int charge_current_adc;
    struct battery_device_info *di = container_of( work,
                            struct battery_device_info,
                            battery_monitor_work.work );

    #if 0
    printk( "[BM] battery monitor [Level:%d, ADC:%d, TEMP.:%d, cable: %d] \n",\
        get_battery_level_ptg(),\
        get_battery_level_adc(),\
        get_system_temperature(),\
        sec_bci.charger.cable_status );
    #endif

    boot_monitor_count++;
    if(!boot_complete && boot_monitor_count >= 2)
    {
        printk("[BM] boot complete \n");
        boot_complete = true;
    }
	if(sec_bci.charger.rechg_count > 0)
		sec_bci.charger.rechg_count--;


//	printk("[BM] MMC2_DAT0 : %x\n", omap_readw(0x4800215c));

    if ( device_config->MONITORING_SYSTEM_TEMP )
        sec_bci.battery.battery_temp = get_system_temperature( TEMP_DEG );
    else
        sec_bci.battery.battery_temp = 0;

    #if 0
	update_rcomp_by_temperature(sec_bci.battery.battery_temp);
	#endif
	
    /* Monitoring the battery info. */
    sec_bci.battery.battery_level_ptg = get_battery_level_ptg();
    msleep(10);
    sec_bci.battery.battery_level_vol= get_battery_level_adc();

    if( !( sec_bci.battery.monitor_field_temp ) && !( sec_bci.battery.monitor_field_rechg_vol ) )
    {
        sec_bci.battery.monitor_duration = MONITOR_DEFAULT_DURATION;
    }
    else
    {
        // Workaround : check status of cabel at this point.
        if ( !_cable_status_now_() )
        {
            _battery_state_change_( STATUS_CATEGORY_ETC, 
                        ETC_CABLE_IS_DISCONNECTED, 
                        CHARGE_DUR_ACTIVE );
        }

        if ( sec_bci.charger.is_charging && device_config->MONITORING_CHG_CURRENT )
        {
            // in charging && enable monitor_chg_current
            charge_current_adc = get_charging_current_adc_val();
            is_full = check_full_charge_using_chg_current( charge_current_adc );

            if ( is_full )
            {
                _battery_state_change_( STATUS_CATEGORY_CHARGING, 
                            POWER_SUPPLY_STATUS_FULL, 
                            CHARGE_DUR_ACTIVE );
            }
            else
            {
                battery_monitor_core( CHARGE_DUR_ACTIVE );
            }   
        }
        else
        {
            battery_monitor_core( CHARGE_DUR_ACTIVE );
        }
    }

    #if 1 
    printk( "[BM] monitor BATT.(%d%%, %dmV, %d*, count=%d, charging=%d)\n", 
            sec_bci.battery.battery_level_ptg,
            sec_bci.battery.battery_level_vol,
            sec_bci.battery.battery_temp,
            boot_monitor_count,
            sec_bci.charger.is_charging
            );
    #endif
	//printk("[BM] adc 167 -> %d^, adc 198 -> %d^\n", t2adc_to_temperature(927, 0), t2adc_to_temperature(884, 0));

    power_supply_changed( &di->sec_battery );
    power_supply_changed( &di->sec_ac );
    power_supply_changed( &di->sec_usb );

    queue_delayed_work( sec_bci.sec_battery_workq, &di->battery_monitor_work, sec_bci.battery.monitor_duration * HZ);

}
Ejemplo n.º 20
0
static void android_bat_monitor_work(struct work_struct *work)
{
	struct android_bat_data *battery =
		container_of(work, struct android_bat_data, monitor_work);
	struct timespec cur_time;

	wake_lock(&battery->monitor_wake_lock);
	android_bat_update_data(battery);
	mutex_lock(&android_bat_state_lock);

	switch (battery->charging_status) {
	case POWER_SUPPLY_STATUS_FULL:
		if (battery->batt_vcell < battery->pdata->recharging_voltage &&
		    !battery->recharging) {
			battery->recharging = true;
			android_bat_enable_charging(battery, true);
			pr_info("battery: start recharging, v=%d\n",
				battery->batt_vcell/1000);
		}
		break;
	case POWER_SUPPLY_STATUS_DISCHARGING:
		break;
	case POWER_SUPPLY_STATUS_CHARGING:
		switch (battery->batt_health) {
		case POWER_SUPPLY_HEALTH_OVERHEAT:
		case POWER_SUPPLY_HEALTH_COLD:
		case POWER_SUPPLY_HEALTH_OVERVOLTAGE:
		case POWER_SUPPLY_HEALTH_DEAD:
		case POWER_SUPPLY_HEALTH_UNSPEC_FAILURE:
			battery->charging_status =
				POWER_SUPPLY_STATUS_NOT_CHARGING;
			android_bat_enable_charging(battery, false);

			pr_info("battery: Not charging, health=%d\n",
				battery->batt_health);
			break;
		default:
			break;
		}
		break;
	case POWER_SUPPLY_STATUS_NOT_CHARGING:
		if (battery->batt_health == POWER_SUPPLY_HEALTH_GOOD) {
			pr_info("battery: battery health recovered\n");
			if (battery->charge_source != CHARGE_SOURCE_NONE) {
				android_bat_enable_charging(battery, true);
				battery->charging_status
					= POWER_SUPPLY_STATUS_CHARGING;
			} else {
				battery->charging_status
					= POWER_SUPPLY_STATUS_DISCHARGING;
			}
		}
		break;
	default:
		pr_err("%s: Undefined battery status: %d\n", __func__,
		       battery->charging_status);
		break;
	}

	android_bat_charging_timer(battery);
	get_monotonic_boottime(&cur_time);
	pr_info("battery: l=%d v=%d c=%d temp=%s%ld.%ld h=%d st=%d%s ct=%lu type=%s\n",
		battery->batt_soc, battery->batt_vcell/1000,
		battery->batt_current, battery->batt_temp < 0 ? "-" : "",
		abs(battery->batt_temp / 10), abs(battery->batt_temp % 10),
		battery->batt_health, battery->charging_status,
		   battery->recharging ? "r" : "",
		   battery->charging_start_time ?
		   cur_time.tv_sec - battery->charging_start_time : 0,
		charge_source_str(battery->charge_source));
	mutex_unlock(&android_bat_state_lock);
	power_supply_changed(&battery->psy_bat);
	battery->last_poll = ktime_get_boottime();
	android_bat_monitor_set_alarm(battery, FAST_POLL);
	wake_unlock(&battery->monitor_wake_lock);
	return;
}
Ejemplo n.º 21
0
static int dwc3_otg_set_power(struct usb_phy *phy, unsigned mA)
{
	enum power_supply_property power_supply_type;
	struct dwc3_otg *dotg = container_of(phy->otg, struct dwc3_otg, otg);


	if (!dotg->psy || !dotg->charger) {
		dev_err(phy->dev, "no usb power supply/charger registered\n");
		return 0;
	}

	if (dotg->charger->charging_disabled)
		return 0;

	if (not_use_sw_chg_det &&
			(dotg->charger->chg_type != DWC3_INVALID_CHARGER)) {
		dev_dbg(phy->dev,
			"SKIP setting power supply type again,chg_type = %d\n",
			dotg->charger->chg_type);
		goto skip_psy_type;
	}

	if (dotg->charger->chg_type == DWC3_SDP_CHARGER)
		power_supply_type = POWER_SUPPLY_TYPE_USB;
	else if (dotg->charger->chg_type == DWC3_CDP_CHARGER)
		power_supply_type = POWER_SUPPLY_TYPE_USB_CDP;
	else if (dotg->charger->chg_type == DWC3_DCP_CHARGER ||
			dotg->charger->chg_type == DWC3_PROPRIETARY_CHARGER ||
			dotg->charger->chg_type == DWC3_PROPRIETARY_1000MA ||
			dotg->charger->chg_type == DWC3_PROPRIETARY_500MA)
		power_supply_type = POWER_SUPPLY_TYPE_USB_DCP;
	else
		power_supply_type = POWER_SUPPLY_TYPE_UNKNOWN;

	power_supply_set_supply_type(dotg->psy, power_supply_type);

skip_psy_type:

	if (dotg->charger->chg_type == DWC3_CDP_CHARGER)
		mA = DWC3_IDEV_CHG_MAX;

	if (dotg->charger->max_power == mA)
		return 0;

	dev_info(phy->dev, "Avail curr from USB = %u\n", mA);

	if (dotg->charger->max_power > 0 && (mA == 0 || mA == 2)) {
		/* Disable charging */
		if (power_supply_set_online(dotg->psy, false))
			goto psy_error;
	} else {
		/* Enable charging */
		if (power_supply_set_online(dotg->psy, true))
			goto psy_error;
	}

	/* Set max current limit in uA */
	if (power_supply_set_current_limit(dotg->psy, 1000*mA))
		goto psy_error;

	power_supply_changed(dotg->psy);
	dotg->charger->max_power = mA;
	return 0;

psy_error:
	dev_dbg(phy->dev, "power supply error when setting property\n");
	return -ENXIO;
}
Ejemplo n.º 22
0
static void bq24297_status_func(struct work_struct *work)
{
	int ret;

	ret = bq24297_read_reg(SYSTEM_STATUS_REG);

	this_chip->pg_stat = (ret & PG_STAT_MASK)>>PG_STAT_SHIFT;
	this_chip->chrg_stat = (ret & CHRG_STAT_MASK)>>CHRG_STAT_SHIFT;
	this_chip->vbus_stat = (ret & VBUS_STAT_MASK)>>VBUS_STAT_SHIFT;

	bq24297_print("%s(), reg[8] = 0x%x\n", __FUNCTION__, ret);

	if (this_chip->pg_stat == 0)
	{
		this_chip->usb_online = 0;
		this_chip->ac_online = 0;
	}
	else if (this_chip->pg_stat == 1 && this_chip->vbus_stat == 0x01)
	{
		this_chip->usb_online = 1;
		this_chip->ac_online = 0;
	}
	else if (this_chip->pg_stat == 1 && this_chip->vbus_stat == 0x02)
	{
		this_chip->usb_online = 0;
		this_chip->ac_online = 1;
	}
	else
	{
		return ;
	}

	if (this_chip->chrg_stat == 0x00)
	{
		this_chip->chrg_stat = POWER_SUPPLY_STATUS_NOT_CHARGING;
	}
	else if (this_chip->chrg_stat == 0x01)
	{
		this_chip->chrg_stat = POWER_SUPPLY_STATUS_CHARGING;
	}
	else if (this_chip->chrg_stat == 0x02)
	{
		this_chip->chrg_stat = POWER_SUPPLY_STATUS_CHARGING;
	}
	else if (this_chip->chrg_stat == 0x03)
	{
		this_chip->chrg_stat = POWER_SUPPLY_STATUS_FULL;
	}

	if (this_chip->ac_online)
		bq24297_set_ac_charge_current();
	else if (this_chip->usb_online)
		bq24297_set_usb_charge_current();
	else
		bq24297_set_usb_charge_current();


	if (!this_chip->battery)
		this_chip->battery = power_supply_get_by_name("battery");
	if (this_chip->battery)
		power_supply_changed(this_chip->battery);
}
Ejemplo n.º 23
0
static void isp1704_charger_work(struct work_struct *data)
{
	int			detect;
	unsigned long		event;
	unsigned		power;
	struct isp1704_charger	*isp =
		container_of(data, struct isp1704_charger, work);
	static DEFINE_MUTEX(lock);

	event = isp->event;
	power = isp->max_power;

	mutex_lock(&lock);

	if (event != USB_EVENT_NONE)
		isp1704_charger_set_power(isp, 1);

	switch (event) {
	case USB_EVENT_VBUS:
		isp->online = true;

		/* detect charger */
		detect = isp1704_charger_detect(isp);

		if (detect) {
			isp->present = detect;
			isp->psy.type = isp1704_charger_type(isp);
		}

		switch (isp->psy.type) {
		case POWER_SUPPLY_TYPE_USB_DCP:
			isp->current_max = 1800;
			break;
		case POWER_SUPPLY_TYPE_USB_CDP:
			/*
			 * Only 500mA here or high speed chirp
			 * handshaking may break
			 */
			isp->current_max = 500;
			/* FALLTHROUGH */
		case POWER_SUPPLY_TYPE_USB:
		default:
			/* enable data pullups */
			if (isp->phy->otg->gadget)
				usb_gadget_connect(isp->phy->otg->gadget);
		}
		break;
	case USB_EVENT_NONE:
		isp->online = false;
		isp->current_max = 0;
		isp->present = 0;
		isp->current_max = 0;
		isp->psy.type = POWER_SUPPLY_TYPE_USB;

		/*
		 * Disable data pullups. We need to prevent the controller from
		 * enumerating.
		 *
		 * FIXME: This is here to allow charger detection with Host/HUB
		 * chargers. The pullups may be enabled elsewhere, so this can
		 * not be the final solution.
		 */
		if (isp->phy->otg->gadget)
			usb_gadget_disconnect(isp->phy->otg->gadget);

		isp1704_charger_set_power(isp, 0);
		break;
	case USB_EVENT_ENUMERATED:
		if (isp->present)
			isp->current_max = 1800;
		else
			isp->current_max = power;
		break;
	default:
		goto out;
	}

	power_supply_changed(&isp->psy);
out:
	mutex_unlock(&lock);
}
Ejemplo n.º 24
0
static int pm2xxx_charger_ac_en(struct ux500_charger *charger,
	int enable, int vset, int iset)
{
	int ret;
	int volt_index;
	int curr_index;
	u8 val;

	struct pm2xxx_charger *pm2 = to_pm2xxx_charger_ac_device_info(charger);

	if (enable) {
		if (!pm2->ac.charger_connected) {
			dev_dbg(pm2->dev, "AC charger not connected\n");
			return -ENXIO;
		}

		dev_dbg(pm2->dev, "Enable AC: %dmV %dmA\n", vset, iset);
		if (!pm2->vddadc_en_ac) {
			ret = regulator_enable(pm2->regu);
			if (ret)
				dev_warn(pm2->dev,
					"Failed to enable vddadc regulator\n");
			else
				pm2->vddadc_en_ac = true;
		}

		ret = pm2xxx_charging_init(pm2);
		if (ret < 0) {
			dev_err(pm2->dev, "%s charging init failed\n",
					__func__);
			goto error_occured;
		}

		volt_index = pm2xxx_voltage_to_regval(vset);
		curr_index = pm2xxx_current_to_regval(iset);

		if (volt_index < 0 || curr_index < 0) {
			dev_err(pm2->dev,
				"Charger voltage or current too high, "
				"charging not started\n");
			return -ENXIO;
		}

		ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG8, &val);
		if (ret < 0) {
			dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
			goto error_occured;
		}
		val &= ~PM2XXX_CH_VOLT_MASK;
		val |= volt_index;
		ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG8, val);
		if (ret < 0) {
			dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
			goto error_occured;
		}

		ret = pm2xxx_reg_read(pm2, PM2XXX_BATT_CTRL_REG6, &val);
		if (ret < 0) {
			dev_err(pm2->dev, "%s pm2xxx read failed\n", __func__);
			goto error_occured;
		}
		val &= ~PM2XXX_DIR_CH_CC_CURRENT_MASK;
		val |= curr_index;
		ret = pm2xxx_reg_write(pm2, PM2XXX_BATT_CTRL_REG6, val);
		if (ret < 0) {
			dev_err(pm2->dev, "%s pm2xxx write failed\n", __func__);
			goto error_occured;
		}

		if (!pm2->bat->enable_overshoot) {
			ret = pm2xxx_reg_read(pm2, PM2XXX_LED_CTRL_REG, &val);
			if (ret < 0) {
				dev_err(pm2->dev, "%s pm2xxx read failed\n",
								__func__);
				goto error_occured;
			}
			val |= PM2XXX_ANTI_OVERSHOOT_EN;
			ret = pm2xxx_reg_write(pm2, PM2XXX_LED_CTRL_REG, val);
			if (ret < 0) {
				dev_err(pm2->dev, "%s pm2xxx write failed\n",
								__func__);
				goto error_occured;
			}
		}

		ret = pm2xxx_charging_enable_mngt(pm2);
		if (ret < 0) {
			dev_err(pm2->dev, "Failed to enable"
						"pm2xxx ac charger\n");
			goto error_occured;
		}

		pm2->ac.charger_online = 1;
	} else {
		pm2->ac.charger_online = 0;
		pm2->ac.wd_expired = false;

		/* Disable regulator if enabled */
		if (pm2->vddadc_en_ac) {
			regulator_disable(pm2->regu);
			pm2->vddadc_en_ac = false;
		}

		ret = pm2xxx_charging_disable_mngt(pm2);
		if (ret < 0) {
			dev_err(pm2->dev, "failed to disable"
						"pm2xxx ac charger\n");
			goto error_occured;
		}

		dev_dbg(pm2->dev, "PM2301: " "Disabled AC charging\n");
	}
	power_supply_changed(pm2->ac_chg.psy);

error_occured:
	return ret;
}
Ejemplo n.º 25
0
static int param_set_ac_online(const char *key, const struct kernel_param *kp)
{
	ac_online = map_get_value(map_ac_online, key, ac_online);
	power_supply_changed(&test_power_supplies[0]);
	return 0;
}
Ejemplo n.º 26
0
static void tegra_battery_poll_timer_func(unsigned long unused)
{
	power_supply_changed(&EC_Bat_supply[NvCharger_Type_Battery]);
	mod_timer(&poll_timer, jiffies + msecs_to_jiffies(batt_status_poll_period));
}
Ejemplo n.º 27
0
static void bq24192_external_power_changed(struct power_supply *psy)
{
	struct bq24192_chip *chip = container_of(psy,
					struct bq24192_chip, ac_psy);
	union power_supply_propval ret = {0,};
	int wlc_online = 0;
	int wlc_chg_current_ma = 0;

	chip->usb_psy->get_property(chip->usb_psy,
			  POWER_SUPPLY_PROP_ONLINE, &ret);
	chip->usb_online = ret.intval;

	if (chip->wlc_support) {
		chip->wlc_psy->get_property(chip->wlc_psy,
				  POWER_SUPPLY_PROP_ONLINE, &ret);
		wlc_online = ret.intval;

		chip->wlc_psy->get_property(chip->wlc_psy,
				  POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
		wlc_chg_current_ma = ret.intval / 1000;
	}

	if (chip->usb_online &&
			bq24192_is_charger_present(chip)) {
		chip->usb_psy->get_property(chip->usb_psy,
				  POWER_SUPPLY_PROP_CURRENT_MAX, &ret);
		bq24192_set_input_vin_limit(chip, chip->vin_limit_mv);
		bq24192_set_input_i_limit(chip, ret.intval / 1000);
		bq24192_set_ibat_max(chip, USB_MAX_IBAT_MA);
		pr_debug("usb is online! i_limit = %d v_limit = %d\n",
				ret.intval / 1000, chip->vin_limit_mv);
	} else if (chip->ac_online &&
			bq24192_is_charger_present(chip)) {
		chip->icl_first = true;
		bq24192_set_input_vin_limit(chip,
				chip->icl_vbus_mv - 2 * VIN_LIMIT_STEP_MV);
		bq24192_set_input_i_limit(chip, adap_tbl[0].input_limit);
		bq24192_set_ibat_max(chip, adap_tbl[0].chg_limit);
		wake_lock(&chip->icl_wake_lock);
		schedule_delayed_work(&chip->input_limit_work,
					msecs_to_jiffies(200));
		pr_debug("ac is online! i_limit = %d v_limit = %d\n",
				adap_tbl[0].chg_limit, chip->vin_limit_mv);
	} else if (wlc_online) {
		chip->dwn_chg_i_ma = chip->wlc_dwn_i_ma;
		chip->up_chg_i_ma = wlc_chg_current_ma;
		chip->dwn_input_i_ma = chip->wlc_dwn_input_i_ma;
		if (bq24192_is_wlc_bounced(chip))
			chip->up_input_i_ma = chip->wlc_dwn_input_i_ma;
		else
			chip->up_input_i_ma = WLC_INPUT_I_LIMIT_MA;
		bq24192_set_input_vin_limit(chip, chip->wlc_vin_limit_mv);
		bq24192_set_input_i_limit(chip, chip->up_input_i_ma);
		bq24192_set_ibat_max(chip, wlc_chg_current_ma);
		bq24192_step_down_detect_init(chip);
		pr_debug("wlc is online! i_limit = %d v_limit = %d\n",
				wlc_chg_current_ma, chip->wlc_vin_limit_mv);
	}

	if (bq24192_is_charger_present(chip))
		schedule_delayed_work(&chip->therm_work,
				msecs_to_jiffies(2000));

	chip->usb_psy->get_property(chip->usb_psy,
			  POWER_SUPPLY_PROP_SCOPE, &ret);

	if (ret.intval) {
		pr_debug("usb host mode = %d\n", ret.intval);
		if ((ret.intval == POWER_SUPPLY_SCOPE_SYSTEM)
					&& !bq24192_is_otg_mode(chip))
			bq24192_enable_otg(chip, true);
		else if ((ret.intval == POWER_SUPPLY_SCOPE_DEVICE)
					&& bq24192_is_otg_mode(chip))
			bq24192_enable_otg(chip, false);
	}

	power_supply_changed(&chip->ac_psy);
}