summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYi Li <r80015@freescale.com>2012-01-02 14:01:46 -0600
committerFrank Li <Frank.Li@freescale.com>2012-01-11 11:42:45 +0800
commitdb95aa35ee1b1ebc4440b7dd9c7b23be953fac86 (patch)
treed89d7d2db937a3f7289e51f7ce6da9cbc6d6a8fc
parent953fe3a3f6c29a71820f31c02b1c06e0ab9806e2 (diff)
ENGR00169489-1 Add OV5642 csi camera support for i.mx6 sabre-lite board.
Add OV5642 csi camera support for i.mx6 sabre-lite board Signed-off-by: Yi Li <R80015@freescale.com>
-rwxr-xr-xarch/arm/mach-mx6/board-mx6q_sabrelite.c125
-rw-r--r--arch/arm/mach-mx6/clock.c114
-rw-r--r--arch/arm/mach-mx6/crm_regs.h4
3 files changed, 216 insertions, 27 deletions
diff --git a/arch/arm/mach-mx6/board-mx6q_sabrelite.c b/arch/arm/mach-mx6/board-mx6q_sabrelite.c
index 9d688153d59f..f723048d4f5c 100755
--- a/arch/arm/mach-mx6/board-mx6q_sabrelite.c
+++ b/arch/arm/mach-mx6/board-mx6q_sabrelite.c
@@ -90,6 +90,8 @@
#define MX6Q_SABRELITE_HOME_KEY IMX_GPIO_NR(2, 4)
#define MX6Q_SABRELITE_VOL_UP_KEY IMX_GPIO_NR(7, 13)
#define MX6Q_SABRELITE_VOL_DOWN_KEY IMX_GPIO_NR(4, 5)
+#define MX6Q_SABRELITE_CSI0_RST IMX_GPIO_NR(1, 8)
+#define MX6Q_SABRELITE_CSI0_PWN IMX_GPIO_NR(1, 6)
#define MX6Q_SABRELITE_SD3_WP_PADCFG (PAD_CTL_PKE | PAD_CTL_PUE | \
PAD_CTL_PUS_22K_UP | PAD_CTL_SPEED_MED | \
@@ -212,29 +214,6 @@ static iomux_v3_cfg_t mx6q_sabrelite_pads[] = {
MX6Q_PAD_GPIO_5__I2C3_SCL, /* GPIO1[5] - J7 - Display card */
MX6Q_PAD_GPIO_16__I2C3_SDA, /* GPIO7[11] - J15 - RGB connector */
- /* IPU1 Camera */
- MX6Q_PAD_CSI0_DAT8__IPU1_CSI0_D_8,
- MX6Q_PAD_CSI0_DAT9__IPU1_CSI0_D_9,
- MX6Q_PAD_CSI0_DAT10__IPU1_CSI0_D_10,
- MX6Q_PAD_CSI0_DAT11__IPU1_CSI0_D_11,
- MX6Q_PAD_CSI0_DAT12__IPU1_CSI0_D_12,
- MX6Q_PAD_CSI0_DAT13__IPU1_CSI0_D_13,
- MX6Q_PAD_CSI0_DAT14__IPU1_CSI0_D_14,
- MX6Q_PAD_CSI0_DAT15__IPU1_CSI0_D_15,
- MX6Q_PAD_CSI0_DAT16__IPU1_CSI0_D_16,
- MX6Q_PAD_CSI0_DAT17__IPU1_CSI0_D_17,
- MX6Q_PAD_CSI0_DAT18__IPU1_CSI0_D_18,
- MX6Q_PAD_CSI0_DAT19__IPU1_CSI0_D_19,
- MX6Q_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN,
- MX6Q_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC,
- MX6Q_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK,
- MX6Q_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC,
- MX6Q_PAD_GPIO_6__GPIO_1_6, /* J5 - Camera GP */
- MX6Q_PAD_GPIO_8__GPIO_1_8, /* J5 - Camera Reset */
- MX6Q_PAD_SD1_DAT0__GPIO_1_16, /* J5 - Camera GP */
- MX6Q_PAD_NANDF_D5__GPIO_2_5, /* J16 - MIPI GP */
- MX6Q_PAD_NANDF_WP_B__GPIO_6_9, /* J16 - MIPI GP */
-
/* DISPLAY */
MX6Q_PAD_DI0_DISP_CLK__IPU1_DI0_DISP_CLK,
MX6Q_PAD_DI0_PIN15__IPU1_DI0_PIN15, /* DE */
@@ -318,6 +297,31 @@ static iomux_v3_cfg_t mx6q_sabrelite_pads[] = {
MX6Q_PAD_NANDF_D7__GPIO_2_7, /* SD4_WP */
};
+static iomux_v3_cfg_t mx6q_sabrelite_csi0_sensor_pads[] = {
+ /* IPU1 Camera */
+ MX6Q_PAD_CSI0_DAT8__IPU1_CSI0_D_8,
+ MX6Q_PAD_CSI0_DAT9__IPU1_CSI0_D_9,
+ MX6Q_PAD_CSI0_DAT10__IPU1_CSI0_D_10,
+ MX6Q_PAD_CSI0_DAT11__IPU1_CSI0_D_11,
+ MX6Q_PAD_CSI0_DAT12__IPU1_CSI0_D_12,
+ MX6Q_PAD_CSI0_DAT13__IPU1_CSI0_D_13,
+ MX6Q_PAD_CSI0_DAT14__IPU1_CSI0_D_14,
+ MX6Q_PAD_CSI0_DAT15__IPU1_CSI0_D_15,
+ MX6Q_PAD_CSI0_DAT16__IPU1_CSI0_D_16,
+ MX6Q_PAD_CSI0_DAT17__IPU1_CSI0_D_17,
+ MX6Q_PAD_CSI0_DAT18__IPU1_CSI0_D_18,
+ MX6Q_PAD_CSI0_DAT19__IPU1_CSI0_D_19,
+ MX6Q_PAD_CSI0_DATA_EN__IPU1_CSI0_DATA_EN,
+ MX6Q_PAD_CSI0_MCLK__IPU1_CSI0_HSYNC,
+ MX6Q_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK,
+ MX6Q_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC,
+ MX6Q_PAD_GPIO_6__GPIO_1_6, /* J5 - Camera GP */
+ MX6Q_PAD_GPIO_8__GPIO_1_8, /* J5 - Camera Reset */
+ MX6Q_PAD_SD1_DAT0__GPIO_1_16, /* J5 - Camera GP */
+ MX6Q_PAD_NANDF_D5__GPIO_2_5, /* J16 - MIPI GP */
+ MX6Q_PAD_NANDF_WP_B__GPIO_6_9, /* J16 - MIPI GP */
+};
+
#define MX6Q_USDHC_PAD_SETTING(id, speed) \
mx6q_sd##id##_##speed##mhz[] = { \
MX6Q_PAD_SD##id##_CLK__USDHC##id##_CLK_##speed##MHZ, \
@@ -550,10 +554,55 @@ static struct i2c_board_info mxc_i2c0_board_info[] __initdata = {
},
};
+
+static void mx6q_csi0_io_init(void)
+{
+ mxc_iomux_v3_setup_multiple_pads(mx6q_sabrelite_csi0_sensor_pads,
+ ARRAY_SIZE(mx6q_sabrelite_csi0_sensor_pads));
+
+ /* Camera power down */
+ gpio_request(MX6Q_SABRELITE_CSI0_PWN, "cam-pwdn");
+ gpio_direction_output(MX6Q_SABRELITE_CSI0_PWN, 1);
+ msleep(1);
+ gpio_set_value(MX6Q_SABRELITE_CSI0_PWN, 0);
+
+ /* Camera reset */
+ gpio_request(MX6Q_SABRELITE_CSI0_RST, "cam-reset");
+ gpio_direction_output(MX6Q_SABRELITE_CSI0_RST, 1);
+
+ gpio_set_value(MX6Q_SABRELITE_CSI0_RST, 0);
+ msleep(1);
+ gpio_set_value(MX6Q_SABRELITE_CSI0_RST, 1);
+
+ /* For MX6Q GPR1 bit19 and bit20 meaning:
+ * Bit19: 0 - Enable mipi to IPU1 CSI0
+ * virtual channel is fixed to 0
+ * 1 - Enable parallel interface to IPU1 CSI0
+ * Bit20: 0 - Enable mipi to IPU2 CSI1
+ * virtual channel is fixed to 3
+ * 1 - Enable parallel interface to IPU2 CSI1
+ * IPU1 CSI1 directly connect to mipi csi2,
+ * virtual channel is fixed to 1
+ * IPU2 CSI0 directly connect to mipi csi2,
+ * virtual channel is fixed to 2
+ */
+ mxc_iomux_set_gpr_register(1, 19, 1, 1);
+}
+
+static struct fsl_mxc_camera_platform_data camera_data = {
+ .mclk = 24000000,
+ .csi = 0,
+ .io_init = mx6q_csi0_io_init,
+};
+
static struct i2c_board_info mxc_i2c1_board_info[] __initdata = {
{
I2C_BOARD_INFO("mxc_hdmi_i2c", 0x50),
},
+ {
+ I2C_BOARD_INFO("ov5642", 0x3c),
+ .platform_data = (void *)&camera_data,
+ },
};
static struct i2c_board_info mxc_i2c2_board_info[] __initdata = {
@@ -771,8 +820,10 @@ static struct fsl_mxc_ldb_platform_data ldb_data = {
static struct imx_ipuv3_platform_data ipu_data[] = {
{
.rev = 4,
+ .csi_clk[0] = "clko2_clk",
}, {
.rev = 4,
+ .csi_clk[0] = "clko2_clk",
},
};
@@ -985,6 +1036,15 @@ static void __init fixup_mxc_board(struct machine_desc *desc, struct tag *tags,
{
}
+static struct mipi_csi2_platform_data mipi_csi2_pdata = {
+ .ipu_id = 0,
+ .csi_id = 0,
+ .v_channel = 0,
+ .lanes = 2,
+ .dphy_clk = "mipi_pllref_clk",
+ .pixel_clk = "emi_clk",
+};
+
/*!
* Board specific initialization.
*/
@@ -992,6 +1052,9 @@ static void __init mx6_sabrelite_board_init(void)
{
int i;
int ret;
+ struct clk *clko2;
+ struct clk *new_parent;
+ int rate;
mxc_iomux_v3_setup_multiple_pads(mx6q_sabrelite_pads,
ARRAY_SIZE(mx6q_sabrelite_pads));
@@ -1009,7 +1072,8 @@ static void __init mx6_sabrelite_board_init(void)
imx6q_add_lcdif(&lcdif_data);
imx6q_add_ldb(&ldb_data);
imx6q_add_v4l2_output(0);
-
+ imx6q_add_v4l2_capture(0);
+ imx6q_add_mipi_csi2(&mipi_csi2_pdata);
imx6q_add_imx_snvs_rtc();
imx6q_add_imx_i2c(0, &mx6q_sabrelite_i2c_data);
@@ -1071,6 +1135,19 @@ static void __init mx6_sabrelite_board_init(void)
pr_err("failed to request flexcan1-gpios: %d\n", ret);
else
imx6q_add_flexcan0(&mx6q_sabrelite_flexcan0_pdata);
+
+ clko2 = clk_get(NULL, "clko2_clk");
+ if (IS_ERR(clko2))
+ pr_err("can't get CLKO2 clock.\n");
+
+ new_parent = clk_get(NULL, "osc_clk");
+ if (!IS_ERR(new_parent)) {
+ clk_set_parent(clko2, new_parent);
+ clk_put(new_parent);
+ }
+ rate = clk_round_rate(clko2, 24000000);
+ clk_set_rate(clko2, rate);
+ clk_enable(clko2);
}
extern void __iomem *twd_base;
diff --git a/arch/arm/mach-mx6/clock.c b/arch/arm/mach-mx6/clock.c
index 6b1fad161b41..e709b347c6a9 100644
--- a/arch/arm/mach-mx6/clock.c
+++ b/arch/arm/mach-mx6/clock.c
@@ -1,6 +1,6 @@
/*
- * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2012 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -4655,6 +4655,100 @@ static unsigned long _clk_clko_round_rate(struct clk *clk,
return parent_rate / div;
}
+static int _clk_clko2_set_parent(struct clk *clk, struct clk *parent)
+{
+ u32 sel, reg;
+
+ if (parent == &mmdc_ch0_axi_clk[0])
+ sel = 0;
+ else if (parent == &mmdc_ch1_axi_clk[0])
+ sel = 1;
+ else if (parent == &usdhc4_clk)
+ sel = 2;
+ else if (parent == &usdhc1_clk)
+ sel = 3;
+ else if (parent == &gpu2d_axi_clk)
+ sel = 4;
+ else if (parent == &ecspi_clk[0])
+ sel = 6;
+ else if (parent == &gpu3d_axi_clk)
+ sel = 7;
+ else if (parent == &usdhc3_clk)
+ sel = 8;
+ else if (parent == &pcie_clk[0])
+ sel = 9;
+ else if (parent == &ipu1_clk)
+ sel = 11;
+ else if (parent == &ipu2_clk)
+ sel = 12;
+ else if (parent == &vdo_axi_clk)
+ sel = 13;
+ else if (parent == &osc_clk)
+ sel = 14;
+ else if (parent == &gpu2d_core_clk[0])
+ sel = 15;
+ else if (parent == &gpu3d_core_clk[0])
+ sel = 16;
+ else if (parent == &usdhc2_clk)
+ sel = 17;
+ else if (parent == &ssi1_clk)
+ sel = 18;
+ else if (parent == &ssi2_clk)
+ sel = 19;
+ else if (parent == &ssi3_clk)
+ sel = 20;
+ else if (parent == &gpu3d_shader_clk)
+ sel = 21;
+ else if (parent == &can_clk_root)
+ sel = 23;
+ else if (parent == &ldb_di0_clk)
+ sel = 24;
+ else if (parent == &ldb_di1_clk)
+ sel = 25;
+ else if (parent == &esai_clk)
+ sel = 26;
+ else if (parent == &uart_clk[0])
+ sel = 28;
+ else if (parent == &spdif0_clk[0])
+ sel = 29;
+ else if (parent == &hsi_tx_clk[0])
+ sel = 31;
+ else
+ return -EINVAL;
+
+ reg = __raw_readl(MXC_CCM_CCOSR);
+ reg &= ~MXC_CCM_CCOSR_CKO2_SEL_MASK;
+ reg |= sel << MXC_CCM_CCOSR_CKO2_SEL_OFFSET;
+ __raw_writel(reg, MXC_CCM_CCOSR);
+ return 0;
+}
+
+static unsigned long _clk_clko2_get_rate(struct clk *clk)
+{
+ u32 reg = __raw_readl(MXC_CCM_CCOSR);
+ u32 div = ((reg & MXC_CCM_CCOSR_CKO2_DIV_MASK) >>
+ MXC_CCM_CCOSR_CKO2_DIV_OFFSET) + 1;
+ return clk_get_rate(clk->parent) / div;
+}
+
+static int _clk_clko2_set_rate(struct clk *clk, unsigned long rate)
+{
+ u32 reg;
+ u32 parent_rate = clk_get_rate(clk->parent);
+ u32 div = parent_rate / rate;
+
+ if (div == 0)
+ div++;
+ if (((parent_rate / div) != rate) || (div > 8))
+ return -EINVAL;
+
+ reg = __raw_readl(MXC_CCM_CCOSR);
+ reg &= ~MXC_CCM_CCOSR_CKO2_DIV_MASK;
+ reg |= (div - 1) << MXC_CCM_CCOSR_CKO2_DIV_OFFSET;
+ __raw_writel(reg, MXC_CCM_CCOSR);
+ return 0;
+}
+
static struct clk clko_clk = {
__INIT_CLK_DEBUG(clko_clk)
.parent = &pll2_528_bus_main_clk,
@@ -4668,6 +4762,19 @@ static struct clk clko_clk = {
.round_rate = _clk_clko_round_rate,
};
+static struct clk clko2_clk = {
+ __INIT_CLK_DEBUG(clko2_clk)
+ .parent = &usdhc4_clk,
+ .enable = _clk_enable1,
+ .enable_reg = MXC_CCM_CCOSR,
+ .enable_shift = MXC_CCM_CCOSR_CKO2_EN_OFFSET,
+ .disable = _clk_disable1,
+ .set_parent = _clk_clko2_set_parent,
+ .set_rate = _clk_clko2_set_rate,
+ .get_rate = _clk_clko2_get_rate,
+ .round_rate = _clk_clko_round_rate,
+};
+
static struct clk perfmon0_clk = {
__INIT_CLK_DEBUG(perfmon0_clk)
.parent = &mmdc_ch0_axi_clk[0],
@@ -4820,6 +4927,7 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK(NULL, NULL, aips_tz2_clk),
_REGISTER_CLOCK(NULL, NULL, aips_tz1_clk),
_REGISTER_CLOCK(NULL, "clko_clk", clko_clk),
+ _REGISTER_CLOCK(NULL, "clko2_clk", clko2_clk),
_REGISTER_CLOCK("mxs-perfmon.0", "perfmon", perfmon0_clk),
_REGISTER_CLOCK("mxs-perfmon.1", "perfmon", perfmon1_clk),
_REGISTER_CLOCK("mxs-perfmon.2", "perfmon", perfmon2_clk),
@@ -4909,6 +5017,10 @@ int __init mx6_clocks_init(unsigned long ckil, unsigned long osc,
clk_set_parent(&gpu3d_core_clk[0], &mmdc_ch0_axi_clk[0]);
clk_set_rate(&gpu3d_core_clk[0], 528000000);
+ /* PCLK camera - J5 */
+ clk_set_parent(&clko2_clk, &osc_clk);
+ clk_set_rate(&clko2_clk, 2400000);
+
/*
* FIXME: asrc needs to use asrc_serial(spdif1) clock to do sample
* rate convertion and this clock frequency can not be too high, set
diff --git a/arch/arm/mach-mx6/crm_regs.h b/arch/arm/mach-mx6/crm_regs.h
index 7ae4396bab01..7f54cab160ac 100644
--- a/arch/arm/mach-mx6/crm_regs.h
+++ b/arch/arm/mach-mx6/crm_regs.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2011 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2012 Freescale Semiconductor, Inc. All Rights Reserved.
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
@@ -448,7 +448,7 @@
#define MXC_CCM_CIMR_MASK_LRF_PLL (1)
/* Define the bits in register CCOSR */
-#define MXC_CCM_CCOSR_CKO2_EN_OFFSET (1 << 24)
+#define MXC_CCM_CCOSR_CKO2_EN_OFFSET (24)
#define MXC_CCM_CCOSR_CKO2_DIV_MASK (0x7 << 21)
#define MXC_CCM_CCOSR_CKO2_DIV_OFFSET (21)
#define MXC_CCM_CCOSR_CKO2_SEL_OFFSET (16)