msm: camera: Initial version of LED Driver on 8960

Initial version of LED driver for Cdp & Mdp comprise

- Enable SC628A LED Driver chip for 8960.
- Configure SX150X Gpio Expander chip.
- Restructure  Camera Gpio Mux settings table
which will later be used to toggle function select for LED Flash
between Mdp & Cdp.

Signed-off-by: Nishant Pandit <npandit@codeaurora.org>
diff --git a/arch/arm/mach-msm/board-msm7x27a.c b/arch/arm/mach-msm/board-msm7x27a.c
index 4e4df0d..4248e87 100644
--- a/arch/arm/mach-msm/board-msm7x27a.c
+++ b/arch/arm/mach-msm/board-msm7x27a.c
@@ -2122,9 +2122,9 @@
 
 #ifdef CONFIG_MSM_CAMERA_FLASH
 static struct msm_camera_sensor_flash_src msm_flash_src = {
-	.flash_sr_type = MSM_CAMERA_FLASH_SRC_CURRENT_DRIVER,
-	._fsrc.current_driver_src.led1 = GPIO_CAM_GP_LED_EN1,
-	._fsrc.current_driver_src.led2 = GPIO_CAM_GP_LED_EN2,
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
+	._fsrc.ext_driver_src.led_en = GPIO_CAM_GP_LED_EN1,
+	._fsrc.ext_driver_src.led_flash_en = GPIO_CAM_GP_LED_EN2,
 };
 #endif
 
@@ -2466,7 +2466,7 @@
 	},
 	#endif
 	{
-		I2C_BOARD_INFO("sc628a", 0x37),
+		I2C_BOARD_INFO("sc628a", 0x6E),
 	},
 };
 #endif
diff --git a/arch/arm/mach-msm/board-msm8960.c b/arch/arm/mach-msm/board-msm8960.c
index 386e3b1..9c21d01 100644
--- a/arch/arm/mach-msm/board-msm8960.c
+++ b/arch/arm/mach-msm/board-msm8960.c
@@ -459,100 +459,101 @@
 		},
 	},
 };
+static struct gpiomux_setting cam_settings[4] = {
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*suspend*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_DOWN,
+	},
 
-static struct gpiomux_setting cam_suspend_cfg = {
-	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_2MA,
-	.pull = GPIOMUX_PULL_DOWN,
+	{
+		.func = GPIOMUX_FUNC_1, /*active 1*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_GPIO, /*active 2*/
+		.drv = GPIOMUX_DRV_2MA,
+		.pull = GPIOMUX_PULL_NONE,
+	},
+
+	{
+		.func = GPIOMUX_FUNC_1, /*active 3*/
+		.drv = GPIOMUX_DRV_8MA,
+		.pull = GPIOMUX_PULL_UP,
+	},
 };
 
-static struct gpiomux_setting cam_active_1_cfg = {
-	.func = GPIOMUX_FUNC_1,
-	.drv = GPIOMUX_DRV_2MA,
-	.pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting cam_active_2_cfg = {
-	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_2MA,
-	.pull = GPIOMUX_PULL_NONE,
-};
-
-static struct gpiomux_setting cam_active_3_cfg = {
-	.func = GPIOMUX_FUNC_1,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_UP,
-};
-
-static struct msm_gpiomux_config msm8960_cam_configs[] __initdata = {
+static struct msm_gpiomux_config msm8960_cam_configs[] = {
 	{
 		.gpio = 2,
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_active_2_cfg,
-			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
 		},
 	},
 	{
 		.gpio = 3,
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_active_1_cfg,
-			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+			[GPIOMUX_ACTIVE]    = &cam_settings[1],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
 		},
 	},
 	{
 		.gpio = 4,
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_active_1_cfg,
-			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+			[GPIOMUX_ACTIVE]    = &cam_settings[1],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
 		},
 	},
 	{
 		.gpio = 5,
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_active_1_cfg,
-			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+			[GPIOMUX_ACTIVE]    = &cam_settings[1],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
 		},
 	},
 	{
 		.gpio = 18,
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_active_3_cfg,
-			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
 		},
 	},
 	{
 		.gpio = 19,
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_active_3_cfg,
-			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
 		},
 	},
 	{
 		.gpio = 20,
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_active_3_cfg,
-			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
 		},
 	},
 	{
 		.gpio = 21,
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_active_3_cfg,
-			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+			[GPIOMUX_ACTIVE]    = &cam_settings[3],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
 		},
 	},
 	{
 		.gpio = 76,
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_active_2_cfg,
-			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
 		},
 	},
 	{
 		.gpio = 107,
 		.settings = {
-			[GPIOMUX_ACTIVE]    = &cam_active_2_cfg,
-			[GPIOMUX_SUSPENDED] = &cam_suspend_cfg,
+			[GPIOMUX_ACTIVE]    = &cam_settings[2],
+			[GPIOMUX_SUSPENDED] = &cam_settings[0],
 		},
 	},
 };
