static int max8997_muic_handle_adc(struct max8997_muic_info *info, int adc)
{
	int ret = 0;

	switch (adc) {
	case MAX8997_ADC_GROUND:
		ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, true);
		break;
	case MAX8997_ADC_MHL:
		max8997_muic_handle_mhl(info, true);
		break;
	case MAX8997_ADC_JIG_USB_1:
	case MAX8997_ADC_JIG_USB_2:
		ret = max8997_muic_handle_usb(info, MAX8997_USB_DEVICE, true);
		break;
	case MAX8997_ADC_DESKDOCK:
	case MAX8997_ADC_CARDOCK:
		ret = max8997_muic_handle_dock(info, adc, true);
		break;
	case MAX8997_ADC_JIG_UART:
		ret = max8997_muic_handle_jig_uart(info, true);
		break;
	case MAX8997_ADC_OPEN:
		ret = max8997_muic_handle_adc_detach(info);
		break;
	default:
		break;
	}

	info->pre_adc = adc;

	return ret;
}
static int max8997_muic_handle_attach(struct max8997_muic_info *info,
		u8 status1, u8 status2)
{
	struct max8997_muic_data *mdata = info->muic_data;
	u8 adc, adclow, adcerr, chgtyp, vbvolt, chgdetrun;
	int ret = 0;
#ifdef CONFIG_USBHUB_USB3803
	/* setting usb hub in Diagnostic(hub) mode */
	usb3803_set_mode(USB_3803_MODE_HUB);
#endif /* CONFIG_USBHUB_USB3803 */

	adc = status1 & STATUS1_ADC_MASK;
	adclow = status1 & STATUS1_ADCLOW_MASK;
	adcerr = status1 & STATUS1_ADCERR_MASK;
	chgtyp = status2 & STATUS2_CHGTYP_MASK;
	vbvolt = status2 & STATUS2_VBVOLT_MASK;
	chgdetrun = status2 & STATUS2_CHGDETRUN_MASK;

	switch (info->cable_type) {
	case CABLE_TYPE_JIG_UART_OFF:
	case CABLE_TYPE_JIG_UART_OFF_VB:
		/* Workaround for Factory mode.
		 * Abandon adc interrupt of approximately +-100K range
		 * if previous cable status was JIG UART BOOT OFF.
		 */
		if (adc == (ADC_JIG_UART_OFF + 1) ||
				adc == (ADC_JIG_UART_OFF - 1)) {
			dev_warn(info->dev, "%s: abandon ADC\n", __func__);
			return 0;
		}

		if (adcerr) {
			dev_warn(info->dev, "%s: current state is jig_uart_off,"
				"just ignore\n", __func__);
			return 0;
		}

		if (adc != ADC_JIG_UART_OFF) {
			if (info->cable_type == CABLE_TYPE_JIG_UART_OFF_VB) {
				dev_info(info->dev, "%s: adc != JIG_UART_OFF, remove JIG UART/OFF/VB\n", __func__);
				info->cable_type = CABLE_TYPE_NONE;
				max8997_muic_set_charging_type(info, false);
			} else {
				dev_info(info->dev, "%s: adc != JIG_UART_OFF, remove JIG UART/BOOTOFF\n", __func__);
				info->cable_type = CABLE_TYPE_NONE;
			}
		}
		break;

	case CABLE_TYPE_DESKDOCK:
		if (adcerr || (adc != ADC_DESKDOCK)) {
			if (adcerr)
				dev_err(info->dev, "%s: ADC err occured(DESKDOCK)\n", __func__);
			else
				dev_warn(info->dev, "%s: ADC != DESKDOCK, remove DESKDOCK\n", __func__);

			info->cable_type = CABLE_TYPE_NONE;

			max8997_muic_set_charging_type(info, false);

			if (mdata->deskdock_cb)
				mdata->deskdock_cb(MAX8997_MUIC_DETACHED);

			if (adcerr)
				return 0;
		}
		break;

	case CABLE_TYPE_CARDOCK:
		if (adcerr || (adc != ADC_CARDOCK)) {
			if (adcerr)
				dev_err(info->dev, "%s: ADC err occured(CARDOCK)\n", __func__);
			else
				dev_warn(info->dev, "%s: ADC != CARDOCK, remove CARDOCK\n", __func__);

			info->cable_type = CABLE_TYPE_NONE;

			max8997_muic_set_charging_type(info, false);

			if (mdata->cardock_cb)
				mdata->cardock_cb(MAX8997_MUIC_DETACHED);

			if (adcerr)
				return 0;
		}
		break;

	default:
		break;
	}

	/* 1Kohm ID regiter detection (mHL)
	 * Old MUIC : ADC value:0x00 or 0x01, ADCLow:1
	 * New MUIC : ADC value is not set(Open), ADCLow:1, ADCError:1
	 */
	if (adclow && adcerr) {
		max8997_muic_attach_mhl(info, chgtyp);
		return 0;
	}

	switch (adc) {
	case ADC_GND:
#if defined(CONFIG_MACH_U1)
		/* This is for support old MUIC */
		if (adclow) {
			max8997_muic_attach_mhl(info, chgtyp);
			break;
		}
#endif

		if (chgtyp == CHGTYP_NO_VOLTAGE) {
			if (info->cable_type == CABLE_TYPE_OTG) {
				dev_info(info->dev,
						"%s: duplicated(OTG)\n",
						__func__);
				break;
			}

			info->cable_type = CABLE_TYPE_OTG;
			max8997_muic_set_usb_path(info, AP_USB_MODE);
			if (mdata->usb_cb && info->is_usb_ready)
				mdata->usb_cb(USB_OTGHOST_ATTACHED);
		} else if (chgtyp == CHGTYP_USB ||
				chgtyp == CHGTYP_DOWNSTREAM_PORT ||
				chgtyp == CHGTYP_DEDICATED_CHGR ||
				chgtyp == CHGTYP_500MA	||
				chgtyp == CHGTYP_1A) {
			dev_info(info->dev, "%s: OTG charging pump\n",
					__func__);
			ret = max8997_muic_set_charging_type(info, false);
		}
		break;
	case ADC_MHL:
#if defined(CONFIG_MACH_U1)
		/* This is for support old MUIC */
		max8997_muic_attach_mhl(info, chgtyp);
#endif
		break;
	case ADC_JIG_UART_OFF:
		max8997_muic_handle_jig_uart(info, vbvolt);
		break;
	case ADC_JIG_USB_OFF:
	case ADC_JIG_USB_ON:
		if (vbvolt & STATUS2_VBVOLT_MASK)
			ret = max8997_muic_attach_usb_type(info, adc);
		break;
	case ADC_DESKDOCK:
	case ADC_CARDOCK:
		max8997_muic_attach_dock_type(info, adc);
		if (chgtyp == CHGTYP_USB ||
				chgtyp == CHGTYP_DOWNSTREAM_PORT ||
				chgtyp == CHGTYP_DEDICATED_CHGR ||
				chgtyp == CHGTYP_500MA	||
				chgtyp == CHGTYP_1A)
			ret = max8997_muic_set_charging_type(info, false);
		else if (chgtyp == CHGTYP_NO_VOLTAGE && !chgdetrun)
			ret = max8997_muic_set_charging_type(info, true);
		break;
	case ADC_CEA936ATYPE1_CHG:
	case ADC_CEA936ATYPE2_CHG:
	case ADC_OPEN:
		switch (chgtyp) {
		case CHGTYP_USB:
			if (adc == ADC_CEA936ATYPE1_CHG
					|| adc == ADC_CEA936ATYPE2_CHG)
				break;
			if (mdata->is_mhl_attached
					&& mdata->is_mhl_attached() &&
					info->cable_type == CABLE_TYPE_MHL) {
				dev_info(info->dev, "%s: MHL(charging)\n",
						__func__);
				info->cable_type = CABLE_TYPE_MHL_VB;
				ret = max8997_muic_set_charging_type(info,
						false);
				return ret;
			}
			ret = max8997_muic_attach_usb_type(info, adc);
			break;
		case CHGTYP_DOWNSTREAM_PORT:
		case CHGTYP_DEDICATED_CHGR:
		case CHGTYP_500MA:
		case CHGTYP_1A:
			dev_info(info->dev, "%s:TA\n", __func__);
			info->cable_type = CABLE_TYPE_TA;
#ifdef CONFIG_USBHUB_USB3803
			/* setting usb hub in default mode (standby) */
			usb3803_set_mode(USB_3803_MODE_STANDBY);
#endif  /* CONFIG_USBHUB_USB3803 */
			ret = max8997_muic_set_charging_type(info, false);
			if (ret)
				info->cable_type = CABLE_TYPE_NONE;
			break;
		default:
			break;
		}
		break;
	default:
		dev_warn(info->dev, "%s: unsupported adc=0x%x\n", __func__,
				adc);
		break;
	}
	return ret;
}
示例#3
0
static int max8997_muic_adc_handler(struct max8997_muic_info *info)
{
	int cable_type;
	bool attached;
	int ret = 0;

	/* Check cable state which is either detached or attached */
	cable_type = max8997_muic_get_cable_type(info,
				MAX8997_CABLE_GROUP_ADC, &attached);

	switch (cable_type) {
	case MAX8997_MUIC_ADC_GROUND:
		ret = max8997_muic_handle_usb(info, MAX8997_USB_HOST, attached);
		if (ret < 0)
			return ret;
		break;
	case MAX8997_MUIC_ADC_MHL:
		extcon_set_state_sync(info->edev, EXTCON_DISP_MHL, attached);
		break;
	case MAX8997_MUIC_ADC_FACTORY_MODE_USB_OFF:
	case MAX8997_MUIC_ADC_FACTORY_MODE_USB_ON:
		ret = max8997_muic_handle_usb(info,
					     MAX8997_USB_DEVICE, attached);
		if (ret < 0)
			return ret;
		break;
	case MAX8997_MUIC_ADC_AV_CABLE_NOLOAD:
	case MAX8997_MUIC_ADC_FACTORY_MODE_UART_ON:
		ret = max8997_muic_handle_dock(info, cable_type, attached);
		if (ret < 0)
			return ret;
		break;
	case MAX8997_MUIC_ADC_FACTORY_MODE_UART_OFF:
		ret = max8997_muic_handle_jig_uart(info, attached);
		break;
	case MAX8997_MUIC_ADC_REMOTE_S1_BUTTON:
	case MAX8997_MUIC_ADC_REMOTE_S2_BUTTON:
	case MAX8997_MUIC_ADC_REMOTE_S3_BUTTON:
	case MAX8997_MUIC_ADC_REMOTE_S4_BUTTON:
	case MAX8997_MUIC_ADC_REMOTE_S5_BUTTON:
	case MAX8997_MUIC_ADC_REMOTE_S6_BUTTON:
	case MAX8997_MUIC_ADC_REMOTE_S7_BUTTON:
	case MAX8997_MUIC_ADC_REMOTE_S8_BUTTON:
	case MAX8997_MUIC_ADC_REMOTE_S9_BUTTON:
	case MAX8997_MUIC_ADC_REMOTE_S10_BUTTON:
	case MAX8997_MUIC_ADC_REMOTE_S11_BUTTON:
	case MAX8997_MUIC_ADC_REMOTE_S12_BUTTON:
	case MAX8997_MUIC_ADC_RESERVED_ACC_1:
	case MAX8997_MUIC_ADC_RESERVED_ACC_2:
	case MAX8997_MUIC_ADC_RESERVED_ACC_3:
	case MAX8997_MUIC_ADC_RESERVED_ACC_4:
	case MAX8997_MUIC_ADC_RESERVED_ACC_5:
	case MAX8997_MUIC_ADC_CEA936_AUDIO:
	case MAX8997_MUIC_ADC_PHONE_POWERED_DEV:
	case MAX8997_MUIC_ADC_TTY_CONVERTER:
	case MAX8997_MUIC_ADC_UART_CABLE:
	case MAX8997_MUIC_ADC_CEA936A_TYPE1_CHG:
	case MAX8997_MUIC_ADC_CEA936A_TYPE2_CHG:
	case MAX8997_MUIC_ADC_AUDIO_MODE_REMOTE:
		/*
		 * This cable isn't used in general case if it is specially
		 * needed to detect additional cable, should implement
		 * proper operation when this cable is attached/detached.
		 */
		dev_info(info->dev,
			"cable is %s but it isn't used (type:0x%x)\n",
			attached ? "attached" : "detached", cable_type);
		return -EAGAIN;
	default:
		dev_err(info->dev,
			"failed to detect %s unknown cable (type:0x%x)\n",
			attached ? "attached" : "detached", cable_type);
		return -EINVAL;
	}

	return 0;
}
static int max8997_muic_handle_attach(struct max8997_muic_info *info,
		u8 status1, u8 status2)
{
	struct max8997_muic_data *mdata = info->muic_data;
	u8 adc, adclow, adcerr, chgtyp, vbvolt, chgdetrun;
	int ret = 0;

	adc = status1 & STATUS1_ADC_MASK;
	adclow = status1 & STATUS1_ADCLOW_MASK;
	adcerr = status1 & STATUS1_ADCERR_MASK;
	chgtyp = status2 & STATUS2_CHGTYP_MASK;
	vbvolt = status2 & STATUS2_VBVOLT_MASK;
	chgdetrun = status2 & STATUS2_CHGDETRUN_MASK;

	/* Workaround for Factory mode.
	 * Abandon adc interrupt of approximately +-100K range
	 * if previous cable status was JIG UART BOOT OFF.
	 */
	if (info->cable_type == CABLE_TYPE_JIG_UART_OFF ||
			info->cable_type == CABLE_TYPE_JIG_UART_OFF_VB) {
		if (adc == (ADC_JIG_UART_OFF + 1) ||
				adc == (ADC_JIG_UART_OFF - 1)) {
			dev_warn(info->dev, "%s: abandon ADC\n", __func__);
			return 0;
		}
	}

	/* 1Kohm ID regiter detection (mHL)
	 * Old MUIC : ADC value:0x00 or 0x01, ADCLow:1
	 * New MUIC : ADC value is not set(Open), ADCLow:1, ADCError:1
	 */
	if (adclow && adcerr) {
		max8997_muic_attach_mhl(info, chgtyp);
		return 0;
	}

	switch (adc) {
	case ADC_GND:
		if (adclow) {
			max8997_muic_attach_mhl(info, chgtyp);
			break;
		}

		if (chgtyp == CHGTYP_NO_VOLTAGE) {
			if (info->cable_type == CABLE_TYPE_OTG) {
				dev_info(info->dev,
						"%s: duplicated(OTG)\n",
						__func__);
				break;
			}

			info->cable_type = CABLE_TYPE_OTG;
			max8997_muic_set_usb_path(info, AP_USB_MODE);
			if (mdata->usb_cb && info->is_usb_ready)
				mdata->usb_cb(USB_OTGHOST_ATTACHED);
		} else if (chgtyp == CHGTYP_USB ||
				chgtyp == CHGTYP_DOWNSTREAM_PORT ||
				chgtyp == CHGTYP_DEDICATED_CHGR ||
				chgtyp == CHGTYP_500MA	||
				chgtyp == CHGTYP_1A) {
			dev_info(info->dev, "%s: OTG charging pump\n",
					__func__);
			ret = max8997_muic_set_charging_type(info, false);
		}
		break;
	case ADC_MHL:
		max8997_muic_attach_mhl(info, chgtyp);
		break;
	case ADC_JIG_UART_OFF:
		max8997_muic_handle_jig_uart(info, vbvolt);
		break;
	case ADC_JIG_USB_OFF:
	case ADC_JIG_USB_ON:
		ret = max8997_muic_attach_usb_type(info, adc);
		break;
	case ADC_DESKDOCK:
	case ADC_CARDOCK:
		max8997_muic_attach_dock_type(info, adc);
		if (chgtyp == CHGTYP_USB ||
				chgtyp == CHGTYP_DOWNSTREAM_PORT ||
				chgtyp == CHGTYP_DEDICATED_CHGR ||
				chgtyp == CHGTYP_500MA	||
				chgtyp == CHGTYP_1A)
			ret = max8997_muic_set_charging_type(info, false);
		else if (chgtyp == CHGTYP_NO_VOLTAGE && !chgdetrun)
			ret = max8997_muic_set_charging_type(info, true);
		break;
	case ADC_CEA936ATYPE1_CHG:
	case ADC_CEA936ATYPE2_CHG:
	case ADC_OPEN:
		switch (chgtyp) {
		case CHGTYP_USB:
			if (adc == ADC_CEA936ATYPE1_CHG
					|| adc == ADC_CEA936ATYPE2_CHG)
				break;
			if (mdata->is_mhl_attached
					&& mdata->is_mhl_attached() &&
					info->cable_type == CABLE_TYPE_MHL) {
				dev_info(info->dev, "%s: MHL(charging)\n",
						__func__);
				info->cable_type = CABLE_TYPE_MHL_VB;
				ret = max8997_muic_set_charging_type(info,
						false);
				return ret;
			}
			ret = max8997_muic_attach_usb_type(info, adc);
			break;
		case CHGTYP_DOWNSTREAM_PORT:
		case CHGTYP_DEDICATED_CHGR:
		case CHGTYP_500MA:
		case CHGTYP_1A:
			dev_info(info->dev, "%s:TA\n", __func__);
			info->cable_type = CABLE_TYPE_TA;
			ret = max8997_muic_set_charging_type(info, false);
			if (ret)
				info->cable_type = CABLE_TYPE_NONE;
			break;
		default:
			break;
		}
		break;
	default:
		dev_warn(info->dev, "%s: unsupported adc=0x%x\n", __func__,
				adc);
		break;
	}
	return ret;
}