1babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki/*
2babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * s3c24xx/s3c64xx SoC series Camera Interface (CAMIF) driver
3babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki *
4babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * Copyright (C) 2012 Sylwester Nawrocki <sylvester.nawrocki@gmail.com>
5babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * Copyright (C) 2012 Tomasz Figa <tomasz.figa@gmail.com>
6babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki *
7babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * This program is free software; you can redistribute it and/or modify
8babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * it under the terms of the GNU General Public License as published
9babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * by the Free Software Foundation, either version 2 of the License,
10babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * or (at your option) any later version.
11babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki */
12babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#define pr_fmt(fmt) "%s:%d " fmt, __func__, __LINE__
13babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
14babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/bug.h>
15babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/clk.h>
16babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/delay.h>
17babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/device.h>
18babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/errno.h>
19babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/gpio.h>
20babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/i2c.h>
21babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/interrupt.h>
22babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/io.h>
23babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/kernel.h>
24babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/list.h>
25babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/module.h>
26babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/platform_device.h>
27babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/pm_runtime.h>
28babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/slab.h>
29babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <linux/types.h>
30250539a36f69aa51e4c68a1f92c4ed2bcc042a1aSachin Kamat#include <linux/version.h>
31babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
32babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <media/media-device.h>
33babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <media/v4l2-ctrls.h>
34babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <media/v4l2-ioctl.h>
35babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <media/videobuf2-core.h>
36babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include <media/videobuf2-dma-contig.h>
37babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
38babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki#include "camif-core.h"
39babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
40babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic char *camif_clocks[CLK_MAX_NUM] = {
41babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	/* HCLK CAMIF clock */
42babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	[CLK_GATE]	= "camif",
43babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	/* CAMIF / external camera sensor master clock */
44babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	[CLK_CAM]	= "camera",
45babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki};
46babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
47babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic const struct camif_fmt camif_formats[] = {
48babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	{
49babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.name		= "YUV 4:2:2 planar, Y/Cb/Cr",
50babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.fourcc		= V4L2_PIX_FMT_YUV422P,
51babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.depth		= 16,
52babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.ybpp		= 1,
53babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.color		= IMG_FMT_YCBCR422P,
54babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.colplanes	= 3,
55babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.flags		= FMT_FL_S3C24XX_CODEC |
56babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki				  FMT_FL_S3C64XX,
57babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}, {
58babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.name		= "YUV 4:2:0 planar, Y/Cb/Cr",
59babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.fourcc		= V4L2_PIX_FMT_YUV420,
60babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.depth		= 12,
61babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.ybpp		= 1,
62babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.color		= IMG_FMT_YCBCR420,
63babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.colplanes	= 3,
64babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.flags		= FMT_FL_S3C24XX_CODEC |
65babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki				  FMT_FL_S3C64XX,
66babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}, {
67babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.name		= "YVU 4:2:0 planar, Y/Cr/Cb",
68babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.fourcc		= V4L2_PIX_FMT_YVU420,
69babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.depth		= 12,
70babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.ybpp		= 1,
71babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.color		= IMG_FMT_YCRCB420,
72babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.colplanes	= 3,
73babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.flags		= FMT_FL_S3C24XX_CODEC |
74babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki				  FMT_FL_S3C64XX,
75babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}, {
76babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.name		= "RGB565, 16 bpp",
77babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.fourcc		= V4L2_PIX_FMT_RGB565X,
78babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.depth		= 16,
79babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.ybpp		= 2,
80babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.color		= IMG_FMT_RGB565,
81babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.colplanes	= 1,
82babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.flags		= FMT_FL_S3C24XX_PREVIEW |
83babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki				  FMT_FL_S3C64XX,
84babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}, {
85babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.name		= "XRGB8888, 32 bpp",
86babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.fourcc		= V4L2_PIX_FMT_RGB32,
87babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.depth		= 32,
88babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.ybpp		= 4,
89babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.color		= IMG_FMT_XRGB8888,
90babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.colplanes	= 1,
91babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.flags		= FMT_FL_S3C24XX_PREVIEW |
92babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki				  FMT_FL_S3C64XX,
93babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}, {
94babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.name		= "BGR666",
95babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.fourcc		= V4L2_PIX_FMT_BGR666,
96babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.depth		= 32,
97babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.ybpp		= 4,
98babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.color		= IMG_FMT_RGB666,
99babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.colplanes	= 1,
100babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.flags		= FMT_FL_S3C64XX,
101babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}
102babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki};
103babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
104babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki/**
105babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * s3c_camif_find_format() - lookup camif color format by fourcc or an index
106babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * @pixelformat: fourcc to match, ignored if null
107babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * @index: index to the camif_formats array, ignored if negative
108babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki */
109babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockiconst struct camif_fmt *s3c_camif_find_format(struct camif_vp *vp,
110babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki					      const u32 *pixelformat,
111babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki					      int index)
112babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
113babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	const struct camif_fmt *fmt, *def_fmt = NULL;
114babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	unsigned int i;
115babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	int id = 0;
116babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
117babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (index >= (int)ARRAY_SIZE(camif_formats))
118babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		return NULL;
119babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
120babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	for (i = 0; i < ARRAY_SIZE(camif_formats); ++i) {
121babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		fmt = &camif_formats[i];
122babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		if (vp && !(vp->fmt_flags & fmt->flags))
123babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			continue;
124babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		if (pixelformat && fmt->fourcc == *pixelformat)
125babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			return fmt;
126babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		if (index == id)
127babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			def_fmt = fmt;
128babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		id++;
129babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}
130babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	return def_fmt;
131babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
132babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
133babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int camif_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
134babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
135babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	unsigned int sh = 6;
136babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
137babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (src >= 64 * tar)
138babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		return -EINVAL;
139babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
140babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	while (sh--) {
141babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		unsigned int tmp = 1 << sh;
142babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		if (src >= tar * tmp) {
143babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			*shift = sh, *ratio = tmp;
144babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			return 0;
145babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		}
146babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}
147babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	*shift = 0, *ratio = 1;
148babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	return 0;
149babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
150babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
151babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockiint s3c_camif_get_scaler_config(struct camif_vp *vp,
152babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki				struct camif_scaler *scaler)
153babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
154babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct v4l2_rect *camif_crop = &vp->camif->camif_crop;
155babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	int source_x = camif_crop->width;
156babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	int source_y = camif_crop->height;
157babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	int target_x = vp->out_frame.rect.width;
158babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	int target_y = vp->out_frame.rect.height;
159babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	int ret;
160babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
161babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (vp->rotation == 90 || vp->rotation == 270)
162babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		swap(target_x, target_y);
163babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
164babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = camif_get_scaler_factor(source_x, target_x, &scaler->pre_h_ratio,
165babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki				      &scaler->h_shift);
166babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
167babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		return ret;
168babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
169babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = camif_get_scaler_factor(source_y, target_y, &scaler->pre_v_ratio,
170babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki				      &scaler->v_shift);
171babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
172babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		return ret;
173babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
174babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	scaler->pre_dst_width = source_x / scaler->pre_h_ratio;
175babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	scaler->pre_dst_height = source_y / scaler->pre_v_ratio;
176babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
177babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	scaler->main_h_ratio = (source_x << 8) / (target_x << scaler->h_shift);
178babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	scaler->main_v_ratio = (source_y << 8) / (target_y << scaler->v_shift);
179babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
180babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	scaler->scaleup_h = (target_x >= source_x);
181babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	scaler->scaleup_v = (target_y >= source_y);
182babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
183babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	scaler->copy = 0;
184babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
185babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	pr_debug("H: ratio: %u, shift: %u. V: ratio: %u, shift: %u.\n",
186babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		 scaler->pre_h_ratio, scaler->h_shift,
187babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		 scaler->pre_v_ratio, scaler->v_shift);
188babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
189babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	pr_debug("Source: %dx%d, Target: %dx%d, scaleup_h/v: %d/%d\n",
190babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		 source_x, source_y, target_x, target_y,
191babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		 scaler->scaleup_h, scaler->scaleup_v);
192babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
193babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	return 0;
194babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
195babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
196babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int camif_register_sensor(struct camif_dev *camif)
197babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
198babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct s3c_camif_sensor_info *sensor = &camif->pdata.sensor;
199babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct v4l2_device *v4l2_dev = &camif->v4l2_dev;
200babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct i2c_adapter *adapter;
201babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct v4l2_subdev_format format;
202babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct v4l2_subdev *sd;
203babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	int ret;
204babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
205babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	camif->sensor.sd = NULL;
206babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
207babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (sensor->i2c_board_info.addr == 0)
208babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		return -EINVAL;
209babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
210babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	adapter = i2c_get_adapter(sensor->i2c_bus_num);
211babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (adapter == NULL) {
212babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		v4l2_warn(v4l2_dev, "failed to get I2C adapter %d\n",
213babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			  sensor->i2c_bus_num);
214babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		return -EPROBE_DEFER;
215babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}
216babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
217babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	sd = v4l2_i2c_new_subdev_board(v4l2_dev, adapter,
218babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki				       &sensor->i2c_board_info, NULL);
219babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (sd == NULL) {
220babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		i2c_put_adapter(adapter);
221babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		v4l2_warn(v4l2_dev, "failed to acquire subdev %s\n",
222babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			  sensor->i2c_board_info.type);
223babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		return -EPROBE_DEFER;
224babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}
225babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	camif->sensor.sd = sd;
226babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
227babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	v4l2_info(v4l2_dev, "registered sensor subdevice %s\n", sd->name);
228babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
229babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	/* Get initial pixel format and set it at the camif sink pad */
230babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	format.pad = 0;
231babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
232babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &format);
233babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
234babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
235babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		return 0;
236babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
237babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	format.pad = CAMIF_SD_PAD_SINK;
238babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	v4l2_subdev_call(&camif->subdev, pad, set_fmt, NULL, &format);
239babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
240babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	v4l2_info(sd, "Initial format from sensor: %dx%d, %#x\n",
241babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		  format.format.width, format.format.height,
242babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		  format.format.code);
243babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	return 0;
244babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
245babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
246babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic void camif_unregister_sensor(struct camif_dev *camif)
247babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
248babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct v4l2_subdev *sd = camif->sensor.sd;
249babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct i2c_client *client = sd ? v4l2_get_subdevdata(sd) : NULL;
250babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct i2c_adapter *adapter;
251babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
252babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (client == NULL)
253babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		return;
254babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
255babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	adapter = client->adapter;
256babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	v4l2_device_unregister_subdev(sd);
257babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	camif->sensor.sd = NULL;
258babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	i2c_unregister_device(client);
259babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (adapter)
260babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		i2c_put_adapter(adapter);
261babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
262babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
263babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int camif_create_media_links(struct camif_dev *camif)
264babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
265babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	int i, ret;
266babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
267babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = media_entity_create_link(&camif->sensor.sd->entity, 0,
268babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki				&camif->subdev.entity, CAMIF_SD_PAD_SINK,
269babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki				MEDIA_LNK_FL_IMMUTABLE |
270babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki				MEDIA_LNK_FL_ENABLED);
271babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret)
272babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		return ret;
273babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
274babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	for (i = 1; i < CAMIF_SD_PADS_NUM && !ret; i++) {
275babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		ret = media_entity_create_link(&camif->subdev.entity, i,
276babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki				&camif->vp[i - 1].vdev.entity, 0,
277babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki				MEDIA_LNK_FL_IMMUTABLE |
278babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki				MEDIA_LNK_FL_ENABLED);
279babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}
280babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
281babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	return ret;
282babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
283babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
284babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int camif_register_video_nodes(struct camif_dev *camif)
285babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
286babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	int ret = s3c_camif_register_video_node(camif, VP_CODEC);
287babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
288babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		return ret;
289babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
290babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	return s3c_camif_register_video_node(camif, VP_PREVIEW);
291babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
292babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
293babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic void camif_unregister_video_nodes(struct camif_dev *camif)
294babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
295babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	s3c_camif_unregister_video_node(camif, VP_CODEC);
296babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	s3c_camif_unregister_video_node(camif, VP_PREVIEW);
297babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
298babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
299babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic void camif_unregister_media_entities(struct camif_dev *camif)
300babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
301babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	camif_unregister_video_nodes(camif);
302babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	camif_unregister_sensor(camif);
303babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	s3c_camif_unregister_subdev(camif);
304babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
305babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
306babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki/*
307babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * Media device
308babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki */
309babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int camif_media_dev_register(struct camif_dev *camif)
310babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
311babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct media_device *md = &camif->media_dev;
312babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct v4l2_device *v4l2_dev = &camif->v4l2_dev;
313babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	unsigned int ip_rev = camif->variant->ip_revision;
314babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	int ret;
315babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
316babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	memset(md, 0, sizeof(*md));
317babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	snprintf(md->model, sizeof(md->model), "SAMSUNG S3C%s CAMIF",
318babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		 ip_rev == S3C6410_CAMIF_IP_REV ? "6410" : "244X");
319babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	strlcpy(md->bus_info, "platform", sizeof(md->bus_info));
320babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	md->hw_revision = ip_rev;
321babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	md->driver_version = KERNEL_VERSION(1, 0, 0);
322babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
323babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	md->dev = camif->dev;
324babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
325babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	strlcpy(v4l2_dev->name, "s3c-camif", sizeof(v4l2_dev->name));
326babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	v4l2_dev->mdev = md;
327babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
328babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = v4l2_device_register(camif->dev, v4l2_dev);
329babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
330babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		return ret;
331babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
332babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = media_device_register(md);
333babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
334babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		v4l2_device_unregister(v4l2_dev);
335babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
336babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	return ret;
337babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
338babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
339babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic void camif_clk_put(struct camif_dev *camif)
340babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
341babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	int i;
342babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
343babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	for (i = 0; i < CLK_MAX_NUM; i++) {
344d46a5a68b1690fc9f47d6b3e13ccef4e79a87e84Sachin Kamat		if (IS_ERR(camif->clock[i]))
345babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			continue;
346babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		clk_unprepare(camif->clock[i]);
347babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		clk_put(camif->clock[i]);
348d46a5a68b1690fc9f47d6b3e13ccef4e79a87e84Sachin Kamat		camif->clock[i] = ERR_PTR(-EINVAL);
349babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}
350babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
351babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
352babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int camif_clk_get(struct camif_dev *camif)
353babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
354babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	int ret, i;
355babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
356d46a5a68b1690fc9f47d6b3e13ccef4e79a87e84Sachin Kamat	for (i = 1; i < CLK_MAX_NUM; i++)
357d46a5a68b1690fc9f47d6b3e13ccef4e79a87e84Sachin Kamat		camif->clock[i] = ERR_PTR(-EINVAL);
358d46a5a68b1690fc9f47d6b3e13ccef4e79a87e84Sachin Kamat
359babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	for (i = 0; i < CLK_MAX_NUM; i++) {
360babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		camif->clock[i] = clk_get(camif->dev, camif_clocks[i]);
361babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		if (IS_ERR(camif->clock[i])) {
362babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			ret = PTR_ERR(camif->clock[i]);
363babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			goto err;
364babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		}
365babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		ret = clk_prepare(camif->clock[i]);
366babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		if (ret < 0) {
367babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			clk_put(camif->clock[i]);
368babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			camif->clock[i] = NULL;
369babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			goto err;
370babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		}
371babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}
372babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	return 0;
373babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockierr:
374babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	camif_clk_put(camif);
375babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	dev_err(camif->dev, "failed to get clock: %s\n",
376babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		camif_clocks[i]);
377babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	return ret;
378babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
379babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
380babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki/*
381babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * The CAMIF device has two relatively independent data processing paths
382babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * that can source data from memory or the common camera input frontend.
383babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki * Register interrupts for each data processing path (camif_vp).
384babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki */
385babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int camif_request_irqs(struct platform_device *pdev,
386babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			      struct camif_dev *camif)
387babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
388babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	int irq, ret, i;
389babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
390babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	for (i = 0; i < CAMIF_VP_NUM; i++) {
391babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		struct camif_vp *vp = &camif->vp[i];
392babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
393babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		init_waitqueue_head(&vp->irq_queue);
394babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
395babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		irq = platform_get_irq(pdev, i);
396babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		if (irq <= 0) {
397babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			dev_err(&pdev->dev, "failed to get IRQ %d\n", i);
398babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			return -ENXIO;
399babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		}
400babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
401babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		ret = devm_request_irq(&pdev->dev, irq, s3c_camif_irq_handler,
402babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki				       0, dev_name(&pdev->dev), vp);
403babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		if (ret < 0) {
404babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			dev_err(&pdev->dev, "failed to install IRQ: %d\n", ret);
405babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			break;
406babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		}
407babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}
408babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
409babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	return ret;
410babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
411babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
412babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int s3c_camif_probe(struct platform_device *pdev)
413babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
414babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct device *dev = &pdev->dev;
415babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct s3c_camif_plat_data *pdata = dev->platform_data;
416babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct s3c_camif_drvdata *drvdata;
417babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct camif_dev *camif;
418babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct resource *mres;
419babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	int ret = 0;
420babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
421babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	camif = devm_kzalloc(dev, sizeof(*camif), GFP_KERNEL);
422babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (!camif)
423babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		return -ENOMEM;
424babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
425babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	spin_lock_init(&camif->slock);
426babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	mutex_init(&camif->lock);
427babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
428babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	camif->dev = dev;
429babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
430babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (!pdata || !pdata->gpio_get || !pdata->gpio_put) {
431babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		dev_err(dev, "wrong platform data\n");
432babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		return -EINVAL;
433babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}
434babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
435babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	camif->pdata = *pdata;
436babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	drvdata = (void *)platform_get_device_id(pdev)->driver_data;
437babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	camif->variant = drvdata->variant;
438babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
439babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	mres = platform_get_resource(pdev, IORESOURCE_MEM, 0);
440babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
441f23999eccb5f1b6ec858279670307b5b1abe887aThierry Reding	camif->io_base = devm_ioremap_resource(dev, mres);
442f23999eccb5f1b6ec858279670307b5b1abe887aThierry Reding	if (IS_ERR(camif->io_base))
443f23999eccb5f1b6ec858279670307b5b1abe887aThierry Reding		return PTR_ERR(camif->io_base);
444babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
445babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = camif_request_irqs(pdev, camif);
446babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
447babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		return ret;
448babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
449babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = pdata->gpio_get();
450babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
451babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		return ret;
452babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
453babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = s3c_camif_create_subdev(camif);
454babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
455babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		goto err_sd;
456babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
457babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = camif_clk_get(camif);
458babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
459babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		goto err_clk;
460babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
461babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	platform_set_drvdata(pdev, camif);
462babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	clk_set_rate(camif->clock[CLK_CAM],
463babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			camif->pdata.sensor.clock_frequency);
464babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
465babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	dev_info(dev, "sensor clock frequency: %lu\n",
466babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		 clk_get_rate(camif->clock[CLK_CAM]));
467babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	/*
468babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	 * Set initial pixel format, resolution and crop rectangle.
469babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	 * Must be done before a sensor subdev is registered as some
470babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	 * settings are overrode with values from sensor subdev.
471babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	 */
472babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	s3c_camif_set_defaults(camif);
473babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
474babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	pm_runtime_enable(dev);
475babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
476babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = pm_runtime_get_sync(dev);
477babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
478babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		goto err_pm;
479babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
480babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	/* Initialize contiguous memory allocator */
481babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	camif->alloc_ctx = vb2_dma_contig_init_ctx(dev);
482babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (IS_ERR(camif->alloc_ctx)) {
483babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		ret = PTR_ERR(camif->alloc_ctx);
484babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		goto err_alloc;
485babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}
486babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
487babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = camif_media_dev_register(camif);
488babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
489babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		goto err_mdev;
490babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
491babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = camif_register_sensor(camif);
492babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
493babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		goto err_sens;
494babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
495babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = v4l2_device_register_subdev(&camif->v4l2_dev, &camif->subdev);
496babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
497babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		goto err_sens;
498babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
499babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	mutex_lock(&camif->media_dev.graph_mutex);
500babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
501babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = v4l2_device_register_subdev_nodes(&camif->v4l2_dev);
502babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
503babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		goto err_unlock;
504babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
505babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = camif_register_video_nodes(camif);
506babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
507babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		goto err_unlock;
508babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
509babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	ret = camif_create_media_links(camif);
510babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	if (ret < 0)
511babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		goto err_unlock;
512babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
513babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	mutex_unlock(&camif->media_dev.graph_mutex);
514babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	pm_runtime_put(dev);
515babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	return 0;
516babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
517babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockierr_unlock:
518babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	mutex_unlock(&camif->media_dev.graph_mutex);
519babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockierr_sens:
520babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	v4l2_device_unregister(&camif->v4l2_dev);
521babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	media_device_unregister(&camif->media_dev);
522babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	camif_unregister_media_entities(camif);
523babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockierr_mdev:
524babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	vb2_dma_contig_cleanup_ctx(camif->alloc_ctx);
525babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockierr_alloc:
526babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	pm_runtime_put(dev);
527babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	pm_runtime_disable(dev);
528babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockierr_pm:
529babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	camif_clk_put(camif);
530babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockierr_clk:
531babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	s3c_camif_unregister_subdev(camif);
532babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockierr_sd:
533babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	pdata->gpio_put();
534babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	return ret;
535babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
536babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
5374c62e9764ab403d42f9b8871b1241fe7812f19d4Greg Kroah-Hartmanstatic int s3c_camif_remove(struct platform_device *pdev)
538babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
539babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct camif_dev *camif = platform_get_drvdata(pdev);
540babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct s3c_camif_plat_data *pdata = &camif->pdata;
541babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
542babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	media_device_unregister(&camif->media_dev);
543babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	camif_unregister_media_entities(camif);
544babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	v4l2_device_unregister(&camif->v4l2_dev);
545babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
546babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	pm_runtime_disable(&pdev->dev);
547babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	camif_clk_put(camif);
548babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	pdata->gpio_put();
549babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
550babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	return 0;
551babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
552babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
553babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int s3c_camif_runtime_resume(struct device *dev)
554babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
555babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct camif_dev *camif = dev_get_drvdata(dev);
556babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
557babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	clk_enable(camif->clock[CLK_GATE]);
558babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	/* null op on s3c244x */
559babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	clk_enable(camif->clock[CLK_CAM]);
560babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	return 0;
561babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
562babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
563babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic int s3c_camif_runtime_suspend(struct device *dev)
564babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki{
565babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	struct camif_dev *camif = dev_get_drvdata(dev);
566babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
567babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	/* null op on s3c244x */
568babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	clk_disable(camif->clock[CLK_CAM]);
569babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
570babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	clk_disable(camif->clock[CLK_GATE]);
571babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	return 0;
572babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki}
573babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
574babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic const struct s3c_camif_variant s3c244x_camif_variant = {
575babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.vp_pix_limits = {
576babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		[VP_CODEC] = {
577babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.max_out_width		= 4096,
578babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.max_sc_out_width	= 2048,
579babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.out_width_align	= 16,
580babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.min_out_width		= 16,
581babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.max_height		= 4096,
582babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		},
583babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		[VP_PREVIEW] = {
584babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.max_out_width		= 640,
585babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.max_sc_out_width	= 640,
586babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.out_width_align	= 16,
587babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.min_out_width		= 16,
588babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.max_height		= 480,
589babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		}
590babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	},
591babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.pix_limits = {
592babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.win_hor_offset_align	= 8,
593babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	},
594babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.ip_revision = S3C244X_CAMIF_IP_REV,
595babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki};
596babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
597babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic struct s3c_camif_drvdata s3c244x_camif_drvdata = {
598babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.variant	= &s3c244x_camif_variant,
599babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.bus_clk_freq	= 24000000UL,
600babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki};
601babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
602babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic const struct s3c_camif_variant s3c6410_camif_variant = {
603babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.vp_pix_limits = {
604babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		[VP_CODEC] = {
605babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.max_out_width		= 4096,
606babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.max_sc_out_width	= 2048,
607babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.out_width_align	= 16,
608babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.min_out_width		= 16,
609babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.max_height		= 4096,
610babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		},
611babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		[VP_PREVIEW] = {
612babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.max_out_width		= 4096,
613babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.max_sc_out_width	= 720,
614babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.out_width_align	= 16,
615babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.min_out_width		= 16,
616babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki			.max_height		= 4096,
617babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		}
618babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	},
619babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.pix_limits = {
620babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.win_hor_offset_align	= 8,
621babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	},
622babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.ip_revision = S3C6410_CAMIF_IP_REV,
623babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.has_img_effect = 1,
624babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.vp_offset = 0x20,
625babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki};
626babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
627babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic struct s3c_camif_drvdata s3c6410_camif_drvdata = {
628babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.variant	= &s3c6410_camif_variant,
629babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.bus_clk_freq	= 133000000UL,
630babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki};
631babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
632babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic struct platform_device_id s3c_camif_driver_ids[] = {
633babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	{
634babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.name		= "s3c2440-camif",
635babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.driver_data	= (unsigned long)&s3c244x_camif_drvdata,
636babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}, {
637babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.name		= "s3c6410-camif",
638babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.driver_data	= (unsigned long)&s3c6410_camif_drvdata,
639babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	},
640babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	{ /* sentinel */ },
641babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki};
642babde1c243b25592038dd7193867a49729e3d505Sylwester NawrockiMODULE_DEVICE_TABLE(platform, s3c_camif_driver_ids);
643babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
644babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic const struct dev_pm_ops s3c_camif_pm_ops = {
645babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.runtime_suspend	= s3c_camif_runtime_suspend,
646babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.runtime_resume		= s3c_camif_runtime_resume,
647babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki};
648babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
649babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockistatic struct platform_driver s3c_camif_driver = {
650babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.probe		= s3c_camif_probe,
6514c62e9764ab403d42f9b8871b1241fe7812f19d4Greg Kroah-Hartman	.remove		= s3c_camif_remove,
652babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.id_table	= s3c_camif_driver_ids,
653babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	.driver = {
654babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.name	= S3C_CAMIF_DRIVER_NAME,
655babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.owner	= THIS_MODULE,
656babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki		.pm	= &s3c_camif_pm_ops,
657babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki	}
658babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki};
659babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
660babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrockimodule_platform_driver(s3c_camif_driver);
661babde1c243b25592038dd7193867a49729e3d505Sylwester Nawrocki
662babde1c243b25592038dd7193867a49729e3d505Sylwester NawrockiMODULE_AUTHOR("Sylwester Nawrocki <sylvester.nawrocki@gmail.com>");
663babde1c243b25592038dd7193867a49729e3d505Sylwester NawrockiMODULE_AUTHOR("Tomasz Figa <tomasz.figa@gmail.com>");
664babde1c243b25592038dd7193867a49729e3d505Sylwester NawrockiMODULE_DESCRIPTION("S3C24XX/S3C64XX SoC camera interface driver");
665babde1c243b25592038dd7193867a49729e3d505Sylwester NawrockiMODULE_LICENSE("GPL");
666