[RFC 05/12] staging: media: max96712: add link frequency V4L2 control

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The downstream nodes can use the V4L2_CID_PIXEL_RATE control to estimate
the link frequency but this can result in innacurate rates. Instead,
implement the V4L2_CID_LINK_FREQ control and pass the link frequency
from DT. If link-frequency DT property is missing fallback to using the
platform info DPLL value to compute the link frequency. Also, remove the
pixel rate control since it's not needed anymore.

Signed-off-by: Laurentiu Palcu <laurentiu.palcu@xxxxxxxxxxx>
---
 drivers/staging/media/max96712/max96712.c | 79 +++++++++++++++++------
 1 file changed, 60 insertions(+), 19 deletions(-)

diff --git a/drivers/staging/media/max96712/max96712.c b/drivers/staging/media/max96712/max96712.c
index 9c255979932d6..546660e4b3d1e 100644
--- a/drivers/staging/media/max96712/max96712.c
+++ b/drivers/staging/media/max96712/max96712.c
@@ -83,7 +83,11 @@
 #define   T_T3_POST_SHIFT				2
 
 /* MIPI_TX: 0 <= phy < 4 */
-#define MAX96712_MIPI_TX_10(phy)			CCI_REG8(0x090a + (phy) * 0x40)
+#define MAX96712_MIPI_TX_DESKEW_INIT(phy)		CCI_REG8(0x0903 + (phy) * 0x40)
+#define   DPHY_DESKEW_AUTO_INIT_EN			BIT(7)
+#define MAX96712_MIPI_TX_DESKEW_PER(phy)		CCI_REG8(0x0904 + (phy) * 0x40)
+#define   PERIODIC_DESKEW_CALIBRATION_EN		BIT(7)
+#define MAX96712_MIPI_TX_10(phy)			(0x090a + (phy) * 0x40)
 #define   CSI2_TWAKEUP_H_MASK				GENMASK(2, 0)
 #define   CSI2_TWAKEUP_H_SHIFT				0
 #define   CSI2_VCX_EN					BIT(4)
@@ -137,6 +141,8 @@
 							 MAX96712_MAX_TX_PORTS + \
 							 MAX96712_MAX_VPG_PORTS)
 
+#define MHZ(f)						((f) * 1000000U)
+
 enum max96712_pattern {
 	MAX96712_PATTERN_CHECKERBOARD = 0,
 	MAX96712_PATTERN_GRADIENT,
@@ -160,6 +166,7 @@ struct max96712_priv {
 
 	bool cphy;
 	struct v4l2_mbus_config_mipi_csi2 mipi;
+	s64 link_freq;
 
 	struct v4l2_subdev sd;
 	struct v4l2_ctrl_handler ctrl_handler;
@@ -252,12 +259,28 @@ static void max96712_mipi_configure(struct max96712_priv *priv)
 			     PHY_CSI_TX_DPLL_FB_FRACTION_PREDEF_EN |
 			     PHY_CSI_TX_DPLL_PREDEF_FREQ_MASK,
 			     PHY_CSI_TX_DPLL_FB_FRACTION_PREDEF_EN |
-			     ((priv->info->dpllfreq / 100) & 0x1f));
+			     (((priv->link_freq * 2) / MHZ(100)) & 0x1f));
 	max96712_update_bits(priv, MAX96712_BACKTOP0_25,
 			     PHY_CSI_TX_DPLL_FB_FRACTION_PREDEF_EN |
 			     PHY_CSI_TX_DPLL_PREDEF_FREQ_MASK,
 			     PHY_CSI_TX_DPLL_FB_FRACTION_PREDEF_EN |
-			     ((priv->info->dpllfreq / 100) & 0x1f));
+			     (((priv->link_freq * 2) / MHZ(100)) & 0x1f));
+
+	/* disable deskew on PHY0 and PHY1 if D-PHY is used and DPLL <= 1500MHz */
+	if (!priv->cphy) {
+		u32 dpll = priv->link_freq * 2;
+		u8 auto_deskew_en = dpll > MHZ(1500) ? DPHY_DESKEW_AUTO_INIT_EN : 0;
+		u8 auto_deskew_calib_en = dpll > MHZ(1500) ? PERIODIC_DESKEW_CALIBRATION_EN : 0;
+
+		max96712_update_bits(priv, MAX96712_MIPI_TX_DESKEW_INIT(0),
+				     DPHY_DESKEW_AUTO_INIT_EN, auto_deskew_en);
+		max96712_update_bits(priv, MAX96712_MIPI_TX_DESKEW_PER(0),
+				     PERIODIC_DESKEW_CALIBRATION_EN, auto_deskew_calib_en);
+		max96712_update_bits(priv, MAX96712_MIPI_TX_DESKEW_INIT(1),
+				     DPHY_DESKEW_AUTO_INIT_EN, auto_deskew_en);
+		max96712_update_bits(priv, MAX96712_MIPI_TX_DESKEW_PER(1),
+				     PERIODIC_DESKEW_CALIBRATION_EN, auto_deskew_calib_en);
+	}
 
 	/* Enable PHY0 and PHY1 */
 	max96712_update_bits(priv, MAX96712_MIPI_PHY_2, PHY_STDBY_N_MASK, PHY0_EN | PHY1_EN);
