Commit 6bc3ea7a authored by Jacopo Mondi's avatar Jacopo Mondi Committed by Mauro Carvalho Chehab
Browse files

media: i2c: adv748x: Handle TX[A|B] power management



As the driver is now allowed to probe with a single output endpoint,
power management routines shall now take into account the case a CSI-2 TX
is not enabled.

Unify the adv748x_tx_power() routine to handle transparently TXA and TXB,
and enable the CSI-2 outputs conditionally.

Tested-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: default avatarJacopo Mondi <jacopo+renesas@jmondi.org>
Signed-off-by: default avatarKieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+samsung@kernel.org>
parent eccf442c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -282,7 +282,7 @@ static int adv748x_afe_s_stream(struct v4l2_subdev *sd, int enable)
			goto unlock;
	}

	ret = adv748x_txb_power(state, enable);
	ret = adv748x_tx_power(&state->txb, enable);
	if (ret)
		goto unlock;

+21 −31
Original line number Diff line number Diff line
@@ -288,33 +288,16 @@ static const struct adv748x_reg_value adv748x_power_down_txb_1lane[] = {
	{ADV748X_PAGE_EOR, 0xff, 0xff}	/* End of register table */
};

int adv748x_txa_power(struct adv748x_state *state, bool on)
int adv748x_tx_power(struct adv748x_csi2 *tx, bool on)
{
	struct adv748x_state *state = tx->state;
	const struct adv748x_reg_value *reglist;
	int val;

	val = txa_read(state, 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");

	if (on)
		return adv748x_write_regs(state, adv748x_power_up_txa_4lane);

	return adv748x_write_regs(state, adv748x_power_down_txa_4lane);
}

int adv748x_txb_power(struct adv748x_state *state, bool on)
{
	int val;
	if (!is_tx_enabled(tx))
		return 0;

	val = txb_read(state, ADV748X_CSI_FS_AS_LS);
	val = tx_read(tx, ADV748X_CSI_FS_AS_LS);
	if (val < 0)
		return val;

@@ -327,9 +310,13 @@ int adv748x_txb_power(struct adv748x_state *state, bool on)
			"Enabling with unknown bit set");

	if (on)
		return adv748x_write_regs(state, adv748x_power_up_txb_1lane);
		reglist = is_txa(tx) ? adv748x_power_up_txa_4lane :
				       adv748x_power_up_txb_1lane;
	else
		reglist = is_txa(tx) ? adv748x_power_down_txa_4lane :
				       adv748x_power_down_txb_1lane;

	return adv748x_write_regs(state, adv748x_power_down_txb_1lane);
	return adv748x_write_regs(state, reglist);
}

/* -----------------------------------------------------------------------------
@@ -478,6 +465,7 @@ static const struct adv748x_reg_value adv748x_init_txb_1lane[] = {
static int adv748x_reset(struct adv748x_state *state)
{
	int ret;
	u8 regval = ADV748X_IO_10_PIX_OUT_EN;

	ret = adv748x_write_regs(state, adv748x_sw_reset);
	if (ret < 0)
@@ -492,22 +480,24 @@ static int adv748x_reset(struct adv748x_state *state)
	if (ret)
		return ret;

	adv748x_txa_power(state, 0);
	adv748x_tx_power(&state->txa, 0);

	/* Init and power down TXB */
	ret = adv748x_write_regs(state, adv748x_init_txb_1lane);
	if (ret)
		return ret;

	adv748x_txb_power(state, 0);
	adv748x_tx_power(&state->txb, 0);

	/* Disable chip powerdown & Enable HDMI Rx block */
	io_write(state, ADV748X_IO_PD, ADV748X_IO_PD_RX_EN);

	/* Enable 4-lane CSI Tx & Pixel Port */
	io_write(state, ADV748X_IO_10, ADV748X_IO_10_CSI4_EN |
				       ADV748X_IO_10_CSI1_EN |
				       ADV748X_IO_10_PIX_OUT_EN);
	/* Conditionally enable TXa and TXb. */
	if (is_tx_enabled(&state->txa))
		regval |= ADV748X_IO_10_CSI4_EN;
	if (is_tx_enabled(&state->txb))
		regval |= ADV748X_IO_10_CSI1_EN;
	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,
+0 −5
Original line number Diff line number Diff line
@@ -14,11 +14,6 @@

#include "adv748x.h"

static bool is_txa(struct adv748x_csi2 *tx)
{
	return tx == &tx->state->txa;
}

static int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx,
					    unsigned int vc)
{
+1 −1
Original line number Diff line number Diff line
@@ -358,7 +358,7 @@ static int adv748x_hdmi_s_stream(struct v4l2_subdev *sd, int enable)

	mutex_lock(&state->mutex);

	ret = adv748x_txa_power(state, enable);
	ret = adv748x_tx_power(&state->txa, enable);
	if (ret)
		goto done;

+2 −5
Original line number Diff line number Diff line
@@ -89,6 +89,7 @@ struct adv748x_csi2 {
#define notifier_to_csi2(n) container_of(n, struct adv748x_csi2, notifier)
#define adv748x_sd_to_csi2(sd) container_of(sd, struct adv748x_csi2, sd)
#define is_tx_enabled(_tx) ((_tx)->state->endpoints[(_tx)->port] != NULL)
#define is_txa(_tx) ((_tx) == &(_tx)->state->txa)

enum adv748x_hdmi_pads {
	ADV748X_HDMI_SINK,
@@ -374,9 +375,6 @@ int adv748x_write_block(struct adv748x_state *state, int client_page,
#define cp_write(s, r, v) adv748x_write(s, ADV748X_PAGE_CP, r, v)
#define cp_clrset(s, r, m, v) cp_write(s, r, (cp_read(s, r) & ~m) | v)

#define txa_read(s, r) adv748x_read(s, ADV748X_PAGE_TXA, r)
#define txb_read(s, r) adv748x_read(s, ADV748X_PAGE_TXB, r)

#define tx_read(t, r) adv748x_read(t->state, t->page, r)
#define tx_write(t, r, v) adv748x_write(t->state, t->page, r, v)

@@ -396,8 +394,7 @@ void adv748x_subdev_init(struct v4l2_subdev *sd, struct adv748x_state *state,
int adv748x_register_subdevs(struct adv748x_state *state,
			     struct v4l2_device *v4l2_dev);

int adv748x_txa_power(struct adv748x_state *state, bool on);
int adv748x_txb_power(struct adv748x_state *state, bool on);
int adv748x_tx_power(struct adv748x_csi2 *tx, bool on);

int adv748x_afe_init(struct adv748x_afe *afe);
void adv748x_afe_cleanup(struct adv748x_afe *afe);