4 * HISTOGRAM module for TI's OMAP3 Camera ISP
6 * Copyright (C) 2009 Texas Instruments, Inc.
9 * Sergio Aguirre <saaguirre@ti.com>
12 * This package is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
16 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21 #include <asm/cacheflush.h>
23 #include <linux/delay.h>
24 #include <linux/dma-mapping.h>
25 #include <linux/uaccess.h>
31 /* Structure for saving/restoring histogram module registers */
32 struct isp_reg isphist_reg_list
[] = {
33 {OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
, 0},
34 {OMAP3_ISP_IOMEM_HIST
, ISPHIST_WB_GAIN
, 0},
35 {OMAP3_ISP_IOMEM_HIST
, ISPHIST_R0_HORZ
, 0},
36 {OMAP3_ISP_IOMEM_HIST
, ISPHIST_R0_VERT
, 0},
37 {OMAP3_ISP_IOMEM_HIST
, ISPHIST_R1_HORZ
, 0},
38 {OMAP3_ISP_IOMEM_HIST
, ISPHIST_R1_VERT
, 0},
39 {OMAP3_ISP_IOMEM_HIST
, ISPHIST_R2_HORZ
, 0},
40 {OMAP3_ISP_IOMEM_HIST
, ISPHIST_R2_VERT
, 0},
41 {OMAP3_ISP_IOMEM_HIST
, ISPHIST_R3_HORZ
, 0},
42 {OMAP3_ISP_IOMEM_HIST
, ISPHIST_R3_VERT
, 0},
43 {OMAP3_ISP_IOMEM_HIST
, ISPHIST_ADDR
, 0},
44 {OMAP3_ISP_IOMEM_HIST
, ISPHIST_RADD
, 0},
45 {OMAP3_ISP_IOMEM_HIST
, ISPHIST_RADD_OFF
, 0},
46 {OMAP3_ISP_IOMEM_HIST
, ISPHIST_H_V_INFO
, 0},
50 static void isp_hist_print_status(struct isp_hist_device
*isp_hist
);
52 void __isp_hist_enable(struct isp_hist_device
*isp_hist
, u8 enable
)
55 DPRINTK_ISPHIST(" histogram enabled \n");
57 DPRINTK_ISPHIST(" histogram disabled \n");
59 isp_reg_and_or(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_PCR
,
60 ~ISPHIST_PCR_EN
, (enable
? ISPHIST_PCR_EN
: 0));
61 isp_hist
->hist_enable
= enable
;
65 * isp_hist_enable - Enables ISP Histogram submodule operation.
66 * @enable: 1 - Enables the histogram submodule.
68 * Client should configure all the Histogram registers before calling this
71 void isp_hist_enable(struct isp_hist_device
*isp_hist
, u8 enable
)
73 __isp_hist_enable(isp_hist
, enable
);
74 isp_hist
->pm_state
= enable
;
78 * isp_hist_suspend - Suspend ISP Histogram submodule.
80 void isp_hist_suspend(struct isp_hist_device
*isp_hist
)
82 if (isp_hist
->pm_state
)
83 __isp_hist_enable(isp_hist
, 0);
87 * isp_hist_resume - Resume ISP Histogram submodule.
89 void isp_hist_resume(struct isp_hist_device
*isp_hist
)
91 if (isp_hist
->pm_state
)
92 __isp_hist_enable(isp_hist
, 1);
95 int isp_hist_busy(struct isp_hist_device
*isp_hist
)
97 return isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_PCR
)
103 * isp_hist_update_regs - Helper function to update Histogram registers.
105 static void isp_hist_update_regs(struct isp_hist_device
*isp_hist
)
107 isp_reg_writel(isp_hist
->dev
, isp_hist
->regs
.pcr
, OMAP3_ISP_IOMEM_HIST
,
109 isp_reg_writel(isp_hist
->dev
, isp_hist
->regs
.cnt
, OMAP3_ISP_IOMEM_HIST
,
111 isp_reg_writel(isp_hist
->dev
, isp_hist
->regs
.wb_gain
,
112 OMAP3_ISP_IOMEM_HIST
, ISPHIST_WB_GAIN
);
113 isp_reg_writel(isp_hist
->dev
, isp_hist
->regs
.r0_h
, OMAP3_ISP_IOMEM_HIST
,
115 isp_reg_writel(isp_hist
->dev
, isp_hist
->regs
.r0_v
, OMAP3_ISP_IOMEM_HIST
,
117 isp_reg_writel(isp_hist
->dev
, isp_hist
->regs
.r1_h
, OMAP3_ISP_IOMEM_HIST
,
119 isp_reg_writel(isp_hist
->dev
, isp_hist
->regs
.r1_v
, OMAP3_ISP_IOMEM_HIST
,
121 isp_reg_writel(isp_hist
->dev
, isp_hist
->regs
.r2_h
, OMAP3_ISP_IOMEM_HIST
,
123 isp_reg_writel(isp_hist
->dev
, isp_hist
->regs
.r2_v
, OMAP3_ISP_IOMEM_HIST
,
125 isp_reg_writel(isp_hist
->dev
, isp_hist
->regs
.r3_h
, OMAP3_ISP_IOMEM_HIST
,
127 isp_reg_writel(isp_hist
->dev
, isp_hist
->regs
.r3_v
, OMAP3_ISP_IOMEM_HIST
,
129 isp_reg_writel(isp_hist
->dev
, isp_hist
->regs
.hist_addr
,
130 OMAP3_ISP_IOMEM_HIST
, ISPHIST_ADDR
);
131 isp_reg_writel(isp_hist
->dev
, isp_hist
->regs
.hist_data
,
132 OMAP3_ISP_IOMEM_HIST
, ISPHIST_DATA
);
133 isp_reg_writel(isp_hist
->dev
, isp_hist
->regs
.hist_radd
,
134 OMAP3_ISP_IOMEM_HIST
, ISPHIST_RADD
);
135 isp_reg_writel(isp_hist
->dev
, isp_hist
->regs
.hist_radd_off
,
136 OMAP3_ISP_IOMEM_HIST
, ISPHIST_RADD_OFF
);
137 isp_reg_writel(isp_hist
->dev
, isp_hist
->regs
.h_v_info
,
138 OMAP3_ISP_IOMEM_HIST
, ISPHIST_H_V_INFO
);
142 * isp_hist_isr - Callback from ISP driver for HIST interrupt.
143 * @status: IRQ0STATUS in case of MMU error, 0 for hist interrupt.
144 * arg1 and arg2 Not used as of now.
146 static void isp_hist_isr(unsigned long status
, isp_vbq_callback_ptr arg1
,
149 struct isp_hist_device
*isp_hist
= arg2
;
151 isp_hist_enable(isp_hist
, 0);
153 if (!(status
& HIST_DONE
))
156 if (!isp_hist
->completed
) {
157 if (isp_hist
->frame_req
== isp_hist
->frame_cnt
) {
158 isp_hist
->frame_cnt
= 0;
159 isp_hist
->frame_req
= 0;
160 isp_hist
->completed
= 1;
162 isp_hist_enable(isp_hist
, 1);
163 isp_hist
->frame_cnt
++;
169 * isp_hist_reset_mem - clear Histogram memory before start stats engine.
171 * Returns 0 after histogram memory was cleared.
173 static int isp_hist_reset_mem(struct isp_hist_device
*isp_hist
)
177 isp_reg_or(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
,
180 for (i
= 0; i
< HIST_MEM_SIZE
; i
++)
181 isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,
184 isp_reg_and(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
,
185 ~ISPHIST_CNT_CLR_EN
);
191 * isp_hist_set_params - Helper function to check and store user given params.
192 * @user_cfg: Pointer to user configuration structure.
194 * Returns 0 on success configuration.
196 static int isp_hist_set_params(struct isp_hist_device
*isp_hist
,
197 struct isp_hist_config
*user_cfg
)
204 if (isp_hist_busy(isp_hist
))
207 if (user_cfg
->input_bit_width
> MIN_BIT_WIDTH
)
208 WRITE_DATA_SIZE(isp_hist
->regs
.cnt
, 0);
210 WRITE_DATA_SIZE(isp_hist
->regs
.cnt
, 1);
212 WRITE_SOURCE(isp_hist
->regs
.cnt
, user_cfg
->hist_source
);
214 if (user_cfg
->hist_source
) {
215 WRITE_HV_INFO(isp_hist
->regs
.h_v_info
, user_cfg
->hist_h_v_info
);
217 if ((user_cfg
->hist_radd
& ISP_32B_BOUNDARY_BUF
) ==
218 user_cfg
->hist_radd
) {
219 WRITE_RADD(isp_hist
->regs
.hist_radd
,
220 user_cfg
->hist_radd
);
222 dev_err(isp_hist
->dev
,
223 "hist: Address should be in 32 byte boundary"
228 if ((user_cfg
->hist_radd_off
& ISP_32B_BOUNDARY_OFFSET
) ==
229 user_cfg
->hist_radd_off
) {
230 WRITE_RADD_OFF(isp_hist
->regs
.hist_radd_off
,
231 user_cfg
->hist_radd_off
);
233 dev_err(isp_hist
->dev
,
234 "hist: Offset should be in 32 byte boundary\n");
240 isp_hist_reset_mem(isp_hist
);
241 DPRINTK_ISPHIST("ISPHIST: Memory Cleared\n");
242 isp_hist
->frame_req
= user_cfg
->hist_frames
;
244 if (unlikely(user_cfg
->wb_gain_R
> MAX_WB_GAIN
||
245 user_cfg
->wb_gain_RG
> MAX_WB_GAIN
||
246 user_cfg
->wb_gain_B
> MAX_WB_GAIN
||
247 user_cfg
->wb_gain_BG
> MAX_WB_GAIN
)) {
248 dev_err(isp_hist
->dev
, "hist: Invalid WB gain\n");
251 WRITE_WB_R(isp_hist
->regs
.wb_gain
, user_cfg
->wb_gain_R
);
252 WRITE_WB_RG(isp_hist
->regs
.wb_gain
, user_cfg
->wb_gain_RG
);
253 WRITE_WB_B(isp_hist
->regs
.wb_gain
, user_cfg
->wb_gain_B
);
254 WRITE_WB_BG(isp_hist
->regs
.wb_gain
, user_cfg
->wb_gain_BG
);
257 /* Regions size and position */
259 if (user_cfg
->num_regions
> MAX_REGIONS
)
262 if (likely((user_cfg
->reg0_hor
& ISPHIST_REGHORIZ_HEND_MASK
) -
263 ((user_cfg
->reg0_hor
& ISPHIST_REGHORIZ_HSTART_MASK
) >>
264 ISPHIST_REGHORIZ_HSTART_SHIFT
))) {
265 WRITE_REG_HORIZ(isp_hist
->regs
.r0_h
, user_cfg
->reg0_hor
);
268 dev_err(isp_hist
->dev
, "hist: Invalid Region parameters\n");
272 if (likely((user_cfg
->reg0_ver
& ISPHIST_REGVERT_VEND_MASK
) -
273 ((user_cfg
->reg0_ver
& ISPHIST_REGVERT_VSTART_MASK
) >>
274 ISPHIST_REGVERT_VSTART_SHIFT
))) {
275 WRITE_REG_VERT(isp_hist
->regs
.r0_v
, user_cfg
->reg0_ver
);
277 dev_err(isp_hist
->dev
, "hist: Invalid Region parameters\n");
281 if (user_cfg
->num_regions
>= 1) {
282 if (likely((user_cfg
->reg1_hor
& ISPHIST_REGHORIZ_HEND_MASK
) -
283 ((user_cfg
->reg1_hor
&
284 ISPHIST_REGHORIZ_HSTART_MASK
) >>
285 ISPHIST_REGHORIZ_HSTART_SHIFT
))) {
286 WRITE_REG_HORIZ(isp_hist
->regs
.r1_h
,
289 dev_err(isp_hist
->dev
,
290 "hist: Invalid Region parameters\n");
294 if (likely((user_cfg
->reg1_ver
& ISPHIST_REGVERT_VEND_MASK
) -
295 ((user_cfg
->reg1_ver
&
296 ISPHIST_REGVERT_VSTART_MASK
) >>
297 ISPHIST_REGVERT_VSTART_SHIFT
))) {
298 WRITE_REG_VERT(isp_hist
->regs
.r1_v
,
301 dev_err(isp_hist
->dev
,
302 "hist: Invalid Region parameters\n");
307 if (user_cfg
->num_regions
>= 2) {
308 if (likely((user_cfg
->reg2_hor
& ISPHIST_REGHORIZ_HEND_MASK
) -
309 ((user_cfg
->reg2_hor
&
310 ISPHIST_REGHORIZ_HSTART_MASK
) >>
311 ISPHIST_REGHORIZ_HSTART_SHIFT
))) {
312 WRITE_REG_HORIZ(isp_hist
->regs
.r2_h
,
315 dev_err(isp_hist
->dev
,
316 "hist: Invalid Region parameters\n");
320 if (likely((user_cfg
->reg2_ver
& ISPHIST_REGVERT_VEND_MASK
) -
321 ((user_cfg
->reg2_ver
&
322 ISPHIST_REGVERT_VSTART_MASK
) >>
323 ISPHIST_REGVERT_VSTART_SHIFT
))) {
324 WRITE_REG_VERT(isp_hist
->regs
.r2_v
,
327 dev_err(isp_hist
->dev
,
328 "hist: Invalid Region parameters\n");
333 if (user_cfg
->num_regions
>= 3) {
334 if (likely((user_cfg
->reg3_hor
& ISPHIST_REGHORIZ_HEND_MASK
) -
335 ((user_cfg
->reg3_hor
&
336 ISPHIST_REGHORIZ_HSTART_MASK
) >>
337 ISPHIST_REGHORIZ_HSTART_SHIFT
))) {
338 WRITE_REG_HORIZ(isp_hist
->regs
.r3_h
,
341 dev_err(isp_hist
->dev
,
342 "hist: Invalid Region parameters\n");
346 if (likely((user_cfg
->reg3_ver
& ISPHIST_REGVERT_VEND_MASK
) -
347 ((user_cfg
->reg3_ver
&
348 ISPHIST_REGVERT_VSTART_MASK
) >>
349 ISPHIST_REGVERT_VSTART_SHIFT
))) {
350 WRITE_REG_VERT(isp_hist
->regs
.r3_v
,
353 dev_err(isp_hist
->dev
,
354 "hist: Invalid Region parameters\n");
358 reg_num
= user_cfg
->num_regions
;
359 if (unlikely(((user_cfg
->hist_bins
> BINS_256
) &&
360 (user_cfg
->hist_bins
!= BINS_32
)) ||
361 ((user_cfg
->hist_bins
== BINS_256
) &&
362 reg_num
!= 0) || ((user_cfg
->hist_bins
==
363 BINS_128
) && reg_num
>= 2))) {
364 dev_err(isp_hist
->dev
, "hist: Invalid Bins Number: %d\n",
365 user_cfg
->hist_bins
);
368 WRITE_NUM_BINS(isp_hist
->regs
.cnt
, user_cfg
->hist_bins
);
371 if (user_cfg
->input_bit_width
> MAX_BIT_WIDTH
||
372 user_cfg
->input_bit_width
< MIN_BIT_WIDTH
) {
373 dev_err(isp_hist
->dev
, "hist: Invalid Bit Width: %d\n",
374 user_cfg
->input_bit_width
);
377 switch (user_cfg
->hist_bins
) {
379 bit_shift
= user_cfg
->input_bit_width
- 8;
382 bit_shift
= user_cfg
->input_bit_width
- 7;
385 bit_shift
= user_cfg
->input_bit_width
- 6;
388 bit_shift
= user_cfg
->input_bit_width
- 5;
393 WRITE_BIT_SHIFT(isp_hist
->regs
.cnt
, bit_shift
);
396 isp_hist_update_regs(isp_hist
);
397 isp_hist
->initialized
= 1;
403 * isp_hist_configure - API to configure HIST registers.
404 * @histcfg: Pointer to user configuration structure.
406 * Returns 0 on success configuration.
408 int isp_hist_configure(struct isp_hist_device
*isp_hist
,
409 struct isp_hist_config
*histcfg
)
414 if (NULL
== histcfg
) {
415 dev_err(isp_hist
->dev
,
416 "hist: Null argument in configuration. \n");
420 if (!isp_hist
->initialized
) {
421 DPRINTK_ISPHIST("Setting callback for HISTOGRAM\n");
422 ret
= isp_set_callback(isp_hist
->dev
, CBK_HIST_DONE
,
423 isp_hist_isr
, (void *)NULL
,
426 dev_err(isp_hist
->dev
, "hist: No callback for HIST\n");
431 ret
= isp_hist_set_params(isp_hist
, histcfg
);
433 dev_err(isp_hist
->dev
, "hist: Invalid parameters! \n");
437 isp_hist
->frame_cnt
= 0;
438 isp_hist
->completed
= 0;
439 isp_hist_enable(isp_hist
, 1);
440 isp_hist_print_status(isp_hist
);
444 EXPORT_SYMBOL(isp_hist_configure
);
447 * isp_hist_request_statistics - Request statistics in Histogram.
448 * @histdata: Pointer to data structure.
450 * This API allows the user to request for histogram statistics.
452 * Returns 0 on successful request.
454 int isp_hist_request_statistics(struct isp_hist_device
*isp_hist
,
455 struct isp_hist_data
*histdata
)
460 if (isp_hist_busy(isp_hist
))
463 if (!isp_hist
->completed
&& isp_hist
->initialized
)
466 isp_reg_or(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
,
469 for (i
= 0; i
< HIST_MEM_SIZE
; i
++) {
470 curr
= isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,
472 ret
= put_user(curr
, histdata
->hist_statistics_buf
+ i
);
474 dev_err(isp_hist
->dev
, "hist: Failed copy_to_user for "
475 "HIST stats buff, %d\n", ret
);
479 isp_reg_and(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
, ISPHIST_CNT
,
480 ~ISPHIST_CNT_CLR_EN
);
481 isp_hist
->completed
= 0;
484 EXPORT_SYMBOL(isp_hist_request_statistics
);
487 * isp_hist_init - Module Initialization.
489 * Returns 0 if successful.
491 int __init
isp_hist_init(struct device
*dev
)
493 struct isp_device
*isp
= dev_get_drvdata(dev
);
495 isp
->isp_hist
.dev
= dev
;
501 * isp_hist_cleanup - Module cleanup.
503 void isp_hist_cleanup(struct device
*dev
)
508 * isphist_save_context - Saves the values of the histogram module registers.
510 void isphist_save_context(struct device
*dev
)
512 DPRINTK_ISPHIST(" Saving context\n");
513 isp_save_context(dev
, isphist_reg_list
);
515 EXPORT_SYMBOL(isphist_save_context
);
518 * isphist_restore_context - Restores the values of the histogram module regs.
520 void isphist_restore_context(struct device
*dev
)
522 DPRINTK_ISPHIST(" Restoring context\n");
523 isp_restore_context(dev
, isphist_reg_list
);
525 EXPORT_SYMBOL(isphist_restore_context
);
528 * isp_hist_print_status - Debug print
530 static void isp_hist_print_status(struct isp_hist_device
*isp_hist
)
532 DPRINTK_ISPHIST("ISPHIST_PCR = 0x%08x\n",
533 isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,
535 DPRINTK_ISPHIST("ISPHIST_CNT = 0x%08x\n",
536 isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,
538 DPRINTK_ISPHIST("ISPHIST_WB_GAIN = 0x%08x\n",
539 isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,
541 DPRINTK_ISPHIST("ISPHIST_R0_HORZ = 0x%08x\n",
542 isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,
544 DPRINTK_ISPHIST("ISPHIST_R0_VERT = 0x%08x\n",
545 isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,
547 DPRINTK_ISPHIST("ISPHIST_R1_HORZ = 0x%08x\n",
548 isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,
550 DPRINTK_ISPHIST("ISPHIST_R1_VERT = 0x%08x\n",
551 isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,
553 DPRINTK_ISPHIST("ISPHIST_R2_HORZ = 0x%08x\n",
554 isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,
556 DPRINTK_ISPHIST("ISPHIST_R2_VERT = 0x%08x\n",
557 isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,
559 DPRINTK_ISPHIST("ISPHIST_R3_HORZ = 0x%08x\n",
560 isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,
562 DPRINTK_ISPHIST("ISPHIST_R3_VERT = 0x%08x\n",
563 isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,
565 DPRINTK_ISPHIST("ISPHIST_ADDR = 0x%08x\n",
566 isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,
568 DPRINTK_ISPHIST("ISPHIST_RADD = 0x%08x\n",
569 isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,
571 DPRINTK_ISPHIST("ISPHIST_RADD_OFF = 0x%08x\n",
572 isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,
574 DPRINTK_ISPHIST("ISPHIST_H_V_INFO = 0x%08x\n",
575 isp_reg_readl(isp_hist
->dev
, OMAP3_ISP_IOMEM_HIST
,