for (i = 0; i < 4; i++) { /* * Enable WRITE_STAT interrupt for writes to all * 4 MSC Status registers.
*/
cbus_writeb(ctx, 0xE0 + i, 0xF2); /* * Enable SET_INT interrupt for writes to all * 4 MSC Interrupt registers.
*/
cbus_writeb(ctx, 0xF0 + i, 0xF2);
}
staticvoid force_usb_id_switch_open(struct sii9234 *ctx)
{ /* Disable CBUS discovery */
mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, 0, 0x01); /* Force USB ID switch to open */
mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, ~0, USB_ID_OVR);
mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL3_REG, ~0, 0x86); /* Force upstream HPD to 0 when not in MHL mode. */
mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, 0, 0x30);
}
staticvoid release_usb_id_switch_open(struct sii9234 *ctx)
{
msleep(T_SRC_CBUS_FLOAT); /* Clear USB ID switch to open */
mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, 0, USB_ID_OVR); /* Enable CBUS discovery */
mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, ~0, 0x01);
}
staticint sii9234_power_init(struct sii9234 *ctx)
{ /* Force the SiI9234 into the D0 state. */
tpi_writeb(ctx, TPI_DPD_REG, 0x3F); /* Enable TxPLL Clock */
hdmi_writeb(ctx, HDMI_RX_TMDS_CLK_EN_REG, 0x01); /* Enable Tx Clock Path & Equalizer */
hdmi_writeb(ctx, HDMI_RX_TMDS_CH_EN_REG, 0x15); /* Power Up TMDS */
mhl_tx_writeb(ctx, 0x08, 0x35); return sii9234_clear_error(ctx);
}
staticint sii9234_reset(struct sii9234 *ctx)
{ int ret;
sii9234_clear_error(ctx);
ret = sii9234_power_init(ctx); if (ret < 0) return ret;
ret = sii9234_cbus_reset(ctx); if (ret < 0) return ret;
ret = sii9234_hdmi_init(ctx); if (ret < 0) return ret;
ret = sii9234_mhl_tx_ctl_int(ctx); if (ret < 0) return ret;
/* Enable HDCP Compliance safety */
mhl_tx_writeb(ctx, 0x2B, 0x01); /* CBUS discovery cycle time for each drive and float = 150us */
mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL1_REG, 0x04, 0x06); /* Clear bit 6 (reg_skip_rgnd) */
mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL2_REG, (1 << 7) /* Reserved */
| 2 << ATT_THRESH_SHIFT | DEGLITCH_TIME_50MS); /* * Changed from 66 to 65 for 94[1:0] = 01 = 5k reg_cbusmhl_pup_sel * 1.8V CBUS VTH & GND threshold * to meet CTS 3.3.7.2 spec
*/
mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL5_REG, 0x77);
cbus_writebm(ctx, CBUS_LINK_CONTROL_2_REG, ~0, MHL_INIT_TIMEOUT);
mhl_tx_writeb(ctx, MHL_TX_MHLTX_CTL6_REG, 0xA0); /* RGND & single discovery attempt (RGND blocking) */
mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL6_REG, BLOCK_RGND_INT |
DVRFLT_SEL | SINGLE_ATT); /* Use VBUS path of discovery state machine */
mhl_tx_writeb(ctx, MHL_TX_DISC_CTRL8_REG, 0); /* 0x92[3] sets the CBUS / ID switch */
mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL6_REG, ~0, USB_ID_OVR); /* * To allow RGND engine to operate correctly. * When moving the chip from D2 to D0 (power up, init regs) * the values should be * 94[1:0] = 01 reg_cbusmhl_pup_sel[1:0] should be set for 5k * 93[7:6] = 10 reg_cbusdisc_pup_sel[1:0] should be * set for 10k (default) * 93[5:4] = 00 reg_cbusidle_pup_sel[1:0] = open (default)
*/
mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL3_REG, ~0, 0x86); /* * Change from CC to 8C to match 5K * to meet CTS 3.3.72 spec
*/
mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL4_REG, ~0, 0x8C); /* Configure the interrupt as active high */
mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, 0, 0x06);
/* This point is very important before measure RGND impedance */
force_usb_id_switch_open(ctx);
mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL4_REG, 0, 0xF0);
mhl_tx_writebm(ctx, MHL_TX_DISC_CTRL5_REG, 0, 0x03);
release_usb_id_switch_open(ctx);
/* Force upstream HPD to 0 when not in MHL mode */
mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, 0, 1 << 5);
mhl_tx_writebm(ctx, MHL_TX_INT_CTRL_REG, ~0, 1 << 4);
return sii9234_clear_error(ctx);
}
staticint sii9234_goto_d3(struct sii9234 *ctx)
{ int ret;
dev_dbg(ctx->dev, "sii9234: detection started d3\n");
ret = sii9234_reset(ctx); if (ret < 0) gotoexit;
hdmi_writeb(ctx, 0x01, 0x03);
tpi_writebm(ctx, TPI_DPD_REG, 0, 1); /* I2C above is expected to fail because power goes down */
sii9234_clear_error(ctx);
staticenum sii9234_state sii9234_rsen_change(struct sii9234 *ctx)
{ int value;
/* Work_around code to handle wrong interrupt */ if (ctx->state != ST_RGND_1K) {
dev_err(ctx->dev, "RSEN_HIGH without RGND_1K\n"); return ST_FAILURE;
}
value = mhl_tx_readb(ctx, MHL_TX_SYSSTAT_REG); if (value < 0) return ST_FAILURE;
if (value & RSEN_STATUS) {
dev_dbg(ctx->dev, "MHL cable connected.. RSEN High\n"); return ST_RSEN_HIGH;
}
dev_dbg(ctx->dev, "RSEN lost\n"); /* * Once RSEN loss is confirmed,we need to check * based on cable status and chip power status,whether * it is SINK Loss(HDMI cable not connected, TV Off) * or MHL cable disconnection * TODO: Define the below mhl_disconnection()
*/
msleep(T_SRC_RXSENSE_DEGLITCH);
value = mhl_tx_readb(ctx, MHL_TX_SYSSTAT_REG); if (value < 0) return ST_FAILURE;
dev_dbg(ctx->dev, "sys_stat: %x\n", value);
if (ctx->state == ST_FAILURE) {
dev_dbg(ctx->dev, "try to reset after failure\n");
sii9234_hw_reset(ctx);
sii9234_goto_d3(ctx);
}
if (ctx->state == ST_FAILURE_DISCOVERY) {
dev_err(ctx->dev, "discovery failed, no power for MHL?\n");
tpi_writebm(ctx, TPI_DPD_REG, 0, 1);
ctx->state = ST_D3;
}
if (!ctx->dev->of_node) {
dev_err(ctx->dev, "not DT device\n"); return -ENODEV;
}
ctx->gpio_reset = devm_gpiod_get(ctx->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->gpio_reset)) {
dev_err(ctx->dev, "failed to get reset gpio from DT\n"); return PTR_ERR(ctx->gpio_reset);
}
ctx->supplies[0].supply = "avcc12";
ctx->supplies[1].supply = "avcc33";
ctx->supplies[2].supply = "iovcc18";
ctx->supplies[3].supply = "cvcc12";
ret = devm_regulator_bulk_get(ctx->dev, 4, ctx->supplies); if (ret) { if (ret != -EPROBE_DEFER)
dev_err(ctx->dev, "regulator_bulk failed\n"); return ret;
}
ctx->client[I2C_MHL] = client;
ctx->client[I2C_TPI] = devm_i2c_new_dummy_device(&client->dev, adapter,
I2C_TPI_ADDR); if (IS_ERR(ctx->client[I2C_TPI])) {
dev_err(ctx->dev, "failed to create TPI client\n"); return PTR_ERR(ctx->client[I2C_TPI]);
}
ctx->client[I2C_HDMI] = devm_i2c_new_dummy_device(&client->dev, adapter,
I2C_HDMI_ADDR); if (IS_ERR(ctx->client[I2C_HDMI])) {
dev_err(ctx->dev, "failed to create HDMI RX client\n"); return PTR_ERR(ctx->client[I2C_HDMI]);
}
ctx->client[I2C_CBUS] = devm_i2c_new_dummy_device(&client->dev, adapter,
I2C_CBUS_ADDR); if (IS_ERR(ctx->client[I2C_CBUS])) {
dev_err(ctx->dev, "failed to create CBUS client\n"); return PTR_ERR(ctx->client[I2C_CBUS]);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.