@@ -622,16 +623,40 @@
 	SX150X_CAM,
 };
 
-static struct sx150x_platform_data sx150x_data[] __initdata = {
+static struct sx150x_platform_data sx150x_data[] = {
 	[SX150X_CAM] = {
 		.gpio_base         = GPIO_CAM_EXPANDER_BASE,
 		.oscio_is_gpo      = false,
 		.io_pullup_ena     = 0x0,
-		.io_pulldn_ena     = 0x0,
+		.io_pulldn_ena     = 0xc0,
 		.io_open_drain_ena = 0x0,
 		.irq_summary       = -1,
 	},
 };
+
+#endif
+
+#ifdef CONFIG_I2C
+
+#define MSM_8960_GSBI4_QUP_I2C_BUS_ID 4
+#define MSM_8960_GSBI3_QUP_I2C_BUS_ID 3
+
+#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
+
+static struct i2c_board_info cam_expander_i2c_info[] = {
+	{
+		I2C_BOARD_INFO("sx1508q", 0x22),
+		.platform_data = &sx150x_data[SX150X_CAM]
+	},
+};
+
+static struct msm_cam_expander_info cam_expander_info[] = {
+	{
+		cam_expander_i2c_info,
+		MSM_8960_GSBI4_QUP_I2C_BUS_ID,
+	},
+};
+#endif
 #endif
 
 #define MSM_PMEM_KERNEL_EBI1_SIZE  0x110C000
@@ -828,6 +853,18 @@
 	.irq = MSM_GPIO_TO_INT(VFE_CAMIF_TIMER3_GPIO_INT),
 };
 
+#ifdef CONFIG_MSM_CAMERA_FLASH
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+	.flash_sr_type = MSM_CAMERA_FLASH_SRC_EXT,
+	._fsrc.ext_driver_src.led_en = GPIO_CAM_GP_LED_EN1,
+	._fsrc.ext_driver_src.led_flash_en = GPIO_CAM_GP_LED_EN2,
+#if defined(CONFIG_I2C) && (defined(CONFIG_GPIO_SX150X) || \
+			defined(CONFIG_GPIO_SX150X_MODULE))
+	._fsrc.ext_driver_src.expander_info = cam_expander_info,
+#endif
+};
+#endif
+
 #ifdef CONFIG_IMX074
 static struct msm_camera_sensor_platform_info sensor_board_info = {
 	.mount_angle = 90
@@ -891,6 +928,9 @@
 #ifdef CONFIG_IMX074
 static struct msm_camera_sensor_flash_data flash_imx074 = {
 	.flash_type	= MSM_CAMERA_FLASH_LED,
+#ifdef CONFIG_MSM_CAMERA_FLASH
+	.flash_src	= &msm_flash_src
+#endif
 };
 
 static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
@@ -3216,8 +3256,6 @@
 #define I2C_RUMI (1 << 2)
 #define I2C_SIM  (1 << 3)
 #define I2C_FLUID (1 << 4)
-#define MSM_8960_GSBI4_QUP_I2C_BUS_ID 4
-#define MSM_8960_GSBI3_QUP_I2C_BUS_ID 3
 
 struct i2c_registry {
 	u8                     machs;
@@ -3226,15 +3264,6 @@
 	int                    len;
 };
 
-#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
-static struct i2c_board_info cam_expander_i2c_info[] __initdata = {
-	{
-		I2C_BOARD_INFO("sx1508q", 0x22),
-		.platform_data = &sx150x_data[SX150X_CAM]
-	},
-};
-#endif
-
 #ifdef CONFIG_MSM_CAMERA
 static struct i2c_board_info msm_camera_boardinfo[] __initdata = {
 #ifdef CONFIG_IMX074
@@ -3250,6 +3279,11 @@
 	{
 	I2C_BOARD_INFO("qs_mt9p017", 0x6C >> 1),
 	},
+#ifdef CONFIG_MSM_CAMERA_FLASH_SC628A
+	{
+	I2C_BOARD_INFO("sc628a", 0x6E),
+	},
+#endif
 };
 #endif
 
@@ -3286,14 +3320,6 @@
 		cyttsp_info,
 		ARRAY_SIZE(cyttsp_info),
 	},
