static void max8997_haptic_configure(struct max8997_haptic *chip)
{
	u8 value;

	value = chip->type << MAX8997_MOTOR_TYPE_SHIFT |
		chip->enabled << MAX8997_ENABLE_SHIFT |
		chip->mode << MAX8997_MODE_SHIFT | chip->pwm_divisor;
	max8997_write_reg(chip->client, MAX8997_HAPTIC_REG_CONF2, value);

	if (chip->mode == MAX8997_INTERNAL_MODE && chip->enabled) {
		value = chip->internal_mode_pattern << MAX8997_CYCLE_SHIFT |
			chip->internal_mode_pattern << MAX8997_SIG_PERIOD_SHIFT |
			chip->internal_mode_pattern << MAX8997_SIG_DUTY_SHIFT |
			chip->internal_mode_pattern << MAX8997_PWM_DUTY_SHIFT;
		max8997_write_reg(chip->client,
			MAX8997_HAPTIC_REG_DRVCONF, value);

		switch (chip->internal_mode_pattern) {
		case 0:
			value = chip->pattern_cycle << 4;
			max8997_write_reg(chip->client,
				MAX8997_HAPTIC_REG_CYCLECONF1, value);
			value = chip->pattern_signal_period;
			max8997_write_reg(chip->client,
				MAX8997_HAPTIC_REG_SIGCONF1, value);
			break;

		case 1:
			value = chip->pattern_cycle;
			max8997_write_reg(chip->client,
				MAX8997_HAPTIC_REG_CYCLECONF1, value);
			value = chip->pattern_signal_period;
			max8997_write_reg(chip->client,
				MAX8997_HAPTIC_REG_SIGCONF2, value);
			break;

		case 2:
			value = chip->pattern_cycle << 4;
			max8997_write_reg(chip->client,
				MAX8997_HAPTIC_REG_CYCLECONF2, value);
			value = chip->pattern_signal_period;
			max8997_write_reg(chip->client,
				MAX8997_HAPTIC_REG_SIGCONF3, value);
			break;

		case 3:
			value = chip->pattern_cycle;
			max8997_write_reg(chip->client,
				MAX8997_HAPTIC_REG_CYCLECONF2, value);
			value = chip->pattern_signal_period;
			max8997_write_reg(chip->client,
				MAX8997_HAPTIC_REG_SIGCONF4, value);
			break;

		default:
			break;
		}
	}
}
static ssize_t max8997_muic_set_status(struct device *dev,
					struct device_attribute *attr,
					const char *buf, size_t count)
{
	struct max8997_muic_info *info = dev_get_drvdata(dev);
	u8  reg_value[3];
	char reg_name[5];

	if (sscanf(buf, "%4s:%02x,%02x,%02x" , reg_name, (u32 *)&reg_value[0],
		(u32 *)&reg_value[1], (u32 *)&reg_value[2])) {
		if (!strncmp(reg_name, "INTM", 4)) {
			dev_info(dev, "Manual Set INTMASK to 0x%02x, 0x%02x, 0x%02x\n",
				reg_value[0], reg_value[1], reg_value[2]);
			max8997_bulk_write(info->muic,
				MAX8997_MUIC_REG_INTMASK1, 3, reg_value);
		} else if (!strncmp(reg_name, "CONT", 4)) {
			dev_info(dev, "Manual Set CONTROL to 0x%02x, 0x%02x, 0x%02x\n",
				reg_value[0], reg_value[1], reg_value[2]);
			max8997_bulk_write(info->muic,
				MAX8997_MUIC_REG_CTRL1, 3, reg_value);
		} else if (!strncmp(reg_name, "CDET", 4)) {
			dev_info(dev, "Manual Set CDETCTRL to 0x%02x\n",
				reg_value[0]);
			max8997_write_reg(info->muic,
				MAX8997_MUIC_REG_CDETCTRL, reg_value[0]);
		} else {
			dev_info(dev, "Unsupported CMD format\n");
		}
	} else {
		dev_info(dev, "Read CMD fail\n");
	}

	return count;
}
Exemplo n.º 3
0
static int __devinit max8997_haptic_probe(struct platform_device *pdev)
{
	struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent);
	static struct max8997_haptic_info *info;
	int ret;
	u8 value;

	info = kzalloc(sizeof(struct max8997_haptic_info), GFP_KERNEL);
	if (!info)
		return -ENOMEM;

	info->dev = &pdev->dev;
	info->max8997 = max8997;
	info->hmotor = max8997->hmotor;
	haptic_i2c = max8997->hmotor;

	platform_set_drvdata(pdev, info);

	value = 0x02;

	ret = max8997_write_reg(haptic_i2c, MAX8997_MUIC_REG_INT2, value);
	if (ret < 0)
		return ret;

	return 0;
}
static void max8997_initialize_device(struct max8997_muic_info *info)
{
	struct max8997_muic_platform_data *mdata = info->muic_pdata;
	int i;

	for (i = 0; i < mdata->num_init_data; i++) {
		max8997_write_reg(info->muic, mdata->init_data[i].addr,
				mdata->init_data[i].data);
	}
}
Exemplo n.º 5
0
static void i2c_max8997_hapticmotor(struct vibrator_drvdata *data, bool en)
{
	int ret;
	u8 value;

	if (en) {
		value = MOTOR_LRA | MOTOR_EN | EXT_PWM | DIVIDER_128;
		ret = max8997_write_reg(data->client,
				MAX8997_MOTOR_REG_CONFIG2, value);
		if (ret < 0)
			pr_err("[VIB] i2c write err : %d\n", ret);

	} else {
		value = MOTOR_LRA | EXT_PWM | DIVIDER_128;
		ret = max8997_write_reg(data->client,
				MAX8997_MOTOR_REG_CONFIG2, value);
		if (ret < 0)
			pr_err("[VIB] i2c write err : %d\n", ret);
	}
}
Exemplo n.º 6
0
Arquivo: max8997.c Projeto: 7799/linux
static int max8997_restore(struct device *dev)
{
	struct i2c_client *i2c = container_of(dev, struct i2c_client, dev);
	struct max8997_dev *max8997 = i2c_get_clientdata(i2c);
	int i;

	for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_pmic); i++)
		max8997_write_reg(i2c, max8997_dumpaddr_pmic[i],
				max8997->reg_dump[i]);

	for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_muic); i++)
		max8997_write_reg(i2c, max8997_dumpaddr_muic[i],
				max8997->reg_dump[i + MAX8997_REG_PMIC_END]);

	for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_haptic); i++)
		max8997_write_reg(i2c, max8997_dumpaddr_haptic[i],
				max8997->reg_dump[i + MAX8997_REG_PMIC_END +
				MAX8997_MUIC_REG_END]);

	return 0;
}
static int max8997_haptic_set_duty_cycle(struct max8997_haptic *chip)
{
	int ret = 0;

	if (chip->mode == MAX8997_EXTERNAL_MODE) {
		unsigned int duty = chip->pwm_period * chip->level / 100;
		ret = pwm_config(chip->pwm, duty, chip->pwm_period);
	} else {
		int i;
		u8 duty_index = 0;

		for (i = 0; i <= 64; i++) {
			if (chip->level <= i * 100 / 64) {
				duty_index = i;
				break;
			}
		}
		switch (chip->internal_mode_pattern) {
		case 0:
			max8997_write_reg(chip->client,
				MAX8997_HAPTIC_REG_SIGPWMDC1, duty_index);
			break;
		case 1:
			max8997_write_reg(chip->client,
				MAX8997_HAPTIC_REG_SIGPWMDC2, duty_index);
			break;
		case 2:
			max8997_write_reg(chip->client,
				MAX8997_HAPTIC_REG_SIGPWMDC3, duty_index);
			break;
		case 3:
			max8997_write_reg(chip->client,
				MAX8997_HAPTIC_REG_SIGPWMDC4, duty_index);
			break;
		default:
			break;
		}
	}
	return ret;
}
Exemplo n.º 8
0
static void vibe_control_max8997(struct pwm_device *pwm, bool on)
{
	int ret;
	u8 value;

	if (on == 1) {
		value = (MOTOR_LRA | MOTOR_EN | EXT_PWM | 0x02);

		ret = max8997_write_reg(haptic_i2c, MAX8997_MUIC_REG_INT2, value);
		if (ret < 0)
			DbgOut(KERN_ERR "i2c write err in on\n");

		pwm_enable(pwm);
	} else {
		pwm_disable(pwm);

		value = 0x02;

		ret = max8997_write_reg(haptic_i2c, MAX8997_MUIC_REG_INT2, value);
		if (ret < 0)
			DbgOut(KERN_ERR "i2c write err in off\n");
	}
}
static int max8997_muic_restore(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct max8997_muic_info *info;
	int i;
	info = platform_get_drvdata(pdev);

	for (i = 0; i < ARRAY_SIZE(max8997_dumpaddr_muic); i++)
		max8997_write_reg(info->max8997->muic, max8997_dumpaddr_muic[i],
			info->max8997->reg_dump[i + MAX8997_REG_PMIC_END]);

	mutex_lock(&info->mutex);
	max8997_muic_detect_dev(info, -1);
	mutex_unlock(&info->mutex);

	return 0;
}
Exemplo n.º 10
0
static void i2c_max8997_hapticmotor(struct vibrator_drvdata *data, bool en)
{
	int ret;
	u8 value = data->pdata->reg2;

	/* the setting of reg2 should be set */
	if (0 == value)
		value = MOTOR_LRA | EXT_PWM | DIVIDER_256;

	if (en)
		value |= MOTOR_EN;

	ret = max8997_write_reg(data->client,
				 MAX8997_MOTOR_REG_CONFIG2, value);
	if (ret < 0)
		pr_err("[VIB] i2c write error\n");
}
Exemplo n.º 11
0
static inline int max8997_rtc_set_update_reg(struct max8997_rtc_info *info)
{
	int ret;

	ret = max8997_write_reg(info->rtc, MAX8997_RTC_UPDATE1,
						RTC_UDR_MASK);
	if (ret < 0)
		dev_err(info->dev, "%s: fail to write update reg(%d)\n",
				__func__, ret);
	else {
		/* Minimum 16ms delay required before RTC update.
		 * Otherwise, we may read and update based on out-of-date
		 * value */
		msleep(20);
	}

	return ret;
}
Exemplo n.º 12
0
static void max8997_irq_sync_unlock(struct irq_data *data)
{
	struct max8997_dev *max8997 = irq_get_chip_data(data->irq);
	int i;

	for (i = 0; i < MAX8997_IRQ_GROUP_NR; i++) {
		u8 mask_reg = max8997_mask_reg[i];
		struct i2c_client *i2c = get_i2c(max8997, i);

		if (mask_reg == MAX8997_REG_INVALID ||
				IS_ERR_OR_NULL(i2c))
			continue;
		max8997->irq_masks_cache[i] = max8997->irq_masks_cur[i];

		max8997_write_reg(i2c, max8997_mask_reg[i],
				max8997->irq_masks_cur[i]);
	}

	mutex_unlock(&max8997->irqlock);
}
Exemplo n.º 13
0
static int max8997_muic_handle_detach(struct max8997_muic_info *info)
{
	struct i2c_client *client = info->muic;
	struct max8997_muic_data *mdata = info->muic_data;
	enum cable_type prev_ct = CABLE_TYPE_NONE;
	int ret = 0;

#if defined(CONFIG_SEC_MODEM_M0_TD)
	gpio_set_value(GPIO_AP_CP_INT1, 0);
#endif

	/*
	 * MAX8996/8997-MUIC bug:
	 *
	 * Auto-switching COMN/P is not restored automatically when detached and
	 * remains undetermined state. UART(UT1, UR2) will be short (because TA
	 * D+/D- is short) if charger(TA) insertion is followed right after the
	 * JIG off. Reset CONTROL1 is needed when detaching cable.
	 */
	max8997_write_reg(client, MAX8997_MUIC_REG_CTRL1, 0x00);

	if (info->cable_type == CABLE_TYPE_MHL) {

		/* Enable Factory Accessory Detection State Machine */
		max8997_update_reg(client, MAX8997_MUIC_REG_CTRL2,
				(1 << CTRL2_ACCDET_SHIFT), CTRL2_ACCDET_MASK);
	}

#ifdef CONFIG_USBHUB_USB3803
	/* setting usb hub in default mode (standby) */
	usb3803_set_mode(USB_3803_MODE_STANDBY);
#endif  /* CONFIG_USBHUB_USB3803 */
	info->previous_key = DOCK_KEY_NONE;

	if (info->cable_type == CABLE_TYPE_NONE) {
		dev_info(info->dev, "%s: duplicated(NONE)\n", __func__);
		return 0;
	}
#if 0
	if (mdata->jig_uart_cb)
		mdata->jig_uart_cb(UART_PATH_AP);
#endif
	if (mdata->is_mhl_attached && mdata->is_mhl_attached()
			&& info->cable_type == CABLE_TYPE_MHL) {
		dev_info(info->dev, "%s: MHL attached. Do Nothing\n",
				__func__);
		return 0;
	}

	switch (info->cable_type) {
	case CABLE_TYPE_OTG:
		dev_info(info->dev, "%s: OTG\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;

		if (mdata->usb_cb && info->is_usb_ready)
			mdata->usb_cb(USB_OTGHOST_DETACHED);
		break;
	case CABLE_TYPE_USB:
	case CABLE_TYPE_JIG_USB_OFF:
	case CABLE_TYPE_JIG_USB_ON:
		dev_info(info->dev, "%s: USB(0x%x)\n", __func__,
				info->cable_type);
		prev_ct = info->cable_type;
		info->cable_type = CABLE_TYPE_NONE;

		ret = max8997_muic_set_charging_type(info, false);
		if (ret) {
			info->cable_type = prev_ct;
			break;
		}

		if (mdata->sw_path == CP_USB_MODE)
			return 0;

		if (mdata->usb_cb && info->is_usb_ready)
			mdata->usb_cb(USB_CABLE_DETACHED);
		break;
	case CABLE_TYPE_DESKDOCK:
		dev_info(info->dev, "%s: DESKDOCK\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;

		ret = max8997_muic_set_charging_type(info, false);
		if (ret) {
			info->cable_type = CABLE_TYPE_DESKDOCK;
			break;
		}

		if (mdata->deskdock_cb)
			mdata->deskdock_cb(MAX8997_MUIC_DETACHED);
		break;
	case CABLE_TYPE_CARDOCK:
		dev_info(info->dev, "%s: CARDOCK\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;

		ret = max8997_muic_set_charging_type(info, false);
		if (ret) {
			info->cable_type = CABLE_TYPE_CARDOCK;
			break;
		}

		if (mdata->cardock_cb)
			mdata->cardock_cb(MAX8997_MUIC_DETACHED);
		break;
	case CABLE_TYPE_TA:
		dev_info(info->dev, "%s: TA\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;
		ret = max8997_muic_set_charging_type(info, false);
		if (ret)
			info->cable_type = CABLE_TYPE_TA;
		break;
	case CABLE_TYPE_JIG_UART_ON:
		dev_info(info->dev, "%s: JIG UART/BOOTON\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;
		break;
	case CABLE_TYPE_JIG_UART_OFF:
		dev_info(info->dev, "%s: JIG UART/BOOTOFF\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;
		break;
	case CABLE_TYPE_JIG_UART_OFF_VB:
		dev_info(info->dev, "%s: JIG UART/OFF/VB\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;
		ret = max8997_muic_set_charging_type(info, false);
		if (ret)
			info->cable_type = CABLE_TYPE_JIG_UART_OFF_VB;
		break;
	case CABLE_TYPE_MHL:
		dev_info(info->dev, "%s: MHL\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;
		break;
	case CABLE_TYPE_MHL_VB:
		dev_info(info->dev, "%s: MHL VBUS\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;
		max8997_muic_set_charging_type(info, false);

		if (mdata->is_mhl_attached && mdata->is_mhl_attached()) {
			if (mdata->mhl_cb && info->is_mhl_ready)
				mdata->mhl_cb(MAX8997_MUIC_DETACHED);
		}
		break;
	case CABLE_TYPE_UNKNOWN:
		dev_info(info->dev, "%s: UNKNOWN\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;

		ret = max8997_muic_set_charging_type(info, false);
		if (ret)
			info->cable_type = CABLE_TYPE_UNKNOWN;
		break;
	default:
		dev_info(info->dev, "%s:invalid cable type %d\n",
				__func__, info->cable_type);
		break;
	}
	return ret;
}
Exemplo n.º 14
0
int max8997_irq_init(struct max8997_dev *max8997)
{
	struct irq_domain *domain;
	int i;
	int ret;
	u8 val;

	if (!max8997->irq) {
		dev_warn(max8997->dev, "No interrupt specified.\n");
		return 0;
	}

	mutex_init(&max8997->irqlock);

	/* Mask individual interrupt sources */
	for (i = 0; i < MAX8997_IRQ_GROUP_NR; i++) {
		struct i2c_client *i2c;

		max8997->irq_masks_cur[i] = 0xff;
		max8997->irq_masks_cache[i] = 0xff;
		i2c = get_i2c(max8997, i);

		if (IS_ERR_OR_NULL(i2c))
			continue;
		if (max8997_mask_reg[i] == MAX8997_REG_INVALID)
			continue;

		max8997_write_reg(i2c, max8997_mask_reg[i], 0xff);
	}

	for (i = 0; i < MAX8997_NUM_GPIO; i++) {
		max8997->gpio_status[i] = (max8997_read_reg(max8997->i2c,
						MAX8997_REG_GPIOCNTL1 + i,
						&val)
					& MAX8997_GPIO_DATA_MASK) ?
					true : false;
	}

	domain = irq_domain_add_linear(NULL, MAX8997_IRQ_NR,
					&max8997_irq_domain_ops, max8997);
	if (!domain) {
		dev_err(max8997->dev, "could not create irq domain\n");
		return -ENODEV;
	}
	max8997->irq_domain = domain;

	ret = request_threaded_irq(max8997->irq, NULL, max8997_irq_thread,
			IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
			"max8997-irq", max8997);

	if (ret) {
		dev_err(max8997->dev, "Failed to request IRQ %d: %d\n",
				max8997->irq, ret);
		return ret;
	}

	if (!max8997->ono)
		return 0;

	ret = request_threaded_irq(max8997->ono, NULL, max8997_irq_thread,
			IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING |
			IRQF_ONESHOT, "max8997-ono", max8997);

	if (ret)
		dev_err(max8997->dev, "Failed to request ono-IRQ %d: %d\n",
				max8997->ono, ret);

	return 0;
}
Exemplo n.º 15
0
static int max8997_muic_probe(struct platform_device *pdev)
{
	struct max8997_dev *max8997 = dev_get_drvdata(pdev->dev.parent);
	struct max8997_platform_data *pdata = dev_get_platdata(max8997->dev);
	struct max8997_muic_info *info;
	int delay_jiffies;
	int ret, i;

	info = devm_kzalloc(&pdev->dev, sizeof(struct max8997_muic_info),
			    GFP_KERNEL);
	if (!info)
		return -ENOMEM;

	info->dev = &pdev->dev;
	info->muic = max8997->muic;

	platform_set_drvdata(pdev, info);
	mutex_init(&info->mutex);

	INIT_WORK(&info->irq_work, max8997_muic_irq_work);

	for (i = 0; i < ARRAY_SIZE(muic_irqs); i++) {
		struct max8997_muic_irq *muic_irq = &muic_irqs[i];
		unsigned int virq = 0;

		virq = irq_create_mapping(max8997->irq_domain, muic_irq->irq);
		if (!virq) {
			ret = -EINVAL;
			goto err_irq;
		}
		muic_irq->virq = virq;

		ret = request_threaded_irq(virq, NULL,
				max8997_muic_irq_handler,
				IRQF_NO_SUSPEND,
				muic_irq->name, info);
		if (ret) {
			dev_err(&pdev->dev,
				"failed: irq request (IRQ: %d, error :%d)\n",
				muic_irq->irq, ret);
			goto err_irq;
		}
	}

	/* External connector */
	info->edev = devm_extcon_dev_allocate(&pdev->dev, max8997_extcon_cable);
	if (IS_ERR(info->edev)) {
		dev_err(&pdev->dev, "failed to allocate memory for extcon\n");
		ret = -ENOMEM;
		goto err_irq;
	}

	ret = devm_extcon_dev_register(&pdev->dev, info->edev);
	if (ret) {
		dev_err(&pdev->dev, "failed to register extcon device\n");
		goto err_irq;
	}

	if (pdata && pdata->muic_pdata) {
		struct max8997_muic_platform_data *muic_pdata
			= pdata->muic_pdata;

		/* Initialize registers according to platform data */
		for (i = 0; i < muic_pdata->num_init_data; i++) {
			max8997_write_reg(info->muic,
					muic_pdata->init_data[i].addr,
					muic_pdata->init_data[i].data);
		}

		/*
		 * Default usb/uart path whether UART/USB or AUX_UART/AUX_USB
		 * h/w path of COMP2/COMN1 on CONTROL1 register.
		 */
		if (muic_pdata->path_uart)
			info->path_uart = muic_pdata->path_uart;
		else
			info->path_uart = CONTROL1_SW_UART;

		if (muic_pdata->path_usb)
			info->path_usb = muic_pdata->path_usb;
		else
			info->path_usb = CONTROL1_SW_USB;

		/*
		 * Default delay time for detecting cable state
		 * after certain time.
		 */
		if (muic_pdata->detcable_delay_ms)
			delay_jiffies =
				msecs_to_jiffies(muic_pdata->detcable_delay_ms);
		else
			delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
	} else {
		info->path_uart = CONTROL1_SW_UART;
		info->path_usb = CONTROL1_SW_USB;
		delay_jiffies = msecs_to_jiffies(DELAY_MS_DEFAULT);
	}

	/* Set initial path for UART */
	 max8997_muic_set_path(info, info->path_uart, true);

	/* Set ADC debounce time */
	max8997_muic_set_debounce_time(info, ADC_DEBOUNCE_TIME_25MS);

	/*
	 * Detect accessory after completing the initialization of platform
	 *
	 * - Use delayed workqueue to detect cable state and then
	 * notify cable state to notifiee/platform through uevent.
	 * After completing the booting of platform, the extcon provider
	 * driver should notify cable state to upper layer.
	 */
	INIT_DELAYED_WORK(&info->wq_detcable, max8997_muic_detect_cable_wq);
	queue_delayed_work(system_power_efficient_wq, &info->wq_detcable,
			delay_jiffies);

	return 0;

err_irq:
	while (--i >= 0)
		free_irq(muic_irqs[i].virq, info);
	return ret;
}
static int max8997_muic_handle_detach(struct max8997_muic_info *info)
{
	struct i2c_client *client = info->muic;
	struct max8997_muic_data *mdata = info->muic_data;
	cable_type_t prev_ct = CABLE_TYPE_NONE;
	int ret = 0;

	/* Workaround: irq doesn't occur after detaching mHL cable */
	max8997_write_reg(client, MAX8997_MUIC_REG_CTRL1, 0x00);

	/* Enable Factory Accessory Detection State Machine */
	max8997_update_reg(client, MAX8997_MUIC_REG_CTRL2,
			(1 << CTRL2_ACCDET_SHIFT), CTRL2_ACCDET_MASK);

	info->previous_key = DOCK_KEY_NONE;

	if (info->cable_type == CABLE_TYPE_NONE) {
		dev_info(info->dev, "%s: duplicated(NONE)\n", __func__);
		return 0;
	}
#if 0
	if (mdata->jig_uart_cb)
		mdata->jig_uart_cb(UART_PATH_AP);
#endif
	if (mdata->is_mhl_attached && mdata->is_mhl_attached()
			&& info->cable_type == CABLE_TYPE_MHL) {
		dev_info(info->dev, "%s: MHL attached. Do Nothing\n",
				__func__);
		return 0;
	}

	switch (info->cable_type) {
	case CABLE_TYPE_OTG:
		dev_info(info->dev, "%s: OTG\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;

		if (mdata->usb_cb && info->is_usb_ready)
			mdata->usb_cb(USB_OTGHOST_DETACHED);
		break;
	case CABLE_TYPE_USB:
	case CABLE_TYPE_JIG_USB_OFF:
	case CABLE_TYPE_JIG_USB_ON:
		dev_info(info->dev, "%s: USB(0x%x)\n", __func__,
				info->cable_type);
		prev_ct = info->cable_type;
		info->cable_type = CABLE_TYPE_NONE;

		ret = max8997_muic_set_charging_type(info, false);
		if (ret) {
			info->cable_type = prev_ct;
			break;
		}

		if (mdata->sw_path == CP_USB_MODE)
			return 0;

		if (mdata->usb_cb && info->is_usb_ready)
			mdata->usb_cb(USB_CABLE_DETACHED);
		break;
	case CABLE_TYPE_DESKDOCK:
		dev_info(info->dev, "%s: DESKDOCK\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;

		ret = max8997_muic_set_charging_type(info, false);
		if (ret) {
			info->cable_type = CABLE_TYPE_DESKDOCK;
			break;
		}

		if (mdata->deskdock_cb)
			mdata->deskdock_cb(MAX8997_MUIC_DETACHED);
		break;
	case CABLE_TYPE_CARDOCK:
		dev_info(info->dev, "%s: CARDOCK\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;

		ret = max8997_muic_set_charging_type(info, false);
		if (ret) {
			info->cable_type = CABLE_TYPE_CARDOCK;
			break;
		}

		if (mdata->cardock_cb)
			mdata->cardock_cb(MAX8997_MUIC_DETACHED);
		break;
	case CABLE_TYPE_TA:
		dev_info(info->dev, "%s: TA\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;
		ret = max8997_muic_set_charging_type(info, false);
		if (ret)
			info->cable_type = CABLE_TYPE_TA;
		break;
	case CABLE_TYPE_JIG_UART_ON:
		dev_info(info->dev, "%s: JIG UART/BOOTON\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;
		break;
	case CABLE_TYPE_JIG_UART_OFF:
		dev_info(info->dev, "%s: JIG UART/BOOTOFF\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;
		break;
	case CABLE_TYPE_JIG_UART_OFF_VB:
		dev_info(info->dev, "%s: JIG UART/OFF/VB\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;
		ret = max8997_muic_set_charging_type(info, false);
		if (ret)
			info->cable_type = CABLE_TYPE_JIG_UART_OFF_VB;
		break;
	case CABLE_TYPE_MHL:
		dev_info(info->dev, "%s: MHL\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;
		break;
	case CABLE_TYPE_MHL_VB:
		dev_info(info->dev, "%s: MHL VBUS\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;
		max8997_muic_set_charging_type(info, false);

		if (mdata->is_mhl_attached && mdata->is_mhl_attached()) {
			if (mdata->mhl_cb && info->is_mhl_ready)
				mdata->mhl_cb(MAX8997_MUIC_DETACHED);
		}
		break;
	case CABLE_TYPE_UNKNOWN:
		dev_info(info->dev, "%s: UNKNOWN\n", __func__);
		info->cable_type = CABLE_TYPE_NONE;

		ret = max8997_muic_set_charging_type(info, false);
		if (ret)
			info->cable_type = CABLE_TYPE_UNKNOWN;
		break;
	default:
		dev_info(info->dev, "%s:invalid cable type %d\n",
				__func__, info->cable_type);
		break;
	}
	return ret;
}