From patchwork Mon Aug 3 17:42:48 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: s-paulraj@ti.com X-Patchwork-Id: 38942 Received: from comal.ext.ti.com (comal.ext.ti.com [198.47.26.152]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n73HjHSV001578 for ; Mon, 3 Aug 2009 17:45:18 GMT Received: from dlep36.itg.ti.com ([157.170.170.91]) by comal.ext.ti.com (8.13.7/8.13.7) with ESMTP id n73HgqUB020124; Mon, 3 Aug 2009 12:42:58 -0500 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep36.itg.ti.com (8.13.8/8.13.8) with ESMTP id n73Hgpis012480; Mon, 3 Aug 2009 12:42:51 -0500 (CDT) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id 295F080627; Mon, 3 Aug 2009 12:42:51 -0500 (CDT) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dlep33.itg.ti.com (dlep33.itg.ti.com [157.170.170.112]) by linux.omap.com (Postfix) with ESMTP id AED5980626 for ; Mon, 3 Aug 2009 12:42:49 -0500 (CDT) Received: from legion.dal.design.ti.com (localhost [127.0.0.1]) by dlep33.itg.ti.com (8.13.7/8.13.7) with ESMTP id n73HgnNi023514; Mon, 3 Aug 2009 12:42:49 -0500 (CDT) Received: from gt5d9d821.telogy.design.ti.com (gt5d9d821.telogy.design.ti.com [158.218.100.23]) by legion.dal.design.ti.com (8.11.7p1+Sun/8.11.7) with ESMTP id n73HgmZ12276; Mon, 3 Aug 2009 12:42:48 -0500 (CDT) Received: from gt5d9d821.telogy.design.ti.com (localhost.localdomain [127.0.0.1]) by gt5d9d821.telogy.design.ti.com (8.13.1/8.13.1) with ESMTP id n73HgmLn009086; Mon, 3 Aug 2009 13:42:48 -0400 Received: (from a0866907@localhost) by gt5d9d821.telogy.design.ti.com (8.13.1/8.13.1/Submit) id n73HgmAx009083; Mon, 3 Aug 2009 13:42:48 -0400 From: s-paulraj@ti.com To: davinci-linux-open-source@linux.davincidsp.com Date: Mon, 3 Aug 2009 13:42:48 -0400 Message-Id: <1249321368-9060-1-git-send-email-s-paulraj@ti.com> X-Mailer: git-send-email 1.6.0.4 Cc: Subject: [PATCH] DaVinci: DM355 Auto Focus driver X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.4 Precedence: list List-Id: davinci-linux-open-source.linux.davincidsp.com List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: davinci-linux-open-source-bounces@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces@linux.davincidsp.com From: Sandeep Paulraj The patch adds support for the DM355 Auto Focus driver Signed-off-by: Sandeep Paulraj --- This patch is dependent on the VPFE patches aubmitted by Murali Karicheri. Those patches are not yet in the Davinci GIT so this patch will not compile These patches can be found at http://arago-project.org/git/people/?p=sneha/linux-davinci-staging.git;a=summary Test applications for Auto Focus driver can be found at http://arago-project.org/git/people/?p=murali/linux-davinci-examples.git;a=summary This Auto Focus driver patch is not meant for upstream submission drivers/media/video/Kconfig | 9 + drivers/media/video/davinci/Makefile | 3 + drivers/media/video/davinci/dm355_af.c | 849 +++++++++++++++++++++++++++++ drivers/media/video/davinci/dm355_af_hw.c | 192 +++++++ include/media/davinci/dm355_af.h | 179 ++++++ include/media/davinci/dm355_af_hw.h | 139 +++++ 6 files changed, 1371 insertions(+), 0 deletions(-) create mode 100644 drivers/media/video/davinci/Makefile create mode 100644 drivers/media/video/davinci/dm355_af.c create mode 100644 drivers/media/video/davinci/dm355_af_hw.c create mode 100644 include/media/davinci/dm355_af.h create mode 100644 include/media/davinci/dm355_af_hw.h diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index 84b6fc1..e772b52 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig @@ -505,6 +505,15 @@ config VIDEO_VIVI Say Y here if you want to test video apps or debug V4L devices. In doubt, say N. +config VIDEO_DM355_AF + tristate "DM355 Auto Focus Driver" + depends on ARCH_DAVINCI_DM355 + default y + help + DM355 Auto Focus Driver. Auto Focus driver is used to support + control loop for Auto Focus. It collects metrics about the image or + video data + source "drivers/media/video/bt8xx/Kconfig" config VIDEO_PMS diff --git a/drivers/media/video/davinci/Makefile b/drivers/media/video/davinci/Makefile new file mode 100644 index 0000000..17b3ab9 --- /dev/null +++ b/drivers/media/video/davinci/Makefile @@ -0,0 +1,3 @@ +dm355_af_driver-objs += dm355_af.o dm355_af_hw.o +obj-$(CONFIG_VIDEO_DM355_AF) += dm355_af_driver.o + diff --git a/drivers/media/video/davinci/dm355_af.c b/drivers/media/video/davinci/dm355_af.c new file mode 100644 index 0000000..e779ab0 --- /dev/null +++ b/drivers/media/video/davinci/dm355_af.c @@ -0,0 +1,849 @@ +/* + * Copyright (C) 2009 Texas Instruments Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct af_device *af_dev_configptr; +static struct cdev c_dev; +static struct class *af_class; +static dev_t dev; +struct device *afdev; + +/* Inline function to free reserver pages */ +inline void af_free_pages(unsigned long addr, unsigned long bufsize) +{ + unsigned long tempaddr; + unsigned long size; + + tempaddr = addr; + + if (!addr) + return; + size = PAGE_SIZE << (get_order(bufsize)); + + while (size > 0) { + ClearPageReserved(virt_to_page(addr)); + addr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + free_pages(tempaddr, get_order(bufsize)); +} + +/* Function to check paxel parameters */ +static int af_validate_parameters(void) +{ + int result = 0; + + /* Check horizontal Count */ + if ((af_dev_configptr->config->paxel_config.hz_cnt < + AF_PAXEL_HORIZONTAL_COUNT_MIN) || + (af_dev_configptr->config->paxel_config.hz_cnt > + AF_PAXEL_HORIZONTAL_COUNT_MAX)) { + dev_err(afdev, "\n Invalid Parameters"); + dev_err(afdev, "\n Paxel Horizontal Count" + " is incorrect"); + result = -EINVAL; + } + + /* Check Vertical Count */ + if ((af_dev_configptr->config->paxel_config.vt_cnt < + AF_PAXEL_VERTICAL_COUNT_MIN) || + (af_dev_configptr->config->paxel_config.vt_cnt > + AF_PAXEL_VERTICAL_COUNT_MAX)) { + dev_err(afdev, "\n Invalid Parameters"); + dev_err(afdev, "\n Paxel Vertical Count" + " is incorrect"); + result = -EINVAL; + } + + /* Check line increment */ + if ((AF_NOT_EVEN == + AF_CHECK_EVEN( + af_dev_configptr->config->paxel_config.line_incr)) || + (af_dev_configptr->config->paxel_config.line_incr < + AF_LINE_INCR_MIN) || + (af_dev_configptr->config->paxel_config.line_incr > + AF_LINE_INCR_MAX)) { + dev_err(afdev, "\n Invalid Parameters"); + dev_err(afdev, "\n Paxel Line Increment" + " is incorrect"); + result = -EINVAL; + } + + /* Check width */ + if ((AF_NOT_EVEN == + AF_CHECK_EVEN( + af_dev_configptr->config->paxel_config.width)) || + (af_dev_configptr->config->paxel_config.width < + AF_WIDTH_MIN) || + (af_dev_configptr->config->paxel_config.width > + AF_WIDTH_MAX)) { + dev_err(afdev, "\n Invalid Parameters"); + dev_err(afdev, "\n Paxel Width is incorrect"); + result = -EINVAL; + } + + /* Check Height */ + if ((AF_NOT_EVEN == + AF_CHECK_EVEN( + af_dev_configptr->config->paxel_config.height)) || + (af_dev_configptr->config->paxel_config.height < + AF_HEIGHT_MIN) || + (af_dev_configptr->config->paxel_config.height > + AF_HEIGHT_MAX)) { + dev_err(afdev, "\n Invalid Parameters"); + dev_err(afdev, "\n Paxel Height is incorrect"); + result = -EINVAL; + } + + /* Check Horizontal Start */ + if ((AF_NOT_EVEN == + AF_CHECK_EVEN( + af_dev_configptr->config->paxel_config.hz_start)) || + (af_dev_configptr->config->paxel_config.hz_start < + (af_dev_configptr->config->iir_config.hz_start_pos + 2)) || + (af_dev_configptr->config->paxel_config.hz_start < + AF_HZSTART_MIN) || + (af_dev_configptr->config->paxel_config.hz_start > + AF_HZSTART_MAX)) { + dev_err(afdev, "\n Invalid Parameters"); + dev_err(afdev, "\n Paxel horizontal start" + "is incorrect"); + result = -EINVAL; + } + + /* Check Vertical Start */ + if ((af_dev_configptr->config->paxel_config.vt_start < + AF_VTSTART_MIN) || + (af_dev_configptr->config->paxel_config.vt_start > + AF_VTSTART_MAX)) { + dev_err(afdev, "\n Invalid Parameters"); + dev_err(afdev, "\n Paxel vertical start is incorrect"); + result = -EINVAL; + } + + /* Check Threshold */ + if ((af_dev_configptr->config->hmf_config.threshold > + AF_MEDTH_MAX) && + (af_dev_configptr->config->hmf_config.enable == + H3A_AF_ENABLE)) { + dev_err(afdev, "\n Invalid Parameters"); + dev_err(afdev, "\n Horizontal Median Filter" + " Threshold is incorrect"); + result = -EINVAL; + } + + /* Check IIRSH start */ + if (af_dev_configptr->config->iir_config.hz_start_pos > + AF_IIRSH_MAX) { + dev_err(afdev, "\n Invalid Parameters"); + dev_err(afdev, "\n IIR FITLER horizontal" + " start position is wrong"); + result = -EINVAL; + } + + /* Verify ALaw */ + if ((af_dev_configptr->config->alaw_enable < + H3A_AF_DISABLE) || + (af_dev_configptr->config->alaw_enable > H3A_AF_ENABLE)) { + dev_err(afdev, "\n Invalid Parameters"); + dev_err(afdev, "\n ALaw Setting is incorrect"); + result = -EINVAL; + } + + /* Check RGB position */ + if ((af_dev_configptr->config->rgb_pos < GR_GB_BAYER) || + (af_dev_configptr->config->rgb_pos > RB_GG_CUSTOM)) { + dev_err(afdev, "\n Invalid Parameters"); + dev_err(afdev, "\n RGB Position Setting is incorrect"); + result = -EINVAL; + } + + /* Verify Horizontal Median Filter Setting */ + if ((af_dev_configptr->config->hmf_config.enable < H3A_AF_DISABLE) || + (af_dev_configptr->config->hmf_config.enable > + H3A_AF_ENABLE)) { + dev_err(afdev, "\n Invalid Parameters"); + dev_err(afdev, "\n Horizontal Median Filter" + " Setting is incorrect"); + result = -EINVAL; + } + + if (((af_dev_configptr->config->paxel_config.vt_cnt) * + (af_dev_configptr->config->paxel_config.height) + + (af_dev_configptr->config->paxel_config.vt_start)) > 156) { + dev_err(afdev, "\n Only 156 Lines are" + " supported for CCDC mode"); + dev_err(afdev, "\n Paxel count * Height" + " + vertical Start should not exceed 156"); + result = -EINVAL; + } + + return result; +} + +/* Function to perform hardware set up */ +int af_hardware_setup(void) +{ + int result; + int buff_size; + unsigned long adr, size; + unsigned int busyaf; + + /* Get the value of PCR register */ + busyaf = AF_GET_PCR; + + /* Mask with BUSYAF bit */ + busyaf = busyaf & AF_BUSYAF; + + /* Shift it 15 times to get value of 1 or 0 */ + busyaf = busyaf >> 15; + + /*If busy bit is 1 then busy lock registers caanot be configured */ + if (busyaf == 1) { + /* Hardware cannot be configure while engine is busy */ + dev_err(afdev, "AF_register_setup_ERROR : Engine Busy"); + dev_err(afdev, "\n Configuration cannot be done "); + return -EBUSY; + } + + /*Check IIR Coefficient and start Values */ + result = af_validate_parameters(); + + if (result < 0) + return result; + + /* Compute buffer size */ + buff_size = + (af_dev_configptr->config->paxel_config.hz_cnt) * + (af_dev_configptr->config->paxel_config.vt_cnt) * AF_PAXEL_SIZE; + + /* Deallocate the previosu buffers */ + if (af_dev_configptr->buff_old) + af_free_pages((unsigned long)af_dev_configptr->buff_old, + af_dev_configptr->size_paxel); + + /* Free current buffer */ + if (af_dev_configptr->buff_curr) + af_free_pages((unsigned long)af_dev_configptr->buff_curr, + af_dev_configptr->size_paxel); + + /* Free application buffers */ + if (af_dev_configptr->buff_app) + af_free_pages((unsigned long)af_dev_configptr->buff_app, + af_dev_configptr->size_paxel); + + /* Reallocate the buffer as per new paxel configurations */ + af_dev_configptr->buff_old = + (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, + get_order(buff_size)); + + if (af_dev_configptr->buff_old == NULL) + return -ENOMEM; + + /* allocate the memory for storing old statistics */ + adr = (unsigned long)af_dev_configptr->buff_old; + size = PAGE_SIZE << (get_order(buff_size)); + while (size > 0) { + /* make sure the frame buffers + are never swapped out of memory */ + SetPageReserved(virt_to_page(adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + /*Allocate memory for current buffer */ + af_dev_configptr->buff_curr = + (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, + get_order(buff_size)); + + /* Free the previously allocated buffer */ + if (af_dev_configptr->buff_curr == NULL) { + if (af_dev_configptr->buff_old) + af_free_pages((unsigned long)af_dev_configptr-> + buff_old, buff_size); + return -ENOMEM; + } + + adr = (unsigned long)af_dev_configptr->buff_curr; + size = PAGE_SIZE << (get_order(buff_size)); + + while (size > 0) { + /* make sure the frame buffers + are never swapped out of memory */ + SetPageReserved(virt_to_page(adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + /*Allocate memory for old buffer */ + af_dev_configptr->buff_app = + (void *)__get_free_pages(GFP_KERNEL | GFP_DMA, + get_order(buff_size)); + + if (af_dev_configptr->buff_app == NULL) { + /*Free the previously allocated buffer */ + if (af_dev_configptr->buff_curr) + af_free_pages((unsigned long)af_dev_configptr-> + buff_curr, buff_size); + /*Free the previously allocated buffer */ + if (af_dev_configptr->buff_old) + af_free_pages((unsigned long)af_dev_configptr-> + buff_old, buff_size); + return -ENOMEM; + } + + adr = (unsigned long)af_dev_configptr->buff_app; + size = PAGE_SIZE << (get_order(buff_size)); + + while (size > 0) { + /* + * make sure the frame buffers + * are never swapped out of memory + */ + SetPageReserved(virt_to_page(adr)); + adr += PAGE_SIZE; + size -= PAGE_SIZE; + } + + result = af_register_setup(af_dev_configptr); + if (result < 0) + return result; + + af_dev_configptr->size_paxel = buff_size; + + /*Set configuration flag to indicate HW setup done */ + af_dev_configptr->af_config = H3A_AF_CONFIG; + + return 0; +} + +/* + * This function called when driver is opened.It creates Channel + * Configuration Structure + */ +static int af_open(struct inode *inode, struct file *filp) +{ + /*Return if device is in use */ + if (af_dev_configptr->in_use == AF_IN_USE) + return -EBUSY; + af_dev_configptr->config = NULL; + + /* Allocate memory for Device Structure */ + af_dev_configptr->config = (struct af_configuration *) + kmalloc(sizeof(struct af_configuration), GFP_KERNEL); + + if (af_dev_configptr->config == NULL) { + dev_err(afdev, "Error : Kmalloc fail\n"); + return -ENOMEM; + } + + /* Initialize the wait queue */ + init_waitqueue_head(&(af_dev_configptr->af_wait_queue)); + + /* Driver is in use */ + af_dev_configptr->in_use = AF_IN_USE; + + /* Hardware is not set up */ + af_dev_configptr->af_config = H3A_AF_CONFIG_NOT_DONE; + af_dev_configptr->buffer_filled = 0; + + /* Initialize the mutex */ + mutex_init(&(af_dev_configptr->read_blocked)); + + return 0; +} + +/* + * This function called when driver is closed. + * It will deallocate all the buffers. + */ +static int af_release(struct inode *inode, struct file *filp) +{ + af_engine_setup(0); + + /* Free all the buffers */ + if (af_dev_configptr->buff_curr) + af_free_pages((unsigned long)af_dev_configptr->buff_curr, + af_dev_configptr->size_paxel); + + /* Free old buffer */ + if (af_dev_configptr->buff_old) + af_free_pages((unsigned long)af_dev_configptr->buff_old, + af_dev_configptr->size_paxel); + + /* Free application buffer */ + if (af_dev_configptr->buff_app) + af_free_pages((unsigned long)af_dev_configptr->buff_app, + af_dev_configptr->size_paxel); + + /* Release memory for configuration structure of this channel */ + af_dev_configptr->buff_curr = NULL; + af_dev_configptr->buff_old = NULL; + af_dev_configptr->buff_app = NULL; + + + kfree(af_dev_configptr->config); + + af_dev_configptr->config = NULL; + + /* Device is not in use */ + af_dev_configptr->in_use = AF_NOT_IN_USE; + + return 0; +} + +static void af_platform_release(struct device *device) +{ + /* This is called when the reference count goes to zero */ +} + +static int af_probe(struct device *device) +{ + afdev = device; + return 0; +} + +static int af_remove(struct device *device) +{ + return 0; +} + +/* + * This function will process IOCTL commands sent by the application and + * control the device IO operations. + */ +static int af_ioctl(struct inode *inode, struct file *filep, + unsigned int cmd, unsigned long arg) +{ + struct af_configuration afconfig = *(af_dev_configptr->config); + int result = 0; + + /* Block the mutex while ioctl is called */ + result = mutex_lock_interruptible(&af_dev_configptr->read_blocked); + if (result) + return result; + + /* + * Extract the type and number bitfields, and don't + * decode wrong cmds return ENOTTY (inappropriate ioctl) + */ + if (_IOC_TYPE(cmd) != AF_MAGIC_NO) { + /* Release the mutex */ + mutex_unlock(&af_dev_configptr->read_blocked); + return -ENOTTY; + } + + if (_IOC_NR(cmd) > AF_IOC_MAXNR) { + /* Release the mutex */ + mutex_unlock(&af_dev_configptr->read_blocked); + return -ENOTTY; + } + + /*Use 'access_ok' to validate user space pointer */ + if (_IOC_DIR(cmd) & _IOC_READ) + result = + !access_ok(VERIFY_WRITE, (void __user *)arg, + _IOC_SIZE(cmd)); + else if (_IOC_DIR(cmd) & _IOC_WRITE) + result = + !access_ok(VERIFY_READ, (void __user *)arg, + _IOC_SIZE(cmd)); + + if (result) { + /* Release the mutex */ + mutex_unlock(&af_dev_configptr->read_blocked); + return -EFAULT; + } + + switch (cmd) { + + /* + * This ioctl is used to perform hardware + * set up for AF Engine + * It will configura all the registers + */ + case AF_S_PARAM: + /* Copy params structure passed by user */ + if (copy_from_user(af_dev_configptr->config, + (struct af_configuration *)arg, + sizeof(struct af_configuration))) { + /* Release the mutex */ + mutex_unlock(&af_dev_configptr->read_blocked); + return -EFAULT; + } + + /* Call AF_hardware_setup to perform register configuration */ + result = af_hardware_setup(); + if (!result) { + result = af_dev_configptr->size_paxel; + } else { + dev_err(afdev, "Error : AF_S_PARAM failed"); + *(af_dev_configptr->config) = afconfig; + } + break; + + /* This ioctl will get the paramters from application */ + case AF_G_PARAM: + /* Check if Hardware is configured or not */ + if (af_dev_configptr->af_config == H3A_AF_CONFIG) { + if (copy_to_user((struct af_configuration *)arg, + af_dev_configptr->config, + sizeof(struct af_configuration))) { + mutex_unlock( + &af_dev_configptr->read_blocked); + return -EFAULT; + } else + result = af_dev_configptr->size_paxel; + } else { + dev_dbg(afdev, "Error : AF Hardware not configured"); + result = -EINVAL; + } + + break; + + /* + * This ioctl will enable AF Engine + * if hardware configuration is done + */ + case AF_ENABLE: + /* Check if hardware is configured or not */ + if (af_dev_configptr->af_config == H3A_AF_CONFIG_NOT_DONE) { + dev_err(afdev, "Error : AF Hardware not configured"); + result = -EINVAL; + } else + af_engine_setup(1); + break; + + /* This ioctl will disable AF Engine */ + case AF_DISABLE: + af_engine_setup(0); + break; + + default: + dev_err(afdev, "Error : Invalid IOCTL!"); + result = -ENOTTY; + break; + } + + /* Before returning increment mutex */ + mutex_unlock(&af_dev_configptr->read_blocked); + + return result; +} + +/* Function will return the statistics to user */ +ssize_t af_read(struct file *filep, char *kbuff, size_t size, loff_t * offset) +{ + void *buff_temp; + int result = 0; + int ret; + + /* mutex will return immediately if read call is busy */ + ret = mutex_lock_interruptible(&af_dev_configptr->read_blocked); + if (ret != 0) { + dev_err(afdev, "\n Read Call : busy"); + return -EBUSY; + } + + /* + * If no of bytes specified by the user is less + * than that of buffer return error + */ + if (size < af_dev_configptr->size_paxel) { + dev_err(afdev, "\n Error : Invalid buffer size"); + mutex_unlock(&(af_dev_configptr->read_blocked)); + return -1; + } + + /* + * The value of bufffer_filled flag determines + * the status of statistics + */ + if (af_dev_configptr->buffer_filled == 0) { + dev_dbg(afdev, "Read call is blocked ................"); + /* Block the read call until + * new statistics are available + * or timer expires + */ + wait_event_interruptible_timeout(af_dev_configptr-> + af_wait_queue, + af_dev_configptr-> + buffer_filled, AF_TIMEOUT); + dev_dbg(afdev, + "\n Read Call Unblocked.........................."); + } + + if (af_dev_configptr->buffer_filled == 1) { + /* + * New Statistics are available + * Disable the interrupts while + * swapping the buffers */ + dev_dbg(afdev, "\n Reading............................."); + disable_irq(4); + + af_dev_configptr->buffer_filled = 0; + + /* Swap application buffer and old buffer */ + buff_temp = af_dev_configptr->buff_old; + af_dev_configptr->buff_old = af_dev_configptr->buff_app; + af_dev_configptr->buff_app = buff_temp; + + dev_dbg(afdev, "\n Reading Done..........................."); + + /* Enable the interrupts once swapping is done */ + enable_irq(4); + + /* + * New Statistics are not availaible + * copy the application buffer to user + * Return the entire statistics to user + */ + if (copy_to_user(kbuff, af_dev_configptr->buff_app, + af_dev_configptr->size_paxel)) { + /* Release the mutex in case of fault */ + mutex_unlock(&(af_dev_configptr->read_blocked)); + return -EFAULT; + } else + result = af_dev_configptr->size_paxel; + } + + /* Release the mutex */ + mutex_unlock(&(af_dev_configptr->read_blocked)); + dev_dbg(afdev, "\n Read APPLICATION BUFFER %d", + *((int *)((af_dev_configptr->buff_app)))); + + return result; +} + +static irqreturn_t af_isr(int irq, void *dev_id) +{ + void *buff_temp; + int busyaf; + + /* Get the value of PCR register */ + busyaf = AF_GET_PCR; + + /* If AF Engine has enabled, interrupt is not for AF */ + if ((busyaf & 0x01) == 0) + return IRQ_RETVAL(IRQ_NONE); + + /* + * Service the Interrupt + * Set buffer filled flag to indicate + * statistics are available + * Swap current buffer and old buffer + */ + if (af_dev_configptr) { + buff_temp = af_dev_configptr->buff_curr; + af_dev_configptr->buff_curr = af_dev_configptr->buff_old; + af_dev_configptr->buff_old = buff_temp; + + /* Set AF Buf st to current register address */ + if (af_dev_configptr->buff_curr) + af_set_address((unsigned long) + virt_to_phys(af_dev_configptr->buff_curr)); + + /* Wake up read as new statistics are available */ + af_dev_configptr->buffer_filled = 1; + wake_up(&(af_dev_configptr->af_wait_queue)); + return IRQ_RETVAL(IRQ_HANDLED); + } + return IRQ_RETVAL(IRQ_NONE); +} + +/* File Operation Structure */ +static const struct file_operations af_fops = { + .owner = THIS_MODULE, + .open = af_open, + .ioctl = af_ioctl, + .read = af_read, + .release = af_release +}; +static struct platform_device afdevice = { + .name = "dm355_af", + .id = 2, + .dev = { + .release = af_platform_release, + } +}; + +static struct device_driver af_driver = { + .name = "dm355_af", + .bus = &platform_bus_type, + .probe = af_probe, + .remove = af_remove, +}; + +/* Function to register the AF character device driver. */ +#define DRIVERNAME "DM355AF" +int __init af_init(void) +{ + int err; + int result = 0; + unsigned int vpssclk; + + /* + * Register the driver in the kernel + * dynmically get the major number + * for the driver using + * alloc_chrdev_region function + */ + result = alloc_chrdev_region(&dev, 0, 1, DRIVERNAME); + + if (result < 0) { + printk(KERN_ERR "Error: Could not register character device"); + return -ENODEV; + } + + printk(KERN_INFO "af major#: %d, minor# %d\n", MAJOR(dev), MINOR(dev)); + + /* allocate memory for device structure and initialize it with 0 */ + af_dev_configptr = kmalloc(sizeof(struct af_device), GFP_KERNEL); + if (!af_dev_configptr) { + printk(KERN_ERR "Error : kmalloc fail"); + unregister_chrdev_region(dev, AF_NR_DEVS); + return -ENOMEM; + } + + /* Initialize character device */ + cdev_init(&c_dev, &af_fops); + c_dev.owner = THIS_MODULE; + c_dev.ops = &af_fops; + + err = cdev_add(&c_dev, dev, 1); + if (err) { + printk("Error : Error in Adding Davinci AF"); + unregister_chrdev_region(dev, AF_NR_DEVS); + kfree(af_dev_configptr); + + return -err; + } + + /* register driver as a platform driver */ + if (driver_register(&af_driver) != 0) { + unregister_chrdev_region(dev, 1); + cdev_del(&c_dev); + return -EINVAL; + } + + /* Register the drive as a platform device */ + if (platform_device_register(&afdevice) != 0) { + driver_unregister(&af_driver); + unregister_chrdev_region(dev, 1); + cdev_del(&c_dev); + return -EINVAL; + } + + af_class = class_create(THIS_MODULE, "dm355_af"); + if (!af_class) { + printk("af_init: error in creating device class\n"); + driver_unregister(&af_driver); + platform_device_unregister(&afdevice); + unregister_chrdev_region(dev, 1); + unregister_chrdev(MAJOR(dev), DRIVERNAME); + cdev_del(&c_dev); + return -EINVAL; + } + + /* register device class */ + device_create(af_class, NULL, dev, NULL, "dm355_af"); + + AF_SETGAMMAWD; + + vpssclk = AF_GETCLKCTRL; + vpssclk |= (1 << 4); + AF_SETCLKCTRL(vpssclk); + + /* Set up the Interrupt handler for H3AINT interrupt */ + result = request_irq(4, af_isr, IRQF_SHARED, "dm355h3a_af", + (void *)af_dev_configptr); + + if (result != 0) { + printk(KERN_ERR "Error : Request IRQ Failed"); + unregister_chrdev_region(dev, AF_NR_DEVS); + + kfree(af_dev_configptr); + device_destroy(af_class, dev); + class_destroy(af_class); + driver_unregister(&af_driver); + platform_device_unregister(&afdevice); + cdev_del(&c_dev); + return result; + } + + /* Initialize device structure */ + memset((unsigned char *)af_dev_configptr, 0, sizeof(struct af_device)); + + af_dev_configptr->in_use = AF_NOT_IN_USE; + af_dev_configptr->buffer_filled = 0; + return 0; +} + +/* + * This function is called by the kernel while unloading the driver. + * It will unregister character device driver + */ +void __exit af_cleanup(void) +{ + /* Return if driver is busy */ + if (af_dev_configptr->in_use == AF_IN_USE) { + printk("Error : Driver in use. Can't remove."); + return; + } + + free_irq(4, af_dev_configptr); + + /* Free device structure */ + kfree(af_dev_configptr); + + unregister_chrdev_region(dev, AF_NR_DEVS); + + driver_unregister(&af_driver); + + device_destroy(af_class, dev); + + class_destroy(af_class); + + platform_device_unregister(&afdevice); + + /* Unregistering the driver from the kernel */ + cdev_del(&c_dev); +} + +module_init(af_init) +module_exit(af_cleanup) +MODULE_LICENSE("GPL"); diff --git a/drivers/media/video/davinci/dm355_af_hw.c b/drivers/media/video/davinci/dm355_af_hw.c new file mode 100644 index 0000000..8ace9e4 --- /dev/null +++ b/drivers/media/video/davinci/dm355_af_hw.c @@ -0,0 +1,192 @@ +/* + * Copyright (C) 2009 Texas Instruments Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include +#include + +int 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 + * Set PCR Register + */ + pcr = regr(AFPCR); + + /* 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_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_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 Input Source as CCDC */ + pcr &= ~AF_INP_SRC; + pcr |= (AF_CCDC) << AF_INP_SRC_SHIFT; + + /* Set PCR Register */ + regw(pcr, AFPCR); + + /* + * Configure AFPAX1 Paxel parameter configuration + * Set Width in AFPAX1 Register + */ + pax1 &= ~PAXW; + pax1 |= + (AF_SET_VAL(af_dev->config->paxel_config.width)) << AF_PAXW_SHIFT; + + /* Set height in AFPAX1 */ + pax1 &= ~PAXH; + pax1 |= (AF_SET_VAL(af_dev->config->paxel_config.height)); + + regw(pax1, AFPAX1); + + /* + * Configure AFPAX2 Register + * Set Line Increment in AFPAX2 Register + */ + pax2 &= ~AFINCV; + pax2 |= + (AF_SET_VAL(af_dev->config->paxel_config.line_incr)) << + AF_LINE_INCR_SHIFT; + + /* Set Vertical Count */ + pax2 &= ~PAXVC; + pax2 |= (af_dev->config->paxel_config.vt_cnt - 1) << AF_VT_COUNT_SHIFT; + + /* Set Horizontal Count */ + pax2 &= ~PAXHC; + pax2 |= (af_dev->config->paxel_config.hz_cnt - 1); + regw(pax2, 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; + regw(paxstart, AFPAXSTART); + + /*Set IIRSH Register */ + regw(af_dev->config->iir_config.hz_start_pos, AFIIRSH); + + /* Set IIR Filter0 Coefficients */ + base_coef_set0 = 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; + regw(coef, base_coef_set0); + dev_dbg(afdev, "\n COEF0 %x", regr(base_coef_set0)); + base_coef_set0 = base_coef_set0 + AFCOEF_OFFSET; + } + + /* Set AFCOEF0010 Register */ + regw(af_dev->config->iir_config.coeff_set0[10], AFCOEF0010); + + /*Set IIR Filter1 Coefficients */ + base_coef_set1 = 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; + regw(coef, base_coef_set1); + dev_dbg(afdev, "\n COEF1 %x", regr(base_coef_set1)); + base_coef_set1 = base_coef_set1 + AFCOEF_OFFSET; + } + + /* Set AFCOEF0110 */ + regw(af_dev->config->iir_config.coeff_set1[10], AFCOEF1010); + + /* Set AFBUFST to Current buffer Physical Address */ + regw((unsigned int)(virt_to_phys(af_dev->buff_curr)), AFBUFST); + + AF_SETGAMMAWD; + dev_dbg(afdev, "\n PCR %x", pcr); + dev_dbg(afdev, "\n AFPAX1 %x", regr(AFPAX1)); + dev_dbg(afdev, "\n PAXSTART %x", paxstart); + dev_dbg(afdev, "\n PAX2 %x", regr(AFPAX2)); + dev_dbg(afdev, "\n COEF 10 %x", regr(AFCOEF0010)); + dev_dbg(afdev, "\n COEF 10 %x", regr(AFCOEF1010)); + dev_dbg(afdev, "\n AFBUFST %x", regr(AFBUFST)); + + return 0; +} + +/* Function to Enable/Disable AF Engine */ +inline void af_engine_setup(int enable) +{ + unsigned int pcr; + + pcr = regr(AFPCR); + dev_dbg(afdev, "\nEngine Setup value before PCR : %x", pcr); + + /* Set AF_EN bit in PCR Register */ + if (enable) + pcr |= AF_EN; + else + pcr &= ~AF_EN; + + regw(pcr, AFPCR); + + dev_dbg(afdev, "\n Engine Setup value after PCR : %x", pcr); +} + +/* Function to set address */ +inline void af_set_address(unsigned long address) +{ + regw(address, AFBUFST); +} diff --git a/include/media/davinci/dm355_af.h b/include/media/davinci/dm355_af.h new file mode 100644 index 0000000..a31e92d --- /dev/null +++ b/include/media/davinci/dm355_af.h @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2009 Texas Instruments Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef AF_DM355_DRIVER_H +#define AF_DM355_DRIVER_H + +/* Kernel Header files */ +#include + +#ifdef __KERNEL__ +#include +#include +#include +#include +#endif + +#ifdef __KERNEL__ +/* Device Constants */ +#define AF_MAJOR_NUMBER 0 +#define DEVICE_NAME "dm355_af" +#define AF_NR_DEVS 1 +#define AF_TIMEOUT ((300 * HZ) / 1000) +#endif + +/* Range Constants */ +#define AF_PAXEL_HORIZONTAL_COUNT_MIN 1 +#define AF_PAXEL_HORIZONTAL_COUNT_MAX 36 +#define AF_PAXEL_VERTICAL_COUNT_MIN 1 +#define AF_PAXEL_VERTICAL_COUNT_MAX 128 +#define AF_PAXEL_SIZE 48 +#define AF_WIDTH_MIN 8 +#define AF_WIDTH_MAX 256 +#define AF_LINE_INCR_MIN 2 +#define AF_LINE_INCR_MAX 32 +#define AF_HEIGHT_MIN 2 +#define AF_HEIGHT_MAX 256 +#define AF_HZSTART_MIN 2 +#define AF_HZSTART_MAX 4094 +#define AF_VTSTART_MIN 0 +#define AF_VTSTART_MAX 4095 +#define AF_MEDTH_MAX 255 +#define AF_IIRSH_MAX 4094 +#define AF_COEF_MIN 0xFFFFF800 +#define AF_COEF_MAX 0x000007FF +#define AF_NUMBER_OF_COEF 11 + +/* list of ioctls */ +#pragma pack(1) +#define AF_IOC_MAXNR 5 +#define AF_MAGIC_NO 'a' +#define AF_S_PARAM _IOWR(AF_MAGIC_NO, 1, struct af_configuration *) +#define AF_G_PARAM _IOWR(AF_MAGIC_NO, 2, struct af_configuration *) +#define AF_ENABLE _IO(AF_MAGIC_NO, 3) +#define AF_DISABLE _IO(AF_MAGIC_NO, 4) +#pragma pack() + +/* enum used for status of specific feature */ +enum h3a_af_enable { + H3A_AF_DISABLE = 0, + H3A_AF_ENABLE = 1 +}; + +enum af_config_flag { + H3A_AF_CONFIG_NOT_DONE, + H3A_AF_CONFIG +}; + +struct af_reg_dump { + unsigned int addr; + unsigned int val; +}; + +/* enum used for keep track of whether hardware is used */ +enum af_In_use { + AF_NOT_IN_USE = 0, + AF_IN_USE = 1 +}; + +enum af_mode { + ACCUMULATOR_SUMMED = 0, + ACCUMULATOR_PEAK = 1 +}; + +/* Red, Green, and blue pixel location in the AF windows */ +enum rgbpos { + GR_GB_BAYER = 0, /* GR and GB as Bayer pattern */ + RG_GB_BAYER = 1, /* RG and GB as Bayer pattern */ + GR_BG_BAYER = 2, /* GR and BG as Bayer pattern */ + RG_BG_BAYER = 3, /* RG and BG as Bayer pattern */ + GG_RB_CUSTOM = 4, /* GG and RB as custom pattern */ + RB_GG_CUSTOM = 5 /* RB and GG as custom pattern */ +}; + +/* Contains the information regarding the Horizontal Median Filter */ +struct af_hmf { + enum h3a_af_enable enable; + + /* Threshhold Value for orizontal Median Filter */ + unsigned int threshold; +}; + +/* Contains the information regarding the IIR Filters */ +struct af_iir { + unsigned int hz_start_pos; + + /* IIR Filter Coefficient for Set 0 */ + int coeff_set0[AF_NUMBER_OF_COEF]; + + /* IIR Filter Coefficient for Set 1 */ + int coeff_set1[AF_NUMBER_OF_COEF]; +}; + +/* Contains the information regarding the Paxels Structure in AF Engine */ +struct af_paxel { + unsigned int width; /* Width of the Paxel */ + unsigned int height; /* Height of the Paxel */ + unsigned int hz_start; /* Horizontal Start Position */ + unsigned int vt_start; /* Vertical Start Position */ + unsigned int hz_cnt; /* Horizontal Count */ + unsigned int vt_cnt; /* vertical Count */ + unsigned int line_incr; /* Line Increment */ +}; + +/* Contains the parameters required for hardware set up of AF Engine */ +struct af_configuration { + enum h3a_af_enable alaw_enable; /*ALAW status */ + struct af_hmf hmf_config; /*HMF configurations */ + enum rgbpos rgb_pos; /*RGB Positions */ + struct af_iir iir_config; /*IIR filter configurations */ + struct af_paxel paxel_config; /*Paxel parameters */ + enum af_mode mode; /*Accumulator mode */ +}; + +#ifdef __KERNEL__ +/* Structure for device of AF Engine */ +struct af_device { + enum af_In_use in_use; + + /*Device configuration structure */ + struct af_configuration *config; + void *buff_old; /*Contains the latest statistics */ + void *buff_curr; /*Buffer in which HW will */ + + /* + * Fill the statistics + * or HW is already filling statistics + */ + + void *buff_app; + + /* User space on read call */ + unsigned int buff_size; /* Size of image buffer */ + int buffer_filled; /* Flag indicates */ + + /*statistics are available */ + int size_paxel; /*Paxel size in bytes */ + wait_queue_head_t af_wait_queue; /*Wait queue for driver */ + /* mutex for driver */ + struct mutex read_blocked; + /* Flag indicates Engine is configured */ + enum af_config_flag af_config; +}; +#endif /* __KERNEL__ */ +#endif /* AF_DM355_DRIVER_H */ diff --git a/include/media/davinci/dm355_af_hw.h b/include/media/davinci/dm355_af_hw.h new file mode 100644 index 0000000..ce2b18f --- /dev/null +++ b/include/media/davinci/dm355_af_hw.h @@ -0,0 +1,139 @@ +/* + * Copyright (C) 2009 Texas Instruments Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef DM355_AF_DRIVER_HW_H +#define DM355_AF_DRIVER_HW_H + +/* Include driver header file */ +#include "dm355_af.h" +#include + +#ifdef __KERNEL__ + +/* Register Offsets */ +#define AFPID 0x0 /*Peripheral Revision */ +#define AFPCR 0x00000004 /*Peripheral Control Register */ +#define AFPAX1 0x00000008 /*Setup for the Paxel Configuration */ +#define AFPAX2 0x0000000c /*Setup for the Paxel Configuration */ +#define AFPAXSTART 0x00000010 /*Start Position for Engine Paxels */ +#define AFIIRSH 0x00000014 /*Start Position for IIRSH */ +#define AFBUFST 0x00000018 /*SDRAM/DDRAM Start address */ + +/*IIR filter coefficient data for SET 0 */ +#define AFCOEF010 0x0000001c +#define AFCOEF032 0x00000020 +#define AFCOEF054 0x00000024 +#define AFCOEF076 0x00000028 +#define AFCOEF098 0x0000002c +#define AFCOEF0010 0x00000030 + +/*IIR filter coefficient data for SET 1 */ +#define AFCOEF110 0x00000034 +#define AFCOEF132 0x00000038 +#define AFCOEF154 0x0000003c +#define AFCOEF176 0x00000040 +#define AFCOEF198 0x00000044 +#define AFCOEF1010 0x00000048 + +#define AF_RSDR_ADDR 0x00000060 /*SDRAM/DDRAM Read Address */ +#define AF_RSDR_OFFSET 0x00000064 /*SDRAM/DDRAM Line Offset */ +#define AF_SDR_FRSIZE 0x00000068 /*Frame Size for SDRAM read data */ + +#define AFCOEF_OFFSET 0x00000004 /* COEFFICIENT BASE ADDRESS */ + +#define AF_SET_VAL(x) (((x)/2)-1) +#define AF_NOT_EVEN 1 +#define AF_CHECK_EVEN(x) ((x)%2) + +/* PID fields */ +#define AF_TID (0xFF<<16) +#define AF_CID (0xFF<<8) +#define AF_PREV 0xFF + +/* PCR fields */ +#define AVE2LMT (0x3FF<<22) +#define AF_INP_SRC (1<<19) +#define AF_BUSYAEWB (1<<18) +#define AEW_ALAW_EN (1<<17) +#define AEW_EN (1<<16) +#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) + +#define AF_SETGAMMAWD __raw_writel(0x00000010, IO_ADDRESS(0x01C70680)) + +/* AFPAX1 fields */ +#define PAXW (0x7F<<16) +#define PAXH 0x7F + +#define AF_CCDC 0 + +/* 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) + +/* SDRAM Frame Size */ +#define AF_SDR_FRSIZE_HSIZE 0xFFF +#define AF_SDR_FRSIZE_VSIZE (0xFFF<<16) +#define AF_SDR_FRSIZE_BITSEL (0x7<<28) + +/* 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_INP_SRC_SHIFT 19 +#define AF_GETFRAME_SIZE (__raw_readl(IO_ADDRESS(0x01C70910))) +#define AF_GETINIT_XY (__raw_readl(IO_ADDRESS(0x01C70910))) +#define AF_INTSTATBASE (IO_ADDRESS(0x01C7080C)) +#define AF_EVNTSELADDR (IO_ADDRESS(0x01C70814)) +#define AF_CLKCTRL_ADDR (IO_ADDRESS(0x01C70004)) +#define AF_GETCLKCTRL __raw_readl(AF_CLKCTRL_ADDR) +#define AF_SETCLKCTRL(val) __raw_writel(val, AF_CLKCTRL_ADDR) + +/* Macros for register read and write */ +#define AF_IOBASE_VADDR IO_ADDRESS(0x01c70080) +#define regr(reg) __raw_readl((reg) + AF_IOBASE_VADDR) +#define regw(val, reg) __raw_writel(val, (reg) + AF_IOBASE_VADDR) +#define AF_GET_PCR __raw_readl(AF_IOBASE_VADDR + AFPCR) +#define AF_GETINTSTAT __raw_readl(AF_INTSTATBASE) + +extern struct device *afdev; +/* Function declaration */ +int af_register_setup(struct af_device *); +void af_engine_setup(int); +void af_set_address(unsigned long); + +#endif +#endif