diff options
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/Kconfig | 2 | ||||
-rw-r--r-- | drivers/media/video/Makefile | 1 | ||||
-rw-r--r-- | drivers/media/video/smiapp-pll.c | 2 | ||||
-rw-r--r-- | drivers/media/video/smiapp/Kconfig | 13 | ||||
-rw-r--r-- | drivers/media/video/smiapp/Makefile | 3 | ||||
-rw-r--r-- | drivers/media/video/smiapp/smiapp-core.c | 2832 | ||||
-rw-r--r-- | drivers/media/video/smiapp/smiapp-debug.h | 32 | ||||
-rw-r--r-- | drivers/media/video/smiapp/smiapp-limits.c | 132 | ||||
-rw-r--r-- | drivers/media/video/smiapp/smiapp-limits.h | 128 | ||||
-rw-r--r-- | drivers/media/video/smiapp/smiapp-quirk.c | 264 | ||||
-rw-r--r-- | drivers/media/video/smiapp/smiapp-quirk.h | 72 | ||||
-rw-r--r-- | drivers/media/video/smiapp/smiapp-reg-defs.h | 503 | ||||
-rw-r--r-- | drivers/media/video/smiapp/smiapp-reg.h | 122 | ||||
-rw-r--r-- | drivers/media/video/smiapp/smiapp-regs.c | 213 | ||||
-rw-r--r-- | drivers/media/video/smiapp/smiapp-regs.h | 46 | ||||
-rw-r--r-- | drivers/media/video/smiapp/smiapp.h | 251 |
16 files changed, 4616 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 | ||
562 | source "drivers/media/video/smiapp/Kconfig" | ||
563 | |||
562 | comment "Flash devices" | 564 | comment "Flash devices" |
563 | 565 | ||
564 | config VIDEO_ADP1653 | 566 | config 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 | |||
79 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o | 79 | obj-$(CONFIG_VIDEO_NOON010PC30) += noon010pc30.o |
80 | obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ | 80 | obj-$(CONFIG_VIDEO_M5MOLS) += m5mols/ |
81 | obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o | 81 | obj-$(CONFIG_VIDEO_S5K6AA) += s5k6aa.o |
82 | obj-$(CONFIG_VIDEO_SMIAPP) += smiapp/ | ||
82 | obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o | 83 | obj-$(CONFIG_VIDEO_ADP1653) += adp1653.o |
83 | obj-$(CONFIG_VIDEO_AS3645A) += as3645a.o | 84 | obj-$(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 @@ | |||
1 | config 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 | |||
8 | config 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 @@ | |||
1 | smiapp-objs += smiapp-core.o smiapp-regs.o \ | ||
2 | smiapp-quirk.o smiapp-limits.o | ||
3 | obj-$(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 | */ | ||
49 | static const struct smiapp_module_ident smiapp_module_idents[] = { | ||
50 | SMIAPP_IDENT_L(0x01, 0x022b, -1, "vs6555"), | ||
51 | SMIAPP_IDENT_L(0x01, 0x022e, -1, "vw6558"), | ||
52 | SMIAPP_IDENT_L(0x07, 0x7698, -1, "ovm7698"), | ||
53 | SMIAPP_IDENT_L(0x0b, 0x4242, -1, "smiapp-003"), | ||
54 | SMIAPP_IDENT_L(0x0c, 0x208a, -1, "tcm8330md"), | ||
55 | SMIAPP_IDENT_LQ(0x0c, 0x2134, -1, "tcm8500md", &smiapp_tcm8500md_quirk), | ||
56 | SMIAPP_IDENT_L(0x0c, 0x213e, -1, "et8en2"), | ||
57 | SMIAPP_IDENT_L(0x0c, 0x2184, -1, "tcm8580md"), | ||
58 | SMIAPP_IDENT_LQ(0x0c, 0x560f, -1, "jt8ew9", &smiapp_jt8ew9_quirk), | ||
59 | SMIAPP_IDENT_LQ(0x10, 0x4141, -1, "jt8ev1", &smiapp_jt8ev1_quirk), | ||
60 | SMIAPP_IDENT_LQ(0x10, 0x4241, -1, "imx125es", &smiapp_imx125es_quirk), | ||
61 | }; | ||
62 | |||
63 | /* | ||
64 | * | ||
65 | * Dynamic Capability Identification | ||
66 | * | ||
67 | */ | ||
68 | |||
69 | static int smiapp_read_frame_fmt(struct smiapp_sensor *sensor) | ||
70 | { | ||
71 | struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd); | ||
72 | u32 fmt_model_type, fmt_model_subtype, ncol_desc, nrow_desc; | ||
73 | unsigned int i; | ||
74 | int rval; | ||
75 | int line_count = 0; | ||
76 | int embedded_start = -1, embedded_end = -1; | ||
77 | int image_start = 0; | ||
78 | |||
79 | rval = smiapp_read(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 | |||
201 | static 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 | |||
243 | static 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 | |||
333 | static 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 | */ | ||
359 | static 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 | |||
374 | const 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 | |||
380 | static 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 | |||
399 | static 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 | |||
424 | static 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 | |||
503 | static const struct v4l2_ctrl_ops smiapp_ctrl_ops = { | ||
504 | .s_ctrl = smiapp_set_ctrl, | ||
505 | }; | ||
506 | |||
507 | static 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 | |||
603 | error: | ||
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 | |||
610 | static 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 | |||
618 | static 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 | |||
640 | static 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 | |||
657 | static 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 | |||
692 | static 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 | |||
775 | static 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 | |||
813 | static 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 | */ | ||
875 | static 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 | |||
927 | out: | ||
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 | */ | ||
940 | static 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 | */ | ||
972 | static 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 | |||
1093 | out: | ||
1094 | sensor->platform_data->strobe_setup->trigger = 0; | ||
1095 | |||
1096 | return rval; | ||
1097 | } | ||
1098 | |||
1099 | /* ----------------------------------------------------------------------------- | ||
1100 | * Power management | ||
1101 | */ | ||
1102 | |||
1103 | static 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 | |||
1233 | out_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 | |||
1238 | out_xclk_fail: | ||
1239 | regulator_disable(sensor->vana); | ||
1240 | return rval; | ||
1241 | } | ||
1242 | |||
1243 | static 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 | |||
1267 | static 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 | |||
1294 | out: | ||
1295 | mutex_unlock(&sensor->power_mutex); | ||
1296 | return ret; | ||
1297 | } | ||
1298 | |||
1299 | /* ----------------------------------------------------------------------------- | ||
1300 | * Video stream management | ||
1301 | */ | ||
1302 | |||
1303 | static 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 | |||
1422 | out: | ||
1423 | mutex_unlock(&sensor->mutex); | ||
1424 | |||
1425 | return rval; | ||
1426 | } | ||
1427 | |||
1428 | static 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 | |||
1443 | out: | ||
1444 | mutex_unlock(&sensor->mutex); | ||
1445 | return rval; | ||
1446 | } | ||
1447 | |||
1448 | /* ----------------------------------------------------------------------------- | ||
1449 | * V4L2 subdev video operations | ||
1450 | */ | ||
1451 | |||
1452 | static 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 | |||
1473 | static 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 | |||
1510 | out: | ||
1511 | mutex_unlock(&sensor->mutex); | ||
1512 | |||
1513 | return rval; | ||
1514 | } | ||
1515 | |||
1516 | static 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 | |||
1527 | static 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 | |||
1551 | static 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 | |||
1565 | static 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. */ | ||
1595 | static 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 | |||
1630 | static 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 | |||
1645 | static 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 | ||
1711 | static 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 | |||
1749 | static 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 | */ | ||
1797 | static 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. */ | ||
1913 | static 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 | |||
1941 | static 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 | |||
1979 | static 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 | |||
2031 | static 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 | |||
2084 | static 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 | } | ||
2097 | static 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 | |||
2137 | static 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 | |||
2149 | static ssize_t | ||
2150 | smiapp_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 | } | ||
2181 | static DEVICE_ATTR(nvm, S_IRUGO, smiapp_sysfs_nvm_read, NULL); | ||
2182 | |||
2183 | /* ----------------------------------------------------------------------------- | ||
2184 | * V4L2 subdev core operations | ||
2185 | */ | ||
2186 | |||
2187 | static 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 | |||
2313 | static const struct v4l2_subdev_ops smiapp_ops; | ||
2314 | static const struct v4l2_subdev_internal_ops smiapp_internal_ops; | ||
2315 | static const struct media_entity_operations smiapp_entity_ops; | ||
2316 | |||
2317 | static 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 | |||
2582 | out_nvm_release: | ||
2583 | device_remove_file(&client->dev, &dev_attr_nvm); | ||
2584 | |||
2585 | out_power_off: | ||
2586 | kfree(sensor->nvm); | ||
2587 | sensor->nvm = NULL; | ||
2588 | smiapp_power_off(sensor); | ||
2589 | |||
2590 | out_smiapp_power_on: | ||
2591 | if (sensor->platform_data->xshutdown != SMIAPP_NO_XSHUTDOWN) | ||
2592 | gpio_free(sensor->platform_data->xshutdown); | ||
2593 | |||
2594 | out_gpio_request: | ||
2595 | regulator_put(sensor->vana); | ||
2596 | sensor->vana = NULL; | ||
2597 | return rval; | ||
2598 | } | ||
2599 | |||
2600 | static 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 | |||
2637 | static int smiapp_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | ||
2638 | { | ||
2639 | return smiapp_set_power(sd, 0); | ||
2640 | } | ||
2641 | |||
2642 | static const struct v4l2_subdev_video_ops smiapp_video_ops = { | ||
2643 | .s_stream = smiapp_set_stream, | ||
2644 | }; | ||
2645 | |||
2646 | static const struct v4l2_subdev_core_ops smiapp_core_ops = { | ||
2647 | .s_power = smiapp_set_power, | ||
2648 | }; | ||
2649 | |||
2650 | static 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 | |||
2658 | static const struct v4l2_subdev_sensor_ops smiapp_sensor_ops = { | ||
2659 | .g_skip_frames = smiapp_get_skip_frames, | ||
2660 | }; | ||
2661 | |||
2662 | static 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 | |||
2669 | static const struct media_entity_operations smiapp_entity_ops = { | ||
2670 | .link_validate = v4l2_subdev_link_validate, | ||
2671 | }; | ||
2672 | |||
2673 | static const struct v4l2_subdev_internal_ops smiapp_internal_src_ops = { | ||
2674 | .registered = smiapp_registered, | ||
2675 | .open = smiapp_open, | ||
2676 | .close = smiapp_close, | ||
2677 | }; | ||
2678 | |||
2679 | static 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 | |||
2690 | static 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 | |||
2715 | static 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 | |||
2742 | static 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 | |||
2774 | static 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 | |||
2807 | static const struct i2c_device_id smiapp_id_table[] = { | ||
2808 | { SMIAPP_NAME, 0 }, | ||
2809 | { }, | ||
2810 | }; | ||
2811 | MODULE_DEVICE_TABLE(i2c, smiapp_id_table); | ||
2812 | |||
2813 | static const struct dev_pm_ops smiapp_pm_ops = { | ||
2814 | .suspend = smiapp_suspend, | ||
2815 | .resume = smiapp_resume, | ||
2816 | }; | ||
2817 | |||
2818 | static 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 | |||
2828 | module_i2c_driver(smiapp_i2c_driver); | ||
2829 | |||
2830 | MODULE_AUTHOR("Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>"); | ||
2831 | MODULE_DESCRIPTION("Generic SMIA/SMIA++ camera module driver"); | ||
2832 | MODULE_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 | |||
27 | struct smiapp_reg_limits smiapp_reg_limits[] = { | ||
28 | { SMIAPP_REG_U16_ANALOGUE_GAIN_CAPABILITY, "analogue_gain_capability" }, /* 0 */ | ||
29 | { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MIN, "analogue_gain_code_min" }, | ||
30 | { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_MAX, "analogue_gain_code_max" }, | ||
31 | { SMIAPP_REG_U8_THS_ZERO_MIN, "ths_zero_min" }, | ||
32 | { SMIAPP_REG_U8_TCLK_TRAIL_MIN, "tclk_trail_min" }, | ||
33 | { SMIAPP_REG_U16_INTEGRATION_TIME_CAPABILITY, "integration_time_capability" }, /* 5 */ | ||
34 | { SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MIN, "coarse_integration_time_min" }, | ||
35 | { SMIAPP_REG_U16_COARSE_INTEGRATION_TIME_MAX_MARGIN, "coarse_integration_time_max_margin" }, | ||
36 | { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN, "fine_integration_time_min" }, | ||
37 | { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN, "fine_integration_time_max_margin" }, | ||
38 | { SMIAPP_REG_U16_DIGITAL_GAIN_CAPABILITY, "digital_gain_capability" }, /* 10 */ | ||
39 | { SMIAPP_REG_U16_DIGITAL_GAIN_MIN, "digital_gain_min" }, | ||
40 | { SMIAPP_REG_U16_DIGITAL_GAIN_MAX, "digital_gain_max" }, | ||
41 | { SMIAPP_REG_F32_MIN_EXT_CLK_FREQ_HZ, "min_ext_clk_freq_hz" }, | ||
42 | { SMIAPP_REG_F32_MAX_EXT_CLK_FREQ_HZ, "max_ext_clk_freq_hz" }, | ||
43 | { SMIAPP_REG_U16_MIN_PRE_PLL_CLK_DIV, "min_pre_pll_clk_div" }, /* 15 */ | ||
44 | { SMIAPP_REG_U16_MAX_PRE_PLL_CLK_DIV, "max_pre_pll_clk_div" }, | ||
45 | { SMIAPP_REG_F32_MIN_PLL_IP_FREQ_HZ, "min_pll_ip_freq_hz" }, | ||
46 | { SMIAPP_REG_F32_MAX_PLL_IP_FREQ_HZ, "max_pll_ip_freq_hz" }, | ||
47 | { SMIAPP_REG_U16_MIN_PLL_MULTIPLIER, "min_pll_multiplier" }, | ||
48 | { SMIAPP_REG_U16_MAX_PLL_MULTIPLIER, "max_pll_multiplier" }, /* 20 */ | ||
49 | { SMIAPP_REG_F32_MIN_PLL_OP_FREQ_HZ, "min_pll_op_freq_hz" }, | ||
50 | { SMIAPP_REG_F32_MAX_PLL_OP_FREQ_HZ, "max_pll_op_freq_hz" }, | ||
51 | { SMIAPP_REG_U16_MIN_VT_SYS_CLK_DIV, "min_vt_sys_clk_div" }, | ||
52 | { SMIAPP_REG_U16_MAX_VT_SYS_CLK_DIV, "max_vt_sys_clk_div" }, | ||
53 | { SMIAPP_REG_F32_MIN_VT_SYS_CLK_FREQ_HZ, "min_vt_sys_clk_freq_hz" }, /* 25 */ | ||
54 | { SMIAPP_REG_F32_MAX_VT_SYS_CLK_FREQ_HZ, "max_vt_sys_clk_freq_hz" }, | ||
55 | { SMIAPP_REG_F32_MIN_VT_PIX_CLK_FREQ_HZ, "min_vt_pix_clk_freq_hz" }, | ||
56 | { SMIAPP_REG_F32_MAX_VT_PIX_CLK_FREQ_HZ, "max_vt_pix_clk_freq_hz" }, | ||
57 | { SMIAPP_REG_U16_MIN_VT_PIX_CLK_DIV, "min_vt_pix_clk_div" }, | ||
58 | { SMIAPP_REG_U16_MAX_VT_PIX_CLK_DIV, "max_vt_pix_clk_div" }, /* 30 */ | ||
59 | { SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES, "min_frame_length_lines" }, | ||
60 | { SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES, "max_frame_length_lines" }, | ||
61 | { SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK, "min_line_length_pck" }, | ||
62 | { SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK, "max_line_length_pck" }, | ||
63 | { SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK, "min_line_blanking_pck" }, /* 35 */ | ||
64 | { SMIAPP_REG_U16_MIN_FRAME_BLANKING_LINES, "min_frame_blanking_lines" }, | ||
65 | { SMIAPP_REG_U8_MIN_LINE_LENGTH_PCK_STEP_SIZE, "min_line_length_pck_step_size" }, | ||
66 | { SMIAPP_REG_U16_MIN_OP_SYS_CLK_DIV, "min_op_sys_clk_div" }, | ||
67 | { SMIAPP_REG_U16_MAX_OP_SYS_CLK_DIV, "max_op_sys_clk_div" }, | ||
68 | { SMIAPP_REG_F32_MIN_OP_SYS_CLK_FREQ_HZ, "min_op_sys_clk_freq_hz" }, /* 40 */ | ||
69 | { SMIAPP_REG_F32_MAX_OP_SYS_CLK_FREQ_HZ, "max_op_sys_clk_freq_hz" }, | ||
70 | { SMIAPP_REG_U16_MIN_OP_PIX_CLK_DIV, "min_op_pix_clk_div" }, | ||
71 | { SMIAPP_REG_U16_MAX_OP_PIX_CLK_DIV, "max_op_pix_clk_div" }, | ||
72 | { SMIAPP_REG_F32_MIN_OP_PIX_CLK_FREQ_HZ, "min_op_pix_clk_freq_hz" }, | ||
73 | { SMIAPP_REG_F32_MAX_OP_PIX_CLK_FREQ_HZ, "max_op_pix_clk_freq_hz" }, /* 45 */ | ||
74 | { SMIAPP_REG_U16_X_ADDR_MIN, "x_addr_min" }, | ||
75 | { SMIAPP_REG_U16_Y_ADDR_MIN, "y_addr_min" }, | ||
76 | { SMIAPP_REG_U16_X_ADDR_MAX, "x_addr_max" }, | ||
77 | { SMIAPP_REG_U16_Y_ADDR_MAX, "y_addr_max" }, | ||
78 | { SMIAPP_REG_U16_MIN_X_OUTPUT_SIZE, "min_x_output_size" }, /* 50 */ | ||
79 | { SMIAPP_REG_U16_MIN_Y_OUTPUT_SIZE, "min_y_output_size" }, | ||
80 | { SMIAPP_REG_U16_MAX_X_OUTPUT_SIZE, "max_x_output_size" }, | ||
81 | { SMIAPP_REG_U16_MAX_Y_OUTPUT_SIZE, "max_y_output_size" }, | ||
82 | { SMIAPP_REG_U16_MIN_EVEN_INC, "min_even_inc" }, | ||
83 | { SMIAPP_REG_U16_MAX_EVEN_INC, "max_even_inc" }, /* 55 */ | ||
84 | { SMIAPP_REG_U16_MIN_ODD_INC, "min_odd_inc" }, | ||
85 | { SMIAPP_REG_U16_MAX_ODD_INC, "max_odd_inc" }, | ||
86 | { SMIAPP_REG_U16_SCALING_CAPABILITY, "scaling_capability" }, | ||
87 | { SMIAPP_REG_U16_SCALER_M_MIN, "scaler_m_min" }, | ||
88 | { SMIAPP_REG_U16_SCALER_M_MAX, "scaler_m_max" }, /* 60 */ | ||
89 | { SMIAPP_REG_U16_SCALER_N_MIN, "scaler_n_min" }, | ||
90 | { SMIAPP_REG_U16_SCALER_N_MAX, "scaler_n_max" }, | ||
91 | { SMIAPP_REG_U16_SPATIAL_SAMPLING_CAPABILITY, "spatial_sampling_capability" }, | ||
92 | { SMIAPP_REG_U8_DIGITAL_CROP_CAPABILITY, "digital_crop_capability" }, | ||
93 | { SMIAPP_REG_U16_COMPRESSION_CAPABILITY, "compression_capability" }, /* 65 */ | ||
94 | { SMIAPP_REG_U8_FIFO_SUPPORT_CAPABILITY, "fifo_support_capability" }, | ||
95 | { SMIAPP_REG_U8_DPHY_CTRL_CAPABILITY, "dphy_ctrl_capability" }, | ||
96 | { SMIAPP_REG_U8_CSI_LANE_MODE_CAPABILITY, "csi_lane_mode_capability" }, | ||
97 | { SMIAPP_REG_U8_CSI_SIGNALLING_MODE_CAPABILITY, "csi_signalling_mode_capability" }, | ||
98 | { SMIAPP_REG_U8_FAST_STANDBY_CAPABILITY, "fast_standby_capability" }, /* 70 */ | ||
99 | { SMIAPP_REG_U8_CCI_ADDRESS_CONTROL_CAPABILITY, "cci_address_control_capability" }, | ||
100 | { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_1_LANE_MODE_MBPS, "max_per_lane_bitrate_1_lane_mode_mbps" }, | ||
101 | { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_2_LANE_MODE_MBPS, "max_per_lane_bitrate_2_lane_mode_mbps" }, | ||
102 | { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_3_LANE_MODE_MBPS, "max_per_lane_bitrate_3_lane_mode_mbps" }, | ||
103 | { SMIAPP_REG_U32_MAX_PER_LANE_BITRATE_4_LANE_MODE_MBPS, "max_per_lane_bitrate_4_lane_mode_mbps" }, /* 75 */ | ||
104 | { SMIAPP_REG_U8_TEMP_SENSOR_CAPABILITY, "temp_sensor_capability" }, | ||
105 | { SMIAPP_REG_U16_MIN_FRAME_LENGTH_LINES_BIN, "min_frame_length_lines_bin" }, | ||
106 | { SMIAPP_REG_U16_MAX_FRAME_LENGTH_LINES_BIN, "max_frame_length_lines_bin" }, | ||
107 | { SMIAPP_REG_U16_MIN_LINE_LENGTH_PCK_BIN, "min_line_length_pck_bin" }, | ||
108 | { SMIAPP_REG_U16_MAX_LINE_LENGTH_PCK_BIN, "max_line_length_pck_bin" }, /* 80 */ | ||
109 | { SMIAPP_REG_U16_MIN_LINE_BLANKING_PCK_BIN, "min_line_blanking_pck_bin" }, | ||
110 | { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MIN_BIN, "fine_integration_time_min_bin" }, | ||
111 | { SMIAPP_REG_U16_FINE_INTEGRATION_TIME_MAX_MARGIN_BIN, "fine_integration_time_max_margin_bin" }, | ||
112 | { SMIAPP_REG_U8_BINNING_CAPABILITY, "binning_capability" }, | ||
113 | { SMIAPP_REG_U8_BINNING_WEIGHTING_CAPABILITY, "binning_weighting_capability" }, /* 85 */ | ||
114 | { SMIAPP_REG_U8_DATA_TRANSFER_IF_CAPABILITY, "data_transfer_if_capability" }, | ||
115 | { SMIAPP_REG_U8_SHADING_CORRECTION_CAPABILITY, "shading_correction_capability" }, | ||
116 | { SMIAPP_REG_U8_GREEN_IMBALANCE_CAPABILITY, "green_imbalance_capability" }, | ||
117 | { SMIAPP_REG_U8_BLACK_LEVEL_CAPABILITY, "black_level_capability" }, | ||
118 | { SMIAPP_REG_U8_MODULE_SPECIFIC_CORRECTION_CAPABILITY, "module_specific_correction_capability" }, /* 90 */ | ||
119 | { SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY, "defect_correction_capability" }, | ||
120 | { SMIAPP_REG_U16_DEFECT_CORRECTION_CAPABILITY_2, "defect_correction_capability_2" }, | ||
121 | { SMIAPP_REG_U8_EDOF_CAPABILITY, "edof_capability" }, | ||
122 | { SMIAPP_REG_U8_COLOUR_FEEDBACK_CAPABILITY, "colour_feedback_capability" }, | ||
123 | { SMIAPP_REG_U8_ESTIMATION_MODE_CAPABILITY, "estimation_mode_capability" }, /* 95 */ | ||
124 | { SMIAPP_REG_U8_ESTIMATION_ZONE_CAPABILITY, "estimation_zone_capability" }, | ||
125 | { SMIAPP_REG_U16_CAPABILITY_TRDY_MIN, "capability_trdy_min" }, | ||
126 | { SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, "flash_mode_capability" }, | ||
127 | { SMIAPP_REG_U8_ACTUATOR_CAPABILITY, "actuator_capability" }, | ||
128 | { SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_1, "bracketing_lut_capability_1" }, /* 100 */ | ||
129 | { SMIAPP_REG_U8_BRACKETING_LUT_CAPABILITY_2, "bracketing_lut_capability_2" }, | ||
130 | { SMIAPP_REG_U16_ANALOGUE_GAIN_CODE_STEP, "analogue_gain_code_step" }, | ||
131 | { 0, NULL }, | ||
132 | }; | ||
diff --git a/drivers/media/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 | |||
31 | static 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 | |||
38 | static 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 | |||
57 | void 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 | |||
68 | int 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 | |||
88 | static 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 | |||
102 | static 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 | |||
140 | const struct smiapp_quirk smiapp_jt8ew9_quirk = { | ||
141 | .limits = jt8ew9_limits, | ||
142 | .post_poweron = jt8ew9_post_poweron, | ||
143 | }; | ||
144 | |||
145 | static 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 | |||
161 | const struct smiapp_quirk smiapp_imx125es_quirk = { | ||
162 | .post_poweron = imx125es_post_poweron, | ||
163 | }; | ||
164 | |||
165 | static 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 | |||
174 | static 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 | |||
222 | static int jt8ev1_pre_streamon(struct smiapp_sensor *sensor) | ||
223 | { | ||
224 | return smiapp_write_8(sensor, 0x3328, 0x00); | ||
225 | } | ||
226 | |||
227 | static 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 | |||
247 | const 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 | |||
255 | static 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 | |||
262 | const 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 | |||
28 | struct smiapp_sensor; | ||
29 | |||
30 | /** | ||
31 | * struct smiapp_quirk - quirks for sensors that deviate from SMIA++ standard | ||
32 | * | ||
33 | * @limits: Replace sensor->limits with values which can't be read from | ||
34 | * sensor registers. Called the first time the sensor is powered up. | ||
35 | * @post_poweron: Called always after the sensor has been fully powered on. | ||
36 | * @pre_streamon: Called just before streaming is enabled. | ||
37 | * @post_streamon: Called right after stopping streaming. | ||
38 | */ | ||
39 | struct smiapp_quirk { | ||
40 | int (*limits)(struct smiapp_sensor *sensor); | ||
41 | int (*post_poweron)(struct smiapp_sensor *sensor); | ||
42 | int (*pre_streamon)(struct smiapp_sensor *sensor); | ||
43 | int (*post_streamoff)(struct smiapp_sensor *sensor); | ||
44 | 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 | |||
50 | struct smiapp_reg_8 { | ||
51 | u16 reg; | ||
52 | u8 val; | ||
53 | }; | ||
54 | |||
55 | void 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 | |||
67 | extern const struct smiapp_quirk smiapp_jt8ev1_quirk; | ||
68 | extern const struct smiapp_quirk smiapp_imx125es_quirk; | ||
69 | extern const struct smiapp_quirk smiapp_jt8ew9_quirk; | ||
70 | extern 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 | |||
32 | static 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 | */ | ||
82 | int 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 | |||
140 | err: | ||
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 | */ | ||
150 | int 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 | ||
37 | struct smia_reg { | ||
38 | u16 type; | ||
39 | u16 reg; /* 16-bit offset */ | ||
40 | u32 val; /* 8/16/32-bit value */ | ||
41 | }; | ||
42 | |||
43 | int smiapp_read(struct i2c_client *client, u32 reg, u32 *val); | ||
44 | int 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 | |||
59 | struct smiapp_quirk; | ||
60 | |||
61 | #define SMIAPP_MODULE_IDENT_FLAG_REV_LE (1 << 0) | ||
62 | |||
63 | struct smiapp_module_ident { | ||
64 | u8 manufacturer_id; | ||
65 | u16 model_id; | ||
66 | u8 revision_number_major; | ||
67 | |||
68 | u8 flags; | ||
69 | |||
70 | char *name; | ||
71 | const struct smiapp_quirk *quirk; | ||
72 | }; | ||
73 | |||
74 | struct smiapp_module_info { | ||
75 | u32 manufacturer_id; | ||
76 | u32 model_id; | ||
77 | u32 revision_number_major; | ||
78 | u32 revision_number_minor; | ||
79 | |||
80 | u32 module_year; | ||
81 | u32 module_month; | ||
82 | u32 module_day; | ||
83 | |||
84 | u32 sensor_manufacturer_id; | ||
85 | u32 sensor_model_id; | ||
86 | u32 sensor_revision_number; | ||
87 | u32 sensor_firmware_version; | ||
88 | |||
89 | u32 smia_version; | ||
90 | u32 smiapp_version; | ||
91 | |||
92 | u32 smiapp_profile; | ||
93 | |||
94 | char *name; | ||
95 | const struct smiapp_quirk *quirk; | ||
96 | }; | ||
97 | |||
98 | #define SMIAPP_IDENT_FQ(manufacturer, model, rev, fl, _name, _quirk) \ | ||
99 | { .manufacturer_id = manufacturer, \ | ||
100 | .model_id = model, \ | ||
101 | .revision_number_major = rev, \ | ||
102 | .flags = fl, \ | ||
103 | .name = _name, \ | ||
104 | .quirk = _quirk, } | ||
105 | |||
106 | #define SMIAPP_IDENT_LQ(manufacturer, model, rev, _name, _quirk) \ | ||
107 | { .manufacturer_id = manufacturer, \ | ||
108 | .model_id = model, \ | ||
109 | .revision_number_major = rev, \ | ||
110 | .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE, \ | ||
111 | .name = _name, \ | ||
112 | .quirk = _quirk, } | ||
113 | |||
114 | #define SMIAPP_IDENT_L(manufacturer, model, rev, _name) \ | ||
115 | { .manufacturer_id = manufacturer, \ | ||
116 | .model_id = model, \ | ||
117 | .revision_number_major = rev, \ | ||
118 | .flags = SMIAPP_MODULE_IDENT_FLAG_REV_LE, \ | ||
119 | .name = _name, } | ||
120 | |||
121 | #define SMIAPP_IDENT_Q(manufacturer, model, rev, _name, _quirk) \ | ||
122 | { .manufacturer_id = manufacturer, \ | ||
123 | .model_id = model, \ | ||
124 | .revision_number_major = rev, \ | ||
125 | .flags = 0, \ | ||
126 | .name = _name, \ | ||
127 | .quirk = _quirk, } | ||
128 | |||
129 | #define SMIAPP_IDENT(manufacturer, model, rev, _name) \ | ||
130 | { .manufacturer_id = manufacturer, \ | ||
131 | .model_id = model, \ | ||
132 | .revision_number_major = rev, \ | ||
133 | .flags = 0, \ | ||
134 | .name = _name, } | ||
135 | |||
136 | struct smiapp_reg_limits { | ||
137 | u32 addr; | ||
138 | char *what; | ||
139 | }; | ||
140 | |||
141 | extern struct smiapp_reg_limits smiapp_reg_limits[]; | ||
142 | |||
143 | struct smiapp_csi_data_format { | ||
144 | u32 code; | ||
145 | u8 width; | ||
146 | u8 compressed; | ||
147 | u8 pixel_order; | ||
148 | }; | ||
149 | |||
150 | #define SMIAPP_SUBDEVS 3 | ||
151 | |||
152 | #define SMIAPP_PA_PAD_SRC 0 | ||
153 | #define SMIAPP_PAD_SINK 0 | ||
154 | #define SMIAPP_PAD_SRC 1 | ||
155 | #define SMIAPP_PADS 2 | ||
156 | |||
157 | struct smiapp_binning_subtype { | ||
158 | u8 horizontal:4; | ||
159 | u8 vertical:4; | ||
160 | } __packed; | ||
161 | |||
162 | struct smiapp_subdev { | ||
163 | struct v4l2_subdev sd; | ||
164 | struct media_pad pads[2]; | ||
165 | struct v4l2_rect sink_fmt; | ||
166 | struct v4l2_rect crop[2]; | ||
167 | struct v4l2_rect compose; /* compose on sink */ | ||
168 | unsigned short sink_pad; | ||
169 | unsigned short source_pad; | ||
170 | int npads; | ||
171 | struct smiapp_sensor *sensor; | ||
172 | struct v4l2_ctrl_handler ctrl_handler; | ||
173 | }; | ||
174 | |||
175 | /* | ||
176 | * struct smiapp_sensor - Main device structure | ||
177 | */ | ||
178 | struct smiapp_sensor { | ||
179 | /* | ||
180 | * "mutex" is used to serialise access to all fields here | ||
181 | * except v4l2_ctrls at the end of the struct. "mutex" is also | ||
182 | * used to serialise access to file handle specific | ||
183 | * information. The exception to this rule is the power_mutex | ||
184 | * below. | ||
185 | */ | ||
186 | struct mutex mutex; | ||
187 | /* | ||
188 | * power_mutex is used to serialise power management related | ||
189 | * activities. Acquiring "mutex" at that time isn't necessary | ||
190 | * since there are no other users anyway. | ||
191 | */ | ||
192 | struct mutex power_mutex; | ||
193 | struct smiapp_subdev ssds[SMIAPP_SUBDEVS]; | ||
194 | u32 ssds_used; | ||
195 | struct smiapp_subdev *src; | ||
196 | struct smiapp_subdev *binner; | ||
197 | struct smiapp_subdev *scaler; | ||
198 | struct smiapp_subdev *pixel_array; | ||
199 | struct smiapp_platform_data *platform_data; | ||
200 | struct regulator *vana; | ||
201 | 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_ */ | ||