iss.c revision 380df42b5730541a740735052d61e9d2ee09d0ce
159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * TI OMAP4 ISS V4L2 Driver
359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Copyright (C) 2012, Texas Instruments
559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * This program is free software; you can redistribute it and/or modify
959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * it under the terms of the GNU General Public License as published by
1059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * the Free Software Foundation; either version 2 of the License, or
1159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * (at your option) any later version.
1259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
1359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
1459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#include <linux/clk.h>
1559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#include <linux/delay.h>
1659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#include <linux/device.h>
1759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#include <linux/dma-mapping.h>
1859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#include <linux/i2c.h>
1959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#include <linux/interrupt.h>
2059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#include <linux/module.h>
2159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#include <linux/platform_device.h>
2259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#include <linux/slab.h>
2359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#include <linux/sched.h>
2459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#include <linux/vmalloc.h>
2559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
2659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#include <media/v4l2-common.h>
2759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#include <media/v4l2-device.h>
2859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#include <media/v4l2-ctrls.h>
2959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
3059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#include "iss.h"
3159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#include "iss_regs.h"
3259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
3359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#define ISS_PRINT_REGISTER(iss, name)\
3459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	dev_dbg(iss->dev, "###ISS " #name "=0x%08x\n", \
3559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_##name))
3659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
3759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic void iss_print_status(struct iss_device *iss)
3859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
3959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	dev_dbg(iss->dev, "-------------ISS HL Register dump-------------\n");
4059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
4159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ISS_PRINT_REGISTER(iss, HL_REVISION);
4259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ISS_PRINT_REGISTER(iss, HL_SYSCONFIG);
43ade1ec3736c432981fefaa07b20e818c8501a44eLaurent Pinchart	ISS_PRINT_REGISTER(iss, HL_IRQSTATUS(5));
44ade1ec3736c432981fefaa07b20e818c8501a44eLaurent Pinchart	ISS_PRINT_REGISTER(iss, HL_IRQENABLE_SET(5));
45ade1ec3736c432981fefaa07b20e818c8501a44eLaurent Pinchart	ISS_PRINT_REGISTER(iss, HL_IRQENABLE_CLR(5));
4659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ISS_PRINT_REGISTER(iss, CTRL);
4759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ISS_PRINT_REGISTER(iss, CLKCTRL);
4859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ISS_PRINT_REGISTER(iss, CLKSTAT);
4959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
5059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	dev_dbg(iss->dev, "-----------------------------------------------\n");
5159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
5259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
5359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
5459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * omap4iss_flush - Post pending L3 bus writes by doing a register readback
5559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @iss: OMAP4 ISS device
5659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
5759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * In order to force posting of pending writes, we need to write and
5859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * readback the same register, in this case the revision register.
5959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
6059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * See this link for reference:
6159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *   http://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html
6259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
6359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrevoid omap4iss_flush(struct iss_device *iss)
6459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
6559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(0, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_REVISION);
6659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_REVISION);
6759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
6859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
6959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
7059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_enable_interrupts - Enable ISS interrupts.
7159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @iss: OMAP4 ISS device
7259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
7359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic void iss_enable_interrupts(struct iss_device *iss)
7459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
7559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	static const u32 hl_irq = ISS_HL_IRQ_CSIA | ISS_HL_IRQ_CSIB | ISS_HL_IRQ_ISP(0);
7659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
7759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Enable HL interrupts */
78ade1ec3736c432981fefaa07b20e818c8501a44eLaurent Pinchart	writel(hl_irq, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQSTATUS(5));
79ade1ec3736c432981fefaa07b20e818c8501a44eLaurent Pinchart	writel(hl_irq, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQENABLE_SET(5));
8059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
8159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
8259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
8359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
8459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_disable_interrupts - Disable ISS interrupts.
8559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @iss: OMAP4 ISS device
8659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
8759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic void iss_disable_interrupts(struct iss_device *iss)
8859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
89ade1ec3736c432981fefaa07b20e818c8501a44eLaurent Pinchart	writel(-1, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQENABLE_CLR(5));
9059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
9159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
9259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
9359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_isp_enable_interrupts - Enable ISS ISP interrupts.
9459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @iss: OMAP4 ISS device
9559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
9659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrevoid omap4iss_isp_enable_interrupts(struct iss_device *iss)
9759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
9859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	static const u32 isp_irq = ISP5_IRQ_OCP_ERR |
99ade1ec3736c432981fefaa07b20e818c8501a44eLaurent Pinchart				   ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR |
10059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				   ISP5_IRQ_RSZ_FIFO_OVF |
10159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				   ISP5_IRQ_RSZ_INT_DMA |
102ade1ec3736c432981fefaa07b20e818c8501a44eLaurent Pinchart				   ISP5_IRQ_ISIF_INT(0);
10359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
10459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Enable ISP interrupts */
10559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(isp_irq, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_IRQSTATUS(0));
10659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(isp_irq, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_IRQENABLE_SET(0));
10759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
10859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
10959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
11059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_isp_disable_interrupts - Disable ISS interrupts.
11159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @iss: OMAP4 ISS device
11259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
11359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrevoid omap4iss_isp_disable_interrupts(struct iss_device *iss)
11459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
11559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(-1, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_IRQENABLE_CLR(0));
11659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
11759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
11859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreint omap4iss_get_external_info(struct iss_pipeline *pipe,
11959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			       struct media_link *link)
12059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
12159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_device *iss =
12259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		container_of(pipe, struct iss_video, pipe)->iss;
12359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct v4l2_subdev_format fmt;
124ea72717e961d1166882370a87876bfeacc967eb0Laurent Pinchart	struct v4l2_ctrl *ctrl;
12559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret;
12659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
12759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!pipe->external)
12859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
12959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
13059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (pipe->external_rate)
13159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
13259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
13359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	memset(&fmt, 0, sizeof(fmt));
13459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
13559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	fmt.pad = link->source->index;
13659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
13759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = v4l2_subdev_call(media_entity_to_v4l2_subdev(link->sink->entity),
13859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			       pad, get_fmt, NULL, &fmt);
13959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
14059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return -EPIPE;
14159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
14259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	pipe->external_bpp = omap4iss_video_format_info(fmt.format.code)->bpp;
14359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
144ea72717e961d1166882370a87876bfeacc967eb0Laurent Pinchart	ctrl = v4l2_ctrl_find(pipe->external->ctrl_handler,
145ea72717e961d1166882370a87876bfeacc967eb0Laurent Pinchart			      V4L2_CID_PIXEL_RATE);
146ea72717e961d1166882370a87876bfeacc967eb0Laurent Pinchart	if (ctrl == NULL) {
14759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_warn(iss->dev, "no pixel rate control in subdev %s\n",
14859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			 pipe->external->name);
149ea72717e961d1166882370a87876bfeacc967eb0Laurent Pinchart		return -EPIPE;
15059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
15159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
152ea72717e961d1166882370a87876bfeacc967eb0Laurent Pinchart	pipe->external_rate = v4l2_ctrl_g_ctrl_int64(ctrl);
15359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
15459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
15559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
15659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
15759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
15859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Configure the bridge. Valid inputs are
15959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
16059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * IPIPEIF_INPUT_CSI2A: CSI2a receiver
16159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * IPIPEIF_INPUT_CSI2B: CSI2b receiver
16259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
16359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * The bridge and lane shifter are configured according to the selected input
16459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * and the ISP platform data.
16559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
16659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrevoid omap4iss_configure_bridge(struct iss_device *iss,
16759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			       enum ipipeif_input_entity input)
16859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
16959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	u32 issctrl_val;
17059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	u32 isp5ctrl_val;
17159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
17259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	issctrl_val  = readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CTRL);
17359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	issctrl_val &= ~ISS_CTRL_INPUT_SEL_MASK;
17459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	issctrl_val &= ~ISS_CTRL_CLK_DIV_MASK;
17559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
17659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	isp5ctrl_val  = readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL);
17759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
17859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	switch (input) {
17959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	case IPIPEIF_INPUT_CSI2A:
18059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		issctrl_val |= ISS_CTRL_INPUT_SEL_CSI2A;
18159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		break;
18259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
18359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	case IPIPEIF_INPUT_CSI2B:
18459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		issctrl_val |= ISS_CTRL_INPUT_SEL_CSI2B;
18559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		break;
18659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
18759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	default:
18859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return;
18959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
19059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
19159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	issctrl_val |= ISS_CTRL_SYNC_DETECT_VS_RAISING;
19259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
193cce093ee559779d376fbd767d70a5b0ce4cf015aLaurent Pinchart	isp5ctrl_val |= ISP5_CTRL_VD_PULSE_EXT | ISP5_CTRL_PSYNC_CLK_SEL |
194cce093ee559779d376fbd767d70a5b0ce4cf015aLaurent Pinchart			ISP5_CTRL_SYNC_ENABLE;
19559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
19659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(issctrl_val, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CTRL);
19759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(isp5ctrl_val, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL);
19859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
19959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
2005122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart#if defined(DEBUG) && defined(ISS_ISR_DEBUG)
201380df42b5730541a740735052d61e9d2ee09d0ceLaurent Pinchartstatic void iss_isr_dbg(struct iss_device *iss, u32 irqstatus)
20259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
2035122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart	static const char * const name[] = {
2045122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"ISP_0",
2055122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"ISP_1",
2065122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"ISP_2",
2075122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"ISP_3",
2085122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"CSIA",
2095122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"CSIB",
2105122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"CCP2_0",
2115122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"CCP2_1",
2125122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"CCP2_2",
2135122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"CCP2_3",
2145122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"CBUFF",
2155122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"BTE",
2165122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"SIMCOP_0",
2175122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"SIMCOP_1",
2185122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"SIMCOP_2",
2195122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"SIMCOP_3",
2205122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"CCP2_8",
2215122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"HS_VS",
2225122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"18",
2235122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"19",
2245122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"20",
2255122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"21",
2265122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"22",
2275122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"23",
2285122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"24",
2295122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"25",
2305122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"26",
2315122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"27",
2325122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"28",
2335122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"29",
2345122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"30",
2355122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"31",
23659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	};
2375122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart	unsigned int i;
23859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
23959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	dev_dbg(iss->dev, "ISS IRQ: ");
24059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
24159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	for (i = 0; i < ARRAY_SIZE(name); i++) {
24259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if ((1 << i) & irqstatus)
24359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			pr_cont("%s ", name[i]);
24459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
24559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	pr_cont("\n");
24659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
24759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
248380df42b5730541a740735052d61e9d2ee09d0ceLaurent Pinchartstatic void iss_isp_isr_dbg(struct iss_device *iss, u32 irqstatus)
2495122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart{
2505122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart	static const char * const name[] = {
2515122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"ISIF_0",
2525122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"ISIF_1",
2535122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"ISIF_2",
2545122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"ISIF_3",
2555122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"IPIPEREQ",
2565122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"IPIPELAST_PIX",
2575122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"IPIPEDMA",
2585122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"IPIPEBSC",
2595122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"IPIPEHST",
2605122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"IPIPEIF",
2615122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"AEW",
2625122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"AF",
2635122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"H3A",
2645122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"RSZ_REG",
2655122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"RSZ_LAST_PIX",
2665122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"RSZ_DMA",
2675122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"RSZ_CYC_RZA",
2685122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"RSZ_CYC_RZB",
2695122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"RSZ_FIFO_OVF",
2705122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"RSZ_FIFO_IN_BLK_ERR",
2715122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"20",
2725122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"21",
2735122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"RSZ_EOF0",
2745122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"RSZ_EOF1",
2755122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"H3A_EOF",
2765122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"IPIPE_EOF",
2775122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"26",
2785122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"IPIPE_DPC_INI",
2795122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"IPIPE_DPC_RNEW0",
2805122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"IPIPE_DPC_RNEW1",
2815122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"30",
2825122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		"OCP_ERR",
2835122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart	};
2845122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart	unsigned int i;
2855122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart
2865122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart	dev_dbg(iss->dev, "ISP IRQ: ");
2875122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart
2885122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart	for (i = 0; i < ARRAY_SIZE(name); i++) {
2895122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		if ((1 << i) & irqstatus)
2905122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart			pr_cont("%s ", name[i]);
2915122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart	}
2925122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart	pr_cont("\n");
2935122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart}
2945122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart#endif
2955122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart
29659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
29759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_isr - Interrupt Service Routine for ISS module.
29859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @irq: Not used currently.
29959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @_iss: Pointer to the OMAP4 ISS device
30059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
30159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Handles the corresponding callback if plugged in.
30259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
30359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the
30459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * IRQ wasn't handled.
30559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
30659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic irqreturn_t iss_isr(int irq, void *_iss)
30759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
308ade1ec3736c432981fefaa07b20e818c8501a44eLaurent Pinchart	static const u32 ipipeif_events = ISP5_IRQ_IPIPEIF_IRQ |
309ade1ec3736c432981fefaa07b20e818c8501a44eLaurent Pinchart					  ISP5_IRQ_ISIF_INT(0);
310ade1ec3736c432981fefaa07b20e818c8501a44eLaurent Pinchart	static const u32 resizer_events = ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR |
31159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					  ISP5_IRQ_RSZ_FIFO_OVF |
31259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					  ISP5_IRQ_RSZ_INT_DMA;
31359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_device *iss = _iss;
31459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	u32 irqstatus;
31559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
316ade1ec3736c432981fefaa07b20e818c8501a44eLaurent Pinchart	irqstatus = readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQSTATUS(5));
317ade1ec3736c432981fefaa07b20e818c8501a44eLaurent Pinchart	writel(irqstatus, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQSTATUS(5));
31859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
31959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (irqstatus & ISS_HL_IRQ_CSIA)
32059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		omap4iss_csi2_isr(&iss->csi2a);
32159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
32259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (irqstatus & ISS_HL_IRQ_CSIB)
32359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		omap4iss_csi2_isr(&iss->csi2b);
32459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
32559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (irqstatus & ISS_HL_IRQ_ISP(0)) {
32659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		u32 isp_irqstatus = readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] +
32759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					  ISP5_IRQSTATUS(0));
32859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		writel(isp_irqstatus, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] +
32959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			ISP5_IRQSTATUS(0));
33059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
33159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (isp_irqstatus & ISP5_IRQ_OCP_ERR)
33259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			dev_dbg(iss->dev, "ISP5 OCP Error!\n");
33359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
33459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (isp_irqstatus & ipipeif_events) {
33559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			omap4iss_ipipeif_isr(&iss->ipipeif,
33659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					     isp_irqstatus & ipipeif_events);
33759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
33859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
33959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (isp_irqstatus & resizer_events)
34059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			omap4iss_resizer_isr(&iss->resizer,
34159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					     isp_irqstatus & resizer_events);
3425122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart
3435122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart#if defined(DEBUG) && defined(ISS_ISR_DEBUG)
3445122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart		iss_isp_isr_dbg(iss, isp_irqstatus);
3455122f6a26d4e706653e1677708594b82b1ec7cd3Laurent Pinchart#endif
34659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
34759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
34859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_flush(iss);
34959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
35059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#if defined(DEBUG) && defined(ISS_ISR_DEBUG)
35159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss_isr_dbg(iss, irqstatus);
35259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#endif
35359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
35459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return IRQ_HANDLED;
35559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
35659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
35759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/* -----------------------------------------------------------------------------
35859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Pipeline power management
35959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
36059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Entities must be powered up when part of a pipeline that contains at least
36159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * one open video device node.
36259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
36359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * To achieve this use the entity use_count field to track the number of users.
36459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * For entities corresponding to video device nodes the use_count field stores
36559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * the users count of the node. For entities corresponding to subdevs the
36659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * use_count field stores the total number of users of all video device nodes
36759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * in the pipeline.
36859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
36959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * The omap4iss_pipeline_pm_use() function must be called in the open() and
37059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * close() handlers of video device nodes. It increments or decrements the use
37159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * count of all subdev entities in the pipeline.
37259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
37359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * To react to link management on powered pipelines, the link setup notification
37459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * callback updates the use count of all entities in the source and sink sides
37559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * of the link.
37659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
37759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
37859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
37959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_pipeline_pm_use_count - Count the number of users of a pipeline
38059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @entity: The entity
38159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
38259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return the total number of users of all video device nodes in the pipeline.
38359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
38459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_pipeline_pm_use_count(struct media_entity *entity)
38559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
38659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_entity_graph graph;
38759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int use = 0;
38859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
38959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	media_entity_graph_walk_start(&graph, entity);
39059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
39159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	while ((entity = media_entity_graph_walk_next(&graph))) {
39259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
39359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			use += entity->use_count;
39459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
39559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
39659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return use;
39759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
39859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
39959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
40059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_pipeline_pm_power_one - Apply power change to an entity
40159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @entity: The entity
40259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @change: Use count change
40359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
40459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Change the entity use count by @change. If the entity is a subdev update its
40559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * power state by calling the core::s_power operation when the use count goes
40659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * from 0 to != 0 or from != 0 to 0.
40759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
40859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return 0 on success or a negative error code on failure.
40959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
41059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_pipeline_pm_power_one(struct media_entity *entity, int change)
41159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
41259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct v4l2_subdev *subdev;
41359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
41459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	subdev = media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV
41559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	       ? media_entity_to_v4l2_subdev(entity) : NULL;
41659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
41759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (entity->use_count == 0 && change > 0 && subdev != NULL) {
41859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		int ret;
41959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
42059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = v4l2_subdev_call(subdev, core, s_power, 1);
42159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (ret < 0 && ret != -ENOIOCTLCMD)
42259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			return ret;
42359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
42459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
42559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	entity->use_count += change;
42659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	WARN_ON(entity->use_count < 0);
42759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
42859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (entity->use_count == 0 && change < 0 && subdev != NULL)
42959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		v4l2_subdev_call(subdev, core, s_power, 0);
43059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
43159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
43259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
43359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
43459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
43559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_pipeline_pm_power - Apply power change to all entities in a pipeline
43659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @entity: The entity
43759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @change: Use count change
43859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
43959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Walk the pipeline to update the use count and the power state of all non-node
44059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * entities.
44159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
44259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return 0 on success or a negative error code on failure.
44359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
44459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_pipeline_pm_power(struct media_entity *entity, int change)
44559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
44659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_entity_graph graph;
44759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_entity *first = entity;
44859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret = 0;
44959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
45059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!change)
45159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
45259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
45359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	media_entity_graph_walk_start(&graph, entity);
45459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
45559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	while (!ret && (entity = media_entity_graph_walk_next(&graph)))
45659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
45759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			ret = iss_pipeline_pm_power_one(entity, change);
45859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
45959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!ret)
46059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
46159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
46259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	media_entity_graph_walk_start(&graph, first);
46359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
46459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	while ((first = media_entity_graph_walk_next(&graph))
46559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	       && first != entity)
46659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE)
46759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			iss_pipeline_pm_power_one(first, -change);
46859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
46959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return ret;
47059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
47159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
47259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
47359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * omap4iss_pipeline_pm_use - Update the use count of an entity
47459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @entity: The entity
47559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @use: Use (1) or stop using (0) the entity
47659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
47759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Update the use count of all entities in the pipeline and power entities on or
47859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * off accordingly.
47959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
48059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return 0 on success or a negative error code on failure. Powering entities
48159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * off is assumed to never fail. No failure can occur when the use parameter is
48259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * set to 0.
48359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
48459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreint omap4iss_pipeline_pm_use(struct media_entity *entity, int use)
48559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
48659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int change = use ? 1 : -1;
48759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret;
48859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
48959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mutex_lock(&entity->parent->graph_mutex);
49059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
49159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Apply use count to node. */
49259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	entity->use_count += change;
49359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	WARN_ON(entity->use_count < 0);
49459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
49559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Apply power change to connected non-nodes. */
49659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = iss_pipeline_pm_power(entity, change);
49759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
49859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		entity->use_count -= change;
49959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
50059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mutex_unlock(&entity->parent->graph_mutex);
50159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
50259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return ret;
50359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
50459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
50559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
50659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_pipeline_link_notify - Link management notification callback
50759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @link: The link
50859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @flags: New link flags that will be applied
50959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
51059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * React to link management on powered pipelines by updating the use count of
51159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * all entities in the source and sink sides of the link. Entities are powered
51259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * on or off accordingly.
51359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
51459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return 0 on success or a negative error code on failure. Powering entities
51559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * off is assumed to never fail. This function will not fail for disconnection
51659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * events.
51759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
51859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_pipeline_link_notify(struct media_link *link, u32 flags,
51959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				    unsigned int notification)
52059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
52159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_entity *source = link->source->entity;
52259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_entity *sink = link->sink->entity;
52359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int source_use = iss_pipeline_pm_use_count(source);
52459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int sink_use = iss_pipeline_pm_use_count(sink);
52559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret;
52659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
52759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
52859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	    !(link->flags & MEDIA_LNK_FL_ENABLED)) {
52959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		/* Powering off entities is assumed to never fail. */
53059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss_pipeline_pm_power(source, -sink_use);
53159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss_pipeline_pm_power(sink, -source_use);
53259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
53359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
53459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
53559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
53659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		(flags & MEDIA_LNK_FL_ENABLED)) {
53759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = iss_pipeline_pm_power(source, sink_use);
53859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (ret < 0)
53959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			return ret;
54059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
54159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = iss_pipeline_pm_power(sink, source_use);
54259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (ret < 0)
54359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			iss_pipeline_pm_power(source, -sink_use);
54459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
54559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return ret;
54659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
54759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
54859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
54959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
55059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
55159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/* -----------------------------------------------------------------------------
55259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Pipeline stream management
55359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
55459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
55559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
55659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_pipeline_enable - Enable streaming on a pipeline
55759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @pipe: ISS pipeline
55859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @mode: Stream mode (single shot or continuous)
55959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
56059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Walk the entities chain starting at the pipeline output video node and start
56159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * all modules in the chain in the given mode.
56259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
56359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return 0 if successful, or the return value of the failed video::s_stream
56459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * operation otherwise.
56559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
56659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_pipeline_enable(struct iss_pipeline *pipe,
56759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			       enum iss_pipeline_stream_state mode)
56859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
56959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_entity *entity;
57059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_pad *pad;
57159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct v4l2_subdev *subdev;
57259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	unsigned long flags;
57359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret;
57459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
57559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	spin_lock_irqsave(&pipe->lock, flags);
57659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	pipe->state &= ~(ISS_PIPELINE_IDLE_INPUT | ISS_PIPELINE_IDLE_OUTPUT);
57759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	spin_unlock_irqrestore(&pipe->lock, flags);
57859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
57959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	pipe->do_propagation = false;
58059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
58159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	entity = &pipe->output->video.entity;
58259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	while (1) {
58359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		pad = &entity->pads[0];
58459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (!(pad->flags & MEDIA_PAD_FL_SINK))
58559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			break;
58659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
58759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		pad = media_entity_remote_pad(pad);
58859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (pad == NULL ||
58959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
59059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			break;
59159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
59259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		entity = pad->entity;
59359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		subdev = media_entity_to_v4l2_subdev(entity);
59459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
59559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = v4l2_subdev_call(subdev, video, s_stream, mode);
59659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (ret < 0 && ret != -ENOIOCTLCMD)
59759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			return ret;
59859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
59959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss_print_status(pipe->output->iss);
60059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
60159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
60259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
60359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
60459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_pipeline_disable - Disable streaming on a pipeline
60559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @pipe: ISS pipeline
60659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
60759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Walk the entities chain starting at the pipeline output video node and stop
60859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * all modules in the chain. Wait synchronously for the modules to be stopped if
60959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * necessary.
61059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
61159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_pipeline_disable(struct iss_pipeline *pipe)
61259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
61359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_entity *entity;
61459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_pad *pad;
61559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct v4l2_subdev *subdev;
61659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
61759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	entity = &pipe->output->video.entity;
61859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	while (1) {
61959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		pad = &entity->pads[0];
62059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (!(pad->flags & MEDIA_PAD_FL_SINK))
62159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			break;
62259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
62359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		pad = media_entity_remote_pad(pad);
62459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (pad == NULL ||
62559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
62659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			break;
62759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
62859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		entity = pad->entity;
62959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		subdev = media_entity_to_v4l2_subdev(entity);
63059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
63159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		v4l2_subdev_call(subdev, video, s_stream, 0);
63259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
63359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
63457da5e47ccf3d727958aeef7675154d48635fa09Laurent Pinchart	return 0;
63559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
63659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
63759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
63859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * omap4iss_pipeline_set_stream - Enable/disable streaming on a pipeline
63959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @pipe: ISS pipeline
64059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @state: Stream state (stopped, single shot or continuous)
64159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
64259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Set the pipeline to the given stream state. Pipelines can be started in
64359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * single-shot or continuous mode.
64459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
64559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return 0 if successful, or the return value of the failed video::s_stream
64659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * operation otherwise. The pipeline state is not updated when the operation
64759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * fails, except when stopping the pipeline.
64859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
64959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreint omap4iss_pipeline_set_stream(struct iss_pipeline *pipe,
65059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				 enum iss_pipeline_stream_state state)
65159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
65259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret;
65359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
65459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (state == ISS_PIPELINE_STREAM_STOPPED)
65559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = iss_pipeline_disable(pipe);
65659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	else
65759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = iss_pipeline_enable(pipe, state);
65859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
65959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret == 0 || state == ISS_PIPELINE_STREAM_STOPPED)
66059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		pipe->stream_state = state;
66159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
66259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return ret;
66359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
66459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
66559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
66659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_pipeline_is_last - Verify if entity has an enabled link to the output
66759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *			  video node
66859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @me: ISS module's media entity
66959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
67059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Returns 1 if the entity has an enabled link to the output video node or 0
67159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * otherwise. It's true only while pipeline can have no more than one output
67259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * node.
67359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
67459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_pipeline_is_last(struct media_entity *me)
67559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
67659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_pipeline *pipe;
67759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_pad *pad;
67859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
67959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!me->pipe)
68059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
68159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	pipe = to_iss_pipeline(me);
68259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED)
68359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
68459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	pad = media_entity_remote_pad(&pipe->output->pad);
68559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return pad->entity == me;
68659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
68759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
68859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_reset(struct iss_device *iss)
68959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
69059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	unsigned long timeout = 0;
69159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
69259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_SYSCONFIG) |
69359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ISS_HL_SYSCONFIG_SOFTRESET,
69459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_SYSCONFIG);
69559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
69659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	while (readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_SYSCONFIG) &
69759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			ISS_HL_SYSCONFIG_SOFTRESET) {
698ca6f19b1cf0fac0fdf1ef06d6bed0f07f8f37ae9Laurent Pinchart		if (timeout++ > 100) {
69959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			dev_alert(iss->dev, "cannot reset ISS\n");
70059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			return -ETIMEDOUT;
70159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
702ca6f19b1cf0fac0fdf1ef06d6bed0f07f8f37ae9Laurent Pinchart		usleep_range(10, 10);
70359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
70459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
70559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
70659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
70759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
70859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_isp_reset(struct iss_device *iss)
70959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
71059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	unsigned long timeout = 0;
71159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
71259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Fist, ensure that the ISP is IDLE (no transactions happening) */
71359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel((readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG) &
71459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		~ISP5_SYSCONFIG_STANDBYMODE_MASK) |
71559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ISP5_SYSCONFIG_STANDBYMODE_SMART,
71659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG);
71759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
71859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL) |
71959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ISP5_CTRL_MSTANDBY,
72059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL);
72159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
72259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	for (;;) {
72359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL) &
72459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				ISP5_CTRL_MSTANDBY_WAIT)
72559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			break;
72659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (timeout++ > 1000) {
72759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			dev_alert(iss->dev, "cannot set ISP5 to standby\n");
72859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			return -ETIMEDOUT;
72959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
730ca6f19b1cf0fac0fdf1ef06d6bed0f07f8f37ae9Laurent Pinchart		usleep_range(1000, 1500);
73159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
73259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
73359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Now finally, do the reset */
73459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG) |
73559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ISP5_SYSCONFIG_SOFTRESET,
73659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG);
73759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
73859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	timeout = 0;
73959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	while (readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG) &
74059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			ISP5_SYSCONFIG_SOFTRESET) {
74159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (timeout++ > 1000) {
74259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			dev_alert(iss->dev, "cannot reset ISP5\n");
74359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			return -ETIMEDOUT;
74459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
745ca6f19b1cf0fac0fdf1ef06d6bed0f07f8f37ae9Laurent Pinchart		usleep_range(1000, 1500);
74659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
74759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
74859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
74959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
75059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
75159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
75259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_module_sync_idle - Helper to sync module with its idle state
75359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @me: ISS submodule's media entity
75459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization
75559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @stopping: flag which tells module wants to stop
75659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
75759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * This function checks if ISS submodule needs to wait for next interrupt. If
75859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * yes, makes the caller to sleep while waiting for such event.
75959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
76059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreint omap4iss_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
76159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			      atomic_t *stopping)
76259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
76359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_pipeline *pipe = to_iss_pipeline(me);
76459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_video *video = pipe->output;
76559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	unsigned long flags;
76659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
76759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED ||
76859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	    (pipe->stream_state == ISS_PIPELINE_STREAM_SINGLESHOT &&
76959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	     !iss_pipeline_ready(pipe)))
77059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
77159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
77259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/*
77359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * atomic_set() doesn't include memory barrier on ARM platform for SMP
77459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * scenario. We'll call it here to avoid race conditions.
77559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 */
77659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	atomic_set(stopping, 1);
77759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	smp_wmb();
77859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
77959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/*
78059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * If module is the last one, it's writing to memory. In this case,
78159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * it's necessary to check if the module is already paused due to
78259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * DMA queue underrun or if it has to wait for next interrupt to be
78359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * idle.
78459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * If it isn't the last one, the function won't sleep but *stopping
78559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * will still be set to warn next submodule caller's interrupt the
78659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * module wants to be idle.
78759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 */
78859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!iss_pipeline_is_last(me))
78959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
79059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
79159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	spin_lock_irqsave(&video->qlock, flags);
79259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (video->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) {
79359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		spin_unlock_irqrestore(&video->qlock, flags);
79459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		atomic_set(stopping, 0);
79559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		smp_wmb();
79659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
79759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
79859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	spin_unlock_irqrestore(&video->qlock, flags);
79959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!wait_event_timeout(*wait, !atomic_read(stopping),
80059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				msecs_to_jiffies(1000))) {
80159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		atomic_set(stopping, 0);
80259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		smp_wmb();
80359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return -ETIMEDOUT;
80459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
80559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
80659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
80759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
80859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
80959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
81059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * omap4iss_module_sync_is_stopped - Helper to verify if module was stopping
81159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization
81259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @stopping: flag which tells module wants to stop
81359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
81459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * This function checks if ISS submodule was stopping. In case of yes, it
81559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * notices the caller by setting stopping to 0 and waking up the wait queue.
81659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Returns 1 if it was stopping or 0 otherwise.
81759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
81859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreint omap4iss_module_sync_is_stopping(wait_queue_head_t *wait,
81959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				     atomic_t *stopping)
82059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
82159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (atomic_cmpxchg(stopping, 1, 0)) {
82259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		wake_up(wait);
82359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 1;
82459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
82559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
82659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
82759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
82859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
82959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/* --------------------------------------------------------------------------
83059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Clock management
83159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
83259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
83359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#define ISS_CLKCTRL_MASK	(ISS_CLKCTRL_CSI2_A |\
83459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				 ISS_CLKCTRL_CSI2_B |\
83559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				 ISS_CLKCTRL_ISP)
83659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
83759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int __iss_subclk_update(struct iss_device *iss)
83859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
83959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	u32 clk = 0;
84059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret = 0, timeout = 1000;
84159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
84259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_A)
84359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISS_CLKCTRL_CSI2_A;
84459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
84559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_B)
84659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISS_CLKCTRL_CSI2_B;
84759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
84859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->subclk_resources & OMAP4_ISS_SUBCLK_ISP)
84959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISS_CLKCTRL_ISP;
85059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
85159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel((readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CLKCTRL) &
85259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		~ISS_CLKCTRL_MASK) | clk,
85359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CLKCTRL);
85459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
85559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Wait for HW assertion */
85659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	while (--timeout > 0) {
85759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		udelay(1);
85859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if ((readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CLKSTAT) &
85959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		     ISS_CLKCTRL_MASK) == clk)
86059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			break;
86159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
86259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
86359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!timeout)
86459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = -EBUSY;
86559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
86659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return ret;
86759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
86859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
86959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreint omap4iss_subclk_enable(struct iss_device *iss,
87059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			    enum iss_subclk_resource res)
87159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
87259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->subclk_resources |= res;
87359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
87459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return __iss_subclk_update(iss);
87559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
87659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
87759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreint omap4iss_subclk_disable(struct iss_device *iss,
87859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			     enum iss_subclk_resource res)
87959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
88059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->subclk_resources &= ~res;
88159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
88259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return __iss_subclk_update(iss);
88359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
88459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
88559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#define ISS_ISP5_CLKCTRL_MASK	(ISP5_CTRL_BL_CLK_ENABLE |\
88659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				 ISP5_CTRL_ISIF_CLK_ENABLE |\
88759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				 ISP5_CTRL_H3A_CLK_ENABLE |\
88859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				 ISP5_CTRL_RSZ_CLK_ENABLE |\
88959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				 ISP5_CTRL_IPIPE_CLK_ENABLE |\
89059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				 ISP5_CTRL_IPIPEIF_CLK_ENABLE)
89159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
89268c03a666c36068428fed43010bde521d4341079Laurent Pinchartstatic void __iss_isp_subclk_update(struct iss_device *iss)
89359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
89459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	u32 clk = 0;
89559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
89659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_ISIF)
89759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISP5_CTRL_ISIF_CLK_ENABLE;
89859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
89959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_H3A)
90059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISP5_CTRL_H3A_CLK_ENABLE;
90159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
90259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_RSZ)
90359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISP5_CTRL_RSZ_CLK_ENABLE;
90459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
90559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPE)
90659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISP5_CTRL_IPIPE_CLK_ENABLE;
90759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
90859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPEIF)
90959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISP5_CTRL_IPIPEIF_CLK_ENABLE;
91059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
91159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (clk)
91259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISP5_CTRL_BL_CLK_ENABLE;
91359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
91459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel((readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL) &
91559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		~ISS_ISP5_CLKCTRL_MASK) | clk,
91659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL);
91759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
91859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
91968c03a666c36068428fed43010bde521d4341079Laurent Pinchartvoid omap4iss_isp_subclk_enable(struct iss_device *iss,
92059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				enum iss_isp_subclk_resource res)
92159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
92259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->isp_subclk_resources |= res;
92359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
92468c03a666c36068428fed43010bde521d4341079Laurent Pinchart	__iss_isp_subclk_update(iss);
92559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
92659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
92768c03a666c36068428fed43010bde521d4341079Laurent Pinchartvoid omap4iss_isp_subclk_disable(struct iss_device *iss,
92868c03a666c36068428fed43010bde521d4341079Laurent Pinchart				 enum iss_isp_subclk_resource res)
92959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
93059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->isp_subclk_resources &= ~res;
93159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
93268c03a666c36068428fed43010bde521d4341079Laurent Pinchart	__iss_isp_subclk_update(iss);
93359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
93459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
93559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
93659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_enable_clocks - Enable ISS clocks
93759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @iss: OMAP4 ISS device
93859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
93959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return 0 if successful, or clk_enable return value if any of tthem fails.
94059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
94159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_enable_clocks(struct iss_device *iss)
94259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
9432b16b44a1c44814ed00cf750d20f3c404b5d4e48Laurent Pinchart	int ret;
94459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
9452b16b44a1c44814ed00cf750d20f3c404b5d4e48Laurent Pinchart	ret = clk_enable(iss->iss_fck);
9462b16b44a1c44814ed00cf750d20f3c404b5d4e48Laurent Pinchart	if (ret) {
94759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "clk_enable iss_fck failed\n");
9482b16b44a1c44814ed00cf750d20f3c404b5d4e48Laurent Pinchart		return ret;
94959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
95059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
9512b16b44a1c44814ed00cf750d20f3c404b5d4e48Laurent Pinchart	ret = clk_enable(iss->iss_ctrlclk);
9522b16b44a1c44814ed00cf750d20f3c404b5d4e48Laurent Pinchart	if (ret) {
95359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "clk_enable iss_ctrlclk failed\n");
9542b16b44a1c44814ed00cf750d20f3c404b5d4e48Laurent Pinchart		clk_disable(iss->iss_fck);
9552b16b44a1c44814ed00cf750d20f3c404b5d4e48Laurent Pinchart		return ret;
95659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
95759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
9582b16b44a1c44814ed00cf750d20f3c404b5d4e48Laurent Pinchart	return 0;
95959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
96059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
96159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
96259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_disable_clocks - Disable ISS clocks
96359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @iss: OMAP4 ISS device
96459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
96559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic void iss_disable_clocks(struct iss_device *iss)
96659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
96759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	clk_disable(iss->iss_ctrlclk);
96859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	clk_disable(iss->iss_fck);
96959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
97059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
97159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic void iss_put_clocks(struct iss_device *iss)
97259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
97359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->iss_fck) {
97459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk_put(iss->iss_fck);
97559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->iss_fck = NULL;
97659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
97759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
97859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->iss_ctrlclk) {
97959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk_put(iss->iss_ctrlclk);
98059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->iss_ctrlclk = NULL;
98159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
98259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
98359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
98459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_get_clocks(struct iss_device *iss)
98559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
98659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->iss_fck = clk_get(iss->dev, "iss_fck");
98759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (IS_ERR(iss->iss_fck)) {
98859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "Unable to get iss_fck clock info\n");
98959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss_put_clocks(iss);
99059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return PTR_ERR(iss->iss_fck);
99159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
99259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
99359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->iss_ctrlclk = clk_get(iss->dev, "iss_ctrlclk");
99459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (IS_ERR(iss->iss_ctrlclk)) {
99559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "Unable to get iss_ctrlclk clock info\n");
99659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss_put_clocks(iss);
99759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return PTR_ERR(iss->iss_fck);
99859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
99959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
100059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
100159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
100259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
100359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
100459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * omap4iss_get - Acquire the ISS resource.
100559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
100659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Initializes the clocks for the first acquire.
100759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
100859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Increment the reference count on the ISS. If the first reference is taken,
100959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * enable clocks and power-up all submodules.
101059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
101159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return a pointer to the ISS device structure, or NULL if an error occurred.
101259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
101359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestruct iss_device *omap4iss_get(struct iss_device *iss)
101459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
101559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_device *__iss = iss;
101659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
101759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss == NULL)
101859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return NULL;
101959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
102059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mutex_lock(&iss->iss_mutex);
102159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->ref_count > 0)
102259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto out;
102359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
102459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss_enable_clocks(iss) < 0) {
102559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		__iss = NULL;
102659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto out;
102759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
102859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
102959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss_enable_interrupts(iss);
103059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
103159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreout:
103259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (__iss != NULL)
103359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->ref_count++;
103459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mutex_unlock(&iss->iss_mutex);
103559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
103659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return __iss;
103759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
103859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
103959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
104059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * omap4iss_put - Release the ISS
104159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
104259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Decrement the reference count on the ISS. If the last reference is released,
104359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * power-down all submodules, disable clocks and free temporary buffers.
104459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
104559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrevoid omap4iss_put(struct iss_device *iss)
104659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
104759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss == NULL)
104859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return;
104959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
105059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mutex_lock(&iss->iss_mutex);
105159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	BUG_ON(iss->ref_count == 0);
105259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (--iss->ref_count == 0) {
105359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss_disable_interrupts(iss);
105459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss_disable_clocks(iss);
105559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
105659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mutex_unlock(&iss->iss_mutex);
105759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
105859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
105959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_map_mem_resource(struct platform_device *pdev,
106059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				struct iss_device *iss,
106159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				enum iss_mem_resources res)
106259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
106359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct resource *mem;
106459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
106559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* request the mem region for the camera registers */
106659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
106759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mem = platform_get_resource(pdev, IORESOURCE_MEM, res);
106859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!mem) {
106959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "no mem resource?\n");
107059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return -ENODEV;
107159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
107259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
107359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
107459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev,
107559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			"cannot reserve camera register I/O region\n");
107659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return -ENODEV;
107759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
107859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->res[res] = mem;
107959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
108059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* map the region */
108159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->regs[res] = ioremap_nocache(mem->start, resource_size(mem));
108259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!iss->regs[res]) {
108359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "cannot map camera register I/O region\n");
108459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return -ENODEV;
108559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
108659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
108759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
108859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
108959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
109059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic void iss_unregister_entities(struct iss_device *iss)
109159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
109259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_resizer_unregister_entities(&iss->resizer);
109359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_ipipe_unregister_entities(&iss->ipipe);
109459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_ipipeif_unregister_entities(&iss->ipipeif);
109559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_csi2_unregister_entities(&iss->csi2a);
109659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_csi2_unregister_entities(&iss->csi2b);
109759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
109859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	v4l2_device_unregister(&iss->v4l2_dev);
109959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	media_device_unregister(&iss->media_dev);
110059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
110159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
110259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
110359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_register_subdev_group - Register a group of subdevices
110459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @iss: OMAP4 ISS device
110559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @board_info: I2C subdevs board information array
110659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
110759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Register all I2C subdevices in the board_info array. The array must be
110859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * terminated by a NULL entry, and the first entry must be the sensor.
110959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
111059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return a pointer to the sensor media entity if it has been successfully
111159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * registered, or NULL otherwise.
111259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
111359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic struct v4l2_subdev *
111459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreiss_register_subdev_group(struct iss_device *iss,
111559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		     struct iss_subdev_i2c_board_info *board_info)
111659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
111759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct v4l2_subdev *sensor = NULL;
111859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	unsigned int first;
111959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
112059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (board_info->board_info == NULL)
112159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return NULL;
112259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
112359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	for (first = 1; board_info->board_info; ++board_info, first = 0) {
112459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		struct v4l2_subdev *subdev;
112559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		struct i2c_adapter *adapter;
112659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
112759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		adapter = i2c_get_adapter(board_info->i2c_adapter_id);
112859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (adapter == NULL) {
1129499226fb196fef838fa38700b96448a2ec41b704Laurent Pinchart			dev_err(iss->dev,
1130499226fb196fef838fa38700b96448a2ec41b704Laurent Pinchart				"%s: Unable to get I2C adapter %d for device %s\n",
1131499226fb196fef838fa38700b96448a2ec41b704Laurent Pinchart				__func__, board_info->i2c_adapter_id,
113259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				board_info->board_info->type);
113359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			continue;
113459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
113559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
113659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		subdev = v4l2_i2c_new_subdev_board(&iss->v4l2_dev, adapter,
113759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				board_info->board_info, NULL);
113859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (subdev == NULL) {
113959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			dev_err(iss->dev, "%s: Unable to register subdev %s\n",
114059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				__func__, board_info->board_info->type);
114159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			continue;
114259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
114359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
114459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (first)
114559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			sensor = subdev;
114659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
114759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
114859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return sensor;
114959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
115059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
115159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_register_entities(struct iss_device *iss)
115259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
115359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_platform_data *pdata = iss->pdata;
115459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_v4l2_subdevs_group *subdevs;
115559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret;
115659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
115759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->media_dev.dev = iss->dev;
115859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	strlcpy(iss->media_dev.model, "TI OMAP4 ISS",
115959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		sizeof(iss->media_dev.model));
116059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->media_dev.hw_revision = iss->revision;
116159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->media_dev.link_notify = iss_pipeline_link_notify;
116259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = media_device_register(&iss->media_dev);
116359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0) {
11644cd89e91bb8dbefe54743df6a5c4437812c96e3aLaurent Pinchart		dev_err(iss->dev, "%s: Media device registration failed (%d)\n",
116559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			__func__, ret);
116659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return ret;
116759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
116859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
116959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->v4l2_dev.mdev = &iss->media_dev;
117059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = v4l2_device_register(iss->dev, &iss->v4l2_dev);
117159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0) {
11724cd89e91bb8dbefe54743df6a5c4437812c96e3aLaurent Pinchart		dev_err(iss->dev, "%s: V4L2 device registration failed (%d)\n",
117359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			__func__, ret);
117459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto done;
117559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
117659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
117759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Register internal entities */
117859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_csi2_register_entities(&iss->csi2a, &iss->v4l2_dev);
117959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
118059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto done;
118159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
118259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_csi2_register_entities(&iss->csi2b, &iss->v4l2_dev);
118359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
118459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto done;
118559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
118659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_ipipeif_register_entities(&iss->ipipeif, &iss->v4l2_dev);
118759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
118859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto done;
118959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
119059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_ipipe_register_entities(&iss->ipipe, &iss->v4l2_dev);
119159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
119259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto done;
119359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
119459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_resizer_register_entities(&iss->resizer, &iss->v4l2_dev);
119559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
119659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto done;
119759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
119859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Register external entities */
119959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) {
120059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		struct v4l2_subdev *sensor;
120159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		struct media_entity *input;
120259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		unsigned int flags;
120359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		unsigned int pad;
120459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
120559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		sensor = iss_register_subdev_group(iss, subdevs->subdevs);
120659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (sensor == NULL)
120759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			continue;
120859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
120959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		sensor->host_priv = subdevs;
121059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
121159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		/* Connect the sensor to the correct interface module.
121259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		 * CSI2a receiver through CSIPHY1, or
121359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		 * CSI2b receiver through CSIPHY2
121459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		 */
121559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		switch (subdevs->interface) {
121659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		case ISS_INTERFACE_CSI2A_PHY1:
121759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			input = &iss->csi2a.subdev.entity;
121859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			pad = CSI2_PAD_SINK;
121959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			flags = MEDIA_LNK_FL_IMMUTABLE
122059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			      | MEDIA_LNK_FL_ENABLED;
122159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			break;
122259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
122359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		case ISS_INTERFACE_CSI2B_PHY2:
122459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			input = &iss->csi2b.subdev.entity;
122559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			pad = CSI2_PAD_SINK;
122659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			flags = MEDIA_LNK_FL_IMMUTABLE
122759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			      | MEDIA_LNK_FL_ENABLED;
122859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			break;
122959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
123059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		default:
12314cd89e91bb8dbefe54743df6a5c4437812c96e3aLaurent Pinchart			dev_err(iss->dev, "%s: invalid interface type %u\n",
12324cd89e91bb8dbefe54743df6a5c4437812c96e3aLaurent Pinchart				__func__, subdevs->interface);
123359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			ret = -EINVAL;
123459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			goto done;
123559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
123659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
123759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = media_entity_create_link(&sensor->entity, 0, input, pad,
123859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					       flags);
123959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (ret < 0)
124059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			goto done;
124159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
124259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
124359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = v4l2_device_register_subdev_nodes(&iss->v4l2_dev);
124459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
124559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirredone:
124659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
124759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss_unregister_entities(iss);
124859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
124959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return ret;
125059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
125159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
125259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic void iss_cleanup_modules(struct iss_device *iss)
125359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
125459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_csi2_cleanup(iss);
125559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_ipipeif_cleanup(iss);
125659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_ipipe_cleanup(iss);
125759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_resizer_cleanup(iss);
125859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
125959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
126059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_initialize_modules(struct iss_device *iss)
126159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
126259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret;
126359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
126459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_csiphy_init(iss);
126559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0) {
126659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "CSI PHY initialization failed\n");
126759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_csiphy;
126859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
126959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
127059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_csi2_init(iss);
127159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0) {
127259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "CSI2 initialization failed\n");
127359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_csi2;
127459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
127559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
127659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_ipipeif_init(iss);
127759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0) {
127859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "ISP IPIPEIF initialization failed\n");
127959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_ipipeif;
128059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
128159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
128259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_ipipe_init(iss);
128359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0) {
128459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "ISP IPIPE initialization failed\n");
128559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_ipipe;
128659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
128759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
128859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_resizer_init(iss);
128959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0) {
129059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "ISP RESIZER initialization failed\n");
129159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_resizer;
129259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
129359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
129459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Connect the submodules. */
129559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = media_entity_create_link(
129659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->csi2a.subdev.entity, CSI2_PAD_SOURCE,
129759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0);
129859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
129959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_link;
130059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
130159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = media_entity_create_link(
130259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->csi2b.subdev.entity, CSI2_PAD_SOURCE,
130359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0);
130459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
130559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_link;
130659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
130759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = media_entity_create_link(
130859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP,
130959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0);
131059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
131159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_link;
131259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
131359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = media_entity_create_link(
131459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP,
131559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->ipipe.subdev.entity, IPIPE_PAD_SINK, 0);
131659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
131759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_link;
131859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
131959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = media_entity_create_link(
132059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->ipipe.subdev.entity, IPIPE_PAD_SOURCE_VP,
132159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0);
132259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
132359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_link;
132459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
132559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
132659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
132759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_link:
132859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_resizer_cleanup(iss);
132959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_resizer:
133059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_ipipe_cleanup(iss);
133159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_ipipe:
133259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_ipipeif_cleanup(iss);
133359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_ipipeif:
133459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_csi2_cleanup(iss);
133559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_csi2:
133659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_csiphy:
133759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return ret;
133859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
133959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
134059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_probe(struct platform_device *pdev)
134159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
134259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_platform_data *pdata = pdev->dev.platform_data;
134359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_device *iss;
13444334fd18e2bcf9c6aa7c535c25b05b462aab05b3Laurent Pinchart	unsigned int i;
13454334fd18e2bcf9c6aa7c535c25b05b462aab05b3Laurent Pinchart	int ret;
134659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
134759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (pdata == NULL)
134859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return -EINVAL;
134959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
135059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss = kzalloc(sizeof(*iss), GFP_KERNEL);
135159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!iss) {
135259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(&pdev->dev, "Could not allocate memory\n");
135359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return -ENOMEM;
135459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
135559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
135659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mutex_init(&iss->iss_mutex);
135759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
135859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->dev = &pdev->dev;
135959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->pdata = pdata;
136059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
136159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->raw_dmamask = DMA_BIT_MASK(32);
136259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->dev->dma_mask = &iss->raw_dmamask;
136359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->dev->coherent_dma_mask = DMA_BIT_MASK(32);
136459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
136559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	platform_set_drvdata(pdev, iss);
136659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
136759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Clocks */
136859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = iss_map_mem_resource(pdev, iss, OMAP4_ISS_MEM_TOP);
136959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
137059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error;
137159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
137259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = iss_get_clocks(iss);
137359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
137459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error;
137559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
137659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (omap4iss_get(iss) == NULL)
137759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error;
137859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
137959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = iss_reset(iss);
138059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
138159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_iss;
138259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
138359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->revision = readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_REVISION);
138459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	dev_info(iss->dev, "Revision %08x found\n", iss->revision);
138559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
138659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	for (i = 1; i < OMAP4_ISS_MEM_LAST; i++) {
138759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = iss_map_mem_resource(pdev, iss, i);
138859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (ret)
138959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			goto error_iss;
139059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
139159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
139259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Configure BTE BW_LIMITER field to max recommended value (1 GB) */
139359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel((readl(iss->regs[OMAP4_ISS_MEM_BTE] + BTE_CTRL) & ~BTE_CTRL_BW_LIMITER_MASK) |
139459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		(18 << BTE_CTRL_BW_LIMITER_SHIFT),
139559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->regs[OMAP4_ISS_MEM_BTE] + BTE_CTRL);
139659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
139759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Perform ISP reset */
139859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_subclk_enable(iss, OMAP4_ISS_SUBCLK_ISP);
139959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
140059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_iss;
140159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
140259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = iss_isp_reset(iss);
140359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
140459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_iss;
140559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
140659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	dev_info(iss->dev, "ISP Revision %08x found\n",
140759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		 readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_REVISION));
140859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
140959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Interrupt */
141059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->irq_num = platform_get_irq(pdev, 0);
141159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->irq_num <= 0) {
141259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "No IRQ resource\n");
141359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = -ENODEV;
141459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_iss;
141559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
141659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
141759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (request_irq(iss->irq_num, iss_isr, IRQF_SHARED, "OMAP4 ISS", iss)) {
141859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "Unable to request IRQ\n");
141959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = -EINVAL;
142059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_iss;
142159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
142259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
142359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Entities */
142459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = iss_initialize_modules(iss);
142559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
142659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_irq;
142759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
142859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = iss_register_entities(iss);
142959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
143059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_modules;
143159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
143259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_put(iss);
143359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
143459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
143559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
143659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_modules:
143759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss_cleanup_modules(iss);
143859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_irq:
143959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	free_irq(iss->irq_num, iss);
144059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_iss:
144159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_put(iss);
144259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror:
144359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss_put_clocks(iss);
144459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
144559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	for (i = 0; i < OMAP4_ISS_MEM_LAST; i++) {
144659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (iss->regs[i]) {
144759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			iounmap(iss->regs[i]);
144859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			iss->regs[i] = NULL;
144959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
145059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
145159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (iss->res[i]) {
145259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			release_mem_region(iss->res[i]->start,
145359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					   resource_size(iss->res[i]));
145459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			iss->res[i] = NULL;
145559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
145659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
145759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	platform_set_drvdata(pdev, NULL);
145859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
145959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mutex_destroy(&iss->iss_mutex);
146059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	kfree(iss);
146159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
146259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return ret;
146359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
146459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
146559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_remove(struct platform_device *pdev)
146659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
146759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_device *iss = platform_get_drvdata(pdev);
14684334fd18e2bcf9c6aa7c535c25b05b462aab05b3Laurent Pinchart	unsigned int i;
146959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
147059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss_unregister_entities(iss);
147159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss_cleanup_modules(iss);
147259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
147359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	free_irq(iss->irq_num, iss);
147459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss_put_clocks(iss);
147559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
147659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	for (i = 0; i < OMAP4_ISS_MEM_LAST; i++) {
147759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (iss->regs[i]) {
147859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			iounmap(iss->regs[i]);
147959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			iss->regs[i] = NULL;
148059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
148159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
148259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (iss->res[i]) {
148359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			release_mem_region(iss->res[i]->start,
148459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					   resource_size(iss->res[i]));
148559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			iss->res[i] = NULL;
148659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
148759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
148859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
148959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	kfree(iss);
149059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
149159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
149259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
149359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
149459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic struct platform_device_id omap4iss_id_table[] = {
149559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	{ "omap4iss", 0 },
149659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	{ },
149759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre};
149859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio AguirreMODULE_DEVICE_TABLE(platform, omap4iss_id_table);
149959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
150059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic struct platform_driver iss_driver = {
150159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	.probe		= iss_probe,
150259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	.remove		= iss_remove,
150359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	.id_table	= omap4iss_id_table,
150459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	.driver = {
150559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		.owner	= THIS_MODULE,
150659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		.name	= "omap4iss",
150759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	},
150859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre};
150959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
151059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirremodule_platform_driver(iss_driver);
151159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
151259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio AguirreMODULE_DESCRIPTION("TI OMAP4 ISS driver");
151359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio AguirreMODULE_AUTHOR("Sergio Aguirre <sergio.a.aguirre@gmail.com>");
151459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio AguirreMODULE_LICENSE("GPL");
151559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio AguirreMODULE_VERSION(ISS_VIDEO_DRIVER_VERSION);
1516