Hi Krzysztof,
see following steps, please !
-----------------
/* the following codes are based on MCIMX6Q-SabreSDP board, see board-mx6q_sabresd.c & board-mx6q_sabresd.c file */
Step 1: /* IOMUX csi0 port : adding them to .h file*/
static iomux_v3_cfg_t mx6q_sabresd_csi0_sensor_pads[] = {
/* IPU1 Camera */
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_MCLK__IPU1_CSI0_HSYNC,
MX6Q_PAD_CSI0_PIXCLK__IPU1_CSI0_PIXCLK,
MX6Q_PAD_CSI0_VSYNC__IPU1_CSI0_VSYNC,
MX6Q_PAD_GPIO_3__CCM_CLKO2, /* using CLKO2 camera clk */
MX6Q_PAD_GPIO_7__GPIO_1_7, /* camera PWDN */
MX6Q_PAD_GPIO_8__GPIO_1_8, /* camera RESET */
};
Step 2:/* add the following code to board-mx6q_sabresd.c */
...
#define SABRESD_CSI0_RST IMX_GPIO_NR(1, 8) /* assume reset pin is GPIO1_8 */
#define SABRESD_CSI0_PWN IMX_GPIO_NR(1, 7) /* assume pwdn pin is GPIO1_7 */
...
static void mx6q_csi0_io_init(void)
{
/* cpu is i.MX6q */
mxc_iomux_v3_setup_multiple_pads(mx6q_sabresd_csi0_sensor_pads,ARRAY_SIZE(mx6q_sabresd_csi0_sensor_pads));
/* Camera reset */
gpio_request(SABRESD_CSI0_RST, "cam-reset");
gpio_direction_output(SABRESD_CSI0_RST, 1);
/* Camera power down */
gpio_request(SABRESD_CSI0_PWN, "cam-pwdn");
gpio_direction_output(SABRESD_CSI0_PWN, 1);
msleep(5);
gpio_set_value(SABRESD_CSI0_PWN, 0);
msleep(5);
gpio_set_value(SABRESD_CSI0_RST, 0);
msleep(1);
gpio_set_value(SABRESD_CSI0_RST, 1);
msleep(5);
gpio_set_value(SABRESD_CSI0_PWN, 1);
/* CPU is i.MX6Q*/
mxc_iomux_set_gpr_register(1, 19, 1, 1);
}
static void mx6q_csi0_cam_powerdown(int powerdown)
{
if (powerdown)
gpio_set_value(SABRESD_CSI0_PWN, 1);
else
gpio_set_value(SABRESD_CSI0_PWN, 0);
msleep(2);
}
static struct fsl_mxc_camera_platform_data camera_data = {
.mclk = 24000000,
.mclk_source = 0,
.csi = 0,
.io_init = mx6q_csi0_io_init,
.pwdn = mx6q_csi0_cam_powerdown,
};
Step 3: /* add ov2640 to i2c3 bus */
static struct i2c_board_info mxc_i2c2_board_info[] __initdata = {
{
I2C_BOARD_INFO("ov2640", 0x30),
.platform_data = (void *)&camera_data,
},
};
Step 4: /* add ov2640 to board init */
static void __init mx6_sabresd_board_init(void)
{
......
imx6q_add_imx_i2c(2, &mx6q_sabresd_i2c_data);
i2c_register_board_info(2, mxc_i2c2_board_info,ARRAY_SIZE(mxc_i2c2_board_info));
......
/* enable CLKO2 for ov2640*/
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);
......
}
step 5: /* add the following code to ov2640.c */
static int ov2640_probe(struct i2c_client *client,const struct i2c_device_id *id)
{
int retval;
u8 chip_id_high, chip_id_low;
...
if (plat_data->gpo_regulator) {
gpo_regulator =
regulator_get(&client->dev, plat_data->gpo_regulator);
if (!IS_ERR(gpo_regulator)) {
if (regulator_enable(gpo_regulator) != 0) {
pr_err("%s:gpo3 set voltage error\n", __func__);
goto err4;
} else {
dev_dbg(&client->dev,
"%s:gpo3 set voltage ok\n", __func__);
}
} else
gpo_regulator = NULL;
}
/*------------------ and the following code--------------------- */
if (plat_data->io_init)
plat_data->io_init();
if (plat_data->pwdn)
plat_data->pwdn(0); /* ov2640 power down */
/* read product ID */
chip_id_high = i2c_smbus_read_byte_data(client,0x0a); /* read product ID MSB */
if (chip_id_high != 0x26) {
pr_warning("camera ov2640 is not found\n");
retval = -ENODEV;
goto err4;
}
chip_id_low = i2c_smbus_read_byte_data(client,0x0b); /* read product ID LSB */
if (chip_id_low != 0x41) {
pr_warning("camera ov2640 is not found\n");
retval = -ENODEV;
goto err4;
}
if (plat_data->pwdn)
plat_data->pwdn(1); /* ov2640 power on */
/*--------- extra code ended--------------------- */
/* This function attaches this structure to the /dev/video0 device.
* The pointer in priv points to the ov2640_data structure here.*/
ov2640_int_device.priv = &ov2640_data;
...
}
step 6: /* when running make menuconfig, select ov2640 dirver module to linux image */
step 7: /* modify init.rc */
setprop back_camera_name ov2640
step 8: /* modify camera HAL */
in android BSP, camera HAL source code is at path ~/myandroid/hardware/imx/mx6/libcamera2
customer can add ov2640 device to here by referring to other example devices , such as ov5642 etc.
-----------------------------------
Regards,
Weidong