drivers/extcon/extcon-intel-cht-wc.c

Source file repositories/reference/linux-study-clean/drivers/extcon/extcon-intel-cht-wc.c

File Facts

System
Linux kernel
Corpus path
drivers/extcon/extcon-intel-cht-wc.c
Extension
.c
Size
18716 bytes
Lines
641
Domain
Driver Families
Bucket
drivers/extcon
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct cht_wc_extcon_data {
	struct device *dev;
	struct regmap *regmap;
	struct extcon_dev *edev;
	struct usb_role_switch *role_sw;
	struct regulator *vbus_boost;
	struct power_supply *psy;
	enum power_supply_usb_type usb_type;
	unsigned int previous_cable;
	bool usb_host;
	bool vbus_boost_enabled;
};

static int cht_wc_extcon_get_id(struct cht_wc_extcon_data *ext, int pwrsrc_sts)
{
	switch ((pwrsrc_sts & CHT_WC_PWRSRC_USBID_MASK) >> CHT_WC_PWRSRC_USBID_SHIFT) {
	case CHT_WC_PWRSRC_RID_GND:
		return INTEL_USB_ID_GND;
	case CHT_WC_PWRSRC_RID_FLOAT:
		return INTEL_USB_ID_FLOAT;
	/*
	 * According to the spec. we should read the USB-ID pin ADC value here
	 * to determine the resistance of the used pull-down resister and then
	 * return RID_A / RID_B / RID_C based on this. But all "Accessory
	 * Charger Adapter"s (ACAs) which users can actually buy always use
	 * a combination of a charging port with one or more USB-A ports, so
	 * they should always use a resistor indicating RID_A. But the spec
	 * is hard to read / badly-worded so some of them actually indicate
	 * they are a RID_B ACA evnen though they clearly are a RID_A ACA.
	 * To workaround this simply always return INTEL_USB_RID_A, which
	 * matches all the ACAs which users can actually buy.
	 */
	case CHT_WC_PWRSRC_RID_ACA:
		return INTEL_USB_RID_A;
	default:
		return INTEL_USB_ID_FLOAT;
	}
}

static int cht_wc_extcon_get_charger(struct cht_wc_extcon_data *ext,
				     bool ignore_errors)
{
	int ret, usbsrc, status;
	unsigned long timeout;

	/* Charger detection can take upto 600ms, wait 800ms max. */
	timeout = jiffies + msecs_to_jiffies(800);
	do {
		ret = regmap_read(ext->regmap, CHT_WC_USBSRC, &usbsrc);
		if (ret) {
			dev_err(ext->dev, "Error reading usbsrc: %d\n", ret);
			return ret;
		}

		status = usbsrc & CHT_WC_USBSRC_STS_MASK;
		if (status == CHT_WC_USBSRC_STS_SUCCESS ||
		    status == CHT_WC_USBSRC_STS_FAIL)
			break;

		msleep(50); /* Wait a bit before retrying */
	} while (time_before(jiffies, timeout));

	if (status != CHT_WC_USBSRC_STS_SUCCESS) {
		if (!ignore_errors) {
			if (status == CHT_WC_USBSRC_STS_FAIL)
				dev_warn(ext->dev, "Could not detect charger type\n");
			else
				dev_warn(ext->dev, "Timeout detecting charger type\n");
		}

		/* Safe fallback */
		usbsrc = CHT_WC_USBSRC_TYPE_SDP << CHT_WC_USBSRC_TYPE_SHIFT;
	}

	usbsrc = (usbsrc & CHT_WC_USBSRC_TYPE_MASK) >> CHT_WC_USBSRC_TYPE_SHIFT;
	switch (usbsrc) {
	default:
		dev_warn(ext->dev,
			"Unhandled charger type %d, defaulting to SDP\n",
			 ret);
		ext->usb_type = POWER_SUPPLY_USB_TYPE_SDP;
		return EXTCON_CHG_USB_SDP;
	case CHT_WC_USBSRC_TYPE_SDP:
	case CHT_WC_USBSRC_TYPE_FLOATING:
	case CHT_WC_USBSRC_TYPE_OTHER:
		ext->usb_type = POWER_SUPPLY_USB_TYPE_SDP;
		return EXTCON_CHG_USB_SDP;
	case CHT_WC_USBSRC_TYPE_CDP:
		ext->usb_type = POWER_SUPPLY_USB_TYPE_CDP;
		return EXTCON_CHG_USB_CDP;

Annotation

Implementation Notes