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: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Jacopo Mondi <jacopo+renesas@jmondi.org>
Signed-off-by: Kieran Bingham <kieran.bingham+renesas@ideasonboard.com>
Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
This commit is contained in:
Jacopo Mondi 2018-09-17 07:30:55 -04:00 committed by Mauro Carvalho Chehab
parent eccf442ce1
commit 6bc3ea7a61
5 changed files with 26 additions and 44 deletions

View File

@ -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;

View File

@ -288,11 +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 (!is_tx_enabled(tx))
return 0;
val = tx_read(tx, ADV748X_CSI_FS_AS_LS);
if (val < 0)
return val;
@ -305,31 +310,13 @@ int adv748x_txa_power(struct adv748x_state *state, bool on)
"Enabling with unknown bit set");
if (on)
return adv748x_write_regs(state, adv748x_power_up_txa_4lane);
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_txa_4lane);
}
int adv748x_txb_power(struct adv748x_state *state, bool on)
{
int val;
val = txb_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_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,

View File

@ -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)
{

View File

@ -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;

View File

@ -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);