Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
isph3a_af.c
Go to the documentation of this file.
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 <[email protected]>
10  * Laurent Pinchart <[email protected]>
11  * Sakari Ailus <[email protected]>
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,
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,
82 
83  /*SetIIRSH Register */
84  isp_reg_writel(af->isp, conf->iir.h_start,
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] <<
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] <<
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],
111  /* set AFCOEF1010 Register */
112  isp_reg_writel(af->isp, conf->iir.coeff_set1[10],
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,
147  } else {
148  isp_reg_clr(af->isp, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
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)
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,
178  return -EINVAL;
179 
180  /* Check Vertical Count */
181  if (IS_OUT_OF_BOUNDS(paxel_cfg->v_cnt,
184  return -EINVAL;
185 
188  paxel_cfg->height % 2)
189  return -EINVAL;
190 
191  /* Check width */
194  paxel_cfg->width % 2)
195  return -EINVAL;
196 
197  /* Check Line Increment */
198  if (IS_OUT_OF_BOUNDS(paxel_cfg->line_inc,
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,
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 
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)
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) {
324  return omap3isp_stat_config(stat, arg);
326  return omap3isp_stat_request_statistics(stat, arg);
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. */
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;
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 
419 {
420  kfree(isp->isp_af.priv);
421  kfree(isp->isp_af.recover_priv);
423 }