summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/bridge/chipone-icn6211.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/bridge/chipone-icn6211.c')
-rw-r--r--drivers/gpu/drm/bridge/chipone-icn6211.c48
1 files changed, 38 insertions, 10 deletions
diff --git a/drivers/gpu/drm/bridge/chipone-icn6211.c b/drivers/gpu/drm/bridge/chipone-icn6211.c
index 481c86b2406e..bf920c3503aa 100644
--- a/drivers/gpu/drm/bridge/chipone-icn6211.c
+++ b/drivers/gpu/drm/bridge/chipone-icn6211.c
@@ -11,6 +11,7 @@
#include <linux/bitfield.h>
#include <linux/bits.h>
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
@@ -151,6 +152,8 @@ struct chipone {
struct regulator *vdd1;
struct regulator *vdd2;
struct regulator *vdd3;
+ struct clk *refclk;
+ unsigned long refclk_rate;
bool interface_i2c;
};
@@ -259,7 +262,7 @@ static void chipone_configure_pll(struct chipone *icn,
/*
* DSI byte clock frequency (input into PLL) is calculated as:
- * DSI_CLK = mode clock * bpp / dsi_data_lanes / 8
+ * DSI_CLK = HS clock / 4
*
* DPI pixel clock frequency (output from PLL) is mode clock.
*
@@ -273,8 +276,10 @@ static void chipone_configure_pll(struct chipone *icn,
* It seems the PLL input clock after applying P pre-divider have
* to be lower than 20 MHz.
*/
- fin = mode_clock * mipi_dsi_pixel_format_to_bpp(icn->dsi->format) /
- icn->dsi->lanes / 8; /* in Hz */
+ if (icn->refclk)
+ fin = icn->refclk_rate;
+ else
+ fin = icn->dsi->hs_rate / 4; /* in Hz */
/* Minimum value of P predivider for PLL input in 5..20 MHz */
p_min = clamp(DIV_ROUND_UP(fin, 20000000), 1U, 31U);
@@ -319,16 +324,18 @@ static void chipone_configure_pll(struct chipone *icn,
best_p_pot = !(best_p & 1);
dev_dbg(icn->dev,
- "PLL: P[3:0]=%d P[4]=2*%d M=%d S[7:5]=2^%d delta=%d => DSI f_in=%d Hz ; DPI f_out=%d Hz\n",
+ "PLL: P[3:0]=%d P[4]=2*%d M=%d S[7:5]=2^%d delta=%d => DSI f_in(%s)=%d Hz ; DPI f_out=%d Hz\n",
best_p >> best_p_pot, best_p_pot, best_m, best_s + 1,
- min_delta, fin, (fin * best_m) / (best_p << (best_s + 1)));
+ min_delta, icn->refclk ? "EXT" : "DSI", fin,
+ (fin * best_m) / (best_p << (best_s + 1)));
ref_div = PLL_REF_DIV_P(best_p >> best_p_pot) | PLL_REF_DIV_S(best_s);
if (best_p_pot) /* Prefer /2 pre-divider */
ref_div |= PLL_REF_DIV_Pe;
- /* Clock source selection fixed to MIPI DSI clock lane */
- chipone_writeb(icn, PLL_CTRL(6), PLL_CTRL_6_MIPI_CLK);
+ /* Clock source selection either external clock or MIPI DSI clock lane */
+ chipone_writeb(icn, PLL_CTRL(6),
+ icn->refclk ? PLL_CTRL_6_EXTERNAL : PLL_CTRL_6_MIPI_CLK);
chipone_writeb(icn, PLL_REF_DIV, ref_div);
chipone_writeb(icn, PLL_INT(0), best_m);
}
@@ -464,6 +471,11 @@ static void chipone_atomic_pre_enable(struct drm_bridge *bridge,
"failed to enable VDD3 regulator: %d\n", ret);
}
+ ret = clk_prepare_enable(icn->refclk);
+ if (ret)
+ DRM_DEV_ERROR(icn->dev,
+ "failed to enable RECLK clock: %d\n", ret);
+
gpiod_set_value(icn->enable_gpio, 1);
usleep_range(10000, 11000);
@@ -474,6 +486,8 @@ static void chipone_atomic_post_disable(struct drm_bridge *bridge,
{
struct chipone *icn = bridge_to_chipone(bridge);
+ clk_disable_unprepare(icn->refclk);
+
if (icn->vdd1)
regulator_disable(icn->vdd1);
@@ -515,6 +529,8 @@ static int chipone_dsi_attach(struct chipone *icn)
dsi->format = MIPI_DSI_FMT_RGB888;
dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST |
MIPI_DSI_MODE_LPM | MIPI_DSI_MODE_NO_EOT_PACKET;
+ dsi->hs_rate = 500000000;
+ dsi->lp_rate = 16000000;
ret = mipi_dsi_attach(dsi);
if (ret < 0)
@@ -617,6 +633,20 @@ static int chipone_parse_dt(struct chipone *icn)
struct device *dev = icn->dev;
int ret;
+ icn->refclk = devm_clk_get_optional(dev, "refclk");
+ if (IS_ERR(icn->refclk)) {
+ ret = PTR_ERR(icn->refclk);
+ DRM_DEV_ERROR(dev, "failed to get REFCLK clock: %d\n", ret);
+ return ret;
+ } else if (icn->refclk) {
+ icn->refclk_rate = clk_get_rate(icn->refclk);
+ if (icn->refclk_rate < 10000000 || icn->refclk_rate > 154000000) {
+ DRM_DEV_ERROR(dev, "REFCLK out of range: %ld Hz\n",
+ icn->refclk_rate);
+ return -EINVAL;
+ }
+ }
+
icn->vdd1 = devm_regulator_get_optional(dev, "vdd1");
if (IS_ERR(icn->vdd1)) {
ret = PTR_ERR(icn->vdd1);
@@ -735,14 +765,12 @@ static int chipone_i2c_probe(struct i2c_client *client,
return chipone_dsi_host_attach(icn);
}
-static int chipone_dsi_remove(struct mipi_dsi_device *dsi)
+static void chipone_dsi_remove(struct mipi_dsi_device *dsi)
{
struct chipone *icn = mipi_dsi_get_drvdata(dsi);
mipi_dsi_detach(dsi);
drm_bridge_remove(&icn->bridge);
-
- return 0;
}
static const struct of_device_id chipone_of_match[] = {