diff options
Diffstat (limited to 'drivers/media/video/omap3isp/isph3a_af.c')
-rw-r--r-- | drivers/media/video/omap3isp/isph3a_af.c | 423 |
1 files changed, 0 insertions, 423 deletions
diff --git a/drivers/media/video/omap3isp/isph3a_af.c b/drivers/media/video/omap3isp/isph3a_af.c deleted file mode 100644 index 42ccce318d5d..000000000000 --- a/drivers/media/video/omap3isp/isph3a_af.c +++ /dev/null | |||
@@ -1,423 +0,0 @@ | |||
1 | /* | ||
2 | * isph3a_af.c | ||
3 | * | ||
4 | * TI OMAP3 ISP - H3A AF module | ||
5 | * | ||
6 | * Copyright (C) 2010 Nokia Corporation | ||
7 | * Copyright (C) 2009 Texas Instruments, Inc. | ||
8 | * | ||
9 | * Contacts: David Cohen <dacohen@gmail.com> | ||
10 | * Laurent Pinchart <laurent.pinchart@ideasonboard.com> | ||
11 | * Sakari Ailus <sakari.ailus@iki.fi> | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or modify | ||
14 | * it under the terms of the GNU General Public License version 2 as | ||
15 | * 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 | /* Linux specific include files */ | ||
29 | #include <linux/device.h> | ||
30 | #include <linux/slab.h> | ||
31 | |||
32 | #include "isp.h" | ||
33 | #include "isph3a.h" | ||
34 | #include "ispstat.h" | ||
35 | |||
36 | #define IS_OUT_OF_BOUNDS(value, min, max) \ | ||
37 | (((value) < (min)) || ((value) > (max))) | ||
38 | |||
39 | static void h3a_af_setup_regs(struct ispstat *af, void *priv) | ||
40 | { | ||
41 | struct omap3isp_h3a_af_config *conf = priv; | ||
42 | u32 pcr; | ||
43 | u32 pax1; | ||
44 | u32 pax2; | ||
45 | u32 paxstart; | ||
46 | u32 coef; | ||
47 | u32 base_coef_set0; | ||
48 | u32 base_coef_set1; | ||
49 | int index; | ||
50 | |||
51 | if (af->state == ISPSTAT_DISABLED) | ||
52 | return; | ||
53 | |||
54 | isp_reg_writel(af->isp, af->active_buf->iommu_addr, OMAP3_ISP_IOMEM_H3A, | ||
55 | ISPH3A_AFBUFST); | ||
56 | |||
57 | if (!af->update) | ||
58 | return; | ||
59 | |||
60 | /* Configure Hardware Registers */ | ||
61 | pax1 = ((conf->paxel.width >> 1) - 1) << AF_PAXW_SHIFT; | ||
62 | /* Set height in AFPAX1 */ | ||
63 | pax1 |= (conf->paxel.height >> 1) - 1; | ||
64 | isp_reg_writel(af->isp, pax1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1); | ||
65 | |||
66 | /* Configure AFPAX2 Register */ | ||
67 | /* Set Line Increment in AFPAX2 Register */ | ||
68 | pax2 = ((conf->paxel.line_inc >> 1) - 1) << AF_LINE_INCR_SHIFT; | ||
69 | /* Set Vertical Count */ | ||
70 | pax2 |= (conf->paxel.v_cnt - 1) << AF_VT_COUNT_SHIFT; | ||
71 | /* Set Horizontal Count */ | ||
72 | pax2 |= (conf->paxel.h_cnt - 1); | ||
73 | isp_reg_writel(af->isp, pax2, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2); | ||
74 | |||
75 | /* Configure PAXSTART Register */ | ||
76 | /*Configure Horizontal Start */ | ||
77 | paxstart = conf->paxel.h_start << AF_HZ_START_SHIFT; | ||
78 | /* Configure Vertical Start */ | ||
79 | paxstart |= conf->paxel.v_start; | ||
80 | isp_reg_writel(af->isp, paxstart, OMAP3_ISP_IOMEM_H3A, | ||
81 | ISPH3A_AFPAXSTART); | ||
82 | |||
83 | /*SetIIRSH Register */ | ||
84 | isp_reg_writel(af->isp, conf->iir.h_start, | ||
85 | OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH); | ||
86 | |||
87 | base_coef_set0 = ISPH3A_AFCOEF010; | ||
88 | base_coef_set1 = ISPH3A_AFCOEF110; | ||
89 | for (index = 0; index <= 8; index += 2) { | ||
90 | /*Set IIR Filter0 Coefficients */ | ||
91 | coef = 0; | ||
92 | coef |= conf->iir.coeff_set0[index]; | ||
93 | coef |= conf->iir.coeff_set0[index + 1] << | ||
94 | AF_COEF_SHIFT; | ||
95 | isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A, | ||
96 | base_coef_set0); | ||
97 | base_coef_set0 += AFCOEF_OFFSET; | ||
98 | |||
99 | /*Set IIR Filter1 Coefficients */ | ||
100 | coef = 0; | ||
101 | coef |= conf->iir.coeff_set1[index]; | ||
102 | coef |= conf->iir.coeff_set1[index + 1] << | ||
103 | AF_COEF_SHIFT; | ||
104 | isp_reg_writel(af->isp, coef, OMAP3_ISP_IOMEM_H3A, | ||
105 | base_coef_set1); | ||
106 | base_coef_set1 += AFCOEF_OFFSET; | ||
107 | } | ||
108 | /* set AFCOEF0010 Register */ | ||
109 | isp_reg_writel(af->isp, conf->iir.coeff_set0[10], | ||
110 | OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF0010); | ||
111 | /* set AFCOEF1010 Register */ | ||
112 | isp_reg_writel(af->isp, conf->iir.coeff_set1[10], | ||
113 | OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010); | ||
114 | |||
115 | /* PCR Register */ | ||
116 | /* Set RGB Position */ | ||
117 | pcr = conf->rgb_pos << AF_RGBPOS_SHIFT; | ||
118 | /* Set Accumulator Mode */ | ||
119 | if (conf->fvmode == OMAP3ISP_AF_MODE_PEAK) | ||
120 | pcr |= AF_FVMODE; | ||
121 | /* Set A-law */ | ||
122 | if (conf->alaw_enable) | ||
123 | pcr |= AF_ALAW_EN; | ||
124 | /* HMF Configurations */ | ||
125 | if (conf->hmf.enable) { | ||
126 | /* Enable HMF */ | ||
127 | pcr |= AF_MED_EN; | ||
128 | /* Set Median Threshold */ | ||
129 | pcr |= conf->hmf.threshold << AF_MED_TH_SHIFT; | ||
130 | } | ||
131 | /* Set PCR Register */ | ||
132 | isp_reg_clr_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, | ||
133 | AF_PCR_MASK, pcr); | ||
134 | |||
135 | af->update = 0; | ||
136 | af->config_counter += af->inc_config; | ||
137 | af->inc_config = 0; | ||
138 | af->buf_size = conf->buf_size; | ||
139 | } | ||
140 | |||
141 | static void h3a_af_enable(struct ispstat *af, int enable) | ||
142 | { | ||
143 | if (enable) { | ||
144 | isp_reg_set(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, | ||
145 | ISPH3A_PCR_AF_EN); | ||
146 | omap3isp_subclk_enable(af->isp, OMAP3_ISP_SUBCLK_AF); | ||
147 | } else { | ||
148 | isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, | ||
149 | ISPH3A_PCR_AF_EN); | ||
150 | omap3isp_subclk_disable(af->isp, OMAP3_ISP_SUBCLK_AF); | ||
151 | } | ||
152 | } | ||
153 | |||
154 | static int h3a_af_busy(struct ispstat *af) | ||
155 | { | ||
156 | return isp_reg_readl(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR) | ||
157 | & ISPH3A_PCR_BUSYAF; | ||
158 | } | ||
159 | |||
160 | static u32 h3a_af_get_buf_size(struct omap3isp_h3a_af_config *conf) | ||
161 | { | ||
162 | return conf->paxel.h_cnt * conf->paxel.v_cnt * OMAP3ISP_AF_PAXEL_SIZE; | ||
163 | } | ||
164 | |||
165 | /* Function to check paxel parameters */ | ||
166 | static int h3a_af_validate_params(struct ispstat *af, void *new_conf) | ||
167 | { | ||
168 | struct omap3isp_h3a_af_config *user_cfg = new_conf; | ||
169 | struct omap3isp_h3a_af_paxel *paxel_cfg = &user_cfg->paxel; | ||
170 | struct omap3isp_h3a_af_iir *iir_cfg = &user_cfg->iir; | ||
171 | int index; | ||
172 | u32 buf_size; | ||
173 | |||
174 | /* Check horizontal Count */ | ||
175 | if (IS_OUT_OF_BOUNDS(paxel_cfg->h_cnt, | ||
176 | OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN, | ||
177 | OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MAX)) | ||
178 | return -EINVAL; | ||
179 | |||
180 | /* Check Vertical Count */ | ||
181 | if (IS_OUT_OF_BOUNDS(paxel_cfg->v_cnt, | ||
182 | OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN, | ||
183 | OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MAX)) | ||
184 | return -EINVAL; | ||
185 | |||
186 | if (IS_OUT_OF_BOUNDS(paxel_cfg->height, OMAP3ISP_AF_PAXEL_HEIGHT_MIN, | ||
187 | OMAP3ISP_AF_PAXEL_HEIGHT_MAX) || | ||
188 | paxel_cfg->height % 2) | ||
189 | return -EINVAL; | ||
190 | |||
191 | /* Check width */ | ||
192 | if (IS_OUT_OF_BOUNDS(paxel_cfg->width, OMAP3ISP_AF_PAXEL_WIDTH_MIN, | ||
193 | OMAP3ISP_AF_PAXEL_WIDTH_MAX) || | ||
194 | paxel_cfg->width % 2) | ||
195 | return -EINVAL; | ||
196 | |||
197 | /* Check Line Increment */ | ||
198 | if (IS_OUT_OF_BOUNDS(paxel_cfg->line_inc, | ||
199 | OMAP3ISP_AF_PAXEL_INCREMENT_MIN, | ||
200 | OMAP3ISP_AF_PAXEL_INCREMENT_MAX) || | ||
201 | paxel_cfg->line_inc % 2) | ||
202 | return -EINVAL; | ||
203 | |||
204 | /* Check Horizontal Start */ | ||
205 | if ((paxel_cfg->h_start < iir_cfg->h_start) || | ||
206 | IS_OUT_OF_BOUNDS(paxel_cfg->h_start, | ||
207 | OMAP3ISP_AF_PAXEL_HZSTART_MIN, | ||
208 | OMAP3ISP_AF_PAXEL_HZSTART_MAX)) | ||
209 | return -EINVAL; | ||
210 | |||
211 | /* Check IIR */ | ||
212 | for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) { | ||
213 | if ((iir_cfg->coeff_set0[index]) > OMAP3ISP_AF_COEF_MAX) | ||
214 | return -EINVAL; | ||
215 | |||
216 | if ((iir_cfg->coeff_set1[index]) > OMAP3ISP_AF_COEF_MAX) | ||
217 | return -EINVAL; | ||
218 | } | ||
219 | |||
220 | if (IS_OUT_OF_BOUNDS(iir_cfg->h_start, OMAP3ISP_AF_IIRSH_MIN, | ||
221 | OMAP3ISP_AF_IIRSH_MAX)) | ||
222 | return -EINVAL; | ||
223 | |||
224 | /* Hack: If paxel size is 12, the 10th AF window may be corrupted */ | ||
225 | if ((paxel_cfg->h_cnt * paxel_cfg->v_cnt > 9) && | ||
226 | (paxel_cfg->width * paxel_cfg->height == 12)) | ||
227 | return -EINVAL; | ||
228 | |||
229 | buf_size = h3a_af_get_buf_size(user_cfg); | ||
230 | if (buf_size > user_cfg->buf_size) | ||
231 | /* User buf_size request wasn't enough */ | ||
232 | user_cfg->buf_size = buf_size; | ||
233 | else if (user_cfg->buf_size > OMAP3ISP_AF_MAX_BUF_SIZE) | ||
234 | user_cfg->buf_size = OMAP3ISP_AF_MAX_BUF_SIZE; | ||
235 | |||
236 | return 0; | ||
237 | } | ||
238 | |||
239 | /* Update local parameters */ | ||
240 | static void h3a_af_set_params(struct ispstat *af, void *new_conf) | ||
241 | { | ||
242 | struct omap3isp_h3a_af_config *user_cfg = new_conf; | ||
243 | struct omap3isp_h3a_af_config *cur_cfg = af->priv; | ||
244 | int update = 0; | ||
245 | int index; | ||
246 | |||
247 | /* alaw */ | ||
248 | if (cur_cfg->alaw_enable != user_cfg->alaw_enable) { | ||
249 | update = 1; | ||
250 | goto out; | ||
251 | } | ||
252 | |||
253 | /* hmf */ | ||
254 | if (cur_cfg->hmf.enable != user_cfg->hmf.enable) { | ||
255 | update = 1; | ||
256 | goto out; | ||
257 | } | ||
258 | if (cur_cfg->hmf.threshold != user_cfg->hmf.threshold) { | ||
259 | update = 1; | ||
260 | goto out; | ||
261 | } | ||
262 | |||
263 | /* rgbpos */ | ||
264 | if (cur_cfg->rgb_pos != user_cfg->rgb_pos) { | ||
265 | update = 1; | ||
266 | goto out; | ||
267 | } | ||
268 | |||
269 | /* iir */ | ||
270 | if (cur_cfg->iir.h_start != user_cfg->iir.h_start) { | ||
271 | update = 1; | ||
272 | goto out; | ||
273 | } | ||
274 | for (index = 0; index < OMAP3ISP_AF_NUM_COEF; index++) { | ||
275 | if (cur_cfg->iir.coeff_set0[index] != | ||
276 | user_cfg->iir.coeff_set0[index]) { | ||
277 | update = 1; | ||
278 | goto out; | ||
279 | } | ||
280 | if (cur_cfg->iir.coeff_set1[index] != | ||
281 | user_cfg->iir.coeff_set1[index]) { | ||
282 | update = 1; | ||
283 | goto out; | ||
284 | } | ||
285 | } | ||
286 | |||
287 | /* paxel */ | ||
288 | if ((cur_cfg->paxel.width != user_cfg->paxel.width) || | ||
289 | (cur_cfg->paxel.height != user_cfg->paxel.height) || | ||
290 | (cur_cfg->paxel.h_start != user_cfg->paxel.h_start) || | ||
291 | (cur_cfg->paxel.v_start != user_cfg->paxel.v_start) || | ||
292 | (cur_cfg->paxel.h_cnt != user_cfg->paxel.h_cnt) || | ||
293 | (cur_cfg->paxel.v_cnt != user_cfg->paxel.v_cnt) || | ||
294 | (cur_cfg->paxel.line_inc != user_cfg->paxel.line_inc)) { | ||
295 | update = 1; | ||
296 | goto out; | ||
297 | } | ||
298 | |||
299 | /* af_mode */ | ||
300 | if (cur_cfg->fvmode != user_cfg->fvmode) | ||
301 | update = 1; | ||
302 | |||
303 | out: | ||
304 | if (update || !af->configured) { | ||
305 | memcpy(cur_cfg, user_cfg, sizeof(*cur_cfg)); | ||
306 | af->inc_config++; | ||
307 | af->update = 1; | ||
308 | /* | ||
309 | * User might be asked for a bigger buffer than necessary for | ||
310 | * this configuration. In order to return the right amount of | ||
311 | * data during buffer request, let's calculate the size here | ||
312 | * instead of stick with user_cfg->buf_size. | ||
313 | */ | ||
314 | cur_cfg->buf_size = h3a_af_get_buf_size(cur_cfg); | ||
315 | } | ||
316 | } | ||
317 | |||
318 | static long h3a_af_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) | ||
319 | { | ||
320 | struct ispstat *stat = v4l2_get_subdevdata(sd); | ||
321 | |||
322 | switch (cmd) { | ||
323 | case VIDIOC_OMAP3ISP_AF_CFG: | ||
324 | return omap3isp_stat_config(stat, arg); | ||
325 | case VIDIOC_OMAP3ISP_STAT_REQ: | ||
326 | return omap3isp_stat_request_statistics(stat, arg); | ||
327 | case VIDIOC_OMAP3ISP_STAT_EN: { | ||
328 | int *en = arg; | ||
329 | return omap3isp_stat_enable(stat, !!*en); | ||
330 | } | ||
331 | } | ||
332 | |||
333 | return -ENOIOCTLCMD; | ||
334 | |||
335 | } | ||
336 | |||
337 | static const struct ispstat_ops h3a_af_ops = { | ||
338 | .validate_params = h3a_af_validate_params, | ||
339 | .set_params = h3a_af_set_params, | ||
340 | .setup_regs = h3a_af_setup_regs, | ||
341 | .enable = h3a_af_enable, | ||
342 | .busy = h3a_af_busy, | ||
343 | }; | ||
344 | |||
345 | static const struct v4l2_subdev_core_ops h3a_af_subdev_core_ops = { | ||
346 | .ioctl = h3a_af_ioctl, | ||
347 | .subscribe_event = omap3isp_stat_subscribe_event, | ||
348 | .unsubscribe_event = omap3isp_stat_unsubscribe_event, | ||
349 | }; | ||
350 | |||
351 | static const struct v4l2_subdev_video_ops h3a_af_subdev_video_ops = { | ||
352 | .s_stream = omap3isp_stat_s_stream, | ||
353 | }; | ||
354 | |||
355 | static const struct v4l2_subdev_ops h3a_af_subdev_ops = { | ||
356 | .core = &h3a_af_subdev_core_ops, | ||
357 | .video = &h3a_af_subdev_video_ops, | ||
358 | }; | ||
359 | |||
360 | /* Function to register the AF character device driver. */ | ||
361 | int omap3isp_h3a_af_init(struct isp_device *isp) | ||
362 | { | ||
363 | struct ispstat *af = &isp->isp_af; | ||
364 | struct omap3isp_h3a_af_config *af_cfg; | ||
365 | struct omap3isp_h3a_af_config *af_recover_cfg; | ||
366 | int ret; | ||
367 | |||
368 | af_cfg = kzalloc(sizeof(*af_cfg), GFP_KERNEL); | ||
369 | if (af_cfg == NULL) | ||
370 | return -ENOMEM; | ||
371 | |||
372 | memset(af, 0, sizeof(*af)); | ||
373 | af->ops = &h3a_af_ops; | ||
374 | af->priv = af_cfg; | ||
375 | af->dma_ch = -1; | ||
376 | af->event_type = V4L2_EVENT_OMAP3ISP_AF; | ||
377 | af->isp = isp; | ||
378 | |||
379 | /* Set recover state configuration */ | ||
380 | af_recover_cfg = kzalloc(sizeof(*af_recover_cfg), GFP_KERNEL); | ||
381 | if (!af_recover_cfg) { | ||
382 | dev_err(af->isp->dev, "AF: cannot allocate memory for recover " | ||
383 | "configuration.\n"); | ||
384 | ret = -ENOMEM; | ||
385 | goto err_recover_alloc; | ||
386 | } | ||
387 | |||
388 | af_recover_cfg->paxel.h_start = OMAP3ISP_AF_PAXEL_HZSTART_MIN; | ||
389 | af_recover_cfg->paxel.width = OMAP3ISP_AF_PAXEL_WIDTH_MIN; | ||
390 | af_recover_cfg->paxel.height = OMAP3ISP_AF_PAXEL_HEIGHT_MIN; | ||
391 | af_recover_cfg->paxel.h_cnt = OMAP3ISP_AF_PAXEL_HORIZONTAL_COUNT_MIN; | ||
392 | af_recover_cfg->paxel.v_cnt = OMAP3ISP_AF_PAXEL_VERTICAL_COUNT_MIN; | ||
393 | af_recover_cfg->paxel.line_inc = OMAP3ISP_AF_PAXEL_INCREMENT_MIN; | ||
394 | if (h3a_af_validate_params(af, af_recover_cfg)) { | ||
395 | dev_err(af->isp->dev, "AF: recover configuration is " | ||
396 | "invalid.\n"); | ||
397 | ret = -EINVAL; | ||
398 | goto err_conf; | ||
399 | } | ||
400 | |||
401 | af_recover_cfg->buf_size = h3a_af_get_buf_size(af_recover_cfg); | ||
402 | af->recover_priv = af_recover_cfg; | ||
403 | |||
404 | ret = omap3isp_stat_init(af, "AF", &h3a_af_subdev_ops); | ||
405 | if (ret) | ||
406 | goto err_conf; | ||
407 | |||
408 | return 0; | ||
409 | |||
410 | err_conf: | ||
411 | kfree(af_recover_cfg); | ||
412 | err_recover_alloc: | ||
413 | kfree(af_cfg); | ||
414 | |||
415 | return ret; | ||
416 | } | ||
417 | |||
418 | void omap3isp_h3a_af_cleanup(struct isp_device *isp) | ||
419 | { | ||
420 | kfree(isp->isp_af.priv); | ||
421 | kfree(isp->isp_af.recover_priv); | ||
422 | omap3isp_stat_cleanup(&isp->isp_af); | ||
423 | } | ||