static int mhl_pf_switch_device_discovery(void *data,
					int id,
					void (*usb_notify_cb)(void *, int),
					void *ctx)
{
	int rc = MHL_USB_NON_INUSE;
	pr_info("%s()\n", __func__);

	if (id) {
		/* todo : this logic can be reused in 8620? */
		pr_debug("%s: USB ID pin high. id=%d\n", __func__, id);
		return id;
	}

	if (!usb_notify_cb) {
		pr_warn("%s: cb || ctrl is NULL\n", __func__);
		return -EINVAL;
	}

	isDiscoveryCalled = true;
	usb_ctx = ctx;

	/* switch gpio to MHL from USB */
	/* todo : must use dtsi for gpio */
	gpio_set_value(GPIO_MHL_SWITCH_SEL_1, 1);
	gpio_set_value(GPIO_MHL_SWITCH_SEL_2, 1);
	pr_debug("%s: gpio(%d) : %d", __func__,
			 GPIO_MHL_SWITCH_SEL_1,
			 gpio_get_value(GPIO_MHL_SWITCH_SEL_1));
	pr_debug("%s: gpio(%d) : %d", __func__,
			 GPIO_MHL_SWITCH_SEL_2,
			 gpio_get_value(GPIO_MHL_SWITCH_SEL_2));

	msleep(20);
	if (!notify_usb_online)
		notify_usb_online = usb_notify_cb;
	if (device_discovery_cb) {
		rc = device_discovery_cb(context_cb);
		if (rc == MHL_USB_INUSE) {
			if (notify_usb_online)
				notify_usb_online(usb_ctx, 1);
		}
	} else {
		/*
		 * Even if there is no registerred call back,
		 * MHL_USB_INUSE must be returned since the
		 * MHL ko object is supposed to be installed
		 * at boot timing and immediately registerring
		 * its call back. So this API must return INUSE
		 * to usb.
		 */
		pr_warn("%s: no registerred cb.\n", __func__);
		rc = MHL_USB_INUSE;
	}

	pr_info("%s: mhl is inuse ? : %d\n", __func__, (rc == MHL_USB_INUSE));


	return rc;
}
Esempio n. 2
0
/*
 * If hardware detected a change in impedance and raised an INTR
 * We check the range of this impedance to infer if the connected
 * device is MHL or USB and take appropriate actions.
 */
static int  mhl_msm_read_rgnd_int(void)
{
	uint8_t rgnd_imp;

	/*
	 * DISC STATUS REG 2
	 * 1:0 RGND
	 * 00  - open (USB)
	 * 01  - 2 kOHM (USB)
	 * 10  - 1 kOHM ***(MHL)**** It's range 800 - 1200 OHM from MHL spec
	 * 11  - short (USB)
	 */
	rgnd_imp = (mhl_i2c_reg_read(TX_PAGE_3, 0x001C) & (BIT1 | BIT0));
	pr_debug("Imp Range read = %02X\n", (int)rgnd_imp);

	if (0x02 == rgnd_imp) {
		pr_debug("MHL: MHL DEVICE!!!\n");
		mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT0, BIT0);
		/*
		 * Handling the MHL event in driver
		 */
		mhl_msm_state->mhl_mode = TRUE;
		if (notify_usb_online)
			notify_usb_online(1);
	} else {
		pr_debug("MHL: NON-MHL DEVICE!!!\n");
		mhl_msm_state->mhl_mode = FALSE;
		mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT3, BIT3);
		switch_mode(POWER_STATE_D3);
	}
	complete(&mhl_msm_state->rgnd_done);
	return mhl_msm_state->mhl_mode ?
		MHL_DISCOVERY_RESULT_MHL : MHL_DISCOVERY_RESULT_USB;
}
/**
 * mhl_pf_switch_to_mhl: switch to mhl
 */
