1 From 9a39eab5ed1b70711c3b10de95cd90749293ef7a Mon Sep 17 00:00:00 2001
2 From: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
3 Date: Tue, 10 Mar 2009 10:49:02 +0200
4 Subject: [PATCH] omap3isp: Add statistics collection modules (H3A and HIST)
6 Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com>
8 drivers/media/video/isp/isp_af.c | 784 +++++++++++++++++++++++++++++++
9 drivers/media/video/isp/isp_af.h | 125 +++++
10 drivers/media/video/isp/isph3a.c | 932 +++++++++++++++++++++++++++++++++++++
11 drivers/media/video/isp/isph3a.h | 127 +++++
12 drivers/media/video/isp/isphist.c | 608 ++++++++++++++++++++++++
13 drivers/media/video/isp/isphist.h | 105 +++++
14 6 files changed, 2681 insertions(+), 0 deletions(-)
15 create mode 100644 drivers/media/video/isp/isp_af.c
16 create mode 100644 drivers/media/video/isp/isp_af.h
17 create mode 100644 drivers/media/video/isp/isph3a.c
18 create mode 100644 drivers/media/video/isp/isph3a.h
19 create mode 100644 drivers/media/video/isp/isphist.c
20 create mode 100644 drivers/media/video/isp/isphist.h
22 diff --git a/drivers/media/video/isp/isp_af.c b/drivers/media/video/isp/isp_af.c
24 index 0000000..a607b97
26 +++ b/drivers/media/video/isp/isp_af.c
31 + * AF module for TI's OMAP3 Camera ISP
33 + * Copyright (C) 2009 Texas Instruments, Inc.
36 + * Sergio Aguirre <saaguirre@ti.com>
39 + * This package is free software; you can redistribute it and/or modify
40 + * it under the terms of the GNU General Public License version 2 as
41 + * published by the Free Software Foundation.
43 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
44 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
45 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
48 +/* Linux specific include files */
49 +#include <asm/cacheflush.h>
51 +#include <linux/uaccess.h>
52 +#include <linux/dma-mapping.h>
53 +#include <asm/atomic.h>
62 + * struct isp_af_buffer - AF frame stats buffer.
63 + * @virt_addr: Virtual address to mmap the buffer.
64 + * @phy_addr: Physical address of the buffer.
65 + * @addr_align: Virtual Address 32 bytes aligned.
66 + * @ispmmu_addr: Address of the buffer mapped by the ISPMMU.
67 + * @mmap_addr: Mapped memory area of buffer. For userspace access.
68 + * @locked: 1 - Buffer locked from write. 0 - Buffer can be overwritten.
69 + * @frame_num: Frame number from which the statistics are taken.
70 + * @lens_position: Lens position currently set in the DW9710 Coil motor driver.
71 + * @next: Pointer to link next buffer.
73 +struct isp_af_buffer {
74 + unsigned long virt_addr;
75 + unsigned long phy_addr;
76 + unsigned long addr_align;
77 + unsigned long ispmmu_addr;
78 + unsigned long mmap_addr;
83 + struct isp_af_xtrastats xtrastats;
84 + struct isp_af_buffer *next;
88 + * struct isp_af_status - AF status.
89 + * @initialized: 1 - Buffers initialized.
90 + * @update: 1 - Update registers.
91 + * @stats_req: 1 - Future stats requested.
92 + * @stats_done: 1 - Stats ready for user.
93 + * @frame_req: Number of frame requested for statistics.
94 + * @af_buff: Array of statistics buffers to access.
95 + * @stats_buf_size: Statistics buffer size.
96 + * @curr_cfg_buf_size: Current user configured stats buff size.
97 + * @min_buf_size: Minimum statisitics buffer size.
98 + * @frame_count: Frame Count.
99 + * @stats_wait: Wait primitive for locking/unlocking the stats request.
100 + * @buffer_lock: Spinlock for statistics buffers access.
102 +static struct isp_af_status {
109 + struct isp_af_buffer af_buff[H3A_MAX_BUFF];
110 + unsigned int stats_buf_size;
111 + unsigned int min_buf_size;
112 + unsigned int curr_cfg_buf_size;
116 + wait_queue_head_t stats_wait;
117 + atomic_t config_counter;
118 + spinlock_t buffer_lock; /* For stats buffers read/write sync */
121 +struct af_device *af_dev_configptr;
122 +static struct isp_af_buffer *active_buff;
123 +static int af_major = -1;
124 +static int camnotify;
127 + * isp_af_setxtrastats - Receives extra statistics from prior frames.
128 + * @xtrastats: Pointer to structure containing extra statistics fields like
129 + * field count and timestamp of frame.
131 + * Called from update_vbq in camera driver
133 +void isp_af_setxtrastats(struct isp_af_xtrastats *xtrastats, u8 updateflag)
137 + if (active_buff == NULL)
140 + for (i = 0; i < H3A_MAX_BUFF; i++) {
141 + if (afstat.af_buff[i].frame_num == active_buff->frame_num)
145 + if (i == H3A_MAX_BUFF)
149 + if (afstat.af_buff[H3A_MAX_BUFF - 1].locked == 0)
150 + past_i = H3A_MAX_BUFF - 1;
152 + past_i = H3A_MAX_BUFF - 2;
153 + } else if (i == 1) {
154 + if (afstat.af_buff[0].locked == 0)
157 + past_i = H3A_MAX_BUFF - 1;
159 + if (afstat.af_buff[i - 1].locked == 0)
165 + if (updateflag & AF_UPDATEXS_TS)
166 + afstat.af_buff[past_i].xtrastats.ts = xtrastats->ts;
168 + if (updateflag & AF_UPDATEXS_FIELDCOUNT)
169 + afstat.af_buff[past_i].xtrastats.field_count =
170 + xtrastats->field_count;
172 +EXPORT_SYMBOL(isp_af_setxtrastats);
175 + * Helper function to update buffer cache pages
177 +static void isp_af_update_req_buffer(struct isp_af_buffer *buffer)
179 + int size = afstat.stats_buf_size;
181 + size = PAGE_ALIGN(size);
182 + /* Update the kernel pages of the requested buffer */
183 + dmac_inv_range((void *)buffer->addr_align, (void *)buffer->addr_align +
187 +#define IS_OUT_OF_BOUNDS(value, min, max) \
188 + (((value) < (min)) || ((value) > (max)))
190 +/* Function to check paxel parameters */
191 +int isp_af_check_paxel(void)
193 + struct af_paxel *paxel_cfg = &af_dev_configptr->config->paxel_config;
194 + struct af_iir *iir_cfg = &af_dev_configptr->config->iir_config;
196 + /* Check horizontal Count */
197 + if (IS_OUT_OF_BOUNDS(paxel_cfg->hz_cnt, AF_PAXEL_HORIZONTAL_COUNT_MIN,
198 + AF_PAXEL_HORIZONTAL_COUNT_MAX)) {
199 + DPRINTK_ISP_AF("Error : Horizontal Count is incorrect");
200 + return -AF_ERR_HZ_COUNT;
203 + /*Check Vertical Count */
204 + if (IS_OUT_OF_BOUNDS(paxel_cfg->vt_cnt, AF_PAXEL_VERTICAL_COUNT_MIN,
205 + AF_PAXEL_VERTICAL_COUNT_MAX)) {
206 + DPRINTK_ISP_AF("Error : Vertical Count is incorrect");
207 + return -AF_ERR_VT_COUNT;
211 + if (IS_OUT_OF_BOUNDS(paxel_cfg->height, AF_PAXEL_HEIGHT_MIN,
212 + AF_PAXEL_HEIGHT_MAX)) {
213 + DPRINTK_ISP_AF("Error : Height is incorrect");
214 + return -AF_ERR_HEIGHT;
218 + if (IS_OUT_OF_BOUNDS(paxel_cfg->width, AF_PAXEL_WIDTH_MIN,
219 + AF_PAXEL_WIDTH_MAX)) {
220 + DPRINTK_ISP_AF("Error : Width is incorrect");
221 + return -AF_ERR_WIDTH;
224 + /*Check Line Increment */
225 + if (IS_OUT_OF_BOUNDS(paxel_cfg->line_incr, AF_PAXEL_INCREMENT_MIN,
226 + AF_PAXEL_INCREMENT_MAX)) {
227 + DPRINTK_ISP_AF("Error : Line Increment is incorrect");
228 + return -AF_ERR_INCR;
231 + /*Check Horizontal Start */
232 + if ((paxel_cfg->hz_start % 2 != 0) ||
233 + (paxel_cfg->hz_start < (iir_cfg->hz_start_pos + 2)) ||
234 + IS_OUT_OF_BOUNDS(paxel_cfg->hz_start,
235 + AF_PAXEL_HZSTART_MIN, AF_PAXEL_HZSTART_MAX)) {
236 + DPRINTK_ISP_AF("Error : Horizontal Start is incorrect");
237 + return -AF_ERR_HZ_START;
240 + /*Check Vertical Start */
241 + if (IS_OUT_OF_BOUNDS(paxel_cfg->vt_start, AF_PAXEL_VTSTART_MIN,
242 + AF_PAXEL_VTSTART_MAX)) {
243 + DPRINTK_ISP_AF("Error : Vertical Start is incorrect");
244 + return -AF_ERR_VT_START;
250 + * isp_af_check_iir - Function to check IIR Coefficient.
252 +int isp_af_check_iir(void)
254 + struct af_iir *iir_cfg = &af_dev_configptr->config->iir_config;
257 + for (index = 0; index < AF_NUMBER_OF_COEF; index++) {
258 + if ((iir_cfg->coeff_set0[index]) > AF_COEF_MAX) {
259 + DPRINTK_ISP_AF("Error : Coefficient for set 0 is "
261 + return -AF_ERR_IIR_COEF;
264 + if ((iir_cfg->coeff_set1[index]) > AF_COEF_MAX) {
265 + DPRINTK_ISP_AF("Error : Coefficient for set 1 is "
267 + return -AF_ERR_IIR_COEF;
271 + if (IS_OUT_OF_BOUNDS(iir_cfg->hz_start_pos, AF_IIRSH_MIN,
273 + DPRINTK_ISP_AF("Error : IIRSH is incorrect");
274 + return -AF_ERR_IIRSH;
280 + * isp_af_unlock_buffers - Helper function to unlock all buffers.
282 +static void isp_af_unlock_buffers(void)
285 + unsigned long irqflags;
287 + spin_lock_irqsave(&afstat.buffer_lock, irqflags);
288 + for (i = 0; i < H3A_MAX_BUFF; i++)
289 + afstat.af_buff[i].locked = 0;
291 + spin_unlock_irqrestore(&afstat.buffer_lock, irqflags);
295 + * Helper function to link allocated buffers
297 +static void isp_af_link_buffers(void)
301 + for (i = 0; i < H3A_MAX_BUFF; i++) {
302 + if ((i + 1) < H3A_MAX_BUFF)
303 + afstat.af_buff[i].next = &afstat.af_buff[i + 1];
305 + afstat.af_buff[i].next = &afstat.af_buff[0];
309 +/* Function to perform hardware set up */
310 +int isp_af_configure(struct af_configuration *afconfig)
314 + unsigned int busyaf;
315 + struct af_configuration *af_curr_cfg = af_dev_configptr->config;
317 + if (NULL == afconfig) {
318 + printk(KERN_ERR "Null argument in configuration. \n");
322 + memcpy(af_curr_cfg, afconfig, sizeof(struct af_configuration));
323 + /* Get the value of PCR register */
324 + busyaf = isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
326 + if ((busyaf & AF_BUSYAF) == AF_BUSYAF) {
327 + DPRINTK_ISP_AF("AF_register_setup_ERROR : Engine Busy");
328 + DPRINTK_ISP_AF("\n Configuration cannot be done ");
329 + return -AF_ERR_ENGINE_BUSY;
332 + /* Check IIR Coefficient and start Values */
333 + result = isp_af_check_iir();
337 + /* Check Paxel Values */
338 + result = isp_af_check_paxel();
342 + /* Check HMF Threshold Values */
343 + if (af_curr_cfg->hmf_config.threshold > AF_THRESHOLD_MAX) {
344 + DPRINTK_ISP_AF("Error : HMF Threshold is incorrect");
345 + return -AF_ERR_THRESHOLD;
348 + /* Compute buffer size */
349 + buff_size = (af_curr_cfg->paxel_config.hz_cnt + 1) *
350 + (af_curr_cfg->paxel_config.vt_cnt + 1) * AF_PAXEL_SIZE;
352 + afstat.curr_cfg_buf_size = buff_size;
353 + /* Deallocate the previous buffers */
354 + if (afstat.stats_buf_size && buff_size > afstat.stats_buf_size) {
356 + for (i = 0; i < H3A_MAX_BUFF; i++) {
357 + ispmmu_kunmap(afstat.af_buff[i].ispmmu_addr);
359 + NULL, afstat.min_buf_size,
360 + (void *)afstat.af_buff[i].virt_addr,
361 + (dma_addr_t)afstat.af_buff[i].phy_addr);
362 + afstat.af_buff[i].virt_addr = 0;
364 + afstat.stats_buf_size = 0;
367 + if (!afstat.af_buff[0].virt_addr) {
368 + afstat.stats_buf_size = buff_size;
369 + afstat.min_buf_size = PAGE_ALIGN(afstat.stats_buf_size);
371 + for (i = 0; i < H3A_MAX_BUFF; i++) {
372 + afstat.af_buff[i].virt_addr =
373 + (unsigned long)dma_alloc_coherent(
375 + afstat.min_buf_size,
377 + &afstat.af_buff[i].phy_addr,
378 + GFP_KERNEL | GFP_DMA);
379 + if (afstat.af_buff[i].virt_addr == 0) {
380 + printk(KERN_ERR "Can't acquire memory for "
381 + "buffer[%d]\n", i);
384 + afstat.af_buff[i].addr_align =
385 + afstat.af_buff[i].virt_addr;
386 + while ((afstat.af_buff[i].addr_align & 0xFFFFFFC0) !=
387 + afstat.af_buff[i].addr_align)
388 + afstat.af_buff[i].addr_align++;
389 + afstat.af_buff[i].ispmmu_addr =
390 + ispmmu_kmap(afstat.af_buff[i].phy_addr,
391 + afstat.min_buf_size);
393 + isp_af_unlock_buffers();
394 + isp_af_link_buffers();
396 + /* First active buffer */
397 + if (active_buff == NULL)
398 + active_buff = &afstat.af_buff[0];
399 + isp_af_set_address(active_buff->ispmmu_addr);
402 + result = isp_af_register_setup(af_dev_configptr);
405 + af_dev_configptr->size_paxel = buff_size;
406 + atomic_inc(&afstat.config_counter);
407 + afstat.initialized = 1;
408 + afstat.frame_count = 1;
409 + active_buff->frame_num = 1;
410 + /* Set configuration flag to indicate HW setup done */
411 + if (af_curr_cfg->af_config)
419 +EXPORT_SYMBOL(isp_af_configure);
421 +int isp_af_register_setup(struct af_device *af_dev)
423 + unsigned int pcr = 0, pax1 = 0, pax2 = 0, paxstart = 0;
424 + unsigned int coef = 0;
425 + unsigned int base_coef_set0 = 0;
426 + unsigned int base_coef_set1 = 0;
429 + /* Configure Hardware Registers */
430 + /* Read PCR Register */
431 + pcr = isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
433 + /* Set Accumulator Mode */
434 + if (af_dev->config->mode == ACCUMULATOR_PEAK)
440 + if (af_dev->config->alaw_enable == H3A_AF_ALAW_ENABLE)
443 + pcr &= ~AF_ALAW_EN;
445 + /* Set RGB Position */
447 + pcr |= af_dev->config->rgb_pos << AF_RGBPOS_SHIFT;
449 + /* HMF Configurations */
450 + if (af_dev->config->hmf_config.enable == H3A_AF_HMF_ENABLE) {
455 + /* Set Median Threshold */
457 + pcr |= af_dev->config->hmf_config.threshold << AF_MED_TH_SHIFT;
461 + /* Set PCR Register */
462 + isp_reg_writel(pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
465 + pax1 |= af_dev->config->paxel_config.width << AF_PAXW_SHIFT;
467 + /* Set height in AFPAX1 */
469 + pax1 |= af_dev->config->paxel_config.height;
471 + isp_reg_writel(pax1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1);
473 + /* Configure AFPAX2 Register */
474 + /* Set Line Increment in AFPAX2 Register */
476 + pax2 |= af_dev->config->paxel_config.line_incr << AF_LINE_INCR_SHIFT;
477 + /* Set Vertical Count */
479 + pax2 |= af_dev->config->paxel_config.vt_cnt << AF_VT_COUNT_SHIFT;
480 + /* Set Horizontal Count */
482 + pax2 |= af_dev->config->paxel_config.hz_cnt;
483 + isp_reg_writel(pax2, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2);
485 + /* Configure PAXSTART Register */
486 + /*Configure Horizontal Start */
487 + paxstart &= ~PAXSH;
488 + paxstart |= af_dev->config->paxel_config.hz_start << AF_HZ_START_SHIFT;
489 + /* Configure Vertical Start */
490 + paxstart &= ~PAXSV;
491 + paxstart |= af_dev->config->paxel_config.vt_start;
492 + isp_reg_writel(paxstart, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAXSTART);
494 + /*SetIIRSH Register */
495 + isp_reg_writel(af_dev->config->iir_config.hz_start_pos,
496 + OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH);
498 + /*Set IIR Filter0 Coefficients */
499 + base_coef_set0 = ISPH3A_AFCOEF010;
500 + for (index = 0; index <= 8; index += 2) {
501 + coef &= ~COEF_MASK0;
502 + coef |= af_dev->config->iir_config.coeff_set0[index];
503 + coef &= ~COEF_MASK1;
504 + coef |= af_dev->config->iir_config.coeff_set0[index + 1] <<
506 + isp_reg_writel(coef, OMAP3_ISP_IOMEM_H3A, base_coef_set0);
507 + base_coef_set0 = base_coef_set0 + AFCOEF_OFFSET;
510 + /* set AFCOEF0010 Register */
511 + isp_reg_writel(af_dev->config->iir_config.coeff_set0[10],
512 + OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF010);
514 + /*Set IIR Filter1 Coefficients */
516 + base_coef_set1 = ISPH3A_AFCOEF110;
517 + for (index = 0; index <= 8; index += 2) {
518 + coef &= ~COEF_MASK0;
519 + coef |= af_dev->config->iir_config.coeff_set1[index];
520 + coef &= ~COEF_MASK1;
521 + coef |= af_dev->config->iir_config.coeff_set1[index + 1] <<
523 + isp_reg_writel(coef, OMAP3_ISP_IOMEM_H3A, base_coef_set1);
525 + base_coef_set1 = base_coef_set1 + AFCOEF_OFFSET;
527 + isp_reg_writel(af_dev->config->iir_config.coeff_set1[10],
528 + OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010);
533 +/* Function to set address */
534 +void isp_af_set_address(unsigned long address)
536 + isp_reg_writel(address, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFBUFST);
539 +static int isp_af_stats_available(struct isp_af_data *afdata)
542 + unsigned long irqflags;
544 + spin_lock_irqsave(&afstat.buffer_lock, irqflags);
545 + for (i = 0; i < H3A_MAX_BUFF; i++) {
546 + DPRINTK_ISP_AF("Checking Stats buff[%d] (%d) for %d\n",
547 + i, afstat.af_buff[i].frame_num,
548 + afdata->frame_number);
549 + if (afdata->frame_number == afstat.af_buff[i].frame_num
550 + && afstat.af_buff[i].frame_num != active_buff->frame_num) {
551 + afstat.af_buff[i].locked = 1;
552 + spin_unlock_irqrestore(&afstat.buffer_lock, irqflags);
553 + isp_af_update_req_buffer(&afstat.af_buff[i]);
554 + afstat.af_buff[i].frame_num = 0;
555 + ret = copy_to_user((void *)afdata->af_statistics_buf,
556 + (void *)afstat.af_buff[i].virt_addr,
557 + afstat.curr_cfg_buf_size);
559 + printk(KERN_ERR "Failed copy_to_user for "
560 + "H3A stats buff, %d\n", ret);
562 + afdata->xtrastats.ts = afstat.af_buff[i].xtrastats.ts;
563 + afdata->xtrastats.field_count =
564 + afstat.af_buff[i].xtrastats.field_count;
568 + spin_unlock_irqrestore(&afstat.buffer_lock, irqflags);
569 + /* Stats unavailable */
574 +void isp_af_notify(int notify)
576 + camnotify = notify;
577 + if (camnotify && afstat.initialized) {
578 + printk(KERN_DEBUG "Warning Camera Off \n");
579 + afstat.stats_req = 0;
580 + afstat.stats_done = 1;
581 + wake_up_interruptible(&afstat.stats_wait);
584 +EXPORT_SYMBOL(isp_af_notify);
586 + * This API allows the user to update White Balance gains, as well as
587 + * exposure time and analog gain. It is also used to request frame
590 +int isp_af_request_statistics(struct isp_af_data *afdata)
593 + u16 frame_diff = 0;
594 + u16 frame_cnt = afstat.frame_count;
597 + if (!af_dev_configptr->config->af_config) {
598 + printk(KERN_ERR "AF engine not enabled\n");
602 + if (!(afdata->update & REQUEST_STATISTICS)) {
603 + afdata->af_statistics_buf = NULL;
607 + isp_af_unlock_buffers();
608 + /* Stats available? */
609 + DPRINTK_ISP_AF("Stats available?\n");
610 + ret = isp_af_stats_available(afdata);
614 + /* Stats in near future? */
615 + DPRINTK_ISP_AF("Stats in near future?\n");
616 + if (afdata->frame_number > frame_cnt)
617 + frame_diff = afdata->frame_number - frame_cnt;
618 + else if (afdata->frame_number < frame_cnt) {
619 + if (frame_cnt > MAX_FRAME_COUNT - MAX_FUTURE_FRAMES
620 + && afdata->frame_number < MAX_FRAME_COUNT) {
621 + frame_diff = afdata->frame_number + MAX_FRAME_COUNT -
624 + /* Frame unavailable */
625 + frame_diff = MAX_FUTURE_FRAMES + 1;
629 + if (frame_diff > MAX_FUTURE_FRAMES) {
630 + printk(KERN_ERR "Invalid frame requested, returning current"
632 + afdata->frame_number = frame_cnt;
635 + /* Block until frame in near future completes */
636 + afstat.frame_req = afdata->frame_number;
637 + afstat.stats_req = 1;
638 + afstat.stats_done = 0;
639 + init_waitqueue_entry(&wqt, current);
640 + ret = wait_event_interruptible(afstat.stats_wait,
641 + afstat.stats_done == 1);
643 + afdata->af_statistics_buf = NULL;
646 + DPRINTK_ISP_AF("ISP AF request status interrupt raised\n");
648 + /* Stats now available */
649 + ret = isp_af_stats_available(afdata);
651 + printk(KERN_ERR "After waiting for stats, stats not"
653 + afdata->af_statistics_buf = NULL;
658 + afdata->curr_frame = afstat.frame_count;
662 +EXPORT_SYMBOL(isp_af_request_statistics);
664 +/* This function will handle the H3A interrupt. */
665 +static void isp_af_isr(unsigned long status, isp_vbq_callback_ptr arg1,
670 + if ((H3A_AF_DONE & status) != H3A_AF_DONE)
673 + /* timestamp stats buffer */
674 + do_gettimeofday(&active_buff->xtrastats.ts);
675 + active_buff->config_counter = atomic_read(&afstat.config_counter);
677 + /* Exchange buffers */
678 + active_buff = active_buff->next;
679 + if (active_buff->locked == 1)
680 + active_buff = active_buff->next;
681 + isp_af_set_address(active_buff->ispmmu_addr);
683 + /* Update frame counter */
684 + afstat.frame_count++;
685 + frame_align = afstat.frame_count;
686 + if (afstat.frame_count > MAX_FRAME_COUNT) {
687 + afstat.frame_count = 1;
690 + active_buff->frame_num = afstat.frame_count;
692 + /* Future Stats requested? */
693 + if (afstat.stats_req) {
694 + /* Is the frame we want already done? */
695 + if (frame_align >= afstat.frame_req + 1) {
696 + afstat.stats_req = 0;
697 + afstat.stats_done = 1;
698 + wake_up_interruptible(&afstat.stats_wait);
703 +int __isp_af_enable(int enable)
707 + pcr = isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
709 + /* Set AF_EN bit in PCR Register */
711 + if (isp_set_callback(CBK_H3A_AF_DONE, isp_af_isr,
712 + (void *)NULL, (void *)NULL)) {
713 + printk(KERN_ERR "No callback for AF\n");
719 + isp_unset_callback(CBK_H3A_AF_DONE);
722 + isp_reg_writel(pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
726 +/* Function to Enable/Disable AF Engine */
727 +int isp_af_enable(int enable)
731 + rval = __isp_af_enable(enable);
734 + afstat.pm_state = enable;
739 +/* Function to Suspend AF Engine */
740 +void isp_af_suspend(void)
742 + if (afstat.pm_state)
743 + __isp_af_enable(0);
746 +/* Function to Resume AF Engine */
747 +void isp_af_resume(void)
749 + if (afstat.pm_state)
750 + __isp_af_enable(1);
753 +int isp_af_busy(void)
755 + return isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
756 + & ISPH3A_PCR_BUSYAF;
759 +/* Function to register the AF character device driver. */
760 +int __init isp_af_init(void)
762 + /*allocate memory for device structure and initialize it with 0 */
763 + af_dev_configptr = kzalloc(sizeof(struct af_device), GFP_KERNEL);
764 + if (!af_dev_configptr)
767 + active_buff = NULL;
769 + af_dev_configptr->config = (struct af_configuration *)
770 + kzalloc(sizeof(struct af_configuration), GFP_KERNEL);
772 + if (af_dev_configptr->config == NULL)
775 + memset(&afstat, 0, sizeof(afstat));
777 + init_waitqueue_head(&afstat.stats_wait);
778 + spin_lock_init(&afstat.buffer_lock);
783 + kfree(af_dev_configptr);
785 + printk(KERN_ERR "Error: kmalloc fail");
789 +void isp_af_exit(void)
794 + for (i = 0; i < H3A_MAX_BUFF; i++) {
795 + if (!afstat.af_buff[i].phy_addr)
798 + ispmmu_kunmap(afstat.af_buff[i].ispmmu_addr);
800 + dma_free_coherent(NULL,
801 + afstat.min_buf_size,
802 + (void *)afstat.af_buff[i].virt_addr,
803 + (dma_addr_t)afstat.af_buff[i].phy_addr);
805 + kfree(af_dev_configptr->config);
806 + kfree(af_dev_configptr);
808 + memset(&afstat, 0, sizeof(afstat));
812 diff --git a/drivers/media/video/isp/isp_af.h b/drivers/media/video/isp/isp_af.h
814 index 0000000..ee2b89f
816 +++ b/drivers/media/video/isp/isp_af.h
821 + * Include file for AF module in TI's OMAP3 Camera ISP
823 + * Copyright (C) 2009 Texas Instruments, Inc.
826 + * Sergio Aguirre <saaguirre@ti.com>
829 + * This package is free software; you can redistribute it and/or modify
830 + * it under the terms of the GNU General Public License version 2 as
831 + * published by the Free Software Foundation.
833 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
834 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
835 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
838 +/* Device Constants */
839 +#ifndef OMAP_ISP_AF_H
840 +#define OMAP_ISP_AF_H
842 +#include <mach/isp_user.h>
844 +#define AF_MAJOR_NUMBER 0
845 +#define ISPAF_NAME "OMAPISP_AF"
846 +#define AF_NR_DEVS 1
847 +#define AF_TIMEOUT ((300 * HZ) / 1000)
852 +/*list of error code */
853 +#define AF_ERR_HZ_COUNT 800 /* Invalid Horizontal Count */
854 +#define AF_ERR_VT_COUNT 801 /* Invalid Vertical Count */
855 +#define AF_ERR_HEIGHT 802 /* Invalid Height */
856 +#define AF_ERR_WIDTH 803 /* Invalid width */
857 +#define AF_ERR_INCR 804 /* Invalid Increment */
858 +#define AF_ERR_HZ_START 805 /* Invalid horizontal Start */
859 +#define AF_ERR_VT_START 806 /* Invalud vertical Start */
860 +#define AF_ERR_IIRSH 807 /* Invalid IIRSH value */
861 +#define AF_ERR_IIR_COEF 808 /* Invalid Coefficient */
862 +#define AF_ERR_SETUP 809 /* Setup not done */
863 +#define AF_ERR_THRESHOLD 810 /* Invalid Threshold */
864 +#define AF_ERR_ENGINE_BUSY 811 /* Engine is busy */
866 +#define AFPID 0x0 /* Peripheral Revision
867 + * and Class Information
870 +#define AFCOEF_OFFSET 0x00000004 /* COEFFICIENT BASE
877 +#define AF_BUSYAF (1 << 15)
878 +#define FVMODE (1 << 14)
879 +#define RGBPOS (0x7 << 11)
880 +#define MED_TH (0xFF << 3)
881 +#define AF_MED_EN (1 << 2)
882 +#define AF_ALAW_EN (1 << 1)
883 +#define AF_EN (1 << 0)
888 +#define PAXW (0x7F << 16)
894 +#define AFINCV (0xF << 13)
895 +#define PAXVC (0x7F << 6)
899 + * AFPAXSTART fields
901 +#define PAXSH (0xFFF<<16)
908 +#define COEF_MASK0 0xFFF
909 +#define COEF_MASK1 (0xFFF<<16)
912 +#define AF_RGBPOS_SHIFT 11
913 +#define AF_MED_TH_SHIFT 3
914 +#define AF_PAXW_SHIFT 16
915 +#define AF_LINE_INCR_SHIFT 13
916 +#define AF_VT_COUNT_SHIFT 6
917 +#define AF_HZ_START_SHIFT 16
918 +#define AF_COEF_SHIFT 16
920 +#define AF_UPDATEXS_TS (1 << 0)
921 +#define AF_UPDATEXS_FIELDCOUNT (1 << 1)
922 +#define AF_UPDATEXS_LENSPOS (1 << 2)
924 +/* Structure for device of AF Engine */
926 + struct af_configuration *config; /*Device configuration structure */
927 + int size_paxel; /*Paxel size in bytes */
930 +int isp_af_check_paxel(void);
931 +int isp_af_check_iir(void);
932 +int isp_af_register_setup(struct af_device *af_dev);
933 +int isp_af_enable(int);
934 +void isp_af_suspend(void);
935 +void isp_af_resume(void);
936 +int isp_af_busy(void);
937 +void isp_af_notify(int notify);
938 +int isp_af_request_statistics(struct isp_af_data *afdata);
939 +int isp_af_configure(struct af_configuration *afconfig);
940 +void isp_af_set_address(unsigned long);
941 +void isp_af_setxtrastats(struct isp_af_xtrastats *xtrastats, u8 updateflag);
942 +#endif /* OMAP_ISP_AF_H */
943 diff --git a/drivers/media/video/isp/isph3a.c b/drivers/media/video/isp/isph3a.c
945 index 0000000..7ff1c5b
947 +++ b/drivers/media/video/isp/isph3a.c
952 + * H3A module for TI's OMAP3 Camera ISP
954 + * Copyright (C) 2009 Texas Instruments, Inc.
957 + * Sergio Aguirre <saaguirre@ti.com>
960 + * This package is free software; you can redistribute it and/or modify
961 + * it under the terms of the GNU General Public License version 2 as
962 + * published by the Free Software Foundation.
964 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
965 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
966 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
969 +#include <asm/cacheflush.h>
971 +#include <linux/dma-mapping.h>
972 +#include <linux/uaccess.h>
978 +#include "isppreview.h"
981 + * struct isph3a_aewb_buffer - AE, AWB frame stats buffer.
982 + * @virt_addr: Virtual address to mmap the buffer.
983 + * @phy_addr: Physical address of the buffer.
984 + * @addr_align: Virtual Address 32 bytes aligned.
985 + * @ispmmu_addr: Address of the buffer mapped by the ISPMMU.
986 + * @mmap_addr: Mapped memory area of buffer. For userspace access.
987 + * @locked: 1 - Buffer locked from write. 0 - Buffer can be overwritten.
988 + * @frame_num: Frame number from which the statistics are taken.
989 + * @next: Pointer to link next buffer.
991 +struct isph3a_aewb_buffer {
992 + unsigned long virt_addr;
993 + unsigned long phy_addr;
994 + unsigned long addr_align;
995 + unsigned long ispmmu_addr;
996 + unsigned long mmap_addr; /* For userspace */
998 + u32 config_counter;
1002 + struct isph3a_aewb_buffer *next;
1006 + * struct isph3a_aewb_status - AE, AWB status.
1007 + * @initialized: 1 - Buffers initialized.
1008 + * @update: 1 - Update registers.
1009 + * @stats_req: 1 - Future stats requested.
1010 + * @stats_done: 1 - Stats ready for user.
1011 + * @frame_req: Number of frame requested for statistics.
1012 + * @h3a_buff: Array of statistics buffers to access.
1013 + * @stats_buf_size: Statistics buffer size.
1014 + * @min_buf_size: Minimum statisitics buffer size.
1015 + * @win_count: Window Count.
1016 + * @frame_count: Frame Count.
1017 + * @stats_wait: Wait primitive for locking/unlocking the stats request.
1018 + * @buffer_lock: Spinlock for statistics buffers access.
1020 +static struct isph3a_aewb_status {
1028 + struct isph3a_aewb_buffer h3a_buff[H3A_MAX_BUFF];
1029 + unsigned int stats_buf_size;
1030 + unsigned int min_buf_size;
1031 + unsigned int curr_cfg_buf_size;
1033 + atomic_t config_counter;
1037 + wait_queue_head_t stats_wait;
1038 + spinlock_t buffer_lock; /* For stats buffers read/write sync */
1042 + * struct isph3a_aewb_regs - Current value of AE, AWB configuration registers.
1043 + * reg_pcr: Peripheral control register.
1044 + * reg_win1: Control register.
1045 + * reg_start: Start position register.
1046 + * reg_blk: Black line register.
1047 + * reg_subwin: Configuration register.
1049 +static struct isph3a_aewb_regs {
1057 +static struct isph3a_aewb_config aewb_config_local = {
1058 + .saturation_limit = 0x3FF,
1061 + .ver_win_count = 0,
1062 + .hor_win_count = 0,
1063 + .ver_win_start = 0,
1064 + .hor_win_start = 0,
1065 + .blk_ver_win_start = 0,
1066 + .blk_win_height = 0,
1067 + .subsample_ver_inc = 0,
1068 + .subsample_hor_inc = 0,
1073 +/* Structure for saving/restoring h3a module registers */
1074 +static struct isp_reg isph3a_reg_list[] = {
1075 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, 0}, /* Should be the first one */
1076 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1, 0},
1077 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINSTART, 0},
1078 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK, 0},
1079 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWSUBWIN, 0},
1080 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST, 0},
1081 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1, 0},
1082 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2, 0},
1083 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAXSTART, 0},
1084 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH, 0},
1085 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFBUFST, 0},
1086 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF010, 0},
1087 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF032, 0},
1088 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF054, 0},
1089 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF076, 0},
1090 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF098, 0},
1091 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF0010, 0},
1092 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF110, 0},
1093 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF132, 0},
1094 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF154, 0},
1095 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF176, 0},
1096 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF198, 0},
1097 + {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010, 0},
1098 + {0, ISP_TOK_TERM, 0}
1101 +static struct ispprev_wbal h3awb_update;
1102 +static struct isph3a_aewb_buffer *active_buff;
1103 +static struct isph3a_aewb_xtrastats h3a_xtrastats[H3A_MAX_BUFF];
1104 +static int camnotify;
1105 +static int wb_update;
1106 +static void isph3a_print_status(void);
1109 + * isph3a_aewb_setxtrastats - Receives extra statistics from prior frames.
1110 + * @xtrastats: Pointer to structure containing extra statistics fields like
1111 + * field count and timestamp of frame.
1113 + * Called from update_vbq in camera driver
1115 +void isph3a_aewb_setxtrastats(struct isph3a_aewb_xtrastats *xtrastats)
1119 + if (active_buff == NULL)
1122 + for (i = 0; i < H3A_MAX_BUFF; i++) {
1123 + if (aewbstat.h3a_buff[i].frame_num != active_buff->frame_num)
1127 + if (aewbstat.h3a_buff[H3A_MAX_BUFF - 1].locked == 0) {
1128 + h3a_xtrastats[H3A_MAX_BUFF - 1] =
1131 + h3a_xtrastats[H3A_MAX_BUFF - 2] =
1134 + } else if (i == 1) {
1135 + if (aewbstat.h3a_buff[0].locked == 0)
1136 + h3a_xtrastats[0] = *xtrastats;
1138 + h3a_xtrastats[H3A_MAX_BUFF - 1] =
1142 + if (aewbstat.h3a_buff[i - 1].locked == 0)
1143 + h3a_xtrastats[i - 1] = *xtrastats;
1145 + h3a_xtrastats[i - 2] = *xtrastats;
1150 +EXPORT_SYMBOL(isph3a_aewb_setxtrastats);
1152 +void __isph3a_aewb_enable(u8 enable)
1154 + isp_reg_writel(IRQ0STATUS_H3A_AWB_DONE_IRQ, OMAP3_ISP_IOMEM_MAIN,
1158 + aewb_regs.reg_pcr |= ISPH3A_PCR_AEW_EN;
1159 + DPRINTK_ISPH3A(" H3A enabled \n");
1161 + aewb_regs.reg_pcr &= ~ISPH3A_PCR_AEW_EN;
1162 + DPRINTK_ISPH3A(" H3A disabled \n");
1164 + isp_reg_and_or(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, ~ISPH3A_PCR_AEW_EN,
1165 + (enable ? ISPH3A_PCR_AEW_EN : 0));
1166 + aewb_config_local.aewb_enable = enable;
1170 + * isph3a_aewb_enable - Enables AE, AWB engine in the H3A module.
1171 + * @enable: 1 - Enables the AE & AWB engine.
1173 + * Client should configure all the AE & AWB registers in H3A before this.
1175 +void isph3a_aewb_enable(u8 enable)
1177 + __isph3a_aewb_enable(enable);
1178 + aewbstat.pm_state = enable;
1182 + * isph3a_aewb_suspend - Suspend AE, AWB engine in the H3A module.
1184 +void isph3a_aewb_suspend(void)
1186 + if (aewbstat.pm_state)
1187 + __isph3a_aewb_enable(0);
1191 + * isph3a_aewb_resume - Resume AE, AWB engine in the H3A module.
1193 +void isph3a_aewb_resume(void)
1195 + if (aewbstat.pm_state)
1196 + __isph3a_aewb_enable(1);
1199 +int isph3a_aewb_busy(void)
1201 + return isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
1202 + & ISPH3A_PCR_BUSYAEAWB;
1206 + * isph3a_update_wb - Updates WB parameters.
1208 + * Needs to be called when no ISP Preview processing is taking place.
1210 +void isph3a_update_wb(void)
1213 + isppreview_config_whitebalance(h3awb_update);
1218 +EXPORT_SYMBOL(isph3a_update_wb);
1221 + * isph3a_aewb_update_regs - Helper function to update h3a registers.
1223 +static void isph3a_aewb_update_regs(void)
1225 + isp_reg_writel(aewb_regs.reg_pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
1226 + isp_reg_writel(aewb_regs.reg_win1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1);
1227 + isp_reg_writel(aewb_regs.reg_start, OMAP3_ISP_IOMEM_H3A,
1228 + ISPH3A_AEWINSTART);
1229 + isp_reg_writel(aewb_regs.reg_blk, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK);
1230 + isp_reg_writel(aewb_regs.reg_subwin, OMAP3_ISP_IOMEM_H3A,
1231 + ISPH3A_AEWSUBWIN);
1233 + aewbstat.update = 0;
1234 + aewbstat.frame_count = 1;
1238 + * isph3a_aewb_update_req_buffer - Helper function to update buffer cache pages
1239 + * @buffer: Pointer to structure
1241 +static void isph3a_aewb_update_req_buffer(struct isph3a_aewb_buffer *buffer)
1243 + int size = aewbstat.stats_buf_size;
1245 + size = PAGE_ALIGN(size);
1246 + dmac_inv_range((void *)buffer->addr_align,
1247 + (void *)buffer->addr_align + size);
1251 + * isph3a_aewb_stats_available - Check for stats available of specified frame.
1252 + * @aewbdata: Pointer to return AE AWB statistics data
1254 + * Returns 0 if successful, or -1 if statistics are unavailable.
1256 +static int isph3a_aewb_stats_available(struct isph3a_aewb_data *aewbdata)
1259 + unsigned long irqflags;
1261 + spin_lock_irqsave(&aewbstat.buffer_lock, irqflags);
1262 + for (i = 0; i < H3A_MAX_BUFF; i++) {
1263 + DPRINTK_ISPH3A("Checking Stats buff[%d] (%d) for %d\n",
1264 + i, aewbstat.h3a_buff[i].frame_num,
1265 + aewbdata->frame_number);
1266 + if ((aewbdata->frame_number !=
1267 + aewbstat.h3a_buff[i].frame_num) ||
1268 + (aewbstat.h3a_buff[i].frame_num ==
1269 + active_buff->frame_num))
1271 + aewbstat.h3a_buff[i].locked = 1;
1272 + spin_unlock_irqrestore(&aewbstat.buffer_lock, irqflags);
1273 + isph3a_aewb_update_req_buffer(&aewbstat.h3a_buff[i]);
1274 + aewbstat.h3a_buff[i].frame_num = 0;
1275 + ret = copy_to_user((void *)aewbdata->h3a_aewb_statistics_buf,
1276 + (void *)aewbstat.h3a_buff[i].virt_addr,
1277 + aewbstat.curr_cfg_buf_size);
1279 + printk(KERN_ERR "Failed copy_to_user for "
1280 + "H3A stats buff, %d\n", ret);
1282 + aewbdata->ts = aewbstat.h3a_buff[i].ts;
1283 + aewbdata->config_counter = aewbstat.h3a_buff[i].config_counter;
1284 + aewbdata->field_count = h3a_xtrastats[i].field_count;
1287 + spin_unlock_irqrestore(&aewbstat.buffer_lock, irqflags);
1293 + * isph3a_aewb_link_buffers - Helper function to link allocated buffers.
1295 +static void isph3a_aewb_link_buffers(void)
1299 + for (i = 0; i < H3A_MAX_BUFF; i++) {
1300 + if ((i + 1) < H3A_MAX_BUFF) {
1301 + aewbstat.h3a_buff[i].next = &aewbstat.h3a_buff[i + 1];
1302 + h3a_xtrastats[i].next = &h3a_xtrastats[i + 1];
1304 + aewbstat.h3a_buff[i].next = &aewbstat.h3a_buff[0];
1305 + h3a_xtrastats[i].next = &h3a_xtrastats[0];
1311 + * isph3a_aewb_unlock_buffers - Helper function to unlock all buffers.
1313 +static void isph3a_aewb_unlock_buffers(void)
1316 + unsigned long irqflags;
1318 + spin_lock_irqsave(&aewbstat.buffer_lock, irqflags);
1319 + for (i = 0; i < H3A_MAX_BUFF; i++)
1320 + aewbstat.h3a_buff[i].locked = 0;
1322 + spin_unlock_irqrestore(&aewbstat.buffer_lock, irqflags);
1326 + * isph3a_aewb_isr - Callback from ISP driver for H3A AEWB interrupt.
1327 + * @status: IRQ0STATUS in case of MMU error, 0 for H3A interrupt.
1328 + * @arg1: Not used as of now.
1329 + * @arg2: Not used as of now.
1331 +static void isph3a_aewb_isr(unsigned long status, isp_vbq_callback_ptr arg1,
1336 + if ((H3A_AWB_DONE & status) != H3A_AWB_DONE)
1339 + do_gettimeofday(&active_buff->ts);
1340 + active_buff->config_counter = atomic_read(&aewbstat.config_counter);
1341 + active_buff = active_buff->next;
1342 + if (active_buff->locked == 1)
1343 + active_buff = active_buff->next;
1344 + isp_reg_writel(active_buff->ispmmu_addr, OMAP3_ISP_IOMEM_H3A,
1347 + aewbstat.frame_count++;
1348 + frame_align = aewbstat.frame_count;
1349 + if (aewbstat.frame_count > MAX_FRAME_COUNT) {
1350 + aewbstat.frame_count = 1;
1353 + active_buff->frame_num = aewbstat.frame_count;
1355 + if (aewbstat.stats_req) {
1356 + DPRINTK_ISPH3A("waiting for frame %d\n", aewbstat.frame_req);
1357 + if (frame_align >= aewbstat.frame_req + 1) {
1358 + aewbstat.stats_req = 0;
1359 + aewbstat.stats_done = 1;
1360 + wake_up_interruptible(&aewbstat.stats_wait);
1364 + if (aewbstat.update)
1365 + isph3a_aewb_update_regs();
1369 + * isph3a_aewb_set_params - Helper function to check & store user given params.
1370 + * @user_cfg: Pointer to AE and AWB parameters struct.
1372 + * As most of them are busy-lock registers, need to wait until AEW_BUSY = 0 to
1373 + * program them during ISR.
1375 + * Returns 0 if successful, or -EINVAL if any of the parameters are invalid.
1377 +static int isph3a_aewb_set_params(struct isph3a_aewb_config *user_cfg)
1379 + if (unlikely(user_cfg->saturation_limit > MAX_SATURATION_LIM)) {
1380 + printk(KERN_ERR "Invalid Saturation_limit: %d\n",
1381 + user_cfg->saturation_limit);
1384 + if (aewb_config_local.saturation_limit != user_cfg->saturation_limit) {
1385 + WRITE_SAT_LIM(aewb_regs.reg_pcr, user_cfg->saturation_limit);
1386 + aewb_config_local.saturation_limit =
1387 + user_cfg->saturation_limit;
1388 + aewbstat.update = 1;
1391 + if (aewb_config_local.alaw_enable != user_cfg->alaw_enable) {
1392 + WRITE_ALAW(aewb_regs.reg_pcr, user_cfg->alaw_enable);
1393 + aewb_config_local.alaw_enable = user_cfg->alaw_enable;
1394 + aewbstat.update = 1;
1397 + if (unlikely(user_cfg->win_height < MIN_WIN_H ||
1398 + user_cfg->win_height > MAX_WIN_H ||
1399 + user_cfg->win_height & 0x01)) {
1400 + printk(KERN_ERR "Invalid window height: %d\n",
1401 + user_cfg->win_height);
1404 + if (aewb_config_local.win_height != user_cfg->win_height) {
1405 + WRITE_WIN_H(aewb_regs.reg_win1, user_cfg->win_height);
1406 + aewb_config_local.win_height = user_cfg->win_height;
1407 + aewbstat.update = 1;
1410 + if (unlikely(user_cfg->win_width < MIN_WIN_W ||
1411 + user_cfg->win_width > MAX_WIN_W ||
1412 + user_cfg->win_width & 0x01)) {
1413 + printk(KERN_ERR "Invalid window width: %d\n",
1414 + user_cfg->win_width);
1417 + if (aewb_config_local.win_width != user_cfg->win_width) {
1418 + WRITE_WIN_W(aewb_regs.reg_win1, user_cfg->win_width);
1419 + aewb_config_local.win_width = user_cfg->win_width;
1420 + aewbstat.update = 1;
1423 + if (unlikely(user_cfg->ver_win_count < 1 ||
1424 + user_cfg->ver_win_count > MAX_WINVC)) {
1425 + printk(KERN_ERR "Invalid vertical window count: %d\n",
1426 + user_cfg->ver_win_count);
1429 + if (aewb_config_local.ver_win_count != user_cfg->ver_win_count) {
1430 + WRITE_VER_C(aewb_regs.reg_win1, user_cfg->ver_win_count);
1431 + aewb_config_local.ver_win_count = user_cfg->ver_win_count;
1432 + aewbstat.update = 1;
1435 + if (unlikely(user_cfg->hor_win_count < 1 ||
1436 + user_cfg->hor_win_count > MAX_WINHC)) {
1437 + printk(KERN_ERR "Invalid horizontal window count: %d\n",
1438 + user_cfg->hor_win_count);
1441 + if (aewb_config_local.hor_win_count != user_cfg->hor_win_count) {
1442 + WRITE_HOR_C(aewb_regs.reg_win1, user_cfg->hor_win_count);
1443 + aewb_config_local.hor_win_count = user_cfg->hor_win_count;
1444 + aewbstat.update = 1;
1447 + if (unlikely(user_cfg->ver_win_start > MAX_WINSTART)) {
1448 + printk(KERN_ERR "Invalid vertical window start: %d\n",
1449 + user_cfg->ver_win_start);
1452 + if (aewb_config_local.ver_win_start != user_cfg->ver_win_start) {
1453 + WRITE_VER_WIN_ST(aewb_regs.reg_start, user_cfg->ver_win_start);
1454 + aewb_config_local.ver_win_start = user_cfg->ver_win_start;
1455 + aewbstat.update = 1;
1458 + if (unlikely(user_cfg->hor_win_start > MAX_WINSTART)) {
1459 + printk(KERN_ERR "Invalid horizontal window start: %d\n",
1460 + user_cfg->hor_win_start);
1463 + if (aewb_config_local.hor_win_start != user_cfg->hor_win_start) {
1464 + WRITE_HOR_WIN_ST(aewb_regs.reg_start, user_cfg->hor_win_start);
1465 + aewb_config_local.hor_win_start = user_cfg->hor_win_start;
1466 + aewbstat.update = 1;
1469 + if (unlikely(user_cfg->blk_ver_win_start > MAX_WINSTART)) {
1470 + printk(KERN_ERR "Invalid black vertical window start: %d\n",
1471 + user_cfg->blk_ver_win_start);
1474 + if (aewb_config_local.blk_ver_win_start !=
1475 + user_cfg->blk_ver_win_start) {
1476 + WRITE_BLK_VER_WIN_ST(aewb_regs.reg_blk,
1477 + user_cfg->blk_ver_win_start);
1478 + aewb_config_local.blk_ver_win_start =
1479 + user_cfg->blk_ver_win_start;
1480 + aewbstat.update = 1;
1483 + if (unlikely(user_cfg->blk_win_height < MIN_WIN_H ||
1484 + user_cfg->blk_win_height > MAX_WIN_H ||
1485 + user_cfg->blk_win_height & 0x01)) {
1486 + printk(KERN_ERR "Invalid black window height: %d\n",
1487 + user_cfg->blk_win_height);
1490 + if (aewb_config_local.blk_win_height != user_cfg->blk_win_height) {
1491 + WRITE_BLK_WIN_H(aewb_regs.reg_blk, user_cfg->blk_win_height);
1492 + aewb_config_local.blk_win_height = user_cfg->blk_win_height;
1493 + aewbstat.update = 1;
1496 + if (unlikely(user_cfg->subsample_ver_inc < MIN_SUB_INC ||
1497 + user_cfg->subsample_ver_inc > MAX_SUB_INC ||
1498 + user_cfg->subsample_ver_inc & 0x01)) {
1499 + printk(KERN_ERR "Invalid vertical subsample increment: %d\n",
1500 + user_cfg->subsample_ver_inc);
1503 + if (aewb_config_local.subsample_ver_inc !=
1504 + user_cfg->subsample_ver_inc) {
1505 + WRITE_SUB_VER_INC(aewb_regs.reg_subwin,
1506 + user_cfg->subsample_ver_inc);
1507 + aewb_config_local.subsample_ver_inc =
1508 + user_cfg->subsample_ver_inc;
1509 + aewbstat.update = 1;
1512 + if (unlikely(user_cfg->subsample_hor_inc < MIN_SUB_INC ||
1513 + user_cfg->subsample_hor_inc > MAX_SUB_INC ||
1514 + user_cfg->subsample_hor_inc & 0x01)) {
1515 + printk(KERN_ERR "Invalid horizontal subsample increment: %d\n",
1516 + user_cfg->subsample_hor_inc);
1519 + if (aewb_config_local.subsample_hor_inc !=
1520 + user_cfg->subsample_hor_inc) {
1521 + WRITE_SUB_HOR_INC(aewb_regs.reg_subwin,
1522 + user_cfg->subsample_hor_inc);
1523 + aewb_config_local.subsample_hor_inc =
1524 + user_cfg->subsample_hor_inc;
1525 + aewbstat.update = 1;
1528 + if (!aewbstat.initialized || !aewb_config_local.aewb_enable) {
1529 + isph3a_aewb_update_regs();
1530 + aewbstat.initialized = 1;
1536 + * isph3a_aewb_configure - Configure AEWB regs, enable/disable H3A engine.
1537 + * @aewbcfg: Pointer to AEWB config structure.
1539 + * Returns 0 if successful, -EINVAL if aewbcfg pointer is NULL, -ENOMEM if
1540 + * was unable to allocate memory for the buffer, of other errors if H3A
1541 + * callback is not set or the parameters for AEWB are invalid.
1543 +int isph3a_aewb_configure(struct isph3a_aewb_config *aewbcfg)
1547 + int win_count = 0;
1549 + if (NULL == aewbcfg) {
1550 + printk(KERN_ERR "Null argument in configuration. \n");
1554 + if (!aewbstat.initialized) {
1555 + DPRINTK_ISPH3A("Setting callback for H3A\n");
1556 + ret = isp_set_callback(CBK_H3A_AWB_DONE, isph3a_aewb_isr,
1557 + (void *)NULL, (void *)NULL);
1559 + printk(KERN_ERR "No callback for H3A\n");
1564 + ret = isph3a_aewb_set_params(aewbcfg);
1566 + printk(KERN_ERR "Invalid parameters! \n");
1570 + win_count = aewbcfg->ver_win_count * aewbcfg->hor_win_count;
1571 + win_count += aewbcfg->hor_win_count;
1572 + ret = win_count / 8;
1573 + win_count += win_count % 8 ? 1 : 0;
1576 + aewbstat.win_count = win_count;
1577 + aewbstat.curr_cfg_buf_size = win_count * AEWB_PACKET_SIZE;
1579 + if (aewbstat.stats_buf_size
1580 + && win_count * AEWB_PACKET_SIZE > aewbstat.stats_buf_size) {
1581 + DPRINTK_ISPH3A("There was a previous buffer... "
1582 + "Freeing/unmapping current stat busffs\n");
1583 + isph3a_aewb_enable(0);
1584 + for (i = 0; i < H3A_MAX_BUFF; i++) {
1585 + ispmmu_kunmap(aewbstat.h3a_buff[i].ispmmu_addr);
1586 + dma_free_coherent(
1588 + aewbstat.min_buf_size,
1589 + (void *)aewbstat.h3a_buff[i].virt_addr,
1590 + (dma_addr_t)aewbstat.h3a_buff[i].phy_addr);
1591 + aewbstat.h3a_buff[i].virt_addr = 0;
1593 + aewbstat.stats_buf_size = 0;
1596 + if (!aewbstat.h3a_buff[0].virt_addr) {
1597 + aewbstat.stats_buf_size = win_count * AEWB_PACKET_SIZE;
1598 + aewbstat.min_buf_size = PAGE_ALIGN(aewbstat.stats_buf_size);
1600 + DPRINTK_ISPH3A("Allocating/mapping new stat buffs\n");
1601 + for (i = 0; i < H3A_MAX_BUFF; i++) {
1602 + aewbstat.h3a_buff[i].virt_addr =
1603 + (unsigned long)dma_alloc_coherent(
1605 + aewbstat.min_buf_size,
1607 + &aewbstat.h3a_buff[i].phy_addr,
1608 + GFP_KERNEL | GFP_DMA);
1609 + if (aewbstat.h3a_buff[i].virt_addr == 0) {
1610 + printk(KERN_ERR "Can't acquire memory for "
1611 + "buffer[%d]\n", i);
1614 + aewbstat.h3a_buff[i].addr_align =
1615 + aewbstat.h3a_buff[i].virt_addr;
1616 + while ((aewbstat.h3a_buff[i].addr_align & 0xFFFFFFC0) !=
1617 + aewbstat.h3a_buff[i].addr_align)
1618 + aewbstat.h3a_buff[i].addr_align++;
1619 + aewbstat.h3a_buff[i].ispmmu_addr =
1620 + ispmmu_kmap(aewbstat.h3a_buff[i].phy_addr,
1621 + aewbstat.min_buf_size);
1623 + isph3a_aewb_unlock_buffers();
1624 + isph3a_aewb_link_buffers();
1626 + if (active_buff == NULL)
1627 + active_buff = &aewbstat.h3a_buff[0];
1629 + isp_reg_writel(active_buff->ispmmu_addr, OMAP3_ISP_IOMEM_H3A,
1632 + for (i = 0; i < H3A_MAX_BUFF; i++) {
1633 + DPRINTK_ISPH3A("buff[%d] addr is:\n virt 0x%lX\n"
1634 + " aligned 0x%lX\n"
1636 + " ispmmu 0x%08lX\n"
1637 + " mmapped 0x%lX\n"
1638 + " frame_num %d\n", i,
1639 + aewbstat.h3a_buff[i].virt_addr,
1640 + aewbstat.h3a_buff[i].addr_align,
1641 + aewbstat.h3a_buff[i].phy_addr,
1642 + aewbstat.h3a_buff[i].ispmmu_addr,
1643 + aewbstat.h3a_buff[i].mmap_addr,
1644 + aewbstat.h3a_buff[i].frame_num);
1647 + active_buff->frame_num = 1;
1649 + atomic_inc(&aewbstat.config_counter);
1650 + isph3a_aewb_enable(aewbcfg->aewb_enable);
1651 + isph3a_print_status();
1655 +EXPORT_SYMBOL(isph3a_aewb_configure);
1658 + * isph3a_aewb_request_statistics - REquest statistics and update gains in AEWB
1659 + * @aewbdata: Pointer to return AE AWB statistics data.
1661 + * This API allows the user to update White Balance gains, as well as
1662 + * exposure time and analog gain. It is also used to request frame
1665 + * Returns 0 if successful, -EINVAL when H3A engine is not enabled, or other
1666 + * errors when setting gains.
1668 +int isph3a_aewb_request_statistics(struct isph3a_aewb_data *aewbdata)
1671 + u16 frame_diff = 0;
1672 + u16 frame_cnt = aewbstat.frame_count;
1675 + if (!aewb_config_local.aewb_enable) {
1676 + printk(KERN_ERR "H3A engine not enabled\n");
1680 + DPRINTK_ISPH3A("isph3a_aewb_request_statistics: Enter "
1681 + "(frame req. => %d, current frame => %d,"
1682 + "update => %d)\n",
1683 + aewbdata->frame_number, frame_cnt, aewbdata->update);
1684 + DPRINTK_ISPH3A("User data received: \n");
1685 + DPRINTK_ISPH3A("Digital gain = 0x%04x\n", aewbdata->dgain);
1686 + DPRINTK_ISPH3A("WB gain b *= 0x%04x\n", aewbdata->wb_gain_b);
1687 + DPRINTK_ISPH3A("WB gain r *= 0x%04x\n", aewbdata->wb_gain_r);
1688 + DPRINTK_ISPH3A("WB gain gb = 0x%04x\n", aewbdata->wb_gain_gb);
1689 + DPRINTK_ISPH3A("WB gain gr = 0x%04x\n", aewbdata->wb_gain_gr);
1691 + if (!aewbdata->update) {
1692 + aewbdata->h3a_aewb_statistics_buf = NULL;
1695 + if (aewbdata->update & SET_DIGITAL_GAIN)
1696 + h3awb_update.dgain = (u16)aewbdata->dgain;
1697 + if (aewbdata->update & SET_COLOR_GAINS) {
1698 + h3awb_update.coef0 = (u8)aewbdata->wb_gain_gr;
1699 + h3awb_update.coef1 = (u8)aewbdata->wb_gain_r;
1700 + h3awb_update.coef2 = (u8)aewbdata->wb_gain_b;
1701 + h3awb_update.coef3 = (u8)aewbdata->wb_gain_gb;
1703 + if (aewbdata->update & (SET_COLOR_GAINS | SET_DIGITAL_GAIN))
1706 + if (!(aewbdata->update & REQUEST_STATISTICS)) {
1707 + aewbdata->h3a_aewb_statistics_buf = NULL;
1711 + if (aewbdata->frame_number < 1) {
1712 + printk(KERN_ERR "Illeagal frame number "
1713 + "requested (%d)\n",
1714 + aewbdata->frame_number);
1718 + isph3a_aewb_unlock_buffers();
1720 + DPRINTK_ISPH3A("Stats available?\n");
1721 + ret = isph3a_aewb_stats_available(aewbdata);
1725 + DPRINTK_ISPH3A("Stats in near future?\n");
1726 + if (aewbdata->frame_number > frame_cnt)
1727 + frame_diff = aewbdata->frame_number - frame_cnt;
1728 + else if (aewbdata->frame_number < frame_cnt) {
1729 + if ((frame_cnt > (MAX_FRAME_COUNT - MAX_FUTURE_FRAMES)) &&
1730 + (aewbdata->frame_number < MAX_FRAME_COUNT)) {
1731 + frame_diff = aewbdata->frame_number + MAX_FRAME_COUNT -
1734 + frame_diff = MAX_FUTURE_FRAMES + 1;
1737 + if (frame_diff > MAX_FUTURE_FRAMES) {
1738 + printk(KERN_ERR "Invalid frame requested, returning current"
1739 + " frame stats\n");
1740 + aewbdata->frame_number = frame_cnt;
1743 + DPRINTK_ISPH3A("NOT Waiting on stats IRQ for frame %d "
1744 + "because camnotify set\n",
1745 + aewbdata->frame_number);
1746 + aewbdata->h3a_aewb_statistics_buf = NULL;
1749 + DPRINTK_ISPH3A("Waiting on stats IRQ for frame %d\n",
1750 + aewbdata->frame_number);
1751 + aewbstat.frame_req = aewbdata->frame_number;
1752 + aewbstat.stats_req = 1;
1753 + aewbstat.stats_done = 0;
1754 + init_waitqueue_entry(&wqt, current);
1755 + ret = wait_event_interruptible(aewbstat.stats_wait,
1756 + aewbstat.stats_done == 1);
1758 + printk(KERN_ERR "isph3a_aewb_request_statistics"
1759 + " Error on wait event %d\n", ret);
1760 + aewbdata->h3a_aewb_statistics_buf = NULL;
1764 + DPRINTK_ISPH3A("ISP AEWB request status interrupt raised\n");
1765 + ret = isph3a_aewb_stats_available(aewbdata);
1767 + DPRINTK_ISPH3A("After waiting for stats,"
1768 + " stats not available!!\n");
1769 + aewbdata->h3a_aewb_statistics_buf = NULL;
1772 + DPRINTK_ISPH3A("isph3a_aewb_request_statistics: "
1773 + "aewbdata->h3a_aewb_statistics_buf => %p\n",
1774 + aewbdata->h3a_aewb_statistics_buf);
1775 + aewbdata->curr_frame = aewbstat.frame_count;
1779 +EXPORT_SYMBOL(isph3a_aewb_request_statistics);
1782 + * isph3a_aewb_init - Module Initialisation.
1784 + * Always returns 0.
1786 +int __init isph3a_aewb_init(void)
1788 + memset(&aewbstat, 0, sizeof(aewbstat));
1789 + memset(&aewb_regs, 0, sizeof(aewb_regs));
1791 + init_waitqueue_head(&aewbstat.stats_wait);
1792 + spin_lock_init(&aewbstat.buffer_lock);
1797 + * isph3a_aewb_cleanup - Module exit.
1799 +void isph3a_aewb_cleanup(void)
1803 + for (i = 0; i < H3A_MAX_BUFF; i++) {
1804 + if (!aewbstat.h3a_buff[i].phy_addr)
1807 + ispmmu_kunmap(aewbstat.h3a_buff[i].ispmmu_addr);
1808 + dma_free_coherent(NULL,
1809 + aewbstat.min_buf_size,
1810 + (void *)aewbstat.h3a_buff[i].virt_addr,
1811 + (dma_addr_t)aewbstat.h3a_buff[i].phy_addr);
1813 + memset(&aewbstat, 0, sizeof(aewbstat));
1814 + memset(&aewb_regs, 0, sizeof(aewb_regs));
1818 + * isph3a_print_status - Debug print. Values of H3A related registers.
1820 +static void isph3a_print_status(void)
1822 + DPRINTK_ISPH3A("ISPH3A_PCR = 0x%08x\n",
1823 + isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR));
1824 + DPRINTK_ISPH3A("ISPH3A_AEWWIN1 = 0x%08x\n",
1825 + isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1));
1826 + DPRINTK_ISPH3A("ISPH3A_AEWINSTART = 0x%08x\n",
1827 + isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINSTART));
1828 + DPRINTK_ISPH3A("ISPH3A_AEWINBLK = 0x%08x\n",
1829 + isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK));
1830 + DPRINTK_ISPH3A("ISPH3A_AEWSUBWIN = 0x%08x\n",
1831 + isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWSUBWIN));
1832 + DPRINTK_ISPH3A("ISPH3A_AEWBUFST = 0x%08x\n",
1833 + isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST));
1834 + DPRINTK_ISPH3A("stats windows = %d\n", aewbstat.win_count);
1835 + DPRINTK_ISPH3A("stats buff size = %d\n", aewbstat.stats_buf_size);
1836 + DPRINTK_ISPH3A("currently configured stats buff size = %d\n",
1837 + aewbstat.curr_cfg_buf_size);
1841 + * isph3a_notify - Unblocks user request for statistics when camera is off
1842 + * @notify: 1 - Camera is turned off
1844 + * Used when the user has requested statistics about a future frame, but the
1845 + * camera is turned off before it happens, and this function unblocks the
1846 + * request so the user can continue in its program.
1848 +void isph3a_notify(int notify)
1850 + camnotify = notify;
1851 + if (camnotify && aewbstat.initialized) {
1852 + printk(KERN_DEBUG "Warning Camera Off \n");
1853 + aewbstat.stats_req = 0;
1854 + aewbstat.stats_done = 1;
1855 + wake_up_interruptible(&aewbstat.stats_wait);
1858 +EXPORT_SYMBOL(isph3a_notify);
1861 + * isph3a_save_context - Saves the values of the h3a module registers.
1863 +void isph3a_save_context(void)
1865 + DPRINTK_ISPH3A(" Saving context\n");
1866 + isp_save_context(isph3a_reg_list);
1867 + /* Avoid enable during restore ctx */
1868 + isph3a_reg_list[0].val &= ~ISPH3A_PCR_AEW_EN;
1870 +EXPORT_SYMBOL(isph3a_save_context);
1873 + * isph3a_restore_context - Restores the values of the h3a module registers.
1875 +void isph3a_restore_context(void)
1877 + DPRINTK_ISPH3A(" Restoring context\n");
1878 + isp_restore_context(isph3a_reg_list);
1880 +EXPORT_SYMBOL(isph3a_restore_context);
1881 diff --git a/drivers/media/video/isp/isph3a.h b/drivers/media/video/isp/isph3a.h
1882 new file mode 100644
1883 index 0000000..7d4c765
1885 +++ b/drivers/media/video/isp/isph3a.h
1890 + * Include file for H3A module in TI's OMAP3 Camera ISP
1892 + * Copyright (C) 2009 Texas Instruments, Inc.
1895 + * Sergio Aguirre <saaguirre@ti.com>
1898 + * This package is free software; you can redistribute it and/or modify
1899 + * it under the terms of the GNU General Public License version 2 as
1900 + * published by the Free Software Foundation.
1902 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1903 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1904 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1907 +#ifndef OMAP_ISP_H3A_H
1908 +#define OMAP_ISP_H3A_H
1910 +#include <mach/isp_user.h>
1912 +#define AEWB_PACKET_SIZE 16
1913 +#define H3A_MAX_BUFF 5
1915 +/* Flags for changed registers */
1916 +#define PCR_CHNG (1 << 0)
1917 +#define AEWWIN1_CHNG (1 << 1)
1918 +#define AEWINSTART_CHNG (1 << 2)
1919 +#define AEWINBLK_CHNG (1 << 3)
1920 +#define AEWSUBWIN_CHNG (1 << 4)
1921 +#define PRV_WBDGAIN_CHNG (1 << 5)
1922 +#define PRV_WBGAIN_CHNG (1 << 6)
1924 +/* ISPH3A REGISTERS bits */
1925 +#define ISPH3A_PCR_AF_EN (1 << 0)
1926 +#define ISPH3A_PCR_AF_ALAW_EN (1 << 1)
1927 +#define ISPH3A_PCR_AF_MED_EN (1 << 2)
1928 +#define ISPH3A_PCR_AF_BUSY (1 << 15)
1929 +#define ISPH3A_PCR_AEW_EN (1 << 16)
1930 +#define ISPH3A_PCR_AEW_ALAW_EN (1 << 17)
1931 +#define ISPH3A_PCR_AEW_BUSY (1 << 18)
1933 +#define WRITE_SAT_LIM(reg, sat_limit) \
1934 + (reg = (reg & (~(ISPH3A_PCR_AEW_AVE2LMT_MASK))) \
1935 + | (sat_limit << ISPH3A_PCR_AEW_AVE2LMT_SHIFT))
1937 +#define WRITE_ALAW(reg, alaw_en) \
1938 + (reg = (reg & (~(ISPH3A_PCR_AEW_ALAW_EN))) \
1939 + | ((alaw_en & ISPH3A_PCR_AF_ALAW_EN) \
1940 + << ISPH3A_PCR_AEW_ALAW_EN_SHIFT))
1942 +#define WRITE_WIN_H(reg, height) \
1943 + (reg = (reg & (~(ISPH3A_AEWWIN1_WINH_MASK))) \
1944 + | (((height >> 1) - 1) << ISPH3A_AEWWIN1_WINH_SHIFT))
1946 +#define WRITE_WIN_W(reg, width) \
1947 + (reg = (reg & (~(ISPH3A_AEWWIN1_WINW_MASK))) \
1948 + | (((width >> 1) - 1) << ISPH3A_AEWWIN1_WINW_SHIFT))
1950 +#define WRITE_VER_C(reg, ver_count) \
1951 + (reg = (reg & ~(ISPH3A_AEWWIN1_WINVC_MASK)) \
1952 + | ((ver_count - 1) << ISPH3A_AEWWIN1_WINVC_SHIFT))
1954 +#define WRITE_HOR_C(reg, hor_count) \
1955 + (reg = (reg & ~(ISPH3A_AEWWIN1_WINHC_MASK)) \
1956 + | ((hor_count - 1) << ISPH3A_AEWWIN1_WINHC_SHIFT))
1958 +#define WRITE_VER_WIN_ST(reg, ver_win_st) \
1959 + (reg = (reg & ~(ISPH3A_AEWINSTART_WINSV_MASK)) \
1960 + | (ver_win_st << ISPH3A_AEWINSTART_WINSV_SHIFT))
1962 +#define WRITE_HOR_WIN_ST(reg, hor_win_st) \
1963 + (reg = (reg & ~(ISPH3A_AEWINSTART_WINSH_MASK)) \
1964 + | (hor_win_st << ISPH3A_AEWINSTART_WINSH_SHIFT))
1966 +#define WRITE_BLK_VER_WIN_ST(reg, blk_win_st) \
1967 + (reg = (reg & ~(ISPH3A_AEWINBLK_WINSV_MASK)) \
1968 + | (blk_win_st << ISPH3A_AEWINBLK_WINSV_SHIFT))
1970 +#define WRITE_BLK_WIN_H(reg, height) \
1971 + (reg = (reg & ~(ISPH3A_AEWINBLK_WINH_MASK)) \
1972 + | (((height >> 1) - 1) << ISPH3A_AEWINBLK_WINH_SHIFT))
1974 +#define WRITE_SUB_VER_INC(reg, sub_ver_inc) \
1975 + (reg = (reg & ~(ISPH3A_AEWSUBWIN_AEWINCV_MASK)) \
1976 + | (((sub_ver_inc >> 1) - 1) << ISPH3A_AEWSUBWIN_AEWINCV_SHIFT))
1978 +#define WRITE_SUB_HOR_INC(reg, sub_hor_inc) \
1979 + (reg = (reg & ~(ISPH3A_AEWSUBWIN_AEWINCH_MASK)) \
1980 + | (((sub_hor_inc >> 1) - 1) << ISPH3A_AEWSUBWIN_AEWINCH_SHIFT))
1983 + * struct isph3a_aewb_xtrastats - Structure with extra statistics sent by cam.
1984 + * @field_count: Sequence number of returned framestats.
1985 + * @isph3a_aewb_xtrastats: Pointer to next buffer with extra stats.
1987 +struct isph3a_aewb_xtrastats {
1988 + unsigned long field_count;
1989 + struct isph3a_aewb_xtrastats *next;
1992 +void isph3a_aewb_setxtrastats(struct isph3a_aewb_xtrastats *xtrastats);
1994 +int isph3a_aewb_configure(struct isph3a_aewb_config *aewbcfg);
1996 +int isph3a_aewb_request_statistics(struct isph3a_aewb_data *aewbdata);
1998 +void isph3a_save_context(void);
2000 +void isph3a_restore_context(void);
2002 +void isph3a_aewb_enable(u8 enable);
2004 +int isph3a_aewb_busy(void);
2006 +void isph3a_aewb_suspend(void);
2008 +void isph3a_aewb_resume(void);
2010 +void isph3a_update_wb(void);
2012 +void isph3a_notify(int notify);
2013 +#endif /* OMAP_ISP_H3A_H */
2014 diff --git a/drivers/media/video/isp/isphist.c b/drivers/media/video/isp/isphist.c
2015 new file mode 100644
2016 index 0000000..c6f6a77
2018 +++ b/drivers/media/video/isp/isphist.c
2023 + * HISTOGRAM module for TI's OMAP3 Camera ISP
2025 + * Copyright (C) 2009 Texas Instruments, Inc.
2028 + * Sergio Aguirre <saaguirre@ti.com>
2031 + * This package is free software; you can redistribute it and/or modify
2032 + * it under the terms of the GNU General Public License version 2 as
2033 + * published by the Free Software Foundation.
2035 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
2036 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
2037 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2040 +#include <asm/cacheflush.h>
2042 +#include <linux/delay.h>
2043 +#include <linux/dma-mapping.h>
2044 +#include <linux/uaccess.h>
2047 +#include "ispreg.h"
2048 +#include "isphist.h"
2049 +#include "ispmmu.h"
2052 + * struct isp_hist_status - Histogram status.
2053 + * @hist_enable: Enables the histogram module.
2054 + * @initialized: Flag to indicate that the module is correctly initializated.
2055 + * @frame_cnt: Actual frame count.
2056 + * @frame_req: Frame requested by user.
2057 + * @completed: Flag to indicate if a frame request is completed.
2059 +struct isp_hist_status {
2069 + * struct isp_hist_buffer - Frame histogram buffer.
2070 + * @virt_addr: Virtual address to mmap the buffer.
2071 + * @phy_addr: Physical address of the buffer.
2072 + * @addr_align: Virtual Address 32 bytes aligned.
2073 + * @ispmmu_addr: Address of the buffer mapped by the ISPMMU.
2074 + * @mmap_addr: Mapped memory area of buffer. For userspace access.
2076 +struct isp_hist_buffer {
2077 + unsigned long virt_addr;
2078 + unsigned long phy_addr;
2079 + unsigned long addr_align;
2080 + unsigned long ispmmu_addr;
2081 + unsigned long mmap_addr;
2085 + * struct isp_hist_regs - Current value of Histogram configuration registers.
2086 + * @reg_pcr: Peripheral control register.
2087 + * @reg_cnt: Histogram control register.
2088 + * @reg_wb_gain: Histogram white balance gain register.
2089 + * @reg_r0_h: Region 0 horizontal register.
2090 + * @reg_r0_v: Region 0 vertical register.
2091 + * @reg_r1_h: Region 1 horizontal register.
2092 + * @reg_r1_v: Region 1 vertical register.
2093 + * @reg_r2_h: Region 2 horizontal register.
2094 + * @reg_r2_v: Region 2 vertical register.
2095 + * @reg_r3_h: Region 3 horizontal register.
2096 + * @reg_r3_v: Region 3 vertical register.
2097 + * @reg_hist_addr: Histogram address register.
2098 + * @reg_hist_data: Histogram data.
2099 + * @reg_hist_radd: Address register. When input data comes from mem.
2100 + * @reg_hist_radd_off: Address offset register. When input data comes from mem.
2101 + * @reg_h_v_info: Image size register. When input data comes from mem.
2103 +static struct isp_hist_regs {
2115 + u32 reg_hist_addr;
2116 + u32 reg_hist_data;
2117 + u32 reg_hist_radd;
2118 + u32 reg_hist_radd_off;
2122 +/* Structure for saving/restoring histogram module registers */
2123 +struct isp_reg isphist_reg_list[] = {
2124 + {OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, 0},
2125 + {OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN, 0},
2126 + {OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ, 0},
2127 + {OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT, 0},
2128 + {OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ, 0},
2129 + {OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT, 0},
2130 + {OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ, 0},
2131 + {OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT, 0},
2132 + {OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ, 0},
2133 + {OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT, 0},
2134 + {OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR, 0},
2135 + {OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD, 0},
2136 + {OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD_OFF, 0},
2137 + {OMAP3_ISP_IOMEM_HIST, ISPHIST_H_V_INFO, 0},
2138 + {0, ISP_TOK_TERM, 0}
2141 +static void isp_hist_print_status(void);
2143 +void __isp_hist_enable(u8 enable)
2146 + DPRINTK_ISPHIST(" histogram enabled \n");
2148 + DPRINTK_ISPHIST(" histogram disabled \n");
2150 + isp_reg_and_or(OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR, ~ISPHIST_PCR_EN,
2151 + (enable ? ISPHIST_PCR_EN : 0));
2152 + histstat.hist_enable = enable;
2156 + * isp_hist_enable - Enables ISP Histogram submodule operation.
2157 + * @enable: 1 - Enables the histogram submodule.
2159 + * Client should configure all the Histogram registers before calling this
2162 +void isp_hist_enable(u8 enable)
2164 + __isp_hist_enable(enable);
2165 + histstat.pm_state = enable;
2169 + * isp_hist_suspend - Suspend ISP Histogram submodule.
2171 +void isp_hist_suspend(void)
2173 + if (histstat.pm_state)
2174 + __isp_hist_enable(0);
2178 + * isp_hist_resume - Resume ISP Histogram submodule.
2180 +void isp_hist_resume(void)
2182 + if (histstat.pm_state)
2183 + __isp_hist_enable(1);
2186 +int isp_hist_busy(void)
2188 + return isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR) &
2194 + * isp_hist_update_regs - Helper function to update Histogram registers.
2196 +static void isp_hist_update_regs(void)
2198 + isp_reg_writel(hist_regs.reg_pcr, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR);
2199 + isp_reg_writel(hist_regs.reg_cnt, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT);
2200 + isp_reg_writel(hist_regs.reg_wb_gain, OMAP3_ISP_IOMEM_HIST,
2202 + isp_reg_writel(hist_regs.reg_r0_h, OMAP3_ISP_IOMEM_HIST,
2204 + isp_reg_writel(hist_regs.reg_r0_v, OMAP3_ISP_IOMEM_HIST,
2206 + isp_reg_writel(hist_regs.reg_r1_h, OMAP3_ISP_IOMEM_HIST,
2208 + isp_reg_writel(hist_regs.reg_r1_v, OMAP3_ISP_IOMEM_HIST,
2210 + isp_reg_writel(hist_regs.reg_r2_h, OMAP3_ISP_IOMEM_HIST,
2212 + isp_reg_writel(hist_regs.reg_r2_v, OMAP3_ISP_IOMEM_HIST,
2214 + isp_reg_writel(hist_regs.reg_r3_h, OMAP3_ISP_IOMEM_HIST,
2216 + isp_reg_writel(hist_regs.reg_r3_v, OMAP3_ISP_IOMEM_HIST,
2218 + isp_reg_writel(hist_regs.reg_hist_addr, OMAP3_ISP_IOMEM_HIST,
2220 + isp_reg_writel(hist_regs.reg_hist_data, OMAP3_ISP_IOMEM_HIST,
2222 + isp_reg_writel(hist_regs.reg_hist_radd, OMAP3_ISP_IOMEM_HIST,
2224 + isp_reg_writel(hist_regs.reg_hist_radd_off, OMAP3_ISP_IOMEM_HIST,
2225 + ISPHIST_RADD_OFF);
2226 + isp_reg_writel(hist_regs.reg_h_v_info, OMAP3_ISP_IOMEM_HIST,
2227 + ISPHIST_H_V_INFO);
2231 + * isp_hist_isr - Callback from ISP driver for HIST interrupt.
2232 + * @status: IRQ0STATUS in case of MMU error, 0 for hist interrupt.
2233 + * arg1 and arg2 Not used as of now.
2235 +static void isp_hist_isr(unsigned long status, isp_vbq_callback_ptr arg1,
2238 + isp_hist_enable(0);
2240 + if (!(status & HIST_DONE))
2243 + if (!histstat.completed) {
2244 + if (histstat.frame_req == histstat.frame_cnt) {
2245 + histstat.frame_cnt = 0;
2246 + histstat.frame_req = 0;
2247 + histstat.completed = 1;
2249 + isp_hist_enable(1);
2250 + histstat.frame_cnt++;
2256 + * isp_hist_reset_mem - clear Histogram memory before start stats engine.
2258 + * Returns 0 after histogram memory was cleared.
2260 +static int isp_hist_reset_mem(void)
2264 + isp_reg_or(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLR_EN);
2266 + for (i = 0; i < HIST_MEM_SIZE; i++)
2267 + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
2269 + isp_reg_and(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ~ISPHIST_CNT_CLR_EN);
2275 + * isp_hist_set_params - Helper function to check and store user given params.
2276 + * @user_cfg: Pointer to user configuration structure.
2278 + * Returns 0 on success configuration.
2280 +static int isp_hist_set_params(struct isp_hist_config *user_cfg)
2284 + int bit_shift = 0;
2287 + if (isp_hist_busy())
2290 + if (user_cfg->input_bit_width > MIN_BIT_WIDTH)
2291 + WRITE_DATA_SIZE(hist_regs.reg_cnt, 0);
2293 + WRITE_DATA_SIZE(hist_regs.reg_cnt, 1);
2295 + WRITE_SOURCE(hist_regs.reg_cnt, user_cfg->hist_source);
2297 + if (user_cfg->hist_source) {
2298 + WRITE_HV_INFO(hist_regs.reg_h_v_info, user_cfg->hist_h_v_info);
2300 + if ((user_cfg->hist_radd & ISP_32B_BOUNDARY_BUF) ==
2301 + user_cfg->hist_radd) {
2302 + WRITE_RADD(hist_regs.reg_hist_radd,
2303 + user_cfg->hist_radd);
2305 + printk(KERN_ERR "Address should be in 32 byte boundary"
2310 + if ((user_cfg->hist_radd_off & ISP_32B_BOUNDARY_OFFSET) ==
2311 + user_cfg->hist_radd_off) {
2312 + WRITE_RADD_OFF(hist_regs.reg_hist_radd_off,
2313 + user_cfg->hist_radd_off);
2315 + printk(KERN_ERR "Offset should be in 32 byte boundary"
2322 + isp_hist_reset_mem();
2323 + DPRINTK_ISPHIST("ISPHIST: Memory Cleared\n");
2324 + histstat.frame_req = user_cfg->hist_frames;
2326 + if (unlikely(user_cfg->wb_gain_R > MAX_WB_GAIN ||
2327 + user_cfg->wb_gain_RG > MAX_WB_GAIN ||
2328 + user_cfg->wb_gain_B > MAX_WB_GAIN ||
2329 + user_cfg->wb_gain_BG > MAX_WB_GAIN)) {
2330 + printk(KERN_ERR "Invalid WB gain\n");
2333 + WRITE_WB_R(hist_regs.reg_wb_gain, user_cfg->wb_gain_R);
2334 + WRITE_WB_RG(hist_regs.reg_wb_gain, user_cfg->wb_gain_RG);
2335 + WRITE_WB_B(hist_regs.reg_wb_gain, user_cfg->wb_gain_B);
2336 + WRITE_WB_BG(hist_regs.reg_wb_gain, user_cfg->wb_gain_BG);
2339 + /* Regions size and position */
2341 + if (user_cfg->num_regions > MAX_REGIONS)
2344 + if (likely((user_cfg->reg0_hor & ISPHIST_REGHORIZ_HEND_MASK) -
2345 + ((user_cfg->reg0_hor & ISPHIST_REGHORIZ_HSTART_MASK) >>
2346 + ISPHIST_REGHORIZ_HSTART_SHIFT))) {
2347 + WRITE_REG_HORIZ(hist_regs.reg_r0_h, user_cfg->reg0_hor);
2350 + printk(KERN_ERR "Invalid Region parameters\n");
2354 + if (likely((user_cfg->reg0_ver & ISPHIST_REGVERT_VEND_MASK) -
2355 + ((user_cfg->reg0_ver & ISPHIST_REGVERT_VSTART_MASK) >>
2356 + ISPHIST_REGVERT_VSTART_SHIFT))) {
2357 + WRITE_REG_VERT(hist_regs.reg_r0_v, user_cfg->reg0_ver);
2359 + printk(KERN_ERR "Invalid Region parameters\n");
2363 + if (user_cfg->num_regions >= 1) {
2364 + if (likely((user_cfg->reg1_hor & ISPHIST_REGHORIZ_HEND_MASK) -
2365 + ((user_cfg->reg1_hor &
2366 + ISPHIST_REGHORIZ_HSTART_MASK) >>
2367 + ISPHIST_REGHORIZ_HSTART_SHIFT))) {
2368 + WRITE_REG_HORIZ(hist_regs.reg_r1_h, user_cfg->reg1_hor);
2370 + printk(KERN_ERR "Invalid Region parameters\n");
2374 + if (likely((user_cfg->reg1_ver & ISPHIST_REGVERT_VEND_MASK) -
2375 + ((user_cfg->reg1_ver &
2376 + ISPHIST_REGVERT_VSTART_MASK) >>
2377 + ISPHIST_REGVERT_VSTART_SHIFT))) {
2378 + WRITE_REG_VERT(hist_regs.reg_r1_v, user_cfg->reg1_ver);
2380 + printk(KERN_ERR "Invalid Region parameters\n");
2385 + if (user_cfg->num_regions >= 2) {
2386 + if (likely((user_cfg->reg2_hor & ISPHIST_REGHORIZ_HEND_MASK) -
2387 + ((user_cfg->reg2_hor &
2388 + ISPHIST_REGHORIZ_HSTART_MASK) >>
2389 + ISPHIST_REGHORIZ_HSTART_SHIFT))) {
2390 + WRITE_REG_HORIZ(hist_regs.reg_r2_h, user_cfg->reg2_hor);
2392 + printk(KERN_ERR "Invalid Region parameters\n");
2396 + if (likely((user_cfg->reg2_ver & ISPHIST_REGVERT_VEND_MASK) -
2397 + ((user_cfg->reg2_ver &
2398 + ISPHIST_REGVERT_VSTART_MASK) >>
2399 + ISPHIST_REGVERT_VSTART_SHIFT))) {
2400 + WRITE_REG_VERT(hist_regs.reg_r2_v, user_cfg->reg2_ver);
2402 + printk(KERN_ERR "Invalid Region parameters\n");
2407 + if (user_cfg->num_regions >= 3) {
2408 + if (likely((user_cfg->reg3_hor & ISPHIST_REGHORIZ_HEND_MASK) -
2409 + ((user_cfg->reg3_hor &
2410 + ISPHIST_REGHORIZ_HSTART_MASK) >>
2411 + ISPHIST_REGHORIZ_HSTART_SHIFT))) {
2412 + WRITE_REG_HORIZ(hist_regs.reg_r3_h, user_cfg->reg3_hor);
2414 + printk(KERN_ERR "Invalid Region parameters\n");
2418 + if (likely((user_cfg->reg3_ver & ISPHIST_REGVERT_VEND_MASK) -
2419 + ((user_cfg->reg3_ver &
2420 + ISPHIST_REGVERT_VSTART_MASK) >>
2421 + ISPHIST_REGVERT_VSTART_SHIFT))) {
2422 + WRITE_REG_VERT(hist_regs.reg_r3_v, user_cfg->reg3_ver);
2424 + printk(KERN_ERR "Invalid Region parameters\n");
2428 + reg_num = user_cfg->num_regions;
2429 + if (unlikely(((user_cfg->hist_bins > BINS_256) &&
2430 + (user_cfg->hist_bins != BINS_32)) ||
2431 + ((user_cfg->hist_bins == BINS_256) &&
2432 + reg_num != 0) || ((user_cfg->hist_bins ==
2433 + BINS_128) && reg_num >= 2))) {
2434 + printk(KERN_ERR "Invalid Bins Number: %d\n",
2435 + user_cfg->hist_bins);
2438 + WRITE_NUM_BINS(hist_regs.reg_cnt, user_cfg->hist_bins);
2441 + if (user_cfg->input_bit_width > MAX_BIT_WIDTH ||
2442 + user_cfg->input_bit_width < MIN_BIT_WIDTH) {
2443 + printk(KERN_ERR "Invalid Bit Width: %d\n",
2444 + user_cfg->input_bit_width);
2447 + switch (user_cfg->hist_bins) {
2449 + bit_shift = user_cfg->input_bit_width - 8;
2452 + bit_shift = user_cfg->input_bit_width - 7;
2455 + bit_shift = user_cfg->input_bit_width - 6;
2458 + bit_shift = user_cfg->input_bit_width - 5;
2463 + WRITE_BIT_SHIFT(hist_regs.reg_cnt, bit_shift);
2466 + isp_hist_update_regs();
2467 + histstat.initialized = 1;
2473 + * isp_hist_configure - API to configure HIST registers.
2474 + * @histcfg: Pointer to user configuration structure.
2476 + * Returns 0 on success configuration.
2478 +int isp_hist_configure(struct isp_hist_config *histcfg)
2483 + if (NULL == histcfg) {
2484 + printk(KERN_ERR "Null argument in configuration. \n");
2488 + if (!histstat.initialized) {
2489 + DPRINTK_ISPHIST("Setting callback for HISTOGRAM\n");
2490 + ret = isp_set_callback(CBK_HIST_DONE, isp_hist_isr,
2491 + (void *)NULL, (void *)NULL);
2493 + printk(KERN_ERR "No callback for HIST\n");
2498 + ret = isp_hist_set_params(histcfg);
2500 + printk(KERN_ERR "Invalid parameters! \n");
2504 + histstat.frame_cnt = 0;
2505 + histstat.completed = 0;
2506 + isp_hist_enable(1);
2507 + isp_hist_print_status();
2511 +EXPORT_SYMBOL(isp_hist_configure);
2514 + * isp_hist_request_statistics - Request statistics in Histogram.
2515 + * @histdata: Pointer to data structure.
2517 + * This API allows the user to request for histogram statistics.
2519 + * Returns 0 on successful request.
2521 +int isp_hist_request_statistics(struct isp_hist_data *histdata)
2526 + if (isp_hist_busy())
2529 + if (!histstat.completed && histstat.initialized)
2532 + isp_reg_or(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLR_EN);
2534 + for (i = 0; i < HIST_MEM_SIZE; i++) {
2535 + curr = isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
2536 + ret = put_user(curr, histdata->hist_statistics_buf + i);
2538 + printk(KERN_ERR "Failed copy_to_user for "
2539 + "HIST stats buff, %d\n", ret);
2543 + isp_reg_and(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
2544 + ~ISPHIST_CNT_CLR_EN);
2545 + histstat.completed = 0;
2548 +EXPORT_SYMBOL(isp_hist_request_statistics);
2551 + * isp_hist_init - Module Initialization.
2553 + * Returns 0 if successful.
2555 +int __init isp_hist_init(void)
2557 + memset(&histstat, 0, sizeof(histstat));
2558 + memset(&hist_regs, 0, sizeof(hist_regs));
2564 + * isp_hist_cleanup - Module cleanup.
2566 +void isp_hist_cleanup(void)
2568 + memset(&histstat, 0, sizeof(histstat));
2569 + memset(&hist_regs, 0, sizeof(hist_regs));
2573 + * isphist_save_context - Saves the values of the histogram module registers.
2575 +void isphist_save_context(void)
2577 + DPRINTK_ISPHIST(" Saving context\n");
2578 + isp_save_context(isphist_reg_list);
2580 +EXPORT_SYMBOL(isphist_save_context);
2583 + * isphist_restore_context - Restores the values of the histogram module regs.
2585 +void isphist_restore_context(void)
2587 + DPRINTK_ISPHIST(" Restoring context\n");
2588 + isp_restore_context(isphist_reg_list);
2590 +EXPORT_SYMBOL(isphist_restore_context);
2593 + * isp_hist_print_status - Debug print
2595 +static void isp_hist_print_status(void)
2597 + DPRINTK_ISPHIST("ISPHIST_PCR = 0x%08x\n",
2598 + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR));
2599 + DPRINTK_ISPHIST("ISPHIST_CNT = 0x%08x\n",
2600 + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT));
2601 + DPRINTK_ISPHIST("ISPHIST_WB_GAIN = 0x%08x\n",
2602 + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN));
2603 + DPRINTK_ISPHIST("ISPHIST_R0_HORZ = 0x%08x\n",
2604 + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ));
2605 + DPRINTK_ISPHIST("ISPHIST_R0_VERT = 0x%08x\n",
2606 + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT));
2607 + DPRINTK_ISPHIST("ISPHIST_R1_HORZ = 0x%08x\n",
2608 + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ));
2609 + DPRINTK_ISPHIST("ISPHIST_R1_VERT = 0x%08x\n",
2610 + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT));
2611 + DPRINTK_ISPHIST("ISPHIST_R2_HORZ = 0x%08x\n",
2612 + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ));
2613 + DPRINTK_ISPHIST("ISPHIST_R2_VERT = 0x%08x\n",
2614 + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT));
2615 + DPRINTK_ISPHIST("ISPHIST_R3_HORZ = 0x%08x\n",
2616 + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ));
2617 + DPRINTK_ISPHIST("ISPHIST_R3_VERT = 0x%08x\n",
2618 + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT));
2619 + DPRINTK_ISPHIST("ISPHIST_ADDR = 0x%08x\n",
2620 + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR));
2621 + DPRINTK_ISPHIST("ISPHIST_RADD = 0x%08x\n",
2622 + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD));
2623 + DPRINTK_ISPHIST("ISPHIST_RADD_OFF = 0x%08x\n",
2624 + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD_OFF));
2625 + DPRINTK_ISPHIST("ISPHIST_H_V_INFO = 0x%08x\n",
2626 + isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_H_V_INFO));
2628 diff --git a/drivers/media/video/isp/isphist.h b/drivers/media/video/isp/isphist.h
2629 new file mode 100644
2630 index 0000000..6b17c4e
2632 +++ b/drivers/media/video/isp/isphist.h
2637 + * Header file for HISTOGRAM module in TI's OMAP3 Camera ISP
2639 + * Copyright (C) 2009 Texas Instruments, Inc.
2642 + * Sergio Aguirre <saaguirre@ti.com>
2645 + * This package is free software; you can redistribute it and/or modify
2646 + * it under the terms of the GNU General Public License version 2 as
2647 + * published by the Free Software Foundation.
2649 + * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
2650 + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
2651 + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
2654 +#ifndef OMAP_ISP_HIST_H
2655 +#define OMAP_ISP_HIST_H
2657 +#include <mach/isp_user.h>
2659 +#define MAX_REGIONS 0x4
2660 +#define MAX_WB_GAIN 255
2661 +#define MIN_WB_GAIN 0x0
2662 +#define MAX_BIT_WIDTH 14
2663 +#define MIN_BIT_WIDTH 8
2665 +#define ISPHIST_PCR_EN (1 << 0)
2666 +#define HIST_MEM_SIZE 1024
2667 +#define ISPHIST_CNT_CLR_EN (1 << 7)
2669 +#define WRITE_SOURCE(reg, source) \
2670 + (reg = (reg & ~(ISPHIST_CNT_SOURCE_MASK)) \
2671 + | (source << ISPHIST_CNT_SOURCE_SHIFT))
2673 +#define WRITE_HV_INFO(reg, hv_info) \
2674 + (reg = ((reg & ~(ISPHIST_HV_INFO_MASK)) \
2675 + | (hv_info & ISPHIST_HV_INFO_MASK)))
2677 +#define WRITE_RADD(reg, radd) \
2678 + (reg = (reg & ~(ISPHIST_RADD_MASK)) \
2679 + | (radd << ISPHIST_RADD_SHIFT))
2681 +#define WRITE_RADD_OFF(reg, radd_off) \
2682 + (reg = (reg & ~(ISPHIST_RADD_OFF_MASK)) \
2683 + | (radd_off << ISPHIST_RADD_OFF_SHIFT))
2685 +#define WRITE_BIT_SHIFT(reg, bit_shift) \
2686 + (reg = (reg & ~(ISPHIST_CNT_SHIFT_MASK)) \
2687 + | (bit_shift << ISPHIST_CNT_SHIFT_SHIFT))
2689 +#define WRITE_DATA_SIZE(reg, data_size) \
2690 + (reg = (reg & ~(ISPHIST_CNT_DATASIZE_MASK)) \
2691 + | (data_size << ISPHIST_CNT_DATASIZE_SHIFT))
2693 +#define WRITE_NUM_BINS(reg, num_bins) \
2694 + (reg = (reg & ~(ISPHIST_CNT_BINS_MASK)) \
2695 + | (num_bins << ISPHIST_CNT_BINS_SHIFT))
2697 +#define WRITE_WB_R(reg, reg_wb_gain) \
2698 + reg = ((reg & ~(ISPHIST_WB_GAIN_WG00_MASK)) \
2699 + | (reg_wb_gain << ISPHIST_WB_GAIN_WG00_SHIFT))
2701 +#define WRITE_WB_RG(reg, reg_wb_gain) \
2702 + (reg = (reg & ~(ISPHIST_WB_GAIN_WG01_MASK)) \
2703 + | (reg_wb_gain << ISPHIST_WB_GAIN_WG01_SHIFT))
2705 +#define WRITE_WB_B(reg, reg_wb_gain) \
2706 + (reg = (reg & ~(ISPHIST_WB_GAIN_WG02_MASK)) \
2707 + | (reg_wb_gain << ISPHIST_WB_GAIN_WG02_SHIFT))
2709 +#define WRITE_WB_BG(reg, reg_wb_gain) \
2710 + (reg = (reg & ~(ISPHIST_WB_GAIN_WG03_MASK)) \
2711 + | (reg_wb_gain << ISPHIST_WB_GAIN_WG03_SHIFT))
2713 +#define WRITE_REG_HORIZ(reg, reg_n_hor) \
2714 + (reg = ((reg & ~ISPHIST_REGHORIZ_MASK) \
2715 + | (reg_n_hor & ISPHIST_REGHORIZ_MASK)))
2717 +#define WRITE_REG_VERT(reg, reg_n_vert) \
2718 + (reg = ((reg & ~ISPHIST_REGVERT_MASK) \
2719 + | (reg_n_vert & ISPHIST_REGVERT_MASK)))
2722 +void isp_hist_enable(u8 enable);
2724 +int isp_hist_busy(void);
2726 +int isp_hist_configure(struct isp_hist_config *histcfg);
2728 +int isp_hist_request_statistics(struct isp_hist_data *histdata);
2730 +void isphist_save_context(void);
2732 +void isp_hist_suspend(void);
2734 +void isp_hist_resume(void);
2736 +void isphist_restore_context(void);
2738 +#endif /* OMAP_ISP_HIST */