aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/ti-vpe/cal.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/ti-vpe/cal.c')
-rw-r--r--drivers/media/platform/ti-vpe/cal.c399
1 files changed, 313 insertions, 86 deletions
diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c
index 59a0266b1f39..fa0931788040 100644
--- a/drivers/media/platform/ti-vpe/cal.c
+++ b/drivers/media/platform/ti-vpe/cal.c
@@ -44,6 +44,133 @@ module_param_named(debug, cal_debug, uint, 0644);
MODULE_PARM_DESC(debug, "activates debug info");
/* ------------------------------------------------------------------
+ * Format Handling
+ * ------------------------------------------------------------------
+ */
+
+const struct cal_format_info cal_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .bpp = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .bpp = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .code = MEDIA_BUS_FMT_YVYU8_2X8,
+ .bpp = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .code = MEDIA_BUS_FMT_VYUY8_2X8,
+ .bpp = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ .bpp = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+ .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
+ .bpp = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
+ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
+ .bpp = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
+ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
+ .bpp = 16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */
+ .code = MEDIA_BUS_FMT_RGB888_2X12_LE,
+ .bpp = 24,
+ }, {
+ .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */
+ .code = MEDIA_BUS_FMT_RGB888_2X12_BE,
+ .bpp = 24,
+ }, {
+ .fourcc = V4L2_PIX_FMT_RGB32, /* argb */
+ .code = MEDIA_BUS_FMT_ARGB8888_1X32,
+ .bpp = 32,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .bpp = 8,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .bpp = 8,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .bpp = 8,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .bpp = 8,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .bpp = 10,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG10,
+ .code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .bpp = 10,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .bpp = 10,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB10,
+ .code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .bpp = 10,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR12,
+ .code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .bpp = 12,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG12,
+ .code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .bpp = 12,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG12,
+ .code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .bpp = 12,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB12,
+ .code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .bpp = 12,
+ },
+};
+
+const unsigned int cal_num_formats = ARRAY_SIZE(cal_formats);
+
+const struct cal_format_info *cal_format_by_fourcc(u32 fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(cal_formats); ++i) {
+ if (cal_formats[i].fourcc == fourcc)
+ return &cal_formats[i];
+ }
+
+ return NULL;
+}
+
+const struct cal_format_info *cal_format_by_code(u32 code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(cal_formats); ++i) {
+ if (cal_formats[i].code == code)
+ return &cal_formats[i];
+ }
+
+ return NULL;
+}
+
+/* ------------------------------------------------------------------
* Platform Data
* ------------------------------------------------------------------
*/
@@ -136,12 +263,9 @@ void cal_quickdump_regs(struct cal_dev *cal)
(__force const void *)cal->base,
resource_size(cal->res), false);
- for (i = 0; i < ARRAY_SIZE(cal->phy); ++i) {
+ for (i = 0; i < cal->data->num_csi2_phy; ++i) {
struct cal_camerarx *phy = cal->phy[i];
- if (!phy)
- continue;
-
cal_info(cal, "CSI2 Core %u Registers @ %pa:\n", i,
&phy->res->start);
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_OFFSET, 16, 4,
@@ -156,7 +280,7 @@ void cal_quickdump_regs(struct cal_dev *cal)
* ------------------------------------------------------------------
*/
-void cal_ctx_csi2_config(struct cal_ctx *ctx)
+static void cal_ctx_csi2_config(struct cal_ctx *ctx)
{
u32 val;
@@ -181,11 +305,11 @@ void cal_ctx_csi2_config(struct cal_ctx *ctx)
cal_read(ctx->cal, CAL_CSI2_CTX0(ctx->index)));
}
-void cal_ctx_pix_proc_config(struct cal_ctx *ctx)
+static void cal_ctx_pix_proc_config(struct cal_ctx *ctx)
{
u32 val, extract, pack;
- switch (ctx->fmt->bpp) {
+ switch (ctx->fmtinfo->bpp) {
case 8:
extract = CAL_PIX_PROC_EXTRACT_B8;
pack = CAL_PIX_PROC_PACK_B8;
@@ -214,7 +338,7 @@ void cal_ctx_pix_proc_config(struct cal_ctx *ctx)
*/
dev_warn_once(ctx->cal->dev,
"%s:%d:%s: bpp:%d unsupported! Overwritten with 8.\n",
- __FILE__, __LINE__, __func__, ctx->fmt->bpp);
+ __FILE__, __LINE__, __func__, ctx->fmtinfo->bpp);
extract = CAL_PIX_PROC_EXTRACT_B8;
pack = CAL_PIX_PROC_PACK_B8;
break;
@@ -232,14 +356,15 @@ void cal_ctx_pix_proc_config(struct cal_ctx *ctx)
cal_read(ctx->cal, CAL_PIX_PROC(ctx->index)));
}
-void cal_ctx_wr_dma_config(struct cal_ctx *ctx, unsigned int width,
- unsigned int height)
+static void cal_ctx_wr_dma_config(struct cal_ctx *ctx)
{
+ unsigned int stride = ctx->v_fmt.fmt.pix.bytesperline;
u32 val;
val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index));
cal_set_field(&val, ctx->cport, CAL_WR_DMA_CTRL_CPORT_MASK);
- cal_set_field(&val, height, CAL_WR_DMA_CTRL_YSIZE_MASK);
+ cal_set_field(&val, ctx->v_fmt.fmt.pix.height,
+ CAL_WR_DMA_CTRL_YSIZE_MASK);
cal_set_field(&val, CAL_WR_DMA_CTRL_DTAG_PIX_DAT,
CAL_WR_DMA_CTRL_DTAG_MASK);
cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_CONST,
@@ -251,14 +376,8 @@ void cal_ctx_wr_dma_config(struct cal_ctx *ctx, unsigned int width,
ctx_dbg(3, ctx, "CAL_WR_DMA_CTRL(%d) = 0x%08x\n", ctx->index,
cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index)));
- /*
- * width/16 not sure but giving it a whirl.
- * zero does not work right
- */
- cal_write_field(ctx->cal,
- CAL_WR_DMA_OFST(ctx->index),
- (width / 16),
- CAL_WR_DMA_OFST_MASK);
+ cal_write_field(ctx->cal, CAL_WR_DMA_OFST(ctx->index),
+ stride / 16, CAL_WR_DMA_OFST_MASK);
ctx_dbg(3, ctx, "CAL_WR_DMA_OFST(%d) = 0x%08x\n", ctx->index,
cal_read(ctx->cal, CAL_WR_DMA_OFST(ctx->index)));
@@ -266,11 +385,11 @@ void cal_ctx_wr_dma_config(struct cal_ctx *ctx, unsigned int width,
/* 64 bit word means no skipping */
cal_set_field(&val, 0, CAL_WR_DMA_XSIZE_XSKIP_MASK);
/*
- * (width*8)/64 this should be size of an entire line
- * in 64bit word but 0 means all data until the end
- * is detected automagically
+ * The XSIZE field is expressed in 64-bit units and prevents overflows
+ * in case of synchronization issues by limiting the number of bytes
+ * written per line.
*/
- cal_set_field(&val, (width / 8), CAL_WR_DMA_XSIZE_MASK);
+ cal_set_field(&val, stride / 8, CAL_WR_DMA_XSIZE_MASK);
cal_write(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index), val);
ctx_dbg(3, ctx, "CAL_WR_DMA_XSIZE(%d) = 0x%08x\n", ctx->index,
cal_read(ctx->cal, CAL_WR_DMA_XSIZE(ctx->index)));
@@ -287,9 +406,74 @@ void cal_ctx_wr_dma_config(struct cal_ctx *ctx, unsigned int width,
ctx_dbg(3, ctx, "CAL_CTRL = 0x%08x\n", cal_read(ctx->cal, CAL_CTRL));
}
-void cal_ctx_wr_dma_addr(struct cal_ctx *ctx, unsigned int dmaaddr)
+void cal_ctx_set_dma_addr(struct cal_ctx *ctx, dma_addr_t addr)
+{
+ cal_write(ctx->cal, CAL_WR_DMA_ADDR(ctx->index), addr);
+}
+
+static void cal_ctx_wr_dma_disable(struct cal_ctx *ctx)
+{
+ u32 val = cal_read(ctx->cal, CAL_WR_DMA_CTRL(ctx->index));
+
+ cal_set_field(&val, CAL_WR_DMA_CTRL_MODE_DIS,
+ CAL_WR_DMA_CTRL_MODE_MASK);
+ cal_write(ctx->cal, CAL_WR_DMA_CTRL(ctx->index), val);
+}
+
+static bool cal_ctx_wr_dma_stopped(struct cal_ctx *ctx)
{
- cal_write(ctx->cal, CAL_WR_DMA_ADDR(ctx->index), dmaaddr);
+ bool stopped;
+
+ spin_lock_irq(&ctx->dma.lock);
+ stopped = ctx->dma.state == CAL_DMA_STOPPED;
+ spin_unlock_irq(&ctx->dma.lock);
+
+ return stopped;
+}
+
+void cal_ctx_start(struct cal_ctx *ctx)
+{
+ ctx->sequence = 0;
+ ctx->dma.state = CAL_DMA_RUNNING;
+
+ /* Configure the CSI-2, pixel processing and write DMA contexts. */
+ cal_ctx_csi2_config(ctx);
+ cal_ctx_pix_proc_config(ctx);
+ cal_ctx_wr_dma_config(ctx);
+
+ /* Enable IRQ_WDMA_END and IRQ_WDMA_START. */
+ cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(1),
+ CAL_HL_IRQ_MASK(ctx->index));
+ cal_write(ctx->cal, CAL_HL_IRQENABLE_SET(2),
+ CAL_HL_IRQ_MASK(ctx->index));
+}
+
+void cal_ctx_stop(struct cal_ctx *ctx)
+{
+ long timeout;
+
+ /*
+ * Request DMA stop and wait until it completes. If completion times
+ * out, forcefully disable the DMA.
+ */
+ spin_lock_irq(&ctx->dma.lock);
+ ctx->dma.state = CAL_DMA_STOP_REQUESTED;
+ spin_unlock_irq(&ctx->dma.lock);
+
+ timeout = wait_event_timeout(ctx->dma.wait, cal_ctx_wr_dma_stopped(ctx),
+ msecs_to_jiffies(500));
+ if (!timeout) {
+ ctx_err(ctx, "failed to disable dma cleanly\n");
+ cal_ctx_wr_dma_disable(ctx);
+ }
+
+ /* Disable IRQ_WDMA_END and IRQ_WDMA_START. */
+ cal_write(ctx->cal, CAL_HL_IRQENABLE_CLR(1),
+ CAL_HL_IRQ_MASK(ctx->index));
+ cal_write(ctx->cal, CAL_HL_IRQENABLE_CLR(2),
+ CAL_HL_IRQ_MASK(ctx->index));
+
+ ctx->dma.state = CAL_DMA_STOPPED;
}
/* ------------------------------------------------------------------
@@ -297,35 +481,70 @@ void cal_ctx_wr_dma_addr(struct cal_ctx *ctx, unsigned int dmaaddr)
* ------------------------------------------------------------------
*/
-static inline void cal_schedule_next_buffer(struct cal_ctx *ctx)
+static inline void cal_irq_wdma_start(struct cal_ctx *ctx)
{
- struct cal_dmaqueue *dma_q = &ctx->vidq;
- struct cal_buffer *buf;
- unsigned long addr;
+ spin_lock(&ctx->dma.lock);
+
+ if (ctx->dma.state == CAL_DMA_STOP_REQUESTED) {
+ /*
+ * If a stop is requested, disable the write DMA context
+ * immediately. The CAL_WR_DMA_CTRL_j.MODE field is shadowed,
+ * the current frame will complete and the DMA will then stop.
+ */
+ cal_ctx_wr_dma_disable(ctx);
+ ctx->dma.state = CAL_DMA_STOP_PENDING;
+ } else if (!list_empty(&ctx->dma.queue) && !ctx->dma.pending) {
+ /*
+ * Otherwise, if a new buffer is available, queue it to the
+ * hardware.
+ */
+ struct cal_buffer *buf;
+ dma_addr_t addr;
+
+ buf = list_first_entry(&ctx->dma.queue, struct cal_buffer,
+ list);
+ addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
+ cal_ctx_set_dma_addr(ctx, addr);
- buf = list_entry(dma_q->active.next, struct cal_buffer, list);
- ctx->next_frm = buf;
- list_del(&buf->list);
+ ctx->dma.pending = buf;
+ list_del(&buf->list);
+ }
- addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
- cal_ctx_wr_dma_addr(ctx, addr);
+ spin_unlock(&ctx->dma.lock);
}
-static inline void cal_process_buffer_complete(struct cal_ctx *ctx)
+static inline void cal_irq_wdma_end(struct cal_ctx *ctx)
{
- ctx->cur_frm->vb.vb2_buf.timestamp = ktime_get_ns();
- ctx->cur_frm->vb.field = ctx->m_fmt.field;
- ctx->cur_frm->vb.sequence = ctx->sequence++;
+ struct cal_buffer *buf = NULL;
+
+ spin_lock(&ctx->dma.lock);
+
+ /* If the DMA context was stopping, it is now stopped. */
+ if (ctx->dma.state == CAL_DMA_STOP_PENDING) {
+ ctx->dma.state = CAL_DMA_STOPPED;
+ wake_up(&ctx->dma.wait);
+ }
- vb2_buffer_done(&ctx->cur_frm->vb.vb2_buf, VB2_BUF_STATE_DONE);
- ctx->cur_frm = ctx->next_frm;
+ /* If a new buffer was queued, complete the current buffer. */
+ if (ctx->dma.pending) {
+ buf = ctx->dma.active;
+ ctx->dma.active = ctx->dma.pending;
+ ctx->dma.pending = NULL;
+ }
+
+ spin_unlock(&ctx->dma.lock);
+
+ if (buf) {
+ buf->vb.vb2_buf.timestamp = ktime_get_ns();
+ buf->vb.field = ctx->v_fmt.fmt.pix.field;
+ buf->vb.sequence = ctx->sequence++;
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
+ }
}
static irqreturn_t cal_irq(int irq_cal, void *data)
{
struct cal_dev *cal = data;
- struct cal_ctx *ctx;
- struct cal_dmaqueue *dma_q;
u32 status;
status = cal_read(cal, CAL_HL_IRQSTATUS(0));
@@ -337,7 +556,7 @@ static irqreturn_t cal_irq(int irq_cal, void *data)
if (status & CAL_HL_IRQ_OCPO_ERR_MASK)
dev_err_ratelimited(cal->dev, "OCPO ERROR\n");
- for (i = 0; i < CAL_NUM_CSI2_PORTS; ++i) {
+ for (i = 0; i < cal->data->num_csi2_phy; ++i) {
if (status & CAL_HL_IRQ_CIO_MASK(i)) {
u32 cio_stat = cal_read(cal,
CAL_CSI2_COMPLEXIO_IRQSTATUS(i));
@@ -360,17 +579,8 @@ static irqreturn_t cal_irq(int irq_cal, void *data)
cal_write(cal, CAL_HL_IRQSTATUS(1), status);
for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) {
- if (status & CAL_HL_IRQ_MASK(i)) {
- ctx = cal->ctx[i];
-
- spin_lock(&ctx->slock);
- ctx->dma_act = false;
-
- if (ctx->cur_frm != ctx->next_frm)
- cal_process_buffer_complete(ctx);
-
- spin_unlock(&ctx->slock);
- }
+ if (status & CAL_HL_IRQ_MASK(i))
+ cal_irq_wdma_end(cal->ctx[i]);
}
}
@@ -383,17 +593,8 @@ static irqreturn_t cal_irq(int irq_cal, void *data)
cal_write(cal, CAL_HL_IRQSTATUS(2), status);
for (i = 0; i < ARRAY_SIZE(cal->ctx); ++i) {
- if (status & CAL_HL_IRQ_MASK(i)) {
- ctx = cal->ctx[i];
- dma_q = &ctx->vidq;
-
- spin_lock(&ctx->slock);
- ctx->dma_act = true;
- if (!list_empty(&dma_q->active) &&
- ctx->cur_frm == ctx->next_frm)
- cal_schedule_next_buffer(ctx);
- spin_unlock(&ctx->slock);
- }
+ if (status & CAL_HL_IRQ_MASK(i))
+ cal_irq_wdma_start(cal->ctx[i]);
}
}
@@ -406,7 +607,7 @@ static irqreturn_t cal_irq(int irq_cal, void *data)
*/
struct cal_v4l2_async_subdev {
- struct v4l2_async_subdev asd;
+ struct v4l2_async_subdev asd; /* Must be first */
struct cal_camerarx *phy;
};
@@ -421,6 +622,8 @@ static int cal_async_notifier_bound(struct v4l2_async_notifier *notifier,
struct v4l2_async_subdev *asd)
{
struct cal_camerarx *phy = to_cal_asd(asd)->phy;
+ int pad;
+ int ret;
if (phy->sensor) {
phy_info(phy, "Rejecting subdev %s (Already set!!)",
@@ -431,6 +634,25 @@ static int cal_async_notifier_bound(struct v4l2_async_notifier *notifier,
phy->sensor = subdev;
phy_dbg(1, phy, "Using sensor %s for capture\n", subdev->name);
+ pad = media_entity_get_fwnode_pad(&subdev->entity,
+ of_fwnode_handle(phy->sensor_ep_node),
+ MEDIA_PAD_FL_SOURCE);
+ if (pad < 0) {
+ phy_err(phy, "Sensor %s has no connected source pad\n",
+ subdev->name);
+ return pad;
+ }
+
+ ret = media_create_pad_link(&subdev->entity, pad,
+ &phy->subdev.entity, CAL_CAMERARX_PAD_SINK,
+ MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (ret) {
+ phy_err(phy, "Failed to create media link for sensor %s\n",
+ subdev->name);
+ return ret;
+ }
+
return 0;
}
@@ -460,26 +682,24 @@ static int cal_async_notifier_register(struct cal_dev *cal)
v4l2_async_notifier_init(&cal->notifier);
cal->notifier.ops = &cal_async_notifier_ops;
- for (i = 0; i < ARRAY_SIZE(cal->phy); ++i) {
+ for (i = 0; i < cal->data->num_csi2_phy; ++i) {
struct cal_camerarx *phy = cal->phy[i];
struct cal_v4l2_async_subdev *casd;
- struct v4l2_async_subdev *asd;
struct fwnode_handle *fwnode;
- if (!phy || !phy->sensor_node)
+ if (!phy->sensor_node)
continue;
fwnode = of_fwnode_handle(phy->sensor_node);
- asd = v4l2_async_notifier_add_fwnode_subdev(&cal->notifier,
- fwnode,
- sizeof(*asd));
- if (IS_ERR(asd)) {
+ casd = v4l2_async_notifier_add_fwnode_subdev(&cal->notifier,
+ fwnode,
+ struct cal_v4l2_async_subdev);
+ if (IS_ERR(casd)) {
phy_err(phy, "Failed to add subdev to notifier\n");
- ret = PTR_ERR(asd);
+ ret = PTR_ERR(casd);
goto error;
}
- casd = to_cal_asd(asd);
casd->phy = phy;
}
@@ -797,6 +1017,11 @@ static int cal_probe(struct platform_device *pdev)
cal_get_hwinfo(cal);
pm_runtime_put_sync(&pdev->dev);
+ /* Initialize the media device. */
+ ret = cal_media_init(cal);
+ if (ret < 0)
+ goto error_pm_runtime;
+
/* Create CAMERARX PHYs. */
for (i = 0; i < cal->data->num_csi2_phy; ++i) {
cal->phy[i] = cal_camerarx_create(cal, i);
@@ -816,11 +1041,6 @@ static int cal_probe(struct platform_device *pdev)
goto error_camerarx;
}
- /* Initialize the media device. */
- ret = cal_media_init(cal);
- if (ret < 0)
- goto error_camerarx;
-
/* Create contexts. */
for (i = 0; i < cal->data->num_csi2_phy; ++i) {
if (!cal->phy[i]->sensor_node)
@@ -848,12 +1068,12 @@ error_context:
cal_ctx_v4l2_cleanup(ctx);
}
- cal_media_cleanup(cal);
-
error_camerarx:
- for (i = 0; i < ARRAY_SIZE(cal->phy); i++)
+ for (i = 0; i < cal->data->num_csi2_phy; i++)
cal_camerarx_destroy(cal->phy[i]);
+ cal_media_cleanup(cal);
+
error_pm_runtime:
pm_runtime_disable(&pdev->dev);
@@ -878,7 +1098,7 @@ static int cal_remove(struct platform_device *pdev)
cal_media_cleanup(cal);
- for (i = 0; i < ARRAY_SIZE(cal->phy); i++)
+ for (i = 0; i < cal->data->num_csi2_phy; i++)
cal_camerarx_destroy(cal->phy[i]);
pm_runtime_put_sync(&pdev->dev);
@@ -890,16 +1110,23 @@ static int cal_remove(struct platform_device *pdev)
static int cal_runtime_resume(struct device *dev)
{
struct cal_dev *cal = dev_get_drvdata(dev);
+ unsigned int i;
if (cal->data->flags & DRA72_CAL_PRE_ES2_LDO_DISABLE) {
/*
* Apply errata on both port everytime we (re-)enable
* the clock
*/
- cal_camerarx_i913_errata(cal->phy[0]);
- cal_camerarx_i913_errata(cal->phy[1]);
+ for (i = 0; i < cal->data->num_csi2_phy; i++)
+ cal_camerarx_i913_errata(cal->phy[i]);
}
+ /*
+ * Enable global interrupts that are not related to a particular
+ * CAMERARAX or context.
+ */
+ cal_write(cal, CAL_HL_IRQENABLE_SET(0), CAL_HL_IRQ_OCPO_ERR_MASK);
+
return 0;
}