From db95aa35ee1b1ebc4440b7dd9c7b23be953fac86 Mon Sep 17 00:00:00 2001 From: Yi Li Date: Mon, 2 Jan 2012 14:01:46 -0600 Subject: 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 --- arch/arm/mach-mx6/board-mx6q_sabrelite.c | 125 +++++++++++++++++++++++++------ arch/arm/mach-mx6/clock.c | 114 +++++++++++++++++++++++++++- arch/arm/mach-mx6/crm_regs.h | 4 +- 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 9d688153d59..f723048d4f5 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 6b1fad161b4..e709b347c6a 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 7ae4396bab0..7f54cab160a 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) -- cgit v1.2.3