[go: nahoru, domu]

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