int diag_bridge_write(char *data, int size)
{
	struct urb		*urb = NULL;
	unsigned int		pipe;
	struct diag_bridge	*dev = __dev;
	int			ret;

	pr_debug("writing %d bytes", size);

	if (!dev || !dev->ifc) {
		pr_err("device is disconnected");
		return -ENODEV;
	}

	if (!dev->ops) {
		pr_err("bridge is not open");
		return -ENODEV;
	}

	if (!size) {
		dev_err(&dev->ifc->dev, "invalid size:%d\n", size);
		return -EINVAL;
	}

	/* if there was a previous unrecoverable error, just quit */
	if (dev->err)
		return -ENODEV;

	kref_get(&dev->kref);

	urb = usb_alloc_urb(0, GFP_KERNEL);
	if (!urb) {
		dev_err(&dev->ifc->dev, "unable to allocate urb\n");
		ret = -ENOMEM;
		goto error;
	}

	ret = usb_autopm_get_interface(dev->ifc);
	if (ret < 0 && ret != -EAGAIN && ret != -EACCES) {
		pr_err_ratelimited("write: autopm_get failed:%d", ret);
		goto free_error;
	}

	pipe = usb_sndbulkpipe(dev->udev, dev->out_epAddr);
	usb_fill_bulk_urb(urb, dev->udev, pipe, data, size,
				diag_bridge_write_cb, dev);
	urb->transfer_flags |= URB_ZERO_PACKET;
	usb_anchor_urb(urb, &dev->submitted);
	dev->pending_writes++;

	ret = usb_submit_urb(urb, GFP_KERNEL);
	
	if (ret) {
#if defined(CONFIG_LGE_HANDLE_PANIC)//unchol.park
		if(lge_pm_get_cable_type() == CABLE_130K)
			printk("[MDM TEST] usb_submit_urb failed. ret = %d\n", ret);
#endif
		pr_err_ratelimited("submitting urb failed err:%d", ret);
		dev->pending_writes--;
		usb_unanchor_urb(urb);
		usb_autopm_put_interface(dev->ifc);
		goto free_error;
	}

free_error:
	usb_free_urb(urb);
error:
	if (ret) /* otherwise this is done in the completion handler */
		kref_put(&dev->kref, diag_bridge_delete);
	return ret;
}
示例#2
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)
#if defined (CONFIG_TOUCHSCREEN_SYNAPTICS_G2) || defined (CONFIG_MACH_MSM8974_TIGERS)
	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);
	}
}
示例#3
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
#ifdef CONFIG_LGE_PM
		/* [email protected]
		 * healthd get battery psy type at init only.
		 * If cable detach before healthd init,
		 * healthd recognize usb psy as battery type.
		 */
		power_supply_type = POWER_SUPPLY_TYPE_UNKNOWN;
#else
		power_supply_type = POWER_SUPPLY_TYPE_BATTERY;
#endif

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

#if 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);

/* [email protected] make psy getter and move it above power_supply_type setter. 2014-02-06 */
#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 (dotg->charger->max_power <= 2 && mA > 2) {
		/* 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
	}

	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;
}