-#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
-	{
-		I2C_SURF | I2C_FFA,
-		MSM_8960_GSBI4_QUP_I2C_BUS_ID,
-		cam_expander_i2c_info,
-		ARRAY_SIZE(cam_expander_i2c_info),
-	},
-#endif
 };
 #endif /* CONFIG_I2C */
 
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index dccdde9..53d56f9 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -61,6 +61,11 @@
 	uint32_t vfe_clk_rate;
 };
 
+struct msm_cam_expander_info {
+	struct i2c_board_info const *board_info;
+	int bus_id;
+};
+
 struct msm_camera_device_platform_data {
 	int (*camera_gpio_on) (void);
 	void (*camera_gpio_off)(void);
@@ -100,6 +105,8 @@
 #define MSM_CAMERA_FLASH_SRC_PMIC (0x00000001<<0)
 #define MSM_CAMERA_FLASH_SRC_PWM  (0x00000001<<1)
 #define MSM_CAMERA_FLASH_SRC_CURRENT_DRIVER	(0x00000001<<2)
+#define MSM_CAMERA_FLASH_SRC_EXT     (0x00000001<<3)
+
 
 struct msm_camera_sensor_flash_pmic {
 	uint8_t num_of_src;
@@ -123,8 +130,12 @@
 	uint32_t low_current;
 	uint32_t high_current;
 	const struct pmic8058_leds_platform_data *driver_channel;
-	uint32_t led1;
-	uint32_t led2;
+};
+
+struct msm_camera_sensor_flash_external {
+	uint32_t led_en;
+	uint32_t led_flash_en;
+	struct msm_cam_expander_info *expander_info;
 };
 
 struct msm_camera_sensor_flash_src {
@@ -135,6 +146,8 @@
 		struct msm_camera_sensor_flash_pwm pwm_src;
 		struct msm_camera_sensor_flash_current_driver
 			current_driver_src;
+		struct msm_camera_sensor_flash_external
+			ext_driver_src;
 	} _fsrc;
 };
 
diff --git a/drivers/media/video/msm/flash.c b/drivers/media/video/msm/flash.c
index cd81125..f1a24cc 100644
--- a/drivers/media/video/msm/flash.c
+++ b/drivers/media/video/msm/flash.c
@@ -22,21 +22,16 @@
 #include <mach/camera.h>
 #include <mach/gpio.h>
 
+struct i2c_client *sx150x_client;
 struct timer_list timer_flash;
-
+static struct msm_camera_sensor_info *sensor_data;
 enum msm_cam_flash_stat{
 	MSM_CAM_FLASH_OFF,
 	MSM_CAM_FLASH_ON,
 };
 
 #if defined CONFIG_MSM_CAMERA_FLASH_SC628A
-static struct sc628a_work_t *sc628a_flash;
 static struct i2c_client *sc628a_client;
-static DECLARE_WAIT_QUEUE_HEAD(sc628a_wait_queue);
-
-struct sc628a_work_t {
-	struct work_struct work;
-};
 
 static const struct i2c_device_id sc628a_i2c_id[] = {
 	{"sc628a", 0},
@@ -55,7 +50,7 @@
 		},
 	};
 	if (i2c_transfer(sc628a_client->adapter, msg, 1) < 0) {
-		pr_err("sc628a_i2c_txdata faild 0x%x\n", saddr);
+		CDBG("sc628a_i2c_txdata faild 0x%x\n", saddr);
 		return -EIO;
 	}
 
@@ -66,24 +61,21 @@
 {
 	int32_t rc = -EFAULT;
 	unsigned char buf[2];
+	if (!sc628a_client)
+		return  -ENOTSUPP;
 
 	memset(buf, 0, sizeof(buf));
 	buf[0] = waddr;
 	buf[1] = bdata;
 
-	rc = sc628a_i2c_txdata(sc628a_client->addr, buf, 2);
+	rc = sc628a_i2c_txdata(sc628a_client->addr>>1, buf, 2);
 	if (rc < 0) {
-		pr_err("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
+		CDBG("i2c_write_b failed, addr = 0x%x, val = 0x%x!\n",
 				waddr, bdata);
 	}
-	return rc;
-}
+	usleep_range(4000, 5000);
 
-static int sc628a_init_client(struct i2c_client *client)
-{
-	/* Initialize the MSM_CAMI2C Chip */
-	init_waitqueue_head(&sc628a_wait_queue);
-	return 0;
+	return rc;
 }
 
 static int sc628a_i2c_probe(struct i2c_client *client,
@@ -97,19 +89,8 @@
 		goto probe_failure;
 	}
 
-	sc628a_flash = kzalloc(sizeof(struct sc628a_work_t), GFP_KERNEL);
-	if (!sc628a_flash) {
-		pr_err("kzalloc failed.\n");
-		rc = -ENOMEM;
-		goto probe_failure;
-	}
-
-	i2c_set_clientdata(client, sc628a_flash);
-	sc628a_init_client(client);
 	sc628a_client = client;
 
-	msleep(50);
-
 	CDBG("sc628a_probe successed! rc = %d\n", rc);
 	return 0;
 
@@ -219,6 +200,9 @@
 					rc);
 		}
 		break;
