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