From patchwork Mon Aug 27 11:28:04 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 10577007 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 398EE174A for ; Mon, 27 Aug 2018 11:28:22 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2AAB229448 for ; Mon, 27 Aug 2018 11:28:22 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 1F7CD2952F; Mon, 27 Aug 2018 11:28:22 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id A467A29448 for ; Mon, 27 Aug 2018 11:28:21 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727206AbeH0POg (ORCPT ); Mon, 27 Aug 2018 11:14:36 -0400 Received: from relay7-d.mail.gandi.net ([217.70.183.200]:43077 "EHLO relay7-d.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726947AbeH0POg (ORCPT ); Mon, 27 Aug 2018 11:14:36 -0400 X-Originating-IP: 2.224.242.101 Received: from w540.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay7-d.mail.gandi.net (Postfix) with ESMTPSA id 3927B2000D; Mon, 27 Aug 2018 11:28:18 +0000 (UTC) From: Jacopo Mondi To: laurent.pinchart@ideasonboard.com, kieran.bingham+renesas@ideasonboard.com, niklas.soderlund+renesas@ragnatech.se Cc: Jacopo Mondi , linux-renesas-soc@vger.kernel.org, linux-media@vger.kernel.org Subject: [PATCH 1/2] media: i2c: adv748x: Support probing a single output Date: Mon, 27 Aug 2018 13:28:04 +0200 Message-Id: <1535369285-26032-2-git-send-email-jacopo+renesas@jmondi.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1535369285-26032-1-git-send-email-jacopo+renesas@jmondi.org> References: <1535369285-26032-1-git-send-email-jacopo+renesas@jmondi.org> Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Currently the adv748x driver refuses to probe if both its output endpoints (TXA and TXB) are not connected. Make the driver support probing with (at least) one output endpoint connected and protect the cleanup function from accessing un-initialized fields. Following patches will fix other user of un-initialized TXs in the driver, such as power management functions. Signed-off-by: Jacopo Mondi --- drivers/media/i2c/adv748x/adv748x-core.c | 38 +++++++++++++++++++++++++------- drivers/media/i2c/adv748x/adv748x-csi2.c | 17 ++++---------- drivers/media/i2c/adv748x/adv748x.h | 2 ++ 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index 6ca88daa..78d5996 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -654,6 +654,24 @@ static int adv748x_probe(struct i2c_client *client, goto err_cleanup_clients; } + /* + * 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; + + if (!is_tx_enabled(&state->txa) && + !is_tx_enabled(&state->txb)) { + ret = -ENODEV; + adv_err(state, "No output endpoint defined\n"); + goto err_cleanup_clients; + } + /* SW reset ADV748X to its default values */ ret = adv748x_reset(state); if (ret) { @@ -676,17 +694,21 @@ static int adv748x_probe(struct i2c_client *client, } /* Initialise TXA */ - ret = adv748x_csi2_init(state, &state->txa); - if (ret) { - adv_err(state, "Failed to probe TXA"); - goto err_cleanup_afe; + if (is_tx_enabled(&state->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; + if (is_tx_enabled(&state->txb)) { + ret = adv748x_csi2_init(state, &state->txb); + if (ret) { + adv_err(state, "Failed to probe TXB"); + goto err_cleanup_txa; + } } return 0; diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c index 469be87..709cdea 100644 --- a/drivers/media/i2c/adv748x/adv748x-csi2.c +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c @@ -266,20 +266,8 @@ static int adv748x_csi2_init_controls(struct adv748x_csi2 *tx) int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx) { - struct device_node *ep; int ret; - /* We can not use container_of to get back to the state with two TXs */ - tx->state = state; - tx->page = is_txa(tx) ? ADV748X_PAGE_TXA : ADV748X_PAGE_TXB; - - ep = state->endpoints[is_txa(tx) ? ADV748X_PORT_TXA : ADV748X_PORT_TXB]; - if (!ep) { - adv_err(state, "No endpoint found for %s\n", - is_txa(tx) ? "txa" : "txb"); - return -ENODEV; - } - /* Initialise the virtual channel */ adv748x_csi2_set_virtual_channel(tx, 0); @@ -288,7 +276,7 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx) is_txa(tx) ? "txa" : "txb"); /* Ensure that matching is based upon the endpoint fwnodes */ - tx->sd.fwnode = of_fwnode_handle(ep); + tx->sd.fwnode = of_fwnode_handle(state->endpoints[tx->port]); /* Register internal ops for incremental subdev registration */ tx->sd.internal_ops = &adv748x_csi2_internal_ops; @@ -321,6 +309,9 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx) void adv748x_csi2_cleanup(struct adv748x_csi2 *tx) { + if (!is_tx_enabled(tx)) + return; + v4l2_async_unregister_subdev(&tx->sd); media_entity_cleanup(&tx->sd.entity); v4l2_ctrl_handler_free(&tx->ctrl_hdl); diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h index 65f8374..1cf46c40 100644 --- a/drivers/media/i2c/adv748x/adv748x.h +++ b/drivers/media/i2c/adv748x/adv748x.h @@ -82,6 +82,7 @@ struct adv748x_csi2 { struct adv748x_state *state; struct v4l2_mbus_framefmt format; unsigned int page; + unsigned int port; struct media_pad pads[ADV748X_CSI2_NR_PADS]; struct v4l2_ctrl_handler ctrl_hdl; @@ -91,6 +92,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) enum adv748x_hdmi_pads { ADV748X_HDMI_SINK, From patchwork Mon Aug 27 11:28:05 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jacopo Mondi X-Patchwork-Id: 10577013 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 5024C174C for ; Mon, 27 Aug 2018 11:28:25 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 4233C29448 for ; Mon, 27 Aug 2018 11:28:25 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 362EE29591; Mon, 27 Aug 2018 11:28:25 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.9 required=2.0 tests=BAYES_00,MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id DDFF629514 for ; Mon, 27 Aug 2018 11:28:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727302AbeH0POi (ORCPT ); Mon, 27 Aug 2018 11:14:38 -0400 Received: from relay7-d.mail.gandi.net ([217.70.183.200]:52669 "EHLO relay7-d.mail.gandi.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726931AbeH0POi (ORCPT ); Mon, 27 Aug 2018 11:14:38 -0400 X-Originating-IP: 2.224.242.101 Received: from w540.lan (2-224-242-101.ip172.fastwebnet.it [2.224.242.101]) (Authenticated sender: jacopo@jmondi.org) by relay7-d.mail.gandi.net (Postfix) with ESMTPSA id 6F27C20010; Mon, 27 Aug 2018 11:28:19 +0000 (UTC) From: Jacopo Mondi To: laurent.pinchart@ideasonboard.com, kieran.bingham+renesas@ideasonboard.com, niklas.soderlund+renesas@ragnatech.se Cc: Jacopo Mondi , linux-renesas-soc@vger.kernel.org, linux-media@vger.kernel.org Subject: [PATCH 2/2] media: i2c: adv748x: Handle TX[A|B] power management Date: Mon, 27 Aug 2018 13:28:05 +0200 Message-Id: <1535369285-26032-3-git-send-email-jacopo+renesas@jmondi.org> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1535369285-26032-1-git-send-email-jacopo+renesas@jmondi.org> References: <1535369285-26032-1-git-send-email-jacopo+renesas@jmondi.org> Sender: linux-media-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-media@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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. The AFE and HDMI backends have fixed output routes, so enable the designated CSI-2 output according to that. Signed-off-by: Jacopo Mondi --- drivers/media/i2c/adv748x/adv748x-afe.c | 2 +- drivers/media/i2c/adv748x/adv748x-core.c | 52 +++++++++++++------------------- drivers/media/i2c/adv748x/adv748x-csi2.c | 5 --- drivers/media/i2c/adv748x/adv748x-hdmi.c | 2 +- drivers/media/i2c/adv748x/adv748x.h | 4 +-- 5 files changed, 25 insertions(+), 40 deletions(-) diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c b/drivers/media/i2c/adv748x/adv748x-afe.c index edd25e8..6d78105 100644 --- a/drivers/media/i2c/adv748x/adv748x-afe.c +++ b/drivers/media/i2c/adv748x/adv748x-afe.c @@ -286,7 +286,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; diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c index 78d5996..0adbcb6 100644 --- a/drivers/media/i2c/adv748x/adv748x-core.c +++ b/drivers/media/i2c/adv748x/adv748x-core.c @@ -292,33 +292,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; @@ -331,9 +314,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); } /* ----------------------------------------------------------------------------- @@ -482,6 +469,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) @@ -496,22 +484,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 4-lane CSI Tx & Pixel Port */ + 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, diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c index 709cdea..36bc786 100644 --- a/drivers/media/i2c/adv748x/adv748x-csi2.c +++ b/drivers/media/i2c/adv748x/adv748x-csi2.c @@ -18,11 +18,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) { diff --git a/drivers/media/i2c/adv748x/adv748x-hdmi.c b/drivers/media/i2c/adv748x/adv748x-hdmi.c index aecc2a8..abb6568 100644 --- a/drivers/media/i2c/adv748x/adv748x-hdmi.c +++ b/drivers/media/i2c/adv748x/adv748x-hdmi.c @@ -362,7 +362,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; diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h index 1cf46c40..2e8d37a 100644 --- a/drivers/media/i2c/adv748x/adv748x.h +++ b/drivers/media/i2c/adv748x/adv748x.h @@ -93,6 +93,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, @@ -400,8 +401,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);