aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSakari Ailus <sakari.ailus@iki.fi>2012-03-03 15:19:52 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-05-14 08:06:00 -0400
commitccfc97bdb5ae8b8edc55169ac6924e08449836ac (patch)
tree8e9215ce9211d2270e7f3598560b4cf96995aa9e
parentcf1c5fae5f8a28d478b7177a2d83e42d25eab072 (diff)
[media] smiapp: Add driver
Add driver for SMIA++/SMIA image sensors. The driver exposes the sensor as three subdevs, pixel array, binner and scaler --- in case the device has a scaler. Currently it relies on the board code for external clock handling. There is no fast way out of this dependency before the ISP drivers (omap3isp) among others will be able to export that clock through the clock framework instead. Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/Kconfig2
-rw-r--r--drivers/media/video/Makefile1
-rw-r--r--drivers/media/video/smiapp-pll.c2
-rw-r--r--drivers/media/video/smiapp/Kconfig13
-rw-r--r--drivers/media/video/smiapp/Makefile3
-rw-r--r--drivers/media/video/smiapp/smiapp-core.c2832
-rw-r--r--drivers/media/video/smiapp/smiapp-debug.h32
-rw-r--r--drivers/media/video/smiapp/smiapp-limits.c132
-rw-r--r--drivers/media/video/smiapp/smiapp-limits.h128
-rw-r--r--drivers/media/video/smiapp/smiapp-quirk.c264
-rw-r--r--drivers/media/video/smiapp/smiapp-quirk.h72
-rw-r--r--drivers/media/video/smiapp/smiapp-reg-defs.h503
-rw-r--r--drivers/media/video/smiapp/smiapp-reg.h122
-rw-r--r--drivers/media/video/smiapp/smiapp-regs.c213
-rw-r--r--drivers/media/video/smiapp/smiapp-regs.h46
-rw-r--r--drivers/media/video/smiapp/smiapp.h251
-rw-r--r--include/media/smiapp.h83
17 files changed, 4699 insertions, 0 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index d3e879f64310..9fc7c5224ac8 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -559,6 +559,8 @@ config VIDEO_S5K6AA
559 This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M 559 This is a V4L2 sensor-level driver for Samsung S5K6AA(FX) 1.3M
560 camera sensor with an embedded SoC image signal processor. 560 camera sensor with an embedded SoC image signal processor.
561 561
562source "drivers/media/video/smiapp/Kconfig"
563
562comment "Flash devices" 564comment "Flash devices"
563 565
564config VIDEO_ADP1653 566config VIDEO_ADP1653
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 4e6c100cf583..5a97da2ae33b 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -79,6 +79,7 @@ obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
79obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o 79obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o
80obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ 80obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/
81obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o 81obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o
82obj-$(CONFIG_VIDEO_SMIAPP) += smiapp/
82obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o 83obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o
83obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o 84obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o
84 85
diff --git a/drivers/media/video/smiapp-pll.c b/drivers/media/video/smiapp-pll.c
index a416e27a4282..501da413dfad 100644
--- a/drivers/media/video/smiapp-pll.c
+++ b/drivers/media/video/smiapp-pll.c
@@ -22,6 +22,8 @@
22 * 22 *
23 */ 23 */
24 24
25#include "smiapp/smiapp-debug.h"
26
25#include <linux/gcd.h> 27#include <linux/gcd.h>
26#include <linux/lcm.h> 28#include <linux/lcm.h>
27#include <linux/module.h> 29#include <linux/module.h>
diff --git a/drivers/media/video/smiapp/Kconfig b/drivers/media/video/smiapp/Kconfig
new file mode 100644
index 000000000000..9504c436a5ca
--- /dev/null
+++ b/drivers/media/video/smiapp/Kconfig
@@ -0,0 +1,13 @@
1config VIDEO_SMIAPP
2 tristate "SMIA++/SMIA sensor support"
3 depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
4 select VIDEO_SMIAPP_PLL
5 ---help---
6 This is a generic driver for SMIA++/SMIA camera modules.
7
8config VIDEO_SMIAPP_DEBUG
9 bool "Enable debugging for the generic SMIA++/SMIA driver"
10 depends on VIDEO_SMIAPP
11 ---help---
12 Enable debugging output in the generic SMIA++/SMIA driver. If you
13 are developing the driver you might want to enable this.
diff --git a/drivers/media/video/smiapp/Makefile b/drivers/media/video/smiapp/Makefile
new file mode 100644
index 000000000000..5a207eecd357
--- /dev/null
+++ b/drivers/media/video/smiapp/Makefile
@@ -0,0 +1,3 @@
1smiapp-objs += smiapp-core.o smiapp-regs.o \
2 smiapp-quirk.o smiapp-limits.o
3obj-$(CONFIG_VIDEO_SMIAPP) += smiapp.o
diff --git a/drivers/media/video/smiapp/smiapp-core.c b/drivers/media/video/smiapp/smiapp-core.c
new file mode 100644
index 000000000000..3991c452acb2
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-core.c
@@ -0,0 +1,2832 @@
1/*
2 * drivers/media/video/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 "smiapp-debug.h"
30
31#include <linux/delay.h>
32#include <linux/device.h>
33#include <linux/gpio.h>
34#include <linux/module.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_SUBDEV_SEL_FLAG_SIZE_GE \
43 ? ALIGN((dim), 2) \
44 : (dim) & ~1)
45
46/*
47 * smiapp_module_idents - supported camera modules
48 */
49static 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
69static 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(client, SMIAPP_REG_U8_FRAME_FORMAT_MODEL_TYPE,
80 &fmt_model_type);
81 if (rval)
82 return rval;
83
84 rval = smiapp_read(client, 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 client,
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 client,
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
201static int smiapp_pll_configure(struct smiapp_sensor *sensor)
202{
203 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
204 struct smiapp_pll *pll = &sensor->pll;
205 int rval;
206
207 rval = smiapp_write(
208 client, SMIAPP_REG_U16_VT_PIX_CLK_DIV, pll->vt_pix_clk_div);
209 if (rval < 0)
210 return rval;
211
212 rval = smiapp_write(
213 client, SMIAPP_REG_U16_VT_SYS_CLK_DIV, pll->vt_sys_clk_div);
214 if (rval < 0)
215 return rval;
216
217 rval = smiapp_write(
218 client, SMIAPP_REG_U16_PRE_PLL_CLK_DIV, pll->pre_pll_clk_div);
219 if (rval < 0)
220 return rval;
221
222 rval = smiapp_write(
223 client, SMIAPP_REG_U16_PLL_MULTIPLIER, pll->pll_multiplier);
224 if (rval < 0)
225 return rval;
226
227 /* Lane op clock ratio does not apply here. */
228 rval = smiapp_write(
229 client, SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS,
230 DIV_ROUND_UP(pll->op_sys_clk_freq_hz, 1000000 / 256 / 256));
231 if (rval < 0 || sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
232 return rval;
233
234 rval = smiapp_write(
235 client, SMIAPP_REG_U16_OP_PIX_CLK_DIV, pll->op_pix_clk_div);
236 if (rval < 0)
237 return rval;
238
239 return smiapp_write(
240 client, SMIAPP_REG_U16_OP_SYS_CLK_DIV, pll->op_sys_clk_div);
241}
242
243static int smiapp_pll_update(struct smiapp_sensor *sensor)
244{
245 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
246 struct smiapp_pll_limits lim = {
247 .min_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_PRE_PLL_CLK_DIV],
248 .max_pre_pll_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_PRE_PLL_CLK_DIV],
249 .min_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ],
250 .max_pll_ip_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_IP_FREQ_HZ],
251 .min_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MIN_PLL_MULTIPLIER],
252 .max_pll_multiplier = sensor->limits[SMIAPP_LIMIT_MAX_PLL_MULTIPLIER],
253 .min_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_PLL_OP_FREQ_HZ],
254 .max_pll_op_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_PLL_OP_FREQ_HZ],
255
256 .min_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV],
257 .max_op_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV],
258 .min_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV],
259 .max_op_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV],
260 .min_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_FREQ_HZ],
261 .max_op_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_FREQ_HZ],
262 .min_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_FREQ_HZ],
263 .max_op_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_FREQ_HZ],
264
265 .min_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_DIV],
266 .max_vt_sys_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_DIV],
267 .min_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_DIV],
268 .max_vt_pix_clk_div = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_DIV],
269 .min_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_SYS_CLK_FREQ_HZ],
270 .max_vt_sys_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_SYS_CLK_FREQ_HZ],
271 .min_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MIN_VT_PIX_CLK_FREQ_HZ],
272 .max_vt_pix_clk_freq_hz = sensor->limits[SMIAPP_LIMIT_MAX_VT_PIX_CLK_FREQ_HZ],
273
274 .min_line_length_pck_bin = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN],
275 .min_line_length_pck = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK],
276 };
277 struct smiapp_pll *pll = &sensor->pll;
278 int rval;
279
280 memset(&sensor->pll, 0, sizeof(sensor->pll));
281
282 pll->lanes = sensor->platform_data->lanes;
283 pll->ext_clk_freq_hz = sensor->platform_data->ext_clk;
284
285 if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) {
286 /*
287 * Fill in operational clock divisors limits from the
288 * video timing ones. On profile 0 sensors the
289 * requirements regarding them are essentially the
290 * same as on VT ones.
291 */
292 lim.min_op_sys_clk_div = lim.min_vt_sys_clk_div;
293 lim.max_op_sys_clk_div = lim.max_vt_sys_clk_div;
294 lim.min_op_pix_clk_div = lim.min_vt_pix_clk_div;
295 lim.max_op_pix_clk_div = lim.max_vt_pix_clk_div;
296 lim.min_op_sys_clk_freq_hz = lim.min_vt_sys_clk_freq_hz;
297 lim.max_op_sys_clk_freq_hz = lim.max_vt_sys_clk_freq_hz;
298 lim.min_op_pix_clk_freq_hz = lim.min_vt_pix_clk_freq_hz;
299 lim.max_op_pix_clk_freq_hz = lim.max_vt_pix_clk_freq_hz;
300 /* Profile 0 sensors have no separate OP clock branch. */
301 pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS;
302 }
303
304 if (smiapp_needs_quirk(sensor,
305 SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE))
306 pll->flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE;
307
308 pll->binning_horizontal = sensor->binning_horizontal;
309 pll->binning_vertical = sensor->binning_vertical;
310 pll->link_freq =
311 sensor->link_freq->qmenu_int[sensor->link_freq->val];
312 pll->scale_m = sensor->scale_m;
313 pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
314 pll->bits_per_pixel = sensor->csi_format->compressed;
315
316 rval = smiapp_pll_calculate(&client->dev, &lim, pll);
317 if (rval < 0)
318 return rval;
319
320 sensor->pixel_rate_parray->cur.val64 = pll->vt_pix_clk_freq_hz;
321 sensor->pixel_rate_csi->cur.val64 = pll->pixel_rate_csi;
322
323 return 0;
324}
325
326
327/*
328 *
329 * V4L2 Controls handling
330 *
331 */
332
333static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor)
334{
335 struct v4l2_ctrl *ctrl = sensor->exposure;
336 int max;
337
338 max = sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
339 + sensor->vblank->val
340 - sensor->limits[SMIAPP_LIMIT_COARSE_INTEGRATION_TIME_MAX_MARGIN];
341
342 ctrl->maximum = max;
343 if (ctrl->default_value > max)
344 ctrl->default_value = max;
345 if (ctrl->val > max)
346 ctrl->val = max;
347 if (ctrl->cur.val > max)
348 ctrl->cur.val = max;
349}
350
351/*
352 * Order matters.
353 *
354 * 1. Bits-per-pixel, descending.
355 * 2. Bits-per-pixel compressed, descending.
356 * 3. Pixel order, same as in pixel_order_str. Formats for all four pixel
357 * orders must be defined.
358 */
359static const struct smiapp_csi_data_format smiapp_csi_data_formats[] = {
360 { V4L2_MBUS_FMT_SGRBG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GRBG, },
361 { V4L2_MBUS_FMT_SRGGB12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_RGGB, },
362 { V4L2_MBUS_FMT_SBGGR12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_BGGR, },
363 { V4L2_MBUS_FMT_SGBRG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GBRG, },
364 { V4L2_MBUS_FMT_SGRBG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GRBG, },
365 { V4L2_MBUS_FMT_SRGGB10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_RGGB, },
366 { V4L2_MBUS_FMT_SBGGR10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_BGGR, },
367 { V4L2_MBUS_FMT_SGBRG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GBRG, },
368 { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GRBG, },
369 { V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_RGGB, },
370 { V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_BGGR, },
371 { V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GBRG, },
372};
373
374const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" };
375
376#define to_csi_format_idx(fmt) (((unsigned long)(fmt) \
377 - (unsigned long)smiapp_csi_data_formats) \
378 / sizeof(*smiapp_csi_data_formats))
379
380static u32 smiapp_pixel_order(struct smiapp_sensor *sensor)
381{
382 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
383 int flip = 0;
384
385 if (sensor->hflip) {
386 if (sensor->hflip->val)
387 flip |= SMIAPP_IMAGE_ORIENTATION_HFLIP;
388
389 if (sensor->vflip->val)
390 flip |= SMIAPP_IMAGE_ORIENTATION_VFLIP;
391 }
392
393 flip ^= sensor->hvflip_inv_mask;
394
395 dev_dbg(&client->dev, "flip %d\n", flip);
396 return sensor->default_pixel_order ^ flip;
397}
398
399static void smiapp_update_mbus_formats(struct smiapp_sensor *sensor)
400{
401 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
402 unsigned int csi_format_idx =
403 to_csi_format_idx(sensor->csi_format) & ~3;
404 unsigned int internal_csi_format_idx =
405 to_csi_format_idx(sensor->internal_csi_format) & ~3;
406 unsigned int pixel_order = smiapp_pixel_order(sensor);
407
408 sensor->mbus_frame_fmts =
409 sensor->default_mbus_frame_fmts << pixel_order;
410 sensor->csi_format =
411 &smiapp_csi_data_formats[csi_format_idx + pixel_order];
412 sensor->internal_csi_format =
413 &smiapp_csi_data_formats[internal_csi_format_idx
414 + pixel_order];
415
416 BUG_ON(max(internal_csi_format_idx, csi_format_idx) + pixel_order
417 >= ARRAY_SIZE(smiapp_csi_data_formats));
418 BUG_ON(min(internal_csi_format_idx, csi_format_idx) < 0);
419
420 dev_dbg(&client->dev, "new pixel order %s\n",
421 pixel_order_str[pixel_order]);
422}
423
424static int smiapp_set_ctrl(struct v4l2_ctrl *ctrl)
425{
426 struct smiapp_sensor *sensor =
427 container_of(ctrl->handler, struct smiapp_subdev, ctrl_handler)
428 ->sensor;
429 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
430 u32 orient = 0;
431 int exposure;
432 int rval;
433
434 switch (ctrl->id) {
435 case V4L2_CID_ANALOGUE_GAIN:
436 return smiapp_write(
437 client,
438 SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_GLOBAL, ctrl->val);
439
440 case V4L2_CID_EXPOSURE:
441 return smiapp_write(
442 client,
443 SMIAPP_REG_U16_COARSE_INTEGRATION_TIME, ctrl->val);
444
445 case V4L2_CID_HFLIP:
446 case V4L2_CID_VFLIP:
447 if (sensor->streaming)
448 return -EBUSY;
449
450 if (sensor->hflip->val)
451 orient |= SMIAPP_IMAGE_ORIENTATION_HFLIP;
452
453 if (sensor->vflip->val)
454 orient |= SMIAPP_IMAGE_ORIENTATION_VFLIP;
455
456 orient ^= sensor->hvflip_inv_mask;
457 rval = smiapp_write(client,
458 SMIAPP_REG_U8_IMAGE_ORIENTATION,
459 orient);
460 if (rval < 0)
461 return rval;
462
463 smiapp_update_mbus_formats(sensor);
464
465 return 0;
466
467 case V4L2_CID_VBLANK:
468 exposure = sensor->exposure->val;
469
470 __smiapp_update_exposure_limits(sensor);
471
472 if (exposure > sensor->exposure->maximum) {
473 sensor->exposure->val =
474 sensor->exposure->maximum;
475 rval = smiapp_set_ctrl(
476 sensor->exposure);
477 if (rval < 0)
478 return rval;
479 }
480
481 return smiapp_write(
482 client, SMIAPP_REG_U16_FRAME_LENGTH_LINES,
483 sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
484 + ctrl->val);
485
486 case V4L2_CID_HBLANK:
487 return smiapp_write(
488 client, SMIAPP_REG_U16_LINE_LENGTH_PCK,
489 sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width
490 + ctrl->val);
491
492 case V4L2_CID_LINK_FREQ:
493 if (sensor->streaming)
494 return -EBUSY;
495
496 return smiapp_pll_update(sensor);
497
498 default:
499 return -EINVAL;
500 }
501}
502
503static const struct v4l2_ctrl_ops smiapp_ctrl_ops = {
504 .s_ctrl = smiapp_set_ctrl,
505};
506
507static int smiapp_init_controls(struct smiapp_sensor *sensor)
508{
509 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
510 struct v4l2_ctrl_config cfg;
511 int rval;
512
513 rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 7);
514 if (rval)
515 return rval;
516 sensor->pixel_array->ctrl_handler.lock = &sensor->mutex;
517
518 sensor->analog_gain = v4l2_ctrl_new_std(
519 &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
520 V4L2_CID_ANALOGUE_GAIN,
521 sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN],
522 sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX],
523 max(sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_STEP], 1U),
524 sensor->limits[SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN]);
525
526 /* Exposure limits will be updated soon, use just something here. */
527 sensor->exposure = v4l2_ctrl_new_std(
528 &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
529 V4L2_CID_EXPOSURE, 0, 0, 1, 0);
530
531 sensor->hflip = v4l2_ctrl_new_std(
532 &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
533 V4L2_CID_HFLIP, 0, 1, 1, 0);
534 sensor->vflip = v4l2_ctrl_new_std(
535 &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
536 V4L2_CID_VFLIP, 0, 1, 1, 0);
537
538 sensor->vblank = v4l2_ctrl_new_std(
539 &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
540 V4L2_CID_VBLANK, 0, 1, 1, 0);
541
542 if (sensor->vblank)
543 sensor->vblank->flags |= V4L2_CTRL_FLAG_UPDATE;
544
545 sensor->hblank = v4l2_ctrl_new_std(
546 &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
547 V4L2_CID_HBLANK, 0, 1, 1, 0);
548
549 if (sensor->hblank)
550 sensor->hblank->flags |= V4L2_CTRL_FLAG_UPDATE;
551
552 sensor->pixel_rate_parray = v4l2_ctrl_new_std(
553 &sensor->pixel_array->ctrl_handler, &smiapp_ctrl_ops,
554 V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
555
556 if (sensor->pixel_array->ctrl_handler.error) {
557 dev_err(&client->dev,
558 "pixel array controls initialization failed (%d)\n",
559 sensor->pixel_array->ctrl_handler.error);
560 rval = sensor->pixel_array->ctrl_handler.error;
561 goto error;
562 }
563
564 sensor->pixel_array->sd.ctrl_handler =
565 &sensor->pixel_array->ctrl_handler;
566
567 v4l2_ctrl_cluster(2, &sensor->hflip);
568
569 rval = v4l2_ctrl_handler_init(&sensor->src->ctrl_handler, 0);
570 if (rval)
571 goto error;
572 sensor->src->ctrl_handler.lock = &sensor->mutex;
573
574 memset(&cfg, 0, sizeof(cfg));
575
576 cfg.ops = &smiapp_ctrl_ops;
577 cfg.id = V4L2_CID_LINK_FREQ;
578 cfg.type = V4L2_CTRL_TYPE_INTEGER_MENU;
579 while (sensor->platform_data->op_sys_clock[cfg.max + 1])
580 cfg.max++;
581 cfg.qmenu_int = sensor->platform_data->op_sys_clock;
582
583 sensor->link_freq = v4l2_ctrl_new_custom(
584 &sensor->src->ctrl_handler, &cfg, NULL);
585
586 sensor->pixel_rate_csi = v4l2_ctrl_new_std(
587 &sensor->src->ctrl_handler, &smiapp_ctrl_ops,
588 V4L2_CID_PIXEL_RATE, 0, 0, 1, 0);
589
590 if (sensor->src->ctrl_handler.error) {
591 dev_err(&client->dev,
592 "src controls initialization failed (%d)\n",
593 sensor->src->ctrl_handler.error);
594 rval = sensor->src->ctrl_handler.error;
595 goto error;
596 }
597
598 sensor->src->sd.ctrl_handler =
599 &sensor->src->ctrl_handler;
600
601 return 0;
602
603error:
604 v4l2_ctrl_handler_free(&sensor->pixel_array->ctrl_handler);
605 v4l2_ctrl_handler_free(&sensor->src->ctrl_handler);
606
607 return rval;
608}
609
610static void smiapp_free_controls(struct smiapp_sensor *sensor)
611{
612 unsigned int i;
613
614 for (i = 0; i < sensor->ssds_used; i++)
615 v4l2_ctrl_handler_free(&sensor->ssds[i].ctrl_handler);
616}
617
618static int smiapp_get_limits(struct smiapp_sensor *sensor, int const *limit,
619 unsigned int n)
620{
621 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
622 unsigned int i;
623 u32 val;
624 int rval;
625
626 for (i = 0; i < n; i++) {
627 rval = smiapp_read(
628 client, smiapp_reg_limits[limit[i]].addr, &val);
629 if (rval)
630 return rval;
631 sensor->limits[limit[i]] = val;
632 dev_dbg(&client->dev, "0x%8.8x \"%s\" = %d, 0x%x\n",
633 smiapp_reg_limits[limit[i]].addr,
634 smiapp_reg_limits[limit[i]].what, val, val);
635 }
636
637 return 0;
638}
639
640static int smiapp_get_all_limits(struct smiapp_sensor *sensor)
641{
642 unsigned int i;
643 int rval;
644
645 for (i = 0; i < SMIAPP_LIMIT_LAST; i++) {
646 rval = smiapp_get_limits(sensor, &i, 1);
647 if (rval < 0)
648 return rval;
649 }
650
651 if (sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] == 0)
652 smiapp_replace_limit(sensor, SMIAPP_LIMIT_SCALER_N_MIN, 16);
653
654 return 0;
655}
656
657static int smiapp_get_limits_binning(struct smiapp_sensor *sensor)
658{
659 static u32 const limits[] = {
660 SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN,
661 SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN,
662 SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN,
663 SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN,
664 SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN,
665 SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN_BIN,
666 SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN,
667 };
668 static u32 const limits_replace[] = {
669 SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES,
670 SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES,
671 SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK,
672 SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK,
673 SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK,
674 SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MIN,
675 SMIAPP_LIMIT_FINE_INTEGRATION_TIME_MAX_MARGIN,
676 };
677
678 if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY] ==
679 SMIAPP_BINNING_CAPABILITY_NO) {
680 unsigned int i;
681
682 for (i = 0; i < ARRAY_SIZE(limits); i++)
683 sensor->limits[limits[i]] =
684 sensor->limits[limits_replace[i]];
685
686 return 0;
687 }
688
689 return smiapp_get_limits(sensor, limits, ARRAY_SIZE(limits));
690}
691
692static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor)
693{
694 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
695 unsigned int type, n;
696 unsigned int i, pixel_order;
697 int rval;
698
699 rval = smiapp_read(
700 client, SMIAPP_REG_U8_DATA_FORMAT_MODEL_TYPE, &type);
701 if (rval)
702 return rval;
703
704 dev_dbg(&client->dev, "data_format_model_type %d\n", type);
705
706 rval = smiapp_read(client, SMIAPP_REG_U8_PIXEL_ORDER,
707 &pixel_order);
708 if (rval)
709 return rval;
710
711 if (pixel_order >= ARRAY_SIZE(pixel_order_str)) {
712 dev_dbg(&client->dev, "bad pixel order %d\n", pixel_order);
713 return -EINVAL;
714 }
715
716 dev_dbg(&client->dev, "pixel order %d (%s)\n", pixel_order,
717 pixel_order_str[pixel_order]);
718
719 switch (type) {
720 case SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL:
721 n = SMIAPP_DATA_FORMAT_MODEL_TYPE_NORMAL_N;
722 break;
723 case SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED:
724 n = SMIAPP_DATA_FORMAT_MODEL_TYPE_EXTENDED_N;
725 break;
726 default:
727 return -EINVAL;
728 }
729
730 sensor->default_pixel_order = pixel_order;
731 sensor->mbus_frame_fmts = 0;
732
733 for (i = 0; i < n; i++) {
734 unsigned int fmt, j;
735
736 rval = smiapp_read(
737 client,
738 SMIAPP_REG_U16_DATA_FORMAT_DESCRIPTOR(i), &fmt);
739 if (rval)
740 return rval;
741
742 dev_dbg(&client->dev, "bpp %d, compressed %d\n",
743 fmt >> 8, (u8)fmt);
744
745 for (j = 0; j < ARRAY_SIZE(smiapp_csi_data_formats); j++) {
746 const struct smiapp_csi_data_format *f =
747 &smiapp_csi_data_formats[j];
748
749 if (f->pixel_order != SMIAPP_PIXEL_ORDER_GRBG)
750 continue;
751
752 if (f->width != fmt >> 8 || f->compressed != (u8)fmt)
753 continue;
754
755 dev_dbg(&client->dev, "jolly good! %d\n", j);
756
757 sensor->default_mbus_frame_fmts |= 1 << j;
758 if (!sensor->csi_format) {
759 sensor->csi_format = f;
760 sensor->internal_csi_format = f;
761 }
762 }
763 }
764
765 if (!sensor->csi_format) {
766 dev_err(&client->dev, "no supported mbus code found\n");
767 return -EINVAL;
768 }
769
770 smiapp_update_mbus_formats(sensor);
771
772 return 0;
773}
774
775static void smiapp_update_blanking(struct smiapp_sensor *sensor)
776{
777 struct v4l2_ctrl *vblank = sensor->vblank;
778 struct v4l2_ctrl *hblank = sensor->hblank;
779
780 vblank->minimum =
781 max_t(int,
782 sensor->limits[SMIAPP_LIMIT_MIN_FRAME_BLANKING_LINES],
783 sensor->limits[SMIAPP_LIMIT_MIN_FRAME_LENGTH_LINES_BIN] -
784 sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height);
785 vblank->maximum =
786 sensor->limits[SMIAPP_LIMIT_MAX_FRAME_LENGTH_LINES_BIN] -
787 sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height;
788
789 vblank->val = clamp_t(int, vblank->val,
790 vblank->minimum, vblank->maximum);
791 vblank->default_value = vblank->minimum;
792 vblank->val = vblank->val;
793 vblank->cur.val = vblank->val;
794
795 hblank->minimum =
796 max_t(int,
797 sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN] -
798 sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width,
799 sensor->limits[SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN]);
800 hblank->maximum =
801 sensor->limits[SMIAPP_LIMIT_MAX_LINE_LENGTH_PCK_BIN] -
802 sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width;
803
804 hblank->val = clamp_t(int, hblank->val,
805 hblank->minimum, hblank->maximum);
806 hblank->default_value = hblank->minimum;
807 hblank->val = hblank->val;
808 hblank->cur.val = hblank->val;
809
810 __smiapp_update_exposure_limits(sensor);
811}
812
813static int smiapp_update_mode(struct smiapp_sensor *sensor)
814{
815 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
816 unsigned int binning_mode;
817 int rval;
818
819 dev_dbg(&client->dev, "frame size: %dx%d\n",
820 sensor->src->crop[SMIAPP_PAD_SRC].width,
821 sensor->src->crop[SMIAPP_PAD_SRC].height);
822 dev_dbg(&client->dev, "csi format width: %d\n",
823 sensor->csi_format->width);
824
825 /* Binning has to be set up here; it affects limits */
826 if (sensor->binning_horizontal == 1 &&
827 sensor->binning_vertical == 1) {
828 binning_mode = 0;
829 } else {
830 u8 binning_type =
831 (sensor->binning_horizontal << 4)
832 | sensor->binning_vertical;
833
834 rval = smiapp_write(
835 client, SMIAPP_REG_U8_BINNING_TYPE, binning_type);
836 if (rval < 0)
837 return rval;
838
839 binning_mode = 1;
840 }
841 rval = smiapp_write(client, SMIAPP_REG_U8_BINNING_MODE, binning_mode);
842 if (rval < 0)
843 return rval;
844
845 /* Get updated limits due to binning */
846 rval = smiapp_get_limits_binning(sensor);
847 if (rval < 0)
848 return rval;
849
850 rval = smiapp_pll_update(sensor);
851 if (rval < 0)
852 return rval;
853
854 /* Output from pixel array, including blanking */
855 smiapp_update_blanking(sensor);
856
857 dev_dbg(&client->dev, "vblank\t\t%d\n", sensor->vblank->val);
858 dev_dbg(&client->dev, "hblank\t\t%d\n", sensor->hblank->val);
859
860 dev_dbg(&client->dev, "real timeperframe\t100/%d\n",
861 sensor->pll.vt_pix_clk_freq_hz /
862 ((sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width
863 + sensor->hblank->val) *
864 (sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
865 + sensor->vblank->val) / 100));
866
867 return 0;
868}
869
870/*
871 *
872 * SMIA++ NVM handling
873 *
874 */
875static int smiapp_read_nvm(struct smiapp_sensor *sensor,
876 unsigned char *nvm)
877{
878 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
879 u32 i, s, p, np, v;
880 int rval, rval2;
881
882 np = sensor->nvm_size / SMIAPP_NVM_PAGE_SIZE;
883 for (p = 0; p < np; p++) {
884 rval = smiapp_write(
885 client,
886 SMIAPP_REG_U8_DATA_TRANSFER_IF_1_PAGE_SELECT, p);
887 if (rval)
888 goto out;
889
890 rval = smiapp_write(client,
891 SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL,
892 SMIAPP_DATA_TRANSFER_IF_1_CTRL_EN |
893 SMIAPP_DATA_TRANSFER_IF_1_CTRL_RD_EN);
894 if (rval)
895 goto out;
896
897 for (i = 0; i < 1000; i++) {
898 rval = smiapp_read(
899 client,
900 SMIAPP_REG_U8_DATA_TRANSFER_IF_1_STATUS, &s);
901
902 if (rval)
903 goto out;
904
905 if (s & SMIAPP_DATA_TRANSFER_IF_1_STATUS_RD_READY)
906 break;
907
908 if (--i == 0) {
909 rval = -ETIMEDOUT;
910 goto out;
911 }
912
913 }
914
915 for (i = 0; i < SMIAPP_NVM_PAGE_SIZE; i++) {
916 rval = smiapp_read(
917 client,
918 SMIAPP_REG_U8_DATA_TRANSFER_IF_1_DATA_0 + i,
919 &v);
920 if (rval)
921 goto out;
922
923 *nvm++ = v;
924 }
925 }
926
927out:
928 rval2 = smiapp_write(client, SMIAPP_REG_U8_DATA_TRANSFER_IF_1_CTRL, 0);
929 if (rval < 0)
930 return rval;
931 else
932 return rval2;
933}
934
935/*
936 *
937 * SMIA++ CCI address control
938 *
939 */
940static int smiapp_change_cci_addr(struct smiapp_sensor *sensor)
941{
942 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
943 int rval;
944 u32 val;
945
946 client->addr = sensor->platform_data->i2c_addr_dfl;
947
948 rval = smiapp_write(client,
949 SMIAPP_REG_U8_CCI_ADDRESS_CONTROL,
950 sensor->platform_data->i2c_addr_alt << 1);
951 if (rval)
952 return rval;
953
954 client->addr = sensor->platform_data->i2c_addr_alt;
955
956 /* verify addr change went ok */
957 rval = smiapp_read(client, SMIAPP_REG_U8_CCI_ADDRESS_CONTROL, &val);
958 if (rval)
959 return rval;
960
961 if (val != sensor->platform_data->i2c_addr_alt << 1)
962 return -ENODEV;
963
964 return 0;
965}
966
967/*
968 *
969 * SMIA++ Mode Control
970 *
971 */
972static int smiapp_setup_flash_strobe(struct smiapp_sensor *sensor)
973{
974 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
975 struct smiapp_flash_strobe_parms *strobe_setup;
976 unsigned int ext_freq = sensor->platform_data->ext_clk;
977 u32 tmp;
978 u32 strobe_adjustment;
979 u32 strobe_width_high_rs;
980 int rval;
981
982 strobe_setup = sensor->platform_data->strobe_setup;
983
984 /*
985 * How to calculate registers related to strobe length. Please
986 * do not change, or if you do at least know what you're
987 * doing. :-)
988 *
989 * Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> 2010-10-25
990 *
991 * flash_strobe_length [us] / 10^6 = (tFlash_strobe_width_ctrl
992 * / EXTCLK freq [Hz]) * flash_strobe_adjustment
993 *
994 * tFlash_strobe_width_ctrl E N, [1 - 0xffff]
995 * flash_strobe_adjustment E N, [1 - 0xff]
996 *
997 * The formula above is written as below to keep it on one
998 * line:
999 *
1000 * l / 10^6 = w / e * a
1001 *
1002 * Let's mark w * a by x:
1003 *
1004 * x = w * a
1005 *
1006 * Thus, we get:
1007 *
1008 * x = l * e / 10^6
1009 *
1010 * The strobe width must be at least as long as requested,
1011 * thus rounding upwards is needed.
1012 *
1013 * x = (l * e + 10^6 - 1) / 10^6
1014 * -----------------------------
1015 *
1016 * Maximum possible accuracy is wanted at all times. Thus keep
1017 * a as small as possible.
1018 *
1019 * Calculate a, assuming maximum w, with rounding upwards:
1020 *
1021 * a = (x + (2^16 - 1) - 1) / (2^16 - 1)
1022 * -------------------------------------
1023 *
1024 * Thus, we also get w, with that a, with rounding upwards:
1025 *
1026 * w = (x + a - 1) / a
1027 * -------------------
1028 *
1029 * To get limits:
1030 *
1031 * x E [1, (2^16 - 1) * (2^8 - 1)]
1032 *
1033 * Substituting maximum x to the original formula (with rounding),
1034 * the maximum l is thus
1035 *
1036 * (2^16 - 1) * (2^8 - 1) * 10^6 = l * e + 10^6 - 1
1037 *
1038 * l = (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / e
1039 * --------------------------------------------------
1040 *
1041 * flash_strobe_length must be clamped between 1 and
1042 * (10^6 * (2^16 - 1) * (2^8 - 1) - 10^6 + 1) / EXTCLK freq.
1043 *
1044 * Then,
1045 *
1046 * flash_strobe_adjustment = ((flash_strobe_length *
1047 * EXTCLK freq + 10^6 - 1) / 10^6 + (2^16 - 1) - 1) / (2^16 - 1)
1048 *
1049 * tFlash_strobe_width_ctrl = ((flash_strobe_length *
1050 * EXTCLK freq + 10^6 - 1) / 10^6 +
1051 * flash_strobe_adjustment - 1) / flash_strobe_adjustment
1052 */
1053 tmp = div_u64(1000000ULL * ((1 << 16) - 1) * ((1 << 8) - 1) -
1054 1000000 + 1, ext_freq);
1055 strobe_setup->strobe_width_high_us =
1056 clamp_t(u32, strobe_setup->strobe_width_high_us, 1, tmp);
1057
1058 tmp = div_u64(((u64)strobe_setup->strobe_width_high_us * (u64)ext_freq +
1059 1000000 - 1), 1000000ULL);
1060 strobe_adjustment = (tmp + (1 << 16) - 1 - 1) / ((1 << 16) - 1);
1061 strobe_width_high_rs = (tmp + strobe_adjustment - 1) /
1062 strobe_adjustment;
1063
1064 rval = smiapp_write(client, SMIAPP_REG_U8_FLASH_MODE_RS,
1065 strobe_setup->mode);
1066 if (rval < 0)
1067 goto out;
1068
1069 rval = smiapp_write(client, SMIAPP_REG_U8_FLASH_STROBE_ADJUSTMENT,
1070 strobe_adjustment);
1071 if (rval < 0)
1072 goto out;
1073
1074 rval = smiapp_write(
1075 client, SMIAPP_REG_U16_TFLASH_STROBE_WIDTH_HIGH_RS_CTRL,
1076 strobe_width_high_rs);
1077 if (rval < 0)
1078 goto out;
1079
1080 rval = smiapp_write(client, SMIAPP_REG_U16_TFLASH_STROBE_DELAY_RS_CTRL,
1081 strobe_setup->strobe_delay);
1082 if (rval < 0)
1083 goto out;
1084
1085 rval = smiapp_write(client, SMIAPP_REG_U16_FLASH_STROBE_START_POINT,
1086 strobe_setup->stobe_start_point);
1087 if (rval < 0)
1088 goto out;
1089
1090 rval = smiapp_write(client, SMIAPP_REG_U8_FLASH_TRIGGER_RS,
1091 strobe_setup->trigger);
1092
1093out:
1094 sensor->platform_data->strobe_setup->trigger = 0;
1095
1096 return rval;
1097}
1098
1099/* -----------------------------------------------------------------------------
1100 * Power management
1101 */
1102
1103static int smiapp_power_on(struct smiapp_sensor *sensor)
1104{
1105 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
1106 unsigned int sleep;
1107 int rval;
1108
1109 rval = regulator_enable(sensor->vana);
1110 if (rval) {
1111 dev_err(&client->dev, "failed to enable vana regulator\n");
1112 return rval;
1113 }
1114 usleep_range(1000, 1000);
1115
1116 rval = sensor->platform_data->set_xclk(&sensor->src->sd,
1117 sensor->platform_data->ext_clk);
1118 if (rval < 0) {
1119 dev_dbg(&client->dev, "failed to set xclk\n");
1120 goto out_xclk_fail;
1121 }
1122 usleep_range(1000, 1000);
1123
1124 if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
1125 gpio_set_value(sensor->platform_data->xshutdown, 1);
1126
1127 sleep = SMIAPP_RESET_DELAY(sensor->platform_data->ext_clk);
1128 usleep_range(sleep, sleep);
1129
1130 /*
1131 * Failures to respond to the address change command have been noticed.
1132 * Those failures seem to be caused by the sensor requiring a longer
1133 * boot time than advertised. An additional 10ms delay seems to work
1134 * around the issue, but the SMIA++ I2C write retry hack makes the delay
1135 * unnecessary. The failures need to be investigated to find a proper
1136 * fix, and a delay will likely need to be added here if the I2C write
1137 * retry hack is reverted before the root cause of the boot time issue
1138 * is found.
1139 */
1140
1141 if (sensor->platform_data->i2c_addr_alt) {
1142 rval = smiapp_change_cci_addr(sensor);
1143 if (rval) {
1144 dev_err(&client->dev, "cci address change error\n");
1145 goto out_cci_addr_fail;
1146 }
1147 }
1148
1149 rval = smiapp_write(client, SMIAPP_REG_U8_SOFTWARE_RESET,
1150 SMIAPP_SOFTWARE_RESET);
1151 if (rval < 0) {
1152 dev_err(&client->dev, "software reset failed\n");
1153 goto out_cci_addr_fail;
1154 }
1155
1156 if (sensor->platform_data->i2c_addr_alt) {
1157 rval = smiapp_change_cci_addr(sensor);
1158 if (rval) {
1159 dev_err(&client->dev, "cci address change error\n");
1160 goto out_cci_addr_fail;
1161 }
1162 }
1163
1164 rval = smiapp_write(client, SMIAPP_REG_U16_COMPRESSION_MODE,
1165 SMIAPP_COMPRESSION_MODE_SIMPLE_PREDICTOR);
1166 if (rval) {
1167 dev_err(&client->dev, "compression mode set failed\n");
1168 goto out_cci_addr_fail;
1169 }
1170
1171 rval = smiapp_write(
1172 client, SMIAPP_REG_U16_EXTCLK_FREQUENCY_MHZ,
1173 sensor->platform_data->ext_clk / (1000000 / (1 << 8)));
1174 if (rval) {
1175 dev_err(&client->dev, "extclk frequency set failed\n");
1176 goto out_cci_addr_fail;
1177 }
1178
1179 rval = smiapp_write(client, SMIAPP_REG_U8_CSI_LANE_MODE,
1180 sensor->platform_data->lanes - 1);
1181 if (rval) {
1182 dev_err(&client->dev, "csi lane mode set failed\n");
1183 goto out_cci_addr_fail;
1184 }
1185
1186 rval = smiapp_write(client, SMIAPP_REG_U8_FAST_STANDBY_CTRL,
1187 SMIAPP_FAST_STANDBY_CTRL_IMMEDIATE);
1188 if (rval) {
1189 dev_err(&client->dev, "fast standby set failed\n");
1190 goto out_cci_addr_fail;
1191 }
1192
1193 rval = smiapp_write(client, SMIAPP_REG_U8_CSI_SIGNALLING_MODE,
1194 sensor->platform_data->csi_signalling_mode);
1195 if (rval) {
1196 dev_err(&client->dev, "csi signalling mode set failed\n");
1197 goto out_cci_addr_fail;
1198 }
1199
1200 /* DPHY control done by sensor based on requested link rate */
1201 rval = smiapp_write(client, SMIAPP_REG_U8_DPHY_CTRL,
1202 SMIAPP_DPHY_CTRL_UI);
1203 if (rval < 0)
1204 return rval;
1205
1206 rval = smiapp_call_quirk(sensor, post_poweron);
1207 if (rval) {
1208 dev_err(&client->dev, "post_poweron quirks failed\n");
1209 goto out_cci_addr_fail;
1210 }
1211
1212 /* Are we still initialising...? If yes, return here. */
1213 if (!sensor->pixel_array)
1214 return 0;
1215
1216 rval = v4l2_ctrl_handler_setup(
1217 &sensor->pixel_array->ctrl_handler);
1218 if (rval)
1219 goto out_cci_addr_fail;
1220
1221 rval = v4l2_ctrl_handler_setup(&sensor->src->ctrl_handler);
1222 if (rval)
1223 goto out_cci_addr_fail;
1224
1225 mutex_lock(&sensor->mutex);
1226 rval = smiapp_update_mode(sensor);
1227 mutex_unlock(&sensor->mutex);
1228 if (rval < 0)
1229 goto out_cci_addr_fail;
1230
1231 return 0;
1232
1233out_cci_addr_fail:
1234 if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
1235 gpio_set_value(sensor->platform_data->xshutdown, 0);
1236 sensor->platform_data->set_xclk(&sensor->src->sd, 0);
1237
1238out_xclk_fail:
1239 regulator_disable(sensor->vana);
1240 return rval;
1241}
1242
1243static void smiapp_power_off(struct smiapp_sensor *sensor)
1244{
1245 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
1246
1247 /*
1248 * Currently power/clock to lens are enable/disabled separately
1249 * but they are essentially the same signals. So if the sensor is
1250 * powered off while the lens is powered on the sensor does not
1251 * really see a power off and next time the cci address change
1252 * will fail. So do a soft reset explicitly here.
1253 */
1254 if (sensor->platform_data->i2c_addr_alt)
1255 smiapp_write(client,
1256 SMIAPP_REG_U8_SOFTWARE_RESET,
1257 SMIAPP_SOFTWARE_RESET);
1258
1259 if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
1260 gpio_set_value(sensor->platform_data->xshutdown, 0);
1261 sensor->platform_data->set_xclk(&sensor->src->sd, 0);
1262 usleep_range(5000, 5000);
1263 regulator_disable(sensor->vana);
1264 sensor->streaming = 0;
1265}
1266
1267static int smiapp_set_power(struct v4l2_subdev *subdev, int on)
1268{
1269 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
1270 int ret = 0;
1271
1272 mutex_lock(&sensor->power_mutex);
1273
1274 /*
1275 * If the power count is modified from 0 to != 0 or from != 0
1276 * to 0, update the power state.
1277 */
1278 if (!sensor->power_count == !on)
1279 goto out;
1280
1281 if (on) {
1282 /* Power on and perform initialisation. */
1283 ret = smiapp_power_on(sensor);
1284 if (ret < 0)
1285 goto out;
1286 } else {
1287 smiapp_power_off(sensor);
1288 }
1289
1290 /* Update the power count. */
1291 sensor->power_count += on ? 1 : -1;
1292 WARN_ON(sensor->power_count < 0);
1293
1294out:
1295 mutex_unlock(&sensor->power_mutex);
1296 return ret;
1297}
1298
1299/* -----------------------------------------------------------------------------
1300 * Video stream management
1301 */
1302
1303static int smiapp_start_streaming(struct smiapp_sensor *sensor)
1304{
1305 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
1306 int rval;
1307
1308 mutex_lock(&sensor->mutex);
1309
1310 rval = smiapp_write(client, SMIAPP_REG_U16_CSI_DATA_FORMAT,
1311 (sensor->csi_format->width << 8) |
1312 sensor->csi_format->compressed);
1313 if (rval)
1314 goto out;
1315
1316 rval = smiapp_pll_configure(sensor);
1317 if (rval)
1318 goto out;
1319
1320 /* Analog crop start coordinates */
1321 rval = smiapp_write(client, SMIAPP_REG_U16_X_ADDR_START,
1322 sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left);
1323 if (rval < 0)
1324 goto out;
1325
1326 rval = smiapp_write(client, SMIAPP_REG_U16_Y_ADDR_START,
1327 sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top);
1328 if (rval < 0)
1329 goto out;
1330
1331 /* Analog crop end coordinates */
1332 rval = smiapp_write(
1333 client, SMIAPP_REG_U16_X_ADDR_END,
1334 sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].left
1335 + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width - 1);
1336 if (rval < 0)
1337 goto out;
1338
1339 rval = smiapp_write(
1340 client, SMIAPP_REG_U16_Y_ADDR_END,
1341 sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].top
1342 + sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height - 1);
1343 if (rval < 0)
1344 goto out;
1345
1346 /*
1347 * Output from pixel array, including blanking, is set using
1348 * controls below. No need to set here.
1349 */
1350
1351 /* Digital crop */
1352 if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
1353 == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
1354 rval = smiapp_write(
1355 client, SMIAPP_REG_U16_DIGITAL_CROP_X_OFFSET,
1356 sensor->scaler->crop[SMIAPP_PAD_SINK].left);
1357 if (rval < 0)
1358 goto out;
1359
1360 rval = smiapp_write(
1361 client, SMIAPP_REG_U16_DIGITAL_CROP_Y_OFFSET,
1362 sensor->scaler->crop[SMIAPP_PAD_SINK].top);
1363 if (rval < 0)
1364 goto out;
1365
1366 rval = smiapp_write(
1367 client, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_WIDTH,
1368 sensor->scaler->crop[SMIAPP_PAD_SINK].width);
1369 if (rval < 0)
1370 goto out;
1371
1372 rval = smiapp_write(
1373 client, SMIAPP_REG_U16_DIGITAL_CROP_IMAGE_HEIGHT,
1374 sensor->scaler->crop[SMIAPP_PAD_SINK].height);
1375 if (rval < 0)
1376 goto out;
1377 }
1378
1379 /* Scaling */
1380 if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
1381 != SMIAPP_SCALING_CAPABILITY_NONE) {
1382 rval = smiapp_write(client, SMIAPP_REG_U16_SCALING_MODE,
1383 sensor->scaling_mode);
1384 if (rval < 0)
1385 goto out;
1386
1387 rval = smiapp_write(client, SMIAPP_REG_U16_SCALE_M,
1388 sensor->scale_m);
1389 if (rval < 0)
1390 goto out;
1391 }
1392
1393 /* Output size from sensor */
1394 rval = smiapp_write(client, SMIAPP_REG_U16_X_OUTPUT_SIZE,
1395 sensor->src->crop[SMIAPP_PAD_SRC].width);
1396 if (rval < 0)
1397 goto out;
1398 rval = smiapp_write(client, SMIAPP_REG_U16_Y_OUTPUT_SIZE,
1399 sensor->src->crop[SMIAPP_PAD_SRC].height);
1400 if (rval < 0)
1401 goto out;
1402
1403 if ((sensor->flash_capability &
1404 (SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE |
1405 SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) &&
1406 sensor->platform_data->strobe_setup != NULL &&
1407 sensor->platform_data->strobe_setup->trigger != 0) {
1408 rval = smiapp_setup_flash_strobe(sensor);
1409 if (rval)
1410 goto out;
1411 }
1412
1413 rval = smiapp_call_quirk(sensor, pre_streamon);
1414 if (rval) {
1415 dev_err(&client->dev, "pre_streamon quirks failed\n");
1416 goto out;
1417 }
1418
1419 rval = smiapp_write(client, SMIAPP_REG_U8_MODE_SELECT,
1420 SMIAPP_MODE_SELECT_STREAMING);
1421
1422out:
1423 mutex_unlock(&sensor->mutex);
1424
1425 return rval;
1426}
1427
1428static int smiapp_stop_streaming(struct smiapp_sensor *sensor)
1429{
1430 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
1431 int rval;
1432
1433 mutex_lock(&sensor->mutex);
1434 rval = smiapp_write(client, SMIAPP_REG_U8_MODE_SELECT,
1435 SMIAPP_MODE_SELECT_SOFTWARE_STANDBY);
1436 if (rval)
1437 goto out;
1438
1439 rval = smiapp_call_quirk(sensor, post_streamoff);
1440 if (rval)
1441 dev_err(&client->dev, "post_streamoff quirks failed\n");
1442
1443out:
1444 mutex_unlock(&sensor->mutex);
1445 return rval;
1446}
1447
1448/* -----------------------------------------------------------------------------
1449 * V4L2 subdev video operations
1450 */
1451
1452static int smiapp_set_stream(struct v4l2_subdev *subdev, int enable)
1453{
1454 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
1455 int rval;
1456
1457 if (sensor->streaming == enable)
1458 return 0;
1459
1460 if (enable) {
1461 sensor->streaming = 1;
1462 rval = smiapp_start_streaming(sensor);
1463 if (rval < 0)
1464 sensor->streaming = 0;
1465 } else {
1466 rval = smiapp_stop_streaming(sensor);
1467 sensor->streaming = 0;
1468 }
1469
1470 return rval;
1471}
1472
1473static int smiapp_enum_mbus_code(struct v4l2_subdev *subdev,
1474 struct v4l2_subdev_fh *fh,
1475 struct v4l2_subdev_mbus_code_enum *code)
1476{
1477 struct i2c_client *client = v4l2_get_subdevdata(subdev);
1478 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
1479 unsigned int i;
1480 int idx = -1;
1481 int rval = -EINVAL;
1482
1483 mutex_lock(&sensor->mutex);
1484
1485 dev_err(&client->dev, "subdev %s, pad %d, index %d\n",
1486 subdev->name, code->pad, code->index);
1487
1488 if (subdev != &sensor->src->sd || code->pad != SMIAPP_PAD_SRC) {
1489 if (code->index)
1490 goto out;
1491
1492 code->code = sensor->internal_csi_format->code;
1493 rval = 0;
1494 goto out;
1495 }
1496
1497 for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
1498 if (sensor->mbus_frame_fmts & (1 << i))
1499 idx++;
1500
1501 if (idx == code->index) {
1502 code->code = smiapp_csi_data_formats[i].code;
1503 dev_err(&client->dev, "found index %d, i %d, code %x\n",
1504 code->index, i, code->code);
1505 rval = 0;
1506 break;
1507 }
1508 }
1509
1510out:
1511 mutex_unlock(&sensor->mutex);
1512
1513 return rval;
1514}
1515
1516static u32 __smiapp_get_mbus_code(struct v4l2_subdev *subdev,
1517 unsigned int pad)
1518{
1519 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
1520
1521 if (subdev == &sensor->src->sd && pad == SMIAPP_PAD_SRC)
1522 return sensor->csi_format->code;
1523 else
1524 return sensor->internal_csi_format->code;
1525}
1526
1527static int __smiapp_get_format(struct v4l2_subdev *subdev,
1528 struct v4l2_subdev_fh *fh,
1529 struct v4l2_subdev_format *fmt)
1530{
1531 struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
1532
1533 if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
1534 fmt->format = *v4l2_subdev_get_try_format(fh, fmt->pad);
1535 } else {
1536 struct v4l2_rect *r;
1537
1538 if (fmt->pad == ssd->source_pad)
1539 r = &ssd->crop[ssd->source_pad];
1540 else
1541 r = &ssd->sink_fmt;
1542
1543 fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad);
1544 fmt->format.width = r->width;
1545 fmt->format.height = r->height;
1546 }
1547
1548 return 0;
1549}
1550
1551static int smiapp_get_format(struct v4l2_subdev *subdev,
1552 struct v4l2_subdev_fh *fh,
1553 struct v4l2_subdev_format *fmt)
1554{
1555 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
1556 int rval;
1557
1558 mutex_lock(&sensor->mutex);
1559 rval = __smiapp_get_format(subdev, fh, fmt);
1560 mutex_unlock(&sensor->mutex);
1561
1562 return rval;
1563}
1564
1565static void smiapp_get_crop_compose(struct v4l2_subdev *subdev,
1566 struct v4l2_subdev_fh *fh,
1567 struct v4l2_rect **crops,
1568 struct v4l2_rect **comps, int which)
1569{
1570 struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
1571 unsigned int i;
1572
1573 if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1574 if (crops)
1575 for (i = 0; i < subdev->entity.num_pads; i++)
1576 crops[i] = &ssd->crop[i];
1577 if (comps)
1578 *comps = &ssd->compose;
1579 } else {
1580 if (crops) {
1581 for (i = 0; i < subdev->entity.num_pads; i++) {
1582 crops[i] = v4l2_subdev_get_try_crop(fh, i);
1583 BUG_ON(!crops[i]);
1584 }
1585 }
1586 if (comps) {
1587 *comps = v4l2_subdev_get_try_compose(fh,
1588 SMIAPP_PAD_SINK);
1589 BUG_ON(!*comps);
1590 }
1591 }
1592}
1593
1594/* Changes require propagation only on sink pad. */
1595static void smiapp_propagate(struct v4l2_subdev *subdev,
1596 struct v4l2_subdev_fh *fh, int which,
1597 int target)
1598{
1599 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
1600 struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
1601 struct v4l2_rect *comp, *crops[SMIAPP_PADS];
1602
1603 smiapp_get_crop_compose(subdev, fh, crops, &comp, which);
1604
1605 switch (target) {
1606 case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
1607 comp->width = crops[SMIAPP_PAD_SINK]->width;
1608 comp->height = crops[SMIAPP_PAD_SINK]->height;
1609 if (which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1610 if (ssd == sensor->scaler) {
1611 sensor->scale_m =
1612 sensor->limits[
1613 SMIAPP_LIMIT_SCALER_N_MIN];
1614 sensor->scaling_mode =
1615 SMIAPP_SCALING_MODE_NONE;
1616 } else if (ssd == sensor->binner) {
1617 sensor->binning_horizontal = 1;
1618 sensor->binning_vertical = 1;
1619 }
1620 }
1621 /* Fall through */
1622 case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
1623 *crops[SMIAPP_PAD_SRC] = *comp;
1624 break;
1625 default:
1626 BUG();
1627 }
1628}
1629
1630static const struct smiapp_csi_data_format
1631*smiapp_validate_csi_data_format(struct smiapp_sensor *sensor, u32 code)
1632{
1633 const struct smiapp_csi_data_format *csi_format = sensor->csi_format;
1634 unsigned int i;
1635
1636 for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
1637 if (sensor->mbus_frame_fmts & (1 << i)
1638 && smiapp_csi_data_formats[i].code == code)
1639 return &smiapp_csi_data_formats[i];
1640 }
1641
1642 return csi_format;
1643}
1644
1645static int smiapp_set_format(struct v4l2_subdev *subdev,
1646 struct v4l2_subdev_fh *fh,
1647 struct v4l2_subdev_format *fmt)
1648{
1649 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
1650 struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
1651 struct v4l2_rect *crops[SMIAPP_PADS];
1652
1653 mutex_lock(&sensor->mutex);
1654
1655 /*
1656 * Media bus code is changeable on src subdev's source pad. On
1657 * other source pads we just get format here.
1658 */
1659 if (fmt->pad == ssd->source_pad) {
1660 u32 code = fmt->format.code;
1661 int rval = __smiapp_get_format(subdev, fh, fmt);
1662
1663 if (!rval && subdev == &sensor->src->sd) {
1664 const struct smiapp_csi_data_format *csi_format =
1665 smiapp_validate_csi_data_format(sensor, code);
1666 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
1667 sensor->csi_format = csi_format;
1668 fmt->format.code = csi_format->code;
1669 }
1670
1671 mutex_unlock(&sensor->mutex);
1672 return rval;
1673 }
1674
1675 /* Sink pad. Width and height are changeable here. */
1676 fmt->format.code = __smiapp_get_mbus_code(subdev, fmt->pad);
1677 fmt->format.width &= ~1;
1678 fmt->format.height &= ~1;
1679
1680 fmt->format.width =
1681 clamp(fmt->format.width,
1682 sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
1683 sensor->limits[SMIAPP_LIMIT_MAX_X_OUTPUT_SIZE]);
1684 fmt->format.height =
1685 clamp(fmt->format.height,
1686 sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
1687 sensor->limits[SMIAPP_LIMIT_MAX_Y_OUTPUT_SIZE]);
1688
1689 smiapp_get_crop_compose(subdev, fh, crops, NULL, fmt->which);
1690
1691 crops[ssd->sink_pad]->left = 0;
1692 crops[ssd->sink_pad]->top = 0;
1693 crops[ssd->sink_pad]->width = fmt->format.width;
1694 crops[ssd->sink_pad]->height = fmt->format.height;
1695 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
1696 ssd->sink_fmt = *crops[ssd->sink_pad];
1697 smiapp_propagate(subdev, fh, fmt->which,
1698 V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL);
1699
1700 mutex_unlock(&sensor->mutex);
1701
1702 return 0;
1703}
1704
1705/*
1706 * Calculate goodness of scaled image size compared to expected image
1707 * size and flags provided.
1708 */
1709#define SCALING_GOODNESS 100000
1710#define SCALING_GOODNESS_EXTREME 100000000
1711static int scaling_goodness(struct v4l2_subdev *subdev, int w, int ask_w,
1712 int h, int ask_h, u32 flags)
1713{
1714 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
1715 struct i2c_client *client = v4l2_get_subdevdata(subdev);
1716 int val = 0;
1717
1718 w &= ~1;
1719 ask_w &= ~1;
1720 h &= ~1;
1721 ask_h &= ~1;
1722
1723 if (flags & V4L2_SUBDEV_SEL_FLAG_SIZE_GE) {
1724 if (w < ask_w)
1725 val -= SCALING_GOODNESS;
1726 if (h < ask_h)
1727 val -= SCALING_GOODNESS;
1728 }
1729
1730 if (flags & V4L2_SUBDEV_SEL_FLAG_SIZE_LE) {
1731 if (w > ask_w)
1732 val -= SCALING_GOODNESS;
1733 if (h > ask_h)
1734 val -= SCALING_GOODNESS;
1735 }
1736
1737 val -= abs(w - ask_w);
1738 val -= abs(h - ask_h);
1739
1740 if (w < sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE])
1741 val -= SCALING_GOODNESS_EXTREME;
1742
1743 dev_dbg(&client->dev, "w %d ask_w %d h %d ask_h %d goodness %d\n",
1744 w, ask_h, h, ask_h, val);
1745
1746 return val;
1747}
1748
1749static void smiapp_set_compose_binner(struct v4l2_subdev *subdev,
1750 struct v4l2_subdev_fh *fh,
1751 struct v4l2_subdev_selection *sel,
1752 struct v4l2_rect **crops,
1753 struct v4l2_rect *comp)
1754{
1755 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
1756 unsigned int i;
1757 unsigned int binh = 1, binv = 1;
1758 unsigned int best = scaling_goodness(
1759 subdev,
1760 crops[SMIAPP_PAD_SINK]->width, sel->r.width,
1761 crops[SMIAPP_PAD_SINK]->height, sel->r.height, sel->flags);
1762
1763 for (i = 0; i < sensor->nbinning_subtypes; i++) {
1764 int this = scaling_goodness(
1765 subdev,
1766 crops[SMIAPP_PAD_SINK]->width
1767 / sensor->binning_subtypes[i].horizontal,
1768 sel->r.width,
1769 crops[SMIAPP_PAD_SINK]->height
1770 / sensor->binning_subtypes[i].vertical,
1771 sel->r.height, sel->flags);
1772
1773 if (this > best) {
1774 binh = sensor->binning_subtypes[i].horizontal;
1775 binv = sensor->binning_subtypes[i].vertical;
1776 best = this;
1777 }
1778 }
1779 if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1780 sensor->binning_vertical = binv;
1781 sensor->binning_horizontal = binh;
1782 }
1783
1784 sel->r.width = (crops[SMIAPP_PAD_SINK]->width / binh) & ~1;
1785 sel->r.height = (crops[SMIAPP_PAD_SINK]->height / binv) & ~1;
1786}
1787
1788/*
1789 * Calculate best scaling ratio and mode for given output resolution.
1790 *
1791 * Try all of these: horizontal ratio, vertical ratio and smallest
1792 * size possible (horizontally).
1793 *
1794 * Also try whether horizontal scaler or full scaler gives a better
1795 * result.
1796 */
1797static void smiapp_set_compose_scaler(struct v4l2_subdev *subdev,
1798 struct v4l2_subdev_fh *fh,
1799 struct v4l2_subdev_selection *sel,
1800 struct v4l2_rect **crops,
1801 struct v4l2_rect *comp)
1802{
1803 struct i2c_client *client = v4l2_get_subdevdata(subdev);
1804 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
1805 u32 min, max, a, b, max_m;
1806 u32 scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
1807 int mode = SMIAPP_SCALING_MODE_HORIZONTAL;
1808 u32 try[4];
1809 u32 ntry = 0;
1810 unsigned int i;
1811 int best = INT_MIN;
1812
1813 sel->r.width = min_t(unsigned int, sel->r.width,
1814 crops[SMIAPP_PAD_SINK]->width);
1815 sel->r.height = min_t(unsigned int, sel->r.height,
1816 crops[SMIAPP_PAD_SINK]->height);
1817
1818 a = crops[SMIAPP_PAD_SINK]->width
1819 * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.width;
1820 b = crops[SMIAPP_PAD_SINK]->height
1821 * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN] / sel->r.height;
1822 max_m = crops[SMIAPP_PAD_SINK]->width
1823 * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]
1824 / sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE];
1825
1826 a = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
1827 max(a, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
1828 b = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
1829 max(b, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
1830 max_m = min(sensor->limits[SMIAPP_LIMIT_SCALER_M_MAX],
1831 max(max_m, sensor->limits[SMIAPP_LIMIT_SCALER_M_MIN]));
1832
1833 dev_dbg(&client->dev, "scaling: a %d b %d max_m %d\n", a, b, max_m);
1834
1835 min = min(max_m, min(a, b));
1836 max = min(max_m, max(a, b));
1837
1838 try[ntry] = min;
1839 ntry++;
1840 if (min != max) {
1841 try[ntry] = max;
1842 ntry++;
1843 }
1844 if (max != max_m) {
1845 try[ntry] = min + 1;
1846 ntry++;
1847 if (min != max) {
1848 try[ntry] = max + 1;
1849 ntry++;
1850 }
1851 }
1852
1853 for (i = 0; i < ntry; i++) {
1854 int this = scaling_goodness(
1855 subdev,
1856 crops[SMIAPP_PAD_SINK]->width
1857 / try[i]
1858 * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
1859 sel->r.width,
1860 crops[SMIAPP_PAD_SINK]->height,
1861 sel->r.height,
1862 sel->flags);
1863
1864 dev_dbg(&client->dev, "trying factor %d (%d)\n", try[i], i);
1865
1866 if (this > best) {
1867 scale_m = try[i];
1868 mode = SMIAPP_SCALING_MODE_HORIZONTAL;
1869 best = this;
1870 }
1871
1872 if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
1873 == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
1874 continue;
1875
1876 this = scaling_goodness(
1877 subdev, crops[SMIAPP_PAD_SINK]->width
1878 / try[i]
1879 * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
1880 sel->r.width,
1881 crops[SMIAPP_PAD_SINK]->height
1882 / try[i]
1883 * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN],
1884 sel->r.height,
1885 sel->flags);
1886
1887 if (this > best) {
1888 scale_m = try[i];
1889 mode = SMIAPP_SCALING_MODE_BOTH;
1890 best = this;
1891 }
1892 }
1893
1894 sel->r.width =
1895 (crops[SMIAPP_PAD_SINK]->width
1896 / scale_m
1897 * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN]) & ~1;
1898 if (mode == SMIAPP_SCALING_MODE_BOTH)
1899 sel->r.height =
1900 (crops[SMIAPP_PAD_SINK]->height
1901 / scale_m
1902 * sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN])
1903 & ~1;
1904 else
1905 sel->r.height = crops[SMIAPP_PAD_SINK]->height;
1906
1907 if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1908 sensor->scale_m = scale_m;
1909 sensor->scaling_mode = mode;
1910 }
1911}
1912/* We're only called on source pads. This function sets scaling. */
1913static int smiapp_set_compose(struct v4l2_subdev *subdev,
1914 struct v4l2_subdev_fh *fh,
1915 struct v4l2_subdev_selection *sel)
1916{
1917 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
1918 struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
1919 struct v4l2_rect *comp, *crops[SMIAPP_PADS];
1920
1921 smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which);
1922
1923 sel->r.top = 0;
1924 sel->r.left = 0;
1925
1926 if (ssd == sensor->binner)
1927 smiapp_set_compose_binner(subdev, fh, sel, crops, comp);
1928 else
1929 smiapp_set_compose_scaler(subdev, fh, sel, crops, comp);
1930
1931 *comp = sel->r;
1932 smiapp_propagate(subdev, fh, sel->which,
1933 V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL);
1934
1935 if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
1936 return smiapp_update_mode(sensor);
1937
1938 return 0;
1939}
1940
1941static int __smiapp_sel_supported(struct v4l2_subdev *subdev,
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
1947 /* We only implement crop in three places. */
1948 switch (sel->target) {
1949 case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
1950 case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
1951 if (ssd == sensor->pixel_array
1952 && sel->pad == SMIAPP_PA_PAD_SRC)
1953 return 0;
1954 if (ssd == sensor->src
1955 && sel->pad == SMIAPP_PAD_SRC)
1956 return 0;
1957 if (ssd == sensor->scaler
1958 && sel->pad == SMIAPP_PAD_SINK
1959 && sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
1960 == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP)
1961 return 0;
1962 return -EINVAL;
1963 case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
1964 case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS:
1965 if (sel->pad == ssd->source_pad)
1966 return -EINVAL;
1967 if (ssd == sensor->binner)
1968 return 0;
1969 if (ssd == sensor->scaler
1970 && sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
1971 != SMIAPP_SCALING_CAPABILITY_NONE)
1972 return 0;
1973 /* Fall through */
1974 default:
1975 return -EINVAL;
1976 }
1977}
1978
1979static int smiapp_set_crop(struct v4l2_subdev *subdev,
1980 struct v4l2_subdev_fh *fh,
1981 struct v4l2_subdev_selection *sel)
1982{
1983 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
1984 struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
1985 struct v4l2_rect *src_size, *crops[SMIAPP_PADS];
1986 struct v4l2_rect _r;
1987
1988 smiapp_get_crop_compose(subdev, fh, crops, NULL, sel->which);
1989
1990 if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
1991 if (sel->pad == ssd->sink_pad)
1992 src_size = &ssd->sink_fmt;
1993 else
1994 src_size = &ssd->compose;
1995 } else {
1996 if (sel->pad == ssd->sink_pad) {
1997 _r.left = 0;
1998 _r.top = 0;
1999 _r.width = v4l2_subdev_get_try_format(fh, sel->pad)
2000 ->width;
2001 _r.height = v4l2_subdev_get_try_format(fh, sel->pad)
2002 ->height;
2003 src_size = &_r;
2004 } else {
2005 src_size =
2006 v4l2_subdev_get_try_compose(
2007 fh, ssd->sink_pad);
2008 }
2009 }
2010
2011 if (ssd == sensor->src && sel->pad == SMIAPP_PAD_SRC) {
2012 sel->r.left = 0;
2013 sel->r.top = 0;
2014 }
2015
2016 sel->r.width = min(sel->r.width, src_size->width);
2017 sel->r.height = min(sel->r.height, src_size->height);
2018
2019 sel->r.left = min(sel->r.left, src_size->width - sel->r.width);
2020 sel->r.top = min(sel->r.top, src_size->height - sel->r.height);
2021
2022 *crops[sel->pad] = sel->r;
2023
2024 if (ssd != sensor->pixel_array && sel->pad == SMIAPP_PAD_SINK)
2025 smiapp_propagate(subdev, fh, sel->which,
2026 V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL);
2027
2028 return 0;
2029}
2030
2031static int __smiapp_get_selection(struct v4l2_subdev *subdev,
2032 struct v4l2_subdev_fh *fh,
2033 struct v4l2_subdev_selection *sel)
2034{
2035 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
2036 struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
2037 struct v4l2_rect *comp, *crops[SMIAPP_PADS];
2038 struct v4l2_rect sink_fmt;
2039 int ret;
2040
2041 ret = __smiapp_sel_supported(subdev, sel);
2042 if (ret)
2043 return ret;
2044
2045 smiapp_get_crop_compose(subdev, fh, crops, &comp, sel->which);
2046
2047 if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
2048 sink_fmt = ssd->sink_fmt;
2049 } else {
2050 struct v4l2_mbus_framefmt *fmt =
2051 v4l2_subdev_get_try_format(fh, ssd->sink_pad);
2052
2053 sink_fmt.left = 0;
2054 sink_fmt.top = 0;
2055 sink_fmt.width = fmt->width;
2056 sink_fmt.height = fmt->height;
2057 }
2058
2059 switch (sel->target) {
2060 case V4L2_SUBDEV_SEL_TGT_CROP_BOUNDS:
2061 if (ssd == sensor->pixel_array) {
2062 sel->r.width =
2063 sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
2064 sel->r.height =
2065 sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
2066 } else if (sel->pad == ssd->sink_pad) {
2067 sel->r = sink_fmt;
2068 } else {
2069 sel->r = *comp;
2070 }
2071 break;
2072 case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
2073 case V4L2_SUBDEV_SEL_TGT_COMPOSE_BOUNDS:
2074 sel->r = *crops[sel->pad];
2075 break;
2076 case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
2077 sel->r = *comp;
2078 break;
2079 }
2080
2081 return 0;
2082}
2083
2084static int smiapp_get_selection(struct v4l2_subdev *subdev,
2085 struct v4l2_subdev_fh *fh,
2086 struct v4l2_subdev_selection *sel)
2087{
2088 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
2089 int rval;
2090
2091 mutex_lock(&sensor->mutex);
2092 rval = __smiapp_get_selection(subdev, fh, sel);
2093 mutex_unlock(&sensor->mutex);
2094
2095 return rval;
2096}
2097static int smiapp_set_selection(struct v4l2_subdev *subdev,
2098 struct v4l2_subdev_fh *fh,
2099 struct v4l2_subdev_selection *sel)
2100{
2101 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
2102 int ret;
2103
2104 ret = __smiapp_sel_supported(subdev, sel);
2105 if (ret)
2106 return ret;
2107
2108 mutex_lock(&sensor->mutex);
2109
2110 sel->r.left = max(0, sel->r.left & ~1);
2111 sel->r.top = max(0, sel->r.top & ~1);
2112 sel->r.width = max(0, SMIAPP_ALIGN_DIM(sel->r.width, sel->flags));
2113 sel->r.height = max(0, SMIAPP_ALIGN_DIM(sel->r.height, sel->flags));
2114
2115 sel->r.width = max_t(unsigned int,
2116 sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
2117 sel->r.width);
2118 sel->r.height = max_t(unsigned int,
2119 sensor->limits[SMIAPP_LIMIT_MIN_Y_OUTPUT_SIZE],
2120 sel->r.height);
2121
2122 switch (sel->target) {
2123 case V4L2_SUBDEV_SEL_TGT_CROP_ACTUAL:
2124 ret = smiapp_set_crop(subdev, fh, sel);
2125 break;
2126 case V4L2_SUBDEV_SEL_TGT_COMPOSE_ACTUAL:
2127 ret = smiapp_set_compose(subdev, fh, sel);
2128 break;
2129 default:
2130 BUG();
2131 }
2132
2133 mutex_unlock(&sensor->mutex);
2134 return ret;
2135}
2136
2137static int smiapp_get_skip_frames(struct v4l2_subdev *subdev, u32 *frames)
2138{
2139 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
2140
2141 *frames = sensor->frame_skip;
2142 return 0;
2143}
2144
2145/* -----------------------------------------------------------------------------
2146 * sysfs attributes
2147 */
2148
2149static ssize_t
2150smiapp_sysfs_nvm_read(struct device *dev, struct device_attribute *attr,
2151 char *buf)
2152{
2153 struct v4l2_subdev *subdev = i2c_get_clientdata(to_i2c_client(dev));
2154 struct i2c_client *client = v4l2_get_subdevdata(subdev);
2155 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
2156 unsigned int nbytes;
2157
2158 if (!sensor->dev_init_done)
2159 return -EBUSY;
2160
2161 if (!sensor->nvm_size) {
2162 /* NVM not read yet - read it now */
2163 sensor->nvm_size = sensor->platform_data->nvm_size;
2164 if (smiapp_set_power(subdev, 1) < 0)
2165 return -ENODEV;
2166 if (smiapp_read_nvm(sensor, sensor->nvm)) {
2167 dev_err(&client->dev, "nvm read failed\n");
2168 return -ENODEV;
2169 }
2170 smiapp_set_power(subdev, 0);
2171 }
2172 /*
2173 * NVM is still way below a PAGE_SIZE, so we can safely
2174 * assume this for now.
2175 */
2176 nbytes = min_t(unsigned int, sensor->nvm_size, PAGE_SIZE);
2177 memcpy(buf, sensor->nvm, nbytes);
2178
2179 return nbytes;
2180}
2181static DEVICE_ATTR(nvm, S_IRUGO, smiapp_sysfs_nvm_read, NULL);
2182
2183/* -----------------------------------------------------------------------------
2184 * V4L2 subdev core operations
2185 */
2186
2187static int smiapp_identify_module(struct v4l2_subdev *subdev)
2188{
2189 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
2190 struct i2c_client *client = v4l2_get_subdevdata(subdev);
2191 struct smiapp_module_info *minfo = &sensor->minfo;
2192 unsigned int i;
2193 int rval = 0;
2194
2195 minfo->name = SMIAPP_NAME;
2196
2197 /* Module info */
2198 rval = smiapp_read(client, SMIAPP_REG_U8_MANUFACTURER_ID,
2199 &minfo->manufacturer_id);
2200 if (!rval)
2201 rval = smiapp_read(client, SMIAPP_REG_U16_MODEL_ID,
2202 &minfo->model_id);
2203 if (!rval)
2204 rval = smiapp_read(client, SMIAPP_REG_U8_REVISION_NUMBER_MAJOR,
2205 &minfo->revision_number_major);
2206 if (!rval)
2207 rval = smiapp_read(client, SMIAPP_REG_U8_REVISION_NUMBER_MINOR,
2208 &minfo->revision_number_minor);
2209 if (!rval)
2210 rval = smiapp_read(client, SMIAPP_REG_U8_MODULE_DATE_YEAR,
2211 &minfo->module_year);
2212 if (!rval)
2213 rval = smiapp_read(client, SMIAPP_REG_U8_MODULE_DATE_MONTH,
2214 &minfo->module_month);
2215 if (!rval)
2216 rval = smiapp_read(client, SMIAPP_REG_U8_MODULE_DATE_DAY,
2217 &minfo->module_day);
2218
2219 /* Sensor info */
2220 if (!rval)
2221 rval = smiapp_read(client,
2222 SMIAPP_REG_U8_SENSOR_MANUFACTURER_ID,
2223 &minfo->sensor_manufacturer_id);
2224 if (!rval)
2225 rval = smiapp_read(client, SMIAPP_REG_U16_SENSOR_MODEL_ID,
2226 &minfo->sensor_model_id);
2227 if (!rval)
2228 rval = smiapp_read(client,
2229 SMIAPP_REG_U8_SENSOR_REVISION_NUMBER,
2230 &minfo->sensor_revision_number);
2231 if (!rval)
2232 rval = smiapp_read(client,
2233 SMIAPP_REG_U8_SENSOR_FIRMWARE_VERSION,
2234 &minfo->sensor_firmware_version);
2235
2236 /* SMIA */
2237 if (!rval)
2238 rval = smiapp_read(client, SMIAPP_REG_U8_SMIA_VERSION,
2239 &minfo->smia_version);
2240 if (!rval)
2241 rval = smiapp_read(client, SMIAPP_REG_U8_SMIAPP_VERSION,
2242 &minfo->smiapp_version);
2243
2244 if (rval) {
2245 dev_err(&client->dev, "sensor detection failed\n");
2246 return -ENODEV;
2247 }
2248
2249 dev_dbg(&client->dev, "module 0x%2.2x-0x%4.4x\n",
2250 minfo->manufacturer_id, minfo->model_id);
2251
2252 dev_dbg(&client->dev,
2253 "module revision 0x%2.2x-0x%2.2x date %2.2d-%2.2d-%2.2d\n",
2254 minfo->revision_number_major, minfo->revision_number_minor,
2255 minfo->module_year, minfo->module_month, minfo->module_day);
2256
2257 dev_dbg(&client->dev, "sensor 0x%2.2x-0x%4.4x\n",
2258 minfo->sensor_manufacturer_id, minfo->sensor_model_id);
2259
2260 dev_dbg(&client->dev,
2261 "sensor revision 0x%2.2x firmware version 0x%2.2x\n",
2262 minfo->sensor_revision_number, minfo->sensor_firmware_version);
2263
2264 dev_dbg(&client->dev, "smia version %2.2d smiapp version %2.2d\n",
2265 minfo->smia_version, minfo->smiapp_version);
2266
2267 /*
2268 * Some modules have bad data in the lvalues below. Hope the
2269 * rvalues have better stuff. The lvalues are module
2270 * parameters whereas the rvalues are sensor parameters.
2271 */
2272 if (!minfo->manufacturer_id && !minfo->model_id) {
2273 minfo->manufacturer_id = minfo->sensor_manufacturer_id;
2274 minfo->model_id = minfo->sensor_model_id;
2275 minfo->revision_number_major = minfo->sensor_revision_number;
2276 }
2277
2278 for (i = 0; i < ARRAY_SIZE(smiapp_module_idents); i++) {
2279 if (smiapp_module_idents[i].manufacturer_id
2280 != minfo->manufacturer_id)
2281 continue;
2282 if (smiapp_module_idents[i].model_id != minfo->model_id)
2283 continue;
2284 if (smiapp_module_idents[i].flags
2285 & SMIAPP_MODULE_IDENT_FLAG_REV_LE) {
2286 if (smiapp_module_idents[i].revision_number_major
2287 < minfo->revision_number_major)
2288 continue;
2289 } else {
2290 if (smiapp_module_idents[i].revision_number_major
2291 != minfo->revision_number_major)
2292 continue;
2293 }
2294
2295 minfo->name = smiapp_module_idents[i].name;
2296 minfo->quirk = smiapp_module_idents[i].quirk;
2297 break;
2298 }
2299
2300 if (i >= ARRAY_SIZE(smiapp_module_idents))
2301 dev_warn(&client->dev,
2302 "no quirks for this module; let's hope it's fully compliant\n");
2303
2304 dev_dbg(&client->dev, "the sensor is called %s, ident %2.2x%4.4x%2.2x\n",
2305 minfo->name, minfo->manufacturer_id, minfo->model_id,
2306 minfo->revision_number_major);
2307
2308 strlcpy(subdev->name, sensor->minfo.name, sizeof(subdev->name));
2309
2310 return 0;
2311}
2312
2313static const struct v4l2_subdev_ops smiapp_ops;
2314static const struct v4l2_subdev_internal_ops smiapp_internal_ops;
2315static const struct media_entity_operations smiapp_entity_ops;
2316
2317static int smiapp_registered(struct v4l2_subdev *subdev)
2318{
2319 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
2320 struct i2c_client *client = v4l2_get_subdevdata(subdev);
2321 struct smiapp_subdev *last = NULL;
2322 u32 tmp;
2323 unsigned int i;
2324 int rval;
2325
2326 sensor->vana = regulator_get(&client->dev, "VANA");
2327 if (IS_ERR(sensor->vana)) {
2328 dev_err(&client->dev, "could not get regulator for vana\n");
2329 return -ENODEV;
2330 }
2331
2332 if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) {
2333 if (gpio_request_one(sensor->platform_data->xshutdown, 0,
2334 "SMIA++ xshutdown") != 0) {
2335 dev_err(&client->dev,
2336 "unable to acquire reset gpio %d\n",
2337 sensor->platform_data->xshutdown);
2338 rval = -ENODEV;
2339 goto out_gpio_request;
2340 }
2341 }
2342
2343 rval = smiapp_power_on(sensor);
2344 if (rval) {
2345 rval = -ENODEV;
2346 goto out_smiapp_power_on;
2347 }
2348
2349 rval = smiapp_identify_module(subdev);
2350 if (rval) {
2351 rval = -ENODEV;
2352 goto out_power_off;
2353 }
2354
2355 rval = smiapp_get_all_limits(sensor);
2356 if (rval) {
2357 rval = -ENODEV;
2358 goto out_power_off;
2359 }
2360
2361 /*
2362 * Handle Sensor Module orientation on the board.
2363 *
2364 * The application of H-FLIP and V-FLIP on the sensor is modified by
2365 * the sensor orientation on the board.
2366 *
2367 * For SMIAPP_BOARD_SENSOR_ORIENT_180 the default behaviour is to set
2368 * both H-FLIP and V-FLIP for normal operation which also implies
2369 * that a set/unset operation for user space HFLIP and VFLIP v4l2
2370 * controls will need to be internally inverted.
2371 *
2372 * Rotation also changes the bayer pattern.
2373 */
2374 if (sensor->platform_data->module_board_orient ==
2375 SMIAPP_MODULE_BOARD_ORIENT_180)
2376 sensor->hvflip_inv_mask = SMIAPP_IMAGE_ORIENTATION_HFLIP |
2377 SMIAPP_IMAGE_ORIENTATION_VFLIP;
2378
2379 rval = smiapp_get_mbus_formats(sensor);
2380 if (rval) {
2381 rval = -ENODEV;
2382 goto out_power_off;
2383 }
2384
2385 if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY]) {
2386 u32 val;
2387
2388 rval = smiapp_read(client,
2389 SMIAPP_REG_U8_BINNING_SUBTYPES, &val);
2390 if (rval < 0) {
2391 rval = -ENODEV;
2392 goto out_power_off;
2393 }
2394 sensor->nbinning_subtypes = min_t(u8, val,
2395 SMIAPP_BINNING_SUBTYPES);
2396
2397 for (i = 0; i < sensor->nbinning_subtypes; i++) {
2398 rval = smiapp_read(
2399 client, SMIAPP_REG_U8_BINNING_TYPE_n(i), &val);
2400 if (rval < 0) {
2401 rval = -ENODEV;
2402 goto out_power_off;
2403 }
2404 sensor->binning_subtypes[i] =
2405 *(struct smiapp_binning_subtype *)&val;
2406
2407 dev_dbg(&client->dev, "binning %xx%x\n",
2408 sensor->binning_subtypes[i].horizontal,
2409 sensor->binning_subtypes[i].vertical);
2410 }
2411 }
2412 sensor->binning_horizontal = 1;
2413 sensor->binning_vertical = 1;
2414
2415 /* SMIA++ NVM initialization - it will be read from the sensor
2416 * when it is first requested by userspace.
2417 */
2418 if (sensor->minfo.smiapp_version && sensor->platform_data->nvm_size) {
2419 sensor->nvm = kzalloc(sensor->platform_data->nvm_size,
2420 GFP_KERNEL);
2421 if (sensor->nvm == NULL) {
2422 dev_err(&client->dev, "nvm buf allocation failed\n");
2423 rval = -ENOMEM;
2424 goto out_power_off;
2425 }
2426
2427 if (device_create_file(&client->dev, &dev_attr_nvm) != 0) {
2428 dev_err(&client->dev, "sysfs nvm entry failed\n");
2429 rval = -EBUSY;
2430 goto out_power_off;
2431 }
2432 }
2433
2434 rval = smiapp_call_quirk(sensor, limits);
2435 if (rval) {
2436 dev_err(&client->dev, "limits quirks failed\n");
2437 goto out_nvm_release;
2438 }
2439
2440 /* We consider this as profile 0 sensor if any of these are zero. */
2441 if (!sensor->limits[SMIAPP_LIMIT_MIN_OP_SYS_CLK_DIV] ||
2442 !sensor->limits[SMIAPP_LIMIT_MAX_OP_SYS_CLK_DIV] ||
2443 !sensor->limits[SMIAPP_LIMIT_MIN_OP_PIX_CLK_DIV] ||
2444 !sensor->limits[SMIAPP_LIMIT_MAX_OP_PIX_CLK_DIV]) {
2445 sensor->minfo.smiapp_profile = SMIAPP_PROFILE_0;
2446 } else if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
2447 != SMIAPP_SCALING_CAPABILITY_NONE) {
2448 if (sensor->limits[SMIAPP_LIMIT_SCALING_CAPABILITY]
2449 == SMIAPP_SCALING_CAPABILITY_HORIZONTAL)
2450 sensor->minfo.smiapp_profile = SMIAPP_PROFILE_1;
2451 else
2452 sensor->minfo.smiapp_profile = SMIAPP_PROFILE_2;
2453 sensor->scaler = &sensor->ssds[sensor->ssds_used];
2454 sensor->ssds_used++;
2455 } else if (sensor->limits[SMIAPP_LIMIT_DIGITAL_CROP_CAPABILITY]
2456 == SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP) {
2457 sensor->scaler = &sensor->ssds[sensor->ssds_used];
2458 sensor->ssds_used++;
2459 }
2460 sensor->binner = &sensor->ssds[sensor->ssds_used];
2461 sensor->ssds_used++;
2462 sensor->pixel_array = &sensor->ssds[sensor->ssds_used];
2463 sensor->ssds_used++;
2464
2465 sensor->scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
2466
2467 for (i = 0; i < SMIAPP_SUBDEVS; i++) {
2468 struct {
2469 struct smiapp_subdev *ssd;
2470 char *name;
2471 } const __this[] = {
2472 { sensor->scaler, "scaler", },
2473 { sensor->binner, "binner", },
2474 { sensor->pixel_array, "pixel array", },
2475 }, *_this = &__this[i];
2476 struct smiapp_subdev *this = _this->ssd;
2477
2478 if (!this)
2479 continue;
2480
2481 if (this != sensor->src)
2482 v4l2_subdev_init(&this->sd, &smiapp_ops);
2483
2484 this->sensor = sensor;
2485
2486 if (this == sensor->pixel_array) {
2487 this->npads = 1;
2488 } else {
2489 this->npads = 2;
2490 this->source_pad = 1;
2491 }
2492
2493 snprintf(this->sd.name,
2494 sizeof(this->sd.name), "%s %s",
2495 sensor->minfo.name, _this->name);
2496
2497 this->sink_fmt.width =
2498 sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
2499 this->sink_fmt.height =
2500 sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
2501 this->compose.width = this->sink_fmt.width;
2502 this->compose.height = this->sink_fmt.height;
2503 this->crop[this->source_pad] = this->compose;
2504 this->pads[this->source_pad].flags = MEDIA_PAD_FL_SOURCE;
2505 if (this != sensor->pixel_array) {
2506 this->crop[this->sink_pad] = this->compose;
2507 this->pads[this->sink_pad].flags = MEDIA_PAD_FL_SINK;
2508 }
2509
2510 this->sd.entity.ops = &smiapp_entity_ops;
2511
2512 if (last == NULL) {
2513 last = this;
2514 continue;
2515 }
2516
2517 this->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
2518 this->sd.internal_ops = &smiapp_internal_ops;
2519 this->sd.owner = NULL;
2520 v4l2_set_subdevdata(&this->sd, client);
2521
2522 rval = media_entity_init(&this->sd.entity,
2523 this->npads, this->pads, 0);
2524 if (rval) {
2525 dev_err(&client->dev,
2526 "media_entity_init failed\n");
2527 goto out_nvm_release;
2528 }
2529
2530 rval = media_entity_create_link(&this->sd.entity,
2531 this->source_pad,
2532 &last->sd.entity,
2533 last->sink_pad,
2534 MEDIA_LNK_FL_ENABLED |
2535 MEDIA_LNK_FL_IMMUTABLE);
2536 if (rval) {
2537 dev_err(&client->dev,
2538 "media_entity_create_link failed\n");
2539 goto out_nvm_release;
2540 }
2541
2542 rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev,
2543 &this->sd);
2544 if (rval) {
2545 dev_err(&client->dev,
2546 "v4l2_device_register_subdev failed\n");
2547 goto out_nvm_release;
2548 }
2549
2550 last = this;
2551 }
2552
2553 dev_dbg(&client->dev, "profile %d\n", sensor->minfo.smiapp_profile);
2554
2555 sensor->pixel_array->sd.entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
2556
2557 /* final steps */
2558 smiapp_read_frame_fmt(sensor);
2559 rval = smiapp_init_controls(sensor);
2560 if (rval < 0)
2561 goto out_nvm_release;
2562
2563 rval = smiapp_update_mode(sensor);
2564 if (rval) {
2565 dev_err(&client->dev, "update mode failed\n");
2566 goto out_nvm_release;
2567 }
2568
2569 sensor->streaming = false;
2570 sensor->dev_init_done = true;
2571
2572 /* check flash capability */
2573 rval = smiapp_read(client, SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, &tmp);
2574 sensor->flash_capability = tmp;
2575 if (rval)
2576 goto out_nvm_release;
2577
2578 smiapp_power_off(sensor);
2579
2580 return 0;
2581
2582out_nvm_release:
2583 device_remove_file(&client->dev, &dev_attr_nvm);
2584
2585out_power_off:
2586 kfree(sensor->nvm);
2587 sensor->nvm = NULL;
2588 smiapp_power_off(sensor);
2589
2590out_smiapp_power_on:
2591 if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
2592 gpio_free(sensor->platform_data->xshutdown);
2593
2594out_gpio_request:
2595 regulator_put(sensor->vana);
2596 sensor->vana = NULL;
2597 return rval;
2598}
2599
2600static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
2601{
2602 struct smiapp_subdev *ssd = to_smiapp_subdev(sd);
2603 struct smiapp_sensor *sensor = ssd->sensor;
2604 u32 mbus_code =
2605 smiapp_csi_data_formats[smiapp_pixel_order(sensor)].code;
2606 unsigned int i;
2607
2608 mutex_lock(&sensor->mutex);
2609
2610 for (i = 0; i < ssd->npads; i++) {
2611 struct v4l2_mbus_framefmt *try_fmt =
2612 v4l2_subdev_get_try_format(fh, i);
2613 struct v4l2_rect *try_crop = v4l2_subdev_get_try_crop(fh, i);
2614 struct v4l2_rect *try_comp;
2615
2616 try_fmt->width = sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
2617 try_fmt->height = sensor->limits[SMIAPP_LIMIT_Y_ADDR_MAX] + 1;
2618 try_fmt->code = mbus_code;
2619
2620 try_crop->top = 0;
2621 try_crop->left = 0;
2622 try_crop->width = try_fmt->width;
2623 try_crop->height = try_fmt->height;
2624
2625 if (ssd != sensor->pixel_array)
2626 continue;
2627
2628 try_comp = v4l2_subdev_get_try_compose(fh, i);
2629 *try_comp = *try_crop;
2630 }
2631
2632 mutex_unlock(&sensor->mutex);
2633
2634 return smiapp_set_power(sd, 1);
2635}
2636
2637static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
2638{
2639 return smiapp_set_power(sd, 0);
2640}
2641
2642static const struct v4l2_subdev_video_ops smiapp_video_ops = {
2643 .s_stream = smiapp_set_stream,
2644};
2645
2646static const struct v4l2_subdev_core_ops smiapp_core_ops = {
2647 .s_power = smiapp_set_power,
2648};
2649
2650static const struct v4l2_subdev_pad_ops smiapp_pad_ops = {
2651 .enum_mbus_code = smiapp_enum_mbus_code,
2652 .get_fmt = smiapp_get_format,
2653 .set_fmt = smiapp_set_format,
2654 .get_selection = smiapp_get_selection,
2655 .set_selection = smiapp_set_selection,
2656};
2657
2658static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = {
2659 .g_skip_frames = smiapp_get_skip_frames,
2660};
2661
2662static const struct v4l2_subdev_ops smiapp_ops = {
2663 .core = &smiapp_core_ops,
2664 .video = &smiapp_video_ops,
2665 .pad = &smiapp_pad_ops,
2666 .sensor = &smiapp_sensor_ops,
2667};
2668
2669static const struct media_entity_operations smiapp_entity_ops = {
2670 .link_validate = v4l2_subdev_link_validate,
2671};
2672
2673static const struct v4l2_subdev_internal_ops smiapp_internal_src_ops = {
2674 .registered = smiapp_registered,
2675 .open = smiapp_open,
2676 .close = smiapp_close,
2677};
2678
2679static const struct v4l2_subdev_internal_ops smiapp_internal_ops = {
2680 .open = smiapp_open,
2681 .close = smiapp_close,
2682};
2683
2684/* -----------------------------------------------------------------------------
2685 * I2C Driver
2686 */
2687
2688#ifdef CONFIG_PM
2689
2690static int smiapp_suspend(struct device *dev)
2691{
2692 struct i2c_client *client = to_i2c_client(dev);
2693 struct v4l2_subdev *subdev = i2c_get_clientdata(client);
2694 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
2695 bool streaming;
2696
2697 BUG_ON(mutex_is_locked(&sensor->mutex));
2698
2699 if (sensor->power_count == 0)
2700 return 0;
2701
2702 if (sensor->streaming)
2703 smiapp_stop_streaming(sensor);
2704
2705 streaming = sensor->streaming;
2706
2707 smiapp_power_off(sensor);
2708
2709 /* save state for resume */
2710 sensor->streaming = streaming;
2711
2712 return 0;
2713}
2714
2715static int smiapp_resume(struct device *dev)
2716{
2717 struct i2c_client *client = to_i2c_client(dev);
2718 struct v4l2_subdev *subdev = i2c_get_clientdata(client);
2719 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
2720 int rval;
2721
2722 if (sensor->power_count == 0)
2723 return 0;
2724
2725 rval = smiapp_power_on(sensor);
2726 if (rval)
2727 return rval;
2728
2729 if (sensor->streaming)
2730 rval = smiapp_start_streaming(sensor);
2731
2732 return rval;
2733}
2734
2735#else
2736
2737#define smiapp_suspend NULL
2738#define smiapp_resume NULL
2739
2740#endif /* CONFIG_PM */
2741
2742static int smiapp_probe(struct i2c_client *client,
2743 const struct i2c_device_id *devid)
2744{
2745 struct smiapp_sensor *sensor;
2746 int rval;
2747
2748 if (client->dev.platform_data == NULL)
2749 return -ENODEV;
2750
2751 sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
2752 if (sensor == NULL)
2753 return -ENOMEM;
2754
2755 sensor->platform_data = client->dev.platform_data;
2756 mutex_init(&sensor->mutex);
2757 mutex_init(&sensor->power_mutex);
2758 sensor->src = &sensor->ssds[sensor->ssds_used];
2759
2760 v4l2_i2c_subdev_init(&sensor->src->sd, client, &smiapp_ops);
2761 sensor->src->sd.internal_ops = &smiapp_internal_src_ops;
2762 sensor->src->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
2763 sensor->src->sensor = sensor;
2764
2765 sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE;
2766 rval = media_entity_init(&sensor->src->sd.entity, 2,
2767 sensor->src->pads, 0);
2768 if (rval < 0)
2769 kfree(sensor);
2770
2771 return rval;
2772}
2773
2774static int __exit smiapp_remove(struct i2c_client *client)
2775{
2776 struct v4l2_subdev *subdev = i2c_get_clientdata(client);
2777 struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
2778 unsigned int i;
2779
2780 if (sensor->power_count) {
2781 if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
2782 gpio_set_value(sensor->platform_data->xshutdown, 0);
2783 sensor->platform_data->set_xclk(&sensor->src->sd, 0);
2784 sensor->power_count = 0;
2785 }
2786
2787 if (sensor->nvm) {
2788 device_remove_file(&client->dev, &dev_attr_nvm);
2789 kfree(sensor->nvm);
2790 }
2791
2792 for (i = 0; i < sensor->ssds_used; i++) {
2793 media_entity_cleanup(&sensor->ssds[i].sd.entity);
2794 v4l2_device_unregister_subdev(&sensor->ssds[i].sd);
2795 }
2796 smiapp_free_controls(sensor);
2797 if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN)
2798 gpio_free(sensor->platform_data->xshutdown);
2799 if (sensor->vana)
2800 regulator_put(sensor->vana);
2801
2802 kfree(sensor);
2803
2804 return 0;
2805}
2806
2807static const struct i2c_device_id smiapp_id_table[] = {
2808 { SMIAPP_NAME, 0 },
2809 { },
2810};
2811MODULE_DEVICE_TABLE(i2c, smiapp_id_table);
2812
2813static const struct dev_pm_ops smiapp_pm_ops = {
2814 .suspend = smiapp_suspend,
2815 .resume = smiapp_resume,
2816};
2817
2818static struct i2c_driver smiapp_i2c_driver = {
2819 .driver = {
2820 .name = SMIAPP_NAME,
2821 .pm = &smiapp_pm_ops,
2822 },
2823 .probe = smiapp_probe,
2824 .remove = __exit_p(smiapp_remove),
2825 .id_table = smiapp_id_table,
2826};
2827
2828module_i2c_driver(smiapp_i2c_driver);
2829
2830MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>");
2831MODULE_DESCRIPTION("Generic SMIA/SMIA++ camera module driver");
2832MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/smiapp/smiapp-debug.h b/drivers/media/video/smiapp/smiapp-debug.h
new file mode 100644
index 000000000000..627809eed1d9
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-debug.h
@@ -0,0 +1,32 @@
1/*
2 * drivers/media/video/smiapp/smiapp-debug.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_DEBUG_H
26#define SMIAPP_DEBUG_H
27
28#ifdef CONFIG_VIDEO_SMIAPP_DEBUG
29#define DEBUG
30#endif
31
32#endif
diff --git a/drivers/media/video/smiapp/smiapp-limits.c b/drivers/media/video/smiapp/smiapp-limits.c
new file mode 100644
index 000000000000..0800e095724e
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-limits.c
@@ -0,0 +1,132 @@
1/*
2 * drivers/media/video/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
27struct 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/video/smiapp/smiapp-limits.h b/drivers/media/video/smiapp/smiapp-limits.h
new file mode 100644
index 000000000000..7f4836bb78db
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-limits.h
@@ -0,0 +1,128 @@
1/*
2 * drivers/media/video/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/video/smiapp/smiapp-quirk.c b/drivers/media/video/smiapp/smiapp-quirk.c
new file mode 100644
index 000000000000..dae85a12f7ec
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-quirk.c
@@ -0,0 +1,264 @@
1/*
2 * drivers/media/video/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 "smiapp-debug.h"
26
27#include <linux/delay.h>
28
29#include "smiapp.h"
30
31static int smiapp_write_8(struct smiapp_sensor *sensor, u16 reg, u8 val)
32{
33 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
34
35 return smiapp_write(client, (SMIA_REG_8BIT << 16) | reg, val);
36}
37
38static int smiapp_write_8s(struct smiapp_sensor *sensor,
39 struct smiapp_reg_8 *regs, int len)
40{
41 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
42 int rval;
43
44 for (; len > 0; len--, regs++) {
45 rval = smiapp_write_8(sensor, regs->reg, regs->val);
46 if (rval < 0) {
47 dev_err(&client->dev,
48 "error %d writing reg 0x%4.4x, val 0x%2.2x",
49 rval, regs->reg, regs->val);
50 return rval;
51 }
52 }
53
54 return 0;
55}
56
57void smiapp_replace_limit(struct smiapp_sensor *sensor,
58 u32 limit, u32 val)
59{
60 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
61
62 dev_dbg(&client->dev, "quirk: 0x%8.8x \"%s\" = %d, 0x%x\n",
63 smiapp_reg_limits[limit].addr,
64 smiapp_reg_limits[limit].what, val, val);
65 sensor->limits[limit] = val;
66}
67
68int smiapp_replace_limit_at(struct smiapp_sensor *sensor,
69 u32 reg, u32 val)
70{
71 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
72 int i;
73
74 for (i = 0; smiapp_reg_limits[i].addr; i++) {
75 if ((smiapp_reg_limits[i].addr & 0xffff) != reg)
76 continue;
77
78 smiapp_replace_limit(sensor, i, val);
79
80 return 0;
81 }
82
83 dev_dbg(&client->dev, "quirk: bad register 0x%4.4x\n", reg);
84
85 return -EINVAL;
86}
87
88static int jt8ew9_limits(struct smiapp_sensor *sensor)
89{
90 if (sensor->minfo.revision_number_major < 0x03)
91 sensor->frame_skip = 1;
92
93 /* Below 24 gain doesn't have effect at all, */
94 /* but ~59 is needed for full dynamic range */
95 smiapp_replace_limit(sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MIN, 59);
96 smiapp_replace_limit(
97 sensor, SMIAPP_LIMIT_ANALOGUE_GAIN_CODE_MAX, 6000);
98
99 return 0;
100}
101
102static int jt8ew9_post_poweron(struct smiapp_sensor *sensor)
103{
104 struct smiapp_reg_8 regs[] = {
105 { 0x30a3, 0xd8 }, /* Output port control : LVDS ports only */
106 { 0x30ae, 0x00 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */
107 { 0x30af, 0xd0 }, /* 0x0307 pll_multiplier maximum value on PLL input 9.6MHz ( 19.2MHz is divided on pre_pll_div) */
108 { 0x322d, 0x04 }, /* Adjusting Processing Image Size to Scaler Toshiba Recommendation Setting */
109 { 0x3255, 0x0f }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
110 { 0x3256, 0x15 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
111 { 0x3258, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */
112 { 0x3259, 0x70 }, /* Analog Gain Control Toshiba Recommendation Setting */
113 { 0x325f, 0x7c }, /* Analog Gain Control Toshiba Recommendation Setting */
114 { 0x3302, 0x06 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
115 { 0x3304, 0x00 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
116 { 0x3307, 0x22 }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
117 { 0x3308, 0x8d }, /* Pixel Reference Voltage Control Toshiba Recommendation Setting */
118 { 0x331e, 0x0f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
119 { 0x3320, 0x30 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
120 { 0x3321, 0x11 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
121 { 0x3322, 0x98 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
122 { 0x3323, 0x64 }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
123 { 0x3325, 0x83 }, /* Read Out Timing Control Toshiba Recommendation Setting */
124 { 0x3330, 0x18 }, /* Read Out Timing Control Toshiba Recommendation Setting */
125 { 0x333c, 0x01 }, /* Read Out Timing Control Toshiba Recommendation Setting */
126 { 0x3345, 0x2f }, /* Black Hole Sun Correction Control Toshiba Recommendation Setting */
127 { 0x33de, 0x38 }, /* Horizontal Noise Reduction Control Toshiba Recommendation Setting */
128 /* Taken from v03. No idea what the rest are. */
129 { 0x32e0, 0x05 },
130 { 0x32e1, 0x05 },
131 { 0x32e2, 0x04 },
132 { 0x32e5, 0x04 },
133 { 0x32e6, 0x04 },
134
135 };
136
137 return smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
138}
139
140const struct smiapp_quirk smiapp_jt8ew9_quirk = {
141 .limits = jt8ew9_limits,
142 .post_poweron = jt8ew9_post_poweron,
143};
144
145static int imx125es_post_poweron(struct smiapp_sensor *sensor)
146{
147 /* Taken from v02. No idea what the other two are. */
148 struct smiapp_reg_8 regs[] = {
149 /*
150 * 0x3302: clk during frame blanking:
151 * 0x00 - HS mode, 0x01 - LP11
152 */
153 { 0x3302, 0x01 },
154 { 0x302d, 0x00 },
155 { 0x3b08, 0x8c },
156 };
157
158 return smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
159}
160
161const struct smiapp_quirk smiapp_imx125es_quirk = {
162 .post_poweron = imx125es_post_poweron,
163};
164
165static int jt8ev1_limits(struct smiapp_sensor *sensor)
166{
167 smiapp_replace_limit(sensor, SMIAPP_LIMIT_X_ADDR_MAX, 4271);
168 smiapp_replace_limit(sensor,
169 SMIAPP_LIMIT_MIN_LINE_BLANKING_PCK_BIN, 184);
170
171 return 0;
172}
173
174static int jt8ev1_post_poweron(struct smiapp_sensor *sensor)
175{
176 struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
177 int rval;
178
179 struct smiapp_reg_8 regs[] = {
180 { 0x3031, 0xcd }, /* For digital binning (EQ_MONI) */
181 { 0x30a3, 0xd0 }, /* FLASH STROBE enable */
182 { 0x3237, 0x00 }, /* For control of pulse timing for ADC */
183 { 0x3238, 0x43 },
184 { 0x3301, 0x06 }, /* For analog bias for sensor */
185 { 0x3302, 0x06 },
186 { 0x3304, 0x00 },
187 { 0x3305, 0x88 },
188 { 0x332a, 0x14 },
189 { 0x332c, 0x6b },
190 { 0x3336, 0x01 },
191 { 0x333f, 0x1f },
192 { 0x3355, 0x00 },
193 { 0x3356, 0x20 },
194 { 0x33bf, 0x20 }, /* Adjust the FBC speed */
195 { 0x33c9, 0x20 },
196 { 0x33ce, 0x30 }, /* Adjust the parameter for logic function */
197 { 0x33cf, 0xec }, /* For Black sun */
198 { 0x3328, 0x80 }, /* Ugh. No idea what's this. */
199 };
200
201 struct smiapp_reg_8 regs_96[] = {
202 { 0x30ae, 0x00 }, /* For control of ADC clock */
203 { 0x30af, 0xd0 },
204 { 0x30b0, 0x01 },
205 };
206
207 rval = smiapp_write_8s(sensor, regs, ARRAY_SIZE(regs));
208 if (rval < 0)
209 return rval;
210
211 switch (sensor->platform_data->ext_clk) {
212 case 9600000:
213 return smiapp_write_8s(sensor, regs_96,
214 ARRAY_SIZE(regs_96));
215 default:
216 dev_warn(&client->dev, "no MSRs for %d Hz ext_clk\n",
217 sensor->platform_data->ext_clk);
218 return 0;
219 }
220}
221
222static int jt8ev1_pre_streamon(struct smiapp_sensor *sensor)
223{
224 return smiapp_write_8(sensor, 0x3328, 0x00);
225}
226
227static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor)
228{
229 int rval;
230
231 /* Workaround: allows fast standby to work properly */
232 rval = smiapp_write_8(sensor, 0x3205, 0x04);
233 if (rval < 0)
234 return rval;
235
236 /* Wait for 1 ms + one line => 2 ms is likely enough */
237 usleep_range(2000, 2000);
238
239 /* Restore it */
240 rval = smiapp_write_8(sensor, 0x3205, 0x00);
241 if (rval < 0)
242 return rval;
243
244 return smiapp_write_8(sensor, 0x3328, 0x80);
245}
246
247const struct smiapp_quirk smiapp_jt8ev1_quirk = {
248 .limits = jt8ev1_limits,
249 .post_poweron = jt8ev1_post_poweron,
250 .pre_streamon = jt8ev1_pre_streamon,
251 .post_streamoff = jt8ev1_post_streamoff,
252 .flags = SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE,
253};
254
255static int tcm8500md_limits(struct smiapp_sensor *sensor)
256{
257 smiapp_replace_limit(sensor, SMIAPP_LIMIT_MIN_PLL_IP_FREQ_HZ, 2700000);
258
259 return 0;
260}
261
262const struct smiapp_quirk smiapp_tcm8500md_quirk = {
263 .limits = tcm8500md_limits,
264};
diff --git a/drivers/media/video/smiapp/smiapp-quirk.h b/drivers/media/video/smiapp/smiapp-quirk.h
new file mode 100644
index 000000000000..7a1b3a02a7bd
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-quirk.h
@@ -0,0 +1,72 @@
1/*
2 * drivers/media/video/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
28struct 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 */
39struct 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 unsigned long flags;
45};
46
47/* op pix clock is for all lanes in total normally */
48#define SMIAPP_QUIRK_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0)
49
50struct smiapp_reg_8 {
51 u16 reg;
52 u8 val;
53};
54
55void smiapp_replace_limit(struct smiapp_sensor *sensor,
56 u32 limit, u32 val);
57
58#define smiapp_call_quirk(_sensor, _quirk, ...) \
59 (_sensor->minfo.quirk && \
60 _sensor->minfo.quirk->_quirk ? \
61 _sensor->minfo.quirk->_quirk(_sensor, ##__VA_ARGS__) : 0)
62
63#define smiapp_needs_quirk(_sensor, _quirk) \
64 (_sensor->minfo.quirk ? \
65 _sensor->minfo.quirk->flags & _quirk : 0)
66
67extern const struct smiapp_quirk smiapp_jt8ev1_quirk;
68extern const struct smiapp_quirk smiapp_imx125es_quirk;
69extern const struct smiapp_quirk smiapp_jt8ew9_quirk;
70extern const struct smiapp_quirk smiapp_tcm8500md_quirk;
71
72#endif /* __SMIAPP_QUIRK__ */
diff --git a/drivers/media/video/smiapp/smiapp-reg-defs.h b/drivers/media/video/smiapp/smiapp-reg-defs.h
new file mode 100644
index 000000000000..a089eb8161e1
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-reg-defs.h
@@ -0,0 +1,503 @@
1/*
2 * drivers/media/video/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/video/smiapp/smiapp-reg.h b/drivers/media/video/smiapp/smiapp-reg.h
new file mode 100644
index 000000000000..d0167aa17534
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-reg.h
@@ -0,0 +1,122 @@
1/*
2 * drivers/media/video/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/video/smiapp/smiapp-regs.c b/drivers/media/video/smiapp/smiapp-regs.c
new file mode 100644
index 000000000000..4851ff710779
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-regs.c
@@ -0,0 +1,213 @@
1/*
2 * drivers/media/video/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 "smiapp-debug.h"
26
27#include <linux/delay.h>
28#include <linux/i2c.h>
29
30#include "smiapp-regs.h"
31
32static uint32_t float_to_u32_mul_1000000(struct i2c_client *client,
33 uint32_t phloat)
34{
35 int32_t exp;
36 uint64_t man;
37
38 if (phloat >= 0x80000000) {
39 dev_err(&client->dev, "this is a negative number\n");
40 return 0;
41 }
42
43 if (phloat == 0x7f800000)
44 return ~0; /* Inf. */
45
46 if ((phloat & 0x7f800000) == 0x7f800000) {
47 dev_err(&client->dev, "NaN or other special number\n");
48 return 0;
49 }
50
51 /* Valid cases begin here */
52 if (phloat == 0)
53 return 0; /* Valid zero */
54
55 if (phloat > 0x4f800000)
56 return ~0; /* larger than 4294967295 */
57
58 /*
59 * Unbias exponent (note how phloat is now guaranteed to
60 * have 0 in the high bit)
61 */
62 exp = ((int32_t)phloat >> 23) - 127;
63
64 /* Extract mantissa, add missing '1' bit and it's in MHz */
65 man = ((phloat & 0x7fffff) | 0x800000) * 1000000ULL;
66
67 if (exp < 0)
68 man >>= -exp;
69 else
70 man <<= exp;
71
72 man >>= 23; /* Remove mantissa bias */
73
74 return man & 0xffffffff;
75}
76
77
78/*
79 * Read a 8/16/32-bit i2c register. The value is returned in 'val'.
80 * Returns zero if successful, or non-zero otherwise.
81 */
82int smiapp_read(struct i2c_client *client, u32 reg, u32 *val)
83{
84 struct i2c_msg msg;
85 unsigned char data[4];
86 unsigned int len = (u8)(reg >> 16);
87 u16 offset = reg;
88 int r;
89
90 if (len != SMIA_REG_8BIT && len != SMIA_REG_16BIT
91 && len != SMIA_REG_32BIT)
92 return -EINVAL;
93
94 msg.addr = client->addr;
95 msg.flags = 0;
96 msg.len = 2;
97 msg.buf = data;
98
99 /* high byte goes out first */
100 data[0] = (u8) (offset >> 8);
101 data[1] = (u8) offset;
102 r = i2c_transfer(client->adapter, &msg, 1);
103 if (r != 1) {
104 if (r >= 0)
105 r = -EBUSY;
106 goto err;
107 }
108
109 msg.len = len;
110 msg.flags = I2C_M_RD;
111 r = i2c_transfer(client->adapter, &msg, 1);
112 if (r != 1) {
113 if (r >= 0)
114 r = -EBUSY;
115 goto err;
116 }
117
118 *val = 0;
119 /* high byte comes first */
120 switch (len) {
121 case SMIA_REG_32BIT:
122 *val = (data[0] << 24) + (data[1] << 16) + (data[2] << 8) +
123 data[3];
124 break;
125 case SMIA_REG_16BIT:
126 *val = (data[0] << 8) + data[1];
127 break;
128 case SMIA_REG_8BIT:
129 *val = data[0];
130 break;
131 default:
132 BUG();
133 }
134
135 if (reg & SMIA_REG_FLAG_FLOAT)
136 *val = float_to_u32_mul_1000000(client, *val);
137
138 return 0;
139
140err:
141 dev_err(&client->dev, "read from offset 0x%x error %d\n", offset, r);
142
143 return r;
144}
145
146/*
147 * Write to a 8/16-bit register.
148 * Returns zero if successful, or non-zero otherwise.
149 */
150int smiapp_write(struct i2c_client *client, u32 reg, u32 val)
151{
152 struct i2c_msg msg;
153 unsigned char data[6];
154 unsigned int retries;
155 unsigned int flags = reg >> 24;
156 unsigned int len = (u8)(reg >> 16);
157 u16 offset = reg;
158 int r;
159
160 if ((len != SMIA_REG_8BIT && len != SMIA_REG_16BIT &&
161 len != SMIA_REG_32BIT) || flags)
162 return -EINVAL;
163
164 msg.addr = client->addr;
165 msg.flags = 0; /* Write */
166 msg.len = 2 + len;
167 msg.buf = data;
168
169 /* high byte goes out first */
170 data[0] = (u8) (reg >> 8);
171 data[1] = (u8) (reg & 0xff);
172
173 switch (len) {
174 case SMIA_REG_8BIT:
175 data[2] = val;
176 break;
177 case SMIA_REG_16BIT:
178 data[2] = val >> 8;
179 data[3] = val;
180 break;
181 case SMIA_REG_32BIT:
182 data[2] = val >> 24;
183 data[3] = val >> 16;
184 data[4] = val >> 8;
185 data[5] = val;
186 break;
187 default:
188 BUG();
189 }
190
191 for (retries = 0; retries < 5; retries++) {
192 /*
193 * Due to unknown reason sensor stops responding. This
194 * loop is a temporaty solution until the root cause
195 * is found.
196 */
197 r = i2c_transfer(client->adapter, &msg, 1);
198 if (r == 1) {
199 if (retries)
200 dev_err(&client->dev,
201 "sensor i2c stall encountered. "
202 "retries: %d\n", retries);
203 return 0;
204 }
205
206 usleep_range(2000, 2000);
207 }
208
209 dev_err(&client->dev,
210 "wrote 0x%x to offset 0x%x error %d\n", val, offset, r);
211
212 return r;
213}
diff --git a/drivers/media/video/smiapp/smiapp-regs.h b/drivers/media/video/smiapp/smiapp-regs.h
new file mode 100644
index 000000000000..58e8009d4aa5
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp-regs.h
@@ -0,0 +1,46 @@
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
37struct smia_reg {
38 u16 type;
39 u16 reg; /* 16-bit offset */
40 u32 val; /* 8/16/32-bit value */
41};
42
43int smiapp_read(struct i2c_client *client, u32 reg, u32 *val);
44int smiapp_write(struct i2c_client *client, u32 reg, u32 val);
45
46#endif
diff --git a/drivers/media/video/smiapp/smiapp.h b/drivers/media/video/smiapp/smiapp.h
new file mode 100644
index 000000000000..805d8c8a3c18
--- /dev/null
+++ b/drivers/media/video/smiapp/smiapp.h
@@ -0,0 +1,251 @@
1/*
2 * drivers/media/video/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
59struct smiapp_quirk;
60
61#define SMIAPP_MODULE_IDENT_FLAG_REV_LE (1 << 0)
62
63struct 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
74struct 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
136struct smiapp_reg_limits {
137 u32 addr;
138 char *what;
139};
140
141extern struct smiapp_reg_limits smiapp_reg_limits[];
142
143struct 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
157struct smiapp_binning_subtype {
158 u8 horizontal:4;
159 u8 vertical:4;
160} __packed;
161
162struct 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 */
178struct 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 u32 limits[SMIAPP_LIMIT_LAST];
202 u8 nbinning_subtypes;
203 struct smiapp_binning_subtype binning_subtypes[SMIAPP_BINNING_SUBTYPES];
204 u32 mbus_frame_fmts;
205 const struct smiapp_csi_data_format *csi_format;
206 const struct smiapp_csi_data_format *internal_csi_format;
207 u32 default_mbus_frame_fmts;
208 int default_pixel_order;
209
210 u8 binning_horizontal;
211 u8 binning_vertical;
212
213 u8 scale_m;
214 u8 scaling_mode;
215
216 u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */
217 u8 flash_capability;
218 u8 frame_skip;
219
220 int power_count;
221
222 bool streaming;
223 bool dev_init_done;
224
225 u8 *nvm; /* nvm memory buffer */
226 unsigned int nvm_size; /* bytes */
227
228 struct smiapp_module_info minfo;
229
230 struct smiapp_pll pll;
231
232 /* Pixel array controls */
233 struct v4l2_ctrl *analog_gain;
234 struct v4l2_ctrl *exposure;
235 struct v4l2_ctrl *hflip;
236 struct v4l2_ctrl *vflip;
237 struct v4l2_ctrl *vblank;
238 struct v4l2_ctrl *hblank;
239 struct v4l2_ctrl *pixel_rate_parray;
240 /* src controls */
241 struct v4l2_ctrl *link_freq;
242 struct v4l2_ctrl *pixel_rate_csi;
243};
244
245#define to_smiapp_subdev(_sd) \
246 container_of(_sd, struct smiapp_subdev, sd)
247
248#define to_smiapp_sensor(_sd) \
249 (to_smiapp_subdev(_sd)->sensor)
250
251#endif /* __SMIAPP_PRIV_H_ */
diff --git a/include/media/smiapp.h b/include/media/smiapp.h
new file mode 100644
index 000000000000..a7877cd0733d
--- /dev/null
+++ b/include/media/smiapp.h
@@ -0,0 +1,83 @@
1/*
2 * include/media/smiapp.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_H_
26#define __SMIAPP_H_
27
28#include <media/v4l2-subdev.h>
29
30#define SMIAPP_NAME "smiapp"
31
32#define SMIAPP_DFL_I2C_ADDR (0x20 >> 1) /* Default I2C Address */
33#define SMIAPP_ALT_I2C_ADDR (0x6e >> 1) /* Alternate I2C Address */
34
35#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_CLOCK 0
36#define SMIAPP_CSI_SIGNALLING_MODE_CCP2_DATA_STROBE 1
37#define SMIAPP_CSI_SIGNALLING_MODE_CSI2 2
38
39#define SMIAPP_NO_XSHUTDOWN -1
40
41/*
42 * Sometimes due to board layout considerations the camera module can be
43 * mounted rotated. The typical rotation used is 180 degrees which can be
44 * corrected by giving a default H-FLIP and V-FLIP in the sensor readout.
45 * FIXME: rotation also changes the bayer pattern.
46 */
47enum smiapp_module_board_orient {
48 SMIAPP_MODULE_BOARD_ORIENT_0 = 0,
49 SMIAPP_MODULE_BOARD_ORIENT_180,
50};
51
52struct smiapp_flash_strobe_parms {
53 u8 mode;
54 u32 strobe_width_high_us;
55 u16 strobe_delay;
56 u16 stobe_start_point;
57 u8 trigger;
58};
59
60struct smiapp_platform_data {
61 /*
62 * Change the cci address if i2c_addr_alt is set.
63 * Both default and alternate cci addr need to be present
64 */
65 unsigned short i2c_addr_dfl; /* Default i2c addr */
66 unsigned short i2c_addr_alt; /* Alternate i2c addr */
67
68 unsigned int nvm_size; /* bytes */
69 unsigned int ext_clk; /* sensor external clk */
70
71 unsigned int lanes; /* Number of CSI-2 lanes */
72 u8 csi_signalling_mode; /* SMIAPP_CSI_SIGNALLING_MODE_* */
73 const s64 *op_sys_clock;
74
75 enum smiapp_module_board_orient module_board_orient;
76
77 struct smiapp_flash_strobe_parms *strobe_setup;
78
79 int (*set_xclk)(struct v4l2_subdev *sd, int hz);
80 int xshutdown; /* gpio or SMIAPP_NO_XSHUTDOWN */
81};
82
83#endif /* __SMIAPP_H_ */