[RFC PATCH V3 1/4] media: platform: mtk-isp: Add Mediatek sensor interface driver

CK Hu ck.hu at mediatek.com
Sun Jun 16 23:34:10 PDT 2019


Hi, Louis:

On Thu, 2019-06-06 at 18:00 +0800, Louis Kuo wrote:
> This patch adds Mediat:ek's sensor interface driver. Sensor interface
> driver
> is a MIPI-CSI2 host driver, namely, a HW camera interface controller.
> It support a widely adopted, simple, high-speed protocol primarily
> intended
> for point-to-point image and video transmission between cameras and host
> devices.
> 
> The mtk-isp directory will contain drivers for multiple IP blocks found in
> Mediatek ISP system. It will include ISP Pass 1 driver, sensor interface
> driver, DIP driver and face detection driver.
> 
> Signed-off-by: Louis Kuo <louis.kuo at mediatek.com>
> ---
>  drivers/media/platform/Makefile                    |    2 +
>  drivers/media/platform/mtk-isp/Makefile            |    3 +
>  drivers/media/platform/mtk-isp/isp_50/Makefile     |    5 +
>  .../media/platform/mtk-isp/isp_50/seninf/Makefile  |    6 +
>  .../platform/mtk-isp/isp_50/seninf/mtk_seninf.c    | 1330 ++++++++++++++++++++
>  .../mtk-isp/isp_50/seninf/mtk_seninf_def.h         |  155 +++
>  .../mtk-isp/isp_50/seninf/mtk_seninf_reg.h         |  965 ++++++++++++++
>  7 files changed, 2466 insertions(+)
>  create mode 100644 drivers/media/platform/mtk-isp/Makefile
>  create mode 100644 drivers/media/platform/mtk-isp/isp_50/Makefile
>  create mode 100644 drivers/media/platform/mtk-isp/isp_50/seninf/Makefile
>  create mode 100644 drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf.c
>  create mode 100644 drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf_def.h
>  create mode 100644 drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf_reg.h
> 
> diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
> index 7cbbd92..b0f4543 100644
> --- a/drivers/media/platform/Makefile
> +++ b/drivers/media/platform/Makefile
> @@ -73,6 +73,8 @@ obj-$(CONFIG_VIDEO_ROCKCHIP_RGA)	+= rockchip/rga/
>  
>  obj-y	+= omap/
>  
> +obj-y	+= mtk-isp/
> +
>  obj-$(CONFIG_VIDEO_AM437X_VPFE)		+= am437x/
>  
>  obj-$(CONFIG_VIDEO_XILINX)		+= xilinx/
> diff --git a/drivers/media/platform/mtk-isp/Makefile b/drivers/media/platform/mtk-isp/Makefile
> new file mode 100644
> index 0000000..c17fb3f
> --- /dev/null
> +++ b/drivers/media/platform/mtk-isp/Makefile
> @@ -0,0 +1,3 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +obj-y += isp_50/
> diff --git a/drivers/media/platform/mtk-isp/isp_50/Makefile b/drivers/media/platform/mtk-isp/isp_50/Makefile
> new file mode 100644
> index 0000000..8b4a792
> --- /dev/null
> +++ b/drivers/media/platform/mtk-isp/isp_50/Makefile
> @@ -0,0 +1,5 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +ifeq ($(CONFIG_MTK_SENINF),y)
> +obj-y += seninf/
> +endif
> diff --git a/drivers/media/platform/mtk-isp/isp_50/seninf/Makefile b/drivers/media/platform/mtk-isp/isp_50/seninf/Makefile
> new file mode 100644
> index 0000000..bf193fe
> --- /dev/null
> +++ b/drivers/media/platform/mtk-isp/isp_50/seninf/Makefile
> @@ -0,0 +1,6 @@
> +# SPDX-License-Identifier: GPL-2.0
> +
> +MODULE		= mtk_seninf
> +LIB_FILES	= mtk_seninf
> +
> +obj-$(CONFIG_MTK_SENINF) += mtk_seninf.o
> diff --git a/drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf.c b/drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf.c
> new file mode 100644
> index 0000000..e791110
> --- /dev/null
> +++ b/drivers/media/platform/mtk-isp/isp_50/seninf/mtk_seninf.c
> @@ -0,0 +1,1330 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/clk.h>
> +#include <linux/interrupt.h>
> +#include <linux/of_graph.h>
> +#include <linux/of_irq.h>
> +#ifdef CONFIG_COMPAT
> +#include <linux/compat.h>
> +#endif
> +#include <linux/videodev2.h>
> +#include <media/v4l2-subdev.h>
> +#include <media/v4l2-fwnode.h>
> +#include <media/v4l2-ctrls.h>
> +#include <media/v4l2-event.h>
> +#include <media/v4l2-async.h>
> +#include "mtk_seninf_reg.h"
> +#include "mtk_seninf_def.h"
> +
> +#define SUBDEV_SENSOR_MAIN_NAME		"sensor_main"
> +#define SUBDEV_SENSOR_SUB_NAME		"sensor_sub"
> +#define MTK_CAM_SENINF_PAD_MAIN_SINK		0
> +#define MTK_CAM_SENINF_PAD_SUB_SINK		1
> +#define MIPI_SENSOR_TYPE MIPI_OPHY_NCSI2
> +
> +static inline void mt_reg_sync_writel(unsigned int v, void *a)
> +{
> +	__raw_writel((v), (void __force __iomem *)((a)));
> +}
> +
> +static inline unsigned int seninf_read_reg
> +	(void *reg_base, unsigned int reg_name)
> +{
> +	return (unsigned int)ioread32(reg_base + reg_name);
> +}
> +
> +static inline void seninf_write_reg
> +	(void *reg_base, unsigned int reg_name,
> +	unsigned int value)
> +{
> +	mt_reg_sync_writel(value, reg_base + reg_name);
> +}
> +
> +static inline void write_master
> +	(void *reg_base, unsigned int reg_name,
> +	unsigned int value, unsigned int mask)
> +{
> +	mt_reg_sync_writel((ioread32(reg_base + reg_name) & ~(mask)) |
> +		value, reg_base + reg_name);
> +}
> +
> +static inline int is_4d1c(unsigned int port)
> +{
> +	return (port < CFG_CSI_PORT_0A);
> +}
> +
> +static inline int is_cdphy_combo(unsigned int port)
> +{
> +	return (port == CFG_CSI_PORT_0A ||
> +		port == CFG_CSI_PORT_0B ||
> +		port == CFG_CSI_PORT_0);
> +}
> +
> +static struct seninf_csi_info SENINF_CSI_INFO[CFG_CSI_PORT_MAX_NUM] = {

Lower case for variable name.

> +	{CFG_CSI_PORT_0,  SENINF_1},
> +	{CFG_CSI_PORT_1,  SENINF_3},
> +	{CFG_CSI_PORT_2,  SENINF_5},
> +	{CFG_CSI_PORT_0A, SENINF_1},
> +	{CFG_CSI_PORT_0B, SENINF_2},
> +};
> +
> +struct _seninf {
> +	struct v4l2_subdev subdev;
> +	struct v4l2_async_notifier notifier;
> +	struct device *dev;
> +	struct v4l2_fwnode_endpoint ep[NUM_PORTS];
> +	struct v4l2_ctrl_handler ctrl_handler;
> +	struct media_pad pads[NUM_PADS];
> +	struct clk *cam_clk, *top_mux_clk;
> +	unsigned int port;
> +	struct v4l2_subdev_format fmt;
> +	unsigned int mux_select;
> +	void __iomem *base_reg;
> +	void __iomem *rx_reg;
> +	unsigned char *csi2_rx[CFG_CSI_PORT_MAX_NUM];
> +};
> +
> +static int set_top_mux_ctrl(struct _seninf *priv,
> +			    unsigned int mux_idx,
> +			    unsigned int seninf_src)
> +{
> +	void *pseninf = priv->base_reg;
> +
> +	seninf_write_reg(pseninf, SENINF_TOP_MUX_CTRL,
> +			 ((seninf_read_reg(pseninf, SENINF_TOP_MUX_CTRL) &
> +			 (~(0xF << (mux_idx * 4)))) | ((seninf_src & 0xF)
> +			 << (mux_idx * 4))));
> +
> +	return 0;
> +}
> +
> +static void set_mux_ctrl
> +	(struct _seninf *priv, unsigned int mux,

Merge to one line.

> +	unsigned int input_data_type)
> +{
> +	void *pseninf = priv->base_reg + 0x1000 * mux;
> +	unsigned int temp;
> +	unsigned int pix_sel_ext;
> +	unsigned int pix_sel;
> +	unsigned int hs_pol = 0;
> +	unsigned int vs_pol = 0;
> +	unsigned int pixel_mode = ONE_PIXEL_MODE;
> +	unsigned int src_type_sel = MIPI_SENSOR;
> +
> +	write_master(pseninf, SENINF1_MUX_CTRL,
> +		     (src_type_sel << 12), 0x0000F000);
> +	temp = (src_type_sel == TEST_MODEL) ? 0 : 1;
> +	write_master(pseninf, SENINF1_MUX_CTRL_EXT,
> +		     (temp << 0), 0x00000003);
> +
> +	switch (pixel_mode) {
> +	case 1: /* 2 Pixel */
> +		pix_sel_ext = 0;
> +		pix_sel = 1 << 8;
> +		break;
> +	case 2: /* 4 Pixel */
> +		pix_sel_ext = 1 << 4;
> +		pix_sel = 0;
> +		break;
> +	default: /* 1 Pixel */
> +		pix_sel_ext = 0;
> +		pix_sel = 0;
> +		break;
> +	}
> +
> +	write_master(pseninf, SENINF1_MUX_CTRL_EXT, pix_sel_ext, 0x00000010);
> +	write_master(pseninf, SENINF1_MUX_CTRL, pix_sel, 0x00000100);
> +
> +	if (input_data_type != JPEG_FMT)
> +		write_master(pseninf, SENINF1_MUX_CTRL,
> +			     (2 << 28), 0x30000000);
> +	else
> +		write_master(pseninf, SENINF1_MUX_CTRL, 0, 0x30000000);
> +
> +	if (src_type_sel == CSI2 || src_type_sel >= MIPI_SENSOR) {
> +		/* Need to use Default for New design */
> +		if (input_data_type != JPEG_FMT)
> +			write_master(pseninf, SENINF1_MUX_CTRL,
> +				     ((0x1B << 22) | (0x1F << 16)),
> +				     0x0FFF0000);
> +		else
> +			write_master(pseninf, SENINF1_MUX_CTRL,
> +				     ((0x18 << 22) | (0x1E << 16)),
> +				     0x0FFF0000);
> +	}
> +
> +	write_master(pseninf, SENINF1_MUX_CTRL,
> +		     ((hs_pol << 10) | (vs_pol << 9)), 0x00000600);
> +
> +	temp = seninf_read_reg(pseninf, SENINF1_MUX_CTRL);
> +	seninf_write_reg(pseninf, SENINF1_MUX_CTRL, temp | 0x3);
> +	seninf_write_reg(pseninf, SENINF1_MUX_CTRL, temp & 0xFFFFFFFC);
> +}
> +
> +static void enable_mux(struct _seninf *priv, unsigned int mux)
> +{
> +	void *pseninf = priv->base_reg + 0x1000 * mux;
> +
> +	write_master(pseninf, SENINF1_MUX_CTRL, (1 << 31), 0x80000000);
> +}
> +
> +static struct seninf_csi_info *get_csi_info(struct _seninf *priv,
> +					    unsigned int mipi_port)
> +{
> +	int i;
> +
> +	for (i = 0; i < CFG_CSI_PORT_MAX_NUM; i++) {
> +		if (SENINF_CSI_INFO[i].port == mipi_port)
> +			return &SENINF_CSI_INFO[i];
> +	}
> +
> +	return NULL;
> +}
> +
> +static void set_dphy
> +	(struct _seninf *priv,
> +	struct seninf_csi_mipi *pcsi_mipi)
> +{
> +	struct seninf_csi_info *csi_info = pcsi_mipi->csi_info;
> +	void *pmipi_rx_base = priv->csi2_rx[CFG_CSI_PORT_0];
> +	void *pmipi_rx = priv->csi2_rx[csi_info->port];
> +	void *pmipi_rx_conf = priv->base_reg + 0x1000 * csi_info->seninf;
> +
> +	/* Set analog phy mode to DPHY */
> +	if (is_cdphy_combo(csi_info->port))
> +		write_master(pmipi_rx, MIPI_RX_ANA00_CSI0A, 0, 0x00000001);
> +	/* 4D1C: MIPIRX_ANALOG_A_BASE = 0x00001A42 */
> +	if (is_4d1c(csi_info->port))
> +		write_master(pmipi_rx, MIPI_RX_ANA00_CSI0A,
> +			     (1 << 6) | (1 << 9) | (1 << 11) | (1 << 12),
> +			     0x00001B60);
> +	else /* MIPIRX_ANALOG_BASE = 0x102 */
> +		write_master(pmipi_rx, MIPI_RX_ANA00_CSI0A,
> +			     (1 << 8), 0x00001B60);
> +
> +	if (is_cdphy_combo(csi_info->port))
> +		write_master(pmipi_rx, MIPI_RX_ANA00_CSI0B, 0, 0x00000001);
> +
> +	/* Only 4d1c need set CSIB: MIPIRX_ANALOG_B_BASE = 0x00001242 */
> +	if (is_4d1c(csi_info->port))
> +		write_master(pmipi_rx, MIPI_RX_ANA00_CSI0B,
> +			     (1 << 6) | (1 << 9) | (1 << 12), 0x00001B60);
> +	else /* MIPIRX_ANALOG_BASE = 0x102 */
> +		write_master(pmipi_rx, MIPI_RX_ANA00_CSI0B,
> +			     (1 << 8) | (1 << 9), 0x00001B40);
> +
> +	/* Byte clock invert */
> +	write_master(pmipi_rx, MIPI_RX_ANAA8_CSI0A,
> +		     (1 << 0) | (1 << 1) | (1 << 2), 0x00000007);
> +	if (is_4d1c(csi_info->port))
> +		write_master(pmipi_rx, MIPI_RX_ANAA8_CSI0B,
> +			     (1 << 0) | (1 << 1) | (1 << 2),
> +			     0x00000007);
> +
> +	/* Start ANA EQ tuning */
> +	if (is_cdphy_combo(csi_info->port)) {
> +		write_master(pmipi_rx, MIPI_RX_ANA18_CSI0A,
> +			     (1 << 4) | (1 << 6), 0x000000F0);
> +		write_master(pmipi_rx, MIPI_RX_ANA1C_CSI0A,
> +			     (1 << 20) | (1 << 22), 0x00F00000);
> +		write_master(pmipi_rx, MIPI_RX_ANA20_CSI0A,
> +			     (1 << 20) | (1 << 22), 0x00F00000);
> +
> +		if (is_4d1c(csi_info->port)) { /* 4d1c */
> +			write_master(pmipi_rx, MIPI_RX_ANA18_CSI0B,
> +				     (1 << 4) | (1 << 6), 0x000000F0);
> +			write_master(pmipi_rx, MIPI_RX_ANA1C_CSI0B,
> +				     (1 << 20) | (1 << 22),
> +				     0x00F00000);
> +			write_master(pmipi_rx, MIPI_RX_ANA20_CSI0B,
> +				     (1 << 20) | (1 << 22),
> +				     0x00F00000);
> +		}
> +	} else {
> +		write_master(pmipi_rx, MIPI_RX_ANA18_CSI1A,
> +			     (1 << 4) | (1 << 6) | (1 << 20) |
> +			     (1 << 22), 0x00F000F0);
> +		write_master(pmipi_rx, MIPI_RX_ANA1C_CSI1A,
> +			     (1 << 4) | (1 << 6), 0x000000F0);
> +
> +		if (is_4d1c(csi_info->port)) { /* 4d1c */
> +			write_master(pmipi_rx,
> +				     MIPI_RX_ANA18_CSI1B, (1 << 4) |
> +				     (1 << 6) | (1 << 20) |
> +				     (1 << 22), 0x00F000F0);
> +			write_master(pmipi_rx,
> +				     MIPI_RX_ANA1C_CSI1B, (1 << 4) |
> +				     (1 << 6), 0x000000F0);
> +		}
> +	}
> +
> +	/* End ANA EQ tuning */
> +	seninf_write_reg(pmipi_rx_base, MIPI_RX_ANA40_CSI0A, 0x90);
> +	write_master(pmipi_rx, MIPI_RX_ANA24_CSI0A,
> +		     (0x40 << 24), 0xFF000000);
> +	if (is_4d1c(csi_info->port))
> +		write_master(pmipi_rx, MIPI_RX_ANA24_CSI0B,
> +			     (0x40 << 24), 0xFF000000);
> +	write_master(pmipi_rx, MIPI_RX_WRAPPER80_CSI0A, 0, 0x00030000);
> +	if (is_4d1c(csi_info->port))
> +		write_master(pmipi_rx, MIPI_RX_WRAPPER80_CSI0B, 0, 0x00030000);
> +	/* ANA power on */
> +	write_master(pmipi_rx, MIPI_RX_ANA00_CSI0A,
> +		     (1 << 3), 0x00000008);
> +	if (is_4d1c(csi_info->port))
> +		write_master(pmipi_rx, MIPI_RX_ANA00_CSI0B,
> +			     (1 << 3), 0x00000008);
> +	usleep_range(20, 40);
> +	write_master(pmipi_rx, MIPI_RX_ANA00_CSI0A,
> +		     (1 << 3), 0x00000008);
> +	if (is_4d1c(csi_info->port))
> +		write_master(pmipi_rx, MIPI_RX_ANA00_CSI0B,
> +			     (1 << 2), 0x00000004);
> +	udelay(1);
> +	/* 4d1c: MIPIRX_CONFIG_CSI_BASE = 0xC9000000; */
> +	if (is_4d1c(csi_info->port)) {
> +		write_master(pmipi_rx_conf, MIPI_RX_CON24_CSI0,
> +			     (1 << 24) | (2 << 26) | (3 << 30), 0xFF000000);
> +	} else { /* 2d1c: MIPIRX_CONFIG_CSI_BASE = 0xE4000000; */
> +		write_master(pmipi_rx_conf, MIPI_RX_CON24_CSI0,
> +			     (1 << 26) | (2 << 28) | (3 << 30), 0xFF000000);
> +	}
> +	pr_debug("pcsi_mipi->CSI2_IP %d, MIPI_RX_CON24_CSI0 0x%x\n",
> +		 csi_info->port,
> +		 seninf_read_reg(pmipi_rx_conf, MIPI_RX_CON24_CSI0));
> +	usleep_range(20, 40);
> +	/* D-PHY SW Delay Line calibration */
> +}
> +
> +static void set_cphy
> +	(struct _seninf *priv,
> +	struct seninf_csi_mipi *pcsi_mipi)
> +{ /* Cphy setting for CSI0 */
> +	struct seninf_csi_info *csi_info = pcsi_mipi->csi_info;
> +	void *pmipi_rx = priv->csi2_rx[csi_info->port];
> +	int status;
> +	int i;
> +
> +	/* Byte clock invert */
> +	write_master(pmipi_rx, MIPI_RX_ANAA8_CSI0A,
> +		     (1 << 0) | (1 << 2), 0x00000005);
> +	write_master(pmipi_rx, MIPI_RX_ANAA8_CSI0B,
> +		     (1 << 0) | (1 << 2), 0x00000005);
> +	/* EQ Power to Enhance Speed */
> +	write_master(pmipi_rx, MIPI_RX_ANA18_CSI0A,
> +		     (1 << 6) | (1 << 22), 0x00C000C0);
> +	write_master(pmipi_rx, MIPI_RX_ANA1C_CSI0A,
> +		     (1 << 6) | (1 << 22), 0x00C000C0);
> +	write_master(pmipi_rx, MIPI_RX_ANA20_CSI0A,
> +		     (1 << 6) | (1 << 22), 0x00C000C0);
> +	write_master(pmipi_rx, MIPI_RX_ANA18_CSI0B,
> +		     (1 << 6) | (1 << 22), 0x00C000C0);
> +	write_master(pmipi_rx, MIPI_RX_ANA1C_CSI0B,
> +		     (1 << 6) | (1 << 22), 0x00C000C0);
> +	write_master(pmipi_rx, MIPI_RX_ANA20_CSI0B,
> +		     (1 << 6) | (1 << 22), 0x00C000C0);
> +
> +	/* CDR register setting */
> +
> +	*((int *)(priv->csi2_rx[csi_info->port] + 0x30)) = 0x06040404;
> +	*((int *)(priv->csi2_rx[csi_info->port] + 0x3c)) = 0x06040404;
> +	*((int *)(priv->csi2_rx[csi_info->port] + 0x34)) = 0x1;
> +	*((int *)(priv->csi2_rx[csi_info->port] + 0x28)) = 0x1;
> +
> +	*((int *)(priv->csi2_rx[csi_info->port] + 0x1030)) =
> +		0x06040404;
> +	*((int *)(priv->csi2_rx[csi_info->port] + 0x103c)) =
> +		0x06040404;
> +	*((int *)(priv->csi2_rx[csi_info->port] + 0x1034)) = 0x1;
> +	*((int *)(priv->csi2_rx[csi_info->port] + 0x1028)) = 0x1;

Use write_master()?

> +
> +	write_master(pmipi_rx, MIPI_RX_ANA00_CSI0A,
> +		     (1 << 0), 0x00001B61);
> +	write_master(pmipi_rx, MIPI_RX_ANA00_CSI0B,
> +		     (1 << 0), 0x00001B61);
> +	/* Power on DPHY */
> +	write_master(pmipi_rx, MIPI_RX_ANA00_CSI0A,
> +		     (1 << 3), 0x00000008);
> +	write_master(pmipi_rx, MIPI_RX_ANA00_CSI0B,
> +		     (1 << 3), 0x00000008);
> +	usleep_range(20, 40);
> +	/* Enable LPF */
> +	write_master(pmipi_rx, MIPI_RX_ANA00_CSI0A,
> +		     (1 << 2), 0x00000004);
> +	write_master(pmipi_rx, MIPI_RX_ANA00_CSI0B,
> +		     (1 << 2), 0x00000004);
> +	udelay(1);
> +	/* Offset calibration */
> +	write_master(pmipi_rx, MIPI_RX_ANA18_CSI0A,
> +		     (1 << 0) | (1 << 16), 0x00010001);
> +	write_master(pmipi_rx, MIPI_RX_ANA1C_CSI0A,
> +		     (1 << 0) | (1 << 16), 0x00010001);
> +	write_master(pmipi_rx, MIPI_RX_ANA20_CSI0A,
> +		     (1 << 0) | (1 << 16), 0x00010001);
> +	write_master(pmipi_rx, MIPI_RX_ANA18_CSI0B,
> +		     (1 << 0) | (1 << 16), 0x00010001);
> +	write_master(pmipi_rx, MIPI_RX_ANA1C_CSI0B,
> +		     (1 << 0) | (1 << 16), 0x00010001);
> +	write_master(pmipi_rx, MIPI_RX_ANA20_CSI0B,
> +		     (1 << 0) | (1 << 16), 0x00010001);
> +	udelay(1);
> +
> +	i = 0;
> +	while (1) {
> +		status = seninf_read_reg(pmipi_rx,
> +					 MIPI_RX_ANA48_CSI0A);
> +		if ((status & 0x3f) == 0x3f)
> +			break;
> +		i++;
> +		if (i > 100) {
> +			pr_debug("CSIA offset calibration timeout\n");
> +			break;
> +		}
> +		usleep_range(20, 40);
> +	}

Use readl_poll_timeout_atomic()?

> +
> +	i = 0;
> +	while (1) {
> +		status = seninf_read_reg(pmipi_rx,
> +					 MIPI_RX_ANA48_CSI0B);
> +		if ((status & 0x3f) == 0x3f)
> +			break;
> +		i++;
> +		if (i > 100) {
> +			pr_debug("CSIB offset calibration timeout\n");
> +			break;
> +		}
> +		usleep_range(20, 40);
> +	}

Ditto.

> +}
> +
> +static void set_csi_mipi
> +	(struct _seninf *priv,
> +	struct seninf_csi_mipi *pcsi_mipi)
> +{
> +	struct seninf_csi_info *csi_info = pcsi_mipi->csi_info;
> +	void *seninf_base = priv->base_reg;
> +	void *pseninf = priv->base_reg + 0x1000 * csi_info->seninf;
> +	void *pmipi_rx = priv->csi2_rx[csi_info->port];
> +	unsigned int cal_sel;
> +	unsigned int mipi_enable = 1;
> +	unsigned int data_header_order = 1;
> +	unsigned int pad_sel = PAD_10BIT;
> +	unsigned int csi_type = (MIPI_SENSOR_TYPE == MIPI_CPHY)
> +		? CSI2_2_5G_CPHY : CSI2_2_5G;

In this patch,

#define MIPI_SENSOR_TYPE MIPI_OPHY_NCSI2

So I think you need not to consider CSI2_2_5G_CPHY case in this patch. You should move the CSI2_2_5G_CPHY related code to another patch.

> +
> +	pr_debug("IS_4D1C %d csi_type %d port %d\n",
> +		 is_4d1c(csi_info->port), csi_type, csi_info->port);
> +
> +	switch (csi_info->port) {
> +	case CFG_CSI_PORT_1:
> +		cal_sel = 1;
> +		write_master(seninf_base, SENINF_TOP_PHY_SENINF_CTL_CSI1,
> +			     ((2 << 8) | (mipi_enable << 31)), 0x80000701);
> +		break;
> +	case CFG_CSI_PORT_2:
> +		cal_sel = 2;
> +		write_master(seninf_base, SENINF_TOP_PHY_SENINF_CTL_CSI2,
> +			     ((2 << 8) | (mipi_enable << 31)), 0x80000701);
> +		break;
> +	case CFG_CSI_PORT_0:
> +		cal_sel = 0;
> +		write_master(seninf_base, SENINF_TOP_PHY_SENINF_CTL_CSI0,
> +			     ((2 << 8) |
> +			     (mipi_enable << 31)), 0x80000701);
> +		break;
> +	case CFG_CSI_PORT_0A:
> +	case CFG_CSI_PORT_0B:
> +		cal_sel = 0;
> +		write_master(seninf_base, SENINF_TOP_PHY_SENINF_CTL_CSI0,
> +			     ((1 << 8) | (1 << 12) |
> +			     (mipi_enable << 31)), 0x80003701);
> +		break;
> +	default:
> +		pr_err("unsupported CSI configuration\n");
> +		cal_sel = 0;
> +		write_master(seninf_base, SENINF_TOP_PHY_SENINF_CTL_CSI0,
> +			     ((2 << 8) |
> +			     (mipi_enable << 31)), 0x80000701);
> +		break;
> +	}
> +
> +	/* First Enable Sensor interface and select pad (0x1a04_0200) */
> +	write_master(pseninf, SENINF1_CTRL,
> +		     mipi_enable << 0, 0x00000001);
> +	write_master(pseninf, SENINF1_CTRL,
> +		     pad_sel << 28, 0x70000000);
> +
> +	if (csi_type == CSI2_1_5G || csi_type == CSI2_2_5G) {

csi_type would never be CSI2_1_5G in this patch.

> +		write_master(pseninf, SENINF1_CTRL, 0, 0x0000F000);
> +		write_master(pseninf, SENINF1_CTRL_EXT,
> +			     (mipi_enable << 6), 0x00000060);
> +	}
> +	if (!mipi_enable) {
> +		seninf_write_reg(pseninf, SENINF1_CSI2_CTL,
> +				 seninf_read_reg(pseninf, SENINF1_CSI2_CTL) &
> +				 0xFFFFFFE0);
> +		/* Disable mipi BG */
> +		write_master(pmipi_rx, MIPI_RX_ANA00_CSI0A, 0, 0x0000000C);
> +		write_master(pmipi_rx, MIPI_RX_ANA00_CSI0B, 0, 0x0000000C);
> +		return;
> +	}
> +
> +	if (csi_type != CSI2_2_5G_CPHY)
> +		set_dphy(priv, pcsi_mipi);
> +	else
> +		set_cphy(priv, pcsi_mipi);
> +
> +	/* DPCM Enable */
> +	seninf_write_reg(pseninf, SENINF1_CSI2_DPCM,
> +			 1 << ((pcsi_mipi->dpcm == 0x2a)
> +			 ? 15 : ((pcsi_mipi->dpcm & 0xF) + 7)));
> +
> +	pr_debug("CSI2-%d cnt:%d LaneNum:%d CSI2_EN:%d HeadOrder:%d dpcm:%d\n",
> +		 cal_sel, SENINF_SETTLE_DELAY,
> +		 (int)(pcsi_mipi->data_lane_num + 1), (int)mipi_enable,
> +		 (int)data_header_order, (int)pcsi_mipi->dpcm);
> +
> +	/* Settle delay */
> +	write_master(pseninf, SENINF1_CSI2_LNRD_TIMING,
> +		     (SENINF_SETTLE_DELAY << 8), 0x0000FF00);
> +	/* CSI2 control */
> +	if (csi_type != CSI2_2_5G_CPHY) { /* DPhy */
> +		seninf_write_reg(pseninf, SENINF1_CSI2_CTL,
> +				 (seninf_read_reg(pseninf, SENINF1_CSI2_CTL) |
> +				 (data_header_order << 16) |
> +				 (mipi_enable << 4) |
> +				 (((1 << (pcsi_mipi->data_lane_num + 1)) - 1)
> +				 )));
> +		write_master(pseninf, SENINF1_CSI2_RESYNC_MERGE_CTL,
> +			     (3 << 0), 0x00000C07);
> +		write_master(pseninf, SENINF1_CSI2_MODE, 0, 0x000007FF);
> +		write_master(pseninf, SENINF1_CSI2_DPHY_SYNC,
> +			     (0xff00 << 0) | (0x001d << 16), 0xFFFFFFFF);
> +		seninf_write_reg(pseninf, SENINF1_CSI2_SPARE0,
> +				 seninf_read_reg(pseninf, SENINF1_CSI2_SPARE0)
> +				 & 0xFFFFFFFE);
> +	} else {
> +		/* CPhy */
> +		unsigned int temp;
> +
> +		write_master(pseninf, SENINF1_CSI2_LNRD_TIMING, 0, 0x000000FF);
> +		seninf_write_reg(pseninf, SENINF1_CSI2_CTL,
> +				 (seninf_read_reg(pseninf, SENINF1_CSI2_CTL) |
> +				 data_header_order << 16));
> +		temp = (pcsi_mipi->data_lane_num == SENSOR_MIPI_1_LANE) ? 1 :
> +			(pcsi_mipi->data_lane_num == SENSOR_MIPI_2_LANE) ? 2 :
> +			(pcsi_mipi->data_lane_num == SENSOR_MIPI_3_LANE) ?
> +			4 : 5;
> +		write_master(pseninf, SENINF1_CSI2_MODE,
> +			     (temp << 8), 0x00000700);
> +		temp = pcsi_mipi->data_lane_num >= SENSOR_MIPI_1_LANE;
> +		write_master(pseninf, SENINF1_CSI2_CTRL_TRIO_CON,
> +			     (temp << 0), 0x00000001);
> +		temp = pcsi_mipi->data_lane_num >= SENSOR_MIPI_2_LANE;
> +		write_master(pseninf, SENINF1_CSI2_CTRL_TRIO_CON,
> +			     (temp << 2), 0x00000004);
> +		temp = pcsi_mipi->data_lane_num >= SENSOR_MIPI_3_LANE;
> +		write_master(pseninf, SENINF1_CSI2_CTRL_TRIO_CON,
> +			     (temp << 4), 0x00000010);
> +		temp = pcsi_mipi->data_lane_num >= SENSOR_MIPI_4_LANE;
> +		write_master(pseninf, SENINF1_CSI2_CTRL_TRIO_CON,
> +			     (temp << 6), 0x00000040);
> +		write_master(pseninf, SENINF1_CSI2_MODE,
> +			     (0x2 << 0), 0x000000FF);
> +		write_master(pseninf, SENINF1_CSI2_RESYNC_MERGE_CTL,
> +			     (3 << 0) | (1 << 11), 0x00000C07);
> +		write_master(pseninf, SENINF1_SYNC_RESYNC_CTL,
> +			     (1 << 0), 0x00000007);
> +		write_master(pseninf, SENINF1_POST_DETECT_CTL,
> +			     (1 << 1), 0x00000002);
> +
> +		seninf_write_reg(pseninf, SENINF1_CSI2_SPARE0,
> +				 seninf_read_reg(pseninf, SENINF1_CSI2_SPARE0)
> +				 | 0x1);
> +	}
> +
> +	write_master(pseninf, SENINF1_CSI2_CTL, (1 << 25), 0x0A000080);
> +	write_master(pseninf, SENINF1_CSI2_HS_TRAIL,
> +		     (SENINF_HS_TRAIL_PARAMETER << 0), 0x000000FF);
> +
> +	/* Set debug port to output packet number */
> +	seninf_write_reg(pseninf, SENINF1_CSI2_DGB_SEL, 0x8000001A);
> +	/* Enable CSI2 IRQ mask */
> +	/* Turn on all interrupt */
> +	seninf_write_reg(pseninf, SENINF1_CSI2_INT_EN, 0xFFFFFFFF);

If you does nothing in irq handler, why do you turn on interrupt?

> +	/* Write clear CSI2 IRQ */
> +	seninf_write_reg(pseninf, SENINF1_CSI2_INT_STATUS, 0xFFFFFFFF);
> +	/* Enable CSI2 Extend IRQ mask */
> +	/* Turn on all interrupt */
> +	seninf_write_reg(pseninf, SENINF1_CSI2_INT_EN_EXT, 0x0000001f);

Ditto.

> +
> +	write_master(pseninf, SENINF1_CTRL, (1 << 7), 0x00000080);
> +	udelay(1);
> +	write_master(pseninf, SENINF1_CTRL, 0, 0x00000080);
> +}
> +
> +static void power_off(struct _seninf *priv, void *pcsi)
> +{
> +	struct seninf_csi_mipi *pcsi_mipi = (struct seninf_csi_mipi *)pcsi;
> +	struct seninf_csi_info *csi_info = pcsi_mipi->csi_info;
> +	void *pmipi_rx = priv->csi2_rx[csi_info->port];
> +	void *pseninf = priv->base_reg + 0x1000 * csi_info->seninf;
> +
> +	/* Disable CSI2(2.5G) first */
> +	seninf_write_reg(pseninf, SENINF1_CSI2_CTL,
> +			 seninf_read_reg(pseninf, SENINF1_CSI2_CTL)
> +			 & 0xFFFFFFE0);
> +	/* Disable mipi BG */
> +	switch (csi_info->port) {
> +	case CFG_CSI_PORT_0A:
> +		write_master(pmipi_rx, MIPI_RX_ANA00_CSI0A,
> +			     0, 0x0000000C);
> +		break;
> +	case CFG_CSI_PORT_0B:
> +		write_master(pmipi_rx, MIPI_RX_ANA00_CSI0B,
> +			     0, 0x0000000C);
> +		break;
> +	default:
> +		write_master(pmipi_rx, MIPI_RX_ANA00_CSI0A,
> +			     0, 0x0000000C);
> +		write_master(pmipi_rx, MIPI_RX_ANA00_CSI0B,
> +			     0, 0x0000000C);
> +		break;
> +	}
> +}
> +
> +static int seninf_subscribe_event(struct v4l2_subdev *sd,
> +				  struct v4l2_fh *fh,
> +				  struct v4l2_event_subscription *sub)
> +{
> +	switch (sub->type) {
> +	case V4L2_EVENT_CTRL:
> +		return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub);
> +	default:
> +		return -EINVAL;
> +	}
> +}
> +
> +static int map_fmt