int mhl_pf_switch_to_mhl(void)
{
	pr_info("%s:", __func__);
	if (!notify_usb_online) {
		pr_warn("%s: no notify_usb_online registration\n", __func__);
		return MHL_FAIL;
	} else {
		notify_usb_online(usb_ctx, 1);
	}
	mhl_pf_switch_gpio_to_mhl();
	return MHL_SUCCESS;
}
/**
 * mhl_pf_switch_register_cb: register
 * a call back for notifying device discovery.
 * The client should start device discovery
 * when call the callback and must notify the
 * result. Only one registration is acceptable.
 * When the register API is called before unregister,
 * the previous call back and context will be
 * replace with new registration.
 *
 * @device_discovery - call back API. Must not be NULL.
 * @context - it can be NULL. It is notified through the call back API.
 *
 */
void mhl_pf_switch_register_cb(int (*device_discovery)(void *context),
								void *context)
{
	int rc = MHL_USB_NON_INUSE;

	pr_info("%s:\n", __func__);
	device_discovery_cb = device_discovery;
	context_cb = context;
	if (isDiscoveryCalled) {
		rc = device_discovery_cb(context_cb);
		if (rc == MHL_USB_INUSE) {
			if (notify_usb_online)
				notify_usb_online(usb_ctx, 1);
		}
	}

}
/**
 * mhl_pf_switch_register_cb: register
 * a call back for notifying device discovery.
 * The client should start device discovery
 * when call the callback and must notify the
 * result. Only one registration is acceptable.
 * When the register API is called before unregister,
 * the previous call back and context will be
 * replace with new registration.
 *
 * @device_discovery - call back API. Must not be NULL.
 * @context - it can be NULL. It is notified through the call back API.
 *
 */
void mhl_pf_switch_register_cb(int (*device_discovery)(void *context),
								void *context)
{
	int rc = MHL_USB_NON_INUSE;

	pr_debug("%s:\n", __func__);
	device_discovery_cb = device_discovery;
	context_cb = context;
	if (isDiscoveryCalled) {
		rc = device_discovery_cb(context_cb);
		if (rc == MHL_USB_INUSE) {
			if (notify_usb_online) {
				/* Found MHL device */
				qpnp_chg_notify_mhl_state(1);
				notify_usb_online(usb_ctx, 1);
			}
		}
	}

}
/**
 * mhl_pf_switch_to_usb: switch to usb.
 * This API must be called after the INT by PMIC.
 */
int mhl_pf_switch_to_usb(void)
{
	pr_debug("%s:", __func__);
	isDiscoveryCalled = false;

	if (mhl_pf_is_switch_to_usb())
		return MHL_SUCCESS;

	/* switch gpio to USB from MHL */
	/* todo : must use dtsi for gpio */
	gpio_set_value(GPIO_MHL_SWITCH_SEL_1, 0);
	gpio_set_value(GPIO_MHL_SWITCH_SEL_2, 0);
	pr_debug("%s: gpio(%d) : %d", __func__,
			 GPIO_MHL_SWITCH_SEL_1,
			 gpio_get_value(GPIO_MHL_SWITCH_SEL_1));
	pr_debug("%s: gpio(%d) : %d", __func__,
			 GPIO_MHL_SWITCH_SEL_2,
			 gpio_get_value(GPIO_MHL_SWITCH_SEL_2));

	msleep(20);

	if (!notify_usb_online) {
		pr_warn("%s: no notify_usb_online registration\n", __func__);
		/*
		 * This API may be called after mhl_pf_switch_device_discovery
		 * is called by USB, otherwise the "online" notification can't
		 * be sent to USB via the "notify_usb_online".
		 * Thought the notification doesn't occur, the GPIO will be
		 * somehow switched to USB.
		 * (USB is default. So, the system will try to switch to USB.)
		 */
		/*return MHL_FAIL;*/
	} else {
		notify_usb_online(usb_ctx, 0);
	}

	return MHL_SUCCESS;
}
static int  mhl_msm_read_rgnd_int(void)
{
	uint8_t rgnd_imp;

	rgnd_imp = (mhl_i2c_reg_read(TX_PAGE_3, 0x001C) & (BIT1 | BIT0));
	pr_debug("Imp Range read = %02X\n", (int)rgnd_imp);

	if (0x02 == rgnd_imp) {
		pr_debug("MHL: MHL DEVICE!!!\n");
		mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT0, BIT0);
		mhl_msm_state->mhl_mode = TRUE;
		if (notify_usb_online)
			notify_usb_online(1);
	} else {
		pr_debug("MHL: NON-MHL DEVICE!!!\n");
		mhl_msm_state->mhl_mode = FALSE;
		mhl_i2c_reg_modify(TX_PAGE_3, 0x0018, BIT3, BIT3);
		switch_mode(POWER_STATE_D3);
	}
	complete(&mhl_msm_state->rgnd_done);
	return mhl_msm_state->mhl_mode ?
		MHL_DISCOVERY_RESULT_MHL : MHL_DISCOVERY_RESULT_USB;
}
/**
 * mhl_pf_switch_to_usb: switch to usb.
 * This API must be called after the INT by PMIC.
 */
