iss.c revision ea72717e961d1166882370a87876bfeacc967eb0
1/*
2 * TI OMAP4 ISS V4L2 Driver
3 *
4 * Copyright (C) 2012, Texas Instruments
5 *
6 * Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 */
13
14#include <linux/clk.h>
15#include <linux/delay.h>
16#include <linux/device.h>
17#include <linux/dma-mapping.h>
18#include <linux/i2c.h>
19#include <linux/interrupt.h>
20#include <linux/module.h>
21#include <linux/platform_device.h>
22#include <linux/slab.h>
23#include <linux/sched.h>
24#include <linux/vmalloc.h>
25
26#include <media/v4l2-common.h>
27#include <media/v4l2-device.h>
28#include <media/v4l2-ctrls.h>
29
30#include "iss.h"
31#include "iss_regs.h"
32
33#define ISS_PRINT_REGISTER(iss, name)\
34	dev_dbg(iss->dev, "###ISS " #name "=0x%08x\n", \
35		readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_##name))
36
37static void iss_print_status(struct iss_device *iss)
38{
39	dev_dbg(iss->dev, "-------------ISS HL Register dump-------------\n");
40
41	ISS_PRINT_REGISTER(iss, HL_REVISION);
42	ISS_PRINT_REGISTER(iss, HL_SYSCONFIG);
43	ISS_PRINT_REGISTER(iss, HL_IRQSTATUS_5);
44	ISS_PRINT_REGISTER(iss, HL_IRQENABLE_5_SET);
45	ISS_PRINT_REGISTER(iss, HL_IRQENABLE_5_CLR);
46	ISS_PRINT_REGISTER(iss, CTRL);
47	ISS_PRINT_REGISTER(iss, CLKCTRL);
48	ISS_PRINT_REGISTER(iss, CLKSTAT);
49
50	dev_dbg(iss->dev, "-----------------------------------------------\n");
51}
52
53/*
54 * omap4iss_flush - Post pending L3 bus writes by doing a register readback
55 * @iss: OMAP4 ISS device
56 *
57 * In order to force posting of pending writes, we need to write and
58 * readback the same register, in this case the revision register.
59 *
60 * See this link for reference:
61 *   http://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html
62 */
63void omap4iss_flush(struct iss_device *iss)
64{
65	writel(0, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_REVISION);
66	readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_REVISION);
67}
68
69/*
70 * iss_enable_interrupts - Enable ISS interrupts.
71 * @iss: OMAP4 ISS device
72 */
73static void iss_enable_interrupts(struct iss_device *iss)
74{
75	static const u32 hl_irq = ISS_HL_IRQ_CSIA | ISS_HL_IRQ_CSIB | ISS_HL_IRQ_ISP(0);
76
77	/* Enable HL interrupts */
78	writel(hl_irq, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQSTATUS_5);
79	writel(hl_irq, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQENABLE_5_SET);
80
81}
82
83/*
84 * iss_disable_interrupts - Disable ISS interrupts.
85 * @iss: OMAP4 ISS device
86 */
87static void iss_disable_interrupts(struct iss_device *iss)
88{
89	writel(-1, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQENABLE_5_CLR);
90}
91
92/*
93 * iss_isp_enable_interrupts - Enable ISS ISP interrupts.
94 * @iss: OMAP4 ISS device
95 */
96void omap4iss_isp_enable_interrupts(struct iss_device *iss)
97{
98	static const u32 isp_irq = ISP5_IRQ_OCP_ERR |
99				   ISP5_IRQ_RSZ_FIFO_IN_BLK |
100				   ISP5_IRQ_RSZ_FIFO_OVF |
101				   ISP5_IRQ_RSZ_INT_DMA |
102				   ISP5_IRQ_ISIF0;
103
104	/* Enable ISP interrupts */
105	writel(isp_irq, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_IRQSTATUS(0));
106	writel(isp_irq, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_IRQENABLE_SET(0));
107}
108
109/*
110 * iss_isp_disable_interrupts - Disable ISS interrupts.
111 * @iss: OMAP4 ISS device
112 */
113void omap4iss_isp_disable_interrupts(struct iss_device *iss)
114{
115	writel(-1, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_IRQENABLE_CLR(0));
116}
117
118int omap4iss_get_external_info(struct iss_pipeline *pipe,
119			       struct media_link *link)
120{
121	struct iss_device *iss =
122		container_of(pipe, struct iss_video, pipe)->iss;
123	struct v4l2_subdev_format fmt;
124	struct v4l2_ctrl *ctrl;
125	int ret;
126
127	if (!pipe->external)
128		return 0;
129
130	if (pipe->external_rate)
131		return 0;
132
133	memset(&fmt, 0, sizeof(fmt));
134
135	fmt.pad = link->source->index;
136	fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
137	ret = v4l2_subdev_call(media_entity_to_v4l2_subdev(link->sink->entity),
138			       pad, get_fmt, NULL, &fmt);
139	if (ret < 0)
140		return -EPIPE;
141
142	pipe->external_bpp = omap4iss_video_format_info(fmt.format.code)->bpp;
143
144	ctrl = v4l2_ctrl_find(pipe->external->ctrl_handler,
145			      V4L2_CID_PIXEL_RATE);
146	if (ctrl == NULL) {
147		dev_warn(iss->dev, "no pixel rate control in subdev %s\n",
148			 pipe->external->name);
149		return -EPIPE;
150	}
151
152	pipe->external_rate = v4l2_ctrl_g_ctrl_int64(ctrl);
153
154	return 0;
155}
156
157/*
158 * Configure the bridge. Valid inputs are
159 *
160 * IPIPEIF_INPUT_CSI2A: CSI2a receiver
161 * IPIPEIF_INPUT_CSI2B: CSI2b receiver
162 *
163 * The bridge and lane shifter are configured according to the selected input
164 * and the ISP platform data.
165 */
166void omap4iss_configure_bridge(struct iss_device *iss,
167			       enum ipipeif_input_entity input)
168{
169	u32 issctrl_val;
170	u32 isp5ctrl_val;
171
172	issctrl_val  = readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CTRL);
173	issctrl_val &= ~ISS_CTRL_INPUT_SEL_MASK;
174	issctrl_val &= ~ISS_CTRL_CLK_DIV_MASK;
175
176	isp5ctrl_val  = readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL);
177
178	switch (input) {
179	case IPIPEIF_INPUT_CSI2A:
180		issctrl_val |= ISS_CTRL_INPUT_SEL_CSI2A;
181		isp5ctrl_val |= ISP5_CTRL_VD_PULSE_EXT;
182		break;
183
184	case IPIPEIF_INPUT_CSI2B:
185		issctrl_val |= ISS_CTRL_INPUT_SEL_CSI2B;
186		isp5ctrl_val |= ISP5_CTRL_VD_PULSE_EXT;
187		break;
188
189	default:
190		return;
191	}
192
193	issctrl_val |= ISS_CTRL_SYNC_DETECT_VS_RAISING;
194
195	isp5ctrl_val |= ISP5_CTRL_PSYNC_CLK_SEL | ISP5_CTRL_SYNC_ENABLE;
196
197	writel(issctrl_val, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CTRL);
198	writel(isp5ctrl_val, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL);
199}
200
201static inline void iss_isr_dbg(struct iss_device *iss, u32 irqstatus)
202{
203	static const char *name[] = {
204		"ISP_IRQ0",
205		"ISP_IRQ1",
206		"ISP_IRQ2",
207		"ISP_IRQ3",
208		"CSIA_IRQ",
209		"CSIB_IRQ",
210		"CCP2_IRQ0",
211		"CCP2_IRQ1",
212		"CCP2_IRQ2",
213		"CCP2_IRQ3",
214		"CBUFF_IRQ",
215		"BTE_IRQ",
216		"SIMCOP_IRQ0",
217		"SIMCOP_IRQ1",
218		"SIMCOP_IRQ2",
219		"SIMCOP_IRQ3",
220		"CCP2_IRQ8",
221		"HS_VS_IRQ",
222		"res18",
223		"res19",
224		"res20",
225		"res21",
226		"res22",
227		"res23",
228		"res24",
229		"res25",
230		"res26",
231		"res27",
232		"res28",
233		"res29",
234		"res30",
235		"res31",
236	};
237	int i;
238
239	dev_dbg(iss->dev, "ISS IRQ: ");
240
241	for (i = 0; i < ARRAY_SIZE(name); i++) {
242		if ((1 << i) & irqstatus)
243			pr_cont("%s ", name[i]);
244	}
245	pr_cont("\n");
246}
247
248/*
249 * iss_isr - Interrupt Service Routine for ISS module.
250 * @irq: Not used currently.
251 * @_iss: Pointer to the OMAP4 ISS device
252 *
253 * Handles the corresponding callback if plugged in.
254 *
255 * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the
256 * IRQ wasn't handled.
257 */
258static irqreturn_t iss_isr(int irq, void *_iss)
259{
260	static const u32 ipipeif_events = ISP5_IRQ_IPIPEIF |
261					  ISP5_IRQ_ISIF0;
262	static const u32 resizer_events = ISP5_IRQ_RSZ_FIFO_IN_BLK |
263					  ISP5_IRQ_RSZ_FIFO_OVF |
264					  ISP5_IRQ_RSZ_INT_DMA;
265	struct iss_device *iss = _iss;
266	u32 irqstatus;
267
268	irqstatus = readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQSTATUS_5);
269	writel(irqstatus, iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_IRQSTATUS_5);
270
271	if (irqstatus & ISS_HL_IRQ_CSIA)
272		omap4iss_csi2_isr(&iss->csi2a);
273
274	if (irqstatus & ISS_HL_IRQ_CSIB)
275		omap4iss_csi2_isr(&iss->csi2b);
276
277	if (irqstatus & ISS_HL_IRQ_ISP(0)) {
278		u32 isp_irqstatus = readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] +
279					  ISP5_IRQSTATUS(0));
280		writel(isp_irqstatus, iss->regs[OMAP4_ISS_MEM_ISP_SYS1] +
281			ISP5_IRQSTATUS(0));
282
283		if (isp_irqstatus & ISP5_IRQ_OCP_ERR)
284			dev_dbg(iss->dev, "ISP5 OCP Error!\n");
285
286		if (isp_irqstatus & ipipeif_events) {
287			omap4iss_ipipeif_isr(&iss->ipipeif,
288					     isp_irqstatus & ipipeif_events);
289		}
290
291		if (isp_irqstatus & resizer_events)
292			omap4iss_resizer_isr(&iss->resizer,
293					     isp_irqstatus & resizer_events);
294	}
295
296	omap4iss_flush(iss);
297
298#if defined(DEBUG) && defined(ISS_ISR_DEBUG)
299	iss_isr_dbg(iss, irqstatus);
300#endif
301
302	return IRQ_HANDLED;
303}
304
305/* -----------------------------------------------------------------------------
306 * Pipeline power management
307 *
308 * Entities must be powered up when part of a pipeline that contains at least
309 * one open video device node.
310 *
311 * To achieve this use the entity use_count field to track the number of users.
312 * For entities corresponding to video device nodes the use_count field stores
313 * the users count of the node. For entities corresponding to subdevs the
314 * use_count field stores the total number of users of all video device nodes
315 * in the pipeline.
316 *
317 * The omap4iss_pipeline_pm_use() function must be called in the open() and
318 * close() handlers of video device nodes. It increments or decrements the use
319 * count of all subdev entities in the pipeline.
320 *
321 * To react to link management on powered pipelines, the link setup notification
322 * callback updates the use count of all entities in the source and sink sides
323 * of the link.
324 */
325
326/*
327 * iss_pipeline_pm_use_count - Count the number of users of a pipeline
328 * @entity: The entity
329 *
330 * Return the total number of users of all video device nodes in the pipeline.
331 */
332static int iss_pipeline_pm_use_count(struct media_entity *entity)
333{
334	struct media_entity_graph graph;
335	int use = 0;
336
337	media_entity_graph_walk_start(&graph, entity);
338
339	while ((entity = media_entity_graph_walk_next(&graph))) {
340		if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
341			use += entity->use_count;
342	}
343
344	return use;
345}
346
347/*
348 * iss_pipeline_pm_power_one - Apply power change to an entity
349 * @entity: The entity
350 * @change: Use count change
351 *
352 * Change the entity use count by @change. If the entity is a subdev update its
353 * power state by calling the core::s_power operation when the use count goes
354 * from 0 to != 0 or from != 0 to 0.
355 *
356 * Return 0 on success or a negative error code on failure.
357 */
358static int iss_pipeline_pm_power_one(struct media_entity *entity, int change)
359{
360	struct v4l2_subdev *subdev;
361
362	subdev = media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV
363	       ? media_entity_to_v4l2_subdev(entity) : NULL;
364
365	if (entity->use_count == 0 && change > 0 && subdev != NULL) {
366		int ret;
367
368		ret = v4l2_subdev_call(subdev, core, s_power, 1);
369		if (ret < 0 && ret != -ENOIOCTLCMD)
370			return ret;
371	}
372
373	entity->use_count += change;
374	WARN_ON(entity->use_count < 0);
375
376	if (entity->use_count == 0 && change < 0 && subdev != NULL)
377		v4l2_subdev_call(subdev, core, s_power, 0);
378
379	return 0;
380}
381
382/*
383 * iss_pipeline_pm_power - Apply power change to all entities in a pipeline
384 * @entity: The entity
385 * @change: Use count change
386 *
387 * Walk the pipeline to update the use count and the power state of all non-node
388 * entities.
389 *
390 * Return 0 on success or a negative error code on failure.
391 */
392static int iss_pipeline_pm_power(struct media_entity *entity, int change)
393{
394	struct media_entity_graph graph;
395	struct media_entity *first = entity;
396	int ret = 0;
397
398	if (!change)
399		return 0;
400
401	media_entity_graph_walk_start(&graph, entity);
402
403	while (!ret && (entity = media_entity_graph_walk_next(&graph)))
404		if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
405			ret = iss_pipeline_pm_power_one(entity, change);
406
407	if (!ret)
408		return 0;
409
410	media_entity_graph_walk_start(&graph, first);
411
412	while ((first = media_entity_graph_walk_next(&graph))
413	       && first != entity)
414		if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE)
415			iss_pipeline_pm_power_one(first, -change);
416
417	return ret;
418}
419
420/*
421 * omap4iss_pipeline_pm_use - Update the use count of an entity
422 * @entity: The entity
423 * @use: Use (1) or stop using (0) the entity
424 *
425 * Update the use count of all entities in the pipeline and power entities on or
426 * off accordingly.
427 *
428 * Return 0 on success or a negative error code on failure. Powering entities
429 * off is assumed to never fail. No failure can occur when the use parameter is
430 * set to 0.
431 */
432int omap4iss_pipeline_pm_use(struct media_entity *entity, int use)
433{
434	int change = use ? 1 : -1;
435	int ret;
436
437	mutex_lock(&entity->parent->graph_mutex);
438
439	/* Apply use count to node. */
440	entity->use_count += change;
441	WARN_ON(entity->use_count < 0);
442
443	/* Apply power change to connected non-nodes. */
444	ret = iss_pipeline_pm_power(entity, change);
445	if (ret < 0)
446		entity->use_count -= change;
447
448	mutex_unlock(&entity->parent->graph_mutex);
449
450	return ret;
451}
452
453/*
454 * iss_pipeline_link_notify - Link management notification callback
455 * @link: The link
456 * @flags: New link flags that will be applied
457 *
458 * React to link management on powered pipelines by updating the use count of
459 * all entities in the source and sink sides of the link. Entities are powered
460 * on or off accordingly.
461 *
462 * Return 0 on success or a negative error code on failure. Powering entities
463 * off is assumed to never fail. This function will not fail for disconnection
464 * events.
465 */
466static int iss_pipeline_link_notify(struct media_link *link, u32 flags,
467				    unsigned int notification)
468{
469	struct media_entity *source = link->source->entity;
470	struct media_entity *sink = link->sink->entity;
471	int source_use = iss_pipeline_pm_use_count(source);
472	int sink_use = iss_pipeline_pm_use_count(sink);
473	int ret;
474
475	if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
476	    !(link->flags & MEDIA_LNK_FL_ENABLED)) {
477		/* Powering off entities is assumed to never fail. */
478		iss_pipeline_pm_power(source, -sink_use);
479		iss_pipeline_pm_power(sink, -source_use);
480		return 0;
481	}
482
483	if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
484		(flags & MEDIA_LNK_FL_ENABLED)) {
485		ret = iss_pipeline_pm_power(source, sink_use);
486		if (ret < 0)
487			return ret;
488
489		ret = iss_pipeline_pm_power(sink, source_use);
490		if (ret < 0)
491			iss_pipeline_pm_power(source, -sink_use);
492
493		return ret;
494	}
495
496	return 0;
497}
498
499/* -----------------------------------------------------------------------------
500 * Pipeline stream management
501 */
502
503/*
504 * iss_pipeline_enable - Enable streaming on a pipeline
505 * @pipe: ISS pipeline
506 * @mode: Stream mode (single shot or continuous)
507 *
508 * Walk the entities chain starting at the pipeline output video node and start
509 * all modules in the chain in the given mode.
510 *
511 * Return 0 if successful, or the return value of the failed video::s_stream
512 * operation otherwise.
513 */
514static int iss_pipeline_enable(struct iss_pipeline *pipe,
515			       enum iss_pipeline_stream_state mode)
516{
517	struct media_entity *entity;
518	struct media_pad *pad;
519	struct v4l2_subdev *subdev;
520	unsigned long flags;
521	int ret;
522
523	spin_lock_irqsave(&pipe->lock, flags);
524	pipe->state &= ~(ISS_PIPELINE_IDLE_INPUT | ISS_PIPELINE_IDLE_OUTPUT);
525	spin_unlock_irqrestore(&pipe->lock, flags);
526
527	pipe->do_propagation = false;
528
529	entity = &pipe->output->video.entity;
530	while (1) {
531		pad = &entity->pads[0];
532		if (!(pad->flags & MEDIA_PAD_FL_SINK))
533			break;
534
535		pad = media_entity_remote_pad(pad);
536		if (pad == NULL ||
537		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
538			break;
539
540		entity = pad->entity;
541		subdev = media_entity_to_v4l2_subdev(entity);
542
543		ret = v4l2_subdev_call(subdev, video, s_stream, mode);
544		if (ret < 0 && ret != -ENOIOCTLCMD)
545			return ret;
546	}
547	iss_print_status(pipe->output->iss);
548	return 0;
549}
550
551/*
552 * iss_pipeline_disable - Disable streaming on a pipeline
553 * @pipe: ISS pipeline
554 *
555 * Walk the entities chain starting at the pipeline output video node and stop
556 * all modules in the chain. Wait synchronously for the modules to be stopped if
557 * necessary.
558 */
559static int iss_pipeline_disable(struct iss_pipeline *pipe)
560{
561	struct media_entity *entity;
562	struct media_pad *pad;
563	struct v4l2_subdev *subdev;
564	int failure = 0;
565
566	entity = &pipe->output->video.entity;
567	while (1) {
568		pad = &entity->pads[0];
569		if (!(pad->flags & MEDIA_PAD_FL_SINK))
570			break;
571
572		pad = media_entity_remote_pad(pad);
573		if (pad == NULL ||
574		    media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
575			break;
576
577		entity = pad->entity;
578		subdev = media_entity_to_v4l2_subdev(entity);
579
580		v4l2_subdev_call(subdev, video, s_stream, 0);
581	}
582
583	return failure;
584}
585
586/*
587 * omap4iss_pipeline_set_stream - Enable/disable streaming on a pipeline
588 * @pipe: ISS pipeline
589 * @state: Stream state (stopped, single shot or continuous)
590 *
591 * Set the pipeline to the given stream state. Pipelines can be started in
592 * single-shot or continuous mode.
593 *
594 * Return 0 if successful, or the return value of the failed video::s_stream
595 * operation otherwise. The pipeline state is not updated when the operation
596 * fails, except when stopping the pipeline.
597 */
598int omap4iss_pipeline_set_stream(struct iss_pipeline *pipe,
599				 enum iss_pipeline_stream_state state)
600{
601	int ret;
602
603	if (state == ISS_PIPELINE_STREAM_STOPPED)
604		ret = iss_pipeline_disable(pipe);
605	else
606		ret = iss_pipeline_enable(pipe, state);
607
608	if (ret == 0 || state == ISS_PIPELINE_STREAM_STOPPED)
609		pipe->stream_state = state;
610
611	return ret;
612}
613
614/*
615 * iss_pipeline_is_last - Verify if entity has an enabled link to the output
616 *			  video node
617 * @me: ISS module's media entity
618 *
619 * Returns 1 if the entity has an enabled link to the output video node or 0
620 * otherwise. It's true only while pipeline can have no more than one output
621 * node.
622 */
623static int iss_pipeline_is_last(struct media_entity *me)
624{
625	struct iss_pipeline *pipe;
626	struct media_pad *pad;
627
628	if (!me->pipe)
629		return 0;
630	pipe = to_iss_pipeline(me);
631	if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED)
632		return 0;
633	pad = media_entity_remote_pad(&pipe->output->pad);
634	return pad->entity == me;
635}
636
637static int iss_reset(struct iss_device *iss)
638{
639	unsigned long timeout = 0;
640
641	writel(readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_SYSCONFIG) |
642		ISS_HL_SYSCONFIG_SOFTRESET,
643		iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_SYSCONFIG);
644
645	while (readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_SYSCONFIG) &
646			ISS_HL_SYSCONFIG_SOFTRESET) {
647		if (timeout++ > 10000) {
648			dev_alert(iss->dev, "cannot reset ISS\n");
649			return -ETIMEDOUT;
650		}
651		udelay(1);
652	}
653
654	return 0;
655}
656
657static int iss_isp_reset(struct iss_device *iss)
658{
659	unsigned long timeout = 0;
660
661	/* Fist, ensure that the ISP is IDLE (no transactions happening) */
662	writel((readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG) &
663		~ISP5_SYSCONFIG_STANDBYMODE_MASK) |
664		ISP5_SYSCONFIG_STANDBYMODE_SMART,
665		iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG);
666
667	writel(readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL) |
668		ISP5_CTRL_MSTANDBY,
669		iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL);
670
671	for (;;) {
672		if (readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL) &
673				ISP5_CTRL_MSTANDBY_WAIT)
674			break;
675		if (timeout++ > 1000) {
676			dev_alert(iss->dev, "cannot set ISP5 to standby\n");
677			return -ETIMEDOUT;
678		}
679		msleep(1);
680	}
681
682	/* Now finally, do the reset */
683	writel(readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG) |
684		ISP5_SYSCONFIG_SOFTRESET,
685		iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG);
686
687	timeout = 0;
688	while (readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_SYSCONFIG) &
689			ISP5_SYSCONFIG_SOFTRESET) {
690		if (timeout++ > 1000) {
691			dev_alert(iss->dev, "cannot reset ISP5\n");
692			return -ETIMEDOUT;
693		}
694		msleep(1);
695	}
696
697	return 0;
698}
699
700/*
701 * iss_module_sync_idle - Helper to sync module with its idle state
702 * @me: ISS submodule's media entity
703 * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization
704 * @stopping: flag which tells module wants to stop
705 *
706 * This function checks if ISS submodule needs to wait for next interrupt. If
707 * yes, makes the caller to sleep while waiting for such event.
708 */
709int omap4iss_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
710			      atomic_t *stopping)
711{
712	struct iss_pipeline *pipe = to_iss_pipeline(me);
713	struct iss_video *video = pipe->output;
714	unsigned long flags;
715
716	if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED ||
717	    (pipe->stream_state == ISS_PIPELINE_STREAM_SINGLESHOT &&
718	     !iss_pipeline_ready(pipe)))
719		return 0;
720
721	/*
722	 * atomic_set() doesn't include memory barrier on ARM platform for SMP
723	 * scenario. We'll call it here to avoid race conditions.
724	 */
725	atomic_set(stopping, 1);
726	smp_wmb();
727
728	/*
729	 * If module is the last one, it's writing to memory. In this case,
730	 * it's necessary to check if the module is already paused due to
731	 * DMA queue underrun or if it has to wait for next interrupt to be
732	 * idle.
733	 * If it isn't the last one, the function won't sleep but *stopping
734	 * will still be set to warn next submodule caller's interrupt the
735	 * module wants to be idle.
736	 */
737	if (!iss_pipeline_is_last(me))
738		return 0;
739
740	spin_lock_irqsave(&video->qlock, flags);
741	if (video->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) {
742		spin_unlock_irqrestore(&video->qlock, flags);
743		atomic_set(stopping, 0);
744		smp_wmb();
745		return 0;
746	}
747	spin_unlock_irqrestore(&video->qlock, flags);
748	if (!wait_event_timeout(*wait, !atomic_read(stopping),
749				msecs_to_jiffies(1000))) {
750		atomic_set(stopping, 0);
751		smp_wmb();
752		return -ETIMEDOUT;
753	}
754
755	return 0;
756}
757
758/*
759 * omap4iss_module_sync_is_stopped - Helper to verify if module was stopping
760 * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization
761 * @stopping: flag which tells module wants to stop
762 *
763 * This function checks if ISS submodule was stopping. In case of yes, it
764 * notices the caller by setting stopping to 0 and waking up the wait queue.
765 * Returns 1 if it was stopping or 0 otherwise.
766 */
767int omap4iss_module_sync_is_stopping(wait_queue_head_t *wait,
768				     atomic_t *stopping)
769{
770	if (atomic_cmpxchg(stopping, 1, 0)) {
771		wake_up(wait);
772		return 1;
773	}
774
775	return 0;
776}
777
778/* --------------------------------------------------------------------------
779 * Clock management
780 */
781
782#define ISS_CLKCTRL_MASK	(ISS_CLKCTRL_CSI2_A |\
783				 ISS_CLKCTRL_CSI2_B |\
784				 ISS_CLKCTRL_ISP)
785
786static int __iss_subclk_update(struct iss_device *iss)
787{
788	u32 clk = 0;
789	int ret = 0, timeout = 1000;
790
791	if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_A)
792		clk |= ISS_CLKCTRL_CSI2_A;
793
794	if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_B)
795		clk |= ISS_CLKCTRL_CSI2_B;
796
797	if (iss->subclk_resources & OMAP4_ISS_SUBCLK_ISP)
798		clk |= ISS_CLKCTRL_ISP;
799
800	writel((readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CLKCTRL) &
801		~ISS_CLKCTRL_MASK) | clk,
802		iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CLKCTRL);
803
804	/* Wait for HW assertion */
805	while (--timeout > 0) {
806		udelay(1);
807		if ((readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_CLKSTAT) &
808		     ISS_CLKCTRL_MASK) == clk)
809			break;
810	}
811
812	if (!timeout)
813		ret = -EBUSY;
814
815	return ret;
816}
817
818int omap4iss_subclk_enable(struct iss_device *iss,
819			    enum iss_subclk_resource res)
820{
821	iss->subclk_resources |= res;
822
823	return __iss_subclk_update(iss);
824}
825
826int omap4iss_subclk_disable(struct iss_device *iss,
827			     enum iss_subclk_resource res)
828{
829	iss->subclk_resources &= ~res;
830
831	return __iss_subclk_update(iss);
832}
833
834#define ISS_ISP5_CLKCTRL_MASK	(ISP5_CTRL_BL_CLK_ENABLE |\
835				 ISP5_CTRL_ISIF_CLK_ENABLE |\
836				 ISP5_CTRL_H3A_CLK_ENABLE |\
837				 ISP5_CTRL_RSZ_CLK_ENABLE |\
838				 ISP5_CTRL_IPIPE_CLK_ENABLE |\
839				 ISP5_CTRL_IPIPEIF_CLK_ENABLE)
840
841static int __iss_isp_subclk_update(struct iss_device *iss)
842{
843	u32 clk = 0;
844
845	if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_ISIF)
846		clk |= ISP5_CTRL_ISIF_CLK_ENABLE;
847
848	if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_H3A)
849		clk |= ISP5_CTRL_H3A_CLK_ENABLE;
850
851	if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_RSZ)
852		clk |= ISP5_CTRL_RSZ_CLK_ENABLE;
853
854	if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPE)
855		clk |= ISP5_CTRL_IPIPE_CLK_ENABLE;
856
857	if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPEIF)
858		clk |= ISP5_CTRL_IPIPEIF_CLK_ENABLE;
859
860	if (clk)
861		clk |= ISP5_CTRL_BL_CLK_ENABLE;
862
863	writel((readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL) &
864		~ISS_ISP5_CLKCTRL_MASK) | clk,
865		iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_CTRL);
866
867	return 0;
868}
869
870int omap4iss_isp_subclk_enable(struct iss_device *iss,
871				enum iss_isp_subclk_resource res)
872{
873	iss->isp_subclk_resources |= res;
874
875	return __iss_isp_subclk_update(iss);
876}
877
878int omap4iss_isp_subclk_disable(struct iss_device *iss,
879				enum iss_isp_subclk_resource res)
880{
881	iss->isp_subclk_resources &= ~res;
882
883	return __iss_isp_subclk_update(iss);
884}
885
886/*
887 * iss_enable_clocks - Enable ISS clocks
888 * @iss: OMAP4 ISS device
889 *
890 * Return 0 if successful, or clk_enable return value if any of tthem fails.
891 */
892static int iss_enable_clocks(struct iss_device *iss)
893{
894	int r;
895
896	r = clk_enable(iss->iss_fck);
897	if (r) {
898		dev_err(iss->dev, "clk_enable iss_fck failed\n");
899		return r;
900	}
901
902	r = clk_enable(iss->iss_ctrlclk);
903	if (r) {
904		dev_err(iss->dev, "clk_enable iss_ctrlclk failed\n");
905		goto out_clk_enable_ctrlclk;
906	}
907	return 0;
908
909out_clk_enable_ctrlclk:
910	clk_disable(iss->iss_fck);
911	return r;
912}
913
914/*
915 * iss_disable_clocks - Disable ISS clocks
916 * @iss: OMAP4 ISS device
917 */
918static void iss_disable_clocks(struct iss_device *iss)
919{
920	clk_disable(iss->iss_ctrlclk);
921	clk_disable(iss->iss_fck);
922}
923
924static void iss_put_clocks(struct iss_device *iss)
925{
926	if (iss->iss_fck) {
927		clk_put(iss->iss_fck);
928		iss->iss_fck = NULL;
929	}
930
931	if (iss->iss_ctrlclk) {
932		clk_put(iss->iss_ctrlclk);
933		iss->iss_ctrlclk = NULL;
934	}
935}
936
937static int iss_get_clocks(struct iss_device *iss)
938{
939	iss->iss_fck = clk_get(iss->dev, "iss_fck");
940	if (IS_ERR(iss->iss_fck)) {
941		dev_err(iss->dev, "Unable to get iss_fck clock info\n");
942		iss_put_clocks(iss);
943		return PTR_ERR(iss->iss_fck);
944	}
945
946	iss->iss_ctrlclk = clk_get(iss->dev, "iss_ctrlclk");
947	if (IS_ERR(iss->iss_ctrlclk)) {
948		dev_err(iss->dev, "Unable to get iss_ctrlclk clock info\n");
949		iss_put_clocks(iss);
950		return PTR_ERR(iss->iss_fck);
951	}
952
953	return 0;
954}
955
956/*
957 * omap4iss_get - Acquire the ISS resource.
958 *
959 * Initializes the clocks for the first acquire.
960 *
961 * Increment the reference count on the ISS. If the first reference is taken,
962 * enable clocks and power-up all submodules.
963 *
964 * Return a pointer to the ISS device structure, or NULL if an error occurred.
965 */
966struct iss_device *omap4iss_get(struct iss_device *iss)
967{
968	struct iss_device *__iss = iss;
969
970	if (iss == NULL)
971		return NULL;
972
973	mutex_lock(&iss->iss_mutex);
974	if (iss->ref_count > 0)
975		goto out;
976
977	if (iss_enable_clocks(iss) < 0) {
978		__iss = NULL;
979		goto out;
980	}
981
982	iss_enable_interrupts(iss);
983
984out:
985	if (__iss != NULL)
986		iss->ref_count++;
987	mutex_unlock(&iss->iss_mutex);
988
989	return __iss;
990}
991
992/*
993 * omap4iss_put - Release the ISS
994 *
995 * Decrement the reference count on the ISS. If the last reference is released,
996 * power-down all submodules, disable clocks and free temporary buffers.
997 */
998void omap4iss_put(struct iss_device *iss)
999{
1000	if (iss == NULL)
1001		return;
1002
1003	mutex_lock(&iss->iss_mutex);
1004	BUG_ON(iss->ref_count == 0);
1005	if (--iss->ref_count == 0) {
1006		iss_disable_interrupts(iss);
1007		iss_disable_clocks(iss);
1008	}
1009	mutex_unlock(&iss->iss_mutex);
1010}
1011
1012static int iss_map_mem_resource(struct platform_device *pdev,
1013				struct iss_device *iss,
1014				enum iss_mem_resources res)
1015{
1016	struct resource *mem;
1017
1018	/* request the mem region for the camera registers */
1019
1020	mem = platform_get_resource(pdev, IORESOURCE_MEM, res);
1021	if (!mem) {
1022		dev_err(iss->dev, "no mem resource?\n");
1023		return -ENODEV;
1024	}
1025
1026	if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
1027		dev_err(iss->dev,
1028			"cannot reserve camera register I/O region\n");
1029		return -ENODEV;
1030	}
1031	iss->res[res] = mem;
1032
1033	/* map the region */
1034	iss->regs[res] = ioremap_nocache(mem->start, resource_size(mem));
1035	if (!iss->regs[res]) {
1036		dev_err(iss->dev, "cannot map camera register I/O region\n");
1037		return -ENODEV;
1038	}
1039
1040	return 0;
1041}
1042
1043static void iss_unregister_entities(struct iss_device *iss)
1044{
1045	omap4iss_resizer_unregister_entities(&iss->resizer);
1046	omap4iss_ipipe_unregister_entities(&iss->ipipe);
1047	omap4iss_ipipeif_unregister_entities(&iss->ipipeif);
1048	omap4iss_csi2_unregister_entities(&iss->csi2a);
1049	omap4iss_csi2_unregister_entities(&iss->csi2b);
1050
1051	v4l2_device_unregister(&iss->v4l2_dev);
1052	media_device_unregister(&iss->media_dev);
1053}
1054
1055/*
1056 * iss_register_subdev_group - Register a group of subdevices
1057 * @iss: OMAP4 ISS device
1058 * @board_info: I2C subdevs board information array
1059 *
1060 * Register all I2C subdevices in the board_info array. The array must be
1061 * terminated by a NULL entry, and the first entry must be the sensor.
1062 *
1063 * Return a pointer to the sensor media entity if it has been successfully
1064 * registered, or NULL otherwise.
1065 */
1066static struct v4l2_subdev *
1067iss_register_subdev_group(struct iss_device *iss,
1068		     struct iss_subdev_i2c_board_info *board_info)
1069{
1070	struct v4l2_subdev *sensor = NULL;
1071	unsigned int first;
1072
1073	if (board_info->board_info == NULL)
1074		return NULL;
1075
1076	for (first = 1; board_info->board_info; ++board_info, first = 0) {
1077		struct v4l2_subdev *subdev;
1078		struct i2c_adapter *adapter;
1079
1080		adapter = i2c_get_adapter(board_info->i2c_adapter_id);
1081		if (adapter == NULL) {
1082			dev_err(iss->dev, "%s: Unable to get I2C adapter %d for "
1083				"device %s\n", __func__,
1084				board_info->i2c_adapter_id,
1085				board_info->board_info->type);
1086			continue;
1087		}
1088
1089		subdev = v4l2_i2c_new_subdev_board(&iss->v4l2_dev, adapter,
1090				board_info->board_info, NULL);
1091		if (subdev == NULL) {
1092			dev_err(iss->dev, "%s: Unable to register subdev %s\n",
1093				__func__, board_info->board_info->type);
1094			continue;
1095		}
1096
1097		if (first)
1098			sensor = subdev;
1099	}
1100
1101	return sensor;
1102}
1103
1104static int iss_register_entities(struct iss_device *iss)
1105{
1106	struct iss_platform_data *pdata = iss->pdata;
1107	struct iss_v4l2_subdevs_group *subdevs;
1108	int ret;
1109
1110	iss->media_dev.dev = iss->dev;
1111	strlcpy(iss->media_dev.model, "TI OMAP4 ISS",
1112		sizeof(iss->media_dev.model));
1113	iss->media_dev.hw_revision = iss->revision;
1114	iss->media_dev.link_notify = iss_pipeline_link_notify;
1115	ret = media_device_register(&iss->media_dev);
1116	if (ret < 0) {
1117		printk(KERN_ERR "%s: Media device registration failed (%d)\n",
1118			__func__, ret);
1119		return ret;
1120	}
1121
1122	iss->v4l2_dev.mdev = &iss->media_dev;
1123	ret = v4l2_device_register(iss->dev, &iss->v4l2_dev);
1124	if (ret < 0) {
1125		printk(KERN_ERR "%s: V4L2 device registration failed (%d)\n",
1126			__func__, ret);
1127		goto done;
1128	}
1129
1130	/* Register internal entities */
1131	ret = omap4iss_csi2_register_entities(&iss->csi2a, &iss->v4l2_dev);
1132	if (ret < 0)
1133		goto done;
1134
1135	ret = omap4iss_csi2_register_entities(&iss->csi2b, &iss->v4l2_dev);
1136	if (ret < 0)
1137		goto done;
1138
1139	ret = omap4iss_ipipeif_register_entities(&iss->ipipeif, &iss->v4l2_dev);
1140	if (ret < 0)
1141		goto done;
1142
1143	ret = omap4iss_ipipe_register_entities(&iss->ipipe, &iss->v4l2_dev);
1144	if (ret < 0)
1145		goto done;
1146
1147	ret = omap4iss_resizer_register_entities(&iss->resizer, &iss->v4l2_dev);
1148	if (ret < 0)
1149		goto done;
1150
1151	/* Register external entities */
1152	for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) {
1153		struct v4l2_subdev *sensor;
1154		struct media_entity *input;
1155		unsigned int flags;
1156		unsigned int pad;
1157
1158		sensor = iss_register_subdev_group(iss, subdevs->subdevs);
1159		if (sensor == NULL)
1160			continue;
1161
1162		sensor->host_priv = subdevs;
1163
1164		/* Connect the sensor to the correct interface module.
1165		 * CSI2a receiver through CSIPHY1, or
1166		 * CSI2b receiver through CSIPHY2
1167		 */
1168		switch (subdevs->interface) {
1169		case ISS_INTERFACE_CSI2A_PHY1:
1170			input = &iss->csi2a.subdev.entity;
1171			pad = CSI2_PAD_SINK;
1172			flags = MEDIA_LNK_FL_IMMUTABLE
1173			      | MEDIA_LNK_FL_ENABLED;
1174			break;
1175
1176		case ISS_INTERFACE_CSI2B_PHY2:
1177			input = &iss->csi2b.subdev.entity;
1178			pad = CSI2_PAD_SINK;
1179			flags = MEDIA_LNK_FL_IMMUTABLE
1180			      | MEDIA_LNK_FL_ENABLED;
1181			break;
1182
1183		default:
1184			printk(KERN_ERR "%s: invalid interface type %u\n",
1185			       __func__, subdevs->interface);
1186			ret = -EINVAL;
1187			goto done;
1188		}
1189
1190		ret = media_entity_create_link(&sensor->entity, 0, input, pad,
1191					       flags);
1192		if (ret < 0)
1193			goto done;
1194	}
1195
1196	ret = v4l2_device_register_subdev_nodes(&iss->v4l2_dev);
1197
1198done:
1199	if (ret < 0)
1200		iss_unregister_entities(iss);
1201
1202	return ret;
1203}
1204
1205static void iss_cleanup_modules(struct iss_device *iss)
1206{
1207	omap4iss_csi2_cleanup(iss);
1208	omap4iss_ipipeif_cleanup(iss);
1209	omap4iss_ipipe_cleanup(iss);
1210	omap4iss_resizer_cleanup(iss);
1211}
1212
1213static int iss_initialize_modules(struct iss_device *iss)
1214{
1215	int ret;
1216
1217	ret = omap4iss_csiphy_init(iss);
1218	if (ret < 0) {
1219		dev_err(iss->dev, "CSI PHY initialization failed\n");
1220		goto error_csiphy;
1221	}
1222
1223	ret = omap4iss_csi2_init(iss);
1224	if (ret < 0) {
1225		dev_err(iss->dev, "CSI2 initialization failed\n");
1226		goto error_csi2;
1227	}
1228
1229	ret = omap4iss_ipipeif_init(iss);
1230	if (ret < 0) {
1231		dev_err(iss->dev, "ISP IPIPEIF initialization failed\n");
1232		goto error_ipipeif;
1233	}
1234
1235	ret = omap4iss_ipipe_init(iss);
1236	if (ret < 0) {
1237		dev_err(iss->dev, "ISP IPIPE initialization failed\n");
1238		goto error_ipipe;
1239	}
1240
1241	ret = omap4iss_resizer_init(iss);
1242	if (ret < 0) {
1243		dev_err(iss->dev, "ISP RESIZER initialization failed\n");
1244		goto error_resizer;
1245	}
1246
1247	/* Connect the submodules. */
1248	ret = media_entity_create_link(
1249			&iss->csi2a.subdev.entity, CSI2_PAD_SOURCE,
1250			&iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0);
1251	if (ret < 0)
1252		goto error_link;
1253
1254	ret = media_entity_create_link(
1255			&iss->csi2b.subdev.entity, CSI2_PAD_SOURCE,
1256			&iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0);
1257	if (ret < 0)
1258		goto error_link;
1259
1260	ret = media_entity_create_link(
1261			&iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP,
1262			&iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0);
1263	if (ret < 0)
1264		goto error_link;
1265
1266	ret = media_entity_create_link(
1267			&iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP,
1268			&iss->ipipe.subdev.entity, IPIPE_PAD_SINK, 0);
1269	if (ret < 0)
1270		goto error_link;
1271
1272	ret = media_entity_create_link(
1273			&iss->ipipe.subdev.entity, IPIPE_PAD_SOURCE_VP,
1274			&iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0);
1275	if (ret < 0)
1276		goto error_link;
1277
1278	return 0;
1279
1280error_link:
1281	omap4iss_resizer_cleanup(iss);
1282error_resizer:
1283	omap4iss_ipipe_cleanup(iss);
1284error_ipipe:
1285	omap4iss_ipipeif_cleanup(iss);
1286error_ipipeif:
1287	omap4iss_csi2_cleanup(iss);
1288error_csi2:
1289error_csiphy:
1290	return ret;
1291}
1292
1293static int iss_probe(struct platform_device *pdev)
1294{
1295	struct iss_platform_data *pdata = pdev->dev.platform_data;
1296	struct iss_device *iss;
1297	int i, ret;
1298
1299	if (pdata == NULL)
1300		return -EINVAL;
1301
1302	iss = kzalloc(sizeof(*iss), GFP_KERNEL);
1303	if (!iss) {
1304		dev_err(&pdev->dev, "Could not allocate memory\n");
1305		return -ENOMEM;
1306	}
1307
1308	mutex_init(&iss->iss_mutex);
1309
1310	iss->dev = &pdev->dev;
1311	iss->pdata = pdata;
1312	iss->ref_count = 0;
1313
1314	iss->raw_dmamask = DMA_BIT_MASK(32);
1315	iss->dev->dma_mask = &iss->raw_dmamask;
1316	iss->dev->coherent_dma_mask = DMA_BIT_MASK(32);
1317
1318	platform_set_drvdata(pdev, iss);
1319
1320	/* Clocks */
1321	ret = iss_map_mem_resource(pdev, iss, OMAP4_ISS_MEM_TOP);
1322	if (ret < 0)
1323		goto error;
1324
1325	ret = iss_get_clocks(iss);
1326	if (ret < 0)
1327		goto error;
1328
1329	if (omap4iss_get(iss) == NULL)
1330		goto error;
1331
1332	ret = iss_reset(iss);
1333	if (ret < 0)
1334		goto error_iss;
1335
1336	iss->revision = readl(iss->regs[OMAP4_ISS_MEM_TOP] + ISS_HL_REVISION);
1337	dev_info(iss->dev, "Revision %08x found\n", iss->revision);
1338
1339	for (i = 1; i < OMAP4_ISS_MEM_LAST; i++) {
1340		ret = iss_map_mem_resource(pdev, iss, i);
1341		if (ret)
1342			goto error_iss;
1343	}
1344
1345	/* Configure BTE BW_LIMITER field to max recommended value (1 GB) */
1346	writel((readl(iss->regs[OMAP4_ISS_MEM_BTE] + BTE_CTRL) & ~BTE_CTRL_BW_LIMITER_MASK) |
1347		(18 << BTE_CTRL_BW_LIMITER_SHIFT),
1348		iss->regs[OMAP4_ISS_MEM_BTE] + BTE_CTRL);
1349
1350	/* Perform ISP reset */
1351	ret = omap4iss_subclk_enable(iss, OMAP4_ISS_SUBCLK_ISP);
1352	if (ret < 0)
1353		goto error_iss;
1354
1355	ret = iss_isp_reset(iss);
1356	if (ret < 0)
1357		goto error_iss;
1358
1359	dev_info(iss->dev, "ISP Revision %08x found\n",
1360		 readl(iss->regs[OMAP4_ISS_MEM_ISP_SYS1] + ISP5_REVISION));
1361
1362	/* Interrupt */
1363	iss->irq_num = platform_get_irq(pdev, 0);
1364	if (iss->irq_num <= 0) {
1365		dev_err(iss->dev, "No IRQ resource\n");
1366		ret = -ENODEV;
1367		goto error_iss;
1368	}
1369
1370	if (request_irq(iss->irq_num, iss_isr, IRQF_SHARED, "OMAP4 ISS", iss)) {
1371		dev_err(iss->dev, "Unable to request IRQ\n");
1372		ret = -EINVAL;
1373		goto error_iss;
1374	}
1375
1376	/* Entities */
1377	ret = iss_initialize_modules(iss);
1378	if (ret < 0)
1379		goto error_irq;
1380
1381	ret = iss_register_entities(iss);
1382	if (ret < 0)
1383		goto error_modules;
1384
1385	omap4iss_put(iss);
1386
1387	return 0;
1388
1389error_modules:
1390	iss_cleanup_modules(iss);
1391error_irq:
1392	free_irq(iss->irq_num, iss);
1393error_iss:
1394	omap4iss_put(iss);
1395error:
1396	iss_put_clocks(iss);
1397
1398	for (i = 0; i < OMAP4_ISS_MEM_LAST; i++) {
1399		if (iss->regs[i]) {
1400			iounmap(iss->regs[i]);
1401			iss->regs[i] = NULL;
1402		}
1403
1404		if (iss->res[i]) {
1405			release_mem_region(iss->res[i]->start,
1406					   resource_size(iss->res[i]));
1407			iss->res[i] = NULL;
1408		}
1409	}
1410	platform_set_drvdata(pdev, NULL);
1411
1412	mutex_destroy(&iss->iss_mutex);
1413	kfree(iss);
1414
1415	return ret;
1416}
1417
1418static int iss_remove(struct platform_device *pdev)
1419{
1420	struct iss_device *iss = platform_get_drvdata(pdev);
1421	int i;
1422
1423	iss_unregister_entities(iss);
1424	iss_cleanup_modules(iss);
1425
1426	free_irq(iss->irq_num, iss);
1427	iss_put_clocks(iss);
1428
1429	for (i = 0; i < OMAP4_ISS_MEM_LAST; i++) {
1430		if (iss->regs[i]) {
1431			iounmap(iss->regs[i]);
1432			iss->regs[i] = NULL;
1433		}
1434
1435		if (iss->res[i]) {
1436			release_mem_region(iss->res[i]->start,
1437					   resource_size(iss->res[i]));
1438			iss->res[i] = NULL;
1439		}
1440	}
1441
1442	kfree(iss);
1443
1444	return 0;
1445}
1446
1447static struct platform_device_id omap4iss_id_table[] = {
1448	{ "omap4iss", 0 },
1449	{ },
1450};
1451MODULE_DEVICE_TABLE(platform, omap4iss_id_table);
1452
1453static struct platform_driver iss_driver = {
1454	.probe		= iss_probe,
1455	.remove		= iss_remove,
1456	.id_table	= omap4iss_id_table,
1457	.driver = {
1458		.owner	= THIS_MODULE,
1459		.name	= "omap4iss",
1460	},
1461};
1462
1463module_platform_driver(iss_driver);
1464
1465MODULE_DESCRIPTION("TI OMAP4 ISS driver");
1466MODULE_AUTHOR("Sergio Aguirre <sergio.a.aguirre@gmail.com>");
1467MODULE_LICENSE("GPL");
1468MODULE_VERSION(ISS_VIDEO_DRIVER_VERSION);
1469