unsigned int.

> +	(struct _seninf *priv,

Merge to one line.

> +	struct seninf_csi_mipi *pcsi_mipi)
> +{
> +	int fmtidx;
> +
> +	switch (priv->fmt.format.code) {
> +	case MEDIA_BUS_FMT_SBGGR8_1X8:
> +	case MEDIA_BUS_FMT_SGBRG8_1X8:
> +	case MEDIA_BUS_FMT_SGRBG8_1X8:
> +	case MEDIA_BUS_FMT_SRGGB8_1X8:
> +		fmtidx = 0;
> +		pcsi_mipi->dpcm = 0;
> +		break;
> +	case MEDIA_BUS_FMT_SGRBG10_1X10:
> +	case MEDIA_BUS_FMT_SRGGB10_1X10:
> +	case MEDIA_BUS_FMT_SBGGR10_1X10:
> +	case MEDIA_BUS_FMT_SGBRG10_1X10:
> +		fmtidx = 1;
> +		pcsi_mipi->dpcm = 0;
> +		break;
> +	case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
> +	case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8:
> +	case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8:
> +	case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8:
> +		fmtidx = 0;
> +		/* dpcm mode 0x2a, */
> +		pcsi_mipi->dpcm = 0x2a;
> +		break;
> +	case MEDIA_BUS_FMT_SBGGR12_1X12:
> +	case MEDIA_BUS_FMT_SGBRG12_1X12:
> +	case MEDIA_BUS_FMT_SGRBG12_1X12:
> +	case MEDIA_BUS_FMT_SRGGB12_1X12:
> +		fmtidx = 2;
> +		pcsi_mipi->dpcm = 0;
> +		break;
> +	case MEDIA_BUS_FMT_UYVY8_1X16:
> +	case MEDIA_BUS_FMT_VYUY8_1X16:
> +	case MEDIA_BUS_FMT_YUYV8_1X16:
> +	case MEDIA_BUS_FMT_YVYU8_1X16:
> +		fmtidx = 3;
> +		pcsi_mipi->dpcm = 0;
> +		break;
> +	case MEDIA_BUS_FMT_JPEG_1X8:
> +	case MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8:
> +		fmtidx = 7;
> +		pcsi_mipi->dpcm = 0;
> +		break;
> +	default:
> +		fmtidx = 0;
> +		pcsi_mipi->dpcm = 0;
> +		WARN(1, "CSI2: pixel format %08x unsupported!\n",
> +		     priv->fmt.format.code);
> +		break;
> +	}
> +	return fmtidx;
> +}
> +
> +static void init_fmt(struct _seninf *priv)
> +{
> +	priv->fmt.format.code = MEDIA_BUS_FMT_SBGGR10_1X10;
> +	priv->fmt.format.width = DEFAULT_WIDTH;
> +	priv->fmt.format.height = DEFAULT_HEIGHT;
> +	priv->fmt.format.field = V4L2_FIELD_NONE;
> +	priv->fmt.format.colorspace = V4L2_COLORSPACE_SRGB;
> +	priv->fmt.format.xfer_func = V4L2_XFER_FUNC_DEFAULT;
> +	priv->fmt.format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
> +	priv->fmt.format.quantization = V4L2_QUANTIZATION_DEFAULT;
> +}
> +
> +static const struct v4l2_mbus_framefmt fmt_default = {
> +	.code = MEDIA_BUS_FMT_SBGGR10_1X10,
> +	.width = DEFAULT_WIDTH,
> +	.height = DEFAULT_HEIGHT,
> +	.field = V4L2_FIELD_NONE,
> +	.colorspace = V4L2_COLORSPACE_SRGB,
> +	.xfer_func = V4L2_XFER_FUNC_DEFAULT,
> +	.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
> +	.quantization = V4L2_QUANTIZATION_DEFAULT,
> +};
> +
> +static int seninf_init_cfg
> +				(struct v4l2_subdev *sd,

Merge to one line.

> +				 struct v4l2_subdev_pad_config *cfg)
> +{
> +	struct v4l2_mbus_framefmt *mf;
> +	unsigned int i;
> +
> +	for (i = 0; i < sd->entity.num_pads; i++) {
> +		mf = v4l2_subdev_get_try_format(sd, cfg, i);
> +		*mf = fmt_default;
> +	}
> +
> +	return 0;
> +}
> +

