Lines Matching +full:hdmi +full:- +full:tx
1 // SPDX-License-Identifier: GPL-2.0+
3 * Driver for Analog Devices ADV748X HDMI receiver with AFE
21 #include <linux/v4l2-dv-timings.h>
23 #include <media/v4l2-ctrls.h>
24 #include <media/v4l2-device.h>
25 #include <media/v4l2-dv-timings.h>
26 #include <media/v4l2-fwnode.h>
27 #include <media/v4l2-ioctl.h>
31 /* -----------------------------------------------------------------------------
48 ADV748X_REGMAP_CONF("hdmi"),
63 if (!state->i2c_clients[region]) in adv748x_configure_regmap()
64 return -ENODEV; in adv748x_configure_regmap()
66 state->regmap[region] = in adv748x_configure_regmap()
67 devm_regmap_init_i2c(state->i2c_clients[region], in adv748x_configure_regmap()
70 if (IS_ERR(state->regmap[region])) { in adv748x_configure_regmap()
71 err = PTR_ERR(state->regmap[region]); in adv748x_configure_regmap()
75 return -EINVAL; in adv748x_configure_regmap()
89 [ADV748X_PAGE_HDMI] = { "hdmi", 0x34 },
103 struct i2c_client *client = state->i2c_clients[client_page]; in adv748x_read_check()
107 err = regmap_read(state->regmap[client_page], reg, &val); in adv748x_read_check()
111 client->addr, reg); in adv748x_read_check()
125 return regmap_write(state->regmap[page], reg, value); in adv748x_write()
148 struct regmap *regmap = state->regmap[client_page]; in adv748x_write_block()
164 client = state->i2c_clients[i]; in adv748x_set_slave_addresses()
166 io_write(state, io_reg, client->addr << 1); in adv748x_set_slave_addresses()
176 for (i = 1; i < ARRAY_SIZE(state->i2c_clients); ++i) in adv748x_unregister_clients()
177 i2c_unregister_device(state->i2c_clients[i]); in adv748x_unregister_clients()
186 state->i2c_clients[i] = i2c_new_ancillary_device( in adv748x_initialise_clients()
187 state->client, in adv748x_initialise_clients()
191 if (IS_ERR(state->i2c_clients[i])) { in adv748x_initialise_clients()
193 return PTR_ERR(state->i2c_clients[i]); in adv748x_initialise_clients()
205 * struct adv748x_reg_value - Register write instruction
221 for (; regs->page != ADV748X_PAGE_EOR; regs++) { in adv748x_write_regs()
222 ret = adv748x_write(state, regs->page, regs->reg, regs->value); in adv748x_write_regs()
225 regs->page, regs->reg); in adv748x_write_regs()
233 /* -----------------------------------------------------------------------------
237 static int adv748x_power_up_tx(struct adv748x_csi2 *tx) in adv748x_power_up_tx() argument
239 struct adv748x_state *state = tx->state; in adv748x_power_up_tx()
240 u8 page = is_txa(tx) ? ADV748X_PAGE_TXA : ADV748X_PAGE_TXB; in adv748x_power_up_tx()
243 /* Enable n-lane MIPI */ in adv748x_power_up_tx()
244 adv748x_write_check(state, page, 0x00, 0x80 | tx->active_lanes, &ret); in adv748x_power_up_tx()
247 adv748x_write_check(state, page, 0x00, 0xa0 | tx->active_lanes, &ret); in adv748x_power_up_tx()
250 if (tx->src == &state->hdmi.sd) { in adv748x_power_up_tx()
261 /* i2c_dphy_pwdn - 1'b0 */ in adv748x_power_up_tx()
268 /* i2c_mipi_pll_en - 1'b1 */ in adv748x_power_up_tx()
272 /* Power-up CSI-TX */ in adv748x_power_up_tx()
273 adv748x_write_check(state, page, 0x00, 0x20 | tx->active_lanes, &ret); in adv748x_power_up_tx()
284 static int adv748x_power_down_tx(struct adv748x_csi2 *tx) in adv748x_power_down_tx() argument
286 struct adv748x_state *state = tx->state; in adv748x_power_down_tx()
287 u8 page = is_txa(tx) ? ADV748X_PAGE_TXA : ADV748X_PAGE_TXB; in adv748x_power_down_tx()
294 /* Enable n-lane MIPI */ in adv748x_power_down_tx()
295 adv748x_write_check(state, page, 0x00, 0x80 | tx->active_lanes, &ret); in adv748x_power_down_tx()
297 /* i2c_mipi_pll_en - 1'b1 */ in adv748x_power_down_tx()
306 int adv748x_tx_power(struct adv748x_csi2 *tx, bool on) in adv748x_tx_power() argument
310 if (!is_tx_enabled(tx)) in adv748x_tx_power()
313 val = tx_read(tx, ADV748X_CSI_FS_AS_LS); in adv748x_tx_power()
325 return on ? adv748x_power_up_tx(tx) : adv748x_power_down_tx(tx); in adv748x_tx_power()
328 /* -----------------------------------------------------------------------------
335 struct v4l2_subdev *rsd = media_entity_to_v4l2_subdev(remote->entity); in adv748x_link_setup()
338 struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); in adv748x_link_setup() local
345 /* Refuse to enable multiple links to the same TX at the same time. */ in adv748x_link_setup()
346 if (enable && tx->src) in adv748x_link_setup()
347 return -EINVAL; in adv748x_link_setup()
349 /* Set or clear the source (HDMI or AFE) and the current TX. */ in adv748x_link_setup()
350 if (rsd == &state->afe.sd) in adv748x_link_setup()
351 state->afe.tx = enable ? tx : NULL; in adv748x_link_setup()
353 state->hdmi.tx = enable ? tx : NULL; in adv748x_link_setup()
355 tx->src = enable ? rsd : NULL; in adv748x_link_setup()
357 if (state->afe.tx) { in adv748x_link_setup()
360 if (is_txa(tx)) { in adv748x_link_setup()
362 * Output from the SD-core (480i and 576i) from the TXA in adv748x_link_setup()
367 tx->active_lanes = min(tx->num_lanes, 2U); in adv748x_link_setup()
375 if (state->hdmi.tx) { in adv748x_link_setup()
378 * through an AFE->TXA streaming sessions. in adv748x_link_setup()
380 tx->active_lanes = tx->num_lanes; in adv748x_link_setup()
396 /* -----------------------------------------------------------------------------
402 /* Disable chip powerdown & Enable HDMI Rx block */
435 {ADV748X_PAGE_IO, 0x03, 0x86}, /* CP-Insert_AV_Code */
448 {ADV748X_PAGE_IO, 0xf2, 0x01}, /* Enable I2C Read Auto-Increment */
465 {ADV748X_PAGE_SDP, 0x03, 0x42}, /* Tri-S Output , PwrDwn 656 pads */
466 {ADV748X_PAGE_SDP, 0x04, 0xb5}, /* ITU-R BT.656-4 compatible */
486 /* Disable CEC Wakeup from power-down mode */ in adv748x_sw_reset()
492 /* Enable I2C Read Auto-Increment for consecutive reads */ in adv748x_sw_reset()
519 adv748x_afe_s_input(&state->afe, state->afe.input); in adv748x_reset()
521 adv_dbg(state, "AFE Default input set to %d\n", state->afe.input); in adv748x_reset()
524 adv748x_tx_power(&state->txa, 1); in adv748x_reset()
525 adv748x_tx_power(&state->txa, 0); in adv748x_reset()
526 adv748x_tx_power(&state->txb, 1); in adv748x_reset()
527 adv748x_tx_power(&state->txb, 0); in adv748x_reset()
529 /* Disable chip powerdown & Enable HDMI Rx block */ in adv748x_reset()
533 if (is_tx_enabled(&state->txa)) { in adv748x_reset()
535 adv748x_csi2_set_virtual_channel(&state->txa, 0); in adv748x_reset()
537 if (is_tx_enabled(&state->txb)) { in adv748x_reset()
539 adv748x_csi2_set_virtual_channel(&state->txb, 0); in adv748x_reset()
559 return -EIO; in adv748x_identify_chip()
563 state->client->addr << 1, lsb, msb); in adv748x_identify_chip()
568 /* -----------------------------------------------------------------------------
580 /* -----------------------------------------------------------------------------
589 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; in adv748x_subdev_init()
592 sd->owner = state->dev->driver->owner; in adv748x_subdev_init()
593 sd->dev = state->dev; in adv748x_subdev_init()
598 snprintf(sd->name, sizeof(sd->name), "%s %d-%04x %s", in adv748x_subdev_init()
599 state->dev->driver->name, in adv748x_subdev_init()
600 i2c_adapter_id(state->client->adapter), in adv748x_subdev_init()
601 state->client->addr, ident); in adv748x_subdev_init()
603 sd->entity.function = function; in adv748x_subdev_init()
604 sd->entity.ops = is_tx(adv748x_sd_to_csi2(sd)) ? in adv748x_subdev_init()
629 return -EINVAL; in adv748x_parse_csi2_lanes()
632 state->txa.num_lanes = num_lanes; in adv748x_parse_csi2_lanes()
633 state->txa.active_lanes = num_lanes; in adv748x_parse_csi2_lanes()
634 adv_dbg(state, "TXA: using %u lanes\n", state->txa.num_lanes); in adv748x_parse_csi2_lanes()
641 return -EINVAL; in adv748x_parse_csi2_lanes()
644 state->txb.num_lanes = num_lanes; in adv748x_parse_csi2_lanes()
645 state->txb.active_lanes = num_lanes; in adv748x_parse_csi2_lanes()
646 adv_dbg(state, "TXB: using %u lanes\n", state->txb.num_lanes); in adv748x_parse_csi2_lanes()
660 for_each_endpoint_of_node(state->dev->of_node, ep_np) { in adv748x_parse_dt()
672 if (state->endpoints[ep.port]) { in adv748x_parse_dt()
679 state->endpoints[ep.port] = ep_np; in adv748x_parse_dt()
690 /* Store number of CSI-2 lanes used for TXA and TXB. */ in adv748x_parse_dt()
696 return in_found && out_found ? 0 : -ENODEV; in adv748x_parse_dt()
704 of_node_put(state->endpoints[i]); in adv748x_dt_cleanup()
713 if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA)) in adv748x_probe()
714 return -EIO; in adv748x_probe()
716 state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL); in adv748x_probe()
718 return -ENOMEM; in adv748x_probe()
720 mutex_init(&state->mutex); in adv748x_probe()
722 state->dev = &client->dev; in adv748x_probe()
723 state->client = client; in adv748x_probe()
724 state->i2c_clients[ADV748X_PAGE_IO] = client; in adv748x_probe()
732 state->txa.state = state->txb.state = state; in adv748x_probe()
733 state->txa.page = ADV748X_PAGE_TXA; in adv748x_probe()
734 state->txb.page = ADV748X_PAGE_TXB; in adv748x_probe()
735 state->txa.port = ADV748X_PORT_TXA; in adv748x_probe()
736 state->txb.port = ADV748X_PORT_TXB; in adv748x_probe()
772 /* Initialise HDMI */ in adv748x_probe()
773 ret = adv748x_hdmi_init(&state->hdmi); in adv748x_probe()
775 adv_err(state, "Failed to probe HDMI"); in adv748x_probe()
780 ret = adv748x_afe_init(&state->afe); in adv748x_probe()
787 ret = adv748x_csi2_init(state, &state->txa); in adv748x_probe()
794 ret = adv748x_csi2_init(state, &state->txb); in adv748x_probe()
803 adv748x_csi2_cleanup(&state->txa); in adv748x_probe()
805 adv748x_afe_cleanup(&state->afe); in adv748x_probe()
807 adv748x_hdmi_cleanup(&state->hdmi); in adv748x_probe()
813 mutex_destroy(&state->mutex); in adv748x_probe()
822 adv748x_afe_cleanup(&state->afe); in adv748x_remove()
823 adv748x_hdmi_cleanup(&state->hdmi); in adv748x_remove()
825 adv748x_csi2_cleanup(&state->txa); in adv748x_remove()
826 adv748x_csi2_cleanup(&state->txb); in adv748x_remove()
830 mutex_destroy(&state->mutex); in adv748x_remove()