Merge changes I09afb2dc,Ia37263f0 into msm-3.0
* changes:
msm: Select ENABLE_HOLES_IN_ZONE
arm: Add HOLES_IN_ZONE option
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 253a238..0cef857 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -199,6 +199,9 @@
obj-$(CONFIG_ARCH_MSM9615) += cpuidle.o
endif
+ifdef CONFIG_MSM_CAMERA_V4L2
+ obj-$(CONFIG_ARCH_MSM8X60) += board-msm8x60-camera.o
+endif
obj-$(CONFIG_ARCH_FSM9XXX) += devices-fsm9xxx.o
obj-$(CONFIG_ARCH_FSM9XXX) += clock-fsm9xxx.o clock-local.o acpuclock-fsm9xxx.o
obj-$(CONFIG_ARCH_FSM9XXX) += dfe-fsm9xxx.o rfic-fsm9xxx.o
diff --git a/arch/arm/mach-msm/board-msm8x60-camera.c b/arch/arm/mach-msm/board-msm8x60-camera.c
new file mode 100644
index 0000000..95561e4
--- /dev/null
+++ b/arch/arm/mach-msm/board-msm8x60-camera.c
@@ -0,0 +1,471 @@
+/* Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <asm/mach-types.h>
+#include <devices-msm8x60.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/mfd/pmic8901.h>
+#include <mach/board.h>
+#include <mach/board-msm8660.h>
+#include <mach/gpiomux.h>
+#include <mach/msm_bus_board.h>
+#include "devices.h"
+
+#define GPIO_EXT_CAMIF_PWR_EN1 (PM8901_MPP_BASE + PM8901_MPPS + 13)
+#ifdef CONFIG_MSM_CAMERA_FLASH
+#define VFE_CAMIF_TIMER1_GPIO 29
+#define VFE_CAMIF_TIMER2_GPIO 30
+#define VFE_CAMIF_TIMER3_GPIO_INT 31
+#define FUSION_VFE_CAMIF_TIMER1_GPIO 42
+
+static struct msm_camera_sensor_flash_src msm_flash_src = {
+ .flash_sr_type = MSM_CAMERA_FLASH_SRC_PMIC,
+ ._fsrc.pmic_src.num_of_src = 2,
+ ._fsrc.pmic_src.low_current = 100,
+ ._fsrc.pmic_src.high_current = 300,
+ ._fsrc.pmic_src.led_src_1 = PMIC8058_ID_FLASH_LED_0,
+ ._fsrc.pmic_src.led_src_2 = PMIC8058_ID_FLASH_LED_1,
+ ._fsrc.pmic_src.pmic_set_current = pm8058_set_flash_led_current,
+};
+static struct msm_camera_sensor_strobe_flash_data strobe_flash_xenon = {
+ .flash_trigger = VFE_CAMIF_TIMER2_GPIO,
+ .flash_charge = VFE_CAMIF_TIMER1_GPIO,
+ .flash_charge_done = VFE_CAMIF_TIMER3_GPIO_INT,
+ .flash_recharge_duration = 50000,
+ .irq = MSM_GPIO_TO_INT(VFE_CAMIF_TIMER3_GPIO_INT),
+};
+#endif
+
+static struct msm_bus_vectors cam_init_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors cam_preview_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 283115520,
+ .ib = 452984832,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors cam_video_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 283115520,
+ .ib = 452984832,
+ },
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 283115520,
+ .ib = 452984832,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 319610880,
+ .ib = 511377408,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors cam_snapshot_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 566231040,
+ .ib = 905969664,
+ },
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 69984000,
+ .ib = 111974400,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 320864256,
+ .ib = 513382810,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 320864256,
+ .ib = 513382810,
+ },
+};
+
+static struct msm_bus_vectors cam_zsl_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 566231040,
+ .ib = 905969664,
+ },
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 706199040,
+ .ib = 1129918464,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 320864256,
+ .ib = 513382810,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 320864256,
+ .ib = 513382810,
+ },
+};
+
+static struct msm_bus_vectors cam_stereo_video_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 212336640,
+ .ib = 339738624,
+ },
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 25090560,
+ .ib = 40144896,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 239708160,
+ .ib = 383533056,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 79902720,
+ .ib = 127844352,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 0,
+ .ib = 0,
+ },
+};
+
+static struct msm_bus_vectors cam_stereo_snapshot_vectors[] = {
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 0,
+ .ib = 0,
+ },
+ {
+ .src = MSM_BUS_MASTER_VFE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 300902400,
+ .ib = 481443840,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 230307840,
+ .ib = 368492544,
+ },
+ {
+ .src = MSM_BUS_MASTER_VPE,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 245113344,
+ .ib = 392181351,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_SMI,
+ .ab = 106536960,
+ .ib = 170459136,
+ },
+ {
+ .src = MSM_BUS_MASTER_JPEG_ENC,
+ .dst = MSM_BUS_SLAVE_EBI_CH0,
+ .ab = 106536960,
+ .ib = 170459136,
+ },
+};
+
+static struct msm_bus_paths cam_bus_client_config[] = {
+ {
+ ARRAY_SIZE(cam_init_vectors),
+ cam_zsl_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_preview_vectors),
+ cam_zsl_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_video_vectors),
+ cam_zsl_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_snapshot_vectors),
+ cam_snapshot_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_zsl_vectors),
+ cam_zsl_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_stereo_video_vectors),
+ cam_stereo_video_vectors,
+ },
+ {
+ ARRAY_SIZE(cam_stereo_snapshot_vectors),
+ cam_stereo_snapshot_vectors,
+ },
+};
+
+static struct msm_bus_scale_pdata cam_bus_client_pdata = {
+ cam_bus_client_config,
+ ARRAY_SIZE(cam_bus_client_config),
+ .name = "msm_camera",
+};
+
+static struct msm_camera_device_platform_data msm_camera_csi_device_data[] = {
+ {
+ .csid_core = 0,
+ .is_csic = 1,
+ .is_vpe = 1,
+ .cam_bus_scale_table = &cam_bus_client_pdata,
+ .ioclk = {
+ .vfe_clk_rate = 228570000,
+ },
+ },
+ {
+ .csid_core = 1,
+ .is_csic = 1,
+ .is_vpe = 1,
+ .cam_bus_scale_table = &cam_bus_client_pdata,
+ .ioclk = {
+ .vfe_clk_rate = 228570000,
+ },
+ },
+};
+static struct camera_vreg_t msm_8x60_back_cam_vreg[] = {
+ {"cam_vana", REG_LDO, 2850000, 2850000, -1},
+ {"cam_vio", REG_VS, 0, 0, 0},
+ {"cam_vdig", REG_LDO, 1200000, 1200000, -1},
+};
+
+static struct gpio msm8x60_common_cam_gpio[] = {
+ {32, GPIOF_DIR_IN, "CAMIF_MCLK"},
+ {47, GPIOF_DIR_IN, "CAMIF_I2C_DATA"},
+ {48, GPIOF_DIR_IN, "CAMIF_I2C_CLK"},
+ {105, GPIOF_DIR_IN, "STANDBY"},
+ {GPIO_EXT_CAMIF_PWR_EN1, GPIOF_DIR_OUT, "CAMIF_PWR_EN"},
+};
+
+static struct gpio msm8x60_back_cam_gpio[] = {
+ {106, GPIOF_DIR_OUT, "CAM_RESET"},
+};
+
+static struct msm_gpio_set_tbl msm8x60_back_cam_gpio_set_tbl[] = {
+ {GPIO_EXT_CAMIF_PWR_EN1, GPIOF_OUT_INIT_LOW, 10000},
+ {GPIO_EXT_CAMIF_PWR_EN1, GPIOF_OUT_INIT_HIGH, 5000},
+ {106, GPIOF_OUT_INIT_LOW, 1000},
+ {106, GPIOF_OUT_INIT_HIGH, 4000},
+};
+
+static struct msm_camera_gpio_conf msm_8x60_back_cam_gpio_conf = {
+ .cam_gpio_common_tbl = msm8x60_common_cam_gpio,
+ .cam_gpio_common_tbl_size = ARRAY_SIZE(msm8x60_common_cam_gpio),
+ .cam_gpio_req_tbl = msm8x60_back_cam_gpio,
+ .cam_gpio_req_tbl_size = ARRAY_SIZE(msm8x60_back_cam_gpio),
+ .cam_gpio_set_tbl = msm8x60_back_cam_gpio_set_tbl,
+ .cam_gpio_set_tbl_size = ARRAY_SIZE(msm8x60_back_cam_gpio_set_tbl),
+};
+
+
+static struct i2c_board_info imx074_actuator_i2c_info = {
+ I2C_BOARD_INFO("imx074_act", 0x11),
+};
+
+static struct msm_actuator_info imx074_actuator_info = {
+ .board_info = &imx074_actuator_i2c_info,
+ .bus_id = MSM_GSBI4_QUP_I2C_BUS_ID,
+ .vcm_pwd = 0,
+ .vcm_enable = 1,
+};
+
+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_platform_info sensor_board_info_imx074 = {
+ .mount_angle = 0,
+ .cam_vreg = msm_8x60_back_cam_vreg,
+ .num_vreg = ARRAY_SIZE(msm_8x60_back_cam_vreg),
+ .gpio_conf = &msm_8x60_back_cam_gpio_conf,
+};
+
+static struct msm_camera_sensor_info msm_camera_sensor_imx074_data = {
+ .sensor_name = "imx074",
+ .pdata = &msm_camera_csi_device_data[0],
+ .flash_data = &flash_imx074,
+ .strobe_flash_data = &strobe_flash_xenon,
+ .sensor_platform_info = &sensor_board_info_imx074,
+ .csi_if = 1,
+ .camera_type = BACK_CAMERA_2D,
+ .actuator_info = &imx074_actuator_info
+};
+
+void __init msm8x60_init_cam(void)
+{
+ platform_device_register(&msm_device_csic0);
+ platform_device_register(&msm_device_csic1);
+ platform_device_register(&msm_device_vfe);
+ platform_device_register(&msm_device_vpe);
+}
+
+#ifdef CONFIG_I2C
+static struct i2c_board_info msm8x60_camera_i2c_boardinfo[] = {
+ {
+ I2C_BOARD_INFO("imx074", 0x1A),
+ .platform_data = &msm_camera_sensor_imx074_data,
+ },
+};
+
+struct msm_camera_board_info msm8x60_camera_board_info = {
+ .board_info = msm8x60_camera_i2c_boardinfo,
+ .num_i2c_board_info = ARRAY_SIZE(msm8x60_camera_i2c_boardinfo),
+};
+#endif
diff --git a/arch/arm/mach-msm/board-msm8x60.c b/arch/arm/mach-msm/board-msm8x60.c
index 5db8de4..9497735 100644
--- a/arch/arm/mach-msm/board-msm8x60.c
+++ b/arch/arm/mach-msm/board-msm8x60.c
@@ -1562,6 +1562,7 @@
#endif
#ifdef CONFIG_MSM_VPE
+#ifndef CONFIG_MSM_CAMERA_V4L2
static struct resource msm_vpe_resources[] = {
{
.start = 0x05300000,
@@ -1582,8 +1583,10 @@
.resource = msm_vpe_resources,
};
#endif
+#endif
#ifdef CONFIG_MSM_CAMERA
+#ifndef CONFIG_MSM_CAMERA_V4L2
#ifdef CONFIG_MSM_CAMERA_FLASH
#define VFE_CAMIF_TIMER1_GPIO 29
#define VFE_CAMIF_TIMER2_GPIO 30
@@ -2486,6 +2489,7 @@
#endif
};
#endif
+#endif
#ifdef CONFIG_MSM_GEMINI
static struct resource msm_gemini_resources[] = {
@@ -3868,6 +3872,7 @@
};
static struct regulator_consumer_supply vreg_consumers_PM8058_L15[] = {
REGULATOR_SUPPLY("8058_l15", NULL),
+ REGULATOR_SUPPLY("cam_vana", "1-001a"),
};
static struct regulator_consumer_supply vreg_consumers_PM8058_L16[] = {
REGULATOR_SUPPLY("8058_l16", NULL),
@@ -3898,6 +3903,7 @@
};
static struct regulator_consumer_supply vreg_consumers_PM8058_L25[] = {
REGULATOR_SUPPLY("8058_l25", NULL),
+ REGULATOR_SUPPLY("cam_vdig", "1-001a"),
};
static struct regulator_consumer_supply vreg_consumers_PM8058_S0[] = {
REGULATOR_SUPPLY("8058_s0", NULL),
@@ -3916,6 +3922,7 @@
};
static struct regulator_consumer_supply vreg_consumers_PM8058_LVS0[] = {
REGULATOR_SUPPLY("8058_lvs0", NULL),
+ REGULATOR_SUPPLY("cam_vio", "1-001a"),
};
static struct regulator_consumer_supply vreg_consumers_PM8058_LVS1[] = {
REGULATOR_SUPPLY("8058_lvs1", NULL),
@@ -4279,6 +4286,7 @@
&hdmi_msm_device,
#endif /* CONFIG_FB_MSM_HDMI_MSM_PANEL */
#ifdef CONFIG_MSM_CAMERA
+#ifndef CONFIG_MSM_CAMERA_V4L2
#ifdef CONFIG_MT9E013
&msm_camera_sensor_mt9e013,
#endif
@@ -4298,12 +4306,15 @@
&msm_camera_sensor_qs_s5k4e1,
#endif
#endif
+#endif
#ifdef CONFIG_MSM_GEMINI
&msm_gemini_device,
#endif
#ifdef CONFIG_MSM_VPE
+#ifndef CONFIG_MSM_CAMERA_V4L2
&msm_vpe_device,
#endif
+#endif
&msm_device_vidc,
};
@@ -5223,6 +5234,7 @@
&mipi_dsi_novatek_panel_device,
#endif
#ifdef CONFIG_MSM_CAMERA
+#ifndef CONFIG_MSM_CAMERA_V4L2
#ifdef CONFIG_MT9E013
&msm_camera_sensor_mt9e013,
#endif
@@ -5242,12 +5254,15 @@
&msm_camera_sensor_vx6953,
#endif
#endif
+#endif
#ifdef CONFIG_MSM_GEMINI
&msm_gemini_device,
#endif
#ifdef CONFIG_MSM_VPE
+#ifndef CONFIG_MSM_CAMERA_V4L2
&msm_vpe_device,
#endif
+#endif
#if defined(CONFIG_MSM_RPM_LOG) || defined(CONFIG_MSM_RPM_LOG_MODULE)
&msm8660_rpm_log_device,
@@ -7245,6 +7260,7 @@
},
#endif
#ifdef CONFIG_MSM_CAMERA
+#ifndef CONFIG_MSM_CAMERA_V4L2
{
I2C_SURF | I2C_FFA | I2C_FLUID ,
MSM_GSBI4_QUP_I2C_BUS_ID,
@@ -7258,6 +7274,7 @@
ARRAY_SIZE(msm_camera_dragon_boardinfo),
},
#endif
+#endif
{
I2C_SURF | I2C_FFA | I2C_FLUID,
MSM_GSBI7_QUP_I2C_BUS_ID,
@@ -7340,6 +7357,14 @@
#ifdef CONFIG_I2C
u8 mach_mask = 0;
int i;
+#ifdef CONFIG_MSM_CAMERA_V4L2
+ struct i2c_registry msm8x60_camera_i2c_devices = {
+ I2C_SURF | I2C_FFA | I2C_FLUID,
+ MSM_GSBI4_QUP_I2C_BUS_ID,
+ msm8x60_camera_board_info.board_info,
+ msm8x60_camera_board_info.num_i2c_board_info,
+ };
+#endif
/* Build the matching 'supported_machs' bitmask */
if (machine_is_msm8x60_surf() || machine_is_msm8x60_fusion())
@@ -7364,6 +7389,12 @@
msm8x60_i2c_devices[i].info,
msm8x60_i2c_devices[i].len);
}
+#ifdef CONFIG_MSM_CAMERA_V4L2
+ if (msm8x60_camera_i2c_devices.machs & mach_mask)
+ i2c_register_board_info(msm8x60_camera_i2c_devices.bus,
+ msm8x60_camera_i2c_devices.info,
+ msm8x60_camera_i2c_devices.len);
+#endif
#endif
}
@@ -10323,8 +10354,12 @@
msm8x60_init_tlmm();
msm8x60_init_gpiomux(board_data->gpiomux_cfgs);
msm8x60_init_uart12dm();
+#ifdef CONFIG_MSM_CAMERA_V4L2
+ msm8x60_init_cam();
+#endif
msm8x60_init_mmc();
+
#if defined(CONFIG_PMIC8058_OTHC) || defined(CONFIG_PMIC8058_OTHC_MODULE)
msm8x60_init_pm8058_othc();
#endif
@@ -10335,13 +10370,13 @@
pm8058_platform_data.keypad_pdata = &dragon_keypad_data;
else
pm8058_platform_data.keypad_pdata = &ffa_keypad_data;
-
+#ifndef CONFIG_MSM_CAMERA_V4L2
/* Specify reset pin for OV9726 */
if (machine_is_msm8x60_dragon()) {
msm_camera_sensor_ov9726_data.sensor_reset = 62;
ov9726_sensor_8660_info.mount_angle = 270;
}
-
+#endif
#ifdef CONFIG_BATTERY_MSM8X60
if (machine_is_msm8x60_surf() || machine_is_msm8x60_ffa() ||
machine_is_msm8x60_fusion() || machine_is_msm8x60_dragon() ||
diff --git a/arch/arm/mach-msm/clock-8x60.c b/arch/arm/mach-msm/clock-8x60.c
index c724414..3bfb5a3 100644
--- a/arch/arm/mach-msm/clock-8x60.c
+++ b/arch/arm/mach-msm/clock-8x60.c
@@ -3612,6 +3612,7 @@
CLK_LOOKUP("csi_clk", csi0_clk.c, NULL),
CLK_LOOKUP("csi_clk", csi1_clk.c, "msm_camera_ov7692.0"),
CLK_LOOKUP("csi_clk", csi1_clk.c, "msm_camera_ov9726.0"),
+ CLK_LOOKUP("csi_clk", csi1_clk.c, "msm_csic.1"),
CLK_LOOKUP("csi_src_clk", csi_src_clk.c, NULL),
CLK_LOOKUP("dsi_byte_div_clk", dsi_byte_clk.c, NULL),
CLK_LOOKUP("dsi_esc_clk", dsi_esc_clk.c, NULL),
@@ -3649,6 +3650,7 @@
CLK_LOOKUP("csi_vfe_clk", csi0_vfe_clk.c, NULL),
CLK_LOOKUP("csi_vfe_clk", csi1_vfe_clk.c, "msm_camera_ov7692.0"),
CLK_LOOKUP("csi_vfe_clk", csi1_vfe_clk.c, "msm_camera_ov9726.0"),
+ CLK_LOOKUP("csi_vfe_clk", csi1_vfe_clk.c, "msm_csic.1"),
CLK_LOOKUP("vfe_clk", vfe_clk.c, NULL),
CLK_LOOKUP("core_clk", vfe_clk.c, "footswitch-8x60.8"),
CLK_LOOKUP("bus_clk", vfe_axi_clk.c, "footswitch-8x60.8"),
@@ -3662,6 +3664,7 @@
CLK_LOOKUP("csi_pclk", csi0_p_clk.c, NULL),
CLK_LOOKUP("csi_pclk", csi1_p_clk.c, "msm_camera_ov7692.0"),
CLK_LOOKUP("csi_pclk", csi1_p_clk.c, "msm_camera_ov9726.0"),
+ CLK_LOOKUP("csi_pclk", csi1_p_clk.c, "msm_csic.1"),
CLK_LOOKUP("dsi_m_pclk", dsi_m_p_clk.c, NULL),
CLK_LOOKUP("dsi_s_pclk", dsi_s_p_clk.c, NULL),
CLK_LOOKUP("iface_clk", gfx2d0_p_clk.c, "kgsl-2d0.0"),
diff --git a/arch/arm/mach-msm/devices-msm8x60.c b/arch/arm/mach-msm/devices-msm8x60.c
index ba7ac2a..84ba9fe 100644
--- a/arch/arm/mach-msm/devices-msm8x60.c
+++ b/arch/arm/mach-msm/devices-msm8x60.c
@@ -1378,6 +1378,98 @@
return platform_device_register(pdev);
}
+#ifdef CONFIG_MSM_CAMERA_V4L2
+static struct resource msm_csic0_resources[] = {
+ {
+ .name = "csic",
+ .start = 0x04800000,
+ .end = 0x04800000 + 0x00000400 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "csic",
+ .start = CSI_0_IRQ,
+ .end = CSI_0_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource msm_csic1_resources[] = {
+ {
+ .name = "csic",
+ .start = 0x04900000,
+ .end = 0x04900000 + 0x00000400 - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "csic",
+ .start = CSI_1_IRQ,
+ .end = CSI_1_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct resource msm_vfe_resources[] = {
+ {
+ .name = "msm_vfe",
+ .start = 0x04500000,
+ .end = 0x04500000 + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "msm_vfe",
+ .start = VFE_IRQ,
+ .end = VFE_IRQ,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource msm_vpe_resources[] = {
+ {
+ .name = "vpe",
+ .start = 0x05300000,
+ .end = 0x05300000 + SZ_1M - 1,
+ .flags = IORESOURCE_MEM,
+ },
+ {
+ .name = "vpe",
+ .start = INT_VPE,
+ .end = INT_VPE,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+struct platform_device msm_device_csic0 = {
+ .name = "msm_csic",
+ .id = 0,
+ .resource = msm_csic0_resources,
+ .num_resources = ARRAY_SIZE(msm_csic0_resources),
+};
+
+struct platform_device msm_device_csic1 = {
+ .name = "msm_csic",
+ .id = 1,
+ .resource = msm_csic1_resources,
+ .num_resources = ARRAY_SIZE(msm_csic1_resources),
+};
+
+struct platform_device msm_device_vfe = {
+ .name = "msm_vfe",
+ .id = 0,
+ .resource = msm_vfe_resources,
+ .num_resources = ARRAY_SIZE(msm_vfe_resources),
+};
+
+struct platform_device msm_device_vpe = {
+ .name = "msm_vpe",
+ .id = 0,
+ .resource = msm_vpe_resources,
+ .num_resources = ARRAY_SIZE(msm_vpe_resources),
+};
+
+#endif
+
+
#define MIPI_DSI_HW_BASE 0x04700000
#define ROTATOR_HW_BASE 0x04E00000
#define TVENC_HW_BASE 0x04F00000
diff --git a/arch/arm/mach-msm/devices.h b/arch/arm/mach-msm/devices.h
index 29e4dd0..624debd 100644
--- a/arch/arm/mach-msm/devices.h
+++ b/arch/arm/mach-msm/devices.h
@@ -356,3 +356,9 @@
extern struct platform_device msm_bus_8930_mm_fabric;
extern struct platform_device msm_bus_8930_sys_fpb;
extern struct platform_device msm_bus_8930_cpss_fpb;
+
+extern struct platform_device msm_device_csic0;
+extern struct platform_device msm_device_csic1;
+extern struct platform_device msm_device_vfe;
+extern struct platform_device msm_device_vpe;
+
diff --git a/arch/arm/mach-msm/dma.c b/arch/arm/mach-msm/dma.c
index b055f4e..087227c 100644
--- a/arch/arm/mach-msm/dma.c
+++ b/arch/arm/mach-msm/dma.c
@@ -61,17 +61,16 @@
size_t sd_size;
struct list_head ready_commands[MSM_DMOV_CHANNEL_COUNT];
struct list_head active_commands[MSM_DMOV_CHANNEL_COUNT];
- struct mutex lock;
- spinlock_t list_lock;
+ spinlock_t lock;
unsigned int irq;
struct clk *clk;
struct clk *pclk;
struct clk *ebiclk;
unsigned int clk_ctl;
- struct delayed_work work;
+ struct timer_list timer;
};
-static void msm_dmov_clock_work(struct work_struct *);
+static void msm_dmov_clock_timer(unsigned long);
static int msm_dmov_clk_toggle(int, int);
#ifdef CONFIG_ARCH_MSM8X60
@@ -164,19 +163,15 @@
{
.crci_conf = adm0_crci_conf,
.chan_conf = adm0_chan_conf,
- .lock = __MUTEX_INITIALIZER(dmov_conf[0].lock),
- .list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
+ .lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
.clk_ctl = CLK_DIS,
- .work = __DELAYED_WORK_INITIALIZER(dmov_conf[0].work,
- msm_dmov_clock_work),
+ .timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 0),
}, {
.crci_conf = adm1_crci_conf,
.chan_conf = adm1_chan_conf,
- .lock = __MUTEX_INITIALIZER(dmov_conf[1].lock),
- .list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
+ .lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
.clk_ctl = CLK_DIS,
- .work = __DELAYED_WORK_INITIALIZER(dmov_conf[1].work,
- msm_dmov_clock_work),
+ .timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 1),
}
};
#else
@@ -184,11 +179,9 @@
{
.crci_conf = NULL,
.chan_conf = NULL,
- .lock = __MUTEX_INITIALIZER(dmov_conf[0].lock),
- .list_lock = __SPIN_LOCK_UNLOCKED(dmov_list_lock),
+ .lock = __SPIN_LOCK_UNLOCKED(dmov_lock),
.clk_ctl = CLK_DIS,
- .work = __DELAYED_WORK_INITIALIZER(dmov_conf[0].work,
- msm_dmov_clock_work),
+ .timer = TIMER_INITIALIZER(msm_dmov_clock_timer, 0, 0),
}
};
#endif
@@ -264,18 +257,16 @@
return ret;
}
-static void msm_dmov_clock_work(struct work_struct *work)
+static void msm_dmov_clock_timer(unsigned long adm)
{
- struct msm_dmov_conf *conf =
- container_of(to_delayed_work(work), struct msm_dmov_conf, work);
- int adm = DMOV_IRQ_TO_ADM(conf->irq);
- mutex_lock(&conf->lock);
- if (conf->clk_ctl == CLK_TO_BE_DIS) {
- BUG_ON(conf->channel_active);
+ unsigned long irq_flags;
+ spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
+ if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) {
+ BUG_ON(dmov_conf[adm].channel_active);
msm_dmov_clk_toggle(adm, 0);
- conf->clk_ctl = CLK_DIS;
+ dmov_conf[adm].clk_ctl = CLK_DIS;
}
- mutex_unlock(&conf->lock);
+ spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
}
void msm_dmov_stop_cmd(unsigned id, struct msm_dmov_cmd *cmd, int graceful)
@@ -287,83 +278,48 @@
}
EXPORT_SYMBOL(msm_dmov_stop_cmd);
-/* Caller must hold the list lock */
-static void start_ready_cmd(unsigned ch, int adm)
+void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd)
{
- struct msm_dmov_cmd *cmd;
-
- if (list_empty(&dmov_conf[adm].ready_commands[ch]))
- return;
-
- cmd = list_entry(dmov_conf[adm].ready_commands[ch].next, typeof(*cmd),
- list);
- list_del(&cmd->list);
- if (cmd->exec_func)
- cmd->exec_func(cmd);
- list_add_tail(&cmd->list, &dmov_conf[adm].active_commands[ch]);
- if (!dmov_conf[adm].channel_active)
- enable_irq(dmov_conf[adm].irq);
- dmov_conf[adm].channel_active |= BIT(ch);
- PRINT_IO("msm dmov enqueue command %x\n", cmd->cmdptr);
- writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm));
-}
-
-static void msm_dmov_enqueue_cmd_ext_work(struct work_struct *work)
-{
- struct msm_dmov_cmd *cmd =
- container_of(work, struct msm_dmov_cmd, work);
- unsigned id = cmd->id;
- unsigned status;
- unsigned long flags;
+ unsigned long irq_flags;
+ unsigned int status;
int adm = DMOV_ID_TO_ADM(id);
int ch = DMOV_ID_TO_CHAN(id);
- mutex_lock(&dmov_conf[adm].lock);
+ spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
if (dmov_conf[adm].clk_ctl == CLK_DIS) {
status = msm_dmov_clk_toggle(adm, 1);
if (status != 0)
goto error;
} else if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS)
- cancel_delayed_work_sync(&dmov_conf[adm].work);
+ del_timer(&dmov_conf[adm].timer);
dmov_conf[adm].clk_ctl = CLK_EN;
- spin_lock_irqsave(&dmov_conf[adm].list_lock, flags);
-
status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch), adm));
if (status & DMOV_STATUS_CMD_PTR_RDY) {
PRINT_IO("msm_dmov_enqueue_cmd(%d), start command, status %x\n",
id, status);
- start_ready_cmd(ch, adm);
+ if (cmd->exec_func)
+ cmd->exec_func(cmd);
+ list_add_tail(&cmd->list, &dmov_conf[adm].active_commands[ch]);
+ if (!dmov_conf[adm].channel_active)
+ enable_irq(dmov_conf[adm].irq);
+ dmov_conf[adm].channel_active |= 1U << ch;
+ PRINT_IO("Writing %x exactly to register", cmd->cmdptr);
+ writel_relaxed(cmd->cmdptr, DMOV_REG(DMOV_CMD_PTR(ch), adm));
} else {
- if (list_empty(&dmov_conf[adm].active_commands[ch]) &&
- !list_empty(&dmov_conf[adm].ready_commands[ch]))
+ if (!dmov_conf[adm].channel_active) {
+ dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
+ mod_timer(&dmov_conf[adm].timer, jiffies + HZ);
+ }
+ if (list_empty(&dmov_conf[adm].active_commands[ch]))
PRINT_ERROR("msm_dmov_enqueue_cmd_ext(%d), stalled, "
"status %x\n", id, status);
PRINT_IO("msm_dmov_enqueue_cmd(%d), enqueue command, status "
"%x\n", id, status);
+ list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]);
}
- if (!dmov_conf[adm].channel_active) {
- dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
- schedule_delayed_work(&dmov_conf[adm].work, HZ);
- }
- spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
error:
- mutex_unlock(&dmov_conf[adm].lock);
-}
-
-void msm_dmov_enqueue_cmd_ext(unsigned id, struct msm_dmov_cmd *cmd)
-{
- int adm = DMOV_ID_TO_ADM(id);
- int ch = DMOV_ID_TO_CHAN(id);
- unsigned long flags;
- cmd->id = id;
- INIT_WORK(&cmd->work, msm_dmov_enqueue_cmd_ext_work);
-
- spin_lock_irqsave(&dmov_conf[adm].list_lock, flags);
- list_add_tail(&cmd->list, &dmov_conf[adm].ready_commands[ch]);
- spin_unlock_irqrestore(&dmov_conf[adm].list_lock, flags);
-
- schedule_work(&cmd->work);
+ spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
}
EXPORT_SYMBOL(msm_dmov_enqueue_cmd_ext);
@@ -381,14 +337,14 @@
unsigned long irq_flags;
int ch = DMOV_ID_TO_CHAN(id);
int adm = DMOV_ID_TO_ADM(id);
- spin_lock_irqsave(&dmov_conf[adm].list_lock, irq_flags);
+ spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
/* XXX not checking if flush cmd sent already */
if (!list_empty(&dmov_conf[adm].active_commands[ch])) {
PRINT_IO("msm_dmov_flush(%d), send flush cmd\n", id);
writel_relaxed(DMOV_FLUSH_TYPE, DMOV_REG(DMOV_FLUSH0(ch), adm));
}
/* spin_unlock_irqrestore has the necessary barrier */
- spin_unlock_irqrestore(&dmov_conf[adm].list_lock, irq_flags);
+ spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
}
EXPORT_SYMBOL(msm_dmov_flush);
@@ -450,7 +406,7 @@
errdata->flush[5] = readl_relaxed(DMOV_REG(DMOV_FLUSH5(ch), adm));
}
-static irqreturn_t msm_dmov_isr(int irq, void *dev_id)
+static irqreturn_t msm_datamover_irq_handler(int irq, void *dev_id)
{
unsigned int int_status;
unsigned int mask;
@@ -463,12 +419,11 @@
struct msm_dmov_cmd *cmd;
int adm = DMOV_IRQ_TO_ADM(irq);
- mutex_lock(&dmov_conf[adm].lock);
+ spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
/* read and clear isr */
int_status = readl_relaxed(DMOV_REG(DMOV_ISR, adm));
PRINT_FLOW("msm_datamover_irq_handler: DMOV_ISR %x\n", int_status);
- spin_lock_irqsave(&dmov_conf[adm].list_lock, irq_flags);
while (int_status) {
mask = int_status & -int_status;
ch = fls(mask) - 1;
@@ -536,40 +491,50 @@
ch_status = readl_relaxed(DMOV_REG(DMOV_STATUS(ch),
adm));
PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
- if (ch_status & DMOV_STATUS_CMD_PTR_RDY) {
- start_ready_cmd(ch, adm);
+ if ((ch_status & DMOV_STATUS_CMD_PTR_RDY) &&
+ !list_empty(&dmov_conf[adm].ready_commands[ch])) {
+ cmd = list_entry(dmov_conf[adm].
+ ready_commands[ch].next, typeof(*cmd),
+ list);
+ list_del(&cmd->list);
+ if (cmd->exec_func)
+ cmd->exec_func(cmd);
+ list_add_tail(&cmd->list,
+ &dmov_conf[adm].active_commands[ch]);
PRINT_FLOW("msm_datamover_irq_handler id %d, start command\n", id);
+ writel_relaxed(cmd->cmdptr,
+ DMOV_REG(DMOV_CMD_PTR(ch), adm));
}
} while (ch_status & DMOV_STATUS_RSLT_VALID);
if (list_empty(&dmov_conf[adm].active_commands[ch]) &&
- list_empty(&dmov_conf[adm].ready_commands[ch]))
+ list_empty(&dmov_conf[adm].ready_commands[ch]))
dmov_conf[adm].channel_active &= ~(1U << ch);
PRINT_FLOW("msm_datamover_irq_handler id %d, status %x\n", id, ch_status);
}
- spin_unlock_irqrestore(&dmov_conf[adm].list_lock, irq_flags);
if (!dmov_conf[adm].channel_active && valid) {
disable_irq_nosync(dmov_conf[adm].irq);
dmov_conf[adm].clk_ctl = CLK_TO_BE_DIS;
- schedule_delayed_work(&dmov_conf[adm].work, HZ);
+ mod_timer(&dmov_conf[adm].timer, jiffies + HZ);
}
- mutex_unlock(&dmov_conf[adm].lock);
+ spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
return valid ? IRQ_HANDLED : IRQ_NONE;
}
static int msm_dmov_suspend_late(struct device *dev)
{
+ unsigned long irq_flags;
struct platform_device *pdev = to_platform_device(dev);
int adm = (pdev->id >= 0) ? pdev->id : 0;
- mutex_lock(&dmov_conf[adm].lock);
+ spin_lock_irqsave(&dmov_conf[adm].lock, irq_flags);
if (dmov_conf[adm].clk_ctl == CLK_TO_BE_DIS) {
BUG_ON(dmov_conf[adm].channel_active);
- cancel_delayed_work_sync(&dmov_conf[adm].work);
+ del_timer(&dmov_conf[adm].timer);
msm_dmov_clk_toggle(adm, 0);
dmov_conf[adm].clk_ctl = CLK_DIS;
}
- mutex_unlock(&dmov_conf[adm].lock);
+ spin_unlock_irqrestore(&dmov_conf[adm].lock, irq_flags);
return 0;
}
@@ -684,8 +649,8 @@
if (!dmov_conf[adm].base)
return -ENOMEM;
- ret = request_threaded_irq(dmov_conf[adm].irq, NULL, msm_dmov_isr,
- IRQF_ONESHOT, "msmdatamover", NULL);
+ ret = request_irq(dmov_conf[adm].irq, msm_datamover_irq_handler,
+ 0, "msmdatamover", NULL);
if (ret) {
PRINT_ERROR("Requesting ADM%d irq %d failed\n", adm,
dmov_conf[adm].irq);
diff --git a/arch/arm/mach-msm/include/mach/board-msm8660.h b/arch/arm/mach-msm/include/mach/board-msm8660.h
index b07cc62..22e378c 100644
--- a/arch/arm/mach-msm/include/mach/board-msm8660.h
+++ b/arch/arm/mach-msm/include/mach/board-msm8660.h
@@ -33,4 +33,9 @@
#define PM8901_IRQ_BASE (PM8058_IRQ_BASE + \
NR_PMIC8058_IRQS)
+#ifdef CONFIG_MSM_CAMERA_V4L2
+extern struct msm_camera_board_info msm8x60_camera_board_info;
+void msm8x60_init_cam(void);
+#endif
+
#endif
diff --git a/arch/arm/mach-msm/include/mach/camera.h b/arch/arm/mach-msm/include/mach/camera.h
index ba038cb..5ee9e1a 100644
--- a/arch/arm/mach-msm/include/mach/camera.h
+++ b/arch/arm/mach-msm/include/mach/camera.h
@@ -200,12 +200,14 @@
struct msm_camera_csiphy_params csiphy_params;
};
+#ifndef CONFIG_MSM_CAMERA_V4L2
#define VFE31_OUTPUT_MODE_PT (0x1 << 0)
#define VFE31_OUTPUT_MODE_S (0x1 << 1)
#define VFE31_OUTPUT_MODE_V (0x1 << 2)
#define VFE31_OUTPUT_MODE_P (0x1 << 3)
#define VFE31_OUTPUT_MODE_T (0x1 << 4)
#define VFE31_OUTPUT_MODE_P_ALL_CHNLS (0x1 << 5)
+#endif
#define CSI_EMBED_DATA 0x12
#define CSI_YUV422_8 0x1E
diff --git a/arch/arm/mach-msm/include/mach/dma.h b/arch/arm/mach-msm/include/mach/dma.h
index 6e58ebe..d170f5f 100644
--- a/arch/arm/mach-msm/include/mach/dma.h
+++ b/arch/arm/mach-msm/include/mach/dma.h
@@ -1,7 +1,7 @@
/* linux/include/asm-arm/arch-msm/dma.h
*
* Copyright (C) 2007 Google, Inc.
- * Copyright (c) 2008-2012, Code Aurora Forum. All rights reserved.
+ * Copyright (c) 2008-2011, Code Aurora Forum. All rights reserved.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
@@ -35,8 +35,6 @@
unsigned int result,
struct msm_dmov_errdata *err);
void (*exec_func)(struct msm_dmov_cmd *cmd);
- struct work_struct work;
- unsigned id; /* For internal use */
void *user; /* Pointer for caller's reference */
};
diff --git a/arch/arm/mach-msm/pm2.c b/arch/arm/mach-msm/pm2.c
index a5e52be..4f3c7e4 100644
--- a/arch/arm/mach-msm/pm2.c
+++ b/arch/arm/mach-msm/pm2.c
@@ -565,7 +565,7 @@
__raw_writel(0, APPS_CLK_SLEEP_EN);
mb();
- if (cpu_is_msm8625()) {
+ if (cpu_is_msm8625() && power_collapsed) {
/*
* enable the SCU while coming out of power
* collapse.
@@ -1089,6 +1089,8 @@
unsigned long saved_acpuclk_rate;
int collapsed = 0;
int ret;
+ int val;
+ int modem_early_exit = 0;
MSM_PM_DPRINTK(MSM_PM_DEBUG_SUSPEND|MSM_PM_DEBUG_POWER_COLLAPSE,
KERN_INFO, "%s(): idle %d, delay %u, limit %u\n", __func__,
@@ -1194,8 +1196,25 @@
#endif
collapsed = msm_pm_collapse();
- if (collapsed)
- power_collapsed = 1;
+
+ /*
+ * TBD: Currently recognise the MODEM early exit
+ * path by reading the MPA5_GDFS_CNT_VAL register.
+ */
+ if (cpu_is_msm8625()) {
+ /*
+ * on system reset default value of MPA5_GDFS_CNT_VAL
+ * is = 0xFF, later power driver reprogrammed this
+ * as: 0x000300FF. Currently based on the value of
+ * MPA5_GDFS_CNT_VAL register decide whether it is
+ * a modem early exit are not.
+ */
+ val = __raw_readl(MSM_CFG_CTL_BASE + 0x38);
+ if (val != 0xFF)
+ modem_early_exit = 1;
+ else
+ power_collapsed = 1;
+ }
#ifdef CONFIG_CACHE_L2X0
l2x0_resume(collapsed);
@@ -1256,7 +1275,7 @@
}
/* Sanity check */
- if (collapsed) {
+ if (collapsed && !modem_early_exit) {
BUG_ON(!(state_grps[0].value_read & DEM_MASTER_SMSM_RSA));
} else {
BUG_ON(!(state_grps[0].value_read &
diff --git a/drivers/gpu/msm/kgsl_pwrctrl.c b/drivers/gpu/msm/kgsl_pwrctrl.c
index d960eaf..7c451a9 100644
--- a/drivers/gpu/msm/kgsl_pwrctrl.c
+++ b/drivers/gpu/msm/kgsl_pwrctrl.c
@@ -334,7 +334,8 @@
do_gettimeofday(&(b->start));
}
-void kgsl_pwrctrl_clk(struct kgsl_device *device, int state)
+void kgsl_pwrctrl_clk(struct kgsl_device *device, int state,
+ int requested_state)
{
struct kgsl_pwrctrl *pwr = &device->pwrctrl;
int i = 0;
@@ -346,7 +347,7 @@
if (pwr->grp_clks[i])
clk_disable(pwr->grp_clks[i]);
if ((pwr->pwrlevels[0].gpu_freq > 0) &&
- (device->requested_state != KGSL_STATE_NAP))
+ (requested_state != KGSL_STATE_NAP))
clk_set_rate(pwr->grp_clks[0],
pwr->pwrlevels[pwr->num_pwrlevels - 1].
gpu_freq);
@@ -698,8 +699,8 @@
return -EBUSY;
}
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
- kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
- kgsl_pwrctrl_set_state(device, device->requested_state);
+ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_NAP);
+ kgsl_pwrctrl_set_state(device, KGSL_STATE_NAP);
if (device->idle_wakelock.name)
wake_unlock(&device->idle_wakelock);
case KGSL_STATE_NAP:
@@ -741,7 +742,7 @@
pwr->pwrlevels[pwr->num_pwrlevels - 1].
gpu_freq);
_sleep_accounting(device);
- kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
+ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_SLEEP);
kgsl_pwrctrl_set_state(device, KGSL_STATE_SLEEP);
wake_unlock(&device->idle_wakelock);
pm_qos_update_request(&device->pm_qos_req_dma,
@@ -845,7 +846,7 @@
/* fall through */
case KGSL_STATE_NAP:
/* Turn on the core clocks */
- kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON);
+ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE);
/* Enable state before turning on irq */
kgsl_pwrctrl_set_state(device, KGSL_STATE_ACTIVE);
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_ON);
@@ -871,7 +872,7 @@
{
/* Order pwrrail/clk sequence based upon platform */
kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_ON);
- kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON);
+ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_ON, KGSL_STATE_ACTIVE);
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_ON);
}
EXPORT_SYMBOL(kgsl_pwrctrl_enable);
@@ -880,7 +881,7 @@
{
/* Order pwrrail/clk sequence based upon platform */
kgsl_pwrctrl_axi(device, KGSL_PWRFLAGS_OFF);
- kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF);
+ kgsl_pwrctrl_clk(device, KGSL_PWRFLAGS_OFF, KGSL_STATE_SLEEP);
kgsl_pwrctrl_pwrrail(device, KGSL_PWRFLAGS_OFF);
}
EXPORT_SYMBOL(kgsl_pwrctrl_disable);
diff --git a/drivers/hwmon/pm8xxx-adc.c b/drivers/hwmon/pm8xxx-adc.c
index 2f59235..6bef3d3 100644
--- a/drivers/hwmon/pm8xxx-adc.c
+++ b/drivers/hwmon/pm8xxx-adc.c
@@ -239,6 +239,7 @@
if (arb_cntrl) {
data_arb_cntrl |= PM8XXX_ADC_ARB_USRP_CNTRL1_REQ;
+ INIT_COMPLETION(adc_pmic->adc_rslt_completion);
rc = pm8xxx_writeb(adc_pmic->dev->parent,
PM8XXX_ADC_ARB_USRP_CNTRL1, data_arb_cntrl);
} else
@@ -336,7 +337,6 @@
static int32_t pm8xxx_adc_configure(
struct pm8xxx_adc_amux_properties *chan_prop)
{
- struct pm8xxx_adc *adc_pmic = pmic_adc;
u8 data_amux_chan = 0, data_arb_rsv = 0, data_dig_param = 0;
int rc;
@@ -395,9 +395,6 @@
if (rc < 0)
return rc;
- if (!pm8xxx_adc_calib_first_adc)
- enable_irq(adc_pmic->adc_irq);
-
rc = pm8xxx_adc_arb_cntrl(1, data_amux_chan);
if (rc < 0) {
pr_err("Configuring ADC Arbiter"
@@ -476,16 +473,21 @@
spin_unlock_irqrestore(&adc_pmic->btm_lock, flags);
}
+void trigger_completion(struct work_struct *work)
+{
+ struct pm8xxx_adc *adc_8xxx = pmic_adc;
+
+ complete(&adc_8xxx->adc_rslt_completion);
+}
+DECLARE_WORK(trigger_completion_work, trigger_completion);
+
static irqreturn_t pm8xxx_adc_isr(int irq, void *dev_id)
{
- struct pm8xxx_adc *adc_8xxx = dev_id;
-
- disable_irq_nosync(adc_8xxx->adc_irq);
if (pm8xxx_adc_calib_first_adc)
return IRQ_HANDLED;
- /* TODO Handle spurius interrupt condition */
- complete(&adc_8xxx->adc_rslt_completion);
+
+ schedule_work(&trigger_completion_work);
return IRQ_HANDLED;
}
@@ -1214,10 +1216,10 @@
if (rc) {
dev_err(&pdev->dev, "failed to request adc irq "
"with error %d\n", rc);
+ } else {
+ enable_irq_wake(adc_pmic->adc_irq);
}
- disable_irq_nosync(adc_pmic->adc_irq);
-
adc_pmic->btm_warm_irq = platform_get_irq(pdev, PM8XXX_ADC_IRQ_1);
if (adc_pmic->btm_warm_irq < 0)
return adc_pmic->btm_warm_irq;
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index 45b0134..198298b 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -56,6 +56,7 @@
rc-norwood.o \
rc-npgtech.o \
rc-pctv-sedna.o \
+ rc-philips.o \
rc-pinnacle-color.o \
rc-pinnacle-grey.o \
rc-pinnacle-pctv-hd.o \
diff --git a/drivers/media/rc/keymaps/rc-philips.c b/drivers/media/rc/keymaps/rc-philips.c
new file mode 100644
index 0000000..ff2caf9
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-philips.c
@@ -0,0 +1,81 @@
+/* Copyright (c) 2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table philips[] = {
+
+ { 0x00, KEY_NUMERIC_0 },
+ { 0x01, KEY_NUMERIC_1 },
+ { 0x02, KEY_NUMERIC_2 },
+ { 0x03, KEY_NUMERIC_3 },
+ { 0x04, KEY_NUMERIC_4 },
+ { 0x05, KEY_NUMERIC_5 },
+ { 0x06, KEY_NUMERIC_6 },
+ { 0x07, KEY_NUMERIC_7 },
+ { 0x08, KEY_NUMERIC_8 },
+ { 0x09, KEY_NUMERIC_9 },
+ { 0xF4, KEY_SOUND },
+ { 0xF3, KEY_SCREEN }, /* Picture */
+
+ { 0x10, KEY_VOLUMEUP },
+ { 0x11, KEY_VOLUMEDOWN },
+ { 0x0d, KEY_MUTE },
+ { 0x20, KEY_CHANNELUP },
+ { 0x21, KEY_CHANNELDOWN },
+ { 0x0A, KEY_BACK },
+ { 0x0f, KEY_INFO },
+ { 0x5c, KEY_OK },
+ { 0x58, KEY_UP },
+ { 0x59, KEY_DOWN },
+ { 0x5a, KEY_LEFT },
+ { 0x5b, KEY_RIGHT },
+ { 0xcc, KEY_PAUSE },
+ { 0x6d, KEY_PVR }, /* Demo */
+ { 0x40, KEY_EXIT },
+ { 0x6e, KEY_PROG1 }, /* Scenea */
+ { 0x6f, KEY_MODE }, /* Dual */
+ { 0x70, KEY_SLEEP },
+ { 0xf5, KEY_TUNER }, /* Format */
+
+ { 0x4f, KEY_TV },
+ { 0x3c, KEY_NEW }, /* USB */
+ { 0x38, KEY_COMPOSE }, /* Source */
+ { 0x54, KEY_MENU },
+
+ { 0x0C, KEY_POWER },
+};
+
+static struct rc_map_list rc6_philips_map = {
+ .map = {
+ .scan = philips,
+ .size = ARRAY_SIZE(philips),
+ .rc_type = RC_TYPE_RC6,
+ .name = RC_MAP_RC6_PHILIPS,
+ }
+};
+
+static int __init init_rc_map_rc6_philips(void)
+{
+ return rc_map_register(&rc6_philips_map);
+}
+
+static void __exit exit_rc_map_rc6_philips(void)
+{
+ rc_map_unregister(&rc6_philips_map);
+}
+
+module_init(init_rc_map_rc6_philips)
+module_exit(exit_rc_map_rc6_philips)
+
+MODULE_DESCRIPTION("Philips Remote Keymap ");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/Kconfig b/drivers/media/video/msm/Kconfig
index ec034b1..c00f4c6 100644
--- a/drivers/media/video/msm/Kconfig
+++ b/drivers/media/video/msm/Kconfig
@@ -82,7 +82,7 @@
# This uses the CSI interface.
config VX6953
bool "Sensor VX6953 (BAYER 5M)"
- depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60)
+ depends on MSM_CAMERA && (ARCH_MSM7X30 || ARCH_MSM8X60) && !MSM_CAMERA_V4L2
default y
---help---
STM 5M Bayer Sensor with EDOF
diff --git a/drivers/media/video/msm/Makefile b/drivers/media/video/msm/Makefile
index f817561..ca80fc1 100644
--- a/drivers/media/video/msm/Makefile
+++ b/drivers/media/video/msm/Makefile
@@ -20,9 +20,14 @@
else
obj-$(CONFIG_ARCH_MSM7X27A) += msm_vfe7x27a.o msm_io_7x27a.o
endif
-obj-$(CONFIG_ARCH_MSM7X30) += msm_vfe31.o msm_io_vfe31.o msm_vpe1.o
obj-$(CONFIG_ARCH_QSD8X50) += msm_vfe8x.o msm_vfe8x_proc.o msm_io8x.o
-obj-$(CONFIG_ARCH_MSM8X60) += msm_vfe31.o msm_io_8x60.o msm_vpe1.o
+ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
+ obj-$(CONFIG_ARCH_MSM8X60) += msm_io_vfe31_v4l2.o msm_vfe31_v4l2.o msm_vpe.o
+ obj-$(CONFIG_ARCH_MSM7X30) += msm_io_vfe31_v4l2.o msm_vfe31_v4l2.o msm_vpe.o msm_axi_qos.o
+else
+ obj-$(CONFIG_ARCH_MSM8X60) += msm_vfe31.o msm_io_8x60.o msm_vpe1.o
+ obj-$(CONFIG_ARCH_MSM7X30) += msm_vfe31.o msm_io_vfe31.o msm_vpe1.o
+endif
obj-$(CONFIG_ARCH_MSM8960) += msm_io_8960.o msm_vfe32.o msm_vpe.o
obj-$(CONFIG_MT9T013) += mt9t013.o mt9t013_reg.o
obj-$(CONFIG_SN12M0PZ) += sn12m0pz.o sn12m0pz_reg.o
@@ -32,9 +37,7 @@
obj-$(CONFIG_MT9P012_KM) += mt9p012_km.o mt9p012_km_reg.o
obj-$(CONFIG_S5K3E2FX) += s5k3e2fx.o
#FIXME: Merge the two ifeq causes VX6953 preview not coming up.
-ifeq ($(CONFIG_MSM_CAMERA_V4L2),y)
- obj-$(CONFIG_VX6953) += vx6953_v4l2.o vx6953_reg_v4l2.o
-else
+ifneq ($(CONFIG_MSM_CAMERA_V4L2),y)
obj-$(CONFIG_VX6953) += vx6953.o vx6953_reg.o
obj-$(CONFIG_IMX074) += imx074.o imx074_reg.o
obj-$(CONFIG_MT9E013) += mt9e013.o mt9e013_reg.o
diff --git a/drivers/media/video/msm/csi/Makefile b/drivers/media/video/msm/csi/Makefile
index 6e8eb122..e5d5966 100644
--- a/drivers/media/video/msm/csi/Makefile
+++ b/drivers/media/video/msm/csi/Makefile
@@ -2,3 +2,5 @@
EXTRA_CFLAGS += -Idrivers/media/video/msm
obj-$(CONFIG_ARCH_MSM8960) += msm_csiphy.o msm_csid.o msm_ispif.o
obj-$(CONFIG_ARCH_MSM7X27A) += msm_csic.o
+obj-$(CONFIG_ARCH_MSM8X60) += msm_csic.o
+obj-$(CONFIG_ARCH_MSM7X30) += msm_csic.o
diff --git a/drivers/media/video/msm/csi/msm_csic.c b/drivers/media/video/msm/csi/msm_csic.c
index 3a642c7..1ca4fa3 100644
--- a/drivers/media/video/msm/csi/msm_csic.c
+++ b/drivers/media/video/msm/csi/msm_csic.c
@@ -13,6 +13,7 @@
#include <linux/delay.h>
#include <linux/clk.h>
#include <linux/io.h>
+#include <mach/clk.h>
#include <mach/board.h>
#include <mach/camera.h>
#include <media/msm_isp.h>
@@ -54,7 +55,7 @@
/* Data format for unpacking purpose */
#define MIPI_PROTOCOL_CONTROL_DATA_FORMAT_SHFT 0x13
/* Enable decoding of payload based on data type filed of packet hdr */
-#define MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK 0x00000
+#define MIPI_PROTOCOL_CONTROL_DECODE_ID_BMSK 0x40000
/* Enable error correction on packet headers */
#define MIPI_PROTOCOL_CONTROL_ECC_EN_BMSK 0x20000
@@ -132,7 +133,7 @@
#define MSM_AXI_QOS_SNAPSHOT 200000
#define MSM_AXI_QOS_RECORDING 200000
-#define MIPI_PWR_CNTL_ENA 0x07
+#define MIPI_PWR_CNTL_EN 0x07
#define MIPI_PWR_CNTL_DIS 0x0
static int msm_csic_config(struct csic_cfg_params *cfg_params)
@@ -210,9 +211,9 @@
break;
}
- msm_io_w(0xFFFFF3FF, csicbase + MIPI_INTERRUPT_MASK);
- /*clear IRQ bits - write 1 clears the status*/
- msm_io_w(0xFFFFF3FF, csicbase + MIPI_INTERRUPT_STATUS);
+ msm_io_w(0xF077F3C0, csicbase + MIPI_INTERRUPT_MASK);
+ /*clear IRQ bits*/
+ msm_io_w(0xF077F3C0, csicbase + MIPI_INTERRUPT_STATUS);
return rc;
}
@@ -244,7 +245,14 @@
return 0;
}
-static struct msm_cam_clk_info csic_clk_info[] = {
+static struct msm_cam_clk_info csic_8x_clk_info[] = {
+ {"csi_src_clk", 384000000},
+ {"csi_clk", -1},
+ {"csi_vfe_clk", -1},
+ {"csi_pclk", -1},
+};
+
+static struct msm_cam_clk_info csic_7x_clk_info[] = {
{"csi_clk", 400000000},
{"csi_vfe_clk", -1},
{"csi_pclk", -1},
@@ -267,12 +275,18 @@
return rc;
}
- pr_info("msm_cam_clk_enable: enable csi_pclk, csi_clk, csi_vfe_clk\n");
- rc = msm_cam_clk_enable(&csic_dev->pdev->dev, csic_clk_info,
- csic_dev->csic_clk, ARRAY_SIZE(csic_clk_info), 1);
+ csic_dev->hw_version = CSIC_8X;
+ rc = msm_cam_clk_enable(&csic_dev->pdev->dev, csic_8x_clk_info,
+ csic_dev->csic_clk, ARRAY_SIZE(csic_8x_clk_info), 1);
if (rc < 0) {
- iounmap(csic_dev->base);
- return rc;
+ csic_dev->hw_version = CSIC_7X;
+ rc = msm_cam_clk_enable(&csic_dev->pdev->dev, csic_7x_clk_info,
+ csic_dev->csic_clk, ARRAY_SIZE(csic_7x_clk_info), 1);
+ if (rc < 0) {
+ csic_dev->hw_version = 0;
+ iounmap(csic_dev->base);
+ return rc;
+ }
}
#if DBG_CSIC
@@ -282,20 +296,58 @@
return 0;
}
+static void msm_csic_disable(struct v4l2_subdev *sd)
+{
+ uint32_t val;
+ struct csic_device *csic_dev;
+ csic_dev = v4l2_get_subdevdata(sd);
+
+ val = 0x0;
+ if (csic_dev->base != NULL) {
+ CDBG("%s MIPI_PHY_D0_CONTROL2 val=0x%x\n", __func__, val);
+ msm_io_w(val, csic_dev->base + MIPI_PHY_D0_CONTROL2);
+ msm_io_w(val, csic_dev->base + MIPI_PHY_D1_CONTROL2);
+ msm_io_w(val, csic_dev->base + MIPI_PHY_D2_CONTROL2);
+ msm_io_w(val, csic_dev->base + MIPI_PHY_D3_CONTROL2);
+ CDBG("%s MIPI_PHY_CL_CONTROL val=0x%x\n", __func__, val);
+ msm_io_w(val, csic_dev->base + MIPI_PHY_CL_CONTROL);
+ msleep(20);
+ val = msm_io_r(csic_dev->base + MIPI_PHY_D1_CONTROL);
+ val &=
+ ~((0x1 << MIPI_PHY_D1_CONTROL_MIPI_CLK_PHY_SHUTDOWNB_SHFT)
+ |(0x1 << MIPI_PHY_D1_CONTROL_MIPI_DATA_PHY_SHUTDOWNB_SHFT));
+ CDBG("%s MIPI_PHY_D1_CONTROL val=0x%x\n", __func__, val);
+ msm_io_w(val, csic_dev->base + MIPI_PHY_D1_CONTROL);
+ usleep_range(5000, 6000);
+ msm_io_w(0x0, csic_dev->base + MIPI_INTERRUPT_MASK);
+ msm_io_w(0x0, csic_dev->base + MIPI_INTERRUPT_STATUS);
+ msm_io_w(MIPI_PROTOCOL_CONTROL_SW_RST_BMSK,
+ csic_dev->base + MIPI_PROTOCOL_CONTROL);
+
+ msm_io_w(0xE400, csic_dev->base + MIPI_CAMERA_CNTL);
+ }
+}
+
static int msm_csic_release(struct v4l2_subdev *sd)
{
struct csic_device *csic_dev;
csic_dev = v4l2_get_subdevdata(sd);
+ msm_csic_disable(sd);
#if DBG_CSIC
disable_irq(csic_dev->irq->start);
#endif
- pr_info("msm_cam_clk_enable: disble csi_pclk, csi_clk, csi_vfe_clk\n");
- msm_cam_clk_enable(&csic_dev->pdev->dev, csic_clk_info,
- csic_dev->csic_clk, ARRAY_SIZE(csic_clk_info), 0);
+ if (csic_dev->hw_version == CSIC_8X) {
+ msm_cam_clk_enable(&csic_dev->pdev->dev, csic_8x_clk_info,
+ csic_dev->csic_clk, ARRAY_SIZE(csic_8x_clk_info), 0);
+ } else if (csic_dev->hw_version == CSIC_7X) {
+ msm_cam_clk_enable(&csic_dev->pdev->dev, csic_7x_clk_info,
+ csic_dev->csic_clk, ARRAY_SIZE(csic_7x_clk_info), 0);
+ }
iounmap(csic_dev->base);
+ csic_dev->base = NULL;
return 0;
}
@@ -365,7 +417,7 @@
}
rc = request_irq(new_csic_dev->irq->start, msm_csic_irq,
- IRQF_TRIGGER_HIGH, "csic", new_csic_dev);
+ IRQF_TRIGGER_HIGH, "csic", new_csic_dev);
if (rc < 0) {
release_mem_region(new_csic_dev->mem->start,
resource_size(new_csic_dev->mem));
@@ -374,20 +426,6 @@
goto csic_no_resource;
}
disable_irq(new_csic_dev->irq->start);
- pr_info("msm_cam_clk_enable: enable csi_pclk\n");
- msm_cam_clk_enable(&pdev->dev, &csic_clk_info[2],
- new_csic_dev->csic_clk, 1, 1);
- new_csic_dev->base = ioremap(new_csic_dev->mem->start,
- resource_size(new_csic_dev->mem));
- if (!new_csic_dev->base) {
- rc = -ENOMEM;
- goto csic_no_resource;
- }
-
- msm_io_w(MIPI_PWR_CNTL_DIS, new_csic_dev->base + MIPI_PWR_CNTL_DIS);
- pr_info("msm_cam_clk_enable: disable csi_pclk\n");
- msm_cam_clk_enable(&pdev->dev, &csic_clk_info[2],
- new_csic_dev->csic_clk, 1, 0);
iounmap(new_csic_dev->base);
new_csic_dev->pdev = pdev;
diff --git a/drivers/media/video/msm/csi/msm_csic.h b/drivers/media/video/msm/csi/msm_csic.h
index 08dde52..177e9d1 100644
--- a/drivers/media/video/msm/csi/msm_csic.h
+++ b/drivers/media/video/msm/csi/msm_csic.h
@@ -17,6 +17,9 @@
#include <linux/io.h>
#include <media/v4l2-subdev.h>
+#define CSIC_7X 0x1
+#define CSIC_8X (0x1 << 1)
+
struct csic_device {
struct platform_device *pdev;
struct v4l2_subdev subdev;
diff --git a/drivers/media/video/msm/io/msm_io_util.c b/drivers/media/video/msm/io/msm_io_util.c
index a04d6fd..cc6bab2 100644
--- a/drivers/media/video/msm/io/msm_io_util.c
+++ b/drivers/media/video/msm/io/msm_io_util.c
@@ -111,15 +111,15 @@
curr_vreg->reg_name);
goto vreg_set_voltage_fail;
}
- if (curr_vreg->op_mode) {
+ if (curr_vreg->op_mode >= 0) {
rc = regulator_set_optimum_mode(
reg_ptr[i],
curr_vreg->op_mode);
if (rc < 0) {
- pr_err("%s: %s set optimum"
- "mode failed\n",
- __func__,
- curr_vreg->reg_name);
+ pr_err(
+ "%s: %s set optimum mode failed\n",
+ __func__,
+ curr_vreg->reg_name);
goto vreg_set_opt_mode_fail;
}
}
@@ -130,9 +130,10 @@
curr_vreg = &cam_vreg[i];
if (reg_ptr[i]) {
if (curr_vreg->type == REG_LDO) {
- if (curr_vreg->op_mode)
+ if (curr_vreg->op_mode >= 0) {
regulator_set_optimum_mode(
reg_ptr[i], 0);
+ }
regulator_set_voltage(
reg_ptr[i], 0, curr_vreg->
max_voltage);
diff --git a/drivers/media/video/msm/msm_io_vfe31_v4l2.c b/drivers/media/video/msm/msm_io_vfe31_v4l2.c
new file mode 100644
index 0000000..03810f4
--- /dev/null
+++ b/drivers/media/video/msm/msm_io_vfe31_v4l2.c
@@ -0,0 +1,408 @@
+/* Copyright (c) 2010-2012, Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/regulator/consumer.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/camera.h>
+#include <mach/vreg.h>
+#include <mach/camera.h>
+#include <mach/clk.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+
+#include <linux/pm_qos_params.h>
+
+/* AXI rates in KHz */
+#define MSM_AXI_QOS_PREVIEW 192000
+#define MSM_AXI_QOS_SNAPSHOT 192000
+#define MSM_AXI_QOS_RECORDING 192000
+
+#define BUFF_SIZE_128 128
+
+static struct clk *camio_jpeg_clk;
+static struct clk *camio_vfe_clk;
+static struct clk *camio_jpeg_pclk;
+static struct clk *camio_vpe_clk;
+static struct clk *camio_vpe_pclk;
+static struct regulator *fs_ijpeg;
+static struct regulator *fs_vpe;
+
+static int vpe_clk_rate;
+void msm_io_w(u32 data, void __iomem *addr)
+{
+ CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+ writel_relaxed((data), (addr));
+}
+
+void msm_io_w_mb(u32 data, void __iomem *addr)
+{
+ CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+ wmb();
+ writel_relaxed((data), (addr));
+ wmb();
+}
+
+u32 msm_io_r(void __iomem *addr)
+{
+ uint32_t data = readl_relaxed(addr);
+ CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+ return data;
+}
+
+u32 msm_io_r_mb(void __iomem *addr)
+{
+ uint32_t data;
+ rmb();
+ data = readl_relaxed(addr);
+ rmb();
+ CDBG("%s: %08x %08x\n", __func__, (int) (addr), (data));
+ return data;
+}
+
+void msm_io_memcpy_toio(void __iomem *dest_addr,
+ void __iomem *src_addr, u32 len)
+{
+ int i;
+ u32 *d = (u32 *) dest_addr;
+ u32 *s = (u32 *) src_addr;
+ /* memcpy_toio does not work. Use writel for now */
+ for (i = 0; i < len; i++)
+ writel_relaxed(*s++, d++);
+}
+
+void msm_io_dump(void __iomem *addr, int size)
+{
+ char line_str[BUFF_SIZE_128], *p_str;
+ int i;
+ u32 *p = (u32 *) addr;
+ u32 data;
+ CDBG("%s: %p %d\n", __func__, addr, size);
+ line_str[0] = '\0';
+ p_str = line_str;
+ for (i = 0; i < size/4; i++) {
+ if (i % 4 == 0) {
+ snprintf(p_str, 12, "%08x: ", (u32) p);
+ p_str += 10;
+ }
+ data = readl_relaxed(p++);
+ snprintf(p_str, 12, "%08x ", data);
+ p_str += 9;
+ if ((i + 1) % 4 == 0) {
+ CDBG("%s\n", line_str);
+ line_str[0] = '\0';
+ p_str = line_str;
+ }
+ }
+ if (line_str[0] != '\0')
+ CDBG("%s\n", line_str);
+}
+
+void msm_io_memcpy(void __iomem *dest_addr, void __iomem *src_addr, u32 len)
+{
+ CDBG("%s: %p %p %d\n", __func__, dest_addr, src_addr, len);
+ msm_io_memcpy_toio(dest_addr, src_addr, len / 4);
+ msm_io_dump(dest_addr, len);
+}
+
+int msm_camio_clk_enable(enum msm_camio_clk_type clktype)
+{
+ int rc = 0;
+ struct clk *clk = NULL;
+
+ switch (clktype) {
+ case CAMIO_JPEG_CLK:
+ camio_jpeg_clk =
+ clk = clk_get(NULL, "ijpeg_clk");
+ rc = clk_set_rate(clk, 228571000);
+ if (rc < 0)
+ rc = clk_set_rate(clk, 153600000);
+ break;
+
+ case CAMIO_JPEG_PCLK:
+ camio_jpeg_pclk =
+ clk = clk_get(NULL, "ijpeg_pclk");
+ break;
+
+ case CAMIO_VPE_CLK:
+ camio_vpe_clk =
+ clk = clk_get(NULL, "vpe_clk");
+ vpe_clk_rate = clk_round_rate(camio_vpe_clk, vpe_clk_rate);
+ clk_set_rate(camio_vpe_clk, vpe_clk_rate);
+ break;
+
+ case CAMIO_VPE_PCLK:
+ camio_vpe_pclk =
+ clk = clk_get(NULL, "vpe_pclk");
+ break;
+
+ default:
+ break;
+ }
+
+ if (!IS_ERR(clk)) {
+ clk_prepare(clk);
+ clk_enable(clk);
+ } else {
+ rc = -1;
+ }
+ return rc;
+}
+
+int msm_camio_clk_disable(enum msm_camio_clk_type clktype)
+{
+ int rc = 0;
+ struct clk *clk = NULL;
+
+ switch (clktype) {
+ case CAMIO_JPEG_CLK:
+ clk = camio_jpeg_clk;
+ break;
+
+ case CAMIO_JPEG_PCLK:
+ clk = camio_jpeg_pclk;
+ break;
+
+ case CAMIO_VPE_CLK:
+ clk = camio_vpe_clk;
+ break;
+
+ case CAMIO_VPE_PCLK:
+ clk = camio_vpe_pclk;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!IS_ERR(clk)) {
+ clk_disable(clk);
+ clk_unprepare(clk);
+ clk_put(clk);
+ } else {
+ rc = -1;
+ }
+
+ return rc;
+}
+
+int msm_camio_vfe_clk_rate_set(int rate)
+{
+ int rc = 0;
+ struct clk *clk = camio_vfe_clk;
+ if (rate > clk_get_rate(clk))
+ rc = clk_set_rate(clk, rate);
+ return rc;
+}
+
+void msm_camio_clk_rate_set_2(struct clk *clk, int rate)
+{
+ clk_set_rate(clk, rate);
+}
+
+int msm_camio_jpeg_clk_disable(void)
+{
+ int rc = 0;
+ if (fs_ijpeg) {
+ rc = regulator_disable(fs_ijpeg);
+ if (rc < 0) {
+ CDBG("%s: Regulator disable failed %d\n", __func__, rc);
+ return rc;
+ }
+ regulator_put(fs_ijpeg);
+ }
+ rc = msm_camio_clk_disable(CAMIO_JPEG_PCLK);
+ if (rc < 0)
+ return rc;
+ rc = msm_camio_clk_disable(CAMIO_JPEG_CLK);
+ CDBG("%s: exit %d\n", __func__, rc);
+ return rc;
+}
+
+int msm_camio_jpeg_clk_enable(void)
+{
+ int rc = 0;
+ rc = msm_camio_clk_enable(CAMIO_JPEG_CLK);
+ if (rc < 0)
+ return rc;
+ rc = msm_camio_clk_enable(CAMIO_JPEG_PCLK);
+ if (rc < 0)
+ return rc;
+ fs_ijpeg = regulator_get(NULL, "fs_ijpeg");
+ if (IS_ERR(fs_ijpeg)) {
+ CDBG("%s: Regulator FS_IJPEG get failed %ld\n", __func__,
+ PTR_ERR(fs_ijpeg));
+ fs_ijpeg = NULL;
+ } else if (regulator_enable(fs_ijpeg)) {
+ CDBG("%s: Regulator FS_IJPEG enable failed\n", __func__);
+ regulator_put(fs_ijpeg);
+ }
+ CDBG("%s: exit %d\n", __func__, rc);
+ return rc;
+}
+
+int msm_camio_vpe_clk_disable(void)
+{
+ int rc = 0;
+ if (fs_vpe) {
+ regulator_disable(fs_vpe);
+ regulator_put(fs_vpe);
+ }
+
+ rc = msm_camio_clk_disable(CAMIO_VPE_CLK);
+ if (rc < 0)
+ return rc;
+ rc = msm_camio_clk_disable(CAMIO_VPE_PCLK);
+ return rc;
+}
+
+int msm_camio_vpe_clk_enable(uint32_t clk_rate)
+{
+ int rc = 0;
+ fs_vpe = regulator_get(NULL, "fs_vpe");
+ if (IS_ERR(fs_vpe)) {
+ CDBG("%s: Regulator FS_VPE get failed %ld\n", __func__,
+ PTR_ERR(fs_vpe));
+ fs_vpe = NULL;
+ } else if (regulator_enable(fs_vpe)) {
+ CDBG("%s: Regulator FS_VPE enable failed\n", __func__);
+ regulator_put(fs_vpe);
+ }
+
+ vpe_clk_rate = clk_rate;
+ rc = msm_camio_clk_enable(CAMIO_VPE_CLK);
+ if (rc < 0)
+ return rc;
+
+ rc = msm_camio_clk_enable(CAMIO_VPE_PCLK);
+ return rc;
+}
+
+void msm_camio_vfe_blk_reset(void)
+{
+ return;
+}
+
+static void msm_camio_axi_cfg(enum msm_bus_perf_setting perf_setting)
+{
+ switch (perf_setting) {
+ case S_INIT:
+ add_axi_qos();
+ break;
+ case S_PREVIEW:
+ update_axi_qos(MSM_AXI_QOS_PREVIEW);
+ break;
+ case S_VIDEO:
+ update_axi_qos(MSM_AXI_QOS_RECORDING);
+ break;
+ case S_CAPTURE:
+ update_axi_qos(MSM_AXI_QOS_SNAPSHOT);
+ break;
+ case S_DEFAULT:
+ update_axi_qos(PM_QOS_DEFAULT_VALUE);
+ break;
+ case S_EXIT:
+ release_axi_qos();
+ break;
+ default:
+ CDBG("%s: INVALID CASE\n", __func__);
+ }
+}
+
+void msm_camio_bus_scale_cfg(struct msm_bus_scale_pdata *cam_bus_scale_table,
+ enum msm_bus_perf_setting perf_setting)
+{
+ static uint32_t bus_perf_client;
+ int rc = 0;
+ if (cam_bus_scale_table == NULL) {
+ msm_camio_axi_cfg(perf_setting);
+ return;
+ }
+
+ switch (perf_setting) {
+ case S_INIT:
+ bus_perf_client =
+ msm_bus_scale_register_client(cam_bus_scale_table);
+ if (!bus_perf_client) {
+ pr_err("%s: Registration Failed!!!\n", __func__);
+ bus_perf_client = 0;
+ return;
+ }
+ CDBG("%s: S_INIT rc = %u\n", __func__, bus_perf_client);
+ break;
+ case S_EXIT:
+ if (bus_perf_client) {
+ CDBG("%s: S_EXIT\n", __func__);
+ msm_bus_scale_unregister_client(bus_perf_client);
+ } else
+ pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+ break;
+ case S_PREVIEW:
+ if (bus_perf_client) {
+ rc = msm_bus_scale_client_update_request(
+ bus_perf_client, 1);
+ CDBG("%s: S_PREVIEW rc = %d\n", __func__, rc);
+ } else
+ pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+ break;
+ case S_VIDEO:
+ if (bus_perf_client) {
+ rc = msm_bus_scale_client_update_request(
+ bus_perf_client, 2);
+ CDBG("%s: S_VIDEO rc = %d\n", __func__, rc);
+ } else
+ pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+ break;
+ case S_CAPTURE:
+ if (bus_perf_client) {
+ rc = msm_bus_scale_client_update_request(
+ bus_perf_client, 3);
+ CDBG("%s: S_CAPTURE rc = %d\n", __func__, rc);
+ } else
+ pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+ break;
+
+ case S_ZSL:
+ if (bus_perf_client) {
+ rc = msm_bus_scale_client_update_request(
+ bus_perf_client, 4);
+ CDBG("%s: S_ZSL rc = %d\n", __func__, rc);
+ } else
+ pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+ break;
+ case S_STEREO_VIDEO:
+ if (bus_perf_client) {
+ rc = msm_bus_scale_client_update_request(
+ bus_perf_client, 5);
+ CDBG("%s: S_STEREO_VIDEO rc = %d\n", __func__, rc);
+ } else
+ pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+ break;
+ case S_STEREO_CAPTURE:
+ if (bus_perf_client) {
+ rc = msm_bus_scale_client_update_request(
+ bus_perf_client, 6);
+ CDBG("%s: S_STEREO_VIDEO rc = %d\n", __func__, rc);
+ } else
+ pr_err("%s: Bus Client NOT Registered!!!\n", __func__);
+ break;
+ case S_DEFAULT:
+ break;
+ default:
+ pr_warning("%s: INVALID CASE\n", __func__);
+ }
+}
+
diff --git a/drivers/media/video/msm/msm_mctl.c b/drivers/media/video/msm/msm_mctl.c
index d7ec5b4..3031e1f 100644
--- a/drivers/media/video/msm/msm_mctl.c
+++ b/drivers/media/video/msm/msm_mctl.c
@@ -632,6 +632,22 @@
goto msm_open_done;
}
+ /* then sensor - move sub dev later*/
+ rc = v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 1);
+
+ if (rc < 0) {
+ pr_err("%s: isp init failed: %d\n", __func__, rc);
+ goto msm_open_done;
+ }
+ if (sync->actctrl.a_power_up)
+ rc = sync->actctrl.a_power_up(
+ sync->sdata->actuator_info);
+
+ if (rc < 0) {
+ pr_err("%s: act power failed:%d\n", __func__, rc);
+ goto msm_open_done;
+ }
+
if (camdev->is_csiphy) {
rc = v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
VIDIOC_MSM_CSIPHY_INIT, NULL);
@@ -683,22 +699,6 @@
}
}
- /* then sensor - move sub dev later*/
- rc = v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 1);
-
- if (rc < 0) {
- pr_err("%s: isp init failed: %d\n", __func__, rc);
- goto msm_open_done;
- }
- if (sync->actctrl.a_power_up)
- rc = sync->actctrl.a_power_up(
- sync->sdata->actuator_info);
-
- if (rc < 0) {
- pr_err("%s: act power failed:%d\n", __func__, rc);
- goto msm_open_done;
- }
-
if (camdev->is_ispif) {
pm_qos_add_request(&p_mctl->pm_qos_req_list,
PM_QOS_CPU_DMA_LATENCY,
@@ -728,6 +728,11 @@
VIDIOC_MSM_ISPIF_RELEASE, NULL);
}
+ if (camdev->is_csic) {
+ v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
+ VIDIOC_MSM_CSIC_RELEASE, NULL);
+ }
+
if (p_mctl->isp_sdev && p_mctl->isp_sdev->isp_release)
p_mctl->isp_sdev->isp_release(&p_mctl->sync,
p_mctl->gemini_sdev);
@@ -737,26 +742,22 @@
VIDIOC_MSM_CSID_RELEASE, NULL);
}
- if (camdev->is_csic) {
- v4l2_subdev_call(p_mctl->csic_sdev, core, ioctl,
- VIDIOC_MSM_CSIC_RELEASE, NULL);
- }
-
if (camdev->is_csiphy) {
v4l2_subdev_call(p_mctl->csiphy_sdev, core, ioctl,
VIDIOC_MSM_CSIPHY_RELEASE, NULL);
}
- if (p_mctl->sync.actctrl.a_power_down)
- p_mctl->sync.actctrl.a_power_down(
- p_mctl->sync.sdata->actuator_info);
-
- v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 0);
if (camdev->is_ispif) {
pm_qos_update_request(&p_mctl->pm_qos_req_list,
PM_QOS_DEFAULT_VALUE);
pm_qos_remove_request(&p_mctl->pm_qos_req_list);
}
+ if (p_mctl->sync.actctrl.a_power_down)
+ p_mctl->sync.actctrl.a_power_down(
+ p_mctl->sync.sdata->actuator_info);
+
+ v4l2_subdev_call(p_mctl->sensor_sdev, core, s_power, 0);
+
wake_unlock(&p_mctl->sync.wake_lock);
return rc;
}
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.c b/drivers/media/video/msm/msm_vfe31_v4l2.c
new file mode 100644
index 0000000..1f17ebe
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.c
@@ -0,0 +1,3850 @@
+/* Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/uaccess.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/atomic.h>
+#include <linux/regulator/consumer.h>
+#include <linux/clk.h>
+#include <mach/clk.h>
+#include <mach/irqs.h>
+#include <mach/camera.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/msm_isp.h>
+
+#include "msm.h"
+#include "msm_vfe31_v4l2.h"
+
+atomic_t irq_cnt;
+
+#define BUFF_SIZE_128 128
+
+#define VFE31_AXI_OFFSET 0x0050
+#define vfe31_get_ch_ping_addr(chn) \
+ (msm_io_r(vfe31_ctrl->vfebase + 0x0050 + 0x18 * (chn)))
+#define vfe31_get_ch_pong_addr(chn) \
+ (msm_io_r(vfe31_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4))
+#define vfe31_get_ch_addr(ping_pong, chn) \
+ (((ping_pong) & (1 << (chn))) == 0 ? \
+ vfe31_get_ch_pong_addr(chn) : vfe31_get_ch_ping_addr(chn))
+
+#define vfe31_put_ch_ping_addr(chn, addr) \
+ (msm_io_w((addr), vfe31_ctrl->vfebase + 0x0050 + 0x18 * (chn)))
+#define vfe31_put_ch_pong_addr(chn, addr) \
+ (msm_io_w((addr), vfe31_ctrl->vfebase + 0x0050 + 0x18 * (chn) + 4))
+#define vfe31_put_ch_addr(ping_pong, chn, addr) \
+ (((ping_pong) & (1 << (chn))) == 0 ? \
+ vfe31_put_ch_pong_addr((chn), (addr)) : \
+ vfe31_put_ch_ping_addr((chn), (addr)))
+
+#define VFE_CLK_RATE 153600000
+#define CAMIF_CFG_RMSK 0x1fffff
+
+static struct vfe31_ctrl_type *vfe31_ctrl;
+static void *vfe_syncdata;
+static uint32_t vfe_clk_rate;
+
+struct vfe31_isr_queue_cmd {
+ struct list_head list;
+ uint32_t vfeInterruptStatus0;
+ uint32_t vfeInterruptStatus1;
+};
+
+/*TODO: Why is V32 reference in arch/arm/mach-msm/include/mach/camera.h?*/
+#define VFE_MSG_V31_START VFE_MSG_V32_START
+#define VFE_MSG_V31_CAPTURE VFE_MSG_V32_CAPTURE
+#define VFE_MSG_V31_JPEG_CAPTURE VFE_MSG_V32_JPEG_CAPTURE
+#define VFE_MSG_V31_START_RECORDING VFE_MSG_V32_START_RECORDING
+
+static struct vfe31_cmd_type vfe31_cmd[] = {
+/* 0*/ {VFE_CMD_DUMMY_0},
+ {VFE_CMD_SET_CLK},
+ {VFE_CMD_RESET},
+ {VFE_CMD_START},
+ {VFE_CMD_TEST_GEN_START},
+/* 5*/ {VFE_CMD_OPERATION_CFG, V31_OPERATION_CFG_LEN},
+ {VFE_CMD_AXI_OUT_CFG, V31_AXI_OUT_LEN, V31_AXI_OUT_OFF, 0xFF},
+ {VFE_CMD_CAMIF_CFG, V31_CAMIF_LEN, V31_CAMIF_OFF, 0xFF},
+ {VFE_CMD_AXI_INPUT_CFG},
+ {VFE_CMD_BLACK_LEVEL_CFG, V31_BLACK_LEVEL_LEN,
+ V31_BLACK_LEVEL_OFF,
+ 0xFF},
+/*10*/ {VFE_CMD_MESH_ROLL_OFF_CFG, V31_MESH_ROLL_OFF_CFG_LEN,
+ V31_MESH_ROLL_OFF_CFG_OFF, 0xFF},
+ {VFE_CMD_DEMUX_CFG, V31_DEMUX_LEN, V31_DEMUX_OFF, 0xFF},
+ {VFE_CMD_FOV_CFG, V31_FOV_LEN, V31_FOV_OFF, 0xFF},
+ {VFE_CMD_MAIN_SCALER_CFG, V31_MAIN_SCALER_LEN,
+ V31_MAIN_SCALER_OFF, 0xFF},
+ {VFE_CMD_WB_CFG, V31_WB_LEN, V31_WB_OFF, 0xFF},
+/*15*/ {VFE_CMD_COLOR_COR_CFG, V31_COLOR_COR_LEN, V31_COLOR_COR_OFF, 0xFF},
+ {VFE_CMD_RGB_G_CFG, V31_RGB_G_LEN, V31_RGB_G_OFF, 0xFF},
+ {VFE_CMD_LA_CFG, V31_LA_LEN, V31_LA_OFF, 0xFF },
+ {VFE_CMD_CHROMA_EN_CFG, V31_CHROMA_EN_LEN, V31_CHROMA_EN_OFF,
+ 0xFF},
+ {VFE_CMD_CHROMA_SUP_CFG, V31_CHROMA_SUP_LEN, V31_CHROMA_SUP_OFF,
+ 0xFF},
+/*20*/ {VFE_CMD_MCE_CFG, V31_MCE_LEN, V31_MCE_OFF, 0xFF},
+ {VFE_CMD_SK_ENHAN_CFG, V31_SCE_LEN, V31_SCE_OFF, 0xFF},
+ {VFE_CMD_ASF_CFG, V31_ASF_LEN, V31_ASF_OFF, 0xFF},
+ {VFE_CMD_S2Y_CFG, V31_S2Y_LEN, V31_S2Y_OFF, 0xFF},
+ {VFE_CMD_S2CbCr_CFG, V31_S2CbCr_LEN, V31_S2CbCr_OFF, 0xFF},
+/*25*/ {VFE_CMD_CHROMA_SUBS_CFG, V31_CHROMA_SUBS_LEN, V31_CHROMA_SUBS_OFF,
+ 0xFF},
+ {VFE_CMD_OUT_CLAMP_CFG, V31_OUT_CLAMP_LEN, V31_OUT_CLAMP_OFF,
+ 0xFF},
+ {VFE_CMD_FRAME_SKIP_CFG, V31_FRAME_SKIP_LEN, V31_FRAME_SKIP_OFF,
+ 0xFF},
+ {VFE_CMD_DUMMY_1},
+ {VFE_CMD_DUMMY_2},
+/*30*/ {VFE_CMD_DUMMY_3},
+ {VFE_CMD_UPDATE},
+ {VFE_CMD_BL_LVL_UPDATE, V31_BLACK_LEVEL_LEN,
+ V31_BLACK_LEVEL_OFF, 0xFF},
+ {VFE_CMD_DEMUX_UPDATE, V31_DEMUX_LEN, V31_DEMUX_OFF, 0xFF},
+ {VFE_CMD_FOV_UPDATE, V31_FOV_LEN, V31_FOV_OFF, 0xFF},
+/*35*/ {VFE_CMD_MAIN_SCALER_UPDATE, V31_MAIN_SCALER_LEN, V31_MAIN_SCALER_OFF,
+ 0xFF},
+ {VFE_CMD_WB_UPDATE, V31_WB_LEN, V31_WB_OFF, 0xFF},
+ {VFE_CMD_COLOR_COR_UPDATE, V31_COLOR_COR_LEN, V31_COLOR_COR_OFF,
+ 0xFF},
+ {VFE_CMD_RGB_G_UPDATE, V31_RGB_G_LEN, V31_CHROMA_EN_OFF, 0xFF},
+ {VFE_CMD_LA_UPDATE, V31_LA_LEN, V31_LA_OFF, 0xFF },
+/*40*/ {VFE_CMD_CHROMA_EN_UPDATE, V31_CHROMA_EN_LEN, V31_CHROMA_EN_OFF,
+ 0xFF},
+ {VFE_CMD_CHROMA_SUP_UPDATE, V31_CHROMA_SUP_LEN,
+ V31_CHROMA_SUP_OFF, 0xFF},
+ {VFE_CMD_MCE_UPDATE, V31_MCE_LEN, V31_MCE_OFF, 0xFF},
+ {VFE_CMD_SK_ENHAN_UPDATE, V31_SCE_LEN, V31_SCE_OFF, 0xFF},
+ {VFE_CMD_S2CbCr_UPDATE, V31_S2CbCr_LEN, V31_S2CbCr_OFF, 0xFF},
+/*45*/ {VFE_CMD_S2Y_UPDATE, V31_S2Y_LEN, V31_S2Y_OFF, 0xFF},
+ {VFE_CMD_ASF_UPDATE, V31_ASF_UPDATE_LEN, V31_ASF_OFF, 0xFF},
+ {VFE_CMD_FRAME_SKIP_UPDATE},
+ {VFE_CMD_CAMIF_FRAME_UPDATE},
+ {VFE_CMD_STATS_AF_UPDATE, V31_STATS_AF_LEN, V31_STATS_AF_OFF},
+/*50*/ {VFE_CMD_STATS_AE_UPDATE, V31_STATS_AE_LEN, V31_STATS_AE_OFF},
+ {VFE_CMD_STATS_AWB_UPDATE, V31_STATS_AWB_LEN,
+ V31_STATS_AWB_OFF},
+ {VFE_CMD_STATS_RS_UPDATE, V31_STATS_RS_LEN, V31_STATS_RS_OFF},
+ {VFE_CMD_STATS_CS_UPDATE, V31_STATS_CS_LEN, V31_STATS_CS_OFF},
+ {VFE_CMD_STATS_SKIN_UPDATE},
+/*55*/ {VFE_CMD_STATS_IHIST_UPDATE, V31_STATS_IHIST_LEN, V31_STATS_IHIST_OFF},
+ {VFE_CMD_DUMMY_4},
+ {VFE_CMD_EPOCH1_ACK},
+ {VFE_CMD_EPOCH2_ACK},
+ {VFE_CMD_START_RECORDING},
+/*60*/ {VFE_CMD_STOP_RECORDING},
+ {VFE_CMD_DUMMY_5},
+ {VFE_CMD_DUMMY_6},
+ {VFE_CMD_CAPTURE, V31_CAPTURE_LEN, 0xFF},
+ {VFE_CMD_DUMMY_7},
+/*65*/ {VFE_CMD_STOP},
+ {VFE_CMD_GET_HW_VERSION, V31_GET_HW_VERSION_LEN,
+ V31_GET_HW_VERSION_OFF},
+ {VFE_CMD_GET_FRAME_SKIP_COUNTS},
+ {VFE_CMD_OUTPUT1_BUFFER_ENQ},
+ {VFE_CMD_OUTPUT2_BUFFER_ENQ},
+/*70*/ {VFE_CMD_OUTPUT3_BUFFER_ENQ},
+ {VFE_CMD_JPEG_OUT_BUF_ENQ},
+ {VFE_CMD_RAW_OUT_BUF_ENQ},
+ {VFE_CMD_RAW_IN_BUF_ENQ},
+ {VFE_CMD_STATS_AF_ENQ},
+/*75*/ {VFE_CMD_STATS_AE_ENQ},
+ {VFE_CMD_STATS_AWB_ENQ},
+ {VFE_CMD_STATS_RS_ENQ},
+ {VFE_CMD_STATS_CS_ENQ},
+ {VFE_CMD_STATS_SKIN_ENQ},
+/*80*/ {VFE_CMD_STATS_IHIST_ENQ},
+ {VFE_CMD_DUMMY_8},
+ {VFE_CMD_JPEG_ENC_CFG},
+ {VFE_CMD_DUMMY_9},
+ {VFE_CMD_STATS_AF_START, V31_STATS_AF_LEN, V31_STATS_AF_OFF},
+/*85*/ {VFE_CMD_STATS_AF_STOP},
+ {VFE_CMD_STATS_AE_START, V31_STATS_AE_LEN, V31_STATS_AE_OFF},
+ {VFE_CMD_STATS_AE_STOP},
+ {VFE_CMD_STATS_AWB_START, V31_STATS_AWB_LEN, V31_STATS_AWB_OFF},
+ {VFE_CMD_STATS_AWB_STOP},
+/*90*/ {VFE_CMD_STATS_RS_START, V31_STATS_RS_LEN, V31_STATS_RS_OFF},
+ {VFE_CMD_STATS_RS_STOP},
+ {VFE_CMD_STATS_CS_START, V31_STATS_CS_LEN, V31_STATS_CS_OFF},
+ {VFE_CMD_STATS_CS_STOP},
+ {VFE_CMD_STATS_SKIN_START},
+/*95*/ {VFE_CMD_STATS_SKIN_STOP},
+ {VFE_CMD_STATS_IHIST_START,
+ V31_STATS_IHIST_LEN, V31_STATS_IHIST_OFF},
+ {VFE_CMD_STATS_IHIST_STOP},
+ {VFE_CMD_DUMMY_10},
+ {VFE_CMD_SYNC_TIMER_SETTING, V31_SYNC_TIMER_LEN,
+ V31_SYNC_TIMER_OFF},
+/*100*/ {VFE_CMD_ASYNC_TIMER_SETTING, V31_ASYNC_TIMER_LEN, V31_ASYNC_TIMER_OFF},
+ {VFE_CMD_LIVESHOT},
+ {VFE_CMD_LA_SETUP},
+ {VFE_CMD_LINEARIZATION_CFG},
+ {VFE_CMD_DEMOSAICV3},
+/*105*/ {VFE_CMD_DEMOSAICV3_ABCC_CFG},
+ {VFE_CMD_DEMOSAICV3_DBCC_CFG},
+ {VFE_CMD_DEMOSAICV3_DBPC_CFG, V31_DEMOSAICV3_DBPC_LEN,
+ V31_DEMOSAICV3_DBPC_CFG_OFF},
+ {VFE_CMD_DEMOSAICV3_ABF_CFG, V31_DEMOSAICV3_ABF_LEN,
+ V31_DEMOSAICV3_ABF_OFF},
+ {VFE_CMD_DEMOSAICV3_ABCC_UPDATE},
+/*110*/ {VFE_CMD_DEMOSAICV3_DBCC_UPDATE},
+ {VFE_CMD_DEMOSAICV3_DBPC_UPDATE, V31_DEMOSAICV3_DBPC_LEN,
+ V31_DEMOSAICV3_DBPC_CFG_OFF},
+ {VFE_CMD_XBAR_CFG},
+ {VFE_CMD_MODULE_CFG, V31_MODULE_CFG_LEN, V31_MODULE_CFG_OFF},
+ {VFE_CMD_ZSL},
+/*115*/ {VFE_CMD_LINEARIZATION_UPDATE},
+ {VFE_CMD_DEMOSAICV3_ABF_UPDATE, V31_DEMOSAICV3_ABF_LEN,
+ V31_DEMOSAICV3_ABF_OFF},
+ {VFE_CMD_CLF_CFG},
+ {VFE_CMD_CLF_LUMA_UPDATE},
+ {VFE_CMD_CLF_CHROMA_UPDATE},
+/*120*/ {VFE_CMD_PCA_ROLL_OFF_CFG},
+ {VFE_CMD_PCA_ROLL_OFF_UPDATE},
+ {VFE_CMD_GET_REG_DUMP},
+ {VFE_CMD_GET_LINEARIZATON_TABLE},
+ {VFE_CMD_GET_MESH_ROLLOFF_TABLE},
+/*125*/ {VFE_CMD_GET_PCA_ROLLOFF_TABLE},
+ {VFE_CMD_GET_RGB_G_TABLE},
+ {VFE_CMD_GET_LA_TABLE},
+ {VFE_CMD_DEMOSAICV3_UPDATE},
+};
+
+uint32_t vfe31_AXI_WM_CFG[] = {
+ 0x0000004C,
+ 0x00000064,
+ 0x0000007C,
+ 0x00000094,
+ 0x000000AC,
+ 0x000000C4,
+ 0x000000DC,
+};
+
+static const char * const vfe31_general_cmd[] = {
+ "DUMMY_0", /* 0 */
+ "SET_CLK",
+ "RESET",
+ "START",
+ "TEST_GEN_START",
+ "OPERATION_CFG", /* 5 */
+ "AXI_OUT_CFG",
+ "CAMIF_CFG",
+ "AXI_INPUT_CFG",
+ "BLACK_LEVEL_CFG",
+ "ROLL_OFF_CFG", /* 10 */
+ "DEMUX_CFG",
+ "FOV_CFG",
+ "MAIN_SCALER_CFG",
+ "WB_CFG",
+ "COLOR_COR_CFG", /* 15 */
+ "RGB_G_CFG",
+ "LA_CFG",
+ "CHROMA_EN_CFG",
+ "CHROMA_SUP_CFG",
+ "MCE_CFG", /* 20 */
+ "SK_ENHAN_CFG",
+ "ASF_CFG",
+ "S2Y_CFG",
+ "S2CbCr_CFG",
+ "CHROMA_SUBS_CFG", /* 25 */
+ "OUT_CLAMP_CFG",
+ "FRAME_SKIP_CFG",
+ "DUMMY_1",
+ "DUMMY_2",
+ "DUMMY_3", /* 30 */
+ "UPDATE",
+ "BL_LVL_UPDATE",
+ "DEMUX_UPDATE",
+ "FOV_UPDATE",
+ "MAIN_SCALER_UPDATE", /* 35 */
+ "WB_UPDATE",
+ "COLOR_COR_UPDATE",
+ "RGB_G_UPDATE",
+ "LA_UPDATE",
+ "CHROMA_EN_UPDATE", /* 40 */
+ "CHROMA_SUP_UPDATE",
+ "MCE_UPDATE",
+ "SK_ENHAN_UPDATE",
+ "S2CbCr_UPDATE",
+ "S2Y_UPDATE", /* 45 */
+ "ASF_UPDATE",
+ "FRAME_SKIP_UPDATE",
+ "CAMIF_FRAME_UPDATE",
+ "STATS_AF_UPDATE",
+ "STATS_AE_UPDATE", /* 50 */
+ "STATS_AWB_UPDATE",
+ "STATS_RS_UPDATE",
+ "STATS_CS_UPDATE",
+ "STATS_SKIN_UPDATE",
+ "STATS_IHIST_UPDATE", /* 55 */
+ "DUMMY_4",
+ "EPOCH1_ACK",
+ "EPOCH2_ACK",
+ "START_RECORDING",
+ "STOP_RECORDING", /* 60 */
+ "DUMMY_5",
+ "DUMMY_6",
+ "CAPTURE",
+ "DUMMY_7",
+ "STOP", /* 65 */
+ "GET_HW_VERSION",
+ "GET_FRAME_SKIP_COUNTS",
+ "OUTPUT1_BUFFER_ENQ",
+ "OUTPUT2_BUFFER_ENQ",
+ "OUTPUT3_BUFFER_ENQ", /* 70 */
+ "JPEG_OUT_BUF_ENQ",
+ "RAW_OUT_BUF_ENQ",
+ "RAW_IN_BUF_ENQ",
+ "STATS_AF_ENQ",
+ "STATS_AE_ENQ", /* 75 */
+ "STATS_AWB_ENQ",
+ "STATS_RS_ENQ",
+ "STATS_CS_ENQ",
+ "STATS_SKIN_ENQ",
+ "STATS_IHIST_ENQ", /* 80 */
+ "DUMMY_8",
+ "JPEG_ENC_CFG",
+ "DUMMY_9",
+ "STATS_AF_START",
+ "STATS_AF_STOP", /* 85 */
+ "STATS_AE_START",
+ "STATS_AE_STOP",
+ "STATS_AWB_START",
+ "STATS_AWB_STOP",
+ "STATS_RS_START", /* 90 */
+ "STATS_RS_STOP",
+ "STATS_CS_START",
+ "STATS_CS_STOP",
+ "STATS_SKIN_START",
+ "STATS_SKIN_STOP", /* 95 */
+ "STATS_IHIST_START",
+ "STATS_IHIST_STOP",
+ "DUMMY_10",
+ "SYNC_TIMER_SETTING",
+ "ASYNC_TIMER_SETTING", /* 100 */
+ "LIVESHOT",
+ "LA_SETUP",
+ "LINEARIZATION_CFG",
+ "DEMOSAICV3",
+ "DEMOSAICV3_ABCC_CFG", /* 105 */
+ "DEMOSAICV3_DBCC_CFG",
+ "DEMOSAICV3_DBPC_CFG",
+ "DEMOSAICV3_ABF_CFG",
+ "DEMOSAICV3_ABCC_UPDATE",
+ "DEMOSAICV3_DBCC_UPDATE", /* 110 */
+ "DEMOSAICV3_DBPC_UPDATE",
+ "XBAR_CFG",
+ "EZTUNE_CFG",
+ "V31_ZSL",
+ "LINEARIZATION_UPDATE", /*115*/
+ "DEMOSAICV3_ABF_UPDATE",
+ "CLF_CFG",
+ "CLF_LUMA_UPDATE",
+ "CLF_CHROMA_UPDATE",
+ "PCA_ROLL_OFF_CFG", /*120*/
+ "PCA_ROLL_OFF_UPDATE",
+ "GET_REG_DUMP",
+ "GET_LINEARIZATON_TABLE",
+ "GET_MESH_ROLLOFF_TABLE",
+ "GET_PCA_ROLLOFF_TABLE", /*125*/
+ "GET_RGB_G_TABLE",
+ "GET_LA_TABLE",
+ "DEMOSAICV3_UPDATE",
+};
+
+static void vfe31_stop(void)
+{
+ unsigned long flags;
+
+ atomic_set(&vfe31_ctrl->vstate, 0);
+
+ /* for reset hw modules, and send msg when reset_irq comes.*/
+ spin_lock_irqsave(&vfe31_ctrl->stop_flag_lock, flags);
+ vfe31_ctrl->stop_ack_pending = TRUE;
+ spin_unlock_irqrestore(&vfe31_ctrl->stop_flag_lock, flags);
+
+ /* disable all interrupts. */
+ /* in either continuous or snapshot mode, stop command can be issued
+ * at any time. stop camif immediately. */
+ msm_io_w_mb(CAMIF_COMMAND_STOP_IMMEDIATELY,
+ vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND);
+
+ /* disable all interrupts. */
+ msm_io_w(VFE_DISABLE_ALL_IRQS,
+ vfe31_ctrl->vfebase + VFE_IRQ_MASK_0);
+ msm_io_w(VFE_DISABLE_ALL_IRQS,
+ vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* clear all pending interrupts*/
+ msm_io_w(VFE_CLEAR_ALL_IRQS,
+ vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ msm_io_w(VFE_CLEAR_ALL_IRQS,
+ vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_io_w_mb(1,
+ vfe31_ctrl->vfebase + VFE_IRQ_CMD);
+
+ /* now enable only halt_irq & reset_irq */
+ msm_io_w(0xf0000000, /* this is for async timer. */
+ vfe31_ctrl->vfebase + VFE_IRQ_MASK_0);
+ msm_io_w(VFE_IMASK_WHILE_STOPPING_1,
+ vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* then apply axi halt command. */
+ msm_io_w_mb(AXI_HALT,
+ vfe31_ctrl->vfebase + VFE_AXI_CMD);
+
+ msm_io_w_mb(VFE_RESET_UPON_STOP_CMD,
+ vfe31_ctrl->vfebase + VFE_GLOBAL_RESET);
+}
+
+static void vfe31_subdev_notify(int id, int path)
+{
+ struct msm_vfe_resp *rp;
+ unsigned long flags;
+ spin_lock_irqsave(&vfe31_ctrl->sd_notify_lock, flags);
+ rp = msm_isp_sync_alloc(sizeof(struct msm_vfe_resp), GFP_ATOMIC);
+ if (!rp) {
+ CDBG("rp: cannot allocate buffer\n");
+ spin_unlock_irqrestore(&vfe31_ctrl->sd_notify_lock, flags);
+ return;
+ }
+ CDBG("vfe31_subdev_notify : msgId = %d\n", id);
+ rp->evt_msg.type = MSM_CAMERA_MSG;
+ rp->evt_msg.msg_id = path;
+ rp->type = id;
+ v4l2_subdev_notify(&vfe31_ctrl->subdev, NOTIFY_VFE_BUF_EVT, rp);
+ spin_unlock_irqrestore(&vfe31_ctrl->sd_notify_lock, flags);
+}
+
+static int vfe31_config_axi(int mode, uint32_t *ao)
+{
+ uint32_t *ch_info;
+ uint32_t *axi_cfg = ao+V31_AXI_RESERVED;
+ /* Update the corresponding write masters for each output*/
+ ch_info = axi_cfg + V31_AXI_CFG_LEN;
+ vfe31_ctrl->outpath.out0.ch0 = 0x0000FFFF & *ch_info;
+ vfe31_ctrl->outpath.out0.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
+ vfe31_ctrl->outpath.out0.ch2 = 0x0000FFFF & *ch_info++;
+ vfe31_ctrl->outpath.out1.ch0 = 0x0000FFFF & *ch_info;
+ vfe31_ctrl->outpath.out1.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
+ vfe31_ctrl->outpath.out1.ch2 = 0x0000FFFF & *ch_info++;
+ vfe31_ctrl->outpath.out2.ch0 = 0x0000FFFF & *ch_info;
+ vfe31_ctrl->outpath.out2.ch1 = 0x0000FFFF & (*ch_info++ >> 16);
+ vfe31_ctrl->outpath.out2.ch2 = 0x0000FFFF & *ch_info++;
+
+ switch (mode) {
+ case OUTPUT_PRIM:
+ vfe31_ctrl->outpath.output_mode =
+ VFE31_OUTPUT_MODE_PRIMARY;
+ break;
+ case OUTPUT_PRIM_ALL_CHNLS:
+ vfe31_ctrl->outpath.output_mode =
+ VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+ break;
+ case OUTPUT_PRIM|OUTPUT_SEC:
+ vfe31_ctrl->outpath.output_mode =
+ VFE31_OUTPUT_MODE_PRIMARY;
+ vfe31_ctrl->outpath.output_mode |=
+ VFE31_OUTPUT_MODE_SECONDARY;
+ break;
+ case OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS:
+ vfe31_ctrl->outpath.output_mode =
+ VFE31_OUTPUT_MODE_PRIMARY;
+ vfe31_ctrl->outpath.output_mode |=
+ VFE31_OUTPUT_MODE_SECONDARY_ALL_CHNLS;
+ break;
+ case OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC:
+ vfe31_ctrl->outpath.output_mode =
+ VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS;
+ vfe31_ctrl->outpath.output_mode |=
+ VFE31_OUTPUT_MODE_SECONDARY;
+ break;
+ default:
+ pr_err("%s Invalid AXI mode %d ", __func__, mode);
+ return -EINVAL;
+ }
+
+ msm_io_memcpy(vfe31_ctrl->vfebase +
+ vfe31_cmd[VFE_CMD_AXI_OUT_CFG].offset, axi_cfg,
+ vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length - V31_AXI_CH_INF_LEN -
+ V31_AXI_RESERVED);
+ return 0;
+}
+
+static void vfe31_reset_internal_variables(void)
+{
+ unsigned long flags;
+ vfe31_ctrl->vfeImaskCompositePacked = 0;
+ /* state control variables */
+ vfe31_ctrl->start_ack_pending = FALSE;
+ atomic_set(&irq_cnt, 0);
+
+ spin_lock_irqsave(&vfe31_ctrl->stop_flag_lock, flags);
+ vfe31_ctrl->stop_ack_pending = FALSE;
+ spin_unlock_irqrestore(&vfe31_ctrl->stop_flag_lock, flags);
+
+ vfe31_ctrl->reset_ack_pending = FALSE;
+
+ spin_lock_irqsave(&vfe31_ctrl->update_ack_lock, flags);
+ vfe31_ctrl->update_ack_pending = FALSE;
+ spin_unlock_irqrestore(&vfe31_ctrl->update_ack_lock, flags);
+
+ vfe31_ctrl->recording_state = VFE_STATE_IDLE;
+ vfe31_ctrl->liveshot_state = VFE_STATE_IDLE;
+
+ atomic_set(&vfe31_ctrl->vstate, 0);
+
+ /* 0 for continuous mode, 1 for snapshot mode */
+ vfe31_ctrl->operation_mode = 0;
+ vfe31_ctrl->outpath.output_mode = 0;
+ vfe31_ctrl->vfe_capture_count = 0;
+
+ /* this is unsigned 32 bit integer. */
+ vfe31_ctrl->vfeFrameId = 0;
+ /* Stats control variables. */
+ memset(&(vfe31_ctrl->afStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe31_ctrl->awbStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe31_ctrl->aecStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe31_ctrl->ihistStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe31_ctrl->rsStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ memset(&(vfe31_ctrl->csStatsControl), 0,
+ sizeof(struct vfe_stats_control));
+
+ vfe31_ctrl->frame_skip_cnt = 31;
+ vfe31_ctrl->frame_skip_pattern = 0xffffffff;
+ vfe31_ctrl->snapshot_frame_cnt = 0;
+}
+
+static void vfe31_reset(void)
+{
+ vfe31_reset_internal_variables();
+ /* disable all interrupts. vfeImaskLocal is also reset to 0
+ * to begin with. */
+ msm_io_w(VFE_DISABLE_ALL_IRQS,
+ vfe31_ctrl->vfebase + VFE_IRQ_MASK_0);
+
+ msm_io_w(VFE_DISABLE_ALL_IRQS,
+ vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* clear all pending interrupts*/
+ msm_io_w(VFE_CLEAR_ALL_IRQS, vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ msm_io_w(VFE_CLEAR_ALL_IRQS, vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_IRQ_CMD);
+
+ /* enable reset_ack interrupt. */
+ msm_io_w(VFE_IMASK_WHILE_STOPPING_1,
+ vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* Write to VFE_GLOBAL_RESET_CMD to reset the vfe hardware. Once reset
+ * is done, hardware interrupt will be generated. VFE ist processes
+ * the interrupt to complete the function call. Note that the reset
+ * function is synchronous. */
+
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_io_w_mb(VFE_RESET_UPON_RESET_CMD,
+ vfe31_ctrl->vfebase + VFE_GLOBAL_RESET);
+}
+
+static int vfe31_operation_config(uint32_t *cmd)
+{
+ uint32_t *p = cmd;
+
+ vfe31_ctrl->operation_mode = *p;
+ vfe31_ctrl->stats_comp = *(++p);
+ vfe31_ctrl->hfr_mode = *(++p);
+
+ msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_CFG);
+ msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_REALIGN_BUF);
+ msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_CHROMA_UP);
+ msm_io_w(*(++p), vfe31_ctrl->vfebase + VFE_STATS_CFG);
+ return 0;
+}
+
+static uint32_t vfe_stats_awb_buf_init(struct vfe_cmd_stats_buf *in)
+{
+ uint32_t *ptr = in->statsBuf;
+ uint32_t addr;
+
+ addr = ptr[0];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PING_ADDR);
+ addr = ptr[1];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_WR_PONG_ADDR);
+ vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+ return 0;
+}
+
+static uint32_t vfe_stats_aec_buf_init(struct vfe_cmd_stats_buf *in)
+{
+ uint32_t *ptr = in->statsBuf;
+ uint32_t addr;
+
+ addr = ptr[0];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PING_ADDR);
+ addr = ptr[1];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_WR_PONG_ADDR);
+
+ vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+ return 0;
+}
+
+static uint32_t vfe_stats_af_buf_init(struct vfe_cmd_stats_buf *in)
+{
+ uint32_t *ptr = in->statsBuf;
+ uint32_t addr;
+
+ addr = ptr[0];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PING_ADDR);
+ addr = ptr[1];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_WR_PONG_ADDR);
+
+ vfe31_ctrl->afStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+ return 0;
+}
+
+static uint32_t vfe_stats_ihist_buf_init(struct vfe_cmd_stats_buf *in)
+{
+ uint32_t *ptr = in->statsBuf;
+ uint32_t addr;
+
+ addr = ptr[0];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PING_ADDR);
+ addr = ptr[1];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_WR_PONG_ADDR);
+
+ vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+ return 0;
+}
+
+static uint32_t vfe_stats_rs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+ uint32_t *ptr = in->statsBuf;
+ uint32_t addr;
+
+ addr = ptr[0];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PING_ADDR);
+ addr = ptr[1];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_WR_PONG_ADDR);
+
+ vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+ return 0;
+}
+
+static uint32_t vfe_stats_cs_buf_init(struct vfe_cmd_stats_buf *in)
+{
+ uint32_t *ptr = in->statsBuf;
+ uint32_t addr;
+
+ addr = ptr[0];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PING_ADDR);
+ addr = ptr[1];
+ msm_io_w(addr, vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_WR_PONG_ADDR);
+
+ vfe31_ctrl->csStatsControl.nextFrameAddrBuf = in->statsBuf[2];
+ return 0;
+}
+
+static void msm_io_dump2(void __iomem *addr, int size)
+{
+ char line_str[BUFF_SIZE_128], *p_str;
+ int i;
+ u32 *p = (u32 *) addr;
+ u32 data;
+ CDBG("%s: %p %d\n", __func__, addr, size);
+ line_str[0] = '\0';
+ p_str = line_str;
+ for (i = 0; i < size/4; i++) {
+ if (i % 4 == 0) {
+ snprintf(p_str, 12, "%08x: ", (u32) p);
+ p_str += 10;
+ }
+ data = readl_relaxed(p++);
+ snprintf(p_str, 12, "%08x ", data);
+ p_str += 9;
+ if ((i + 1) % 4 == 0) {
+ CDBG("%s\n", line_str);
+ line_str[0] = '\0';
+ p_str = line_str;
+ }
+ }
+ if (line_str[0] != '\0')
+ CDBG("%s\n", line_str);
+}
+
+static void vfe31_start_common(void)
+{
+ uint32_t irq_mask = 0x00E00021;
+ vfe31_ctrl->start_ack_pending = TRUE;
+ CDBG("VFE opertaion mode = 0x%x, output mode = 0x%x\n",
+ vfe31_ctrl->operation_mode, vfe31_ctrl->outpath.output_mode);
+ if (vfe31_ctrl->stats_comp)
+ irq_mask |= VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK;
+ else
+ irq_mask |= 0x000FE000;
+
+ msm_io_w(irq_mask, vfe31_ctrl->vfebase + VFE_IRQ_MASK_0);
+ msm_io_w(VFE_IMASK_WHILE_STOPPING_1,
+ vfe31_ctrl->vfebase + VFE_IRQ_MASK_1);
+
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND);
+
+ msm_io_dump2(vfe31_ctrl->vfebase, vfe31_ctrl->register_total*4);
+ atomic_set(&vfe31_ctrl->vstate, 1);
+}
+
+static int vfe31_start_recording(void)
+{
+ struct msm_sync *sync = vfe_syncdata;
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_VIDEO);
+ vfe31_ctrl->recording_state = VFE_STATE_START_REQUESTED;
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ return 0;
+}
+
+static int vfe31_stop_recording(void)
+{
+ struct msm_sync *sync = vfe_syncdata;
+ vfe31_ctrl->recording_state = VFE_STATE_STOP_REQUESTED;
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+ return 0;
+}
+
+static void vfe31_start_liveshot(void){
+ struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
+ if (p_sync)
+ p_sync->liveshot_enabled = true;
+
+ /* Hardcode 1 live snapshot for now. */
+ vfe31_ctrl->outpath.out0.capture_cnt = 1;
+ vfe31_ctrl->vfe_capture_count = vfe31_ctrl->outpath.out0.capture_cnt;
+
+ vfe31_ctrl->liveshot_state = VFE_STATE_START_REQUESTED;
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+}
+
+static int vfe31_zsl(void)
+{
+ struct msm_sync *sync = vfe_syncdata;
+ uint32_t irq_comp_mask = 0;
+ /* capture command is valid for both idle and active state. */
+ irq_comp_mask =
+ msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+ CDBG("%s:op mode %d O/P Mode %d\n", __func__,
+ vfe31_ctrl->operation_mode, vfe31_ctrl->outpath.output_mode);
+
+ if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PRIMARY) {
+ irq_comp_mask |= ((0x1 << (vfe31_ctrl->outpath.out0.ch0)) |
+ (0x1 << (vfe31_ctrl->outpath.out0.ch1)));
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ irq_comp_mask |= ((0x1 << (vfe31_ctrl->outpath.out0.ch0)) |
+ (0x1 << (vfe31_ctrl->outpath.out0.ch1)) |
+ (0x1 << (vfe31_ctrl->outpath.out0.ch2)));
+ }
+
+ if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_SECONDARY) {
+ irq_comp_mask |= ((0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8)) |
+ (0x1 << (vfe31_ctrl->outpath.out1.ch1 + 8)));
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ irq_comp_mask |= ((0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8)) |
+ (0x1 << (vfe31_ctrl->outpath.out1.ch1 + 8)) |
+ (0x1 << (vfe31_ctrl->outpath.out1.ch2 + 8)));
+ }
+
+ if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PRIMARY) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch2]);
+ }
+
+ if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_SECONDARY) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch2]);
+ }
+
+ msm_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ vfe31_start_common();
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_ZSL);
+
+ msm_io_w(1, vfe31_ctrl->vfebase + 0x18C);
+ msm_io_w(1, vfe31_ctrl->vfebase + 0x188);
+ return 0;
+}
+static int vfe31_capture_raw(uint32_t num_frames_capture)
+{
+ uint32_t irq_comp_mask = 0;
+ struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
+
+ vfe31_ctrl->outpath.out0.capture_cnt = num_frames_capture;
+ vfe31_ctrl->vfe_capture_count = num_frames_capture;
+
+ irq_comp_mask =
+ msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+ if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PRIMARY) {
+ irq_comp_mask |= (0x1 << (vfe31_ctrl->outpath.out0.ch0));
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ }
+
+ msm_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camio_bus_scale_cfg(
+ p_sync->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
+ vfe31_start_common();
+ return 0;
+}
+
+static int vfe31_capture(uint32_t num_frames_capture)
+{
+ uint32_t irq_comp_mask = 0;
+ struct msm_sync* p_sync = (struct msm_sync *)vfe_syncdata;
+ if (p_sync) {
+ p_sync->snap_count = num_frames_capture;
+ p_sync->thumb_count = num_frames_capture;
+ }
+ /* capture command is valid for both idle and active state. */
+ vfe31_ctrl->outpath.out1.capture_cnt = num_frames_capture;
+ if (vfe31_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_MAIN ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_JPEG) {
+ vfe31_ctrl->outpath.out0.capture_cnt =
+ num_frames_capture;
+ }
+
+ vfe31_ctrl->vfe_capture_count = num_frames_capture;
+ irq_comp_mask = msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+ if (vfe31_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_MAIN) {
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY) {
+ irq_comp_mask |= (0x1 << vfe31_ctrl->outpath.out0.ch0 |
+ 0x1 << vfe31_ctrl->outpath.out0.ch1);
+ }
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY) {
+ irq_comp_mask |=
+ (0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8) |
+ 0x1 << (vfe31_ctrl->outpath.out1.ch1 + 8));
+ }
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ }
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+ }
+ }
+
+ vfe31_ctrl->vfe_capture_count = num_frames_capture;
+
+ msm_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+ msm_camio_bus_scale_cfg(
+ p_sync->sdata->pdata->cam_bus_scale_table, S_CAPTURE);
+
+ vfe31_start_common();
+ /* for debug */
+ msm_io_w(1, vfe31_ctrl->vfebase + 0x18C);
+ msm_io_w(1, vfe31_ctrl->vfebase + 0x188);
+ return 0;
+}
+
+static int vfe31_start(void)
+{
+ uint32_t irq_comp_mask = 0;
+ struct msm_sync *sync = vfe_syncdata;
+
+ irq_comp_mask =
+ msm_io_r(vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+ if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_PRIMARY) {
+ irq_comp_mask |= (0x1 << vfe31_ctrl->outpath.out0.ch0 |
+ 0x1 << vfe31_ctrl->outpath.out0.ch1);
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ irq_comp_mask |= (0x1 << vfe31_ctrl->outpath.out0.ch0 |
+ 0x1 << vfe31_ctrl->outpath.out0.ch1 |
+ 0x1 << vfe31_ctrl->outpath.out0.ch2);
+ }
+ if (vfe31_ctrl->outpath.output_mode & VFE31_OUTPUT_MODE_SECONDARY) {
+ irq_comp_mask |= (0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8) |
+ 0x1 << (vfe31_ctrl->outpath.out1.ch1 + 8));
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ irq_comp_mask |= (0x1 << (vfe31_ctrl->outpath.out1.ch0 + 8) |
+ 0x1 << (vfe31_ctrl->outpath.out1.ch1 + 8) |
+ 0x1 << (vfe31_ctrl->outpath.out1.ch2 + 8));
+ }
+ msm_io_w(irq_comp_mask, vfe31_ctrl->vfebase + VFE_IRQ_COMP_MASK);
+
+ switch (vfe31_ctrl->operation_mode) {
+ case VFE_OUTPUTS_PREVIEW:
+ case VFE_OUTPUTS_PREVIEW_AND_VIDEO:
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch2]);
+ }
+ break;
+ default:
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+ } else if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY_ALL_CHNLS) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch2]);
+ }
+ break;
+ }
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+ vfe31_start_common();
+ return 0;
+}
+
+static void vfe31_update(void)
+{
+ unsigned long flags;
+
+ if (vfe31_ctrl->update_la) {
+ if (!msm_io_r(vfe31_ctrl->vfebase + V31_LA_OFF))
+ msm_io_w(1, vfe31_ctrl->vfebase + V31_LA_OFF);
+ else
+ msm_io_w(0, vfe31_ctrl->vfebase + V31_LA_OFF);
+ vfe31_ctrl->update_la = false;
+ }
+
+ if (vfe31_ctrl->update_gamma) {
+ if (!msm_io_r(vfe31_ctrl->vfebase + V31_RGB_G_OFF))
+ msm_io_w(7, vfe31_ctrl->vfebase+V31_RGB_G_OFF);
+ else
+ msm_io_w(0, vfe31_ctrl->vfebase+V31_RGB_G_OFF);
+ vfe31_ctrl->update_gamma = false;
+ }
+
+ spin_lock_irqsave(&vfe31_ctrl->update_ack_lock, flags);
+ vfe31_ctrl->update_ack_pending = TRUE;
+ spin_unlock_irqrestore(&vfe31_ctrl->update_ack_lock, flags);
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ return;
+}
+
+static void vfe31_sync_timer_stop(void)
+{
+ uint32_t value = 0;
+ vfe31_ctrl->sync_timer_state = 0;
+ if (vfe31_ctrl->sync_timer_number == 0)
+ value = 0x10000;
+ else if (vfe31_ctrl->sync_timer_number == 1)
+ value = 0x20000;
+ else if (vfe31_ctrl->sync_timer_number == 2)
+ value = 0x40000;
+
+ /* Timer Stop */
+ msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF);
+}
+
+static void vfe31_sync_timer_start(const uint32_t *tbl)
+{
+ /* set bit 8 for auto increment. */
+ uint32_t value = 1;
+ uint32_t val;
+
+ vfe31_ctrl->sync_timer_state = *tbl++;
+ vfe31_ctrl->sync_timer_repeat_count = *tbl++;
+ vfe31_ctrl->sync_timer_number = *tbl++;
+ CDBG("%s timer_state %d, repeat_cnt %d timer number %d\n",
+ __func__, vfe31_ctrl->sync_timer_state,
+ vfe31_ctrl->sync_timer_repeat_count,
+ vfe31_ctrl->sync_timer_number);
+
+ if (vfe31_ctrl->sync_timer_state) { /* Start Timer */
+ value = value << vfe31_ctrl->sync_timer_number;
+ } else { /* Stop Timer */
+ CDBG("Failed to Start timer\n");
+ return;
+ }
+
+ /* Timer Start */
+ msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF);
+ /* Sync Timer Line Start */
+ value = *tbl++;
+ msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF +
+ 4 + ((vfe31_ctrl->sync_timer_number) * 12));
+ /* Sync Timer Pixel Start */
+ value = *tbl++;
+ msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF +
+ 8 + ((vfe31_ctrl->sync_timer_number) * 12));
+ /* Sync Timer Pixel Duration */
+ value = *tbl++;
+ val = vfe_clk_rate / 10000;
+ val = 10000000 / val;
+ val = value * 10000 / val;
+ CDBG("%s: Pixel Clk Cycles!!! %d\n", __func__, val);
+ msm_io_w(val, vfe31_ctrl->vfebase + V31_SYNC_TIMER_OFF +
+ 12 + ((vfe31_ctrl->sync_timer_number) * 12));
+ /* Timer0 Active High/LOW */
+ value = *tbl++;
+ msm_io_w(value, vfe31_ctrl->vfebase + V31_SYNC_TIMER_POLARITY_OFF);
+ /* Selects sync timer 0 output to drive onto timer1 port */
+ value = 0;
+ msm_io_w(value, vfe31_ctrl->vfebase + V31_TIMER_SELECT_OFF);
+}
+
+static void vfe31_program_dmi_cfg(enum VFE31_DMI_RAM_SEL bankSel)
+{
+ /* set bit 8 for auto increment. */
+ uint32_t value = VFE_DMI_CFG_DEFAULT;
+ value += (uint32_t)bankSel;
+ CDBG("%s: banksel = %d\n", __func__, bankSel);
+
+ msm_io_w(value, vfe31_ctrl->vfebase + VFE_DMI_CFG);
+ /* by default, always starts with offset 0.*/
+ msm_io_w(0, vfe31_ctrl->vfebase + VFE_DMI_ADDR);
+}
+static void vfe31_write_gamma_cfg(enum VFE31_DMI_RAM_SEL channel_sel,
+ const uint32_t *tbl)
+{
+ int i;
+ uint32_t value, value1, value2;
+ vfe31_program_dmi_cfg(channel_sel);
+ for (i = 0 ; i < (VFE31_GAMMA_NUM_ENTRIES/2) ; i++) {
+ value = *tbl++;
+ value1 = value & 0x0000FFFF;
+ value2 = (value & 0xFFFF0000)>>16;
+ msm_io_w((value1), vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ msm_io_w((value2), vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ }
+ vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+}
+
+static void vfe31_read_gamma_cfg(enum VFE31_DMI_RAM_SEL channel_sel,
+ uint32_t *tbl)
+{
+ int i;
+ vfe31_program_dmi_cfg(channel_sel);
+ CDBG("%s: Gamma table channel: %d\n", __func__, channel_sel);
+ for (i = 0 ; i < VFE31_GAMMA_NUM_ENTRIES ; i++) {
+ *tbl = msm_io_r(vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ CDBG("%s: %08x\n", __func__, *tbl);
+ tbl++;
+ }
+ vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+}
+
+static void vfe31_write_la_cfg(enum VFE31_DMI_RAM_SEL channel_sel,
+ const uint32_t *tbl)
+{
+ uint32_t i;
+ uint32_t value, value1, value2;
+
+ vfe31_program_dmi_cfg(channel_sel);
+ for (i = 0 ; i < (VFE31_LA_TABLE_LENGTH/2) ; i++) {
+ value = *tbl++;
+ value1 = value & 0x0000FFFF;
+ value2 = (value & 0xFFFF0000)>>16;
+ msm_io_w((value1), vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ msm_io_w((value2), vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ }
+ vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+}
+
+static struct vfe31_output_ch *vfe31_get_ch(int path)
+{
+ struct vfe31_output_ch *ch = NULL;
+
+ if (path == VFE_MSG_OUTPUT_PRIMARY)
+ ch = &vfe31_ctrl->outpath.out0;
+ else if (path == VFE_MSG_OUTPUT_SECONDARY)
+ ch = &vfe31_ctrl->outpath.out1;
+ else
+ pr_err("%s: Invalid path %d\n", __func__, path);
+
+ BUG_ON(ch == NULL);
+ return ch;
+}
+static struct msm_free_buf *vfe31_check_free_buffer(int id, int path)
+{
+ struct vfe31_output_ch *outch = NULL;
+ struct msm_free_buf *b = NULL;
+ vfe31_subdev_notify(id, path);
+ outch = vfe31_get_ch(path);
+ if (outch->free_buf.ch_paddr[0])
+ b = &outch->free_buf;
+ return b;
+}
+static int vfe31_configure_pingpong_buffers(int id, int path)
+{
+ struct vfe31_output_ch *outch = NULL;
+ int rc = 0;
+ vfe31_subdev_notify(id, path);
+ outch = vfe31_get_ch(path);
+ if (outch->ping.ch_paddr[0] && outch->pong.ch_paddr[0]) {
+ /* Configure Preview Ping Pong */
+ CDBG("%s Configure ping/pong address for %d",
+ __func__, path);
+ vfe31_put_ch_ping_addr(outch->ch0,
+ outch->ping.ch_paddr[0]);
+ vfe31_put_ch_pong_addr(outch->ch0,
+ outch->pong.ch_paddr[0]);
+
+ if (vfe31_ctrl->operation_mode !=
+ VFE_OUTPUTS_RAW) {
+ vfe31_put_ch_ping_addr(outch->ch1,
+ outch->ping.ch_paddr[1]);
+ vfe31_put_ch_pong_addr(outch->ch1,
+ outch->pong.ch_paddr[1]);
+ }
+
+ if (outch->ping.num_planes > 2)
+ vfe31_put_ch_ping_addr(outch->ch2,
+ outch->ping.ch_paddr[2]);
+ if (outch->pong.num_planes > 2)
+ vfe31_put_ch_pong_addr(outch->ch2,
+ outch->pong.ch_paddr[2]);
+
+ /* avoid stale info */
+ memset(&outch->ping, 0, sizeof(struct msm_free_buf));
+ memset(&outch->pong, 0, sizeof(struct msm_free_buf));
+ } else {
+ pr_err("%s ping/pong addr is null!!", __func__);
+ rc = -EINVAL;
+ }
+ return rc;
+}
+
+static void vfe31_send_isp_msg(struct vfe31_ctrl_type *vctrl,
+ uint32_t isp_msg_id)
+{
+ struct isp_msg_event isp_msg_evt;
+
+ isp_msg_evt.msg_id = isp_msg_id;
+ isp_msg_evt.sof_count = vfe31_ctrl->vfeFrameId;
+ v4l2_subdev_notify(&vctrl->subdev,
+ NOTIFY_ISP_MSG_EVT, (void *)&isp_msg_evt);
+}
+
+static int vfe31_proc_general(struct msm_isp_cmd *cmd)
+{
+ int i , rc = 0;
+ uint32_t old_val = 0 , new_val = 0;
+ uint32_t *cmdp = NULL;
+ uint32_t *cmdp_local = NULL;
+ uint32_t snapshot_cnt = 0;
+ uint32_t temp1 = 0, temp2 = 0;
+
+ CDBG("vfe31_proc_general: cmdID = %s, length = %d\n",
+ vfe31_general_cmd[cmd->id], cmd->length);
+ switch (cmd->id) {
+ case VFE_CMD_RESET:
+ pr_info("vfe31_proc_general: cmdID = %s\n",
+ vfe31_general_cmd[cmd->id]);
+ vfe31_reset();
+ break;
+ case VFE_CMD_START:
+ pr_info("vfe31_proc_general: cmdID = %s\n",
+ vfe31_general_cmd[cmd->id]);
+ if ((vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO) ||
+ (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_PREVIEW))
+ /* Configure primary channel */
+ rc = vfe31_configure_pingpong_buffers(
+ VFE_MSG_V31_START, VFE_MSG_OUTPUT_PRIMARY);
+ else
+ /* Configure secondary channel */
+ rc = vfe31_configure_pingpong_buffers(
+ VFE_MSG_V31_START, VFE_MSG_OUTPUT_SECONDARY);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for preview", __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ rc = vfe31_start();
+ break;
+ case VFE_CMD_UPDATE:
+ vfe31_update();
+ break;
+ case VFE_CMD_CAPTURE_RAW:
+ pr_info("%s: cmdID = VFE_CMD_CAPTURE_RAW\n", __func__);
+ if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
+ sizeof(uint32_t))) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ rc = vfe31_configure_pingpong_buffers(VFE_MSG_V31_CAPTURE,
+ VFE_MSG_OUTPUT_PRIMARY);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for snapshot", __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ rc = vfe31_capture_raw(snapshot_cnt);
+ break;
+ case VFE_CMD_CAPTURE:
+ if (copy_from_user(&snapshot_cnt, (void __user *)(cmd->value),
+ sizeof(uint32_t))) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+
+ if (vfe31_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_JPEG) {
+ if (snapshot_cnt != 1) {
+ pr_err("only support 1 inline snapshot\n");
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ /* Configure primary channel for JPEG */
+ rc = vfe31_configure_pingpong_buffers(
+ VFE_MSG_V31_JPEG_CAPTURE,
+ VFE_MSG_OUTPUT_PRIMARY);
+ } else {
+ /* Configure primary channel */
+ rc = vfe31_configure_pingpong_buffers(
+ VFE_MSG_V31_CAPTURE,
+ VFE_MSG_OUTPUT_PRIMARY);
+ }
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for primary output", __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ /* Configure secondary channel */
+ rc = vfe31_configure_pingpong_buffers(VFE_MSG_V31_CAPTURE,
+ VFE_MSG_OUTPUT_SECONDARY);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for secondary output", __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ rc = vfe31_capture(snapshot_cnt);
+ break;
+ case VFE_CMD_START_RECORDING:
+ pr_info("vfe31_proc_general: cmdID = %s\n",
+ vfe31_general_cmd[cmd->id]);
+ if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO)
+ rc = vfe31_configure_pingpong_buffers(
+ VFE_MSG_V31_START_RECORDING,
+ VFE_MSG_OUTPUT_SECONDARY);
+ else if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_VIDEO_AND_PREVIEW)
+ rc = vfe31_configure_pingpong_buffers(
+ VFE_MSG_V31_START_RECORDING,
+ VFE_MSG_OUTPUT_PRIMARY);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for video", __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ rc = vfe31_start_recording();
+ break;
+ case VFE_CMD_STOP_RECORDING:
+ pr_info("vfe31_proc_general: cmdID = %s\n",
+ vfe31_general_cmd[cmd->id]);
+ rc = vfe31_stop_recording();
+ break;
+ case VFE_CMD_OPERATION_CFG:
+ if (cmd->length != V31_OPERATION_CFG_LEN) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(V31_OPERATION_CFG_LEN, GFP_ATOMIC);
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ V31_OPERATION_CFG_LEN)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ rc = vfe31_operation_config(cmdp);
+ break;
+
+ case VFE_CMD_STATS_AE_START:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val |= AE_BG_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ break;
+ case VFE_CMD_STATS_AF_START:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val |= AF_BF_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ break;
+ case VFE_CMD_STATS_AWB_START:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val |= AWB_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ break;
+
+ case VFE_CMD_STATS_IHIST_START:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val |= IHIST_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ break;
+
+ case VFE_CMD_STATS_RS_START:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ break;
+
+ case VFE_CMD_STATS_CS_START:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ break;
+
+ case VFE_CMD_MCE_UPDATE:
+ case VFE_CMD_MCE_CFG:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ /* Incrementing with 4 so as to point to the 2nd Register as
+ the 2nd register has the mce_enable bit */
+ old_val = msm_io_r(vfe31_ctrl->vfebase +
+ V31_CHROMA_SUP_OFF + 4);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ new_val = *cmdp_local;
+ old_val &= MCE_EN_MASK;
+ new_val = new_val | old_val;
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_CHROMA_SUP_OFF + 4,
+ &new_val, 4);
+ cmdp_local += 1;
+
+ old_val = msm_io_r(vfe31_ctrl->vfebase +
+ V31_CHROMA_SUP_OFF + 8);
+ new_val = *cmdp_local;
+ old_val &= MCE_Q_K_MASK;
+ new_val = new_val | old_val;
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_CHROMA_SUP_OFF + 8,
+ &new_val, 4);
+ cmdp_local += 1;
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp_local, (vfe31_cmd[cmd->id].length));
+ break;
+ case VFE_CMD_CHROMA_SUP_UPDATE:
+ case VFE_CMD_CHROMA_SUP_CFG:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_CHROMA_SUP_OFF,
+ cmdp_local, 4);
+
+ cmdp_local += 1;
+ new_val = *cmdp_local;
+ /* Incrementing with 4 so as to point to the 2nd Register as
+ * the 2nd register has the mce_enable bit
+ */
+ old_val = msm_io_r(vfe31_ctrl->vfebase +
+ V31_CHROMA_SUP_OFF + 4);
+ old_val &= ~MCE_EN_MASK;
+ new_val = new_val | old_val;
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_CHROMA_SUP_OFF + 4,
+ &new_val, 4);
+ cmdp_local += 1;
+
+ old_val = msm_io_r(vfe31_ctrl->vfebase +
+ V31_CHROMA_SUP_OFF + 8);
+ new_val = *cmdp_local;
+ old_val &= ~MCE_Q_K_MASK;
+ new_val = new_val | old_val;
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_CHROMA_SUP_OFF + 8,
+ &new_val, 4);
+ break;
+
+ case VFE_CMD_MESH_ROLL_OFF_CFG:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value) , cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp_local, 16);
+ cmdp_local += 4;
+ vfe31_program_dmi_cfg(ROLLOFF_RAM);
+ /* for loop for extrcting init table. */
+ for (i = 0; i < (V31_MESH_ROLL_OFF_INIT_TABLE_SIZE * 2); i++) {
+ msm_io_w(*cmdp_local ,
+ vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ cmdp_local++;
+ }
+ CDBG("done writing init table\n");
+ /* by default, always starts with offset 0. */
+ msm_io_w(V31_MESH_ROLL_OFF_DELTA_TABLE_OFFSET,
+ vfe31_ctrl->vfebase + VFE_DMI_ADDR);
+ /* for loop for extracting delta table. */
+ for (i = 0; i < (V31_MESH_ROLL_OFF_DELTA_TABLE_SIZE * 2); i++) {
+ msm_io_w(*cmdp_local,
+ vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ cmdp_local++;
+ }
+ vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+ break;
+
+ case VFE_CMD_GET_MESH_ROLLOFF_TABLE:
+ temp1 = sizeof(uint32_t) * ((V31_MESH_ROLL_OFF_INIT_TABLE_SIZE *
+ 2) + (V31_MESH_ROLL_OFF_DELTA_TABLE_SIZE * 2));
+ if (cmd->length != temp1) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kzalloc(temp1, GFP_KERNEL);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ vfe31_program_dmi_cfg(ROLLOFF_RAM);
+ CDBG("%s: Mesh Rolloff init Table\n", __func__);
+ for (i = 0; i < (V31_MESH_ROLL_OFF_INIT_TABLE_SIZE * 2); i++) {
+ *cmdp_local =
+ msm_io_r(vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ CDBG("%s: %08x\n", __func__, *cmdp_local);
+ cmdp_local++;
+ }
+ msm_io_w(V31_MESH_ROLL_OFF_DELTA_TABLE_OFFSET,
+ vfe31_ctrl->vfebase + VFE_DMI_ADDR);
+ CDBG("%s: Mesh Rolloff Delta Table\n", __func__);
+ for (i = 0; i < (V31_MESH_ROLL_OFF_DELTA_TABLE_SIZE * 2); i++) {
+ *cmdp_local =
+ msm_io_r(vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ CDBG("%s: %08x\n", __func__, *cmdp_local);
+ cmdp_local++;
+ }
+ CDBG("done reading delta table\n");
+ vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+ if (copy_to_user((void __user *)(cmd->value), cmdp,
+ temp1)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ break;
+ case VFE_CMD_LA_CFG:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp_local, (vfe31_cmd[cmd->id].length));
+
+ cmdp_local += 1;
+ vfe31_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0, cmdp_local);
+ break;
+
+ case VFE_CMD_LA_UPDATE:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+
+ cmdp_local = cmdp + 1;
+ old_val = msm_io_r(vfe31_ctrl->vfebase + V31_LA_OFF);
+ if (old_val != 0x0)
+ vfe31_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK0,
+ cmdp_local);
+ else
+ vfe31_write_la_cfg(LUMA_ADAPT_LUT_RAM_BANK1,
+ cmdp_local);
+ vfe31_ctrl->update_la = true;
+ break;
+
+ case VFE_CMD_GET_LA_TABLE:
+ temp1 = sizeof(uint32_t) * VFE31_LA_TABLE_LENGTH / 2;
+ if (cmd->length != temp1) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kzalloc(temp1, GFP_KERNEL);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ if (msm_io_r(vfe31_ctrl->vfebase + V31_LA_OFF))
+ vfe31_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK1);
+ else
+ vfe31_program_dmi_cfg(LUMA_ADAPT_LUT_RAM_BANK0);
+ for (i = 0 ; i < (VFE31_LA_TABLE_LENGTH / 2) ; i++) {
+ *cmdp_local =
+ msm_io_r(vfe31_ctrl->vfebase + VFE_DMI_DATA_LO);
+ *cmdp_local |= (msm_io_r(vfe31_ctrl->vfebase +
+ VFE_DMI_DATA_LO)) << 16;
+ cmdp_local++;
+ }
+ vfe31_program_dmi_cfg(NO_MEM_SELECTED);
+ if (copy_to_user((void __user *)(cmd->value), cmdp,
+ temp1)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ break;
+ case VFE_CMD_SK_ENHAN_CFG:
+ case VFE_CMD_SK_ENHAN_UPDATE:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_SCE_OFF,
+ cmdp, V31_SCE_LEN);
+ break;
+
+ case VFE_CMD_LIVESHOT:
+ /* Configure primary channel */
+ rc = vfe31_configure_pingpong_buffers(VFE_MSG_V31_CAPTURE,
+ VFE_MSG_OUTPUT_PRIMARY);
+ if (rc < 0) {
+ pr_err("%s error configuring pingpong buffers"
+ " for primary output", __func__);
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ vfe31_start_liveshot();
+ break;
+
+ case VFE_CMD_DEMOSAICV3:
+ if (cmd->length != V31_DEMOSAICV3_LEN) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ new_val = *cmdp_local;
+
+ old_val = msm_io_r(vfe31_ctrl->vfebase + V31_DEMOSAICV3_OFF);
+ old_val &= DEMOSAIC_MASK;
+ new_val = new_val | old_val;
+ *cmdp_local = new_val;
+
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_DEMOSAICV3_OFF,
+ cmdp_local, V31_DEMOSAICV3_LEN);
+ break;
+
+ case VFE_CMD_DEMOSAICV3_UPDATE:
+ if (cmd->length !=
+ V31_DEMOSAICV3_LEN * V31_DEMOSAICV3_UP_REG_CNT) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ new_val = *cmdp_local;
+
+ old_val = msm_io_r(vfe31_ctrl->vfebase + V31_DEMOSAICV3_OFF);
+ old_val &= DEMOSAIC_MASK;
+ new_val = new_val | old_val;
+ *cmdp_local = new_val;
+
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_DEMOSAICV3_OFF,
+ cmdp_local, V31_DEMOSAICV3_LEN);
+
+ break;
+
+ case VFE_CMD_DEMOSAICV3_ABCC_CFG:
+ rc = -EFAULT;
+ break;
+
+ case VFE_CMD_DEMOSAICV3_ABF_UPDATE:/* 116 ABF update */
+ case VFE_CMD_DEMOSAICV3_ABF_CFG: /* 108 ABF config */
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ new_val = *cmdp_local;
+
+ old_val = msm_io_r(vfe31_ctrl->vfebase + V31_DEMOSAICV3_OFF);
+ old_val &= ABF_MASK;
+ new_val = new_val | old_val;
+ *cmdp_local = new_val;
+
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_DEMOSAICV3_OFF,
+ cmdp_local, 4);
+
+ cmdp_local += 1;
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp_local, (vfe31_cmd[cmd->id].length));
+ break;
+
+ case VFE_CMD_DEMOSAICV3_DBCC_CFG:
+ case VFE_CMD_DEMOSAICV3_DBCC_UPDATE:
+ return -EINVAL;
+
+ case VFE_CMD_DEMOSAICV3_DBPC_CFG:
+ case VFE_CMD_DEMOSAICV3_DBPC_UPDATE:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+ new_val = *cmdp_local;
+
+ old_val = msm_io_r(vfe31_ctrl->vfebase + V31_DEMOSAICV3_OFF);
+ old_val &= BPC_MASK;
+
+ new_val = new_val | old_val;
+ *cmdp_local = new_val;
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_DEMOSAICV3_OFF,
+ cmdp_local, V31_DEMOSAICV3_LEN);
+ cmdp_local += 1;
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_DEMOSAICV3_DBPC_CFG_OFF,
+ cmdp_local, V31_DEMOSAICV3_DBPC_LEN);
+ break;
+
+ case VFE_CMD_RGB_G_CFG:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_io_memcpy(vfe31_ctrl->vfebase + V31_RGB_G_OFF,
+ cmdp, 4);
+ cmdp += 1;
+
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, cmdp);
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, cmdp);
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, cmdp);
+ cmdp -= 1;
+ break;
+
+ case VFE_CMD_RGB_G_UPDATE:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp, (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+
+ old_val = msm_io_r(vfe31_ctrl->vfebase + V31_RGB_G_OFF);
+ cmdp += 1;
+ if (old_val != 0x0) {
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH0_BANK0, cmdp);
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH1_BANK0, cmdp);
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH2_BANK0, cmdp);
+ } else {
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH0_BANK1, cmdp);
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH1_BANK1, cmdp);
+ vfe31_write_gamma_cfg(RGBLUT_RAM_CH2_BANK1, cmdp);
+ }
+ vfe31_ctrl->update_gamma = TRUE;
+ cmdp -= 1;
+ break;
+
+ case VFE_CMD_GET_RGB_G_TABLE:
+ temp1 = sizeof(uint32_t) * VFE31_GAMMA_NUM_ENTRIES * 3;
+ if (cmd->length != temp1) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kzalloc(temp1, GFP_KERNEL);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ cmdp_local = cmdp;
+
+ old_val = msm_io_r(vfe31_ctrl->vfebase + V31_RGB_G_OFF);
+ temp2 = old_val ? RGBLUT_RAM_CH0_BANK1 :
+ RGBLUT_RAM_CH0_BANK0;
+ for (i = 0; i < 3; i++) {
+ vfe31_read_gamma_cfg(temp2,
+ cmdp_local + (VFE31_GAMMA_NUM_ENTRIES * i));
+ temp2 += 2;
+ }
+ if (copy_to_user((void __user *)(cmd->value), cmdp,
+ temp1)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ break;
+
+ case VFE_CMD_STATS_AWB_STOP:
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~AWB_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ break;
+ case VFE_CMD_STATS_AE_STOP:
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~AE_BG_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ break;
+ case VFE_CMD_STATS_AF_STOP:
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~AF_BF_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ break;
+
+ case VFE_CMD_STATS_IHIST_STOP:
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~IHIST_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ break;
+
+ case VFE_CMD_STATS_RS_STOP:
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~RS_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ break;
+
+ case VFE_CMD_STATS_CS_STOP:
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= ~CS_ENABLE_MASK;
+ msm_io_w(old_val,
+ vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ break;
+
+ case VFE_CMD_STOP:
+ pr_info("vfe31_proc_general: cmdID = %s\n",
+ vfe31_general_cmd[cmd->id]);
+ vfe31_stop();
+ break;
+
+ case VFE_CMD_SYNC_TIMER_SETTING:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp, (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ vfe31_sync_timer_start(cmdp);
+ break;
+
+ case VFE_CMD_MODULE_CFG:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp,
+ (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ *cmdp &= ~STATS_ENABLE_MASK;
+ old_val = msm_io_r(vfe31_ctrl->vfebase + VFE_MODULE_CFG);
+ old_val &= STATS_ENABLE_MASK;
+ *cmdp |= old_val;
+
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ break;
+
+ case VFE_CMD_ZSL:
+ rc = vfe31_configure_pingpong_buffers(VFE_MSG_V31_START,
+ VFE_MSG_OUTPUT_PRIMARY);
+ if (rc < 0)
+ goto proc_general_done;
+ rc = vfe31_configure_pingpong_buffers(VFE_MSG_V31_START,
+ VFE_MSG_OUTPUT_SECONDARY);
+ if (rc < 0)
+ goto proc_general_done;
+
+ rc = vfe31_zsl();
+ break;
+
+ case VFE_CMD_ASF_CFG:
+ case VFE_CMD_ASF_UPDATE:
+ cmdp = kmalloc(cmd->length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ if (copy_from_user(cmdp, (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ cmdp_local = cmdp + V31_ASF_LEN/4;
+ break;
+
+ case VFE_CMD_GET_HW_VERSION:
+ if (cmd->length != V31_GET_HW_VERSION_LEN) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(V31_GET_HW_VERSION_LEN, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ *cmdp = msm_io_r(vfe31_ctrl->vfebase+V31_GET_HW_VERSION_OFF);
+ if (copy_to_user((void __user *)(cmd->value), cmdp,
+ V31_GET_HW_VERSION_LEN)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ break;
+ case VFE_CMD_GET_REG_DUMP:
+ temp1 = sizeof(uint32_t) * vfe31_ctrl->register_total;
+ if (cmd->length != temp1) {
+ rc = -EINVAL;
+ goto proc_general_done;
+ }
+ cmdp = kmalloc(temp1, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+ msm_io_dump(vfe31_ctrl->vfebase, vfe31_ctrl->register_total*4);
+ CDBG("%s: %p %p %d\n", __func__, (void *)cmdp,
+ vfe31_ctrl->vfebase, temp1);
+ memcpy_fromio((void *)cmdp, vfe31_ctrl->vfebase, temp1);
+ if (copy_to_user((void __user *)(cmd->value), cmdp, temp1)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ break;
+ case VFE_CMD_FRAME_SKIP_CFG:
+ if (cmd->length != vfe31_cmd[cmd->id].length)
+ return -EINVAL;
+
+ cmdp = kmalloc(vfe31_cmd[cmd->id].length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+
+ if (copy_from_user(cmdp, (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ vfe31_ctrl->frame_skip_cnt = ((uint32_t)
+ *cmdp & VFE_FRAME_SKIP_PERIOD_MASK) + 1;
+ vfe31_ctrl->frame_skip_pattern = (uint32_t)(*(cmdp + 2));
+ break;
+ default:
+ if (cmd->length != vfe31_cmd[cmd->id].length)
+ return -EINVAL;
+
+ cmdp = kmalloc(vfe31_cmd[cmd->id].length, GFP_ATOMIC);
+ if (!cmdp) {
+ rc = -ENOMEM;
+ goto proc_general_done;
+ }
+
+ if (copy_from_user(cmdp, (void __user *)(cmd->value),
+ cmd->length)) {
+ rc = -EFAULT;
+ goto proc_general_done;
+ }
+ msm_io_memcpy(vfe31_ctrl->vfebase + vfe31_cmd[cmd->id].offset,
+ cmdp, (vfe31_cmd[cmd->id].length));
+ break;
+
+ }
+
+proc_general_done:
+ kfree(cmdp);
+
+ return rc;
+}
+
+static void vfe31_stats_af_ack(struct vfe_cmd_stats_ack *pAck)
+{
+ unsigned long flags;
+ spinlock_t *lock = (vfe31_ctrl->stats_comp ?
+ &vfe31_ctrl->comp_stats_ack_lock :
+ &vfe31_ctrl->af_ack_lock);
+ spin_lock_irqsave(lock, flags);
+ vfe31_ctrl->afStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+ vfe31_ctrl->afStatsControl.ackPending = FALSE;
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static void vfe31_stats_awb_ack(struct vfe_cmd_stats_ack *pAck)
+{
+ unsigned long flags;
+ spinlock_t *lock = (vfe31_ctrl->stats_comp ?
+ &vfe31_ctrl->comp_stats_ack_lock :
+ &vfe31_ctrl->awb_ack_lock);
+ spin_lock_irqsave(lock, flags);
+ vfe31_ctrl->awbStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+ vfe31_ctrl->awbStatsControl.ackPending = FALSE;
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static void vfe31_stats_aec_ack(struct vfe_cmd_stats_ack *pAck)
+{
+ unsigned long flags;
+ spinlock_t *lock = (vfe31_ctrl->stats_comp ?
+ &vfe31_ctrl->comp_stats_ack_lock :
+ &vfe31_ctrl->aec_ack_lock);
+ spin_lock_irqsave(lock, flags);
+ vfe31_ctrl->aecStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+ vfe31_ctrl->aecStatsControl.ackPending = FALSE;
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static void vfe31_stats_ihist_ack(struct vfe_cmd_stats_ack *pAck)
+{
+ unsigned long flags;
+ spinlock_t *lock = (vfe31_ctrl->stats_comp ?
+ &vfe31_ctrl->comp_stats_ack_lock :
+ &vfe31_ctrl->ihist_ack_lock);
+ spin_lock_irqsave(lock, flags);
+ vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+ vfe31_ctrl->ihistStatsControl.ackPending = FALSE;
+ spin_unlock_irqrestore(lock, flags);
+}
+static void vfe31_stats_rs_ack(struct vfe_cmd_stats_ack *pAck)
+{
+ unsigned long flags;
+ spinlock_t *lock = (vfe31_ctrl->stats_comp ?
+ &vfe31_ctrl->comp_stats_ack_lock :
+ &vfe31_ctrl->rs_ack_lock);
+ spin_lock_irqsave(lock, flags);
+ vfe31_ctrl->rsStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+ vfe31_ctrl->rsStatsControl.ackPending = FALSE;
+ spin_unlock_irqrestore(lock, flags);
+}
+static void vfe31_stats_cs_ack(struct vfe_cmd_stats_ack *pAck)
+{
+ unsigned long flags;
+ spinlock_t *lock = (vfe31_ctrl->stats_comp ?
+ &vfe31_ctrl->comp_stats_ack_lock :
+ &vfe31_ctrl->cs_ack_lock);
+ spin_lock_irqsave(lock, flags);
+ vfe31_ctrl->csStatsControl.nextFrameAddrBuf = pAck->nextStatsBuf;
+ vfe31_ctrl->csStatsControl.ackPending = FALSE;
+ spin_unlock_irqrestore(lock, flags);
+}
+
+static inline void vfe31_read_irq_status(struct vfe31_irq_status *out)
+{
+ uint32_t *temp;
+ memset(out, 0, sizeof(struct vfe31_irq_status));
+ temp = (uint32_t *)(vfe31_ctrl->vfebase + VFE_IRQ_STATUS_0);
+ out->vfeIrqStatus0 = msm_io_r(temp);
+
+ temp = (uint32_t *)(vfe31_ctrl->vfebase + VFE_IRQ_STATUS_1);
+ out->vfeIrqStatus1 = msm_io_r(temp);
+
+ temp = (uint32_t *)(vfe31_ctrl->vfebase + VFE_CAMIF_STATUS);
+ out->camifStatus = msm_io_r(temp);
+ CDBG("camifStatus = 0x%x\n", out->camifStatus);
+
+ /* clear the pending interrupt of the same kind.*/
+ msm_io_w(out->vfeIrqStatus0, vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_0);
+ msm_io_w(out->vfeIrqStatus1, vfe31_ctrl->vfebase + VFE_IRQ_CLEAR_1);
+
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_IRQ_CMD);
+
+}
+
+static void vfe31_process_reg_update_irq(void)
+{
+ unsigned long flags;
+
+ if (vfe31_ctrl->recording_state == VFE_STATE_START_REQUESTED) {
+ if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ } else if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+ }
+ vfe31_ctrl->recording_state = VFE_STATE_STARTED;
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ CDBG("start video triggered .\n");
+ } else if (vfe31_ctrl->recording_state ==
+ VFE_STATE_STOP_REQUESTED) {
+ if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_VIDEO_AND_PREVIEW) {
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ } else if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_PREVIEW_AND_VIDEO) {
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch0]);
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out1.ch1]);
+ }
+ CDBG("stop video triggered .\n");
+ }
+
+ if (vfe31_ctrl->start_ack_pending == TRUE) {
+ vfe31_send_isp_msg(vfe31_ctrl, MSG_ID_START_ACK);
+ vfe31_ctrl->start_ack_pending = FALSE;
+ } else {
+ if (vfe31_ctrl->recording_state ==
+ VFE_STATE_STOP_REQUESTED) {
+ vfe31_ctrl->recording_state = VFE_STATE_STOPPED;
+ /* request a reg update and send STOP_REC_ACK
+ * when we process the next reg update irq.
+ */
+ msm_io_w_mb(1,
+ vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ } else if (vfe31_ctrl->recording_state ==
+ VFE_STATE_STOPPED) {
+ vfe31_send_isp_msg(vfe31_ctrl, MSG_ID_STOP_REC_ACK);
+ vfe31_ctrl->recording_state = VFE_STATE_IDLE;
+ }
+ spin_lock_irqsave(&vfe31_ctrl->update_ack_lock, flags);
+ if (vfe31_ctrl->update_ack_pending == TRUE) {
+ vfe31_ctrl->update_ack_pending = FALSE;
+ spin_unlock_irqrestore(
+ &vfe31_ctrl->update_ack_lock, flags);
+ vfe31_send_isp_msg(vfe31_ctrl, MSG_ID_UPDATE_ACK);
+ } else {
+ spin_unlock_irqrestore(
+ &vfe31_ctrl->update_ack_lock, flags);
+ }
+ }
+
+ if (vfe31_ctrl->liveshot_state == VFE_STATE_START_REQUESTED) {
+ pr_info("%s enabling liveshot output\n", __func__);
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY) {
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(1, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ vfe31_ctrl->liveshot_state = VFE_STATE_STARTED;
+ }
+ }
+
+ if (vfe31_ctrl->liveshot_state == VFE_STATE_STARTED) {
+ vfe31_ctrl->vfe_capture_count--;
+ if (!vfe31_ctrl->vfe_capture_count)
+ vfe31_ctrl->liveshot_state = VFE_STATE_STOP_REQUESTED;
+ msm_io_w_mb(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ } else if (vfe31_ctrl->liveshot_state == VFE_STATE_STOP_REQUESTED) {
+ CDBG("%s: disabling liveshot output\n", __func__);
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY) {
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch0]);
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->outpath.out0.ch1]);
+ vfe31_ctrl->liveshot_state = VFE_STATE_STOPPED;
+ msm_io_w_mb(1, vfe31_ctrl->vfebase +
+ VFE_REG_UPDATE_CMD);
+ }
+ } else if (vfe31_ctrl->liveshot_state == VFE_STATE_STOPPED) {
+ vfe31_ctrl->liveshot_state = VFE_STATE_IDLE;
+ }
+
+ if ((vfe31_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_MAIN) ||
+ (vfe31_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB) ||
+ (vfe31_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_JPEG) ||
+ (vfe31_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB)) {
+ /* in snapshot mode */
+ /* later we need to add check for live snapshot mode. */
+ if (vfe31_ctrl->frame_skip_pattern & (0x1 <<
+ (vfe31_ctrl->snapshot_frame_cnt %
+ vfe31_ctrl->frame_skip_cnt))) {
+ vfe31_ctrl->vfe_capture_count--;
+ /* if last frame to be captured: */
+ if (vfe31_ctrl->vfe_capture_count == 0) {
+ /* stop the bus output:write master enable = 0*/
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_PRIMARY) {
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->
+ outpath.out0.ch0]);
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->
+ outpath.out0.ch1]);
+ }
+ if (vfe31_ctrl->outpath.output_mode &
+ VFE31_OUTPUT_MODE_SECONDARY) {
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->
+ outpath.out1.ch0]);
+ msm_io_w(0, vfe31_ctrl->vfebase +
+ vfe31_AXI_WM_CFG[vfe31_ctrl->
+ outpath.out1.ch1]);
+ }
+ msm_io_w_mb
+ (CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+ vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND);
+ vfe31_ctrl->snapshot_frame_cnt = -1;
+ vfe31_ctrl->frame_skip_cnt = 31;
+ vfe31_ctrl->frame_skip_pattern = 0xffffffff;
+ } /*if snapshot count is 0*/
+ } /*if frame is not being dropped*/
+ vfe31_ctrl->snapshot_frame_cnt++;
+ /* then do reg_update. */
+ msm_io_w(1, vfe31_ctrl->vfebase + VFE_REG_UPDATE_CMD);
+ } /* if snapshot mode. */
+}
+
+static void vfe31_set_default_reg_values(void)
+{
+ msm_io_w(0x800080, vfe31_ctrl->vfebase + VFE_DEMUX_GAIN_0);
+ msm_io_w(0x800080, vfe31_ctrl->vfebase + VFE_DEMUX_GAIN_1);
+ /* What value should we program CGC_OVERRIDE to? */
+ msm_io_w(0xFFFFF, vfe31_ctrl->vfebase + VFE_CGC_OVERRIDE);
+
+ /* default frame drop period and pattern */
+ msm_io_w(0x1f, vfe31_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_CFG);
+ msm_io_w(0x1f, vfe31_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_CFG);
+ msm_io_w(0xFFFFFFFF, vfe31_ctrl->vfebase + VFE_FRAMEDROP_ENC_Y_PATTERN);
+ msm_io_w(0xFFFFFFFF,
+ vfe31_ctrl->vfebase + VFE_FRAMEDROP_ENC_CBCR_PATTERN);
+ msm_io_w(0x1f, vfe31_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y);
+ msm_io_w(0x1f, vfe31_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR);
+ msm_io_w(0xFFFFFFFF,
+ vfe31_ctrl->vfebase + VFE_FRAMEDROP_VIEW_Y_PATTERN);
+ msm_io_w(0xFFFFFFFF,
+ vfe31_ctrl->vfebase + VFE_FRAMEDROP_VIEW_CBCR_PATTERN);
+ msm_io_w(0, vfe31_ctrl->vfebase + VFE_CLAMP_MIN);
+ msm_io_w(0xFFFFFF, vfe31_ctrl->vfebase + VFE_CLAMP_MAX);
+
+ /* stats UB config */
+ msm_io_w(0x3980007, vfe31_ctrl->vfebase + VFE_BUS_STATS_AEC_UB_CFG);
+ msm_io_w(0x3A00007, vfe31_ctrl->vfebase + VFE_BUS_STATS_AF_UB_CFG);
+ msm_io_w(0x3A8000F, vfe31_ctrl->vfebase + VFE_BUS_STATS_AWB_UB_CFG);
+ msm_io_w(0x3B80007, vfe31_ctrl->vfebase + VFE_BUS_STATS_RS_UB_CFG);
+ msm_io_w(0x3C0001F, vfe31_ctrl->vfebase + VFE_BUS_STATS_CS_UB_CFG);
+ msm_io_w(0x3E0001F, vfe31_ctrl->vfebase + VFE_BUS_STATS_HIST_UB_CFG);
+}
+
+static void vfe31_process_reset_irq(void)
+{
+ unsigned long flags;
+
+ atomic_set(&vfe31_ctrl->vstate, 0);
+
+ spin_lock_irqsave(&vfe31_ctrl->stop_flag_lock, flags);
+ if (vfe31_ctrl->stop_ack_pending) {
+ vfe31_ctrl->stop_ack_pending = FALSE;
+ spin_unlock_irqrestore(&vfe31_ctrl->stop_flag_lock, flags);
+ vfe31_send_isp_msg(vfe31_ctrl, MSG_ID_STOP_ACK);
+ } else {
+ spin_unlock_irqrestore(&vfe31_ctrl->stop_flag_lock, flags);
+ /* this is from reset command. */
+ vfe31_set_default_reg_values();
+
+ /* reload all write masters. (frame & line)*/
+ msm_io_w(0x7FFF, vfe31_ctrl->vfebase + VFE_BUS_CMD);
+ vfe31_send_isp_msg(vfe31_ctrl, MSG_ID_RESET_ACK);
+ }
+}
+
+static void vfe31_process_camif_sof_irq(void)
+{
+ if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW) {
+ if (vfe31_ctrl->start_ack_pending) {
+ vfe31_send_isp_msg(vfe31_ctrl, MSG_ID_START_ACK);
+ vfe31_ctrl->start_ack_pending = FALSE;
+ }
+ vfe31_ctrl->vfe_capture_count--;
+ /* if last frame to be captured: */
+ if (vfe31_ctrl->vfe_capture_count == 0) {
+ /* Ensure the write order while writing
+ to the command register using the barrier */
+ msm_io_w_mb(CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY,
+ vfe31_ctrl->vfebase + VFE_CAMIF_COMMAND);
+ }
+ } /* if raw snapshot mode. */
+ if ((vfe31_ctrl->hfr_mode != HFR_MODE_OFF) &&
+ (vfe31_ctrl->operation_mode == VFE_MODE_OF_OPERATION_VIDEO) &&
+ (vfe31_ctrl->vfeFrameId % vfe31_ctrl->hfr_mode != 0)) {
+ vfe31_ctrl->vfeFrameId++;
+ CDBG("Skip the SOF notification when HFR enabled\n");
+ return;
+ }
+ vfe31_ctrl->vfeFrameId++;
+ vfe31_send_isp_msg(vfe31_ctrl, MSG_ID_SOF_ACK);
+ CDBG("camif_sof_irq, frameId = %d\n", vfe31_ctrl->vfeFrameId);
+
+ if (vfe31_ctrl->sync_timer_state) {
+ if (vfe31_ctrl->sync_timer_repeat_count == 0)
+ vfe31_sync_timer_stop();
+ else
+ vfe31_ctrl->sync_timer_repeat_count--;
+ }
+}
+
+static void vfe31_process_error_irq(uint32_t errStatus)
+{
+ uint32_t reg_value, read_val;
+
+ if (errStatus & VFE31_IMASK_CAMIF_ERROR) {
+ pr_err("vfe31_irq: camif errors\n");
+ reg_value = msm_io_r(vfe31_ctrl->vfebase + VFE_CAMIF_STATUS);
+ pr_err("camifStatus = 0x%x\n", reg_value);
+ vfe31_send_isp_msg(vfe31_ctrl, MSG_ID_CAMIF_ERROR);
+ }
+
+ if (errStatus & VFE31_IMASK_STATS_CS_OVWR)
+ pr_err("vfe31_irq: stats cs overwrite\n");
+
+ if (errStatus & VFE31_IMASK_STATS_IHIST_OVWR)
+ pr_err("vfe31_irq: stats ihist overwrite\n");
+
+ if (errStatus & VFE31_IMASK_REALIGN_BUF_Y_OVFL)
+ pr_err("vfe31_irq: realign bug Y overflow\n");
+
+ if (errStatus & VFE31_IMASK_REALIGN_BUF_CB_OVFL)
+ pr_err("vfe31_irq: realign bug CB overflow\n");
+
+ if (errStatus & VFE31_IMASK_REALIGN_BUF_CR_OVFL)
+ pr_err("vfe31_irq: realign bug CR overflow\n");
+
+ if (errStatus & VFE31_IMASK_VIOLATION)
+ pr_err("vfe31_irq: violation interrupt\n");
+
+ if (errStatus & VFE31_IMASK_IMG_MAST_0_BUS_OVFL)
+ pr_err("vfe31_irq: image master 0 bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_IMG_MAST_1_BUS_OVFL)
+ pr_err("vfe31_irq: image master 1 bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_IMG_MAST_2_BUS_OVFL)
+ pr_err("vfe31_irq: image master 2 bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_IMG_MAST_3_BUS_OVFL)
+ pr_err("vfe31_irq: image master 3 bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_IMG_MAST_4_BUS_OVFL)
+ pr_err("vfe31_irq: image master 4 bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_IMG_MAST_5_BUS_OVFL)
+ pr_err("vfe31_irq: image master 5 bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_IMG_MAST_6_BUS_OVFL)
+ pr_err("vfe31_irq: image master 6 bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_STATS_AE_BG_BUS_OVFL)
+ pr_err("vfe31_irq: ae/bg stats bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_STATS_AF_BF_BUS_OVFL)
+ pr_err("vfe31_irq: af/bf stats bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_STATS_AWB_BUS_OVFL)
+ pr_err("vfe31_irq: awb stats bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_STATS_RS_BUS_OVFL)
+ pr_err("vfe31_irq: rs stats bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_STATS_CS_BUS_OVFL)
+ pr_err("vfe31_irq: cs stats bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_STATS_IHIST_BUS_OVFL)
+ pr_err("vfe31_irq: ihist stats bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_STATS_SKIN_BHIST_BUS_OVFL)
+ pr_err("vfe31_irq: skin/bhist stats bus overflow\n");
+
+ if (errStatus & VFE31_IMASK_AXI_ERROR) {
+ pr_err("vfe31_irq: axi error\n");
+ /* read status too when overflow happens.*/
+ read_val = msm_io_r(vfe31_ctrl->vfebase +
+ VFE_BUS_PING_PONG_STATUS);
+ pr_debug("VFE_BUS_PING_PONG_STATUS = 0x%x\n", read_val);
+ read_val = msm_io_r(vfe31_ctrl->vfebase +
+ VFE_BUS_OPERATION_STATUS);
+ pr_debug("VFE_BUS_OPERATION_STATUS = 0x%x\n", read_val);
+ read_val = msm_io_r(vfe31_ctrl->vfebase +
+ VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_0);
+ pr_debug("VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_0 = 0x%x\n",
+ read_val);
+ read_val = msm_io_r(vfe31_ctrl->vfebase +
+ VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_1);
+ pr_debug("VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_1 = 0x%x\n",
+ read_val);
+ read_val = msm_io_r(vfe31_ctrl->vfebase +
+ VFE_AXI_STATUS);
+ pr_debug("VFE_AXI_STATUS = 0x%x\n", read_val);
+ }
+}
+static void vfe_send_outmsg(struct v4l2_subdev *sd, uint8_t msgid,
+ uint32_t ch0_paddr, uint32_t ch1_paddr, uint32_t ch2_paddr)
+{
+ struct isp_msg_output msg;
+
+ msg.output_id = msgid;
+ msg.buf.ch_paddr[0] = ch0_paddr;
+ msg.buf.ch_paddr[1] = ch1_paddr;
+ msg.buf.ch_paddr[2] = ch2_paddr;
+ msg.frameCounter = vfe31_ctrl->vfeFrameId;
+
+ v4l2_subdev_notify(&vfe31_ctrl->subdev,
+ NOTIFY_VFE_MSG_OUT, &msg);
+ return;
+}
+
+static void vfe31_process_output_path_irq_0(void)
+{
+ uint32_t ping_pong;
+ uint32_t ch0_paddr, ch1_paddr, ch2_paddr;
+ uint8_t out_bool = 0;
+ struct msm_free_buf *free_buf = NULL;
+
+ free_buf = vfe31_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_PRIMARY);
+
+ /* we render frames in the following conditions:
+ * 1. Continuous mode and the free buffer is avaialable.
+ * 2. In snapshot shot mode, free buffer is not always available.
+ * when pending snapshot count is <=1, then no need to use
+ * free buffer.
+ */
+ out_bool = ((vfe31_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_MAIN ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_THUMB_AND_JPEG ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe31_ctrl->operation_mode == VFE_OUTPUTS_RAW ||
+ vfe31_ctrl->liveshot_state == VFE_STATE_STARTED ||
+ vfe31_ctrl->liveshot_state == VFE_STATE_STOP_REQUESTED ||
+ vfe31_ctrl->liveshot_state == VFE_STATE_STOPPED) &&
+ (vfe31_ctrl->vfe_capture_count <= 1)) || free_buf;
+
+ if (out_bool) {
+ ping_pong = msm_io_r(vfe31_ctrl->vfebase +
+ VFE_BUS_PING_PONG_STATUS);
+
+ /* Channel 0*/
+ ch0_paddr = vfe31_get_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out0.ch0);
+ /* Channel 1*/
+ ch1_paddr = vfe31_get_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out0.ch1);
+ /* Channel 2*/
+ ch2_paddr = vfe31_get_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out0.ch2);
+
+ CDBG("output path 0, ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
+ ch0_paddr, ch1_paddr, ch2_paddr);
+ if (free_buf) {
+ /* Y channel */
+ vfe31_put_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out0.ch0,
+ free_buf->ch_paddr[0]);
+ /* Chroma channel */
+ vfe31_put_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out0.ch1,
+ free_buf->ch_paddr[1]);
+ if (free_buf->num_planes > 2)
+ vfe31_put_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out0.ch2,
+ free_buf->ch_paddr[2]);
+ }
+ if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_JPEG ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW ||
+ vfe31_ctrl->liveshot_state == VFE_STATE_STOPPED)
+ vfe31_ctrl->outpath.out0.capture_cnt--;
+
+ vfe_send_outmsg(&vfe31_ctrl->subdev,
+ MSG_ID_OUTPUT_PRIMARY, ch0_paddr,
+ ch1_paddr, ch2_paddr);
+
+ if (vfe31_ctrl->liveshot_state == VFE_STATE_STOPPED)
+ vfe31_ctrl->liveshot_state = VFE_STATE_IDLE;
+
+ } else {
+ vfe31_ctrl->outpath.out0.frame_drop_cnt++;
+ CDBG("path_irq_0 - no free buffer!\n");
+ }
+}
+
+static void vfe31_process_output_path_irq_1(void)
+{
+ uint32_t ping_pong;
+ uint32_t ch0_paddr, ch1_paddr, ch2_paddr;
+ /* this must be snapshot main image output. */
+ uint8_t out_bool = 0;
+ struct msm_free_buf *free_buf = NULL;
+
+ free_buf = vfe31_check_free_buffer(VFE_MSG_OUTPUT_IRQ,
+ VFE_MSG_OUTPUT_SECONDARY);
+ out_bool = ((vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB) &&
+ (vfe31_ctrl->vfe_capture_count <= 1)) || free_buf;
+
+ if (out_bool) {
+ ping_pong = msm_io_r(vfe31_ctrl->vfebase +
+ VFE_BUS_PING_PONG_STATUS);
+
+ /* Y channel */
+ ch0_paddr = vfe31_get_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out1.ch0);
+ /* Chroma channel */
+ ch1_paddr = vfe31_get_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out1.ch1);
+ ch2_paddr = vfe31_get_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out1.ch2);
+
+ pr_debug("%s ch0 = 0x%x, ch1 = 0x%x, ch2 = 0x%x\n",
+ __func__, ch0_paddr, ch1_paddr, ch2_paddr);
+ if (free_buf) {
+ /* Y channel */
+ vfe31_put_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out1.ch0,
+ free_buf->ch_paddr[0]);
+ /* Chroma channel */
+ vfe31_put_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out1.ch1,
+ free_buf->ch_paddr[1]);
+ if (free_buf->num_planes > 2)
+ vfe31_put_ch_addr(ping_pong,
+ vfe31_ctrl->outpath.out1.ch2,
+ free_buf->ch_paddr[2]);
+ }
+ if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB)
+ vfe31_ctrl->outpath.out1.capture_cnt--;
+
+ vfe_send_outmsg(&vfe31_ctrl->subdev,
+ MSG_ID_OUTPUT_SECONDARY, ch0_paddr,
+ ch1_paddr, ch2_paddr);
+ } else {
+ vfe31_ctrl->outpath.out1.frame_drop_cnt++;
+ CDBG("path_irq_1 - no free buffer!\n");
+ }
+}
+
+static uint32_t vfe31_process_stats_irq_common(uint32_t statsNum,
+ uint32_t newAddr)
+{
+
+ uint32_t pingpongStatus;
+ uint32_t returnAddr;
+ uint32_t pingpongAddr;
+
+ /* must be 0=ping, 1=pong */
+ pingpongStatus =
+ ((msm_io_r(vfe31_ctrl->vfebase +
+ VFE_BUS_PING_PONG_STATUS))
+ & ((uint32_t)(1<<(statsNum + 7)))) >> (statsNum + 7);
+ /* stats bits starts at 7 */
+ CDBG("statsNum %d, pingpongStatus %d\n", statsNum, pingpongStatus);
+ pingpongAddr =
+ ((uint32_t)(vfe31_ctrl->vfebase +
+ VFE_BUS_STATS_PING_PONG_BASE)) +
+ (3*statsNum)*4 + (1-pingpongStatus)*4;
+ returnAddr = msm_io_r((uint32_t *)pingpongAddr);
+ msm_io_w(newAddr, (uint32_t *)pingpongAddr);
+ return returnAddr;
+}
+
+static void
+vfe_send_stats_msg(uint32_t bufAddress, uint32_t statsNum)
+{
+ unsigned long flags;
+ /* fill message with right content. */
+ /* @todo This is causing issues, need further investigate */
+ /* spin_lock_irqsave(&ctrl->state_lock, flags); */
+ struct isp_msg_stats msgStats;
+ msgStats.frameCounter = vfe31_ctrl->vfeFrameId;
+ msgStats.buffer = bufAddress;
+
+ switch (statsNum) {
+ case STATS_AE_NUM:{
+ msgStats.id = MSG_ID_STATS_AEC;
+ spin_lock_irqsave(&vfe31_ctrl->aec_ack_lock, flags);
+ vfe31_ctrl->aecStatsControl.ackPending = TRUE;
+ spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+ }
+ break;
+ case STATS_AF_NUM:{
+ msgStats.id = MSG_ID_STATS_AF;
+ spin_lock_irqsave(&vfe31_ctrl->af_ack_lock, flags);
+ vfe31_ctrl->afStatsControl.ackPending = TRUE;
+ spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+ }
+ break;
+ case STATS_AWB_NUM: {
+ msgStats.id = MSG_ID_STATS_AWB;
+ spin_lock_irqsave(&vfe31_ctrl->awb_ack_lock, flags);
+ vfe31_ctrl->awbStatsControl.ackPending = TRUE;
+ spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+ }
+ break;
+
+ case STATS_IHIST_NUM: {
+ msgStats.id = MSG_ID_STATS_IHIST;
+ spin_lock_irqsave(&vfe31_ctrl->ihist_ack_lock, flags);
+ vfe31_ctrl->ihistStatsControl.ackPending = TRUE;
+ spin_unlock_irqrestore(&vfe31_ctrl->ihist_ack_lock, flags);
+ }
+ break;
+ case STATS_RS_NUM: {
+ msgStats.id = MSG_ID_STATS_RS;
+ spin_lock_irqsave(&vfe31_ctrl->rs_ack_lock, flags);
+ vfe31_ctrl->rsStatsControl.ackPending = TRUE;
+ spin_unlock_irqrestore(&vfe31_ctrl->rs_ack_lock, flags);
+ }
+ break;
+ case STATS_CS_NUM: {
+ msgStats.id = MSG_ID_STATS_CS;
+ spin_lock_irqsave(&vfe31_ctrl->cs_ack_lock, flags);
+ vfe31_ctrl->csStatsControl.ackPending = TRUE;
+ spin_unlock_irqrestore(&vfe31_ctrl->cs_ack_lock, flags);
+ }
+ break;
+
+ default:
+ goto stats_done;
+ }
+
+ v4l2_subdev_notify(&vfe31_ctrl->subdev,
+ NOTIFY_VFE_MSG_STATS,
+ &msgStats);
+stats_done:
+ /* spin_unlock_irqrestore(&ctrl->state_lock, flags); */
+ return;
+}
+
+static void vfe_send_comp_stats_msg(uint32_t status_bits)
+{
+ struct msm_stats_buf msgStats;
+ uint32_t temp;
+
+ msgStats.frame_id = vfe31_ctrl->vfeFrameId;
+ msgStats.status_bits = status_bits;
+
+ msgStats.aec.buff = vfe31_ctrl->aecStatsControl.bufToRender;
+ msgStats.awb.buff = vfe31_ctrl->awbStatsControl.bufToRender;
+ msgStats.af.buff = vfe31_ctrl->afStatsControl.bufToRender;
+
+ msgStats.ihist.buff = vfe31_ctrl->ihistStatsControl.bufToRender;
+ msgStats.rs.buff = vfe31_ctrl->rsStatsControl.bufToRender;
+ msgStats.cs.buff = vfe31_ctrl->csStatsControl.bufToRender;
+
+ temp = msm_io_r(vfe31_ctrl->vfebase + VFE_STATS_AWB_SGW_CFG);
+ msgStats.awb_ymin = (0xFF00 & temp) >> 8;
+
+ v4l2_subdev_notify(&vfe31_ctrl->subdev,
+ NOTIFY_VFE_MSG_COMP_STATS, &msgStats);
+}
+
+static void vfe31_process_stats_ae_irq(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&vfe31_ctrl->aec_ack_lock, flags);
+ if (!(vfe31_ctrl->aecStatsControl.ackPending)) {
+ spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+ vfe31_ctrl->aecStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_AE_NUM,
+ vfe31_ctrl->aecStatsControl.nextFrameAddrBuf);
+
+ vfe_send_stats_msg(vfe31_ctrl->aecStatsControl.bufToRender,
+ STATS_AE_NUM);
+ } else{
+ spin_unlock_irqrestore(&vfe31_ctrl->aec_ack_lock, flags);
+ vfe31_ctrl->aecStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe31_ctrl->aecStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe31_process_stats_awb_irq(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&vfe31_ctrl->awb_ack_lock, flags);
+ if (!(vfe31_ctrl->awbStatsControl.ackPending)) {
+ spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+ vfe31_ctrl->awbStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_AWB_NUM,
+ vfe31_ctrl->awbStatsControl.nextFrameAddrBuf);
+
+ vfe_send_stats_msg(vfe31_ctrl->awbStatsControl.bufToRender,
+ STATS_AWB_NUM);
+ } else{
+ spin_unlock_irqrestore(&vfe31_ctrl->awb_ack_lock, flags);
+ vfe31_ctrl->awbStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe31_ctrl->awbStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe31_process_stats_af_irq(void)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&vfe31_ctrl->af_ack_lock, flags);
+ if (!(vfe31_ctrl->afStatsControl.ackPending)) {
+ spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+ vfe31_ctrl->afStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_AF_NUM,
+ vfe31_ctrl->afStatsControl.nextFrameAddrBuf);
+
+ vfe_send_stats_msg(vfe31_ctrl->afStatsControl.bufToRender,
+ STATS_AF_NUM);
+ } else{
+ spin_unlock_irqrestore(&vfe31_ctrl->af_ack_lock, flags);
+ vfe31_ctrl->afStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe31_ctrl->afStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe31_process_stats_ihist_irq(void)
+{
+ if (!(vfe31_ctrl->ihistStatsControl.ackPending)) {
+ vfe31_ctrl->ihistStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_IHIST_NUM,
+ vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf);
+
+ vfe_send_stats_msg(vfe31_ctrl->ihistStatsControl.bufToRender,
+ STATS_IHIST_NUM);
+ } else {
+ vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe31_process_stats_rs_irq(void)
+{
+ if (!(vfe31_ctrl->rsStatsControl.ackPending)) {
+ vfe31_ctrl->rsStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_RS_NUM,
+ vfe31_ctrl->rsStatsControl.nextFrameAddrBuf);
+
+ vfe_send_stats_msg(vfe31_ctrl->rsStatsControl.bufToRender,
+ STATS_RS_NUM);
+ } else {
+ vfe31_ctrl->rsStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe31_ctrl->rsStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe31_process_stats_cs_irq(void)
+{
+ if (!(vfe31_ctrl->csStatsControl.ackPending)) {
+ vfe31_ctrl->csStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_CS_NUM,
+ vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
+
+ vfe_send_stats_msg(vfe31_ctrl->csStatsControl.bufToRender,
+ STATS_CS_NUM);
+ } else {
+ vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
+ CDBG("%s: droppedStatsFrameCount = %d", __func__,
+ vfe31_ctrl->csStatsControl.droppedStatsFrameCount);
+ }
+}
+
+static void vfe31_process_stats(uint32_t status_bits)
+{
+ unsigned long flags;
+ int32_t process_stats = false;
+ CDBG("%s, stats = 0x%x\n", __func__, status_bits);
+
+ spin_lock_irqsave(&vfe31_ctrl->comp_stats_ack_lock, flags);
+ if (status_bits & VFE_IRQ_STATUS0_STATS_AEC) {
+ if (!vfe31_ctrl->aecStatsControl.ackPending) {
+ vfe31_ctrl->aecStatsControl.ackPending = TRUE;
+ vfe31_ctrl->aecStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_AE_NUM,
+ vfe31_ctrl->aecStatsControl.nextFrameAddrBuf);
+ process_stats = true;
+ } else{
+ vfe31_ctrl->aecStatsControl.bufToRender = 0;
+ vfe31_ctrl->aecStatsControl.droppedStatsFrameCount++;
+ }
+ } else {
+ vfe31_ctrl->aecStatsControl.bufToRender = 0;
+ }
+
+ if (status_bits & VFE_IRQ_STATUS0_STATS_AWB) {
+ if (!vfe31_ctrl->awbStatsControl.ackPending) {
+ vfe31_ctrl->awbStatsControl.ackPending = TRUE;
+ vfe31_ctrl->awbStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_AWB_NUM,
+ vfe31_ctrl->awbStatsControl.nextFrameAddrBuf);
+ process_stats = true;
+ } else{
+ vfe31_ctrl->awbStatsControl.droppedStatsFrameCount++;
+ vfe31_ctrl->awbStatsControl.bufToRender = 0;
+ }
+ } else {
+ vfe31_ctrl->awbStatsControl.bufToRender = 0;
+ }
+
+
+ if (status_bits & VFE_IRQ_STATUS0_STATS_AF) {
+ if (!vfe31_ctrl->afStatsControl.ackPending) {
+ vfe31_ctrl->afStatsControl.ackPending = TRUE;
+ vfe31_ctrl->afStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_AF_NUM,
+ vfe31_ctrl->afStatsControl.nextFrameAddrBuf);
+ process_stats = true;
+ } else {
+ vfe31_ctrl->afStatsControl.bufToRender = 0;
+ vfe31_ctrl->afStatsControl.droppedStatsFrameCount++;
+ }
+ } else {
+ vfe31_ctrl->afStatsControl.bufToRender = 0;
+ }
+
+ if (status_bits & VFE_IRQ_STATUS0_STATS_IHIST) {
+ if (!vfe31_ctrl->ihistStatsControl.ackPending) {
+ vfe31_ctrl->ihistStatsControl.ackPending = TRUE;
+ vfe31_ctrl->ihistStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_IHIST_NUM,
+ vfe31_ctrl->ihistStatsControl.nextFrameAddrBuf);
+ process_stats = true;
+ } else {
+ vfe31_ctrl->ihistStatsControl.droppedStatsFrameCount++;
+ vfe31_ctrl->ihistStatsControl.bufToRender = 0;
+ }
+ } else {
+ vfe31_ctrl->ihistStatsControl.bufToRender = 0;
+ }
+
+ if (status_bits & VFE_IRQ_STATUS0_STATS_RS) {
+ if (!vfe31_ctrl->rsStatsControl.ackPending) {
+ vfe31_ctrl->rsStatsControl.ackPending = TRUE;
+ vfe31_ctrl->rsStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_RS_NUM,
+ vfe31_ctrl->rsStatsControl.nextFrameAddrBuf);
+ process_stats = true;
+ } else {
+ vfe31_ctrl->rsStatsControl.droppedStatsFrameCount++;
+ vfe31_ctrl->rsStatsControl.bufToRender = 0;
+ }
+ } else {
+ vfe31_ctrl->rsStatsControl.bufToRender = 0;
+ }
+
+
+ if (status_bits & VFE_IRQ_STATUS0_STATS_CS) {
+ if (!vfe31_ctrl->csStatsControl.ackPending) {
+ vfe31_ctrl->csStatsControl.ackPending = TRUE;
+ vfe31_ctrl->csStatsControl.bufToRender =
+ vfe31_process_stats_irq_common(STATS_CS_NUM,
+ vfe31_ctrl->csStatsControl.nextFrameAddrBuf);
+ process_stats = true;
+ } else {
+ vfe31_ctrl->csStatsControl.droppedStatsFrameCount++;
+ vfe31_ctrl->csStatsControl.bufToRender = 0;
+ }
+ } else {
+ vfe31_ctrl->csStatsControl.bufToRender = 0;
+ }
+
+ spin_unlock_irqrestore(&vfe31_ctrl->comp_stats_ack_lock, flags);
+ if (process_stats)
+ vfe_send_comp_stats_msg(status_bits);
+
+ return;
+}
+
+static void vfe31_process_stats_irq(uint32_t *irqstatus)
+{
+ uint32_t status_bits = VFE_COM_STATUS & *irqstatus;
+
+ if ((vfe31_ctrl->hfr_mode != HFR_MODE_OFF) &&
+ (vfe31_ctrl->vfeFrameId % vfe31_ctrl->hfr_mode != 0)) {
+ CDBG("Skip the stats when HFR enabled\n");
+ return;
+ }
+
+ vfe31_process_stats(status_bits);
+ return;
+}
+
+static void vfe31_do_tasklet(unsigned long data)
+{
+ unsigned long flags;
+
+ struct vfe31_isr_queue_cmd *qcmd = NULL;
+
+ CDBG("=== vfe31_do_tasklet start ===\n");
+
+ while (atomic_read(&irq_cnt)) {
+ spin_lock_irqsave(&vfe31_ctrl->tasklet_lock, flags);
+ qcmd = list_first_entry(&vfe31_ctrl->tasklet_q,
+ struct vfe31_isr_queue_cmd, list);
+ atomic_sub(1, &irq_cnt);
+
+ if (!qcmd) {
+ spin_unlock_irqrestore(&vfe31_ctrl->tasklet_lock,
+ flags);
+ return;
+ }
+
+ list_del(&qcmd->list);
+ spin_unlock_irqrestore(&vfe31_ctrl->tasklet_lock,
+ flags);
+
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_CAMIF_SOF_MASK) {
+ CDBG("irq camifSofIrq\n");
+ vfe31_process_camif_sof_irq();
+ }
+ /* interrupt to be processed, *qcmd has the payload. */
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_REG_UPDATE_MASK) {
+ CDBG("irq regUpdateIrq\n");
+ vfe31_process_reg_update_irq();
+ }
+
+ if (qcmd->vfeInterruptStatus1 &
+ VFE_IMASK_WHILE_STOPPING_1) {
+ CDBG("irq resetAckIrq\n");
+ vfe31_process_reset_irq();
+ }
+
+ if (atomic_read(&vfe31_ctrl->vstate)) {
+ if (qcmd->vfeInterruptStatus1 &
+ VFE31_IMASK_ERROR_ONLY_1) {
+ pr_err("irq errorIrq\n");
+ vfe31_process_error_irq(
+ qcmd->vfeInterruptStatus1 &
+ VFE31_IMASK_ERROR_ONLY_1);
+ }
+ /* next, check output path related interrupts. */
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK) {
+ CDBG("Image composite done 0 irq occured.\n");
+ vfe31_process_output_path_irq_0();
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK) {
+ CDBG("Image composite done 1 irq occured.\n");
+ vfe31_process_output_path_irq_1();
+ }
+ /* in snapshot mode if done then send
+ snapshot done message */
+ if (vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_MAIN ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_MAIN_AND_THUMB ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_THUMB_AND_JPEG ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_JPEG_AND_THUMB ||
+ vfe31_ctrl->operation_mode ==
+ VFE_OUTPUTS_RAW) {
+ if ((vfe31_ctrl->outpath.out0.capture_cnt == 0)
+ && (vfe31_ctrl->outpath.out1.
+ capture_cnt == 0)) {
+ msm_io_w_mb(
+ CAMIF_COMMAND_STOP_IMMEDIATELY,
+ vfe31_ctrl->vfebase +
+ VFE_CAMIF_COMMAND);
+ vfe31_send_isp_msg(vfe31_ctrl,
+ MSG_ID_SNAPSHOT_DONE);
+ }
+ }
+ /* then process stats irq. */
+ if (vfe31_ctrl->stats_comp) {
+ /* process stats comb interrupt. */
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK) {
+ CDBG("Stats composite irq occured.\n");
+ vfe31_process_stats_irq(
+ &qcmd->vfeInterruptStatus0);
+ }
+ } else {
+ /* process individual stats interrupt. */
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_AEC) {
+ CDBG("Stats AEC irq occured.\n");
+ vfe31_process_stats_ae_irq();
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_AWB) {
+ CDBG("Stats AWB irq occured.\n");
+ vfe31_process_stats_awb_irq();
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_AF) {
+ CDBG("Stats AF irq occured.\n");
+ vfe31_process_stats_af_irq();
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_IHIST) {
+ CDBG("Stats IHIST irq occured.\n");
+ vfe31_process_stats_ihist_irq();
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_RS) {
+ CDBG("Stats RS irq occured.\n");
+ vfe31_process_stats_rs_irq();
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_STATS_CS) {
+ CDBG("Stats CS irq occured.\n");
+ vfe31_process_stats_cs_irq();
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_SYNC_TIMER0) {
+ CDBG("SYNC_TIMER 0 irq occured.\n");
+ vfe31_send_isp_msg(vfe31_ctrl,
+ MSG_ID_SYNC_TIMER0_DONE);
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_SYNC_TIMER1) {
+ CDBG("SYNC_TIMER 1 irq occured.\n");
+ vfe31_send_isp_msg(vfe31_ctrl,
+ MSG_ID_SYNC_TIMER1_DONE);
+ }
+ if (qcmd->vfeInterruptStatus0 &
+ VFE_IRQ_STATUS0_SYNC_TIMER2) {
+ CDBG("SYNC_TIMER 2 irq occured.\n");
+ vfe31_send_isp_msg(vfe31_ctrl,
+ MSG_ID_SYNC_TIMER2_DONE);
+ }
+ }
+ }
+ kfree(qcmd);
+ }
+ CDBG("=== vfe31_do_tasklet end ===\n");
+}
+
+DECLARE_TASKLET(vfe31_tasklet, vfe31_do_tasklet, 0);
+
+static irqreturn_t vfe31_parse_irq(int irq_num, void *data)
+{
+ unsigned long flags;
+ struct vfe31_irq_status irq;
+ struct vfe31_isr_queue_cmd *qcmd;
+
+ CDBG("vfe_parse_irq\n");
+
+ vfe31_read_irq_status(&irq);
+
+ if ((irq.vfeIrqStatus0 == 0) && (irq.vfeIrqStatus1 == 0)) {
+ CDBG("vfe_parse_irq: vfeIrqStatus0 & 1 are both 0!\n");
+ return IRQ_HANDLED;
+ }
+
+ qcmd = kzalloc(sizeof(struct vfe31_isr_queue_cmd),
+ GFP_ATOMIC);
+ if (!qcmd) {
+ pr_err("vfe_parse_irq: qcmd malloc failed!\n");
+ return IRQ_HANDLED;
+ }
+
+ spin_lock_irqsave(&vfe31_ctrl->stop_flag_lock, flags);
+ if (vfe31_ctrl->stop_ack_pending) {
+ irq.vfeIrqStatus0 &= VFE_IMASK_WHILE_STOPPING_0;
+ irq.vfeIrqStatus1 &= VFE_IMASK_WHILE_STOPPING_1;
+ }
+ spin_unlock_irqrestore(&vfe31_ctrl->stop_flag_lock, flags);
+
+ CDBG("vfe_parse_irq: Irq_status0 = 0x%x, Irq_status1 = 0x%x.\n",
+ irq.vfeIrqStatus0, irq.vfeIrqStatus1);
+
+ qcmd->vfeInterruptStatus0 = irq.vfeIrqStatus0;
+ qcmd->vfeInterruptStatus1 = irq.vfeIrqStatus1;
+
+ spin_lock_irqsave(&vfe31_ctrl->tasklet_lock, flags);
+ list_add_tail(&qcmd->list, &vfe31_ctrl->tasklet_q);
+
+ atomic_add(1, &irq_cnt);
+ spin_unlock_irqrestore(&vfe31_ctrl->tasklet_lock, flags);
+ tasklet_schedule(&vfe31_tasklet);
+ return IRQ_HANDLED;
+}
+
+static long msm_vfe_subdev_ioctl(struct v4l2_subdev *sd,
+ unsigned int subdev_cmd, void *arg)
+{
+ struct msm_isp_cmd vfecmd;
+ struct msm_camvfe_params *vfe_params =
+ (struct msm_camvfe_params *)arg;
+ struct msm_vfe_cfg_cmd *cmd = vfe_params->vfe_cfg;
+ void *data = vfe_params->data;
+
+ long rc = 0;
+ uint32_t i = 0;
+ struct vfe_cmd_stats_buf *scfg = NULL;
+ struct msm_pmem_region *regptr = NULL;
+ struct vfe_cmd_stats_ack *sack = NULL;
+ if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR &&
+ cmd->cmd_type != CMD_STATS_AEC_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AWB_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_IHIST_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_RS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_CS_BUF_RELEASE &&
+ cmd->cmd_type != CMD_STATS_AF_BUF_RELEASE) {
+ if (copy_from_user(&vfecmd,
+ (void __user *)(cmd->value),
+ sizeof(vfecmd))) {
+ pr_err("%s %d: copy_from_user failed\n", __func__,
+ __LINE__);
+ return -EFAULT;
+ }
+ } else {
+ /* here eith stats release or frame release. */
+ if (cmd->cmd_type != CMD_CONFIG_PING_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_PONG_ADDR &&
+ cmd->cmd_type != CMD_CONFIG_FREE_BUF_ADDR) {
+ /* then must be stats release. */
+ if (!data)
+ return -EFAULT;
+ sack = kmalloc(sizeof(struct vfe_cmd_stats_ack),
+ GFP_ATOMIC);
+ if (!sack)
+ return -ENOMEM;
+
+ sack->nextStatsBuf = *(uint32_t *)data;
+ }
+ }
+
+ CDBG("%s: cmdType = %d\n", __func__, cmd->cmd_type);
+
+ if ((cmd->cmd_type == CMD_STATS_AF_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_AWB_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_IHIST_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_RS_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_CS_ENABLE) ||
+ (cmd->cmd_type == CMD_STATS_AEC_ENABLE)) {
+ struct axidata *axid;
+ axid = data;
+ if (!axid) {
+ rc = -EFAULT;
+ goto vfe31_config_done;
+ }
+
+ scfg =
+ kmalloc(sizeof(struct vfe_cmd_stats_buf),
+ GFP_ATOMIC);
+ if (!scfg) {
+ rc = -ENOMEM;
+ goto vfe31_config_done;
+ }
+ regptr = axid->region;
+ if (axid->bufnum1 > 0) {
+ for (i = 0; i < axid->bufnum1; i++) {
+ scfg->statsBuf[i] =
+ (uint32_t)(regptr->paddr);
+ regptr++;
+ }
+ }
+ /* individual */
+ switch (cmd->cmd_type) {
+ case CMD_STATS_AEC_ENABLE:
+ rc = vfe_stats_aec_buf_init(scfg);
+ break;
+ case CMD_STATS_AF_ENABLE:
+ rc = vfe_stats_af_buf_init(scfg);
+ break;
+ case CMD_STATS_AWB_ENABLE:
+ rc = vfe_stats_awb_buf_init(scfg);
+ break;
+ case CMD_STATS_IHIST_ENABLE:
+ rc = vfe_stats_ihist_buf_init(scfg);
+ break;
+ case CMD_STATS_RS_ENABLE:
+ rc = vfe_stats_rs_buf_init(scfg);
+ break;
+ case CMD_STATS_CS_ENABLE:
+ rc = vfe_stats_cs_buf_init(scfg);
+ break;
+ default:
+ pr_err("%s Unsupported cmd type %d",
+ __func__, cmd->cmd_type);
+ break;
+ }
+ goto vfe31_config_done;
+ }
+ switch (cmd->cmd_type) {
+ case CMD_GENERAL: {
+ rc = vfe31_proc_general(&vfecmd);
+ }
+ break;
+ case CMD_CONFIG_PING_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe31_output_ch *outch = vfe31_get_ch(path);
+ outch->ping = *((struct msm_free_buf *)data);
+ }
+ break;
+
+ case CMD_CONFIG_PONG_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe31_output_ch *outch = vfe31_get_ch(path);
+ outch->pong = *((struct msm_free_buf *)data);
+ }
+ break;
+
+ case CMD_CONFIG_FREE_BUF_ADDR: {
+ int path = *((int *)cmd->value);
+ struct vfe31_output_ch *outch = vfe31_get_ch(path);
+ outch->free_buf = *((struct msm_free_buf *)data);
+ }
+ break;
+
+ case CMD_SNAP_BUF_RELEASE:
+ break;
+
+ case CMD_STATS_AEC_BUF_RELEASE: {
+ vfe31_stats_aec_ack(sack);
+ }
+ break;
+
+ case CMD_STATS_AF_BUF_RELEASE: {
+ vfe31_stats_af_ack(sack);
+ }
+ break;
+
+ case CMD_STATS_AWB_BUF_RELEASE: {
+ vfe31_stats_awb_ack(sack);
+ }
+ break;
+
+ case CMD_STATS_IHIST_BUF_RELEASE: {
+ vfe31_stats_ihist_ack(sack);
+ }
+ break;
+
+ case CMD_STATS_RS_BUF_RELEASE: {
+ vfe31_stats_rs_ack(sack);
+ }
+ break;
+
+ case CMD_STATS_CS_BUF_RELEASE: {
+ vfe31_stats_cs_ack(sack);
+ }
+ break;
+
+ case CMD_AXI_CFG_PRIM: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi(OUTPUT_PRIM, axio);
+ kfree(axio);
+ }
+ break;
+
+ case CMD_AXI_CFG_PRIM_ALL_CHNLS: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi(OUTPUT_PRIM_ALL_CHNLS, axio);
+ kfree(axio);
+ }
+ break;
+
+ case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi(OUTPUT_PRIM|OUTPUT_SEC, axio);
+ kfree(axio);
+ }
+ break;
+
+ case CMD_AXI_CFG_PRIM|CMD_AXI_CFG_SEC_ALL_CHNLS: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi(OUTPUT_PRIM|OUTPUT_SEC_ALL_CHNLS, axio);
+ kfree(axio);
+ }
+ break;
+
+ case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC: {
+ uint32_t *axio = NULL;
+ axio = kmalloc(vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length,
+ GFP_ATOMIC);
+ if (!axio) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ if (copy_from_user(axio, (void __user *)(vfecmd.value),
+ vfe31_cmd[VFE_CMD_AXI_OUT_CFG].length)) {
+ kfree(axio);
+ rc = -EFAULT;
+ break;
+ }
+ vfe31_config_axi(OUTPUT_PRIM_ALL_CHNLS|OUTPUT_SEC, axio);
+ kfree(axio);
+ }
+ break;
+
+ case CMD_AXI_CFG_PRIM_ALL_CHNLS|CMD_AXI_CFG_SEC_ALL_CHNLS: {
+ pr_err("%s Invalid/Unsupported AXI configuration %x",
+ __func__, cmd->cmd_type);
+ }
+ break;
+
+ default:
+ pr_err("%s Unsupported AXI configuration %x ", __func__,
+ cmd->cmd_type);
+ break;
+ }
+vfe31_config_done:
+ kfree(scfg);
+ kfree(sack);
+ CDBG("%s done: rc = %d\n", __func__, (int) rc);
+ return rc;
+}
+
+static int msm_vfe_subdev_s_crystal_freq(struct v4l2_subdev *sd,
+ u32 freq, u32 flags)
+{
+ int rc = 0;
+ int round_rate;
+
+ round_rate = clk_round_rate(vfe31_ctrl->vfe_clk[0], freq);
+ if (rc < 0) {
+ pr_err("%s: clk_round_rate failed %d\n",
+ __func__, rc);
+ return rc;
+ }
+
+ vfe_clk_rate = round_rate;
+ rc = clk_set_rate(vfe31_ctrl->vfe_clk[0], round_rate);
+ if (rc < 0)
+ pr_err("%s: clk_set_rate failed %d\n",
+ __func__, rc);
+
+ return rc;
+}
+
+static const struct v4l2_subdev_video_ops msm_vfe_subdev_video_ops = {
+ .s_crystal_freq = msm_vfe_subdev_s_crystal_freq,
+};
+
+static const struct v4l2_subdev_core_ops msm_vfe_subdev_core_ops = {
+ .ioctl = msm_vfe_subdev_ioctl,
+};
+
+static const struct v4l2_subdev_ops msm_vfe_subdev_ops = {
+ .core = &msm_vfe_subdev_core_ops,
+ .video = &msm_vfe_subdev_video_ops,
+};
+
+static struct msm_cam_clk_info vfe_clk_info[] = {
+ {"vfe_clk", VFE_CLK_RATE},
+ {"vfe_pclk", -1},
+};
+
+static struct msm_cam_clk_info vfe_camif_clk_info[] = {
+ {"camif_pad_pclk", -1},
+ {"vfe_camif_clk", -1},
+};
+
+static void msm_vfe_camio_clk_sel(enum msm_camio_clk_src_type srctype)
+{
+ struct clk *clk = NULL;
+
+ clk = vfe31_ctrl->vfe_camif_clk[1];
+
+ if (clk != NULL) {
+ switch (srctype) {
+ case MSM_CAMIO_CLK_SRC_INTERNAL:
+ clk_set_flags(clk, 0x00000100 << 1);
+ break;
+
+ case MSM_CAMIO_CLK_SRC_EXTERNAL:
+ clk_set_flags(clk, 0x00000100);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+static void msm_vfe_camif_pad_reg_reset(void)
+{
+ uint32_t reg;
+
+ msm_vfe_camio_clk_sel(MSM_CAMIO_CLK_SRC_INTERNAL);
+ usleep_range(10000, 15000);
+
+ reg = (msm_io_r(vfe31_ctrl->camifbase)) & CAMIF_CFG_RMSK;
+ reg |= 0x3;
+ msm_io_w(reg, vfe31_ctrl->camifbase);
+ usleep_range(10000, 15000);
+
+ reg = (msm_io_r(vfe31_ctrl->camifbase)) & CAMIF_CFG_RMSK;
+ reg |= 0x10;
+ msm_io_w(reg, vfe31_ctrl->camifbase);
+ usleep_range(10000, 15000);
+
+ reg = (msm_io_r(vfe31_ctrl->camifbase)) & CAMIF_CFG_RMSK;
+ /* Need to be uninverted*/
+ reg &= 0x03;
+ msm_io_w(reg, vfe31_ctrl->camifbase);
+ usleep_range(10000, 15000);
+}
+
+int msm_vfe_subdev_init(struct v4l2_subdev *sd, void *data,
+ struct platform_device *pdev)
+{
+ int rc = 0;
+ struct msm_sync *sync = data;
+ v4l2_set_subdev_hostdata(sd, data);
+ vfe_syncdata = data;
+
+ spin_lock_init(&vfe31_ctrl->stop_flag_lock);
+ spin_lock_init(&vfe31_ctrl->state_lock);
+ spin_lock_init(&vfe31_ctrl->io_lock);
+ spin_lock_init(&vfe31_ctrl->update_ack_lock);
+ spin_lock_init(&vfe31_ctrl->tasklet_lock);
+
+ spin_lock_init(&vfe31_ctrl->aec_ack_lock);
+ spin_lock_init(&vfe31_ctrl->awb_ack_lock);
+ spin_lock_init(&vfe31_ctrl->af_ack_lock);
+ spin_lock_init(&vfe31_ctrl->ihist_ack_lock);
+ spin_lock_init(&vfe31_ctrl->rs_ack_lock);
+ spin_lock_init(&vfe31_ctrl->cs_ack_lock);
+ spin_lock_init(&vfe31_ctrl->comp_stats_ack_lock);
+ spin_lock_init(&vfe31_ctrl->sd_notify_lock);
+ INIT_LIST_HEAD(&vfe31_ctrl->tasklet_q);
+
+ vfe31_ctrl->update_linear = false;
+ vfe31_ctrl->update_rolloff = false;
+ vfe31_ctrl->update_la = false;
+ vfe31_ctrl->update_gamma = false;
+ vfe31_ctrl->hfr_mode = HFR_MODE_OFF;
+
+ vfe31_ctrl->vfebase = ioremap(vfe31_ctrl->vfemem->start,
+ resource_size(vfe31_ctrl->vfemem));
+ if (!vfe31_ctrl->vfebase) {
+ rc = -ENOMEM;
+ pr_err("%s: vfe ioremap failed\n", __func__);
+ goto vfe_remap_failed;
+ }
+ if (!sync->sdata->csi_if) {
+ vfe31_ctrl->camifbase = ioremap(vfe31_ctrl->camifmem->start,
+ resource_size(vfe31_ctrl->camifmem));
+ if (!vfe31_ctrl->camifbase) {
+ rc = -ENOMEM;
+ pr_err("%s: camif ioremap failed\n", __func__);
+ goto camif_remap_failed;
+ }
+ }
+
+ if (vfe31_ctrl->fs_vfe == NULL) {
+ vfe31_ctrl->fs_vfe =
+ regulator_get(&vfe31_ctrl->pdev->dev, "fs_vfe");
+ if (IS_ERR(vfe31_ctrl->fs_vfe)) {
+ pr_err("%s: Regulator FS_VFE get failed %ld\n",
+ __func__, PTR_ERR(vfe31_ctrl->fs_vfe));
+ vfe31_ctrl->fs_vfe = NULL;
+ goto vfe_fs_failed;
+ } else if (regulator_enable(vfe31_ctrl->fs_vfe)) {
+ pr_err("%s: Regulator FS_VFE enable failed\n",
+ __func__);
+ regulator_put(vfe31_ctrl->fs_vfe);
+ vfe31_ctrl->fs_vfe = NULL;
+ goto vfe_fs_failed;
+ }
+ }
+
+ rc = msm_cam_clk_enable(&vfe31_ctrl->pdev->dev, vfe_clk_info,
+ vfe31_ctrl->vfe_clk, ARRAY_SIZE(vfe_clk_info), 1);
+ if (rc < 0)
+ goto vfe_clk_enable_failed;
+
+ if (!sync->sdata->csi_if) {
+ rc = msm_cam_clk_enable(&vfe31_ctrl->pdev->dev,
+ vfe_camif_clk_info,
+ vfe31_ctrl->vfe_camif_clk,
+ ARRAY_SIZE(vfe_camif_clk_info), 1);
+ if (rc < 0)
+ goto vfe_clk_enable_failed;
+ msm_vfe_camif_pad_reg_reset();
+ }
+
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_INIT);
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_PREVIEW);
+ vfe31_ctrl->register_total = VFE31_REGISTER_TOTAL;
+
+ enable_irq(vfe31_ctrl->vfeirq->start);
+
+ return rc;
+
+vfe_clk_enable_failed:
+ regulator_disable(vfe31_ctrl->fs_vfe);
+ regulator_put(vfe31_ctrl->fs_vfe);
+ vfe31_ctrl->fs_vfe = NULL;
+vfe_fs_failed:
+ if (!sync->sdata->csi_if)
+ iounmap(vfe31_ctrl->camifbase);
+camif_remap_failed:
+ iounmap(vfe31_ctrl->vfebase);
+vfe_remap_failed:
+ disable_irq(vfe31_ctrl->vfeirq->start);
+ return rc;
+}
+
+void msm_vfe_subdev_release(struct platform_device *pdev)
+{
+ struct msm_sync *sync = vfe_syncdata;
+ disable_irq(vfe31_ctrl->vfeirq->start);
+ tasklet_kill(&vfe31_tasklet);
+
+ if (!sync->sdata->csi_if)
+ msm_cam_clk_enable(&vfe31_ctrl->pdev->dev,
+ vfe_camif_clk_info,
+ vfe31_ctrl->vfe_camif_clk,
+ ARRAY_SIZE(vfe_camif_clk_info), 0);
+
+ msm_cam_clk_enable(&vfe31_ctrl->pdev->dev, vfe_clk_info,
+ vfe31_ctrl->vfe_clk, ARRAY_SIZE(vfe_clk_info), 0);
+ if (vfe31_ctrl->fs_vfe) {
+ regulator_disable(vfe31_ctrl->fs_vfe);
+ regulator_put(vfe31_ctrl->fs_vfe);
+ vfe31_ctrl->fs_vfe = NULL;
+ }
+ CDBG("%s, 31ee_irq\n", __func__);
+ if (!sync->sdata->csi_if)
+ iounmap(vfe31_ctrl->camifbase);
+ iounmap(vfe31_ctrl->vfebase);
+
+ if (atomic_read(&irq_cnt))
+ pr_warning("%s, Warning IRQ Count not ZERO\n", __func__);
+
+ msm_camio_bus_scale_cfg(
+ sync->sdata->pdata->cam_bus_scale_table, S_EXIT);
+ vfe_syncdata = NULL;
+}
+
+
+static int __devinit vfe31_probe(struct platform_device *pdev)
+{
+ int rc = 0;
+ CDBG("%s: device id = %d\n", __func__, pdev->id);
+ vfe31_ctrl = kzalloc(sizeof(struct vfe31_ctrl_type), GFP_KERNEL);
+ if (!vfe31_ctrl) {
+ pr_err("%s: no enough memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ v4l2_subdev_init(&vfe31_ctrl->subdev, &msm_vfe_subdev_ops);
+ snprintf(vfe31_ctrl->subdev.name,
+ sizeof(vfe31_ctrl->subdev.name), "vfe3.1");
+ v4l2_set_subdevdata(&vfe31_ctrl->subdev, vfe31_ctrl);
+ platform_set_drvdata(pdev, &vfe31_ctrl->subdev);
+
+ vfe31_ctrl->vfemem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "msm_vfe");
+ if (!vfe31_ctrl->vfemem) {
+ pr_err("%s: no mem resource?\n", __func__);
+ rc = -ENODEV;
+ goto vfe31_no_resource;
+ }
+ vfe31_ctrl->vfeirq = platform_get_resource_byname(pdev,
+ IORESOURCE_IRQ, "msm_vfe");
+ if (!vfe31_ctrl->vfeirq) {
+ pr_err("%s: no irq resource?\n", __func__);
+ rc = -ENODEV;
+ goto vfe31_no_resource;
+ }
+ vfe31_ctrl->camifmem = platform_get_resource_byname(pdev,
+ IORESOURCE_MEM, "msm_camif");
+ if (!vfe31_ctrl->camifmem)
+ pr_err("%s: camif not supported\n", __func__);
+
+ vfe31_ctrl->vfeio = request_mem_region(vfe31_ctrl->vfemem->start,
+ resource_size(vfe31_ctrl->vfemem), pdev->name);
+ if (!vfe31_ctrl->vfeio) {
+ pr_err("%s: no valid mem region\n", __func__);
+ rc = -EBUSY;
+ goto vfe31_no_resource;
+ }
+
+ if (vfe31_ctrl->camifmem) {
+ vfe31_ctrl->camifio = request_mem_region(
+ vfe31_ctrl->camifmem->start,
+ resource_size(vfe31_ctrl->camifmem), pdev->name);
+ if (!vfe31_ctrl->camifio) {
+ release_mem_region(vfe31_ctrl->vfemem->start,
+ resource_size(vfe31_ctrl->vfemem));
+ pr_err("%s: no valid mem region\n", __func__);
+ rc = -EBUSY;
+ goto vfe31_no_resource;
+ }
+ }
+
+ rc = request_irq(vfe31_ctrl->vfeirq->start, vfe31_parse_irq,
+ IRQF_TRIGGER_RISING, "vfe", 0);
+ if (rc < 0) {
+ if (vfe31_ctrl->camifmem) {
+ release_mem_region(vfe31_ctrl->camifmem->start,
+ resource_size(vfe31_ctrl->camifmem));
+ }
+ release_mem_region(vfe31_ctrl->vfemem->start,
+ resource_size(vfe31_ctrl->vfemem));
+ pr_err("%s: irq request fail\n", __func__);
+ rc = -EBUSY;
+ goto vfe31_no_resource;
+ }
+
+ disable_irq(vfe31_ctrl->vfeirq->start);
+
+ vfe31_ctrl->pdev = pdev;
+ return 0;
+
+vfe31_no_resource:
+ kfree(vfe31_ctrl);
+ return 0;
+}
+
+static struct platform_driver vfe31_driver = {
+ .probe = vfe31_probe,
+ .driver = {
+ .name = MSM_VFE_DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init msm_vfe31_init_module(void)
+{
+ return platform_driver_register(&vfe31_driver);
+}
+
+static void __exit msm_vfe31_exit_module(void)
+{
+ platform_driver_unregister(&vfe31_driver);
+}
+
+module_init(msm_vfe31_init_module);
+module_exit(msm_vfe31_exit_module);
+MODULE_DESCRIPTION("VFE 3.1 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/msm/msm_vfe31_v4l2.h b/drivers/media/video/msm/msm_vfe31_v4l2.h
new file mode 100644
index 0000000..e94f286
--- /dev/null
+++ b/drivers/media/video/msm/msm_vfe31_v4l2.h
@@ -0,0 +1,955 @@
+/* Copyright (c) 2012 Code Aurora Forum. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __MSM_VFE31_V4L2_H__
+#define __MSM_VFE31_V4L2_H__
+
+#include <linux/bitops.h>
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* This defines total number registers in VFE.
+ * Each register is 4 bytes so to get the range,
+ * multiply this number with 4. */
+#define VFE31_REGISTER_TOTAL 0x0000017F
+
+/* at start of camif, bit 1:0 = 0x01:enable
+ * image data capture at frame boundary. */
+#define CAMIF_COMMAND_START 0x00000005
+
+/* bit 2= 0x1:clear the CAMIF_STATUS register
+ * value. */
+#define CAMIF_COMMAND_CLEAR 0x00000004
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x10:
+ * disable image data capture immediately. */
+#define CAMIF_COMMAND_STOP_IMMEDIATELY 0x00000002
+
+/* at stop of vfe pipeline, for now it is assumed
+ * that camif will stop at any time. Bit 1:0 = 0x00:
+ * disable image data capture at frame boundary */
+#define CAMIF_COMMAND_STOP_AT_FRAME_BOUNDARY 0x00000000
+
+/* to halt axi bridge */
+#define AXI_HALT 0x00000001
+
+/* clear the halt bit. */
+#define AXI_HALT_CLEAR 0x00000000
+
+/* clear axi_halt_irq */
+#define MASK_AXI_HALT_IRQ 0xFF7FFFFF
+
+/* reset the pipeline when stop command is issued.
+ * (without reset the register.) bit 26-31 = 0,
+ * domain reset, bit 0-9 = 1 for module reset, except
+ * register module. */
+#define VFE_RESET_UPON_STOP_CMD 0x000003ef
+
+/* reset the pipeline when reset command.
+ * bit 26-31 = 0, domain reset, bit 0-9 = 1 for module reset. */
+#define VFE_RESET_UPON_RESET_CMD 0x000003ff
+
+/* bit 5 is for axi status idle or busy.
+ * 1 = halted, 0 = busy */
+#define AXI_STATUS_BUSY_MASK 0x00000020
+
+/* bit 0 & bit 1 = 1, both y and cbcr irqs need to be present
+ * for frame done interrupt */
+#define VFE_COMP_IRQ_BOTH_Y_CBCR 3
+
+/* bit 1 = 1, only cbcr irq triggers frame done interrupt */
+#define VFE_COMP_IRQ_CBCR_ONLY 2
+
+/* bit 0 = 1, only y irq triggers frame done interrupt */
+#define VFE_COMP_IRQ_Y_ONLY 1
+
+/* bit 0 = 1, PM go; bit1 = 1, PM stop */
+#define VFE_PERFORMANCE_MONITOR_GO 0x00000001
+#define VFE_PERFORMANCE_MONITOR_STOP 0x00000002
+
+/* bit 0 = 1, test gen go; bit1 = 1, test gen stop */
+#define VFE_TEST_GEN_GO 0x00000001
+#define VFE_TEST_GEN_STOP 0x00000002
+
+/* the chroma is assumed to be interpolated between
+ * the luma samples. JPEG 4:2:2 */
+#define VFE_CHROMA_UPSAMPLE_INTERPOLATED 0
+
+/* constants for irq registers */
+#define VFE_DISABLE_ALL_IRQS 0
+/* bit =1 is to clear the corresponding bit in VFE_IRQ_STATUS. */
+#define VFE_CLEAR_ALL_IRQS 0xffffffff
+
+#define VFE_IRQ_STATUS0_CAMIF_SOF_MASK 0x00000001
+#define VFE_IRQ_STATUS0_CAMIF_EOF_MASK 0x00000004
+#define VFE_IRQ_STATUS0_REG_UPDATE_MASK 0x00000020
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE0_MASK 0x00200000
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE1_MASK 0x00400000
+#define VFE_IRQ_STATUS0_IMAGE_COMPOSIT_DONE2_MASK 0x00800000
+#define VFE_IRQ_STATUS1_RESET_AXI_HALT_ACK_MASK 0x00800000
+#define VFE_IRQ_STATUS0_STATS_COMPOSIT_MASK 0x01000000
+
+#define VFE_IRQ_STATUS0_STATS_AEC 0x2000 /* bit 13 */
+#define VFE_IRQ_STATUS0_STATS_AF 0x4000 /* bit 14 */
+#define VFE_IRQ_STATUS0_STATS_AWB 0x8000 /* bit 15 */
+#define VFE_IRQ_STATUS0_STATS_RS 0x10000 /* bit 16 */
+#define VFE_IRQ_STATUS0_STATS_CS 0x20000 /* bit 17 */
+#define VFE_IRQ_STATUS0_STATS_IHIST 0x40000 /* bit 18 */
+
+#define VFE_IRQ_STATUS0_SYNC_TIMER0 0x2000000 /* bit 25 */
+#define VFE_IRQ_STATUS0_SYNC_TIMER1 0x4000000 /* bit 26 */
+#define VFE_IRQ_STATUS0_SYNC_TIMER2 0x8000000 /* bit 27 */
+#define VFE_IRQ_STATUS0_ASYNC_TIMER0 0x10000000 /* bit 28 */
+#define VFE_IRQ_STATUS0_ASYNC_TIMER1 0x20000000 /* bit 29 */
+#define VFE_IRQ_STATUS0_ASYNC_TIMER2 0x40000000 /* bit 30 */
+#define VFE_IRQ_STATUS0_ASYNC_TIMER3 0x80000000 /* bit 31 */
+
+/* imask for while waiting for stop ack, driver has already
+ * requested stop, waiting for reset irq, and async timer irq.
+ * For irq_status_0, bit 28-31 are for async timer. For
+ * irq_status_1, bit 22 for reset irq, bit 23 for axi_halt_ack
+ irq */
+#define VFE_IMASK_WHILE_STOPPING_0 0xF0000000
+#define VFE_IMASK_WHILE_STOPPING_1 0x00C00000
+#define VFE_IMASK_RESET 0x00400000
+#define VFE_IMASK_AXI_HALT 0x00800000
+
+
+/* no error irq in mask 0 */
+#define VFE_IMASK_ERROR_ONLY_0 0x0
+/* when normal case, don't want to block error status. */
+/* bit 0-21 are error irq bits */
+#define VFE_IMASK_ERROR_ONLY_1 0x003fffff
+
+/* For BPC bit 0,bit 12-17 and bit 26 -20 are set to zero and other's 1 */
+#define BPC_MASK 0xF80C0FFE
+
+/* For BPC bit 1 and 2 are set to zero and other's 1 */
+#define ABF_MASK 0xFFFFFFF9
+
+/* For DBPC bit 0 is set to zero and other's 1 */
+#define DBPC_MASK 0xFFFFFFFE
+
+/* For DBCC bit 1 is set to zero and other's 1 */
+#define DBCC_MASK 0xFFFFFFFD
+
+/* For DBPC/ABF/DBCC/ABCC bits are set to 1 all others 0 */
+#define DEMOSAIC_MASK 0x8FFFFFFF
+/* For MCE enable bit 28 set to zero and other's 1 */
+#define MCE_EN_MASK 0xEFFFFFFF
+
+/* For MCE Q_K bit 28 to 31 set to zero and other's 1 */
+#define MCE_Q_K_MASK 0x0FFFFFFF
+
+#define AE_BG_ENABLE_MASK 0x00000020 /* bit 5 */
+#define AF_BF_ENABLE_MASK 0x00000040 /* bit 6 */
+#define AWB_ENABLE_MASK 0x00000080 /* bit 7 */
+
+#define RS_ENABLE_MASK 0x00000100 /* bit 8 */
+#define CS_ENABLE_MASK 0x00000200 /* bit 9 */
+#define RS_CS_ENABLE_MASK 0x00000300 /* bit 8,9 */
+#define IHIST_ENABLE_MASK 0x00008000 /* bit 15 */
+#define STATS_ENABLE_MASK 0x000483E0 /* bit 18,15,9,8,7,6,5*/
+
+#define VFE_REG_UPDATE_TRIGGER 1
+#define VFE_PM_BUF_MAX_CNT_MASK 0xFF
+#define VFE_DMI_CFG_DEFAULT 0x00000100
+#define VFE_AE_PINGPONG_STATUS_BIT 0x80
+#define VFE_AF_PINGPONG_STATUS_BIT 0x100
+#define VFE_AWB_PINGPONG_STATUS_BIT 0x200
+
+#define HFR_MODE_OFF 1
+#define VFE_FRAME_SKIP_PERIOD_MASK 0x0000001F /*bits 0 -4*/
+
+enum VFE31_DMI_RAM_SEL {
+ NO_MEM_SELECTED = 0,
+ ROLLOFF_RAM = 0x1,
+ RGBLUT_RAM_CH0_BANK0 = 0x2,
+ RGBLUT_RAM_CH0_BANK1 = 0x3,
+ RGBLUT_RAM_CH1_BANK0 = 0x4,
+ RGBLUT_RAM_CH1_BANK1 = 0x5,
+ RGBLUT_RAM_CH2_BANK0 = 0x6,
+ RGBLUT_RAM_CH2_BANK1 = 0x7,
+ STATS_HIST_RAM = 0x8,
+ RGBLUT_CHX_BANK0 = 0x9,
+ RGBLUT_CHX_BANK1 = 0xa,
+ LUMA_ADAPT_LUT_RAM_BANK0 = 0xb,
+ LUMA_ADAPT_LUT_RAM_BANK1 = 0xc
+};
+
+enum vfe_output_state {
+ VFE_STATE_IDLE,
+ VFE_STATE_START_REQUESTED,
+ VFE_STATE_STARTED,
+ VFE_STATE_STOP_REQUESTED,
+ VFE_STATE_STOPPED,
+};
+
+#define V31_CAMIF_OFF 0x000001E4
+#define V31_CAMIF_LEN 32
+
+#define V31_DEMUX_OFF 0x00000284
+#define V31_DEMUX_LEN 20
+
+#define V31_DEMOSAICV3_UP_REG_CNT 5
+
+#define V31_OUT_CLAMP_OFF 0x00000524
+#define V31_OUT_CLAMP_LEN 8
+
+#define V31_OPERATION_CFG_LEN 32
+
+#define V31_AXI_OUT_OFF 0x00000038
+#define V31_AXI_OUT_LEN 212
+#define V31_AXI_CH_INF_LEN 24
+#define V31_AXI_CFG_LEN 47
+#define V31_AXI_RESERVED 1
+
+#define V31_FRAME_SKIP_OFF 0x00000504
+#define V31_FRAME_SKIP_LEN 32
+
+#define V31_CHROMA_SUBS_OFF 0x000004F8
+#define V31_CHROMA_SUBS_LEN 12
+
+#define V31_FOV_OFF 0x00000360
+#define V31_FOV_LEN 8
+
+#define V31_MAIN_SCALER_OFF 0x00000368
+#define V31_MAIN_SCALER_LEN 28
+
+#define V31_S2Y_OFF 0x000004D0
+#define V31_S2Y_LEN 20
+
+#define V31_S2CbCr_OFF 0x000004E4
+#define V31_S2CbCr_LEN 20
+
+#define V31_CHROMA_EN_OFF 0x000003C4
+#define V31_CHROMA_EN_LEN 36
+
+#define V31_SYNC_TIMER_OFF 0x0000020C
+#define V31_SYNC_TIMER_POLARITY_OFF 0x00000234
+#define V31_TIMER_SELECT_OFF 0x0000025C
+#define V31_SYNC_TIMER_LEN 28
+
+#define V31_ASYNC_TIMER_OFF 0x00000238
+#define V31_ASYNC_TIMER_LEN 28
+
+#define V31_BLACK_LEVEL_OFF 0x00000264
+#define V31_BLACK_LEVEL_LEN 16
+
+#define V31_MESH_ROLL_OFF_CFG_OFF 0x00000274
+#define V31_MESH_ROLL_OFF_CFG_LEN 16
+#define V31_MESH_ROLL_OFF_INIT_TABLE_SIZE 13
+#define V31_MESH_ROLL_OFF_DELTA_TABLE_SIZE 208
+#define V31_MESH_ROLL_OFF_DELTA_TABLE_OFFSET 32
+
+#define V31_COLOR_COR_OFF 0x00000388
+#define V31_COLOR_COR_LEN 52
+
+#define V31_WB_OFF 0x00000384
+#define V31_WB_LEN 4
+
+#define V31_RGB_G_OFF 0x000003BC
+#define V31_RGB_G_LEN 4
+
+#define V31_LA_OFF 0x000003C0
+#define V31_LA_LEN 4
+
+#define V31_SCE_OFF 0x00000418
+#define V31_SCE_LEN 136
+
+#define V31_CHROMA_SUP_OFF 0x000003E8
+#define V31_CHROMA_SUP_LEN 12
+
+#define V31_MCE_OFF 0x000003F4
+#define V31_MCE_LEN 36
+#define V31_STATS_AF_OFF 0x0000053c
+#define V31_STATS_AF_LEN 16
+
+#define V31_STATS_AE_OFF 0x00000534
+#define V31_STATS_AE_LEN 8
+
+#define V31_STATS_AWB_OFF 0x0000054c
+#define V31_STATS_AWB_LEN 32
+
+#define V31_STATS_IHIST_OFF 0x0000057c
+#define V31_STATS_IHIST_LEN 8
+
+#define V31_STATS_RS_OFF 0x0000056c
+#define V31_STATS_RS_LEN 8
+
+#define V31_STATS_CS_OFF 0x00000574
+#define V31_STATS_CS_LEN 8
+
+#define V31_ASF_OFF 0x000004A0
+#define V31_ASF_LEN 48
+#define V31_ASF_UPDATE_LEN 36
+#define V31_CAPTURE_LEN 4
+#define V31_GET_HW_VERSION_OFF 0
+#define V31_GET_HW_VERSION_LEN 4
+#define V31_DEMOSAICV3_OFF 0x00000298
+#define V31_DEMOSAICV3_LEN 4
+/* BPC */
+#define V31_DEMOSAICV3_DBPC_CFG_OFF 0x0000029C
+#define V31_DEMOSAICV3_DBPC_LEN 8
+#define V31_XBAR_CFG_OFF 0x00000040
+/* ABF */
+#define V31_DEMOSAICV3_ABF_OFF 0x000002A4
+#define V31_DEMOSAICV3_ABF_LEN 180
+#define V31_XBAR_CFG_LEN 8
+
+#define V31_MODULE_CFG_OFF 0x00000010
+#define V31_MODULE_CFG_LEN 4
+#define V31_EZTUNE_CFG_OFF 0x00000010
+#define V31_EZTUNE_CFG_LEN 4
+
+struct vfe_cmd_hw_version {
+ uint32_t minorVersion;
+ uint32_t majorVersion;
+ uint32_t coreVersion;
+};
+
+enum VFE_AXI_OUTPUT_MODE {
+ VFE_AXI_OUTPUT_MODE_Output1,
+ VFE_AXI_OUTPUT_MODE_Output2,
+ VFE_AXI_OUTPUT_MODE_Output1AndOutput2,
+ VFE_AXI_OUTPUT_MODE_CAMIFToAXIViaOutput2,
+ VFE_AXI_OUTPUT_MODE_Output2AndCAMIFToAXIViaOutput1,
+ VFE_AXI_OUTPUT_MODE_Output1AndCAMIFToAXIViaOutput2,
+ VFE_AXI_LAST_OUTPUT_MODE_ENUM
+};
+
+enum VFE_RAW_WR_PATH_SEL {
+ VFE_RAW_OUTPUT_DISABLED,
+ VFE_RAW_OUTPUT_ENC_CBCR_PATH,
+ VFE_RAW_OUTPUT_VIEW_CBCR_PATH,
+ VFE_RAW_OUTPUT_PATH_INVALID
+};
+
+#define VFE_AXI_OUTPUT_BURST_LENGTH 4
+#define VFE_MAX_NUM_FRAGMENTS_PER_FRAME 4
+#define VFE_AXI_OUTPUT_CFG_FRAME_COUNT 3
+
+struct vfe_cmds_per_write_master {
+ uint16_t imageWidth;
+ uint16_t imageHeight;
+ uint16_t outRowCount;
+ uint16_t outRowIncrement;
+ uint32_t outFragments[VFE_AXI_OUTPUT_CFG_FRAME_COUNT]
+ [VFE_MAX_NUM_FRAGMENTS_PER_FRAME];
+};
+
+struct vfe_cmds_axi_per_output_path {
+ uint8_t fragmentCount;
+ struct vfe_cmds_per_write_master firstWM;
+ struct vfe_cmds_per_write_master secondWM;
+};
+
+enum VFE_AXI_BURST_LENGTH {
+ VFE_AXI_BURST_LENGTH_IS_2 = 2,
+ VFE_AXI_BURST_LENGTH_IS_4 = 4,
+ VFE_AXI_BURST_LENGTH_IS_8 = 8,
+ VFE_AXI_BURST_LENGTH_IS_16 = 16
+};
+
+struct vfe_cmd_fov_crop_config {
+ uint8_t enable;
+ uint16_t firstPixel;
+ uint16_t lastPixel;
+ uint16_t firstLine;
+ uint16_t lastLine;
+};
+
+struct vfe_cmds_main_scaler_stripe_init {
+ uint16_t MNCounterInit;
+ uint16_t phaseInit;
+};
+
+struct vfe_cmds_scaler_one_dimension {
+ uint8_t enable;
+ uint16_t inputSize;
+ uint16_t outputSize;
+ uint32_t phaseMultiplicationFactor;
+ uint8_t interpolationResolution;
+};
+
+struct vfe_cmd_main_scaler_config {
+ uint8_t enable;
+ struct vfe_cmds_scaler_one_dimension hconfig;
+ struct vfe_cmds_scaler_one_dimension vconfig;
+ struct vfe_cmds_main_scaler_stripe_init MNInitH;
+ struct vfe_cmds_main_scaler_stripe_init MNInitV;
+};
+
+struct vfe_cmd_scaler2_config {
+ uint8_t enable;
+ struct vfe_cmds_scaler_one_dimension hconfig;
+ struct vfe_cmds_scaler_one_dimension vconfig;
+};
+
+
+struct vfe_cmd_frame_skip_update {
+ uint32_t output1Pattern;
+ uint32_t output2Pattern;
+};
+
+struct vfe_cmd_output_clamp_config {
+ uint8_t minCh0;
+ uint8_t minCh1;
+ uint8_t minCh2;
+ uint8_t maxCh0;
+ uint8_t maxCh1;
+ uint8_t maxCh2;
+};
+
+struct vfe_cmd_chroma_subsample_config {
+ uint8_t enable;
+ uint8_t cropEnable;
+ uint8_t vsubSampleEnable;
+ uint8_t hsubSampleEnable;
+ uint8_t vCosited;
+ uint8_t hCosited;
+ uint8_t vCositedPhase;
+ uint8_t hCositedPhase;
+ uint16_t cropWidthFirstPixel;
+ uint16_t cropWidthLastPixel;
+ uint16_t cropHeightFirstLine;
+ uint16_t cropHeightLastLine;
+};
+
+enum VFE_START_PIXEL_PATTERN {
+ VFE_BAYER_RGRGRG,
+ VFE_BAYER_GRGRGR,
+ VFE_BAYER_BGBGBG,
+ VFE_BAYER_GBGBGB,
+ VFE_YUV_YCbYCr,
+ VFE_YUV_YCrYCb,
+ VFE_YUV_CbYCrY,
+ VFE_YUV_CrYCbY
+};
+
+enum VFE_BUS_RD_INPUT_PIXEL_PATTERN {
+ VFE_BAYER_RAW,
+ VFE_YUV_INTERLEAVED,
+ VFE_YUV_PSEUDO_PLANAR_Y,
+ VFE_YUV_PSEUDO_PLANAR_CBCR
+};
+
+enum VFE_YUV_INPUT_COSITING_MODE {
+ VFE_YUV_COSITED,
+ VFE_YUV_INTERPOLATED
+};
+
+#define VFE31_GAMMA_NUM_ENTRIES 64
+
+#define VFE31_LA_TABLE_LENGTH 64
+
+#define VFE31_HIST_TABLE_LENGTH 256
+
+struct vfe_cmds_demosaic_abf {
+ uint8_t enable;
+ uint8_t forceOn;
+ uint8_t shift;
+ uint16_t lpThreshold;
+ uint16_t max;
+ uint16_t min;
+ uint8_t ratio;
+};
+
+struct vfe_cmds_demosaic_bpc {
+ uint8_t enable;
+ uint16_t fmaxThreshold;
+ uint16_t fminThreshold;
+ uint16_t redDiffThreshold;
+ uint16_t blueDiffThreshold;
+ uint16_t greenDiffThreshold;
+};
+
+struct vfe_cmd_demosaic_config {
+ uint8_t enable;
+ uint8_t slopeShift;
+ struct vfe_cmds_demosaic_abf abfConfig;
+ struct vfe_cmds_demosaic_bpc bpcConfig;
+};
+
+struct vfe_cmd_demosaic_bpc_update {
+ struct vfe_cmds_demosaic_bpc bpcUpdate;
+};
+
+struct vfe_cmd_demosaic_abf_update {
+ struct vfe_cmds_demosaic_abf abfUpdate;
+};
+
+struct vfe_cmd_white_balance_config {
+ uint8_t enable;
+ uint16_t ch2Gain;
+ uint16_t ch1Gain;
+ uint16_t ch0Gain;
+};
+
+enum VFE_COLOR_CORRECTION_COEF_QFACTOR {
+ COEF_IS_Q7_SIGNED,
+ COEF_IS_Q8_SIGNED,
+ COEF_IS_Q9_SIGNED,
+ COEF_IS_Q10_SIGNED
+};
+
+struct vfe_cmd_color_correction_config {
+ uint8_t enable;
+ enum VFE_COLOR_CORRECTION_COEF_QFACTOR coefQFactor;
+ int16_t C0;
+ int16_t C1;
+ int16_t C2;
+ int16_t C3;
+ int16_t C4;
+ int16_t C5;
+ int16_t C6;
+ int16_t C7;
+ int16_t C8;
+ int16_t K0;
+ int16_t K1;
+ int16_t K2;
+};
+
+#define VFE_LA_TABLE_LENGTH 64
+
+struct vfe_cmd_la_config {
+ uint8_t enable;
+ int16_t table[VFE_LA_TABLE_LENGTH];
+};
+
+#define VFE_GAMMA_TABLE_LENGTH 256
+enum VFE_RGB_GAMMA_TABLE_SELECT {
+ RGB_GAMMA_CH0_SELECTED,
+ RGB_GAMMA_CH1_SELECTED,
+ RGB_GAMMA_CH2_SELECTED,
+ RGB_GAMMA_CH0_CH1_SELECTED,
+ RGB_GAMMA_CH0_CH2_SELECTED,
+ RGB_GAMMA_CH1_CH2_SELECTED,
+ RGB_GAMMA_CH0_CH1_CH2_SELECTED
+};
+
+struct vfe_cmd_rgb_gamma_config {
+ uint8_t enable;
+ enum VFE_RGB_GAMMA_TABLE_SELECT channelSelect;
+ int16_t table[VFE_GAMMA_TABLE_LENGTH];
+};
+
+struct vfe_cmd_chroma_enhan_config {
+ uint8_t enable;
+ int16_t am;
+ int16_t ap;
+ int16_t bm;
+ int16_t bp;
+ int16_t cm;
+ int16_t cp;
+ int16_t dm;
+ int16_t dp;
+ int16_t kcr;
+ int16_t kcb;
+ int16_t RGBtoYConversionV0;
+ int16_t RGBtoYConversionV1;
+ int16_t RGBtoYConversionV2;
+ uint8_t RGBtoYConversionOffset;
+};
+
+struct vfe_cmd_chroma_suppression_config {
+ uint8_t enable;
+ uint8_t m1;
+ uint8_t m3;
+ uint8_t n1;
+ uint8_t n3;
+ uint8_t nn1;
+ uint8_t mm1;
+};
+
+struct vfe_cmd_asf_config {
+ uint8_t enable;
+ uint8_t smoothFilterEnabled;
+ uint8_t sharpMode;
+ uint8_t smoothCoefCenter;
+ uint8_t smoothCoefSurr;
+ uint8_t normalizeFactor;
+ uint8_t sharpK1;
+ uint8_t sharpK2;
+ uint8_t sharpThreshE1;
+ int8_t sharpThreshE2;
+ int8_t sharpThreshE3;
+ int8_t sharpThreshE4;
+ int8_t sharpThreshE5;
+ int8_t filter1Coefficients[9];
+ int8_t filter2Coefficients[9];
+ uint8_t cropEnable;
+ uint16_t cropFirstPixel;
+ uint16_t cropLastPixel;
+ uint16_t cropFirstLine;
+ uint16_t cropLastLine;
+};
+
+struct vfe_cmd_asf_update {
+ uint8_t enable;
+ uint8_t smoothFilterEnabled;
+ uint8_t sharpMode;
+ uint8_t smoothCoefCenter;
+ uint8_t smoothCoefSurr;
+ uint8_t normalizeFactor;
+ uint8_t sharpK1;
+ uint8_t sharpK2;
+ uint8_t sharpThreshE1;
+ int8_t sharpThreshE2;
+ int8_t sharpThreshE3;
+ int8_t sharpThreshE4;
+ int8_t sharpThreshE5;
+ int8_t filter1Coefficients[9];
+ int8_t filter2Coefficients[9];
+ uint8_t cropEnable;
+};
+
+enum VFE_TEST_GEN_SYNC_EDGE {
+ VFE_TEST_GEN_SYNC_EDGE_ActiveHigh,
+ VFE_TEST_GEN_SYNC_EDGE_ActiveLow
+};
+
+
+struct vfe_cmd_bus_pm_start {
+ uint8_t output2YWrPmEnable;
+ uint8_t output2CbcrWrPmEnable;
+ uint8_t output1YWrPmEnable;
+ uint8_t output1CbcrWrPmEnable;
+};
+
+struct vfe_frame_skip_counts {
+ uint32_t totalFrameCount;
+ uint32_t output1Count;
+ uint32_t output2Count;
+};
+
+enum VFE_AXI_RD_UNPACK_HBI_SEL {
+ VFE_AXI_RD_HBI_32_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_64_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_128_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_256_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_512_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_1024_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_2048_CLOCK_CYCLES,
+ VFE_AXI_RD_HBI_4096_CLOCK_CYCLES
+};
+
+struct vfe_frame_bpc_info {
+ uint32_t greenDefectPixelCount;
+ uint32_t redBlueDefectPixelCount;
+};
+
+struct vfe_frame_asf_info {
+ uint32_t asfMaxEdge;
+ uint32_t asfHbiCount;
+};
+
+struct vfe_msg_camif_status {
+ uint8_t camifState;
+ uint32_t pixelCount;
+ uint32_t lineCount;
+};
+
+struct vfe31_irq_status {
+ uint32_t vfeIrqStatus0;
+ uint32_t vfeIrqStatus1;
+ uint32_t camifStatus;
+ uint32_t demosaicStatus;
+ uint32_t asfMaxEdge;
+};
+
+#define V31_PREVIEW_AXI_FLAG 0x00000001
+#define V31_SNAPSHOT_AXI_FLAG (0x00000001<<1)
+
+struct vfe31_cmd_type {
+ uint16_t id;
+ uint32_t length;
+ uint32_t offset;
+ uint32_t flag;
+};
+
+struct vfe31_free_buf {
+ struct list_head node;
+ uint32_t paddr;
+ uint32_t y_off;
+ uint32_t cbcr_off;
+};
+
+struct vfe31_output_ch {
+ struct list_head free_buf_queue;
+ spinlock_t free_buf_lock;
+ uint16_t output_fmt;
+ int8_t ch0;
+ int8_t ch1;
+ int8_t ch2;
+ uint32_t capture_cnt;
+ uint32_t frame_drop_cnt;
+ struct msm_free_buf ping;
+ struct msm_free_buf pong;
+ struct msm_free_buf free_buf;
+};
+
+/* no error irq in mask 0 */
+#define VFE31_IMASK_ERROR_ONLY_0 0x0
+/* when normal case, don't want to block error status. */
+/* bit 0-21 are error irq bits */
+#define VFE31_IMASK_ERROR_ONLY_1 0x003FFFFF
+#define VFE31_IMASK_CAMIF_ERROR (0x00000001<<0)
+#define VFE31_IMASK_STATS_CS_OVWR (0x00000001<<1)
+#define VFE31_IMASK_STATS_IHIST_OVWR (0x00000001<<2)
+#define VFE31_IMASK_REALIGN_BUF_Y_OVFL (0x00000001<<3)
+#define VFE31_IMASK_REALIGN_BUF_CB_OVFL (0x00000001<<4)
+#define VFE31_IMASK_REALIGN_BUF_CR_OVFL (0x00000001<<5)
+#define VFE31_IMASK_VIOLATION (0x00000001<<6)
+#define VFE31_IMASK_IMG_MAST_0_BUS_OVFL (0x00000001<<7)
+#define VFE31_IMASK_IMG_MAST_1_BUS_OVFL (0x00000001<<8)
+#define VFE31_IMASK_IMG_MAST_2_BUS_OVFL (0x00000001<<9)
+#define VFE31_IMASK_IMG_MAST_3_BUS_OVFL (0x00000001<<10)
+#define VFE31_IMASK_IMG_MAST_4_BUS_OVFL (0x00000001<<11)
+#define VFE31_IMASK_IMG_MAST_5_BUS_OVFL (0x00000001<<12)
+#define VFE31_IMASK_IMG_MAST_6_BUS_OVFL (0x00000001<<13)
+#define VFE31_IMASK_STATS_AE_BG_BUS_OVFL (0x00000001<<14)
+#define VFE31_IMASK_STATS_AF_BF_BUS_OVFL (0x00000001<<15)
+#define VFE31_IMASK_STATS_AWB_BUS_OVFL (0x00000001<<16)
+#define VFE31_IMASK_STATS_RS_BUS_OVFL (0x00000001<<17)
+#define VFE31_IMASK_STATS_CS_BUS_OVFL (0x00000001<<18)
+#define VFE31_IMASK_STATS_IHIST_BUS_OVFL (0x00000001<<19)
+#define VFE31_IMASK_STATS_SKIN_BHIST_BUS_OVFL (0x00000001<<20)
+#define VFE31_IMASK_AXI_ERROR (0x00000001<<21)
+
+#define VFE_COM_STATUS 0x000FE000
+
+struct vfe31_output_path {
+ uint16_t output_mode; /* bitmask */
+
+ struct vfe31_output_ch out0; /* preview and thumbnail */
+ struct vfe31_output_ch out1; /* snapshot */
+ struct vfe31_output_ch out2; /* video */
+};
+
+struct vfe31_frame_extra {
+ uint32_t greenDefectPixelCount;
+ uint32_t redBlueDefectPixelCount;
+
+ uint32_t asfMaxEdge;
+ uint32_t asfHbiCount;
+
+ uint32_t yWrPmStats0;
+ uint32_t yWrPmStats1;
+ uint32_t cbcrWrPmStats0;
+ uint32_t cbcrWrPmStats1;
+
+ uint32_t frameCounter;
+};
+
+#define VFE_DISABLE_ALL_IRQS 0
+#define VFE_CLEAR_ALL_IRQS 0xffffffff
+
+#define VFE_HW_VERSION 0x00000000
+#define VFE_GLOBAL_RESET 0x00000004
+#define VFE_MODULE_RESET 0x00000008
+#define VFE_CGC_OVERRIDE 0x0000000C
+#define VFE_MODULE_CFG 0x00000010
+#define VFE_CFG 0x00000014
+#define VFE_IRQ_CMD 0x00000018
+#define VFE_IRQ_MASK_0 0x0000001C
+#define VFE_IRQ_MASK_1 0x00000020
+#define VFE_IRQ_CLEAR_0 0x00000024
+#define VFE_IRQ_CLEAR_1 0x00000028
+#define VFE_IRQ_STATUS_0 0x0000002C
+#define VFE_IRQ_STATUS_1 0x00000030
+#define VFE_IRQ_COMP_MASK 0x00000034
+#define VFE_BUS_CMD 0x00000038
+#define VFE_BUS_PING_PONG_STATUS 0x00000180
+#define VFE_BUS_OPERATION_STATUS 0x00000184
+
+#define VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_0 0x00000190
+#define VFE_BUS_IMAGE_MASTER_0_WR_PM_STATS_1 0x00000194
+
+#define VFE_AXI_CMD 0x000001D8
+#define VFE_AXI_STATUS 0x000001DC
+#define VFE_BUS_STATS_PING_PONG_BASE 0x000000F4
+
+#define VFE_BUS_STATS_AEC_WR_PING_ADDR 0x000000F4
+#define VFE_BUS_STATS_AEC_WR_PONG_ADDR 0x000000F8
+#define VFE_BUS_STATS_AEC_UB_CFG 0x000000FC
+#define VFE_BUS_STATS_AF_WR_PING_ADDR 0x00000100
+#define VFE_BUS_STATS_AF_WR_PONG_ADDR 0x00000104
+#define VFE_BUS_STATS_AF_UB_CFG 0x00000108
+#define VFE_BUS_STATS_AWB_WR_PING_ADDR 0x0000010C
+#define VFE_BUS_STATS_AWB_WR_PONG_ADDR 0x00000110
+#define VFE_BUS_STATS_AWB_UB_CFG 0x00000114
+#define VFE_BUS_STATS_RS_WR_PING_ADDR 0x00000118
+#define VFE_BUS_STATS_RS_WR_PONG_ADDR 0x0000011C
+#define VFE_BUS_STATS_RS_UB_CFG 0x00000120
+
+#define VFE_BUS_STATS_CS_WR_PING_ADDR 0x00000124
+#define VFE_BUS_STATS_CS_WR_PONG_ADDR 0x00000128
+#define VFE_BUS_STATS_CS_UB_CFG 0x0000012C
+#define VFE_BUS_STATS_HIST_WR_PING_ADDR 0x00000130
+#define VFE_BUS_STATS_HIST_WR_PONG_ADDR 0x00000134
+#define VFE_BUS_STATS_HIST_UB_CFG 0x00000138
+#define VFE_BUS_STATS_SKIN_WR_PING_ADDR 0x0000013C
+#define VFE_BUS_STATS_SKIN_WR_PONG_ADDR 0x00000140
+#define VFE_BUS_STATS_SKIN_UB_CFG 0x00000144
+#define VFE_BUS_PM_CMD 0x00000188
+#define VFE_BUS_PM_CFG 0x0000018C
+#define VFE_CAMIF_COMMAND 0x000001E0
+#define VFE_CAMIF_STATUS 0x00000204
+#define VFE_REG_UPDATE_CMD 0x00000260
+#define VFE_DEMUX_GAIN_0 0x00000288
+#define VFE_DEMUX_GAIN_1 0x0000028C
+#define VFE_CHROMA_UP 0x0000035C
+#define VFE_FRAMEDROP_ENC_Y_CFG 0x00000504
+#define VFE_FRAMEDROP_ENC_CBCR_CFG 0x00000508
+#define VFE_FRAMEDROP_ENC_Y_PATTERN 0x0000050C
+#define VFE_FRAMEDROP_ENC_CBCR_PATTERN 0x00000510
+#define VFE_FRAMEDROP_VIEW_Y 0x00000514
+#define VFE_FRAMEDROP_VIEW_CBCR 0x00000518
+#define VFE_FRAMEDROP_VIEW_Y_PATTERN 0x0000051C
+#define VFE_FRAMEDROP_VIEW_CBCR_PATTERN 0x00000520
+#define VFE_CLAMP_MAX 0x00000524
+#define VFE_CLAMP_MIN 0x00000528
+#define VFE_REALIGN_BUF 0x0000052C
+#define VFE_STATS_CFG 0x00000530
+#define VFE_STATS_AWB_SGW_CFG 0x00000554
+#define VFE_DMI_CFG 0x00000598
+#define VFE_DMI_ADDR 0x0000059C
+#define VFE_DMI_DATA_LO 0x000005A4
+#define VFE_AXI_CFG 0x00000600
+
+#define VFE31_OUTPUT_MODE_PT BIT(0)
+#define VFE31_OUTPUT_MODE_S BIT(1)
+#define VFE31_OUTPUT_MODE_V BIT(2)
+#define VFE31_OUTPUT_MODE_P BIT(3)
+#define VFE31_OUTPUT_MODE_T BIT(4)
+#define VFE31_OUTPUT_MODE_P_ALL_CHNLS BIT(5)
+#define VFE31_OUTPUT_MODE_PRIMARY BIT(6)
+#define VFE31_OUTPUT_MODE_PRIMARY_ALL_CHNLS BIT(7)
+#define VFE31_OUTPUT_MODE_SECONDARY BIT(8)
+#define VFE31_OUTPUT_MODE_SECONDARY_ALL_CHNLS BIT(9)
+struct vfe_stats_control {
+ uint8_t ackPending;
+ uint32_t nextFrameAddrBuf;
+ uint32_t droppedStatsFrameCount;
+ uint32_t bufToRender;
+};
+
+struct vfe31_ctrl_type {
+ uint16_t operation_mode; /* streaming or snapshot */
+ struct vfe31_output_path outpath;
+
+ uint32_t vfeImaskCompositePacked;
+
+ spinlock_t stop_flag_lock;
+ spinlock_t update_ack_lock;
+ spinlock_t state_lock;
+ spinlock_t io_lock;
+
+ spinlock_t aec_ack_lock;
+ spinlock_t awb_ack_lock;
+ spinlock_t af_ack_lock;
+ spinlock_t ihist_ack_lock;
+ spinlock_t rs_ack_lock;
+ spinlock_t cs_ack_lock;
+ spinlock_t comp_stats_ack_lock;
+
+ uint32_t extlen;
+ void *extdata;
+
+ int8_t start_ack_pending;
+ int8_t stop_ack_pending;
+ int8_t reset_ack_pending;
+ int8_t update_ack_pending;
+ enum vfe_output_state recording_state;
+ int8_t update_linear;
+ int8_t update_rolloff;
+ int8_t update_la;
+ int8_t update_gamma;
+ enum vfe_output_state liveshot_state;
+
+ spinlock_t tasklet_lock;
+ struct list_head tasklet_q;
+ void __iomem *vfebase;
+ void __iomem *camifbase;
+ void *syncdata;
+ uint32_t register_total;
+
+ struct resource *vfemem;
+ struct resource *camifmem;
+ struct resource *vfeio;
+ struct resource *camifio;
+ struct resource *vfeirq;
+ struct regulator *fs_vfe;
+
+ uint32_t stats_comp;
+ atomic_t vstate;
+ uint32_t vfe_capture_count;
+ uint32_t sync_timer_repeat_count;
+ uint32_t sync_timer_state;
+ uint32_t sync_timer_number;
+
+ uint32_t vfeFrameId;
+ uint32_t output1Pattern;
+ uint32_t output1Period;
+ uint32_t output2Pattern;
+ uint32_t output2Period;
+ uint32_t vfeFrameSkipCount;
+ uint32_t vfeFrameSkipPeriod;
+ struct vfe_stats_control afStatsControl;
+ struct vfe_stats_control awbStatsControl;
+ struct vfe_stats_control aecStatsControl;
+ struct vfe_stats_control ihistStatsControl;
+ struct vfe_stats_control rsStatsControl;
+ struct vfe_stats_control csStatsControl;
+
+ /* v4l2 subdev */
+ struct v4l2_subdev subdev;
+ struct platform_device *pdev;
+ struct clk *vfe_clk[5];
+ struct clk *vfe_camif_clk[2];
+ spinlock_t sd_notify_lock;
+ uint32_t hfr_mode;
+ uint32_t frame_skip_cnt;
+ uint32_t frame_skip_pattern;
+ uint32_t snapshot_frame_cnt;
+};
+
+enum VFE31_STATS_NUM {
+ STATS_AE_NUM,
+ STATS_AF_NUM,
+ STATS_AWB_NUM,
+ STATS_RS_NUM,
+ STATS_CS_NUM,
+ STATS_IHIST_NUM,
+ STATS_SKIN_NUM,
+ STATS_MAX_NUM,
+};
+
+struct vfe_cmd_stats_ack {
+ uint32_t nextStatsBuf;
+};
+
+#define VFE_STATS_BUFFER_COUNT 3
+
+struct vfe_cmd_stats_buf {
+ uint32_t statsBuf[VFE_STATS_BUFFER_COUNT];
+};
+#endif /* __MSM_VFE31_H__ */
diff --git a/drivers/media/video/msm/sensors/imx074_v4l2.c b/drivers/media/video/msm/sensors/imx074_v4l2.c
index af9d1f4..5330d7b 100644
--- a/drivers/media/video/msm/sensors/imx074_v4l2.c
+++ b/drivers/media/video/msm/sensors/imx074_v4l2.c
@@ -168,6 +168,19 @@
},
};
+static struct msm_camera_csi_params imx074_csic_params = {
+ .data_format = CSI_10BIT,
+ .lane_cnt = 4,
+ .lane_assign = 0xe4,
+ .dpcm_scheme = 0,
+ .settle_cnt = 0x14,
+};
+
+static struct msm_camera_csi_params *imx074_csic_params_array[] = {
+ &imx074_csic_params,
+ &imx074_csic_params,
+};
+
static struct msm_camera_csid_vc_cfg imx074_cid_cfg[] = {
{0, CSI_RAW10, CSI_DECODE_10BIT},
{1, CSI_EMBED_DATA, CSI_DECODE_8BIT},
@@ -288,6 +301,7 @@
.sensor_write_exp_gain = msm_sensor_write_exp_gain1,
.sensor_write_snapshot_exp_gain = msm_sensor_write_exp_gain1,
.sensor_setting = msm_sensor_setting,
+ .sensor_csi_setting = msm_sensor_setting1,
.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
@@ -323,6 +337,7 @@
.sensor_id_info = &imx074_id_info,
.sensor_exp_gain_info = &imx074_exp_gain_info,
.cam_mode = MSM_SENSOR_MODE_INVALID,
+ .csic_params = &imx074_csic_params_array[0],
.csi_params = &imx074_csi_params_array[0],
.msm_sensor_mutex = &imx074_mut,
.sensor_i2c_driver = &imx074_i2c_driver,
diff --git a/drivers/media/video/msm/sensors/msm_sensor.c b/drivers/media/video/msm/sensors/msm_sensor.c
index d882e52..3da7c5d 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.c
+++ b/drivers/media/video/msm/sensors/msm_sensor.c
@@ -245,6 +245,10 @@
msleep(30);
csi_config = 1;
}
+ v4l2_subdev_notify(&s_ctrl->sensor_v4l2_subdev,
+ NOTIFY_PCLK_CHANGE,
+ &s_ctrl->sensordata->pdata->ioclk.vfe_clk_rate);
+
s_ctrl->func_tbl->sensor_start_stream(s_ctrl);
msleep(50);
}
@@ -312,8 +316,13 @@
s_ctrl->msm_sensor_reg->
output_settings[res].line_length_pclk;
- if (s_ctrl->func_tbl->sensor_setting
- (s_ctrl, MSM_SENSOR_UPDATE_PERIODIC, res) < 0)
+ if (s_ctrl->sensordata->pdata->is_csic)
+ rc = s_ctrl->func_tbl->sensor_csi_setting(s_ctrl,
+ MSM_SENSOR_UPDATE_PERIODIC, res);
+ else
+ rc = s_ctrl->func_tbl->sensor_setting(s_ctrl,
+ MSM_SENSOR_UPDATE_PERIODIC, res);
+ if (rc < 0)
return rc;
s_ctrl->curr_res = res;
}
@@ -333,8 +342,12 @@
s_ctrl->curr_res = MSM_SENSOR_INVALID_RES;
s_ctrl->cam_mode = mode;
- rc = s_ctrl->func_tbl->sensor_setting(s_ctrl,
- MSM_SENSOR_REG_INIT, 0);
+ if (s_ctrl->sensordata->pdata->is_csic)
+ rc = s_ctrl->func_tbl->sensor_csi_setting(s_ctrl,
+ MSM_SENSOR_REG_INIT, 0);
+ else
+ rc = s_ctrl->func_tbl->sensor_setting(s_ctrl,
+ MSM_SENSOR_REG_INIT, 0);
}
return rc;
}
@@ -608,6 +621,8 @@
msm_sensor_disable_i2c_mux(
data->sensor_platform_info->i2c_conf);
+ s_ctrl->func_tbl->sensor_stop_stream(s_ctrl);
+ msleep(20);
if (data->sensor_platform_info->ext_power_ctrl != NULL)
data->sensor_platform_info->ext_power_ctrl(0);
msm_cam_clk_enable(&s_ctrl->sensor_i2c_client->client->dev,
@@ -626,7 +641,6 @@
return 0;
}
-
int32_t msm_sensor_match_id(struct msm_sensor_ctrl_t *s_ctrl)
{
int32_t rc = 0;
@@ -686,7 +700,10 @@
if (rc < 0)
goto probe_fail;
- rc = msm_sensor_match_id(s_ctrl);
+ if (s_ctrl->func_tbl->sensor_match_id)
+ rc = s_ctrl->func_tbl->sensor_match_id(s_ctrl);
+ else
+ rc = msm_sensor_match_id(s_ctrl);
if (rc < 0)
goto probe_fail;
@@ -717,7 +734,7 @@
msm_sensor_register(&s_ctrl->sensor_v4l2_subdev);
goto power_down;
probe_fail:
- CDBG("%s_i2c_probe failed\n", client->name);
+ pr_err("%s_i2c_probe failed\n", client->name);
power_down:
if (rc > 0)
rc = 0;
diff --git a/drivers/media/video/msm/sensors/msm_sensor.h b/drivers/media/video/msm/sensors/msm_sensor.h
index d1a6cee..421e1d1 100644
--- a/drivers/media/video/msm/sensors/msm_sensor.h
+++ b/drivers/media/video/msm/sensors/msm_sensor.h
@@ -120,6 +120,8 @@
uint16_t, uint32_t);
int32_t (*sensor_setting) (struct msm_sensor_ctrl_t *,
int update_type, int rt);
+ int32_t (*sensor_csi_setting) (struct msm_sensor_ctrl_t *,
+ int update_type, int rt);
int32_t (*sensor_set_sensor_mode)
(struct msm_sensor_ctrl_t *, int, int);
int32_t (*sensor_mode_init) (struct msm_sensor_ctrl_t *,
@@ -130,6 +132,7 @@
int (*sensor_power_down)
(struct msm_sensor_ctrl_t *);
int (*sensor_power_up) (struct msm_sensor_ctrl_t *);
+ int32_t (*sensor_match_id)(struct msm_sensor_ctrl_t *s_ctrl);
};
struct msm_sensor_ctrl_t {
diff --git a/drivers/media/video/msm/sensors/mt9e013_v4l2.c b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
index a6bc653..e6e2d52 100644
--- a/drivers/media/video/msm/sensors/mt9e013_v4l2.c
+++ b/drivers/media/video/msm/sensors/mt9e013_v4l2.c
@@ -465,7 +465,7 @@
.sensor_set_fps = msm_sensor_set_fps,
.sensor_write_exp_gain = mt9e013_write_exp_gain,
.sensor_write_snapshot_exp_gain = mt9e013_write_exp_snapshot_gain,
- .sensor_setting = msm_sensor_setting1,
+ .sensor_csi_setting = msm_sensor_setting1,
.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
diff --git a/drivers/media/video/msm/sensors/ov5647_v4l2.c b/drivers/media/video/msm/sensors/ov5647_v4l2.c
index ba0592e..7c23fe6 100644
--- a/drivers/media/video/msm/sensors/ov5647_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov5647_v4l2.c
@@ -693,7 +693,7 @@
.sensor_set_fps = msm_sensor_set_fps,
.sensor_write_exp_gain = ov5647_write_prev_exp_gain,
.sensor_write_snapshot_exp_gain = ov5647_write_pict_exp_gain,
- .sensor_setting = ov5647_sensor_setting,
+ .sensor_csi_setting = ov5647_sensor_setting,
.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
diff --git a/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c b/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
index 99e96f0..9fe2e8a 100644
--- a/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov7692_qrd_v4l2.c
@@ -688,7 +688,7 @@
.sensor_group_hold_on = msm_sensor_group_hold_on,
.sensor_group_hold_off = msm_sensor_group_hold_off,
.sensor_set_fps = ov7692_sensor_set_fps,
- .sensor_setting = msm_sensor_setting3,
+ .sensor_csi_setting = msm_sensor_setting3,
.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
diff --git a/drivers/media/video/msm/sensors/ov9726_v4l2.c b/drivers/media/video/msm/sensors/ov9726_v4l2.c
index 17291ff..61c693e 100644
--- a/drivers/media/video/msm/sensors/ov9726_v4l2.c
+++ b/drivers/media/video/msm/sensors/ov9726_v4l2.c
@@ -229,7 +229,7 @@
.sensor_set_fps = msm_sensor_set_fps,
.sensor_write_exp_gain = msm_sensor_write_exp_gain1,
.sensor_write_snapshot_exp_gain = msm_sensor_write_exp_gain1,
- .sensor_setting = msm_sensor_setting1,
+ .sensor_csi_setting = msm_sensor_setting1,
.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
diff --git a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
index 699f0dd..6671073 100644
--- a/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
+++ b/drivers/media/video/msm/sensors/s5k4e1_v4l2.c
@@ -450,7 +450,7 @@
.sensor_set_fps = msm_sensor_set_fps,
.sensor_write_exp_gain = s5k4e1_write_prev_exp_gain,
.sensor_write_snapshot_exp_gain = s5k4e1_write_pict_exp_gain,
- .sensor_setting = msm_sensor_setting1,
+ .sensor_csi_setting = msm_sensor_setting1,
.sensor_set_sensor_mode = msm_sensor_set_sensor_mode,
.sensor_mode_init = msm_sensor_mode_init,
.sensor_get_output_info = msm_sensor_get_output_info,
diff --git a/drivers/power/pm8921-bms.c b/drivers/power/pm8921-bms.c
index c275a06..e21862a 100644
--- a/drivers/power/pm8921-bms.c
+++ b/drivers/power/pm8921-bms.c
@@ -44,6 +44,8 @@
#define ADC_ARB_SECP_DATA0 0x196
#define ADC_ARB_BMS_CNTRL 0x18D
+#define AMUX_TRIM_2 0x322
+#define TEST_PROGRAM_REV 0x339
enum pmic_bms_interrupts {
PM8921_BMS_SBI_WRITE_OK,
@@ -121,6 +123,7 @@
int batt_temp_suspend;
int soc_rbatt_suspend;
int default_rbatt_mohm;
+ int amux_2_trim_delta;
uint16_t prev_last_good_ocv_raw;
};
@@ -520,6 +523,20 @@
return 0;
}
+static int adjust_xo_vbatt_reading_for_mbg(struct pm8921_bms_chip *chip,
+ int result)
+{
+ int64_t numerator;
+ int64_t denominator;
+
+ if (chip->amux_2_trim_delta == 0)
+ return result;
+
+ numerator = (s64)result * 1000000;
+ denominator = (1000000 + (410 * (s64)chip->amux_2_trim_delta));
+ return div_s64(numerator, denominator);
+}
+
static int convert_vbatt_raw_to_uv(struct pm8921_bms_chip *chip,
int usb_chg,
uint16_t reading, int *result)
@@ -528,6 +545,7 @@
pr_debug("raw = %04x vbatt = %u\n", reading, *result);
*result = adjust_xo_vbatt_reading(chip, usb_chg, *result);
pr_debug("after adj vbatt = %u\n", *result);
+ *result = adjust_xo_vbatt_reading_for_mbg(chip, *result);
return 0;
}
@@ -902,6 +920,19 @@
return 0;
}
+#define MBG_TRANSIENT_ERROR_RAW 51
+static void adjust_pon_ocv_raw(struct pm8921_bms_chip *chip,
+ struct pm8921_soc_params *raw)
+{
+ /* in 8921 parts the PON ocv is taken when the MBG is not settled.
+ * decrease the pon ocv by 15mV raw value to account for it
+ * Since a 1/3rd of vbatt is supplied to the adc the raw value
+ * needs to be adjusted by 5mV worth bits
+ */
+ if (raw->last_good_ocv_raw >= MBG_TRANSIENT_ERROR_RAW)
+ raw->last_good_ocv_raw -= MBG_TRANSIENT_ERROR_RAW;
+}
+
static int read_soc_params_raw(struct pm8921_bms_chip *chip,
struct pm8921_soc_params *raw)
{
@@ -919,8 +950,13 @@
usb_chg = usb_chg_plugged_in();
- if (chip->prev_last_good_ocv_raw == 0 ||
- chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
+ if (chip->prev_last_good_ocv_raw == 0) {
+ chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
+ adjust_pon_ocv_raw(chip, raw);
+ convert_vbatt_raw_to_uv(chip, usb_chg,
+ raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
+ last_ocv_uv = raw->last_good_ocv_uv;
+ } else if (chip->prev_last_good_ocv_raw != raw->last_good_ocv_raw) {
chip->prev_last_good_ocv_raw = raw->last_good_ocv_raw;
convert_vbatt_raw_to_uv(chip, usb_chg,
raw->last_good_ocv_raw, &raw->last_good_ocv_uv);
@@ -929,9 +965,6 @@
raw->last_good_ocv_uv = last_ocv_uv;
}
- if (raw->last_good_ocv_uv)
- last_ocv_uv = raw->last_good_ocv_uv;
-
pr_debug("0p625 = %duV\n", chip->xoadc_v0625);
pr_debug("1p25 = %duV\n", chip->xoadc_v125);
pr_debug("last_good_ocv_raw= 0x%x, last_good_ocv_uv= %duV\n",
@@ -2190,6 +2223,61 @@
}
}
+#define REG_SBI_CONFIG 0x04F
+#define PAGE3_ENABLE_MASK 0x6
+#define PROGRAM_REV_MASK 0x0F
+#define PROGRAM_REV 0x9
+static int read_ocv_trim(struct pm8921_bms_chip *chip)
+{
+ int rc;
+ u8 reg, sbi_config;
+
+ rc = pm8xxx_readb(chip->dev->parent, REG_SBI_CONFIG, &sbi_config);
+ if (rc) {
+ pr_err("error = %d reading sbi config reg\n", rc);
+ return rc;
+ }
+
+ reg = sbi_config | PAGE3_ENABLE_MASK;
+ rc = pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, reg);
+ if (rc) {
+ pr_err("error = %d writing sbi config reg\n", rc);
+ return rc;
+ }
+
+ rc = pm8xxx_readb(chip->dev->parent, TEST_PROGRAM_REV, ®);
+ if (rc)
+ pr_err("Error %d reading %d addr %d\n",
+ rc, reg, TEST_PROGRAM_REV);
+ pr_err("program rev reg is 0x%x\n", reg);
+ reg &= PROGRAM_REV_MASK;
+
+ /* If the revision is equal or higher do not adjust trim delta */
+ if (reg >= PROGRAM_REV) {
+ chip->amux_2_trim_delta = 0;
+ goto restore_sbi_config;
+ }
+
+ rc = pm8xxx_readb(chip->dev->parent, AMUX_TRIM_2, ®);
+ if (rc) {
+ pr_err("error = %d reading trim reg\n", rc);
+ return rc;
+ }
+
+ pr_err("trim reg is 0x%x\n", reg);
+ chip->amux_2_trim_delta = abs(0x49 - reg);
+ pr_err("trim delta is %d\n", chip->amux_2_trim_delta);
+
+restore_sbi_config:
+ rc = pm8xxx_writeb(chip->dev->parent, REG_SBI_CONFIG, sbi_config);
+ if (rc) {
+ pr_err("error = %d writing sbi config reg\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
static int __devinit pm8921_bms_probe(struct platform_device *pdev)
{
int rc = 0;
@@ -2259,6 +2347,11 @@
the_chip = chip;
create_debugfs_entries(chip);
+ rc = read_ocv_trim(chip);
+ if (rc) {
+ pr_err("couldn't adjust ocv_trim rc= %d\n", rc);
+ goto free_irqs;
+ }
check_initial_ocv(chip);
INIT_DELAYED_WORK(&chip->calib_ccadc_work, calibrate_ccadc_work);
diff --git a/drivers/usb/gadget/f_mbim.c b/drivers/usb/gadget/f_mbim.c
index 8288496..21b393e 100644
--- a/drivers/usb/gadget/f_mbim.c
+++ b/drivers/usb/gadget/f_mbim.c
@@ -553,7 +553,7 @@
}
spin_lock_irqsave(&dev->lock, flags);
- list_add(&cpkt->list, &dev->cpkt_resp_q);
+ list_add_tail(&cpkt->list, &dev->cpkt_resp_q);
spin_unlock_irqrestore(&dev->lock, flags);
fmbim_ctrl_response_available(dev);
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 226ea68..2114287 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -114,6 +114,7 @@
#define RC_MAP_NORWOOD "rc-norwood"
#define RC_MAP_NPGTECH "rc-npgtech"
#define RC_MAP_PCTV_SEDNA "rc-pctv-sedna"
+#define RC_MAP_RC6_PHILIPS "rc-philips"
#define RC_MAP_PINNACLE_COLOR "rc-pinnacle-color"
#define RC_MAP_PINNACLE_GREY "rc-pinnacle-grey"
#define RC_MAP_PINNACLE_PCTV_HD "rc-pinnacle-pctv-hd"