[snip]

> +
> +static int mtk_seninf_fwnode_parse(struct device *dev,
> +				   struct v4l2_fwnode_endpoint *vep,
> +				   struct v4l2_async_subdev *asd)
> +{
> +	return 0;
> +}
> +
> +static int seninf_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
> +{
> +	struct _seninf *priv = container_of(sd, struct _seninf, subdev);
> +	int ret;
> +
> +	ret = pm_runtime_get_sync(priv->dev);
> +	if (ret < 0) {
> +		dev_err(priv->dev, "Failed to pm_runtime_get_sync: %d\n", ret);
> +		return ret;
> +	}
> +
> +	clk_prepare_enable(priv->cam_clk);
> +	clk_prepare_enable(priv->top_mux_clk);
> +
> +	return ret;
> +}
> +
> +static int seninf_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
> +{
> +	struct _seninf *priv = container_of(sd, struct _seninf, subdev);
> +
> +	clk_disable_unprepare(priv->top_mux_clk);
> +	clk_disable_unprepare(priv->cam_clk);
> +	pm_runtime_put(priv->dev);
> +
> +	return 0;
> +}
> +
> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
> +static const struct v4l2_subdev_internal_ops seninf_internal_ops = {
> +	.open = seninf_open,
> +	.close = seninf_close,
> +};
> +#endif
> +
> +static irqreturn_t seninf_irq(int irq, void *device_id)
> +{
> +	return IRQ_HANDLED;
> +}