+	case MSM_CAMERA_LED_INIT:
+	case MSM_CAMERA_LED_RELEASE:
+		break;
 
 	default:
 		rc = -EFAULT;
@@ -226,39 +210,101 @@
 	}
 	CDBG("msm_camera_flash_led_pmic8058: return %d\n", rc);
 #endif /* CONFIG_LEDS_PMIC8058 */
+	return rc;
+}
+int msm_camera_flash_external(
+	struct msm_camera_sensor_flash_external *external,
+	unsigned led_state)
+{
+	int rc = 0;
+
 #if defined CONFIG_MSM_CAMERA_FLASH_SC628A
-	if (!sc628a_client) {
-		rc = i2c_add_driver(&sc628a_i2c_driver);
-		if (rc < 0 || sc628a_client == NULL) {
-			rc = -ENOTSUPP;
-			pr_err("I2C add driver failed");
-			return rc;
-		}
-		rc = gpio_request(current_driver->led1, "sc628a");
-		if (!rc) {
-			gpio_direction_output(current_driver->led1, 0);
-			gpio_set_value_cansleep(current_driver->led1, 1);
-		} else
-			i2c_del_driver(&sc628a_i2c_driver);
-		rc = gpio_request(current_driver->led2, "sc628a");
-		if (!rc) {
-			gpio_direction_output(current_driver->led2, 0);
-			gpio_set_value_cansleep(current_driver->led2, 1);
-		} else {
-			i2c_del_driver(&sc628a_i2c_driver);
-			gpio_free(current_driver->led1);
-		}
-	}
 	switch (led_state) {
+
+	case MSM_CAMERA_LED_INIT:
+		if (!sc628a_client) {
+			rc = i2c_add_driver(&sc628a_i2c_driver);
+			if (rc < 0 || sc628a_client == NULL) {
+				rc = -ENOTSUPP;
+				CDBG("I2C add driver failed");
+				return rc;
+			}
+		}
+#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
+		if (external->expander_info && !sx150x_client) {
+			struct i2c_adapter *adapter =
+			i2c_get_adapter(external->expander_info->bus_id);
+			if (adapter)
+				sx150x_client = i2c_new_device(adapter,
+					external->expander_info->board_info);
+			if (!sx150x_client || !adapter) {
+				rc = -ENOTSUPP;
+				i2c_del_driver(&sc628a_i2c_driver);
+				sc628a_client = NULL;
+				return rc;
+			}
+		}
+#endif
+		rc = gpio_request(external->led_en, "sc628a");
+		if (!rc) {
+			gpio_direction_output(external->led_en, 1);
+		} else {
+			goto err1;
+		}
+		rc = gpio_request(external->led_flash_en, "sc628a");
+		if (!rc) {
+			gpio_direction_output(external->led_flash_en, 1);
+			break;
+		}
+
+		gpio_set_value_cansleep(external->led_en, 0);
+		gpio_free(external->led_en);
+
+err1:
+		i2c_del_driver(&sc628a_i2c_driver);
+		sc628a_client = NULL;
+
+		break;
+
+	case MSM_CAMERA_LED_RELEASE:
+		if (sc628a_client) {
+			gpio_set_value_cansleep(external->led_en, 0);
+			gpio_free(external->led_en);
+			gpio_set_value_cansleep(external->led_flash_en, 0);
+			gpio_free(external->led_flash_en);
+		}
+#if defined(CONFIG_GPIO_SX150X) || defined(CONFIG_GPIO_SX150X_MODULE)
+		if (external->expander_info && sx150x_client) {
+			i2c_unregister_device(sx150x_client);
+			sx150x_client = NULL;
+		}
+#endif
+		break;
+
 	case MSM_CAMERA_LED_OFF:
-		sc628a_i2c_write_b_flash(0x02, 0x0);
+		rc = sc628a_i2c_write_b_flash(0x02, 0x0);
+		if (sc628a_client) {
+			gpio_set_value_cansleep(external->led_en, 0);
+			gpio_set_value_cansleep(external->led_flash_en, 0);
+		}
 		break;
+
 	case MSM_CAMERA_LED_LOW:
-		sc628a_i2c_write_b_flash(0x02, 0x06);
+		if (sc628a_client) {
+			gpio_set_value_cansleep(external->led_en, 1);
+			gpio_set_value_cansleep(external->led_flash_en, 1);
+		}
+		rc = sc628a_i2c_write_b_flash(0x02, 0x06);
 		break;
+
 	case MSM_CAMERA_LED_HIGH:
-		sc628a_i2c_write_b_flash(0x02, 0x49);
+		if (sc628a_client) {
+			gpio_set_value_cansleep(external->led_en, 1);
+			gpio_set_value_cansleep(external->led_flash_en, 1);
+		}
+		rc = sc628a_i2c_write_b_flash(0x02, 0x49);
 		break;
+
 	default:
 		rc = -EFAULT;
 		break;
@@ -268,7 +314,6 @@
 	return rc;
 }
 
-
 static int msm_camera_flash_pwm(
 	struct msm_camera_sensor_flash_pwm *pwm,
 	unsigned led_state)
@@ -308,12 +353,14 @@
 	case MSM_CAMERA_LED_OFF:
 		pwm_disable(flash_pwm);
 		break;
+	case MSM_CAMERA_LED_INIT:
+	case MSM_CAMERA_LED_RELEASE:
+		break;
 
 	default:
 		rc = -EFAULT;
 		break;
 	}
