* [REVIEW PATCH 07/14] OMAP: CAM: Add ISP CSI2 API
@ 2008-12-11 20:38 Aguirre Rodriguez, Sergio Alberto
2008-12-15 16:16 ` Tony Lindgren
2008-12-16 16:55 ` Hans Verkuil
0 siblings, 2 replies; 3+ messages in thread
From: Aguirre Rodriguez, Sergio Alberto @ 2008-12-11 20:38 UTC (permalink / raw)
To: linux-omap@vger.kernel.org, video4linux-list@redhat.com
Cc: Sakari Ailus, Tuukka.O Toivonen, Nagalla, Hari
>From c442f389de719b47f8ec63f0ae07b5e2c2ef7b9d Mon Sep 17 00:00:00 2001
From: Sergio Aguirre <saaguirre@ti.com>
Date: Thu, 11 Dec 2008 13:35:49 -0600
Subject: [PATCH] OMAP: CAM: Add ISP CSI2 API
Add ISP CSI2 API for operating OMAP3430 CSI2 receiver registers
Signed-off-by: Sergio Aguirre <saaguirre@ti.com>
---
drivers/media/video/isp/ispcsi2.c | 2106 +++++++++++++++++++++++++++++++++++++
drivers/media/video/isp/ispcsi2.h | 232 ++++
2 files changed, 2338 insertions(+), 0 deletions(-)
create mode 100644 drivers/media/video/isp/ispcsi2.c
create mode 100644 drivers/media/video/isp/ispcsi2.h
diff --git a/drivers/media/video/isp/ispcsi2.c b/drivers/media/video/isp/ispcsi2.c
new file mode 100644
index 0000000..423ea3a
--- /dev/null
+++ b/drivers/media/video/isp/ispcsi2.c
@@ -0,0 +1,2106 @@
+/*
+ * drivers/media/video/isp/ispcsi2.c
+ *
+ * Driver Library for ISP CSI Control module in TI's OMAP3 Camera ISP
+ * ISP CSI interface and IRQ related APIs are defined here.
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ *
+ * Contributors:
+ * Sergio Aguirre <saaguirre@ti.com>
+ * Dominic Curran <dcurran@ti.com>
+ *
+ * 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 <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <asm/mach-types.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-int-device.h>
+#include <linux/io.h>
+#include <mach/io.h>
+
+#include "isp.h"
+#include "ispreg.h"
+#include "ispcsi2.h"
+
+static struct isp_csi2_cfg current_csi2_cfg;
+static struct isp_csi2_cfg_update current_csi2_cfg_update;
+
+static bool update_complexio_cfg1;
+static bool update_phy_cfg0;
+static bool update_phy_cfg1;
+static bool update_ctx_ctrl1[8];
+static bool update_ctx_ctrl2[8];
+static bool update_ctx_ctrl3[8];
+static bool update_timing;
+static bool update_ctrl;
+static bool uses_videoport;
+
+/**
+ * isp_csi2_complexio_lanes_config - Configuration of CSI2 ComplexIO lanes.
+ * @reqcfg: Pointer to structure containing desired lane configuration
+ *
+ * Validates and saves to internal driver memory the passed configuration.
+ * Returns 0 if successful, or -EINVAL if null pointer is passed, invalid
+ * lane position or polarity is set, and if 2 lanes try to occupy the same
+ * position. To apply this settings, use the isp_csi2_complexio_lanes_update()
+ * function just after calling this function.
+ **/
+int isp_csi2_complexio_lanes_config(struct isp_csi2_lanes_cfg *reqcfg)
+{
+ int i;
+ bool pos_occupied[5] = {false, false, false, false, false};
+ struct isp_csi2_lanes_cfg *currlanes = ¤t_csi2_cfg.lanes;
+ struct isp_csi2_lanes_cfg_update *currlanes_u =
+ ¤t_csi2_cfg_update.lanes;
+
+ /* Validating parameters sent by driver */
+ if (reqcfg == NULL) {
+ printk(KERN_ERR "Invalid Complex IO Configuration sent by"
+ " sensor\n");
+ goto err_einval;
+ }
+
+ /* Data lanes verification */
+ for (i = 0; i < 4; i++) {
+ if ((reqcfg->data[i].pol > 1) || (reqcfg->data[i].pos > 5)) {
+ printk(KERN_ERR "Invalid CSI-2 Complex IO configuration"
+ " parameters for data lane #%d\n", i);
+ goto err_einval;
+ }
+ if ((pos_occupied[reqcfg->data[i].pos - 1] == true) &&
+ reqcfg->data[i].pos > 0) {
+ printk(KERN_ERR "Lane #%d already occupied\n",
+ reqcfg->data[i].pos);
+ goto err_einval;
+ } else
+ pos_occupied[reqcfg->data[i].pos - 1] = true;
+ }
+
+ /* Clock lane verification */
+ if ((reqcfg->clk.pol > 1) || (reqcfg->clk.pos > 5) ||
+ (reqcfg->clk.pos == 0)) {
+ printk(KERN_ERR "Invalid CSI-2 Complex IO configuration"
+ " parameters for clock lane\n");
+ goto err_einval;
+ }
+ if (pos_occupied[reqcfg->clk.pos - 1] == true) {
+ printk(KERN_ERR "Lane #%d already occupied",
+ reqcfg->clk.pos);
+ goto err_einval;
+ } else
+ pos_occupied[reqcfg->clk.pos - 1] = true;
+
+ for (i = 0; i < 4; i++) {
+ if (currlanes->data[i].pos != reqcfg->data[i].pos) {
+ currlanes->data[i].pos = reqcfg->data[i].pos;
+ currlanes_u->data[i] = true;
+ update_complexio_cfg1 = true;
+ }
+ if (currlanes->data[i].pol != reqcfg->data[i].pol) {
+ currlanes->data[i].pol = reqcfg->data[i].pol;
+ currlanes_u->data[i] = true;
+ update_complexio_cfg1 = true;
+ }
+ }
+
+ if (currlanes->clk.pos != reqcfg->clk.pos) {
+ currlanes->clk.pos = reqcfg->clk.pos;
+ currlanes_u->clk = true;
+ update_complexio_cfg1 = true;
+ }
+ if (currlanes->clk.pol != reqcfg->clk.pol) {
+ currlanes->clk.pol = reqcfg->clk.pol;
+ currlanes_u->clk = true;
+ update_complexio_cfg1 = true;
+ }
+ return 0;
+err_einval:
+ return -EINVAL;
+}
+
+/**
+ * isp_csi2_complexio_lanes_update - Applies CSI2 ComplexIO lanes configuration.
+ * @force_update: Flag to force rewrite of registers, even if they haven't been
+ * updated with the isp_csi2_complexio_lanes_config() function.
+ *
+ * It only saves settings when they were previously updated using the
+ * isp_csi2_complexio_lanes_config() function, unless the force_update flag is
+ * set to true.
+ * Always returns 0.
+ **/
+int isp_csi2_complexio_lanes_update(bool force_update)
+{
+ struct isp_csi2_lanes_cfg *currlanes = ¤t_csi2_cfg.lanes;
+ struct isp_csi2_lanes_cfg_update *currlanes_u =
+ ¤t_csi2_cfg_update.lanes;
+ u32 reg;
+ int i;
+
+ if ((update_complexio_cfg1 == false) && (force_update == false))
+ return 0;
+
+ reg = omap_readl(ISPCSI2_COMPLEXIO_CFG1);
+ for (i = 0; i < 4; i++) {
+ if ((currlanes_u->data[i] == true) || (force_update == true)) {
+ reg &= ~(ISPCSI2_COMPLEXIO_CFG1_DATA_POL_MASK(i + 1) |
+ ISPCSI2_COMPLEXIO_CFG1_DATA_POSITION_MASK(i +
+ 1));
+ reg |= (currlanes->data[i].pol <<
+ ISPCSI2_COMPLEXIO_CFG1_DATA_POL_SHIFT(i + 1));
+ reg |= (currlanes->data[i].pos <<
+ ISPCSI2_COMPLEXIO_CFG1_DATA_POSITION_SHIFT(i +
+ 1));
+ currlanes_u->data[i] = false;
+ }
+ }
+
+ if ((currlanes_u->clk == true) || (force_update == true)) {
+ reg &= ~(ISPCSI2_COMPLEXIO_CFG1_CLOCK_POL_MASK |
+ ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_MASK);
+ reg |= (currlanes->clk.pol <<
+ ISPCSI2_COMPLEXIO_CFG1_CLOCK_POL_SHIFT);
+ reg |= (currlanes->clk.pos <<
+ ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_SHIFT);
+ currlanes_u->clk = false;
+ }
+ omap_writel(reg, ISPCSI2_COMPLEXIO_CFG1);
+
+ update_complexio_cfg1 = false;
+ return 0;
+}
+
+/**
+ * isp_csi2_complexio_lanes_get - Gets CSI2 ComplexIO lanes configuration.
+ *
+ * Gets settings from HW registers and fills in the internal driver memory
+ * Always returns 0.
+ **/
+int isp_csi2_complexio_lanes_get(void)
+{
+ struct isp_csi2_lanes_cfg *currlanes = ¤t_csi2_cfg.lanes;
+ struct isp_csi2_lanes_cfg_update *currlanes_u =
+ ¤t_csi2_cfg_update.lanes;
+ u32 reg;
+ int i;
+
+ reg = omap_readl(ISPCSI2_COMPLEXIO_CFG1);
+ for (i = 0; i < 4; i++) {
+ currlanes->data[i].pol = (reg &
+ ISPCSI2_COMPLEXIO_CFG1_DATA_POL_MASK(i + 1)) >>
+ ISPCSI2_COMPLEXIO_CFG1_DATA_POL_SHIFT(i + 1);
+ currlanes->data[i].pos = (reg &
+ ISPCSI2_COMPLEXIO_CFG1_DATA_POSITION_MASK(i + 1)) >>
+ ISPCSI2_COMPLEXIO_CFG1_DATA_POSITION_SHIFT(i + 1);
+ currlanes_u->data[i] = false;
+ }
+ currlanes->clk.pol = (reg & ISPCSI2_COMPLEXIO_CFG1_CLOCK_POL_MASK) >>
+ ISPCSI2_COMPLEXIO_CFG1_CLOCK_POL_SHIFT;
+ currlanes->clk.pos = (reg &
+ ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_MASK) >>
+ ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_SHIFT;
+ currlanes_u->clk = false;
+
+ update_complexio_cfg1 = false;
+ return 0;
+}
+
+/**
+ * isp_csi2_complexio_power_status - Gets CSI2 ComplexIO power status.
+ *
+ * Returns 3 possible valid states: ISP_CSI2_POWER_OFF, ISP_CSI2_POWER_ON,
+ * and ISP_CSI2_POWER_ULPW.
+ **/
+static enum isp_csi2_power_cmds isp_csi2_complexio_power_status(void)
+{
+ enum isp_csi2_power_cmds ret;
+ u32 reg;
+
+ reg = omap_readl(ISPCSI2_COMPLEXIO_CFG1) &
+ ISPCSI2_COMPLEXIO_CFG1_PWR_STATUS_MASK;
+ switch (reg) {
+ case ISPCSI2_COMPLEXIO_CFG1_PWR_STATUS_OFF:
+ ret = ISP_CSI2_POWER_OFF;
+ break;
+ case ISPCSI2_COMPLEXIO_CFG1_PWR_STATUS_ON:
+ ret = ISP_CSI2_POWER_ON;
+ break;
+ case ISPCSI2_COMPLEXIO_CFG1_PWR_STATUS_ULPW:
+ ret = ISP_CSI2_POWER_ULPW;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return ret;
+}
+
+/**
+ * isp_csi2_complexio_power_autoswitch - Sets CSI2 ComplexIO power autoswitch.
+ * @enable: Sets or clears the autoswitch function enable flag.
+ *
+ * Always returns 0.
+ **/
+int isp_csi2_complexio_power_autoswitch(bool enable)
+{
+ u32 reg;
+
+ reg = omap_readl(ISPCSI2_COMPLEXIO_CFG1);
+ reg &= ~ISPCSI2_COMPLEXIO_CFG1_PWR_AUTO_MASK;
+
+ if (enable == true)
+ reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_AUTO_ENABLE;
+ else
+ reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_AUTO_DISABLE;
+
+ omap_writel(reg, ISPCSI2_COMPLEXIO_CFG1);
+ return 0;
+}
+
+/**
+ * isp_csi2_complexio_power - Sets the desired power command for CSI2 ComplexIO.
+ * @power_cmd: Power command to be set.
+ *
+ * Returns 0 if successful, or -EBUSY if the retry count is exceeded.
+ **/
+int isp_csi2_complexio_power(enum isp_csi2_power_cmds power_cmd)
+{
+ enum isp_csi2_power_cmds current_state;
+ u32 reg;
+ u8 retry_count;
+
+ reg = omap_readl(ISPCSI2_COMPLEXIO_CFG1) &
+ ~ISPCSI2_COMPLEXIO_CFG1_PWR_CMD_MASK;
+ switch (power_cmd) {
+ case ISP_CSI2_POWER_OFF:
+ reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_CMD_OFF;
+ break;
+ case ISP_CSI2_POWER_ON:
+ reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_CMD_ON;
+ break;
+ case ISP_CSI2_POWER_ULPW:
+ reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_CMD_ULPW;
+ break;
+ default:
+ printk(KERN_ERR "CSI2: ERROR - Wrong Power command!\n");
+ return -EINVAL;
+ }
+ omap_writel(reg, ISPCSI2_COMPLEXIO_CFG1);
+
+ retry_count = 0;
+ do {
+ udelay(50);
+ current_state = isp_csi2_complexio_power_status();
+
+ if (current_state != power_cmd) {
+ printk(KERN_DEBUG "CSI2: Complex IO power command not"
+ " yet taken.");
+ if (++retry_count < 100) {
+ printk(KERN_DEBUG " Retrying...\n");
+ udelay(50);
+ } else {
+ printk(KERN_DEBUG " Retry count exceeded!\n");
+ }
+ }
+ } while ((current_state != power_cmd) && (retry_count < 100));
+
+ if (retry_count == 100)
+ return -EBUSY;
+
+ return 0;
+}
+
+/**
+ * isp_csi2_ctrl_config_frame_mode - Configure if_en behaviour for CSI2
+ * @frame_mode: Desired action for IF_EN switch off. 0 - disable IF immediately
+ * 1 - disable after all Frame end Code is received in all
+ * contexts.
+ *
+ * Validates and saves to internal driver memory the passed configuration.
+ * Always returns 0.
+ **/
+int isp_csi2_ctrl_config_frame_mode(enum isp_csi2_frame_mode frame_mode)
+{
+ struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg_update *currctrl_u =
+ ¤t_csi2_cfg_update.ctrl;
+
+ if (currctrl->frame_mode != frame_mode) {
+ currctrl->frame_mode = frame_mode;
+ currctrl_u->frame_mode = true;
+ update_ctrl = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctrl_config_vp_clk_enable - Enables/disables CSI2 Videoport clock.
+ * @vp_clk_enable: Boolean value to specify the Videoport clock state.
+ *
+ * Validates and saves to internal driver memory the passed configuration.
+ * Always returns 0.
+ **/
+int isp_csi2_ctrl_config_vp_clk_enable(bool vp_clk_enable)
+{
+ struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg_update *currctrl_u =
+ ¤t_csi2_cfg_update.ctrl;
+
+ if (currctrl->vp_clk_enable != vp_clk_enable) {
+ currctrl->vp_clk_enable = vp_clk_enable;
+ currctrl_u->vp_clk_enable = true;
+ update_ctrl = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctrl_config_vp_only_enable - Sets CSI2 Videoport clock as exclusive
+ * @vp_only_enable: Boolean value to specify if the Videoport clock is
+ * exclusive, setting the OCP port as disabled.
+ *
+ * Validates and saves to internal driver memory the passed configuration.
+ * Always returns 0.
+ **/
+int isp_csi2_ctrl_config_vp_only_enable(bool vp_only_enable)
+{
+ struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg_update *currctrl_u =
+ ¤t_csi2_cfg_update.ctrl;
+
+ if (currctrl->vp_only_enable != vp_only_enable) {
+ currctrl->vp_only_enable = vp_only_enable;
+ currctrl_u->vp_only_enable = true;
+ update_ctrl = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctrl_config_vp_out_ctrl - Sets CSI2 Videoport clock divider
+ * @vp_out_ctrl: Divider value for setting videoport clock frequency based on
+ * OCP port frequency, valid dividers are between 1 and 4.
+ *
+ * Validates and saves to internal driver memory the passed configuration.
+ * Returns 0 if successful, or -EINVAL if wrong divider value is passed.
+ **/
+int isp_csi2_ctrl_config_vp_out_ctrl(u8 vp_out_ctrl)
+{
+ struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg_update *currctrl_u =
+ ¤t_csi2_cfg_update.ctrl;
+
+ if ((vp_out_ctrl == 0) || (vp_out_ctrl > 4)) {
+ printk(KERN_ERR "CSI2: Wrong divisor value. Must be between"
+ " 1 and 4");
+ return -EINVAL;
+ }
+
+ if (currctrl->vp_out_ctrl != vp_out_ctrl) {
+ currctrl->vp_out_ctrl = vp_out_ctrl;
+ currctrl_u->vp_out_ctrl = true;
+ update_ctrl = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctrl_config_debug_enable - Sets CSI2 debug
+ * @debug_enable: Boolean for setting debug configuration on CSI2.
+ *
+ * Always returns 0.
+ **/
+int isp_csi2_ctrl_config_debug_enable(bool debug_enable)
+{
+ struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg_update *currctrl_u =
+ ¤t_csi2_cfg_update.ctrl;
+
+ if (currctrl->debug_enable != debug_enable) {
+ currctrl->debug_enable = debug_enable;
+ currctrl_u->debug_enable = true;
+ update_ctrl = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctrl_config_burst_size - Sets CSI2 burst size.
+ * @burst_size: Burst size of the memory saving capability of receiver.
+ *
+ * Returns 0 if successful, or -EINVAL if burst size is wrong.
+ **/
+int isp_csi2_ctrl_config_burst_size(u8 burst_size)
+{
+ struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg_update *currctrl_u =
+ ¤t_csi2_cfg_update.ctrl;
+ if (burst_size > 3) {
+ printk(KERN_ERR "CSI2: Wrong burst size. Must be between"
+ " 0 and 3");
+ return -EINVAL;
+ }
+
+ if (currctrl->burst_size != burst_size) {
+ currctrl->burst_size = burst_size;
+ currctrl_u->burst_size = true;
+ update_ctrl = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctrl_config_ecc_enable - Enables ECC on CSI2 Receiver
+ * @ecc_enable: Boolean to enable/disable the CSI2 receiver ECC handling.
+ *
+ * Always returns 0.
+ **/
+int isp_csi2_ctrl_config_ecc_enable(bool ecc_enable)
+{
+ struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg_update *currctrl_u =
+ ¤t_csi2_cfg_update.ctrl;
+
+ if (currctrl->ecc_enable != ecc_enable) {
+ currctrl->ecc_enable = ecc_enable;
+ currctrl_u->ecc_enable = true;
+ update_ctrl = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctrl_config_ecc_enable - Enables ECC on CSI2 Receiver
+ * @ecc_enable: Boolean to enable/disable the CSI2 receiver ECC handling.
+ *
+ * Always returns 0.
+ **/
+int isp_csi2_ctrl_config_secure_mode(bool secure_mode)
+{
+ struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg_update *currctrl_u =
+ ¤t_csi2_cfg_update.ctrl;
+
+ if (currctrl->secure_mode != secure_mode) {
+ currctrl->secure_mode = secure_mode;
+ currctrl_u->secure_mode = true;
+ update_ctrl = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctrl_config_if_enable - Enables CSI2 Receiver interface.
+ * @if_enable: Boolean to enable/disable the CSI2 receiver interface.
+ *
+ * Always returns 0.
+ **/
+int isp_csi2_ctrl_config_if_enable(bool if_enable)
+{
+ struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg_update *currctrl_u =
+ ¤t_csi2_cfg_update.ctrl;
+
+ if (currctrl->if_enable != if_enable) {
+ currctrl->if_enable = if_enable;
+ currctrl_u->if_enable = true;
+ update_ctrl = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctrl_update - Applies CSI2 control configuration.
+ * @force_update: Flag to force rewrite of registers, even if they haven't been
+ * updated with the isp_csi2_ctrl_config_*() functions.
+ *
+ * It only saves settings when they were previously updated using the
+ * isp_csi2_ctrl_config_*() functions, unless the force_update flag is
+ * set to true.
+ * Always returns 0.
+ **/
+int isp_csi2_ctrl_update(bool force_update)
+{
+ struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg_update *currctrl_u =
+ ¤t_csi2_cfg_update.ctrl;
+ u32 reg;
+
+ if ((update_ctrl == true) || (force_update == true)) {
+ reg = omap_readl(ISPCSI2_CTRL);
+ if ((currctrl_u->frame_mode == true) ||
+ (force_update == true)) {
+ reg &= ~ISPCSI2_CTRL_FRAME_MASK;
+ if (currctrl->frame_mode)
+ reg |= ISPCSI2_CTRL_FRAME_DISABLE_FEC;
+ else
+ reg |= ISPCSI2_CTRL_FRAME_DISABLE_IMM;
+ currctrl_u->frame_mode = false;
+ }
+ if ((currctrl_u->vp_clk_enable == true) ||
+ (force_update == true)) {
+ reg &= ~ISPCSI2_CTRL_VP_CLK_EN_MASK;
+ if (currctrl->vp_clk_enable)
+ reg |= ISPCSI2_CTRL_VP_CLK_EN_ENABLE;
+ else
+ reg |= ISPCSI2_CTRL_VP_CLK_EN_DISABLE;
+ currctrl_u->vp_clk_enable = false;
+ }
+ if ((currctrl_u->vp_only_enable == true) ||
+ (force_update == true)) {
+ reg &= ~ISPCSI2_CTRL_VP_ONLY_EN_MASK;
+ uses_videoport = currctrl->vp_only_enable;
+ if (currctrl->vp_only_enable)
+ reg |= ISPCSI2_CTRL_VP_ONLY_EN_ENABLE;
+ else
+ reg |= ISPCSI2_CTRL_VP_ONLY_EN_DISABLE;
+ currctrl_u->vp_only_enable = false;
+ }
+ if ((currctrl_u->vp_out_ctrl == true) ||
+ (force_update == true)) {
+ reg &= ~ISPCSI2_CTRL_VP_OUT_CTRL_MASK;
+ reg |= (currctrl->vp_out_ctrl - 1) <<
+ ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT;
+ currctrl_u->vp_out_ctrl = false;
+ }
+ if ((currctrl_u->debug_enable == true) ||
+ (force_update == true)) {
+ reg &= ~ISPCSI2_CTRL_DBG_EN_MASK;
+ if (currctrl->debug_enable)
+ reg |= ISPCSI2_CTRL_DBG_EN_ENABLE;
+ else
+ reg |= ISPCSI2_CTRL_DBG_EN_DISABLE;
+ currctrl_u->debug_enable = false;
+ }
+ if ((currctrl_u->burst_size == true) ||
+ (force_update == true)) {
+ reg &= ~ISPCSI2_CTRL_BURST_SIZE_MASK;
+ reg |= currctrl->burst_size <<
+ ISPCSI2_CTRL_BURST_SIZE_SHIFT;
+ currctrl_u->burst_size = false;
+ }
+ if ((currctrl_u->ecc_enable == true) ||
+ (force_update == true)) {
+ reg &= ~ISPCSI2_CTRL_ECC_EN_MASK;
+ if (currctrl->ecc_enable)
+ reg |= ISPCSI2_CTRL_ECC_EN_ENABLE;
+ else
+ reg |= ISPCSI2_CTRL_ECC_EN_DISABLE;
+ currctrl_u->ecc_enable = false;
+ }
+ if ((currctrl_u->secure_mode == true) ||
+ (force_update == true)) {
+ reg &= ~ISPCSI2_CTRL_SECURE_MASK;
+ if (currctrl->secure_mode)
+ reg |= ISPCSI2_CTRL_SECURE_ENABLE;
+ else
+ reg |= ISPCSI2_CTRL_SECURE_DISABLE;
+ currctrl_u->secure_mode = false;
+ }
+ if ((currctrl_u->if_enable == true) ||
+ (force_update == true)) {
+ reg &= ~ISPCSI2_CTRL_IF_EN_MASK;
+ if (currctrl->if_enable)
+ reg |= ISPCSI2_CTRL_IF_EN_ENABLE;
+ else
+ reg |= ISPCSI2_CTRL_IF_EN_DISABLE;
+ currctrl_u->if_enable = false;
+ }
+ omap_writel(reg, ISPCSI2_CTRL);
+ update_ctrl = false;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctrl_get - Gets CSI2 control configuration
+ *
+ * Always returns 0.
+ **/
+int isp_csi2_ctrl_get(void)
+{
+ struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
+ struct isp_csi2_ctrl_cfg_update *currctrl_u =
+ ¤t_csi2_cfg_update.ctrl;
+ u32 reg;
+
+ reg = omap_readl(ISPCSI2_CTRL);
+ currctrl->frame_mode = (reg & ISPCSI2_CTRL_FRAME_MASK) >>
+ ISPCSI2_CTRL_FRAME_SHIFT;
+ currctrl_u->frame_mode = false;
+
+ if ((reg & ISPCSI2_CTRL_VP_CLK_EN_MASK) ==
+ ISPCSI2_CTRL_VP_CLK_EN_ENABLE)
+ currctrl->vp_clk_enable = true;
+ else
+ currctrl->vp_clk_enable = false;
+ currctrl_u->vp_clk_enable = false;
+
+ if ((reg & ISPCSI2_CTRL_VP_ONLY_EN_MASK) ==
+ ISPCSI2_CTRL_VP_ONLY_EN_ENABLE)
+ currctrl->vp_only_enable = true;
+ else
+ currctrl->vp_only_enable = false;
+ uses_videoport = currctrl->vp_only_enable;
+ currctrl_u->vp_only_enable = false;
+
+ currctrl->vp_out_ctrl = ((reg & ISPCSI2_CTRL_VP_OUT_CTRL_MASK) >>
+ ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT) + 1;
+ currctrl_u->vp_out_ctrl = false;
+
+ if ((reg & ISPCSI2_CTRL_DBG_EN_MASK) == ISPCSI2_CTRL_DBG_EN_ENABLE)
+ currctrl->debug_enable = true;
+ else
+ currctrl->debug_enable = false;
+ currctrl_u->debug_enable = false;
+
+ currctrl->burst_size = (reg & ISPCSI2_CTRL_BURST_SIZE_MASK) >>
+ ISPCSI2_CTRL_BURST_SIZE_SHIFT;
+ currctrl_u->burst_size = false;
+
+ if ((reg & ISPCSI2_CTRL_ECC_EN_MASK) == ISPCSI2_CTRL_ECC_EN_ENABLE)
+ currctrl->ecc_enable = true;
+ else
+ currctrl->ecc_enable = false;
+ currctrl_u->ecc_enable = false;
+
+ if ((reg & ISPCSI2_CTRL_SECURE_MASK) == ISPCSI2_CTRL_SECURE_ENABLE)
+ currctrl->secure_mode = true;
+ else
+ currctrl->secure_mode = false;
+ currctrl_u->secure_mode = false;
+
+ if ((reg & ISPCSI2_CTRL_IF_EN_MASK) == ISPCSI2_CTRL_IF_EN_ENABLE)
+ currctrl->if_enable = true;
+ else
+ currctrl->if_enable = false;
+ currctrl_u->if_enable = false;
+
+ update_ctrl = false;
+ return 0;
+}
+
+/**
+ * isp_csi2_ctx_validate - Validates the context number value
+ * @ctxnum: Pointer to variable containing context number.
+ *
+ * If the value is not in range (3 bits), it is being ANDed with 0x7 to force
+ * it to be on range.
+ **/
+static void isp_csi2_ctx_validate(u8 *ctxnum)
+{
+ if (*ctxnum > 7) {
+ printk(KERN_ERR "Invalid context number. Forcing valid"
+ " value...\n");
+ *ctxnum &= ~(0x7);
+ }
+}
+
+/**
+ * isp_csi2_ctx_config_virtual_id - Maps a virtual ID with a CSI2 Rx context
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ * @virtual_id: CSI2 Virtual ID to associate with specified context number.
+ *
+ * Returns 0 if successful, or -EINVAL if Virtual ID is not in range (0-3).
+ **/
+int isp_csi2_ctx_config_virtual_id(u8 ctxnum, u8 virtual_id)
+{
+ struct isp_csi2_ctx_cfg *selected_ctx;
+ struct isp_csi2_ctx_cfg_update *selected_ctx_u;
+
+ isp_csi2_ctx_validate(&ctxnum);
+
+ if (virtual_id > 3) {
+ printk(KERN_ERR "Wrong requested virtual_id\n");
+ return -EINVAL;
+ }
+
+ selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
+ selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+
+ if (selected_ctx->virtual_id != virtual_id) {
+ selected_ctx->virtual_id = virtual_id;
+ selected_ctx_u->virtual_id = true;
+ update_ctx_ctrl2[ctxnum] = true;
+ }
+
+ return 0;
+}
+
+/**
+ * isp_csi2_ctx_config_frame_count - Sets frame count to be received in CSI2 Rx.
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ * @frame_count: Number of frames to acquire.
+ *
+ * Always returns 0.
+ **/
+int isp_csi2_ctx_config_frame_count(u8 ctxnum, u8 frame_count)
+{
+ struct isp_csi2_ctx_cfg *selected_ctx;
+ struct isp_csi2_ctx_cfg_update *selected_ctx_u;
+
+ isp_csi2_ctx_validate(&ctxnum);
+
+ selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
+ selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+
+ if (selected_ctx->frame_count != frame_count) {
+ selected_ctx->frame_count = frame_count;
+ selected_ctx_u->frame_count = true;
+ update_ctx_ctrl1[ctxnum] = true;
+ }
+
+ return 0;
+}
+
+/**
+ * isp_csi2_ctx_config_format - Maps a pixel format to a specified context.
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ * @pixformat: V4L2 structure for pixel format.
+ *
+ * Returns 0 if successful, or -EINVAL if the format is not supported by the
+ * receiver.
+ **/
+int isp_csi2_ctx_config_format(u8 ctxnum, u32 pixformat)
+{
+ struct isp_csi2_ctx_cfg *selected_ctx;
+ struct isp_csi2_ctx_cfg_update *selected_ctx_u;
+ struct v4l2_pix_format pix;
+
+ isp_csi2_ctx_validate(&ctxnum);
+
+ pix.pixelformat = pixformat;
+ switch (pix.pixelformat) {
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_RGB565X:
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_RGB555:
+ case V4L2_PIX_FMT_RGB555X:
+ case V4L2_PIX_FMT_SGRBG10:
+ break;
+ default:
+ printk(KERN_ERR "Context config pixel format unsupported\n");
+ return -EINVAL;
+ }
+
+ selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
+ selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+
+ selected_ctx->format = pix;
+ selected_ctx_u->format = true;
+ update_ctx_ctrl2[ctxnum] = true;
+
+ return 0;
+}
+
+/**
+ * isp_csi2_ctx_config_alpha - Sets the alpha value for pixel format
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ * @alpha: Alpha value.
+ *
+ * Returns 0 if successful, or -EINVAL if the alpha value is bigger than 16383.
+ **/
+int isp_csi2_ctx_config_alpha(u8 ctxnum, u16 alpha)
+{
+ struct isp_csi2_ctx_cfg *selected_ctx;
+ struct isp_csi2_ctx_cfg_update *selected_ctx_u;
+
+ isp_csi2_ctx_validate(&ctxnum);
+
+ if (alpha > 0x3FFF) {
+ printk(KERN_ERR "Wrong alpha value\n");
+ return -EINVAL;
+ }
+
+ selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
+ selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+
+ if (selected_ctx->alpha != alpha) {
+ selected_ctx->alpha = alpha;
+ selected_ctx_u->alpha = true;
+ update_ctx_ctrl3[ctxnum] = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctx_config_data_offset - Sets the offset between received lines
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ * @data_offset: Offset between first pixel of each 2 contiguous lines.
+ *
+ * Returns 0 if successful, or -EINVAL if the line offset is bigger than 1023.
+ **/
+int isp_csi2_ctx_config_data_offset(u8 ctxnum, u16 data_offset)
+{
+ struct isp_csi2_ctx_cfg *selected_ctx;
+ struct isp_csi2_ctx_cfg_update *selected_ctx_u;
+
+ isp_csi2_ctx_validate(&ctxnum);
+
+ if (data_offset > 0x3FF) {
+ printk(KERN_ERR "Wrong line offset\n");
+ return -EINVAL;
+ }
+
+ selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
+ selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+
+ if (selected_ctx->data_offset != data_offset) {
+ selected_ctx->data_offset = data_offset;
+ selected_ctx_u->data_offset = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctx_config_ping_addr - Sets Ping address for CSI2 Rx. buffer saving
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ * @ping_addr: 32 bit ISP MMU mapped address.
+ *
+ * Always returns 0.
+ **/
+int isp_csi2_ctx_config_ping_addr(u8 ctxnum, u32 ping_addr)
+{
+ struct isp_csi2_ctx_cfg *selected_ctx;
+ struct isp_csi2_ctx_cfg_update *selected_ctx_u;
+
+ isp_csi2_ctx_validate(&ctxnum);
+
+ ping_addr &= ~(0x1F);
+
+ selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
+ selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+
+ if (selected_ctx->ping_addr != ping_addr) {
+ selected_ctx->ping_addr = ping_addr;
+ selected_ctx_u->ping_addr = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctx_config_pong_addr - Sets Pong address for CSI2 Rx. buffer saving
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ * @pong_addr: 32 bit ISP MMU mapped address.
+ *
+ * Always returns 0.
+ **/
+int isp_csi2_ctx_config_pong_addr(u8 ctxnum, u32 pong_addr)
+{
+ struct isp_csi2_ctx_cfg *selected_ctx;
+ struct isp_csi2_ctx_cfg_update *selected_ctx_u;
+
+ isp_csi2_ctx_validate(&ctxnum);
+
+ pong_addr &= ~(0x1F);
+
+ selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
+ selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+
+ if (selected_ctx->pong_addr != pong_addr) {
+ selected_ctx->pong_addr = pong_addr;
+ selected_ctx_u->pong_addr = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctx_config_eof_enabled - Enables EOF signal assertion
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ * @eof_enabled: Boolean to enable/disable EOF signal assertion on received
+ * packets.
+ *
+ * Always returns 0.
+ **/
+int isp_csi2_ctx_config_eof_enabled(u8 ctxnum, bool eof_enabled)
+{
+ struct isp_csi2_ctx_cfg *selected_ctx;
+ struct isp_csi2_ctx_cfg_update *selected_ctx_u;
+
+ isp_csi2_ctx_validate(&ctxnum);
+
+ selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
+ selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+
+ if (selected_ctx->eof_enabled != eof_enabled) {
+ selected_ctx->eof_enabled = eof_enabled;
+ selected_ctx_u->eof_enabled = true;
+ update_ctx_ctrl1[ctxnum] = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctx_config_eol_enabled - Enables EOL signal assertion
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ * @eol_enabled: Boolean to enable/disable EOL signal assertion on received
+ * packets.
+ *
+ * Always returns 0.
+ **/
+int isp_csi2_ctx_config_eol_enabled(u8 ctxnum, bool eol_enabled)
+{
+ struct isp_csi2_ctx_cfg *selected_ctx;
+ struct isp_csi2_ctx_cfg_update *selected_ctx_u;
+
+ isp_csi2_ctx_validate(&ctxnum);
+
+ selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
+ selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+
+ if (selected_ctx->eol_enabled != eol_enabled) {
+ selected_ctx->eol_enabled = eol_enabled;
+ selected_ctx_u->eol_enabled = true;
+ update_ctx_ctrl1[ctxnum] = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctx_config_checksum_enabled - Enables Checksum check in rcvd packets
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ * @checksum_enabled: Boolean to enable/disable Checksum check on received
+ * packets
+ *
+ * Always returns 0.
+ **/
+int isp_csi2_ctx_config_checksum_enabled(u8 ctxnum, bool checksum_enabled)
+{
+ struct isp_csi2_ctx_cfg *selected_ctx;
+ struct isp_csi2_ctx_cfg_update *selected_ctx_u;
+
+ isp_csi2_ctx_validate(&ctxnum);
+
+ selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
+ selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+
+ if (selected_ctx->checksum_enabled != checksum_enabled) {
+ selected_ctx->checksum_enabled = checksum_enabled;
+ selected_ctx_u->checksum_enabled = true;
+ update_ctx_ctrl1[ctxnum] = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctx_config_enabled - Enables specified CSI2 context
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ * @enabled: Boolean to enable/disable specified context.
+ *
+ * Always returns 0.
+ **/
+int isp_csi2_ctx_config_enabled(u8 ctxnum, bool enabled)
+{
+ struct isp_csi2_ctx_cfg *selected_ctx;
+ struct isp_csi2_ctx_cfg_update *selected_ctx_u;
+
+ isp_csi2_ctx_validate(&ctxnum);
+
+ selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
+ selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+
+ if (selected_ctx->enabled != enabled) {
+ selected_ctx->enabled = enabled;
+ selected_ctx_u->enabled = true;
+ update_ctx_ctrl1[ctxnum] = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctx_update - Applies CSI2 context configuration.
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ * @force_update: Flag to force rewrite of registers, even if they haven't been
+ * updated with the isp_csi2_ctx_config_*() functions.
+ *
+ * It only saves settings when they were previously updated using the
+ * isp_csi2_ctx_config_*() functions, unless the force_update flag is
+ * set to true.
+ * Always returns 0.
+ **/
+int isp_csi2_ctx_update(u8 ctxnum, bool force_update)
+{
+ struct isp_csi2_ctx_cfg *selected_ctx;
+ struct isp_csi2_ctx_cfg_update *selected_ctx_u;
+ u32 reg;
+
+ isp_csi2_ctx_validate(&ctxnum);
+
+ selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
+ selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+
+ if ((update_ctx_ctrl1[ctxnum] == true) || (force_update == true)) {
+ reg = omap_readl(ISPCSI2_CTX_CTRL1(ctxnum));
+ if ((selected_ctx_u->frame_count == true) ||
+ (force_update == true)) {
+ reg &= ~(ISPCSI2_CTX_CTRL1_COUNT_MASK);
+ reg |= selected_ctx->frame_count <<
+ ISPCSI2_CTX_CTRL1_COUNT_SHIFT;
+ selected_ctx_u->frame_count = false;
+ }
+ if ((selected_ctx_u->eof_enabled == true) ||
+ (force_update == true)) {
+ reg &= ~(ISPCSI2_CTX_CTRL1_EOF_EN_MASK);
+ if (selected_ctx->eof_enabled == true)
+ reg |= ISPCSI2_CTX_CTRL1_EOF_EN_ENABLE;
+ else
+ reg |= ISPCSI2_CTX_CTRL1_EOF_EN_DISABLE;
+ selected_ctx_u->eof_enabled = false;
+ }
+ if ((selected_ctx_u->eol_enabled == true) ||
+ (force_update == true)) {
+ reg &= ~(ISPCSI2_CTX_CTRL1_EOL_EN_MASK);
+ if (selected_ctx->eol_enabled == true)
+ reg |= ISPCSI2_CTX_CTRL1_EOL_EN_ENABLE;
+ else
+ reg |= ISPCSI2_CTX_CTRL1_EOL_EN_DISABLE;
+ selected_ctx_u->eol_enabled = false;
+ }
+ if ((selected_ctx_u->checksum_enabled == true) ||
+ (force_update == true)) {
+ reg &= ~(ISPCSI2_CTX_CTRL1_CS_EN_MASK);
+ if (selected_ctx->checksum_enabled == true)
+ reg |= ISPCSI2_CTX_CTRL1_CS_EN_ENABLE;
+ else
+ reg |= ISPCSI2_CTX_CTRL1_CS_EN_DISABLE;
+ selected_ctx_u->checksum_enabled = false;
+ }
+ if ((selected_ctx_u->enabled == true) ||
+ (force_update == true)) {
+ reg &= ~(ISPCSI2_CTX_CTRL1_CTX_EN_MASK);
+ if (selected_ctx->enabled == true)
+ reg |= ISPCSI2_CTX_CTRL1_CTX_EN_ENABLE;
+ else
+ reg |= ISPCSI2_CTX_CTRL1_CTX_EN_DISABLE;
+ selected_ctx_u->enabled = false;
+ }
+ omap_writel(reg, ISPCSI2_CTX_CTRL1(ctxnum));
+ update_ctx_ctrl1[ctxnum] = false;
+ }
+
+ if ((update_ctx_ctrl2[ctxnum] == true) || (force_update == true)) {
+ reg = omap_readl(ISPCSI2_CTX_CTRL2(ctxnum));
+ if ((selected_ctx_u->virtual_id == true) ||
+ (force_update == true)) {
+ reg &= ~(ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK);
+ reg |= selected_ctx->virtual_id <<
+ ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT;
+ selected_ctx_u->virtual_id = false;
+ }
+
+ if ((selected_ctx_u->format == true) ||
+ (force_update == true)) {
+ struct v4l2_pix_format *pix;
+ u16 new_format = 0;
+
+ reg &= ~(ISPCSI2_CTX_CTRL2_FORMAT_MASK);
+ pix = &selected_ctx->format;
+ switch (pix->pixelformat) {
+ case V4L2_PIX_FMT_RGB565:
+ case V4L2_PIX_FMT_RGB565X:
+ new_format = 0x22;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ if (uses_videoport)
+ new_format = 0x9E;
+ else
+ new_format = 0x1E;
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ case V4L2_PIX_FMT_RGB555X:
+ new_format = 0xA1;
+ break;
+ case V4L2_PIX_FMT_SGRBG10:
+ if (uses_videoport)
+ new_format = 0x12F;
+ else
+ new_format = 0xAB;
+ break;
+ }
+ reg |= (new_format << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT);
+ selected_ctx_u->format = false;
+ }
+ omap_writel(reg, ISPCSI2_CTX_CTRL2(ctxnum));
+ update_ctx_ctrl2[ctxnum] = false;
+ }
+
+ if ((update_ctx_ctrl3[ctxnum] == true) || (force_update == true)) {
+ reg = omap_readl(ISPCSI2_CTX_CTRL3(ctxnum));
+ if ((selected_ctx_u->alpha == true) ||
+ (force_update == true)) {
+ reg &= ~(ISPCSI2_CTX_CTRL3_ALPHA_MASK);
+ reg |= (selected_ctx->alpha <<
+ ISPCSI2_CTX_CTRL3_ALPHA_SHIFT);
+ selected_ctx_u->alpha = false;
+ }
+ omap_writel(reg, ISPCSI2_CTX_CTRL3(ctxnum));
+ update_ctx_ctrl3[ctxnum] = false;
+ }
+
+ if (selected_ctx_u->data_offset == true) {
+ reg = omap_readl(ISPCSI2_CTX_DAT_OFST(ctxnum));
+ reg &= ~ISPCSI2_CTX_DAT_OFST_OFST_MASK;
+ reg |= selected_ctx->data_offset <<
+ ISPCSI2_CTX_DAT_OFST_OFST_SHIFT;
+ omap_writel(reg, ISPCSI2_CTX_DAT_OFST(ctxnum));
+ selected_ctx_u->data_offset = false;
+ }
+
+ if (selected_ctx_u->ping_addr == true) {
+ reg = selected_ctx->ping_addr;
+ omap_writel(reg, ISPCSI2_CTX_DAT_PING_ADDR(ctxnum));
+ selected_ctx_u->ping_addr = false;
+ }
+
+ if (selected_ctx_u->pong_addr == true) {
+ reg = selected_ctx->pong_addr;
+ omap_writel(reg, ISPCSI2_CTX_DAT_PONG_ADDR(ctxnum));
+ selected_ctx_u->pong_addr = false;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_ctx_get - Gets specific CSI2 Context configuration
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ *
+ * Always returns 0.
+ **/
+int isp_csi2_ctx_get(u8 ctxnum)
+{
+ struct isp_csi2_ctx_cfg *selected_ctx;
+ struct isp_csi2_ctx_cfg_update *selected_ctx_u;
+ u32 reg;
+
+ isp_csi2_ctx_validate(&ctxnum);
+
+ selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
+ selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
+
+ reg = omap_readl(ISPCSI2_CTX_CTRL1(ctxnum));
+ selected_ctx->frame_count = (reg & ISPCSI2_CTX_CTRL1_COUNT_MASK) >>
+ ISPCSI2_CTX_CTRL1_COUNT_SHIFT;
+ selected_ctx_u->frame_count = false;
+
+ if ((reg & ISPCSI2_CTX_CTRL1_EOF_EN_MASK) ==
+ ISPCSI2_CTX_CTRL1_EOF_EN_ENABLE)
+ selected_ctx->eof_enabled = true;
+ else
+ selected_ctx->eof_enabled = false;
+ selected_ctx_u->eof_enabled = false;
+
+ if ((reg & ISPCSI2_CTX_CTRL1_EOL_EN_MASK) ==
+ ISPCSI2_CTX_CTRL1_EOL_EN_ENABLE)
+ selected_ctx->eol_enabled = true;
+ else
+ selected_ctx->eol_enabled = false;
+ selected_ctx_u->eol_enabled = false;
+
+ if ((reg & ISPCSI2_CTX_CTRL1_CS_EN_MASK) ==
+ ISPCSI2_CTX_CTRL1_CS_EN_ENABLE)
+ selected_ctx->checksum_enabled = true;
+ else
+ selected_ctx->checksum_enabled = false;
+ selected_ctx_u->checksum_enabled = false;
+
+ if ((reg & ISPCSI2_CTX_CTRL1_CTX_EN_MASK) ==
+ ISPCSI2_CTX_CTRL1_CTX_EN_ENABLE)
+ selected_ctx->enabled = true;
+ else
+ selected_ctx->enabled = false;
+ selected_ctx_u->enabled = false;
+ update_ctx_ctrl1[ctxnum] = false;
+
+ reg = omap_readl(ISPCSI2_CTX_CTRL2(ctxnum));
+
+ selected_ctx->virtual_id = (reg & ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK) >>
+ ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT;
+ selected_ctx_u->virtual_id = false;
+
+ switch ((reg & ISPCSI2_CTX_CTRL2_FORMAT_MASK) >>
+ ISPCSI2_CTX_CTRL2_FORMAT_SHIFT) {
+ case 0x22:
+ selected_ctx->format.pixelformat = V4L2_PIX_FMT_RGB565;
+ break;
+ case 0x9E:
+ case 0x1E:
+ selected_ctx->format.pixelformat = V4L2_PIX_FMT_YUYV;
+ break;
+ case 0xA1:
+ selected_ctx->format.pixelformat = V4L2_PIX_FMT_RGB555;
+ break;
+ case 0xAB:
+ case 0x12F:
+ selected_ctx->format.pixelformat = V4L2_PIX_FMT_SGRBG10;
+ break;
+ }
+ selected_ctx_u->format = false;
+ update_ctx_ctrl2[ctxnum] = false;
+
+ selected_ctx->alpha = (omap_readl(ISPCSI2_CTX_CTRL3(ctxnum)) &
+ ISPCSI2_CTX_CTRL3_ALPHA_MASK) >>
+ ISPCSI2_CTX_CTRL3_ALPHA_SHIFT;
+ selected_ctx_u->alpha = false;
+ update_ctx_ctrl3[ctxnum] = false;
+
+ selected_ctx->data_offset = (omap_readl(ISPCSI2_CTX_DAT_OFST(ctxnum)) &
+ ISPCSI2_CTX_DAT_OFST_OFST_MASK) >>
+ ISPCSI2_CTX_DAT_OFST_OFST_SHIFT;
+ selected_ctx_u->data_offset = false;
+
+ selected_ctx->ping_addr = omap_readl(ISPCSI2_CTX_DAT_PING_ADDR(ctxnum));
+ selected_ctx_u->ping_addr = false;
+
+ selected_ctx->pong_addr = omap_readl(ISPCSI2_CTX_DAT_PONG_ADDR(ctxnum));
+ selected_ctx_u->pong_addr = false;
+ return 0;
+}
+
+/**
+ * isp_csi2_ctx_update_all - Applies all CSI2 context configuration.
+ * @force_update: Flag to force rewrite of registers, even if they haven't been
+ * updated with the isp_csi2_ctx_config_*() functions.
+ *
+ * It only saves settings when they were previously updated using the
+ * isp_csi2_ctx_config_*() functions, unless the force_update flag is
+ * set to true.
+ * Always returns 0.
+ **/
+int isp_csi2_ctx_update_all(bool force_update)
+{
+ u8 ctxnum;
+
+ for (ctxnum = 0; ctxnum < 8; ctxnum++)
+ isp_csi2_ctx_update(ctxnum, force_update);
+
+ return 0;
+}
+
+/**
+ * isp_csi2_ctx_get_all - Gets all CSI2 Context configurations
+ *
+ * Always returns 0.
+ **/
+int isp_csi2_ctx_get_all(void)
+{
+ u8 ctxnum;
+
+ for (ctxnum = 0; ctxnum < 8; ctxnum++)
+ isp_csi2_ctx_get(ctxnum);
+
+ return 0;
+}
+
+int isp_csi2_phy_config(struct isp_csi2_phy_cfg *desiredphyconfig)
+{
+ struct isp_csi2_phy_cfg *currphy = ¤t_csi2_cfg.phy;
+ struct isp_csi2_phy_cfg_update *currphy_u =
+ ¤t_csi2_cfg_update.phy;
+
+ if ((desiredphyconfig->tclk_term > 0x7f) ||
+ (desiredphyconfig->tclk_miss > 0x3)) {
+ printk(KERN_ERR "Invalid PHY configuration sent by the"
+ " driver\n");
+ return -EINVAL;
+ }
+
+ if (currphy->ths_term != desiredphyconfig->ths_term) {
+ currphy->ths_term = desiredphyconfig->ths_term;
+ currphy_u->ths_term = true;
+ update_phy_cfg0 = true;
+ }
+ if (currphy->ths_settle != desiredphyconfig->ths_settle) {
+ currphy->ths_settle = desiredphyconfig->ths_settle;
+ currphy_u->ths_settle = true;
+ update_phy_cfg0 = true;
+ }
+ if (currphy->tclk_term != desiredphyconfig->tclk_term) {
+ currphy->tclk_term = desiredphyconfig->tclk_term;
+ currphy_u->tclk_term = true;
+ update_phy_cfg1 = true;
+ }
+ if (currphy->tclk_miss != desiredphyconfig->tclk_miss) {
+ currphy->tclk_miss = desiredphyconfig->tclk_miss;
+ currphy_u->tclk_miss = true;
+ update_phy_cfg1 = true;
+ }
+ if (currphy->tclk_settle != desiredphyconfig->tclk_settle) {
+ currphy->tclk_settle = desiredphyconfig->tclk_settle;
+ currphy_u->tclk_settle = true;
+ update_phy_cfg1 = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_calc_phy_cfg0 - Calculates D-PHY config based on the MIPIClk speed.
+ * @mipiclk: MIPI clock frequency being used with CSI2 sensor.
+ * @lbound_hs_settle: Lower bound for CSI2 High Speed Settle transition.
+ * @ubound_hs_settle: Upper bound for CSI2 High Speed Settle transition.
+ *
+ * From TRM, we have the same calculation for HS Termination signal.
+ * THS_TERM = ceil( 12.5ns / DDRCLK period ) - 1
+ * But for Settle, we use the mid value between the two passed boundaries from
+ * sensor:
+ * THS_SETTLE = (Upper bound + Lower bound) / 2
+ *
+ * Always returns 0.
+ */
+int isp_csi2_calc_phy_cfg0(u32 mipiclk, u32 lbound_hs_settle,
+ u32 ubound_hs_settle)
+{
+ struct isp_csi2_phy_cfg *currphy = ¤t_csi2_cfg.phy;
+ struct isp_csi2_phy_cfg_update *currphy_u =
+ ¤t_csi2_cfg_update.phy;
+ u32 tmp, ddrclk = mipiclk >> 1;
+
+ /* Calculate THS_TERM */
+ tmp = ddrclk / 80000000;
+ if ((ddrclk % 80000000) > 0)
+ tmp++;
+ currphy->ths_term = tmp - 1;
+ currphy_u->ths_term = true;
+
+ /* Calculate THS_SETTLE */
+ currphy->ths_settle = (ubound_hs_settle + lbound_hs_settle) / 2;
+
+ currphy_u->ths_settle = true;
+ isp_csi2_phy_update(true);
+ return 0;
+}
+EXPORT_SYMBOL(isp_csi2_calc_phy_cfg0);
+
+/**
+ * isp_csi2_phy_update - Applies CSI2 D-PHY configuration.
+ * @force_update: Flag to force rewrite of registers, even if they haven't been
+ * updated with the isp_csi2_phy_config_*() functions.
+ *
+ * It only saves settings when they were previously updated using the
+ * isp_csi2_phy_config_*() functions, unless the force_update flag is
+ * set to true.
+ * Always returns 0.
+ **/
+int isp_csi2_phy_update(bool force_update)
+{
+ struct isp_csi2_phy_cfg *currphy = ¤t_csi2_cfg.phy;
+ struct isp_csi2_phy_cfg_update *currphy_u =
+ ¤t_csi2_cfg_update.phy;
+ u32 reg;
+
+ if ((update_phy_cfg0 == true) || (force_update == true)) {
+ reg = omap_readl(ISPCSI2PHY_CFG0);
+ if ((currphy_u->ths_term == true) || (force_update == true)) {
+ reg &= ~ISPCSI2PHY_CFG0_THS_TERM_MASK;
+ reg |= (currphy->ths_term <<
+ ISPCSI2PHY_CFG0_THS_TERM_SHIFT);
+ currphy_u->ths_term = false;
+ }
+ if ((currphy_u->ths_settle == true) || (force_update == true)) {
+ reg &= ~ISPCSI2PHY_CFG0_THS_SETTLE_MASK;
+ reg |= (currphy->ths_settle <<
+ ISPCSI2PHY_CFG0_THS_SETTLE_SHIFT);
+ currphy_u->ths_settle = false;
+ }
+ omap_writel(reg, ISPCSI2PHY_CFG0);
+ update_phy_cfg0 = false;
+ }
+
+ if ((update_phy_cfg1 == true) || (force_update == true)) {
+ reg = omap_readl(ISPCSI2PHY_CFG1);
+ if ((currphy_u->tclk_term == true) || (force_update == true)) {
+ reg &= ~ISPCSI2PHY_CFG1_TCLK_TERM_MASK;
+ reg |= (currphy->tclk_term <<
+ ISPCSI2PHY_CFG1_TCLK_TERM_SHIFT);
+ currphy_u->tclk_term = false;
+ }
+ if ((currphy_u->tclk_miss == true) || (force_update == true)) {
+ reg &= ~ISPCSI2PHY_CFG1_TCLK_MISS_MASK;
+ reg |= (currphy->tclk_miss <<
+ ISPCSI2PHY_CFG1_TCLK_MISS_SHIFT);
+ currphy_u->tclk_miss = false;
+ }
+ if ((currphy_u->tclk_settle == true) ||
+ (force_update == true)) {
+ reg &= ~ISPCSI2PHY_CFG1_TCLK_SETTLE_MASK;
+ reg |= (currphy->tclk_settle <<
+ ISPCSI2PHY_CFG1_TCLK_SETTLE_SHIFT);
+ currphy_u->tclk_settle = false;
+ }
+ omap_writel(reg, ISPCSI2PHY_CFG1);
+ update_phy_cfg1 = false;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_phy_get - Gets CSI2 D-PHY configuration
+ *
+ * Gets settings from HW registers and fills in the internal driver memory
+ * Always returns 0.
+ **/
+int isp_csi2_phy_get(void)
+{
+ struct isp_csi2_phy_cfg *currphy = ¤t_csi2_cfg.phy;
+ struct isp_csi2_phy_cfg_update *currphy_u =
+ ¤t_csi2_cfg_update.phy;
+ u32 reg;
+
+ reg = omap_readl(ISPCSI2PHY_CFG0);
+ currphy->ths_term = (reg & ISPCSI2PHY_CFG0_THS_TERM_MASK) >>
+ ISPCSI2PHY_CFG0_THS_TERM_SHIFT;
+ currphy_u->ths_term = false;
+
+ currphy->ths_settle = (reg & ISPCSI2PHY_CFG0_THS_SETTLE_MASK) >>
+ ISPCSI2PHY_CFG0_THS_SETTLE_SHIFT;
+ currphy_u->ths_settle = false;
+ update_phy_cfg0 = false;
+
+ reg = omap_readl(ISPCSI2PHY_CFG1);
+
+ currphy->tclk_term = (reg & ISPCSI2PHY_CFG1_TCLK_TERM_MASK) >>
+ ISPCSI2PHY_CFG1_TCLK_TERM_SHIFT;
+ currphy_u->tclk_term = false;
+
+ currphy->tclk_miss = (reg & ISPCSI2PHY_CFG1_TCLK_MISS_MASK) >>
+ ISPCSI2PHY_CFG1_TCLK_MISS_SHIFT;
+ currphy_u->tclk_miss = false;
+
+ currphy->tclk_settle = (reg & ISPCSI2PHY_CFG1_TCLK_SETTLE_MASK) >>
+ ISPCSI2PHY_CFG1_TCLK_SETTLE_SHIFT;
+ currphy_u->tclk_settle = false;
+
+ update_phy_cfg1 = false;
+ return 0;
+}
+
+/**
+ * isp_csi2_timings_config_forcerxmode - Sets Force Rx mode on stop state count
+ * @force_rx_mode: Boolean to enable/disable forcing Rx mode in CSI2 receiver
+ *
+ * Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected.
+ **/
+int isp_csi2_timings_config_forcerxmode(u8 io, bool force_rx_mode)
+{
+ struct isp_csi2_timings_cfg *currtimings;
+ struct isp_csi2_timings_cfg_update *currtimings_u;
+
+ if (io > 2) {
+ printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n");
+ return -EINVAL;
+ }
+
+ currtimings = ¤t_csi2_cfg.timings[io - 1];
+ currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
+ if (currtimings->force_rx_mode != force_rx_mode) {
+ currtimings->force_rx_mode = force_rx_mode;
+ currtimings_u->force_rx_mode = true;
+ update_timing = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_timings_config_stopstate_16x - Sets 16x factor for L3 cycles
+ * @stop_state_16x: Boolean to use or not use the 16x multiplier for stop count
+ *
+ * Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected.
+ **/
+int isp_csi2_timings_config_stopstate_16x(u8 io, bool stop_state_16x)
+{
+ struct isp_csi2_timings_cfg *currtimings;
+ struct isp_csi2_timings_cfg_update *currtimings_u;
+
+ if (io > 2) {
+ printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n");
+ return -EINVAL;
+ }
+
+ currtimings = ¤t_csi2_cfg.timings[io - 1];
+ currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
+ if (currtimings->stop_state_16x != stop_state_16x) {
+ currtimings->stop_state_16x = stop_state_16x;
+ currtimings_u->stop_state_16x = true;
+ update_timing = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_timings_config_stopstate_4x - Sets 4x factor for L3 cycles
+ * @stop_state_4x: Boolean to use or not use the 4x multiplier for stop count
+ *
+ * Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected.
+ **/
+int isp_csi2_timings_config_stopstate_4x(u8 io, bool stop_state_4x)
+{
+ struct isp_csi2_timings_cfg *currtimings;
+ struct isp_csi2_timings_cfg_update *currtimings_u;
+
+ if (io > 2) {
+ printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n");
+ return -EINVAL;
+ }
+
+ currtimings = ¤t_csi2_cfg.timings[io - 1];
+ currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
+ if (currtimings->stop_state_4x != stop_state_4x) {
+ currtimings->stop_state_4x = stop_state_4x;
+ currtimings_u->stop_state_4x = true;
+ update_timing = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_timings_config_stopstate_cnt - Sets L3 cycles
+ * @stop_state_counter: Stop state counter value for L3 cycles
+ *
+ * Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected.
+ **/
+int isp_csi2_timings_config_stopstate_cnt(u8 io, u16 stop_state_counter)
+{
+ struct isp_csi2_timings_cfg *currtimings;
+ struct isp_csi2_timings_cfg_update *currtimings_u;
+
+ if (io > 2) {
+ printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n");
+ return -EINVAL;
+ }
+
+ currtimings = ¤t_csi2_cfg.timings[io - 1];
+ currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
+ if (currtimings->stop_state_counter != stop_state_counter) {
+ currtimings->stop_state_counter = (stop_state_counter & 0x1FFF);
+ currtimings_u->stop_state_counter = true;
+ update_timing = true;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_timings_update - Applies specified CSI2 timing configuration.
+ * @io: IO number (1 or 2) which specifies which ComplexIO are we updating
+ * @force_update: Flag to force rewrite of registers, even if they haven't been
+ * updated with the isp_csi2_timings_config_*() functions.
+ *
+ * It only saves settings when they were previously updated using the
+ * isp_csi2_timings_config_*() functions, unless the force_update flag is
+ * set to true.
+ * Returns 0 if successful, or -EINVAL if invalid IO number is passed.
+ **/
+int isp_csi2_timings_update(u8 io, bool force_update)
+{
+ struct isp_csi2_timings_cfg *currtimings;
+ struct isp_csi2_timings_cfg_update *currtimings_u;
+ u32 reg;
+
+ if (io > 2) {
+ printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n");
+ return -EINVAL;
+ }
+
+ currtimings = ¤t_csi2_cfg.timings[io - 1];
+ currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
+
+ if ((update_timing == true) || (force_update == true)) {
+ reg = omap_readl(ISPCSI2_TIMING);
+ if ((currtimings_u->force_rx_mode == true) ||
+ (force_update == true)) {
+ reg &= ~ISPCSI2_TIMING_FORCE_RX_MODE_IO_MASK(io);
+ if (currtimings->force_rx_mode == true)
+ reg |= ISPCSI2_TIMING_FORCE_RX_MODE_IO_ENABLE
+ (io);
+ else
+ reg |= ISPCSI2_TIMING_FORCE_RX_MODE_IO_DISABLE
+ (io);
+ currtimings_u->force_rx_mode = false;
+ }
+ if ((currtimings_u->stop_state_16x == true) ||
+ (force_update == true)) {
+ reg &= ~ISPCSI2_TIMING_STOP_STATE_X16_IO_MASK(io);
+ if (currtimings->stop_state_16x == true)
+ reg |= ISPCSI2_TIMING_STOP_STATE_X16_IO_ENABLE
+ (io);
+ else
+ reg |= ISPCSI2_TIMING_STOP_STATE_X16_IO_DISABLE
+ (io);
+ currtimings_u->stop_state_16x = false;
+ }
+ if ((currtimings_u->stop_state_4x == true) ||
+ (force_update == true)) {
+ reg &= ~ISPCSI2_TIMING_STOP_STATE_X4_IO_MASK(io);
+ if (currtimings->stop_state_4x == true) {
+ reg |= ISPCSI2_TIMING_STOP_STATE_X4_IO_ENABLE
+ (io);
+ } else {
+ reg |= ISPCSI2_TIMING_STOP_STATE_X4_IO_DISABLE
+ (io);
+ }
+ currtimings_u->stop_state_4x = false;
+ }
+ if ((currtimings_u->stop_state_counter == true) ||
+ (force_update == true)) {
+ reg &= ~ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(io);
+ reg |= currtimings->stop_state_counter <<
+ ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(io);
+ currtimings_u->stop_state_counter = false;
+ }
+ omap_writel(reg, ISPCSI2_TIMING);
+ update_timing = false;
+ }
+ return 0;
+}
+
+/**
+ * isp_csi2_timings_get - Gets specific CSI2 ComplexIO timing configuration
+ * @io: IO number (1 or 2) which specifies which ComplexIO are we getting
+ *
+ * Gets settings from HW registers and fills in the internal driver memory
+ * Returns 0 if successful, or -EINVAL if invalid IO number is passed.
+ **/
+int isp_csi2_timings_get(u8 io)
+{
+ struct isp_csi2_timings_cfg *currtimings;
+ struct isp_csi2_timings_cfg_update *currtimings_u;
+ u32 reg;
+
+ if (io > 2) {
+ printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n");
+ return -EINVAL;
+ }
+
+ currtimings = ¤t_csi2_cfg.timings[io - 1];
+ currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
+
+ reg = omap_readl(ISPCSI2_TIMING);
+ if ((reg & ISPCSI2_TIMING_FORCE_RX_MODE_IO_MASK(io)) ==
+ ISPCSI2_TIMING_FORCE_RX_MODE_IO_ENABLE(io))
+ currtimings->force_rx_mode = true;
+ else
+ currtimings->force_rx_mode = false;
+ currtimings_u->force_rx_mode = false;
+
+ if ((reg & ISPCSI2_TIMING_STOP_STATE_X16_IO_MASK(io)) ==
+ ISPCSI2_TIMING_STOP_STATE_X16_IO_ENABLE(io))
+ currtimings->stop_state_16x = true;
+ else
+ currtimings->stop_state_16x = false;
+ currtimings_u->stop_state_16x = false;
+
+ if ((reg & ISPCSI2_TIMING_STOP_STATE_X4_IO_MASK(io)) ==
+ ISPCSI2_TIMING_STOP_STATE_X4_IO_ENABLE(io))
+ currtimings->stop_state_4x = true;
+ else
+ currtimings->stop_state_4x = false;
+ currtimings_u->stop_state_4x = false;
+
+ currtimings->stop_state_counter = (reg &
+ ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(io)) >>
+ ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(io);
+ currtimings_u->stop_state_counter = false;
+ update_timing = false;
+ return 0;
+}
+
+/**
+ * isp_csi2_timings_update_all - Applies specified CSI2 timing configuration.
+ * @force_update: Flag to force rewrite of registers, even if they haven't been
+ * updated with the isp_csi2_timings_config_*() functions.
+ *
+ * It only saves settings when they were previously updated using the
+ * isp_csi2_timings_config_*() functions, unless the force_update flag is
+ * set to true.
+ * Always returns 0.
+ **/
+int isp_csi2_timings_update_all(bool force_update)
+{
+ int i;
+
+ for (i = 0; i < 2; i++)
+ isp_csi2_timings_update(i, force_update);
+ return 0;
+}
+
+/**
+ * isp_csi2_timings_get_all - Gets all CSI2 ComplexIO timing configurations
+ *
+ * Always returns 0.
+ **/
+int isp_csi2_timings_get_all(void)
+{
+ int i;
+
+ for (i = 0; i < 2; i++)
+ isp_csi2_timings_get(i);
+ return 0;
+}
+
+/**
+ * isp_csi2_isr - CSI2 interrupt handling.
+ **/
+void isp_csi2_isr(void)
+{
+ u32 csi2_irqstatus, cpxio1_irqstatus, ctxirqstatus;
+
+ csi2_irqstatus = omap_readl(ISPCSI2_IRQSTATUS);
+ omap_writel(csi2_irqstatus, ISPCSI2_IRQSTATUS);
+
+ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ) {
+ cpxio1_irqstatus = omap_readl(ISPCSI2_COMPLEXIO1_IRQSTATUS);
+ omap_writel(cpxio1_irqstatus, ISPCSI2_COMPLEXIO1_IRQSTATUS);
+ printk(KERN_ERR "CSI2: ComplexIO Error IRQ %x\n",
+ cpxio1_irqstatus);
+ }
+
+ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0)) {
+ ctxirqstatus = omap_readl(ISPCSI2_CTX_IRQSTATUS(0));
+ omap_writel(ctxirqstatus, ISPCSI2_CTX_IRQSTATUS(0));
+ }
+
+ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_OCP_ERR_IRQ)
+ printk(KERN_ERR "CSI2: OCP Transmission Error\n");
+
+ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ)
+ printk(KERN_ERR "CSI2: Short packet receive error\n");
+
+ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ)
+ printk(KERN_DEBUG "CSI2: ECC correction done\n");
+
+ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ)
+ printk(KERN_ERR "CSI2: ECC correction failed\n");
+
+ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ)
+ printk(KERN_ERR "CSI2: ComplexIO #2 failed\n");
+
+ if (csi2_irqstatus & ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)
+ printk(KERN_ERR "CSI2: FIFO overflow error\n");
+
+ return;
+}
+EXPORT_SYMBOL(isp_csi2_isr);
+
+/**
+ * isp_csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs.
+ * @enable: Enable/disable CSI2 ComplexIO #1 interrupts
+ **/
+void isp_csi2_irq_complexio1_set(int enable)
+{
+ u32 reg;
+ reg = ISPCSI2_COMPLEXIO1_IRQENABLE_STATEALLULPMEXIT |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_STATEALLULPMENTER |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_STATEULPM5 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRCONTROL5 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC5 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS5 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS5 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_STATEULPM4 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRCONTROL4 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC4 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS4 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS4 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_STATEULPM3 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRCONTROL3 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC3 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS3 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS3 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_STATEULPM2 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRCONTROL2 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC2 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS2 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS2 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_STATEULPM1 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRCONTROL1 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC1 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS1 |
+ ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS1;
+ omap_writel(reg, ISPCSI2_COMPLEXIO1_IRQSTATUS);
+ if (enable)
+ reg |= omap_readl(ISPCSI2_COMPLEXIO1_IRQENABLE);
+ else
+ reg = 0;
+ omap_writel(reg, ISPCSI2_COMPLEXIO1_IRQENABLE);
+}
+EXPORT_SYMBOL(isp_csi2_irq_complexio1_set);
+
+/**
+ * isp_csi2_irq_ctx_set - Enables CSI2 Context IRQs.
+ * @enable: Enable/disable CSI2 Context interrupts
+ **/
+void isp_csi2_irq_ctx_set(int enable)
+{
+ u32 reg;
+ int i;
+
+ reg = ISPCSI2_CTX_IRQSTATUS_FS_IRQ | ISPCSI2_CTX_IRQSTATUS_FE_IRQ;
+ for (i = 0; i < 8; i++) {
+ omap_writel(reg, ISPCSI2_CTX_IRQSTATUS(i));
+ if (enable) {
+ omap_writel(omap_readl(ISPCSI2_CTX_IRQENABLE(i)) | reg,
+ ISPCSI2_CTX_IRQENABLE(i));
+ } else
+ omap_writel(0, ISPCSI2_CTX_IRQENABLE(i));
+ }
+
+}
+EXPORT_SYMBOL(isp_csi2_irq_ctx_set);
+
+/**
+ * isp_csi2_irq_status_set - Enables CSI2 Status IRQs.
+ * @enable: Enable/disable CSI2 Status interrupts
+ **/
+void isp_csi2_irq_status_set(int enable)
+{
+ u32 reg;
+ reg = ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
+ ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ |
+ ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ |
+ ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ |
+ ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ |
+ ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ |
+ ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ |
+ ISPCSI2_IRQSTATUS_CONTEXT(0);
+ omap_writel(reg, ISPCSI2_IRQSTATUS);
+ if (enable)
+ reg |= omap_readl(ISPCSI2_IRQENABLE);
+ else
+ reg = 0;
+
+ omap_writel(reg, ISPCSI2_IRQENABLE);
+}
+EXPORT_SYMBOL(isp_csi2_irq_status_set);
+
+/**
+ * isp_csi2_irq_status_set - Enables main CSI2 IRQ.
+ * @enable: Enable/disable main CSI2 interrupt
+ **/
+void isp_csi2_irq_set(int enable)
+{
+ if (enable) {
+ omap_writel(IRQ0STATUS_CSIA_IRQ, ISP_IRQ0STATUS);
+ omap_writel(omap_readl(ISP_IRQ0ENABLE) | IRQ0ENABLE_CSIA_IRQ,
+ ISP_IRQ0ENABLE);
+ } else {
+ omap_writel(IRQ0STATUS_CSIA_IRQ, ISP_IRQ0STATUS);
+ omap_writel(omap_readl(ISP_IRQ0ENABLE) & ~IRQ0ENABLE_CSIA_IRQ,
+ ISP_IRQ0ENABLE);
+ }
+}
+EXPORT_SYMBOL(isp_csi2_irq_set);
+
+/**
+ * isp_csi2_irq_all_set - Enable/disable CSI2 interrupts.
+ * @enable: 0-Disable, 1-Enable.
+ **/
+void isp_csi2_irq_all_set(int enable)
+{
+ if (enable) {
+ isp_csi2_irq_complexio1_set(enable);
+ isp_csi2_irq_ctx_set(enable);
+ isp_csi2_irq_status_set(enable);
+ isp_csi2_irq_set(enable);
+ } else {
+ isp_csi2_irq_set(enable);
+ isp_csi2_irq_status_set(enable);
+ isp_csi2_irq_ctx_set(enable);
+ isp_csi2_irq_complexio1_set(enable);
+ }
+ return;
+}
+EXPORT_SYMBOL(isp_csi2_irq_all_set);
+
+/**
+ * isp_csi2_reset - Resets the CSI2 module.
+ *
+ * Returns 0 if successful, or -EBUSY if power command didn't respond.
+ **/
+int isp_csi2_reset(void)
+{
+ u32 reg;
+ u8 soft_reset_retries = 0;
+ int i;
+
+ reg = omap_readl(ISPCSI2_SYSCONFIG);
+ reg |= ISPCSI2_SYSCONFIG_SOFT_RESET_RESET;
+ omap_writel(reg, ISPCSI2_SYSCONFIG);
+
+ do {
+ reg = omap_readl(ISPCSI2_SYSSTATUS) &
+ ISPCSI2_SYSSTATUS_RESET_DONE_MASK;
+ if (reg == ISPCSI2_SYSSTATUS_RESET_DONE_DONE)
+ break;
+ soft_reset_retries++;
+ if (soft_reset_retries < 5)
+ udelay(100);
+ } while (soft_reset_retries < 5);
+
+ if (soft_reset_retries == 5) {
+ printk(KERN_ERR "CSI2: Soft reset try count exceeded!\n");
+ return -EBUSY;
+ }
+
+ reg = omap_readl(ISPCSI2_SYSCONFIG);
+ reg &= ~ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK;
+ reg |= ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO;
+ reg &= ~ISPCSI2_SYSCONFIG_AUTO_IDLE_MASK;
+ omap_writel(reg, ISPCSI2_SYSCONFIG);
+
+ uses_videoport = false;
+ update_complexio_cfg1 = false;
+ update_phy_cfg0 = false;
+ update_phy_cfg1 = false;
+ for (i = 0; i < 8; i++) {
+ update_ctx_ctrl1[i] = false;
+ update_ctx_ctrl2[i] = false;
+ update_ctx_ctrl3[i] = false;
+ }
+ update_timing = false;
+ update_ctrl = false;
+
+ isp_csi2_complexio_lanes_get();
+ isp_csi2_ctrl_get();
+ isp_csi2_ctx_get_all();
+ isp_csi2_phy_get();
+ isp_csi2_timings_get_all();
+
+ isp_csi2_complexio_power_autoswitch(true);
+ isp_csi2_complexio_power(ISP_CSI2_POWER_ON);
+
+ isp_csi2_timings_config_forcerxmode(1, true);
+ isp_csi2_timings_config_stopstate_cnt(1, 0x1FF);
+ isp_csi2_timings_update_all(true);
+
+ return 0;
+}
+
+/**
+ * isp_csi2_enable - Enables the CSI2 module.
+ * @enable: Enables/disables the CSI2 module.
+ **/
+void isp_csi2_enable(int enable)
+{
+ if (enable) {
+ isp_csi2_ctx_config_enabled(0, true);
+ isp_csi2_ctx_config_eof_enabled(0, true);
+ isp_csi2_ctx_config_checksum_enabled(0, true);
+ isp_csi2_ctx_update(0, false);
+
+ isp_csi2_ctrl_config_ecc_enable(true);
+ isp_csi2_ctrl_config_if_enable(true);
+ isp_csi2_ctrl_update(false);
+ } else {
+ isp_csi2_ctx_config_enabled(0, false);
+ isp_csi2_ctx_config_eof_enabled(0, false);
+ isp_csi2_ctx_config_checksum_enabled(0, false);
+ isp_csi2_ctx_update(0, false);
+
+ isp_csi2_ctrl_config_ecc_enable(false);
+ isp_csi2_ctrl_config_if_enable(false);
+ isp_csi2_ctrl_update(false);
+ }
+}
+EXPORT_SYMBOL(isp_csi2_enable);
+
+/**
+ * isp_csi2_regdump - Prints CSI2 debug information.
+ **/
+void isp_csi2_regdump(void)
+{
+ printk(KERN_DEBUG "-------------Register dump-------------\n");
+
+ printk(KERN_DEBUG "ISP_CTRL: %x\n", omap_readl(ISP_CTRL));
+ printk(KERN_DEBUG "ISP_TCTRL_CTRL: %x\n", omap_readl(ISP_TCTRL_CTRL));
+
+ printk(KERN_DEBUG "ISPCCDC_SDR_ADDR: %x\n",
+ omap_readl(ISPCCDC_SDR_ADDR));
+ printk(KERN_DEBUG "ISPCCDC_SYN_MODE: %x\n",
+ omap_readl(ISPCCDC_SYN_MODE));
+ printk(KERN_DEBUG "ISPCCDC_CFG: %x\n", omap_readl(ISPCCDC_CFG));
+ printk(KERN_DEBUG "ISPCCDC_FMTCFG: %x\n", omap_readl(ISPCCDC_FMTCFG));
+ printk(KERN_DEBUG "ISPCCDC_HSIZE_OFF: %x\n",
+ omap_readl(ISPCCDC_HSIZE_OFF));
+ printk(KERN_DEBUG "ISPCCDC_HORZ_INFO: %x\n",
+ omap_readl(ISPCCDC_HORZ_INFO));
+ printk(KERN_DEBUG "ISPCCDC_VERT_START: %x\n",
+ omap_readl(ISPCCDC_VERT_START));
+ printk(KERN_DEBUG "ISPCCDC_VERT_LINES: %x\n",
+ omap_readl(ISPCCDC_VERT_LINES));
+
+ printk(KERN_DEBUG "ISPCSI2_COMPLEXIO_CFG1: %x\n",
+ omap_readl(ISPCSI2_COMPLEXIO_CFG1));
+ printk(KERN_DEBUG "ISPCSI2_SYSSTATUS: %x\n",
+ omap_readl(ISPCSI2_SYSSTATUS));
+ printk(KERN_DEBUG "ISPCSI2_SYSCONFIG: %x\n",
+ omap_readl(ISPCSI2_SYSCONFIG));
+ printk(KERN_DEBUG "ISPCSI2_IRQENABLE: %x\n",
+ omap_readl(ISPCSI2_IRQENABLE));
+ printk(KERN_DEBUG "ISPCSI2_IRQSTATUS: %x\n",
+ omap_readl(ISPCSI2_IRQSTATUS));
+
+ printk(KERN_DEBUG "ISPCSI2_CTX_IRQENABLE(0): %x\n",
+ omap_readl(ISPCSI2_CTX_IRQENABLE(0)));
+ printk(KERN_DEBUG "ISPCSI2_CTX_IRQSTATUS(0): %x\n",
+ omap_readl(ISPCSI2_CTX_IRQSTATUS(0)));
+ printk(KERN_DEBUG "ISPCSI2_TIMING: %x\n", omap_readl(ISPCSI2_TIMING));
+ printk(KERN_DEBUG "ISPCSI2PHY_CFG0: %x\n", omap_readl(ISPCSI2PHY_CFG0));
+ printk(KERN_DEBUG "ISPCSI2PHY_CFG1: %x\n", omap_readl(ISPCSI2PHY_CFG1));
+ printk(KERN_DEBUG "ISPCSI2_CTX_CTRL1(0): %x\n",
+ omap_readl(ISPCSI2_CTX_CTRL1(0)));
+ printk(KERN_DEBUG "ISPCSI2_CTX_CTRL2(0): %x\n",
+ omap_readl(ISPCSI2_CTX_CTRL2(0)));
+ printk(KERN_DEBUG "ISPCSI2_CTX_CTRL3(0): %x\n",
+ omap_readl(ISPCSI2_CTX_CTRL3(0)));
+ printk(KERN_DEBUG "ISPCSI2_CTX_DAT_OFST(0): %x\n",
+ omap_readl(ISPCSI2_CTX_DAT_OFST(0)));
+ printk(KERN_DEBUG "ISPCSI2_CTX_DAT_PING_ADDR(0): %x\n",
+ omap_readl(ISPCSI2_CTX_DAT_PING_ADDR(0)));
+ printk(KERN_DEBUG "ISPCSI2_CTX_DAT_PONG_ADDR(0): %x\n",
+ omap_readl(ISPCSI2_CTX_DAT_PONG_ADDR(0)));
+ printk(KERN_DEBUG "ISPCSI2_CTRL: %x\n", omap_readl(ISPCSI2_CTRL));
+ printk(KERN_DEBUG "---------------------------------------\n");
+}
+
+/**
+ * isp_csi2_cleanup - Routine for module driver cleanup
+ **/
+void __exit isp_csi2_cleanup(void)
+{
+ return;
+}
+
+/**
+ * isp_csi2_init - Routine for module driver init
+ **/
+int __init isp_csi2_init(void)
+{
+ int i;
+
+ update_complexio_cfg1 = false;
+ update_phy_cfg0 = false;
+ update_phy_cfg1 = false;
+ for (i = 0; i < 8; i++) {
+ update_ctx_ctrl1[i] = false;
+ update_ctx_ctrl2[i] = false;
+ update_ctx_ctrl3[i] = false;
+ }
+ update_timing = false;
+ update_ctrl = false;
+
+ memset(¤t_csi2_cfg, 0, sizeof(current_csi2_cfg));
+ memset(¤t_csi2_cfg_update, 0, sizeof(current_csi2_cfg_update));
+ return 0;
+}
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("ISP CSI2 Receiver Module");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/isp/ispcsi2.h b/drivers/media/video/isp/ispcsi2.h
new file mode 100644
index 0000000..1419bda
--- /dev/null
+++ b/drivers/media/video/isp/ispcsi2.h
@@ -0,0 +1,232 @@
+/*
+ * drivers/media/video/isp/ispcsi2.h
+ *
+ * Copyright (C) 2008 Texas Instruments.
+ *
+ * Contributors:
+ * Sergio Aguirre <saaguirre@ti.com>
+ * Dominic Curran <dcurran@ti.com>
+ *
+ * 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_CSI2_API_H
+#define OMAP_ISP_CSI2_API_H
+#include <linux/videodev2.h>
+
+enum isp_csi2_irqevents {
+ OCP_ERR_IRQ = 0x4000,
+ SHORT_PACKET_IRQ = 0x2000,
+ ECC_CORRECTION_IRQ = 0x1000,
+ ECC_NO_CORRECTION_IRQ = 0x800,
+ COMPLEXIO2_ERR_IRQ = 0x400,
+ COMPLEXIO1_ERR_IRQ = 0x200,
+ FIFO_OVF_IRQ = 0x100,
+ CONTEXT7 = 0x80,
+ CONTEXT6 = 0x40,
+ CONTEXT5 = 0x20,
+ CONTEXT4 = 0x10,
+ CONTEXT3 = 0x8,
+ CONTEXT2 = 0x4,
+ CONTEXT1 = 0x2,
+ CONTEXT0 = 0x1,
+};
+
+enum isp_csi2_ctx_irqevents {
+ CTX_ECC_CORRECTION = 0x100,
+ CTX_LINE_NUMBER = 0x80,
+ CTX_FRAME_NUMBER = 0x40,
+ CTX_CS = 0x20,
+ CTX_LE = 0x8,
+ CTX_LS = 0x4,
+ CTX_FE = 0x2,
+ CTX_FS = 0x1,
+};
+
+enum isp_csi2_power_cmds {
+ ISP_CSI2_POWER_OFF,
+ ISP_CSI2_POWER_ON,
+ ISP_CSI2_POWER_ULPW,
+};
+
+enum isp_csi2_frame_mode {
+ ISP_CSI2_FRAME_IMMEDIATE,
+ ISP_CSI2_FRAME_AFTERFEC,
+};
+
+struct csi2_lanecfg {
+ u8 pos;
+ u8 pol;
+};
+
+struct isp_csi2_lanes_cfg {
+ struct csi2_lanecfg data[4];
+ struct csi2_lanecfg clk;
+};
+
+struct isp_csi2_lanes_cfg_update {
+ bool data[4];
+ bool clk;
+};
+
+struct isp_csi2_phy_cfg {
+ u8 ths_term;
+ u8 ths_settle;
+ u8 tclk_term;
+ unsigned tclk_miss:1;
+ u8 tclk_settle;
+};
+
+struct isp_csi2_phy_cfg_update {
+ bool ths_term;
+ bool ths_settle;
+ bool tclk_term;
+ bool tclk_miss;
+ bool tclk_settle;
+};
+
+struct isp_csi2_ctx_cfg {
+ u8 virtual_id;
+ u8 frame_count;
+ struct v4l2_pix_format format;
+ u16 alpha;
+ u16 data_offset;
+ u32 ping_addr;
+ u32 pong_addr;
+ bool eof_enabled;
+ bool eol_enabled;
+ bool checksum_enabled;
+ bool enabled;
+};
+
+struct isp_csi2_ctx_cfg_update {
+ bool virtual_id;
+ bool frame_count;
+ bool format;
+ bool alpha;
+ bool data_offset;
+ bool ping_addr;
+ bool pong_addr;
+ bool eof_enabled;
+ bool eol_enabled;
+ bool checksum_enabled;
+ bool enabled;
+};
+
+struct isp_csi2_timings_cfg {
+ bool force_rx_mode;
+ bool stop_state_16x;
+ bool stop_state_4x;
+ u16 stop_state_counter;
+};
+
+struct isp_csi2_timings_cfg_update {
+ bool force_rx_mode;
+ bool stop_state_16x;
+ bool stop_state_4x;
+ bool stop_state_counter;
+};
+
+struct isp_csi2_ctrl_cfg {
+ bool vp_clk_enable;
+ bool vp_only_enable;
+ u8 vp_out_ctrl;
+ bool debug_enable;
+ u8 burst_size;
+ enum isp_csi2_frame_mode frame_mode;
+ bool ecc_enable;
+ bool secure_mode;
+ bool if_enable;
+};
+
+struct isp_csi2_ctrl_cfg_update {
+ bool vp_clk_enable;
+ bool vp_only_enable;
+ bool vp_out_ctrl;
+ bool debug_enable;
+ bool burst_size;
+ bool frame_mode;
+ bool ecc_enable;
+ bool secure_mode;
+ bool if_enable;
+};
+
+struct isp_csi2_cfg {
+ struct isp_csi2_lanes_cfg lanes;
+ struct isp_csi2_phy_cfg phy;
+ struct isp_csi2_ctx_cfg contexts[8];
+ struct isp_csi2_timings_cfg timings[2];
+ struct isp_csi2_ctrl_cfg ctrl;
+};
+
+struct isp_csi2_cfg_update {
+ struct isp_csi2_lanes_cfg_update lanes;
+ struct isp_csi2_phy_cfg_update phy;
+ struct isp_csi2_ctx_cfg_update contexts[8];
+ struct isp_csi2_timings_cfg_update timings[2];
+ struct isp_csi2_ctrl_cfg_update ctrl;
+};
+
+int isp_csi2_complexio_lanes_config(struct isp_csi2_lanes_cfg *reqcfg);
+int isp_csi2_complexio_lanes_update(bool force_update);
+int isp_csi2_complexio_lanes_get(void);
+int isp_csi2_complexio_power_autoswitch(bool enable);
+int isp_csi2_complexio_power(enum isp_csi2_power_cmds power_cmd);
+int isp_csi2_ctrl_config_frame_mode(enum isp_csi2_frame_mode frame_mode);
+int isp_csi2_ctrl_config_vp_clk_enable(bool vp_clk_enable);
+int isp_csi2_ctrl_config_vp_only_enable(bool vp_only_enable);
+int isp_csi2_ctrl_config_debug_enable(bool debug_enable);
+int isp_csi2_ctrl_config_burst_size(u8 burst_size);
+int isp_csi2_ctrl_config_ecc_enable(bool ecc_enable);
+int isp_csi2_ctrl_config_secure_mode(bool secure_mode);
+int isp_csi2_ctrl_config_if_enable(bool if_enable);
+int isp_csi2_ctrl_config_vp_out_ctrl(u8 vp_out_ctrl);
+int isp_csi2_ctrl_update(bool force_update);
+int isp_csi2_ctrl_get(void);
+int isp_csi2_ctx_config_virtual_id(u8 ctxnum, u8 virtual_id);
+int isp_csi2_ctx_config_frame_count(u8 ctxnum, u8 frame_count);
+int isp_csi2_ctx_config_format(u8 ctxnum, u32 pixformat);
+int isp_csi2_ctx_config_alpha(u8 ctxnum, u16 alpha);
+int isp_csi2_ctx_config_data_offset(u8 ctxnum, u16 data_offset);
+int isp_csi2_ctx_config_ping_addr(u8 ctxnum, u32 ping_addr);
+int isp_csi2_ctx_config_pong_addr(u8 ctxnum, u32 pong_addr);
+int isp_csi2_ctx_config_eof_enabled(u8 ctxnum, bool eof_enabled);
+int isp_csi2_ctx_config_eol_enabled(u8 ctxnum, bool eol_enabled);
+int isp_csi2_ctx_config_checksum_enabled(u8 ctxnum, bool checksum_enabled);
+int isp_csi2_ctx_config_enabled(u8 ctxnum, bool enabled);
+int isp_csi2_ctx_update(u8 ctxnum, bool force_update);
+int isp_csi2_ctx_get(u8 ctxnum);
+int isp_csi2_ctx_update_all(bool force_update);
+int isp_csi2_ctx_get_all(void);
+int isp_csi2_phy_config(struct isp_csi2_phy_cfg *desiredphyconfig);
+int isp_csi2_calc_phy_cfg0(u32 mipiclk, u32 lbound_hs_settle,
+ u32 ubound_hs_settle);
+int isp_csi2_phy_update(bool force_update);
+int isp_csi2_phy_get(void);
+int isp_csi2_timings_config_forcerxmode(u8 io, bool force_rx_mode);
+int isp_csi2_timings_config_stopstate_16x(u8 io, bool stop_state_16x);
+int isp_csi2_timings_config_stopstate_4x(u8 io, bool stop_state_4x);
+int isp_csi2_timings_config_stopstate_cnt(u8 io, u16 stop_state_counter);
+int isp_csi2_timings_update(u8 io, bool force_update);
+int isp_csi2_timings_get(u8 io);
+int isp_csi2_timings_update_all(bool force_update);
+int isp_csi2_timings_get_all(void);
+void isp_csi2_irq_complexio1_set(int enable);
+void isp_csi2_irq_ctx_set(int enable);
+void isp_csi2_irq_status_set(int enable);
+void isp_csi2_irq_set(int enable);
+void isp_csi2_irq_all_set(int enable);
+
+void isp_csi2_isr(void);
+int isp_csi2_reset(void);
+void isp_csi2_enable(int enable);
+void isp_csi2_regdump(void);
+
+#endif /* OMAP_ISP_CSI2_H */
+
--
1.5.6.5
--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
^ permalink raw reply related [flat|nested] 3+ messages in thread
* Re: [REVIEW PATCH 07/14] OMAP: CAM: Add ISP CSI2 API
2008-12-11 20:38 [REVIEW PATCH 07/14] OMAP: CAM: Add ISP CSI2 API Aguirre Rodriguez, Sergio Alberto
@ 2008-12-15 16:16 ` Tony Lindgren
2008-12-16 16:55 ` Hans Verkuil
1 sibling, 0 replies; 3+ messages in thread
From: Tony Lindgren @ 2008-12-15 16:16 UTC (permalink / raw)
To: Aguirre Rodriguez, Sergio Alberto
Cc: linux-omap@vger.kernel.org, video4linux-list@redhat.com,
Sakari Ailus, Tuukka.O Toivonen, Hiremath, Vaibhav, Nagalla, Hari
* Aguirre Rodriguez, Sergio Alberto <saaguirre@ti.com> [081211 12:41]:
> From c442f389de719b47f8ec63f0ae07b5e2c2ef7b9d Mon Sep 17 00:00:00 2001
> From: Sergio Aguirre <saaguirre@ti.com>
> Date: Thu, 11 Dec 2008 13:35:49 -0600
> Subject: [PATCH] OMAP: CAM: Add ISP CSI2 API
>
> Add ISP CSI2 API for operating OMAP3430 CSI2 receiver registers
>
> Signed-off-by: Sergio Aguirre <saaguirre@ti.com>
> ---
> drivers/media/video/isp/ispcsi2.c | 2106 +++++++++++++++++++++++++++++++++++++
> drivers/media/video/isp/ispcsi2.h | 232 ++++
> 2 files changed, 2338 insertions(+), 0 deletions(-)
> create mode 100644 drivers/media/video/isp/ispcsi2.c
> create mode 100644 drivers/media/video/isp/ispcsi2.h
>
> diff --git a/drivers/media/video/isp/ispcsi2.c b/drivers/media/video/isp/ispcsi2.c
> new file mode 100644
> index 0000000..423ea3a
> --- /dev/null
> +++ b/drivers/media/video/isp/ispcsi2.c
> @@ -0,0 +1,2106 @@
> +/*
> + * drivers/media/video/isp/ispcsi2.c
> + *
> + * Driver Library for ISP CSI Control module in TI's OMAP3 Camera ISP
> + * ISP CSI interface and IRQ related APIs are defined here.
> + *
> + * Copyright (C) 2008 Texas Instruments.
> + *
> + * Contributors:
> + * Sergio Aguirre <saaguirre@ti.com>
> + * Dominic Curran <dcurran@ti.com>
> + *
> + * 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 <linux/errno.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/types.h>
> +#include <asm/mach-types.h>
This should not be needed.
> +#include <media/v4l2-common.h>
> +#include <media/v4l2-int-device.h>
> +#include <linux/io.h>
> +#include <mach/io.h>
> +
> +#include "isp.h"
> +#include "ispreg.h"
> +#include "ispcsi2.h"
> +
<snip>
> +/**
> + * isp_csi2_complexio_lanes_update - Applies CSI2 ComplexIO lanes configuration.
> + * @force_update: Flag to force rewrite of registers, even if they haven't been
> + * updated with the isp_csi2_complexio_lanes_config() function.
> + *
> + * It only saves settings when they were previously updated using the
> + * isp_csi2_complexio_lanes_config() function, unless the force_update flag is
> + * set to true.
> + * Always returns 0.
> + **/
> +int isp_csi2_complexio_lanes_update(bool force_update)
> +{
> + struct isp_csi2_lanes_cfg *currlanes = ¤t_csi2_cfg.lanes;
> + struct isp_csi2_lanes_cfg_update *currlanes_u =
> + ¤t_csi2_cfg_update.lanes;
> + u32 reg;
> + int i;
> +
> + if ((update_complexio_cfg1 == false) && (force_update == false))
> + return 0;
> +
> + reg = omap_readl(ISPCSI2_COMPLEXIO_CFG1);
> + for (i = 0; i < 4; i++) {
> + if ((currlanes_u->data[i] == true) || (force_update == true)) {
> + reg &= ~(ISPCSI2_COMPLEXIO_CFG1_DATA_POL_MASK(i + 1) |
> + ISPCSI2_COMPLEXIO_CFG1_DATA_POSITION_MASK(i +
> + 1));
> + reg |= (currlanes->data[i].pol <<
> + ISPCSI2_COMPLEXIO_CFG1_DATA_POL_SHIFT(i + 1));
> + reg |= (currlanes->data[i].pos <<
> + ISPCSI2_COMPLEXIO_CFG1_DATA_POSITION_SHIFT(i +
> + 1));
> + currlanes_u->data[i] = false;
> + }
> + }
> +
> + if ((currlanes_u->clk == true) || (force_update == true)) {
> + reg &= ~(ISPCSI2_COMPLEXIO_CFG1_CLOCK_POL_MASK |
> + ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_MASK);
> + reg |= (currlanes->clk.pol <<
> + ISPCSI2_COMPLEXIO_CFG1_CLOCK_POL_SHIFT);
> + reg |= (currlanes->clk.pos <<
> + ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_SHIFT);
> + currlanes_u->clk = false;
> + }
> + omap_writel(reg, ISPCSI2_COMPLEXIO_CFG1);
You should change this driver too to pass IORESOURCE from
platform_data, then ioremap it in the driver, and then use
__raw_read/write instead of __omap_read/write.
Regards,
Tony
^ permalink raw reply [flat|nested] 3+ messages in thread
* Re: [REVIEW PATCH 07/14] OMAP: CAM: Add ISP CSI2 API
2008-12-11 20:38 [REVIEW PATCH 07/14] OMAP: CAM: Add ISP CSI2 API Aguirre Rodriguez, Sergio Alberto
2008-12-15 16:16 ` Tony Lindgren
@ 2008-12-16 16:55 ` Hans Verkuil
1 sibling, 0 replies; 3+ messages in thread
From: Hans Verkuil @ 2008-12-16 16:55 UTC (permalink / raw)
To: video4linux-list
Cc: Sakari Ailus, linux-omap@vger.kernel.org, Tuukka.O Toivonen,
Nagalla, Hari
On Thursday 11 December 2008 21:38:04 Aguirre Rodriguez, Sergio Alberto wrote:
> >From c442f389de719b47f8ec63f0ae07b5e2c2ef7b9d Mon Sep 17 00:00:00 2001
> From: Sergio Aguirre <saaguirre@ti.com>
> Date: Thu, 11 Dec 2008 13:35:49 -0600
> Subject: [PATCH] OMAP: CAM: Add ISP CSI2 API
>
> Add ISP CSI2 API for operating OMAP3430 CSI2 receiver registers
>
> Signed-off-by: Sergio Aguirre <saaguirre@ti.com>
> ---
> drivers/media/video/isp/ispcsi2.c | 2106 +++++++++++++++++++++++++++++++++++++
> drivers/media/video/isp/ispcsi2.h | 232 ++++
> 2 files changed, 2338 insertions(+), 0 deletions(-)
> create mode 100644 drivers/media/video/isp/ispcsi2.c
> create mode 100644 drivers/media/video/isp/ispcsi2.h
>
> diff --git a/drivers/media/video/isp/ispcsi2.c b/drivers/media/video/isp/ispcsi2.c
> new file mode 100644
> index 0000000..423ea3a
> --- /dev/null
> +++ b/drivers/media/video/isp/ispcsi2.c
> @@ -0,0 +1,2106 @@
> +/*
> + * drivers/media/video/isp/ispcsi2.c
> + *
> + * Driver Library for ISP CSI Control module in TI's OMAP3 Camera ISP
> + * ISP CSI interface and IRQ related APIs are defined here.
> + *
> + * Copyright (C) 2008 Texas Instruments.
> + *
> + * Contributors:
> + * Sergio Aguirre <saaguirre@ti.com>
> + * Dominic Curran <dcurran@ti.com>
> + *
> + * 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 <linux/errno.h>
> +#include <linux/delay.h>
> +#include <linux/device.h>
> +#include <linux/types.h>
> +#include <asm/mach-types.h>
> +#include <media/v4l2-common.h>
> +#include <media/v4l2-int-device.h>
> +#include <linux/io.h>
> +#include <mach/io.h>
> +
> +#include "isp.h"
> +#include "ispreg.h"
> +#include "ispcsi2.h"
> +
> +static struct isp_csi2_cfg current_csi2_cfg;
> +static struct isp_csi2_cfg_update current_csi2_cfg_update;
> +
> +static bool update_complexio_cfg1;
> +static bool update_phy_cfg0;
> +static bool update_phy_cfg1;
> +static bool update_ctx_ctrl1[8];
> +static bool update_ctx_ctrl2[8];
> +static bool update_ctx_ctrl3[8];
> +static bool update_timing;
> +static bool update_ctrl;
> +static bool uses_videoport;
> +
> +/**
> + * isp_csi2_complexio_lanes_config - Configuration of CSI2 ComplexIO lanes.
> + * @reqcfg: Pointer to structure containing desired lane configuration
> + *
> + * Validates and saves to internal driver memory the passed configuration.
> + * Returns 0 if successful, or -EINVAL if null pointer is passed, invalid
> + * lane position or polarity is set, and if 2 lanes try to occupy the same
> + * position. To apply this settings, use the isp_csi2_complexio_lanes_update()
> + * function just after calling this function.
> + **/
> +int isp_csi2_complexio_lanes_config(struct isp_csi2_lanes_cfg *reqcfg)
> +{
> + int i;
> + bool pos_occupied[5] = {false, false, false, false, false};
> + struct isp_csi2_lanes_cfg *currlanes = ¤t_csi2_cfg.lanes;
> + struct isp_csi2_lanes_cfg_update *currlanes_u =
> + ¤t_csi2_cfg_update.lanes;
> +
> + /* Validating parameters sent by driver */
> + if (reqcfg == NULL) {
> + printk(KERN_ERR "Invalid Complex IO Configuration sent by"
> + " sensor\n");
> + goto err_einval;
> + }
> +
> + /* Data lanes verification */
> + for (i = 0; i < 4; i++) {
> + if ((reqcfg->data[i].pol > 1) || (reqcfg->data[i].pos > 5)) {
> + printk(KERN_ERR "Invalid CSI-2 Complex IO configuration"
> + " parameters for data lane #%d\n", i);
> + goto err_einval;
> + }
> + if ((pos_occupied[reqcfg->data[i].pos - 1] == true) &&
> + reqcfg->data[i].pos > 0) {
> + printk(KERN_ERR "Lane #%d already occupied\n",
> + reqcfg->data[i].pos);
> + goto err_einval;
> + } else
> + pos_occupied[reqcfg->data[i].pos - 1] = true;
> + }
> +
> + /* Clock lane verification */
> + if ((reqcfg->clk.pol > 1) || (reqcfg->clk.pos > 5) ||
> + (reqcfg->clk.pos == 0)) {
> + printk(KERN_ERR "Invalid CSI-2 Complex IO configuration"
> + " parameters for clock lane\n");
> + goto err_einval;
> + }
> + if (pos_occupied[reqcfg->clk.pos - 1] == true) {
> + printk(KERN_ERR "Lane #%d already occupied",
> + reqcfg->clk.pos);
> + goto err_einval;
> + } else
> + pos_occupied[reqcfg->clk.pos - 1] = true;
> +
> + for (i = 0; i < 4; i++) {
> + if (currlanes->data[i].pos != reqcfg->data[i].pos) {
> + currlanes->data[i].pos = reqcfg->data[i].pos;
> + currlanes_u->data[i] = true;
> + update_complexio_cfg1 = true;
> + }
> + if (currlanes->data[i].pol != reqcfg->data[i].pol) {
> + currlanes->data[i].pol = reqcfg->data[i].pol;
> + currlanes_u->data[i] = true;
> + update_complexio_cfg1 = true;
> + }
> + }
> +
> + if (currlanes->clk.pos != reqcfg->clk.pos) {
> + currlanes->clk.pos = reqcfg->clk.pos;
> + currlanes_u->clk = true;
> + update_complexio_cfg1 = true;
> + }
> + if (currlanes->clk.pol != reqcfg->clk.pol) {
> + currlanes->clk.pol = reqcfg->clk.pol;
> + currlanes_u->clk = true;
> + update_complexio_cfg1 = true;
> + }
> + return 0;
> +err_einval:
> + return -EINVAL;
> +}
> +
> +/**
> + * isp_csi2_complexio_lanes_update - Applies CSI2 ComplexIO lanes configuration.
> + * @force_update: Flag to force rewrite of registers, even if they haven't been
> + * updated with the isp_csi2_complexio_lanes_config() function.
> + *
> + * It only saves settings when they were previously updated using the
> + * isp_csi2_complexio_lanes_config() function, unless the force_update flag is
> + * set to true.
> + * Always returns 0.
> + **/
> +int isp_csi2_complexio_lanes_update(bool force_update)
> +{
> + struct isp_csi2_lanes_cfg *currlanes = ¤t_csi2_cfg.lanes;
> + struct isp_csi2_lanes_cfg_update *currlanes_u =
> + ¤t_csi2_cfg_update.lanes;
> + u32 reg;
> + int i;
> +
> + if ((update_complexio_cfg1 == false) && (force_update == false))
> + return 0;
> +
> + reg = omap_readl(ISPCSI2_COMPLEXIO_CFG1);
> + for (i = 0; i < 4; i++) {
> + if ((currlanes_u->data[i] == true) || (force_update == true)) {
> + reg &= ~(ISPCSI2_COMPLEXIO_CFG1_DATA_POL_MASK(i + 1) |
> + ISPCSI2_COMPLEXIO_CFG1_DATA_POSITION_MASK(i +
> + 1));
> + reg |= (currlanes->data[i].pol <<
> + ISPCSI2_COMPLEXIO_CFG1_DATA_POL_SHIFT(i + 1));
> + reg |= (currlanes->data[i].pos <<
> + ISPCSI2_COMPLEXIO_CFG1_DATA_POSITION_SHIFT(i +
> + 1));
> + currlanes_u->data[i] = false;
> + }
> + }
> +
> + if ((currlanes_u->clk == true) || (force_update == true)) {
Why not just:
if (currlanes_u->clk || force_update) {
The same unnecessary test against 'true' is used in a lot of places.
Regards,
Hans
> + reg &= ~(ISPCSI2_COMPLEXIO_CFG1_CLOCK_POL_MASK |
> + ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_MASK);
> + reg |= (currlanes->clk.pol <<
> + ISPCSI2_COMPLEXIO_CFG1_CLOCK_POL_SHIFT);
> + reg |= (currlanes->clk.pos <<
> + ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_SHIFT);
> + currlanes_u->clk = false;
> + }
> + omap_writel(reg, ISPCSI2_COMPLEXIO_CFG1);
> +
> + update_complexio_cfg1 = false;
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_complexio_lanes_get - Gets CSI2 ComplexIO lanes configuration.
> + *
> + * Gets settings from HW registers and fills in the internal driver memory
> + * Always returns 0.
> + **/
> +int isp_csi2_complexio_lanes_get(void)
> +{
> + struct isp_csi2_lanes_cfg *currlanes = ¤t_csi2_cfg.lanes;
> + struct isp_csi2_lanes_cfg_update *currlanes_u =
> + ¤t_csi2_cfg_update.lanes;
> + u32 reg;
> + int i;
> +
> + reg = omap_readl(ISPCSI2_COMPLEXIO_CFG1);
> + for (i = 0; i < 4; i++) {
> + currlanes->data[i].pol = (reg &
> + ISPCSI2_COMPLEXIO_CFG1_DATA_POL_MASK(i + 1)) >>
> + ISPCSI2_COMPLEXIO_CFG1_DATA_POL_SHIFT(i + 1);
> + currlanes->data[i].pos = (reg &
> + ISPCSI2_COMPLEXIO_CFG1_DATA_POSITION_MASK(i + 1)) >>
> + ISPCSI2_COMPLEXIO_CFG1_DATA_POSITION_SHIFT(i + 1);
> + currlanes_u->data[i] = false;
> + }
> + currlanes->clk.pol = (reg & ISPCSI2_COMPLEXIO_CFG1_CLOCK_POL_MASK) >>
> + ISPCSI2_COMPLEXIO_CFG1_CLOCK_POL_SHIFT;
> + currlanes->clk.pos = (reg &
> + ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_MASK) >>
> + ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_SHIFT;
> + currlanes_u->clk = false;
> +
> + update_complexio_cfg1 = false;
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_complexio_power_status - Gets CSI2 ComplexIO power status.
> + *
> + * Returns 3 possible valid states: ISP_CSI2_POWER_OFF, ISP_CSI2_POWER_ON,
> + * and ISP_CSI2_POWER_ULPW.
> + **/
> +static enum isp_csi2_power_cmds isp_csi2_complexio_power_status(void)
> +{
> + enum isp_csi2_power_cmds ret;
> + u32 reg;
> +
> + reg = omap_readl(ISPCSI2_COMPLEXIO_CFG1) &
> + ISPCSI2_COMPLEXIO_CFG1_PWR_STATUS_MASK;
> + switch (reg) {
> + case ISPCSI2_COMPLEXIO_CFG1_PWR_STATUS_OFF:
> + ret = ISP_CSI2_POWER_OFF;
> + break;
> + case ISPCSI2_COMPLEXIO_CFG1_PWR_STATUS_ON:
> + ret = ISP_CSI2_POWER_ON;
> + break;
> + case ISPCSI2_COMPLEXIO_CFG1_PWR_STATUS_ULPW:
> + ret = ISP_CSI2_POWER_ULPW;
> + break;
> + default:
> + return -EINVAL;
> + }
> + return ret;
> +}
> +
> +/**
> + * isp_csi2_complexio_power_autoswitch - Sets CSI2 ComplexIO power autoswitch.
> + * @enable: Sets or clears the autoswitch function enable flag.
> + *
> + * Always returns 0.
> + **/
> +int isp_csi2_complexio_power_autoswitch(bool enable)
> +{
> + u32 reg;
> +
> + reg = omap_readl(ISPCSI2_COMPLEXIO_CFG1);
> + reg &= ~ISPCSI2_COMPLEXIO_CFG1_PWR_AUTO_MASK;
> +
> + if (enable == true)
> + reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_AUTO_ENABLE;
> + else
> + reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_AUTO_DISABLE;
> +
> + omap_writel(reg, ISPCSI2_COMPLEXIO_CFG1);
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_complexio_power - Sets the desired power command for CSI2 ComplexIO.
> + * @power_cmd: Power command to be set.
> + *
> + * Returns 0 if successful, or -EBUSY if the retry count is exceeded.
> + **/
> +int isp_csi2_complexio_power(enum isp_csi2_power_cmds power_cmd)
> +{
> + enum isp_csi2_power_cmds current_state;
> + u32 reg;
> + u8 retry_count;
> +
> + reg = omap_readl(ISPCSI2_COMPLEXIO_CFG1) &
> + ~ISPCSI2_COMPLEXIO_CFG1_PWR_CMD_MASK;
> + switch (power_cmd) {
> + case ISP_CSI2_POWER_OFF:
> + reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_CMD_OFF;
> + break;
> + case ISP_CSI2_POWER_ON:
> + reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_CMD_ON;
> + break;
> + case ISP_CSI2_POWER_ULPW:
> + reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_CMD_ULPW;
> + break;
> + default:
> + printk(KERN_ERR "CSI2: ERROR - Wrong Power command!\n");
> + return -EINVAL;
> + }
> + omap_writel(reg, ISPCSI2_COMPLEXIO_CFG1);
> +
> + retry_count = 0;
> + do {
> + udelay(50);
> + current_state = isp_csi2_complexio_power_status();
> +
> + if (current_state != power_cmd) {
> + printk(KERN_DEBUG "CSI2: Complex IO power command not"
> + " yet taken.");
> + if (++retry_count < 100) {
> + printk(KERN_DEBUG " Retrying...\n");
> + udelay(50);
> + } else {
> + printk(KERN_DEBUG " Retry count exceeded!\n");
> + }
> + }
> + } while ((current_state != power_cmd) && (retry_count < 100));
> +
> + if (retry_count == 100)
> + return -EBUSY;
> +
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctrl_config_frame_mode - Configure if_en behaviour for CSI2
> + * @frame_mode: Desired action for IF_EN switch off. 0 - disable IF immediately
> + * 1 - disable after all Frame end Code is received in all
> + * contexts.
> + *
> + * Validates and saves to internal driver memory the passed configuration.
> + * Always returns 0.
> + **/
> +int isp_csi2_ctrl_config_frame_mode(enum isp_csi2_frame_mode frame_mode)
> +{
> + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
> + struct isp_csi2_ctrl_cfg_update *currctrl_u =
> + ¤t_csi2_cfg_update.ctrl;
> +
> + if (currctrl->frame_mode != frame_mode) {
> + currctrl->frame_mode = frame_mode;
> + currctrl_u->frame_mode = true;
> + update_ctrl = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctrl_config_vp_clk_enable - Enables/disables CSI2 Videoport clock.
> + * @vp_clk_enable: Boolean value to specify the Videoport clock state.
> + *
> + * Validates and saves to internal driver memory the passed configuration.
> + * Always returns 0.
> + **/
> +int isp_csi2_ctrl_config_vp_clk_enable(bool vp_clk_enable)
> +{
> + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
> + struct isp_csi2_ctrl_cfg_update *currctrl_u =
> + ¤t_csi2_cfg_update.ctrl;
> +
> + if (currctrl->vp_clk_enable != vp_clk_enable) {
> + currctrl->vp_clk_enable = vp_clk_enable;
> + currctrl_u->vp_clk_enable = true;
> + update_ctrl = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctrl_config_vp_only_enable - Sets CSI2 Videoport clock as exclusive
> + * @vp_only_enable: Boolean value to specify if the Videoport clock is
> + * exclusive, setting the OCP port as disabled.
> + *
> + * Validates and saves to internal driver memory the passed configuration.
> + * Always returns 0.
> + **/
> +int isp_csi2_ctrl_config_vp_only_enable(bool vp_only_enable)
> +{
> + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
> + struct isp_csi2_ctrl_cfg_update *currctrl_u =
> + ¤t_csi2_cfg_update.ctrl;
> +
> + if (currctrl->vp_only_enable != vp_only_enable) {
> + currctrl->vp_only_enable = vp_only_enable;
> + currctrl_u->vp_only_enable = true;
> + update_ctrl = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctrl_config_vp_out_ctrl - Sets CSI2 Videoport clock divider
> + * @vp_out_ctrl: Divider value for setting videoport clock frequency based on
> + * OCP port frequency, valid dividers are between 1 and 4.
> + *
> + * Validates and saves to internal driver memory the passed configuration.
> + * Returns 0 if successful, or -EINVAL if wrong divider value is passed.
> + **/
> +int isp_csi2_ctrl_config_vp_out_ctrl(u8 vp_out_ctrl)
> +{
> + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
> + struct isp_csi2_ctrl_cfg_update *currctrl_u =
> + ¤t_csi2_cfg_update.ctrl;
> +
> + if ((vp_out_ctrl == 0) || (vp_out_ctrl > 4)) {
> + printk(KERN_ERR "CSI2: Wrong divisor value. Must be between"
> + " 1 and 4");
> + return -EINVAL;
> + }
> +
> + if (currctrl->vp_out_ctrl != vp_out_ctrl) {
> + currctrl->vp_out_ctrl = vp_out_ctrl;
> + currctrl_u->vp_out_ctrl = true;
> + update_ctrl = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctrl_config_debug_enable - Sets CSI2 debug
> + * @debug_enable: Boolean for setting debug configuration on CSI2.
> + *
> + * Always returns 0.
> + **/
> +int isp_csi2_ctrl_config_debug_enable(bool debug_enable)
> +{
> + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
> + struct isp_csi2_ctrl_cfg_update *currctrl_u =
> + ¤t_csi2_cfg_update.ctrl;
> +
> + if (currctrl->debug_enable != debug_enable) {
> + currctrl->debug_enable = debug_enable;
> + currctrl_u->debug_enable = true;
> + update_ctrl = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctrl_config_burst_size - Sets CSI2 burst size.
> + * @burst_size: Burst size of the memory saving capability of receiver.
> + *
> + * Returns 0 if successful, or -EINVAL if burst size is wrong.
> + **/
> +int isp_csi2_ctrl_config_burst_size(u8 burst_size)
> +{
> + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
> + struct isp_csi2_ctrl_cfg_update *currctrl_u =
> + ¤t_csi2_cfg_update.ctrl;
> + if (burst_size > 3) {
> + printk(KERN_ERR "CSI2: Wrong burst size. Must be between"
> + " 0 and 3");
> + return -EINVAL;
> + }
> +
> + if (currctrl->burst_size != burst_size) {
> + currctrl->burst_size = burst_size;
> + currctrl_u->burst_size = true;
> + update_ctrl = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctrl_config_ecc_enable - Enables ECC on CSI2 Receiver
> + * @ecc_enable: Boolean to enable/disable the CSI2 receiver ECC handling.
> + *
> + * Always returns 0.
> + **/
> +int isp_csi2_ctrl_config_ecc_enable(bool ecc_enable)
> +{
> + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
> + struct isp_csi2_ctrl_cfg_update *currctrl_u =
> + ¤t_csi2_cfg_update.ctrl;
> +
> + if (currctrl->ecc_enable != ecc_enable) {
> + currctrl->ecc_enable = ecc_enable;
> + currctrl_u->ecc_enable = true;
> + update_ctrl = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctrl_config_ecc_enable - Enables ECC on CSI2 Receiver
> + * @ecc_enable: Boolean to enable/disable the CSI2 receiver ECC handling.
> + *
> + * Always returns 0.
> + **/
> +int isp_csi2_ctrl_config_secure_mode(bool secure_mode)
> +{
> + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
> + struct isp_csi2_ctrl_cfg_update *currctrl_u =
> + ¤t_csi2_cfg_update.ctrl;
> +
> + if (currctrl->secure_mode != secure_mode) {
> + currctrl->secure_mode = secure_mode;
> + currctrl_u->secure_mode = true;
> + update_ctrl = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctrl_config_if_enable - Enables CSI2 Receiver interface.
> + * @if_enable: Boolean to enable/disable the CSI2 receiver interface.
> + *
> + * Always returns 0.
> + **/
> +int isp_csi2_ctrl_config_if_enable(bool if_enable)
> +{
> + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
> + struct isp_csi2_ctrl_cfg_update *currctrl_u =
> + ¤t_csi2_cfg_update.ctrl;
> +
> + if (currctrl->if_enable != if_enable) {
> + currctrl->if_enable = if_enable;
> + currctrl_u->if_enable = true;
> + update_ctrl = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctrl_update - Applies CSI2 control configuration.
> + * @force_update: Flag to force rewrite of registers, even if they haven't been
> + * updated with the isp_csi2_ctrl_config_*() functions.
> + *
> + * It only saves settings when they were previously updated using the
> + * isp_csi2_ctrl_config_*() functions, unless the force_update flag is
> + * set to true.
> + * Always returns 0.
> + **/
> +int isp_csi2_ctrl_update(bool force_update)
> +{
> + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
> + struct isp_csi2_ctrl_cfg_update *currctrl_u =
> + ¤t_csi2_cfg_update.ctrl;
> + u32 reg;
> +
> + if ((update_ctrl == true) || (force_update == true)) {
> + reg = omap_readl(ISPCSI2_CTRL);
> + if ((currctrl_u->frame_mode == true) ||
> + (force_update == true)) {
> + reg &= ~ISPCSI2_CTRL_FRAME_MASK;
> + if (currctrl->frame_mode)
> + reg |= ISPCSI2_CTRL_FRAME_DISABLE_FEC;
> + else
> + reg |= ISPCSI2_CTRL_FRAME_DISABLE_IMM;
> + currctrl_u->frame_mode = false;
> + }
> + if ((currctrl_u->vp_clk_enable == true) ||
> + (force_update == true)) {
> + reg &= ~ISPCSI2_CTRL_VP_CLK_EN_MASK;
> + if (currctrl->vp_clk_enable)
> + reg |= ISPCSI2_CTRL_VP_CLK_EN_ENABLE;
> + else
> + reg |= ISPCSI2_CTRL_VP_CLK_EN_DISABLE;
> + currctrl_u->vp_clk_enable = false;
> + }
> + if ((currctrl_u->vp_only_enable == true) ||
> + (force_update == true)) {
> + reg &= ~ISPCSI2_CTRL_VP_ONLY_EN_MASK;
> + uses_videoport = currctrl->vp_only_enable;
> + if (currctrl->vp_only_enable)
> + reg |= ISPCSI2_CTRL_VP_ONLY_EN_ENABLE;
> + else
> + reg |= ISPCSI2_CTRL_VP_ONLY_EN_DISABLE;
> + currctrl_u->vp_only_enable = false;
> + }
> + if ((currctrl_u->vp_out_ctrl == true) ||
> + (force_update == true)) {
> + reg &= ~ISPCSI2_CTRL_VP_OUT_CTRL_MASK;
> + reg |= (currctrl->vp_out_ctrl - 1) <<
> + ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT;
> + currctrl_u->vp_out_ctrl = false;
> + }
> + if ((currctrl_u->debug_enable == true) ||
> + (force_update == true)) {
> + reg &= ~ISPCSI2_CTRL_DBG_EN_MASK;
> + if (currctrl->debug_enable)
> + reg |= ISPCSI2_CTRL_DBG_EN_ENABLE;
> + else
> + reg |= ISPCSI2_CTRL_DBG_EN_DISABLE;
> + currctrl_u->debug_enable = false;
> + }
> + if ((currctrl_u->burst_size == true) ||
> + (force_update == true)) {
> + reg &= ~ISPCSI2_CTRL_BURST_SIZE_MASK;
> + reg |= currctrl->burst_size <<
> + ISPCSI2_CTRL_BURST_SIZE_SHIFT;
> + currctrl_u->burst_size = false;
> + }
> + if ((currctrl_u->ecc_enable == true) ||
> + (force_update == true)) {
> + reg &= ~ISPCSI2_CTRL_ECC_EN_MASK;
> + if (currctrl->ecc_enable)
> + reg |= ISPCSI2_CTRL_ECC_EN_ENABLE;
> + else
> + reg |= ISPCSI2_CTRL_ECC_EN_DISABLE;
> + currctrl_u->ecc_enable = false;
> + }
> + if ((currctrl_u->secure_mode == true) ||
> + (force_update == true)) {
> + reg &= ~ISPCSI2_CTRL_SECURE_MASK;
> + if (currctrl->secure_mode)
> + reg |= ISPCSI2_CTRL_SECURE_ENABLE;
> + else
> + reg |= ISPCSI2_CTRL_SECURE_DISABLE;
> + currctrl_u->secure_mode = false;
> + }
> + if ((currctrl_u->if_enable == true) ||
> + (force_update == true)) {
> + reg &= ~ISPCSI2_CTRL_IF_EN_MASK;
> + if (currctrl->if_enable)
> + reg |= ISPCSI2_CTRL_IF_EN_ENABLE;
> + else
> + reg |= ISPCSI2_CTRL_IF_EN_DISABLE;
> + currctrl_u->if_enable = false;
> + }
> + omap_writel(reg, ISPCSI2_CTRL);
> + update_ctrl = false;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctrl_get - Gets CSI2 control configuration
> + *
> + * Always returns 0.
> + **/
> +int isp_csi2_ctrl_get(void)
> +{
> + struct isp_csi2_ctrl_cfg *currctrl = ¤t_csi2_cfg.ctrl;
> + struct isp_csi2_ctrl_cfg_update *currctrl_u =
> + ¤t_csi2_cfg_update.ctrl;
> + u32 reg;
> +
> + reg = omap_readl(ISPCSI2_CTRL);
> + currctrl->frame_mode = (reg & ISPCSI2_CTRL_FRAME_MASK) >>
> + ISPCSI2_CTRL_FRAME_SHIFT;
> + currctrl_u->frame_mode = false;
> +
> + if ((reg & ISPCSI2_CTRL_VP_CLK_EN_MASK) ==
> + ISPCSI2_CTRL_VP_CLK_EN_ENABLE)
> + currctrl->vp_clk_enable = true;
> + else
> + currctrl->vp_clk_enable = false;
> + currctrl_u->vp_clk_enable = false;
> +
> + if ((reg & ISPCSI2_CTRL_VP_ONLY_EN_MASK) ==
> + ISPCSI2_CTRL_VP_ONLY_EN_ENABLE)
> + currctrl->vp_only_enable = true;
> + else
> + currctrl->vp_only_enable = false;
> + uses_videoport = currctrl->vp_only_enable;
> + currctrl_u->vp_only_enable = false;
> +
> + currctrl->vp_out_ctrl = ((reg & ISPCSI2_CTRL_VP_OUT_CTRL_MASK) >>
> + ISPCSI2_CTRL_VP_OUT_CTRL_SHIFT) + 1;
> + currctrl_u->vp_out_ctrl = false;
> +
> + if ((reg & ISPCSI2_CTRL_DBG_EN_MASK) == ISPCSI2_CTRL_DBG_EN_ENABLE)
> + currctrl->debug_enable = true;
> + else
> + currctrl->debug_enable = false;
> + currctrl_u->debug_enable = false;
> +
> + currctrl->burst_size = (reg & ISPCSI2_CTRL_BURST_SIZE_MASK) >>
> + ISPCSI2_CTRL_BURST_SIZE_SHIFT;
> + currctrl_u->burst_size = false;
> +
> + if ((reg & ISPCSI2_CTRL_ECC_EN_MASK) == ISPCSI2_CTRL_ECC_EN_ENABLE)
> + currctrl->ecc_enable = true;
> + else
> + currctrl->ecc_enable = false;
> + currctrl_u->ecc_enable = false;
> +
> + if ((reg & ISPCSI2_CTRL_SECURE_MASK) == ISPCSI2_CTRL_SECURE_ENABLE)
> + currctrl->secure_mode = true;
> + else
> + currctrl->secure_mode = false;
> + currctrl_u->secure_mode = false;
> +
> + if ((reg & ISPCSI2_CTRL_IF_EN_MASK) == ISPCSI2_CTRL_IF_EN_ENABLE)
> + currctrl->if_enable = true;
> + else
> + currctrl->if_enable = false;
> + currctrl_u->if_enable = false;
> +
> + update_ctrl = false;
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctx_validate - Validates the context number value
> + * @ctxnum: Pointer to variable containing context number.
> + *
> + * If the value is not in range (3 bits), it is being ANDed with 0x7 to force
> + * it to be on range.
> + **/
> +static void isp_csi2_ctx_validate(u8 *ctxnum)
> +{
> + if (*ctxnum > 7) {
> + printk(KERN_ERR "Invalid context number. Forcing valid"
> + " value...\n");
> + *ctxnum &= ~(0x7);
> + }
> +}
> +
> +/**
> + * isp_csi2_ctx_config_virtual_id - Maps a virtual ID with a CSI2 Rx context
> + * @ctxnum: Context number, valid between 0 and 7 values.
> + * @virtual_id: CSI2 Virtual ID to associate with specified context number.
> + *
> + * Returns 0 if successful, or -EINVAL if Virtual ID is not in range (0-3).
> + **/
> +int isp_csi2_ctx_config_virtual_id(u8 ctxnum, u8 virtual_id)
> +{
> + struct isp_csi2_ctx_cfg *selected_ctx;
> + struct isp_csi2_ctx_cfg_update *selected_ctx_u;
> +
> + isp_csi2_ctx_validate(&ctxnum);
> +
> + if (virtual_id > 3) {
> + printk(KERN_ERR "Wrong requested virtual_id\n");
> + return -EINVAL;
> + }
> +
> + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
> + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
> +
> + if (selected_ctx->virtual_id != virtual_id) {
> + selected_ctx->virtual_id = virtual_id;
> + selected_ctx_u->virtual_id = true;
> + update_ctx_ctrl2[ctxnum] = true;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctx_config_frame_count - Sets frame count to be received in CSI2 Rx.
> + * @ctxnum: Context number, valid between 0 and 7 values.
> + * @frame_count: Number of frames to acquire.
> + *
> + * Always returns 0.
> + **/
> +int isp_csi2_ctx_config_frame_count(u8 ctxnum, u8 frame_count)
> +{
> + struct isp_csi2_ctx_cfg *selected_ctx;
> + struct isp_csi2_ctx_cfg_update *selected_ctx_u;
> +
> + isp_csi2_ctx_validate(&ctxnum);
> +
> + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
> + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
> +
> + if (selected_ctx->frame_count != frame_count) {
> + selected_ctx->frame_count = frame_count;
> + selected_ctx_u->frame_count = true;
> + update_ctx_ctrl1[ctxnum] = true;
> + }
> +
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctx_config_format - Maps a pixel format to a specified context.
> + * @ctxnum: Context number, valid between 0 and 7 values.
> + * @pixformat: V4L2 structure for pixel format.
> + *
> + * Returns 0 if successful, or -EINVAL if the format is not supported by the
> + * receiver.
> + **/
> +int isp_csi2_ctx_config_format(u8 ctxnum, u32 pixformat)
> +{
> + struct isp_csi2_ctx_cfg *selected_ctx;
> + struct isp_csi2_ctx_cfg_update *selected_ctx_u;
> + struct v4l2_pix_format pix;
> +
> + isp_csi2_ctx_validate(&ctxnum);
> +
> + pix.pixelformat = pixformat;
> + switch (pix.pixelformat) {
> + case V4L2_PIX_FMT_RGB565:
> + case V4L2_PIX_FMT_RGB565X:
> + case V4L2_PIX_FMT_YUYV:
> + case V4L2_PIX_FMT_UYVY:
> + case V4L2_PIX_FMT_RGB555:
> + case V4L2_PIX_FMT_RGB555X:
> + case V4L2_PIX_FMT_SGRBG10:
> + break;
> + default:
> + printk(KERN_ERR "Context config pixel format unsupported\n");
> + return -EINVAL;
> + }
> +
> + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
> + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
> +
> + selected_ctx->format = pix;
> + selected_ctx_u->format = true;
> + update_ctx_ctrl2[ctxnum] = true;
> +
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctx_config_alpha - Sets the alpha value for pixel format
> + * @ctxnum: Context number, valid between 0 and 7 values.
> + * @alpha: Alpha value.
> + *
> + * Returns 0 if successful, or -EINVAL if the alpha value is bigger than 16383.
> + **/
> +int isp_csi2_ctx_config_alpha(u8 ctxnum, u16 alpha)
> +{
> + struct isp_csi2_ctx_cfg *selected_ctx;
> + struct isp_csi2_ctx_cfg_update *selected_ctx_u;
> +
> + isp_csi2_ctx_validate(&ctxnum);
> +
> + if (alpha > 0x3FFF) {
> + printk(KERN_ERR "Wrong alpha value\n");
> + return -EINVAL;
> + }
> +
> + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
> + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
> +
> + if (selected_ctx->alpha != alpha) {
> + selected_ctx->alpha = alpha;
> + selected_ctx_u->alpha = true;
> + update_ctx_ctrl3[ctxnum] = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctx_config_data_offset - Sets the offset between received lines
> + * @ctxnum: Context number, valid between 0 and 7 values.
> + * @data_offset: Offset between first pixel of each 2 contiguous lines.
> + *
> + * Returns 0 if successful, or -EINVAL if the line offset is bigger than 1023.
> + **/
> +int isp_csi2_ctx_config_data_offset(u8 ctxnum, u16 data_offset)
> +{
> + struct isp_csi2_ctx_cfg *selected_ctx;
> + struct isp_csi2_ctx_cfg_update *selected_ctx_u;
> +
> + isp_csi2_ctx_validate(&ctxnum);
> +
> + if (data_offset > 0x3FF) {
> + printk(KERN_ERR "Wrong line offset\n");
> + return -EINVAL;
> + }
> +
> + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
> + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
> +
> + if (selected_ctx->data_offset != data_offset) {
> + selected_ctx->data_offset = data_offset;
> + selected_ctx_u->data_offset = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctx_config_ping_addr - Sets Ping address for CSI2 Rx. buffer saving
> + * @ctxnum: Context number, valid between 0 and 7 values.
> + * @ping_addr: 32 bit ISP MMU mapped address.
> + *
> + * Always returns 0.
> + **/
> +int isp_csi2_ctx_config_ping_addr(u8 ctxnum, u32 ping_addr)
> +{
> + struct isp_csi2_ctx_cfg *selected_ctx;
> + struct isp_csi2_ctx_cfg_update *selected_ctx_u;
> +
> + isp_csi2_ctx_validate(&ctxnum);
> +
> + ping_addr &= ~(0x1F);
> +
> + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
> + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
> +
> + if (selected_ctx->ping_addr != ping_addr) {
> + selected_ctx->ping_addr = ping_addr;
> + selected_ctx_u->ping_addr = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctx_config_pong_addr - Sets Pong address for CSI2 Rx. buffer saving
> + * @ctxnum: Context number, valid between 0 and 7 values.
> + * @pong_addr: 32 bit ISP MMU mapped address.
> + *
> + * Always returns 0.
> + **/
> +int isp_csi2_ctx_config_pong_addr(u8 ctxnum, u32 pong_addr)
> +{
> + struct isp_csi2_ctx_cfg *selected_ctx;
> + struct isp_csi2_ctx_cfg_update *selected_ctx_u;
> +
> + isp_csi2_ctx_validate(&ctxnum);
> +
> + pong_addr &= ~(0x1F);
> +
> + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
> + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
> +
> + if (selected_ctx->pong_addr != pong_addr) {
> + selected_ctx->pong_addr = pong_addr;
> + selected_ctx_u->pong_addr = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctx_config_eof_enabled - Enables EOF signal assertion
> + * @ctxnum: Context number, valid between 0 and 7 values.
> + * @eof_enabled: Boolean to enable/disable EOF signal assertion on received
> + * packets.
> + *
> + * Always returns 0.
> + **/
> +int isp_csi2_ctx_config_eof_enabled(u8 ctxnum, bool eof_enabled)
> +{
> + struct isp_csi2_ctx_cfg *selected_ctx;
> + struct isp_csi2_ctx_cfg_update *selected_ctx_u;
> +
> + isp_csi2_ctx_validate(&ctxnum);
> +
> + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
> + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
> +
> + if (selected_ctx->eof_enabled != eof_enabled) {
> + selected_ctx->eof_enabled = eof_enabled;
> + selected_ctx_u->eof_enabled = true;
> + update_ctx_ctrl1[ctxnum] = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctx_config_eol_enabled - Enables EOL signal assertion
> + * @ctxnum: Context number, valid between 0 and 7 values.
> + * @eol_enabled: Boolean to enable/disable EOL signal assertion on received
> + * packets.
> + *
> + * Always returns 0.
> + **/
> +int isp_csi2_ctx_config_eol_enabled(u8 ctxnum, bool eol_enabled)
> +{
> + struct isp_csi2_ctx_cfg *selected_ctx;
> + struct isp_csi2_ctx_cfg_update *selected_ctx_u;
> +
> + isp_csi2_ctx_validate(&ctxnum);
> +
> + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
> + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
> +
> + if (selected_ctx->eol_enabled != eol_enabled) {
> + selected_ctx->eol_enabled = eol_enabled;
> + selected_ctx_u->eol_enabled = true;
> + update_ctx_ctrl1[ctxnum] = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctx_config_checksum_enabled - Enables Checksum check in rcvd packets
> + * @ctxnum: Context number, valid between 0 and 7 values.
> + * @checksum_enabled: Boolean to enable/disable Checksum check on received
> + * packets
> + *
> + * Always returns 0.
> + **/
> +int isp_csi2_ctx_config_checksum_enabled(u8 ctxnum, bool checksum_enabled)
> +{
> + struct isp_csi2_ctx_cfg *selected_ctx;
> + struct isp_csi2_ctx_cfg_update *selected_ctx_u;
> +
> + isp_csi2_ctx_validate(&ctxnum);
> +
> + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
> + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
> +
> + if (selected_ctx->checksum_enabled != checksum_enabled) {
> + selected_ctx->checksum_enabled = checksum_enabled;
> + selected_ctx_u->checksum_enabled = true;
> + update_ctx_ctrl1[ctxnum] = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctx_config_enabled - Enables specified CSI2 context
> + * @ctxnum: Context number, valid between 0 and 7 values.
> + * @enabled: Boolean to enable/disable specified context.
> + *
> + * Always returns 0.
> + **/
> +int isp_csi2_ctx_config_enabled(u8 ctxnum, bool enabled)
> +{
> + struct isp_csi2_ctx_cfg *selected_ctx;
> + struct isp_csi2_ctx_cfg_update *selected_ctx_u;
> +
> + isp_csi2_ctx_validate(&ctxnum);
> +
> + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
> + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
> +
> + if (selected_ctx->enabled != enabled) {
> + selected_ctx->enabled = enabled;
> + selected_ctx_u->enabled = true;
> + update_ctx_ctrl1[ctxnum] = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctx_update - Applies CSI2 context configuration.
> + * @ctxnum: Context number, valid between 0 and 7 values.
> + * @force_update: Flag to force rewrite of registers, even if they haven't been
> + * updated with the isp_csi2_ctx_config_*() functions.
> + *
> + * It only saves settings when they were previously updated using the
> + * isp_csi2_ctx_config_*() functions, unless the force_update flag is
> + * set to true.
> + * Always returns 0.
> + **/
> +int isp_csi2_ctx_update(u8 ctxnum, bool force_update)
> +{
> + struct isp_csi2_ctx_cfg *selected_ctx;
> + struct isp_csi2_ctx_cfg_update *selected_ctx_u;
> + u32 reg;
> +
> + isp_csi2_ctx_validate(&ctxnum);
> +
> + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
> + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
> +
> + if ((update_ctx_ctrl1[ctxnum] == true) || (force_update == true)) {
> + reg = omap_readl(ISPCSI2_CTX_CTRL1(ctxnum));
> + if ((selected_ctx_u->frame_count == true) ||
> + (force_update == true)) {
> + reg &= ~(ISPCSI2_CTX_CTRL1_COUNT_MASK);
> + reg |= selected_ctx->frame_count <<
> + ISPCSI2_CTX_CTRL1_COUNT_SHIFT;
> + selected_ctx_u->frame_count = false;
> + }
> + if ((selected_ctx_u->eof_enabled == true) ||
> + (force_update == true)) {
> + reg &= ~(ISPCSI2_CTX_CTRL1_EOF_EN_MASK);
> + if (selected_ctx->eof_enabled == true)
> + reg |= ISPCSI2_CTX_CTRL1_EOF_EN_ENABLE;
> + else
> + reg |= ISPCSI2_CTX_CTRL1_EOF_EN_DISABLE;
> + selected_ctx_u->eof_enabled = false;
> + }
> + if ((selected_ctx_u->eol_enabled == true) ||
> + (force_update == true)) {
> + reg &= ~(ISPCSI2_CTX_CTRL1_EOL_EN_MASK);
> + if (selected_ctx->eol_enabled == true)
> + reg |= ISPCSI2_CTX_CTRL1_EOL_EN_ENABLE;
> + else
> + reg |= ISPCSI2_CTX_CTRL1_EOL_EN_DISABLE;
> + selected_ctx_u->eol_enabled = false;
> + }
> + if ((selected_ctx_u->checksum_enabled == true) ||
> + (force_update == true)) {
> + reg &= ~(ISPCSI2_CTX_CTRL1_CS_EN_MASK);
> + if (selected_ctx->checksum_enabled == true)
> + reg |= ISPCSI2_CTX_CTRL1_CS_EN_ENABLE;
> + else
> + reg |= ISPCSI2_CTX_CTRL1_CS_EN_DISABLE;
> + selected_ctx_u->checksum_enabled = false;
> + }
> + if ((selected_ctx_u->enabled == true) ||
> + (force_update == true)) {
> + reg &= ~(ISPCSI2_CTX_CTRL1_CTX_EN_MASK);
> + if (selected_ctx->enabled == true)
> + reg |= ISPCSI2_CTX_CTRL1_CTX_EN_ENABLE;
> + else
> + reg |= ISPCSI2_CTX_CTRL1_CTX_EN_DISABLE;
> + selected_ctx_u->enabled = false;
> + }
> + omap_writel(reg, ISPCSI2_CTX_CTRL1(ctxnum));
> + update_ctx_ctrl1[ctxnum] = false;
> + }
> +
> + if ((update_ctx_ctrl2[ctxnum] == true) || (force_update == true)) {
> + reg = omap_readl(ISPCSI2_CTX_CTRL2(ctxnum));
> + if ((selected_ctx_u->virtual_id == true) ||
> + (force_update == true)) {
> + reg &= ~(ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK);
> + reg |= selected_ctx->virtual_id <<
> + ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT;
> + selected_ctx_u->virtual_id = false;
> + }
> +
> + if ((selected_ctx_u->format == true) ||
> + (force_update == true)) {
> + struct v4l2_pix_format *pix;
> + u16 new_format = 0;
> +
> + reg &= ~(ISPCSI2_CTX_CTRL2_FORMAT_MASK);
> + pix = &selected_ctx->format;
> + switch (pix->pixelformat) {
> + case V4L2_PIX_FMT_RGB565:
> + case V4L2_PIX_FMT_RGB565X:
> + new_format = 0x22;
> + break;
> + case V4L2_PIX_FMT_YUYV:
> + case V4L2_PIX_FMT_UYVY:
> + if (uses_videoport)
> + new_format = 0x9E;
> + else
> + new_format = 0x1E;
> + break;
> + case V4L2_PIX_FMT_RGB555:
> + case V4L2_PIX_FMT_RGB555X:
> + new_format = 0xA1;
> + break;
> + case V4L2_PIX_FMT_SGRBG10:
> + if (uses_videoport)
> + new_format = 0x12F;
> + else
> + new_format = 0xAB;
> + break;
> + }
> + reg |= (new_format << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT);
> + selected_ctx_u->format = false;
> + }
> + omap_writel(reg, ISPCSI2_CTX_CTRL2(ctxnum));
> + update_ctx_ctrl2[ctxnum] = false;
> + }
> +
> + if ((update_ctx_ctrl3[ctxnum] == true) || (force_update == true)) {
> + reg = omap_readl(ISPCSI2_CTX_CTRL3(ctxnum));
> + if ((selected_ctx_u->alpha == true) ||
> + (force_update == true)) {
> + reg &= ~(ISPCSI2_CTX_CTRL3_ALPHA_MASK);
> + reg |= (selected_ctx->alpha <<
> + ISPCSI2_CTX_CTRL3_ALPHA_SHIFT);
> + selected_ctx_u->alpha = false;
> + }
> + omap_writel(reg, ISPCSI2_CTX_CTRL3(ctxnum));
> + update_ctx_ctrl3[ctxnum] = false;
> + }
> +
> + if (selected_ctx_u->data_offset == true) {
> + reg = omap_readl(ISPCSI2_CTX_DAT_OFST(ctxnum));
> + reg &= ~ISPCSI2_CTX_DAT_OFST_OFST_MASK;
> + reg |= selected_ctx->data_offset <<
> + ISPCSI2_CTX_DAT_OFST_OFST_SHIFT;
> + omap_writel(reg, ISPCSI2_CTX_DAT_OFST(ctxnum));
> + selected_ctx_u->data_offset = false;
> + }
> +
> + if (selected_ctx_u->ping_addr == true) {
> + reg = selected_ctx->ping_addr;
> + omap_writel(reg, ISPCSI2_CTX_DAT_PING_ADDR(ctxnum));
> + selected_ctx_u->ping_addr = false;
> + }
> +
> + if (selected_ctx_u->pong_addr == true) {
> + reg = selected_ctx->pong_addr;
> + omap_writel(reg, ISPCSI2_CTX_DAT_PONG_ADDR(ctxnum));
> + selected_ctx_u->pong_addr = false;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctx_get - Gets specific CSI2 Context configuration
> + * @ctxnum: Context number, valid between 0 and 7 values.
> + *
> + * Always returns 0.
> + **/
> +int isp_csi2_ctx_get(u8 ctxnum)
> +{
> + struct isp_csi2_ctx_cfg *selected_ctx;
> + struct isp_csi2_ctx_cfg_update *selected_ctx_u;
> + u32 reg;
> +
> + isp_csi2_ctx_validate(&ctxnum);
> +
> + selected_ctx = ¤t_csi2_cfg.contexts[ctxnum];
> + selected_ctx_u = ¤t_csi2_cfg_update.contexts[ctxnum];
> +
> + reg = omap_readl(ISPCSI2_CTX_CTRL1(ctxnum));
> + selected_ctx->frame_count = (reg & ISPCSI2_CTX_CTRL1_COUNT_MASK) >>
> + ISPCSI2_CTX_CTRL1_COUNT_SHIFT;
> + selected_ctx_u->frame_count = false;
> +
> + if ((reg & ISPCSI2_CTX_CTRL1_EOF_EN_MASK) ==
> + ISPCSI2_CTX_CTRL1_EOF_EN_ENABLE)
> + selected_ctx->eof_enabled = true;
> + else
> + selected_ctx->eof_enabled = false;
> + selected_ctx_u->eof_enabled = false;
> +
> + if ((reg & ISPCSI2_CTX_CTRL1_EOL_EN_MASK) ==
> + ISPCSI2_CTX_CTRL1_EOL_EN_ENABLE)
> + selected_ctx->eol_enabled = true;
> + else
> + selected_ctx->eol_enabled = false;
> + selected_ctx_u->eol_enabled = false;
> +
> + if ((reg & ISPCSI2_CTX_CTRL1_CS_EN_MASK) ==
> + ISPCSI2_CTX_CTRL1_CS_EN_ENABLE)
> + selected_ctx->checksum_enabled = true;
> + else
> + selected_ctx->checksum_enabled = false;
> + selected_ctx_u->checksum_enabled = false;
> +
> + if ((reg & ISPCSI2_CTX_CTRL1_CTX_EN_MASK) ==
> + ISPCSI2_CTX_CTRL1_CTX_EN_ENABLE)
> + selected_ctx->enabled = true;
> + else
> + selected_ctx->enabled = false;
> + selected_ctx_u->enabled = false;
> + update_ctx_ctrl1[ctxnum] = false;
> +
> + reg = omap_readl(ISPCSI2_CTX_CTRL2(ctxnum));
> +
> + selected_ctx->virtual_id = (reg & ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK) >>
> + ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT;
> + selected_ctx_u->virtual_id = false;
> +
> + switch ((reg & ISPCSI2_CTX_CTRL2_FORMAT_MASK) >>
> + ISPCSI2_CTX_CTRL2_FORMAT_SHIFT) {
> + case 0x22:
> + selected_ctx->format.pixelformat = V4L2_PIX_FMT_RGB565;
> + break;
> + case 0x9E:
> + case 0x1E:
> + selected_ctx->format.pixelformat = V4L2_PIX_FMT_YUYV;
> + break;
> + case 0xA1:
> + selected_ctx->format.pixelformat = V4L2_PIX_FMT_RGB555;
> + break;
> + case 0xAB:
> + case 0x12F:
> + selected_ctx->format.pixelformat = V4L2_PIX_FMT_SGRBG10;
> + break;
> + }
> + selected_ctx_u->format = false;
> + update_ctx_ctrl2[ctxnum] = false;
> +
> + selected_ctx->alpha = (omap_readl(ISPCSI2_CTX_CTRL3(ctxnum)) &
> + ISPCSI2_CTX_CTRL3_ALPHA_MASK) >>
> + ISPCSI2_CTX_CTRL3_ALPHA_SHIFT;
> + selected_ctx_u->alpha = false;
> + update_ctx_ctrl3[ctxnum] = false;
> +
> + selected_ctx->data_offset = (omap_readl(ISPCSI2_CTX_DAT_OFST(ctxnum)) &
> + ISPCSI2_CTX_DAT_OFST_OFST_MASK) >>
> + ISPCSI2_CTX_DAT_OFST_OFST_SHIFT;
> + selected_ctx_u->data_offset = false;
> +
> + selected_ctx->ping_addr = omap_readl(ISPCSI2_CTX_DAT_PING_ADDR(ctxnum));
> + selected_ctx_u->ping_addr = false;
> +
> + selected_ctx->pong_addr = omap_readl(ISPCSI2_CTX_DAT_PONG_ADDR(ctxnum));
> + selected_ctx_u->pong_addr = false;
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctx_update_all - Applies all CSI2 context configuration.
> + * @force_update: Flag to force rewrite of registers, even if they haven't been
> + * updated with the isp_csi2_ctx_config_*() functions.
> + *
> + * It only saves settings when they were previously updated using the
> + * isp_csi2_ctx_config_*() functions, unless the force_update flag is
> + * set to true.
> + * Always returns 0.
> + **/
> +int isp_csi2_ctx_update_all(bool force_update)
> +{
> + u8 ctxnum;
> +
> + for (ctxnum = 0; ctxnum < 8; ctxnum++)
> + isp_csi2_ctx_update(ctxnum, force_update);
> +
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_ctx_get_all - Gets all CSI2 Context configurations
> + *
> + * Always returns 0.
> + **/
> +int isp_csi2_ctx_get_all(void)
> +{
> + u8 ctxnum;
> +
> + for (ctxnum = 0; ctxnum < 8; ctxnum++)
> + isp_csi2_ctx_get(ctxnum);
> +
> + return 0;
> +}
> +
> +int isp_csi2_phy_config(struct isp_csi2_phy_cfg *desiredphyconfig)
> +{
> + struct isp_csi2_phy_cfg *currphy = ¤t_csi2_cfg.phy;
> + struct isp_csi2_phy_cfg_update *currphy_u =
> + ¤t_csi2_cfg_update.phy;
> +
> + if ((desiredphyconfig->tclk_term > 0x7f) ||
> + (desiredphyconfig->tclk_miss > 0x3)) {
> + printk(KERN_ERR "Invalid PHY configuration sent by the"
> + " driver\n");
> + return -EINVAL;
> + }
> +
> + if (currphy->ths_term != desiredphyconfig->ths_term) {
> + currphy->ths_term = desiredphyconfig->ths_term;
> + currphy_u->ths_term = true;
> + update_phy_cfg0 = true;
> + }
> + if (currphy->ths_settle != desiredphyconfig->ths_settle) {
> + currphy->ths_settle = desiredphyconfig->ths_settle;
> + currphy_u->ths_settle = true;
> + update_phy_cfg0 = true;
> + }
> + if (currphy->tclk_term != desiredphyconfig->tclk_term) {
> + currphy->tclk_term = desiredphyconfig->tclk_term;
> + currphy_u->tclk_term = true;
> + update_phy_cfg1 = true;
> + }
> + if (currphy->tclk_miss != desiredphyconfig->tclk_miss) {
> + currphy->tclk_miss = desiredphyconfig->tclk_miss;
> + currphy_u->tclk_miss = true;
> + update_phy_cfg1 = true;
> + }
> + if (currphy->tclk_settle != desiredphyconfig->tclk_settle) {
> + currphy->tclk_settle = desiredphyconfig->tclk_settle;
> + currphy_u->tclk_settle = true;
> + update_phy_cfg1 = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_calc_phy_cfg0 - Calculates D-PHY config based on the MIPIClk speed.
> + * @mipiclk: MIPI clock frequency being used with CSI2 sensor.
> + * @lbound_hs_settle: Lower bound for CSI2 High Speed Settle transition.
> + * @ubound_hs_settle: Upper bound for CSI2 High Speed Settle transition.
> + *
> + * From TRM, we have the same calculation for HS Termination signal.
> + * THS_TERM = ceil( 12.5ns / DDRCLK period ) - 1
> + * But for Settle, we use the mid value between the two passed boundaries from
> + * sensor:
> + * THS_SETTLE = (Upper bound + Lower bound) / 2
> + *
> + * Always returns 0.
> + */
> +int isp_csi2_calc_phy_cfg0(u32 mipiclk, u32 lbound_hs_settle,
> + u32 ubound_hs_settle)
> +{
> + struct isp_csi2_phy_cfg *currphy = ¤t_csi2_cfg.phy;
> + struct isp_csi2_phy_cfg_update *currphy_u =
> + ¤t_csi2_cfg_update.phy;
> + u32 tmp, ddrclk = mipiclk >> 1;
> +
> + /* Calculate THS_TERM */
> + tmp = ddrclk / 80000000;
> + if ((ddrclk % 80000000) > 0)
> + tmp++;
> + currphy->ths_term = tmp - 1;
> + currphy_u->ths_term = true;
> +
> + /* Calculate THS_SETTLE */
> + currphy->ths_settle = (ubound_hs_settle + lbound_hs_settle) / 2;
> +
> + currphy_u->ths_settle = true;
> + isp_csi2_phy_update(true);
> + return 0;
> +}
> +EXPORT_SYMBOL(isp_csi2_calc_phy_cfg0);
> +
> +/**
> + * isp_csi2_phy_update - Applies CSI2 D-PHY configuration.
> + * @force_update: Flag to force rewrite of registers, even if they haven't been
> + * updated with the isp_csi2_phy_config_*() functions.
> + *
> + * It only saves settings when they were previously updated using the
> + * isp_csi2_phy_config_*() functions, unless the force_update flag is
> + * set to true.
> + * Always returns 0.
> + **/
> +int isp_csi2_phy_update(bool force_update)
> +{
> + struct isp_csi2_phy_cfg *currphy = ¤t_csi2_cfg.phy;
> + struct isp_csi2_phy_cfg_update *currphy_u =
> + ¤t_csi2_cfg_update.phy;
> + u32 reg;
> +
> + if ((update_phy_cfg0 == true) || (force_update == true)) {
> + reg = omap_readl(ISPCSI2PHY_CFG0);
> + if ((currphy_u->ths_term == true) || (force_update == true)) {
> + reg &= ~ISPCSI2PHY_CFG0_THS_TERM_MASK;
> + reg |= (currphy->ths_term <<
> + ISPCSI2PHY_CFG0_THS_TERM_SHIFT);
> + currphy_u->ths_term = false;
> + }
> + if ((currphy_u->ths_settle == true) || (force_update == true)) {
> + reg &= ~ISPCSI2PHY_CFG0_THS_SETTLE_MASK;
> + reg |= (currphy->ths_settle <<
> + ISPCSI2PHY_CFG0_THS_SETTLE_SHIFT);
> + currphy_u->ths_settle = false;
> + }
> + omap_writel(reg, ISPCSI2PHY_CFG0);
> + update_phy_cfg0 = false;
> + }
> +
> + if ((update_phy_cfg1 == true) || (force_update == true)) {
> + reg = omap_readl(ISPCSI2PHY_CFG1);
> + if ((currphy_u->tclk_term == true) || (force_update == true)) {
> + reg &= ~ISPCSI2PHY_CFG1_TCLK_TERM_MASK;
> + reg |= (currphy->tclk_term <<
> + ISPCSI2PHY_CFG1_TCLK_TERM_SHIFT);
> + currphy_u->tclk_term = false;
> + }
> + if ((currphy_u->tclk_miss == true) || (force_update == true)) {
> + reg &= ~ISPCSI2PHY_CFG1_TCLK_MISS_MASK;
> + reg |= (currphy->tclk_miss <<
> + ISPCSI2PHY_CFG1_TCLK_MISS_SHIFT);
> + currphy_u->tclk_miss = false;
> + }
> + if ((currphy_u->tclk_settle == true) ||
> + (force_update == true)) {
> + reg &= ~ISPCSI2PHY_CFG1_TCLK_SETTLE_MASK;
> + reg |= (currphy->tclk_settle <<
> + ISPCSI2PHY_CFG1_TCLK_SETTLE_SHIFT);
> + currphy_u->tclk_settle = false;
> + }
> + omap_writel(reg, ISPCSI2PHY_CFG1);
> + update_phy_cfg1 = false;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_phy_get - Gets CSI2 D-PHY configuration
> + *
> + * Gets settings from HW registers and fills in the internal driver memory
> + * Always returns 0.
> + **/
> +int isp_csi2_phy_get(void)
> +{
> + struct isp_csi2_phy_cfg *currphy = ¤t_csi2_cfg.phy;
> + struct isp_csi2_phy_cfg_update *currphy_u =
> + ¤t_csi2_cfg_update.phy;
> + u32 reg;
> +
> + reg = omap_readl(ISPCSI2PHY_CFG0);
> + currphy->ths_term = (reg & ISPCSI2PHY_CFG0_THS_TERM_MASK) >>
> + ISPCSI2PHY_CFG0_THS_TERM_SHIFT;
> + currphy_u->ths_term = false;
> +
> + currphy->ths_settle = (reg & ISPCSI2PHY_CFG0_THS_SETTLE_MASK) >>
> + ISPCSI2PHY_CFG0_THS_SETTLE_SHIFT;
> + currphy_u->ths_settle = false;
> + update_phy_cfg0 = false;
> +
> + reg = omap_readl(ISPCSI2PHY_CFG1);
> +
> + currphy->tclk_term = (reg & ISPCSI2PHY_CFG1_TCLK_TERM_MASK) >>
> + ISPCSI2PHY_CFG1_TCLK_TERM_SHIFT;
> + currphy_u->tclk_term = false;
> +
> + currphy->tclk_miss = (reg & ISPCSI2PHY_CFG1_TCLK_MISS_MASK) >>
> + ISPCSI2PHY_CFG1_TCLK_MISS_SHIFT;
> + currphy_u->tclk_miss = false;
> +
> + currphy->tclk_settle = (reg & ISPCSI2PHY_CFG1_TCLK_SETTLE_MASK) >>
> + ISPCSI2PHY_CFG1_TCLK_SETTLE_SHIFT;
> + currphy_u->tclk_settle = false;
> +
> + update_phy_cfg1 = false;
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_timings_config_forcerxmode - Sets Force Rx mode on stop state count
> + * @force_rx_mode: Boolean to enable/disable forcing Rx mode in CSI2 receiver
> + *
> + * Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected.
> + **/
> +int isp_csi2_timings_config_forcerxmode(u8 io, bool force_rx_mode)
> +{
> + struct isp_csi2_timings_cfg *currtimings;
> + struct isp_csi2_timings_cfg_update *currtimings_u;
> +
> + if (io > 2) {
> + printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n");
> + return -EINVAL;
> + }
> +
> + currtimings = ¤t_csi2_cfg.timings[io - 1];
> + currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
> + if (currtimings->force_rx_mode != force_rx_mode) {
> + currtimings->force_rx_mode = force_rx_mode;
> + currtimings_u->force_rx_mode = true;
> + update_timing = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_timings_config_stopstate_16x - Sets 16x factor for L3 cycles
> + * @stop_state_16x: Boolean to use or not use the 16x multiplier for stop count
> + *
> + * Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected.
> + **/
> +int isp_csi2_timings_config_stopstate_16x(u8 io, bool stop_state_16x)
> +{
> + struct isp_csi2_timings_cfg *currtimings;
> + struct isp_csi2_timings_cfg_update *currtimings_u;
> +
> + if (io > 2) {
> + printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n");
> + return -EINVAL;
> + }
> +
> + currtimings = ¤t_csi2_cfg.timings[io - 1];
> + currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
> + if (currtimings->stop_state_16x != stop_state_16x) {
> + currtimings->stop_state_16x = stop_state_16x;
> + currtimings_u->stop_state_16x = true;
> + update_timing = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_timings_config_stopstate_4x - Sets 4x factor for L3 cycles
> + * @stop_state_4x: Boolean to use or not use the 4x multiplier for stop count
> + *
> + * Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected.
> + **/
> +int isp_csi2_timings_config_stopstate_4x(u8 io, bool stop_state_4x)
> +{
> + struct isp_csi2_timings_cfg *currtimings;
> + struct isp_csi2_timings_cfg_update *currtimings_u;
> +
> + if (io > 2) {
> + printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n");
> + return -EINVAL;
> + }
> +
> + currtimings = ¤t_csi2_cfg.timings[io - 1];
> + currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
> + if (currtimings->stop_state_4x != stop_state_4x) {
> + currtimings->stop_state_4x = stop_state_4x;
> + currtimings_u->stop_state_4x = true;
> + update_timing = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_timings_config_stopstate_cnt - Sets L3 cycles
> + * @stop_state_counter: Stop state counter value for L3 cycles
> + *
> + * Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected.
> + **/
> +int isp_csi2_timings_config_stopstate_cnt(u8 io, u16 stop_state_counter)
> +{
> + struct isp_csi2_timings_cfg *currtimings;
> + struct isp_csi2_timings_cfg_update *currtimings_u;
> +
> + if (io > 2) {
> + printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n");
> + return -EINVAL;
> + }
> +
> + currtimings = ¤t_csi2_cfg.timings[io - 1];
> + currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
> + if (currtimings->stop_state_counter != stop_state_counter) {
> + currtimings->stop_state_counter = (stop_state_counter & 0x1FFF);
> + currtimings_u->stop_state_counter = true;
> + update_timing = true;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_timings_update - Applies specified CSI2 timing configuration.
> + * @io: IO number (1 or 2) which specifies which ComplexIO are we updating
> + * @force_update: Flag to force rewrite of registers, even if they haven't been
> + * updated with the isp_csi2_timings_config_*() functions.
> + *
> + * It only saves settings when they were previously updated using the
> + * isp_csi2_timings_config_*() functions, unless the force_update flag is
> + * set to true.
> + * Returns 0 if successful, or -EINVAL if invalid IO number is passed.
> + **/
> +int isp_csi2_timings_update(u8 io, bool force_update)
> +{
> + struct isp_csi2_timings_cfg *currtimings;
> + struct isp_csi2_timings_cfg_update *currtimings_u;
> + u32 reg;
> +
> + if (io > 2) {
> + printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n");
> + return -EINVAL;
> + }
> +
> + currtimings = ¤t_csi2_cfg.timings[io - 1];
> + currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
> +
> + if ((update_timing == true) || (force_update == true)) {
> + reg = omap_readl(ISPCSI2_TIMING);
> + if ((currtimings_u->force_rx_mode == true) ||
> + (force_update == true)) {
> + reg &= ~ISPCSI2_TIMING_FORCE_RX_MODE_IO_MASK(io);
> + if (currtimings->force_rx_mode == true)
> + reg |= ISPCSI2_TIMING_FORCE_RX_MODE_IO_ENABLE
> + (io);
> + else
> + reg |= ISPCSI2_TIMING_FORCE_RX_MODE_IO_DISABLE
> + (io);
> + currtimings_u->force_rx_mode = false;
> + }
> + if ((currtimings_u->stop_state_16x == true) ||
> + (force_update == true)) {
> + reg &= ~ISPCSI2_TIMING_STOP_STATE_X16_IO_MASK(io);
> + if (currtimings->stop_state_16x == true)
> + reg |= ISPCSI2_TIMING_STOP_STATE_X16_IO_ENABLE
> + (io);
> + else
> + reg |= ISPCSI2_TIMING_STOP_STATE_X16_IO_DISABLE
> + (io);
> + currtimings_u->stop_state_16x = false;
> + }
> + if ((currtimings_u->stop_state_4x == true) ||
> + (force_update == true)) {
> + reg &= ~ISPCSI2_TIMING_STOP_STATE_X4_IO_MASK(io);
> + if (currtimings->stop_state_4x == true) {
> + reg |= ISPCSI2_TIMING_STOP_STATE_X4_IO_ENABLE
> + (io);
> + } else {
> + reg |= ISPCSI2_TIMING_STOP_STATE_X4_IO_DISABLE
> + (io);
> + }
> + currtimings_u->stop_state_4x = false;
> + }
> + if ((currtimings_u->stop_state_counter == true) ||
> + (force_update == true)) {
> + reg &= ~ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(io);
> + reg |= currtimings->stop_state_counter <<
> + ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(io);
> + currtimings_u->stop_state_counter = false;
> + }
> + omap_writel(reg, ISPCSI2_TIMING);
> + update_timing = false;
> + }
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_timings_get - Gets specific CSI2 ComplexIO timing configuration
> + * @io: IO number (1 or 2) which specifies which ComplexIO are we getting
> + *
> + * Gets settings from HW registers and fills in the internal driver memory
> + * Returns 0 if successful, or -EINVAL if invalid IO number is passed.
> + **/
> +int isp_csi2_timings_get(u8 io)
> +{
> + struct isp_csi2_timings_cfg *currtimings;
> + struct isp_csi2_timings_cfg_update *currtimings_u;
> + u32 reg;
> +
> + if (io > 2) {
> + printk(KERN_ERR "CSI2 - Timings config: Invalid IO number\n");
> + return -EINVAL;
> + }
> +
> + currtimings = ¤t_csi2_cfg.timings[io - 1];
> + currtimings_u = ¤t_csi2_cfg_update.timings[io - 1];
> +
> + reg = omap_readl(ISPCSI2_TIMING);
> + if ((reg & ISPCSI2_TIMING_FORCE_RX_MODE_IO_MASK(io)) ==
> + ISPCSI2_TIMING_FORCE_RX_MODE_IO_ENABLE(io))
> + currtimings->force_rx_mode = true;
> + else
> + currtimings->force_rx_mode = false;
> + currtimings_u->force_rx_mode = false;
> +
> + if ((reg & ISPCSI2_TIMING_STOP_STATE_X16_IO_MASK(io)) ==
> + ISPCSI2_TIMING_STOP_STATE_X16_IO_ENABLE(io))
> + currtimings->stop_state_16x = true;
> + else
> + currtimings->stop_state_16x = false;
> + currtimings_u->stop_state_16x = false;
> +
> + if ((reg & ISPCSI2_TIMING_STOP_STATE_X4_IO_MASK(io)) ==
> + ISPCSI2_TIMING_STOP_STATE_X4_IO_ENABLE(io))
> + currtimings->stop_state_4x = true;
> + else
> + currtimings->stop_state_4x = false;
> + currtimings_u->stop_state_4x = false;
> +
> + currtimings->stop_state_counter = (reg &
> + ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(io)) >>
> + ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(io);
> + currtimings_u->stop_state_counter = false;
> + update_timing = false;
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_timings_update_all - Applies specified CSI2 timing configuration.
> + * @force_update: Flag to force rewrite of registers, even if they haven't been
> + * updated with the isp_csi2_timings_config_*() functions.
> + *
> + * It only saves settings when they were previously updated using the
> + * isp_csi2_timings_config_*() functions, unless the force_update flag is
> + * set to true.
> + * Always returns 0.
> + **/
> +int isp_csi2_timings_update_all(bool force_update)
> +{
> + int i;
> +
> + for (i = 0; i < 2; i++)
> + isp_csi2_timings_update(i, force_update);
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_timings_get_all - Gets all CSI2 ComplexIO timing configurations
> + *
> + * Always returns 0.
> + **/
> +int isp_csi2_timings_get_all(void)
> +{
> + int i;
> +
> + for (i = 0; i < 2; i++)
> + isp_csi2_timings_get(i);
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_isr - CSI2 interrupt handling.
> + **/
> +void isp_csi2_isr(void)
> +{
> + u32 csi2_irqstatus, cpxio1_irqstatus, ctxirqstatus;
> +
> + csi2_irqstatus = omap_readl(ISPCSI2_IRQSTATUS);
> + omap_writel(csi2_irqstatus, ISPCSI2_IRQSTATUS);
> +
> + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ) {
> + cpxio1_irqstatus = omap_readl(ISPCSI2_COMPLEXIO1_IRQSTATUS);
> + omap_writel(cpxio1_irqstatus, ISPCSI2_COMPLEXIO1_IRQSTATUS);
> + printk(KERN_ERR "CSI2: ComplexIO Error IRQ %x\n",
> + cpxio1_irqstatus);
> + }
> +
> + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0)) {
> + ctxirqstatus = omap_readl(ISPCSI2_CTX_IRQSTATUS(0));
> + omap_writel(ctxirqstatus, ISPCSI2_CTX_IRQSTATUS(0));
> + }
> +
> + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_OCP_ERR_IRQ)
> + printk(KERN_ERR "CSI2: OCP Transmission Error\n");
> +
> + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ)
> + printk(KERN_ERR "CSI2: Short packet receive error\n");
> +
> + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ)
> + printk(KERN_DEBUG "CSI2: ECC correction done\n");
> +
> + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ)
> + printk(KERN_ERR "CSI2: ECC correction failed\n");
> +
> + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ)
> + printk(KERN_ERR "CSI2: ComplexIO #2 failed\n");
> +
> + if (csi2_irqstatus & ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)
> + printk(KERN_ERR "CSI2: FIFO overflow error\n");
> +
> + return;
> +}
> +EXPORT_SYMBOL(isp_csi2_isr);
> +
> +/**
> + * isp_csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs.
> + * @enable: Enable/disable CSI2 ComplexIO #1 interrupts
> + **/
> +void isp_csi2_irq_complexio1_set(int enable)
> +{
> + u32 reg;
> + reg = ISPCSI2_COMPLEXIO1_IRQENABLE_STATEALLULPMEXIT |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_STATEALLULPMENTER |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_STATEULPM5 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRCONTROL5 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC5 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS5 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS5 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_STATEULPM4 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRCONTROL4 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC4 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS4 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS4 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_STATEULPM3 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRCONTROL3 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC3 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS3 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS3 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_STATEULPM2 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRCONTROL2 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC2 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS2 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS2 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_STATEULPM1 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRCONTROL1 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC1 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS1 |
> + ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS1;
> + omap_writel(reg, ISPCSI2_COMPLEXIO1_IRQSTATUS);
> + if (enable)
> + reg |= omap_readl(ISPCSI2_COMPLEXIO1_IRQENABLE);
> + else
> + reg = 0;
> + omap_writel(reg, ISPCSI2_COMPLEXIO1_IRQENABLE);
> +}
> +EXPORT_SYMBOL(isp_csi2_irq_complexio1_set);
> +
> +/**
> + * isp_csi2_irq_ctx_set - Enables CSI2 Context IRQs.
> + * @enable: Enable/disable CSI2 Context interrupts
> + **/
> +void isp_csi2_irq_ctx_set(int enable)
> +{
> + u32 reg;
> + int i;
> +
> + reg = ISPCSI2_CTX_IRQSTATUS_FS_IRQ | ISPCSI2_CTX_IRQSTATUS_FE_IRQ;
> + for (i = 0; i < 8; i++) {
> + omap_writel(reg, ISPCSI2_CTX_IRQSTATUS(i));
> + if (enable) {
> + omap_writel(omap_readl(ISPCSI2_CTX_IRQENABLE(i)) | reg,
> + ISPCSI2_CTX_IRQENABLE(i));
> + } else
> + omap_writel(0, ISPCSI2_CTX_IRQENABLE(i));
> + }
> +
> +}
> +EXPORT_SYMBOL(isp_csi2_irq_ctx_set);
> +
> +/**
> + * isp_csi2_irq_status_set - Enables CSI2 Status IRQs.
> + * @enable: Enable/disable CSI2 Status interrupts
> + **/
> +void isp_csi2_irq_status_set(int enable)
> +{
> + u32 reg;
> + reg = ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
> + ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ |
> + ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ |
> + ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ |
> + ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ |
> + ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ |
> + ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ |
> + ISPCSI2_IRQSTATUS_CONTEXT(0);
> + omap_writel(reg, ISPCSI2_IRQSTATUS);
> + if (enable)
> + reg |= omap_readl(ISPCSI2_IRQENABLE);
> + else
> + reg = 0;
> +
> + omap_writel(reg, ISPCSI2_IRQENABLE);
> +}
> +EXPORT_SYMBOL(isp_csi2_irq_status_set);
> +
> +/**
> + * isp_csi2_irq_status_set - Enables main CSI2 IRQ.
> + * @enable: Enable/disable main CSI2 interrupt
> + **/
> +void isp_csi2_irq_set(int enable)
> +{
> + if (enable) {
> + omap_writel(IRQ0STATUS_CSIA_IRQ, ISP_IRQ0STATUS);
> + omap_writel(omap_readl(ISP_IRQ0ENABLE) | IRQ0ENABLE_CSIA_IRQ,
> + ISP_IRQ0ENABLE);
> + } else {
> + omap_writel(IRQ0STATUS_CSIA_IRQ, ISP_IRQ0STATUS);
> + omap_writel(omap_readl(ISP_IRQ0ENABLE) & ~IRQ0ENABLE_CSIA_IRQ,
> + ISP_IRQ0ENABLE);
> + }
> +}
> +EXPORT_SYMBOL(isp_csi2_irq_set);
> +
> +/**
> + * isp_csi2_irq_all_set - Enable/disable CSI2 interrupts.
> + * @enable: 0-Disable, 1-Enable.
> + **/
> +void isp_csi2_irq_all_set(int enable)
> +{
> + if (enable) {
> + isp_csi2_irq_complexio1_set(enable);
> + isp_csi2_irq_ctx_set(enable);
> + isp_csi2_irq_status_set(enable);
> + isp_csi2_irq_set(enable);
> + } else {
> + isp_csi2_irq_set(enable);
> + isp_csi2_irq_status_set(enable);
> + isp_csi2_irq_ctx_set(enable);
> + isp_csi2_irq_complexio1_set(enable);
> + }
> + return;
> +}
> +EXPORT_SYMBOL(isp_csi2_irq_all_set);
> +
> +/**
> + * isp_csi2_reset - Resets the CSI2 module.
> + *
> + * Returns 0 if successful, or -EBUSY if power command didn't respond.
> + **/
> +int isp_csi2_reset(void)
> +{
> + u32 reg;
> + u8 soft_reset_retries = 0;
> + int i;
> +
> + reg = omap_readl(ISPCSI2_SYSCONFIG);
> + reg |= ISPCSI2_SYSCONFIG_SOFT_RESET_RESET;
> + omap_writel(reg, ISPCSI2_SYSCONFIG);
> +
> + do {
> + reg = omap_readl(ISPCSI2_SYSSTATUS) &
> + ISPCSI2_SYSSTATUS_RESET_DONE_MASK;
> + if (reg == ISPCSI2_SYSSTATUS_RESET_DONE_DONE)
> + break;
> + soft_reset_retries++;
> + if (soft_reset_retries < 5)
> + udelay(100);
> + } while (soft_reset_retries < 5);
> +
> + if (soft_reset_retries == 5) {
> + printk(KERN_ERR "CSI2: Soft reset try count exceeded!\n");
> + return -EBUSY;
> + }
> +
> + reg = omap_readl(ISPCSI2_SYSCONFIG);
> + reg &= ~ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK;
> + reg |= ISPCSI2_SYSCONFIG_MSTANDBY_MODE_NO;
> + reg &= ~ISPCSI2_SYSCONFIG_AUTO_IDLE_MASK;
> + omap_writel(reg, ISPCSI2_SYSCONFIG);
> +
> + uses_videoport = false;
> + update_complexio_cfg1 = false;
> + update_phy_cfg0 = false;
> + update_phy_cfg1 = false;
> + for (i = 0; i < 8; i++) {
> + update_ctx_ctrl1[i] = false;
> + update_ctx_ctrl2[i] = false;
> + update_ctx_ctrl3[i] = false;
> + }
> + update_timing = false;
> + update_ctrl = false;
> +
> + isp_csi2_complexio_lanes_get();
> + isp_csi2_ctrl_get();
> + isp_csi2_ctx_get_all();
> + isp_csi2_phy_get();
> + isp_csi2_timings_get_all();
> +
> + isp_csi2_complexio_power_autoswitch(true);
> + isp_csi2_complexio_power(ISP_CSI2_POWER_ON);
> +
> + isp_csi2_timings_config_forcerxmode(1, true);
> + isp_csi2_timings_config_stopstate_cnt(1, 0x1FF);
> + isp_csi2_timings_update_all(true);
> +
> + return 0;
> +}
> +
> +/**
> + * isp_csi2_enable - Enables the CSI2 module.
> + * @enable: Enables/disables the CSI2 module.
> + **/
> +void isp_csi2_enable(int enable)
> +{
> + if (enable) {
> + isp_csi2_ctx_config_enabled(0, true);
> + isp_csi2_ctx_config_eof_enabled(0, true);
> + isp_csi2_ctx_config_checksum_enabled(0, true);
> + isp_csi2_ctx_update(0, false);
> +
> + isp_csi2_ctrl_config_ecc_enable(true);
> + isp_csi2_ctrl_config_if_enable(true);
> + isp_csi2_ctrl_update(false);
> + } else {
> + isp_csi2_ctx_config_enabled(0, false);
> + isp_csi2_ctx_config_eof_enabled(0, false);
> + isp_csi2_ctx_config_checksum_enabled(0, false);
> + isp_csi2_ctx_update(0, false);
> +
> + isp_csi2_ctrl_config_ecc_enable(false);
> + isp_csi2_ctrl_config_if_enable(false);
> + isp_csi2_ctrl_update(false);
> + }
> +}
> +EXPORT_SYMBOL(isp_csi2_enable);
> +
> +/**
> + * isp_csi2_regdump - Prints CSI2 debug information.
> + **/
> +void isp_csi2_regdump(void)
> +{
> + printk(KERN_DEBUG "-------------Register dump-------------\n");
> +
> + printk(KERN_DEBUG "ISP_CTRL: %x\n", omap_readl(ISP_CTRL));
> + printk(KERN_DEBUG "ISP_TCTRL_CTRL: %x\n", omap_readl(ISP_TCTRL_CTRL));
> +
> + printk(KERN_DEBUG "ISPCCDC_SDR_ADDR: %x\n",
> + omap_readl(ISPCCDC_SDR_ADDR));
> + printk(KERN_DEBUG "ISPCCDC_SYN_MODE: %x\n",
> + omap_readl(ISPCCDC_SYN_MODE));
> + printk(KERN_DEBUG "ISPCCDC_CFG: %x\n", omap_readl(ISPCCDC_CFG));
> + printk(KERN_DEBUG "ISPCCDC_FMTCFG: %x\n", omap_readl(ISPCCDC_FMTCFG));
> + printk(KERN_DEBUG "ISPCCDC_HSIZE_OFF: %x\n",
> + omap_readl(ISPCCDC_HSIZE_OFF));
> + printk(KERN_DEBUG "ISPCCDC_HORZ_INFO: %x\n",
> + omap_readl(ISPCCDC_HORZ_INFO));
> + printk(KERN_DEBUG "ISPCCDC_VERT_START: %x\n",
> + omap_readl(ISPCCDC_VERT_START));
> + printk(KERN_DEBUG "ISPCCDC_VERT_LINES: %x\n",
> + omap_readl(ISPCCDC_VERT_LINES));
> +
> + printk(KERN_DEBUG "ISPCSI2_COMPLEXIO_CFG1: %x\n",
> + omap_readl(ISPCSI2_COMPLEXIO_CFG1));
> + printk(KERN_DEBUG "ISPCSI2_SYSSTATUS: %x\n",
> + omap_readl(ISPCSI2_SYSSTATUS));
> + printk(KERN_DEBUG "ISPCSI2_SYSCONFIG: %x\n",
> + omap_readl(ISPCSI2_SYSCONFIG));
> + printk(KERN_DEBUG "ISPCSI2_IRQENABLE: %x\n",
> + omap_readl(ISPCSI2_IRQENABLE));
> + printk(KERN_DEBUG "ISPCSI2_IRQSTATUS: %x\n",
> + omap_readl(ISPCSI2_IRQSTATUS));
> +
> + printk(KERN_DEBUG "ISPCSI2_CTX_IRQENABLE(0): %x\n",
> + omap_readl(ISPCSI2_CTX_IRQENABLE(0)));
> + printk(KERN_DEBUG "ISPCSI2_CTX_IRQSTATUS(0): %x\n",
> + omap_readl(ISPCSI2_CTX_IRQSTATUS(0)));
> + printk(KERN_DEBUG "ISPCSI2_TIMING: %x\n", omap_readl(ISPCSI2_TIMING));
> + printk(KERN_DEBUG "ISPCSI2PHY_CFG0: %x\n", omap_readl(ISPCSI2PHY_CFG0));
> + printk(KERN_DEBUG "ISPCSI2PHY_CFG1: %x\n", omap_readl(ISPCSI2PHY_CFG1));
> + printk(KERN_DEBUG "ISPCSI2_CTX_CTRL1(0): %x\n",
> + omap_readl(ISPCSI2_CTX_CTRL1(0)));
> + printk(KERN_DEBUG "ISPCSI2_CTX_CTRL2(0): %x\n",
> + omap_readl(ISPCSI2_CTX_CTRL2(0)));
> + printk(KERN_DEBUG "ISPCSI2_CTX_CTRL3(0): %x\n",
> + omap_readl(ISPCSI2_CTX_CTRL3(0)));
> + printk(KERN_DEBUG "ISPCSI2_CTX_DAT_OFST(0): %x\n",
> + omap_readl(ISPCSI2_CTX_DAT_OFST(0)));
> + printk(KERN_DEBUG "ISPCSI2_CTX_DAT_PING_ADDR(0): %x\n",
> + omap_readl(ISPCSI2_CTX_DAT_PING_ADDR(0)));
> + printk(KERN_DEBUG "ISPCSI2_CTX_DAT_PONG_ADDR(0): %x\n",
> + omap_readl(ISPCSI2_CTX_DAT_PONG_ADDR(0)));
> + printk(KERN_DEBUG "ISPCSI2_CTRL: %x\n", omap_readl(ISPCSI2_CTRL));
> + printk(KERN_DEBUG "---------------------------------------\n");
> +}
> +
> +/**
> + * isp_csi2_cleanup - Routine for module driver cleanup
> + **/
> +void __exit isp_csi2_cleanup(void)
> +{
> + return;
> +}
> +
> +/**
> + * isp_csi2_init - Routine for module driver init
> + **/
> +int __init isp_csi2_init(void)
> +{
> + int i;
> +
> + update_complexio_cfg1 = false;
> + update_phy_cfg0 = false;
> + update_phy_cfg1 = false;
> + for (i = 0; i < 8; i++) {
> + update_ctx_ctrl1[i] = false;
> + update_ctx_ctrl2[i] = false;
> + update_ctx_ctrl3[i] = false;
> + }
> + update_timing = false;
> + update_ctrl = false;
> +
> + memset(¤t_csi2_cfg, 0, sizeof(current_csi2_cfg));
> + memset(¤t_csi2_cfg_update, 0, sizeof(current_csi2_cfg_update));
> + return 0;
> +}
> +
> +MODULE_AUTHOR("Texas Instruments");
> +MODULE_DESCRIPTION("ISP CSI2 Receiver Module");
> +MODULE_LICENSE("GPL");
> diff --git a/drivers/media/video/isp/ispcsi2.h b/drivers/media/video/isp/ispcsi2.h
> new file mode 100644
> index 0000000..1419bda
> --- /dev/null
> +++ b/drivers/media/video/isp/ispcsi2.h
> @@ -0,0 +1,232 @@
> +/*
> + * drivers/media/video/isp/ispcsi2.h
> + *
> + * Copyright (C) 2008 Texas Instruments.
> + *
> + * Contributors:
> + * Sergio Aguirre <saaguirre@ti.com>
> + * Dominic Curran <dcurran@ti.com>
> + *
> + * 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_CSI2_API_H
> +#define OMAP_ISP_CSI2_API_H
> +#include <linux/videodev2.h>
> +
> +enum isp_csi2_irqevents {
> + OCP_ERR_IRQ = 0x4000,
> + SHORT_PACKET_IRQ = 0x2000,
> + ECC_CORRECTION_IRQ = 0x1000,
> + ECC_NO_CORRECTION_IRQ = 0x800,
> + COMPLEXIO2_ERR_IRQ = 0x400,
> + COMPLEXIO1_ERR_IRQ = 0x200,
> + FIFO_OVF_IRQ = 0x100,
> + CONTEXT7 = 0x80,
> + CONTEXT6 = 0x40,
> + CONTEXT5 = 0x20,
> + CONTEXT4 = 0x10,
> + CONTEXT3 = 0x8,
> + CONTEXT2 = 0x4,
> + CONTEXT1 = 0x2,
> + CONTEXT0 = 0x1,
> +};
> +
> +enum isp_csi2_ctx_irqevents {
> + CTX_ECC_CORRECTION = 0x100,
> + CTX_LINE_NUMBER = 0x80,
> + CTX_FRAME_NUMBER = 0x40,
> + CTX_CS = 0x20,
> + CTX_LE = 0x8,
> + CTX_LS = 0x4,
> + CTX_FE = 0x2,
> + CTX_FS = 0x1,
> +};
> +
> +enum isp_csi2_power_cmds {
> + ISP_CSI2_POWER_OFF,
> + ISP_CSI2_POWER_ON,
> + ISP_CSI2_POWER_ULPW,
> +};
> +
> +enum isp_csi2_frame_mode {
> + ISP_CSI2_FRAME_IMMEDIATE,
> + ISP_CSI2_FRAME_AFTERFEC,
> +};
> +
> +struct csi2_lanecfg {
> + u8 pos;
> + u8 pol;
> +};
> +
> +struct isp_csi2_lanes_cfg {
> + struct csi2_lanecfg data[4];
> + struct csi2_lanecfg clk;
> +};
> +
> +struct isp_csi2_lanes_cfg_update {
> + bool data[4];
> + bool clk;
> +};
> +
> +struct isp_csi2_phy_cfg {
> + u8 ths_term;
> + u8 ths_settle;
> + u8 tclk_term;
> + unsigned tclk_miss:1;
> + u8 tclk_settle;
> +};
> +
> +struct isp_csi2_phy_cfg_update {
> + bool ths_term;
> + bool ths_settle;
> + bool tclk_term;
> + bool tclk_miss;
> + bool tclk_settle;
> +};
> +
> +struct isp_csi2_ctx_cfg {
> + u8 virtual_id;
> + u8 frame_count;
> + struct v4l2_pix_format format;
> + u16 alpha;
> + u16 data_offset;
> + u32 ping_addr;
> + u32 pong_addr;
> + bool eof_enabled;
> + bool eol_enabled;
> + bool checksum_enabled;
> + bool enabled;
> +};
> +
> +struct isp_csi2_ctx_cfg_update {
> + bool virtual_id;
> + bool frame_count;
> + bool format;
> + bool alpha;
> + bool data_offset;
> + bool ping_addr;
> + bool pong_addr;
> + bool eof_enabled;
> + bool eol_enabled;
> + bool checksum_enabled;
> + bool enabled;
> +};
> +
> +struct isp_csi2_timings_cfg {
> + bool force_rx_mode;
> + bool stop_state_16x;
> + bool stop_state_4x;
> + u16 stop_state_counter;
> +};
> +
> +struct isp_csi2_timings_cfg_update {
> + bool force_rx_mode;
> + bool stop_state_16x;
> + bool stop_state_4x;
> + bool stop_state_counter;
> +};
> +
> +struct isp_csi2_ctrl_cfg {
> + bool vp_clk_enable;
> + bool vp_only_enable;
> + u8 vp_out_ctrl;
> + bool debug_enable;
> + u8 burst_size;
> + enum isp_csi2_frame_mode frame_mode;
> + bool ecc_enable;
> + bool secure_mode;
> + bool if_enable;
> +};
> +
> +struct isp_csi2_ctrl_cfg_update {
> + bool vp_clk_enable;
> + bool vp_only_enable;
> + bool vp_out_ctrl;
> + bool debug_enable;
> + bool burst_size;
> + bool frame_mode;
> + bool ecc_enable;
> + bool secure_mode;
> + bool if_enable;
> +};
> +
> +struct isp_csi2_cfg {
> + struct isp_csi2_lanes_cfg lanes;
> + struct isp_csi2_phy_cfg phy;
> + struct isp_csi2_ctx_cfg contexts[8];
> + struct isp_csi2_timings_cfg timings[2];
> + struct isp_csi2_ctrl_cfg ctrl;
> +};
> +
> +struct isp_csi2_cfg_update {
> + struct isp_csi2_lanes_cfg_update lanes;
> + struct isp_csi2_phy_cfg_update phy;
> + struct isp_csi2_ctx_cfg_update contexts[8];
> + struct isp_csi2_timings_cfg_update timings[2];
> + struct isp_csi2_ctrl_cfg_update ctrl;
> +};
> +
> +int isp_csi2_complexio_lanes_config(struct isp_csi2_lanes_cfg *reqcfg);
> +int isp_csi2_complexio_lanes_update(bool force_update);
> +int isp_csi2_complexio_lanes_get(void);
> +int isp_csi2_complexio_power_autoswitch(bool enable);
> +int isp_csi2_complexio_power(enum isp_csi2_power_cmds power_cmd);
> +int isp_csi2_ctrl_config_frame_mode(enum isp_csi2_frame_mode frame_mode);
> +int isp_csi2_ctrl_config_vp_clk_enable(bool vp_clk_enable);
> +int isp_csi2_ctrl_config_vp_only_enable(bool vp_only_enable);
> +int isp_csi2_ctrl_config_debug_enable(bool debug_enable);
> +int isp_csi2_ctrl_config_burst_size(u8 burst_size);
> +int isp_csi2_ctrl_config_ecc_enable(bool ecc_enable);
> +int isp_csi2_ctrl_config_secure_mode(bool secure_mode);
> +int isp_csi2_ctrl_config_if_enable(bool if_enable);
> +int isp_csi2_ctrl_config_vp_out_ctrl(u8 vp_out_ctrl);
> +int isp_csi2_ctrl_update(bool force_update);
> +int isp_csi2_ctrl_get(void);
> +int isp_csi2_ctx_config_virtual_id(u8 ctxnum, u8 virtual_id);
> +int isp_csi2_ctx_config_frame_count(u8 ctxnum, u8 frame_count);
> +int isp_csi2_ctx_config_format(u8 ctxnum, u32 pixformat);
> +int isp_csi2_ctx_config_alpha(u8 ctxnum, u16 alpha);
> +int isp_csi2_ctx_config_data_offset(u8 ctxnum, u16 data_offset);
> +int isp_csi2_ctx_config_ping_addr(u8 ctxnum, u32 ping_addr);
> +int isp_csi2_ctx_config_pong_addr(u8 ctxnum, u32 pong_addr);
> +int isp_csi2_ctx_config_eof_enabled(u8 ctxnum, bool eof_enabled);
> +int isp_csi2_ctx_config_eol_enabled(u8 ctxnum, bool eol_enabled);
> +int isp_csi2_ctx_config_checksum_enabled(u8 ctxnum, bool checksum_enabled);
> +int isp_csi2_ctx_config_enabled(u8 ctxnum, bool enabled);
> +int isp_csi2_ctx_update(u8 ctxnum, bool force_update);
> +int isp_csi2_ctx_get(u8 ctxnum);
> +int isp_csi2_ctx_update_all(bool force_update);
> +int isp_csi2_ctx_get_all(void);
> +int isp_csi2_phy_config(struct isp_csi2_phy_cfg *desiredphyconfig);
> +int isp_csi2_calc_phy_cfg0(u32 mipiclk, u32 lbound_hs_settle,
> + u32 ubound_hs_settle);
> +int isp_csi2_phy_update(bool force_update);
> +int isp_csi2_phy_get(void);
> +int isp_csi2_timings_config_forcerxmode(u8 io, bool force_rx_mode);
> +int isp_csi2_timings_config_stopstate_16x(u8 io, bool stop_state_16x);
> +int isp_csi2_timings_config_stopstate_4x(u8 io, bool stop_state_4x);
> +int isp_csi2_timings_config_stopstate_cnt(u8 io, u16 stop_state_counter);
> +int isp_csi2_timings_update(u8 io, bool force_update);
> +int isp_csi2_timings_get(u8 io);
> +int isp_csi2_timings_update_all(bool force_update);
> +int isp_csi2_timings_get_all(void);
> +void isp_csi2_irq_complexio1_set(int enable);
> +void isp_csi2_irq_ctx_set(int enable);
> +void isp_csi2_irq_status_set(int enable);
> +void isp_csi2_irq_set(int enable);
> +void isp_csi2_irq_all_set(int enable);
> +
> +void isp_csi2_isr(void);
> +int isp_csi2_reset(void);
> +void isp_csi2_enable(int enable);
> +void isp_csi2_regdump(void);
> +
> +#endif /* OMAP_ISP_CSI2_H */
> +
> --
> 1.5.6.5
>
>
> --
> video4linux-list mailing list
> Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
> https://www.redhat.com/mailman/listinfo/video4linux-list
>
>
--
Hans Verkuil - video4linux developer - sponsored by TANDBERG
--
video4linux-list mailing list
Unsubscribe mailto:video4linux-list-request@redhat.com?subject=unsubscribe
https://www.redhat.com/mailman/listinfo/video4linux-list
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2008-12-16 16:55 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-12-11 20:38 [REVIEW PATCH 07/14] OMAP: CAM: Add ISP CSI2 API Aguirre Rodriguez, Sergio Alberto
2008-12-15 16:16 ` Tony Lindgren
2008-12-16 16:55 ` Hans Verkuil
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox