diff options
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap-2.6.29/isp/omap3camera/0006-omap3isp-Add-statistics-collection-modules-H3A-and.patch')
-rw-r--r-- | meta/recipes-kernel/linux/linux-omap-2.6.29/isp/omap3camera/0006-omap3isp-Add-statistics-collection-modules-H3A-and.patch | 2741 |
1 files changed, 0 insertions, 2741 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap-2.6.29/isp/omap3camera/0006-omap3isp-Add-statistics-collection-modules-H3A-and.patch b/meta/recipes-kernel/linux/linux-omap-2.6.29/isp/omap3camera/0006-omap3isp-Add-statistics-collection-modules-H3A-and.patch deleted file mode 100644 index 876ce780f..000000000 --- a/meta/recipes-kernel/linux/linux-omap-2.6.29/isp/omap3camera/0006-omap3isp-Add-statistics-collection-modules-H3A-and.patch +++ /dev/null @@ -1,2741 +0,0 @@ -From 9a39eab5ed1b70711c3b10de95cd90749293ef7a Mon Sep 17 00:00:00 2001 -From: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> -Date: Tue, 10 Mar 2009 10:49:02 +0200 -Subject: [PATCH] omap3isp: Add statistics collection modules (H3A and HIST) - -Signed-off-by: Sakari Ailus <sakari.ailus@maxwell.research.nokia.com> ---- - drivers/media/video/isp/isp_af.c | 784 +++++++++++++++++++++++++++++++ - drivers/media/video/isp/isp_af.h | 125 +++++ - drivers/media/video/isp/isph3a.c | 932 +++++++++++++++++++++++++++++++++++++ - drivers/media/video/isp/isph3a.h | 127 +++++ - drivers/media/video/isp/isphist.c | 608 ++++++++++++++++++++++++ - drivers/media/video/isp/isphist.h | 105 +++++ - 6 files changed, 2681 insertions(+), 0 deletions(-) - create mode 100644 drivers/media/video/isp/isp_af.c - create mode 100644 drivers/media/video/isp/isp_af.h - create mode 100644 drivers/media/video/isp/isph3a.c - create mode 100644 drivers/media/video/isp/isph3a.h - create mode 100644 drivers/media/video/isp/isphist.c - create mode 100644 drivers/media/video/isp/isphist.h - -diff --git a/drivers/media/video/isp/isp_af.c b/drivers/media/video/isp/isp_af.c -new file mode 100644 -index 0000000..a607b97 ---- /dev/null -+++ b/drivers/media/video/isp/isp_af.c -@@ -0,0 +1,784 @@ -+/* -+ * isp_af.c -+ * -+ * AF module for TI's OMAP3 Camera ISP -+ * -+ * Copyright (C) 2009 Texas Instruments, Inc. -+ * -+ * Contributors: -+ * Sergio Aguirre <saaguirre@ti.com> -+ * Troy Laramy -+ * -+ * This package is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. -+ */ -+ -+/* Linux specific include files */ -+#include <asm/cacheflush.h> -+ -+#include <linux/uaccess.h> -+#include <linux/dma-mapping.h> -+#include <asm/atomic.h> -+ -+#include "isp.h" -+#include "ispreg.h" -+#include "isph3a.h" -+#include "isp_af.h" -+#include "ispmmu.h" -+ -+/** -+ * struct isp_af_buffer - AF frame stats buffer. -+ * @virt_addr: Virtual address to mmap the buffer. -+ * @phy_addr: Physical address of the buffer. -+ * @addr_align: Virtual Address 32 bytes aligned. -+ * @ispmmu_addr: Address of the buffer mapped by the ISPMMU. -+ * @mmap_addr: Mapped memory area of buffer. For userspace access. -+ * @locked: 1 - Buffer locked from write. 0 - Buffer can be overwritten. -+ * @frame_num: Frame number from which the statistics are taken. -+ * @lens_position: Lens position currently set in the DW9710 Coil motor driver. -+ * @next: Pointer to link next buffer. -+ */ -+struct isp_af_buffer { -+ unsigned long virt_addr; -+ unsigned long phy_addr; -+ unsigned long addr_align; -+ unsigned long ispmmu_addr; -+ unsigned long mmap_addr; -+ -+ u8 locked; -+ u16 frame_num; -+ u32 config_counter; -+ struct isp_af_xtrastats xtrastats; -+ struct isp_af_buffer *next; -+}; -+ -+/** -+ * struct isp_af_status - AF status. -+ * @initialized: 1 - Buffers initialized. -+ * @update: 1 - Update registers. -+ * @stats_req: 1 - Future stats requested. -+ * @stats_done: 1 - Stats ready for user. -+ * @frame_req: Number of frame requested for statistics. -+ * @af_buff: Array of statistics buffers to access. -+ * @stats_buf_size: Statistics buffer size. -+ * @curr_cfg_buf_size: Current user configured stats buff size. -+ * @min_buf_size: Minimum statisitics buffer size. -+ * @frame_count: Frame Count. -+ * @stats_wait: Wait primitive for locking/unlocking the stats request. -+ * @buffer_lock: Spinlock for statistics buffers access. -+ */ -+static struct isp_af_status { -+ u8 initialized; -+ u8 update; -+ u8 stats_req; -+ u8 stats_done; -+ u16 frame_req; -+ -+ struct isp_af_buffer af_buff[H3A_MAX_BUFF]; -+ unsigned int stats_buf_size; -+ unsigned int min_buf_size; -+ unsigned int curr_cfg_buf_size; -+ -+ int pm_state; -+ u32 frame_count; -+ wait_queue_head_t stats_wait; -+ atomic_t config_counter; -+ spinlock_t buffer_lock; /* For stats buffers read/write sync */ -+} afstat; -+ -+struct af_device *af_dev_configptr; -+static struct isp_af_buffer *active_buff; -+static int af_major = -1; -+static int camnotify; -+ -+/** -+ * isp_af_setxtrastats - Receives extra statistics from prior frames. -+ * @xtrastats: Pointer to structure containing extra statistics fields like -+ * field count and timestamp of frame. -+ * -+ * Called from update_vbq in camera driver -+ **/ -+void isp_af_setxtrastats(struct isp_af_xtrastats *xtrastats, u8 updateflag) -+{ -+ int i, past_i; -+ -+ if (active_buff == NULL) -+ return; -+ -+ for (i = 0; i < H3A_MAX_BUFF; i++) { -+ if (afstat.af_buff[i].frame_num == active_buff->frame_num) -+ break; -+ } -+ -+ if (i == H3A_MAX_BUFF) -+ return; -+ -+ if (i == 0) { -+ if (afstat.af_buff[H3A_MAX_BUFF - 1].locked == 0) -+ past_i = H3A_MAX_BUFF - 1; -+ else -+ past_i = H3A_MAX_BUFF - 2; -+ } else if (i == 1) { -+ if (afstat.af_buff[0].locked == 0) -+ past_i = 0; -+ else -+ past_i = H3A_MAX_BUFF - 1; -+ } else { -+ if (afstat.af_buff[i - 1].locked == 0) -+ past_i = i - 1; -+ else -+ past_i = i - 2; -+ } -+ -+ if (updateflag & AF_UPDATEXS_TS) -+ afstat.af_buff[past_i].xtrastats.ts = xtrastats->ts; -+ -+ if (updateflag & AF_UPDATEXS_FIELDCOUNT) -+ afstat.af_buff[past_i].xtrastats.field_count = -+ xtrastats->field_count; -+} -+EXPORT_SYMBOL(isp_af_setxtrastats); -+ -+/* -+ * Helper function to update buffer cache pages -+ */ -+static void isp_af_update_req_buffer(struct isp_af_buffer *buffer) -+{ -+ int size = afstat.stats_buf_size; -+ -+ size = PAGE_ALIGN(size); -+ /* Update the kernel pages of the requested buffer */ -+ dmac_inv_range((void *)buffer->addr_align, (void *)buffer->addr_align + -+ size); -+} -+ -+#define IS_OUT_OF_BOUNDS(value, min, max) \ -+ (((value) < (min)) || ((value) > (max))) -+ -+/* Function to check paxel parameters */ -+int isp_af_check_paxel(void) -+{ -+ struct af_paxel *paxel_cfg = &af_dev_configptr->config->paxel_config; -+ struct af_iir *iir_cfg = &af_dev_configptr->config->iir_config; -+ -+ /* Check horizontal Count */ -+ if (IS_OUT_OF_BOUNDS(paxel_cfg->hz_cnt, AF_PAXEL_HORIZONTAL_COUNT_MIN, -+ AF_PAXEL_HORIZONTAL_COUNT_MAX)) { -+ DPRINTK_ISP_AF("Error : Horizontal Count is incorrect"); -+ return -AF_ERR_HZ_COUNT; -+ } -+ -+ /*Check Vertical Count */ -+ if (IS_OUT_OF_BOUNDS(paxel_cfg->vt_cnt, AF_PAXEL_VERTICAL_COUNT_MIN, -+ AF_PAXEL_VERTICAL_COUNT_MAX)) { -+ DPRINTK_ISP_AF("Error : Vertical Count is incorrect"); -+ return -AF_ERR_VT_COUNT; -+ } -+ -+ /*Check Height */ -+ if (IS_OUT_OF_BOUNDS(paxel_cfg->height, AF_PAXEL_HEIGHT_MIN, -+ AF_PAXEL_HEIGHT_MAX)) { -+ DPRINTK_ISP_AF("Error : Height is incorrect"); -+ return -AF_ERR_HEIGHT; -+ } -+ -+ /*Check width */ -+ if (IS_OUT_OF_BOUNDS(paxel_cfg->width, AF_PAXEL_WIDTH_MIN, -+ AF_PAXEL_WIDTH_MAX)) { -+ DPRINTK_ISP_AF("Error : Width is incorrect"); -+ return -AF_ERR_WIDTH; -+ } -+ -+ /*Check Line Increment */ -+ if (IS_OUT_OF_BOUNDS(paxel_cfg->line_incr, AF_PAXEL_INCREMENT_MIN, -+ AF_PAXEL_INCREMENT_MAX)) { -+ DPRINTK_ISP_AF("Error : Line Increment is incorrect"); -+ return -AF_ERR_INCR; -+ } -+ -+ /*Check Horizontal Start */ -+ if ((paxel_cfg->hz_start % 2 != 0) || -+ (paxel_cfg->hz_start < (iir_cfg->hz_start_pos + 2)) || -+ IS_OUT_OF_BOUNDS(paxel_cfg->hz_start, -+ AF_PAXEL_HZSTART_MIN, AF_PAXEL_HZSTART_MAX)) { -+ DPRINTK_ISP_AF("Error : Horizontal Start is incorrect"); -+ return -AF_ERR_HZ_START; -+ } -+ -+ /*Check Vertical Start */ -+ if (IS_OUT_OF_BOUNDS(paxel_cfg->vt_start, AF_PAXEL_VTSTART_MIN, -+ AF_PAXEL_VTSTART_MAX)) { -+ DPRINTK_ISP_AF("Error : Vertical Start is incorrect"); -+ return -AF_ERR_VT_START; -+ } -+ return 0; -+} -+ -+/** -+ * isp_af_check_iir - Function to check IIR Coefficient. -+ **/ -+int isp_af_check_iir(void) -+{ -+ struct af_iir *iir_cfg = &af_dev_configptr->config->iir_config; -+ int index; -+ -+ for (index = 0; index < AF_NUMBER_OF_COEF; index++) { -+ if ((iir_cfg->coeff_set0[index]) > AF_COEF_MAX) { -+ DPRINTK_ISP_AF("Error : Coefficient for set 0 is " -+ "incorrect"); -+ return -AF_ERR_IIR_COEF; -+ } -+ -+ if ((iir_cfg->coeff_set1[index]) > AF_COEF_MAX) { -+ DPRINTK_ISP_AF("Error : Coefficient for set 1 is " -+ "incorrect"); -+ return -AF_ERR_IIR_COEF; -+ } -+ } -+ -+ if (IS_OUT_OF_BOUNDS(iir_cfg->hz_start_pos, AF_IIRSH_MIN, -+ AF_IIRSH_MAX)) { -+ DPRINTK_ISP_AF("Error : IIRSH is incorrect"); -+ return -AF_ERR_IIRSH; -+ } -+ -+ return 0; -+} -+/** -+ * isp_af_unlock_buffers - Helper function to unlock all buffers. -+ **/ -+static void isp_af_unlock_buffers(void) -+{ -+ int i; -+ unsigned long irqflags; -+ -+ spin_lock_irqsave(&afstat.buffer_lock, irqflags); -+ for (i = 0; i < H3A_MAX_BUFF; i++) -+ afstat.af_buff[i].locked = 0; -+ -+ spin_unlock_irqrestore(&afstat.buffer_lock, irqflags); -+} -+ -+/* -+ * Helper function to link allocated buffers -+ */ -+static void isp_af_link_buffers(void) -+{ -+ int i; -+ -+ for (i = 0; i < H3A_MAX_BUFF; i++) { -+ if ((i + 1) < H3A_MAX_BUFF) -+ afstat.af_buff[i].next = &afstat.af_buff[i + 1]; -+ else -+ afstat.af_buff[i].next = &afstat.af_buff[0]; -+ } -+} -+ -+/* Function to perform hardware set up */ -+int isp_af_configure(struct af_configuration *afconfig) -+{ -+ int result; -+ int buff_size, i; -+ unsigned int busyaf; -+ struct af_configuration *af_curr_cfg = af_dev_configptr->config; -+ -+ if (NULL == afconfig) { -+ printk(KERN_ERR "Null argument in configuration. \n"); -+ return -EINVAL; -+ } -+ -+ memcpy(af_curr_cfg, afconfig, sizeof(struct af_configuration)); -+ /* Get the value of PCR register */ -+ busyaf = isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR); -+ -+ if ((busyaf & AF_BUSYAF) == AF_BUSYAF) { -+ DPRINTK_ISP_AF("AF_register_setup_ERROR : Engine Busy"); -+ DPRINTK_ISP_AF("\n Configuration cannot be done "); -+ return -AF_ERR_ENGINE_BUSY; -+ } -+ -+ /* Check IIR Coefficient and start Values */ -+ result = isp_af_check_iir(); -+ if (result < 0) -+ return result; -+ -+ /* Check Paxel Values */ -+ result = isp_af_check_paxel(); -+ if (result < 0) -+ return result; -+ -+ /* Check HMF Threshold Values */ -+ if (af_curr_cfg->hmf_config.threshold > AF_THRESHOLD_MAX) { -+ DPRINTK_ISP_AF("Error : HMF Threshold is incorrect"); -+ return -AF_ERR_THRESHOLD; -+ } -+ -+ /* Compute buffer size */ -+ buff_size = (af_curr_cfg->paxel_config.hz_cnt + 1) * -+ (af_curr_cfg->paxel_config.vt_cnt + 1) * AF_PAXEL_SIZE; -+ -+ afstat.curr_cfg_buf_size = buff_size; -+ /* Deallocate the previous buffers */ -+ if (afstat.stats_buf_size && buff_size > afstat.stats_buf_size) { -+ isp_af_enable(0); -+ for (i = 0; i < H3A_MAX_BUFF; i++) { -+ ispmmu_kunmap(afstat.af_buff[i].ispmmu_addr); -+ dma_free_coherent( -+ NULL, afstat.min_buf_size, -+ (void *)afstat.af_buff[i].virt_addr, -+ (dma_addr_t)afstat.af_buff[i].phy_addr); -+ afstat.af_buff[i].virt_addr = 0; -+ } -+ afstat.stats_buf_size = 0; -+ } -+ -+ if (!afstat.af_buff[0].virt_addr) { -+ afstat.stats_buf_size = buff_size; -+ afstat.min_buf_size = PAGE_ALIGN(afstat.stats_buf_size); -+ -+ for (i = 0; i < H3A_MAX_BUFF; i++) { -+ afstat.af_buff[i].virt_addr = -+ (unsigned long)dma_alloc_coherent( -+ NULL, -+ afstat.min_buf_size, -+ (dma_addr_t *) -+ &afstat.af_buff[i].phy_addr, -+ GFP_KERNEL | GFP_DMA); -+ if (afstat.af_buff[i].virt_addr == 0) { -+ printk(KERN_ERR "Can't acquire memory for " -+ "buffer[%d]\n", i); -+ return -ENOMEM; -+ } -+ afstat.af_buff[i].addr_align = -+ afstat.af_buff[i].virt_addr; -+ while ((afstat.af_buff[i].addr_align & 0xFFFFFFC0) != -+ afstat.af_buff[i].addr_align) -+ afstat.af_buff[i].addr_align++; -+ afstat.af_buff[i].ispmmu_addr = -+ ispmmu_kmap(afstat.af_buff[i].phy_addr, -+ afstat.min_buf_size); -+ } -+ isp_af_unlock_buffers(); -+ isp_af_link_buffers(); -+ -+ /* First active buffer */ -+ if (active_buff == NULL) -+ active_buff = &afstat.af_buff[0]; -+ isp_af_set_address(active_buff->ispmmu_addr); -+ } -+ -+ result = isp_af_register_setup(af_dev_configptr); -+ if (result < 0) -+ return result; -+ af_dev_configptr->size_paxel = buff_size; -+ atomic_inc(&afstat.config_counter); -+ afstat.initialized = 1; -+ afstat.frame_count = 1; -+ active_buff->frame_num = 1; -+ /* Set configuration flag to indicate HW setup done */ -+ if (af_curr_cfg->af_config) -+ isp_af_enable(1); -+ else -+ isp_af_enable(0); -+ -+ /* Success */ -+ return 0; -+} -+EXPORT_SYMBOL(isp_af_configure); -+ -+int isp_af_register_setup(struct af_device *af_dev) -+{ -+ unsigned int pcr = 0, pax1 = 0, pax2 = 0, paxstart = 0; -+ unsigned int coef = 0; -+ unsigned int base_coef_set0 = 0; -+ unsigned int base_coef_set1 = 0; -+ int index; -+ -+ /* Configure Hardware Registers */ -+ /* Read PCR Register */ -+ pcr = isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR); -+ -+ /* Set Accumulator Mode */ -+ if (af_dev->config->mode == ACCUMULATOR_PEAK) -+ pcr |= FVMODE; -+ else -+ pcr &= ~FVMODE; -+ -+ /* Set A-law */ -+ if (af_dev->config->alaw_enable == H3A_AF_ALAW_ENABLE) -+ pcr |= AF_ALAW_EN; -+ else -+ pcr &= ~AF_ALAW_EN; -+ -+ /* Set RGB Position */ -+ pcr &= ~RGBPOS; -+ pcr |= af_dev->config->rgb_pos << AF_RGBPOS_SHIFT; -+ -+ /* HMF Configurations */ -+ if (af_dev->config->hmf_config.enable == H3A_AF_HMF_ENABLE) { -+ pcr &= ~AF_MED_EN; -+ /* Enable HMF */ -+ pcr |= AF_MED_EN; -+ -+ /* Set Median Threshold */ -+ pcr &= ~MED_TH; -+ pcr |= af_dev->config->hmf_config.threshold << AF_MED_TH_SHIFT; -+ } else -+ pcr &= ~AF_MED_EN; -+ -+ /* Set PCR Register */ -+ isp_reg_writel(pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR); -+ -+ pax1 &= ~PAXW; -+ pax1 |= af_dev->config->paxel_config.width << AF_PAXW_SHIFT; -+ -+ /* Set height in AFPAX1 */ -+ pax1 &= ~PAXH; -+ pax1 |= af_dev->config->paxel_config.height; -+ -+ isp_reg_writel(pax1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1); -+ -+ /* Configure AFPAX2 Register */ -+ /* Set Line Increment in AFPAX2 Register */ -+ pax2 &= ~AFINCV; -+ pax2 |= af_dev->config->paxel_config.line_incr << AF_LINE_INCR_SHIFT; -+ /* Set Vertical Count */ -+ pax2 &= ~PAXVC; -+ pax2 |= af_dev->config->paxel_config.vt_cnt << AF_VT_COUNT_SHIFT; -+ /* Set Horizontal Count */ -+ pax2 &= ~PAXHC; -+ pax2 |= af_dev->config->paxel_config.hz_cnt; -+ isp_reg_writel(pax2, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2); -+ -+ /* Configure PAXSTART Register */ -+ /*Configure Horizontal Start */ -+ paxstart &= ~PAXSH; -+ paxstart |= af_dev->config->paxel_config.hz_start << AF_HZ_START_SHIFT; -+ /* Configure Vertical Start */ -+ paxstart &= ~PAXSV; -+ paxstart |= af_dev->config->paxel_config.vt_start; -+ isp_reg_writel(paxstart, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAXSTART); -+ -+ /*SetIIRSH Register */ -+ isp_reg_writel(af_dev->config->iir_config.hz_start_pos, -+ OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH); -+ -+ /*Set IIR Filter0 Coefficients */ -+ base_coef_set0 = ISPH3A_AFCOEF010; -+ for (index = 0; index <= 8; index += 2) { -+ coef &= ~COEF_MASK0; -+ coef |= af_dev->config->iir_config.coeff_set0[index]; -+ coef &= ~COEF_MASK1; -+ coef |= af_dev->config->iir_config.coeff_set0[index + 1] << -+ AF_COEF_SHIFT; -+ isp_reg_writel(coef, OMAP3_ISP_IOMEM_H3A, base_coef_set0); -+ base_coef_set0 = base_coef_set0 + AFCOEF_OFFSET; -+ } -+ -+ /* set AFCOEF0010 Register */ -+ isp_reg_writel(af_dev->config->iir_config.coeff_set0[10], -+ OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF010); -+ -+ /*Set IIR Filter1 Coefficients */ -+ -+ base_coef_set1 = ISPH3A_AFCOEF110; -+ for (index = 0; index <= 8; index += 2) { -+ coef &= ~COEF_MASK0; -+ coef |= af_dev->config->iir_config.coeff_set1[index]; -+ coef &= ~COEF_MASK1; -+ coef |= af_dev->config->iir_config.coeff_set1[index + 1] << -+ AF_COEF_SHIFT; -+ isp_reg_writel(coef, OMAP3_ISP_IOMEM_H3A, base_coef_set1); -+ -+ base_coef_set1 = base_coef_set1 + AFCOEF_OFFSET; -+ } -+ isp_reg_writel(af_dev->config->iir_config.coeff_set1[10], -+ OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010); -+ -+ return 0; -+} -+ -+/* Function to set address */ -+void isp_af_set_address(unsigned long address) -+{ -+ isp_reg_writel(address, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFBUFST); -+} -+ -+static int isp_af_stats_available(struct isp_af_data *afdata) -+{ -+ int i, ret; -+ unsigned long irqflags; -+ -+ spin_lock_irqsave(&afstat.buffer_lock, irqflags); -+ for (i = 0; i < H3A_MAX_BUFF; i++) { -+ DPRINTK_ISP_AF("Checking Stats buff[%d] (%d) for %d\n", -+ i, afstat.af_buff[i].frame_num, -+ afdata->frame_number); -+ if (afdata->frame_number == afstat.af_buff[i].frame_num -+ && afstat.af_buff[i].frame_num != active_buff->frame_num) { -+ afstat.af_buff[i].locked = 1; -+ spin_unlock_irqrestore(&afstat.buffer_lock, irqflags); -+ isp_af_update_req_buffer(&afstat.af_buff[i]); -+ afstat.af_buff[i].frame_num = 0; -+ ret = copy_to_user((void *)afdata->af_statistics_buf, -+ (void *)afstat.af_buff[i].virt_addr, -+ afstat.curr_cfg_buf_size); -+ if (ret) { -+ printk(KERN_ERR "Failed copy_to_user for " -+ "H3A stats buff, %d\n", ret); -+ } -+ afdata->xtrastats.ts = afstat.af_buff[i].xtrastats.ts; -+ afdata->xtrastats.field_count = -+ afstat.af_buff[i].xtrastats.field_count; -+ return 0; -+ } -+ } -+ spin_unlock_irqrestore(&afstat.buffer_lock, irqflags); -+ /* Stats unavailable */ -+ -+ return -1; -+} -+ -+void isp_af_notify(int notify) -+{ -+ camnotify = notify; -+ if (camnotify && afstat.initialized) { -+ printk(KERN_DEBUG "Warning Camera Off \n"); -+ afstat.stats_req = 0; -+ afstat.stats_done = 1; -+ wake_up_interruptible(&afstat.stats_wait); -+ } -+} -+EXPORT_SYMBOL(isp_af_notify); -+/* -+ * This API allows the user to update White Balance gains, as well as -+ * exposure time and analog gain. It is also used to request frame -+ * statistics. -+ */ -+int isp_af_request_statistics(struct isp_af_data *afdata) -+{ -+ int ret = 0; -+ u16 frame_diff = 0; -+ u16 frame_cnt = afstat.frame_count; -+ wait_queue_t wqt; -+ -+ if (!af_dev_configptr->config->af_config) { -+ printk(KERN_ERR "AF engine not enabled\n"); -+ return -EINVAL; -+ } -+ -+ if (!(afdata->update & REQUEST_STATISTICS)) { -+ afdata->af_statistics_buf = NULL; -+ goto out; -+ } -+ -+ isp_af_unlock_buffers(); -+ /* Stats available? */ -+ DPRINTK_ISP_AF("Stats available?\n"); -+ ret = isp_af_stats_available(afdata); -+ if (!ret) -+ goto out; -+ -+ /* Stats in near future? */ -+ DPRINTK_ISP_AF("Stats in near future?\n"); -+ if (afdata->frame_number > frame_cnt) -+ frame_diff = afdata->frame_number - frame_cnt; -+ else if (afdata->frame_number < frame_cnt) { -+ if (frame_cnt > MAX_FRAME_COUNT - MAX_FUTURE_FRAMES -+ && afdata->frame_number < MAX_FRAME_COUNT) { -+ frame_diff = afdata->frame_number + MAX_FRAME_COUNT - -+ frame_cnt; -+ } else { -+ /* Frame unavailable */ -+ frame_diff = MAX_FUTURE_FRAMES + 1; -+ } -+ } -+ -+ if (frame_diff > MAX_FUTURE_FRAMES) { -+ printk(KERN_ERR "Invalid frame requested, returning current" -+ " frame stats\n"); -+ afdata->frame_number = frame_cnt; -+ } -+ if (!camnotify) { -+ /* Block until frame in near future completes */ -+ afstat.frame_req = afdata->frame_number; -+ afstat.stats_req = 1; -+ afstat.stats_done = 0; -+ init_waitqueue_entry(&wqt, current); -+ ret = wait_event_interruptible(afstat.stats_wait, -+ afstat.stats_done == 1); -+ if (ret < 0) { -+ afdata->af_statistics_buf = NULL; -+ return ret; -+ } -+ DPRINTK_ISP_AF("ISP AF request status interrupt raised\n"); -+ -+ /* Stats now available */ -+ ret = isp_af_stats_available(afdata); -+ if (ret) { -+ printk(KERN_ERR "After waiting for stats, stats not" -+ " available!!\n"); -+ afdata->af_statistics_buf = NULL; -+ } -+ } -+ -+out: -+ afdata->curr_frame = afstat.frame_count; -+ -+ return 0; -+} -+EXPORT_SYMBOL(isp_af_request_statistics); -+ -+/* This function will handle the H3A interrupt. */ -+static void isp_af_isr(unsigned long status, isp_vbq_callback_ptr arg1, -+ void *arg2) -+{ -+ u16 frame_align; -+ -+ if ((H3A_AF_DONE & status) != H3A_AF_DONE) -+ return; -+ -+ /* timestamp stats buffer */ -+ do_gettimeofday(&active_buff->xtrastats.ts); -+ active_buff->config_counter = atomic_read(&afstat.config_counter); -+ -+ /* Exchange buffers */ -+ active_buff = active_buff->next; -+ if (active_buff->locked == 1) -+ active_buff = active_buff->next; -+ isp_af_set_address(active_buff->ispmmu_addr); -+ -+ /* Update frame counter */ -+ afstat.frame_count++; -+ frame_align = afstat.frame_count; -+ if (afstat.frame_count > MAX_FRAME_COUNT) { -+ afstat.frame_count = 1; -+ frame_align++; -+ } -+ active_buff->frame_num = afstat.frame_count; -+ -+ /* Future Stats requested? */ -+ if (afstat.stats_req) { -+ /* Is the frame we want already done? */ -+ if (frame_align >= afstat.frame_req + 1) { -+ afstat.stats_req = 0; -+ afstat.stats_done = 1; -+ wake_up_interruptible(&afstat.stats_wait); -+ } -+ } -+} -+ -+int __isp_af_enable(int enable) -+{ -+ unsigned int pcr; -+ -+ pcr = isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR); -+ -+ /* Set AF_EN bit in PCR Register */ -+ if (enable) { -+ if (isp_set_callback(CBK_H3A_AF_DONE, isp_af_isr, -+ (void *)NULL, (void *)NULL)) { -+ printk(KERN_ERR "No callback for AF\n"); -+ return -EINVAL; -+ } -+ -+ pcr |= AF_EN; -+ } else { -+ isp_unset_callback(CBK_H3A_AF_DONE); -+ pcr &= ~AF_EN; -+ } -+ isp_reg_writel(pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR); -+ return 0; -+} -+ -+/* Function to Enable/Disable AF Engine */ -+int isp_af_enable(int enable) -+{ -+ int rval; -+ -+ rval = __isp_af_enable(enable); -+ -+ if (!rval) -+ afstat.pm_state = enable; -+ -+ return rval; -+} -+ -+/* Function to Suspend AF Engine */ -+void isp_af_suspend(void) -+{ -+ if (afstat.pm_state) -+ __isp_af_enable(0); -+} -+ -+/* Function to Resume AF Engine */ -+void isp_af_resume(void) -+{ -+ if (afstat.pm_state) -+ __isp_af_enable(1); -+} -+ -+int isp_af_busy(void) -+{ -+ return isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR) -+ & ISPH3A_PCR_BUSYAF; -+} -+ -+/* Function to register the AF character device driver. */ -+int __init isp_af_init(void) -+{ -+ /*allocate memory for device structure and initialize it with 0 */ -+ af_dev_configptr = kzalloc(sizeof(struct af_device), GFP_KERNEL); -+ if (!af_dev_configptr) -+ goto err_nomem1; -+ -+ active_buff = NULL; -+ -+ af_dev_configptr->config = (struct af_configuration *) -+ kzalloc(sizeof(struct af_configuration), GFP_KERNEL); -+ -+ if (af_dev_configptr->config == NULL) -+ goto err_nomem2; -+ -+ memset(&afstat, 0, sizeof(afstat)); -+ -+ init_waitqueue_head(&afstat.stats_wait); -+ spin_lock_init(&afstat.buffer_lock); -+ -+ return 0; -+ -+err_nomem2: -+ kfree(af_dev_configptr); -+err_nomem1: -+ printk(KERN_ERR "Error: kmalloc fail"); -+ return -ENOMEM; -+} -+ -+void isp_af_exit(void) -+{ -+ int i; -+ -+ /* Free buffers */ -+ for (i = 0; i < H3A_MAX_BUFF; i++) { -+ if (!afstat.af_buff[i].phy_addr) -+ continue; -+ -+ ispmmu_kunmap(afstat.af_buff[i].ispmmu_addr); -+ -+ dma_free_coherent(NULL, -+ afstat.min_buf_size, -+ (void *)afstat.af_buff[i].virt_addr, -+ (dma_addr_t)afstat.af_buff[i].phy_addr); -+ } -+ kfree(af_dev_configptr->config); -+ kfree(af_dev_configptr); -+ -+ memset(&afstat, 0, sizeof(afstat)); -+ -+ af_major = -1; -+} -diff --git a/drivers/media/video/isp/isp_af.h b/drivers/media/video/isp/isp_af.h -new file mode 100644 -index 0000000..ee2b89f ---- /dev/null -+++ b/drivers/media/video/isp/isp_af.h -@@ -0,0 +1,125 @@ -+/* -+ * isp_af.h -+ * -+ * Include file for AF module in TI's OMAP3 Camera ISP -+ * -+ * Copyright (C) 2009 Texas Instruments, Inc. -+ * -+ * Contributors: -+ * Sergio Aguirre <saaguirre@ti.com> -+ * Troy Laramy -+ * -+ * This package is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. -+ */ -+ -+/* Device Constants */ -+#ifndef OMAP_ISP_AF_H -+#define OMAP_ISP_AF_H -+ -+#include <mach/isp_user.h> -+ -+#define AF_MAJOR_NUMBER 0 -+#define ISPAF_NAME "OMAPISP_AF" -+#define AF_NR_DEVS 1 -+#define AF_TIMEOUT ((300 * HZ) / 1000) -+ -+ -+ -+/* Print Macros */ -+/*list of error code */ -+#define AF_ERR_HZ_COUNT 800 /* Invalid Horizontal Count */ -+#define AF_ERR_VT_COUNT 801 /* Invalid Vertical Count */ -+#define AF_ERR_HEIGHT 802 /* Invalid Height */ -+#define AF_ERR_WIDTH 803 /* Invalid width */ -+#define AF_ERR_INCR 804 /* Invalid Increment */ -+#define AF_ERR_HZ_START 805 /* Invalid horizontal Start */ -+#define AF_ERR_VT_START 806 /* Invalud vertical Start */ -+#define AF_ERR_IIRSH 807 /* Invalid IIRSH value */ -+#define AF_ERR_IIR_COEF 808 /* Invalid Coefficient */ -+#define AF_ERR_SETUP 809 /* Setup not done */ -+#define AF_ERR_THRESHOLD 810 /* Invalid Threshold */ -+#define AF_ERR_ENGINE_BUSY 811 /* Engine is busy */ -+ -+#define AFPID 0x0 /* Peripheral Revision -+ * and Class Information -+ */ -+ -+#define AFCOEF_OFFSET 0x00000004 /* COEFFICIENT BASE -+ * ADDRESS -+ */ -+ -+/* -+ * PCR fields -+ */ -+#define AF_BUSYAF (1 << 15) -+#define FVMODE (1 << 14) -+#define RGBPOS (0x7 << 11) -+#define MED_TH (0xFF << 3) -+#define AF_MED_EN (1 << 2) -+#define AF_ALAW_EN (1 << 1) -+#define AF_EN (1 << 0) -+ -+/* -+ * AFPAX1 fields -+ */ -+#define PAXW (0x7F << 16) -+#define PAXH 0x7F -+ -+/* -+ * AFPAX2 fields -+ */ -+#define AFINCV (0xF << 13) -+#define PAXVC (0x7F << 6) -+#define PAXHC 0x3F -+ -+/* -+ * AFPAXSTART fields -+ */ -+#define PAXSH (0xFFF<<16) -+#define PAXSV 0xFFF -+ -+/* -+ * COEFFICIENT MASK -+ */ -+ -+#define COEF_MASK0 0xFFF -+#define COEF_MASK1 (0xFFF<<16) -+ -+/* BIT SHIFTS */ -+#define AF_RGBPOS_SHIFT 11 -+#define AF_MED_TH_SHIFT 3 -+#define AF_PAXW_SHIFT 16 -+#define AF_LINE_INCR_SHIFT 13 -+#define AF_VT_COUNT_SHIFT 6 -+#define AF_HZ_START_SHIFT 16 -+#define AF_COEF_SHIFT 16 -+ -+#define AF_UPDATEXS_TS (1 << 0) -+#define AF_UPDATEXS_FIELDCOUNT (1 << 1) -+#define AF_UPDATEXS_LENSPOS (1 << 2) -+ -+/* Structure for device of AF Engine */ -+struct af_device { -+ struct af_configuration *config; /*Device configuration structure */ -+ int size_paxel; /*Paxel size in bytes */ -+}; -+ -+int isp_af_check_paxel(void); -+int isp_af_check_iir(void); -+int isp_af_register_setup(struct af_device *af_dev); -+int isp_af_enable(int); -+void isp_af_suspend(void); -+void isp_af_resume(void); -+int isp_af_busy(void); -+void isp_af_notify(int notify); -+int isp_af_request_statistics(struct isp_af_data *afdata); -+int isp_af_configure(struct af_configuration *afconfig); -+void isp_af_set_address(unsigned long); -+void isp_af_setxtrastats(struct isp_af_xtrastats *xtrastats, u8 updateflag); -+#endif /* OMAP_ISP_AF_H */ -diff --git a/drivers/media/video/isp/isph3a.c b/drivers/media/video/isp/isph3a.c -new file mode 100644 -index 0000000..7ff1c5b ---- /dev/null -+++ b/drivers/media/video/isp/isph3a.c -@@ -0,0 +1,932 @@ -+/* -+ * isph3a.c -+ * -+ * H3A module for TI's OMAP3 Camera ISP -+ * -+ * Copyright (C) 2009 Texas Instruments, Inc. -+ * -+ * Contributors: -+ * Sergio Aguirre <saaguirre@ti.com> -+ * Troy Laramy -+ * -+ * This package is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. -+ */ -+ -+#include <asm/cacheflush.h> -+ -+#include <linux/dma-mapping.h> -+#include <linux/uaccess.h> -+ -+#include "isp.h" -+#include "ispreg.h" -+#include "isph3a.h" -+#include "ispmmu.h" -+#include "isppreview.h" -+ -+/** -+ * struct isph3a_aewb_buffer - AE, AWB frame stats buffer. -+ * @virt_addr: Virtual address to mmap the buffer. -+ * @phy_addr: Physical address of the buffer. -+ * @addr_align: Virtual Address 32 bytes aligned. -+ * @ispmmu_addr: Address of the buffer mapped by the ISPMMU. -+ * @mmap_addr: Mapped memory area of buffer. For userspace access. -+ * @locked: 1 - Buffer locked from write. 0 - Buffer can be overwritten. -+ * @frame_num: Frame number from which the statistics are taken. -+ * @next: Pointer to link next buffer. -+ */ -+struct isph3a_aewb_buffer { -+ unsigned long virt_addr; -+ unsigned long phy_addr; -+ unsigned long addr_align; -+ unsigned long ispmmu_addr; -+ unsigned long mmap_addr; /* For userspace */ -+ struct timeval ts; -+ u32 config_counter; -+ -+ u8 locked; -+ u16 frame_num; -+ struct isph3a_aewb_buffer *next; -+}; -+ -+/** -+ * struct isph3a_aewb_status - AE, AWB status. -+ * @initialized: 1 - Buffers initialized. -+ * @update: 1 - Update registers. -+ * @stats_req: 1 - Future stats requested. -+ * @stats_done: 1 - Stats ready for user. -+ * @frame_req: Number of frame requested for statistics. -+ * @h3a_buff: Array of statistics buffers to access. -+ * @stats_buf_size: Statistics buffer size. -+ * @min_buf_size: Minimum statisitics buffer size. -+ * @win_count: Window Count. -+ * @frame_count: Frame Count. -+ * @stats_wait: Wait primitive for locking/unlocking the stats request. -+ * @buffer_lock: Spinlock for statistics buffers access. -+ */ -+static struct isph3a_aewb_status { -+ u8 initialized; -+ u8 update; -+ u8 stats_req; -+ u8 stats_done; -+ u16 frame_req; -+ int pm_state; -+ -+ struct isph3a_aewb_buffer h3a_buff[H3A_MAX_BUFF]; -+ unsigned int stats_buf_size; -+ unsigned int min_buf_size; -+ unsigned int curr_cfg_buf_size; -+ -+ atomic_t config_counter; -+ -+ u16 win_count; -+ u32 frame_count; -+ wait_queue_head_t stats_wait; -+ spinlock_t buffer_lock; /* For stats buffers read/write sync */ -+} aewbstat; -+ -+/** -+ * struct isph3a_aewb_regs - Current value of AE, AWB configuration registers. -+ * reg_pcr: Peripheral control register. -+ * reg_win1: Control register. -+ * reg_start: Start position register. -+ * reg_blk: Black line register. -+ * reg_subwin: Configuration register. -+ */ -+static struct isph3a_aewb_regs { -+ u32 reg_pcr; -+ u32 reg_win1; -+ u32 reg_start; -+ u32 reg_blk; -+ u32 reg_subwin; -+} aewb_regs; -+ -+static struct isph3a_aewb_config aewb_config_local = { -+ .saturation_limit = 0x3FF, -+ .win_height = 0, -+ .win_width = 0, -+ .ver_win_count = 0, -+ .hor_win_count = 0, -+ .ver_win_start = 0, -+ .hor_win_start = 0, -+ .blk_ver_win_start = 0, -+ .blk_win_height = 0, -+ .subsample_ver_inc = 0, -+ .subsample_hor_inc = 0, -+ .alaw_enable = 0, -+ .aewb_enable = 0, -+}; -+ -+/* Structure for saving/restoring h3a module registers */ -+static struct isp_reg isph3a_reg_list[] = { -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, 0}, /* Should be the first one */ -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINSTART, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWSUBWIN, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAXSTART, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFBUFST, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF010, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF032, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF054, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF076, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF098, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF0010, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF110, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF132, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF154, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF176, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF198, 0}, -+ {OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010, 0}, -+ {0, ISP_TOK_TERM, 0} -+}; -+ -+static struct ispprev_wbal h3awb_update; -+static struct isph3a_aewb_buffer *active_buff; -+static struct isph3a_aewb_xtrastats h3a_xtrastats[H3A_MAX_BUFF]; -+static int camnotify; -+static int wb_update; -+static void isph3a_print_status(void); -+ -+/** -+ * isph3a_aewb_setxtrastats - Receives extra statistics from prior frames. -+ * @xtrastats: Pointer to structure containing extra statistics fields like -+ * field count and timestamp of frame. -+ * -+ * Called from update_vbq in camera driver -+ **/ -+void isph3a_aewb_setxtrastats(struct isph3a_aewb_xtrastats *xtrastats) -+{ -+ int i; -+ -+ if (active_buff == NULL) -+ return; -+ -+ for (i = 0; i < H3A_MAX_BUFF; i++) { -+ if (aewbstat.h3a_buff[i].frame_num != active_buff->frame_num) -+ continue; -+ -+ if (i == 0) { -+ if (aewbstat.h3a_buff[H3A_MAX_BUFF - 1].locked == 0) { -+ h3a_xtrastats[H3A_MAX_BUFF - 1] = -+ *xtrastats; -+ } else { -+ h3a_xtrastats[H3A_MAX_BUFF - 2] = -+ *xtrastats; -+ } -+ } else if (i == 1) { -+ if (aewbstat.h3a_buff[0].locked == 0) -+ h3a_xtrastats[0] = *xtrastats; -+ else { -+ h3a_xtrastats[H3A_MAX_BUFF - 1] = -+ *xtrastats; -+ } -+ } else { -+ if (aewbstat.h3a_buff[i - 1].locked == 0) -+ h3a_xtrastats[i - 1] = *xtrastats; -+ else -+ h3a_xtrastats[i - 2] = *xtrastats; -+ } -+ return; -+ } -+} -+EXPORT_SYMBOL(isph3a_aewb_setxtrastats); -+ -+void __isph3a_aewb_enable(u8 enable) -+{ -+ isp_reg_writel(IRQ0STATUS_H3A_AWB_DONE_IRQ, OMAP3_ISP_IOMEM_MAIN, -+ ISP_IRQ0STATUS); -+ -+ if (enable) { -+ aewb_regs.reg_pcr |= ISPH3A_PCR_AEW_EN; -+ DPRINTK_ISPH3A(" H3A enabled \n"); -+ } else { -+ aewb_regs.reg_pcr &= ~ISPH3A_PCR_AEW_EN; -+ DPRINTK_ISPH3A(" H3A disabled \n"); -+ } -+ isp_reg_and_or(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, ~ISPH3A_PCR_AEW_EN, -+ (enable ? ISPH3A_PCR_AEW_EN : 0)); -+ aewb_config_local.aewb_enable = enable; -+} -+ -+/** -+ * isph3a_aewb_enable - Enables AE, AWB engine in the H3A module. -+ * @enable: 1 - Enables the AE & AWB engine. -+ * -+ * Client should configure all the AE & AWB registers in H3A before this. -+ **/ -+void isph3a_aewb_enable(u8 enable) -+{ -+ __isph3a_aewb_enable(enable); -+ aewbstat.pm_state = enable; -+} -+ -+/** -+ * isph3a_aewb_suspend - Suspend AE, AWB engine in the H3A module. -+ **/ -+void isph3a_aewb_suspend(void) -+{ -+ if (aewbstat.pm_state) -+ __isph3a_aewb_enable(0); -+} -+ -+/** -+ * isph3a_aewb_resume - Resume AE, AWB engine in the H3A module. -+ **/ -+void isph3a_aewb_resume(void) -+{ -+ if (aewbstat.pm_state) -+ __isph3a_aewb_enable(1); -+} -+ -+int isph3a_aewb_busy(void) -+{ -+ return isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR) -+ & ISPH3A_PCR_BUSYAEAWB; -+} -+ -+/** -+ * isph3a_update_wb - Updates WB parameters. -+ * -+ * Needs to be called when no ISP Preview processing is taking place. -+ **/ -+void isph3a_update_wb(void) -+{ -+ if (wb_update) { -+ isppreview_config_whitebalance(h3awb_update); -+ wb_update = 0; -+ } -+ return; -+} -+EXPORT_SYMBOL(isph3a_update_wb); -+ -+/** -+ * isph3a_aewb_update_regs - Helper function to update h3a registers. -+ **/ -+static void isph3a_aewb_update_regs(void) -+{ -+ isp_reg_writel(aewb_regs.reg_pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR); -+ isp_reg_writel(aewb_regs.reg_win1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1); -+ isp_reg_writel(aewb_regs.reg_start, OMAP3_ISP_IOMEM_H3A, -+ ISPH3A_AEWINSTART); -+ isp_reg_writel(aewb_regs.reg_blk, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK); -+ isp_reg_writel(aewb_regs.reg_subwin, OMAP3_ISP_IOMEM_H3A, -+ ISPH3A_AEWSUBWIN); -+ -+ aewbstat.update = 0; -+ aewbstat.frame_count = 1; -+} -+ -+/** -+ * isph3a_aewb_update_req_buffer - Helper function to update buffer cache pages -+ * @buffer: Pointer to structure -+ **/ -+static void isph3a_aewb_update_req_buffer(struct isph3a_aewb_buffer *buffer) -+{ -+ int size = aewbstat.stats_buf_size; -+ -+ size = PAGE_ALIGN(size); -+ dmac_inv_range((void *)buffer->addr_align, -+ (void *)buffer->addr_align + size); -+} -+ -+/** -+ * isph3a_aewb_stats_available - Check for stats available of specified frame. -+ * @aewbdata: Pointer to return AE AWB statistics data -+ * -+ * Returns 0 if successful, or -1 if statistics are unavailable. -+ **/ -+static int isph3a_aewb_stats_available(struct isph3a_aewb_data *aewbdata) -+{ -+ int i, ret; -+ unsigned long irqflags; -+ -+ spin_lock_irqsave(&aewbstat.buffer_lock, irqflags); -+ for (i = 0; i < H3A_MAX_BUFF; i++) { -+ DPRINTK_ISPH3A("Checking Stats buff[%d] (%d) for %d\n", -+ i, aewbstat.h3a_buff[i].frame_num, -+ aewbdata->frame_number); -+ if ((aewbdata->frame_number != -+ aewbstat.h3a_buff[i].frame_num) || -+ (aewbstat.h3a_buff[i].frame_num == -+ active_buff->frame_num)) -+ continue; -+ aewbstat.h3a_buff[i].locked = 1; -+ spin_unlock_irqrestore(&aewbstat.buffer_lock, irqflags); -+ isph3a_aewb_update_req_buffer(&aewbstat.h3a_buff[i]); -+ aewbstat.h3a_buff[i].frame_num = 0; -+ ret = copy_to_user((void *)aewbdata->h3a_aewb_statistics_buf, -+ (void *)aewbstat.h3a_buff[i].virt_addr, -+ aewbstat.curr_cfg_buf_size); -+ if (ret) { -+ printk(KERN_ERR "Failed copy_to_user for " -+ "H3A stats buff, %d\n", ret); -+ } -+ aewbdata->ts = aewbstat.h3a_buff[i].ts; -+ aewbdata->config_counter = aewbstat.h3a_buff[i].config_counter; -+ aewbdata->field_count = h3a_xtrastats[i].field_count; -+ return 0; -+ } -+ spin_unlock_irqrestore(&aewbstat.buffer_lock, irqflags); -+ -+ return -1; -+} -+ -+/** -+ * isph3a_aewb_link_buffers - Helper function to link allocated buffers. -+ **/ -+static void isph3a_aewb_link_buffers(void) -+{ -+ int i; -+ -+ for (i = 0; i < H3A_MAX_BUFF; i++) { -+ if ((i + 1) < H3A_MAX_BUFF) { -+ aewbstat.h3a_buff[i].next = &aewbstat.h3a_buff[i + 1]; -+ h3a_xtrastats[i].next = &h3a_xtrastats[i + 1]; -+ } else { -+ aewbstat.h3a_buff[i].next = &aewbstat.h3a_buff[0]; -+ h3a_xtrastats[i].next = &h3a_xtrastats[0]; -+ } -+ } -+} -+ -+/** -+ * isph3a_aewb_unlock_buffers - Helper function to unlock all buffers. -+ **/ -+static void isph3a_aewb_unlock_buffers(void) -+{ -+ int i; -+ unsigned long irqflags; -+ -+ spin_lock_irqsave(&aewbstat.buffer_lock, irqflags); -+ for (i = 0; i < H3A_MAX_BUFF; i++) -+ aewbstat.h3a_buff[i].locked = 0; -+ -+ spin_unlock_irqrestore(&aewbstat.buffer_lock, irqflags); -+} -+ -+/** -+ * isph3a_aewb_isr - Callback from ISP driver for H3A AEWB interrupt. -+ * @status: IRQ0STATUS in case of MMU error, 0 for H3A interrupt. -+ * @arg1: Not used as of now. -+ * @arg2: Not used as of now. -+ */ -+static void isph3a_aewb_isr(unsigned long status, isp_vbq_callback_ptr arg1, -+ void *arg2) -+{ -+ u16 frame_align; -+ -+ if ((H3A_AWB_DONE & status) != H3A_AWB_DONE) -+ return; -+ -+ do_gettimeofday(&active_buff->ts); -+ active_buff->config_counter = atomic_read(&aewbstat.config_counter); -+ active_buff = active_buff->next; -+ if (active_buff->locked == 1) -+ active_buff = active_buff->next; -+ isp_reg_writel(active_buff->ispmmu_addr, OMAP3_ISP_IOMEM_H3A, -+ ISPH3A_AEWBUFST); -+ -+ aewbstat.frame_count++; -+ frame_align = aewbstat.frame_count; -+ if (aewbstat.frame_count > MAX_FRAME_COUNT) { -+ aewbstat.frame_count = 1; -+ frame_align++; -+ } -+ active_buff->frame_num = aewbstat.frame_count; -+ -+ if (aewbstat.stats_req) { -+ DPRINTK_ISPH3A("waiting for frame %d\n", aewbstat.frame_req); -+ if (frame_align >= aewbstat.frame_req + 1) { -+ aewbstat.stats_req = 0; -+ aewbstat.stats_done = 1; -+ wake_up_interruptible(&aewbstat.stats_wait); -+ } -+ } -+ -+ if (aewbstat.update) -+ isph3a_aewb_update_regs(); -+} -+ -+/** -+ * isph3a_aewb_set_params - Helper function to check & store user given params. -+ * @user_cfg: Pointer to AE and AWB parameters struct. -+ * -+ * As most of them are busy-lock registers, need to wait until AEW_BUSY = 0 to -+ * program them during ISR. -+ * -+ * Returns 0 if successful, or -EINVAL if any of the parameters are invalid. -+ **/ -+static int isph3a_aewb_set_params(struct isph3a_aewb_config *user_cfg) -+{ -+ if (unlikely(user_cfg->saturation_limit > MAX_SATURATION_LIM)) { -+ printk(KERN_ERR "Invalid Saturation_limit: %d\n", -+ user_cfg->saturation_limit); -+ return -EINVAL; -+ } -+ if (aewb_config_local.saturation_limit != user_cfg->saturation_limit) { -+ WRITE_SAT_LIM(aewb_regs.reg_pcr, user_cfg->saturation_limit); -+ aewb_config_local.saturation_limit = -+ user_cfg->saturation_limit; -+ aewbstat.update = 1; -+ } -+ -+ if (aewb_config_local.alaw_enable != user_cfg->alaw_enable) { -+ WRITE_ALAW(aewb_regs.reg_pcr, user_cfg->alaw_enable); -+ aewb_config_local.alaw_enable = user_cfg->alaw_enable; -+ aewbstat.update = 1; -+ } -+ -+ if (unlikely(user_cfg->win_height < MIN_WIN_H || -+ user_cfg->win_height > MAX_WIN_H || -+ user_cfg->win_height & 0x01)) { -+ printk(KERN_ERR "Invalid window height: %d\n", -+ user_cfg->win_height); -+ return -EINVAL; -+ } -+ if (aewb_config_local.win_height != user_cfg->win_height) { -+ WRITE_WIN_H(aewb_regs.reg_win1, user_cfg->win_height); -+ aewb_config_local.win_height = user_cfg->win_height; -+ aewbstat.update = 1; -+ } -+ -+ if (unlikely(user_cfg->win_width < MIN_WIN_W || -+ user_cfg->win_width > MAX_WIN_W || -+ user_cfg->win_width & 0x01)) { -+ printk(KERN_ERR "Invalid window width: %d\n", -+ user_cfg->win_width); -+ return -EINVAL; -+ } -+ if (aewb_config_local.win_width != user_cfg->win_width) { -+ WRITE_WIN_W(aewb_regs.reg_win1, user_cfg->win_width); -+ aewb_config_local.win_width = user_cfg->win_width; -+ aewbstat.update = 1; -+ } -+ -+ if (unlikely(user_cfg->ver_win_count < 1 || -+ user_cfg->ver_win_count > MAX_WINVC)) { -+ printk(KERN_ERR "Invalid vertical window count: %d\n", -+ user_cfg->ver_win_count); -+ return -EINVAL; -+ } -+ if (aewb_config_local.ver_win_count != user_cfg->ver_win_count) { -+ WRITE_VER_C(aewb_regs.reg_win1, user_cfg->ver_win_count); -+ aewb_config_local.ver_win_count = user_cfg->ver_win_count; -+ aewbstat.update = 1; -+ } -+ -+ if (unlikely(user_cfg->hor_win_count < 1 || -+ user_cfg->hor_win_count > MAX_WINHC)) { -+ printk(KERN_ERR "Invalid horizontal window count: %d\n", -+ user_cfg->hor_win_count); -+ return -EINVAL; -+ } -+ if (aewb_config_local.hor_win_count != user_cfg->hor_win_count) { -+ WRITE_HOR_C(aewb_regs.reg_win1, user_cfg->hor_win_count); -+ aewb_config_local.hor_win_count = user_cfg->hor_win_count; -+ aewbstat.update = 1; -+ } -+ -+ if (unlikely(user_cfg->ver_win_start > MAX_WINSTART)) { -+ printk(KERN_ERR "Invalid vertical window start: %d\n", -+ user_cfg->ver_win_start); -+ return -EINVAL; -+ } -+ if (aewb_config_local.ver_win_start != user_cfg->ver_win_start) { -+ WRITE_VER_WIN_ST(aewb_regs.reg_start, user_cfg->ver_win_start); -+ aewb_config_local.ver_win_start = user_cfg->ver_win_start; -+ aewbstat.update = 1; -+ } -+ -+ if (unlikely(user_cfg->hor_win_start > MAX_WINSTART)) { -+ printk(KERN_ERR "Invalid horizontal window start: %d\n", -+ user_cfg->hor_win_start); -+ return -EINVAL; -+ } -+ if (aewb_config_local.hor_win_start != user_cfg->hor_win_start) { -+ WRITE_HOR_WIN_ST(aewb_regs.reg_start, user_cfg->hor_win_start); -+ aewb_config_local.hor_win_start = user_cfg->hor_win_start; -+ aewbstat.update = 1; -+ } -+ -+ if (unlikely(user_cfg->blk_ver_win_start > MAX_WINSTART)) { -+ printk(KERN_ERR "Invalid black vertical window start: %d\n", -+ user_cfg->blk_ver_win_start); -+ return -EINVAL; -+ } -+ if (aewb_config_local.blk_ver_win_start != -+ user_cfg->blk_ver_win_start) { -+ WRITE_BLK_VER_WIN_ST(aewb_regs.reg_blk, -+ user_cfg->blk_ver_win_start); -+ aewb_config_local.blk_ver_win_start = -+ user_cfg->blk_ver_win_start; -+ aewbstat.update = 1; -+ } -+ -+ if (unlikely(user_cfg->blk_win_height < MIN_WIN_H || -+ user_cfg->blk_win_height > MAX_WIN_H || -+ user_cfg->blk_win_height & 0x01)) { -+ printk(KERN_ERR "Invalid black window height: %d\n", -+ user_cfg->blk_win_height); -+ return -EINVAL; -+ } -+ if (aewb_config_local.blk_win_height != user_cfg->blk_win_height) { -+ WRITE_BLK_WIN_H(aewb_regs.reg_blk, user_cfg->blk_win_height); -+ aewb_config_local.blk_win_height = user_cfg->blk_win_height; -+ aewbstat.update = 1; -+ } -+ -+ if (unlikely(user_cfg->subsample_ver_inc < MIN_SUB_INC || -+ user_cfg->subsample_ver_inc > MAX_SUB_INC || -+ user_cfg->subsample_ver_inc & 0x01)) { -+ printk(KERN_ERR "Invalid vertical subsample increment: %d\n", -+ user_cfg->subsample_ver_inc); -+ return -EINVAL; -+ } -+ if (aewb_config_local.subsample_ver_inc != -+ user_cfg->subsample_ver_inc) { -+ WRITE_SUB_VER_INC(aewb_regs.reg_subwin, -+ user_cfg->subsample_ver_inc); -+ aewb_config_local.subsample_ver_inc = -+ user_cfg->subsample_ver_inc; -+ aewbstat.update = 1; -+ } -+ -+ if (unlikely(user_cfg->subsample_hor_inc < MIN_SUB_INC || -+ user_cfg->subsample_hor_inc > MAX_SUB_INC || -+ user_cfg->subsample_hor_inc & 0x01)) { -+ printk(KERN_ERR "Invalid horizontal subsample increment: %d\n", -+ user_cfg->subsample_hor_inc); -+ return -EINVAL; -+ } -+ if (aewb_config_local.subsample_hor_inc != -+ user_cfg->subsample_hor_inc) { -+ WRITE_SUB_HOR_INC(aewb_regs.reg_subwin, -+ user_cfg->subsample_hor_inc); -+ aewb_config_local.subsample_hor_inc = -+ user_cfg->subsample_hor_inc; -+ aewbstat.update = 1; -+ } -+ -+ if (!aewbstat.initialized || !aewb_config_local.aewb_enable) { -+ isph3a_aewb_update_regs(); -+ aewbstat.initialized = 1; -+ } -+ return 0; -+} -+ -+/** -+ * isph3a_aewb_configure - Configure AEWB regs, enable/disable H3A engine. -+ * @aewbcfg: Pointer to AEWB config structure. -+ * -+ * Returns 0 if successful, -EINVAL if aewbcfg pointer is NULL, -ENOMEM if -+ * was unable to allocate memory for the buffer, of other errors if H3A -+ * callback is not set or the parameters for AEWB are invalid. -+ **/ -+int isph3a_aewb_configure(struct isph3a_aewb_config *aewbcfg) -+{ -+ int ret = 0; -+ int i; -+ int win_count = 0; -+ -+ if (NULL == aewbcfg) { -+ printk(KERN_ERR "Null argument in configuration. \n"); -+ return -EINVAL; -+ } -+ -+ if (!aewbstat.initialized) { -+ DPRINTK_ISPH3A("Setting callback for H3A\n"); -+ ret = isp_set_callback(CBK_H3A_AWB_DONE, isph3a_aewb_isr, -+ (void *)NULL, (void *)NULL); -+ if (ret) { -+ printk(KERN_ERR "No callback for H3A\n"); -+ return ret; -+ } -+ } -+ -+ ret = isph3a_aewb_set_params(aewbcfg); -+ if (ret) { -+ printk(KERN_ERR "Invalid parameters! \n"); -+ return ret; -+ } -+ -+ win_count = aewbcfg->ver_win_count * aewbcfg->hor_win_count; -+ win_count += aewbcfg->hor_win_count; -+ ret = win_count / 8; -+ win_count += win_count % 8 ? 1 : 0; -+ win_count += ret; -+ -+ aewbstat.win_count = win_count; -+ aewbstat.curr_cfg_buf_size = win_count * AEWB_PACKET_SIZE; -+ -+ if (aewbstat.stats_buf_size -+ && win_count * AEWB_PACKET_SIZE > aewbstat.stats_buf_size) { -+ DPRINTK_ISPH3A("There was a previous buffer... " -+ "Freeing/unmapping current stat busffs\n"); -+ isph3a_aewb_enable(0); -+ for (i = 0; i < H3A_MAX_BUFF; i++) { -+ ispmmu_kunmap(aewbstat.h3a_buff[i].ispmmu_addr); -+ dma_free_coherent( -+ NULL, -+ aewbstat.min_buf_size, -+ (void *)aewbstat.h3a_buff[i].virt_addr, -+ (dma_addr_t)aewbstat.h3a_buff[i].phy_addr); -+ aewbstat.h3a_buff[i].virt_addr = 0; -+ } -+ aewbstat.stats_buf_size = 0; -+ } -+ -+ if (!aewbstat.h3a_buff[0].virt_addr) { -+ aewbstat.stats_buf_size = win_count * AEWB_PACKET_SIZE; -+ aewbstat.min_buf_size = PAGE_ALIGN(aewbstat.stats_buf_size); -+ -+ DPRINTK_ISPH3A("Allocating/mapping new stat buffs\n"); -+ for (i = 0; i < H3A_MAX_BUFF; i++) { -+ aewbstat.h3a_buff[i].virt_addr = -+ (unsigned long)dma_alloc_coherent( -+ NULL, -+ aewbstat.min_buf_size, -+ (dma_addr_t *) -+ &aewbstat.h3a_buff[i].phy_addr, -+ GFP_KERNEL | GFP_DMA); -+ if (aewbstat.h3a_buff[i].virt_addr == 0) { -+ printk(KERN_ERR "Can't acquire memory for " -+ "buffer[%d]\n", i); -+ return -ENOMEM; -+ } -+ aewbstat.h3a_buff[i].addr_align = -+ aewbstat.h3a_buff[i].virt_addr; -+ while ((aewbstat.h3a_buff[i].addr_align & 0xFFFFFFC0) != -+ aewbstat.h3a_buff[i].addr_align) -+ aewbstat.h3a_buff[i].addr_align++; -+ aewbstat.h3a_buff[i].ispmmu_addr = -+ ispmmu_kmap(aewbstat.h3a_buff[i].phy_addr, -+ aewbstat.min_buf_size); -+ } -+ isph3a_aewb_unlock_buffers(); -+ isph3a_aewb_link_buffers(); -+ -+ if (active_buff == NULL) -+ active_buff = &aewbstat.h3a_buff[0]; -+ -+ isp_reg_writel(active_buff->ispmmu_addr, OMAP3_ISP_IOMEM_H3A, -+ ISPH3A_AEWBUFST); -+ } -+ for (i = 0; i < H3A_MAX_BUFF; i++) { -+ DPRINTK_ISPH3A("buff[%d] addr is:\n virt 0x%lX\n" -+ " aligned 0x%lX\n" -+ " phys 0x%lX\n" -+ " ispmmu 0x%08lX\n" -+ " mmapped 0x%lX\n" -+ " frame_num %d\n", i, -+ aewbstat.h3a_buff[i].virt_addr, -+ aewbstat.h3a_buff[i].addr_align, -+ aewbstat.h3a_buff[i].phy_addr, -+ aewbstat.h3a_buff[i].ispmmu_addr, -+ aewbstat.h3a_buff[i].mmap_addr, -+ aewbstat.h3a_buff[i].frame_num); -+ } -+ -+ active_buff->frame_num = 1; -+ -+ atomic_inc(&aewbstat.config_counter); -+ isph3a_aewb_enable(aewbcfg->aewb_enable); -+ isph3a_print_status(); -+ -+ return 0; -+} -+EXPORT_SYMBOL(isph3a_aewb_configure); -+ -+/** -+ * isph3a_aewb_request_statistics - REquest statistics and update gains in AEWB -+ * @aewbdata: Pointer to return AE AWB statistics data. -+ * -+ * This API allows the user to update White Balance gains, as well as -+ * exposure time and analog gain. It is also used to request frame -+ * statistics. -+ * -+ * Returns 0 if successful, -EINVAL when H3A engine is not enabled, or other -+ * errors when setting gains. -+ **/ -+int isph3a_aewb_request_statistics(struct isph3a_aewb_data *aewbdata) -+{ -+ int ret = 0; -+ u16 frame_diff = 0; -+ u16 frame_cnt = aewbstat.frame_count; -+ wait_queue_t wqt; -+ -+ if (!aewb_config_local.aewb_enable) { -+ printk(KERN_ERR "H3A engine not enabled\n"); -+ return -EINVAL; -+ } -+ -+ DPRINTK_ISPH3A("isph3a_aewb_request_statistics: Enter " -+ "(frame req. => %d, current frame => %d," -+ "update => %d)\n", -+ aewbdata->frame_number, frame_cnt, aewbdata->update); -+ DPRINTK_ISPH3A("User data received: \n"); -+ DPRINTK_ISPH3A("Digital gain = 0x%04x\n", aewbdata->dgain); -+ DPRINTK_ISPH3A("WB gain b *= 0x%04x\n", aewbdata->wb_gain_b); -+ DPRINTK_ISPH3A("WB gain r *= 0x%04x\n", aewbdata->wb_gain_r); -+ DPRINTK_ISPH3A("WB gain gb = 0x%04x\n", aewbdata->wb_gain_gb); -+ DPRINTK_ISPH3A("WB gain gr = 0x%04x\n", aewbdata->wb_gain_gr); -+ -+ if (!aewbdata->update) { -+ aewbdata->h3a_aewb_statistics_buf = NULL; -+ goto out; -+ } -+ if (aewbdata->update & SET_DIGITAL_GAIN) -+ h3awb_update.dgain = (u16)aewbdata->dgain; -+ if (aewbdata->update & SET_COLOR_GAINS) { -+ h3awb_update.coef0 = (u8)aewbdata->wb_gain_gr; -+ h3awb_update.coef1 = (u8)aewbdata->wb_gain_r; -+ h3awb_update.coef2 = (u8)aewbdata->wb_gain_b; -+ h3awb_update.coef3 = (u8)aewbdata->wb_gain_gb; -+ } -+ if (aewbdata->update & (SET_COLOR_GAINS | SET_DIGITAL_GAIN)) -+ wb_update = 1; -+ -+ if (!(aewbdata->update & REQUEST_STATISTICS)) { -+ aewbdata->h3a_aewb_statistics_buf = NULL; -+ goto out; -+ } -+ -+ if (aewbdata->frame_number < 1) { -+ printk(KERN_ERR "Illeagal frame number " -+ "requested (%d)\n", -+ aewbdata->frame_number); -+ return -EINVAL; -+ } -+ -+ isph3a_aewb_unlock_buffers(); -+ -+ DPRINTK_ISPH3A("Stats available?\n"); -+ ret = isph3a_aewb_stats_available(aewbdata); -+ if (!ret) -+ goto out; -+ -+ DPRINTK_ISPH3A("Stats in near future?\n"); -+ if (aewbdata->frame_number > frame_cnt) -+ frame_diff = aewbdata->frame_number - frame_cnt; -+ else if (aewbdata->frame_number < frame_cnt) { -+ if ((frame_cnt > (MAX_FRAME_COUNT - MAX_FUTURE_FRAMES)) && -+ (aewbdata->frame_number < MAX_FRAME_COUNT)) { -+ frame_diff = aewbdata->frame_number + MAX_FRAME_COUNT - -+ frame_cnt; -+ } else -+ frame_diff = MAX_FUTURE_FRAMES + 1; -+ } -+ -+ if (frame_diff > MAX_FUTURE_FRAMES) { -+ printk(KERN_ERR "Invalid frame requested, returning current" -+ " frame stats\n"); -+ aewbdata->frame_number = frame_cnt; -+ } -+ if (camnotify) { -+ DPRINTK_ISPH3A("NOT Waiting on stats IRQ for frame %d " -+ "because camnotify set\n", -+ aewbdata->frame_number); -+ aewbdata->h3a_aewb_statistics_buf = NULL; -+ goto out; -+ } -+ DPRINTK_ISPH3A("Waiting on stats IRQ for frame %d\n", -+ aewbdata->frame_number); -+ aewbstat.frame_req = aewbdata->frame_number; -+ aewbstat.stats_req = 1; -+ aewbstat.stats_done = 0; -+ init_waitqueue_entry(&wqt, current); -+ ret = wait_event_interruptible(aewbstat.stats_wait, -+ aewbstat.stats_done == 1); -+ if (ret < 0) { -+ printk(KERN_ERR "isph3a_aewb_request_statistics" -+ " Error on wait event %d\n", ret); -+ aewbdata->h3a_aewb_statistics_buf = NULL; -+ return ret; -+ } -+ -+ DPRINTK_ISPH3A("ISP AEWB request status interrupt raised\n"); -+ ret = isph3a_aewb_stats_available(aewbdata); -+ if (ret) { -+ DPRINTK_ISPH3A("After waiting for stats," -+ " stats not available!!\n"); -+ aewbdata->h3a_aewb_statistics_buf = NULL; -+ } -+out: -+ DPRINTK_ISPH3A("isph3a_aewb_request_statistics: " -+ "aewbdata->h3a_aewb_statistics_buf => %p\n", -+ aewbdata->h3a_aewb_statistics_buf); -+ aewbdata->curr_frame = aewbstat.frame_count; -+ -+ return 0; -+} -+EXPORT_SYMBOL(isph3a_aewb_request_statistics); -+ -+/** -+ * isph3a_aewb_init - Module Initialisation. -+ * -+ * Always returns 0. -+ **/ -+int __init isph3a_aewb_init(void) -+{ -+ memset(&aewbstat, 0, sizeof(aewbstat)); -+ memset(&aewb_regs, 0, sizeof(aewb_regs)); -+ -+ init_waitqueue_head(&aewbstat.stats_wait); -+ spin_lock_init(&aewbstat.buffer_lock); -+ return 0; -+} -+ -+/** -+ * isph3a_aewb_cleanup - Module exit. -+ **/ -+void isph3a_aewb_cleanup(void) -+{ -+ int i; -+ -+ for (i = 0; i < H3A_MAX_BUFF; i++) { -+ if (!aewbstat.h3a_buff[i].phy_addr) -+ continue; -+ -+ ispmmu_kunmap(aewbstat.h3a_buff[i].ispmmu_addr); -+ dma_free_coherent(NULL, -+ aewbstat.min_buf_size, -+ (void *)aewbstat.h3a_buff[i].virt_addr, -+ (dma_addr_t)aewbstat.h3a_buff[i].phy_addr); -+ } -+ memset(&aewbstat, 0, sizeof(aewbstat)); -+ memset(&aewb_regs, 0, sizeof(aewb_regs)); -+} -+ -+/** -+ * isph3a_print_status - Debug print. Values of H3A related registers. -+ **/ -+static void isph3a_print_status(void) -+{ -+ DPRINTK_ISPH3A("ISPH3A_PCR = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)); -+ DPRINTK_ISPH3A("ISPH3A_AEWWIN1 = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1)); -+ DPRINTK_ISPH3A("ISPH3A_AEWINSTART = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINSTART)); -+ DPRINTK_ISPH3A("ISPH3A_AEWINBLK = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK)); -+ DPRINTK_ISPH3A("ISPH3A_AEWSUBWIN = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWSUBWIN)); -+ DPRINTK_ISPH3A("ISPH3A_AEWBUFST = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST)); -+ DPRINTK_ISPH3A("stats windows = %d\n", aewbstat.win_count); -+ DPRINTK_ISPH3A("stats buff size = %d\n", aewbstat.stats_buf_size); -+ DPRINTK_ISPH3A("currently configured stats buff size = %d\n", -+ aewbstat.curr_cfg_buf_size); -+} -+ -+/** -+ * isph3a_notify - Unblocks user request for statistics when camera is off -+ * @notify: 1 - Camera is turned off -+ * -+ * Used when the user has requested statistics about a future frame, but the -+ * camera is turned off before it happens, and this function unblocks the -+ * request so the user can continue in its program. -+ **/ -+void isph3a_notify(int notify) -+{ -+ camnotify = notify; -+ if (camnotify && aewbstat.initialized) { -+ printk(KERN_DEBUG "Warning Camera Off \n"); -+ aewbstat.stats_req = 0; -+ aewbstat.stats_done = 1; -+ wake_up_interruptible(&aewbstat.stats_wait); -+ } -+} -+EXPORT_SYMBOL(isph3a_notify); -+ -+/** -+ * isph3a_save_context - Saves the values of the h3a module registers. -+ **/ -+void isph3a_save_context(void) -+{ -+ DPRINTK_ISPH3A(" Saving context\n"); -+ isp_save_context(isph3a_reg_list); -+ /* Avoid enable during restore ctx */ -+ isph3a_reg_list[0].val &= ~ISPH3A_PCR_AEW_EN; -+} -+EXPORT_SYMBOL(isph3a_save_context); -+ -+/** -+ * isph3a_restore_context - Restores the values of the h3a module registers. -+ **/ -+void isph3a_restore_context(void) -+{ -+ DPRINTK_ISPH3A(" Restoring context\n"); -+ isp_restore_context(isph3a_reg_list); -+} -+EXPORT_SYMBOL(isph3a_restore_context); -diff --git a/drivers/media/video/isp/isph3a.h b/drivers/media/video/isp/isph3a.h -new file mode 100644 -index 0000000..7d4c765 ---- /dev/null -+++ b/drivers/media/video/isp/isph3a.h -@@ -0,0 +1,127 @@ -+/* -+ * isph3a.h -+ * -+ * Include file for H3A module in TI's OMAP3 Camera ISP -+ * -+ * Copyright (C) 2009 Texas Instruments, Inc. -+ * -+ * Contributors: -+ * Sergio Aguirre <saaguirre@ti.com> -+ * Troy Laramy -+ * -+ * This package is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. -+ */ -+ -+#ifndef OMAP_ISP_H3A_H -+#define OMAP_ISP_H3A_H -+ -+#include <mach/isp_user.h> -+ -+#define AEWB_PACKET_SIZE 16 -+#define H3A_MAX_BUFF 5 -+ -+/* Flags for changed registers */ -+#define PCR_CHNG (1 << 0) -+#define AEWWIN1_CHNG (1 << 1) -+#define AEWINSTART_CHNG (1 << 2) -+#define AEWINBLK_CHNG (1 << 3) -+#define AEWSUBWIN_CHNG (1 << 4) -+#define PRV_WBDGAIN_CHNG (1 << 5) -+#define PRV_WBGAIN_CHNG (1 << 6) -+ -+/* ISPH3A REGISTERS bits */ -+#define ISPH3A_PCR_AF_EN (1 << 0) -+#define ISPH3A_PCR_AF_ALAW_EN (1 << 1) -+#define ISPH3A_PCR_AF_MED_EN (1 << 2) -+#define ISPH3A_PCR_AF_BUSY (1 << 15) -+#define ISPH3A_PCR_AEW_EN (1 << 16) -+#define ISPH3A_PCR_AEW_ALAW_EN (1 << 17) -+#define ISPH3A_PCR_AEW_BUSY (1 << 18) -+ -+#define WRITE_SAT_LIM(reg, sat_limit) \ -+ (reg = (reg & (~(ISPH3A_PCR_AEW_AVE2LMT_MASK))) \ -+ | (sat_limit << ISPH3A_PCR_AEW_AVE2LMT_SHIFT)) -+ -+#define WRITE_ALAW(reg, alaw_en) \ -+ (reg = (reg & (~(ISPH3A_PCR_AEW_ALAW_EN))) \ -+ | ((alaw_en & ISPH3A_PCR_AF_ALAW_EN) \ -+ << ISPH3A_PCR_AEW_ALAW_EN_SHIFT)) -+ -+#define WRITE_WIN_H(reg, height) \ -+ (reg = (reg & (~(ISPH3A_AEWWIN1_WINH_MASK))) \ -+ | (((height >> 1) - 1) << ISPH3A_AEWWIN1_WINH_SHIFT)) -+ -+#define WRITE_WIN_W(reg, width) \ -+ (reg = (reg & (~(ISPH3A_AEWWIN1_WINW_MASK))) \ -+ | (((width >> 1) - 1) << ISPH3A_AEWWIN1_WINW_SHIFT)) -+ -+#define WRITE_VER_C(reg, ver_count) \ -+ (reg = (reg & ~(ISPH3A_AEWWIN1_WINVC_MASK)) \ -+ | ((ver_count - 1) << ISPH3A_AEWWIN1_WINVC_SHIFT)) -+ -+#define WRITE_HOR_C(reg, hor_count) \ -+ (reg = (reg & ~(ISPH3A_AEWWIN1_WINHC_MASK)) \ -+ | ((hor_count - 1) << ISPH3A_AEWWIN1_WINHC_SHIFT)) -+ -+#define WRITE_VER_WIN_ST(reg, ver_win_st) \ -+ (reg = (reg & ~(ISPH3A_AEWINSTART_WINSV_MASK)) \ -+ | (ver_win_st << ISPH3A_AEWINSTART_WINSV_SHIFT)) -+ -+#define WRITE_HOR_WIN_ST(reg, hor_win_st) \ -+ (reg = (reg & ~(ISPH3A_AEWINSTART_WINSH_MASK)) \ -+ | (hor_win_st << ISPH3A_AEWINSTART_WINSH_SHIFT)) -+ -+#define WRITE_BLK_VER_WIN_ST(reg, blk_win_st) \ -+ (reg = (reg & ~(ISPH3A_AEWINBLK_WINSV_MASK)) \ -+ | (blk_win_st << ISPH3A_AEWINBLK_WINSV_SHIFT)) -+ -+#define WRITE_BLK_WIN_H(reg, height) \ -+ (reg = (reg & ~(ISPH3A_AEWINBLK_WINH_MASK)) \ -+ | (((height >> 1) - 1) << ISPH3A_AEWINBLK_WINH_SHIFT)) -+ -+#define WRITE_SUB_VER_INC(reg, sub_ver_inc) \ -+ (reg = (reg & ~(ISPH3A_AEWSUBWIN_AEWINCV_MASK)) \ -+ | (((sub_ver_inc >> 1) - 1) << ISPH3A_AEWSUBWIN_AEWINCV_SHIFT)) -+ -+#define WRITE_SUB_HOR_INC(reg, sub_hor_inc) \ -+ (reg = (reg & ~(ISPH3A_AEWSUBWIN_AEWINCH_MASK)) \ -+ | (((sub_hor_inc >> 1) - 1) << ISPH3A_AEWSUBWIN_AEWINCH_SHIFT)) -+ -+/** -+ * struct isph3a_aewb_xtrastats - Structure with extra statistics sent by cam. -+ * @field_count: Sequence number of returned framestats. -+ * @isph3a_aewb_xtrastats: Pointer to next buffer with extra stats. -+ */ -+struct isph3a_aewb_xtrastats { -+ unsigned long field_count; -+ struct isph3a_aewb_xtrastats *next; -+}; -+ -+void isph3a_aewb_setxtrastats(struct isph3a_aewb_xtrastats *xtrastats); -+ -+int isph3a_aewb_configure(struct isph3a_aewb_config *aewbcfg); -+ -+int isph3a_aewb_request_statistics(struct isph3a_aewb_data *aewbdata); -+ -+void isph3a_save_context(void); -+ -+void isph3a_restore_context(void); -+ -+void isph3a_aewb_enable(u8 enable); -+ -+int isph3a_aewb_busy(void); -+ -+void isph3a_aewb_suspend(void); -+ -+void isph3a_aewb_resume(void); -+ -+void isph3a_update_wb(void); -+ -+void isph3a_notify(int notify); -+#endif /* OMAP_ISP_H3A_H */ -diff --git a/drivers/media/video/isp/isphist.c b/drivers/media/video/isp/isphist.c -new file mode 100644 -index 0000000..c6f6a77 ---- /dev/null -+++ b/drivers/media/video/isp/isphist.c -@@ -0,0 +1,608 @@ -+/* -+ * isphist.c -+ * -+ * HISTOGRAM module for TI's OMAP3 Camera ISP -+ * -+ * Copyright (C) 2009 Texas Instruments, Inc. -+ * -+ * Contributors: -+ * Sergio Aguirre <saaguirre@ti.com> -+ * Troy Laramy -+ * -+ * This package is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. -+ */ -+ -+#include <asm/cacheflush.h> -+ -+#include <linux/delay.h> -+#include <linux/dma-mapping.h> -+#include <linux/uaccess.h> -+ -+#include "isp.h" -+#include "ispreg.h" -+#include "isphist.h" -+#include "ispmmu.h" -+ -+/** -+ * struct isp_hist_status - Histogram status. -+ * @hist_enable: Enables the histogram module. -+ * @initialized: Flag to indicate that the module is correctly initializated. -+ * @frame_cnt: Actual frame count. -+ * @frame_req: Frame requested by user. -+ * @completed: Flag to indicate if a frame request is completed. -+ */ -+struct isp_hist_status { -+ u8 hist_enable; -+ u8 pm_state; -+ u8 initialized; -+ u8 frame_cnt; -+ u8 frame_req; -+ u8 completed; -+} histstat; -+ -+/** -+ * struct isp_hist_buffer - Frame histogram buffer. -+ * @virt_addr: Virtual address to mmap the buffer. -+ * @phy_addr: Physical address of the buffer. -+ * @addr_align: Virtual Address 32 bytes aligned. -+ * @ispmmu_addr: Address of the buffer mapped by the ISPMMU. -+ * @mmap_addr: Mapped memory area of buffer. For userspace access. -+ */ -+struct isp_hist_buffer { -+ unsigned long virt_addr; -+ unsigned long phy_addr; -+ unsigned long addr_align; -+ unsigned long ispmmu_addr; -+ unsigned long mmap_addr; -+} hist_buff; -+ -+/** -+ * struct isp_hist_regs - Current value of Histogram configuration registers. -+ * @reg_pcr: Peripheral control register. -+ * @reg_cnt: Histogram control register. -+ * @reg_wb_gain: Histogram white balance gain register. -+ * @reg_r0_h: Region 0 horizontal register. -+ * @reg_r0_v: Region 0 vertical register. -+ * @reg_r1_h: Region 1 horizontal register. -+ * @reg_r1_v: Region 1 vertical register. -+ * @reg_r2_h: Region 2 horizontal register. -+ * @reg_r2_v: Region 2 vertical register. -+ * @reg_r3_h: Region 3 horizontal register. -+ * @reg_r3_v: Region 3 vertical register. -+ * @reg_hist_addr: Histogram address register. -+ * @reg_hist_data: Histogram data. -+ * @reg_hist_radd: Address register. When input data comes from mem. -+ * @reg_hist_radd_off: Address offset register. When input data comes from mem. -+ * @reg_h_v_info: Image size register. When input data comes from mem. -+ */ -+static struct isp_hist_regs { -+ u32 reg_pcr; -+ u32 reg_cnt; -+ u32 reg_wb_gain; -+ u32 reg_r0_h; -+ u32 reg_r0_v; -+ u32 reg_r1_h; -+ u32 reg_r1_v; -+ u32 reg_r2_h; -+ u32 reg_r2_v; -+ u32 reg_r3_h; -+ u32 reg_r3_v; -+ u32 reg_hist_addr; -+ u32 reg_hist_data; -+ u32 reg_hist_radd; -+ u32 reg_hist_radd_off; -+ u32 reg_h_v_info; -+} hist_regs; -+ -+/* Structure for saving/restoring histogram module registers */ -+struct isp_reg isphist_reg_list[] = { -+ {OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, 0}, -+ {OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN, 0}, -+ {OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ, 0}, -+ {OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT, 0}, -+ {OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ, 0}, -+ {OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT, 0}, -+ {OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ, 0}, -+ {OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT, 0}, -+ {OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ, 0}, -+ {OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT, 0}, -+ {OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR, 0}, -+ {OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD, 0}, -+ {OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD_OFF, 0}, -+ {OMAP3_ISP_IOMEM_HIST, ISPHIST_H_V_INFO, 0}, -+ {0, ISP_TOK_TERM, 0} -+}; -+ -+static void isp_hist_print_status(void); -+ -+void __isp_hist_enable(u8 enable) -+{ -+ if (enable) -+ DPRINTK_ISPHIST(" histogram enabled \n"); -+ else -+ DPRINTK_ISPHIST(" histogram disabled \n"); -+ -+ isp_reg_and_or(OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR, ~ISPHIST_PCR_EN, -+ (enable ? ISPHIST_PCR_EN : 0)); -+ histstat.hist_enable = enable; -+} -+ -+/** -+ * isp_hist_enable - Enables ISP Histogram submodule operation. -+ * @enable: 1 - Enables the histogram submodule. -+ * -+ * Client should configure all the Histogram registers before calling this -+ * function. -+ **/ -+void isp_hist_enable(u8 enable) -+{ -+ __isp_hist_enable(enable); -+ histstat.pm_state = enable; -+} -+ -+/** -+ * isp_hist_suspend - Suspend ISP Histogram submodule. -+ **/ -+void isp_hist_suspend(void) -+{ -+ if (histstat.pm_state) -+ __isp_hist_enable(0); -+} -+ -+/** -+ * isp_hist_resume - Resume ISP Histogram submodule. -+ **/ -+void isp_hist_resume(void) -+{ -+ if (histstat.pm_state) -+ __isp_hist_enable(1); -+} -+ -+int isp_hist_busy(void) -+{ -+ return isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR) & -+ ISPHIST_PCR_BUSY; -+} -+ -+ -+/** -+ * isp_hist_update_regs - Helper function to update Histogram registers. -+ **/ -+static void isp_hist_update_regs(void) -+{ -+ isp_reg_writel(hist_regs.reg_pcr, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR); -+ isp_reg_writel(hist_regs.reg_cnt, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT); -+ isp_reg_writel(hist_regs.reg_wb_gain, OMAP3_ISP_IOMEM_HIST, -+ ISPHIST_WB_GAIN); -+ isp_reg_writel(hist_regs.reg_r0_h, OMAP3_ISP_IOMEM_HIST, -+ ISPHIST_R0_HORZ); -+ isp_reg_writel(hist_regs.reg_r0_v, OMAP3_ISP_IOMEM_HIST, -+ ISPHIST_R0_VERT); -+ isp_reg_writel(hist_regs.reg_r1_h, OMAP3_ISP_IOMEM_HIST, -+ ISPHIST_R1_HORZ); -+ isp_reg_writel(hist_regs.reg_r1_v, OMAP3_ISP_IOMEM_HIST, -+ ISPHIST_R1_VERT); -+ isp_reg_writel(hist_regs.reg_r2_h, OMAP3_ISP_IOMEM_HIST, -+ ISPHIST_R2_HORZ); -+ isp_reg_writel(hist_regs.reg_r2_v, OMAP3_ISP_IOMEM_HIST, -+ ISPHIST_R2_VERT); -+ isp_reg_writel(hist_regs.reg_r3_h, OMAP3_ISP_IOMEM_HIST, -+ ISPHIST_R3_HORZ); -+ isp_reg_writel(hist_regs.reg_r3_v, OMAP3_ISP_IOMEM_HIST, -+ ISPHIST_R3_VERT); -+ isp_reg_writel(hist_regs.reg_hist_addr, OMAP3_ISP_IOMEM_HIST, -+ ISPHIST_ADDR); -+ isp_reg_writel(hist_regs.reg_hist_data, OMAP3_ISP_IOMEM_HIST, -+ ISPHIST_DATA); -+ isp_reg_writel(hist_regs.reg_hist_radd, OMAP3_ISP_IOMEM_HIST, -+ ISPHIST_RADD); -+ isp_reg_writel(hist_regs.reg_hist_radd_off, OMAP3_ISP_IOMEM_HIST, -+ ISPHIST_RADD_OFF); -+ isp_reg_writel(hist_regs.reg_h_v_info, OMAP3_ISP_IOMEM_HIST, -+ ISPHIST_H_V_INFO); -+} -+ -+/** -+ * isp_hist_isr - Callback from ISP driver for HIST interrupt. -+ * @status: IRQ0STATUS in case of MMU error, 0 for hist interrupt. -+ * arg1 and arg2 Not used as of now. -+ **/ -+static void isp_hist_isr(unsigned long status, isp_vbq_callback_ptr arg1, -+ void *arg2) -+{ -+ isp_hist_enable(0); -+ -+ if (!(status & HIST_DONE)) -+ return; -+ -+ if (!histstat.completed) { -+ if (histstat.frame_req == histstat.frame_cnt) { -+ histstat.frame_cnt = 0; -+ histstat.frame_req = 0; -+ histstat.completed = 1; -+ } else { -+ isp_hist_enable(1); -+ histstat.frame_cnt++; -+ } -+ } -+} -+ -+/** -+ * isp_hist_reset_mem - clear Histogram memory before start stats engine. -+ * -+ * Returns 0 after histogram memory was cleared. -+ **/ -+static int isp_hist_reset_mem(void) -+{ -+ int i; -+ -+ isp_reg_or(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLR_EN); -+ -+ for (i = 0; i < HIST_MEM_SIZE; i++) -+ isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); -+ -+ isp_reg_and(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ~ISPHIST_CNT_CLR_EN); -+ -+ return 0; -+} -+ -+/** -+ * isp_hist_set_params - Helper function to check and store user given params. -+ * @user_cfg: Pointer to user configuration structure. -+ * -+ * Returns 0 on success configuration. -+ **/ -+static int isp_hist_set_params(struct isp_hist_config *user_cfg) -+{ -+ -+ int reg_num = 0; -+ int bit_shift = 0; -+ -+ -+ if (isp_hist_busy()) -+ return -EINVAL; -+ -+ if (user_cfg->input_bit_width > MIN_BIT_WIDTH) -+ WRITE_DATA_SIZE(hist_regs.reg_cnt, 0); -+ else -+ WRITE_DATA_SIZE(hist_regs.reg_cnt, 1); -+ -+ WRITE_SOURCE(hist_regs.reg_cnt, user_cfg->hist_source); -+ -+ if (user_cfg->hist_source) { -+ WRITE_HV_INFO(hist_regs.reg_h_v_info, user_cfg->hist_h_v_info); -+ -+ if ((user_cfg->hist_radd & ISP_32B_BOUNDARY_BUF) == -+ user_cfg->hist_radd) { -+ WRITE_RADD(hist_regs.reg_hist_radd, -+ user_cfg->hist_radd); -+ } else { -+ printk(KERN_ERR "Address should be in 32 byte boundary" -+ "\n"); -+ return -EINVAL; -+ } -+ -+ if ((user_cfg->hist_radd_off & ISP_32B_BOUNDARY_OFFSET) == -+ user_cfg->hist_radd_off) { -+ WRITE_RADD_OFF(hist_regs.reg_hist_radd_off, -+ user_cfg->hist_radd_off); -+ } else { -+ printk(KERN_ERR "Offset should be in 32 byte boundary" -+ "\n"); -+ return -EINVAL; -+ } -+ -+ } -+ -+ isp_hist_reset_mem(); -+ DPRINTK_ISPHIST("ISPHIST: Memory Cleared\n"); -+ histstat.frame_req = user_cfg->hist_frames; -+ -+ if (unlikely(user_cfg->wb_gain_R > MAX_WB_GAIN || -+ user_cfg->wb_gain_RG > MAX_WB_GAIN || -+ user_cfg->wb_gain_B > MAX_WB_GAIN || -+ user_cfg->wb_gain_BG > MAX_WB_GAIN)) { -+ printk(KERN_ERR "Invalid WB gain\n"); -+ return -EINVAL; -+ } else { -+ WRITE_WB_R(hist_regs.reg_wb_gain, user_cfg->wb_gain_R); -+ WRITE_WB_RG(hist_regs.reg_wb_gain, user_cfg->wb_gain_RG); -+ WRITE_WB_B(hist_regs.reg_wb_gain, user_cfg->wb_gain_B); -+ WRITE_WB_BG(hist_regs.reg_wb_gain, user_cfg->wb_gain_BG); -+ } -+ -+ /* Regions size and position */ -+ -+ if (user_cfg->num_regions > MAX_REGIONS) -+ return -EINVAL; -+ -+ if (likely((user_cfg->reg0_hor & ISPHIST_REGHORIZ_HEND_MASK) - -+ ((user_cfg->reg0_hor & ISPHIST_REGHORIZ_HSTART_MASK) >> -+ ISPHIST_REGHORIZ_HSTART_SHIFT))) { -+ WRITE_REG_HORIZ(hist_regs.reg_r0_h, user_cfg->reg0_hor); -+ reg_num++; -+ } else { -+ printk(KERN_ERR "Invalid Region parameters\n"); -+ return -EINVAL; -+ } -+ -+ if (likely((user_cfg->reg0_ver & ISPHIST_REGVERT_VEND_MASK) - -+ ((user_cfg->reg0_ver & ISPHIST_REGVERT_VSTART_MASK) >> -+ ISPHIST_REGVERT_VSTART_SHIFT))) { -+ WRITE_REG_VERT(hist_regs.reg_r0_v, user_cfg->reg0_ver); -+ } else { -+ printk(KERN_ERR "Invalid Region parameters\n"); -+ return -EINVAL; -+ } -+ -+ if (user_cfg->num_regions >= 1) { -+ if (likely((user_cfg->reg1_hor & ISPHIST_REGHORIZ_HEND_MASK) - -+ ((user_cfg->reg1_hor & -+ ISPHIST_REGHORIZ_HSTART_MASK) >> -+ ISPHIST_REGHORIZ_HSTART_SHIFT))) { -+ WRITE_REG_HORIZ(hist_regs.reg_r1_h, user_cfg->reg1_hor); -+ } else { -+ printk(KERN_ERR "Invalid Region parameters\n"); -+ return -EINVAL; -+ } -+ -+ if (likely((user_cfg->reg1_ver & ISPHIST_REGVERT_VEND_MASK) - -+ ((user_cfg->reg1_ver & -+ ISPHIST_REGVERT_VSTART_MASK) >> -+ ISPHIST_REGVERT_VSTART_SHIFT))) { -+ WRITE_REG_VERT(hist_regs.reg_r1_v, user_cfg->reg1_ver); -+ } else { -+ printk(KERN_ERR "Invalid Region parameters\n"); -+ return -EINVAL; -+ } -+ } -+ -+ if (user_cfg->num_regions >= 2) { -+ if (likely((user_cfg->reg2_hor & ISPHIST_REGHORIZ_HEND_MASK) - -+ ((user_cfg->reg2_hor & -+ ISPHIST_REGHORIZ_HSTART_MASK) >> -+ ISPHIST_REGHORIZ_HSTART_SHIFT))) { -+ WRITE_REG_HORIZ(hist_regs.reg_r2_h, user_cfg->reg2_hor); -+ } else { -+ printk(KERN_ERR "Invalid Region parameters\n"); -+ return -EINVAL; -+ } -+ -+ if (likely((user_cfg->reg2_ver & ISPHIST_REGVERT_VEND_MASK) - -+ ((user_cfg->reg2_ver & -+ ISPHIST_REGVERT_VSTART_MASK) >> -+ ISPHIST_REGVERT_VSTART_SHIFT))) { -+ WRITE_REG_VERT(hist_regs.reg_r2_v, user_cfg->reg2_ver); -+ } else { -+ printk(KERN_ERR "Invalid Region parameters\n"); -+ return -EINVAL; -+ } -+ } -+ -+ if (user_cfg->num_regions >= 3) { -+ if (likely((user_cfg->reg3_hor & ISPHIST_REGHORIZ_HEND_MASK) - -+ ((user_cfg->reg3_hor & -+ ISPHIST_REGHORIZ_HSTART_MASK) >> -+ ISPHIST_REGHORIZ_HSTART_SHIFT))) { -+ WRITE_REG_HORIZ(hist_regs.reg_r3_h, user_cfg->reg3_hor); -+ } else { -+ printk(KERN_ERR "Invalid Region parameters\n"); -+ return -EINVAL; -+ } -+ -+ if (likely((user_cfg->reg3_ver & ISPHIST_REGVERT_VEND_MASK) - -+ ((user_cfg->reg3_ver & -+ ISPHIST_REGVERT_VSTART_MASK) >> -+ ISPHIST_REGVERT_VSTART_SHIFT))) { -+ WRITE_REG_VERT(hist_regs.reg_r3_v, user_cfg->reg3_ver); -+ } else { -+ printk(KERN_ERR "Invalid Region parameters\n"); -+ return -EINVAL; -+ } -+ } -+ reg_num = user_cfg->num_regions; -+ if (unlikely(((user_cfg->hist_bins > BINS_256) && -+ (user_cfg->hist_bins != BINS_32)) || -+ ((user_cfg->hist_bins == BINS_256) && -+ reg_num != 0) || ((user_cfg->hist_bins == -+ BINS_128) && reg_num >= 2))) { -+ printk(KERN_ERR "Invalid Bins Number: %d\n", -+ user_cfg->hist_bins); -+ return -EINVAL; -+ } else { -+ WRITE_NUM_BINS(hist_regs.reg_cnt, user_cfg->hist_bins); -+ } -+ -+ if (user_cfg->input_bit_width > MAX_BIT_WIDTH || -+ user_cfg->input_bit_width < MIN_BIT_WIDTH) { -+ printk(KERN_ERR "Invalid Bit Width: %d\n", -+ user_cfg->input_bit_width); -+ return -EINVAL; -+ } else { -+ switch (user_cfg->hist_bins) { -+ case BINS_256: -+ bit_shift = user_cfg->input_bit_width - 8; -+ break; -+ case BINS_128: -+ bit_shift = user_cfg->input_bit_width - 7; -+ break; -+ case BINS_64: -+ bit_shift = user_cfg->input_bit_width - 6; -+ break; -+ case BINS_32: -+ bit_shift = user_cfg->input_bit_width - 5; -+ break; -+ default: -+ return -EINVAL; -+ } -+ WRITE_BIT_SHIFT(hist_regs.reg_cnt, bit_shift); -+ } -+ -+ isp_hist_update_regs(); -+ histstat.initialized = 1; -+ -+ return 0; -+} -+ -+/** -+ * isp_hist_configure - API to configure HIST registers. -+ * @histcfg: Pointer to user configuration structure. -+ * -+ * Returns 0 on success configuration. -+ **/ -+int isp_hist_configure(struct isp_hist_config *histcfg) -+{ -+ -+ int ret = 0; -+ -+ if (NULL == histcfg) { -+ printk(KERN_ERR "Null argument in configuration. \n"); -+ return -EINVAL; -+ } -+ -+ if (!histstat.initialized) { -+ DPRINTK_ISPHIST("Setting callback for HISTOGRAM\n"); -+ ret = isp_set_callback(CBK_HIST_DONE, isp_hist_isr, -+ (void *)NULL, (void *)NULL); -+ if (ret) { -+ printk(KERN_ERR "No callback for HIST\n"); -+ return ret; -+ } -+ } -+ -+ ret = isp_hist_set_params(histcfg); -+ if (ret) { -+ printk(KERN_ERR "Invalid parameters! \n"); -+ return ret; -+ } -+ -+ histstat.frame_cnt = 0; -+ histstat.completed = 0; -+ isp_hist_enable(1); -+ isp_hist_print_status(); -+ -+ return 0; -+} -+EXPORT_SYMBOL(isp_hist_configure); -+ -+/** -+ * isp_hist_request_statistics - Request statistics in Histogram. -+ * @histdata: Pointer to data structure. -+ * -+ * This API allows the user to request for histogram statistics. -+ * -+ * Returns 0 on successful request. -+ **/ -+int isp_hist_request_statistics(struct isp_hist_data *histdata) -+{ -+ int i, ret; -+ u32 curr; -+ -+ if (isp_hist_busy()) -+ return -EBUSY; -+ -+ if (!histstat.completed && histstat.initialized) -+ return -EINVAL; -+ -+ isp_reg_or(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLR_EN); -+ -+ for (i = 0; i < HIST_MEM_SIZE; i++) { -+ curr = isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA); -+ ret = put_user(curr, histdata->hist_statistics_buf + i); -+ if (ret) { -+ printk(KERN_ERR "Failed copy_to_user for " -+ "HIST stats buff, %d\n", ret); -+ } -+ } -+ -+ isp_reg_and(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, -+ ~ISPHIST_CNT_CLR_EN); -+ histstat.completed = 0; -+ return 0; -+} -+EXPORT_SYMBOL(isp_hist_request_statistics); -+ -+/** -+ * isp_hist_init - Module Initialization. -+ * -+ * Returns 0 if successful. -+ **/ -+int __init isp_hist_init(void) -+{ -+ memset(&histstat, 0, sizeof(histstat)); -+ memset(&hist_regs, 0, sizeof(hist_regs)); -+ -+ return 0; -+} -+ -+/** -+ * isp_hist_cleanup - Module cleanup. -+ **/ -+void isp_hist_cleanup(void) -+{ -+ memset(&histstat, 0, sizeof(histstat)); -+ memset(&hist_regs, 0, sizeof(hist_regs)); -+} -+ -+/** -+ * isphist_save_context - Saves the values of the histogram module registers. -+ **/ -+void isphist_save_context(void) -+{ -+ DPRINTK_ISPHIST(" Saving context\n"); -+ isp_save_context(isphist_reg_list); -+} -+EXPORT_SYMBOL(isphist_save_context); -+ -+/** -+ * isphist_restore_context - Restores the values of the histogram module regs. -+ **/ -+void isphist_restore_context(void) -+{ -+ DPRINTK_ISPHIST(" Restoring context\n"); -+ isp_restore_context(isphist_reg_list); -+} -+EXPORT_SYMBOL(isphist_restore_context); -+ -+/** -+ * isp_hist_print_status - Debug print -+ **/ -+static void isp_hist_print_status(void) -+{ -+ DPRINTK_ISPHIST("ISPHIST_PCR = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR)); -+ DPRINTK_ISPHIST("ISPHIST_CNT = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT)); -+ DPRINTK_ISPHIST("ISPHIST_WB_GAIN = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN)); -+ DPRINTK_ISPHIST("ISPHIST_R0_HORZ = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ)); -+ DPRINTK_ISPHIST("ISPHIST_R0_VERT = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT)); -+ DPRINTK_ISPHIST("ISPHIST_R1_HORZ = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ)); -+ DPRINTK_ISPHIST("ISPHIST_R1_VERT = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT)); -+ DPRINTK_ISPHIST("ISPHIST_R2_HORZ = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ)); -+ DPRINTK_ISPHIST("ISPHIST_R2_VERT = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT)); -+ DPRINTK_ISPHIST("ISPHIST_R3_HORZ = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ)); -+ DPRINTK_ISPHIST("ISPHIST_R3_VERT = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT)); -+ DPRINTK_ISPHIST("ISPHIST_ADDR = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR)); -+ DPRINTK_ISPHIST("ISPHIST_RADD = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD)); -+ DPRINTK_ISPHIST("ISPHIST_RADD_OFF = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD_OFF)); -+ DPRINTK_ISPHIST("ISPHIST_H_V_INFO = 0x%08x\n", -+ isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_H_V_INFO)); -+} -diff --git a/drivers/media/video/isp/isphist.h b/drivers/media/video/isp/isphist.h -new file mode 100644 -index 0000000..6b17c4e ---- /dev/null -+++ b/drivers/media/video/isp/isphist.h -@@ -0,0 +1,105 @@ -+/* -+ * isphist.h -+ * -+ * Header file for HISTOGRAM module in TI's OMAP3 Camera ISP -+ * -+ * Copyright (C) 2009 Texas Instruments, Inc. -+ * -+ * Contributors: -+ * Sergio Aguirre <saaguirre@ti.com> -+ * Troy Laramy -+ * -+ * This package is free software; you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License version 2 as -+ * published by the Free Software Foundation. -+ * -+ * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR -+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED -+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. -+ */ -+ -+#ifndef OMAP_ISP_HIST_H -+#define OMAP_ISP_HIST_H -+ -+#include <mach/isp_user.h> -+ -+#define MAX_REGIONS 0x4 -+#define MAX_WB_GAIN 255 -+#define MIN_WB_GAIN 0x0 -+#define MAX_BIT_WIDTH 14 -+#define MIN_BIT_WIDTH 8 -+ -+#define ISPHIST_PCR_EN (1 << 0) -+#define HIST_MEM_SIZE 1024 -+#define ISPHIST_CNT_CLR_EN (1 << 7) -+ -+#define WRITE_SOURCE(reg, source) \ -+ (reg = (reg & ~(ISPHIST_CNT_SOURCE_MASK)) \ -+ | (source << ISPHIST_CNT_SOURCE_SHIFT)) -+ -+#define WRITE_HV_INFO(reg, hv_info) \ -+ (reg = ((reg & ~(ISPHIST_HV_INFO_MASK)) \ -+ | (hv_info & ISPHIST_HV_INFO_MASK))) -+ -+#define WRITE_RADD(reg, radd) \ -+ (reg = (reg & ~(ISPHIST_RADD_MASK)) \ -+ | (radd << ISPHIST_RADD_SHIFT)) -+ -+#define WRITE_RADD_OFF(reg, radd_off) \ -+ (reg = (reg & ~(ISPHIST_RADD_OFF_MASK)) \ -+ | (radd_off << ISPHIST_RADD_OFF_SHIFT)) -+ -+#define WRITE_BIT_SHIFT(reg, bit_shift) \ -+ (reg = (reg & ~(ISPHIST_CNT_SHIFT_MASK)) \ -+ | (bit_shift << ISPHIST_CNT_SHIFT_SHIFT)) -+ -+#define WRITE_DATA_SIZE(reg, data_size) \ -+ (reg = (reg & ~(ISPHIST_CNT_DATASIZE_MASK)) \ -+ | (data_size << ISPHIST_CNT_DATASIZE_SHIFT)) -+ -+#define WRITE_NUM_BINS(reg, num_bins) \ -+ (reg = (reg & ~(ISPHIST_CNT_BINS_MASK)) \ -+ | (num_bins << ISPHIST_CNT_BINS_SHIFT)) -+ -+#define WRITE_WB_R(reg, reg_wb_gain) \ -+ reg = ((reg & ~(ISPHIST_WB_GAIN_WG00_MASK)) \ -+ | (reg_wb_gain << ISPHIST_WB_GAIN_WG00_SHIFT)) -+ -+#define WRITE_WB_RG(reg, reg_wb_gain) \ -+ (reg = (reg & ~(ISPHIST_WB_GAIN_WG01_MASK)) \ -+ | (reg_wb_gain << ISPHIST_WB_GAIN_WG01_SHIFT)) -+ -+#define WRITE_WB_B(reg, reg_wb_gain) \ -+ (reg = (reg & ~(ISPHIST_WB_GAIN_WG02_MASK)) \ -+ | (reg_wb_gain << ISPHIST_WB_GAIN_WG02_SHIFT)) -+ -+#define WRITE_WB_BG(reg, reg_wb_gain) \ -+ (reg = (reg & ~(ISPHIST_WB_GAIN_WG03_MASK)) \ -+ | (reg_wb_gain << ISPHIST_WB_GAIN_WG03_SHIFT)) -+ -+#define WRITE_REG_HORIZ(reg, reg_n_hor) \ -+ (reg = ((reg & ~ISPHIST_REGHORIZ_MASK) \ -+ | (reg_n_hor & ISPHIST_REGHORIZ_MASK))) -+ -+#define WRITE_REG_VERT(reg, reg_n_vert) \ -+ (reg = ((reg & ~ISPHIST_REGVERT_MASK) \ -+ | (reg_n_vert & ISPHIST_REGVERT_MASK))) -+ -+ -+void isp_hist_enable(u8 enable); -+ -+int isp_hist_busy(void); -+ -+int isp_hist_configure(struct isp_hist_config *histcfg); -+ -+int isp_hist_request_statistics(struct isp_hist_data *histdata); -+ -+void isphist_save_context(void); -+ -+void isp_hist_suspend(void); -+ -+void isp_hist_resume(void); -+ -+void isphist_restore_context(void); -+ -+#endif /* OMAP_ISP_HIST */ --- -1.5.6.5 - |