-
 	return rc;
 }
 
@@ -345,6 +392,10 @@
 				pmic->high_current);
 		break;
 
+	case MSM_CAMERA_LED_INIT:
+	case MSM_CAMERA_LED_RELEASE:
+		 break;
+
 	default:
 		rc = -EFAULT;
 		break;
@@ -359,10 +410,8 @@
 {
 	int32_t rc;
 
-	CDBG("flash_set_led_state: %d flash_sr_type=%d\n", led_state,
-	    fdata->flash_src->flash_sr_type);
-
-	if (fdata->flash_type != MSM_CAMERA_FLASH_LED)
+	if (fdata->flash_type != MSM_CAMERA_FLASH_LED ||
+		fdata->flash_src == NULL)
 		return -ENODEV;
 
 	switch (fdata->flash_src->flash_sr_type) {
@@ -382,6 +431,12 @@
 			led_state);
 		break;
 
+	case MSM_CAMERA_FLASH_SRC_EXT:
+		rc = msm_camera_flash_external(
+			&fdata->flash_src->_fsrc.ext_driver_src,
+			led_state);
+		break;
+
 	default:
 		rc = -ENODEV;
 		break;
@@ -546,6 +601,7 @@
 	struct flash_ctrl_data *flash_info)
 {
 	int rc = 0;
+	sensor_data = sdata;
 	switch (flash_info->flashtype) {
 	case LED_FLASH:
 		rc = msm_camera_flash_set_led_state(sdata->flash_data,
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index 8f1589e..8d90eef 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -1452,12 +1452,6 @@
 	f->private_data = NULL;
 
 	if (pcam->use_count == 0) {
-		if (pcam->mctl.mctl_release) {
-			rc = pcam->mctl.mctl_release(&(pcam->mctl));
-			if (rc < 0)
-				pr_err("mctl_release fails %d\n", rc);
-		}
-
 		v4l2_device_unregister_subdev(&pcam->mctl.isp_sdev->sd);
 
 		rc = msm_cam_server_close_session(&g_server_dev, pcam);
@@ -1467,6 +1461,11 @@
 		rc = msm_send_close_server(pcam->vnode_id);
 		if (rc < 0)
 			pr_err("msm_send_close_server failed %d\n", rc);
+		if (pcam->mctl.mctl_release) {
+			rc = pcam->mctl.mctl_release(&(pcam->mctl));
+			if (rc < 0)
+				pr_err("mctl_release fails %d\n", rc);
+		}
 
 		dma_release_declared_memory(&pcam->pdev->dev);
 	}
diff --git a/include/media/msm_camera.h b/include/media/msm_camera.h
index f9f8385..81450cc 100644
--- a/include/media/msm_camera.h
+++ b/include/media/msm_camera.h
@@ -141,6 +141,8 @@
 #define MSM_CAMERA_LED_OFF  0
 #define MSM_CAMERA_LED_LOW  1
 #define MSM_CAMERA_LED_HIGH 2
+#define MSM_CAMERA_LED_INIT 3
+#define MSM_CAMERA_LED_RELEASE 4
 
 #define MSM_CAMERA_STROBE_FLASH_NONE 0
 #define MSM_CAMERA_STROBE_FLASH_XENON 1