aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeng Du <pengdu@marvell.com>2015-06-26 15:35:42 +0800
committerQing Zhu <qzhu@marvell.com>2015-07-08 21:14:46 +0800
commitb2eed46d962146f825fb91d12a663f6208815dbd (patch)
tree6afa04b46d1d815e1b841a94b3f1fc1186695bdf
parenta7c608f084df2436a9676cc624dcf2f1793ed8b2 (diff)
downloadpxa-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.dtsi6
-rw-r--r--arch/arm64/mach/helanx-dt.c5
-rw-r--r--arch/arm64/mach/soc_camera_dkb.c183
-rw-r--r--arch/arm64/mach/soc_camera_dkb.h6
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