/* adv748x_write_block(): Write raw data with a maximum of I2C_SMBUS_BLOCK_MAX * size to one or more registers. * * A value of zero will be returned on success, a negative errno will * be returned in error cases.
*/ int adv748x_write_block(struct adv748x_state *state, int client_page, unsignedint init_reg, constvoid *val,
size_t val_len)
{ struct regmap *regmap = state->regmap[client_page];
if (val_len > I2C_SMBUS_BLOCK_MAX)
val_len = I2C_SMBUS_BLOCK_MAX;
for (i = 1; i < ARRAY_SIZE(state->i2c_clients); ++i)
i2c_unregister_device(state->i2c_clients[i]);
}
staticint adv748x_initialise_clients(struct adv748x_state *state)
{ unsignedint i; int ret;
for (i = ADV748X_PAGE_DPLL; i < ADV748X_PAGE_MAX; ++i) {
state->i2c_clients[i] = i2c_new_ancillary_device(
state->client,
adv748x_default_addresses[i].name,
adv748x_default_addresses[i].default_addr);
if (IS_ERR(state->i2c_clients[i])) {
adv_err(state, "failed to create i2c client %u\n", i); return PTR_ERR(state->i2c_clients[i]);
}
ret = adv748x_configure_regmap(state, i); if (ret) return ret;
}
return 0;
}
/** * struct adv748x_reg_value - Register write instruction * @page: Regmap page identifier * @reg: I2C register * @value: value to write to @page at @reg
*/ struct adv748x_reg_value {
u8 page;
u8 reg;
u8 value;
};
staticint adv748x_write_regs(struct adv748x_state *state, conststruct adv748x_reg_value *regs)
{ int ret;
/* ADI Required Write */
adv748x_write_check(state, page, 0xc1, 0x3b, &ret);
return ret;
}
int adv748x_tx_power(struct adv748x_csi2 *tx, bool on)
{ int val;
if (!is_tx_enabled(tx)) return 0;
val = tx_read(tx, ADV748X_CSI_FS_AS_LS); if (val < 0) return val;
/* * This test against BIT(6) is not documented by the datasheet, but was * specified in the downstream driver. * Track with a WARN_ONCE to determine if it is ever set by HW.
*/
WARN_ONCE((on && val & ADV748X_CSI_FS_AS_LS_UNKNOWN), "Enabling with unknown bit set");
return on ? adv748x_power_up_tx(tx) : adv748x_power_down_tx(tx);
}
/* Refuse to enable multiple links to the same TX at the same time. */ if (enable && tx->src) return -EINVAL;
/* Set or clear the source (HDMI or AFE) and the current TX. */ if (rsd == &state->afe.sd)
state->afe.tx = enable ? tx : NULL; else
state->hdmi.tx = enable ? tx : NULL;
tx->src = enable ? rsd : NULL;
if (state->afe.tx) { /* AFE Requires TXA enabled, even when output to TXB */
io10 |= ADV748X_IO_10_CSI4_EN; if (is_txa(tx)) { /* * Output from the SD-core (480i and 576i) from the TXA * interface requires reducing the number of enabled * data lanes in order to guarantee a valid link * frequency.
*/
tx->active_lanes = min(tx->num_lanes, 2U);
io10 |= ADV748X_IO_10_CSI4_IN_SEL_AFE;
} else { /* TXB has a single data lane, no need to adjust. */
io10 |= ADV748X_IO_10_CSI1_EN;
}
}
if (state->hdmi.tx) { /* * Restore the number of active lanes, in case we have gone * through an AFE->TXA streaming sessions.
*/
tx->active_lanes = tx->num_lanes;
io10 |= ADV748X_IO_10_CSI4_EN;
}
/* Conditionally enable TXa and TXb. */ if (is_tx_enabled(&state->txa)) {
regval |= ADV748X_IO_10_CSI4_EN;
adv748x_csi2_set_virtual_channel(&state->txa, 0);
} if (is_tx_enabled(&state->txb)) {
regval |= ADV748X_IO_10_CSI1_EN;
adv748x_csi2_set_virtual_channel(&state->txb, 0);
}
io_write(state, ADV748X_IO_10, regval);
/* Use vid_std and v_freq as freerun resolution for CP */
cp_clrset(state, ADV748X_CP_CLMP_POS, ADV748X_CP_CLMP_POS_DIS_AUTO,
ADV748X_CP_CLMP_POS_DIS_AUTO);
return 0;
}
staticint adv748x_identify_chip(struct adv748x_state *state)
{ int msb, lsb;
/* * At least one input endpoint and one output endpoint shall * be defined.
*/ if (ep.port < ADV748X_PORT_TXA)
in_found = true; else
out_found = true;
/* Store number of CSI-2 lanes used for TXA and TXB. */
ret = adv748x_parse_csi2_lanes(state, ep.port, ep_np); if (ret) return ret;
}
/* * We can not use container_of to get back to the state with two TXs; * Initialize the TXs's fields unconditionally on the endpoint * presence to access them later.
*/
state->txa.state = state->txb.state = state;
state->txa.page = ADV748X_PAGE_TXA;
state->txb.page = ADV748X_PAGE_TXB;
state->txa.port = ADV748X_PORT_TXA;
state->txb.port = ADV748X_PORT_TXB;
/* Discover and process ports declared by the Device tree endpoints */
ret = adv748x_parse_dt(state); if (ret) {
adv_err(state, "Failed to parse device tree"); goto err_free_mutex;
}
/* Configure IO Regmap region */
ret = adv748x_configure_regmap(state, ADV748X_PAGE_IO); if (ret) {
adv_err(state, "Error configuring IO regmap region"); goto err_cleanup_dt;
}
ret = adv748x_identify_chip(state); if (ret) {
adv_err(state, "Failed to identify chip"); goto err_cleanup_dt;
}
/* Configure remaining pages as I2C clients with regmap access */
ret = adv748x_initialise_clients(state); if (ret) {
adv_err(state, "Failed to setup client regmap pages"); goto err_cleanup_clients;
}
/* SW reset ADV748X to its default values */
ret = adv748x_reset(state); if (ret) {
adv_err(state, "Failed to reset hardware"); goto err_cleanup_clients;
}
/* Initialise HDMI */
ret = adv748x_hdmi_init(&state->hdmi); if (ret) {
adv_err(state, "Failed to probe HDMI"); goto err_cleanup_clients;
}
/* Initialise AFE */
ret = adv748x_afe_init(&state->afe); if (ret) {
adv_err(state, "Failed to probe AFE"); goto err_cleanup_hdmi;
}
/* Initialise TXA */
ret = adv748x_csi2_init(state, &state->txa); if (ret) {
adv_err(state, "Failed to probe TXA"); goto err_cleanup_afe;
}
/* Initialise TXB */
ret = adv748x_csi2_init(state, &state->txb); if (ret) {
adv_err(state, "Failed to probe TXB"); goto err_cleanup_txa;
}
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.