static int ab8500_charger_usb_en()

in supply/ab8500_charger.c [1570:1717]


static int ab8500_charger_usb_en(struct ux500_charger *charger,
	int enable, int vset_uv, int ich_out_ua)
{
	int ret;
	int volt_index;
	int curr_index;
	u8 overshoot = 0;

	struct ab8500_charger *di = to_ab8500_charger_usb_device_info(charger);

	if (enable) {
		/* Check if USB is connected */
		if (!di->usb.charger_connected) {
			dev_err(di->dev, "USB charger not connected\n");
			return -ENXIO;
		}

		/*
		 * Due to a bug in AB8500, BTEMP_HIGH/LOW interrupts
		 * will be triggered every time we enable the VDD ADC supply.
		 * This will turn off charging for a short while.
		 * It can be avoided by having the supply on when
		 * there is a charger enabled. Normally the VDD ADC supply
		 * is enabled every time a GPADC conversion is triggered.
		 * We will force it to be enabled from this driver to have
		 * the GPADC module independent of the AB8500 chargers
		 */
		if (!di->vddadc_en_usb) {
			ret = regulator_enable(di->regu);
			if (ret)
				dev_warn(di->dev,
					"Failed to enable regulator\n");
			else
				di->vddadc_en_usb = true;
		}

		/* Enable USB charging */
		dev_dbg(di->dev, "Enable USB: %d uV %d uA\n", vset_uv, ich_out_ua);

		/* Check if the requested voltage or current is valid */
		volt_index = ab8500_voltage_to_regval(vset_uv);
		curr_index = ab8500_current_to_regval(di, ich_out_ua);
		if (volt_index < 0 || curr_index < 0) {
			dev_err(di->dev,
				"Charger voltage or current too high, "
				"charging not started\n");
			return -ENXIO;
		}

		/*
		 * ChVoltLevel: max voltage up to which battery can be
		 * charged
		 */
		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
			AB8500_CH_VOLT_LVL_REG, (u8) volt_index);
		if (ret) {
			dev_err(di->dev, "%s write failed\n", __func__);
			return ret;
		}
		/* Check if VBAT overshoot control should be enabled */
		if (!di->bm->enable_overshoot)
			overshoot = USB_CHG_NO_OVERSHOOT_ENA_N;

		/* Enable USB Charger */
		dev_dbg(di->dev,
			"Enabling USB with write to AB8500_USBCH_CTRL1_REG\n");
		ret = abx500_set_register_interruptible(di->dev, AB8500_CHARGER,
			AB8500_USBCH_CTRL1_REG, USB_CH_ENA | overshoot);
		if (ret) {
			dev_err(di->dev, "%s write failed\n", __func__);
			return ret;
		}

		/* If success power on charging LED indication */
		ret = ab8500_charger_led_en(di, true);
		if (ret < 0)
			dev_err(di->dev, "failed to enable LED\n");

		di->usb.charger_online = 1;

		/* USBChInputCurr: current that can be drawn from the usb */
		ret = ab8500_charger_set_vbus_in_curr(di,
					di->max_usb_in_curr.usb_type_max_ua);
		if (ret) {
			dev_err(di->dev, "setting USBChInputCurr failed\n");
			return ret;
		}

		/* ChOutputCurentLevel: protected output current */
		ret = ab8500_charger_set_output_curr(di, ich_out_ua);
		if (ret) {
			dev_err(di->dev, "%s "
				"Failed to set ChOutputCurentLevel\n",
				__func__);
			return ret;
		}

		queue_delayed_work(di->charger_wq, &di->check_vbat_work, HZ);

	} else {
		/* Disable USB charging */
		dev_dbg(di->dev, "%s Disabled USB charging\n", __func__);
		ret = abx500_set_register_interruptible(di->dev,
			AB8500_CHARGER,
			AB8500_USBCH_CTRL1_REG, 0);
		if (ret) {
			dev_err(di->dev,
				"%s write failed\n", __func__);
			return ret;
		}

		ret = ab8500_charger_led_en(di, false);
		if (ret < 0)
			dev_err(di->dev, "failed to disable LED\n");
		/* USBChInputCurr: current that can be drawn from the usb */
		ret = ab8500_charger_set_vbus_in_curr(di, 0);
		if (ret) {
			dev_err(di->dev, "setting USBChInputCurr failed\n");
			return ret;
		}

		/* ChOutputCurentLevel: protected output current */
		ret = ab8500_charger_set_output_curr(di, 0);
		if (ret) {
			dev_err(di->dev, "%s "
				"Failed to reset ChOutputCurentLevel\n",
				__func__);
			return ret;
		}
		di->usb.charger_online = 0;
		di->usb.wd_expired = false;

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

		dev_dbg(di->dev, "%s Disabled USB charging\n", __func__);

		/* Cancel any pending Vbat check work */
		cancel_delayed_work(&di->check_vbat_work);

	}
	ab8500_power_supply_changed(di, di->usb_chg.psy);

	return ret;
}