Commit b329650e authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab
Browse files

media: imx: imx7_mipi_csis: Reorganize code in sections



Improve readability by reorganizing the code in sections. No functional
change intended.

Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: default avatarRui Miguel Silva <rmfrfs@gmail.com>
Tested-by: default avatarFrieder Schrempf <frieder.schrempf@kontron.de>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 90ce0472
Loading
Loading
Loading
Loading
+283 −256
Original line number Diff line number Diff line
@@ -324,6 +324,10 @@ struct csi_state {
	struct regulator *mipi_phy_regulator;
};

/* -----------------------------------------------------------------------------
 * Format helpers
 */

struct csis_pix_format {
	u32 code;
	u32 fmt_reg;
@@ -417,69 +421,28 @@ static const struct csis_pix_format mipi_csis_formats[] = {
	}
};

static inline void mipi_csis_write(struct csi_state *state, u32 reg, u32 val)
{
	writel(val, state->regs + reg);
}

static inline u32 mipi_csis_read(struct csi_state *state, u32 reg)
{
	return readl(state->regs + reg);
}

static int mipi_csis_dump_regs(struct csi_state *state)
static const struct csis_pix_format *find_csis_format(u32 code)
{
	static const struct {
		u32 offset;
		const char * const name;
	} registers[] = {
		{ MIPI_CSIS_CMN_CTRL, "CMN_CTRL" },
		{ MIPI_CSIS_CLK_CTRL, "CLK_CTRL" },
		{ MIPI_CSIS_INT_MSK, "INT_MSK" },
		{ MIPI_CSIS_DPHY_STATUS, "DPHY_STATUS" },
		{ MIPI_CSIS_DPHY_CMN_CTRL, "DPHY_CMN_CTRL" },
		{ MIPI_CSIS_DPHY_SCTRL_L, "DPHY_SCTRL_L" },
		{ MIPI_CSIS_DPHY_SCTRL_H, "DPHY_SCTRL_H" },
		{ MIPI_CSIS_ISP_CONFIG_CH(0), "ISP_CONFIG_CH0" },
		{ MIPI_CSIS_ISP_RESOL_CH(0), "ISP_RESOL_CH0" },
		{ MIPI_CSIS_SDW_CONFIG_CH(0), "SDW_CONFIG_CH0" },
		{ MIPI_CSIS_SDW_RESOL_CH(0), "SDW_RESOL_CH0" },
		{ MIPI_CSIS_DBG_CTRL, "DBG_CTRL" },
	};

	struct device *dev = &state->pdev->dev;
	unsigned int i;
	u32 cfg;

	dev_info(dev, "--- REGISTERS ---\n");

	for (i = 0; i < ARRAY_SIZE(registers); i++) {
		cfg = mipi_csis_read(state, registers[i].offset);
		dev_info(dev, "%14s: 0x%08x\n", registers[i].name, cfg);
	}

	return 0;
	for (i = 0; i < ARRAY_SIZE(mipi_csis_formats); i++)
		if (code == mipi_csis_formats[i].code)
			return &mipi_csis_formats[i];
	return NULL;
}

static struct csi_state *
mipi_notifier_to_csis_state(struct v4l2_async_notifier *n)
{
	return container_of(n, struct csi_state, notifier);
}
/* -----------------------------------------------------------------------------
 * Hardware configuration
 */

static struct csi_state *mipi_sd_to_csis_state(struct v4l2_subdev *sdev)
static inline u32 mipi_csis_read(struct csi_state *state, u32 reg)
{
	return container_of(sdev, struct csi_state, mipi_sd);
	return readl(state->regs + reg);
}

static const struct csis_pix_format *find_csis_format(u32 code)
static inline void mipi_csis_write(struct csi_state *state, u32 reg, u32 val)
{
	unsigned int i;

	for (i = 0; i < ARRAY_SIZE(mipi_csis_formats); i++)
		if (code == mipi_csis_formats[i].code)
			return &mipi_csis_formats[i];
	return NULL;
	writel(val, state->regs + reg);
}

static void mipi_csis_enable_interrupts(struct csi_state *state, bool on)
@@ -684,6 +647,41 @@ static void mipi_csis_stop_stream(struct csi_state *state)
	mipi_csis_system_enable(state, false);
}

