diff options
author | Peng Du <pengdu@marvell.com> | 2015-06-26 15:35:42 +0800 |
---|---|---|
committer | Qing Zhu <qzhu@marvell.com> | 2015-07-08 21:14:46 +0800 |
commit | b2eed46d962146f825fb91d12a663f6208815dbd (patch) | |
tree | 6afa04b46d1d815e1b841a94b3f1fc1186695bdf | |
parent | a7c608f084df2436a9676cc624dcf2f1793ed8b2 (diff) | |
download | pxa-v3.14-b2eed46d962146f825fb91d12a663f6208815dbd.tar.gz |
arm64: add support for soc camera sp2529
Change-Id: I47983a674bac70e86710dbd0b5a09e34f61dee0b
Signed-off-by: Peng Du <pengdu@marvell.com>
-rw-r--r-- | arch/arm64/boot/dts/pxa1908.dtsi | 6 | ||||
-rw-r--r-- | arch/arm64/mach/helanx-dt.c | 5 | ||||
-rw-r--r-- | arch/arm64/mach/soc_camera_dkb.c | 183 | ||||
-rw-r--r-- | arch/arm64/mach/soc_camera_dkb.h | 6 |
4 files changed, 199 insertions, 1 deletions
diff --git a/arch/arm64/boot/dts/pxa1908.dtsi b/arch/arm64/boot/dts/pxa1908.dtsi index a6d0684c767..6b3f8cfaf62 100644 --- a/arch/arm64/boot/dts/pxa1908.dtsi +++ b/arch/arm64/boot/dts/pxa1908.dtsi @@ -977,6 +977,12 @@ reg = <0x2 0x0>; }; + soc-camera@3 { + compatible = "soc-camera-pdrv"; + status = "disabled"; + reg = <0x3 0x0>; + }; + plat_cam { compatible = "marvell,platform-cam"; status = "disabled"; diff --git a/arch/arm64/mach/helanx-dt.c b/arch/arm64/mach/helanx-dt.c index 1245667c417..2f0b5bcccc0 100644 --- a/arch/arm64/mach/helanx-dt.c +++ b/arch/arm64/mach/helanx-dt.c @@ -55,7 +55,10 @@ static const struct of_dev_auxdata helanx_auxdata_lookup[] __initconst = { OF_DEV_AUXDATA("soc-camera-pdrv", 2, "soc-camera-pdrv.2", &soc_camera_desc_2), #endif - +#ifdef CONFIG_SOC_CAMERA_SP2529_ECS + OF_DEV_AUXDATA("soc-camera-pdrv", 3, "soc-camera-pdrv.3", + &soc_camera_desc_4), +#endif OF_DEV_AUXDATA("marvell,mmp-disp", 0xd420b000, "mmp-disp", NULL), #ifdef CONFIG_SD8XXX_RFKILL OF_DEV_AUXDATA("mrvl,sd8x-rfkill", 0, "sd8x-rfkill", NULL), diff --git a/arch/arm64/mach/soc_camera_dkb.c b/arch/arm64/mach/soc_camera_dkb.c index 5350f8c8394..f06ccf13a4e 100644 --- a/arch/arm64/mach/soc_camera_dkb.c +++ b/arch/arm64/mach/soc_camera_dkb.c @@ -786,3 +786,186 @@ struct soc_camera_desc soc_camera_desc_2 = { }, }; #endif +#ifdef CONFIG_SOC_CAMERA_SP2529_ECS +static int sp2529_sensor_power(struct device *dev, int on) +{ + int cam_enable, cam_reset; + int ret; + + /* Get the regulators and never put it */ + /* + * The regulators is for sensor and should be in sensor driver + * As SoC camera does not support device tree, leave it here + */ + mclk = devm_clk_get(dev, "SC2MCLK"); + if (IS_ERR(mclk)) + return PTR_ERR(mclk); + if (!avdd_2v8) { + avdd_2v8 = regulator_get(dev, "avdd_2v8"); + if (IS_ERR(avdd_2v8)) { + dev_warn(dev, "Failed to get regulator avdd_2v8\n"); + avdd_2v8 = NULL; + } + } + + if (!dovdd_1v8) { + dovdd_1v8 = regulator_get(dev, "dovdd_1v8"); + if (IS_ERR(dovdd_1v8)) { + dev_warn(dev, "Failed to get regulator dovdd_1v8\n"); + dovdd_1v8 = NULL; + } + } + + if (!af_2v8) { + af_2v8 = regulator_get(dev, "af_2v8"); + if (IS_ERR(af_2v8)) { + dev_warn(dev, "Failed to get regulator af_2v8\n"); + af_2v8 = NULL; + } + } + + if (!dvdd_1v2) { + dvdd_1v2 = regulator_get(dev, "dvdd_1v2"); + if (IS_ERR(dvdd_1v2)) { + dev_warn(dev, "Failed to get regulator dvdd_1v2\n"); + dvdd_1v2 = NULL; + } + } + + cam_enable = of_get_named_gpio(dev->of_node, "pwdn-gpios", 0); + if (gpio_is_valid(cam_enable)) { + if (gpio_request(cam_enable, "CAM2_POWER")) { + dev_err(dev, "Request GPIO %d failed\n", cam_enable); + goto cam_enable_failed; + } + } else { + dev_err(dev, "invalid pwdn gpio %d\n", cam_enable); + goto cam_enable_failed; + } + + cam_reset = of_get_named_gpio(dev->of_node, "reset-gpios", 0); + if (gpio_is_valid(cam_reset)) { + if (gpio_request(cam_reset, "CAM2_RESET")) { + dev_err(dev, "Request GPIO %d failed\n", cam_reset); + goto cam_reset_failed; + } + } else { + dev_err(dev, "invalid pwdn gpio %d\n", cam_reset); + goto cam_reset_failed; + } + + if (on) { + gpio_direction_output(cam_enable, 0); + usleep_range(500, 1000); + + if (avdd_2v8) { + regulator_set_voltage(avdd_2v8, 2800000, 2800000); + ret = regulator_enable(avdd_2v8); + if (ret) + goto cam_regulator_enable_failed; + } + + if (af_2v8) { + regulator_set_voltage(af_2v8, 2800000, 2800000); + ret = regulator_enable(af_2v8); + if (ret) + goto cam_regulator_enable_failed; + } + usleep_range(500, 1000); + + if (dovdd_1v8) { + regulator_set_voltage(dovdd_1v8, + 1800000, 1800000); + ret = regulator_enable(dovdd_1v8); + if (ret) + goto cam_regulator_enable_failed; + } + + if (dvdd_1v2) { + regulator_set_voltage(dvdd_1v2, + 1200000, 1200000); + ret = regulator_enable(dvdd_1v2); + if (ret) + goto cam_regulator_enable_failed; + } + + clk_set_rate(mclk, 26000000); + clk_prepare_enable(mclk); + gpio_direction_output(cam_reset, 0); + usleep_range(5000, 20000); + gpio_direction_output(cam_enable, 1); + usleep_range(5000, 20000); + gpio_direction_output(cam_enable, 0); + usleep_range(5000, 20000); + gpio_direction_output(cam_reset, 1); + usleep_range(5000, 20000); + } else { + gpio_direction_output(cam_reset, 0); + usleep_range(5000, 20000); + gpio_direction_output(cam_enable, 0); + usleep_range(5000, 20000); + gpio_direction_output(cam_enable, 1); + clk_disable_unprepare(mclk); + devm_clk_put(dev, mclk); + if (dovdd_1v8) + regulator_disable(dovdd_1v8); + if (dvdd_1v2) + regulator_disable(dvdd_1v2); + if (avdd_2v8) + regulator_disable(avdd_2v8); + if (af_2v8) + regulator_disable(af_2v8); + + } + gpio_free(cam_enable); + gpio_free(cam_reset); + + return 0; + +cam_reset_failed: + gpio_free(cam_enable); +cam_enable_failed: + ret = -EIO; +cam_regulator_enable_failed: + if (dvdd_1v2) + regulator_put(dvdd_1v2); + dvdd_1v2 = NULL; + if (af_2v8) + regulator_put(af_2v8); + af_2v8 = NULL; + if (dovdd_1v8) + regulator_put(dovdd_1v8); + dovdd_1v8 = NULL; + if (avdd_2v8) + regulator_put(avdd_2v8); + avdd_2v8 = NULL; + + return ret; +} + +static struct sensor_board_data sp2529_data = { + .mount_pos = SENSOR_USED | SENSOR_POS_FRONT | SENSOR_RES_HIGH, + .bus_type = V4L2_MBUS_CSI2, + .bus_flag = V4L2_MBUS_CSI2_1_LANE, + .flags = V4L2_MBUS_CSI2_1_LANE, + .dphy = {0x1806, 0x00011, 0xe00}, +}; + +static struct i2c_board_info dkb_i2c_sp2529 = { + I2C_BOARD_INFO("sp2529", 0x30), +}; + +struct soc_camera_desc soc_camera_desc_4 = { + .subdev_desc = { + .power = sp2529_sensor_power, + .drv_priv = &sp2529_data, + .flags = 0, + }, + .host_desc = { + .bus_id = SP2529_CCIC_PORT, /* Default as ccic2 */ + .i2c_adapter_id = 0, + .board_info = &dkb_i2c_sp2529, + .module_name = "sp2529", + }, +}; +#endif diff --git a/arch/arm64/mach/soc_camera_dkb.h b/arch/arm64/mach/soc_camera_dkb.h index a8b0f5558cd..9abe7034b0c 100644 --- a/arch/arm64/mach/soc_camera_dkb.h +++ b/arch/arm64/mach/soc_camera_dkb.h @@ -19,6 +19,12 @@ extern struct soc_camera_desc soc_camera_desc_0; #endif +#ifdef CONFIG_SOC_CAMERA_SP2529_ECS +#define SP2529_PWDN_PIN 70 +#define SP2529_RESET_PIN 69 +#define SP2529_CCIC_PORT 1 +extern struct soc_camera_desc soc_camera_desc_4; +#endif #ifdef CONFIG_SOC_CAMERA_OV5640_ECS #define OV5640_PWDN_PIN_1L88 80 #define OV5640_RESET_PIN_1L88 67 |