diff options
author | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-14 15:23:43 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-08-15 15:42:14 -0400 |
commit | cb7a01ac324bf2ee2c666f37ac867e4135f9785a (patch) | |
tree | 7246b915a9334d4bc823c93ba9acab65ef882678 /drivers/media/i2c/smiapp | |
parent | f0af8fa4dad0839f844fd0633e1936493f6d685a (diff) |
[media] move i2c files into drivers/media/i2c
Move ancillary I2C drivers into drivers/media/i2c, in order to
better organize them.
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/i2c/smiapp')
-rw-r--r-- | drivers/media/i2c/smiapp/Kconfig | 7 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/Makefile | 5 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-core.c | 2895 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-limits.c | 132 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-limits.h | 128 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-quirk.c | 306 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-quirk.h | 83 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-reg-defs.h | 503 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-reg.h | 122 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-regs.c | 273 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp-regs.h | 49 | ||||
-rw-r--r-- | drivers/media/i2c/smiapp/smiapp.h | 252 |
12 files changed, 4755 insertions, 0 deletions
diff --git a/drivers/media/i2c/smiapp/Kconfig b/drivers/media/i2c/smiapp/Kconfig new file mode 100644 index 000000000000..3149cda1d0db --- /dev/null +++ b/drivers/media/i2c/smiapp/Kconfig | |||
@@ -0,0 +1,7 @@ | |||
1 | config VIDEO_SMIAPP | ||
2 | tristate "SMIA++/SMIA sensor support" | ||
3 | depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAVE_CLK | ||
4 | depends on MEDIA_CAMERA_SUPPORT | ||
5 | select VIDEO_SMIAPP_PLL | ||
6 | ---help--- | ||
7 | This is a generic driver for SMIA++/SMIA camera modules. | ||
diff --git a/drivers/media/i2c/smiapp/Makefile b/drivers/media/i2c/smiapp/Makefile new file mode 100644 index 000000000000..f45a003cbe7e --- /dev/null +++ b/drivers/media/i2c/smiapp/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | smiapp-objs += smiapp-core.o smiapp-regs.o \ | ||
2 | smiapp-quirk.o smiapp-limits.o | ||
3 | obj-$(CONFIG_VIDEO_SMIAPP) += smiapp.o | ||
4 | |||
5 | ccflags-y += -Idrivers/media/i2c | ||
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c new file mode 100644 index 000000000000..1cf914d11345 --- /dev/null +++ b/drivers/media/i2c/smiapp/smiapp-core.c | |||
@@ -0,0 +1,2895 @@ | |||
1 | /* | ||
2 | * drivers/media/i2c/smiapp/smiapp-core.c | ||
3 | * | ||
4 | * Generic driver for SMIA/SMIA++ compliant camera modules | ||
5 | * | ||
6 | * Copyright (C) 2010--2012 Nokia Corporation | ||
7 | * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> | ||
8 | * | ||
9 | * Based on smiapp driver by Vimarsh Zutshi | ||
10 | * Based on jt8ev1.c by Vimarsh Zutshi | ||
11 | * Based on smia-sensor.c by Tuukka Toivonen <tuukkat76@gmail.com> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * version 2 as published by the Free Software Foundation. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, but | ||
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
20 | * General Public License for more details. | ||
21 | * | ||
22 | * You should have received a copy of the GNU General Public License | ||
23 | * along with this program; if not, write to the Free Software | ||
24 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
25 | * 02110-1301 USA | ||
26 | * | ||
27 | */ | ||
28 | |||
29 | #include <linux/clk.h> | ||
30 | #include <linux/delay.h> | ||
31 | #include <linux/device.h> | ||
32 | #include <linux/gpio.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/slab.h> | ||
35 | #include <linux/regulator/consumer.h> | ||
36 | #include <linux/v4l2-mediabus.h> | ||
37 | #include <media/v4l2-device.h> | ||
38 | |||
39 | #include "smiapp.h" | ||
40 | |||
41 | #define SMIAPP_ALIGN_DIM(dim, flags) \ | ||
42 | ((flags) & V4L2_SEL_FLAG_GE \ | ||
43 | ? ALIGN((dim), 2) \ | ||
44 | : (dim) & ~1) | ||
45 | |||
46 | /* | ||
47 | * smiapp_module_idents - supported camera modules | ||
48 | */ | ||
49 | static const struct smiapp_module_ident smiapp_module_idents[] = { | ||
50 | SMIAPP_IDENT_L(0x01, 0x022b, -1, "vs6555"), | ||
51 | SMIAPP_IDENT_L(0x01, 0x022e, -1, "vw6558"), | ||
52 | SMIAPP_IDENT_L(0x07, 0x7698, -1, "ovm7698"), | ||
53 | SMIAPP_IDENT_L(0x0b, 0x4242, -1, "smiapp-003"), | ||
54 | SMIAPP_IDENT_L(0x0c, 0x208a, -1, "tcm8330md"), | ||
55 | SMIAPP_IDENT_LQ(0x0c, 0x2134, -1, "tcm8500md", &smiapp_tcm8500md_quirk), | ||
56 | SMIAPP_IDENT_L(0x0c, 0x213e, -1, "et8en2"), | ||
57 | SMIAPP_IDENT_L(0x0c, 0x2184, -1, "tcm8580md"), | ||
58 | SMIAPP_IDENT_LQ(0x0c, 0x560f, -1, "jt8ew9", &smiapp_jt8ew9_quirk), | ||
59 | SMIAPP_IDENT_LQ(0x10, 0x4141, -1, "jt8ev1", &smiapp_jt8ev1_quirk), | ||
60 | SMIAPP_IDENT_LQ(0x10, 0x4241, -1, "imx125es", &smiapp_imx125es_quirk), | ||
61 | }; | ||
62 | |||
63 | /* | ||
64 | * | ||
65 | * Dynamic Capability Identification | ||
66 | * | ||
67 | */ | ||
68 | |||
69 | static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) | ||
70 | { | ||
71 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
72 | u32 fmt_model_type, fmt_model_subtype, ncol_desc, nrow_desc; | ||
73 | unsigned int i; | ||
74 | int rval; | ||
75 | int line_count = 0; | ||
76 | int embedded_start = -1, embedded_end = -1; | ||
77 | int image_start = 0; | ||
78 | |||
79 | rval = smiapp_read(sensor, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE, | ||
80 | &fmt_model_type); | ||
81 | if (rval) | ||
82 | return rval; | ||
83 | |||
84 | rval = smiapp_read(sensor, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE, | ||
85 | &fmt_model_subtype); | ||
86 | if (rval) | ||
87 | return rval; | ||
88 | |||
89 | ncol_desc = (fmt_model_subtype | ||
90 | & SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK) | ||
91 | >> SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT; | ||
92 | nrow_desc = fmt_model_subtype | ||
93 | & SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK; | ||
94 | |||
95 | dev_dbg(&client->dev, "format_model_type %s\n", | ||
96 | fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE | ||
97 | ? "2 byte" : | ||
98 | fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE | ||
99 | ? "4 byte" : "is simply bad"); | ||
100 | |||
101 | for (i = 0; i < ncol_desc + nrow_desc; i++) { | ||
102 | u32 desc; | ||
103 | u32 pixelcode; | ||
104 | u32 pixels; | ||
105 | char *which; | ||
106 | char *what; | ||
107 | |||
108 | if (fmt_model_type == SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE) { | ||
109 | rval = smiapp_read( | ||
110 | sensor, | ||
111 | SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(i), | ||
112 | &desc); | ||
113 | if (rval) | ||
114 | return rval; | ||
115 | |||
116 | pixelcode = | ||
117 | (desc | ||
118 | & SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK) | ||
119 | >> SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT; | ||
120 | pixels = desc & SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK; | ||
121 | } else if (fmt_model_type | ||
122 | == SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE) { | ||
123 | rval = smiapp_read( | ||
124 | sensor, | ||
125 | SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(i), | ||
126 | &desc); | ||
127 | if (rval) | ||
128 | return rval; | ||
129 | |||
130 | pixelcode = | ||
131 | (desc | ||
132 | & SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK) | ||
133 | >> SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT; | ||
134 | pixels = desc & SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK; | ||
135 | } else { | ||
136 | dev_dbg(&client->dev, | ||
137 | "invalid frame format model type %d\n", | ||
138 | fmt_model_type); | ||
139 | return -EINVAL; | ||
140 | } | ||
141 | |||
142 | if (i < ncol_desc) | ||
143 | which = "columns"; | ||
144 | else | ||
145 | which = "rows"; | ||
146 | |||
147 | switch (pixelcode) { | ||
148 | case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED: | ||
149 | what = "embedded"; | ||
150 | break; | ||
151 | case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY: | ||
152 | what = "dummy"; | ||
153 | break; | ||
154 | case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK: | ||
155 | what = "black"; | ||
156 | break; | ||
157 | case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK: | ||
158 | what = "dark"; | ||
159 | break; | ||
160 | case SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE: | ||
161 | what = "visible"; | ||
162 | break; | ||
163 | default: | ||
164 | what = "invalid"; | ||
165 | dev_dbg(&client->dev, "pixelcode %d\n", pixelcode); | ||
166 | break; | ||
167 | } | ||
168 | |||
169 | dev_dbg(&client->dev, "%s pixels: %d %s\n", | ||
170 | what, pixels, which); | ||
171 | |||
172 | if (i < ncol_desc) | ||
173 | continue; | ||
174 | |||
175 | /* Handle row descriptors */ | ||
176 | if (pixelcode | ||
177 | == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED) { | ||
178 | embedded_start = line_count; | ||
179 | } else { | ||
180 | if (pixelcode == SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE | ||
181 | || pixels >= sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES] / 2) | ||
182 | image_start = line_count; | ||
183 | if (embedded_start != -1 && embedded_end == -1) | ||
184 | embedded_end = line_count; | ||
185 | } | ||
186 | line_count += pixels; | ||
187 | } | ||
188 | |||
189 | if (embedded_start == -1 || embedded_end == -1) { | ||
190 | embedded_start = 0; | ||
191 | embedded_end = 0; | ||
192 | } | ||
193 | |||
194 | dev_dbg(&client->dev, "embedded data from lines %d to %d\n", | ||
195 | embedded_start, embedded_end); | ||
196 | dev_dbg(&client->dev, "image data starts at line %d\n", image_start); | ||
197 | |||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | static int smiapp_pll_configure(struct smiapp_sensor *sensor) | ||
202 | { | ||
203 | struct smiapp_pll *pll = &sensor->pll; | ||
204 | int rval; | ||
205 | |||
206 | rval = smiapp_write( | ||
207 | sensor, SMIAPP_REG_U16_VT_PIX_CLK_DIV, pll->vt_pix_clk_div); | ||
208 | if (rval < 0) | ||
209 | return rval; | ||
210 | |||
211 | rval = smiapp_write( | ||
212 | sensor, SMIAPP_REG_U16_VT_SYS_CLK_DIV, pll->vt_sys_clk_div); | ||
213 | if (rval < 0) | ||
214 | return rval; | ||
215 | |||
216 | rval = smiapp_write( | ||
217 | sensor, SMIAPP_REG_U16_PRE_PLL_CLK_DIV, pll->pre_pll_clk_div); | ||
218 | if (rval < 0) | ||
219 | return rval; | ||
220 | |||
221 | rval = smiapp_write( | ||
222 | sensor, SMIAPP_REG_U16_PLL_MULTIPLIER, pll->pll_multiplier); | ||
223 | if (rval < 0) | ||
224 | return rval; | ||
225 | |||
226 | /* Lane op clock ratio does not apply here. */ | ||
227 | rval = smiapp_write( | ||
228 | sensor, SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS, | ||
229 | DIV_ROUND_UP(pll->op_sys_clk_freq_hz, 1000000 / 256 / 256)); | ||
230 | if (rval < 0 || sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) | ||
231 | return rval; | ||
232 | |||
233 | rval = smiapp_write( | ||
234 | sensor, SMIAPP_REG_U16_OP_PIX_CLK_DIV, pll->op_pix_clk_div); | ||
235 | if (rval < 0) | ||
236 | return rval; | ||
237 | |||
238 | return smiapp_write( | ||
239 | sensor, SMIAPP_REG_U16_OP_SYS_CLK_DIV, pll->op_sys_clk_div); | ||
240 | } | ||
241 | |||
242 | static int smiapp_pll_update(struct smiapp_sensor *sensor) | ||
243 | { | ||
244 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
245 | struct smiapp_pll_limits lim = { | ||
246 | .min_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV], | ||
247 | .max_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV], | ||
248 | .min_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ], | ||
249 | .max_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ], | ||
250 | .min_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MIN_PLL_MULTIPLIER], | ||
251 | .max_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MAX_PLL_MULTIPLIER], | ||
252 | .min_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ], | ||
253 | .max_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ], | ||
254 | |||
255 | .min_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV], | ||
256 | .max_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV], | ||
257 | .min_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV], | ||
258 | .max_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV], | ||
259 | .min_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ], | ||
260 | .max_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ], | ||
261 | .min_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ], | ||
262 | .max_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ], | ||
263 | |||
264 | .min_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV], | ||
265 | .max_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV], | ||
266 | .min_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV], | ||
267 | .max_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV], | ||
268 | .min_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ], | ||
269 | .max_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ], | ||
270 | .min_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ], | ||
271 | .max_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ], | ||
272 | |||
273 | .min_line_length_pck_bin = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN], | ||
274 | .min_line_length_pck = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK], | ||
275 | }; | ||
276 | struct smiapp_pll *pll = &sensor->pll; | ||
277 | int rval; | ||
278 | |||
279 | memset(&sensor->pll, 0, sizeof(sensor->pll)); | ||
280 | |||
281 | pll->lanes = sensor->platform_data->lanes; | ||
282 | pll->ext_clk_freq_hz = sensor->platform_data->ext_clk; | ||
283 | |||
284 | if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) { | ||
285 | /* | ||
286 | * Fill in operational clock divisors limits from the | ||
287 | * video timing ones. On profile 0 sensors the | ||
288 | * requirements regarding them are essentially the | ||
289 | * same as on VT ones. | ||
290 | */ | ||
291 | lim.min_op_sys_clk_div = lim.min_vt_sys_clk_div; | ||
292 | lim.max_op_sys_clk_div = lim.max_vt_sys_clk_div; | ||
293 | lim.min_op_pix_clk_div = lim.min_vt_pix_clk_div; | ||
294 | lim.max_op_pix_clk_div = lim.max_vt_pix_clk_div; | ||
295 | lim.min_op_sys_clk_freq_hz = lim.min_vt_sys_clk_freq_hz; | ||
296 | lim.max_op_sys_clk_freq_hz = lim.max_vt_sys_clk_freq_hz; | ||
297 | lim.min_op_pix_clk_freq_hz = lim.min_vt_pix_clk_freq_hz; | ||
298 | lim.max_op_pix_clk_freq_hz = lim.max_vt_pix_clk_freq_hz; | ||
299 | /* Profile 0 sensors have no separate OP clock branch. */ | ||
300 | pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS; | ||
301 | } | ||
302 | |||
303 | if (smiapp_needs_quirk(sensor, | ||
304 | SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE)) | ||
305 | pll->flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE; | ||
306 | |||
307 | pll->binning_horizontal = sensor->binning_horizontal; | ||
308 | pll->binning_vertical = sensor->binning_vertical; | ||
309 | pll->link_freq = | ||
310 | sensor->link_freq->qmenu_int[sensor->link_freq->val]; | ||
311 | pll->scale_m = sensor->scale_m; | ||
312 | pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; | ||
313 | pll->bits_per_pixel = sensor->csi_format->compressed; | ||
314 | |||
315 | rval = smiapp_pll_calculate(&client->dev, &lim, pll); | ||
316 | if (rval < 0) | ||
317 | return rval; | ||
318 | |||
319 | sensor->pixel_rate_parray->cur.val64 = pll->vt_pix_clk_freq_hz; | ||
320 | sensor->pixel_rate_csi->cur.val64 = pll->pixel_rate_csi; | ||
321 | |||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | |||
326 | /* | ||
327 | * | ||
328 | * V4L2 Controls handling | ||
329 | * | ||
330 | */ | ||
331 | |||
332 | static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor) | ||
333 | { | ||
334 | struct v4l2_ctrl *ctrl = sensor->exposure; | ||
335 | int max; | ||
336 | |||
337 | max = sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height | ||
338 | + sensor->vblank->val | ||
339 | - sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN]; | ||
340 | |||
341 | ctrl->maximum = max; | ||
342 | if (ctrl->default_value > max) | ||
343 | ctrl->default_value = max; | ||
344 | if (ctrl->val > max) | ||
345 | ctrl->val = max; | ||
346 | if (ctrl->cur.val > max) | ||
347 | ctrl->cur.val = max; | ||
348 | } | ||
349 | |||
350 | /* | ||
351 | * Order matters. | ||
352 | * | ||
353 | * 1. Bits-per-pixel, descending. | ||
354 | * 2. Bits-per-pixel compressed, descending. | ||
355 | * 3. Pixel order, same as in pixel_order_str. Formats for all four pixel | ||
356 | * orders must be defined. | ||
357 | */ | ||
358 | static const struct smiapp_csi_data_format smiapp_csi_data_formats[] = { | ||
359 | { V4L2_MBUS_FMT_SGRBG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GRBG, }, | ||
360 | { V4L2_MBUS_FMT_SRGGB12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_RGGB, }, | ||
361 | { V4L2_MBUS_FMT_SBGGR12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_BGGR, }, | ||
362 | { V4L2_MBUS_FMT_SGBRG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GBRG, }, | ||
363 | { V4L2_MBUS_FMT_SGRBG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GRBG, }, | ||
364 | { V4L2_MBUS_FMT_SRGGB10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_RGGB, }, | ||
365 | { V4L2_MBUS_FMT_SBGGR10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_BGGR, }, | ||
366 | { V4L2_MBUS_FMT_SGBRG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GBRG, }, | ||
367 | { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GRBG, }, | ||
368 | { V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_RGGB, }, | ||
369 | { V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_BGGR, }, | ||
370 | { V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GBRG, }, | ||
371 | { V4L2_MBUS_FMT_SGRBG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GRBG, }, | ||
372 | { V4L2_MBUS_FMT_SRGGB8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_RGGB, }, | ||
373 | { V4L2_MBUS_FMT_SBGGR8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_BGGR, }, | ||
374 | { V4L2_MBUS_FMT_SGBRG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GBRG, }, | ||
375 | }; | ||
376 | |||
377 | const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" }; | ||
378 | |||
379 | #define to_csi_format_idx(fmt) (((unsigned long)(fmt) \ | ||
380 | - (unsigned long)smiapp_csi_data_formats) \ | ||
381 | / sizeof(*smiapp_csi_data_formats)) | ||
382 | |||
383 | static u32 smiapp_pixel_order(struct smiapp_sensor *sensor) | ||
384 | { | ||
385 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
386 | int flip = 0; | ||
387 | |||
388 | if (sensor->hflip) { | ||
389 | if (sensor->hflip->val) | ||
390 | flip |= SMIAPP_IMAGE_ORIENTATION_HFLIP; | ||
391 | |||
392 | if (sensor->vflip->val) | ||
393 | flip |= SMIAPP_IMAGE_ORIENTATION_VFLIP; | ||
394 | } | ||
395 | |||
396 | flip ^= sensor->hvflip_inv_mask; | ||
397 | |||
398 | dev_dbg(&client->dev, "flip %d\n", flip); | ||
399 | return sensor->default_pixel_order ^ flip; | ||
400 | } | ||
401 | |||
402 | static void smiapp_update_mbus_formats(struct smiapp_sensor *sensor) | ||
403 | { | ||
404 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
405 | unsigned int csi_format_idx = | ||
406 | to_csi_format_idx(sensor->csi_format) & ~3; | ||
407 | unsigned int internal_csi_format_idx = | ||
408 | to_csi_format_idx(sensor->internal_csi_format) & ~3; | ||
409 | unsigned int pixel_order = smiapp_pixel_order(sensor); | ||
410 | |||
411 | sensor->mbus_frame_fmts = | ||
412 | sensor->default_mbus_frame_fmts << pixel_order; | ||
413 | sensor->csi_format = | ||
414 | &smiapp_csi_data_formats[csi_format_idx + pixel_order]; | ||
415 | sensor->internal_csi_format = | ||
416 | &smiapp_csi_data_formats[internal_csi_format_idx | ||
417 | + pixel_order]; | ||
418 | |||
419 | BUG_ON(max(internal_csi_format_idx, csi_format_idx) + pixel_order | ||
420 | >= ARRAY_SIZE(smiapp_csi_data_formats)); | ||
421 | BUG_ON(min(internal_csi_format_idx, csi_format_idx) < 0); | ||
422 | |||
423 | dev_dbg(&client->dev, "new pixel order %s\n", | ||
424 | pixel_order_str[pixel_order]); | ||
425 | } | ||
426 | |||
427 | static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl) | ||
428 | { | ||
429 | struct smiapp_sensor *sensor = | ||
430 | container_of(ctrl->handler, struct smiapp_subdev, ctrl_handler) | ||
431 | ->sensor; | ||
432 | u32 orient = 0; | ||
433 | int exposure; | ||
434 | int rval; | ||
435 | |||
436 | switch (ctrl->id) { | ||
437 | case V4L2_CID_ANALOGUE_GAIN: | ||
438 | return smiapp_write( | ||
439 | sensor, | ||
440 | SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL, ctrl->val); | ||
441 | |||
442 | case V4L2_CID_EXPOSURE: | ||
443 | return smiapp_write( | ||
444 | sensor, | ||
445 | SMIAPP_REG_U16_COARSE_INTEGRATION_TIME, ctrl->val); | ||
446 | |||
447 | case V4L2_CID_HFLIP: | ||
448 | case V4L2_CID_VFLIP: | ||
449 | if (sensor->streaming) | ||
450 | return -EBUSY; | ||
451 | |||
452 | if (sensor->hflip->val) | ||
453 | orient |= SMIAPP_IMAGE_ORIENTATION_HFLIP; | ||
454 | |||
455 | if (sensor->vflip->val) | ||
456 | orient |= SMIAPP_IMAGE_ORIENTATION_VFLIP; | ||
457 | |||
458 | orient ^= sensor->hvflip_inv_mask; | ||
459 | rval = smiapp_write(sensor, | ||
460 | SMIAPP_REG_U8_IMAGE_ORIENTATION, | ||
461 | orient); | ||
462 | if (rval < 0) | ||
463 | return rval; | ||
464 | |||
465 | smiapp_update_mbus_formats(sensor); | ||
466 | |||
467 | return 0; | ||
468 | |||
469 | case V4L2_CID_VBLANK: | ||
470 | exposure = sensor->exposure->val; | ||
471 | |||
472 | __smiapp_update_exposure_limits(sensor); | ||
473 | |||
474 | if (exposure > sensor->exposure->maximum) { | ||
475 | sensor->exposure->val = | ||
476 | sensor->exposure->maximum; | ||
477 | rval = smiapp_set_ctrl( | ||
478 | sensor->exposure); | ||
479 | if (rval < 0) | ||
480 | return rval; | ||
481 | } | ||
482 | |||
483 | return smiapp_write( | ||
484 | sensor, SMIAPP_REG_U16_FRAME_LENGTH_LINES, | ||
485 | sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height | ||
486 | + ctrl->val); | ||
487 | |||
488 | case V4L2_CID_HBLANK: | ||
489 | return smiapp_write( | ||
490 | sensor, SMIAPP_REG_U16_LINE_LENGTH_PCK, | ||
491 | sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width | ||
492 | + ctrl->val); | ||
493 | |||
494 | case V4L2_CID_LINK_FREQ: | ||
495 | if (sensor->streaming) | ||
496 | return -EBUSY; | ||
497 | |||
498 | return smiapp_pll_update(sensor); | ||
499 | |||
500 | default: | ||
501 | return -EINVAL; | ||
502 | } | ||
503 | } | ||
504 | |||
505 | static const struct v4l2_ctrl_ops smiapp_ctrl_ops = { | ||
506 | .s_ctrl = smiapp_set_ctrl, | ||
507 | }; | ||
508 | |||
509 | static int smiapp_init_controls(struct smiapp_sensor *sensor) | ||
510 | { | ||
511 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
512 | unsigned int max; | ||
513 | int rval; | ||
514 | |||
515 | rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 7); | ||
516 | if (rval) | ||
517 | return rval; | ||
518 | sensor->pixel_array->ctrl_handler.lock = &sensor->mutex; | ||
519 | |||
520 | sensor->analog_gain = v4l2_ctrl_new_std( | ||
521 | &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, | ||
522 | V4L2_CID_ANALOGUE_GAIN, | ||
523 | sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN], | ||
524 | sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX], | ||
525 | max(sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP], 1U), | ||
526 | sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN]); | ||
527 | |||
528 | /* Exposure limits will be updated soon, use just something here. */ | ||
529 | sensor->exposure = v4l2_ctrl_new_std( | ||
530 | &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, | ||
531 | V4L2_CID_EXPOSURE, 0, 0, 1, 0); | ||
532 | |||
533 | sensor->hflip = v4l2_ctrl_new_std( | ||
534 | &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, | ||
535 | V4L2_CID_HFLIP, 0, 1, 1, 0); | ||
536 | sensor->vflip = v4l2_ctrl_new_std( | ||
537 | &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, | ||
538 | V4L2_CID_VFLIP, 0, 1, 1, 0); | ||
539 | |||
540 | sensor->vblank = v4l2_ctrl_new_std( | ||
541 | &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, | ||
542 | V4L2_CID_VBLANK, 0, 1, 1, 0); | ||
543 | |||
544 | if (sensor->vblank) | ||
545 | sensor->vblank->flags |= V4L2_CTRL_FLAG_UPDATE; | ||
546 | |||
547 | sensor->hblank = v4l2_ctrl_new_std( | ||
548 | &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, | ||
549 | V4L2_CID_HBLANK, 0, 1, 1, 0); | ||
550 | |||
551 | if (sensor->hblank) | ||
552 | sensor->hblank->flags |= V4L2_CTRL_FLAG_UPDATE; | ||
553 | |||
554 | sensor->pixel_rate_parray = v4l2_ctrl_new_std( | ||
555 | &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops, | ||
556 | V4L2_CID_PIXEL_RATE, 0, 0, 1, 0); | ||
557 | |||
558 | if (sensor->pixel_array->ctrl_handler.error) { | ||
559 | dev_err(&client->dev, | ||
560 | "pixel array controls initialization failed (%d)\n", | ||
561 | sensor->pixel_array->ctrl_handler.error); | ||
562 | rval = sensor->pixel_array->ctrl_handler.error; | ||
563 | goto error; | ||
564 | } | ||
565 | |||
566 | sensor->pixel_array->sd.ctrl_handler = | ||
567 | &sensor->pixel_array->ctrl_handler; | ||
568 | |||
569 | v4l2_ctrl_cluster(2, &sensor->hflip); | ||
570 | |||
571 | rval = v4l2_ctrl_handler_init(&sensor->src->ctrl_handler, 0); | ||
572 | if (rval) | ||
573 | goto error; | ||
574 | sensor->src->ctrl_handler.lock = &sensor->mutex; | ||
575 | |||
576 | for (max = 0; sensor->platform_data->op_sys_clock[max + 1]; max++); | ||
577 | |||
578 | sensor->link_freq = v4l2_ctrl_new_int_menu( | ||
579 | &sensor->src->ctrl_handler, &smiapp_ctrl_ops, | ||
580 | V4L2_CID_LINK_FREQ, max, 0, | ||
581 | sensor->platform_data->op_sys_clock); | ||
582 | |||
583 | sensor->pixel_rate_csi = v4l2_ctrl_new_std( | ||
584 | &sensor->src->ctrl_handler, &smiapp_ctrl_ops, | ||
585 | V4L2_CID_PIXEL_RATE, 0, 0, 1, 0); | ||
586 | |||
587 | if (sensor->src->ctrl_handler.error) { | ||
588 | dev_err(&client->dev, | ||
589 | "src controls initialization failed (%d)\n", | ||
590 | sensor->src->ctrl_handler.error); | ||
591 | rval = sensor->src->ctrl_handler.error; | ||
592 | goto error; | ||
593 | } | ||
594 | |||
595 | sensor->src->sd.ctrl_handler = | ||
596 | &sensor->src->ctrl_handler; | ||
597 | |||
598 | return 0; | ||
599 | |||
600 | error: | ||
601 | v4l2_ctrl_handler_free(&sensor->pixel_array->ctrl_handler); | ||
602 | v4l2_ctrl_handler_free(&sensor->src->ctrl_handler); | ||
603 | |||
604 | return rval; | ||
605 | } | ||
606 | |||
607 | static void smiapp_free_controls(struct smiapp_sensor *sensor) | ||
608 | { | ||
609 | unsigned int i; | ||
610 | |||
611 | for (i = 0; i < sensor->ssds_used; i++) | ||
612 | v4l2_ctrl_handler_free(&sensor->ssds[i].ctrl_handler); | ||
613 | } | ||
614 | |||
615 | static int smiapp_get_limits(struct smiapp_sensor *sensor, int const *limit, | ||
616 | unsigned int n) | ||
617 | { | ||
618 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
619 | unsigned int i; | ||
620 | u32 val; | ||
621 | int rval; | ||
622 | |||
623 | for (i = 0; i < n; i++) { | ||
624 | rval = smiapp_read( | ||
625 | sensor, smiapp_reg_limits[limit[i]].addr, &val); | ||
626 | if (rval) | ||
627 | return rval; | ||
628 | sensor->limits[limit[i]] = val; | ||
629 | dev_dbg(&client->dev, "0x%8.8x \"%s\" = %d, 0x%x\n", | ||
630 | smiapp_reg_limits[limit[i]].addr, | ||
631 | smiapp_reg_limits[limit[i]].what, val, val); | ||
632 | } | ||
633 | |||
634 | return 0; | ||
635 | } | ||
636 | |||
637 | static int smiapp_get_all_limits(struct smiapp_sensor *sensor) | ||
638 | { | ||
639 | unsigned int i; | ||
640 | int rval; | ||
641 | |||
642 | for (i = 0; i < SMIAPP_LIMIT_LAST; i++) { | ||
643 | rval = smiapp_get_limits(sensor, &i, 1); | ||
644 | if (rval < 0) | ||
645 | return rval; | ||
646 | } | ||
647 | |||
648 | if (sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] == 0) | ||
649 | smiapp_replace_limit(sensor, SMIAPP_LIMIT_SCALER_N_MIN, 16); | ||
650 | |||
651 | return 0; | ||
652 | } | ||
653 | |||
654 | static int smiapp_get_limits_binning(struct smiapp_sensor *sensor) | ||
655 | { | ||
656 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
657 | static u32 const limits[] = { | ||
658 | SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN, | ||
659 | SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN, | ||
660 | SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN, | ||
661 | SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN, | ||
662 | SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN, | ||
663 | SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN, | ||
664 | SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN, | ||
665 | }; | ||
666 | static u32 const limits_replace[] = { | ||
667 | SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES, | ||
668 | SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES, | ||
669 | SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK, | ||
670 | SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK, | ||
671 | SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK, | ||
672 | SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN, | ||
673 | SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN, | ||
674 | }; | ||
675 | unsigned int i; | ||
676 | int rval; | ||
677 | |||
678 | if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY] == | ||
679 | SMIAPP_BINNING_CAPABILITY_NO) { | ||
680 | for (i = 0; i < ARRAY_SIZE(limits); i++) | ||
681 | sensor->limits[limits[i]] = | ||
682 | sensor->limits[limits_replace[i]]; | ||
683 | |||
684 | return 0; | ||
685 | } | ||
686 | |||
687 | rval = smiapp_get_limits(sensor, limits, ARRAY_SIZE(limits)); | ||
688 | if (rval < 0) | ||
689 | return rval; | ||
690 | |||
691 | /* | ||
692 | * Sanity check whether the binning limits are valid. If not, | ||
693 | * use the non-binning ones. | ||
694 | */ | ||
695 | if (sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] | ||
696 | && sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] | ||
697 | && sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]) | ||
698 | return 0; | ||
699 | |||
700 | for (i = 0; i < ARRAY_SIZE(limits); i++) { | ||
701 | dev_dbg(&client->dev, | ||
702 | "replace limit 0x%8.8x \"%s\" = %d, 0x%x\n", | ||
703 | smiapp_reg_limits[limits[i]].addr, | ||
704 | smiapp_reg_limits[limits[i]].what, | ||
705 | sensor->limits[limits_replace[i]], | ||
706 | sensor->limits[limits_replace[i]]); | ||
707 | sensor->limits[limits[i]] = | ||
708 | sensor->limits[limits_replace[i]]; | ||
709 | } | ||
710 | |||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor) | ||
715 | { | ||
716 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
717 | unsigned int type, n; | ||
718 | unsigned int i, pixel_order; | ||
719 | int rval; | ||
720 | |||
721 | rval = smiapp_read( | ||
722 | sensor, SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE, &type); | ||
723 | if (rval) | ||
724 | return rval; | ||
725 | |||
726 | dev_dbg(&client->dev, "data_format_model_type %d\n", type); | ||
727 | |||
728 | rval = smiapp_read(sensor, SMIAPP_REG_U8_PIXEL_ORDER, | ||
729 | &pixel_order); | ||
730 | if (rval) | ||
731 | return rval; | ||
732 | |||
733 | if (pixel_order >= ARRAY_SIZE(pixel_order_str)) { | ||
734 | dev_dbg(&client->dev, "bad pixel order %d\n", pixel_order); | ||
735 | return -EINVAL; | ||
736 | } | ||
737 | |||
738 | dev_dbg(&client->dev, "pixel order %d (%s)\n", pixel_order, | ||
739 | pixel_order_str[pixel_order]); | ||
740 | |||
741 | switch (type) { | ||
742 | case SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL: | ||
743 | n = SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N; | ||
744 | break; | ||
745 | case SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED: | ||
746 | n = SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N; | ||
747 | break; | ||
748 | default: | ||
749 | return -EINVAL; | ||
750 | } | ||
751 | |||
752 | sensor->default_pixel_order = pixel_order; | ||
753 | sensor->mbus_frame_fmts = 0; | ||
754 | |||
755 | for (i = 0; i < n; i++) { | ||
756 | unsigned int fmt, j; | ||
757 | |||
758 | rval = smiapp_read( | ||
759 | sensor, | ||
760 | SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(i), &fmt); | ||
761 | if (rval) | ||
762 | return rval; | ||
763 | |||
764 | dev_dbg(&client->dev, "bpp %d, compressed %d\n", | ||
765 | fmt >> 8, (u8)fmt); | ||
766 | |||
767 | for (j = 0; j < ARRAY_SIZE(smiapp_csi_data_formats); j++) { | ||
768 | const struct smiapp_csi_data_format *f = | ||
769 | &smiapp_csi_data_formats[j]; | ||
770 | |||
771 | if (f->pixel_order != SMIAPP_PIXEL_ORDER_GRBG) | ||
772 | continue; | ||
773 | |||
774 | if (f->width != fmt >> 8 || f->compressed != (u8)fmt) | ||
775 | continue; | ||
776 | |||
777 | dev_dbg(&client->dev, "jolly good! %d\n", j); | ||
778 | |||
779 | sensor->default_mbus_frame_fmts |= 1 << j; | ||
780 | if (!sensor->csi_format) { | ||
781 | sensor->csi_format = f; | ||
782 | sensor->internal_csi_format = f; | ||
783 | } | ||
784 | } | ||
785 | } | ||
786 | |||
787 | if (!sensor->csi_format) { | ||
788 | dev_err(&client->dev, "no supported mbus code found\n"); | ||
789 | return -EINVAL; | ||
790 | } | ||
791 | |||
792 | smiapp_update_mbus_formats(sensor); | ||
793 | |||
794 | return 0; | ||
795 | } | ||
796 | |||
797 | static void smiapp_update_blanking(struct smiapp_sensor *sensor) | ||
798 | { | ||
799 | struct v4l2_ctrl *vblank = sensor->vblank; | ||
800 | struct v4l2_ctrl *hblank = sensor->hblank; | ||
801 | |||
802 | vblank->minimum = | ||
803 | max_t(int, | ||
804 | sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES], | ||
805 | sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] - | ||
806 | sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height); | ||
807 | vblank->maximum = | ||
808 | sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] - | ||
809 | sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height; | ||
810 | |||
811 | vblank->val = clamp_t(int, vblank->val, | ||
812 | vblank->minimum, vblank->maximum); | ||
813 | vblank->default_value = vblank->minimum; | ||
814 | vblank->val = vblank->val; | ||
815 | vblank->cur.val = vblank->val; | ||
816 | |||
817 | hblank->minimum = | ||
818 | max_t(int, | ||
819 | sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] - | ||
820 | sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width, | ||
821 | sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]); | ||
822 | hblank->maximum = | ||
823 | sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] - | ||
824 | sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width; | ||
825 | |||
826 | hblank->val = clamp_t(int, hblank->val, | ||
827 | hblank->minimum, hblank->maximum); | ||
828 | hblank->default_value = hblank->minimum; | ||
829 | hblank->val = hblank->val; | ||
830 | hblank->cur.val = hblank->val; | ||
831 | |||
832 | __smiapp_update_exposure_limits(sensor); | ||
833 | } | ||
834 | |||
835 | static int smiapp_update_mode(struct smiapp_sensor *sensor) | ||
836 | { | ||
837 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
838 | unsigned int binning_mode; | ||
839 | int rval; | ||
840 | |||
841 | dev_dbg(&client->dev, "frame size: %dx%d\n", | ||
842 | sensor->src->crop[SMIAPP_PAD_SRC].width, | ||
843 | sensor->src->crop[SMIAPP_PAD_SRC].height); | ||
844 | dev_dbg(&client->dev, "csi format width: %d\n", | ||
845 | sensor->csi_format->width); | ||
846 | |||
847 | /* Binning has to be set up here; it affects limits */ | ||
848 | if (sensor->binning_horizontal == 1 && | ||
849 | sensor->binning_vertical == 1) { | ||
850 | binning_mode = 0; | ||
851 | } else { | ||
852 | u8 binning_type = | ||
853 | (sensor->binning_horizontal << 4) | ||
854 | | sensor->binning_vertical; | ||
855 | |||
856 | rval = smiapp_write( | ||
857 | sensor, SMIAPP_REG_U8_BINNING_TYPE, binning_type); | ||
858 | if (rval < 0) | ||
859 | return rval; | ||
860 | |||
861 | binning_mode = 1; | ||
862 | } | ||
863 | rval = smiapp_write(sensor, SMIAPP_REG_U8_BINNING_MODE, binning_mode); | ||
864 | if (rval < 0) | ||
865 | return rval; | ||
866 | |||
867 | /* Get updated limits due to binning */ | ||
868 | rval = smiapp_get_limits_binning(sensor); | ||
869 | if (rval < 0) | ||
870 | return rval; | ||
871 | |||
872 | rval = smiapp_pll_update(sensor); | ||
873 | if (rval < 0) | ||
874 | return rval; | ||
875 | |||
876 | /* Output from pixel array, including blanking */ | ||
877 | smiapp_update_blanking(sensor); | ||
878 | |||
879 | dev_dbg(&client->dev, "vblank\t\t%d\n", sensor->vblank->val); | ||
880 | dev_dbg(&client->dev, "hblank\t\t%d\n", sensor->hblank->val); | ||
881 | |||
882 | dev_dbg(&client->dev, "real timeperframe\t100/%d\n", | ||
883 | sensor->pll.vt_pix_clk_freq_hz / | ||
884 | ((sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width | ||
885 | + sensor->hblank->val) * | ||
886 | (sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height | ||
887 | + sensor->vblank->val) / 100)); | ||
888 | |||
889 | return 0; | ||
890 | } | ||
891 | |||
892 | /* | ||
893 | * | ||
894 | * SMIA++ NVM handling | ||
895 | * | ||
896 | */ | ||
897 | static int smiapp_read_nvm(struct smiapp_sensor *sensor, | ||
898 | unsigned char *nvm) | ||
899 | { | ||
900 | u32 i, s, p, np, v; | ||
901 | int rval = 0, rval2; | ||
902 | |||
903 | np = sensor->nvm_size / SMIAPP_NVM_PAGE_SIZE; | ||
904 | for (p = 0; p < np; p++) { | ||
905 | rval = smiapp_write( | ||
906 | sensor, | ||
907 | SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT, p); | ||
908 | if (rval) | ||
909 | goto out; | ||
910 | |||
911 | rval = smiapp_write(sensor, | ||
912 | SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL, | ||
913 | SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN | | ||
914 | SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN); | ||
915 | if (rval) | ||
916 | goto out; | ||
917 | |||
918 | for (i = 0; i < 1000; i++) { | ||
919 | rval = smiapp_read( | ||
920 | sensor, | ||
921 | SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, &s); | ||
922 | |||
923 | if (rval) | ||
924 | goto out; | ||
925 | |||
926 | if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY) | ||
927 | break; | ||
928 | |||
929 | if (--i == 0) { | ||
930 | rval = -ETIMEDOUT; | ||
931 | goto out; | ||
932 | } | ||
933 | |||
934 | } | ||
935 | |||
936 | for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) { | ||
937 | rval = smiapp_read( | ||
938 | sensor, | ||
939 | SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 + i, | ||
940 | &v); | ||
941 | if (rval) | ||
942 | goto out; | ||
943 | |||
944 | *nvm++ = v; | ||
945 | } | ||
946 | } | ||
947 | |||
948 | out: | ||
949 | rval2 = smiapp_write(sensor, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL, 0); | ||
950 | if (rval < 0) | ||
951 | return rval; | ||
952 | else | ||
953 | return rval2; | ||
954 | } | ||
955 | |||
956 | /* | ||
957 | * | ||
958 | * SMIA++ CCI address control | ||
959 | * | ||
960 | */ | ||
961 | static int smiapp_change_cci_addr(struct smiapp_sensor *sensor) | ||
962 | { | ||
963 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
964 | int rval; | ||
965 | u32 val; | ||
966 | |||
967 | client->addr = sensor->platform_data->i2c_addr_dfl; | ||
968 | |||
969 | rval = smiapp_write(sensor, | ||
970 | SMIAPP_REG_U8_CCI_ADDRESS_CONTROL, | ||
971 | sensor->platform_data->i2c_addr_alt << 1); | ||
972 | if (rval) | ||
973 | return rval; | ||
974 | |||
975 | client->addr = sensor->platform_data->i2c_addr_alt; | ||
976 | |||
977 | /* verify addr change went ok */ | ||
978 | rval = smiapp_read(sensor, SMIAPP_REG_U8_CCI_ADDRESS_CONTROL, &val); | ||
979 | if (rval) | ||
980 | return rval; | ||
981 | |||
982 | if (val != sensor->platform_data->i2c_addr_alt << 1) | ||
983 | return -ENODEV; | ||
984 | |||
985 | return 0; | ||
986 | } | ||
987 | |||
988 | /* | ||
989 | * | ||
990 | * SMIA++ Mode Control | ||
991 | * | ||
992 | */ | ||
993 | static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor) | ||
994 | { | ||
995 | struct smiapp_flash_strobe_parms *strobe_setup; | ||
996 | unsigned int ext_freq = sensor->platform_data->ext_clk; | ||
997 | u32 tmp; | ||
998 | u32 strobe_adjustment; | ||
999 | u32 strobe_width_high_rs; | ||
1000 | int rval; | ||
1001 | |||
1002 | strobe_setup = sensor->platform_data->strobe_setup; | ||
1003 | |||
1004 | /* | ||
1005 | * How to calculate registers related to strobe length. Please | ||
1006 | * do not change, or if you do at least know what you're | ||
1007 | * doing. :-) | ||
1008 | * | ||
1009 | * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> 2010-10-25 | ||
1010 | * | ||
1011 | * flash_strobe_length [us] / 10^6 = (tFlash_strobe_width_ctrl | ||
1012 | * / EXTCLK freq [Hz]) * flash_strobe_adjustment | ||
1013 | * | ||
1014 | * tFlash_strobe_width_ctrl E N, [1 - 0xffff] | ||
1015 | * flash_strobe_adjustment E N, [1 - 0xff] | ||
1016 | * | ||
1017 | * The formula above is written as below to keep it on one | ||
1018 | * line: | ||
1019 | * | ||
1020 | * l / 10^6 = w / e * a | ||
1021 | * | ||
1022 | * Let's mark w * a by x: | ||
1023 | * | ||
1024 | * x = w * a | ||
1025 | * | ||
1026 | * Thus, we get: | ||
1027 | * | ||
1028 | * x = l * e / 10^6 | ||
1029 | * | ||
1030 | * The strobe width must be at least as long as requested, | ||
1031 | * thus rounding upwards is needed. | ||
1032 | * | ||
1033 | * x = (l * e + 10^6 - 1) / 10^6 | ||
1034 | * ----------------------------- | ||
1035 | * | ||
1036 | * Maximum possible accuracy is wanted at all times. Thus keep | ||
1037 | * a as small as possible. | ||
1038 | * | ||
1039 | * Calculate a, assuming maximum w, with rounding upwards: | ||
1040 | * | ||
1041 | * a = (x + (2^16 - 1) - 1) / (2^16 - 1) | ||
1042 | * ------------------------------------- | ||
1043 | * | ||
1044 | * Thus, we also get w, with that a, with rounding upwards: | ||
1045 | * | ||
1046 | * w = (x + a - 1) / a | ||
1047 | * ------------------- | ||
1048 | * | ||
1049 | * To get limits: | ||
1050 | * | ||
1051 | * x E [1, (2^16 - 1) * (2^8 - 1)] | ||
1052 | * | ||
1053 | * Substituting maximum x to the original formula (with rounding), | ||
1054 | * the maximum l is thus | ||
1055 | * | ||
1056 | * (2^16 - 1) * (2^8 - 1) * 10^6 = l * e + 10^6 - 1 | ||
1057 | * | ||
1058 | * l = (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / e | ||
1059 | * -------------------------------------------------- | ||
1060 | * | ||
1061 | * flash_strobe_length must be clamped between 1 and | ||
1062 | * (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / EXTCLK freq. | ||
1063 | * | ||
1064 | * Then, | ||
1065 | * | ||
1066 | * flash_strobe_adjustment = ((flash_strobe_length * | ||
1067 | * EXTCLK freq + 10^6 - 1) / 10^6 + (2^16 - 1) - 1) / (2^16 - 1) | ||
1068 | * | ||
1069 | * tFlash_strobe_width_ctrl = ((flash_strobe_length * | ||
1070 | * EXTCLK freq + 10^6 - 1) / 10^6 + | ||
1071 | * flash_strobe_adjustment - 1) / flash_strobe_adjustment | ||
1072 | */ | ||
1073 | tmp = div_u64(1000000ULL * ((1 << 16) - 1) * ((1 << 8) - 1) - | ||
1074 | 1000000 + 1, ext_freq); | ||
1075 | strobe_setup->strobe_width_high_us = | ||
1076 | clamp_t(u32, strobe_setup->strobe_width_high_us, 1, tmp); | ||
1077 | |||
1078 | tmp = div_u64(((u64)strobe_setup->strobe_width_high_us * (u64)ext_freq + | ||
1079 | 1000000 - 1), 1000000ULL); | ||
1080 | strobe_adjustment = (tmp + (1 << 16) - 1 - 1) / ((1 << 16) - 1); | ||
1081 | strobe_width_high_rs = (tmp + strobe_adjustment - 1) / | ||
1082 | strobe_adjustment; | ||
1083 | |||
1084 | rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_MODE_RS, | ||
1085 | strobe_setup->mode); | ||
1086 | if (rval < 0) | ||
1087 | goto out; | ||
1088 | |||
1089 | rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT, | ||
1090 | strobe_adjustment); | ||
1091 | if (rval < 0) | ||
1092 | goto out; | ||
1093 | |||
1094 | rval = smiapp_write( | ||
1095 | sensor, SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL, | ||
1096 | strobe_width_high_rs); | ||
1097 | if (rval < 0) | ||
1098 | goto out; | ||
1099 | |||
1100 | rval = smiapp_write(sensor, SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL, | ||
1101 | strobe_setup->strobe_delay); | ||
1102 | if (rval < 0) | ||
1103 | goto out; | ||
1104 | |||
1105 | rval = smiapp_write(sensor, SMIAPP_REG_U16_FLASH_STROBE_START_POINT, | ||
1106 | strobe_setup->stobe_start_point); | ||
1107 | if (rval < 0) | ||
1108 | goto out; | ||
1109 | |||
1110 | rval = smiapp_write(sensor, SMIAPP_REG_U8_FLASH_TRIGGER_RS, | ||
1111 | strobe_setup->trigger); | ||
1112 | |||
1113 | out: | ||
1114 | sensor->platform_data->strobe_setup->trigger = 0; | ||
1115 | |||
1116 | return rval; | ||
1117 | } | ||
1118 | |||
1119 | /* ----------------------------------------------------------------------------- | ||
1120 | * Power management | ||
1121 | */ | ||
1122 | |||
1123 | static int smiapp_power_on(struct smiapp_sensor *sensor) | ||
1124 | { | ||
1125 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
1126 | unsigned int sleep; | ||
1127 | int rval; | ||
1128 | |||
1129 | rval = regulator_enable(sensor->vana); | ||
1130 | if (rval) { | ||
1131 | dev_err(&client->dev, "failed to enable vana regulator\n"); | ||
1132 | return rval; | ||
1133 | } | ||
1134 | usleep_range(1000, 1000); | ||
1135 | |||
1136 | if (sensor->platform_data->set_xclk) | ||
1137 | rval = sensor->platform_data->set_xclk( | ||
1138 | &sensor->src->sd, sensor->platform_data->ext_clk); | ||
1139 | else | ||
1140 | rval = clk_enable(sensor->ext_clk); | ||
1141 | if (rval < 0) { | ||
1142 | dev_dbg(&client->dev, "failed to set xclk\n"); | ||
1143 | goto out_xclk_fail; | ||
1144 | } | ||
1145 | usleep_range(1000, 1000); | ||
1146 | |||
1147 | if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) | ||
1148 | gpio_set_value(sensor->platform_data->xshutdown, 1); | ||
1149 | |||
1150 | sleep = SMIAPP_RESET_DELAY(sensor->platform_data->ext_clk); | ||
1151 | usleep_range(sleep, sleep); | ||
1152 | |||
1153 | /* | ||
1154 | * Failures to respond to the address change command have been noticed. | ||
1155 | * Those failures seem to be caused by the sensor requiring a longer | ||
1156 | * boot time than advertised. An additional 10ms delay seems to work | ||
1157 | * around the issue, but the SMIA++ I2C write retry hack makes the delay | ||
1158 | * unnecessary. The failures need to be investigated to find a proper | ||
1159 | * fix, and a delay will likely need to be added here if the I2C write | ||
1160 | * retry hack is reverted before the root cause of the boot time issue | ||
1161 | * is found. | ||
1162 | */ | ||
1163 | |||
1164 | if (sensor->platform_data->i2c_addr_alt) { | ||
1165 | rval = smiapp_change_cci_addr(sensor); | ||
1166 | if (rval) { | ||
1167 | dev_err(&client->dev, "cci address change error\n"); | ||
1168 | goto out_cci_addr_fail; | ||
1169 | } | ||
1170 | } | ||
1171 | |||
1172 | rval = smiapp_write(sensor, SMIAPP_REG_U8_SOFTWARE_RESET, | ||
1173 | SMIAPP_SOFTWARE_RESET); | ||
1174 | if (rval < 0) { | ||
1175 | dev_err(&client->dev, "software reset failed\n"); | ||
1176 | goto out_cci_addr_fail; | ||
1177 | } | ||
1178 | |||
1179 | if (sensor->platform_data->i2c_addr_alt) { | ||
1180 | rval = smiapp_change_cci_addr(sensor); | ||
1181 | if (rval) { | ||
1182 | dev_err(&client->dev, "cci address change error\n"); | ||
1183 | goto out_cci_addr_fail; | ||
1184 | } | ||
1185 | } | ||
1186 | |||
1187 | rval = smiapp_write(sensor, SMIAPP_REG_U16_COMPRESSION_MODE, | ||
1188 | SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR); | ||
1189 | if (rval) { | ||
1190 | dev_err(&client->dev, "compression mode set failed\n"); | ||
1191 | goto out_cci_addr_fail; | ||
1192 | } | ||
1193 | |||
1194 | rval = smiapp_write( | ||
1195 | sensor, SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ, | ||
1196 | sensor->platform_data->ext_clk / (1000000 / (1 << 8))); | ||
1197 | if (rval) { | ||
1198 | dev_err(&client->dev, "extclk frequency set failed\n"); | ||
1199 | goto out_cci_addr_fail; | ||
1200 | } | ||
1201 | |||
1202 | rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_LANE_MODE, | ||
1203 | sensor->platform_data->lanes - 1); | ||
1204 | if (rval) { | ||
1205 | dev_err(&client->dev, "csi lane mode set failed\n"); | ||
1206 | goto out_cci_addr_fail; | ||
1207 | } | ||
1208 | |||
1209 | rval = smiapp_write(sensor, SMIAPP_REG_U8_FAST_STANDBY_CTRL, | ||
1210 | SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE); | ||
1211 | if (rval) { | ||
1212 | dev_err(&client->dev, "fast standby set failed\n"); | ||
1213 | goto out_cci_addr_fail; | ||
1214 | } | ||
1215 | |||
1216 | rval = smiapp_write(sensor, SMIAPP_REG_U8_CSI_SIGNALLING_MODE, | ||
1217 | sensor->platform_data->csi_signalling_mode); | ||
1218 | if (rval) { | ||
1219 | dev_err(&client->dev, "csi signalling mode set failed\n"); | ||
1220 | goto out_cci_addr_fail; | ||
1221 | } | ||
1222 | |||
1223 | /* DPHY control done by sensor based on requested link rate */ | ||
1224 | rval = smiapp_write(sensor, SMIAPP_REG_U8_DPHY_CTRL, | ||
1225 | SMIAPP_DPHY_CTRL_UI); | ||
1226 | if (rval < 0) | ||
1227 | return rval; | ||
1228 | |||
1229 | rval = smiapp_call_quirk(sensor, post_poweron); | ||
1230 | if (rval) { | ||
1231 | dev_err(&client->dev, "post_poweron quirks failed\n"); | ||
1232 | goto out_cci_addr_fail; | ||
1233 | } | ||
1234 | |||
1235 | /* Are we still initialising...? If yes, return here. */ | ||
1236 | if (!sensor->pixel_array) | ||
1237 | return 0; | ||
1238 | |||
1239 | rval = v4l2_ctrl_handler_setup( | ||
1240 | &sensor->pixel_array->ctrl_handler); | ||
1241 | if (rval) | ||
1242 | goto out_cci_addr_fail; | ||
1243 | |||
1244 | rval = v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler); | ||
1245 | if (rval) | ||
1246 | goto out_cci_addr_fail; | ||
1247 | |||
1248 | mutex_lock(&sensor->mutex); | ||
1249 | rval = smiapp_update_mode(sensor); | ||
1250 | mutex_unlock(&sensor->mutex); | ||
1251 | if (rval < 0) | ||
1252 | goto out_cci_addr_fail; | ||
1253 | |||
1254 | return 0; | ||
1255 | |||
1256 | out_cci_addr_fail: | ||
1257 | if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) | ||
1258 | gpio_set_value(sensor->platform_data->xshutdown, 0); | ||
1259 | if (sensor->platform_data->set_xclk) | ||
1260 | sensor->platform_data->set_xclk(&sensor->src->sd, 0); | ||
1261 | else | ||
1262 | clk_disable(sensor->ext_clk); | ||
1263 | |||
1264 | out_xclk_fail: | ||
1265 | regulator_disable(sensor->vana); | ||
1266 | return rval; | ||
1267 | } | ||
1268 | |||
1269 | static void smiapp_power_off(struct smiapp_sensor *sensor) | ||
1270 | { | ||
1271 | /* | ||
1272 | * Currently power/clock to lens are enable/disabled separately | ||
1273 | * but they are essentially the same signals. So if the sensor is | ||
1274 | * powered off while the lens is powered on the sensor does not | ||
1275 | * really see a power off and next time the cci address change | ||
1276 | * will fail. So do a soft reset explicitly here. | ||
1277 | */ | ||
1278 | if (sensor->platform_data->i2c_addr_alt) | ||
1279 | smiapp_write(sensor, | ||
1280 | SMIAPP_REG_U8_SOFTWARE_RESET, | ||
1281 | SMIAPP_SOFTWARE_RESET); | ||
1282 | |||
1283 | if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) | ||
1284 | gpio_set_value(sensor->platform_data->xshutdown, 0); | ||
1285 | if (sensor->platform_data->set_xclk) | ||
1286 | sensor->platform_data->set_xclk(&sensor->src->sd, 0); | ||
1287 | else | ||
1288 | clk_disable(sensor->ext_clk); | ||
1289 | usleep_range(5000, 5000); | ||
1290 | regulator_disable(sensor->vana); | ||
1291 | sensor->streaming = 0; | ||
1292 | } | ||
1293 | |||
1294 | static int smiapp_set_power(struct v4l2_subdev *subdev, int on) | ||
1295 | { | ||
1296 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
1297 | int ret = 0; | ||
1298 | |||
1299 | mutex_lock(&sensor->power_mutex); | ||
1300 | |||
1301 | /* | ||
1302 | * If the power count is modified from 0 to != 0 or from != 0 | ||
1303 | * to 0, update the power state. | ||
1304 | */ | ||
1305 | if (!sensor->power_count == !on) | ||
1306 | goto out; | ||
1307 | |||
1308 | if (on) { | ||
1309 | /* Power on and perform initialisation. */ | ||
1310 | ret = smiapp_power_on(sensor); | ||
1311 | if (ret < 0) | ||
1312 | goto out; | ||
1313 | } else { | ||
1314 | smiapp_power_off(sensor); | ||
1315 | } | ||
1316 | |||
1317 | /* Update the power count. */ | ||
1318 | sensor->power_count += on ? 1 : -1; | ||
1319 | WARN_ON(sensor->power_count < 0); | ||
1320 | |||
1321 | out: | ||
1322 | mutex_unlock(&sensor->power_mutex); | ||
1323 | return ret; | ||
1324 | } | ||
1325 | |||
1326 | /* ----------------------------------------------------------------------------- | ||
1327 | * Video stream management | ||
1328 | */ | ||
1329 | |||
1330 | static int smiapp_start_streaming(struct smiapp_sensor *sensor) | ||
1331 | { | ||
1332 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
1333 | int rval; | ||
1334 | |||
1335 | mutex_lock(&sensor->mutex); | ||
1336 | |||
1337 | rval = smiapp_write(sensor, SMIAPP_REG_U16_CSI_DATA_FORMAT, | ||
1338 | (sensor->csi_format->width << 8) | | ||
1339 | sensor->csi_format->compressed); | ||
1340 | if (rval) | ||
1341 | goto out; | ||
1342 | |||
1343 | rval = smiapp_pll_configure(sensor); | ||
1344 | if (rval) | ||
1345 | goto out; | ||
1346 | |||
1347 | /* Analog crop start coordinates */ | ||
1348 | rval = smiapp_write(sensor, SMIAPP_REG_U16_X_ADDR_START, | ||
1349 | sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left); | ||
1350 | if (rval < 0) | ||
1351 | goto out; | ||
1352 | |||
1353 | rval = smiapp_write(sensor, SMIAPP_REG_U16_Y_ADDR_START, | ||
1354 | sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top); | ||
1355 | if (rval < 0) | ||
1356 | goto out; | ||
1357 | |||
1358 | /* Analog crop end coordinates */ | ||
1359 | rval = smiapp_write( | ||
1360 | sensor, SMIAPP_REG_U16_X_ADDR_END, | ||
1361 | sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left | ||
1362 | + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width - 1); | ||
1363 | if (rval < 0) | ||
1364 | goto out; | ||
1365 | |||
1366 | rval = smiapp_write( | ||
1367 | sensor, SMIAPP_REG_U16_Y_ADDR_END, | ||
1368 | sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top | ||
1369 | + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height - 1); | ||
1370 | if (rval < 0) | ||
1371 | goto out; | ||
1372 | |||
1373 | /* | ||
1374 | * Output from pixel array, including blanking, is set using | ||
1375 | * controls below. No need to set here. | ||
1376 | */ | ||
1377 | |||
1378 | /* Digital crop */ | ||
1379 | if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY] | ||
1380 | == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { | ||
1381 | rval = smiapp_write( | ||
1382 | sensor, SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET, | ||
1383 | sensor->scaler->crop[SMIAPP_PAD_SINK].left); | ||
1384 | if (rval < 0) | ||
1385 | goto out; | ||
1386 | |||
1387 | rval = smiapp_write( | ||
1388 | sensor, SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET, | ||
1389 | sensor->scaler->crop[SMIAPP_PAD_SINK].top); | ||
1390 | if (rval < 0) | ||
1391 | goto out; | ||
1392 | |||
1393 | rval = smiapp_write( | ||
1394 | sensor, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH, | ||
1395 | sensor->scaler->crop[SMIAPP_PAD_SINK].width); | ||
1396 | if (rval < 0) | ||
1397 | goto out; | ||
1398 | |||
1399 | rval = smiapp_write( | ||
1400 | sensor, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT, | ||
1401 | sensor->scaler->crop[SMIAPP_PAD_SINK].height); | ||
1402 | if (rval < 0) | ||
1403 | goto out; | ||
1404 | } | ||
1405 | |||
1406 | /* Scaling */ | ||
1407 | if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY] | ||
1408 | != SMIAPP_SCALING_CAPABILITY_NONE) { | ||
1409 | rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALING_MODE, | ||
1410 | sensor->scaling_mode); | ||
1411 | if (rval < 0) | ||
1412 | goto out; | ||
1413 | |||
1414 | rval = smiapp_write(sensor, SMIAPP_REG_U16_SCALE_M, | ||
1415 | sensor->scale_m); | ||
1416 | if (rval < 0) | ||
1417 | goto out; | ||
1418 | } | ||
1419 | |||
1420 | /* Output size from sensor */ | ||
1421 | rval = smiapp_write(sensor, SMIAPP_REG_U16_X_OUTPUT_SIZE, | ||
1422 | sensor->src->crop[SMIAPP_PAD_SRC].width); | ||
1423 | if (rval < 0) | ||
1424 | goto out; | ||
1425 | rval = smiapp_write(sensor, SMIAPP_REG_U16_Y_OUTPUT_SIZE, | ||
1426 | sensor->src->crop[SMIAPP_PAD_SRC].height); | ||
1427 | if (rval < 0) | ||
1428 | goto out; | ||
1429 | |||
1430 | if ((sensor->flash_capability & | ||
1431 | (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE | | ||
1432 | SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) && | ||
1433 | sensor->platform_data->strobe_setup != NULL && | ||
1434 | sensor->platform_data->strobe_setup->trigger != 0) { | ||
1435 | rval = smiapp_setup_flash_strobe(sensor); | ||
1436 | if (rval) | ||
1437 | goto out; | ||
1438 | } | ||
1439 | |||
1440 | rval = smiapp_call_quirk(sensor, pre_streamon); | ||
1441 | if (rval) { | ||
1442 | dev_err(&client->dev, "pre_streamon quirks failed\n"); | ||
1443 | goto out; | ||
1444 | } | ||
1445 | |||
1446 | rval = smiapp_write(sensor, SMIAPP_REG_U8_MODE_SELECT, | ||
1447 | SMIAPP_MODE_SELECT_STREAMING); | ||
1448 | |||
1449 | out: | ||
1450 | mutex_unlock(&sensor->mutex); | ||
1451 | |||
1452 | return rval; | ||
1453 | } | ||
1454 | |||
1455 | static int smiapp_stop_streaming(struct smiapp_sensor *sensor) | ||
1456 | { | ||
1457 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
1458 | int rval; | ||
1459 | |||
1460 | mutex_lock(&sensor->mutex); | ||
1461 | rval = smiapp_write(sensor, SMIAPP_REG_U8_MODE_SELECT, | ||
1462 | SMIAPP_MODE_SELECT_SOFTWARE_STANDBY); | ||
1463 | if (rval) | ||
1464 | goto out; | ||
1465 | |||
1466 | rval = smiapp_call_quirk(sensor, post_streamoff); | ||
1467 | if (rval) | ||
1468 | dev_err(&client->dev, "post_streamoff quirks failed\n"); | ||
1469 | |||
1470 | out: | ||
1471 | mutex_unlock(&sensor->mutex); | ||
1472 | return rval; | ||
1473 | } | ||
1474 | |||
1475 | /* ----------------------------------------------------------------------------- | ||
1476 | * V4L2 subdev video operations | ||
1477 | */ | ||
1478 | |||
1479 | static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable) | ||
1480 | { | ||
1481 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
1482 | int rval; | ||
1483 | |||
1484 | if (sensor->streaming == enable) | ||
1485 | return 0; | ||
1486 | |||
1487 | if (enable) { | ||
1488 | sensor->streaming = 1; | ||
1489 | rval = smiapp_start_streaming(sensor); | ||
1490 | if (rval < 0) | ||
1491 | sensor->streaming = 0; | ||
1492 | } else { | ||
1493 | rval = smiapp_stop_streaming(sensor); | ||
1494 | sensor->streaming = 0; | ||
1495 | } | ||
1496 | |||
1497 | return rval; | ||
1498 | } | ||
1499 | |||
1500 | static int smiapp_enum_mbus_code(struct v4l2_subdev *subdev, | ||
1501 | struct v4l2_subdev_fh *fh, | ||
1502 | struct v4l2_subdev_mbus_code_enum *code) | ||
1503 | { | ||
1504 | struct i2c_client *client = v4l2_get_subdevdata(subdev); | ||
1505 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
1506 | unsigned int i; | ||
1507 | int idx = -1; | ||
1508 | int rval = -EINVAL; | ||
1509 | |||
1510 | mutex_lock(&sensor->mutex); | ||
1511 | |||
1512 | dev_err(&client->dev, "subdev %s, pad %d, index %d\n", | ||
1513 | subdev->name, code->pad, code->index); | ||
1514 | |||
1515 | if (subdev != &sensor->src->sd || code->pad != SMIAPP_PAD_SRC) { | ||
1516 | if (code->index) | ||
1517 | goto out; | ||
1518 | |||
1519 | code->code = sensor->internal_csi_format->code; | ||
1520 | rval = 0; | ||
1521 | goto out; | ||
1522 | } | ||
1523 | |||
1524 | for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) { | ||
1525 | if (sensor->mbus_frame_fmts & (1 << i)) | ||
1526 | idx++; | ||
1527 | |||
1528 | if (idx == code->index) { | ||
1529 | code->code = smiapp_csi_data_formats[i].code; | ||
1530 | dev_err(&client->dev, "found index %d, i %d, code %x\n", | ||
1531 | code->index, i, code->code); | ||
1532 | rval = 0; | ||
1533 | break; | ||
1534 | } | ||
1535 | } | ||
1536 | |||
1537 | out: | ||
1538 | mutex_unlock(&sensor->mutex); | ||
1539 | |||
1540 | return rval; | ||
1541 | } | ||
1542 | |||
1543 | static u32 __smiapp_get_mbus_code(struct v4l2_subdev *subdev, | ||
1544 | unsigned int pad) | ||
1545 | { | ||
1546 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
1547 | |||
1548 | if (subdev == &sensor->src->sd && pad == SMIAPP_PAD_SRC) | ||
1549 | return sensor->csi_format->code; | ||
1550 | else | ||
1551 | return sensor->internal_csi_format->code; | ||
1552 | } | ||
1553 | |||
1554 | static int __smiapp_get_format(struct v4l2_subdev *subdev, | ||
1555 | struct v4l2_subdev_fh *fh, | ||
1556 | struct v4l2_subdev_format *fmt) | ||
1557 | { | ||
1558 | struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); | ||
1559 | |||
1560 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | ||
1561 | fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad); | ||
1562 | } else { | ||
1563 | struct v4l2_rect *r; | ||
1564 | |||
1565 | if (fmt->pad == ssd->source_pad) | ||
1566 | r = &ssd->crop[ssd->source_pad]; | ||
1567 | else | ||
1568 | r = &ssd->sink_fmt; | ||
1569 | |||
1570 | fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad); | ||
1571 | fmt->format.width = r->width; | ||
1572 | fmt->format.height = r->height; | ||
1573 | } | ||
1574 | |||
1575 | return 0; | ||
1576 | } | ||
1577 | |||
1578 | static int smiapp_get_format(struct v4l2_subdev *subdev, | ||
1579 | struct v4l2_subdev_fh *fh, | ||
1580 | struct v4l2_subdev_format *fmt) | ||
1581 | { | ||
1582 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
1583 | int rval; | ||
1584 | |||
1585 | mutex_lock(&sensor->mutex); | ||
1586 | rval = __smiapp_get_format(subdev, fh, fmt); | ||
1587 | mutex_unlock(&sensor->mutex); | ||
1588 | |||
1589 | return rval; | ||
1590 | } | ||
1591 | |||
1592 | static void smiapp_get_crop_compose(struct v4l2_subdev *subdev, | ||
1593 | struct v4l2_subdev_fh *fh, | ||
1594 | struct v4l2_rect **crops, | ||
1595 | struct v4l2_rect **comps, int which) | ||
1596 | { | ||
1597 | struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); | ||
1598 | unsigned int i; | ||
1599 | |||
1600 | if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { | ||
1601 | if (crops) | ||
1602 | for (i = 0; i < subdev->entity.num_pads; i++) | ||
1603 | crops[i] = &ssd->crop[i]; | ||
1604 | if (comps) | ||
1605 | *comps = &ssd->compose; | ||
1606 | } else { | ||
1607 | if (crops) { | ||
1608 | for (i = 0; i < subdev->entity.num_pads; i++) { | ||
1609 | crops[i] = v4l2_subdev_get_try_crop(fh, i); | ||
1610 | BUG_ON(!crops[i]); | ||
1611 | } | ||
1612 | } | ||
1613 | if (comps) { | ||
1614 | *comps = v4l2_subdev_get_try_compose(fh, | ||
1615 | SMIAPP_PAD_SINK); | ||
1616 | BUG_ON(!*comps); | ||
1617 | } | ||
1618 | } | ||
1619 | } | ||
1620 | |||
1621 | /* Changes require propagation only on sink pad. */ | ||
1622 | static void smiapp_propagate(struct v4l2_subdev *subdev, | ||
1623 | struct v4l2_subdev_fh *fh, int which, | ||
1624 | int target) | ||
1625 | { | ||
1626 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
1627 | struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); | ||
1628 | struct v4l2_rect *comp, *crops[SMIAPP_PADS]; | ||
1629 | |||
1630 | smiapp_get_crop_compose(subdev, fh, crops, &comp, which); | ||
1631 | |||
1632 | switch (target) { | ||
1633 | case V4L2_SEL_TGT_CROP: | ||
1634 | comp->width = crops[SMIAPP_PAD_SINK]->width; | ||
1635 | comp->height = crops[SMIAPP_PAD_SINK]->height; | ||
1636 | if (which == V4L2_SUBDEV_FORMAT_ACTIVE) { | ||
1637 | if (ssd == sensor->scaler) { | ||
1638 | sensor->scale_m = | ||
1639 | sensor->limits[ | ||
1640 | SMIAPP_LIMIT_SCALER_N_MIN]; | ||
1641 | sensor->scaling_mode = | ||
1642 | SMIAPP_SCALING_MODE_NONE; | ||
1643 | } else if (ssd == sensor->binner) { | ||
1644 | sensor->binning_horizontal = 1; | ||
1645 | sensor->binning_vertical = 1; | ||
1646 | } | ||
1647 | } | ||
1648 | /* Fall through */ | ||
1649 | case V4L2_SEL_TGT_COMPOSE: | ||
1650 | *crops[SMIAPP_PAD_SRC] = *comp; | ||
1651 | break; | ||
1652 | default: | ||
1653 | BUG(); | ||
1654 | } | ||
1655 | } | ||
1656 | |||
1657 | static const struct smiapp_csi_data_format | ||
1658 | *smiapp_validate_csi_data_format(struct smiapp_sensor *sensor, u32 code) | ||
1659 | { | ||
1660 | const struct smiapp_csi_data_format *csi_format = sensor->csi_format; | ||
1661 | unsigned int i; | ||
1662 | |||
1663 | for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) { | ||
1664 | if (sensor->mbus_frame_fmts & (1 << i) | ||
1665 | && smiapp_csi_data_formats[i].code == code) | ||
1666 | return &smiapp_csi_data_formats[i]; | ||
1667 | } | ||
1668 | |||
1669 | return csi_format; | ||
1670 | } | ||
1671 | |||
1672 | static int smiapp_set_format(struct v4l2_subdev *subdev, | ||
1673 | struct v4l2_subdev_fh *fh, | ||
1674 | struct v4l2_subdev_format *fmt) | ||
1675 | { | ||
1676 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
1677 | struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); | ||
1678 | struct v4l2_rect *crops[SMIAPP_PADS]; | ||
1679 | |||
1680 | mutex_lock(&sensor->mutex); | ||
1681 | |||
1682 | /* | ||
1683 | * Media bus code is changeable on src subdev's source pad. On | ||
1684 | * other source pads we just get format here. | ||
1685 | */ | ||
1686 | if (fmt->pad == ssd->source_pad) { | ||
1687 | u32 code = fmt->format.code; | ||
1688 | int rval = __smiapp_get_format(subdev, fh, fmt); | ||
1689 | |||
1690 | if (!rval && subdev == &sensor->src->sd) { | ||
1691 | const struct smiapp_csi_data_format *csi_format = | ||
1692 | smiapp_validate_csi_data_format(sensor, code); | ||
1693 | if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) | ||
1694 | sensor->csi_format = csi_format; | ||
1695 | fmt->format.code = csi_format->code; | ||
1696 | } | ||
1697 | |||
1698 | mutex_unlock(&sensor->mutex); | ||
1699 | return rval; | ||
1700 | } | ||
1701 | |||
1702 | /* Sink pad. Width and height are changeable here. */ | ||
1703 | fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad); | ||
1704 | fmt->format.width &= ~1; | ||
1705 | fmt->format.height &= ~1; | ||
1706 | |||
1707 | fmt->format.width = | ||
1708 | clamp(fmt->format.width, | ||
1709 | sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE], | ||
1710 | sensor->limits[SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE]); | ||
1711 | fmt->format.height = | ||
1712 | clamp(fmt->format.height, | ||
1713 | sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE], | ||
1714 | sensor->limits[SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE]); | ||
1715 | |||
1716 | smiapp_get_crop_compose(subdev, fh, crops, NULL, fmt->which); | ||
1717 | |||
1718 | crops[ssd->sink_pad]->left = 0; | ||
1719 | crops[ssd->sink_pad]->top = 0; | ||
1720 | crops[ssd->sink_pad]->width = fmt->format.width; | ||
1721 | crops[ssd->sink_pad]->height = fmt->format.height; | ||
1722 | if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) | ||
1723 | ssd->sink_fmt = *crops[ssd->sink_pad]; | ||
1724 | smiapp_propagate(subdev, fh, fmt->which, | ||
1725 | V4L2_SEL_TGT_CROP); | ||
1726 | |||
1727 | mutex_unlock(&sensor->mutex); | ||
1728 | |||
1729 | return 0; | ||
1730 | } | ||
1731 | |||
1732 | /* | ||
1733 | * Calculate goodness of scaled image size compared to expected image | ||
1734 | * size and flags provided. | ||
1735 | */ | ||
1736 | #define SCALING_GOODNESS 100000 | ||
1737 | #define SCALING_GOODNESS_EXTREME 100000000 | ||
1738 | static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w, | ||
1739 | int h, int ask_h, u32 flags) | ||
1740 | { | ||
1741 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
1742 | struct i2c_client *client = v4l2_get_subdevdata(subdev); | ||
1743 | int val = 0; | ||
1744 | |||
1745 | w &= ~1; | ||
1746 | ask_w &= ~1; | ||
1747 | h &= ~1; | ||
1748 | ask_h &= ~1; | ||
1749 | |||
1750 | if (flags & V4L2_SEL_FLAG_GE) { | ||
1751 | if (w < ask_w) | ||
1752 | val -= SCALING_GOODNESS; | ||
1753 | if (h < ask_h) | ||
1754 | val -= SCALING_GOODNESS; | ||
1755 | } | ||
1756 | |||
1757 | if (flags & V4L2_SEL_FLAG_LE) { | ||
1758 | if (w > ask_w) | ||
1759 | val -= SCALING_GOODNESS; | ||
1760 | if (h > ask_h) | ||
1761 | val -= SCALING_GOODNESS; | ||
1762 | } | ||
1763 | |||
1764 | val -= abs(w - ask_w); | ||
1765 | val -= abs(h - ask_h); | ||
1766 | |||
1767 | if (w < sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE]) | ||
1768 | val -= SCALING_GOODNESS_EXTREME; | ||
1769 | |||
1770 | dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n", | ||
1771 | w, ask_h, h, ask_h, val); | ||
1772 | |||
1773 | return val; | ||
1774 | } | ||
1775 | |||
1776 | static void smiapp_set_compose_binner(struct v4l2_subdev *subdev, | ||
1777 | struct v4l2_subdev_fh *fh, | ||
1778 | struct v4l2_subdev_selection *sel, | ||
1779 | struct v4l2_rect **crops, | ||
1780 | struct v4l2_rect *comp) | ||
1781 | { | ||
1782 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
1783 | unsigned int i; | ||
1784 | unsigned int binh = 1, binv = 1; | ||
1785 | unsigned int best = scaling_goodness( | ||
1786 | subdev, | ||
1787 | crops[SMIAPP_PAD_SINK]->width, sel->r.width, | ||
1788 | crops[SMIAPP_PAD_SINK]->height, sel->r.height, sel->flags); | ||
1789 | |||
1790 | for (i = 0; i < sensor->nbinning_subtypes; i++) { | ||
1791 | int this = scaling_goodness( | ||
1792 | subdev, | ||
1793 | crops[SMIAPP_PAD_SINK]->width | ||
1794 | / sensor->binning_subtypes[i].horizontal, | ||
1795 | sel->r.width, | ||
1796 | crops[SMIAPP_PAD_SINK]->height | ||
1797 | / sensor->binning_subtypes[i].vertical, | ||
1798 | sel->r.height, sel->flags); | ||
1799 | |||
1800 | if (this > best) { | ||
1801 | binh = sensor->binning_subtypes[i].horizontal; | ||
1802 | binv = sensor->binning_subtypes[i].vertical; | ||
1803 | best = this; | ||
1804 | } | ||
1805 | } | ||
1806 | if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | ||
1807 | sensor->binning_vertical = binv; | ||
1808 | sensor->binning_horizontal = binh; | ||
1809 | } | ||
1810 | |||
1811 | sel->r.width = (crops[SMIAPP_PAD_SINK]->width / binh) & ~1; | ||
1812 | sel->r.height = (crops[SMIAPP_PAD_SINK]->height / binv) & ~1; | ||
1813 | } | ||
1814 | |||
1815 | /* | ||
1816 | * Calculate best scaling ratio and mode for given output resolution. | ||
1817 | * | ||
1818 | * Try all of these: horizontal ratio, vertical ratio and smallest | ||
1819 | * size possible (horizontally). | ||
1820 | * | ||
1821 | * Also try whether horizontal scaler or full scaler gives a better | ||
1822 | * result. | ||
1823 | */ | ||
1824 | static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev, | ||
1825 | struct v4l2_subdev_fh *fh, | ||
1826 | struct v4l2_subdev_selection *sel, | ||
1827 | struct v4l2_rect **crops, | ||
1828 | struct v4l2_rect *comp) | ||
1829 | { | ||
1830 | struct i2c_client *client = v4l2_get_subdevdata(subdev); | ||
1831 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
1832 | u32 min, max, a, b, max_m; | ||
1833 | u32 scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; | ||
1834 | int mode = SMIAPP_SCALING_MODE_HORIZONTAL; | ||
1835 | u32 try[4]; | ||
1836 | u32 ntry = 0; | ||
1837 | unsigned int i; | ||
1838 | int best = INT_MIN; | ||
1839 | |||
1840 | sel->r.width = min_t(unsigned int, sel->r.width, | ||
1841 | crops[SMIAPP_PAD_SINK]->width); | ||
1842 | sel->r.height = min_t(unsigned int, sel->r.height, | ||
1843 | crops[SMIAPP_PAD_SINK]->height); | ||
1844 | |||
1845 | a = crops[SMIAPP_PAD_SINK]->width | ||
1846 | * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.width; | ||
1847 | b = crops[SMIAPP_PAD_SINK]->height | ||
1848 | * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.height; | ||
1849 | max_m = crops[SMIAPP_PAD_SINK]->width | ||
1850 | * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] | ||
1851 | / sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE]; | ||
1852 | |||
1853 | a = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX], | ||
1854 | max(a, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN])); | ||
1855 | b = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX], | ||
1856 | max(b, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN])); | ||
1857 | max_m = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX], | ||
1858 | max(max_m, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN])); | ||
1859 | |||
1860 | dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m); | ||
1861 | |||
1862 | min = min(max_m, min(a, b)); | ||
1863 | max = min(max_m, max(a, b)); | ||
1864 | |||
1865 | try[ntry] = min; | ||
1866 | ntry++; | ||
1867 | if (min != max) { | ||
1868 | try[ntry] = max; | ||
1869 | ntry++; | ||
1870 | } | ||
1871 | if (max != max_m) { | ||
1872 | try[ntry] = min + 1; | ||
1873 | ntry++; | ||
1874 | if (min != max) { | ||
1875 | try[ntry] = max + 1; | ||
1876 | ntry++; | ||
1877 | } | ||
1878 | } | ||
1879 | |||
1880 | for (i = 0; i < ntry; i++) { | ||
1881 | int this = scaling_goodness( | ||
1882 | subdev, | ||
1883 | crops[SMIAPP_PAD_SINK]->width | ||
1884 | / try[i] | ||
1885 | * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN], | ||
1886 | sel->r.width, | ||
1887 | crops[SMIAPP_PAD_SINK]->height, | ||
1888 | sel->r.height, | ||
1889 | sel->flags); | ||
1890 | |||
1891 | dev_dbg(&client->dev, "trying factor %d (%d)\n", try[i], i); | ||
1892 | |||
1893 | if (this > best) { | ||
1894 | scale_m = try[i]; | ||
1895 | mode = SMIAPP_SCALING_MODE_HORIZONTAL; | ||
1896 | best = this; | ||
1897 | } | ||
1898 | |||
1899 | if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY] | ||
1900 | == SMIAPP_SCALING_CAPABILITY_HORIZONTAL) | ||
1901 | continue; | ||
1902 | |||
1903 | this = scaling_goodness( | ||
1904 | subdev, crops[SMIAPP_PAD_SINK]->width | ||
1905 | / try[i] | ||
1906 | * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN], | ||
1907 | sel->r.width, | ||
1908 | crops[SMIAPP_PAD_SINK]->height | ||
1909 | / try[i] | ||
1910 | * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN], | ||
1911 | sel->r.height, | ||
1912 | sel->flags); | ||
1913 | |||
1914 | if (this > best) { | ||
1915 | scale_m = try[i]; | ||
1916 | mode = SMIAPP_SCALING_MODE_BOTH; | ||
1917 | best = this; | ||
1918 | } | ||
1919 | } | ||
1920 | |||
1921 | sel->r.width = | ||
1922 | (crops[SMIAPP_PAD_SINK]->width | ||
1923 | / scale_m | ||
1924 | * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]) & ~1; | ||
1925 | if (mode == SMIAPP_SCALING_MODE_BOTH) | ||
1926 | sel->r.height = | ||
1927 | (crops[SMIAPP_PAD_SINK]->height | ||
1928 | / scale_m | ||
1929 | * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]) | ||
1930 | & ~1; | ||
1931 | else | ||
1932 | sel->r.height = crops[SMIAPP_PAD_SINK]->height; | ||
1933 | |||
1934 | if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | ||
1935 | sensor->scale_m = scale_m; | ||
1936 | sensor->scaling_mode = mode; | ||
1937 | } | ||
1938 | } | ||
1939 | /* We're only called on source pads. This function sets scaling. */ | ||
1940 | static int smiapp_set_compose(struct v4l2_subdev *subdev, | ||
1941 | struct v4l2_subdev_fh *fh, | ||
1942 | struct v4l2_subdev_selection *sel) | ||
1943 | { | ||
1944 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
1945 | struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); | ||
1946 | struct v4l2_rect *comp, *crops[SMIAPP_PADS]; | ||
1947 | |||
1948 | smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which); | ||
1949 | |||
1950 | sel->r.top = 0; | ||
1951 | sel->r.left = 0; | ||
1952 | |||
1953 | if (ssd == sensor->binner) | ||
1954 | smiapp_set_compose_binner(subdev, fh, sel, crops, comp); | ||
1955 | else | ||
1956 | smiapp_set_compose_scaler(subdev, fh, sel, crops, comp); | ||
1957 | |||
1958 | *comp = sel->r; | ||
1959 | smiapp_propagate(subdev, fh, sel->which, | ||
1960 | V4L2_SEL_TGT_COMPOSE); | ||
1961 | |||
1962 | if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) | ||
1963 | return smiapp_update_mode(sensor); | ||
1964 | |||
1965 | return 0; | ||
1966 | } | ||
1967 | |||
1968 | static int __smiapp_sel_supported(struct v4l2_subdev *subdev, | ||
1969 | struct v4l2_subdev_selection *sel) | ||
1970 | { | ||
1971 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
1972 | struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); | ||
1973 | |||
1974 | /* We only implement crop in three places. */ | ||
1975 | switch (sel->target) { | ||
1976 | case V4L2_SEL_TGT_CROP: | ||
1977 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
1978 | if (ssd == sensor->pixel_array | ||
1979 | && sel->pad == SMIAPP_PA_PAD_SRC) | ||
1980 | return 0; | ||
1981 | if (ssd == sensor->src | ||
1982 | && sel->pad == SMIAPP_PAD_SRC) | ||
1983 | return 0; | ||
1984 | if (ssd == sensor->scaler | ||
1985 | && sel->pad == SMIAPP_PAD_SINK | ||
1986 | && sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY] | ||
1987 | == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) | ||
1988 | return 0; | ||
1989 | return -EINVAL; | ||
1990 | case V4L2_SEL_TGT_COMPOSE: | ||
1991 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: | ||
1992 | if (sel->pad == ssd->source_pad) | ||
1993 | return -EINVAL; | ||
1994 | if (ssd == sensor->binner) | ||
1995 | return 0; | ||
1996 | if (ssd == sensor->scaler | ||
1997 | && sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY] | ||
1998 | != SMIAPP_SCALING_CAPABILITY_NONE) | ||
1999 | return 0; | ||
2000 | /* Fall through */ | ||
2001 | default: | ||
2002 | return -EINVAL; | ||
2003 | } | ||
2004 | } | ||
2005 | |||
2006 | static int smiapp_set_crop(struct v4l2_subdev *subdev, | ||
2007 | struct v4l2_subdev_fh *fh, | ||
2008 | struct v4l2_subdev_selection *sel) | ||
2009 | { | ||
2010 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
2011 | struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); | ||
2012 | struct v4l2_rect *src_size, *crops[SMIAPP_PADS]; | ||
2013 | struct v4l2_rect _r; | ||
2014 | |||
2015 | smiapp_get_crop_compose(subdev, fh, crops, NULL, sel->which); | ||
2016 | |||
2017 | if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | ||
2018 | if (sel->pad == ssd->sink_pad) | ||
2019 | src_size = &ssd->sink_fmt; | ||
2020 | else | ||
2021 | src_size = &ssd->compose; | ||
2022 | } else { | ||
2023 | if (sel->pad == ssd->sink_pad) { | ||
2024 | _r.left = 0; | ||
2025 | _r.top = 0; | ||
2026 | _r.width = v4l2_subdev_get_try_format(fh, sel->pad) | ||
2027 | ->width; | ||
2028 | _r.height = v4l2_subdev_get_try_format(fh, sel->pad) | ||
2029 | ->height; | ||
2030 | src_size = &_r; | ||
2031 | } else { | ||
2032 | src_size = | ||
2033 | v4l2_subdev_get_try_compose( | ||
2034 | fh, ssd->sink_pad); | ||
2035 | } | ||
2036 | } | ||
2037 | |||
2038 | if (ssd == sensor->src && sel->pad == SMIAPP_PAD_SRC) { | ||
2039 | sel->r.left = 0; | ||
2040 | sel->r.top = 0; | ||
2041 | } | ||
2042 | |||
2043 | sel->r.width = min(sel->r.width, src_size->width); | ||
2044 | sel->r.height = min(sel->r.height, src_size->height); | ||
2045 | |||
2046 | sel->r.left = min(sel->r.left, src_size->width - sel->r.width); | ||
2047 | sel->r.top = min(sel->r.top, src_size->height - sel->r.height); | ||
2048 | |||
2049 | *crops[sel->pad] = sel->r; | ||
2050 | |||
2051 | if (ssd != sensor->pixel_array && sel->pad == SMIAPP_PAD_SINK) | ||
2052 | smiapp_propagate(subdev, fh, sel->which, | ||
2053 | V4L2_SEL_TGT_CROP); | ||
2054 | |||
2055 | return 0; | ||
2056 | } | ||
2057 | |||
2058 | static int __smiapp_get_selection(struct v4l2_subdev *subdev, | ||
2059 | struct v4l2_subdev_fh *fh, | ||
2060 | struct v4l2_subdev_selection *sel) | ||
2061 | { | ||
2062 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
2063 | struct smiapp_subdev *ssd = to_smiapp_subdev(subdev); | ||
2064 | struct v4l2_rect *comp, *crops[SMIAPP_PADS]; | ||
2065 | struct v4l2_rect sink_fmt; | ||
2066 | int ret; | ||
2067 | |||
2068 | ret = __smiapp_sel_supported(subdev, sel); | ||
2069 | if (ret) | ||
2070 | return ret; | ||
2071 | |||
2072 | smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which); | ||
2073 | |||
2074 | if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | ||
2075 | sink_fmt = ssd->sink_fmt; | ||
2076 | } else { | ||
2077 | struct v4l2_mbus_framefmt *fmt = | ||
2078 | v4l2_subdev_get_try_format(fh, ssd->sink_pad); | ||
2079 | |||
2080 | sink_fmt.left = 0; | ||
2081 | sink_fmt.top = 0; | ||
2082 | sink_fmt.width = fmt->width; | ||
2083 | sink_fmt.height = fmt->height; | ||
2084 | } | ||
2085 | |||
2086 | switch (sel->target) { | ||
2087 | case V4L2_SEL_TGT_CROP_BOUNDS: | ||
2088 | if (ssd == sensor->pixel_array) { | ||
2089 | sel->r.width = | ||
2090 | sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1; | ||
2091 | sel->r.height = | ||
2092 | sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1; | ||
2093 | } else if (sel->pad == ssd->sink_pad) { | ||
2094 | sel->r = sink_fmt; | ||
2095 | } else { | ||
2096 | sel->r = *comp; | ||
2097 | } | ||
2098 | break; | ||
2099 | case V4L2_SEL_TGT_CROP: | ||
2100 | case V4L2_SEL_TGT_COMPOSE_BOUNDS: | ||
2101 | sel->r = *crops[sel->pad]; | ||
2102 | break; | ||
2103 | case V4L2_SEL_TGT_COMPOSE: | ||
2104 | sel->r = *comp; | ||
2105 | break; | ||
2106 | } | ||
2107 | |||
2108 | return 0; | ||
2109 | } | ||
2110 | |||
2111 | static int smiapp_get_selection(struct v4l2_subdev *subdev, | ||
2112 | struct v4l2_subdev_fh *fh, | ||
2113 | struct v4l2_subdev_selection *sel) | ||
2114 | { | ||
2115 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
2116 | int rval; | ||
2117 | |||
2118 | mutex_lock(&sensor->mutex); | ||
2119 | rval = __smiapp_get_selection(subdev, fh, sel); | ||
2120 | mutex_unlock(&sensor->mutex); | ||
2121 | |||
2122 | return rval; | ||
2123 | } | ||
2124 | static int smiapp_set_selection(struct v4l2_subdev *subdev, | ||
2125 | struct v4l2_subdev_fh *fh, | ||
2126 | struct v4l2_subdev_selection *sel) | ||
2127 | { | ||
2128 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
2129 | int ret; | ||
2130 | |||
2131 | ret = __smiapp_sel_supported(subdev, sel); | ||
2132 | if (ret) | ||
2133 | return ret; | ||
2134 | |||
2135 | mutex_lock(&sensor->mutex); | ||
2136 | |||
2137 | sel->r.left = max(0, sel->r.left & ~1); | ||
2138 | sel->r.top = max(0, sel->r.top & ~1); | ||
2139 | sel->r.width = max(0, SMIAPP_ALIGN_DIM(sel->r.width, sel->flags)); | ||
2140 | sel->r.height = max(0, SMIAPP_ALIGN_DIM(sel->r.height, sel->flags)); | ||
2141 | |||
2142 | sel->r.width = max_t(unsigned int, | ||
2143 | sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE], | ||
2144 | sel->r.width); | ||
2145 | sel->r.height = max_t(unsigned int, | ||
2146 | sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE], | ||
2147 | sel->r.height); | ||
2148 | |||
2149 | switch (sel->target) { | ||
2150 | case V4L2_SEL_TGT_CROP: | ||
2151 | ret = smiapp_set_crop(subdev, fh, sel); | ||
2152 | break; | ||
2153 | case V4L2_SEL_TGT_COMPOSE: | ||
2154 | ret = smiapp_set_compose(subdev, fh, sel); | ||
2155 | break; | ||
2156 | default: | ||
2157 | BUG(); | ||
2158 | } | ||
2159 | |||
2160 | mutex_unlock(&sensor->mutex); | ||
2161 | return ret; | ||
2162 | } | ||
2163 | |||
2164 | static int smiapp_get_skip_frames(struct v4l2_subdev *subdev, u32 *frames) | ||
2165 | { | ||
2166 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
2167 | |||
2168 | *frames = sensor->frame_skip; | ||
2169 | return 0; | ||
2170 | } | ||
2171 | |||
2172 | /* ----------------------------------------------------------------------------- | ||
2173 | * sysfs attributes | ||
2174 | */ | ||
2175 | |||
2176 | static ssize_t | ||
2177 | smiapp_sysfs_nvm_read(struct device *dev, struct device_attribute *attr, | ||
2178 | char *buf) | ||
2179 | { | ||
2180 | struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev)); | ||
2181 | struct i2c_client *client = v4l2_get_subdevdata(subdev); | ||
2182 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
2183 | unsigned int nbytes; | ||
2184 | |||
2185 | if (!sensor->dev_init_done) | ||
2186 | return -EBUSY; | ||
2187 | |||
2188 | if (!sensor->nvm_size) { | ||
2189 | /* NVM not read yet - read it now */ | ||
2190 | sensor->nvm_size = sensor->platform_data->nvm_size; | ||
2191 | if (smiapp_set_power(subdev, 1) < 0) | ||
2192 | return -ENODEV; | ||
2193 | if (smiapp_read_nvm(sensor, sensor->nvm)) { | ||
2194 | dev_err(&client->dev, "nvm read failed\n"); | ||
2195 | return -ENODEV; | ||
2196 | } | ||
2197 | smiapp_set_power(subdev, 0); | ||
2198 | } | ||
2199 | /* | ||
2200 | * NVM is still way below a PAGE_SIZE, so we can safely | ||
2201 | * assume this for now. | ||
2202 | */ | ||
2203 | nbytes = min_t(unsigned int, sensor->nvm_size, PAGE_SIZE); | ||
2204 | memcpy(buf, sensor->nvm, nbytes); | ||
2205 | |||
2206 | return nbytes; | ||
2207 | } | ||
2208 | static DEVICE_ATTR(nvm, S_IRUGO, smiapp_sysfs_nvm_read, NULL); | ||
2209 | |||
2210 | /* ----------------------------------------------------------------------------- | ||
2211 | * V4L2 subdev core operations | ||
2212 | */ | ||
2213 | |||
2214 | static int smiapp_identify_module(struct v4l2_subdev *subdev) | ||
2215 | { | ||
2216 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
2217 | struct i2c_client *client = v4l2_get_subdevdata(subdev); | ||
2218 | struct smiapp_module_info *minfo = &sensor->minfo; | ||
2219 | unsigned int i; | ||
2220 | int rval = 0; | ||
2221 | |||
2222 | minfo->name = SMIAPP_NAME; | ||
2223 | |||
2224 | /* Module info */ | ||
2225 | rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MANUFACTURER_ID, | ||
2226 | &minfo->manufacturer_id); | ||
2227 | if (!rval) | ||
2228 | rval = smiapp_read_8only(sensor, SMIAPP_REG_U16_MODEL_ID, | ||
2229 | &minfo->model_id); | ||
2230 | if (!rval) | ||
2231 | rval = smiapp_read_8only(sensor, | ||
2232 | SMIAPP_REG_U8_REVISION_NUMBER_MAJOR, | ||
2233 | &minfo->revision_number_major); | ||
2234 | if (!rval) | ||
2235 | rval = smiapp_read_8only(sensor, | ||
2236 | SMIAPP_REG_U8_REVISION_NUMBER_MINOR, | ||
2237 | &minfo->revision_number_minor); | ||
2238 | if (!rval) | ||
2239 | rval = smiapp_read_8only(sensor, | ||
2240 | SMIAPP_REG_U8_MODULE_DATE_YEAR, | ||
2241 | &minfo->module_year); | ||
2242 | if (!rval) | ||
2243 | rval = smiapp_read_8only(sensor, | ||
2244 | SMIAPP_REG_U8_MODULE_DATE_MONTH, | ||
2245 | &minfo->module_month); | ||
2246 | if (!rval) | ||
2247 | rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_MODULE_DATE_DAY, | ||
2248 | &minfo->module_day); | ||
2249 | |||
2250 | /* Sensor info */ | ||
2251 | if (!rval) | ||
2252 | rval = smiapp_read_8only(sensor, | ||
2253 | SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID, | ||
2254 | &minfo->sensor_manufacturer_id); | ||
2255 | if (!rval) | ||
2256 | rval = smiapp_read_8only(sensor, | ||
2257 | SMIAPP_REG_U16_SENSOR_MODEL_ID, | ||
2258 | &minfo->sensor_model_id); | ||
2259 | if (!rval) | ||
2260 | rval = smiapp_read_8only(sensor, | ||
2261 | SMIAPP_REG_U8_SENSOR_REVISION_NUMBER, | ||
2262 | &minfo->sensor_revision_number); | ||
2263 | if (!rval) | ||
2264 | rval = smiapp_read_8only(sensor, | ||
2265 | SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION, | ||
2266 | &minfo->sensor_firmware_version); | ||
2267 | |||
2268 | /* SMIA */ | ||
2269 | if (!rval) | ||
2270 | rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SMIA_VERSION, | ||
2271 | &minfo->smia_version); | ||
2272 | if (!rval) | ||
2273 | rval = smiapp_read_8only(sensor, SMIAPP_REG_U8_SMIAPP_VERSION, | ||
2274 | &minfo->smiapp_version); | ||
2275 | |||
2276 | if (rval) { | ||
2277 | dev_err(&client->dev, "sensor detection failed\n"); | ||
2278 | return -ENODEV; | ||
2279 | } | ||
2280 | |||
2281 | dev_dbg(&client->dev, "module 0x%2.2x-0x%4.4x\n", | ||
2282 | minfo->manufacturer_id, minfo->model_id); | ||
2283 | |||
2284 | dev_dbg(&client->dev, | ||
2285 | "module revision 0x%2.2x-0x%2.2x date %2.2d-%2.2d-%2.2d\n", | ||
2286 | minfo->revision_number_major, minfo->revision_number_minor, | ||
2287 | minfo->module_year, minfo->module_month, minfo->module_day); | ||
2288 | |||
2289 | dev_dbg(&client->dev, "sensor 0x%2.2x-0x%4.4x\n", | ||
2290 | minfo->sensor_manufacturer_id, minfo->sensor_model_id); | ||
2291 | |||
2292 | dev_dbg(&client->dev, | ||
2293 | "sensor revision 0x%2.2x firmware version 0x%2.2x\n", | ||
2294 | minfo->sensor_revision_number, minfo->sensor_firmware_version); | ||
2295 | |||
2296 | dev_dbg(&client->dev, "smia version %2.2d smiapp version %2.2d\n", | ||
2297 | minfo->smia_version, minfo->smiapp_version); | ||
2298 | |||
2299 | /* | ||
2300 | * Some modules have bad data in the lvalues below. Hope the | ||
2301 | * rvalues have better stuff. The lvalues are module | ||
2302 | * parameters whereas the rvalues are sensor parameters. | ||
2303 | */ | ||
2304 | if (!minfo->manufacturer_id && !minfo->model_id) { | ||
2305 | minfo->manufacturer_id = minfo->sensor_manufacturer_id; | ||
2306 | minfo->model_id = minfo->sensor_model_id; | ||
2307 | minfo->revision_number_major = minfo->sensor_revision_number; | ||
2308 | } | ||
2309 | |||
2310 | for (i = 0; i < ARRAY_SIZE(smiapp_module_idents); i++) { | ||
2311 | if (smiapp_module_idents[i].manufacturer_id | ||
2312 | != minfo->manufacturer_id) | ||
2313 | continue; | ||
2314 | if (smiapp_module_idents[i].model_id != minfo->model_id) | ||
2315 | continue; | ||
2316 | if (smiapp_module_idents[i].flags | ||
2317 | & SMIAPP_MODULE_IDENT_FLAG_REV_LE) { | ||
2318 | if (smiapp_module_idents[i].revision_number_major | ||
2319 | < minfo->revision_number_major) | ||
2320 | continue; | ||
2321 | } else { | ||
2322 | if (smiapp_module_idents[i].revision_number_major | ||
2323 | != minfo->revision_number_major) | ||
2324 | continue; | ||
2325 | } | ||
2326 | |||
2327 | minfo->name = smiapp_module_idents[i].name; | ||
2328 | minfo->quirk = smiapp_module_idents[i].quirk; | ||
2329 | break; | ||
2330 | } | ||
2331 | |||
2332 | if (i >= ARRAY_SIZE(smiapp_module_idents)) | ||
2333 | dev_warn(&client->dev, | ||
2334 | "no quirks for this module; let's hope it's fully compliant\n"); | ||
2335 | |||
2336 | dev_dbg(&client->dev, "the sensor is called %s, ident %2.2x%4.4x%2.2x\n", | ||
2337 | minfo->name, minfo->manufacturer_id, minfo->model_id, | ||
2338 | minfo->revision_number_major); | ||
2339 | |||
2340 | strlcpy(subdev->name, sensor->minfo.name, sizeof(subdev->name)); | ||
2341 | |||
2342 | return 0; | ||
2343 | } | ||
2344 | |||
2345 | static const struct v4l2_subdev_ops smiapp_ops; | ||
2346 | static const struct v4l2_subdev_internal_ops smiapp_internal_ops; | ||
2347 | static const struct media_entity_operations smiapp_entity_ops; | ||
2348 | |||
2349 | static int smiapp_registered(struct v4l2_subdev *subdev) | ||
2350 | { | ||
2351 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
2352 | struct i2c_client *client = v4l2_get_subdevdata(subdev); | ||
2353 | struct smiapp_subdev *last = NULL; | ||
2354 | u32 tmp; | ||
2355 | unsigned int i; | ||
2356 | int rval; | ||
2357 | |||
2358 | sensor->vana = regulator_get(&client->dev, "VANA"); | ||
2359 | if (IS_ERR(sensor->vana)) { | ||
2360 | dev_err(&client->dev, "could not get regulator for vana\n"); | ||
2361 | return -ENODEV; | ||
2362 | } | ||
2363 | |||
2364 | if (!sensor->platform_data->set_xclk) { | ||
2365 | sensor->ext_clk = clk_get(&client->dev, | ||
2366 | sensor->platform_data->ext_clk_name); | ||
2367 | if (IS_ERR(sensor->ext_clk)) { | ||
2368 | dev_err(&client->dev, "could not get clock %s\n", | ||
2369 | sensor->platform_data->ext_clk_name); | ||
2370 | rval = -ENODEV; | ||
2371 | goto out_clk_get; | ||
2372 | } | ||
2373 | |||
2374 | rval = clk_set_rate(sensor->ext_clk, | ||
2375 | sensor->platform_data->ext_clk); | ||
2376 | if (rval < 0) { | ||
2377 | dev_err(&client->dev, | ||
2378 | "unable to set clock %s freq to %u\n", | ||
2379 | sensor->platform_data->ext_clk_name, | ||
2380 | sensor->platform_data->ext_clk); | ||
2381 | rval = -ENODEV; | ||
2382 | goto out_clk_set_rate; | ||
2383 | } | ||
2384 | } | ||
2385 | |||
2386 | if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) { | ||
2387 | if (gpio_request_one(sensor->platform_data->xshutdown, 0, | ||
2388 | "SMIA++ xshutdown") != 0) { | ||
2389 | dev_err(&client->dev, | ||
2390 | "unable to acquire reset gpio %d\n", | ||
2391 | sensor->platform_data->xshutdown); | ||
2392 | rval = -ENODEV; | ||
2393 | goto out_clk_set_rate; | ||
2394 | } | ||
2395 | } | ||
2396 | |||
2397 | rval = smiapp_power_on(sensor); | ||
2398 | if (rval) { | ||
2399 | rval = -ENODEV; | ||
2400 | goto out_smiapp_power_on; | ||
2401 | } | ||
2402 | |||
2403 | rval = smiapp_identify_module(subdev); | ||
2404 | if (rval) { | ||
2405 | rval = -ENODEV; | ||
2406 | goto out_power_off; | ||
2407 | } | ||
2408 | |||
2409 | rval = smiapp_get_all_limits(sensor); | ||
2410 | if (rval) { | ||
2411 | rval = -ENODEV; | ||
2412 | goto out_power_off; | ||
2413 | } | ||
2414 | |||
2415 | /* | ||
2416 | * Handle Sensor Module orientation on the board. | ||
2417 | * | ||
2418 | * The application of H-FLIP and V-FLIP on the sensor is modified by | ||
2419 | * the sensor orientation on the board. | ||
2420 | * | ||
2421 | * For SMIAPP_BOARD_SENSOR_ORIENT_180 the default behaviour is to set | ||
2422 | * both H-FLIP and V-FLIP for normal operation which also implies | ||
2423 | * that a set/unset operation for user space HFLIP and VFLIP v4l2 | ||
2424 | * controls will need to be internally inverted. | ||
2425 | * | ||
2426 | * Rotation also changes the bayer pattern. | ||
2427 | */ | ||
2428 | if (sensor->platform_data->module_board_orient == | ||
2429 | SMIAPP_MODULE_BOARD_ORIENT_180) | ||
2430 | sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP | | ||
2431 | SMIAPP_IMAGE_ORIENTATION_VFLIP; | ||
2432 | |||
2433 | rval = smiapp_get_mbus_formats(sensor); | ||
2434 | if (rval) { | ||
2435 | rval = -ENODEV; | ||
2436 | goto out_power_off; | ||
2437 | } | ||
2438 | |||
2439 | if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY]) { | ||
2440 | u32 val; | ||
2441 | |||
2442 | rval = smiapp_read(sensor, | ||
2443 | SMIAPP_REG_U8_BINNING_SUBTYPES, &val); | ||
2444 | if (rval < 0) { | ||
2445 | rval = -ENODEV; | ||
2446 | goto out_power_off; | ||
2447 | } | ||
2448 | sensor->nbinning_subtypes = min_t(u8, val, | ||
2449 | SMIAPP_BINNING_SUBTYPES); | ||
2450 | |||
2451 | for (i = 0; i < sensor->nbinning_subtypes; i++) { | ||
2452 | rval = smiapp_read( | ||
2453 | sensor, SMIAPP_REG_U8_BINNING_TYPE_n(i), &val); | ||
2454 | if (rval < 0) { | ||
2455 | rval = -ENODEV; | ||
2456 | goto out_power_off; | ||
2457 | } | ||
2458 | sensor->binning_subtypes[i] = | ||
2459 | *(struct smiapp_binning_subtype *)&val; | ||
2460 | |||
2461 | dev_dbg(&client->dev, "binning %xx%x\n", | ||
2462 | sensor->binning_subtypes[i].horizontal, | ||
2463 | sensor->binning_subtypes[i].vertical); | ||
2464 | } | ||
2465 | } | ||
2466 | sensor->binning_horizontal = 1; | ||
2467 | sensor->binning_vertical = 1; | ||
2468 | |||
2469 | /* SMIA++ NVM initialization - it will be read from the sensor | ||
2470 | * when it is first requested by userspace. | ||
2471 | */ | ||
2472 | if (sensor->minfo.smiapp_version && sensor->platform_data->nvm_size) { | ||
2473 | sensor->nvm = kzalloc(sensor->platform_data->nvm_size, | ||
2474 | GFP_KERNEL); | ||
2475 | if (sensor->nvm == NULL) { | ||
2476 | dev_err(&client->dev, "nvm buf allocation failed\n"); | ||
2477 | rval = -ENOMEM; | ||
2478 | goto out_power_off; | ||
2479 | } | ||
2480 | |||
2481 | if (device_create_file(&client->dev, &dev_attr_nvm) != 0) { | ||
2482 | dev_err(&client->dev, "sysfs nvm entry failed\n"); | ||
2483 | rval = -EBUSY; | ||
2484 | goto out_power_off; | ||
2485 | } | ||
2486 | } | ||
2487 | |||
2488 | rval = smiapp_call_quirk(sensor, limits); | ||
2489 | if (rval) { | ||
2490 | dev_err(&client->dev, "limits quirks failed\n"); | ||
2491 | goto out_nvm_release; | ||
2492 | } | ||
2493 | |||
2494 | /* We consider this as profile 0 sensor if any of these are zero. */ | ||
2495 | if (!sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV] || | ||
2496 | !sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV] || | ||
2497 | !sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV] || | ||
2498 | !sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV]) { | ||
2499 | sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0; | ||
2500 | } else if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY] | ||
2501 | != SMIAPP_SCALING_CAPABILITY_NONE) { | ||
2502 | if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY] | ||
2503 | == SMIAPP_SCALING_CAPABILITY_HORIZONTAL) | ||
2504 | sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1; | ||
2505 | else | ||
2506 | sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2; | ||
2507 | sensor->scaler = &sensor->ssds[sensor->ssds_used]; | ||
2508 | sensor->ssds_used++; | ||
2509 | } else if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY] | ||
2510 | == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) { | ||
2511 | sensor->scaler = &sensor->ssds[sensor->ssds_used]; | ||
2512 | sensor->ssds_used++; | ||
2513 | } | ||
2514 | sensor->binner = &sensor->ssds[sensor->ssds_used]; | ||
2515 | sensor->ssds_used++; | ||
2516 | sensor->pixel_array = &sensor->ssds[sensor->ssds_used]; | ||
2517 | sensor->ssds_used++; | ||
2518 | |||
2519 | sensor->scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]; | ||
2520 | |||
2521 | for (i = 0; i < SMIAPP_SUBDEVS; i++) { | ||
2522 | struct { | ||
2523 | struct smiapp_subdev *ssd; | ||
2524 | char *name; | ||
2525 | } const __this[] = { | ||
2526 | { sensor->scaler, "scaler", }, | ||
2527 | { sensor->binner, "binner", }, | ||
2528 | { sensor->pixel_array, "pixel array", }, | ||
2529 | }, *_this = &__this[i]; | ||
2530 | struct smiapp_subdev *this = _this->ssd; | ||
2531 | |||
2532 | if (!this) | ||
2533 | continue; | ||
2534 | |||
2535 | if (this != sensor->src) | ||
2536 | v4l2_subdev_init(&this->sd, &smiapp_ops); | ||
2537 | |||
2538 | this->sensor = sensor; | ||
2539 | |||
2540 | if (this == sensor->pixel_array) { | ||
2541 | this->npads = 1; | ||
2542 | } else { | ||
2543 | this->npads = 2; | ||
2544 | this->source_pad = 1; | ||
2545 | } | ||
2546 | |||
2547 | snprintf(this->sd.name, | ||
2548 | sizeof(this->sd.name), "%s %s", | ||
2549 | sensor->minfo.name, _this->name); | ||
2550 | |||
2551 | this->sink_fmt.width = | ||
2552 | sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1; | ||
2553 | this->sink_fmt.height = | ||
2554 | sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1; | ||
2555 | this->compose.width = this->sink_fmt.width; | ||
2556 | this->compose.height = this->sink_fmt.height; | ||
2557 | this->crop[this->source_pad] = this->compose; | ||
2558 | this->pads[this->source_pad].flags = MEDIA_PAD_FL_SOURCE; | ||
2559 | if (this != sensor->pixel_array) { | ||
2560 | this->crop[this->sink_pad] = this->compose; | ||
2561 | this->pads[this->sink_pad].flags = MEDIA_PAD_FL_SINK; | ||
2562 | } | ||
2563 | |||
2564 | this->sd.entity.ops = &smiapp_entity_ops; | ||
2565 | |||
2566 | if (last == NULL) { | ||
2567 | last = this; | ||
2568 | continue; | ||
2569 | } | ||
2570 | |||
2571 | this->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
2572 | this->sd.internal_ops = &smiapp_internal_ops; | ||
2573 | this->sd.owner = NULL; | ||
2574 | v4l2_set_subdevdata(&this->sd, client); | ||
2575 | |||
2576 | rval = media_entity_init(&this->sd.entity, | ||
2577 | this->npads, this->pads, 0); | ||
2578 | if (rval) { | ||
2579 | dev_err(&client->dev, | ||
2580 | "media_entity_init failed\n"); | ||
2581 | goto out_nvm_release; | ||
2582 | } | ||
2583 | |||
2584 | rval = media_entity_create_link(&this->sd.entity, | ||
2585 | this->source_pad, | ||
2586 | &last->sd.entity, | ||
2587 | last->sink_pad, | ||
2588 | MEDIA_LNK_FL_ENABLED | | ||
2589 | MEDIA_LNK_FL_IMMUTABLE); | ||
2590 | if (rval) { | ||
2591 | dev_err(&client->dev, | ||
2592 | "media_entity_create_link failed\n"); | ||
2593 | goto out_nvm_release; | ||
2594 | } | ||
2595 | |||
2596 | rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev, | ||
2597 | &this->sd); | ||
2598 | if (rval) { | ||
2599 | dev_err(&client->dev, | ||
2600 | "v4l2_device_register_subdev failed\n"); | ||
2601 | goto out_nvm_release; | ||
2602 | } | ||
2603 | |||
2604 | last = this; | ||
2605 | } | ||
2606 | |||
2607 | dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile); | ||
2608 | |||
2609 | sensor->pixel_array->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR; | ||
2610 | |||
2611 | /* final steps */ | ||
2612 | smiapp_read_frame_fmt(sensor); | ||
2613 | rval = smiapp_init_controls(sensor); | ||
2614 | if (rval < 0) | ||
2615 | goto out_nvm_release; | ||
2616 | |||
2617 | rval = smiapp_update_mode(sensor); | ||
2618 | if (rval) { | ||
2619 | dev_err(&client->dev, "update mode failed\n"); | ||
2620 | goto out_nvm_release; | ||
2621 | } | ||
2622 | |||
2623 | sensor->streaming = false; | ||
2624 | sensor->dev_init_done = true; | ||
2625 | |||
2626 | /* check flash capability */ | ||
2627 | rval = smiapp_read(sensor, SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, &tmp); | ||
2628 | sensor->flash_capability = tmp; | ||
2629 | if (rval) | ||
2630 | goto out_nvm_release; | ||
2631 | |||
2632 | smiapp_power_off(sensor); | ||
2633 | |||
2634 | return 0; | ||
2635 | |||
2636 | out_nvm_release: | ||
2637 | device_remove_file(&client->dev, &dev_attr_nvm); | ||
2638 | |||
2639 | out_power_off: | ||
2640 | kfree(sensor->nvm); | ||
2641 | sensor->nvm = NULL; | ||
2642 | smiapp_power_off(sensor); | ||
2643 | |||
2644 | out_smiapp_power_on: | ||
2645 | if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) | ||
2646 | gpio_free(sensor->platform_data->xshutdown); | ||
2647 | |||
2648 | out_clk_set_rate: | ||
2649 | clk_put(sensor->ext_clk); | ||
2650 | sensor->ext_clk = NULL; | ||
2651 | |||
2652 | out_clk_get: | ||
2653 | regulator_put(sensor->vana); | ||
2654 | sensor->vana = NULL; | ||
2655 | return rval; | ||
2656 | } | ||
2657 | |||
2658 | static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
2659 | { | ||
2660 | struct smiapp_subdev *ssd = to_smiapp_subdev(sd); | ||
2661 | struct smiapp_sensor *sensor = ssd->sensor; | ||
2662 | u32 mbus_code = | ||
2663 | smiapp_csi_data_formats[smiapp_pixel_order(sensor)].code; | ||
2664 | unsigned int i; | ||
2665 | |||
2666 | mutex_lock(&sensor->mutex); | ||
2667 | |||
2668 | for (i = 0; i < ssd->npads; i++) { | ||
2669 | struct v4l2_mbus_framefmt *try_fmt = | ||
2670 | v4l2_subdev_get_try_format(fh, i); | ||
2671 | struct v4l2_rect *try_crop = v4l2_subdev_get_try_crop(fh, i); | ||
2672 | struct v4l2_rect *try_comp; | ||
2673 | |||
2674 | try_fmt->width = sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1; | ||
2675 | try_fmt->height = sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1; | ||
2676 | try_fmt->code = mbus_code; | ||
2677 | |||
2678 | try_crop->top = 0; | ||
2679 | try_crop->left = 0; | ||
2680 | try_crop->width = try_fmt->width; | ||
2681 | try_crop->height = try_fmt->height; | ||
2682 | |||
2683 | if (ssd != sensor->pixel_array) | ||
2684 | continue; | ||
2685 | |||
2686 | try_comp = v4l2_subdev_get_try_compose(fh, i); | ||
2687 | *try_comp = *try_crop; | ||
2688 | } | ||
2689 | |||
2690 | mutex_unlock(&sensor->mutex); | ||
2691 | |||
2692 | return smiapp_set_power(sd, 1); | ||
2693 | } | ||
2694 | |||
2695 | static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
2696 | { | ||
2697 | return smiapp_set_power(sd, 0); | ||
2698 | } | ||
2699 | |||
2700 | static const struct v4l2_subdev_video_ops smiapp_video_ops = { | ||
2701 | .s_stream = smiapp_set_stream, | ||
2702 | }; | ||
2703 | |||
2704 | static const struct v4l2_subdev_core_ops smiapp_core_ops = { | ||
2705 | .s_power = smiapp_set_power, | ||
2706 | }; | ||
2707 | |||
2708 | static const struct v4l2_subdev_pad_ops smiapp_pad_ops = { | ||
2709 | .enum_mbus_code = smiapp_enum_mbus_code, | ||
2710 | .get_fmt = smiapp_get_format, | ||
2711 | .set_fmt = smiapp_set_format, | ||
2712 | .get_selection = smiapp_get_selection, | ||
2713 | .set_selection = smiapp_set_selection, | ||
2714 | }; | ||
2715 | |||
2716 | static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = { | ||
2717 | .g_skip_frames = smiapp_get_skip_frames, | ||
2718 | }; | ||
2719 | |||
2720 | static const struct v4l2_subdev_ops smiapp_ops = { | ||
2721 | .core = &smiapp_core_ops, | ||
2722 | .video = &smiapp_video_ops, | ||
2723 | .pad = &smiapp_pad_ops, | ||
2724 | .sensor = &smiapp_sensor_ops, | ||
2725 | }; | ||
2726 | |||
2727 | static const struct media_entity_operations smiapp_entity_ops = { | ||
2728 | .link_validate = v4l2_subdev_link_validate, | ||
2729 | }; | ||
2730 | |||
2731 | static const struct v4l2_subdev_internal_ops smiapp_internal_src_ops = { | ||
2732 | .registered = smiapp_registered, | ||
2733 | .open = smiapp_open, | ||
2734 | .close = smiapp_close, | ||
2735 | }; | ||
2736 | |||
2737 | static const struct v4l2_subdev_internal_ops smiapp_internal_ops = { | ||
2738 | .open = smiapp_open, | ||
2739 | .close = smiapp_close, | ||
2740 | }; | ||
2741 | |||
2742 | /* ----------------------------------------------------------------------------- | ||
2743 | * I2C Driver | ||
2744 | */ | ||
2745 | |||
2746 | #ifdef CONFIG_PM | ||
2747 | |||
2748 | static int smiapp_suspend(struct device *dev) | ||
2749 | { | ||
2750 | struct i2c_client *client = to_i2c_client(dev); | ||
2751 | struct v4l2_subdev *subdev = i2c_get_clientdata(client); | ||
2752 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
2753 | bool streaming; | ||
2754 | |||
2755 | BUG_ON(mutex_is_locked(&sensor->mutex)); | ||
2756 | |||
2757 | if (sensor->power_count == 0) | ||
2758 | return 0; | ||
2759 | |||
2760 | if (sensor->streaming) | ||
2761 | smiapp_stop_streaming(sensor); | ||
2762 | |||
2763 | streaming = sensor->streaming; | ||
2764 | |||
2765 | smiapp_power_off(sensor); | ||
2766 | |||
2767 | /* save state for resume */ | ||
2768 | sensor->streaming = streaming; | ||
2769 | |||
2770 | return 0; | ||
2771 | } | ||
2772 | |||
2773 | static int smiapp_resume(struct device *dev) | ||
2774 | { | ||
2775 | struct i2c_client *client = to_i2c_client(dev); | ||
2776 | struct v4l2_subdev *subdev = i2c_get_clientdata(client); | ||
2777 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
2778 | int rval; | ||
2779 | |||
2780 | if (sensor->power_count == 0) | ||
2781 | return 0; | ||
2782 | |||
2783 | rval = smiapp_power_on(sensor); | ||
2784 | if (rval) | ||
2785 | return rval; | ||
2786 | |||
2787 | if (sensor->streaming) | ||
2788 | rval = smiapp_start_streaming(sensor); | ||
2789 | |||
2790 | return rval; | ||
2791 | } | ||
2792 | |||
2793 | #else | ||
2794 | |||
2795 | #define smiapp_suspend NULL | ||
2796 | #define smiapp_resume NULL | ||
2797 | |||
2798 | #endif /* CONFIG_PM */ | ||
2799 | |||
2800 | static int smiapp_probe(struct i2c_client *client, | ||
2801 | const struct i2c_device_id *devid) | ||
2802 | { | ||
2803 | struct smiapp_sensor *sensor; | ||
2804 | int rval; | ||
2805 | |||
2806 | if (client->dev.platform_data == NULL) | ||
2807 | return -ENODEV; | ||
2808 | |||
2809 | sensor = kzalloc(sizeof(*sensor), GFP_KERNEL); | ||
2810 | if (sensor == NULL) | ||
2811 | return -ENOMEM; | ||
2812 | |||
2813 | sensor->platform_data = client->dev.platform_data; | ||
2814 | mutex_init(&sensor->mutex); | ||
2815 | mutex_init(&sensor->power_mutex); | ||
2816 | sensor->src = &sensor->ssds[sensor->ssds_used]; | ||
2817 | |||
2818 | v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops); | ||
2819 | sensor->src->sd.internal_ops = &smiapp_internal_src_ops; | ||
2820 | sensor->src->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | ||
2821 | sensor->src->sensor = sensor; | ||
2822 | |||
2823 | sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE; | ||
2824 | rval = media_entity_init(&sensor->src->sd.entity, 2, | ||
2825 | sensor->src->pads, 0); | ||
2826 | if (rval < 0) | ||
2827 | kfree(sensor); | ||
2828 | |||
2829 | return rval; | ||
2830 | } | ||
2831 | |||
2832 | static int __exit smiapp_remove(struct i2c_client *client) | ||
2833 | { | ||
2834 | struct v4l2_subdev *subdev = i2c_get_clientdata(client); | ||
2835 | struct smiapp_sensor *sensor = to_smiapp_sensor(subdev); | ||
2836 | unsigned int i; | ||
2837 | |||
2838 | if (sensor->power_count) { | ||
2839 | if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) | ||
2840 | gpio_set_value(sensor->platform_data->xshutdown, 0); | ||
2841 | if (sensor->platform_data->set_xclk) | ||
2842 | sensor->platform_data->set_xclk(&sensor->src->sd, 0); | ||
2843 | else | ||
2844 | clk_disable(sensor->ext_clk); | ||
2845 | sensor->power_count = 0; | ||
2846 | } | ||
2847 | |||
2848 | if (sensor->nvm) { | ||
2849 | device_remove_file(&client->dev, &dev_attr_nvm); | ||
2850 | kfree(sensor->nvm); | ||
2851 | } | ||
2852 | |||
2853 | for (i = 0; i < sensor->ssds_used; i++) { | ||
2854 | media_entity_cleanup(&sensor->ssds[i].sd.entity); | ||
2855 | v4l2_device_unregister_subdev(&sensor->ssds[i].sd); | ||
2856 | } | ||
2857 | smiapp_free_controls(sensor); | ||
2858 | if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) | ||
2859 | gpio_free(sensor->platform_data->xshutdown); | ||
2860 | if (sensor->ext_clk) | ||
2861 | clk_put(sensor->ext_clk); | ||
2862 | if (sensor->vana) | ||
2863 | regulator_put(sensor->vana); | ||
2864 | |||
2865 | kfree(sensor); | ||
2866 | |||
2867 | return 0; | ||
2868 | } | ||
2869 | |||
2870 | static const struct i2c_device_id smiapp_id_table[] = { | ||
2871 | { SMIAPP_NAME, 0 }, | ||
2872 | { }, | ||
2873 | }; | ||
2874 | MODULE_DEVICE_TABLE(i2c, smiapp_id_table); | ||
2875 | |||
2876 | static const struct dev_pm_ops smiapp_pm_ops = { | ||
2877 | .suspend = smiapp_suspend, | ||
2878 | .resume = smiapp_resume, | ||
2879 | }; | ||
2880 | |||
2881 | static struct i2c_driver smiapp_i2c_driver = { | ||
2882 | .driver = { | ||
2883 | .name = SMIAPP_NAME, | ||
2884 | .pm = &smiapp_pm_ops, | ||
2885 | }, | ||
2886 | .probe = smiapp_probe, | ||
2887 | .remove = __exit_p(smiapp_remove), | ||
2888 | .id_table = smiapp_id_table, | ||
2889 | }; | ||
2890 | |||
2891 | module_i2c_driver(smiapp_i2c_driver); | ||
2892 | |||
2893 | MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>"); | ||
2894 | MODULE_DESCRIPTION("Generic SMIA/SMIA++ camera module driver"); | ||
2895 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/media/i2c/smiapp/smiapp-limits.c b/drivers/media/i2c/smiapp/smiapp-limits.c new file mode 100644 index 000000000000..fb2f81ad8c3b --- /dev/null +++ b/drivers/media/i2c/smiapp/smiapp-limits.c | |||
@@ -0,0 +1,132 @@ | |||
1 | /* | ||
2 | * drivers/media/i2c/smiapp/smiapp-limits.c | ||
3 | * | ||
4 | * Generic driver for SMIA/SMIA++ compliant camera modules | ||
5 | * | ||
6 | * Copyright (C) 2011--2012 Nokia Corporation | ||
7 | * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include "smiapp.h" | ||
26 | |||
27 | struct smiapp_reg_limits smiapp_reg_limits[] = { | ||
28 | { SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY, "analogue_gain_capability" }, /* 0 */ | ||
29 | { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN, "analogue_gain_code_min" }, | ||
30 | { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX, "analogue_gain_code_max" }, | ||
31 | { SMIAPP_REG_U8_THS_ZERO_MIN, "ths_zero_min" }, | ||
32 | { SMIAPP_REG_U8_TCLK_TRAIL_MIN, "tclk_trail_min" }, | ||
33 | { SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY, "integration_time_capability" }, /* 5 */ | ||
34 | { SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN, "coarse_integration_time_min" }, | ||
35 | { SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN, "coarse_integration_time_max_margin" }, | ||
36 | { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN, "fine_integration_time_min" }, | ||
37 | { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN, "fine_integration_time_max_margin" }, | ||
38 | { SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY, "digital_gain_capability" }, /* 10 */ | ||
39 | { SMIAPP_REG_U16_DIGITAL_GAIN_MIN, "digital_gain_min" }, | ||
40 | { SMIAPP_REG_U16_DIGITAL_GAIN_MAX, "digital_gain_max" }, | ||
41 | { SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ, "min_ext_clk_freq_hz" }, | ||
42 | { SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ, "max_ext_clk_freq_hz" }, | ||
43 | { SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV, "min_pre_pll_clk_div" }, /* 15 */ | ||
44 | { SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV, "max_pre_pll_clk_div" }, | ||
45 | { SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ, "min_pll_ip_freq_hz" }, | ||
46 | { SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ, "max_pll_ip_freq_hz" }, | ||
47 | { SMIAPP_REG_U16_MIN_PLL_MULTIPLIER, "min_pll_multiplier" }, | ||
48 | { SMIAPP_REG_U16_MAX_PLL_MULTIPLIER, "max_pll_multiplier" }, /* 20 */ | ||
49 | { SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ, "min_pll_op_freq_hz" }, | ||
50 | { SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ, "max_pll_op_freq_hz" }, | ||
51 | { SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV, "min_vt_sys_clk_div" }, | ||
52 | { SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV, "max_vt_sys_clk_div" }, | ||
53 | { SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ, "min_vt_sys_clk_freq_hz" }, /* 25 */ | ||
54 | { SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ, "max_vt_sys_clk_freq_hz" }, | ||
55 | { SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ, "min_vt_pix_clk_freq_hz" }, | ||
56 | { SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ, "max_vt_pix_clk_freq_hz" }, | ||
57 | { SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV, "min_vt_pix_clk_div" }, | ||
58 | { SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV, "max_vt_pix_clk_div" }, /* 30 */ | ||
59 | { SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES, "min_frame_length_lines" }, | ||
60 | { SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES, "max_frame_length_lines" }, | ||
61 | { SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK, "min_line_length_pck" }, | ||
62 | { SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK, "max_line_length_pck" }, | ||
63 | { SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK, "min_line_blanking_pck" }, /* 35 */ | ||
64 | { SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES, "min_frame_blanking_lines" }, | ||
65 | { SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE, "min_line_length_pck_step_size" }, | ||
66 | { SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV, "min_op_sys_clk_div" }, | ||
67 | { SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV, "max_op_sys_clk_div" }, | ||
68 | { SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ, "min_op_sys_clk_freq_hz" }, /* 40 */ | ||
69 | { SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ, "max_op_sys_clk_freq_hz" }, | ||
70 | { SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV, "min_op_pix_clk_div" }, | ||
71 | { SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV, "max_op_pix_clk_div" }, | ||
72 | { SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ, "min_op_pix_clk_freq_hz" }, | ||
73 | { SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ, "max_op_pix_clk_freq_hz" }, /* 45 */ | ||
74 | { SMIAPP_REG_U16_X_ADDR_MIN, "x_addr_min" }, | ||
75 | { SMIAPP_REG_U16_Y_ADDR_MIN, "y_addr_min" }, | ||
76 | { SMIAPP_REG_U16_X_ADDR_MAX, "x_addr_max" }, | ||
77 | { SMIAPP_REG_U16_Y_ADDR_MAX, "y_addr_max" }, | ||
78 | { SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE, "min_x_output_size" }, /* 50 */ | ||
79 | { SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE, "min_y_output_size" }, | ||
80 | { SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE, "max_x_output_size" }, | ||
81 | { SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE, "max_y_output_size" }, | ||
82 | { SMIAPP_REG_U16_MIN_EVEN_INC, "min_even_inc" }, | ||
83 | { SMIAPP_REG_U16_MAX_EVEN_INC, "max_even_inc" }, /* 55 */ | ||
84 | { SMIAPP_REG_U16_MIN_ODD_INC, "min_odd_inc" }, | ||
85 | { SMIAPP_REG_U16_MAX_ODD_INC, "max_odd_inc" }, | ||
86 | { SMIAPP_REG_U16_SCALING_CAPABILITY, "scaling_capability" }, | ||
87 | { SMIAPP_REG_U16_SCALER_M_MIN, "scaler_m_min" }, | ||
88 | { SMIAPP_REG_U16_SCALER_M_MAX, "scaler_m_max" }, /* 60 */ | ||
89 | { SMIAPP_REG_U16_SCALER_N_MIN, "scaler_n_min" }, | ||
90 | { SMIAPP_REG_U16_SCALER_N_MAX, "scaler_n_max" }, | ||
91 | { SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY, "spatial_sampling_capability" }, | ||
92 | { SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY, "digital_crop_capability" }, | ||
93 | { SMIAPP_REG_U16_COMPRESSION_CAPABILITY, "compression_capability" }, /* 65 */ | ||
94 | { SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY, "fifo_support_capability" }, | ||
95 | { SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY, "dphy_ctrl_capability" }, | ||
96 | { SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY, "csi_lane_mode_capability" }, | ||
97 | { SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY, "csi_signalling_mode_capability" }, | ||
98 | { SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY, "fast_standby_capability" }, /* 70 */ | ||
99 | { SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY, "cci_address_control_capability" }, | ||
100 | { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS, "max_per_lane_bitrate_1_lane_mode_mbps" }, | ||
101 | { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS, "max_per_lane_bitrate_2_lane_mode_mbps" }, | ||
102 | { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS, "max_per_lane_bitrate_3_lane_mode_mbps" }, | ||
103 | { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS, "max_per_lane_bitrate_4_lane_mode_mbps" }, /* 75 */ | ||
104 | { SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY, "temp_sensor_capability" }, | ||
105 | { SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN, "min_frame_length_lines_bin" }, | ||
106 | { SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN, "max_frame_length_lines_bin" }, | ||
107 | { SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN, "min_line_length_pck_bin" }, | ||
108 | { SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN, "max_line_length_pck_bin" }, /* 80 */ | ||
109 | { SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN, "min_line_blanking_pck_bin" }, | ||
110 | { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN, "fine_integration_time_min_bin" }, | ||
111 | { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN, "fine_integration_time_max_margin_bin" }, | ||
112 | { SMIAPP_REG_U8_BINNING_CAPABILITY, "binning_capability" }, | ||
113 | { SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY, "binning_weighting_capability" }, /* 85 */ | ||
114 | { SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY, "data_transfer_if_capability" }, | ||
115 | { SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY, "shading_correction_capability" }, | ||
116 | { SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY, "green_imbalance_capability" }, | ||
117 | { SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY, "black_level_capability" }, | ||
118 | { SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY, "module_specific_correction_capability" }, /* 90 */ | ||
119 | { SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY, "defect_correction_capability" }, | ||
120 | { SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2, "defect_correction_capability_2" }, | ||
121 | { SMIAPP_REG_U8_EDOF_CAPABILITY, "edof_capability" }, | ||
122 | { SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY, "colour_feedback_capability" }, | ||
123 | { SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY, "estimation_mode_capability" }, /* 95 */ | ||
124 | { SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY, "estimation_zone_capability" }, | ||
125 | { SMIAPP_REG_U16_CAPABILITY_TRDY_MIN, "capability_trdy_min" }, | ||
126 | { SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, "flash_mode_capability" }, | ||
127 | { SMIAPP_REG_U8_ACTUATOR_CAPABILITY, "actuator_capability" }, | ||
128 | { SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1, "bracketing_lut_capability_1" }, /* 100 */ | ||
129 | { SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2, "bracketing_lut_capability_2" }, | ||
130 | { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP, "analogue_gain_code_step" }, | ||
131 | { 0, NULL }, | ||
132 | }; | ||
diff --git a/drivers/media/i2c/smiapp/smiapp-limits.h b/drivers/media/i2c/smiapp/smiapp-limits.h new file mode 100644 index 000000000000..9ae765e23ea5 --- /dev/null +++ b/drivers/media/i2c/smiapp/smiapp-limits.h | |||
@@ -0,0 +1,128 @@ | |||
1 | /* | ||
2 | * drivers/media/i2c/smiapp/smiapp-limits.h | ||
3 | * | ||
4 | * Generic driver for SMIA/SMIA++ compliant camera modules | ||
5 | * | ||
6 | * Copyright (C) 2011--2012 Nokia Corporation | ||
7 | * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #define SMIAPP_LIMIT_ANALOGUE_GAIN_CAPABILITY 0 | ||
26 | #define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN 1 | ||
27 | #define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX 2 | ||
28 | #define SMIAPP_LIMIT_THS_ZERO_MIN 3 | ||
29 | #define SMIAPP_LIMIT_TCLK_TRAIL_MIN 4 | ||
30 | #define SMIAPP_LIMIT_INTEGRATION_TIME_CAPABILITY 5 | ||
31 | #define SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MIN 6 | ||
32 | #define SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN 7 | ||
33 | #define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN 8 | ||
34 | #define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN 9 | ||
35 | #define SMIAPP_LIMIT_DIGITAL_GAIN_CAPABILITY 10 | ||
36 | #define SMIAPP_LIMIT_DIGITAL_GAIN_MIN 11 | ||
37 | #define SMIAPP_LIMIT_DIGITAL_GAIN_MAX 12 | ||
38 | #define SMIAPP_LIMIT_MIN_EXT_CLK_FREQ_HZ 13 | ||
39 | #define SMIAPP_LIMIT_MAX_EXT_CLK_FREQ_HZ 14 | ||
40 | #define SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV 15 | ||
41 | #define SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV 16 | ||
42 | #define SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ 17 | ||
43 | #define SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ 18 | ||
44 | #define SMIAPP_LIMIT_MIN_PLL_MULTIPLIER 19 | ||
45 | #define SMIAPP_LIMIT_MAX_PLL_MULTIPLIER 20 | ||
46 | #define SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ 21 | ||
47 | #define SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ 22 | ||
48 | #define SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV 23 | ||
49 | #define SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV 24 | ||
50 | #define SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ 25 | ||
51 | #define SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ 26 | ||
52 | #define SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ 27 | ||
53 | #define SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ 28 | ||
54 | #define SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV 29 | ||
55 | #define SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV 30 | ||
56 | #define SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES 31 | ||
57 | #define SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES 32 | ||
58 | #define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK 33 | ||
59 | #define SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK 34 | ||
60 | #define SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK 35 | ||
61 | #define SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES 36 | ||
62 | #define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_STEP_SIZE 37 | ||
63 | #define SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV 38 | ||
64 | #define SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV 39 | ||
65 | #define SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ 40 | ||
66 | #define SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ 41 | ||
67 | #define SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV 42 | ||
68 | #define SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV 43 | ||
69 | #define SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ 44 | ||
70 | #define SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ 45 | ||
71 | #define SMIAPP_LIMIT_X_ADDR_MIN 46 | ||
72 | #define SMIAPP_LIMIT_Y_ADDR_MIN 47 | ||
73 | #define SMIAPP_LIMIT_X_ADDR_MAX 48 | ||
74 | #define SMIAPP_LIMIT_Y_ADDR_MAX 49 | ||
75 | #define SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE 50 | ||
76 | #define SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE 51 | ||
77 | #define SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE 52 | ||
78 | #define SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE 53 | ||
79 | #define SMIAPP_LIMIT_MIN_EVEN_INC 54 | ||
80 | #define SMIAPP_LIMIT_MAX_EVEN_INC 55 | ||
81 | #define SMIAPP_LIMIT_MIN_ODD_INC 56 | ||
82 | #define SMIAPP_LIMIT_MAX_ODD_INC 57 | ||
83 | #define SMIAPP_LIMIT_SCALING_CAPABILITY 58 | ||
84 | #define SMIAPP_LIMIT_SCALER_M_MIN 59 | ||
85 | #define SMIAPP_LIMIT_SCALER_M_MAX 60 | ||
86 | #define SMIAPP_LIMIT_SCALER_N_MIN 61 | ||
87 | #define SMIAPP_LIMIT_SCALER_N_MAX 62 | ||
88 | #define SMIAPP_LIMIT_SPATIAL_SAMPLING_CAPABILITY 63 | ||
89 | #define SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY 64 | ||
90 | #define SMIAPP_LIMIT_COMPRESSION_CAPABILITY 65 | ||
91 | #define SMIAPP_LIMIT_FIFO_SUPPORT_CAPABILITY 66 | ||
92 | #define SMIAPP_LIMIT_DPHY_CTRL_CAPABILITY 67 | ||
93 | #define SMIAPP_LIMIT_CSI_LANE_MODE_CAPABILITY 68 | ||
94 | #define SMIAPP_LIMIT_CSI_SIGNALLING_MODE_CAPABILITY 69 | ||
95 | #define SMIAPP_LIMIT_FAST_STANDBY_CAPABILITY 70 | ||
96 | #define SMIAPP_LIMIT_CCI_ADDRESS_CONTROL_CAPABILITY 71 | ||
97 | #define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS 72 | ||
98 | #define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS 73 | ||
99 | #define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS 74 | ||
100 | #define SMIAPP_LIMIT_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS 75 | ||
101 | #define SMIAPP_LIMIT_TEMP_SENSOR_CAPABILITY 76 | ||
102 | #define SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN 77 | ||
103 | #define SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN 78 | ||
104 | #define SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN 79 | ||
105 | #define SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN 80 | ||
106 | #define SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN 81 | ||
107 | #define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN 82 | ||
108 | #define SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN 83 | ||
109 | #define SMIAPP_LIMIT_BINNING_CAPABILITY 84 | ||
110 | #define SMIAPP_LIMIT_BINNING_WEIGHTING_CAPABILITY 85 | ||
111 | #define SMIAPP_LIMIT_DATA_TRANSFER_IF_CAPABILITY 86 | ||
112 | #define SMIAPP_LIMIT_SHADING_CORRECTION_CAPABILITY 87 | ||
113 | #define SMIAPP_LIMIT_GREEN_IMBALANCE_CAPABILITY 88 | ||
114 | #define SMIAPP_LIMIT_BLACK_LEVEL_CAPABILITY 89 | ||
115 | #define SMIAPP_LIMIT_MODULE_SPECIFIC_CORRECTION_CAPABILITY 90 | ||
116 | #define SMIAPP_LIMIT_DEFECT_CORRECTION_CAPABILITY 91 | ||
117 | #define SMIAPP_LIMIT_DEFECT_CORRECTION_CAPABILITY_2 92 | ||
118 | #define SMIAPP_LIMIT_EDOF_CAPABILITY 93 | ||
119 | #define SMIAPP_LIMIT_COLOUR_FEEDBACK_CAPABILITY 94 | ||
120 | #define SMIAPP_LIMIT_ESTIMATION_MODE_CAPABILITY 95 | ||
121 | #define SMIAPP_LIMIT_ESTIMATION_ZONE_CAPABILITY 96 | ||
122 | #define SMIAPP_LIMIT_CAPABILITY_TRDY_MIN 97 | ||
123 | #define SMIAPP_LIMIT_FLASH_MODE_CAPABILITY 98 | ||
124 | #define SMIAPP_LIMIT_ACTUATOR_CAPABILITY 99 | ||
125 | #define SMIAPP_LIMIT_BRACKETING_LUT_CAPABILITY_1 100 | ||
126 | #define SMIAPP_LIMIT_BRACKETING_LUT_CAPABILITY_2 101 | ||
127 | #define SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP 102 | ||
128 | #define SMIAPP_LIMIT_LAST 103 | ||
diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c new file mode 100644 index 000000000000..cf048128367c --- /dev/null +++ b/drivers/media/i2c/smiapp/smiapp-quirk.c | |||
@@ -0,0 +1,306 @@ | |||
1 | /* | ||
2 | * drivers/media/i2c/smiapp/smiapp-quirk.c | ||
3 | * | ||
4 | * Generic driver for SMIA/SMIA++ compliant camera modules | ||
5 | * | ||
6 | * Copyright (C) 2011--2012 Nokia Corporation | ||
7 | * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/delay.h> | ||
26 | |||
27 | #include "smiapp.h" | ||
28 | |||
29 | static int smiapp_write_8(struct smiapp_sensor *sensor, u16 reg, u8 val) | ||
30 | { | ||
31 | return smiapp_write(sensor, (SMIA_REG_8BIT << 16) | reg, val); | ||
32 | } | ||
33 | |||
34 | static int smiapp_write_8s(struct smiapp_sensor *sensor, | ||
35 | struct smiapp_reg_8 *regs, int len) | ||
36 | { | ||
37 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
38 | int rval; | ||
39 | |||
40 | for (; len > 0; len--, regs++) { | ||
41 | rval = smiapp_write_8(sensor, regs->reg, regs->val); | ||
42 | if (rval < 0) { | ||
43 | dev_err(&client->dev, | ||
44 | "error %d writing reg 0x%4.4x, val 0x%2.2x", | ||
45 | rval, regs->reg, regs->val); | ||
46 | return rval; | ||
47 | } | ||
48 | } | ||
49 | |||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | void smiapp_replace_limit(struct smiapp_sensor *sensor, | ||
54 | u32 limit, u32 val) | ||
55 | { | ||
56 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
57 | |||
58 | dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" = %d, 0x%x\n", | ||
59 | smiapp_reg_limits[limit].addr, | ||
60 | smiapp_reg_limits[limit].what, val, val); | ||
61 | sensor->limits[limit] = val; | ||
62 | } | ||
63 | |||
64 | int smiapp_replace_limit_at(struct smiapp_sensor *sensor, | ||
65 | u32 reg, u32 val) | ||
66 | { | ||
67 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
68 | int i; | ||
69 | |||
70 | for (i = 0; smiapp_reg_limits[i].addr; i++) { | ||
71 | if ((smiapp_reg_limits[i].addr & 0xffff) != reg) | ||
72 | continue; | ||
73 | |||
74 | smiapp_replace_limit(sensor, i, val); | ||
75 | |||
76 | return 0; | ||
77 | } | ||
78 | |||
79 | dev_dbg(&client->dev, "quirk: bad register 0x%4.4x\n", reg); | ||
80 | |||
81 | return -EINVAL; | ||
82 | } | ||
83 | |||
84 | bool smiapp_quirk_reg(struct smiapp_sensor *sensor, | ||
85 | u32 reg, u32 *val) | ||
86 | { | ||
87 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
88 | const struct smia_reg *sreg; | ||
89 | |||
90 | if (!sensor->minfo.quirk) | ||
91 | return false; | ||
92 | |||
93 | sreg = sensor->minfo.quirk->regs; | ||
94 | |||
95 | if (!sreg) | ||
96 | return false; | ||
97 | |||
98 | while (sreg->type) { | ||
99 | u16 type = reg >> 16; | ||
100 | u16 reg16 = reg; | ||
101 | |||
102 | if (sreg->type != type || sreg->reg != reg16) { | ||
103 | sreg++; | ||
104 | continue; | ||
105 | } | ||
106 | |||
107 | switch ((u8)type) { | ||
108 | case SMIA_REG_8BIT: | ||
109 | dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%2.2x\n", | ||
110 | reg, sreg->val); | ||
111 | break; | ||
112 | case SMIA_REG_16BIT: | ||
113 | dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%4.4x\n", | ||
114 | reg, sreg->val); | ||
115 | break; | ||
116 | case SMIA_REG_32BIT: | ||
117 | dev_dbg(&client->dev, "quirk: 0x%8.8x: 0x%8.8x\n", | ||
118 | reg, sreg->val); | ||
119 | break; | ||
120 | } | ||
121 | |||
122 | *val = sreg->val; | ||
123 | |||
124 | return true; | ||
125 | } | ||
126 | |||
127 | return false; | ||
128 | } | ||
129 | |||
130 | static int jt8ew9_limits(struct smiapp_sensor *sensor) | ||
131 | { | ||
132 | if (sensor->minfo.revision_number_major < 0x03) | ||
133 | sensor->frame_skip = 1; | ||
134 | |||
135 | /* Below 24 gain doesn't have effect at all, */ | ||
136 | /* but ~59 is needed for full dynamic range */ | ||
137 | smiapp_replace_limit(sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN, 59); | ||
138 | smiapp_replace_limit( | ||
139 | sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX, 6000); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | static int jt8ew9_post_poweron(struct smiapp_sensor *sensor) | ||
145 | { | ||
146 | struct smiapp_reg_8 regs[] = { | ||
147 | { 0x30a3, 0xd8 }, /* Output port control : LVDS ports only */ | ||
148 | { 0x30ae, 0x00 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */ | ||
149 | { 0x30af, 0xd0 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */ | ||
150 | { 0x322d, 0x04 }, /* Adjusting Processing Image Size to Scaler Toshiba Recommendation Setting */ | ||
151 | { 0x3255, 0x0f }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */ | ||
152 | { 0x3256, 0x15 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */ | ||
153 | { 0x3258, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */ | ||
154 | { 0x3259, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */ | ||
155 | { 0x325f, 0x7c }, /* Analog Gain Control Toshiba Recommendation Setting */ | ||
156 | { 0x3302, 0x06 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ | ||
157 | { 0x3304, 0x00 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ | ||
158 | { 0x3307, 0x22 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ | ||
159 | { 0x3308, 0x8d }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */ | ||
160 | { 0x331e, 0x0f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ | ||
161 | { 0x3320, 0x30 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ | ||
162 | { 0x3321, 0x11 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ | ||
163 | { 0x3322, 0x98 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ | ||
164 | { 0x3323, 0x64 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ | ||
165 | { 0x3325, 0x83 }, /* Read Out Timing Control Toshiba Recommendation Setting */ | ||
166 | { 0x3330, 0x18 }, /* Read Out Timing Control Toshiba Recommendation Setting */ | ||
167 | { 0x333c, 0x01 }, /* Read Out Timing Control Toshiba Recommendation Setting */ | ||
168 | { 0x3345, 0x2f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */ | ||
169 | { 0x33de, 0x38 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */ | ||
170 | /* Taken from v03. No idea what the rest are. */ | ||
171 | { 0x32e0, 0x05 }, | ||
172 | { 0x32e1, 0x05 }, | ||
173 | { 0x32e2, 0x04 }, | ||
174 | { 0x32e5, 0x04 }, | ||
175 | { 0x32e6, 0x04 }, | ||
176 | |||
177 | }; | ||
178 | |||
179 | return smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs)); | ||
180 | } | ||
181 | |||
182 | const struct smiapp_quirk smiapp_jt8ew9_quirk = { | ||
183 | .limits = jt8ew9_limits, | ||
184 | .post_poweron = jt8ew9_post_poweron, | ||
185 | }; | ||
186 | |||
187 | static int imx125es_post_poweron(struct smiapp_sensor *sensor) | ||
188 | { | ||
189 | /* Taken from v02. No idea what the other two are. */ | ||
190 | struct smiapp_reg_8 regs[] = { | ||
191 | /* | ||
192 | * 0x3302: clk during frame blanking: | ||
193 | * 0x00 - HS mode, 0x01 - LP11 | ||
194 | */ | ||
195 | { 0x3302, 0x01 }, | ||
196 | { 0x302d, 0x00 }, | ||
197 | { 0x3b08, 0x8c }, | ||
198 | }; | ||
199 | |||
200 | return smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs)); | ||
201 | } | ||
202 | |||
203 | const struct smiapp_quirk smiapp_imx125es_quirk = { | ||
204 | .post_poweron = imx125es_post_poweron, | ||
205 | }; | ||
206 | |||
207 | static int jt8ev1_limits(struct smiapp_sensor *sensor) | ||
208 | { | ||
209 | smiapp_replace_limit(sensor, SMIAPP_LIMIT_X_ADDR_MAX, 4271); | ||
210 | smiapp_replace_limit(sensor, | ||
211 | SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN, 184); | ||
212 | |||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int jt8ev1_post_poweron(struct smiapp_sensor *sensor) | ||
217 | { | ||
218 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
219 | int rval; | ||
220 | |||
221 | struct smiapp_reg_8 regs[] = { | ||
222 | { 0x3031, 0xcd }, /* For digital binning (EQ_MONI) */ | ||
223 | { 0x30a3, 0xd0 }, /* FLASH STROBE enable */ | ||
224 | { 0x3237, 0x00 }, /* For control of pulse timing for ADC */ | ||
225 | { 0x3238, 0x43 }, | ||
226 | { 0x3301, 0x06 }, /* For analog bias for sensor */ | ||
227 | { 0x3302, 0x06 }, | ||
228 | { 0x3304, 0x00 }, | ||
229 | { 0x3305, 0x88 }, | ||
230 | { 0x332a, 0x14 }, | ||
231 | { 0x332c, 0x6b }, | ||
232 | { 0x3336, 0x01 }, | ||
233 | { 0x333f, 0x1f }, | ||
234 | { 0x3355, 0x00 }, | ||
235 | { 0x3356, 0x20 }, | ||
236 | { 0x33bf, 0x20 }, /* Adjust the FBC speed */ | ||
237 | { 0x33c9, 0x20 }, | ||
238 | { 0x33ce, 0x30 }, /* Adjust the parameter for logic function */ | ||
239 | { 0x33cf, 0xec }, /* For Black sun */ | ||
240 | { 0x3328, 0x80 }, /* Ugh. No idea what's this. */ | ||
241 | }; | ||
242 | |||
243 | struct smiapp_reg_8 regs_96[] = { | ||
244 | { 0x30ae, 0x00 }, /* For control of ADC clock */ | ||
245 | { 0x30af, 0xd0 }, | ||
246 | { 0x30b0, 0x01 }, | ||
247 | }; | ||
248 | |||
249 | rval = smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs)); | ||
250 | if (rval < 0) | ||
251 | return rval; | ||
252 | |||
253 | switch (sensor->platform_data->ext_clk) { | ||
254 | case 9600000: | ||
255 | return smiapp_write_8s(sensor, regs_96, | ||
256 | ARRAY_SIZE(regs_96)); | ||
257 | default: | ||
258 | dev_warn(&client->dev, "no MSRs for %d Hz ext_clk\n", | ||
259 | sensor->platform_data->ext_clk); | ||
260 | return 0; | ||
261 | } | ||
262 | } | ||
263 | |||
264 | static int jt8ev1_pre_streamon(struct smiapp_sensor *sensor) | ||
265 | { | ||
266 | return smiapp_write_8(sensor, 0x3328, 0x00); | ||
267 | } | ||
268 | |||
269 | static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor) | ||
270 | { | ||
271 | int rval; | ||
272 | |||
273 | /* Workaround: allows fast standby to work properly */ | ||
274 | rval = smiapp_write_8(sensor, 0x3205, 0x04); | ||
275 | if (rval < 0) | ||
276 | return rval; | ||
277 | |||
278 | /* Wait for 1 ms + one line => 2 ms is likely enough */ | ||
279 | usleep_range(2000, 2000); | ||
280 | |||
281 | /* Restore it */ | ||
282 | rval = smiapp_write_8(sensor, 0x3205, 0x00); | ||
283 | if (rval < 0) | ||
284 | return rval; | ||
285 | |||
286 | return smiapp_write_8(sensor, 0x3328, 0x80); | ||
287 | } | ||
288 | |||
289 | const struct smiapp_quirk smiapp_jt8ev1_quirk = { | ||
290 | .limits = jt8ev1_limits, | ||
291 | .post_poweron = jt8ev1_post_poweron, | ||
292 | .pre_streamon = jt8ev1_pre_streamon, | ||
293 | .post_streamoff = jt8ev1_post_streamoff, | ||
294 | .flags = SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE, | ||
295 | }; | ||
296 | |||
297 | static int tcm8500md_limits(struct smiapp_sensor *sensor) | ||
298 | { | ||
299 | smiapp_replace_limit(sensor, SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ, 2700000); | ||
300 | |||
301 | return 0; | ||
302 | } | ||
303 | |||
304 | const struct smiapp_quirk smiapp_tcm8500md_quirk = { | ||
305 | .limits = tcm8500md_limits, | ||
306 | }; | ||
diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.h b/drivers/media/i2c/smiapp/smiapp-quirk.h new file mode 100644 index 000000000000..86fd3e8bfb0f --- /dev/null +++ b/drivers/media/i2c/smiapp/smiapp-quirk.h | |||
@@ -0,0 +1,83 @@ | |||
1 | /* | ||
2 | * drivers/media/i2c/smiapp/smiapp-quirk.h | ||
3 | * | ||
4 | * Generic driver for SMIA/SMIA++ compliant camera modules | ||
5 | * | ||
6 | * Copyright (C) 2011--2012 Nokia Corporation | ||
7 | * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __SMIAPP_QUIRK__ | ||
26 | #define __SMIAPP_QUIRK__ | ||
27 | |||
28 | struct smiapp_sensor; | ||
29 | |||
30 | /** | ||
31 | * struct smiapp_quirk - quirks for sensors that deviate from SMIA++ standard | ||
32 | * | ||
33 | * @limits: Replace sensor->limits with values which can't be read from | ||
34 | * sensor registers. Called the first time the sensor is powered up. | ||
35 | * @post_poweron: Called always after the sensor has been fully powered on. | ||
36 | * @pre_streamon: Called just before streaming is enabled. | ||
37 | * @post_streamon: Called right after stopping streaming. | ||
38 | */ | ||
39 | struct smiapp_quirk { | ||
40 | int (*limits)(struct smiapp_sensor *sensor); | ||
41 | int (*post_poweron)(struct smiapp_sensor *sensor); | ||
42 | int (*pre_streamon)(struct smiapp_sensor *sensor); | ||
43 | int (*post_streamoff)(struct smiapp_sensor *sensor); | ||
44 | const struct smia_reg *regs; | ||
45 | unsigned long flags; | ||
46 | }; | ||
47 | |||
48 | /* op pix clock is for all lanes in total normally */ | ||
49 | #define SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0) | ||
50 | #define SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY (1 << 1) | ||
51 | |||
52 | struct smiapp_reg_8 { | ||
53 | u16 reg; | ||
54 | u8 val; | ||
55 | }; | ||
56 | |||
57 | void smiapp_replace_limit(struct smiapp_sensor *sensor, | ||
58 | u32 limit, u32 val); | ||
59 | bool smiapp_quirk_reg(struct smiapp_sensor *sensor, | ||
60 | u32 reg, u32 *val); | ||
61 | |||
62 | #define SMIAPP_MK_QUIRK_REG(_reg, _val) \ | ||
63 | { \ | ||
64 | .type = (_reg >> 16), \ | ||
65 | .reg = (u16)_reg, \ | ||
66 | .val = _val, \ | ||
67 | } | ||
68 | |||
69 | #define smiapp_call_quirk(_sensor, _quirk, ...) \ | ||
70 | (_sensor->minfo.quirk && \ | ||
71 | _sensor->minfo.quirk->_quirk ? \ | ||
72 | _sensor->minfo.quirk->_quirk(_sensor, ##__VA_ARGS__) : 0) | ||
73 | |||
74 | #define smiapp_needs_quirk(_sensor, _quirk) \ | ||
75 | (_sensor->minfo.quirk ? \ | ||
76 | _sensor->minfo.quirk->flags & _quirk : 0) | ||
77 | |||
78 | extern const struct smiapp_quirk smiapp_jt8ev1_quirk; | ||
79 | extern const struct smiapp_quirk smiapp_imx125es_quirk; | ||
80 | extern const struct smiapp_quirk smiapp_jt8ew9_quirk; | ||
81 | extern const struct smiapp_quirk smiapp_tcm8500md_quirk; | ||
82 | |||
83 | #endif /* __SMIAPP_QUIRK__ */ | ||
diff --git a/drivers/media/i2c/smiapp/smiapp-reg-defs.h b/drivers/media/i2c/smiapp/smiapp-reg-defs.h new file mode 100644 index 000000000000..defa7c5adebf --- /dev/null +++ b/drivers/media/i2c/smiapp/smiapp-reg-defs.h | |||
@@ -0,0 +1,503 @@ | |||
1 | /* | ||
2 | * drivers/media/i2c/smiapp/smiapp-reg-defs.h | ||
3 | * | ||
4 | * Generic driver for SMIA/SMIA++ compliant camera modules | ||
5 | * | ||
6 | * Copyright (C) 2011--2012 Nokia Corporation | ||
7 | * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | #define SMIAPP_REG_MK_U8(r) ((SMIA_REG_8BIT << 16) | (r)) | ||
25 | #define SMIAPP_REG_MK_U16(r) ((SMIA_REG_16BIT << 16) | (r)) | ||
26 | #define SMIAPP_REG_MK_U32(r) ((SMIA_REG_32BIT << 16) | (r)) | ||
27 | |||
28 | #define SMIAPP_REG_MK_F32(r) (SMIA_REG_FLAG_FLOAT | (SMIA_REG_32BIT << 16) | (r)) | ||
29 | |||
30 | #define SMIAPP_REG_U16_MODEL_ID SMIAPP_REG_MK_U16(0x0000) | ||
31 | #define SMIAPP_REG_U8_REVISION_NUMBER_MAJOR SMIAPP_REG_MK_U8(0x0002) | ||
32 | #define SMIAPP_REG_U8_MANUFACTURER_ID SMIAPP_REG_MK_U8(0x0003) | ||
33 | #define SMIAPP_REG_U8_SMIA_VERSION SMIAPP_REG_MK_U8(0x0004) | ||
34 | #define SMIAPP_REG_U8_FRAME_COUNT SMIAPP_REG_MK_U8(0x0005) | ||
35 | #define SMIAPP_REG_U8_PIXEL_ORDER SMIAPP_REG_MK_U8(0x0006) | ||
36 | #define SMIAPP_REG_U16_DATA_PEDESTAL SMIAPP_REG_MK_U16(0x0008) | ||
37 | #define SMIAPP_REG_U8_PIXEL_DEPTH SMIAPP_REG_MK_U8(0x000c) | ||
38 | #define SMIAPP_REG_U8_REVISION_NUMBER_MINOR SMIAPP_REG_MK_U8(0x0010) | ||
39 | #define SMIAPP_REG_U8_SMIAPP_VERSION SMIAPP_REG_MK_U8(0x0011) | ||
40 | #define SMIAPP_REG_U8_MODULE_DATE_YEAR SMIAPP_REG_MK_U8(0x0012) | ||
41 | #define SMIAPP_REG_U8_MODULE_DATE_MONTH SMIAPP_REG_MK_U8(0x0013) | ||
42 | #define SMIAPP_REG_U8_MODULE_DATE_DAY SMIAPP_REG_MK_U8(0x0014) | ||
43 | #define SMIAPP_REG_U8_MODULE_DATE_PHASE SMIAPP_REG_MK_U8(0x0015) | ||
44 | #define SMIAPP_REG_U16_SENSOR_MODEL_ID SMIAPP_REG_MK_U16(0x0016) | ||
45 | #define SMIAPP_REG_U8_SENSOR_REVISION_NUMBER SMIAPP_REG_MK_U8(0x0018) | ||
46 | #define SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID SMIAPP_REG_MK_U8(0x0019) | ||
47 | #define SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION SMIAPP_REG_MK_U8(0x001a) | ||
48 | #define SMIAPP_REG_U32_SERIAL_NUMBER SMIAPP_REG_MK_U32(0x001c) | ||
49 | #define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE SMIAPP_REG_MK_U8(0x0040) | ||
50 | #define SMIAPP_REG_U8_FRAME_FORMAT_MODEL_SUBTYPE SMIAPP_REG_MK_U8(0x0041) | ||
51 | #define SMIAPP_REG_U16_FRAME_FORMAT_DESCRIPTOR_2(n) SMIAPP_REG_MK_U16(0x0042 + ((n) << 1)) /* 0 <= n <= 14 */ | ||
52 | #define SMIAPP_REG_U32_FRAME_FORMAT_DESCRIPTOR_4(n) SMIAPP_REG_MK_U32(0x0060 + ((n) << 2)) /* 0 <= n <= 7 */ | ||
53 | #define SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY SMIAPP_REG_MK_U16(0x0080) | ||
54 | #define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN SMIAPP_REG_MK_U16(0x0084) | ||
55 | #define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX SMIAPP_REG_MK_U16(0x0086) | ||
56 | #define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP SMIAPP_REG_MK_U16(0x0088) | ||
57 | #define SMIAPP_REG_U16_ANALOGUE_GAIN_TYPE SMIAPP_REG_MK_U16(0x008a) | ||
58 | #define SMIAPP_REG_U16_ANALOGUE_GAIN_M0 SMIAPP_REG_MK_U16(0x008c) | ||
59 | #define SMIAPP_REG_U16_ANALOGUE_GAIN_C0 SMIAPP_REG_MK_U16(0x008e) | ||
60 | #define SMIAPP_REG_U16_ANALOGUE_GAIN_M1 SMIAPP_REG_MK_U16(0x0090) | ||
61 | #define SMIAPP_REG_U16_ANALOGUE_GAIN_C1 SMIAPP_REG_MK_U16(0x0092) | ||
62 | #define SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE SMIAPP_REG_MK_U8(0x00c0) | ||
63 | #define SMIAPP_REG_U8_DATA_FORMAT_MODEL_SUBTYPE SMIAPP_REG_MK_U8(0x00c1) | ||
64 | #define SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(n) SMIAPP_REG_MK_U16(0x00c2 + ((n) << 1)) | ||
65 | #define SMIAPP_REG_U8_MODE_SELECT SMIAPP_REG_MK_U8(0x0100) | ||
66 | #define SMIAPP_REG_U8_IMAGE_ORIENTATION SMIAPP_REG_MK_U8(0x0101) | ||
67 | #define SMIAPP_REG_U8_SOFTWARE_RESET SMIAPP_REG_MK_U8(0x0103) | ||
68 | #define SMIAPP_REG_U8_GROUPED_PARAMETER_HOLD SMIAPP_REG_MK_U8(0x0104) | ||
69 | #define SMIAPP_REG_U8_MASK_CORRUPTED_FRAMES SMIAPP_REG_MK_U8(0x0105) | ||
70 | #define SMIAPP_REG_U8_FAST_STANDBY_CTRL SMIAPP_REG_MK_U8(0x0106) | ||
71 | #define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL SMIAPP_REG_MK_U8(0x0107) | ||
72 | #define SMIAPP_REG_U8_2ND_CCI_IF_CONTROL SMIAPP_REG_MK_U8(0x0108) | ||
73 | #define SMIAPP_REG_U8_2ND_CCI_ADDRESS_CONTROL SMIAPP_REG_MK_U8(0x0109) | ||
74 | #define SMIAPP_REG_U8_CSI_CHANNEL_IDENTIFIER SMIAPP_REG_MK_U8(0x0110) | ||
75 | #define SMIAPP_REG_U8_CSI_SIGNALLING_MODE SMIAPP_REG_MK_U8(0x0111) | ||
76 | #define SMIAPP_REG_U16_CSI_DATA_FORMAT SMIAPP_REG_MK_U16(0x0112) | ||
77 | #define SMIAPP_REG_U8_CSI_LANE_MODE SMIAPP_REG_MK_U8(0x0114) | ||
78 | #define SMIAPP_REG_U8_CSI2_10_TO_8_DT SMIAPP_REG_MK_U8(0x0115) | ||
79 | #define SMIAPP_REG_U8_CSI2_10_TO_7_DT SMIAPP_REG_MK_U8(0x0116) | ||
80 | #define SMIAPP_REG_U8_CSI2_10_TO_6_DT SMIAPP_REG_MK_U8(0x0117) | ||
81 | #define SMIAPP_REG_U8_CSI2_12_TO_8_DT SMIAPP_REG_MK_U8(0x0118) | ||
82 | #define SMIAPP_REG_U8_CSI2_12_TO_7_DT SMIAPP_REG_MK_U8(0x0119) | ||
83 | #define SMIAPP_REG_U8_CSI2_12_TO_6_DT SMIAPP_REG_MK_U8(0x011a) | ||
84 | #define SMIAPP_REG_U8_CSI2_14_TO_10_DT SMIAPP_REG_MK_U8(0x011b) | ||
85 | #define SMIAPP_REG_U8_CSI2_14_TO_8_DT SMIAPP_REG_MK_U8(0x011c) | ||
86 | #define SMIAPP_REG_U8_CSI2_16_TO_10_DT SMIAPP_REG_MK_U8(0x011d) | ||
87 | #define SMIAPP_REG_U8_CSI2_16_TO_8_DT SMIAPP_REG_MK_U8(0x011e) | ||
88 | #define SMIAPP_REG_U8_GAIN_MODE SMIAPP_REG_MK_U8(0x0120) | ||
89 | #define SMIAPP_REG_U16_VANA_VOLTAGE SMIAPP_REG_MK_U16(0x0130) | ||
90 | #define SMIAPP_REG_U16_VDIG_VOLTAGE SMIAPP_REG_MK_U16(0x0132) | ||
91 | #define SMIAPP_REG_U16_VIO_VOLTAGE SMIAPP_REG_MK_U16(0x0134) | ||
92 | #define SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ SMIAPP_REG_MK_U16(0x0136) | ||
93 | #define SMIAPP_REG_U8_TEMP_SENSOR_CONTROL SMIAPP_REG_MK_U8(0x0138) | ||
94 | #define SMIAPP_REG_U8_TEMP_SENSOR_MODE SMIAPP_REG_MK_U8(0x0139) | ||
95 | #define SMIAPP_REG_U8_TEMP_SENSOR_OUTPUT SMIAPP_REG_MK_U8(0x013a) | ||
96 | #define SMIAPP_REG_U16_FINE_INTEGRATION_TIME SMIAPP_REG_MK_U16(0x0200) | ||
97 | #define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME SMIAPP_REG_MK_U16(0x0202) | ||
98 | #define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL SMIAPP_REG_MK_U16(0x0204) | ||
99 | #define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENR SMIAPP_REG_MK_U16(0x0206) | ||
100 | #define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_RED SMIAPP_REG_MK_U16(0x0208) | ||
101 | #define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_BLUE SMIAPP_REG_MK_U16(0x020a) | ||
102 | #define SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GREENB SMIAPP_REG_MK_U16(0x020c) | ||
103 | #define SMIAPP_REG_U16_DIGITAL_GAIN_GREENR SMIAPP_REG_MK_U16(0x020e) | ||
104 | #define SMIAPP_REG_U16_DIGITAL_GAIN_RED SMIAPP_REG_MK_U16(0x0210) | ||
105 | #define SMIAPP_REG_U16_DIGITAL_GAIN_BLUE SMIAPP_REG_MK_U16(0x0212) | ||
106 | #define SMIAPP_REG_U16_DIGITAL_GAIN_GREENB SMIAPP_REG_MK_U16(0x0214) | ||
107 | #define SMIAPP_REG_U16_VT_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x0300) | ||
108 | #define SMIAPP_REG_U16_VT_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x0302) | ||
109 | #define SMIAPP_REG_U16_PRE_PLL_CLK_DIV SMIAPP_REG_MK_U16(0x0304) | ||
110 | #define SMIAPP_REG_U16_PLL_MULTIPLIER SMIAPP_REG_MK_U16(0x0306) | ||
111 | #define SMIAPP_REG_U16_OP_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x0308) | ||
112 | #define SMIAPP_REG_U16_OP_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x030a) | ||
113 | #define SMIAPP_REG_U16_FRAME_LENGTH_LINES SMIAPP_REG_MK_U16(0x0340) | ||
114 | #define SMIAPP_REG_U16_LINE_LENGTH_PCK SMIAPP_REG_MK_U16(0x0342) | ||
115 | #define SMIAPP_REG_U16_X_ADDR_START SMIAPP_REG_MK_U16(0x0344) | ||
116 | #define SMIAPP_REG_U16_Y_ADDR_START SMIAPP_REG_MK_U16(0x0346) | ||
117 | #define SMIAPP_REG_U16_X_ADDR_END SMIAPP_REG_MK_U16(0x0348) | ||
118 | #define SMIAPP_REG_U16_Y_ADDR_END SMIAPP_REG_MK_U16(0x034a) | ||
119 | #define SMIAPP_REG_U16_X_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x034c) | ||
120 | #define SMIAPP_REG_U16_Y_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x034e) | ||
121 | #define SMIAPP_REG_U16_X_EVEN_INC SMIAPP_REG_MK_U16(0x0380) | ||
122 | #define SMIAPP_REG_U16_X_ODD_INC SMIAPP_REG_MK_U16(0x0382) | ||
123 | #define SMIAPP_REG_U16_Y_EVEN_INC SMIAPP_REG_MK_U16(0x0384) | ||
124 | #define SMIAPP_REG_U16_Y_ODD_INC SMIAPP_REG_MK_U16(0x0386) | ||
125 | #define SMIAPP_REG_U16_SCALING_MODE SMIAPP_REG_MK_U16(0x0400) | ||
126 | #define SMIAPP_REG_U16_SPATIAL_SAMPLING SMIAPP_REG_MK_U16(0x0402) | ||
127 | #define SMIAPP_REG_U16_SCALE_M SMIAPP_REG_MK_U16(0x0404) | ||
128 | #define SMIAPP_REG_U16_SCALE_N SMIAPP_REG_MK_U16(0x0406) | ||
129 | #define SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET SMIAPP_REG_MK_U16(0x0408) | ||
130 | #define SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET SMIAPP_REG_MK_U16(0x040a) | ||
131 | #define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH SMIAPP_REG_MK_U16(0x040c) | ||
132 | #define SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT SMIAPP_REG_MK_U16(0x040e) | ||
133 | #define SMIAPP_REG_U16_COMPRESSION_MODE SMIAPP_REG_MK_U16(0x0500) | ||
134 | #define SMIAPP_REG_U16_TEST_PATTERN_MODE SMIAPP_REG_MK_U16(0x0600) | ||
135 | #define SMIAPP_REG_U16_TEST_DATA_RED SMIAPP_REG_MK_U16(0x0602) | ||
136 | #define SMIAPP_REG_U16_TEST_DATA_GREENR SMIAPP_REG_MK_U16(0x0604) | ||
137 | #define SMIAPP_REG_U16_TEST_DATA_BLUE SMIAPP_REG_MK_U16(0x0606) | ||
138 | #define SMIAPP_REG_U16_TEST_DATA_GREENB SMIAPP_REG_MK_U16(0x0608) | ||
139 | #define SMIAPP_REG_U16_HORIZONTAL_CURSOR_WIDTH SMIAPP_REG_MK_U16(0x060a) | ||
140 | #define SMIAPP_REG_U16_HORIZONTAL_CURSOR_POSITION SMIAPP_REG_MK_U16(0x060c) | ||
141 | #define SMIAPP_REG_U16_VERTICAL_CURSOR_WIDTH SMIAPP_REG_MK_U16(0x060e) | ||
142 | #define SMIAPP_REG_U16_VERTICAL_CURSOR_POSITION SMIAPP_REG_MK_U16(0x0610) | ||
143 | #define SMIAPP_REG_U16_FIFO_WATER_MARK_PIXELS SMIAPP_REG_MK_U16(0x0700) | ||
144 | #define SMIAPP_REG_U8_TCLK_POST SMIAPP_REG_MK_U8(0x0800) | ||
145 | #define SMIAPP_REG_U8_THS_PREPARE SMIAPP_REG_MK_U8(0x0801) | ||
146 | #define SMIAPP_REG_U8_THS_ZERO_MIN SMIAPP_REG_MK_U8(0x0802) | ||
147 | #define SMIAPP_REG_U8_THS_TRAIL SMIAPP_REG_MK_U8(0x0803) | ||
148 | #define SMIAPP_REG_U8_TCLK_TRAIL_MIN SMIAPP_REG_MK_U8(0x0804) | ||
149 | #define SMIAPP_REG_U8_TCLK_PREPARE SMIAPP_REG_MK_U8(0x0805) | ||
150 | #define SMIAPP_REG_U8_TCLK_ZERO SMIAPP_REG_MK_U8(0x0806) | ||
151 | #define SMIAPP_REG_U8_TLPX SMIAPP_REG_MK_U8(0x0807) | ||
152 | #define SMIAPP_REG_U8_DPHY_CTRL SMIAPP_REG_MK_U8(0x0808) | ||
153 | #define SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS SMIAPP_REG_MK_U32(0x0820) | ||
154 | #define SMIAPP_REG_U8_BINNING_MODE SMIAPP_REG_MK_U8(0x0900) | ||
155 | #define SMIAPP_REG_U8_BINNING_TYPE SMIAPP_REG_MK_U8(0x0901) | ||
156 | #define SMIAPP_REG_U8_BINNING_WEIGHTING SMIAPP_REG_MK_U8(0x0902) | ||
157 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL SMIAPP_REG_MK_U8(0x0a00) | ||
158 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS SMIAPP_REG_MK_U8(0x0a01) | ||
159 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT SMIAPP_REG_MK_U8(0x0a02) | ||
160 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 SMIAPP_REG_MK_U8(0x0a04) | ||
161 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_1 SMIAPP_REG_MK_U8(0x0a05) | ||
162 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_2 SMIAPP_REG_MK_U8(0x0a06) | ||
163 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_3 SMIAPP_REG_MK_U8(0x0a07) | ||
164 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_4 SMIAPP_REG_MK_U8(0x0a08) | ||
165 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_5 SMIAPP_REG_MK_U8(0x0a09) | ||
166 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_12 SMIAPP_REG_MK_U8(0x0a10) | ||
167 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_13 SMIAPP_REG_MK_U8(0x0a11) | ||
168 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_14 SMIAPP_REG_MK_U8(0x0a12) | ||
169 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_15 SMIAPP_REG_MK_U8(0x0a13) | ||
170 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_16 SMIAPP_REG_MK_U8(0x0a14) | ||
171 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_17 SMIAPP_REG_MK_U8(0x0a15) | ||
172 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_18 SMIAPP_REG_MK_U8(0x0a16) | ||
173 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_19 SMIAPP_REG_MK_U8(0x0a17) | ||
174 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_20 SMIAPP_REG_MK_U8(0x0a18) | ||
175 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_21 SMIAPP_REG_MK_U8(0x0a19) | ||
176 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_22 SMIAPP_REG_MK_U8(0x0a1a) | ||
177 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_23 SMIAPP_REG_MK_U8(0x0a1b) | ||
178 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_24 SMIAPP_REG_MK_U8(0x0a1c) | ||
179 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_25 SMIAPP_REG_MK_U8(0x0a1d) | ||
180 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_26 SMIAPP_REG_MK_U8(0x0a1e) | ||
181 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_27 SMIAPP_REG_MK_U8(0x0a1f) | ||
182 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_28 SMIAPP_REG_MK_U8(0x0a20) | ||
183 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_29 SMIAPP_REG_MK_U8(0x0a21) | ||
184 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_30 SMIAPP_REG_MK_U8(0x0a22) | ||
185 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_31 SMIAPP_REG_MK_U8(0x0a23) | ||
186 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_32 SMIAPP_REG_MK_U8(0x0a24) | ||
187 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_33 SMIAPP_REG_MK_U8(0x0a25) | ||
188 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_34 SMIAPP_REG_MK_U8(0x0a26) | ||
189 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_35 SMIAPP_REG_MK_U8(0x0a27) | ||
190 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_36 SMIAPP_REG_MK_U8(0x0a28) | ||
191 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_37 SMIAPP_REG_MK_U8(0x0a29) | ||
192 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_38 SMIAPP_REG_MK_U8(0x0a2a) | ||
193 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_39 SMIAPP_REG_MK_U8(0x0a2b) | ||
194 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_40 SMIAPP_REG_MK_U8(0x0a2c) | ||
195 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_41 SMIAPP_REG_MK_U8(0x0a2d) | ||
196 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_42 SMIAPP_REG_MK_U8(0x0a2e) | ||
197 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_43 SMIAPP_REG_MK_U8(0x0a2f) | ||
198 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_44 SMIAPP_REG_MK_U8(0x0a30) | ||
199 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_45 SMIAPP_REG_MK_U8(0x0a31) | ||
200 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_46 SMIAPP_REG_MK_U8(0x0a32) | ||
201 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_47 SMIAPP_REG_MK_U8(0x0a33) | ||
202 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_48 SMIAPP_REG_MK_U8(0x0a34) | ||
203 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_49 SMIAPP_REG_MK_U8(0x0a35) | ||
204 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_50 SMIAPP_REG_MK_U8(0x0a36) | ||
205 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_51 SMIAPP_REG_MK_U8(0x0a37) | ||
206 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_52 SMIAPP_REG_MK_U8(0x0a38) | ||
207 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_53 SMIAPP_REG_MK_U8(0x0a39) | ||
208 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_54 SMIAPP_REG_MK_U8(0x0a3a) | ||
209 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_55 SMIAPP_REG_MK_U8(0x0a3b) | ||
210 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_56 SMIAPP_REG_MK_U8(0x0a3c) | ||
211 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_57 SMIAPP_REG_MK_U8(0x0a3d) | ||
212 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_58 SMIAPP_REG_MK_U8(0x0a3e) | ||
213 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_59 SMIAPP_REG_MK_U8(0x0a3f) | ||
214 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_60 SMIAPP_REG_MK_U8(0x0a40) | ||
215 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_61 SMIAPP_REG_MK_U8(0x0a41) | ||
216 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_62 SMIAPP_REG_MK_U8(0x0a42) | ||
217 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_63 SMIAPP_REG_MK_U8(0x0a43) | ||
218 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_CTRL SMIAPP_REG_MK_U8(0x0a44) | ||
219 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_STATUS SMIAPP_REG_MK_U8(0x0a45) | ||
220 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_PAGE_SELECT SMIAPP_REG_MK_U8(0x0a46) | ||
221 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_0 SMIAPP_REG_MK_U8(0x0a48) | ||
222 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_1 SMIAPP_REG_MK_U8(0x0a49) | ||
223 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_2 SMIAPP_REG_MK_U8(0x0a4a) | ||
224 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_3 SMIAPP_REG_MK_U8(0x0a4b) | ||
225 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_4 SMIAPP_REG_MK_U8(0x0a4c) | ||
226 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_5 SMIAPP_REG_MK_U8(0x0a4d) | ||
227 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_6 SMIAPP_REG_MK_U8(0x0a4e) | ||
228 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_7 SMIAPP_REG_MK_U8(0x0a4f) | ||
229 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_8 SMIAPP_REG_MK_U8(0x0a50) | ||
230 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_9 SMIAPP_REG_MK_U8(0x0a51) | ||
231 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_10 SMIAPP_REG_MK_U8(0x0a52) | ||
232 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_11 SMIAPP_REG_MK_U8(0x0a53) | ||
233 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_12 SMIAPP_REG_MK_U8(0x0a54) | ||
234 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_13 SMIAPP_REG_MK_U8(0x0a55) | ||
235 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_14 SMIAPP_REG_MK_U8(0x0a56) | ||
236 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_15 SMIAPP_REG_MK_U8(0x0a57) | ||
237 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_16 SMIAPP_REG_MK_U8(0x0a58) | ||
238 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_17 SMIAPP_REG_MK_U8(0x0a59) | ||
239 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_18 SMIAPP_REG_MK_U8(0x0a5a) | ||
240 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_19 SMIAPP_REG_MK_U8(0x0a5b) | ||
241 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_20 SMIAPP_REG_MK_U8(0x0a5c) | ||
242 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_21 SMIAPP_REG_MK_U8(0x0a5d) | ||
243 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_22 SMIAPP_REG_MK_U8(0x0a5e) | ||
244 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_23 SMIAPP_REG_MK_U8(0x0a5f) | ||
245 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_24 SMIAPP_REG_MK_U8(0x0a60) | ||
246 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_25 SMIAPP_REG_MK_U8(0x0a61) | ||
247 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_26 SMIAPP_REG_MK_U8(0x0a62) | ||
248 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_27 SMIAPP_REG_MK_U8(0x0a63) | ||
249 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_28 SMIAPP_REG_MK_U8(0x0a64) | ||
250 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_29 SMIAPP_REG_MK_U8(0x0a65) | ||
251 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_30 SMIAPP_REG_MK_U8(0x0a66) | ||
252 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_31 SMIAPP_REG_MK_U8(0x0a67) | ||
253 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_32 SMIAPP_REG_MK_U8(0x0a68) | ||
254 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_33 SMIAPP_REG_MK_U8(0x0a69) | ||
255 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_34 SMIAPP_REG_MK_U8(0x0a6a) | ||
256 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_35 SMIAPP_REG_MK_U8(0x0a6b) | ||
257 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_36 SMIAPP_REG_MK_U8(0x0a6c) | ||
258 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_37 SMIAPP_REG_MK_U8(0x0a6d) | ||
259 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_38 SMIAPP_REG_MK_U8(0x0a6e) | ||
260 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_39 SMIAPP_REG_MK_U8(0x0a6f) | ||
261 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_40 SMIAPP_REG_MK_U8(0x0a70) | ||
262 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_41 SMIAPP_REG_MK_U8(0x0a71) | ||
263 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_42 SMIAPP_REG_MK_U8(0x0a72) | ||
264 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_43 SMIAPP_REG_MK_U8(0x0a73) | ||
265 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_44 SMIAPP_REG_MK_U8(0x0a74) | ||
266 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_45 SMIAPP_REG_MK_U8(0x0a75) | ||
267 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_46 SMIAPP_REG_MK_U8(0x0a76) | ||
268 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_47 SMIAPP_REG_MK_U8(0x0a77) | ||
269 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_48 SMIAPP_REG_MK_U8(0x0a78) | ||
270 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_49 SMIAPP_REG_MK_U8(0x0a79) | ||
271 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_50 SMIAPP_REG_MK_U8(0x0a7a) | ||
272 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_51 SMIAPP_REG_MK_U8(0x0a7b) | ||
273 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_52 SMIAPP_REG_MK_U8(0x0a7c) | ||
274 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_53 SMIAPP_REG_MK_U8(0x0a7d) | ||
275 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_54 SMIAPP_REG_MK_U8(0x0a7e) | ||
276 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_55 SMIAPP_REG_MK_U8(0x0a7f) | ||
277 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_56 SMIAPP_REG_MK_U8(0x0a80) | ||
278 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_57 SMIAPP_REG_MK_U8(0x0a81) | ||
279 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_58 SMIAPP_REG_MK_U8(0x0a82) | ||
280 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_59 SMIAPP_REG_MK_U8(0x0a83) | ||
281 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_60 SMIAPP_REG_MK_U8(0x0a84) | ||
282 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_61 SMIAPP_REG_MK_U8(0x0a85) | ||
283 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_62 SMIAPP_REG_MK_U8(0x0a86) | ||
284 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_2_DATA_63 SMIAPP_REG_MK_U8(0x0a87) | ||
285 | #define SMIAPP_REG_U8_SHADING_CORRECTION_ENABLE SMIAPP_REG_MK_U8(0x0b00) | ||
286 | #define SMIAPP_REG_U8_LUMINANCE_CORRECTION_LEVEL SMIAPP_REG_MK_U8(0x0b01) | ||
287 | #define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_ENABLE SMIAPP_REG_MK_U8(0x0b02) | ||
288 | #define SMIAPP_REG_U8_GREEN_IMBALANCE_FILTER_WEIGHT SMIAPP_REG_MK_U8(0x0b03) | ||
289 | #define SMIAPP_REG_U8_BLACK_LEVEL_CORRECTION_ENABLE SMIAPP_REG_MK_U8(0x0b04) | ||
290 | #define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b05) | ||
291 | #define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b06) | ||
292 | #define SMIAPP_REG_U8_SINGLE_DEFECT_CORRECT_WEIGHT SMIAPP_REG_MK_U8(0x0b07) | ||
293 | #define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b08) | ||
294 | #define SMIAPP_REG_U8_DYNAMIC_COUPLET_CORRECT_WEIGHT SMIAPP_REG_MK_U8(0x0b09) | ||
295 | #define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b0a) | ||
296 | #define SMIAPP_REG_U8_COMBINED_DEFECT_CORRECT_WEIGHT SMIAPP_REG_MK_U8(0x0b0b) | ||
297 | #define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_ENABLE SMIAPP_REG_MK_U8(0x0b0c) | ||
298 | #define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_WEIGHT SMIAPP_REG_MK_U8(0x0b0d) | ||
299 | #define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b0e) | ||
300 | #define SMIAPP_REG_U8_MAPPED_LINE_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b0f) | ||
301 | #define SMIAPP_REG_U8_MAPPED_COUPLET_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b10) | ||
302 | #define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b11) | ||
303 | #define SMIAPP_REG_U8_MAPPED_TRIPLET_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b12) | ||
304 | #define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b13) | ||
305 | #define SMIAPP_REG_U8_DYNAMIC_TRIPLET_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b14) | ||
306 | #define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ENABLE SMIAPP_REG_MK_U8(0x0b15) | ||
307 | #define SMIAPP_REG_U8_DYNAMIC_LINE_DEFECT_CORRECT_ADJUST SMIAPP_REG_MK_U8(0x0b16) | ||
308 | #define SMIAPP_REG_U8_EDOF_MODE SMIAPP_REG_MK_U8(0x0b80) | ||
309 | #define SMIAPP_REG_U8_SHARPNESS SMIAPP_REG_MK_U8(0x0b83) | ||
310 | #define SMIAPP_REG_U8_DENOISING SMIAPP_REG_MK_U8(0x0b84) | ||
311 | #define SMIAPP_REG_U8_MODULE_SPECIFIC SMIAPP_REG_MK_U8(0x0b85) | ||
312 | #define SMIAPP_REG_U16_DEPTH_OF_FIELD SMIAPP_REG_MK_U16(0x0b86) | ||
313 | #define SMIAPP_REG_U16_FOCUS_DISTANCE SMIAPP_REG_MK_U16(0x0b88) | ||
314 | #define SMIAPP_REG_U8_ESTIMATION_MODE_CTRL SMIAPP_REG_MK_U8(0x0b8a) | ||
315 | #define SMIAPP_REG_U16_COLOUR_TEMPERATURE SMIAPP_REG_MK_U16(0x0b8c) | ||
316 | #define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENR SMIAPP_REG_MK_U16(0x0b8e) | ||
317 | #define SMIAPP_REG_U16_ABSOLUTE_GAIN_RED SMIAPP_REG_MK_U16(0x0b90) | ||
318 | #define SMIAPP_REG_U16_ABSOLUTE_GAIN_BLUE SMIAPP_REG_MK_U16(0x0b92) | ||
319 | #define SMIAPP_REG_U16_ABSOLUTE_GAIN_GREENB SMIAPP_REG_MK_U16(0x0b94) | ||
320 | #define SMIAPP_REG_U8_ESTIMATION_ZONE_MODE SMIAPP_REG_MK_U8(0x0bc0) | ||
321 | #define SMIAPP_REG_U16_FIXED_ZONE_WEIGHTING SMIAPP_REG_MK_U16(0x0bc2) | ||
322 | #define SMIAPP_REG_U16_CUSTOM_ZONE_X_START SMIAPP_REG_MK_U16(0x0bc4) | ||
323 | #define SMIAPP_REG_U16_CUSTOM_ZONE_Y_START SMIAPP_REG_MK_U16(0x0bc6) | ||
324 | #define SMIAPP_REG_U16_CUSTOM_ZONE_WIDTH SMIAPP_REG_MK_U16(0x0bc8) | ||
325 | #define SMIAPP_REG_U16_CUSTOM_ZONE_HEIGHT SMIAPP_REG_MK_U16(0x0bca) | ||
326 | #define SMIAPP_REG_U8_GLOBAL_RESET_CTRL1 SMIAPP_REG_MK_U8(0x0c00) | ||
327 | #define SMIAPP_REG_U8_GLOBAL_RESET_CTRL2 SMIAPP_REG_MK_U8(0x0c01) | ||
328 | #define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_1 SMIAPP_REG_MK_U8(0x0c02) | ||
329 | #define SMIAPP_REG_U8_GLOBAL_RESET_MODE_CONFIG_2 SMIAPP_REG_MK_U8(0x0c03) | ||
330 | #define SMIAPP_REG_U16_TRDY_CTRL SMIAPP_REG_MK_U16(0x0c04) | ||
331 | #define SMIAPP_REG_U16_TRDOUT_CTRL SMIAPP_REG_MK_U16(0x0c06) | ||
332 | #define SMIAPP_REG_U16_TSHUTTER_STROBE_DELAY_CTRL SMIAPP_REG_MK_U16(0x0c08) | ||
333 | #define SMIAPP_REG_U16_TSHUTTER_STROBE_WIDTH_CTRL SMIAPP_REG_MK_U16(0x0c0a) | ||
334 | #define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_CTRL SMIAPP_REG_MK_U16(0x0c0c) | ||
335 | #define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_CTRL SMIAPP_REG_MK_U16(0x0c0e) | ||
336 | #define SMIAPP_REG_U16_TGRST_INTERVAL_CTRL SMIAPP_REG_MK_U16(0x0c10) | ||
337 | #define SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT SMIAPP_REG_MK_U8(0x0c12) | ||
338 | #define SMIAPP_REG_U16_FLASH_STROBE_START_POINT SMIAPP_REG_MK_U16(0x0c14) | ||
339 | #define SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL SMIAPP_REG_MK_U16(0x0c16) | ||
340 | #define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL SMIAPP_REG_MK_U16(0x0c18) | ||
341 | #define SMIAPP_REG_U8_FLASH_MODE_RS SMIAPP_REG_MK_U8(0x0c1a) | ||
342 | #define SMIAPP_REG_U8_FLASH_TRIGGER_RS SMIAPP_REG_MK_U8(0x0c1b) | ||
343 | #define SMIAPP_REG_U8_FLASH_STATUS SMIAPP_REG_MK_U8(0x0c1c) | ||
344 | #define SMIAPP_REG_U8_SA_STROBE_MODE SMIAPP_REG_MK_U8(0x0c1d) | ||
345 | #define SMIAPP_REG_U16_SA_STROBE_START_POINT SMIAPP_REG_MK_U16(0x0c1e) | ||
346 | #define SMIAPP_REG_U16_TSA_STROBE_DELAY_CTRL SMIAPP_REG_MK_U16(0x0c20) | ||
347 | #define SMIAPP_REG_U16_TSA_STROBE_WIDTH_CTRL SMIAPP_REG_MK_U16(0x0c22) | ||
348 | #define SMIAPP_REG_U8_SA_STROBE_TRIGGER SMIAPP_REG_MK_U8(0x0c24) | ||
349 | #define SMIAPP_REG_U8_SPECIAL_ACTUATOR_STATUS SMIAPP_REG_MK_U8(0x0c25) | ||
350 | #define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_RS_CTRL SMIAPP_REG_MK_U16(0x0c26) | ||
351 | #define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_RS_CTRL SMIAPP_REG_MK_U16(0x0c28) | ||
352 | #define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_RS_CTRL SMIAPP_REG_MK_U8(0x0c2a) | ||
353 | #define SMIAPP_REG_U8_TFLASH_STROBE_COUNT_CTRL SMIAPP_REG_MK_U8(0x0c2b) | ||
354 | #define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH2_HIGH_CTRL SMIAPP_REG_MK_U16(0x0c2c) | ||
355 | #define SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_LOW_CTRL SMIAPP_REG_MK_U16(0x0c2e) | ||
356 | #define SMIAPP_REG_U8_LOW_LEVEL_CTRL SMIAPP_REG_MK_U8(0x0c80) | ||
357 | #define SMIAPP_REG_U16_MAIN_TRIGGER_REF_POINT SMIAPP_REG_MK_U16(0x0c82) | ||
358 | #define SMIAPP_REG_U16_MAIN_TRIGGER_T3 SMIAPP_REG_MK_U16(0x0c84) | ||
359 | #define SMIAPP_REG_U8_MAIN_TRIGGER_COUNT SMIAPP_REG_MK_U8(0x0c86) | ||
360 | #define SMIAPP_REG_U16_PHASE1_TRIGGER_T3 SMIAPP_REG_MK_U16(0x0c88) | ||
361 | #define SMIAPP_REG_U8_PHASE1_TRIGGER_COUNT SMIAPP_REG_MK_U8(0x0c8a) | ||
362 | #define SMIAPP_REG_U16_PHASE2_TRIGGER_T3 SMIAPP_REG_MK_U16(0x0c8c) | ||
363 | #define SMIAPP_REG_U8_PHASE2_TRIGGER_COUNT SMIAPP_REG_MK_U8(0x0c8e) | ||
364 | #define SMIAPP_REG_U8_MECH_SHUTTER_CTRL SMIAPP_REG_MK_U8(0x0d00) | ||
365 | #define SMIAPP_REG_U8_OPERATION_MODE SMIAPP_REG_MK_U8(0x0d01) | ||
366 | #define SMIAPP_REG_U8_ACT_STATE1 SMIAPP_REG_MK_U8(0x0d02) | ||
367 | #define SMIAPP_REG_U8_ACT_STATE2 SMIAPP_REG_MK_U8(0x0d03) | ||
368 | #define SMIAPP_REG_U16_FOCUS_CHANGE SMIAPP_REG_MK_U16(0x0d80) | ||
369 | #define SMIAPP_REG_U16_FOCUS_CHANGE_CONTROL SMIAPP_REG_MK_U16(0x0d82) | ||
370 | #define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE1 SMIAPP_REG_MK_U16(0x0d84) | ||
371 | #define SMIAPP_REG_U16_FOCUS_CHANGE_NUMBER_PHASE2 SMIAPP_REG_MK_U16(0x0d86) | ||
372 | #define SMIAPP_REG_U8_STROBE_COUNT_PHASE1 SMIAPP_REG_MK_U8(0x0d88) | ||
373 | #define SMIAPP_REG_U8_STROBE_COUNT_PHASE2 SMIAPP_REG_MK_U8(0x0d89) | ||
374 | #define SMIAPP_REG_U8_POSITION SMIAPP_REG_MK_U8(0x0d8a) | ||
375 | #define SMIAPP_REG_U8_BRACKETING_LUT_CONTROL SMIAPP_REG_MK_U8(0x0e00) | ||
376 | #define SMIAPP_REG_U8_BRACKETING_LUT_MODE SMIAPP_REG_MK_U8(0x0e01) | ||
377 | #define SMIAPP_REG_U8_BRACKETING_LUT_ENTRY_CONTROL SMIAPP_REG_MK_U8(0x0e02) | ||
378 | #define SMIAPP_REG_U8_LUT_PARAMETERS_START SMIAPP_REG_MK_U8(0x0e10) | ||
379 | #define SMIAPP_REG_U8_LUT_PARAMETERS_END SMIAPP_REG_MK_U8(0x0eff) | ||
380 | #define SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY SMIAPP_REG_MK_U16(0x1000) | ||
381 | #define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN SMIAPP_REG_MK_U16(0x1004) | ||
382 | #define SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN SMIAPP_REG_MK_U16(0x1006) | ||
383 | #define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN SMIAPP_REG_MK_U16(0x1008) | ||
384 | #define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN SMIAPP_REG_MK_U16(0x100a) | ||
385 | #define SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY SMIAPP_REG_MK_U16(0x1080) | ||
386 | #define SMIAPP_REG_U16_DIGITAL_GAIN_MIN SMIAPP_REG_MK_U16(0x1084) | ||
387 | #define SMIAPP_REG_U16_DIGITAL_GAIN_MAX SMIAPP_REG_MK_U16(0x1086) | ||
388 | #define SMIAPP_REG_U16_DIGITAL_GAIN_STEP_SIZE SMIAPP_REG_MK_U16(0x1088) | ||
389 | #define SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1100) | ||
390 | #define SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1104) | ||
391 | #define SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV SMIAPP_REG_MK_U16(0x1108) | ||
392 | #define SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV SMIAPP_REG_MK_U16(0x110a) | ||
393 | #define SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ SMIAPP_REG_MK_F32(0x110c) | ||
394 | #define SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ SMIAPP_REG_MK_F32(0x1110) | ||
395 | #define SMIAPP_REG_U16_MIN_PLL_MULTIPLIER SMIAPP_REG_MK_U16(0x1114) | ||
396 | #define SMIAPP_REG_U16_MAX_PLL_MULTIPLIER SMIAPP_REG_MK_U16(0x1116) | ||
397 | #define SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ SMIAPP_REG_MK_F32(0x1118) | ||
398 | #define SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ SMIAPP_REG_MK_F32(0x111c) | ||
399 | #define SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1120) | ||
400 | #define SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1122) | ||
401 | #define SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1124) | ||
402 | #define SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1128) | ||
403 | #define SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x112c) | ||
404 | #define SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1130) | ||
405 | #define SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x1134) | ||
406 | #define SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x1136) | ||
407 | #define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES SMIAPP_REG_MK_U16(0x1140) | ||
408 | #define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES SMIAPP_REG_MK_U16(0x1142) | ||
409 | #define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK SMIAPP_REG_MK_U16(0x1144) | ||
410 | #define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK SMIAPP_REG_MK_U16(0x1146) | ||
411 | #define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK SMIAPP_REG_MK_U16(0x1148) | ||
412 | #define SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES SMIAPP_REG_MK_U16(0x114a) | ||
413 | #define SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE SMIAPP_REG_MK_U8(0x114c) | ||
414 | #define SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1160) | ||
415 | #define SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV SMIAPP_REG_MK_U16(0x1162) | ||
416 | #define SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1164) | ||
417 | #define SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1168) | ||
418 | #define SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x116c) | ||
419 | #define SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV SMIAPP_REG_MK_U16(0x116e) | ||
420 | #define SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1170) | ||
421 | #define SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ SMIAPP_REG_MK_F32(0x1174) | ||
422 | #define SMIAPP_REG_U16_X_ADDR_MIN SMIAPP_REG_MK_U16(0x1180) | ||
423 | #define SMIAPP_REG_U16_Y_ADDR_MIN SMIAPP_REG_MK_U16(0x1182) | ||
424 | #define SMIAPP_REG_U16_X_ADDR_MAX SMIAPP_REG_MK_U16(0x1184) | ||
425 | #define SMIAPP_REG_U16_Y_ADDR_MAX SMIAPP_REG_MK_U16(0x1186) | ||
426 | #define SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x1188) | ||
427 | #define SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x118a) | ||
428 | #define SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x118c) | ||
429 | #define SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE SMIAPP_REG_MK_U16(0x118e) | ||
430 | #define SMIAPP_REG_U16_MIN_EVEN_INC SMIAPP_REG_MK_U16(0x11c0) | ||
431 | #define SMIAPP_REG_U16_MAX_EVEN_INC SMIAPP_REG_MK_U16(0x11c2) | ||
432 | #define SMIAPP_REG_U16_MIN_ODD_INC SMIAPP_REG_MK_U16(0x11c4) | ||
433 | #define SMIAPP_REG_U16_MAX_ODD_INC SMIAPP_REG_MK_U16(0x11c6) | ||
434 | #define SMIAPP_REG_U16_SCALING_CAPABILITY SMIAPP_REG_MK_U16(0x1200) | ||
435 | #define SMIAPP_REG_U16_SCALER_M_MIN SMIAPP_REG_MK_U16(0x1204) | ||
436 | #define SMIAPP_REG_U16_SCALER_M_MAX SMIAPP_REG_MK_U16(0x1206) | ||
437 | #define SMIAPP_REG_U16_SCALER_N_MIN SMIAPP_REG_MK_U16(0x1208) | ||
438 | #define SMIAPP_REG_U16_SCALER_N_MAX SMIAPP_REG_MK_U16(0x120a) | ||
439 | #define SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY SMIAPP_REG_MK_U16(0x120c) | ||
440 | #define SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY SMIAPP_REG_MK_U8(0x120e) | ||
441 | #define SMIAPP_REG_U16_COMPRESSION_CAPABILITY SMIAPP_REG_MK_U16(0x1300) | ||
442 | #define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINRED SMIAPP_REG_MK_U16(0x1400) | ||
443 | #define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINRED SMIAPP_REG_MK_U16(0x1402) | ||
444 | #define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINRED SMIAPP_REG_MK_U16(0x1404) | ||
445 | #define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINGREEN SMIAPP_REG_MK_U16(0x1406) | ||
446 | #define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINGREEN SMIAPP_REG_MK_U16(0x1408) | ||
447 | #define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINGREEN SMIAPP_REG_MK_U16(0x140a) | ||
448 | #define SMIAPP_REG_U16_MATRIX_ELEMENT_REDINBLUE SMIAPP_REG_MK_U16(0x140c) | ||
449 | #define SMIAPP_REG_U16_MATRIX_ELEMENT_GREENINBLUE SMIAPP_REG_MK_U16(0x140e) | ||
450 | #define SMIAPP_REG_U16_MATRIX_ELEMENT_BLUEINBLUE SMIAPP_REG_MK_U16(0x1410) | ||
451 | #define SMIAPP_REG_U16_FIFO_SIZE_PIXELS SMIAPP_REG_MK_U16(0x1500) | ||
452 | #define SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY SMIAPP_REG_MK_U8(0x1502) | ||
453 | #define SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY SMIAPP_REG_MK_U8(0x1600) | ||
454 | #define SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x1601) | ||
455 | #define SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x1602) | ||
456 | #define SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY SMIAPP_REG_MK_U8(0x1603) | ||
457 | #define SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY SMIAPP_REG_MK_U8(0x1604) | ||
458 | #define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x1608) | ||
459 | #define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x160c) | ||
460 | #define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x1610) | ||
461 | #define SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS SMIAPP_REG_MK_U32(0x1614) | ||
462 | #define SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY SMIAPP_REG_MK_U8(0x1618) | ||
463 | #define SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN SMIAPP_REG_MK_U16(0x1700) | ||
464 | #define SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN SMIAPP_REG_MK_U16(0x1702) | ||
465 | #define SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN SMIAPP_REG_MK_U16(0x1704) | ||
466 | #define SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN SMIAPP_REG_MK_U16(0x1706) | ||
467 | #define SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN SMIAPP_REG_MK_U16(0x1708) | ||
468 | #define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN SMIAPP_REG_MK_U16(0x170a) | ||
469 | #define SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN SMIAPP_REG_MK_U16(0x170c) | ||
470 | #define SMIAPP_REG_U8_BINNING_CAPABILITY SMIAPP_REG_MK_U8(0x1710) | ||
471 | #define SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY SMIAPP_REG_MK_U8(0x1711) | ||
472 | #define SMIAPP_REG_U8_BINNING_SUBTYPES SMIAPP_REG_MK_U8(0x1712) | ||
473 | #define SMIAPP_REG_U8_BINNING_TYPE_n(n) SMIAPP_REG_MK_U8(0x1713 + (n)) /* 1 <= n <= 237 */ | ||
474 | #define SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY SMIAPP_REG_MK_U8(0x1800) | ||
475 | #define SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY SMIAPP_REG_MK_U8(0x1900) | ||
476 | #define SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY SMIAPP_REG_MK_U8(0x1901) | ||
477 | #define SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY SMIAPP_REG_MK_U8(0x1902) | ||
478 | #define SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY SMIAPP_REG_MK_U8(0x1903) | ||
479 | #define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY SMIAPP_REG_MK_U16(0x1904) | ||
480 | #define SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2 SMIAPP_REG_MK_U16(0x1906) | ||
481 | #define SMIAPP_REG_U8_EDOF_CAPABILITY SMIAPP_REG_MK_U8(0x1980) | ||
482 | #define SMIAPP_REG_U8_ESTIMATION_FRAMES SMIAPP_REG_MK_U8(0x1981) | ||
483 | #define SMIAPP_REG_U8_SUPPORTS_SHARPNESS_ADJ SMIAPP_REG_MK_U8(0x1982) | ||
484 | #define SMIAPP_REG_U8_SUPPORTS_DENOISING_ADJ SMIAPP_REG_MK_U8(0x1983) | ||
485 | #define SMIAPP_REG_U8_SUPPORTS_MODULE_SPECIFIC_ADJ SMIAPP_REG_MK_U8(0x1984) | ||
486 | #define SMIAPP_REG_U8_SUPPORTS_DEPTH_OF_FIELD_ADJ SMIAPP_REG_MK_U8(0x1985) | ||
487 | #define SMIAPP_REG_U8_SUPPORTS_FOCUS_DISTANCE_ADJ SMIAPP_REG_MK_U8(0x1986) | ||
488 | #define SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY SMIAPP_REG_MK_U8(0x1987) | ||
489 | #define SMIAPP_REG_U8_EDOF_SUPPORT_AB_NXM SMIAPP_REG_MK_U8(0x1988) | ||
490 | #define SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x19c0) | ||
491 | #define SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY SMIAPP_REG_MK_U8(0x19c1) | ||
492 | #define SMIAPP_REG_U16_EST_DEPTH_OF_FIELD SMIAPP_REG_MK_U16(0x19c2) | ||
493 | #define SMIAPP_REG_U16_EST_FOCUS_DISTANCE SMIAPP_REG_MK_U16(0x19c4) | ||
494 | #define SMIAPP_REG_U16_CAPABILITY_TRDY_MIN SMIAPP_REG_MK_U16(0x1a00) | ||
495 | #define SMIAPP_REG_U8_FLASH_MODE_CAPABILITY SMIAPP_REG_MK_U8(0x1a02) | ||
496 | #define SMIAPP_REG_U16_MECH_SHUT_AND_ACT_START_ADDR SMIAPP_REG_MK_U16(0x1b02) | ||
497 | #define SMIAPP_REG_U8_ACTUATOR_CAPABILITY SMIAPP_REG_MK_U8(0x1b04) | ||
498 | #define SMIAPP_REG_U16_ACTUATOR_TYPE SMIAPP_REG_MK_U16(0x1b40) | ||
499 | #define SMIAPP_REG_U8_AF_DEVICE_ADDRESS SMIAPP_REG_MK_U8(0x1b42) | ||
500 | #define SMIAPP_REG_U16_FOCUS_CHANGE_ADDRESS SMIAPP_REG_MK_U16(0x1b44) | ||
501 | #define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1 SMIAPP_REG_MK_U8(0x1c00) | ||
502 | #define SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2 SMIAPP_REG_MK_U8(0x1c01) | ||
503 | #define SMIAPP_REG_U8_BRACKETING_LUT_SIZE SMIAPP_REG_MK_U8(0x1c02) | ||
diff --git a/drivers/media/i2c/smiapp/smiapp-reg.h b/drivers/media/i2c/smiapp/smiapp-reg.h new file mode 100644 index 000000000000..54568ca2fe6d --- /dev/null +++ b/drivers/media/i2c/smiapp/smiapp-reg.h | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * drivers/media/i2c/smiapp/smiapp-reg.h | ||
3 | * | ||
4 | * Generic driver for SMIA/SMIA++ compliant camera modules | ||
5 | * | ||
6 | * Copyright (C) 2011--2012 Nokia Corporation | ||
7 | * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __SMIAPP_REG_H_ | ||
26 | #define __SMIAPP_REG_H_ | ||
27 | |||
28 | #include "smiapp-reg-defs.h" | ||
29 | |||
30 | /* Bits for above register */ | ||
31 | #define SMIAPP_IMAGE_ORIENTATION_HFLIP (1 << 0) | ||
32 | #define SMIAPP_IMAGE_ORIENTATION_VFLIP (1 << 1) | ||
33 | |||
34 | #define SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN (1 << 0) | ||
35 | #define SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN (0 << 1) | ||
36 | #define SMIAPP_DATA_TRANSFER_IF_1_CTRL_WR_EN (1 << 1) | ||
37 | #define SMIAPP_DATA_TRANSFER_IF_1_CTRL_ERR_CLEAR (1 << 2) | ||
38 | #define SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY (1 << 0) | ||
39 | #define SMIAPP_DATA_TRANSFER_IF_1_STATUS_WR_READY (1 << 1) | ||
40 | #define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EDATA (1 << 2) | ||
41 | #define SMIAPP_DATA_TRANSFER_IF_1_STATUS_EUSAGE (1 << 3) | ||
42 | |||
43 | #define SMIAPP_SOFTWARE_RESET (1 << 0) | ||
44 | |||
45 | #define SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE (1 << 0) | ||
46 | #define SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE (1 << 1) | ||
47 | |||
48 | #define SMIAPP_DPHY_CTRL_AUTOMATIC 0 | ||
49 | /* DPHY control based on REQUESTED_LINK_BIT_RATE_MBPS */ | ||
50 | #define SMIAPP_DPHY_CTRL_UI 1 | ||
51 | #define SMIAPP_DPHY_CTRL_REGISTER 2 | ||
52 | |||
53 | #define SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR 1 | ||
54 | #define SMIAPP_COMPRESSION_MODE_ADVANCED_PREDICTOR 2 | ||
55 | |||
56 | #define SMIAPP_MODE_SELECT_SOFTWARE_STANDBY 0 | ||
57 | #define SMIAPP_MODE_SELECT_STREAMING 1 | ||
58 | |||
59 | #define SMIAPP_SCALING_MODE_NONE 0 | ||
60 | #define SMIAPP_SCALING_MODE_HORIZONTAL 1 | ||
61 | #define SMIAPP_SCALING_MODE_BOTH 2 | ||
62 | |||
63 | #define SMIAPP_SCALING_CAPABILITY_NONE 0 | ||
64 | #define SMIAPP_SCALING_CAPABILITY_HORIZONTAL 1 | ||
65 | #define SMIAPP_SCALING_CAPABILITY_BOTH 2 /* horizontal/both */ | ||
66 | |||
67 | /* digital crop right before scaler */ | ||
68 | #define SMIAPP_DIGITAL_CROP_CAPABILITY_NONE 0 | ||
69 | #define SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP 1 | ||
70 | |||
71 | #define SMIAPP_BINNING_CAPABILITY_NO 0 | ||
72 | #define SMIAPP_BINNING_CAPABILITY_YES 1 | ||
73 | |||
74 | /* Maximum number of binning subtypes */ | ||
75 | #define SMIAPP_BINNING_SUBTYPES 253 | ||
76 | |||
77 | #define SMIAPP_PIXEL_ORDER_GRBG 0 | ||
78 | #define SMIAPP_PIXEL_ORDER_RGGB 1 | ||
79 | #define SMIAPP_PIXEL_ORDER_BGGR 2 | ||
80 | #define SMIAPP_PIXEL_ORDER_GBRG 3 | ||
81 | |||
82 | #define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL 1 | ||
83 | #define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED 2 | ||
84 | #define SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N 8 | ||
85 | #define SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N 16 | ||
86 | |||
87 | #define SMIAPP_FRAME_FORMAT_MODEL_TYPE_2BYTE 0x01 | ||
88 | #define SMIAPP_FRAME_FORMAT_MODEL_TYPE_4BYTE 0x02 | ||
89 | #define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NROWS_MASK 0x0f | ||
90 | #define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_MASK 0xf0 | ||
91 | #define SMIAPP_FRAME_FORMAT_MODEL_SUBTYPE_NCOLS_SHIFT 4 | ||
92 | |||
93 | #define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_MASK 0xf000 | ||
94 | #define SMIAPP_FRAME_FORMAT_DESC_2_PIXELCODE_SHIFT 12 | ||
95 | #define SMIAPP_FRAME_FORMAT_DESC_2_PIXELS_MASK 0x0fff | ||
96 | |||
97 | #define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_MASK 0xf0000000 | ||
98 | #define SMIAPP_FRAME_FORMAT_DESC_4_PIXELCODE_SHIFT 28 | ||
99 | #define SMIAPP_FRAME_FORMAT_DESC_4_PIXELS_MASK 0x0000ffff | ||
100 | |||
101 | #define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_EMBEDDED 1 | ||
102 | #define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DUMMY 2 | ||
103 | #define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_BLACK 3 | ||
104 | #define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_DARK 4 | ||
105 | #define SMIAPP_FRAME_FORMAT_DESC_PIXELCODE_VISIBLE 5 | ||
106 | |||
107 | #define SMIAPP_FAST_STANDBY_CTRL_COMPLETE_FRAMES 0 | ||
108 | #define SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE 1 | ||
109 | |||
110 | /* Scaling N factor */ | ||
111 | #define SMIAPP_SCALE_N 16 | ||
112 | |||
113 | /* Image statistics registers */ | ||
114 | /* Registers 0x2000 to 0x2fff are reserved for future | ||
115 | * use for statistics features. | ||
116 | */ | ||
117 | |||
118 | /* Manufacturer Specific Registers: 0x3000 to 0x3fff | ||
119 | * The manufacturer specifies these as a black box. | ||
120 | */ | ||
121 | |||
122 | #endif /* __SMIAPP_REG_H_ */ | ||
diff --git a/drivers/media/i2c/smiapp/smiapp-regs.c b/drivers/media/i2c/smiapp/smiapp-regs.c new file mode 100644 index 000000000000..70e0d8db0130 --- /dev/null +++ b/drivers/media/i2c/smiapp/smiapp-regs.c | |||
@@ -0,0 +1,273 @@ | |||
1 | /* | ||
2 | * drivers/media/i2c/smiapp/smiapp-regs.c | ||
3 | * | ||
4 | * Generic driver for SMIA/SMIA++ compliant camera modules | ||
5 | * | ||
6 | * Copyright (C) 2011--2012 Nokia Corporation | ||
7 | * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/delay.h> | ||
26 | #include <linux/i2c.h> | ||
27 | |||
28 | #include "smiapp.h" | ||
29 | #include "smiapp-regs.h" | ||
30 | |||
31 | static uint32_t float_to_u32_mul_1000000(struct i2c_client *client, | ||
32 | uint32_t phloat) | ||
33 | { | ||
34 | int32_t exp; | ||
35 | uint64_t man; | ||
36 | |||
37 | if (phloat >= 0x80000000) { | ||
38 | dev_err(&client->dev, "this is a negative number\n"); | ||
39 | return 0; | ||
40 | } | ||
41 | |||
42 | if (phloat == 0x7f800000) | ||
43 | return ~0; /* Inf. */ | ||
44 | |||
45 | if ((phloat & 0x7f800000) == 0x7f800000) { | ||
46 | dev_err(&client->dev, "NaN or other special number\n"); | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | /* Valid cases begin here */ | ||
51 | if (phloat == 0) | ||
52 | return 0; /* Valid zero */ | ||
53 | |||
54 | if (phloat > 0x4f800000) | ||
55 | return ~0; /* larger than 4294967295 */ | ||
56 | |||
57 | /* | ||
58 | * Unbias exponent (note how phloat is now guaranteed to | ||
59 | * have 0 in the high bit) | ||
60 | */ | ||
61 | exp = ((int32_t)phloat >> 23) - 127; | ||
62 | |||
63 | /* Extract mantissa, add missing '1' bit and it's in MHz */ | ||
64 | man = ((phloat & 0x7fffff) | 0x800000) * 1000000ULL; | ||
65 | |||
66 | if (exp < 0) | ||
67 | man >>= -exp; | ||
68 | else | ||
69 | man <<= exp; | ||
70 | |||
71 | man >>= 23; /* Remove mantissa bias */ | ||
72 | |||
73 | return man & 0xffffffff; | ||
74 | } | ||
75 | |||
76 | |||
77 | /* | ||
78 | * Read a 8/16/32-bit i2c register. The value is returned in 'val'. | ||
79 | * Returns zero if successful, or non-zero otherwise. | ||
80 | */ | ||
81 | static int ____smiapp_read(struct smiapp_sensor *sensor, u16 reg, | ||
82 | u16 len, u32 *val) | ||
83 | { | ||
84 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
85 | struct i2c_msg msg; | ||
86 | unsigned char data[4]; | ||
87 | u16 offset = reg; | ||
88 | int r; | ||
89 | |||
90 | msg.addr = client->addr; | ||
91 | msg.flags = 0; | ||
92 | msg.len = 2; | ||
93 | msg.buf = data; | ||
94 | |||
95 | /* high byte goes out first */ | ||
96 | data[0] = (u8) (offset >> 8); | ||
97 | data[1] = (u8) offset; | ||
98 | r = i2c_transfer(client->adapter, &msg, 1); | ||
99 | if (r != 1) { | ||
100 | if (r >= 0) | ||
101 | r = -EBUSY; | ||
102 | goto err; | ||
103 | } | ||
104 | |||
105 | msg.len = len; | ||
106 | msg.flags = I2C_M_RD; | ||
107 | r = i2c_transfer(client->adapter, &msg, 1); | ||
108 | if (r != 1) { | ||
109 | if (r >= 0) | ||
110 | r = -EBUSY; | ||
111 | goto err; | ||
112 | } | ||
113 | |||
114 | *val = 0; | ||
115 | /* high byte comes first */ | ||
116 | switch (len) { | ||
117 | case SMIA_REG_32BIT: | ||
118 | *val = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) + | ||
119 | data[3]; | ||
120 | break; | ||
121 | case SMIA_REG_16BIT: | ||
122 | *val = (data[0] << 8) + data[1]; | ||
123 | break; | ||
124 | case SMIA_REG_8BIT: | ||
125 | *val = data[0]; | ||
126 | break; | ||
127 | default: | ||
128 | BUG(); | ||
129 | } | ||
130 | |||
131 | return 0; | ||
132 | |||
133 | err: | ||
134 | dev_err(&client->dev, "read from offset 0x%x error %d\n", offset, r); | ||
135 | |||
136 | return r; | ||
137 | } | ||
138 | |||
139 | /* Read a register using 8-bit access only. */ | ||
140 | static int ____smiapp_read_8only(struct smiapp_sensor *sensor, u16 reg, | ||
141 | u16 len, u32 *val) | ||
142 | { | ||
143 | unsigned int i; | ||
144 | int rval; | ||
145 | |||
146 | *val = 0; | ||
147 | |||
148 | for (i = 0; i < len; i++) { | ||
149 | u32 val8; | ||
150 | |||
151 | rval = ____smiapp_read(sensor, reg + i, 1, &val8); | ||
152 | if (rval < 0) | ||
153 | return rval; | ||
154 | *val |= val8 << ((len - i - 1) << 3); | ||
155 | } | ||
156 | |||
157 | return 0; | ||
158 | } | ||
159 | |||
160 | /* | ||
161 | * Read a 8/16/32-bit i2c register. The value is returned in 'val'. | ||
162 | * Returns zero if successful, or non-zero otherwise. | ||
163 | */ | ||
164 | static int __smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val, | ||
165 | bool only8) | ||
166 | { | ||
167 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
168 | unsigned int len = (u8)(reg >> 16); | ||
169 | int rval; | ||
170 | |||
171 | if (len != SMIA_REG_8BIT && len != SMIA_REG_16BIT | ||
172 | && len != SMIA_REG_32BIT) | ||
173 | return -EINVAL; | ||
174 | |||
175 | if (smiapp_quirk_reg(sensor, reg, val)) | ||
176 | goto found_quirk; | ||
177 | |||
178 | if (len == SMIA_REG_8BIT && !only8) | ||
179 | rval = ____smiapp_read(sensor, (u16)reg, len, val); | ||
180 | else | ||
181 | rval = ____smiapp_read_8only(sensor, (u16)reg, len, val); | ||
182 | if (rval < 0) | ||
183 | return rval; | ||
184 | |||
185 | found_quirk: | ||
186 | if (reg & SMIA_REG_FLAG_FLOAT) | ||
187 | *val = float_to_u32_mul_1000000(client, *val); | ||
188 | |||
189 | return 0; | ||
190 | } | ||
191 | |||
192 | int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val) | ||
193 | { | ||
194 | return __smiapp_read( | ||
195 | sensor, reg, val, | ||
196 | smiapp_needs_quirk(sensor, | ||
197 | SMIAPP_QUIRK_FLAG_8BIT_READ_ONLY)); | ||
198 | } | ||
199 | |||
200 | int smiapp_read_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val) | ||
201 | { | ||
202 | return __smiapp_read(sensor, reg, val, true); | ||
203 | } | ||
204 | |||
205 | /* | ||
206 | * Write to a 8/16-bit register. | ||
207 | * Returns zero if successful, or non-zero otherwise. | ||
208 | */ | ||
209 | int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val) | ||
210 | { | ||
211 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
212 | struct i2c_msg msg; | ||
213 | unsigned char data[6]; | ||
214 | unsigned int retries; | ||
215 | unsigned int flags = reg >> 24; | ||
216 | unsigned int len = (u8)(reg >> 16); | ||
217 | u16 offset = reg; | ||
218 | int r; | ||
219 | |||
220 | if ((len != SMIA_REG_8BIT && len != SMIA_REG_16BIT && | ||
221 | len != SMIA_REG_32BIT) || flags) | ||
222 | return -EINVAL; | ||
223 | |||
224 | msg.addr = client->addr; | ||
225 | msg.flags = 0; /* Write */ | ||
226 | msg.len = 2 + len; | ||
227 | msg.buf = data; | ||
228 | |||
229 | /* high byte goes out first */ | ||
230 | data[0] = (u8) (reg >> 8); | ||
231 | data[1] = (u8) (reg & 0xff); | ||
232 | |||
233 | switch (len) { | ||
234 | case SMIA_REG_8BIT: | ||
235 | data[2] = val; | ||
236 | break; | ||
237 | case SMIA_REG_16BIT: | ||
238 | data[2] = val >> 8; | ||
239 | data[3] = val; | ||
240 | break; | ||
241 | case SMIA_REG_32BIT: | ||
242 | data[2] = val >> 24; | ||
243 | data[3] = val >> 16; | ||
244 | data[4] = val >> 8; | ||
245 | data[5] = val; | ||
246 | break; | ||
247 | default: | ||
248 | BUG(); | ||
249 | } | ||
250 | |||
251 | for (retries = 0; retries < 5; retries++) { | ||
252 | /* | ||
253 | * Due to unknown reason sensor stops responding. This | ||
254 | * loop is a temporaty solution until the root cause | ||
255 | * is found. | ||
256 | */ | ||
257 | r = i2c_transfer(client->adapter, &msg, 1); | ||
258 | if (r == 1) { | ||
259 | if (retries) | ||
260 | dev_err(&client->dev, | ||
261 | "sensor i2c stall encountered. " | ||
262 | "retries: %d\n", retries); | ||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | usleep_range(2000, 2000); | ||
267 | } | ||
268 | |||
269 | dev_err(&client->dev, | ||
270 | "wrote 0x%x to offset 0x%x error %d\n", val, offset, r); | ||
271 | |||
272 | return r; | ||
273 | } | ||
diff --git a/drivers/media/i2c/smiapp/smiapp-regs.h b/drivers/media/i2c/smiapp/smiapp-regs.h new file mode 100644 index 000000000000..7f9013b47971 --- /dev/null +++ b/drivers/media/i2c/smiapp/smiapp-regs.h | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * include/media/smiapp/smiapp-regs.h | ||
3 | * | ||
4 | * Generic driver for SMIA/SMIA++ compliant camera modules | ||
5 | * | ||
6 | * Copyright (C) 2011--2012 Nokia Corporation | ||
7 | * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef SMIAPP_REGS_H | ||
26 | #define SMIAPP_REGS_H | ||
27 | |||
28 | #include <linux/i2c.h> | ||
29 | #include <linux/types.h> | ||
30 | |||
31 | /* Use upper 8 bits of the type field for flags */ | ||
32 | #define SMIA_REG_FLAG_FLOAT (1 << 24) | ||
33 | |||
34 | #define SMIA_REG_8BIT 1 | ||
35 | #define SMIA_REG_16BIT 2 | ||
36 | #define SMIA_REG_32BIT 4 | ||
37 | struct smia_reg { | ||
38 | u16 type; | ||
39 | u16 reg; /* 16-bit offset */ | ||
40 | u32 val; /* 8/16/32-bit value */ | ||
41 | }; | ||
42 | |||
43 | struct smiapp_sensor; | ||
44 | |||
45 | int smiapp_read(struct smiapp_sensor *sensor, u32 reg, u32 *val); | ||
46 | int smiapp_read_8only(struct smiapp_sensor *sensor, u32 reg, u32 *val); | ||
47 | int smiapp_write(struct smiapp_sensor *sensor, u32 reg, u32 val); | ||
48 | |||
49 | #endif | ||
diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h new file mode 100644 index 000000000000..4182a695ab53 --- /dev/null +++ b/drivers/media/i2c/smiapp/smiapp.h | |||
@@ -0,0 +1,252 @@ | |||
1 | /* | ||
2 | * drivers/media/i2c/smiapp/smiapp.h | ||
3 | * | ||
4 | * Generic driver for SMIA/SMIA++ compliant camera modules | ||
5 | * | ||
6 | * Copyright (C) 2010--2012 Nokia Corporation | ||
7 | * Contact: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or | ||
10 | * modify it under the terms of the GNU General Public License | ||
11 | * version 2 as published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | ||
21 | * 02110-1301 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef __SMIAPP_PRIV_H_ | ||
26 | #define __SMIAPP_PRIV_H_ | ||
27 | |||
28 | #include <linux/mutex.h> | ||
29 | #include <media/v4l2-ctrls.h> | ||
30 | #include <media/v4l2-subdev.h> | ||
31 | #include <media/smiapp.h> | ||
32 | |||
33 | #include "smiapp-pll.h" | ||
34 | #include "smiapp-reg.h" | ||
35 | #include "smiapp-regs.h" | ||
36 | #include "smiapp-quirk.h" | ||
37 | |||
38 | /* | ||
39 | * Standard SMIA++ constants | ||
40 | */ | ||
41 | #define SMIA_VERSION_1 10 | ||
42 | #define SMIAPP_VERSION_0_8 8 /* Draft 0.8 */ | ||
43 | #define SMIAPP_VERSION_0_9 9 /* Draft 0.9 */ | ||
44 | #define SMIAPP_VERSION_1 10 | ||
45 | |||
46 | #define SMIAPP_PROFILE_0 0 | ||
47 | #define SMIAPP_PROFILE_1 1 | ||
48 | #define SMIAPP_PROFILE_2 2 | ||
49 | |||
50 | #define SMIAPP_NVM_PAGE_SIZE 64 /* bytes */ | ||
51 | |||
52 | #define SMIAPP_RESET_DELAY_CLOCKS 2400 | ||
53 | #define SMIAPP_RESET_DELAY(clk) \ | ||
54 | (1000 + (SMIAPP_RESET_DELAY_CLOCKS * 1000 \ | ||
55 | + (clk) / 1000 - 1) / ((clk) / 1000)) | ||
56 | |||
57 | #include "smiapp-limits.h" | ||
58 | |||
59 | struct smiapp_quirk; | ||
60 | |||
61 | #define SMIAPP_MODULE_IDENT_FLAG_REV_LE (1 << 0) | ||
62 | |||
63 | struct smiapp_module_ident { | ||
64 | u8 manufacturer_id; | ||
65 | u16 model_id; | ||
66 | u8 revision_number_major; | ||
67 | |||
68 | u8 flags; | ||
69 | |||
70 | char *name; | ||
71 | const struct smiapp_quirk *quirk; | ||
72 | }; | ||
73 | |||
74 | struct smiapp_module_info { | ||
75 | u32 manufacturer_id; | ||
76 | u32 model_id; | ||
77 | u32 revision_number_major; | ||
78 | u32 revision_number_minor; | ||
79 | |||
80 | u32 module_year; | ||
81 | u32 module_month; | ||
82 | u32 module_day; | ||
83 | |||
84 | u32 sensor_manufacturer_id; | ||
85 | u32 sensor_model_id; | ||
86 | u32 sensor_revision_number; | ||
87 | u32 sensor_firmware_version; | ||
88 | |||
89 | u32 smia_version; | ||
90 | u32 smiapp_version; | ||
91 | |||
92 | u32 smiapp_profile; | ||
93 | |||
94 | char *name; | ||
95 | const struct smiapp_quirk *quirk; | ||
96 | }; | ||
97 | |||
98 | #define SMIAPP_IDENT_FQ(manufacturer, model, rev, fl, _name, _quirk) \ | ||
99 | { .manufacturer_id = manufacturer, \ | ||
100 | .model_id = model, \ | ||
101 | .revision_number_major = rev, \ | ||
102 | .flags = fl, \ | ||
103 | .name = _name, \ | ||
104 | .quirk = _quirk, } | ||
105 | |||
106 | #define SMIAPP_IDENT_LQ(manufacturer, model, rev, _name, _quirk) \ | ||
107 | { .manufacturer_id = manufacturer, \ | ||
108 | .model_id = model, \ | ||
109 | .revision_number_major = rev, \ | ||
110 | .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE, \ | ||
111 | .name = _name, \ | ||
112 | .quirk = _quirk, } | ||
113 | |||
114 | #define SMIAPP_IDENT_L(manufacturer, model, rev, _name) \ | ||
115 | { .manufacturer_id = manufacturer, \ | ||
116 | .model_id = model, \ | ||
117 | .revision_number_major = rev, \ | ||
118 | .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE, \ | ||
119 | .name = _name, } | ||
120 | |||
121 | #define SMIAPP_IDENT_Q(manufacturer, model, rev, _name, _quirk) \ | ||
122 | { .manufacturer_id = manufacturer, \ | ||
123 | .model_id = model, \ | ||
124 | .revision_number_major = rev, \ | ||
125 | .flags = 0, \ | ||
126 | .name = _name, \ | ||
127 | .quirk = _quirk, } | ||
128 | |||
129 | #define SMIAPP_IDENT(manufacturer, model, rev, _name) \ | ||
130 | { .manufacturer_id = manufacturer, \ | ||
131 | .model_id = model, \ | ||
132 | .revision_number_major = rev, \ | ||
133 | .flags = 0, \ | ||
134 | .name = _name, } | ||
135 | |||
136 | struct smiapp_reg_limits { | ||
137 | u32 addr; | ||
138 | char *what; | ||
139 | }; | ||
140 | |||
141 | extern struct smiapp_reg_limits smiapp_reg_limits[]; | ||
142 | |||
143 | struct smiapp_csi_data_format { | ||
144 | u32 code; | ||
145 | u8 width; | ||
146 | u8 compressed; | ||
147 | u8 pixel_order; | ||
148 | }; | ||
149 | |||
150 | #define SMIAPP_SUBDEVS 3 | ||
151 | |||
152 | #define SMIAPP_PA_PAD_SRC 0 | ||
153 | #define SMIAPP_PAD_SINK 0 | ||
154 | #define SMIAPP_PAD_SRC 1 | ||
155 | #define SMIAPP_PADS 2 | ||
156 | |||
157 | struct smiapp_binning_subtype { | ||
158 | u8 horizontal:4; | ||
159 | u8 vertical:4; | ||
160 | } __packed; | ||
161 | |||
162 | struct smiapp_subdev { | ||
163 | struct v4l2_subdev sd; | ||
164 | struct media_pad pads[2]; | ||
165 | struct v4l2_rect sink_fmt; | ||
166 | struct v4l2_rect crop[2]; | ||
167 | struct v4l2_rect compose; /* compose on sink */ | ||
168 | unsigned short sink_pad; | ||
169 | unsigned short source_pad; | ||
170 | int npads; | ||
171 | struct smiapp_sensor *sensor; | ||
172 | struct v4l2_ctrl_handler ctrl_handler; | ||
173 | }; | ||
174 | |||
175 | /* | ||
176 | * struct smiapp_sensor - Main device structure | ||
177 | */ | ||
178 | struct smiapp_sensor { | ||
179 | /* | ||
180 | * "mutex" is used to serialise access to all fields here | ||
181 | * except v4l2_ctrls at the end of the struct. "mutex" is also | ||
182 | * used to serialise access to file handle specific | ||
183 | * information. The exception to this rule is the power_mutex | ||
184 | * below. | ||
185 | */ | ||
186 | struct mutex mutex; | ||
187 | /* | ||
188 | * power_mutex is used to serialise power management related | ||
189 | * activities. Acquiring "mutex" at that time isn't necessary | ||
190 | * since there are no other users anyway. | ||
191 | */ | ||
192 | struct mutex power_mutex; | ||
193 | struct smiapp_subdev ssds[SMIAPP_SUBDEVS]; | ||
194 | u32 ssds_used; | ||
195 | struct smiapp_subdev *src; | ||
196 | struct smiapp_subdev *binner; | ||
197 | struct smiapp_subdev *scaler; | ||
198 | struct smiapp_subdev *pixel_array; | ||
199 | struct smiapp_platform_data *platform_data; | ||
200 | struct regulator *vana; | ||
201 | struct clk *ext_clk; | ||
202 | u32 limits[SMIAPP_LIMIT_LAST]; | ||
203 | u8 nbinning_subtypes; | ||
204 | struct smiapp_binning_subtype binning_subtypes[SMIAPP_BINNING_SUBTYPES]; | ||
205 | u32 mbus_frame_fmts; | ||
206 | const struct smiapp_csi_data_format *csi_format; | ||
207 | const struct smiapp_csi_data_format *internal_csi_format; | ||
208 | u32 default_mbus_frame_fmts; | ||
209 | int default_pixel_order; | ||
210 | |||
211 | u8 binning_horizontal; | ||
212 | u8 binning_vertical; | ||
213 | |||
214 | u8 scale_m; | ||
215 | u8 scaling_mode; | ||
216 | |||
217 | u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */ | ||
218 | u8 flash_capability; | ||
219 | u8 frame_skip; | ||
220 | |||
221 | int power_count; | ||
222 | |||
223 | bool streaming; | ||
224 | bool dev_init_done; | ||
225 | |||
226 | u8 *nvm; /* nvm memory buffer */ | ||
227 | unsigned int nvm_size; /* bytes */ | ||
228 | |||
229 | struct smiapp_module_info minfo; | ||
230 | |||
231 | struct smiapp_pll pll; | ||
232 | |||
233 | /* Pixel array controls */ | ||
234 | struct v4l2_ctrl *analog_gain; | ||
235 | struct v4l2_ctrl *exposure; | ||
236 | struct v4l2_ctrl *hflip; | ||
237 | struct v4l2_ctrl *vflip; | ||
238 | struct v4l2_ctrl *vblank; | ||
239 | struct v4l2_ctrl *hblank; | ||
240 | struct v4l2_ctrl *pixel_rate_parray; | ||
241 | /* src controls */ | ||
242 | struct v4l2_ctrl *link_freq; | ||
243 | struct v4l2_ctrl *pixel_rate_csi; | ||
244 | }; | ||
245 | |||
246 | #define to_smiapp_subdev(_sd) \ | ||
247 | container_of(_sd, struct smiapp_subdev, sd) | ||
248 | |||
249 | #define to_smiapp_sensor(_sd) \ | ||
250 | (to_smiapp_subdev(_sd)->sensor) | ||
251 | |||
252 | #endif /* __SMIAPP_PRIV_H_ */ | ||