static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
{
	struct csi_state *state = dev_id;
	unsigned long flags;
	unsigned int i;
	u32 status;
	u32 dbg_status;

	status = mipi_csis_read(state, MIPI_CSIS_INT_SRC);
	dbg_status = mipi_csis_read(state, MIPI_CSIS_DBG_INTR_SRC);

	spin_lock_irqsave(&state->slock, flags);

	/* Update the event/error counters */
	if ((status & MIPI_CSIS_INT_SRC_ERRORS) || state->debug) {
		for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) {
			struct mipi_csis_event *event = &state->events[i];

			if ((!event->debug && (status & event->mask)) ||
			    (event->debug && (dbg_status & event->mask)))
				event->counter++;
		}
	}
	spin_unlock_irqrestore(&state->slock, flags);

	mipi_csis_write(state, MIPI_CSIS_INT_SRC, status);
	mipi_csis_write(state, MIPI_CSIS_DBG_INTR_SRC, dbg_status);

	return IRQ_HANDLED;
}

/* -----------------------------------------------------------------------------
 * Debug
 */

static void mipi_csis_clear_counters(struct csi_state *state)
{
	unsigned long flags;
@@ -713,9 +711,72 @@ static void mipi_csis_log_counters(struct csi_state *state, bool non_errors)
	spin_unlock_irqrestore(&state->slock, flags);
}

/*
static int mipi_csis_dump_regs(struct csi_state *state)
{
	static const struct {
		u32 offset;
		const char * const name;
	} registers[] = {
		{ MIPI_CSIS_CMN_CTRL, "CMN_CTRL" },
		{ MIPI_CSIS_CLK_CTRL, "CLK_CTRL" },
		{ MIPI_CSIS_INT_MSK, "INT_MSK" },
		{ MIPI_CSIS_DPHY_STATUS, "DPHY_STATUS" },
		{ MIPI_CSIS_DPHY_CMN_CTRL, "DPHY_CMN_CTRL" },
		{ MIPI_CSIS_DPHY_SCTRL_L, "DPHY_SCTRL_L" },
		{ MIPI_CSIS_DPHY_SCTRL_H, "DPHY_SCTRL_H" },
		{ MIPI_CSIS_ISP_CONFIG_CH(0), "ISP_CONFIG_CH0" },
		{ MIPI_CSIS_ISP_RESOL_CH(0), "ISP_RESOL_CH0" },
		{ MIPI_CSIS_SDW_CONFIG_CH(0), "SDW_CONFIG_CH0" },
		{ MIPI_CSIS_SDW_RESOL_CH(0), "SDW_RESOL_CH0" },
		{ MIPI_CSIS_DBG_CTRL, "DBG_CTRL" },
	};

	struct device *dev = &state->pdev->dev;
	unsigned int i;
	u32 cfg;

	dev_info(dev, "--- REGISTERS ---\n");

	for (i = 0; i < ARRAY_SIZE(registers); i++) {
		cfg = mipi_csis_read(state, registers[i].offset);
		dev_info(dev, "%14s: 0x%08x\n", registers[i].name, cfg);
	}

	return 0;
}

static int mipi_csis_dump_regs_show(struct seq_file *m, void *private)
{
	struct csi_state *state = m->private;

	return mipi_csis_dump_regs(state);
}
DEFINE_SHOW_ATTRIBUTE(mipi_csis_dump_regs);

static void mipi_csis_debugfs_init(struct csi_state *state)
{
	state->debugfs_root = debugfs_create_dir(dev_name(state->dev), NULL);

	debugfs_create_bool("debug_enable", 0600, state->debugfs_root,
			    &state->debug);
	debugfs_create_file("dump_regs", 0600, state->debugfs_root, state,
			    &mipi_csis_dump_regs_fops);
}

static void mipi_csis_debugfs_exit(struct csi_state *state)
{
	debugfs_remove_recursive(state->debugfs_root);
}

/* -----------------------------------------------------------------------------
 * V4L2 subdev operations
 */

static struct csi_state *mipi_sd_to_csis_state(struct v4l2_subdev *sdev)
{
	return container_of(sdev, struct csi_state, mipi_sd);
}

static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable)
{
	struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
@@ -774,35 +835,6 @@ static int mipi_csis_s_stream(struct v4l2_subdev *mipi_sd, int enable)
	return ret;
}

static int mipi_csis_link_setup(struct media_entity *entity,
				const struct media_pad *local_pad,
				const struct media_pad *remote_pad, u32 flags)
{
	struct v4l2_subdev *mipi_sd = media_entity_to_v4l2_subdev(entity);
	struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
	struct v4l2_subdev *remote_sd;

	dev_dbg(state->dev, "link setup %s -> %s", remote_pad->entity->name,
		local_pad->entity->name);

	/* We only care about the link to the source. */
	if (!(local_pad->flags & MEDIA_PAD_FL_SINK))
		return 0;

	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);

	if (flags & MEDIA_LNK_FL_ENABLED) {
		if (state->src_sd)
			return -EBUSY;

		state->src_sd = remote_sd;
	} else {
		state->src_sd = NULL;
	}

	return 0;
}

