media: imx: imx7_mipi_csis: Reorganize code in sections

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

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Rui Miguel Silva <rmfrfs@gmail.com>
Tested-by: Frieder Schrempf <frieder.schrempf@kontron.de>
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
This commit is contained in:
Laurent Pinchart 2021-04-13 04:29:58 +02:00 committed by Mauro Carvalho Chehab
parent 90ce047218
commit b329650e3f

View File

@ -324,6 +324,10 @@ struct csi_state {
struct regulator *mipi_phy_regulator;
};
/* -----------------------------------------------------------------------------
* Format helpers
*/
struct csis_pix_format {
u32 code;
u32 fmt_reg;
@ -417,61 +421,6 @@ 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 {
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 struct csi_state *
mipi_notifier_to_csis_state(struct v4l2_async_notifier *n)
{
return container_of(n, struct csi_state, notifier);
}
static struct csi_state *mipi_sd_to_csis_state(struct v4l2_subdev *sdev)
{
return container_of(sdev, struct csi_state, mipi_sd);
}
static const struct csis_pix_format *find_csis_format(u32 code)
{
unsigned int i;
@ -482,6 +431,20 @@ static const struct csis_pix_format *find_csis_format(u32 code)
return NULL;
}
/* -----------------------------------------------------------------------------
* Hardware configuration
*/
static inline u32 mipi_csis_read(struct csi_state *state, u32 reg)
{
return readl(state->regs + reg);
}
static inline void mipi_csis_write(struct csi_state *state, u32 reg, u32 val)
{
writel(val, state->regs + reg);
}
static void mipi_csis_enable_interrupts(struct csi_state *state, bool on)
{
mipi_csis_write(state, MIPI_CSIS_INT_MSK, on ? 0xffffffff : 0);
@ -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 @@ done:
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,24 +1044,54 @@ 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)
/* -----------------------------------------------------------------------------
* Media entity operations
*/
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 device_node *node = pdev->dev.of_node;
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;
if (of_property_read_u32(node, "clock-frequency",
&state->clk_frequency))
state->clk_frequency = DEFAULT_SCLK_CSIS_FREQ;
dev_dbg(state->dev, "link setup %s -> %s", remote_pad->entity->name,
local_pad->entity->name);
/* Get MIPI PHY resets */
state->mrst = devm_reset_control_get_exclusive(&pdev->dev, NULL);
if (IS_ERR(state->mrst))
return PTR_ERR(state->mrst);
/* 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 int mipi_csis_pm_resume(struct device *dev, bool runtime);
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,
@ -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 @@ err_parse:
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);
}
DEFINE_SHOW_ATTRIBUTE(mipi_csis_dump_regs);
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;
}
static void mipi_csis_debugfs_init(struct csi_state *state)
{
state->debugfs_root = debugfs_create_dir(dev_name(state->dev), NULL);
unlock:
mutex_unlock(&state->lock);
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);
return ret ? -EAGAIN : 0;
}
static void mipi_csis_debugfs_exit(struct csi_state *state)
static int mipi_csis_pm_resume(struct device *dev, bool runtime)
{
debugfs_remove_recursive(state->debugfs_root);
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 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 @@ disable_clock:
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 */ },