If you does nothing in irq handler, you should remove this handler.

> +

[snip]

> +
> +static int seninf_probe(struct platform_device *pdev)
> +{
> +	struct resource *res;
> +	struct _seninf *priv;
> +	struct v4l2_subdev *sd;
> +	struct device *dev = &pdev->dev;
> +	struct media_pad *pads;
> +	unsigned int irq_info[3];
> +	unsigned int irq;
> +	int i;
> +	int ret;
> +
> +	dev_dbg(dev, "seninf probe +\n");
> +	priv = devm_kzalloc(&pdev->dev, sizeof(struct _seninf), GFP_KERNEL);
> +	if (!priv)
> +		return -ENOMEM;
> +	memset(priv, 0, sizeof(struct _seninf));
> +	priv->dev = &pdev->dev;
> +	sd = &priv->subdev;
> +	pads = priv->pads;
> +	/* Get IRQ ID and request IRQ */
> +	irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
> +
> +	if (!irq) {
> +		pr_debug("No IRQ found!!\n");
> +		return 0;
> +	}
> +	/* Get IRQ Flag from device node */
> +	if (of_property_read_u32_array(pdev->dev.of_node,
> +				       "interrupts", irq_info,
> +				       ARRAY_SIZE(irq_info))) {
> +		dev_err(dev, "get irq flags from DTS fail!!\n");
> +		return -ENODEV;
> +	}
> +	ret = request_irq(irq, seninf_irq,
> +			  irq_info[2], "SENINF", NULL);
> +	if (ret) {
> +		dev_err(dev, "request_irq fail\n");
> +		return ret;
> +	}
> +	pr_debug("Seninf devnode:%s, irq=%d\n",
> +		 pdev->dev.of_node->name, irq);
> +
> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base_reg");
> +	priv->base_reg = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(priv->base_reg))
> +		return PTR_ERR(priv->base_reg);
> +	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rx_reg");
> +	priv->rx_reg = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(priv->rx_reg))
> +		return PTR_ERR(priv->rx_reg);
> +
> +	priv->csi2_rx[CFG_CSI_PORT_0]  = priv->rx_reg;
> +	priv->csi2_rx[CFG_CSI_PORT_0A] = priv->rx_reg;
> +	priv->csi2_rx[CFG_CSI_PORT_0B] = priv->rx_reg + 0x1000;
> +	priv->csi2_rx[CFG_CSI_PORT_1]  = priv->rx_reg + 0x2000;
> +	priv->csi2_rx[CFG_CSI_PORT_2]  = priv->rx_reg + 0x4000;
> +
> +	priv->cam_clk = devm_clk_get(dev, "CLK_CAM_SENINF");
> +	if (IS_ERR(priv->cam_clk)) {
> +		dev_err(dev, "Failed to get cam_clk\n");
> +		return -EINVAL;
> +	}
> +
> +	priv->top_mux_clk = devm_clk_get(dev, "CLK_TOP_MUX_SENINF");
> +	if (IS_ERR(priv->top_mux_clk)) {
> +		dev_err(dev, "Failed to get top_mux_clk\n");
> +		return -EINVAL;
> +	}
> +
> +	v4l2_subdev_init(sd, &seninf_subdev_ops);
> +
> +	init_fmt(priv);
> +	ret = seninf_initialize_controls(priv);
> +	if (ret) {
> +		dev_err(dev, "Failed to initialize controls\n");
> +		return ret;
> +	}
> +#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
> +	sd->internal_ops = &seninf_internal_ops;
> +	sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
> +	sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
> +#endif
> +	priv->subdev.dev = &pdev->dev;
> +	snprintf(sd->name, V4L2_SUBDEV_NAME_SIZE, "%s.mipi-csi",
> +		 dev_name(&pdev->dev));
> +	v4l2_set_subdevdata(sd, priv);
> +#if defined(CONFIG_MEDIA_CONTROLLER)
> +	sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
> +	sd->entity.ops = &seninf_media_ops;
> +	for (i = 0; i < 4; i++)
> +		pads[i].flags = MEDIA_PAD_FL_SINK;
> +	for (i = 4; i < NUM_PADS; i++)
> +		pads[i].flags = MEDIA_PAD_FL_SOURCE;
> +	ret = media_entity_pads_init(&sd->entity, NUM_PADS, pads);
> +	if (ret < 0)
> +		goto err_free_handler;
> +#endif
> +	ret = v4l2_async_notifier_parse_fwnode_endpoints
> +		(dev, &priv->notifier, sizeof(struct v4l2_async_subdev),
> +		 mtk_seninf_fwnode_parse);