static struct v4l2_mbus_framefmt *
mipi_csis_get_format(struct csi_state *state,
		     struct v4l2_subdev_pad_config *cfg,
@@ -991,47 +1023,10 @@ static int mipi_csis_log_status(struct v4l2_subdev *mipi_sd)
	return 0;
}

static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id)
{
	struct csi_state *state = dev_id;
	unsigned long flags;
	unsigned int i;
	u32 status;
	u32 dbg_status;

	status = mipi_csis_read(state, MIPI_CSIS_INT_SRC);
	dbg_status = mipi_csis_read(state, MIPI_CSIS_DBG_INTR_SRC);

	spin_lock_irqsave(&state->slock, flags);

	/* Update the event/error counters */
	if ((status & MIPI_CSIS_INT_SRC_ERRORS) || state->debug) {
		for (i = 0; i < MIPI_CSIS_NUM_EVENTS; i++) {
			struct mipi_csis_event *event = &state->events[i];

			if ((!event->debug && (status & event->mask)) ||
			    (event->debug && (dbg_status & event->mask)))
				event->counter++;
		}
	}
	spin_unlock_irqrestore(&state->slock, flags);

	mipi_csis_write(state, MIPI_CSIS_INT_SRC, status);
	mipi_csis_write(state, MIPI_CSIS_DBG_INTR_SRC, dbg_status);

	return IRQ_HANDLED;
}

static const struct v4l2_subdev_core_ops mipi_csis_core_ops = {
	.log_status	= mipi_csis_log_status,
};

static const struct media_entity_operations mipi_csis_entity_ops = {
	.link_setup	= mipi_csis_link_setup,
	.link_validate	= v4l2_subdev_link_validate,
	.get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
};

static const struct v4l2_subdev_video_ops mipi_csis_video_ops = {
	.s_stream	= mipi_csis_s_stream,
};
@@ -1049,28 +1044,58 @@ static const struct v4l2_subdev_ops mipi_csis_subdev_ops = {
	.pad	= &mipi_csis_pad_ops,
};

static int mipi_csis_parse_dt(struct platform_device *pdev,
			      struct csi_state *state)
{
	struct device_node *node = pdev->dev.of_node;
/* -----------------------------------------------------------------------------
 * Media entity operations
 */

	if (of_property_read_u32(node, "clock-frequency",
				 &state->clk_frequency))
		state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ;
static int mipi_csis_link_setup(struct media_entity *entity,
				const struct media_pad *local_pad,
				const struct media_pad *remote_pad, u32 flags)
{
	struct v4l2_subdev *mipi_sd = media_entity_to_v4l2_subdev(entity);
	struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
	struct v4l2_subdev *remote_sd;

	/* Get MIPI PHY resets */
	state->mrst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
	if (IS_ERR(state->mrst))
		return PTR_ERR(state->mrst);
	dev_dbg(state->dev, "link setup %s -> %s", remote_pad->entity->name,
		local_pad->entity->name);

	/* We only care about the link to the source. */
	if (!(local_pad->flags & MEDIA_PAD_FL_SINK))
		return 0;
}

static int mipi_csis_pm_resume(struct device *dev, bool runtime);
	remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);

static int mipi_csis_notify_bound(struct v4l2_async_notifier *notifier,
				  struct v4l2_subdev *sd,
				  struct v4l2_async_subdev *asd)
	if (flags & MEDIA_LNK_FL_ENABLED) {
		if (state->src_sd)
			return -EBUSY;

		state->src_sd = remote_sd;
	} else {
		state->src_sd = NULL;
	}

	return 0;
}

static const struct media_entity_operations mipi_csis_entity_ops = {
	.link_setup	= mipi_csis_link_setup,
	.link_validate	= v4l2_subdev_link_validate,
	.get_fwnode_pad = v4l2_subdev_get_fwnode_pad_1_to_1,
};

/* -----------------------------------------------------------------------------
 * Async subdev notifier
 */

static struct csi_state *
mipi_notifier_to_csis_state(struct v4l2_async_notifier *n)
{
	return container_of(n, struct csi_state, notifier);
}

static int mipi_csis_notify_bound(struct v4l2_async_notifier *notifier,
				  struct v4l2_subdev *sd,
				  struct v4l2_async_subdev *asd)
{
	struct csi_state *state = mipi_notifier_to_csis_state(notifier);
	struct media_pad *sink = &state->mipi_sd.entity.pads[CSIS_PAD_SINK];
@@ -1082,36 +1107,6 @@ static const struct v4l2_async_notifier_operations mipi_csis_notify_ops = {
	.bound = mipi_csis_notify_bound,
};

static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd,
				 struct platform_device *pdev,
				 const struct v4l2_subdev_ops *ops)
{
	struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);

	v4l2_subdev_init(mipi_sd, ops);
	mipi_sd->owner = THIS_MODULE;
	snprintf(mipi_sd->name, sizeof(mipi_sd->name), "%s.%d",
		 CSIS_SUBDEV_NAME, state->index);

	mipi_sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
	mipi_sd->ctrl_handler = NULL;

	mipi_sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
	mipi_sd->entity.ops = &mipi_csis_entity_ops;

	mipi_sd->dev = &pdev->dev;

	state->csis_fmt = &mipi_csis_formats[0];
	mipi_csis_init_cfg(mipi_sd, NULL);

	state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK
					 | MEDIA_PAD_FL_MUST_CONNECT;
	state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE
					   | MEDIA_PAD_FL_MUST_CONNECT;
	return media_entity_pads_init(&mipi_sd->entity, CSIS_PADS_NUM,
				      state->pads);
}

static int mipi_csis_async_register(struct csi_state *state)
{
	struct v4l2_fwnode_endpoint vep = {
@@ -1161,27 +1156,138 @@ static int mipi_csis_async_register(struct csi_state *state)
	return ret;
}

static int mipi_csis_dump_regs_show(struct seq_file *m, void *private)
/* -----------------------------------------------------------------------------
 * Suspend/resume
 */

static int mipi_csis_pm_suspend(struct device *dev, bool runtime)
{
	struct csi_state *state = m->private;
	struct v4l2_subdev *mipi_sd = dev_get_drvdata(dev);
	struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
	int ret = 0;

	return mipi_csis_dump_regs(state);
	mutex_lock(&state->lock);
	if (state->flags & ST_POWERED) {
		mipi_csis_stop_stream(state);
		ret = regulator_disable(state->mipi_phy_regulator);
		if (ret)
			goto unlock;
		mipi_csis_clk_disable(state);
		state->flags &= ~ST_POWERED;
		if (!runtime)
			state->flags |= ST_SUSPENDED;
	}
DEFINE_SHOW_ATTRIBUTE(mipi_csis_dump_regs);

static void mipi_csis_debugfs_init(struct csi_state *state)
unlock:
	mutex_unlock(&state->lock);

	return ret ? -EAGAIN : 0;
}

static int mipi_csis_pm_resume(struct device *dev, bool runtime)
{
	state->debugfs_root = debugfs_create_dir(dev_name(state->dev), NULL);
	struct v4l2_subdev *mipi_sd = dev_get_drvdata(dev);
	struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
	int ret = 0;

	debugfs_create_bool("debug_enable", 0600, state->debugfs_root,
			    &state->debug);
	debugfs_create_file("dump_regs", 0600, state->debugfs_root, state,
			    &mipi_csis_dump_regs_fops);
	mutex_lock(&state->lock);
	if (!runtime && !(state->flags & ST_SUSPENDED))
		goto unlock;

	if (!(state->flags & ST_POWERED)) {
		ret = regulator_enable(state->mipi_phy_regulator);
		if (ret)
			goto unlock;

		state->flags |= ST_POWERED;
		mipi_csis_clk_enable(state);
	}
	if (state->flags & ST_STREAMING)
		mipi_csis_start_stream(state);

static void mipi_csis_debugfs_exit(struct csi_state *state)
	state->flags &= ~ST_SUSPENDED;

unlock:
	mutex_unlock(&state->lock);

	return ret ? -EAGAIN : 0;
}

static int __maybe_unused mipi_csis_suspend(struct device *dev)
{
	debugfs_remove_recursive(state->debugfs_root);
	return mipi_csis_pm_suspend(dev, false);
}

static int __maybe_unused mipi_csis_resume(struct device *dev)
{
	return mipi_csis_pm_resume(dev, false);
}

static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev)
{
	return mipi_csis_pm_suspend(dev, true);
}

static int __maybe_unused mipi_csis_runtime_resume(struct device *dev)
{
	return mipi_csis_pm_resume(dev, true);
}

static const struct dev_pm_ops mipi_csis_pm_ops = {
	SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume,
			   NULL)
	SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume)
};

/* -----------------------------------------------------------------------------
 * Probe/remove & platform driver
 */