@@ -409,7 +432,7 @@ static const struct v4l2_ctrl_ops max96712_ctrl_ops = {
 
 static int max96712_v4l2_register(struct max96712_priv *priv)
 {
-	long pixel_rate;
+	struct v4l2_ctrl *link_freq_ctrl;
 	int ret;
 	int i;
 
@@ -420,18 +443,15 @@ static int max96712_v4l2_register(struct max96712_priv *priv)
 
 	v4l2_ctrl_handler_init(&priv->ctrl_handler, 2);
 
-	/*
-	 * TODO: Once V4L2_CID_LINK_FREQ is changed from a menu control to an
-	 * INT64 control it should be used here instead of V4L2_CID_PIXEL_RATE.
-	 */
-	pixel_rate = priv->info->dpllfreq / priv->mipi.num_data_lanes * 1000000;
-	v4l2_ctrl_new_std(&priv->ctrl_handler, NULL, V4L2_CID_PIXEL_RATE,
-			  pixel_rate, pixel_rate, 1, pixel_rate);
+	v4l2_ctrl_new_int_menu(&priv->ctrl_handler, NULL, V4L2_CID_LINK_FREQ,
+			       0, 0, &priv->link_freq);
 
-	v4l2_ctrl_new_std_menu_items(&priv->ctrl_handler, &max96712_ctrl_ops,
-				     V4L2_CID_TEST_PATTERN,
-				     ARRAY_SIZE(max96712_test_pattern) - 1,
-				     0, 0, max96712_test_pattern);
+	link_freq_ctrl = v4l2_ctrl_new_std_menu_items(&priv->ctrl_handler, &max96712_ctrl_ops,
+						      V4L2_CID_TEST_PATTERN,
+						      ARRAY_SIZE(max96712_test_pattern) - 1,
+						      0, 0, max96712_test_pattern);
+	if (link_freq_ctrl)
+		link_freq_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
 
 	priv->sd.ctrl_handler = &priv->ctrl_handler;
 	ret = priv->ctrl_handler.error;
@@ -515,7 +535,7 @@ static int max96712_parse_tx_ports(struct max96712_priv *priv, struct device_nod
 	unsigned int supported_lanes;
 	int ret;
 
-	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &v4l2_ep);
+	ret = v4l2_fwnode_endpoint_alloc_parse(of_fwnode_handle(node), &v4l2_ep);
 	if (ret) {
 		dev_err(&priv->client->dev, "Could not parse v4l2 endpoint\n");
 		return -EINVAL;
@@ -533,18 +553,39 @@ static int max96712_parse_tx_ports(struct max96712_priv *priv, struct device_nod
 	default:
 		dev_err(&priv->client->dev, "Unsupported bus-type %u\n",
 			v4l2_ep.bus_type);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto free_v4l2_ep;
 	}
 
 	if (v4l2_ep.bus.mipi_csi2.num_data_lanes != supported_lanes) {
 		dev_err(&priv->client->dev, "Only %u data lanes supported\n",
 			supported_lanes);
-		return -EINVAL;
+		ret = -EINVAL;
+		goto free_v4l2_ep;
+	}
+
+	if (v4l2_ep.nr_of_link_frequencies != 1) {
+		dev_info(&priv->client->dev,
+			 "No link frequencies provided in DT, use platform info.\n");
+		priv->link_freq = MHZ(priv->info->dpllfreq) / 2;
+	} else {
+		priv->link_freq = v4l2_ep.link_frequencies[0];
+
+		if (priv->link_freq < MHZ(100) || priv->link_freq > MHZ(1250) ||
+		    priv->link_freq % MHZ(50)) {
+			dev_err(&priv->client->dev,
+				"Link frequency must be a multiple of 50MHz.\n");
+			ret = -EINVAL;
+			goto free_v4l2_ep;
+		}
 	}
 
 	priv->mipi = v4l2_ep.bus.mipi_csi2;
 
-	return 0;
+free_v4l2_ep:
+	v4l2_fwnode_endpoint_free(&v4l2_ep);
+
+	return ret;
 }
 
 static int max96712_parse_dt(struct max96712_priv *priv)
-- 
2.44.1





[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]

  Powered by Linux