cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dw_mipi_dsi-stm.c (16538B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) STMicroelectronics SA 2017
      4 *
      5 * Authors: Philippe Cornu <philippe.cornu@st.com>
      6 *          Yannick Fertre <yannick.fertre@st.com>
      7 */
      8
      9#include <linux/clk.h>
     10#include <linux/iopoll.h>
     11#include <linux/mod_devicetable.h>
     12#include <linux/module.h>
     13#include <linux/platform_device.h>
     14#include <linux/regulator/consumer.h>
     15
     16#include <video/mipi_display.h>
     17
     18#include <drm/bridge/dw_mipi_dsi.h>
     19#include <drm/drm_mipi_dsi.h>
     20#include <drm/drm_print.h>
     21
     22#define HWVER_130			0x31333000	/* IP version 1.30 */
     23#define HWVER_131			0x31333100	/* IP version 1.31 */
     24
     25/* DSI digital registers & bit definitions */
     26#define DSI_VERSION			0x00
     27#define VERSION				GENMASK(31, 8)
     28
     29/* DSI wrapper registers & bit definitions */
     30/* Note: registers are named as in the Reference Manual */
     31#define DSI_WCFGR	0x0400		/* Wrapper ConFiGuration Reg */
     32#define WCFGR_DSIM	BIT(0)		/* DSI Mode */
     33#define WCFGR_COLMUX	GENMASK(3, 1)	/* COLor MUltipleXing */
     34
     35#define DSI_WCR		0x0404		/* Wrapper Control Reg */
     36#define WCR_DSIEN	BIT(3)		/* DSI ENable */
     37
     38#define DSI_WISR	0x040C		/* Wrapper Interrupt and Status Reg */
     39#define WISR_PLLLS	BIT(8)		/* PLL Lock Status */
     40#define WISR_RRS	BIT(12)		/* Regulator Ready Status */
     41
     42#define DSI_WPCR0	0x0418		/* Wrapper Phy Conf Reg 0 */
     43#define WPCR0_UIX4	GENMASK(5, 0)	/* Unit Interval X 4 */
     44#define WPCR0_TDDL	BIT(16)		/* Turn Disable Data Lanes */
     45
     46#define DSI_WRPCR	0x0430		/* Wrapper Regulator & Pll Ctrl Reg */
     47#define WRPCR_PLLEN	BIT(0)		/* PLL ENable */
     48#define WRPCR_NDIV	GENMASK(8, 2)	/* pll loop DIVision Factor */
     49#define WRPCR_IDF	GENMASK(14, 11)	/* pll Input Division Factor */
     50#define WRPCR_ODF	GENMASK(17, 16)	/* pll Output Division Factor */
     51#define WRPCR_REGEN	BIT(24)		/* REGulator ENable */
     52#define WRPCR_BGREN	BIT(28)		/* BandGap Reference ENable */
     53#define IDF_MIN		1
     54#define IDF_MAX		7
     55#define NDIV_MIN	10
     56#define NDIV_MAX	125
     57#define ODF_MIN		1
     58#define ODF_MAX		8
     59
     60/* dsi color format coding according to the datasheet */
     61enum dsi_color {
     62	DSI_RGB565_CONF1,
     63	DSI_RGB565_CONF2,
     64	DSI_RGB565_CONF3,
     65	DSI_RGB666_CONF1,
     66	DSI_RGB666_CONF2,
     67	DSI_RGB888,
     68};
     69
     70#define LANE_MIN_KBPS	31250
     71#define LANE_MAX_KBPS	500000
     72
     73/* Sleep & timeout for regulator on/off, pll lock/unlock & fifo empty */
     74#define SLEEP_US	1000
     75#define TIMEOUT_US	200000
     76
     77struct dw_mipi_dsi_stm {
     78	void __iomem *base;
     79	struct clk *pllref_clk;
     80	struct dw_mipi_dsi *dsi;
     81	u32 hw_version;
     82	int lane_min_kbps;
     83	int lane_max_kbps;
     84	struct regulator *vdd_supply;
     85};
     86
     87static inline void dsi_write(struct dw_mipi_dsi_stm *dsi, u32 reg, u32 val)
     88{
     89	writel(val, dsi->base + reg);
     90}
     91
     92static inline u32 dsi_read(struct dw_mipi_dsi_stm *dsi, u32 reg)
     93{
     94	return readl(dsi->base + reg);
     95}
     96
     97static inline void dsi_set(struct dw_mipi_dsi_stm *dsi, u32 reg, u32 mask)
     98{
     99	dsi_write(dsi, reg, dsi_read(dsi, reg) | mask);
    100}
    101
    102static inline void dsi_clear(struct dw_mipi_dsi_stm *dsi, u32 reg, u32 mask)
    103{
    104	dsi_write(dsi, reg, dsi_read(dsi, reg) & ~mask);
    105}
    106
    107static inline void dsi_update_bits(struct dw_mipi_dsi_stm *dsi, u32 reg,
    108				   u32 mask, u32 val)
    109{
    110	dsi_write(dsi, reg, (dsi_read(dsi, reg) & ~mask) | val);
    111}
    112
    113static enum dsi_color dsi_color_from_mipi(enum mipi_dsi_pixel_format fmt)
    114{
    115	switch (fmt) {
    116	case MIPI_DSI_FMT_RGB888:
    117		return DSI_RGB888;
    118	case MIPI_DSI_FMT_RGB666:
    119		return DSI_RGB666_CONF2;
    120	case MIPI_DSI_FMT_RGB666_PACKED:
    121		return DSI_RGB666_CONF1;
    122	case MIPI_DSI_FMT_RGB565:
    123		return DSI_RGB565_CONF1;
    124	default:
    125		DRM_DEBUG_DRIVER("MIPI color invalid, so we use rgb888\n");
    126	}
    127	return DSI_RGB888;
    128}
    129
    130static int dsi_pll_get_clkout_khz(int clkin_khz, int idf, int ndiv, int odf)
    131{
    132	int divisor = idf * odf;
    133
    134	/* prevent from division by 0 */
    135	if (!divisor)
    136		return 0;
    137
    138	return DIV_ROUND_CLOSEST(clkin_khz * ndiv, divisor);
    139}
    140
    141static int dsi_pll_get_params(struct dw_mipi_dsi_stm *dsi,
    142			      int clkin_khz, int clkout_khz,
    143			      int *idf, int *ndiv, int *odf)
    144{
    145	int i, o, n, n_min, n_max;
    146	int fvco_min, fvco_max, delta, best_delta; /* all in khz */
    147
    148	/* Early checks preventing division by 0 & odd results */
    149	if (clkin_khz <= 0 || clkout_khz <= 0)
    150		return -EINVAL;
    151
    152	fvco_min = dsi->lane_min_kbps * 2 * ODF_MAX;
    153	fvco_max = dsi->lane_max_kbps * 2 * ODF_MIN;
    154
    155	best_delta = 1000000; /* big started value (1000000khz) */
    156
    157	for (i = IDF_MIN; i <= IDF_MAX; i++) {
    158		/* Compute ndiv range according to Fvco */
    159		n_min = ((fvco_min * i) / (2 * clkin_khz)) + 1;
    160		n_max = (fvco_max * i) / (2 * clkin_khz);
    161
    162		/* No need to continue idf loop if we reach ndiv max */
    163		if (n_min >= NDIV_MAX)
    164			break;
    165
    166		/* Clamp ndiv to valid values */
    167		if (n_min < NDIV_MIN)
    168			n_min = NDIV_MIN;
    169		if (n_max > NDIV_MAX)
    170			n_max = NDIV_MAX;
    171
    172		for (o = ODF_MIN; o <= ODF_MAX; o *= 2) {
    173			n = DIV_ROUND_CLOSEST(i * o * clkout_khz, clkin_khz);
    174			/* Check ndiv according to vco range */
    175			if (n < n_min || n > n_max)
    176				continue;
    177			/* Check if new delta is better & saves parameters */
    178			delta = dsi_pll_get_clkout_khz(clkin_khz, i, n, o) -
    179				clkout_khz;
    180			if (delta < 0)
    181				delta = -delta;
    182			if (delta < best_delta) {
    183				*idf = i;
    184				*ndiv = n;
    185				*odf = o;
    186				best_delta = delta;
    187			}
    188			/* fast return in case of "perfect result" */
    189			if (!delta)
    190				return 0;
    191		}
    192	}
    193
    194	return 0;
    195}
    196
    197static int dw_mipi_dsi_phy_init(void *priv_data)
    198{
    199	struct dw_mipi_dsi_stm *dsi = priv_data;
    200	u32 val;
    201	int ret;
    202
    203	/* Enable the regulator */
    204	dsi_set(dsi, DSI_WRPCR, WRPCR_REGEN | WRPCR_BGREN);
    205	ret = readl_poll_timeout(dsi->base + DSI_WISR, val, val & WISR_RRS,
    206				 SLEEP_US, TIMEOUT_US);
    207	if (ret)
    208		DRM_DEBUG_DRIVER("!TIMEOUT! waiting REGU, let's continue\n");
    209
    210	/* Enable the DSI PLL & wait for its lock */
    211	dsi_set(dsi, DSI_WRPCR, WRPCR_PLLEN);
    212	ret = readl_poll_timeout(dsi->base + DSI_WISR, val, val & WISR_PLLLS,
    213				 SLEEP_US, TIMEOUT_US);
    214	if (ret)
    215		DRM_DEBUG_DRIVER("!TIMEOUT! waiting PLL, let's continue\n");
    216
    217	return 0;
    218}
    219
    220static void dw_mipi_dsi_phy_power_on(void *priv_data)
    221{
    222	struct dw_mipi_dsi_stm *dsi = priv_data;
    223
    224	DRM_DEBUG_DRIVER("\n");
    225
    226	/* Enable the DSI wrapper */
    227	dsi_set(dsi, DSI_WCR, WCR_DSIEN);
    228}
    229
    230static void dw_mipi_dsi_phy_power_off(void *priv_data)
    231{
    232	struct dw_mipi_dsi_stm *dsi = priv_data;
    233
    234	DRM_DEBUG_DRIVER("\n");
    235
    236	/* Disable the DSI wrapper */
    237	dsi_clear(dsi, DSI_WCR, WCR_DSIEN);
    238}
    239
    240static int
    241dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode,
    242			  unsigned long mode_flags, u32 lanes, u32 format,
    243			  unsigned int *lane_mbps)
    244{
    245	struct dw_mipi_dsi_stm *dsi = priv_data;
    246	unsigned int idf, ndiv, odf, pll_in_khz, pll_out_khz;
    247	int ret, bpp;
    248	u32 val;
    249
    250	pll_in_khz = (unsigned int)(clk_get_rate(dsi->pllref_clk) / 1000);
    251
    252	/* Compute requested pll out */
    253	bpp = mipi_dsi_pixel_format_to_bpp(format);
    254	pll_out_khz = mode->clock * bpp / lanes;
    255
    256	/* Add 20% to pll out to be higher than pixel bw (burst mode only) */
    257	if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST)
    258		pll_out_khz = (pll_out_khz * 12) / 10;
    259
    260	if (pll_out_khz > dsi->lane_max_kbps) {
    261		pll_out_khz = dsi->lane_max_kbps;
    262		DRM_WARN("Warning max phy mbps is used\n");
    263	}
    264	if (pll_out_khz < dsi->lane_min_kbps) {
    265		pll_out_khz = dsi->lane_min_kbps;
    266		DRM_WARN("Warning min phy mbps is used\n");
    267	}
    268
    269	/* Compute best pll parameters */
    270	idf = 0;
    271	ndiv = 0;
    272	odf = 0;
    273	ret = dsi_pll_get_params(dsi, pll_in_khz, pll_out_khz,
    274				 &idf, &ndiv, &odf);
    275	if (ret)
    276		DRM_WARN("Warning dsi_pll_get_params(): bad params\n");
    277
    278	/* Get the adjusted pll out value */
    279	pll_out_khz = dsi_pll_get_clkout_khz(pll_in_khz, idf, ndiv, odf);
    280
    281	/* Set the PLL division factors */
    282	dsi_update_bits(dsi, DSI_WRPCR,	WRPCR_NDIV | WRPCR_IDF | WRPCR_ODF,
    283			(ndiv << 2) | (idf << 11) | ((ffs(odf) - 1) << 16));
    284
    285	/* Compute uix4 & set the bit period in high-speed mode */
    286	val = 4000000 / pll_out_khz;
    287	dsi_update_bits(dsi, DSI_WPCR0, WPCR0_UIX4, val);
    288
    289	/* Select video mode by resetting DSIM bit */
    290	dsi_clear(dsi, DSI_WCFGR, WCFGR_DSIM);
    291
    292	/* Select the color coding */
    293	dsi_update_bits(dsi, DSI_WCFGR, WCFGR_COLMUX,
    294			dsi_color_from_mipi(format) << 1);
    295
    296	*lane_mbps = pll_out_khz / 1000;
    297
    298	DRM_DEBUG_DRIVER("pll_in %ukHz pll_out %ukHz lane_mbps %uMHz\n",
    299			 pll_in_khz, pll_out_khz, *lane_mbps);
    300
    301	return 0;
    302}
    303
    304#define DSI_PHY_DELAY(fp, vp, mbps) DIV_ROUND_UP((fp) * (mbps) + 1000 * (vp), 8000)
    305
    306static int
    307dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps,
    308			   struct dw_mipi_dsi_dphy_timing *timing)
    309{
    310	/*
    311	 * From STM32MP157 datasheet, valid for STM32F469, STM32F7x9, STM32H747
    312	 * phy_clkhs2lp_time = (272+136*UI)/(8*UI)
    313	 * phy_clklp2hs_time = (512+40*UI)/(8*UI)
    314	 * phy_hs2lp_time = (192+64*UI)/(8*UI)
    315	 * phy_lp2hs_time = (256+32*UI)/(8*UI)
    316	 */
    317	timing->clk_hs2lp = DSI_PHY_DELAY(272, 136, lane_mbps);
    318	timing->clk_lp2hs = DSI_PHY_DELAY(512, 40, lane_mbps);
    319	timing->data_hs2lp = DSI_PHY_DELAY(192, 64, lane_mbps);
    320	timing->data_lp2hs = DSI_PHY_DELAY(256, 32, lane_mbps);
    321
    322	return 0;
    323}
    324
    325#define CLK_TOLERANCE_HZ 50
    326
    327static enum drm_mode_status
    328dw_mipi_dsi_stm_mode_valid(void *priv_data,
    329			   const struct drm_display_mode *mode,
    330			   unsigned long mode_flags, u32 lanes, u32 format)
    331{
    332	struct dw_mipi_dsi_stm *dsi = priv_data;
    333	unsigned int idf, ndiv, odf, pll_in_khz, pll_out_khz;
    334	int ret, bpp;
    335
    336	bpp = mipi_dsi_pixel_format_to_bpp(format);
    337	if (bpp < 0)
    338		return MODE_BAD;
    339
    340	/* Compute requested pll out */
    341	pll_out_khz = mode->clock * bpp / lanes;
    342
    343	if (pll_out_khz > dsi->lane_max_kbps)
    344		return MODE_CLOCK_HIGH;
    345
    346	if (mode_flags & MIPI_DSI_MODE_VIDEO_BURST) {
    347		/* Add 20% to pll out to be higher than pixel bw */
    348		pll_out_khz = (pll_out_khz * 12) / 10;
    349	} else {
    350		if (pll_out_khz < dsi->lane_min_kbps)
    351			return MODE_CLOCK_LOW;
    352	}
    353
    354	/* Compute best pll parameters */
    355	idf = 0;
    356	ndiv = 0;
    357	odf = 0;
    358	pll_in_khz = clk_get_rate(dsi->pllref_clk) / 1000;
    359	ret = dsi_pll_get_params(dsi, pll_in_khz, pll_out_khz, &idf, &ndiv, &odf);
    360	if (ret) {
    361		DRM_WARN("Warning dsi_pll_get_params(): bad params\n");
    362		return MODE_ERROR;
    363	}
    364
    365	if (!(mode_flags & MIPI_DSI_MODE_VIDEO_BURST)) {
    366		unsigned int px_clock_hz, target_px_clock_hz, lane_mbps;
    367		int dsi_short_packet_size_px, hfp, hsync, hbp, delay_to_lp;
    368		struct dw_mipi_dsi_dphy_timing dphy_timing;
    369
    370		/* Get the adjusted pll out value */
    371		pll_out_khz = dsi_pll_get_clkout_khz(pll_in_khz, idf, ndiv, odf);
    372
    373		px_clock_hz = DIV_ROUND_CLOSEST_ULL(1000ULL * pll_out_khz * lanes, bpp);
    374		target_px_clock_hz = mode->clock * 1000;
    375		/*
    376		 * Filter modes according to the clock value, particularly useful for
    377		 * hdmi modes that require precise pixel clocks.
    378		 */
    379		if (px_clock_hz < target_px_clock_hz - CLK_TOLERANCE_HZ ||
    380		    px_clock_hz > target_px_clock_hz + CLK_TOLERANCE_HZ)
    381			return MODE_CLOCK_RANGE;
    382
    383		/* sync packets are codes as DSI short packets (4 bytes) */
    384		dsi_short_packet_size_px = DIV_ROUND_UP(4 * BITS_PER_BYTE, bpp);
    385
    386		hfp = mode->hsync_start - mode->hdisplay;
    387		hsync = mode->hsync_end - mode->hsync_start;
    388		hbp = mode->htotal - mode->hsync_end;
    389
    390		/* hsync must be longer than 4 bytes HSS packets */
    391		if (hsync < dsi_short_packet_size_px)
    392			return MODE_HSYNC_NARROW;
    393
    394		if (mode_flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
    395			/* HBP must be longer than 4 bytes HSE packets */
    396			if (hbp < dsi_short_packet_size_px)
    397				return MODE_HSYNC_NARROW;
    398			hbp -= dsi_short_packet_size_px;
    399		} else {
    400			/* With sync events HBP extends in the hsync */
    401			hbp += hsync - dsi_short_packet_size_px;
    402		}
    403
    404		lane_mbps = pll_out_khz / 1000;
    405		ret = dw_mipi_dsi_phy_get_timing(priv_data, lane_mbps, &dphy_timing);
    406		if (ret)
    407			return MODE_ERROR;
    408		/*
    409		 * In non-burst mode DSI has to enter in LP during HFP
    410		 * (horizontal front porch) or HBP (horizontal back porch) to
    411		 * resync with LTDC pixel clock.
    412		 */
    413		delay_to_lp = DIV_ROUND_UP((dphy_timing.data_hs2lp + dphy_timing.data_lp2hs) *
    414					   lanes * BITS_PER_BYTE, bpp);
    415		if (hfp < delay_to_lp && hbp < delay_to_lp)
    416			return MODE_HSYNC;
    417	}
    418
    419	return MODE_OK;
    420}
    421
    422static const struct dw_mipi_dsi_phy_ops dw_mipi_dsi_stm_phy_ops = {
    423	.init = dw_mipi_dsi_phy_init,
    424	.power_on = dw_mipi_dsi_phy_power_on,
    425	.power_off = dw_mipi_dsi_phy_power_off,
    426	.get_lane_mbps = dw_mipi_dsi_get_lane_mbps,
    427	.get_timing = dw_mipi_dsi_phy_get_timing,
    428};
    429
    430static struct dw_mipi_dsi_plat_data dw_mipi_dsi_stm_plat_data = {
    431	.max_data_lanes = 2,
    432	.mode_valid = dw_mipi_dsi_stm_mode_valid,
    433	.phy_ops = &dw_mipi_dsi_stm_phy_ops,
    434};
    435
    436static const struct of_device_id dw_mipi_dsi_stm_dt_ids[] = {
    437	{ .compatible = "st,stm32-dsi", .data = &dw_mipi_dsi_stm_plat_data, },
    438	{ },
    439};
    440MODULE_DEVICE_TABLE(of, dw_mipi_dsi_stm_dt_ids);
    441
    442static int dw_mipi_dsi_stm_probe(struct platform_device *pdev)
    443{
    444	struct device *dev = &pdev->dev;
    445	struct dw_mipi_dsi_stm *dsi;
    446	struct clk *pclk;
    447	struct resource *res;
    448	int ret;
    449
    450	dsi = devm_kzalloc(dev, sizeof(*dsi), GFP_KERNEL);
    451	if (!dsi)
    452		return -ENOMEM;
    453
    454	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
    455	dsi->base = devm_ioremap_resource(dev, res);
    456	if (IS_ERR(dsi->base)) {
    457		ret = PTR_ERR(dsi->base);
    458		DRM_ERROR("Unable to get dsi registers %d\n", ret);
    459		return ret;
    460	}
    461
    462	dsi->vdd_supply = devm_regulator_get(dev, "phy-dsi");
    463	if (IS_ERR(dsi->vdd_supply)) {
    464		ret = PTR_ERR(dsi->vdd_supply);
    465		dev_err_probe(dev, ret, "Failed to request regulator\n");
    466		return ret;
    467	}
    468
    469	ret = regulator_enable(dsi->vdd_supply);
    470	if (ret) {
    471		DRM_ERROR("Failed to enable regulator: %d\n", ret);
    472		return ret;
    473	}
    474
    475	dsi->pllref_clk = devm_clk_get(dev, "ref");
    476	if (IS_ERR(dsi->pllref_clk)) {
    477		ret = PTR_ERR(dsi->pllref_clk);
    478		dev_err_probe(dev, ret, "Unable to get pll reference clock\n");
    479		goto err_clk_get;
    480	}
    481
    482	ret = clk_prepare_enable(dsi->pllref_clk);
    483	if (ret) {
    484		DRM_ERROR("Failed to enable pllref_clk: %d\n", ret);
    485		goto err_clk_get;
    486	}
    487
    488	pclk = devm_clk_get(dev, "pclk");
    489	if (IS_ERR(pclk)) {
    490		ret = PTR_ERR(pclk);
    491		DRM_ERROR("Unable to get peripheral clock: %d\n", ret);
    492		goto err_dsi_probe;
    493	}
    494
    495	ret = clk_prepare_enable(pclk);
    496	if (ret) {
    497		DRM_ERROR("%s: Failed to enable peripheral clk\n", __func__);
    498		goto err_dsi_probe;
    499	}
    500
    501	dsi->hw_version = dsi_read(dsi, DSI_VERSION) & VERSION;
    502	clk_disable_unprepare(pclk);
    503
    504	if (dsi->hw_version != HWVER_130 && dsi->hw_version != HWVER_131) {
    505		ret = -ENODEV;
    506		DRM_ERROR("bad dsi hardware version\n");
    507		goto err_dsi_probe;
    508	}
    509
    510	/* set lane capabilities according to hw version */
    511	dsi->lane_min_kbps = LANE_MIN_KBPS;
    512	dsi->lane_max_kbps = LANE_MAX_KBPS;
    513	if (dsi->hw_version == HWVER_131) {
    514		dsi->lane_min_kbps *= 2;
    515		dsi->lane_max_kbps *= 2;
    516	}
    517
    518	dw_mipi_dsi_stm_plat_data.base = dsi->base;
    519	dw_mipi_dsi_stm_plat_data.priv_data = dsi;
    520
    521	platform_set_drvdata(pdev, dsi);
    522
    523	dsi->dsi = dw_mipi_dsi_probe(pdev, &dw_mipi_dsi_stm_plat_data);
    524	if (IS_ERR(dsi->dsi)) {
    525		ret = PTR_ERR(dsi->dsi);
    526		dev_err_probe(dev, ret, "Failed to initialize mipi dsi host\n");
    527		goto err_dsi_probe;
    528	}
    529
    530	return 0;
    531
    532err_dsi_probe:
    533	clk_disable_unprepare(dsi->pllref_clk);
    534err_clk_get:
    535	regulator_disable(dsi->vdd_supply);
    536
    537	return ret;
    538}
    539
    540static int dw_mipi_dsi_stm_remove(struct platform_device *pdev)
    541{
    542	struct dw_mipi_dsi_stm *dsi = platform_get_drvdata(pdev);
    543
    544	dw_mipi_dsi_remove(dsi->dsi);
    545	clk_disable_unprepare(dsi->pllref_clk);
    546	regulator_disable(dsi->vdd_supply);
    547
    548	return 0;
    549}
    550
    551static int __maybe_unused dw_mipi_dsi_stm_suspend(struct device *dev)
    552{
    553	struct dw_mipi_dsi_stm *dsi = dw_mipi_dsi_stm_plat_data.priv_data;
    554
    555	DRM_DEBUG_DRIVER("\n");
    556
    557	clk_disable_unprepare(dsi->pllref_clk);
    558	regulator_disable(dsi->vdd_supply);
    559
    560	return 0;
    561}
    562
    563static int __maybe_unused dw_mipi_dsi_stm_resume(struct device *dev)
    564{
    565	struct dw_mipi_dsi_stm *dsi = dw_mipi_dsi_stm_plat_data.priv_data;
    566	int ret;
    567
    568	DRM_DEBUG_DRIVER("\n");
    569
    570	ret = regulator_enable(dsi->vdd_supply);
    571	if (ret) {
    572		DRM_ERROR("Failed to enable regulator: %d\n", ret);
    573		return ret;
    574	}
    575
    576	ret = clk_prepare_enable(dsi->pllref_clk);
    577	if (ret) {
    578		regulator_disable(dsi->vdd_supply);
    579		DRM_ERROR("Failed to enable pllref_clk: %d\n", ret);
    580		return ret;
    581	}
    582
    583	return 0;
    584}
    585
    586static const struct dev_pm_ops dw_mipi_dsi_stm_pm_ops = {
    587	SET_SYSTEM_SLEEP_PM_OPS(dw_mipi_dsi_stm_suspend,
    588				dw_mipi_dsi_stm_resume)
    589};
    590
    591static struct platform_driver dw_mipi_dsi_stm_driver = {
    592	.probe		= dw_mipi_dsi_stm_probe,
    593	.remove		= dw_mipi_dsi_stm_remove,
    594	.driver		= {
    595		.of_match_table = dw_mipi_dsi_stm_dt_ids,
    596		.name	= "stm32-display-dsi",
    597		.pm = &dw_mipi_dsi_stm_pm_ops,
    598	},
    599};
    600
    601module_platform_driver(dw_mipi_dsi_stm_driver);
    602
    603MODULE_AUTHOR("Philippe Cornu <philippe.cornu@st.com>");
    604MODULE_AUTHOR("Yannick Fertre <yannick.fertre@st.com>");
    605MODULE_DESCRIPTION("STMicroelectronics DW MIPI DSI host controller driver");
    606MODULE_LICENSE("GPL v2");