summaryrefslogtreecommitdiff
path: root/drivers/mipi_bif
diff options
context:
space:
mode:
authorChaitanya Bandi <bandik@nvidia.com>2012-12-03 09:35:30 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 12:48:49 -0700
commit5bace921d740ad674473bb150f55324b34bff575 (patch)
tree9d6e00a03dfdc4db93035417a98675dde1275e23 /drivers/mipi_bif
parenta11f86eed184c84f0d09065c3ef5b751fa8ac919 (diff)
mipi_bif: tegra: Add Tegra MIPIBIF Driver support
Bug 1022139 Change-Id: Ic76596ba288cadc76691be42284e5ac3c43603ad Signed-off-by: Chaitanya Bandi <bandik@nvidia.com> Reviewed-on: http://git-master/r/187718 Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com>
Diffstat (limited to 'drivers/mipi_bif')
-rw-r--r--drivers/mipi_bif/Kconfig12
-rw-r--r--drivers/mipi_bif/Makefile1
-rw-r--r--drivers/mipi_bif/mipi-bif-tegra.c1005
3 files changed, 1018 insertions, 0 deletions
diff --git a/drivers/mipi_bif/Kconfig b/drivers/mipi_bif/Kconfig
index 581e24f80389..510505b5453a 100644
--- a/drivers/mipi_bif/Kconfig
+++ b/drivers/mipi_bif/Kconfig
@@ -5,3 +5,15 @@ menuconfig MIPI_BIF
---help---
Say y here if you want MIPI_BIF support to be
enabled.
+
+if MIPI_BIF
+
+
+config MIPI_BIF_TEGRA
+ tristate "NVIDIA Tegra internal MIPIBIF controller"
+ depends on ARCH_TEGRA_14x_SOC
+ help
+ If you say yes to this option, support will be included for the
+ Tegra MIPIBIF Controller
+
+endif
diff --git a/drivers/mipi_bif/Makefile b/drivers/mipi_bif/Makefile
index 616fd2c4eb3f..ac3ec3ec878f 100644
--- a/drivers/mipi_bif/Makefile
+++ b/drivers/mipi_bif/Makefile
@@ -1,3 +1,4 @@
obj-$(CONFIG_MIPI_BIF) += mipi-bif-core.o
+obj-$(CONFIG_MIPI_BIF_TEGRA) += mipi-bif-tegra.o
CFLAGS_mipi-bif-core.o := -Wno-deprecated-declarations
diff --git a/drivers/mipi_bif/mipi-bif-tegra.c b/drivers/mipi_bif/mipi-bif-tegra.c
new file mode 100644
index 000000000000..f336771646d2
--- /dev/null
+++ b/drivers/mipi_bif/mipi-bif-tegra.c
@@ -0,0 +1,1005 @@
+/*
+ * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DEBUG 1
+#define VERBOSE_DEBUG 1
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/mipi-bif.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/mipi-bif-tegra.h>
+
+#include <mach/clk.h>
+#define TEGRA_MIPIBIF_TIMEOUT 1000
+
+#define MIPIBIF_CTRL 0x0
+#define MIPIBIF_CTRL_GO (1<<31)
+#define MIPIBIF_CTRL_COMMAND_TYPE_SHIFT 20
+#define MIPIBIF_CTRL_COMMAND_NO_READ (0x0 << MIPIBIF_CTRL_COMMAND_TYPE_SHIFT)
+#define MIPIBIF_CTRL_COMMAND_READ_DATA (0x1 << MIPIBIF_CTRL_COMMAND_TYPE_SHIFT)
+#define MIPIBIF_CTRL_COMMAND_INTERRUPT_DATA (0x2 << MIPIBIF_CTRL_COMMAND_TYPE_SHIFT)
+#define MIPIBIF_CTRL_COMMAND_BUS_QUERY (0x3 << MIPIBIF_CTRL_COMMAND_TYPE_SHIFT)
+#define MIPIBIF_CTRL_COMMAND_STBY (0x4 << MIPIBIF_CTRL_COMMAND_TYPE_SHIFT)
+#define MIPIBIF_CTRL_COMMAND_PWDN (0x5 << MIPIBIF_CTRL_COMMAND_TYPE_SHIFT)
+#define MIPIBIF_CTRL_COMMAND_HARD_RESET (0x6 << MIPIBIF_CTRL_COMMAND_TYPE_SHIFT)
+#define MIPIBIF_CTRL_ACTIVATE (0x7 << MIPIBIF_CTRL_COMMAND_TYPE_SHIFT)
+#define MIPIBIF_CTRL_COMMAND_EXIT_INT (0x8 << MIPIBIF_CTRL_COMMAND_TYPE_SHIFT)
+#define MIPIBIF_CTRL_PACKETCOUNT_SHIFT 8
+#define MIPIBIF_CTRL_PACKETCOUNT_MASK (1FF << MIPIBIF_CTRL_PACKETCOUNT_SHIFT)
+
+#define MIPIBIF_TIMING_PVT 0x4
+#define MIPIBIF_TIMING_TBIF_0_SHIFT 16
+#define MIPIBIF_TIMING_TBIF_1_SHIFT 12
+#define MIPIBIF_TIMING_TBIF_STOP_SHIFT 8
+
+#define MIPIBIF_TIMING0 0x8
+#define MIPIBIF_TIMING0_TRESP_MIN_SHIFT 28
+#define MIPIBIF_TIMING0_TRESP_MAX_SHIFT 20
+#define MIPIBIF_TIMING0_TBIF_SHIFT 0
+
+#define MIPIBIF_TIMING1 0xc
+#define MIPIBIF_TIMING1_INT_TO_SHIFT 16
+#define MIPIBIF_TIMING1_TINTARM_SHIFT 8
+#define MIPIBIF_TIMING1_TINTTRA_SHIFT 4
+#define MIPIBIF_TIMING1_TINTACT_SHIFT 0
+
+#define MIPIBIF_TIMING2 0x10
+#define MIPIBIF_TIMING2_TPDL_SHIFT 15
+#define MIPIBIF_TIMING2_TPUL_SHIFT 0
+
+#define MIPIBIF_TIMING3 0x14
+#define MIPIBIF_TIMING3_TACT_SHIFT 20
+#define MIPIBIF_TIMING3_TPUP_SHIFT 0
+
+#define MIPIBIF_TIMING4 0x18
+#define MIPIBIF_TIMING4_TCLWS_SHIFT 0
+
+#define MIPIBIF_STATUS 0x2c
+#define MIPIBIF_NUM_PACKETS_TRANSMITTED_SHIFT 16
+#define MIPIBIF_NUM_PACKETS_TRANSMITTED_MASK (0x1FF << MIPIBIF_NUM_PACKETS_TRANSMITTED_SHIFT)
+#define MIPIBIF_NUM_PACKETS_RCVD_SHIFT 4
+#define MIPIBIF_NUM_PACKETS_RCVD_MASK (0x1FF << MIPIBIF_NUM_PACKETS_RCVD_SHIFT)
+#define MIPIBIF_CTRL_BUSY (1<<2)
+#define MIPIBIF_INTERRUPT_RECV_STATUS (1<<1)
+#define MIPIBIF_BQ_RECV_STATUS (1<<0)
+
+#define MIPIBIF_INTERRUPT_EN 0x30
+#define MIPIBIF_INTERRUPT_RXF_UNR_OVR_INT_EN (1<<10)
+#define MIPIBIF_INTERRUPT_TXF_UNR_OVR_INT_EN (1<<9)
+#define MIPIBIF_INTERRUPT_NO_RESPONSE_ERR_INT_EN (1<<8)
+#define MIPIBIF_INTERRUPT_RXF_DATA_REQ_INT_EN (1<<7)
+#define MIPIBIF_INTERRUPT_TXF_DATA_REQ_INT_EN (1<<6)
+#define MIPIBIF_INTERRUPT_XFER_DONE_INT_EN (1<<5)
+#define MIPIBIF_INTERRUPT_INV_ERR_INT_EN (1<<4)
+#define MIPIBIF_INTERRUPT_PKT_RECV_ERR_INT_EN (1<<3)
+#define MIPIBIF_INTERRUPT_LOW_PHASE_IN_WORD_ERR_INT_EN (1<<2)
+#define MIPIBIF_INTERRUPT_INCOMPLETE_PKT_RECV_ERR_INT_EN (1<<1)
+#define MIPIBIF_INTERRUPT_PARITY_ERR_INT_EN (1<<0)
+
+#define MIPIBIF_BCL_ERROR_INTERRUPTS_EN (MIPIBIF_INTERRUPT_LOW_PHASE_IN_WORD_ERR_INT_EN | MIPIBIF_INTERRUPT_INCOMPLETE_PKT_RECV_ERR_INT_EN | MIPIBIF_INTERRUPT_NO_RESPONSE_ERR_INT_EN)
+
+#define MIPIBIF_FIFO_ERROR_INTERRUPTS_EN (MIPIBIF_INTERRUPT_RXF_UNR_OVR_INT_EN | MIPIBIF_INTERRUPT_TXF_UNR_OVR_INT_EN)
+
+#define MIPIBIF_DEFAULT_INTMASK (MIPIBIF_BCL_ERROR_INTERRUPTS_EN | MIPIBIF_FIFO_ERROR_INTERRUPTS_EN | MIPIBIF_INTERRUPT_XFER_DONE_INT_EN)
+
+#define MIPIBIF_INTERRUPT_STATUS 0x34
+#define MIPIBIF_INTERRUPT_NO_RESPONSE_ERR (1<<8)
+#define MIPIBIF_INTERRUPT_RXF_DATA_REQ (1<<7)
+#define MIPIBIF_INTERRUPT_TXF_DATA_REQ (1<<6)
+#define MIPIBIF_INTERRUPT_XFER_DONE (1<<5)
+#define MIPIBIF_INTERRUPT_INV_ERR (1<<4)
+#define MIPIBIF_INTERRUPT_PKT_RECV_ERR (1<<3)
+#define MIPIBIF_INTERRUPT_LOW_PHASE_IN_WORD_ERR (1<<2)
+#define MIPIBIF_INTERRUPT_INCOMPLETE_PKT_RECV_ERR (1<<1)
+#define MIPIBIF_INTERRUPT_PARITY_ERR (1<<0)
+
+#define MIPIBIF_TX_FIFO 0x38
+#define MIPIBIF_TX_FIFO_MASK 0x3FF
+
+#define MIPIBIF_RX_FIFO 0x3c
+#define MIPIBIF_RX_FIFO_MASK 0x3FFFF
+
+#define MIPIBIF_FIFO_CONTROL 0x40
+#define MIPIBIF_RXFIFO_FLUSH (1<<9)
+#define MIPIBIF_TXFIFO_FLUSH (1<<8)
+#define MIPIBIF_RXFIFO_ATN_LVL_SHIFT 4
+#define MIPIBIF_TXFIFO_ATN_LVL_SHIFT 0
+
+#define MIPIBIF_FIFO_STATUS 0x44
+#define MIPIBIF_RX_FIFO_FULL_COUNT_SHIFT 24
+#define MIPIBIF_RX_FIFO_FULL_COUNT_MASK (0xFF<<MIPIBIF_RX_FIFO_FULL_COUNT_SHIFT)
+#define MIPIBIF_TX_FIFO_EMPTY_COUNT_SHIFT 16
+#define MIPIBIF_TX_FIFO_EMPTY_COUNT_MASK (0xFF << MIPIBIF_TX_FIFO_EMPTY_COUNT_SHIFT)
+#define MIPIBIF_TX_FIFO_OVF (1<<7)
+#define MIPIBIF_TX_FIFO_UNR (1<<6)
+#define MIPIBIF_RX_FIFO_OVF (1<<5)
+#define MIPIBIF_RX_FIFO_UNR (1<<4)
+#define MIPIBIF_TX_FIFO_FULL (1<<3)
+#define MIPIBIF_TX_FIFO_EMPTY (1<<2)
+#define MIPIBIF_RX_FIFO_FULL (1<<1)
+#define MIPIBIF_RX_FIFO_EMPTY (1<<0)
+
+#define MIPIBIF_ERR_NONE 0
+#define MIPIBIF_ERR_NO_RESPONSE 0x1
+#define MIPIBIF_ERR_INV 0x2
+#define MIPIBIF_ERR_PKT_RECV 0x4
+#define MIPIBIF_ERR_LOW_PHASE_IN_WORD 0x8
+#define MIPIBIF_ERR_INCOMPLETE_PKT_RECV 0x10
+#define MIPIBIF_ERR_PARITY 0x20
+#define MIPIBIF_ERR_RECV_DATA_TYPE (MIPIBIF_ERR_PARITY | MIPIBIF_ERR_PKT_RECV | MIPIBIF_ERR_INV)
+
+struct tegra_mipi_bif_dev {
+ struct device *dev;
+ struct clk *mipi_bif_clk;
+ struct rt_mutex dev_lock;
+ spinlock_t fifo_lock;
+ void __iomem *base;
+ int cont_id;
+ int irq;
+ int tauBIF;
+ struct completion msg_complete;
+ int msg_err;
+ u8 *msg_buf;
+ u16 msg_device_addr;
+ u16 msg_reg_addr;
+ u16 msg_commands;
+ u16 msg_len;
+ size_t msg_buf_remaining;
+ int current_command_count;
+ struct mipi_bif_adapter adapter;
+ unsigned long bus_clk_rate;
+ bool is_suspended;
+};
+
+static void tegra_mipi_bif_send(struct tegra_mipi_bif_dev *mipi_bif_dev,
+ u32 cmd)
+{
+ writel(cmd, mipi_bif_dev->base + MIPIBIF_TX_FIFO);
+ mipi_bif_dev->current_command_count++;
+}
+
+static void tegra_mipi_bif_mask_irq(struct tegra_mipi_bif_dev *mipi_bif_dev,
+ u32 mask)
+{
+ u32 int_mask = readl(mipi_bif_dev->base + MIPIBIF_INTERRUPT_EN);
+ int_mask &= ~mask;
+ writel(int_mask, mipi_bif_dev->base + MIPIBIF_INTERRUPT_EN);
+}
+
+static void tegra_mipi_bif_unmask_irq(struct tegra_mipi_bif_dev *mipi_bif_dev,
+ u32 mask)
+{
+ u32 int_mask = readl(mipi_bif_dev->base + MIPIBIF_INTERRUPT_EN);
+ int_mask |= mask;
+ writel(int_mask, mipi_bif_dev->base + MIPIBIF_INTERRUPT_EN);
+}
+
+static int
+tegra_mipi_bif_send_DIP0_command(struct tegra_mipi_bif_dev *mipi_bif_dev)
+{
+ int ret;
+
+ init_completion(&mipi_bif_dev->msg_complete);
+
+ writel(MIPI_BIF_BUS_COMMAND_DIP0,
+ mipi_bif_dev->base + MIPIBIF_TX_FIFO);
+ writel(MIPIBIF_DEFAULT_INTMASK,
+ mipi_bif_dev->base + MIPIBIF_INTERRUPT_EN);
+ writel(MIPIBIF_CTRL_GO | MIPIBIF_CTRL_COMMAND_BUS_QUERY,
+ mipi_bif_dev->base + MIPIBIF_CTRL);
+
+ ret = wait_for_completion_timeout(&mipi_bif_dev->msg_complete,
+ TEGRA_MIPIBIF_TIMEOUT);
+ if (WARN_ON(ret == 0)) {
+ dev_err(mipi_bif_dev->dev, "%s:transfer timed out", __func__);
+ return -ETIMEDOUT;
+ }
+
+ if (readl(mipi_bif_dev->base + MIPIBIF_STATUS) & MIPIBIF_BQ_RECV_STATUS)
+ return 1;
+
+ return 0;
+}
+
+static int
+tegra_mipi_bif_send_DIP1_command(struct tegra_mipi_bif_dev *mipi_bif_dev)
+{
+ int ret;
+
+ init_completion(&mipi_bif_dev->msg_complete);
+
+ writel(MIPI_BIF_BUS_COMMAND_DIP1,
+ mipi_bif_dev->base + MIPIBIF_TX_FIFO);
+ writel(MIPIBIF_DEFAULT_INTMASK,
+ mipi_bif_dev->base + MIPIBIF_INTERRUPT_EN);
+ writel(MIPIBIF_CTRL_GO | MIPIBIF_CTRL_COMMAND_BUS_QUERY,
+ mipi_bif_dev->base + MIPIBIF_CTRL);
+
+ ret = wait_for_completion_timeout(&mipi_bif_dev->msg_complete,
+ TEGRA_MIPIBIF_TIMEOUT);
+ if (WARN_ON(ret == 0)) {
+ dev_err(mipi_bif_dev->dev, "%s:transfer timed out", __func__);
+ return -ETIMEDOUT;
+ }
+
+ if (readl(mipi_bif_dev->base + MIPIBIF_STATUS) & MIPIBIF_BQ_RECV_STATUS)
+ return 1;
+
+ return 0;
+}
+
+static int
+tegra_mipi_bif_send_DIE0_command(struct tegra_mipi_bif_dev *mipi_bif_dev)
+{
+ int ret;
+
+ init_completion(&mipi_bif_dev->msg_complete);
+
+ writel(MIPI_BIF_BUS_COMMAND_DIE0,
+ mipi_bif_dev->base + MIPIBIF_TX_FIFO);
+ writel(MIPIBIF_DEFAULT_INTMASK,
+ mipi_bif_dev->base + MIPIBIF_INTERRUPT_EN);
+ writel(MIPIBIF_CTRL_GO, mipi_bif_dev->base + MIPIBIF_CTRL);
+
+ ret = wait_for_completion_timeout(&mipi_bif_dev->msg_complete,
+ TEGRA_MIPIBIF_TIMEOUT);
+ if (WARN_ON(ret == 0)) {
+ dev_err(mipi_bif_dev->dev, "%s:transfer timed out", __func__);
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+static int
+tegra_mipi_bif_send_DIE1_command(struct tegra_mipi_bif_dev *mipi_bif_dev)
+{
+ int ret;
+
+ init_completion(&mipi_bif_dev->msg_complete);
+
+ writel(MIPI_BIF_BUS_COMMAND_DIE1,
+ mipi_bif_dev->base + MIPIBIF_TX_FIFO);
+ writel(MIPIBIF_DEFAULT_INTMASK,
+ mipi_bif_dev->base + MIPIBIF_INTERRUPT_EN);
+ writel(MIPIBIF_CTRL_GO, mipi_bif_dev->base + MIPIBIF_CTRL);
+
+ ret = wait_for_completion_timeout(&mipi_bif_dev->msg_complete,
+ TEGRA_MIPIBIF_TIMEOUT);
+ if (WARN_ON(ret == 0)) {
+ dev_err(mipi_bif_dev->dev, "%s:transfer timed out", __func__);
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+static int
+tegra_mipi_bif_send_DISS_command(struct tegra_mipi_bif_dev *mipi_bif_dev)
+{
+ int ret;
+
+ init_completion(&mipi_bif_dev->msg_complete);
+
+ writel(MIPI_BIF_BUS_COMMAND_DISS,
+ mipi_bif_dev->base + MIPIBIF_TX_FIFO);
+ writel(MIPIBIF_DEFAULT_INTMASK,
+ mipi_bif_dev->base + MIPIBIF_INTERRUPT_EN);
+ writel(MIPIBIF_CTRL_GO, mipi_bif_dev->base + MIPIBIF_CTRL);
+
+ ret = wait_for_completion_timeout(&mipi_bif_dev->msg_complete,
+ TEGRA_MIPIBIF_TIMEOUT);
+ if (WARN_ON(ret == 0)) {
+ dev_err(mipi_bif_dev->dev, "%s:transfer timed out", __func__);
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+static int tegra_mipi_bif_HardReset(struct tegra_mipi_bif_dev *mipi_bif_dev)
+{
+ int ret;
+
+ init_completion(&mipi_bif_dev->msg_complete);
+
+ writel(MIPIBIF_DEFAULT_INTMASK,
+ mipi_bif_dev->base + MIPIBIF_INTERRUPT_EN);
+ writel(MIPIBIF_CTRL_GO | MIPIBIF_CTRL_COMMAND_HARD_RESET,
+ mipi_bif_dev->base + MIPIBIF_CTRL);
+
+ ret = wait_for_completion_timeout(&mipi_bif_dev->msg_complete,
+ TEGRA_MIPIBIF_TIMEOUT);
+ if (WARN_ON(ret == 0)) {
+ dev_err(mipi_bif_dev->dev, "%s:transfer timed out", __func__);
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+static int tegra_mipi_bif_StandBy(struct tegra_mipi_bif_dev *mipi_bif_dev)
+{
+ int ret;
+
+ init_completion(&mipi_bif_dev->msg_complete);
+
+ writel(MIPI_BIF_BUS_COMMAND_STBY,
+ mipi_bif_dev->base + MIPIBIF_TX_FIFO);
+ writel(MIPIBIF_DEFAULT_INTMASK,
+ mipi_bif_dev->base + MIPIBIF_INTERRUPT_EN);
+ writel(MIPIBIF_CTRL_GO | MIPIBIF_CTRL_COMMAND_STBY,
+ mipi_bif_dev->base + MIPIBIF_CTRL);
+
+ ret = wait_for_completion_timeout(&mipi_bif_dev->msg_complete,
+ TEGRA_MIPIBIF_TIMEOUT);
+ if (WARN_ON(ret == 0)) {
+ dev_err(mipi_bif_dev->dev, "%s:transfer timed out", __func__);
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+static int tegra_mipi_bif_Activate(struct tegra_mipi_bif_dev *mipi_bif_dev)
+{
+ int ret;
+
+ init_completion(&mipi_bif_dev->msg_complete);
+
+ writel(MIPIBIF_DEFAULT_INTMASK,
+ mipi_bif_dev->base + MIPIBIF_INTERRUPT_EN);
+ writel(MIPIBIF_CTRL_GO | MIPIBIF_CTRL_ACTIVATE,
+ mipi_bif_dev->base + MIPIBIF_CTRL);
+
+ ret = wait_for_completion_timeout(&mipi_bif_dev->msg_complete,
+ TEGRA_MIPIBIF_TIMEOUT);
+ if (WARN_ON(ret == 0)) {
+ dev_err(mipi_bif_dev->dev, "%s:transfer timed out", __func__);
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+static int tegra_mipi_bif_PowerDown(struct tegra_mipi_bif_dev *mipi_bif_dev)
+{
+ int ret;
+
+ init_completion(&mipi_bif_dev->msg_complete);
+
+ writel(MIPIBIF_DEFAULT_INTMASK,
+ mipi_bif_dev->base + MIPIBIF_INTERRUPT_EN);
+ writel(MIPI_BIF_BUS_COMMAND_PWDN,
+ mipi_bif_dev->base + MIPIBIF_TX_FIFO);
+ writel(MIPIBIF_CTRL_GO | MIPIBIF_CTRL_COMMAND_PWDN,
+ mipi_bif_dev->base + MIPIBIF_CTRL);
+
+ ret = wait_for_completion_timeout(&mipi_bif_dev->msg_complete,
+ TEGRA_MIPIBIF_TIMEOUT);
+ if (WARN_ON(ret == 0)) {
+ dev_err(mipi_bif_dev->dev, "%s:transfer timed out", __func__);
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+static int tegra_mipi_bif_Exit_Interrupt(
+ struct tegra_mipi_bif_dev *mipi_bif_dev)
+{
+ int ret;
+ init_completion(&mipi_bif_dev->msg_complete);
+
+ writel(MIPIBIF_DEFAULT_INTMASK,
+ mipi_bif_dev->base + MIPIBIF_INTERRUPT_EN);
+ writel(MIPIBIF_CTRL_GO | MIPIBIF_CTRL_COMMAND_EXIT_INT,
+ mipi_bif_dev->base + MIPIBIF_CTRL);
+
+ ret = wait_for_completion_timeout(&mipi_bif_dev->msg_complete,
+ TEGRA_MIPIBIF_TIMEOUT);
+ if (WARN_ON(ret == 0)) {
+ dev_err(mipi_bif_dev->dev, "%s:transfer timed out", __func__);
+ return -ETIMEDOUT;
+ }
+ return 0;
+}
+
+static int tegra_mipi_bif_flush_fifos(struct tegra_mipi_bif_dev *mipi_bif_dev)
+{
+ unsigned long timeout = jiffies + HZ;
+
+ u32 val = readl(mipi_bif_dev->base + MIPIBIF_FIFO_CONTROL);
+ val |= MIPIBIF_RXFIFO_FLUSH;
+ val |= MIPIBIF_TXFIFO_FLUSH;
+ writel(val, mipi_bif_dev->base + MIPIBIF_FIFO_CONTROL);
+
+ while (readl(mipi_bif_dev->base + MIPIBIF_FIFO_CONTROL) &
+ (MIPIBIF_RXFIFO_FLUSH | MIPIBIF_RXFIFO_FLUSH)) {
+ if (time_after(jiffies, timeout)) {
+ dev_warn(mipi_bif_dev->dev, "timeout for fifo flush\n");
+ return -ETIMEDOUT;
+ }
+ msleep(1);
+ }
+ return 0;
+}
+
+static int
+tegra_mipi_bif_program_timings(struct tegra_mipi_bif_dev *mipi_bif_dev)
+{
+ u32 timing_pvt;
+ u32 timing0, timing1, timing2, timing3, timing4;
+
+ timing_pvt = 0 << MIPIBIF_TIMING_TBIF_0_SHIFT;
+ timing_pvt |= 2 << MIPIBIF_TIMING_TBIF_1_SHIFT;
+ timing_pvt |= 4 << MIPIBIF_TIMING_TBIF_STOP_SHIFT;
+ writel(timing_pvt, mipi_bif_dev->base + MIPIBIF_TIMING_PVT);
+
+ timing0 = 3 << MIPIBIF_TIMING0_TRESP_MIN_SHIFT;
+ timing0 |= 0xe << MIPIBIF_TIMING0_TRESP_MAX_SHIFT;
+ timing0 |= (mipi_bif_dev->bus_clk_rate * mipi_bif_dev->tauBIF - 1)
+ << MIPIBIF_TIMING0_TBIF_SHIFT;
+ writel(timing0, mipi_bif_dev->base + MIPIBIF_TIMING0);
+
+ timing2 = (2500 * mipi_bif_dev->bus_clk_rate - 1)
+ << MIPIBIF_TIMING2_TPDL_SHIFT;
+ timing2 |= (50 * mipi_bif_dev->bus_clk_rate - 1)
+ << MIPIBIF_TIMING2_TPUL_SHIFT;
+ writel(timing2, mipi_bif_dev->base + MIPIBIF_TIMING2);
+
+ timing3 = (100 * mipi_bif_dev->bus_clk_rate - 1)
+ << MIPIBIF_TIMING3_TACT_SHIFT;
+ timing3 |= (11000 * mipi_bif_dev->bus_clk_rate - 1)
+ << MIPIBIF_TIMING3_TPUP_SHIFT;
+ writel(timing3, mipi_bif_dev->base + MIPIBIF_TIMING3);
+
+ timing1 = readl(mipi_bif_dev->base + MIPIBIF_TIMING1);
+ writel(timing1 | ((5000 / mipi_bif_dev->tauBIF) - 1),
+ mipi_bif_dev->base + MIPIBIF_TIMING1);
+
+ timing4 = 0xdab << MIPIBIF_TIMING4_TCLWS_SHIFT;
+ writel(timing4, mipi_bif_dev->base + MIPIBIF_TIMING4);
+ return 0;
+}
+
+static int tegra_mipi_bif_init(struct tegra_mipi_bif_dev *mipi_bif_dev)
+{
+ u32 fifo_control;
+ clk_prepare_enable(mipi_bif_dev->mipi_bif_clk);
+
+ tegra_periph_reset_assert(mipi_bif_dev->mipi_bif_clk);
+ udelay(2);
+ tegra_periph_reset_deassert(mipi_bif_dev->mipi_bif_clk);
+ clk_set_rate(mipi_bif_dev->mipi_bif_clk,
+ mipi_bif_dev->bus_clk_rate * 1000000);
+
+ writel(0, mipi_bif_dev->base + MIPIBIF_INTERRUPT_EN);
+ fifo_control = 0 << MIPIBIF_RXFIFO_ATN_LVL_SHIFT;
+ fifo_control |= 5 << MIPIBIF_TXFIFO_ATN_LVL_SHIFT;
+ fifo_control |= MIPIBIF_RXFIFO_FLUSH;
+ fifo_control |= MIPIBIF_TXFIFO_FLUSH;
+ writel(fifo_control, mipi_bif_dev->base + MIPIBIF_FIFO_CONTROL);
+
+ tegra_mipi_bif_program_timings(mipi_bif_dev);
+
+ clk_disable_unprepare(mipi_bif_dev->mipi_bif_clk);
+ return 0;
+}
+
+static int tegra_mipi_bif_empty_rx_fifo(struct tegra_mipi_bif_dev *mipi_bif_dev)
+{
+ u32 val;
+ int rx_fifo_avail;
+ u8 *buf = mipi_bif_dev->msg_buf;
+ size_t buf_remaining = mipi_bif_dev->msg_buf_remaining;
+ int to_be_transferred = buf_remaining;
+ int ret = 0;
+ val = readl(mipi_bif_dev->base + MIPIBIF_FIFO_STATUS);
+ rx_fifo_avail = (val & MIPIBIF_RX_FIFO_FULL_COUNT_MASK)
+ >> MIPIBIF_RX_FIFO_FULL_COUNT_SHIFT;
+ if (to_be_transferred > rx_fifo_avail)
+ to_be_transferred = rx_fifo_avail;
+
+ while (to_be_transferred > 0) {
+ val = readl(mipi_bif_dev->base + MIPIBIF_RX_FIFO);
+ val = val >> 7;
+ if (!(val & MIPI_BIF_RD_ACK_BIT)) {
+ dev_warn(mipi_bif_dev->dev, "Error in data:%x\n", val);
+ mipi_bif_dev->msg_err = MIPIBIF_ERR_RECV_DATA_TYPE;
+ ret = -EIO;
+ break;
+ }
+ *buf = val & 0xFF;
+
+ rx_fifo_avail--;
+ to_be_transferred--;
+ buf_remaining--;
+ buf++;
+
+ }
+ mipi_bif_dev->msg_buf_remaining = buf_remaining;
+ mipi_bif_dev->msg_buf = buf;
+ return ret;
+}
+
+static int tegra_mipi_bif_fill_tx_fifo(struct tegra_mipi_bif_dev *mipi_bif_dev)
+{
+ u8 *buf;
+ u32 val;
+ size_t buf_remaining;
+ int tx_fifo_available;
+ int to_be_transferred;
+
+ buf = mipi_bif_dev->msg_buf;
+ buf_remaining = mipi_bif_dev->msg_buf_remaining;
+ to_be_transferred = buf_remaining;
+
+ val = readl(mipi_bif_dev->base + MIPIBIF_FIFO_STATUS);
+
+ tx_fifo_available = (val & MIPIBIF_TX_FIFO_EMPTY_COUNT_MASK)
+ >> MIPIBIF_TX_FIFO_EMPTY_COUNT_SHIFT;
+
+ if (tx_fifo_available > 0) {
+ if (to_be_transferred > tx_fifo_available)
+ to_be_transferred = tx_fifo_available;
+
+ mipi_bif_dev->msg_buf = buf + to_be_transferred;
+ mipi_bif_dev->msg_buf_remaining -= to_be_transferred;
+ buf_remaining = mipi_bif_dev->msg_buf_remaining;
+
+ while (to_be_transferred) {
+ writel(*buf, mipi_bif_dev->base + MIPIBIF_TX_FIFO);
+ buf++;
+ to_be_transferred--;
+ tx_fifo_available--;
+ }
+ }
+ return 0;
+}
+
+static void
+tegra_mipi_bif_device_detect(struct tegra_mipi_bif_dev *mipi_bif_dev, int n)
+{
+ int ret;
+ if (!n)
+ return;
+ if (tegra_mipi_bif_send_DIP0_command(mipi_bif_dev)) {
+ dev_dbg(mipi_bif_dev->dev, "0");
+ ret = tegra_mipi_bif_send_DIE0_command(mipi_bif_dev);
+ tegra_mipi_bif_device_detect(mipi_bif_dev, n - 1);
+ }
+ if (tegra_mipi_bif_send_DIP1_command(mipi_bif_dev)) {
+ dev_dbg(mipi_bif_dev->dev, "1");
+ ret = tegra_mipi_bif_send_DIE1_command(mipi_bif_dev);
+ tegra_mipi_bif_device_detect(mipi_bif_dev, n - 1);
+ }
+}
+
+static int
+tegra_mipi_bif_xfer(struct mipi_bif_adapter *adap, struct mipi_bif_msg *msg)
+{
+ struct tegra_mipi_bif_dev *mipi_bif_dev = mipi_bif_get_adapdata(adap);
+ int ret = 0;
+ u32 sda_part;
+ u32 era_part;
+ u32 wra_part;
+ u32 rra_part;
+ u32 rbe = MIPI_BIF_BUS_COMMAND_RBE0;
+ u32 rbl = MIPI_BIF_BUS_COMMAND_RBL0;
+ u32 ctrl_reg = 0;
+
+ u32 def_int_mask = MIPIBIF_DEFAULT_INTMASK;
+ u32 int_mask = def_int_mask;
+
+ rt_mutex_lock(&mipi_bif_dev->dev_lock);
+
+ if (mipi_bif_dev->is_suspended) {
+ rt_mutex_unlock(&mipi_bif_dev->dev_lock);
+ return -EBUSY;
+ }
+
+ tegra_mipi_bif_init(mipi_bif_dev);
+
+ clk_prepare_enable(mipi_bif_dev->mipi_bif_clk);
+
+ tegra_mipi_bif_flush_fifos(mipi_bif_dev);
+
+ INIT_COMPLETION(mipi_bif_dev->msg_complete);
+
+ mipi_bif_dev->msg_device_addr = msg->device_addr;
+ mipi_bif_dev->msg_commands = msg->commands;
+ mipi_bif_dev->msg_buf_remaining = 0;
+ mipi_bif_dev->current_command_count = 0;
+ mipi_bif_dev->msg_err = MIPIBIF_ERR_NONE;
+ sda_part = msg->device_addr & 0xFF;
+
+ if (msg->commands == MIPI_BIF_WRITE) {
+
+ if (msg->len == 0 || (!msg->buf))
+ ret = -EINVAL;
+
+ mipi_bif_dev->msg_buf = msg->buf;
+ mipi_bif_dev->msg_len = msg->len;
+ mipi_bif_dev->msg_buf_remaining = msg->len;
+ mipi_bif_dev->msg_reg_addr = msg->reg_addr;
+
+ wra_part = msg->reg_addr & 0xFF;
+ era_part = (msg->reg_addr & 0xFF00) >> 8;
+
+ tegra_mipi_bif_send(mipi_bif_dev, sda_part | MIPI_BIF_SDA);
+ tegra_mipi_bif_send(mipi_bif_dev, era_part | MIPI_BIF_ERA);
+ tegra_mipi_bif_send(mipi_bif_dev, wra_part | MIPI_BIF_WRA);
+
+ ctrl_reg = MIPIBIF_CTRL_COMMAND_NO_READ;
+ ctrl_reg |= ((msg->len + mipi_bif_dev->current_command_count - 1)
+ << MIPIBIF_CTRL_PACKETCOUNT_SHIFT);
+
+ tegra_mipi_bif_fill_tx_fifo(mipi_bif_dev);
+
+ if (mipi_bif_dev->msg_buf_remaining)
+ int_mask |= MIPIBIF_INTERRUPT_TXF_DATA_REQ_INT_EN;
+
+ tegra_mipi_bif_unmask_irq(mipi_bif_dev, int_mask);
+
+ ctrl_reg |= MIPIBIF_CTRL_GO;
+ writel(ctrl_reg, mipi_bif_dev->base + MIPIBIF_CTRL);
+
+ ret = wait_for_completion_timeout(&mipi_bif_dev->msg_complete,
+ TEGRA_MIPIBIF_TIMEOUT);
+ if (WARN_ON(ret == 0)) {
+ dev_err(mipi_bif_dev->dev, "%s:timed out", __func__);
+ ret = -ETIMEDOUT;
+ }
+
+ } else if (msg->commands == MIPI_BIF_READDATA) {
+
+ if (msg->len == 0)
+ ret = -EINVAL;
+
+ mipi_bif_dev->msg_buf = msg->buf;
+ mipi_bif_dev->msg_len = msg->len;
+ mipi_bif_dev->msg_buf_remaining = msg->len;
+ mipi_bif_dev->msg_reg_addr = msg->reg_addr;
+
+ rra_part = msg->reg_addr & 0xFF;
+ era_part = (msg->reg_addr & 0xFF00) >> 8;
+ rbe |= ((msg->len & 0xFF00) >> 8);
+ rbl |= (msg->len & 0xFF);
+
+ if (msg->len == 256)
+ rbe = rbl = 0;
+
+ tegra_mipi_bif_send(mipi_bif_dev, sda_part | MIPI_BIF_SDA);
+ tegra_mipi_bif_send(mipi_bif_dev,
+ rbe | MIPI_BIF_BUS_COMMAND_RBE0);
+ tegra_mipi_bif_send(mipi_bif_dev,
+ rbl | MIPI_BIF_BUS_COMMAND_RBL0);
+ tegra_mipi_bif_send(mipi_bif_dev, era_part | MIPI_BIF_ERA);
+ tegra_mipi_bif_send(mipi_bif_dev, rra_part | MIPI_BIF_RRA);
+
+ int_mask |= MIPIBIF_INTERRUPT_RXF_DATA_REQ_INT_EN;
+ tegra_mipi_bif_unmask_irq(mipi_bif_dev, int_mask);
+
+
+ ctrl_reg |= MIPIBIF_CTRL_COMMAND_READ_DATA;
+ ctrl_reg |= ((mipi_bif_dev->current_command_count - 1)
+ << MIPIBIF_CTRL_PACKETCOUNT_SHIFT);
+ ctrl_reg |= MIPIBIF_CTRL_GO;
+ writel(ctrl_reg, mipi_bif_dev->base + MIPIBIF_CTRL);
+
+ ret = wait_for_completion_timeout(&mipi_bif_dev->msg_complete,
+ TEGRA_MIPIBIF_TIMEOUT);
+ if (WARN_ON(ret == 0)) {
+ dev_err(mipi_bif_dev->dev, "%s:timed out", __func__);
+ ret = -ETIMEDOUT;
+ }
+
+ } else if (msg->commands == MIPI_BIF_INT_READ) {
+
+ tegra_mipi_bif_send(mipi_bif_dev, sda_part | MIPI_BIF_SDA);
+ tegra_mipi_bif_send(mipi_bif_dev,
+ sda_part | MIPI_BIF_BUS_COMMAND_EINT);
+
+ tegra_mipi_bif_unmask_irq(mipi_bif_dev, int_mask);
+
+ ctrl_reg = MIPIBIF_CTRL_COMMAND_INTERRUPT_DATA;
+ ctrl_reg |= ((mipi_bif_dev->current_command_count - 1)
+ << MIPIBIF_CTRL_PACKETCOUNT_SHIFT);
+ ctrl_reg |= MIPIBIF_CTRL_GO;
+ writel(ctrl_reg, mipi_bif_dev->base + MIPIBIF_CTRL);
+
+ ret = wait_for_completion_timeout(&mipi_bif_dev->msg_complete,
+ TEGRA_MIPIBIF_TIMEOUT);
+ if (WARN_ON(ret == 0)) {
+ dev_err(mipi_bif_dev->dev, "%s:timed out", __func__);
+ ret = -ETIMEDOUT;
+ }
+
+ if (!(readl(mipi_bif_dev->base + MIPIBIF_STATUS)
+ & MIPIBIF_INTERRUPT_RECV_STATUS)) {
+ dev_err(mipi_bif_dev->dev, "%s:no interrupt", __func__);
+ ret = -EIO;
+ }
+
+ } else if (msg->commands == MIPI_BIF_STDBY) {
+ ret = tegra_mipi_bif_StandBy(mipi_bif_dev);
+ } else if (msg->commands == MIPI_BIF_PWRDOWN) {
+ ret = tegra_mipi_bif_PowerDown(mipi_bif_dev);
+ } else if (msg->commands == MIPI_BIF_ACTIVATE) {
+ ret = tegra_mipi_bif_Activate(mipi_bif_dev);
+ } else if (msg->commands == MIPI_BIF_INT_EXIT) {
+ ret = tegra_mipi_bif_Exit_Interrupt(mipi_bif_dev);
+ } else if (msg->commands == MIPI_BIF_HARD_RESET) {
+ ret = tegra_mipi_bif_HardReset(mipi_bif_dev);
+ }/* else if (msg->commands == MIPI_BIF_BUSQUERY) {
+ ret = tegra_mipi_bif_send_DISS_command(mipi_bif_dev);
+ tegra_mipi_bif_device_detect(mipi_bif_dev, 80);
+ }*/
+
+ tegra_mipi_bif_mask_irq(mipi_bif_dev, int_mask);
+
+ if (mipi_bif_dev->msg_err & MIPIBIF_ERR_RECV_DATA_TYPE)
+ ret = -EAGAIN;
+ else if (mipi_bif_dev->msg_err != MIPIBIF_ERR_NONE)
+ ret = -EIO;
+
+ clk_disable_unprepare(mipi_bif_dev->mipi_bif_clk);
+ rt_mutex_unlock(&mipi_bif_dev->dev_lock);
+ return ret;
+}
+
+static const struct mipi_bif_algorithm tegra_mipi_bif_algo = {
+ .master_xfer = tegra_mipi_bif_xfer,
+};
+
+static irqreturn_t tegra_mipi_bif_isr(int irq, void *dev_id)
+{
+ u32 status;
+ int ret;
+ struct tegra_mipi_bif_dev *mipi_bif_dev = dev_id;
+ status = readl(mipi_bif_dev->base + MIPIBIF_INTERRUPT_STATUS);
+
+ if (status == 0) {
+ dev_warn(mipi_bif_dev->dev, "Unknown interrupt\n");
+ goto err;
+ }
+
+ if (status & MIPIBIF_INTERRUPT_NO_RESPONSE_ERR) {
+ mipi_bif_dev->msg_err = MIPIBIF_ERR_NO_RESPONSE;
+ dev_warn(mipi_bif_dev->dev,
+ "error: No response from slave within tresp\n");
+ goto err;
+ }
+
+ if (status & MIPIBIF_INTERRUPT_INV_ERR) {
+ mipi_bif_dev->msg_err = MIPIBIF_ERR_INV;
+ dev_warn(mipi_bif_dev->dev,
+ "error: Incorrect inversion received\n");
+ goto err;
+ }
+
+ if (status & MIPIBIF_INTERRUPT_PKT_RECV_ERR) {
+ mipi_bif_dev->msg_err = MIPIBIF_ERR_PKT_RECV;
+ dev_warn(mipi_bif_dev->dev,
+ "error: Incorrect ack received\n");
+ goto err;
+ }
+
+ if (status & MIPIBIF_INTERRUPT_LOW_PHASE_IN_WORD_ERR) {
+ mipi_bif_dev->msg_err = MIPIBIF_ERR_LOW_PHASE_IN_WORD;
+ dev_warn(mipi_bif_dev->dev,
+ "error: Low phase in word err received\n");
+ goto err;
+ }
+
+ if (status & MIPIBIF_INTERRUPT_INCOMPLETE_PKT_RECV_ERR) {
+ mipi_bif_dev->msg_err = MIPIBIF_ERR_INCOMPLETE_PKT_RECV;
+ dev_warn(mipi_bif_dev->dev,
+ "error: Incomplete packet received\n");
+ goto err;
+ }
+
+ if (status & MIPIBIF_INTERRUPT_PARITY_ERR) {
+ mipi_bif_dev->msg_err = MIPIBIF_ERR_PARITY;
+ dev_warn(mipi_bif_dev->dev,
+ "error: Incorrect parity received\n");
+ goto err;
+ }
+
+ if ((mipi_bif_dev->msg_commands == MIPI_BIF_WRITE)
+ && (status & MIPIBIF_INTERRUPT_TXF_DATA_REQ)) {
+ if (mipi_bif_dev->msg_buf_remaining)
+ tegra_mipi_bif_fill_tx_fifo(mipi_bif_dev);
+ else
+ tegra_mipi_bif_mask_irq(mipi_bif_dev,
+ MIPIBIF_INTERRUPT_TXF_DATA_REQ_INT_EN);
+ }
+
+ if ((mipi_bif_dev->msg_commands == MIPI_BIF_READDATA)
+ && (status & MIPIBIF_INTERRUPT_RXF_DATA_REQ)) {
+ if (mipi_bif_dev->msg_buf_remaining) {
+ ret = tegra_mipi_bif_empty_rx_fifo(mipi_bif_dev);
+ if (ret)
+ goto err;
+ } else {
+ tegra_mipi_bif_mask_irq(mipi_bif_dev,
+ MIPIBIF_INTERRUPT_RXF_DATA_REQ_INT_EN);
+ }
+ }
+
+ if (status & MIPIBIF_INTERRUPT_XFER_DONE) {
+ WARN_ON(mipi_bif_dev->msg_buf_remaining);
+ complete(&mipi_bif_dev->msg_complete);
+ }
+ writel(status, mipi_bif_dev->base + MIPIBIF_INTERRUPT_STATUS);
+ return IRQ_HANDLED;
+
+err:
+ writel(status, mipi_bif_dev->base + MIPIBIF_INTERRUPT_STATUS);
+ complete(&mipi_bif_dev->msg_complete);
+ return IRQ_HANDLED;
+}
+
+static int tegra_mipi_bif_remove(struct platform_device *pdev)
+{
+
+ return 0;
+}
+static int tegra_mipi_bif_probe(struct platform_device *pdev)
+{
+ struct tegra_mipi_bif_dev *mipi_bif_dev;
+ struct tegra_mipi_bif_platform_data *plat = pdev->dev.platform_data;
+ struct resource *res;
+ struct clk *mipi_bif_clk;
+ void __iomem *base;
+ int irq;
+ int ret;
+
+ if (!plat) {
+ dev_err(&pdev->dev, "no platform data?\n");
+ return -ENODEV;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no mem resource\n");
+ return -EINVAL;
+ }
+
+ base = devm_request_and_ioremap(&pdev->dev, res);
+ if (!base) {
+ dev_err(&pdev->dev, "Cannot request/ioremap MIPIBIF regs\n");
+ return -EADDRNOTAVAIL;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no irq resource\n");
+ return -EINVAL;
+ }
+ irq = res->start;
+
+ mipi_bif_clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(mipi_bif_clk)) {
+ dev_err(&pdev->dev, "missing mipi bif controller clock\n");
+ return PTR_ERR(mipi_bif_clk);
+ }
+
+ mipi_bif_dev = devm_kzalloc(&pdev->dev,
+ sizeof(struct tegra_mipi_bif_dev), GFP_KERNEL);
+ if (!mipi_bif_dev) {
+ dev_err(&pdev->dev, "Failed to allocate memory\n");
+ return -ENOMEM;
+ }
+
+ mipi_bif_dev->bus_clk_rate = plat->bus_clk_rate;
+ mipi_bif_dev->tauBIF = plat->tauBIF;
+ mipi_bif_dev->base = base;
+ mipi_bif_dev->mipi_bif_clk = mipi_bif_clk;
+ mipi_bif_dev->irq = irq;
+ mipi_bif_dev->cont_id = pdev->id;
+ mipi_bif_dev->dev = &pdev->dev;
+
+ ret = devm_request_irq(&pdev->dev, mipi_bif_dev->irq,
+ tegra_mipi_bif_isr, 0, pdev->name, mipi_bif_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq %i\n",
+ mipi_bif_dev->irq);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, mipi_bif_dev);
+
+ rt_mutex_init(&mipi_bif_dev->dev_lock);
+ spin_lock_init(&mipi_bif_dev->fifo_lock);
+ init_completion(&mipi_bif_dev->msg_complete);
+
+ mipi_bif_dev->adapter.algo = &tegra_mipi_bif_algo;
+ strlcpy(mipi_bif_dev->adapter.name, "Tegra MIPIBIF adapter",
+ sizeof(mipi_bif_dev->adapter.name));
+
+ mipi_bif_dev->adapter.dev.parent = &pdev->dev;
+ mipi_bif_dev->adapter.nr = plat->adapter_nr;
+ mipi_bif_set_adapdata(&mipi_bif_dev->adapter, mipi_bif_dev);
+
+ ret = mipi_bif_add_numbered_adapter(&mipi_bif_dev->adapter);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to add mipi_bif adapter\n");
+ return ret;
+ }
+ return 0;
+}
+
+static int tegra_mipi_bif_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct tegra_mipi_bif_dev *mipi_bif_dev = platform_get_drvdata(pdev);
+
+ rt_mutex_lock(&mipi_bif_dev->dev_lock);
+
+ mipi_bif_dev->is_suspended = false;
+
+ rt_mutex_unlock(&mipi_bif_dev->dev_lock);
+
+ return 0;
+}
+
+static int tegra_mipi_bif_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct tegra_mipi_bif_dev *mipi_bif_dev = platform_get_drvdata(pdev);
+
+ rt_mutex_lock(&mipi_bif_dev->dev_lock);
+
+ mipi_bif_dev->is_suspended = true;
+
+ rt_mutex_unlock(&mipi_bif_dev->dev_lock);
+
+ return 0;
+}
+
+static const struct dev_pm_ops tegra_mipi_bif_pm = {
+ .suspend = tegra_mipi_bif_suspend,
+ .resume = tegra_mipi_bif_resume,
+};
+
+static struct platform_driver tegra_mipi_bif_driver = {
+ .probe = tegra_mipi_bif_probe,
+ .remove = tegra_mipi_bif_remove,
+ .driver = {
+ .name = "tegra-mipi-bif",
+ .owner = THIS_MODULE,
+ .pm = &tegra_mipi_bif_pm
+ },
+};
+
+static int __init tegra_mipi_bif_init_driver(void)
+{
+ return platform_driver_register(&tegra_mipi_bif_driver);
+}
+
+static void __exit tegra_mipi_bif_exit_driver(void)
+{
+ platform_driver_unregister(&tegra_mipi_bif_driver);
+}
+
+subsys_initcall(tegra_mipi_bif_init_driver);
+module_exit(tegra_mipi_bif_exit_driver);
+
+MODULE_DESCRIPTION("nVidia Tegra MIPI BIF Controller driver");
+MODULE_AUTHOR("Chaitanya Bandi");
+MODULE_LICENSE("GPL v2");