int mhl_pf_switch_to_usb(void)
{
	pr_info("%s:", __func__);
	isDiscoveryCalled = false;
	mhl_pf_switch_gpio_to_usb();
	msleep(20);

	if (!notify_usb_online) {
		pr_warn("%s: no notify_usb_online registration\n", __func__);
		/*
		 * This API may be called after mhl_pf_switch_device_discovery
		 * is called by USB, otherwise the "online" notification can't be sent
		 * to USB via the "notify_usb_online".
		 * Thought the notification doesn't occur, the GPIO will be somehow
		 * switched to USB.
		 * (USB is default. So, the system will try to switch to USB.)
		 */
		/*return MHL_FAIL;*/
	} else {
		notify_usb_online(usb_ctx, 0);
	}

	return MHL_SUCCESS;
}
Esempio n. 9
0
static void int_4_isr(void)
{
	uint8_t status, reg ;

	/* INTR_STATUS4 */
	status = mhl_i2c_reg_read(TX_PAGE_3, 0x0021);

	/*
	 * When I2C is inoperational (D3) and
	 * a previous interrupt brought us here,
	 * do nothing.
	 */
	if ((0x00 == status) && (mhl_msm_state->cur_state == POWER_STATE_D3)) {
		pr_debug("MHL: spurious interrupt\n");
		return;
	}
	if (0xFF != status) {
		if ((status & BIT0) && (mhl_msm_state->chip_rev_id < 1)) {
			uint8_t tmds_cstat;
			uint8_t mhl_fifo_status;

			/* TMDS CSTAT */
			tmds_cstat = mhl_i2c_reg_read(TX_PAGE_3, 0x0040);

			pr_debug("TMDS CSTAT: 0x%02x\n", tmds_cstat);

			if (tmds_cstat & 0x02) {
				mhl_fifo_status = mhl_i2c_reg_read(TX_PAGE_3,
					0x0023);
				pr_debug("MHL FIFO status: 0x%02x\n",
					mhl_fifo_status);
				if (mhl_fifo_status & 0x0C) {
					mhl_i2c_reg_write(TX_PAGE_3, 0x0023,
						0x0C);

					pr_debug("Apply MHL FIFO Reset\n");
					mhl_i2c_reg_write(TX_PAGE_3, 0x0000,
						0x94);
					mhl_i2c_reg_write(TX_PAGE_3, 0x0000,
						0x84);
				}
			}
		}

		if (status & BIT1)
			pr_debug("MHL: INT4 BIT1 is set\n");

		/* MHL_EST interrupt */
		if (status & BIT2) {
			pr_debug("mhl_msm_connection() from ISR\n");
			mhl_connect_api(true);
			mhl_msm_connection();
			pr_debug("MHL Connect  Drv: INT4 Status = %02X\n",
				(int) status);
		} else if (status & BIT3) {
			pr_debug("MHL: uUSB-A type device detected.\n");
			mhl_i2c_reg_write(TX_PAGE_3, 0x001C, 0x80);
			switch_mode(POWER_STATE_D3);
		}

		if (status & BIT5) {
			mhl_connect_api(false);
			/* Clear interrupts - REG INTR4 */
			reg = mhl_i2c_reg_read(TX_PAGE_3, 0x0021);
			mhl_i2c_reg_write(TX_PAGE_3, 0x0021, reg);
			mhl_msm_disconnection();
			if (notify_usb_online)
				notify_usb_online(0);
			pr_debug("MHL Disconnect Drv: INT4 Status = %02X\n",
				(int)status);
		}

		if ((mhl_msm_state->cur_state != POWER_STATE_D0_MHL) &&\
			(status & BIT6)) {
			/* RGND READY Intr */
			switch_mode(POWER_STATE_D0_MHL);
			mhl_msm_read_rgnd_int();
		}

		/* Can't succeed at these in D3 */
		if (mhl_msm_state->cur_state != POWER_STATE_D3) {
			/* CBUS Lockout interrupt? */
			/*
			 * Hardware detection mechanism figures that
			 * CBUS line is latched and raises this intr
			 * where we force usb switch open and release
			 */
			if (status & BIT4) {
				force_usb_switch_open();
				release_usb_switch_open();
			}
		}
	}
	pr_debug("MHL END  Drv: INT4 Status = %02X\n", (int) status);
	mhl_i2c_reg_write(TX_PAGE_3, 0x0021, status);

	return;
}
static void int_4_isr(void)
{
	uint8_t status, reg ;

	
	status = mhl_i2c_reg_read(TX_PAGE_3, 0x0021);

	if ((0x00 == status) && (mhl_msm_state->cur_state == POWER_STATE_D3)) {
		pr_debug("MHL: spurious interrupt\n");
		return;
	}
	if (0xFF != status) {
		if ((status & BIT0) && (mhl_msm_state->chip_rev_id < 1)) {
			uint8_t tmds_cstat;
			uint8_t mhl_fifo_status;

			
			tmds_cstat = mhl_i2c_reg_read(TX_PAGE_3, 0x0040);

			pr_debug("TMDS CSTAT: 0x%02x\n", tmds_cstat);

			if (tmds_cstat & 0x02) {
				mhl_fifo_status = mhl_i2c_reg_read(TX_PAGE_3,
					0x0023);
				pr_debug("MHL FIFO status: 0x%02x\n",
					mhl_fifo_status);
				if (mhl_fifo_status & 0x0C) {
					mhl_i2c_reg_write(TX_PAGE_3, 0x0023,
						0x0C);

					pr_debug("Apply MHL FIFO Reset\n");
					mhl_i2c_reg_write(TX_PAGE_3, 0x0000,
						0x94);
					mhl_i2c_reg_write(TX_PAGE_3, 0x0000,
						0x84);
				}
			}
		}

		if (status & BIT1)
			pr_debug("MHL: INT4 BIT1 is set\n");

		
		if (status & BIT2) {
			pr_debug("mhl_msm_connection() from ISR\n");
			mhl_connect_api(true);
			mhl_msm_connection();
			pr_debug("MHL Connect  Drv: INT4 Status = %02X\n",
				(int) status);
		} else if (status & BIT3) {
			pr_debug("MHL: uUSB-A type device detected.\n");
			mhl_i2c_reg_write(TX_PAGE_3, 0x001C, 0x80);
			switch_mode(POWER_STATE_D3);
		}

		if (status & BIT5) {
			mhl_connect_api(false);
			
			reg = mhl_i2c_reg_read(TX_PAGE_3, 0x0021);
			mhl_i2c_reg_write(TX_PAGE_3, 0x0021, reg);
			mhl_msm_disconnection();
			if (notify_usb_online)
				notify_usb_online(0);
			pr_debug("MHL Disconnect Drv: INT4 Status = %02X\n",
				(int)status);
		}

		if ((mhl_msm_state->cur_state != POWER_STATE_D0_MHL) &&\
			(status & BIT6)) {
			
			switch_mode(POWER_STATE_D0_MHL);
			mhl_msm_read_rgnd_int();
		}

		
		if (mhl_msm_state->cur_state != POWER_STATE_D3) {
			
			if (status & BIT4) {
				force_usb_switch_open();
				release_usb_switch_open();
			}
		}
	}
	pr_debug("MHL END  Drv: INT4 Status = %02X\n", (int) status);
	mhl_i2c_reg_write(TX_PAGE_3, 0x0021, status);

	return;
}