static int mipi_csis_subdev_init(struct v4l2_subdev *mipi_sd,
				 struct platform_device *pdev,
				 const struct v4l2_subdev_ops *ops)
{
	struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);

	v4l2_subdev_init(mipi_sd, ops);
	mipi_sd->owner = THIS_MODULE;
	snprintf(mipi_sd->name, sizeof(mipi_sd->name), "%s.%d",
		 CSIS_SUBDEV_NAME, state->index);

	mipi_sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
	mipi_sd->ctrl_handler = NULL;

	mipi_sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
	mipi_sd->entity.ops = &mipi_csis_entity_ops;

	mipi_sd->dev = &pdev->dev;

	state->csis_fmt = &mipi_csis_formats[0];
	mipi_csis_init_cfg(mipi_sd, NULL);

	state->pads[CSIS_PAD_SINK].flags = MEDIA_PAD_FL_SINK
					 | MEDIA_PAD_FL_MUST_CONNECT;
	state->pads[CSIS_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE
					   | MEDIA_PAD_FL_MUST_CONNECT;
	return media_entity_pads_init(&mipi_sd->entity, CSIS_PADS_NUM,
				      state->pads);
}

static int mipi_csis_parse_dt(struct platform_device *pdev,
			      struct csi_state *state)
{
	struct device_node *node = pdev->dev.of_node;

	if (of_property_read_u32(node, "clock-frequency",
				 &state->clk_frequency))
		state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ;

	/* Get MIPI PHY resets */
	state->mrst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
	if (IS_ERR(state->mrst))
		return PTR_ERR(state->mrst);

	return 0;
}

static int mipi_csis_probe(struct platform_device *pdev)
@@ -1279,79 +1385,6 @@ static int mipi_csis_probe(struct platform_device *pdev)
	return ret;
}

static int mipi_csis_pm_suspend(struct device *dev, bool runtime)
{
	struct v4l2_subdev *mipi_sd = dev_get_drvdata(dev);
	struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
	int ret = 0;

	mutex_lock(&state->lock);
	if (state->flags & ST_POWERED) {
		mipi_csis_stop_stream(state);
		ret = regulator_disable(state->mipi_phy_regulator);
		if (ret)
			goto unlock;
		mipi_csis_clk_disable(state);
		state->flags &= ~ST_POWERED;
		if (!runtime)
			state->flags |= ST_SUSPENDED;
	}

unlock:
	mutex_unlock(&state->lock);

	return ret ? -EAGAIN : 0;
}

static int mipi_csis_pm_resume(struct device *dev, bool runtime)
{
	struct v4l2_subdev *mipi_sd = dev_get_drvdata(dev);
	struct csi_state *state = mipi_sd_to_csis_state(mipi_sd);
	int ret = 0;

	mutex_lock(&state->lock);
	if (!runtime && !(state->flags & ST_SUSPENDED))
		goto unlock;

	if (!(state->flags & ST_POWERED)) {
		ret = regulator_enable(state->mipi_phy_regulator);
		if (ret)
			goto unlock;

		state->flags |= ST_POWERED;
		mipi_csis_clk_enable(state);
	}
	if (state->flags & ST_STREAMING)
		mipi_csis_start_stream(state);

	state->flags &= ~ST_SUSPENDED;

unlock:
	mutex_unlock(&state->lock);

	return ret ? -EAGAIN : 0;
}

static int __maybe_unused mipi_csis_suspend(struct device *dev)
{
	return mipi_csis_pm_suspend(dev, false);
}

static int __maybe_unused mipi_csis_resume(struct device *dev)
{
	return mipi_csis_pm_resume(dev, false);
}

static int __maybe_unused mipi_csis_runtime_suspend(struct device *dev)
{
	return mipi_csis_pm_suspend(dev, true);
}

static int __maybe_unused mipi_csis_runtime_resume(struct device *dev)
{
	return mipi_csis_pm_resume(dev, true);
}

static int mipi_csis_remove(struct platform_device *pdev)
{
	struct v4l2_subdev *mipi_sd = platform_get_drvdata(pdev);
@@ -1372,12 +1405,6 @@ static int mipi_csis_remove(struct platform_device *pdev)
	return 0;
}

static const struct dev_pm_ops mipi_csis_pm_ops = {
	SET_RUNTIME_PM_OPS(mipi_csis_runtime_suspend, mipi_csis_runtime_resume,
			   NULL)
	SET_SYSTEM_SLEEP_PM_OPS(mipi_csis_suspend, mipi_csis_resume)
};

static const struct of_device_id mipi_csis_of_match[] = {
	{ .compatible = "fsl,imx7-mipi-csi2", },
	{ /* sentinel */ },