If mtk_seninf_fwnode_parse() does nothing, you could just pass NULL for the callback function.

> +	if (ret < 0)
> +		goto err_clean_entity;
> +
> +	if (!priv->notifier.num_subdevs) {
> +		ret = -ENODEV;	/* no endpoint */
> +		goto err_clean_entity;
> +	}
> +
> +	priv->subdev.subdev_notifier = &priv->notifier;
> +	priv->notifier.ops = &mtk_seninf_async_ops;
> +	ret = v4l2_async_subdev_notifier_register(sd, &priv->notifier);
> +	if (ret < 0) {
> +		dev_err(dev, "v4l2 async notifier register failed\n");
> +		goto err_clean_notififer;
> +	}
> +
> +	ret = v4l2_async_register_subdev(sd);
> +	if (ret < 0) {
> +		dev_err(dev, "v4l2 async register subdev failed\n");
> +		goto err_clean_notififer;
> +	}
> +	pm_runtime_set_active(dev);
> +	pm_runtime_enable(dev);
> +	pm_runtime_idle(dev);
> +	dev_info(dev, "seninf probe -\n");
> +	return 0;
> +
> +err_clean_notififer:
> +	v4l2_async_notifier_cleanup(&priv->notifier);
> +err_clean_entity:
> +#if defined(CONFIG_MEDIA_CONTROLLER)
> +	media_entity_cleanup(&sd->entity);
> +#endif
> +err_free_handler:
> +	v4l2_ctrl_handler_free(&priv->ctrl_handler);
> +
> +	return ret;
> +}
> +
> +static int seninf_pm_suspend(struct device *dev)
> +{
> +	pr_debug("seninf_runtime_suspend\n");
> +
> +	return 0;
> +}
> +
> +static int seninf_pm_resume(struct device *dev)
> +{
> +	pr_debug("seninf_runtime_resume\n");
> +
> +	return 0;
> +}
> +
> +static const struct dev_pm_ops runtime_pm_ops = {
> +	SET_RUNTIME_PM_OPS(seninf_pm_suspend,
> +			   seninf_pm_resume,
> +			   NULL)
> +};

If you does nothing in suspend and resume function, I think you should
remove these two callback function.

Regards,
CK

> +
> +static int seninf_remove(struct platform_device *pdev)
> +{
> +	struct v4l2_subdev *subdev = platform_get_drvdata(pdev);
> +	struct _seninf *priv = container_of(subdev, struct _seninf, subdev);
> +	struct v4l2_subdev *sd = &priv->subdev;
> +
> +#if defined(CONFIG_MEDIA_CONTROLLER)
> +	media_entity_cleanup(&sd->entity);
> +#endif
> +	v4l2_ctrl_handler_free(&priv->ctrl_handler);
> +	v4l2_async_unregister_subdev(&priv->subdev);
> +	pm_runtime_disable(priv->dev);
> +	return 0;
> +}
> +







More information about the Linux-mediatek mailing list