iss.c revision 59f0ad8076816d13f7cba80d2b178ff5ab787e2e
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);
4359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ISS_PRINT_REGISTER(iss, HL_IRQSTATUS_5);
4459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ISS_PRINT_REGISTER(iss, HL_IRQENABLE_5_SET);
4559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ISS_PRINT_REGISTER(iss, HL_IRQENABLE_5_CLR);
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 */
7859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(hl_irq, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQSTATUS_5);
7959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(hl_irq, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQENABLE_5_SET);
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{
8959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(-1, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQENABLE_5_CLR);
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 |
9959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				   ISP5_IRQ_RSZ_FIFO_IN_BLK |
10059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				   ISP5_IRQ_RSZ_FIFO_OVF |
10159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				   ISP5_IRQ_RSZ_INT_DMA |
10259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				   ISP5_IRQ_ISIF0;
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;
12459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct v4l2_ext_controls ctrls;
12559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct v4l2_ext_control ctrl;
12659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret;
12759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
12859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!pipe->external)
12959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
13059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
13159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (pipe->external_rate)
13259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
13359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
13459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	memset(&fmt, 0, sizeof(fmt));
13559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
13659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	fmt.pad = link->source->index;
13759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
13859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = v4l2_subdev_call(media_entity_to_v4l2_subdev(link->sink->entity),
13959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			       pad, get_fmt, NULL, &fmt);
14059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
14159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return -EPIPE;
14259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
14359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	pipe->external_bpp = omap4iss_video_format_info(fmt.format.code)->bpp;
14459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
14559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	memset(&ctrls, 0, sizeof(ctrls));
14659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	memset(&ctrl, 0, sizeof(ctrl));
14759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
14859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ctrl.id = V4L2_CID_PIXEL_RATE;
14959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
15059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ctrls.ctrl_class = V4L2_CTRL_ID2CLASS(ctrl.id);
15159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ctrls.count = 1;
15259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ctrls.controls = &ctrl;
15359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
15459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = v4l2_g_ext_ctrls(pipe->external->ctrl_handler, &ctrls);
15559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0) {
15659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_warn(iss->dev, "no pixel rate control in subdev %s\n",
15759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			 pipe->external->name);
15859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return ret;
15959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
16059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
16159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	pipe->external_rate = ctrl.value64;
16259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
16359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
16459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
16559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
16659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
16759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Configure the bridge. Valid inputs are
16859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
16959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * IPIPEIF_INPUT_CSI2A: CSI2a receiver
17059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * IPIPEIF_INPUT_CSI2B: CSI2b receiver
17159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
17259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * The bridge and lane shifter are configured according to the selected input
17359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * and the ISP platform data.
17459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
17559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrevoid omap4iss_configure_bridge(struct iss_device *iss,
17659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			       enum ipipeif_input_entity input)
17759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
17859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	u32 issctrl_val;
17959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	u32 isp5ctrl_val;
18059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
18159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	issctrl_val  = readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CTRL);
18259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	issctrl_val &= ~ISS_CTRL_INPUT_SEL_MASK;
18359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	issctrl_val &= ~ISS_CTRL_CLK_DIV_MASK;
18459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
18559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	isp5ctrl_val  = readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL);
18659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
18759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	switch (input) {
18859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	case IPIPEIF_INPUT_CSI2A:
18959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		issctrl_val |= ISS_CTRL_INPUT_SEL_CSI2A;
19059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		isp5ctrl_val |= ISP5_CTRL_VD_PULSE_EXT;
19159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		break;
19259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
19359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	case IPIPEIF_INPUT_CSI2B:
19459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		issctrl_val |= ISS_CTRL_INPUT_SEL_CSI2B;
19559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		isp5ctrl_val |= ISP5_CTRL_VD_PULSE_EXT;
19659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		break;
19759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
19859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	default:
19959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return;
20059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
20159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
20259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	issctrl_val |= ISS_CTRL_SYNC_DETECT_VS_RAISING;
20359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
20459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	isp5ctrl_val |= ISP5_CTRL_PSYNC_CLK_SEL | ISP5_CTRL_SYNC_ENABLE;
20559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
20659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(issctrl_val, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CTRL);
20759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(isp5ctrl_val, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL);
20859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
20959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
21059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic inline void iss_isr_dbg(struct iss_device *iss, u32 irqstatus)
21159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
21259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	static const char *name[] = {
21359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"ISP_IRQ0",
21459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"ISP_IRQ1",
21559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"ISP_IRQ2",
21659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"ISP_IRQ3",
21759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"CSIA_IRQ",
21859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"CSIB_IRQ",
21959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"CCP2_IRQ0",
22059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"CCP2_IRQ1",
22159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"CCP2_IRQ2",
22259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"CCP2_IRQ3",
22359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"CBUFF_IRQ",
22459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"BTE_IRQ",
22559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"SIMCOP_IRQ0",
22659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"SIMCOP_IRQ1",
22759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"SIMCOP_IRQ2",
22859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"SIMCOP_IRQ3",
22959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"CCP2_IRQ8",
23059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"HS_VS_IRQ",
23159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"res18",
23259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"res19",
23359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"res20",
23459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"res21",
23559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"res22",
23659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"res23",
23759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"res24",
23859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"res25",
23959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"res26",
24059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"res27",
24159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"res28",
24259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"res29",
24359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"res30",
24459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		"res31",
24559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	};
24659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int i;
24759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
24859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	dev_dbg(iss->dev, "ISS IRQ: ");
24959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
25059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	for (i = 0; i < ARRAY_SIZE(name); i++) {
25159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if ((1 << i) & irqstatus)
25259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			pr_cont("%s ", name[i]);
25359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
25459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	pr_cont("\n");
25559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
25659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
25759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
25859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_isr - Interrupt Service Routine for ISS module.
25959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @irq: Not used currently.
26059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @_iss: Pointer to the OMAP4 ISS device
26159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
26259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Handles the corresponding callback if plugged in.
26359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
26459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the
26559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * IRQ wasn't handled.
26659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
26759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic irqreturn_t iss_isr(int irq, void *_iss)
26859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
26959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	static const u32 ipipeif_events = ISP5_IRQ_IPIPEIF |
27059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					  ISP5_IRQ_ISIF0;
27159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	static const u32 resizer_events = ISP5_IRQ_RSZ_FIFO_IN_BLK |
27259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					  ISP5_IRQ_RSZ_FIFO_OVF |
27359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					  ISP5_IRQ_RSZ_INT_DMA;
27459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_device *iss = _iss;
27559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	u32 irqstatus;
27659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
27759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	irqstatus = readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQSTATUS_5);
27859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(irqstatus, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQSTATUS_5);
27959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
28059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (irqstatus & ISS_HL_IRQ_CSIA)
28159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		omap4iss_csi2_isr(&iss->csi2a);
28259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
28359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (irqstatus & ISS_HL_IRQ_CSIB)
28459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		omap4iss_csi2_isr(&iss->csi2b);
28559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
28659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (irqstatus & ISS_HL_IRQ_ISP(0)) {
28759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		u32 isp_irqstatus = readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] +
28859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					  ISP5_IRQSTATUS(0));
28959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		writel(isp_irqstatus, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] +
29059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			ISP5_IRQSTATUS(0));
29159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
29259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (isp_irqstatus & ISP5_IRQ_OCP_ERR)
29359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			dev_dbg(iss->dev, "ISP5 OCP Error!\n");
29459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
29559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (isp_irqstatus & ipipeif_events) {
29659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			omap4iss_ipipeif_isr(&iss->ipipeif,
29759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					     isp_irqstatus & ipipeif_events);
29859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
29959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
30059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (isp_irqstatus & resizer_events)
30159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			omap4iss_resizer_isr(&iss->resizer,
30259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					     isp_irqstatus & resizer_events);
30359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
30459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
30559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_flush(iss);
30659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
30759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#if defined(DEBUG) && defined(ISS_ISR_DEBUG)
30859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss_isr_dbg(iss, irqstatus);
30959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#endif
31059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
31159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return IRQ_HANDLED;
31259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
31359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
31459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/* -----------------------------------------------------------------------------
31559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Pipeline power management
31659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
31759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Entities must be powered up when part of a pipeline that contains at least
31859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * one open video device node.
31959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
32059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * To achieve this use the entity use_count field to track the number of users.
32159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * For entities corresponding to video device nodes the use_count field stores
32259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * the users count of the node. For entities corresponding to subdevs the
32359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * use_count field stores the total number of users of all video device nodes
32459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * in the pipeline.
32559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
32659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * The omap4iss_pipeline_pm_use() function must be called in the open() and
32759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * close() handlers of video device nodes. It increments or decrements the use
32859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * count of all subdev entities in the pipeline.
32959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
33059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * To react to link management on powered pipelines, the link setup notification
33159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * callback updates the use count of all entities in the source and sink sides
33259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * of the link.
33359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
33459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
33559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
33659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_pipeline_pm_use_count - Count the number of users of a pipeline
33759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @entity: The entity
33859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
33959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return the total number of users of all video device nodes in the pipeline.
34059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
34159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_pipeline_pm_use_count(struct media_entity *entity)
34259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
34359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_entity_graph graph;
34459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int use = 0;
34559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
34659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	media_entity_graph_walk_start(&graph, entity);
34759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
34859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	while ((entity = media_entity_graph_walk_next(&graph))) {
34959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
35059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			use += entity->use_count;
35159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
35259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
35359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return use;
35459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
35559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
35659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
35759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_pipeline_pm_power_one - Apply power change to an entity
35859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @entity: The entity
35959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @change: Use count change
36059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
36159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Change the entity use count by @change. If the entity is a subdev update its
36259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * power state by calling the core::s_power operation when the use count goes
36359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * from 0 to != 0 or from != 0 to 0.
36459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
36559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return 0 on success or a negative error code on failure.
36659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
36759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_pipeline_pm_power_one(struct media_entity *entity, int change)
36859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
36959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct v4l2_subdev *subdev;
37059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
37159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	subdev = media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV
37259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	       ? media_entity_to_v4l2_subdev(entity) : NULL;
37359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
37459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (entity->use_count == 0 && change > 0 && subdev != NULL) {
37559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		int ret;
37659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
37759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = v4l2_subdev_call(subdev, core, s_power, 1);
37859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (ret < 0 && ret != -ENOIOCTLCMD)
37959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			return ret;
38059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
38159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
38259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	entity->use_count += change;
38359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	WARN_ON(entity->use_count < 0);
38459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
38559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (entity->use_count == 0 && change < 0 && subdev != NULL)
38659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		v4l2_subdev_call(subdev, core, s_power, 0);
38759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
38859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
38959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
39059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
39159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
39259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_pipeline_pm_power - Apply power change to all entities in a pipeline
39359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @entity: The entity
39459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @change: Use count change
39559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
39659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Walk the pipeline to update the use count and the power state of all non-node
39759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * entities.
39859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
39959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return 0 on success or a negative error code on failure.
40059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
40159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_pipeline_pm_power(struct media_entity *entity, int change)
40259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
40359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_entity_graph graph;
40459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_entity *first = entity;
40559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret = 0;
40659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
40759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!change)
40859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
40959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
41059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	media_entity_graph_walk_start(&graph, entity);
41159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
41259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	while (!ret && (entity = media_entity_graph_walk_next(&graph)))
41359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
41459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			ret = iss_pipeline_pm_power_one(entity, change);
41559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
41659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!ret)
41759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
41859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
41959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	media_entity_graph_walk_start(&graph, first);
42059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
42159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	while ((first = media_entity_graph_walk_next(&graph))
42259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	       && first != entity)
42359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE)
42459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			iss_pipeline_pm_power_one(first, -change);
42559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
42659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return ret;
42759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
42859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
42959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
43059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * omap4iss_pipeline_pm_use - Update the use count of an entity
43159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @entity: The entity
43259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @use: Use (1) or stop using (0) the entity
43359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
43459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Update the use count of all entities in the pipeline and power entities on or
43559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * off accordingly.
43659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
43759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return 0 on success or a negative error code on failure. Powering entities
43859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * off is assumed to never fail. No failure can occur when the use parameter is
43959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * set to 0.
44059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
44159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreint omap4iss_pipeline_pm_use(struct media_entity *entity, int use)
44259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
44359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int change = use ? 1 : -1;
44459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret;
44559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
44659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mutex_lock(&entity->parent->graph_mutex);
44759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
44859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Apply use count to node. */
44959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	entity->use_count += change;
45059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	WARN_ON(entity->use_count < 0);
45159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
45259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Apply power change to connected non-nodes. */
45359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = iss_pipeline_pm_power(entity, change);
45459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
45559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		entity->use_count -= change;
45659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
45759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mutex_unlock(&entity->parent->graph_mutex);
45859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
45959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return ret;
46059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
46159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
46259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
46359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_pipeline_link_notify - Link management notification callback
46459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @link: The link
46559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @flags: New link flags that will be applied
46659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
46759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * React to link management on powered pipelines by updating the use count of
46859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * all entities in the source and sink sides of the link. Entities are powered
46959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * on or off accordingly.
47059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
47159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return 0 on success or a negative error code on failure. Powering entities
47259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * off is assumed to never fail. This function will not fail for disconnection
47359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * events.
47459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
47559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_pipeline_link_notify(struct media_link *link, u32 flags,
47659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				    unsigned int notification)
47759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
47859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_entity *source = link->source->entity;
47959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_entity *sink = link->sink->entity;
48059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int source_use = iss_pipeline_pm_use_count(source);
48159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int sink_use = iss_pipeline_pm_use_count(sink);
48259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret;
48359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
48459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
48559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	    !(link->flags & MEDIA_LNK_FL_ENABLED)) {
48659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		/* Powering off entities is assumed to never fail. */
48759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss_pipeline_pm_power(source, -sink_use);
48859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss_pipeline_pm_power(sink, -source_use);
48959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
49059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
49159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
49259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
49359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		(flags & MEDIA_LNK_FL_ENABLED)) {
49459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = iss_pipeline_pm_power(source, sink_use);
49559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (ret < 0)
49659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			return ret;
49759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
49859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = iss_pipeline_pm_power(sink, source_use);
49959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (ret < 0)
50059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			iss_pipeline_pm_power(source, -sink_use);
50159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
50259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return ret;
50359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
50459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
50559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
50659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
50759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
50859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/* -----------------------------------------------------------------------------
50959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Pipeline stream management
51059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
51159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
51259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
51359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_pipeline_enable - Enable streaming on a pipeline
51459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @pipe: ISS pipeline
51559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @mode: Stream mode (single shot or continuous)
51659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
51759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Walk the entities chain starting at the pipeline output video node and start
51859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * all modules in the chain in the given mode.
51959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
52059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return 0 if successful, or the return value of the failed video::s_stream
52159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * operation otherwise.
52259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
52359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_pipeline_enable(struct iss_pipeline *pipe,
52459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			       enum iss_pipeline_stream_state mode)
52559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
52659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_entity *entity;
52759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_pad *pad;
52859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct v4l2_subdev *subdev;
52959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	unsigned long flags;
53059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret;
53159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
53259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	spin_lock_irqsave(&pipe->lock, flags);
53359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	pipe->state &= ~(ISS_PIPELINE_IDLE_INPUT | ISS_PIPELINE_IDLE_OUTPUT);
53459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	spin_unlock_irqrestore(&pipe->lock, flags);
53559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
53659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	pipe->do_propagation = false;
53759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
53859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	entity = &pipe->output->video.entity;
53959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	while (1) {
54059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		pad = &entity->pads[0];
54159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (!(pad->flags & MEDIA_PAD_FL_SINK))
54259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			break;
54359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
54459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		pad = media_entity_remote_pad(pad);
54559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (pad == NULL ||
54659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
54759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			break;
54859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
54959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		entity = pad->entity;
55059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		subdev = media_entity_to_v4l2_subdev(entity);
55159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
55259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = v4l2_subdev_call(subdev, video, s_stream, mode);
55359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (ret < 0 && ret != -ENOIOCTLCMD)
55459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			return ret;
55559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
55659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss_print_status(pipe->output->iss);
55759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
55859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
55959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
56059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
56159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_pipeline_disable - Disable streaming on a pipeline
56259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @pipe: ISS pipeline
56359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
56459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Walk the entities chain starting at the pipeline output video node and stop
56559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * all modules in the chain. Wait synchronously for the modules to be stopped if
56659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * necessary.
56759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
56859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_pipeline_disable(struct iss_pipeline *pipe)
56959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
57059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_entity *entity;
57159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_pad *pad;
57259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct v4l2_subdev *subdev;
57359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int failure = 0;
57459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
57559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	entity = &pipe->output->video.entity;
57659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	while (1) {
57759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		pad = &entity->pads[0];
57859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (!(pad->flags & MEDIA_PAD_FL_SINK))
57959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			break;
58059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
58159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		pad = media_entity_remote_pad(pad);
58259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (pad == NULL ||
58359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
58459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			break;
58559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
58659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		entity = pad->entity;
58759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		subdev = media_entity_to_v4l2_subdev(entity);
58859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
58959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		v4l2_subdev_call(subdev, video, s_stream, 0);
59059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
59159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
59259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return failure;
59359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
59459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
59559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
59659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * omap4iss_pipeline_set_stream - Enable/disable streaming on a pipeline
59759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @pipe: ISS pipeline
59859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @state: Stream state (stopped, single shot or continuous)
59959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
60059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Set the pipeline to the given stream state. Pipelines can be started in
60159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * single-shot or continuous mode.
60259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
60359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return 0 if successful, or the return value of the failed video::s_stream
60459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * operation otherwise. The pipeline state is not updated when the operation
60559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * fails, except when stopping the pipeline.
60659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
60759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreint omap4iss_pipeline_set_stream(struct iss_pipeline *pipe,
60859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				 enum iss_pipeline_stream_state state)
60959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
61059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret;
61159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
61259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (state == ISS_PIPELINE_STREAM_STOPPED)
61359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = iss_pipeline_disable(pipe);
61459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	else
61559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = iss_pipeline_enable(pipe, state);
61659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
61759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret == 0 || state == ISS_PIPELINE_STREAM_STOPPED)
61859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		pipe->stream_state = state;
61959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
62059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return ret;
62159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
62259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
62359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
62459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_pipeline_is_last - Verify if entity has an enabled link to the output
62559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *			  video node
62659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @me: ISS module's media entity
62759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
62859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Returns 1 if the entity has an enabled link to the output video node or 0
62959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * otherwise. It's true only while pipeline can have no more than one output
63059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * node.
63159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
63259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_pipeline_is_last(struct media_entity *me)
63359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
63459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_pipeline *pipe;
63559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct media_pad *pad;
63659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
63759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!me->pipe)
63859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
63959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	pipe = to_iss_pipeline(me);
64059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED)
64159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
64259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	pad = media_entity_remote_pad(&pipe->output->pad);
64359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return pad->entity == me;
64459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
64559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
64659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_reset(struct iss_device *iss)
64759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
64859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	unsigned long timeout = 0;
64959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
65059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_SYSCONFIG) |
65159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ISS_HL_SYSCONFIG_SOFTRESET,
65259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_SYSCONFIG);
65359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
65459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	while (readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_SYSCONFIG) &
65559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			ISS_HL_SYSCONFIG_SOFTRESET) {
65659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (timeout++ > 10000) {
65759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			dev_alert(iss->dev, "cannot reset ISS\n");
65859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			return -ETIMEDOUT;
65959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
66059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		udelay(1);
66159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
66259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
66359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
66459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
66559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
66659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_isp_reset(struct iss_device *iss)
66759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
66859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	unsigned long timeout = 0;
66959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
67059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Fist, ensure that the ISP is IDLE (no transactions happening) */
67159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel((readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG) &
67259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		~ISP5_SYSCONFIG_STANDBYMODE_MASK) |
67359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ISP5_SYSCONFIG_STANDBYMODE_SMART,
67459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG);
67559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
67659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL) |
67759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ISP5_CTRL_MSTANDBY,
67859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL);
67959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
68059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	for (;;) {
68159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL) &
68259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				ISP5_CTRL_MSTANDBY_WAIT)
68359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			break;
68459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (timeout++ > 1000) {
68559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			dev_alert(iss->dev, "cannot set ISP5 to standby\n");
68659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			return -ETIMEDOUT;
68759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
68859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		msleep(1);
68959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
69059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
69159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Now finally, do the reset */
69259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel(readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG) |
69359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ISP5_SYSCONFIG_SOFTRESET,
69459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG);
69559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
69659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	timeout = 0;
69759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	while (readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG) &
69859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			ISP5_SYSCONFIG_SOFTRESET) {
69959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (timeout++ > 1000) {
70059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			dev_alert(iss->dev, "cannot reset ISP5\n");
70159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			return -ETIMEDOUT;
70259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
70359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		msleep(1);
70459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
70559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
70659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
70759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
70859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
70959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
71059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_module_sync_idle - Helper to sync module with its idle state
71159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @me: ISS submodule's media entity
71259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization
71359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @stopping: flag which tells module wants to stop
71459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
71559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * This function checks if ISS submodule needs to wait for next interrupt. If
71659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * yes, makes the caller to sleep while waiting for such event.
71759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
71859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreint omap4iss_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
71959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			      atomic_t *stopping)
72059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
72159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_pipeline *pipe = to_iss_pipeline(me);
72259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_video *video = pipe->output;
72359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	unsigned long flags;
72459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
72559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED ||
72659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	    (pipe->stream_state == ISS_PIPELINE_STREAM_SINGLESHOT &&
72759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	     !iss_pipeline_ready(pipe)))
72859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
72959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
73059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/*
73159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * atomic_set() doesn't include memory barrier on ARM platform for SMP
73259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * scenario. We'll call it here to avoid race conditions.
73359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 */
73459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	atomic_set(stopping, 1);
73559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	smp_wmb();
73659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
73759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/*
73859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * If module is the last one, it's writing to memory. In this case,
73959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * it's necessary to check if the module is already paused due to
74059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * DMA queue underrun or if it has to wait for next interrupt to be
74159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * idle.
74259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * If it isn't the last one, the function won't sleep but *stopping
74359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * will still be set to warn next submodule caller's interrupt the
74459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 * module wants to be idle.
74559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	 */
74659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!iss_pipeline_is_last(me))
74759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
74859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
74959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	spin_lock_irqsave(&video->qlock, flags);
75059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (video->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) {
75159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		spin_unlock_irqrestore(&video->qlock, flags);
75259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		atomic_set(stopping, 0);
75359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		smp_wmb();
75459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 0;
75559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
75659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	spin_unlock_irqrestore(&video->qlock, flags);
75759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!wait_event_timeout(*wait, !atomic_read(stopping),
75859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				msecs_to_jiffies(1000))) {
75959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		atomic_set(stopping, 0);
76059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		smp_wmb();
76159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return -ETIMEDOUT;
76259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
76359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
76459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
76559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
76659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
76759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
76859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * omap4iss_module_sync_is_stopped - Helper to verify if module was stopping
76959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization
77059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @stopping: flag which tells module wants to stop
77159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
77259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * This function checks if ISS submodule was stopping. In case of yes, it
77359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * notices the caller by setting stopping to 0 and waking up the wait queue.
77459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Returns 1 if it was stopping or 0 otherwise.
77559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
77659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreint omap4iss_module_sync_is_stopping(wait_queue_head_t *wait,
77759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				     atomic_t *stopping)
77859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
77959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (atomic_cmpxchg(stopping, 1, 0)) {
78059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		wake_up(wait);
78159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return 1;
78259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
78359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
78459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
78559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
78659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
78759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/* --------------------------------------------------------------------------
78859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Clock management
78959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
79059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
79159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#define ISS_CLKCTRL_MASK	(ISS_CLKCTRL_CSI2_A |\
79259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				 ISS_CLKCTRL_CSI2_B |\
79359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				 ISS_CLKCTRL_ISP)
79459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
79559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int __iss_subclk_update(struct iss_device *iss)
79659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
79759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	u32 clk = 0;
79859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret = 0, timeout = 1000;
79959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
80059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_A)
80159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISS_CLKCTRL_CSI2_A;
80259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
80359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_B)
80459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISS_CLKCTRL_CSI2_B;
80559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
80659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->subclk_resources & OMAP4_ISS_SUBCLK_ISP)
80759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISS_CLKCTRL_ISP;
80859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
80959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel((readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CLKCTRL) &
81059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		~ISS_CLKCTRL_MASK) | clk,
81159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CLKCTRL);
81259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
81359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Wait for HW assertion */
81459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	while (--timeout > 0) {
81559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		udelay(1);
81659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if ((readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CLKSTAT) &
81759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		     ISS_CLKCTRL_MASK) == clk)
81859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			break;
81959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
82059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
82159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!timeout)
82259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = -EBUSY;
82359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
82459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return ret;
82559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
82659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
82759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreint omap4iss_subclk_enable(struct iss_device *iss,
82859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			    enum iss_subclk_resource res)
82959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
83059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->subclk_resources |= res;
83159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
83259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return __iss_subclk_update(iss);
83359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
83459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
83559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreint omap4iss_subclk_disable(struct iss_device *iss,
83659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			     enum iss_subclk_resource res)
83759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
83859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->subclk_resources &= ~res;
83959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
84059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return __iss_subclk_update(iss);
84159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
84259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
84359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre#define ISS_ISP5_CLKCTRL_MASK	(ISP5_CTRL_BL_CLK_ENABLE |\
84459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				 ISP5_CTRL_ISIF_CLK_ENABLE |\
84559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				 ISP5_CTRL_H3A_CLK_ENABLE |\
84659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				 ISP5_CTRL_RSZ_CLK_ENABLE |\
84759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				 ISP5_CTRL_IPIPE_CLK_ENABLE |\
84859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				 ISP5_CTRL_IPIPEIF_CLK_ENABLE)
84959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
85059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int __iss_isp_subclk_update(struct iss_device *iss)
85159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
85259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	u32 clk = 0;
85359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
85459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_ISIF)
85559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISP5_CTRL_ISIF_CLK_ENABLE;
85659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
85759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_H3A)
85859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISP5_CTRL_H3A_CLK_ENABLE;
85959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
86059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_RSZ)
86159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISP5_CTRL_RSZ_CLK_ENABLE;
86259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
86359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPE)
86459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISP5_CTRL_IPIPE_CLK_ENABLE;
86559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
86659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPEIF)
86759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISP5_CTRL_IPIPEIF_CLK_ENABLE;
86859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
86959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (clk)
87059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk |= ISP5_CTRL_BL_CLK_ENABLE;
87159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
87259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel((readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL) &
87359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		~ISS_ISP5_CLKCTRL_MASK) | clk,
87459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL);
87559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
87659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
87759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
87859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
87959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreint omap4iss_isp_subclk_enable(struct iss_device *iss,
88059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				enum iss_isp_subclk_resource res)
88159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
88259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->isp_subclk_resources |= res;
88359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
88459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return __iss_isp_subclk_update(iss);
88559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
88659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
88759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreint omap4iss_isp_subclk_disable(struct iss_device *iss,
88859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				enum iss_isp_subclk_resource res)
88959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
89059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->isp_subclk_resources &= ~res;
89159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
89259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return __iss_isp_subclk_update(iss);
89359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
89459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
89559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
89659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_enable_clocks - Enable ISS clocks
89759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @iss: OMAP4 ISS device
89859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
89959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return 0 if successful, or clk_enable return value if any of tthem fails.
90059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
90159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_enable_clocks(struct iss_device *iss)
90259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
90359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int r;
90459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
90559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	r = clk_enable(iss->iss_fck);
90659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (r) {
90759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "clk_enable iss_fck failed\n");
90859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return r;
90959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
91059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
91159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	r = clk_enable(iss->iss_ctrlclk);
91259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (r) {
91359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "clk_enable iss_ctrlclk failed\n");
91459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto out_clk_enable_ctrlclk;
91559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
91659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
91759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
91859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreout_clk_enable_ctrlclk:
91959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	clk_disable(iss->iss_fck);
92059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return r;
92159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
92259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
92359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
92459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_disable_clocks - Disable ISS clocks
92559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @iss: OMAP4 ISS device
92659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
92759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic void iss_disable_clocks(struct iss_device *iss)
92859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
92959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	clk_disable(iss->iss_ctrlclk);
93059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	clk_disable(iss->iss_fck);
93159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
93259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
93359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic void iss_put_clocks(struct iss_device *iss)
93459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
93559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->iss_fck) {
93659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk_put(iss->iss_fck);
93759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->iss_fck = NULL;
93859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
93959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
94059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->iss_ctrlclk) {
94159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		clk_put(iss->iss_ctrlclk);
94259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->iss_ctrlclk = NULL;
94359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
94459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
94559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
94659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_get_clocks(struct iss_device *iss)
94759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
94859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->iss_fck = clk_get(iss->dev, "iss_fck");
94959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (IS_ERR(iss->iss_fck)) {
95059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "Unable to get iss_fck clock info\n");
95159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss_put_clocks(iss);
95259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return PTR_ERR(iss->iss_fck);
95359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
95459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
95559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->iss_ctrlclk = clk_get(iss->dev, "iss_ctrlclk");
95659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (IS_ERR(iss->iss_ctrlclk)) {
95759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "Unable to get iss_ctrlclk clock info\n");
95859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss_put_clocks(iss);
95959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return PTR_ERR(iss->iss_fck);
96059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
96159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
96259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
96359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
96459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
96559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
96659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * omap4iss_get - Acquire the ISS resource.
96759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
96859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Initializes the clocks for the first acquire.
96959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
97059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Increment the reference count on the ISS. If the first reference is taken,
97159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * enable clocks and power-up all submodules.
97259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
97359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return a pointer to the ISS device structure, or NULL if an error occurred.
97459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
97559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestruct iss_device *omap4iss_get(struct iss_device *iss)
97659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
97759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_device *__iss = iss;
97859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
97959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss == NULL)
98059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return NULL;
98159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
98259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mutex_lock(&iss->iss_mutex);
98359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->ref_count > 0)
98459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto out;
98559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
98659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss_enable_clocks(iss) < 0) {
98759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		__iss = NULL;
98859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto out;
98959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
99059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
99159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss_enable_interrupts(iss);
99259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
99359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreout:
99459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (__iss != NULL)
99559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->ref_count++;
99659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mutex_unlock(&iss->iss_mutex);
99759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
99859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return __iss;
99959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
100059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
100159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
100259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * omap4iss_put - Release the ISS
100359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
100459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Decrement the reference count on the ISS. If the last reference is released,
100559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * power-down all submodules, disable clocks and free temporary buffers.
100659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
100759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrevoid omap4iss_put(struct iss_device *iss)
100859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
100959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss == NULL)
101059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return;
101159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
101259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mutex_lock(&iss->iss_mutex);
101359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	BUG_ON(iss->ref_count == 0);
101459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (--iss->ref_count == 0) {
101559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss_disable_interrupts(iss);
101659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss_disable_clocks(iss);
101759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
101859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mutex_unlock(&iss->iss_mutex);
101959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
102059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
102159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_map_mem_resource(struct platform_device *pdev,
102259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				struct iss_device *iss,
102359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				enum iss_mem_resources res)
102459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
102559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct resource *mem;
102659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
102759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* request the mem region for the camera registers */
102859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
102959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mem = platform_get_resource(pdev, IORESOURCE_MEM, res);
103059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!mem) {
103159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "no mem resource?\n");
103259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return -ENODEV;
103359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
103459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
103559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
103659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev,
103759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			"cannot reserve camera register I/O region\n");
103859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return -ENODEV;
103959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
104059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->res[res] = mem;
104159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
104259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* map the region */
104359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->regs[res] = ioremap_nocache(mem->start, resource_size(mem));
104459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!iss->regs[res]) {
104559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "cannot map camera register I/O region\n");
104659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return -ENODEV;
104759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
104859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
104959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
105059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
105159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
105259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic void iss_unregister_entities(struct iss_device *iss)
105359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
105459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_resizer_unregister_entities(&iss->resizer);
105559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_ipipe_unregister_entities(&iss->ipipe);
105659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_ipipeif_unregister_entities(&iss->ipipeif);
105759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_csi2_unregister_entities(&iss->csi2a);
105859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_csi2_unregister_entities(&iss->csi2b);
105959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
106059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	v4l2_device_unregister(&iss->v4l2_dev);
106159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	media_device_unregister(&iss->media_dev);
106259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
106359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
106459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre/*
106559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * iss_register_subdev_group - Register a group of subdevices
106659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @iss: OMAP4 ISS device
106759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * @board_info: I2C subdevs board information array
106859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
106959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Register all I2C subdevices in the board_info array. The array must be
107059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * terminated by a NULL entry, and the first entry must be the sensor.
107159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre *
107259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * Return a pointer to the sensor media entity if it has been successfully
107359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre * registered, or NULL otherwise.
107459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre */
107559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic struct v4l2_subdev *
107659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreiss_register_subdev_group(struct iss_device *iss,
107759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		     struct iss_subdev_i2c_board_info *board_info)
107859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
107959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct v4l2_subdev *sensor = NULL;
108059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	unsigned int first;
108159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
108259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (board_info->board_info == NULL)
108359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return NULL;
108459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
108559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	for (first = 1; board_info->board_info; ++board_info, first = 0) {
108659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		struct v4l2_subdev *subdev;
108759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		struct i2c_adapter *adapter;
108859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
108959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		adapter = i2c_get_adapter(board_info->i2c_adapter_id);
109059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (adapter == NULL) {
109159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			dev_err(iss->dev, "%s: Unable to get I2C adapter %d for "
109259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				"device %s\n", __func__,
109359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				board_info->i2c_adapter_id,
109459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				board_info->board_info->type);
109559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			continue;
109659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
109759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
109859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		subdev = v4l2_i2c_new_subdev_board(&iss->v4l2_dev, adapter,
109959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				board_info->board_info, NULL);
110059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (subdev == NULL) {
110159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			dev_err(iss->dev, "%s: Unable to register subdev %s\n",
110259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre				__func__, board_info->board_info->type);
110359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			continue;
110459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
110559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
110659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (first)
110759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			sensor = subdev;
110859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
110959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
111059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return sensor;
111159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
111259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
111359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_register_entities(struct iss_device *iss)
111459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
111559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_platform_data *pdata = iss->pdata;
111659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_v4l2_subdevs_group *subdevs;
111759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret;
111859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
111959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->media_dev.dev = iss->dev;
112059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	strlcpy(iss->media_dev.model, "TI OMAP4 ISS",
112159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		sizeof(iss->media_dev.model));
112259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->media_dev.hw_revision = iss->revision;
112359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->media_dev.link_notify = iss_pipeline_link_notify;
112459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = media_device_register(&iss->media_dev);
112559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0) {
112659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		printk(KERN_ERR "%s: Media device registration failed (%d)\n",
112759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			__func__, ret);
112859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return ret;
112959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
113059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
113159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->v4l2_dev.mdev = &iss->media_dev;
113259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = v4l2_device_register(iss->dev, &iss->v4l2_dev);
113359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0) {
113459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		printk(KERN_ERR "%s: V4L2 device registration failed (%d)\n",
113559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			__func__, ret);
113659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto done;
113759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
113859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
113959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Register internal entities */
114059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_csi2_register_entities(&iss->csi2a, &iss->v4l2_dev);
114159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
114259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto done;
114359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
114459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_csi2_register_entities(&iss->csi2b, &iss->v4l2_dev);
114559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
114659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto done;
114759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
114859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_ipipeif_register_entities(&iss->ipipeif, &iss->v4l2_dev);
114959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
115059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto done;
115159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
115259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_ipipe_register_entities(&iss->ipipe, &iss->v4l2_dev);
115359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
115459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto done;
115559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
115659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_resizer_register_entities(&iss->resizer, &iss->v4l2_dev);
115759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
115859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto done;
115959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
116059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Register external entities */
116159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) {
116259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		struct v4l2_subdev *sensor;
116359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		struct media_entity *input;
116459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		unsigned int flags;
116559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		unsigned int pad;
116659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
116759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		sensor = iss_register_subdev_group(iss, subdevs->subdevs);
116859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (sensor == NULL)
116959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			continue;
117059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
117159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		sensor->host_priv = subdevs;
117259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
117359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		/* Connect the sensor to the correct interface module.
117459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		 * CSI2a receiver through CSIPHY1, or
117559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		 * CSI2b receiver through CSIPHY2
117659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		 */
117759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		switch (subdevs->interface) {
117859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		case ISS_INTERFACE_CSI2A_PHY1:
117959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			input = &iss->csi2a.subdev.entity;
118059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			pad = CSI2_PAD_SINK;
118159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			flags = MEDIA_LNK_FL_IMMUTABLE
118259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			      | MEDIA_LNK_FL_ENABLED;
118359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			break;
118459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
118559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		case ISS_INTERFACE_CSI2B_PHY2:
118659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			input = &iss->csi2b.subdev.entity;
118759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			pad = CSI2_PAD_SINK;
118859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			flags = MEDIA_LNK_FL_IMMUTABLE
118959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			      | MEDIA_LNK_FL_ENABLED;
119059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			break;
119159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
119259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		default:
119359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			printk(KERN_ERR "%s: invalid interface type %u\n",
119459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			       __func__, subdevs->interface);
119559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			ret = -EINVAL;
119659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			goto done;
119759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
119859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
119959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = media_entity_create_link(&sensor->entity, 0, input, pad,
120059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					       flags);
120159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (ret < 0)
120259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			goto done;
120359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
120459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
120559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = v4l2_device_register_subdev_nodes(&iss->v4l2_dev);
120659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
120759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirredone:
120859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
120959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss_unregister_entities(iss);
121059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
121159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return ret;
121259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
121359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
121459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic void iss_cleanup_modules(struct iss_device *iss)
121559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
121659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_csi2_cleanup(iss);
121759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_ipipeif_cleanup(iss);
121859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_ipipe_cleanup(iss);
121959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_resizer_cleanup(iss);
122059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
122159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
122259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_initialize_modules(struct iss_device *iss)
122359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
122459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int ret;
122559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
122659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_csiphy_init(iss);
122759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0) {
122859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "CSI PHY initialization failed\n");
122959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_csiphy;
123059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
123159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
123259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_csi2_init(iss);
123359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0) {
123459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "CSI2 initialization failed\n");
123559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_csi2;
123659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
123759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
123859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_ipipeif_init(iss);
123959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0) {
124059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "ISP IPIPEIF initialization failed\n");
124159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_ipipeif;
124259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
124359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
124459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_ipipe_init(iss);
124559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0) {
124659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "ISP IPIPE initialization failed\n");
124759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_ipipe;
124859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
124959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
125059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_resizer_init(iss);
125159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0) {
125259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "ISP RESIZER initialization failed\n");
125359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_resizer;
125459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
125559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
125659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Connect the submodules. */
125759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = media_entity_create_link(
125859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->csi2a.subdev.entity, CSI2_PAD_SOURCE,
125959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0);
126059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
126159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_link;
126259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
126359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = media_entity_create_link(
126459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->csi2b.subdev.entity, CSI2_PAD_SOURCE,
126559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0);
126659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
126759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_link;
126859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
126959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = media_entity_create_link(
127059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP,
127159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0);
127259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
127359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_link;
127459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
127559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = media_entity_create_link(
127659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP,
127759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->ipipe.subdev.entity, IPIPE_PAD_SINK, 0);
127859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
127959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_link;
128059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
128159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = media_entity_create_link(
128259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->ipipe.subdev.entity, IPIPE_PAD_SOURCE_VP,
128359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			&iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0);
128459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
128559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_link;
128659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
128759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
128859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
128959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_link:
129059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_resizer_cleanup(iss);
129159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_resizer:
129259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_ipipe_cleanup(iss);
129359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_ipipe:
129459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_ipipeif_cleanup(iss);
129559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_ipipeif:
129659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_csi2_cleanup(iss);
129759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_csi2:
129859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_csiphy:
129959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return ret;
130059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
130159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
130259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_probe(struct platform_device *pdev)
130359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
130459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_platform_data *pdata = pdev->dev.platform_data;
130559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_device *iss;
130659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int i, ret;
130759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
130859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (pdata == NULL)
130959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return -EINVAL;
131059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
131159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss = kzalloc(sizeof(*iss), GFP_KERNEL);
131259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (!iss) {
131359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(&pdev->dev, "Could not allocate memory\n");
131459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		return -ENOMEM;
131559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
131659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
131759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mutex_init(&iss->iss_mutex);
131859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
131959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->dev = &pdev->dev;
132059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->pdata = pdata;
132159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->ref_count = 0;
132259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
132359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->raw_dmamask = DMA_BIT_MASK(32);
132459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->dev->dma_mask = &iss->raw_dmamask;
132559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->dev->coherent_dma_mask = DMA_BIT_MASK(32);
132659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
132759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	platform_set_drvdata(pdev, iss);
132859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
132959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Clocks */
133059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = iss_map_mem_resource(pdev, iss, OMAP4_ISS_MEM_TOP);
133159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
133259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error;
133359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
133459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = iss_get_clocks(iss);
133559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
133659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error;
133759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
133859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (omap4iss_get(iss) == NULL)
133959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error;
134059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
134159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = iss_reset(iss);
134259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
134359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_iss;
134459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
134559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->revision = readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_REVISION);
134659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	dev_info(iss->dev, "Revision %08x found\n", iss->revision);
134759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
134859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	for (i = 1; i < OMAP4_ISS_MEM_LAST; i++) {
134959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = iss_map_mem_resource(pdev, iss, i);
135059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (ret)
135159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			goto error_iss;
135259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
135359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
135459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Configure BTE BW_LIMITER field to max recommended value (1 GB) */
135559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	writel((readl(iss->regs[OMAP4_ISS_MEM_BTE] + BTE_CTRL) & ~BTE_CTRL_BW_LIMITER_MASK) |
135659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		(18 << BTE_CTRL_BW_LIMITER_SHIFT),
135759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		iss->regs[OMAP4_ISS_MEM_BTE] + BTE_CTRL);
135859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
135959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Perform ISP reset */
136059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = omap4iss_subclk_enable(iss, OMAP4_ISS_SUBCLK_ISP);
136159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
136259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_iss;
136359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
136459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = iss_isp_reset(iss);
136559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
136659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_iss;
136759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
136859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	dev_info(iss->dev, "ISP Revision %08x found\n",
136959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		 readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_REVISION));
137059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
137159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Interrupt */
137259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss->irq_num = platform_get_irq(pdev, 0);
137359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (iss->irq_num <= 0) {
137459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "No IRQ resource\n");
137559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = -ENODEV;
137659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_iss;
137759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
137859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
137959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (request_irq(iss->irq_num, iss_isr, IRQF_SHARED, "OMAP4 ISS", iss)) {
138059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		dev_err(iss->dev, "Unable to request IRQ\n");
138159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		ret = -EINVAL;
138259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_iss;
138359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
138459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
138559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	/* Entities */
138659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = iss_initialize_modules(iss);
138759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
138859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_irq;
138959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
139059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	ret = iss_register_entities(iss);
139159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	if (ret < 0)
139259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		goto error_modules;
139359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
139459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_put(iss);
139559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
139659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
139759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
139859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_modules:
139959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss_cleanup_modules(iss);
140059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_irq:
140159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	free_irq(iss->irq_num, iss);
140259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror_iss:
140359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	omap4iss_put(iss);
140459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirreerror:
140559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss_put_clocks(iss);
140659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
140759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	for (i = 0; i < OMAP4_ISS_MEM_LAST; i++) {
140859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (iss->regs[i]) {
140959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			iounmap(iss->regs[i]);
141059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			iss->regs[i] = NULL;
141159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
141259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
141359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (iss->res[i]) {
141459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			release_mem_region(iss->res[i]->start,
141559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					   resource_size(iss->res[i]));
141659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			iss->res[i] = NULL;
141759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
141859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
141959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	platform_set_drvdata(pdev, NULL);
142059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
142159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	mutex_destroy(&iss->iss_mutex);
142259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	kfree(iss);
142359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
142459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return ret;
142559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
142659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
142759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic int iss_remove(struct platform_device *pdev)
142859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre{
142959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	struct iss_device *iss = platform_get_drvdata(pdev);
143059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	int i;
143159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
143259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss_unregister_entities(iss);
143359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss_cleanup_modules(iss);
143459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
143559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	free_irq(iss->irq_num, iss);
143659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	iss_put_clocks(iss);
143759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
143859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	for (i = 0; i < OMAP4_ISS_MEM_LAST; i++) {
143959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (iss->regs[i]) {
144059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			iounmap(iss->regs[i]);
144159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			iss->regs[i] = NULL;
144259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
144359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
144459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		if (iss->res[i]) {
144559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			release_mem_region(iss->res[i]->start,
144659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre					   resource_size(iss->res[i]));
144759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre			iss->res[i] = NULL;
144859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		}
144959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	}
145059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
145159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	kfree(iss);
145259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
145359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	return 0;
145459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre}
145559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
145659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic struct platform_device_id omap4iss_id_table[] = {
145759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	{ "omap4iss", 0 },
145859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	{ },
145959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre};
146059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio AguirreMODULE_DEVICE_TABLE(platform, omap4iss_id_table);
146159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
146259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirrestatic struct platform_driver iss_driver = {
146359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	.probe		= iss_probe,
146459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	.remove		= iss_remove,
146559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	.id_table	= omap4iss_id_table,
146659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	.driver = {
146759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		.owner	= THIS_MODULE,
146859f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre		.name	= "omap4iss",
146959f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre	},
147059f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre};
147159f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
147259f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirremodule_platform_driver(iss_driver);
147359f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio Aguirre
147459f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio AguirreMODULE_DESCRIPTION("TI OMAP4 ISS driver");
147559f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio AguirreMODULE_AUTHOR("Sergio Aguirre <sergio.a.aguirre@gmail.com>");
147659f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio AguirreMODULE_LICENSE("GPL");
147759f0ad8076816d13f7cba80d2b178ff5ab787e2eSergio AguirreMODULE_VERSION(ISS_VIDEO_DRIVER_VERSION);
1478